@analyticscli/sdk 0.1.0-preview.4 → 0.1.0-preview.6

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.
@@ -93,6 +93,9 @@ var validateEvent = (event, index) => {
93
93
  if (!isOptionalStringMax(event.platform, 64)) {
94
94
  return { success: false, reason: `events[${index}].platform is invalid` };
95
95
  }
96
+ if (!isOptionalStringMax(event.projectSurface, 64)) {
97
+ return { success: false, reason: `events[${index}].projectSurface is invalid` };
98
+ }
96
99
  if (!isOptionalStringMax(event.appVersion, 64)) {
97
100
  return { success: false, reason: `events[${index}].appVersion is invalid` };
98
101
  }
@@ -521,6 +524,7 @@ var sanitizeSurveyResponseInput = (input) => {
521
524
  };
522
525
 
523
526
  // src/analytics-client.ts
527
+ var DEFAULT_CONSENT_STORAGE_KEY = "analyticscli:consent:v1";
524
528
  var AnalyticsClient = class {
525
529
  apiKey;
526
530
  hasIngestConfig;
@@ -530,10 +534,17 @@ var AnalyticsClient = class {
530
534
  maxRetries;
531
535
  debug;
532
536
  platform;
537
+ projectSurface;
533
538
  appVersion;
539
+ identityTrackingMode;
534
540
  context;
541
+ configuredStorage;
535
542
  storage;
536
543
  storageReadsAreAsync;
544
+ persistConsentState;
545
+ consentStorageKey;
546
+ hasExplicitInitialConsent;
547
+ hasExplicitInitialFullTrackingConsent;
537
548
  sessionTimeoutMs;
538
549
  dedupeOnboardingStepViewsPerSession;
539
550
  runtimeEnv;
@@ -544,6 +555,7 @@ var AnalyticsClient = class {
544
555
  flushTimer = null;
545
556
  isFlushing = false;
546
557
  consentGranted = true;
558
+ fullTrackingConsentGranted = false;
547
559
  userId = null;
548
560
  anonId;
549
561
  sessionId;
@@ -566,34 +578,46 @@ var AnalyticsClient = class {
566
578
  this.maxRetries = normalizedOptions.maxRetries ?? 4;
567
579
  this.debug = normalizedOptions.debug ?? false;
568
580
  this.platform = this.normalizePlatformOption(normalizedOptions.platform) ?? detectDefaultPlatform();
581
+ this.projectSurface = this.normalizeProjectSurfaceOption(normalizedOptions.projectSurface);
569
582
  this.appVersion = this.readRequiredStringOption(normalizedOptions.appVersion) || detectDefaultAppVersion();
583
+ this.identityTrackingMode = this.resolveIdentityTrackingModeOption(normalizedOptions);
570
584
  this.context = { ...normalizedOptions.context ?? {} };
571
585
  this.runtimeEnv = detectRuntimeEnv();
572
- const useCookieStorage = normalizedOptions.useCookieStorage ?? Boolean(normalizedOptions.cookieDomain);
573
- const cookieStorage = resolveCookieStorageAdapter(
574
- useCookieStorage,
575
- normalizedOptions.cookieDomain,
576
- normalizedOptions.cookieMaxAgeSeconds ?? DEFAULT_COOKIE_MAX_AGE_SECONDS
577
- );
578
- const browserStorage = resolveBrowserStorageAdapter();
579
- this.storage = normalizedOptions.storage ?? (cookieStorage && browserStorage ? combineStorageAdapters(cookieStorage, browserStorage) : cookieStorage ?? browserStorage);
580
- this.storageReadsAreAsync = this.detectAsyncStorageReads();
586
+ this.persistConsentState = normalizedOptions.persistConsentState ?? false;
587
+ this.consentStorageKey = this.readRequiredStringOption(normalizedOptions.consentStorageKey) || DEFAULT_CONSENT_STORAGE_KEY;
588
+ this.hasExplicitInitialConsent = typeof normalizedOptions.initialConsentGranted === "boolean";
589
+ this.hasExplicitInitialFullTrackingConsent = typeof normalizedOptions.initialFullTrackingConsentGranted === "boolean";
581
590
  this.sessionTimeoutMs = normalizedOptions.sessionTimeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS;
582
- this.dedupeOnboardingStepViewsPerSession = normalizedOptions.dedupeOnboardingStepViewsPerSession ?? false;
583
- const providedAnonId = normalizedOptions.anonId?.trim();
584
- const providedSessionId = normalizedOptions.sessionId?.trim();
591
+ this.dedupeOnboardingStepViewsPerSession = normalizedOptions.dedupeOnboardingStepViewsPerSession ?? true;
592
+ this.configuredStorage = this.resolveConfiguredStorage(normalizedOptions);
593
+ const persistedFullTrackingConsent = this.readPersistedConsentSync(this.configuredStorage);
594
+ const configuredFullTrackingConsent = normalizedOptions.initialFullTrackingConsentGranted;
595
+ const initialFullTrackingConsentGranted = typeof configuredFullTrackingConsent === "boolean" ? configuredFullTrackingConsent : persistedFullTrackingConsent ?? false;
596
+ this.fullTrackingConsentGranted = this.identityTrackingMode === "always_on" || initialFullTrackingConsentGranted;
597
+ this.storage = this.isFullTrackingActive() ? this.configuredStorage : null;
598
+ this.storageReadsAreAsync = this.detectAsyncStorageReads();
599
+ const providedAnonId = this.isFullTrackingActive() ? this.readRequiredStringOption(normalizedOptions.anonId) : "";
600
+ const providedSessionId = this.isFullTrackingActive() ? this.readRequiredStringOption(normalizedOptions.sessionId) : "";
585
601
  this.hasExplicitAnonId = Boolean(providedAnonId);
586
602
  this.hasExplicitSessionId = Boolean(providedSessionId);
587
603
  this.anonId = providedAnonId || this.ensureDeviceId();
588
604
  this.sessionId = providedSessionId || this.ensureSessionId();
589
605
  this.sessionEventSeq = this.readSessionEventSeq(this.sessionId);
590
- this.consentGranted = this.hasIngestConfig;
606
+ const persistedConsent = this.readPersistedConsentSync(this.storage);
607
+ const configuredConsent = normalizedOptions.initialConsentGranted;
608
+ const initialConsentGranted = typeof configuredConsent === "boolean" ? configuredConsent : persistedConsent ?? this.hasIngestConfig;
609
+ this.consentGranted = this.hasIngestConfig && initialConsentGranted;
610
+ if (this.hasExplicitInitialConsent && this.persistConsentState) {
611
+ this.writePersistedConsent(this.storage, this.consentGranted);
612
+ }
613
+ if (this.hasExplicitInitialFullTrackingConsent && this.persistConsentState) {
614
+ this.writePersistedConsent(this.configuredStorage, this.fullTrackingConsentGranted);
615
+ }
591
616
  this.hydrationPromise = this.hydrateIdentityFromStorage();
592
617
  this.startAutoFlush();
593
618
  }
594
619
  /**
595
- * Resolves once any async storage adapter hydration completes.
596
- * Useful in React Native when using async persistence (for example AsyncStorage).
620
+ * Resolves once client initialization work completes.
597
621
  */
598
622
  async ready() {
599
623
  await this.hydrationPromise;
@@ -602,22 +626,41 @@ var AnalyticsClient = class {
602
626
  * Enables or disables event collection.
603
627
  * When disabled, queued events are dropped immediately.
604
628
  */
605
- setConsent(granted) {
629
+ setConsent(granted, options = {}) {
606
630
  if (granted && !this.hasIngestConfig) {
607
631
  this.log("Ignoring consent opt-in because `apiKey` is missing");
608
632
  return;
609
633
  }
610
634
  this.consentGranted = granted;
635
+ if ((options.persist ?? true) && this.persistConsentState) {
636
+ this.writePersistedConsent(this.storage, granted);
637
+ }
638
+ if (this.identityTrackingMode === "consent_gated") {
639
+ this.setFullTrackingConsent(granted, options);
640
+ }
611
641
  if (!granted) {
612
642
  this.queue = [];
613
643
  this.deferredEventsBeforeHydration = [];
614
644
  }
615
645
  }
616
- optIn() {
617
- this.setConsent(true);
646
+ optIn(options) {
647
+ this.setConsent(true, options);
648
+ }
649
+ optOut(options) {
650
+ this.setConsent(false, options);
618
651
  }
619
- optOut() {
620
- this.setConsent(false);
652
+ getConsent() {
653
+ return this.consentGranted;
654
+ }
655
+ getConsentState() {
656
+ const persisted = this.readPersistedConsentSync(this.storage);
657
+ if (persisted === true) {
658
+ return "granted";
659
+ }
660
+ if (persisted === false) {
661
+ return "denied";
662
+ }
663
+ return this.consentGranted ? "granted" : "unknown";
621
664
  }
622
665
  /**
623
666
  * Sets or updates shared event context fields (useful for mobile device/app metadata).
@@ -633,22 +676,25 @@ var AnalyticsClient = class {
633
676
  * Anonymous history remains linked by anonId/sessionId.
634
677
  */
635
678
  identify(userId, traits) {
636
- if (!this.consentGranted) {
637
- return;
638
- }
639
679
  const normalizedUserId = this.readRequiredStringOption(userId);
640
680
  if (!normalizedUserId) {
641
- this.log("Dropping identify call without required `userId`");
642
681
  return;
643
682
  }
683
+ if (!this.isFullTrackingActive()) {
684
+ this.log("Ignoring identify() because identity persistence is not enabled");
685
+ return;
686
+ }
687
+ this.userId = normalizedUserId;
688
+ if (!this.consentGranted) {
689
+ return;
690
+ }
691
+ const normalizedTraits = this.cloneProperties(traits);
644
692
  if (this.shouldDeferEventsUntilHydrated()) {
645
- const deferredTraits = this.cloneProperties(traits);
646
693
  this.deferEventUntilHydrated(() => {
647
- this.identify(normalizedUserId, deferredTraits);
694
+ this.identify(normalizedUserId, normalizedTraits);
648
695
  });
649
696
  return;
650
697
  }
651
- this.userId = normalizedUserId;
652
698
  const sessionId = this.getSessionId();
653
699
  this.enqueue({
654
700
  eventId: randomId(),
@@ -657,8 +703,9 @@ var AnalyticsClient = class {
657
703
  sessionId,
658
704
  anonId: this.anonId,
659
705
  userId: normalizedUserId,
660
- properties: this.withRuntimeMetadata(traits, sessionId),
706
+ properties: this.withRuntimeMetadata(normalizedTraits, sessionId),
661
707
  platform: this.platform,
708
+ projectSurface: this.projectSurface,
662
709
  appVersion: this.appVersion,
663
710
  ...this.withEventContext(),
664
711
  type: "identify"
@@ -670,13 +717,39 @@ var AnalyticsClient = class {
670
717
  * - pass null/undefined/empty string to clear user linkage
671
718
  */
672
719
  setUser(userId, traits) {
673
- const normalizedUserId = typeof userId === "string" ? this.readRequiredStringOption(userId) : "";
720
+ const normalizedUserId = this.readRequiredStringOption(userId);
674
721
  if (!normalizedUserId) {
675
722
  this.clearUser();
676
723
  return;
677
724
  }
678
725
  this.identify(normalizedUserId, traits);
679
726
  }
727
+ /**
728
+ * Sets consent specifically for persistent identity tracking.
729
+ * In `consent_gated` mode this toggles strict-vs-full identity behavior while generic event tracking can stay enabled.
730
+ */
731
+ setFullTrackingConsent(granted, options = {}) {
732
+ if (this.identityTrackingMode === "strict") {
733
+ return;
734
+ }
735
+ if (this.identityTrackingMode === "always_on") {
736
+ return;
737
+ }
738
+ this.fullTrackingConsentGranted = granted;
739
+ if ((options.persist ?? true) && this.persistConsentState) {
740
+ this.writePersistedConsent(this.configuredStorage, granted);
741
+ }
742
+ this.applyIdentityTrackingState();
743
+ }
744
+ optInFullTracking(options) {
745
+ this.setFullTrackingConsent(true, options);
746
+ }
747
+ optOutFullTracking(options) {
748
+ this.setFullTrackingConsent(false, options);
749
+ }
750
+ isFullTrackingEnabled() {
751
+ return this.isFullTrackingActive();
752
+ }
680
753
  /**
681
754
  * Clears the current identified user from in-memory SDK state.
682
755
  */
@@ -707,9 +780,10 @@ var AnalyticsClient = class {
707
780
  ts: nowIso(),
708
781
  sessionId,
709
782
  anonId: this.anonId,
710
- userId: this.userId,
783
+ userId: this.getEventUserId(),
711
784
  properties: this.withRuntimeMetadata(properties, sessionId),
712
785
  platform: this.platform,
786
+ projectSurface: this.projectSurface,
713
787
  appVersion: this.appVersion,
714
788
  ...this.withEventContext(),
715
789
  type: "track"
@@ -806,6 +880,8 @@ var AnalyticsClient = class {
806
880
  /**
807
881
  * Creates a scoped paywall tracker that applies shared paywall defaults to every journey event.
808
882
  * Useful when a flow has a stable `source`, `paywallId`, `offering`, or experiment metadata.
883
+ * Reuse the returned tracker for that flow context; creating a new tracker per event resets
884
+ * paywall entry correlation.
809
885
  */
810
886
  createPaywallTracker(defaults) {
811
887
  const { source: rawDefaultSource, ...defaultProperties } = defaults;
@@ -909,9 +985,10 @@ var AnalyticsClient = class {
909
985
  ts: nowIso(),
910
986
  sessionId,
911
987
  anonId: this.anonId,
912
- userId: this.userId,
988
+ userId: this.getEventUserId(),
913
989
  properties: this.withRuntimeMetadata(properties, sessionId),
914
990
  platform: this.platform,
991
+ projectSurface: this.projectSurface,
915
992
  appVersion: this.appVersion,
916
993
  ...this.withEventContext(),
917
994
  type: "screen"
@@ -944,9 +1021,10 @@ var AnalyticsClient = class {
944
1021
  ts: nowIso(),
945
1022
  sessionId,
946
1023
  anonId: this.anonId,
947
- userId: this.userId,
1024
+ userId: this.getEventUserId(),
948
1025
  properties: this.withRuntimeMetadata({ message, rating, ...properties }, sessionId),
949
1026
  platform: this.platform,
1027
+ projectSurface: this.projectSurface,
950
1028
  appVersion: this.appVersion,
951
1029
  ...this.withEventContext(),
952
1030
  type: "feedback"
@@ -1034,6 +1112,36 @@ var AnalyticsClient = class {
1034
1112
  }
1035
1113
  }
1036
1114
  }
1115
+ parsePersistedConsent(raw) {
1116
+ if (raw === "granted") {
1117
+ return true;
1118
+ }
1119
+ if (raw === "denied") {
1120
+ return false;
1121
+ }
1122
+ return null;
1123
+ }
1124
+ readPersistedConsentSync(storage) {
1125
+ if (!this.persistConsentState) {
1126
+ return null;
1127
+ }
1128
+ if (storage === this.storage && this.storageReadsAreAsync) {
1129
+ return null;
1130
+ }
1131
+ return this.parsePersistedConsent(readStorageSync(storage, this.consentStorageKey));
1132
+ }
1133
+ async readPersistedConsentAsync(storage) {
1134
+ if (!this.persistConsentState) {
1135
+ return null;
1136
+ }
1137
+ return this.parsePersistedConsent(await readStorageAsync(storage, this.consentStorageKey));
1138
+ }
1139
+ writePersistedConsent(storage, granted) {
1140
+ if (!this.persistConsentState) {
1141
+ return;
1142
+ }
1143
+ writeStorageSync(storage, this.consentStorageKey, granted ? "granted" : "denied");
1144
+ }
1037
1145
  startAutoFlush() {
1038
1146
  if (!this.hasIngestConfig) {
1039
1147
  return;
@@ -1125,10 +1233,11 @@ var AnalyticsClient = class {
1125
1233
  return;
1126
1234
  }
1127
1235
  try {
1128
- const [storedAnonId, storedSessionId, storedLastSeen] = await Promise.all([
1236
+ const [storedAnonId, storedSessionId, storedLastSeen, storedConsent] = await Promise.all([
1129
1237
  readStorageAsync(this.storage, DEVICE_ID_KEY),
1130
1238
  readStorageAsync(this.storage, SESSION_ID_KEY),
1131
- readStorageAsync(this.storage, LAST_SEEN_KEY)
1239
+ readStorageAsync(this.storage, LAST_SEEN_KEY),
1240
+ this.readPersistedConsentAsync(this.storage)
1132
1241
  ]);
1133
1242
  if (!this.hasExplicitAnonId && storedAnonId) {
1134
1243
  this.anonId = storedAnonId;
@@ -1140,6 +1249,13 @@ var AnalyticsClient = class {
1140
1249
  this.inMemoryLastSeenMs = Date.now();
1141
1250
  }
1142
1251
  }
1252
+ if (!this.hasExplicitInitialConsent && typeof storedConsent === "boolean") {
1253
+ this.consentGranted = this.hasIngestConfig && storedConsent;
1254
+ if (!this.consentGranted) {
1255
+ this.queue = [];
1256
+ this.deferredEventsBeforeHydration = [];
1257
+ }
1258
+ }
1143
1259
  this.sessionEventSeq = await this.readSessionEventSeqAsync(this.sessionId);
1144
1260
  await this.hydrateOnboardingStepViewState(this.sessionId);
1145
1261
  writeStorageSync(this.storage, DEVICE_ID_KEY, this.anonId);
@@ -1308,6 +1424,81 @@ var AnalyticsClient = class {
1308
1424
  return null;
1309
1425
  }
1310
1426
  }
1427
+ resolveIdentityTrackingModeOption(options) {
1428
+ const explicitMode = this.readRequiredStringOption(options.identityTrackingMode).toLowerCase();
1429
+ if (explicitMode === "strict") {
1430
+ return "strict";
1431
+ }
1432
+ if (explicitMode === "consent_gated") {
1433
+ return "consent_gated";
1434
+ }
1435
+ if (explicitMode === "always_on") {
1436
+ return "always_on";
1437
+ }
1438
+ if (options.enableFullTrackingWithoutConsent === true) {
1439
+ return "always_on";
1440
+ }
1441
+ return "consent_gated";
1442
+ }
1443
+ resolveConfiguredStorage(options) {
1444
+ if (this.identityTrackingMode === "strict") {
1445
+ if (options.storage || options.useCookieStorage || options.cookieDomain) {
1446
+ this.log("Ignoring storage/cookie configuration because identityTrackingMode=strict");
1447
+ }
1448
+ return null;
1449
+ }
1450
+ const customStorage = options.storage ?? null;
1451
+ const browserStorage = resolveBrowserStorageAdapter();
1452
+ const primaryStorage = customStorage ?? browserStorage;
1453
+ const cookieStorage = resolveCookieStorageAdapter(
1454
+ options.useCookieStorage === true,
1455
+ this.readRequiredStringOption(options.cookieDomain) || void 0,
1456
+ this.normalizeCookieMaxAgeSeconds(options.cookieMaxAgeSeconds)
1457
+ );
1458
+ if (primaryStorage && cookieStorage) {
1459
+ return combineStorageAdapters(primaryStorage, cookieStorage);
1460
+ }
1461
+ return primaryStorage ?? cookieStorage;
1462
+ }
1463
+ normalizeCookieMaxAgeSeconds(value) {
1464
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
1465
+ return DEFAULT_COOKIE_MAX_AGE_SECONDS;
1466
+ }
1467
+ return Math.floor(value);
1468
+ }
1469
+ isFullTrackingActive() {
1470
+ if (!this.hasIngestConfig) {
1471
+ return false;
1472
+ }
1473
+ if (this.identityTrackingMode === "always_on") {
1474
+ return true;
1475
+ }
1476
+ if (this.identityTrackingMode === "strict") {
1477
+ return false;
1478
+ }
1479
+ return this.fullTrackingConsentGranted;
1480
+ }
1481
+ applyIdentityTrackingState() {
1482
+ if (!this.isFullTrackingActive()) {
1483
+ this.storage = null;
1484
+ this.storageReadsAreAsync = false;
1485
+ this.userId = null;
1486
+ return;
1487
+ }
1488
+ this.storage = this.configuredStorage;
1489
+ this.storageReadsAreAsync = this.detectAsyncStorageReads();
1490
+ this.sessionId = this.ensureSessionId();
1491
+ this.sessionEventSeq = this.readSessionEventSeq(this.sessionId);
1492
+ writeStorageSync(this.storage, DEVICE_ID_KEY, this.anonId);
1493
+ writeStorageSync(this.storage, SESSION_ID_KEY, this.sessionId);
1494
+ writeStorageSync(this.storage, LAST_SEEN_KEY, String(this.inMemoryLastSeenMs));
1495
+ }
1496
+ getEventUserId() {
1497
+ if (!this.isFullTrackingActive()) {
1498
+ return null;
1499
+ }
1500
+ return this.userId;
1501
+ }
1311
1502
  withEventContext() {
1312
1503
  return {
1313
1504
  appBuild: this.context.appBuild,
@@ -1343,6 +1534,16 @@ var AnalyticsClient = class {
1343
1534
  }
1344
1535
  return void 0;
1345
1536
  }
1537
+ normalizeProjectSurfaceOption(value) {
1538
+ const normalized = this.readRequiredStringOption(value).toLowerCase();
1539
+ if (!normalized) {
1540
+ return void 0;
1541
+ }
1542
+ if (normalized.length > 64) {
1543
+ return normalized.slice(0, 64);
1544
+ }
1545
+ return normalized;
1546
+ }
1346
1547
  log(message, data) {
1347
1548
  if (!this.debug) {
1348
1549
  return;
@@ -1351,117 +1552,110 @@ var AnalyticsClient = class {
1351
1552
  }
1352
1553
  reportMissingApiKey() {
1353
1554
  console.error(
1354
- "[analyticscli-sdk] Missing required `apiKey`. Tracking is disabled (safe no-op). Pass your long write key."
1555
+ "[analyticscli-sdk] Missing required `apiKey`. Tracking is disabled (safe no-op). Pass your publishable API key."
1355
1556
  );
1356
1557
  }
1357
1558
  };
1358
1559
 
1359
- // src/bootstrap.ts
1360
- var DEFAULT_API_KEY_ENV_KEYS = [
1361
- "ANALYTICSCLI_WRITE_KEY",
1362
- "NEXT_PUBLIC_ANALYTICSCLI_WRITE_KEY",
1363
- "EXPO_PUBLIC_ANALYTICSCLI_WRITE_KEY",
1364
- "VITE_ANALYTICSCLI_WRITE_KEY"
1365
- ];
1366
- var readTrimmedString2 = (value) => {
1367
- if (typeof value === "string") {
1368
- return value.trim();
1369
- }
1370
- if (typeof value === "number" || typeof value === "boolean") {
1371
- return String(value).trim();
1372
- }
1373
- return "";
1374
- };
1375
- var resolveDefaultEnv = () => {
1376
- const withProcess = globalThis;
1377
- if (typeof withProcess.process?.env === "object" && withProcess.process.env !== null) {
1378
- return withProcess.process.env;
1560
+ // src/context.ts
1561
+ var normalizeInitInput = (input) => {
1562
+ if (typeof input === "string") {
1563
+ return { apiKey: input };
1379
1564
  }
1380
- return {};
1381
- };
1382
- var resolveValueFromEnv = (env, keys) => {
1383
- for (const key of keys) {
1384
- const value = readTrimmedString2(env[key]);
1385
- if (value.length > 0) {
1386
- return value;
1387
- }
1565
+ if (input === null || input === void 0) {
1566
+ return {};
1388
1567
  }
1389
- return "";
1568
+ return input;
1390
1569
  };
1391
- var toMissingMessage = (details) => {
1392
- const parts = [];
1393
- if (details.missingApiKey) {
1394
- parts.push(`apiKey (searched: ${details.searchedApiKeyEnvKeys.join(", ") || "none"})`);
1570
+ var resolveClient = (input) => {
1571
+ if (input instanceof AnalyticsClient) {
1572
+ return input;
1395
1573
  }
1396
- return `[analyticscli-sdk] Missing required configuration: ${parts.join("; ")}.`;
1574
+ return new AnalyticsClient(normalizeInitInput(input ?? {}));
1397
1575
  };
1398
- var initFromEnv = (options = {}) => {
1399
- const {
1400
- env,
1401
- apiKey,
1402
- apiKeyEnvKeys,
1403
- missingConfigMode = "noop",
1404
- onMissingConfig,
1405
- ...clientOptions
1406
- } = options;
1407
- const resolvedApiKeyEnvKeys = [...apiKeyEnvKeys ?? DEFAULT_API_KEY_ENV_KEYS];
1408
- const envSource = env ?? resolveDefaultEnv();
1409
- const resolvedApiKey = readTrimmedString2(apiKey) || resolveValueFromEnv(envSource, resolvedApiKeyEnvKeys);
1410
- const missingConfig = {
1411
- missingApiKey: resolvedApiKey.length === 0,
1412
- searchedApiKeyEnvKeys: resolvedApiKeyEnvKeys
1576
+ var createAnalyticsContext = (options = {}) => {
1577
+ const client = resolveClient(options.client);
1578
+ let onboardingTracker = client.createOnboardingTracker(options.onboarding ?? {});
1579
+ let paywallTracker = options.paywall ? client.createPaywallTracker(options.paywall) : null;
1580
+ const consent = {
1581
+ get: () => client.getConsent(),
1582
+ getState: () => client.getConsentState(),
1583
+ set: (granted, setOptions) => client.setConsent(granted, setOptions),
1584
+ optIn: (setOptions) => client.optIn(setOptions),
1585
+ optOut: (setOptions) => client.optOut(setOptions),
1586
+ setFullTracking: (granted, setOptions) => client.setFullTrackingConsent(granted, setOptions),
1587
+ optInFullTracking: (setOptions) => client.optInFullTracking(setOptions),
1588
+ optOutFullTracking: (setOptions) => client.optOutFullTracking(setOptions),
1589
+ isFullTrackingEnabled: () => client.isFullTrackingEnabled()
1590
+ };
1591
+ const user = {
1592
+ identify: (userId, traits) => client.identify(userId, traits),
1593
+ set: (userId, traits) => client.setUser(userId, traits),
1594
+ clear: () => client.clearUser()
1595
+ };
1596
+ return {
1597
+ client,
1598
+ get onboarding() {
1599
+ return onboardingTracker;
1600
+ },
1601
+ get paywall() {
1602
+ return paywallTracker;
1603
+ },
1604
+ consent,
1605
+ user,
1606
+ track: (eventName, properties) => client.track(eventName, properties),
1607
+ trackOnboardingEvent: (eventName, properties) => client.trackOnboardingEvent(eventName, properties),
1608
+ trackOnboardingSurveyResponse: (input, eventName) => client.trackOnboardingSurveyResponse(input, eventName),
1609
+ trackPaywallEvent: (eventName, properties) => client.trackPaywallEvent(eventName, properties),
1610
+ screen: (name, properties) => client.screen(name, properties),
1611
+ page: (name, properties) => client.page(name, properties),
1612
+ feedback: (message, rating, properties) => client.feedback(message, rating, properties),
1613
+ setContext: (context) => client.setContext(context),
1614
+ createOnboarding: (defaults) => client.createOnboardingTracker(defaults),
1615
+ createPaywall: (defaults) => client.createPaywallTracker(defaults),
1616
+ configureOnboarding: (defaults) => {
1617
+ onboardingTracker = client.createOnboardingTracker(defaults);
1618
+ return onboardingTracker;
1619
+ },
1620
+ configurePaywall: (defaults) => {
1621
+ paywallTracker = client.createPaywallTracker(defaults);
1622
+ return paywallTracker;
1623
+ },
1624
+ ready: () => client.ready(),
1625
+ flush: () => client.flush(),
1626
+ shutdown: () => client.shutdown()
1413
1627
  };
1414
- if (missingConfig.missingApiKey) {
1415
- onMissingConfig?.(missingConfig);
1416
- if (missingConfigMode === "throw") {
1417
- throw new Error(toMissingMessage(missingConfig));
1418
- }
1419
- }
1420
- return new AnalyticsClient({
1421
- ...clientOptions,
1422
- apiKey: resolvedApiKey
1423
- });
1424
1628
  };
1425
1629
 
1426
1630
  // src/index.ts
1427
- var normalizeInitInput = (input) => {
1631
+ var normalizeInitInput2 = (input) => {
1428
1632
  if (typeof input === "string") {
1429
1633
  return { apiKey: input };
1430
1634
  }
1635
+ if (input === null || input === void 0) {
1636
+ return {};
1637
+ }
1431
1638
  return input;
1432
1639
  };
1433
1640
  var init = (input = {}) => {
1434
- return new AnalyticsClient(normalizeInitInput(input));
1641
+ return new AnalyticsClient(normalizeInitInput2(input));
1642
+ };
1643
+ var initConsentFirst = (input = {}) => {
1644
+ const normalized = normalizeInitInput2(input);
1645
+ return new AnalyticsClient({
1646
+ ...normalized,
1647
+ initialConsentGranted: false
1648
+ });
1435
1649
  };
1436
1650
  var initAsync = async (input = {}) => {
1437
- const client = new AnalyticsClient(normalizeInitInput(input));
1651
+ const client = new AnalyticsClient(normalizeInitInput2(input));
1438
1652
  await client.ready();
1439
1653
  return client;
1440
1654
  };
1441
- var BROWSER_API_KEY_ENV_KEYS = [
1442
- "ANALYTICSCLI_WRITE_KEY",
1443
- "NEXT_PUBLIC_ANALYTICSCLI_WRITE_KEY",
1444
- "PUBLIC_ANALYTICSCLI_WRITE_KEY",
1445
- "VITE_ANALYTICSCLI_WRITE_KEY",
1446
- "EXPO_PUBLIC_ANALYTICSCLI_WRITE_KEY"
1447
- ];
1448
- var REACT_NATIVE_API_KEY_ENV_KEYS = [
1449
- "ANALYTICSCLI_WRITE_KEY",
1450
- "EXPO_PUBLIC_ANALYTICSCLI_WRITE_KEY"
1451
- ];
1452
- var initBrowserFromEnv = (options = {}) => {
1453
- const { apiKeyEnvKeys, ...rest } = options;
1454
- return initFromEnv({
1455
- ...rest,
1456
- apiKeyEnvKeys: [...apiKeyEnvKeys ?? BROWSER_API_KEY_ENV_KEYS]
1457
- });
1458
- };
1459
- var initReactNativeFromEnv = (options = {}) => {
1460
- const { apiKeyEnvKeys, ...rest } = options;
1461
- return initFromEnv({
1462
- ...rest,
1463
- apiKeyEnvKeys: [...apiKeyEnvKeys ?? REACT_NATIVE_API_KEY_ENV_KEYS]
1464
- });
1655
+ var initConsentFirstAsync = async (input = {}) => {
1656
+ const client = initConsentFirst(input);
1657
+ await client.ready();
1658
+ return client;
1465
1659
  };
1466
1660
 
1467
1661
  export {
@@ -1476,12 +1670,9 @@ export {
1476
1670
  PAYWALL_SKIP_EVENT_CANDIDATES,
1477
1671
  PURCHASE_SUCCESS_EVENT_CANDIDATES,
1478
1672
  AnalyticsClient,
1479
- DEFAULT_API_KEY_ENV_KEYS,
1480
- initFromEnv,
1673
+ createAnalyticsContext,
1481
1674
  init,
1675
+ initConsentFirst,
1482
1676
  initAsync,
1483
- BROWSER_API_KEY_ENV_KEYS,
1484
- REACT_NATIVE_API_KEY_ENV_KEYS,
1485
- initBrowserFromEnv,
1486
- initReactNativeFromEnv
1677
+ initConsentFirstAsync
1487
1678
  };