posthog-react-native 3.13.2 → 3.15.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.
Files changed (149) hide show
  1. package/lib/index.cjs.js +4677 -0
  2. package/lib/index.cjs.js.map +1 -0
  3. package/lib/index.d.ts +875 -0
  4. package/lib/index.esm.js +4659 -0
  5. package/lib/index.esm.js.map +1 -0
  6. package/lib/posthog-core/src/eventemitter.d.ts +8 -8
  7. package/lib/posthog-core/src/featureFlagUtils.d.ts +34 -34
  8. package/lib/posthog-core/src/index.d.ts +239 -239
  9. package/lib/posthog-core/src/lz-string.d.ts +8 -8
  10. package/lib/posthog-core/src/types.d.ts +423 -422
  11. package/lib/posthog-core/src/utils.d.ts +19 -16
  12. package/lib/posthog-core/src/vendor/uuidv7.d.ts +179 -179
  13. package/lib/posthog-react-native/index.d.ts +10 -10
  14. package/lib/posthog-react-native/src/PostHogContext.d.ts +5 -5
  15. package/lib/posthog-react-native/src/PostHogProvider.d.ts +14 -14
  16. package/lib/posthog-react-native/src/autocapture.d.ts +4 -4
  17. package/lib/posthog-react-native/src/frameworks/wix-navigation.d.ts +3 -3
  18. package/lib/posthog-react-native/src/hooks/useFeatureFlag.d.ts +5 -5
  19. package/lib/posthog-react-native/src/hooks/useFeatureFlags.d.ts +3 -3
  20. package/lib/posthog-react-native/src/hooks/useNavigationTracker.d.ts +6 -6
  21. package/lib/posthog-react-native/src/hooks/usePostHog.d.ts +2 -2
  22. package/lib/posthog-react-native/src/legacy.d.ts +4 -4
  23. package/lib/posthog-react-native/src/native-deps.d.ts +4 -4
  24. package/lib/posthog-react-native/src/optional/OptionalAsyncStorage.d.ts +2 -2
  25. package/lib/posthog-react-native/src/optional/OptionalExpoApplication.d.ts +2 -2
  26. package/lib/posthog-react-native/src/optional/OptionalExpoDevice.d.ts +2 -2
  27. package/lib/posthog-react-native/src/optional/OptionalExpoFileSystem.d.ts +2 -2
  28. package/lib/posthog-react-native/src/optional/OptionalExpoLocalization.d.ts +2 -2
  29. package/lib/posthog-react-native/src/optional/OptionalReactNativeDeviceInfo.d.ts +2 -2
  30. package/lib/posthog-react-native/src/optional/OptionalReactNativeLocalize.d.ts +13 -13
  31. package/lib/posthog-react-native/src/optional/OptionalReactNativeNavigation.d.ts +2 -2
  32. package/lib/posthog-react-native/src/optional/OptionalReactNativeNavigationWix.d.ts +2 -2
  33. package/lib/posthog-react-native/src/optional/OptionalReactNativeSafeArea.d.ts +2 -2
  34. package/lib/posthog-react-native/src/optional/OptionalSessionReplay.d.ts +2 -2
  35. package/lib/posthog-react-native/src/posthog-rn.d.ts +71 -71
  36. package/lib/posthog-react-native/src/storage.d.ts +21 -21
  37. package/lib/posthog-react-native/src/surveys/PostHogSurveyProvider.d.ts +16 -16
  38. package/lib/posthog-react-native/src/surveys/components/BottomSection.d.ts +9 -9
  39. package/lib/posthog-react-native/src/surveys/components/Cancel.d.ts +6 -6
  40. package/lib/posthog-react-native/src/surveys/components/ConfirmationMessage.d.ts +13 -13
  41. package/lib/posthog-react-native/src/surveys/components/QuestionHeader.d.ts +7 -7
  42. package/lib/posthog-react-native/src/surveys/components/QuestionTypes.d.ts +27 -27
  43. package/lib/posthog-react-native/src/surveys/components/SurveyModal.d.ts +10 -10
  44. package/lib/posthog-react-native/src/surveys/components/Surveys.d.ts +14 -14
  45. package/lib/posthog-react-native/src/surveys/getActiveMatchingSurveys.d.ts +2 -2
  46. package/lib/posthog-react-native/src/surveys/icons.d.ts +10 -8
  47. package/lib/posthog-react-native/src/surveys/index.d.ts +6 -6
  48. package/lib/posthog-react-native/src/surveys/surveys-utils.d.ts +13 -13
  49. package/lib/posthog-react-native/src/surveys/useActivatedSurveys.d.ts +3 -3
  50. package/lib/posthog-react-native/src/surveys/useSurveyStorage.d.ts +8 -8
  51. package/lib/posthog-react-native/src/types.d.ts +112 -112
  52. package/lib/posthog-react-native/src/version.d.ts +1 -1
  53. package/lib/posthog-react-native/test/test-utils.d.ts +2 -0
  54. package/package.json +9 -8
  55. package/lib/posthog-core/src/eventemitter.js +0 -1
  56. package/lib/posthog-core/src/eventemitter.js.map +0 -1
  57. package/lib/posthog-core/src/featureFlagUtils.js +0 -1
  58. package/lib/posthog-core/src/featureFlagUtils.js.map +0 -1
  59. package/lib/posthog-core/src/index.js +0 -1
  60. package/lib/posthog-core/src/index.js.map +0 -1
  61. package/lib/posthog-core/src/lz-string.js +0 -1
  62. package/lib/posthog-core/src/lz-string.js.map +0 -1
  63. package/lib/posthog-core/src/types.js +0 -1
  64. package/lib/posthog-core/src/types.js.map +0 -1
  65. package/lib/posthog-core/src/utils.js +0 -1
  66. package/lib/posthog-core/src/utils.js.map +0 -1
  67. package/lib/posthog-core/src/vendor/uuidv7.js +0 -7
  68. package/lib/posthog-core/src/vendor/uuidv7.js.map +0 -1
  69. package/lib/posthog-react-native/index.js +0 -1
  70. package/lib/posthog-react-native/index.js.map +0 -1
  71. package/lib/posthog-react-native/src/PostHogContext.js +0 -1
  72. package/lib/posthog-react-native/src/PostHogContext.js.map +0 -1
  73. package/lib/posthog-react-native/src/PostHogProvider.js +0 -1
  74. package/lib/posthog-react-native/src/PostHogProvider.js.map +0 -1
  75. package/lib/posthog-react-native/src/autocapture.js +0 -1
  76. package/lib/posthog-react-native/src/autocapture.js.map +0 -1
  77. package/lib/posthog-react-native/src/frameworks/wix-navigation.js +0 -1
  78. package/lib/posthog-react-native/src/frameworks/wix-navigation.js.map +0 -1
  79. package/lib/posthog-react-native/src/hooks/useFeatureFlag.js +0 -1
  80. package/lib/posthog-react-native/src/hooks/useFeatureFlag.js.map +0 -1
  81. package/lib/posthog-react-native/src/hooks/useFeatureFlags.js +0 -1
  82. package/lib/posthog-react-native/src/hooks/useFeatureFlags.js.map +0 -1
  83. package/lib/posthog-react-native/src/hooks/useNavigationTracker.js +0 -1
  84. package/lib/posthog-react-native/src/hooks/useNavigationTracker.js.map +0 -1
  85. package/lib/posthog-react-native/src/hooks/usePostHog.js +0 -1
  86. package/lib/posthog-react-native/src/hooks/usePostHog.js.map +0 -1
  87. package/lib/posthog-react-native/src/legacy.js +0 -1
  88. package/lib/posthog-react-native/src/legacy.js.map +0 -1
  89. package/lib/posthog-react-native/src/native-deps.js +0 -1
  90. package/lib/posthog-react-native/src/native-deps.js.map +0 -1
  91. package/lib/posthog-react-native/src/optional/OptionalAsyncStorage.js +0 -1
  92. package/lib/posthog-react-native/src/optional/OptionalAsyncStorage.js.map +0 -1
  93. package/lib/posthog-react-native/src/optional/OptionalExpoApplication.js +0 -1
  94. package/lib/posthog-react-native/src/optional/OptionalExpoApplication.js.map +0 -1
  95. package/lib/posthog-react-native/src/optional/OptionalExpoDevice.js +0 -1
  96. package/lib/posthog-react-native/src/optional/OptionalExpoDevice.js.map +0 -1
  97. package/lib/posthog-react-native/src/optional/OptionalExpoFileSystem.js +0 -1
  98. package/lib/posthog-react-native/src/optional/OptionalExpoFileSystem.js.map +0 -1
  99. package/lib/posthog-react-native/src/optional/OptionalExpoLocalization.js +0 -1
  100. package/lib/posthog-react-native/src/optional/OptionalExpoLocalization.js.map +0 -1
  101. package/lib/posthog-react-native/src/optional/OptionalReactNativeDeviceInfo.js +0 -1
  102. package/lib/posthog-react-native/src/optional/OptionalReactNativeDeviceInfo.js.map +0 -1
  103. package/lib/posthog-react-native/src/optional/OptionalReactNativeLocalize.js +0 -1
  104. package/lib/posthog-react-native/src/optional/OptionalReactNativeLocalize.js.map +0 -1
  105. package/lib/posthog-react-native/src/optional/OptionalReactNativeNavigation.js +0 -1
  106. package/lib/posthog-react-native/src/optional/OptionalReactNativeNavigation.js.map +0 -1
  107. package/lib/posthog-react-native/src/optional/OptionalReactNativeNavigationWix.js +0 -1
  108. package/lib/posthog-react-native/src/optional/OptionalReactNativeNavigationWix.js.map +0 -1
  109. package/lib/posthog-react-native/src/optional/OptionalReactNativeSafeArea.js +0 -1
  110. package/lib/posthog-react-native/src/optional/OptionalReactNativeSafeArea.js.map +0 -1
  111. package/lib/posthog-react-native/src/optional/OptionalSessionReplay.js +0 -1
  112. package/lib/posthog-react-native/src/optional/OptionalSessionReplay.js.map +0 -1
  113. package/lib/posthog-react-native/src/posthog-rn.js +0 -1
  114. package/lib/posthog-react-native/src/posthog-rn.js.map +0 -1
  115. package/lib/posthog-react-native/src/storage.js +0 -1
  116. package/lib/posthog-react-native/src/storage.js.map +0 -1
  117. package/lib/posthog-react-native/src/surveys/PostHogSurveyProvider.js +0 -1
  118. package/lib/posthog-react-native/src/surveys/PostHogSurveyProvider.js.map +0 -1
  119. package/lib/posthog-react-native/src/surveys/components/BottomSection.js +0 -1
  120. package/lib/posthog-react-native/src/surveys/components/BottomSection.js.map +0 -1
  121. package/lib/posthog-react-native/src/surveys/components/Cancel.js +0 -1
  122. package/lib/posthog-react-native/src/surveys/components/Cancel.js.map +0 -1
  123. package/lib/posthog-react-native/src/surveys/components/ConfirmationMessage.js +0 -1
  124. package/lib/posthog-react-native/src/surveys/components/ConfirmationMessage.js.map +0 -1
  125. package/lib/posthog-react-native/src/surveys/components/QuestionHeader.js +0 -1
  126. package/lib/posthog-react-native/src/surveys/components/QuestionHeader.js.map +0 -1
  127. package/lib/posthog-react-native/src/surveys/components/QuestionTypes.js +0 -1
  128. package/lib/posthog-react-native/src/surveys/components/QuestionTypes.js.map +0 -1
  129. package/lib/posthog-react-native/src/surveys/components/SurveyModal.js +0 -1
  130. package/lib/posthog-react-native/src/surveys/components/SurveyModal.js.map +0 -1
  131. package/lib/posthog-react-native/src/surveys/components/Surveys.js +0 -1
  132. package/lib/posthog-react-native/src/surveys/components/Surveys.js.map +0 -1
  133. package/lib/posthog-react-native/src/surveys/getActiveMatchingSurveys.js +0 -1
  134. package/lib/posthog-react-native/src/surveys/getActiveMatchingSurveys.js.map +0 -1
  135. package/lib/posthog-react-native/src/surveys/icons.js +0 -1
  136. package/lib/posthog-react-native/src/surveys/icons.js.map +0 -1
  137. package/lib/posthog-react-native/src/surveys/index.js +0 -1
  138. package/lib/posthog-react-native/src/surveys/index.js.map +0 -1
  139. package/lib/posthog-react-native/src/surveys/surveys-utils.js +0 -1
  140. package/lib/posthog-react-native/src/surveys/surveys-utils.js.map +0 -1
  141. package/lib/posthog-react-native/src/surveys/useActivatedSurveys.js +0 -1
  142. package/lib/posthog-react-native/src/surveys/useActivatedSurveys.js.map +0 -1
  143. package/lib/posthog-react-native/src/surveys/useSurveyStorage.js +0 -1
  144. package/lib/posthog-react-native/src/surveys/useSurveyStorage.js.map +0 -1
  145. package/lib/posthog-react-native/src/types.js +0 -1
  146. package/lib/posthog-react-native/src/types.js.map +0 -1
  147. package/lib/posthog-react-native/src/version.js +0 -1
  148. package/lib/posthog-react-native/src/version.js.map +0 -1
  149. package/lib/posthog-react-native/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,4659 @@
1
+ import { Platform, AppState, Dimensions, Linking, View, StyleSheet, TouchableOpacity, Text, TextInput, Pressable, ScrollView, Modal, KeyboardAvoidingView, TouchableWithoutFeedback, Keyboard } from 'react-native';
2
+ import React, { useCallback, useEffect, useState, useMemo } from 'react';
3
+ import { Svg, Path } from 'react-native-svg';
4
+
5
+ var PostHogPersistedProperty;
6
+ (function (PostHogPersistedProperty) {
7
+ PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
8
+ PostHogPersistedProperty["DistinctId"] = "distinct_id";
9
+ PostHogPersistedProperty["Props"] = "props";
10
+ PostHogPersistedProperty["FeatureFlagDetails"] = "feature_flag_details";
11
+ PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
12
+ PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
13
+ PostHogPersistedProperty["BootstrapFeatureFlagDetails"] = "bootstrap_feature_flag_details";
14
+ PostHogPersistedProperty["BootstrapFeatureFlags"] = "bootstrap_feature_flags";
15
+ PostHogPersistedProperty["BootstrapFeatureFlagPayloads"] = "bootstrap_feature_flag_payloads";
16
+ PostHogPersistedProperty["OverrideFeatureFlags"] = "override_feature_flags";
17
+ PostHogPersistedProperty["Queue"] = "queue";
18
+ PostHogPersistedProperty["OptedOut"] = "opted_out";
19
+ PostHogPersistedProperty["SessionId"] = "session_id";
20
+ PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
21
+ PostHogPersistedProperty["PersonProperties"] = "person_properties";
22
+ PostHogPersistedProperty["GroupProperties"] = "group_properties";
23
+ PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
24
+ PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
25
+ PostHogPersistedProperty["SessionReplay"] = "session_replay";
26
+ PostHogPersistedProperty["DecideEndpointWasHit"] = "decide_endpoint_was_hit";
27
+ PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
28
+ PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
29
+ PostHogPersistedProperty["Surveys"] = "surveys";
30
+ PostHogPersistedProperty["RemoteConfig"] = "remote_config";
31
+ })(PostHogPersistedProperty || (PostHogPersistedProperty = {}));
32
+ var SurveyPosition;
33
+ (function (SurveyPosition) {
34
+ SurveyPosition["Left"] = "left";
35
+ SurveyPosition["Right"] = "right";
36
+ SurveyPosition["Center"] = "center";
37
+ })(SurveyPosition || (SurveyPosition = {}));
38
+ var SurveyWidgetType;
39
+ (function (SurveyWidgetType) {
40
+ SurveyWidgetType["Button"] = "button";
41
+ SurveyWidgetType["Tab"] = "tab";
42
+ SurveyWidgetType["Selector"] = "selector";
43
+ })(SurveyWidgetType || (SurveyWidgetType = {}));
44
+ var SurveyType;
45
+ (function (SurveyType) {
46
+ SurveyType["Popover"] = "popover";
47
+ SurveyType["API"] = "api";
48
+ SurveyType["Widget"] = "widget";
49
+ })(SurveyType || (SurveyType = {}));
50
+ var SurveyQuestionDescriptionContentType;
51
+ (function (SurveyQuestionDescriptionContentType) {
52
+ SurveyQuestionDescriptionContentType["Html"] = "html";
53
+ SurveyQuestionDescriptionContentType["Text"] = "text";
54
+ })(SurveyQuestionDescriptionContentType || (SurveyQuestionDescriptionContentType = {}));
55
+ var SurveyRatingDisplay;
56
+ (function (SurveyRatingDisplay) {
57
+ SurveyRatingDisplay["Number"] = "number";
58
+ SurveyRatingDisplay["Emoji"] = "emoji";
59
+ })(SurveyRatingDisplay || (SurveyRatingDisplay = {}));
60
+ var SurveyQuestionType;
61
+ (function (SurveyQuestionType) {
62
+ SurveyQuestionType["Open"] = "open";
63
+ SurveyQuestionType["MultipleChoice"] = "multiple_choice";
64
+ SurveyQuestionType["SingleChoice"] = "single_choice";
65
+ SurveyQuestionType["Rating"] = "rating";
66
+ SurveyQuestionType["Link"] = "link";
67
+ })(SurveyQuestionType || (SurveyQuestionType = {}));
68
+ var SurveyQuestionBranchingType;
69
+ (function (SurveyQuestionBranchingType) {
70
+ SurveyQuestionBranchingType["NextQuestion"] = "next_question";
71
+ SurveyQuestionBranchingType["End"] = "end";
72
+ SurveyQuestionBranchingType["ResponseBased"] = "response_based";
73
+ SurveyQuestionBranchingType["SpecificQuestion"] = "specific_question";
74
+ })(SurveyQuestionBranchingType || (SurveyQuestionBranchingType = {}));
75
+ var SurveyMatchType;
76
+ (function (SurveyMatchType) {
77
+ SurveyMatchType["Regex"] = "regex";
78
+ SurveyMatchType["NotRegex"] = "not_regex";
79
+ SurveyMatchType["Exact"] = "exact";
80
+ SurveyMatchType["IsNot"] = "is_not";
81
+ SurveyMatchType["Icontains"] = "icontains";
82
+ SurveyMatchType["NotIcontains"] = "not_icontains";
83
+ })(SurveyMatchType || (SurveyMatchType = {}));
84
+ /** Sync with plugin-server/src/types.ts */
85
+ var ActionStepStringMatching;
86
+ (function (ActionStepStringMatching) {
87
+ ActionStepStringMatching["Contains"] = "contains";
88
+ ActionStepStringMatching["Exact"] = "exact";
89
+ ActionStepStringMatching["Regex"] = "regex";
90
+ })(ActionStepStringMatching || (ActionStepStringMatching = {}));
91
+
92
+ const normalizeDecideResponse = (decideResponse) => {
93
+ var _a;
94
+ if ('flags' in decideResponse) {
95
+ // Convert v4 format to v3 format
96
+ const featureFlags = getFlagValuesFromFlags(decideResponse.flags);
97
+ const featureFlagPayloads = getPayloadsFromFlags(decideResponse.flags);
98
+ return {
99
+ ...decideResponse,
100
+ featureFlags,
101
+ featureFlagPayloads,
102
+ };
103
+ }
104
+ else {
105
+ // Convert v3 format to v4 format
106
+ const featureFlags = (_a = decideResponse.featureFlags) !== null && _a !== void 0 ? _a : {};
107
+ const featureFlagPayloads = Object.fromEntries(Object.entries(decideResponse.featureFlagPayloads || {}).map(([k, v]) => [k, parsePayload(v)]));
108
+ const flags = Object.fromEntries(Object.entries(featureFlags).map(([key, value]) => [
109
+ key,
110
+ getFlagDetailFromFlagAndPayload(key, value, featureFlagPayloads[key]),
111
+ ]));
112
+ return {
113
+ ...decideResponse,
114
+ featureFlags,
115
+ featureFlagPayloads,
116
+ flags,
117
+ };
118
+ }
119
+ };
120
+ function getFlagDetailFromFlagAndPayload(key, value, payload) {
121
+ return {
122
+ key: key,
123
+ enabled: typeof value === 'string' ? true : value,
124
+ variant: typeof value === 'string' ? value : undefined,
125
+ reason: undefined,
126
+ metadata: {
127
+ id: undefined,
128
+ version: undefined,
129
+ payload: payload ? JSON.stringify(payload) : undefined,
130
+ description: undefined,
131
+ },
132
+ };
133
+ }
134
+ /**
135
+ * Get the flag values from the flags v4 response.
136
+ * @param flags - The flags
137
+ * @returns The flag values
138
+ */
139
+ const getFlagValuesFromFlags = (flags) => {
140
+ return Object.fromEntries(Object.entries(flags !== null && flags !== void 0 ? flags : {})
141
+ .map(([key, detail]) => [key, getFeatureFlagValue(detail)])
142
+ .filter(([, value]) => value !== undefined));
143
+ };
144
+ /**
145
+ * Get the payloads from the flags v4 response.
146
+ * @param flags - The flags
147
+ * @returns The payloads
148
+ */
149
+ const getPayloadsFromFlags = (flags) => {
150
+ const safeFlags = flags !== null && flags !== void 0 ? flags : {};
151
+ return Object.fromEntries(Object.keys(safeFlags)
152
+ .filter((flag) => {
153
+ const details = safeFlags[flag];
154
+ return details.enabled && details.metadata && details.metadata.payload !== undefined;
155
+ })
156
+ .map((flag) => {
157
+ var _a;
158
+ const payload = (_a = safeFlags[flag].metadata) === null || _a === void 0 ? void 0 : _a.payload;
159
+ return [flag, payload ? parsePayload(payload) : undefined];
160
+ }));
161
+ };
162
+ const getFeatureFlagValue = (detail) => {
163
+ var _a;
164
+ return detail === undefined ? undefined : (_a = detail.variant) !== null && _a !== void 0 ? _a : detail.enabled;
165
+ };
166
+ const parsePayload = (response) => {
167
+ if (typeof response !== 'string') {
168
+ return response;
169
+ }
170
+ try {
171
+ return JSON.parse(response);
172
+ }
173
+ catch (_a) {
174
+ return response;
175
+ }
176
+ };
177
+ /**
178
+ * Get the normalized flag details from the flags and payloads.
179
+ * This is used to convert things like boostrap and stored feature flags and payloads to the v4 format.
180
+ * This helps us ensure backwards compatibility.
181
+ * If a key exists in the featureFlagPayloads that is not in the featureFlags, we treat it as a true feature flag.
182
+ *
183
+ * @param featureFlags - The feature flags
184
+ * @param featureFlagPayloads - The feature flag payloads
185
+ * @returns The normalized flag details
186
+ */
187
+ const createDecideResponseFromFlagsAndPayloads = (featureFlags, featureFlagPayloads) => {
188
+ // If a feature flag payload key is not in the feature flags, we treat it as true feature flag.
189
+ const allKeys = [...new Set([...Object.keys(featureFlags !== null && featureFlags !== void 0 ? featureFlags : {}), ...Object.keys(featureFlagPayloads !== null && featureFlagPayloads !== void 0 ? featureFlagPayloads : {})])];
190
+ const enabledFlags = allKeys
191
+ .filter((flag) => !!featureFlags[flag] || !!featureFlagPayloads[flag])
192
+ .reduce((res, key) => { var _a; return ((res[key] = (_a = featureFlags[key]) !== null && _a !== void 0 ? _a : true), res); }, {});
193
+ const flagDetails = {
194
+ featureFlags: enabledFlags,
195
+ featureFlagPayloads: featureFlagPayloads !== null && featureFlagPayloads !== void 0 ? featureFlagPayloads : {},
196
+ };
197
+ return normalizeDecideResponse(flagDetails);
198
+ };
199
+ const updateFlagValue = (flag, value) => {
200
+ return {
201
+ ...flag,
202
+ enabled: getEnabledFromValue(value),
203
+ variant: getVariantFromValue(value),
204
+ };
205
+ };
206
+ function getEnabledFromValue(value) {
207
+ return typeof value === 'string' ? true : value;
208
+ }
209
+ function getVariantFromValue(value) {
210
+ return typeof value === 'string' ? value : undefined;
211
+ }
212
+
213
+ // Rollout constants
214
+ const NEW_FLAGS_ROLLOUT_PERCENTAGE = 1;
215
+ // The fnv1a hashes of the tokens that are explicitly excluded from the rollout
216
+ // see https://github.com/PostHog/posthog-js-lite/blob/main/posthog-core/src/utils.ts#L84
217
+ // are hashed API tokens from our top 10 for each category supported by this SDK.
218
+ const NEW_FLAGS_EXCLUDED_HASHES = new Set([
219
+ // Node
220
+ '61be3dd8',
221
+ '96f6df5f',
222
+ '8cfdba9b',
223
+ 'bf027177',
224
+ 'e59430a8',
225
+ '7fa5500b',
226
+ '569798e9',
227
+ '04809ff7',
228
+ '0ebc61a5',
229
+ '32de7f98',
230
+ '3beeb69a',
231
+ '12d34ad9',
232
+ '733853ec',
233
+ '0645bb64',
234
+ '5dcbee21',
235
+ 'b1f95fa3',
236
+ '2189e408',
237
+ '82b460c2',
238
+ '3a8cc979',
239
+ '29ef8843',
240
+ '2cdbf767',
241
+ '38084b54',
242
+ // React Native
243
+ '50f9f8de',
244
+ '41d0df91',
245
+ '5c236689',
246
+ 'c11aedd3',
247
+ 'ada46672',
248
+ 'f4331ee1',
249
+ '42fed62a',
250
+ 'c957462c',
251
+ 'd62f705a',
252
+ // Web (lots of teams per org, hence lots of API tokens)
253
+ 'e0162666',
254
+ '01b3e5cf',
255
+ '441cef7f',
256
+ 'bb9cafee',
257
+ '8f348eb0',
258
+ 'b2553f3a',
259
+ '97469d7d',
260
+ '39f21a76',
261
+ '03706dcc',
262
+ '27d50569',
263
+ '307584a7',
264
+ '6433e92e',
265
+ '150c7fbb',
266
+ '49f57f22',
267
+ '3772f65b',
268
+ '01eb8256',
269
+ '3c9e9234',
270
+ 'f853c7f7',
271
+ 'c0ac4b67',
272
+ 'cd609d40',
273
+ '10ca9b1a',
274
+ '8a87f11b',
275
+ '8e8e5216',
276
+ '1f6b63b3',
277
+ 'db7943dd',
278
+ '79b7164c',
279
+ '07f78e33',
280
+ '2d21b6fd',
281
+ '952db5ee',
282
+ 'a7d3b43f',
283
+ '1924dd9c',
284
+ '84e1b8f6',
285
+ 'dff631b6',
286
+ 'c5aa8a79',
287
+ 'fa133a95',
288
+ '498a4508',
289
+ '24748755',
290
+ '98f3d658',
291
+ '21bbda67',
292
+ '7dbfed69',
293
+ 'be3ec24c',
294
+ 'fc80b8e2',
295
+ '75cc0998',
296
+ ]);
297
+ function assert(truthyValue, message) {
298
+ if (!truthyValue || typeof truthyValue !== 'string' || isEmpty(truthyValue)) {
299
+ throw new Error(message);
300
+ }
301
+ }
302
+ function isEmpty(truthyValue) {
303
+ if (truthyValue.trim().length === 0) {
304
+ return true;
305
+ }
306
+ return false;
307
+ }
308
+ function removeTrailingSlash(url) {
309
+ return url === null || url === void 0 ? void 0 : url.replace(/\/+$/, '');
310
+ }
311
+ async function retriable(fn, props) {
312
+ let lastError = null;
313
+ for (let i = 0; i < props.retryCount + 1; i++) {
314
+ if (i > 0) {
315
+ // don't wait when it's the last try
316
+ await new Promise((r) => setTimeout(r, props.retryDelay));
317
+ }
318
+ try {
319
+ const res = await fn();
320
+ return res;
321
+ }
322
+ catch (e) {
323
+ lastError = e;
324
+ if (!props.retryCheck(e)) {
325
+ throw e;
326
+ }
327
+ }
328
+ }
329
+ throw lastError;
330
+ }
331
+ function currentTimestamp() {
332
+ return new Date().getTime();
333
+ }
334
+ function currentISOTime() {
335
+ return new Date().toISOString();
336
+ }
337
+ function safeSetTimeout(fn, timeout) {
338
+ // NOTE: we use this so rarely that it is totally fine to do `safeSetTimeout(fn, 0)``
339
+ // rather than setImmediate.
340
+ const t = setTimeout(fn, timeout);
341
+ // We unref if available to prevent Node.js hanging on exit
342
+ (t === null || t === void 0 ? void 0 : t.unref) && (t === null || t === void 0 ? void 0 : t.unref());
343
+ return t;
344
+ }
345
+ // NOTE: We opt for this slightly imperfect check as the global "Promise" object can get mutated in certain environments
346
+ const isPromise = (obj) => {
347
+ return obj && typeof obj.then === 'function';
348
+ };
349
+ const isError = (x) => {
350
+ return x instanceof Error;
351
+ };
352
+ // FNV-1a hash function
353
+ // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
354
+ // I know, I know, I'm rolling my own hash function, but I didn't want to take on
355
+ // a crypto dependency and this is just temporary anyway
356
+ function fnv1a(str) {
357
+ let hash = 0x811c9dc5; // FNV offset basis
358
+ for (let i = 0; i < str.length; i++) {
359
+ hash ^= str.charCodeAt(i);
360
+ hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
361
+ }
362
+ // Convert to hex string, padding to 8 chars
363
+ return (hash >>> 0).toString(16).padStart(8, '0');
364
+ }
365
+ function isTokenInRollout(token, percentage = 0, excludedHashes) {
366
+ const tokenHash = fnv1a(token);
367
+ // Check excluded hashes (we're explicitly including these tokens from the rollout)
368
+ if (excludedHashes === null || excludedHashes === void 0 ? void 0 : excludedHashes.has(tokenHash)) {
369
+ return false;
370
+ }
371
+ // Convert hash to int and divide by max value to get number between 0-1
372
+ const hashInt = parseInt(tokenHash, 16);
373
+ const hashFloat = hashInt / 0xffffffff;
374
+ return hashFloat < percentage;
375
+ }
376
+
377
+ // Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
378
+ // This work is free. You can redistribute it and/or modify it
379
+ // under the terms of the WTFPL, Version 2
380
+ // For more information see LICENSE.txt or http://www.wtfpl.net/
381
+ //
382
+ // For more information, the home page:
383
+ // http://pieroxy.net/blog/pages/lz-string/testing.html
384
+ //
385
+ // LZ-based compression algorithm, version 1.4.4
386
+ // private property
387
+ const f = String.fromCharCode;
388
+ const keyStrBase64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
389
+ const baseReverseDic = {};
390
+ function getBaseValue(alphabet, character) {
391
+ if (!baseReverseDic[alphabet]) {
392
+ baseReverseDic[alphabet] = {};
393
+ for (let i = 0; i < alphabet.length; i++) {
394
+ baseReverseDic[alphabet][alphabet.charAt(i)] = i;
395
+ }
396
+ }
397
+ return baseReverseDic[alphabet][character];
398
+ }
399
+ const LZString = {
400
+ compressToBase64: function (input) {
401
+ if (input == null) {
402
+ return '';
403
+ }
404
+ const res = LZString._compress(input, 6, function (a) {
405
+ return keyStrBase64.charAt(a);
406
+ });
407
+ switch (res.length % 4 // To produce valid Base64
408
+ ) {
409
+ default: // When could this happen ?
410
+ case 0:
411
+ return res;
412
+ case 1:
413
+ return res + '===';
414
+ case 2:
415
+ return res + '==';
416
+ case 3:
417
+ return res + '=';
418
+ }
419
+ },
420
+ decompressFromBase64: function (input) {
421
+ if (input == null) {
422
+ return '';
423
+ }
424
+ if (input == '') {
425
+ return null;
426
+ }
427
+ return LZString._decompress(input.length, 32, function (index) {
428
+ return getBaseValue(keyStrBase64, input.charAt(index));
429
+ });
430
+ },
431
+ compress: function (uncompressed) {
432
+ return LZString._compress(uncompressed, 16, function (a) {
433
+ return f(a);
434
+ });
435
+ },
436
+ _compress: function (uncompressed, bitsPerChar, getCharFromInt) {
437
+ if (uncompressed == null) {
438
+ return '';
439
+ }
440
+ const context_dictionary = {}, context_dictionaryToCreate = {}, context_data = [];
441
+ let i, value, context_c = '', context_wc = '', context_w = '', context_enlargeIn = 2, // Compensate for the first entry which should not count
442
+ context_dictSize = 3, context_numBits = 2, context_data_val = 0, context_data_position = 0, ii;
443
+ for (ii = 0; ii < uncompressed.length; ii += 1) {
444
+ context_c = uncompressed.charAt(ii);
445
+ if (!Object.prototype.hasOwnProperty.call(context_dictionary, context_c)) {
446
+ context_dictionary[context_c] = context_dictSize++;
447
+ context_dictionaryToCreate[context_c] = true;
448
+ }
449
+ context_wc = context_w + context_c;
450
+ if (Object.prototype.hasOwnProperty.call(context_dictionary, context_wc)) {
451
+ context_w = context_wc;
452
+ }
453
+ else {
454
+ if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
455
+ if (context_w.charCodeAt(0) < 256) {
456
+ for (i = 0; i < context_numBits; i++) {
457
+ context_data_val = context_data_val << 1;
458
+ if (context_data_position == bitsPerChar - 1) {
459
+ context_data_position = 0;
460
+ context_data.push(getCharFromInt(context_data_val));
461
+ context_data_val = 0;
462
+ }
463
+ else {
464
+ context_data_position++;
465
+ }
466
+ }
467
+ value = context_w.charCodeAt(0);
468
+ for (i = 0; i < 8; i++) {
469
+ context_data_val = (context_data_val << 1) | (value & 1);
470
+ if (context_data_position == bitsPerChar - 1) {
471
+ context_data_position = 0;
472
+ context_data.push(getCharFromInt(context_data_val));
473
+ context_data_val = 0;
474
+ }
475
+ else {
476
+ context_data_position++;
477
+ }
478
+ value = value >> 1;
479
+ }
480
+ }
481
+ else {
482
+ value = 1;
483
+ for (i = 0; i < context_numBits; i++) {
484
+ context_data_val = (context_data_val << 1) | value;
485
+ if (context_data_position == bitsPerChar - 1) {
486
+ context_data_position = 0;
487
+ context_data.push(getCharFromInt(context_data_val));
488
+ context_data_val = 0;
489
+ }
490
+ else {
491
+ context_data_position++;
492
+ }
493
+ value = 0;
494
+ }
495
+ value = context_w.charCodeAt(0);
496
+ for (i = 0; i < 16; i++) {
497
+ context_data_val = (context_data_val << 1) | (value & 1);
498
+ if (context_data_position == bitsPerChar - 1) {
499
+ context_data_position = 0;
500
+ context_data.push(getCharFromInt(context_data_val));
501
+ context_data_val = 0;
502
+ }
503
+ else {
504
+ context_data_position++;
505
+ }
506
+ value = value >> 1;
507
+ }
508
+ }
509
+ context_enlargeIn--;
510
+ if (context_enlargeIn == 0) {
511
+ context_enlargeIn = Math.pow(2, context_numBits);
512
+ context_numBits++;
513
+ }
514
+ delete context_dictionaryToCreate[context_w];
515
+ }
516
+ else {
517
+ value = context_dictionary[context_w];
518
+ for (i = 0; i < context_numBits; i++) {
519
+ context_data_val = (context_data_val << 1) | (value & 1);
520
+ if (context_data_position == bitsPerChar - 1) {
521
+ context_data_position = 0;
522
+ context_data.push(getCharFromInt(context_data_val));
523
+ context_data_val = 0;
524
+ }
525
+ else {
526
+ context_data_position++;
527
+ }
528
+ value = value >> 1;
529
+ }
530
+ }
531
+ context_enlargeIn--;
532
+ if (context_enlargeIn == 0) {
533
+ context_enlargeIn = Math.pow(2, context_numBits);
534
+ context_numBits++;
535
+ }
536
+ // Add wc to the dictionary.
537
+ context_dictionary[context_wc] = context_dictSize++;
538
+ context_w = String(context_c);
539
+ }
540
+ }
541
+ // Output the code for w.
542
+ if (context_w !== '') {
543
+ if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
544
+ if (context_w.charCodeAt(0) < 256) {
545
+ for (i = 0; i < context_numBits; i++) {
546
+ context_data_val = context_data_val << 1;
547
+ if (context_data_position == bitsPerChar - 1) {
548
+ context_data_position = 0;
549
+ context_data.push(getCharFromInt(context_data_val));
550
+ context_data_val = 0;
551
+ }
552
+ else {
553
+ context_data_position++;
554
+ }
555
+ }
556
+ value = context_w.charCodeAt(0);
557
+ for (i = 0; i < 8; i++) {
558
+ context_data_val = (context_data_val << 1) | (value & 1);
559
+ if (context_data_position == bitsPerChar - 1) {
560
+ context_data_position = 0;
561
+ context_data.push(getCharFromInt(context_data_val));
562
+ context_data_val = 0;
563
+ }
564
+ else {
565
+ context_data_position++;
566
+ }
567
+ value = value >> 1;
568
+ }
569
+ }
570
+ else {
571
+ value = 1;
572
+ for (i = 0; i < context_numBits; i++) {
573
+ context_data_val = (context_data_val << 1) | value;
574
+ if (context_data_position == bitsPerChar - 1) {
575
+ context_data_position = 0;
576
+ context_data.push(getCharFromInt(context_data_val));
577
+ context_data_val = 0;
578
+ }
579
+ else {
580
+ context_data_position++;
581
+ }
582
+ value = 0;
583
+ }
584
+ value = context_w.charCodeAt(0);
585
+ for (i = 0; i < 16; i++) {
586
+ context_data_val = (context_data_val << 1) | (value & 1);
587
+ if (context_data_position == bitsPerChar - 1) {
588
+ context_data_position = 0;
589
+ context_data.push(getCharFromInt(context_data_val));
590
+ context_data_val = 0;
591
+ }
592
+ else {
593
+ context_data_position++;
594
+ }
595
+ value = value >> 1;
596
+ }
597
+ }
598
+ context_enlargeIn--;
599
+ if (context_enlargeIn == 0) {
600
+ context_enlargeIn = Math.pow(2, context_numBits);
601
+ context_numBits++;
602
+ }
603
+ delete context_dictionaryToCreate[context_w];
604
+ }
605
+ else {
606
+ value = context_dictionary[context_w];
607
+ for (i = 0; i < context_numBits; i++) {
608
+ context_data_val = (context_data_val << 1) | (value & 1);
609
+ if (context_data_position == bitsPerChar - 1) {
610
+ context_data_position = 0;
611
+ context_data.push(getCharFromInt(context_data_val));
612
+ context_data_val = 0;
613
+ }
614
+ else {
615
+ context_data_position++;
616
+ }
617
+ value = value >> 1;
618
+ }
619
+ }
620
+ context_enlargeIn--;
621
+ if (context_enlargeIn == 0) {
622
+ context_enlargeIn = Math.pow(2, context_numBits);
623
+ context_numBits++;
624
+ }
625
+ }
626
+ // Mark the end of the stream
627
+ value = 2;
628
+ for (i = 0; i < context_numBits; i++) {
629
+ context_data_val = (context_data_val << 1) | (value & 1);
630
+ if (context_data_position == bitsPerChar - 1) {
631
+ context_data_position = 0;
632
+ context_data.push(getCharFromInt(context_data_val));
633
+ context_data_val = 0;
634
+ }
635
+ else {
636
+ context_data_position++;
637
+ }
638
+ value = value >> 1;
639
+ }
640
+ // Flush the last char
641
+ while (true) {
642
+ context_data_val = context_data_val << 1;
643
+ if (context_data_position == bitsPerChar - 1) {
644
+ context_data.push(getCharFromInt(context_data_val));
645
+ break;
646
+ }
647
+ else {
648
+ context_data_position++;
649
+ }
650
+ }
651
+ return context_data.join('');
652
+ },
653
+ decompress: function (compressed) {
654
+ if (compressed == null) {
655
+ return '';
656
+ }
657
+ if (compressed == '') {
658
+ return null;
659
+ }
660
+ return LZString._decompress(compressed.length, 32768, function (index) {
661
+ return compressed.charCodeAt(index);
662
+ });
663
+ },
664
+ _decompress: function (length, resetValue, getNextValue) {
665
+ const dictionary = [], result = [], data = { val: getNextValue(0), position: resetValue, index: 1 };
666
+ let enlargeIn = 4, dictSize = 4, numBits = 3, entry = '', i, w, bits, resb, maxpower, power, c;
667
+ for (i = 0; i < 3; i += 1) {
668
+ dictionary[i] = i;
669
+ }
670
+ bits = 0;
671
+ maxpower = Math.pow(2, 2);
672
+ power = 1;
673
+ while (power != maxpower) {
674
+ resb = data.val & data.position;
675
+ data.position >>= 1;
676
+ if (data.position == 0) {
677
+ data.position = resetValue;
678
+ data.val = getNextValue(data.index++);
679
+ }
680
+ bits |= (resb > 0 ? 1 : 0) * power;
681
+ power <<= 1;
682
+ }
683
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
684
+ switch ((bits)) {
685
+ case 0:
686
+ bits = 0;
687
+ maxpower = Math.pow(2, 8);
688
+ power = 1;
689
+ while (power != maxpower) {
690
+ resb = data.val & data.position;
691
+ data.position >>= 1;
692
+ if (data.position == 0) {
693
+ data.position = resetValue;
694
+ data.val = getNextValue(data.index++);
695
+ }
696
+ bits |= (resb > 0 ? 1 : 0) * power;
697
+ power <<= 1;
698
+ }
699
+ c = f(bits);
700
+ break;
701
+ case 1:
702
+ bits = 0;
703
+ maxpower = Math.pow(2, 16);
704
+ power = 1;
705
+ while (power != maxpower) {
706
+ resb = data.val & data.position;
707
+ data.position >>= 1;
708
+ if (data.position == 0) {
709
+ data.position = resetValue;
710
+ data.val = getNextValue(data.index++);
711
+ }
712
+ bits |= (resb > 0 ? 1 : 0) * power;
713
+ power <<= 1;
714
+ }
715
+ c = f(bits);
716
+ break;
717
+ case 2:
718
+ return '';
719
+ }
720
+ dictionary[3] = c;
721
+ w = c;
722
+ result.push(c);
723
+ while (true) {
724
+ if (data.index > length) {
725
+ return '';
726
+ }
727
+ bits = 0;
728
+ maxpower = Math.pow(2, numBits);
729
+ power = 1;
730
+ while (power != maxpower) {
731
+ resb = data.val & data.position;
732
+ data.position >>= 1;
733
+ if (data.position == 0) {
734
+ data.position = resetValue;
735
+ data.val = getNextValue(data.index++);
736
+ }
737
+ bits |= (resb > 0 ? 1 : 0) * power;
738
+ power <<= 1;
739
+ }
740
+ switch ((c = bits)) {
741
+ case 0:
742
+ bits = 0;
743
+ maxpower = Math.pow(2, 8);
744
+ power = 1;
745
+ while (power != maxpower) {
746
+ resb = data.val & data.position;
747
+ data.position >>= 1;
748
+ if (data.position == 0) {
749
+ data.position = resetValue;
750
+ data.val = getNextValue(data.index++);
751
+ }
752
+ bits |= (resb > 0 ? 1 : 0) * power;
753
+ power <<= 1;
754
+ }
755
+ dictionary[dictSize++] = f(bits);
756
+ c = dictSize - 1;
757
+ enlargeIn--;
758
+ break;
759
+ case 1:
760
+ bits = 0;
761
+ maxpower = Math.pow(2, 16);
762
+ power = 1;
763
+ while (power != maxpower) {
764
+ resb = data.val & data.position;
765
+ data.position >>= 1;
766
+ if (data.position == 0) {
767
+ data.position = resetValue;
768
+ data.val = getNextValue(data.index++);
769
+ }
770
+ bits |= (resb > 0 ? 1 : 0) * power;
771
+ power <<= 1;
772
+ }
773
+ dictionary[dictSize++] = f(bits);
774
+ c = dictSize - 1;
775
+ enlargeIn--;
776
+ break;
777
+ case 2:
778
+ return result.join('');
779
+ }
780
+ if (enlargeIn == 0) {
781
+ enlargeIn = Math.pow(2, numBits);
782
+ numBits++;
783
+ }
784
+ if (dictionary[c]) {
785
+ entry = dictionary[c];
786
+ }
787
+ else {
788
+ if (c === dictSize) {
789
+ entry = w + w.charAt(0);
790
+ }
791
+ else {
792
+ return null;
793
+ }
794
+ }
795
+ result.push(entry);
796
+ // Add w+entry[0] to the dictionary.
797
+ dictionary[dictSize++] = w + entry.charAt(0);
798
+ enlargeIn--;
799
+ w = entry;
800
+ if (enlargeIn == 0) {
801
+ enlargeIn = Math.pow(2, numBits);
802
+ numBits++;
803
+ }
804
+ }
805
+ },
806
+ };
807
+
808
+ class SimpleEventEmitter {
809
+ constructor() {
810
+ this.events = {};
811
+ this.events = {};
812
+ }
813
+ on(event, listener) {
814
+ if (!this.events[event]) {
815
+ this.events[event] = [];
816
+ }
817
+ this.events[event].push(listener);
818
+ return () => {
819
+ this.events[event] = this.events[event].filter((x) => x !== listener);
820
+ };
821
+ }
822
+ emit(event, payload) {
823
+ for (const listener of this.events[event] || []) {
824
+ listener(payload);
825
+ }
826
+ for (const listener of this.events['*'] || []) {
827
+ listener(event, payload);
828
+ }
829
+ }
830
+ }
831
+
832
+ // vendor from: https://github.com/LiosK/uuidv7/blob/f30b7a7faff73afbce0b27a46c638310f96912ba/src/index.ts
833
+ // https://github.com/LiosK/uuidv7#license
834
+ /**
835
+ * uuidv7: An experimental implementation of the proposed UUID Version 7
836
+ *
837
+ * @license Apache-2.0
838
+ * @copyright 2021-2023 LiosK
839
+ * @packageDocumentation
840
+ */
841
+ const DIGITS = "0123456789abcdef";
842
+ /** Represents a UUID as a 16-byte byte array. */
843
+ class UUID {
844
+ /** @param bytes - The 16-byte byte array representation. */
845
+ constructor(bytes) {
846
+ this.bytes = bytes;
847
+ }
848
+ /**
849
+ * Creates an object from the internal representation, a 16-byte byte array
850
+ * containing the binary UUID representation in the big-endian byte order.
851
+ *
852
+ * This method does NOT shallow-copy the argument, and thus the created object
853
+ * holds the reference to the underlying buffer.
854
+ *
855
+ * @throws TypeError if the length of the argument is not 16.
856
+ */
857
+ static ofInner(bytes) {
858
+ if (bytes.length !== 16) {
859
+ throw new TypeError("not 128-bit length");
860
+ }
861
+ else {
862
+ return new UUID(bytes);
863
+ }
864
+ }
865
+ /**
866
+ * Builds a byte array from UUIDv7 field values.
867
+ *
868
+ * @param unixTsMs - A 48-bit `unix_ts_ms` field value.
869
+ * @param randA - A 12-bit `rand_a` field value.
870
+ * @param randBHi - The higher 30 bits of 62-bit `rand_b` field value.
871
+ * @param randBLo - The lower 32 bits of 62-bit `rand_b` field value.
872
+ * @throws RangeError if any field value is out of the specified range.
873
+ */
874
+ static fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
875
+ if (!Number.isInteger(unixTsMs) ||
876
+ !Number.isInteger(randA) ||
877
+ !Number.isInteger(randBHi) ||
878
+ !Number.isInteger(randBLo) ||
879
+ unixTsMs < 0 ||
880
+ randA < 0 ||
881
+ randBHi < 0 ||
882
+ randBLo < 0 ||
883
+ unixTsMs > 281474976710655 ||
884
+ randA > 0xfff ||
885
+ randBHi > 1073741823 ||
886
+ randBLo > 4294967295) {
887
+ throw new RangeError("invalid field value");
888
+ }
889
+ const bytes = new Uint8Array(16);
890
+ bytes[0] = unixTsMs / 2 ** 40;
891
+ bytes[1] = unixTsMs / 2 ** 32;
892
+ bytes[2] = unixTsMs / 2 ** 24;
893
+ bytes[3] = unixTsMs / 2 ** 16;
894
+ bytes[4] = unixTsMs / 2 ** 8;
895
+ bytes[5] = unixTsMs;
896
+ bytes[6] = 0x70 | (randA >>> 8);
897
+ bytes[7] = randA;
898
+ bytes[8] = 0x80 | (randBHi >>> 24);
899
+ bytes[9] = randBHi >>> 16;
900
+ bytes[10] = randBHi >>> 8;
901
+ bytes[11] = randBHi;
902
+ bytes[12] = randBLo >>> 24;
903
+ bytes[13] = randBLo >>> 16;
904
+ bytes[14] = randBLo >>> 8;
905
+ bytes[15] = randBLo;
906
+ return new UUID(bytes);
907
+ }
908
+ /**
909
+ * Builds a byte array from a string representation.
910
+ *
911
+ * This method accepts the following formats:
912
+ *
913
+ * - 32-digit hexadecimal format without hyphens: `0189dcd553117d408db09496a2eef37b`
914
+ * - 8-4-4-4-12 hyphenated format: `0189dcd5-5311-7d40-8db0-9496a2eef37b`
915
+ * - Hyphenated format with surrounding braces: `{0189dcd5-5311-7d40-8db0-9496a2eef37b}`
916
+ * - RFC 4122 URN format: `urn:uuid:0189dcd5-5311-7d40-8db0-9496a2eef37b`
917
+ *
918
+ * Leading and trailing whitespaces represents an error.
919
+ *
920
+ * @throws SyntaxError if the argument could not parse as a valid UUID string.
921
+ */
922
+ static parse(uuid) {
923
+ var _a, _b, _c, _d;
924
+ let hex = undefined;
925
+ switch (uuid.length) {
926
+ case 32:
927
+ hex = (_a = /^[0-9a-f]{32}$/i.exec(uuid)) === null || _a === void 0 ? void 0 : _a[0];
928
+ break;
929
+ case 36:
930
+ hex =
931
+ (_b = /^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i
932
+ .exec(uuid)) === null || _b === void 0 ? void 0 : _b.slice(1, 6).join("");
933
+ break;
934
+ case 38:
935
+ hex =
936
+ (_c = /^\{([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})\}$/i
937
+ .exec(uuid)) === null || _c === void 0 ? void 0 : _c.slice(1, 6).join("");
938
+ break;
939
+ case 45:
940
+ hex =
941
+ (_d = /^urn:uuid:([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i
942
+ .exec(uuid)) === null || _d === void 0 ? void 0 : _d.slice(1, 6).join("");
943
+ break;
944
+ }
945
+ if (hex) {
946
+ const inner = new Uint8Array(16);
947
+ for (let i = 0; i < 16; i += 4) {
948
+ const n = parseInt(hex.substring(2 * i, 2 * i + 8), 16);
949
+ inner[i + 0] = n >>> 24;
950
+ inner[i + 1] = n >>> 16;
951
+ inner[i + 2] = n >>> 8;
952
+ inner[i + 3] = n;
953
+ }
954
+ return new UUID(inner);
955
+ }
956
+ else {
957
+ throw new SyntaxError("could not parse UUID string");
958
+ }
959
+ }
960
+ /**
961
+ * @returns The 8-4-4-4-12 canonical hexadecimal string representation
962
+ * (`0189dcd5-5311-7d40-8db0-9496a2eef37b`).
963
+ */
964
+ toString() {
965
+ let text = "";
966
+ for (let i = 0; i < this.bytes.length; i++) {
967
+ text += DIGITS.charAt(this.bytes[i] >>> 4);
968
+ text += DIGITS.charAt(this.bytes[i] & 0xf);
969
+ if (i === 3 || i === 5 || i === 7 || i === 9) {
970
+ text += "-";
971
+ }
972
+ }
973
+ return text;
974
+ }
975
+ /**
976
+ * @returns The 32-digit hexadecimal representation without hyphens
977
+ * (`0189dcd553117d408db09496a2eef37b`).
978
+ */
979
+ toHex() {
980
+ let text = "";
981
+ for (let i = 0; i < this.bytes.length; i++) {
982
+ text += DIGITS.charAt(this.bytes[i] >>> 4);
983
+ text += DIGITS.charAt(this.bytes[i] & 0xf);
984
+ }
985
+ return text;
986
+ }
987
+ /** @returns The 8-4-4-4-12 canonical hexadecimal string representation. */
988
+ toJSON() {
989
+ return this.toString();
990
+ }
991
+ /**
992
+ * Reports the variant field value of the UUID or, if appropriate, "NIL" or
993
+ * "MAX".
994
+ *
995
+ * For convenience, this method reports "NIL" or "MAX" if `this` represents
996
+ * the Nil or Max UUID, although the Nil and Max UUIDs are technically
997
+ * subsumed under the variants `0b0` and `0b111`, respectively.
998
+ */
999
+ getVariant() {
1000
+ const n = this.bytes[8] >>> 4;
1001
+ if (n < 0) {
1002
+ throw new Error("unreachable");
1003
+ }
1004
+ else if (n <= 0b0111) {
1005
+ return this.bytes.every((e) => e === 0) ? "NIL" : "VAR_0";
1006
+ }
1007
+ else if (n <= 0b1011) {
1008
+ return "VAR_10";
1009
+ }
1010
+ else if (n <= 0b1101) {
1011
+ return "VAR_110";
1012
+ }
1013
+ else if (n <= 0b1111) {
1014
+ return this.bytes.every((e) => e === 0xff) ? "MAX" : "VAR_RESERVED";
1015
+ }
1016
+ else {
1017
+ throw new Error("unreachable");
1018
+ }
1019
+ }
1020
+ /**
1021
+ * Returns the version field value of the UUID or `undefined` if the UUID does
1022
+ * not have the variant field value of `0b10`.
1023
+ */
1024
+ getVersion() {
1025
+ return this.getVariant() === "VAR_10" ? this.bytes[6] >>> 4 : undefined;
1026
+ }
1027
+ /** Creates an object from `this`. */
1028
+ clone() {
1029
+ return new UUID(this.bytes.slice(0));
1030
+ }
1031
+ /** Returns true if `this` is equivalent to `other`. */
1032
+ equals(other) {
1033
+ return this.compareTo(other) === 0;
1034
+ }
1035
+ /**
1036
+ * Returns a negative integer, zero, or positive integer if `this` is less
1037
+ * than, equal to, or greater than `other`, respectively.
1038
+ */
1039
+ compareTo(other) {
1040
+ for (let i = 0; i < 16; i++) {
1041
+ const diff = this.bytes[i] - other.bytes[i];
1042
+ if (diff !== 0) {
1043
+ return Math.sign(diff);
1044
+ }
1045
+ }
1046
+ return 0;
1047
+ }
1048
+ }
1049
+ /**
1050
+ * Encapsulates the monotonic counter state.
1051
+ *
1052
+ * This class provides APIs to utilize a separate counter state from that of the
1053
+ * global generator used by {@link uuidv7} and {@link uuidv7obj}. In addition to
1054
+ * the default {@link generate} method, this class has {@link generateOrAbort}
1055
+ * that is useful to absolutely guarantee the monotonically increasing order of
1056
+ * generated UUIDs. See their respective documentation for details.
1057
+ */
1058
+ class V7Generator {
1059
+ /**
1060
+ * Creates a generator object with the default random number generator, or
1061
+ * with the specified one if passed as an argument. The specified random
1062
+ * number generator should be cryptographically strong and securely seeded.
1063
+ */
1064
+ constructor(randomNumberGenerator) {
1065
+ this.timestamp = 0;
1066
+ this.counter = 0;
1067
+ this.random = randomNumberGenerator !== null && randomNumberGenerator !== void 0 ? randomNumberGenerator : getDefaultRandom();
1068
+ }
1069
+ /**
1070
+ * Generates a new UUIDv7 object from the current timestamp, or resets the
1071
+ * generator upon significant timestamp rollback.
1072
+ *
1073
+ * This method returns a monotonically increasing UUID by reusing the previous
1074
+ * timestamp even if the up-to-date timestamp is smaller than the immediately
1075
+ * preceding UUID's. However, when such a clock rollback is considered
1076
+ * significant (i.e., by more than ten seconds), this method resets the
1077
+ * generator and returns a new UUID based on the given timestamp, breaking the
1078
+ * increasing order of UUIDs.
1079
+ *
1080
+ * See {@link generateOrAbort} for the other mode of generation and
1081
+ * {@link generateOrResetCore} for the low-level primitive.
1082
+ */
1083
+ generate() {
1084
+ return this.generateOrResetCore(Date.now(), 10000);
1085
+ }
1086
+ /**
1087
+ * Generates a new UUIDv7 object from the current timestamp, or returns
1088
+ * `undefined` upon significant timestamp rollback.
1089
+ *
1090
+ * This method returns a monotonically increasing UUID by reusing the previous
1091
+ * timestamp even if the up-to-date timestamp is smaller than the immediately
1092
+ * preceding UUID's. However, when such a clock rollback is considered
1093
+ * significant (i.e., by more than ten seconds), this method aborts and
1094
+ * returns `undefined` immediately.
1095
+ *
1096
+ * See {@link generate} for the other mode of generation and
1097
+ * {@link generateOrAbortCore} for the low-level primitive.
1098
+ */
1099
+ generateOrAbort() {
1100
+ return this.generateOrAbortCore(Date.now(), 10000);
1101
+ }
1102
+ /**
1103
+ * Generates a new UUIDv7 object from the `unixTsMs` passed, or resets the
1104
+ * generator upon significant timestamp rollback.
1105
+ *
1106
+ * This method is equivalent to {@link generate} except that it takes a custom
1107
+ * timestamp and clock rollback allowance.
1108
+ *
1109
+ * @param rollbackAllowance - The amount of `unixTsMs` rollback that is
1110
+ * considered significant. A suggested value is `10_000` (milliseconds).
1111
+ * @throws RangeError if `unixTsMs` is not a 48-bit positive integer.
1112
+ */
1113
+ generateOrResetCore(unixTsMs, rollbackAllowance) {
1114
+ let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
1115
+ if (value === undefined) {
1116
+ // reset state and resume
1117
+ this.timestamp = 0;
1118
+ value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
1119
+ }
1120
+ return value;
1121
+ }
1122
+ /**
1123
+ * Generates a new UUIDv7 object from the `unixTsMs` passed, or returns
1124
+ * `undefined` upon significant timestamp rollback.
1125
+ *
1126
+ * This method is equivalent to {@link generateOrAbort} except that it takes a
1127
+ * custom timestamp and clock rollback allowance.
1128
+ *
1129
+ * @param rollbackAllowance - The amount of `unixTsMs` rollback that is
1130
+ * considered significant. A suggested value is `10_000` (milliseconds).
1131
+ * @throws RangeError if `unixTsMs` is not a 48-bit positive integer.
1132
+ */
1133
+ generateOrAbortCore(unixTsMs, rollbackAllowance) {
1134
+ const MAX_COUNTER = 4398046511103;
1135
+ if (!Number.isInteger(unixTsMs) ||
1136
+ unixTsMs < 1 ||
1137
+ unixTsMs > 281474976710655) {
1138
+ throw new RangeError("`unixTsMs` must be a 48-bit positive integer");
1139
+ }
1140
+ else if (rollbackAllowance < 0 || rollbackAllowance > 281474976710655) {
1141
+ throw new RangeError("`rollbackAllowance` out of reasonable range");
1142
+ }
1143
+ if (unixTsMs > this.timestamp) {
1144
+ this.timestamp = unixTsMs;
1145
+ this.resetCounter();
1146
+ }
1147
+ else if (unixTsMs + rollbackAllowance >= this.timestamp) {
1148
+ // go on with previous timestamp if new one is not much smaller
1149
+ this.counter++;
1150
+ if (this.counter > MAX_COUNTER) {
1151
+ // increment timestamp at counter overflow
1152
+ this.timestamp++;
1153
+ this.resetCounter();
1154
+ }
1155
+ }
1156
+ else {
1157
+ // abort if clock went backwards to unbearable extent
1158
+ return undefined;
1159
+ }
1160
+ return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter / 2 ** 30), this.counter & (2 ** 30 - 1), this.random.nextUint32());
1161
+ }
1162
+ /** Initializes the counter at a 42-bit random integer. */
1163
+ resetCounter() {
1164
+ this.counter =
1165
+ this.random.nextUint32() * 0x400 + (this.random.nextUint32() & 0x3ff);
1166
+ }
1167
+ /**
1168
+ * Generates a new UUIDv4 object utilizing the random number generator inside.
1169
+ *
1170
+ * @internal
1171
+ */
1172
+ generateV4() {
1173
+ const bytes = new Uint8Array(Uint32Array.of(this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32()).buffer);
1174
+ bytes[6] = 0x40 | (bytes[6] >>> 4);
1175
+ bytes[8] = 0x80 | (bytes[8] >>> 2);
1176
+ return UUID.ofInner(bytes);
1177
+ }
1178
+ }
1179
+ /** A global flag to force use of cryptographically strong RNG. */
1180
+ // declare const UUIDV7_DENY_WEAK_RNG: boolean;
1181
+ /** Returns the default random number generator available in the environment. */
1182
+ const getDefaultRandom = () => {
1183
+ // fix: crypto isn't available in react-native, always use Math.random
1184
+ // // detect Web Crypto API
1185
+ // if (
1186
+ // typeof crypto !== "undefined" &&
1187
+ // typeof crypto.getRandomValues !== "undefined"
1188
+ // ) {
1189
+ // return new BufferedCryptoRandom();
1190
+ // } else {
1191
+ // // fall back on Math.random() unless the flag is set to true
1192
+ // if (typeof UUIDV7_DENY_WEAK_RNG !== "undefined" && UUIDV7_DENY_WEAK_RNG) {
1193
+ // throw new Error("no cryptographically strong RNG available");
1194
+ // }
1195
+ // return {
1196
+ // nextUint32: (): number =>
1197
+ // Math.trunc(Math.random() * 0x1_0000) * 0x1_0000 +
1198
+ // Math.trunc(Math.random() * 0x1_0000),
1199
+ // };
1200
+ // }
1201
+ return {
1202
+ nextUint32: () => Math.trunc(Math.random() * 65536) * 65536 +
1203
+ Math.trunc(Math.random() * 65536),
1204
+ };
1205
+ };
1206
+ // /**
1207
+ // * Wraps `crypto.getRandomValues()` to enable buffering; this uses a small
1208
+ // * buffer by default to avoid both unbearable throughput decline in some
1209
+ // * environments and the waste of time and space for unused values.
1210
+ // */
1211
+ // class BufferedCryptoRandom {
1212
+ // private readonly buffer = new Uint32Array(8);
1213
+ // private cursor = 0xffff;
1214
+ // nextUint32(): number {
1215
+ // if (this.cursor >= this.buffer.length) {
1216
+ // crypto.getRandomValues(this.buffer);
1217
+ // this.cursor = 0;
1218
+ // }
1219
+ // return this.buffer[this.cursor++];
1220
+ // }
1221
+ // }
1222
+ let defaultGenerator;
1223
+ /**
1224
+ * Generates a UUIDv7 string.
1225
+ *
1226
+ * @returns The 8-4-4-4-12 canonical hexadecimal string representation
1227
+ * ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx").
1228
+ */
1229
+ const uuidv7 = () => uuidv7obj().toString();
1230
+ /** Generates a UUIDv7 object. */
1231
+ const uuidv7obj = () => (defaultGenerator || (defaultGenerator = new V7Generator())).generate();
1232
+
1233
+ class PostHogFetchHttpError extends Error {
1234
+ constructor(response) {
1235
+ super('HTTP error while fetching PostHog: ' + response.status);
1236
+ this.response = response;
1237
+ this.name = 'PostHogFetchHttpError';
1238
+ }
1239
+ }
1240
+ class PostHogFetchNetworkError extends Error {
1241
+ constructor(error) {
1242
+ // TRICKY: "cause" is a newer property but is just ignored otherwise. Cast to any to ignore the type issue.
1243
+ // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
1244
+ // @ts-ignore
1245
+ super('Network error while fetching PostHog', error instanceof Error ? { cause: error } : {});
1246
+ this.error = error;
1247
+ this.name = 'PostHogFetchNetworkError';
1248
+ }
1249
+ }
1250
+ function isPostHogFetchError(err) {
1251
+ return typeof err === 'object' && (err instanceof PostHogFetchHttpError || err instanceof PostHogFetchNetworkError);
1252
+ }
1253
+ var QuotaLimitedFeature;
1254
+ (function (QuotaLimitedFeature) {
1255
+ QuotaLimitedFeature["FeatureFlags"] = "feature_flags";
1256
+ QuotaLimitedFeature["Recordings"] = "recordings";
1257
+ })(QuotaLimitedFeature || (QuotaLimitedFeature = {}));
1258
+ class PostHogCoreStateless {
1259
+ constructor(apiKey, options) {
1260
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
1261
+ this.flushPromise = null;
1262
+ this.pendingPromises = {};
1263
+ // internal
1264
+ this._events = new SimpleEventEmitter();
1265
+ this._isInitialized = false;
1266
+ assert(apiKey, "You must pass your PostHog project's api key.");
1267
+ this.apiKey = apiKey;
1268
+ this.host = removeTrailingSlash((options === null || options === void 0 ? void 0 : options.host) || 'https://us.i.posthog.com');
1269
+ this.flushAt = (options === null || options === void 0 ? void 0 : options.flushAt) ? Math.max(options === null || options === void 0 ? void 0 : options.flushAt, 1) : 20;
1270
+ this.maxBatchSize = Math.max(this.flushAt, (_a = options === null || options === void 0 ? void 0 : options.maxBatchSize) !== null && _a !== void 0 ? _a : 100);
1271
+ this.maxQueueSize = Math.max(this.flushAt, (_b = options === null || options === void 0 ? void 0 : options.maxQueueSize) !== null && _b !== void 0 ? _b : 1000);
1272
+ this.flushInterval = (_c = options === null || options === void 0 ? void 0 : options.flushInterval) !== null && _c !== void 0 ? _c : 10000;
1273
+ this.captureMode = (options === null || options === void 0 ? void 0 : options.captureMode) || 'json';
1274
+ this.preloadFeatureFlags = (_d = options === null || options === void 0 ? void 0 : options.preloadFeatureFlags) !== null && _d !== void 0 ? _d : true;
1275
+ // If enable is explicitly set to false we override the optout
1276
+ this.defaultOptIn = (_e = options === null || options === void 0 ? void 0 : options.defaultOptIn) !== null && _e !== void 0 ? _e : true;
1277
+ this.disableSurveys = (_f = options === null || options === void 0 ? void 0 : options.disableSurveys) !== null && _f !== void 0 ? _f : false;
1278
+ this._retryOptions = {
1279
+ retryCount: (_g = options === null || options === void 0 ? void 0 : options.fetchRetryCount) !== null && _g !== void 0 ? _g : 3,
1280
+ retryDelay: (_h = options === null || options === void 0 ? void 0 : options.fetchRetryDelay) !== null && _h !== void 0 ? _h : 3000,
1281
+ retryCheck: isPostHogFetchError,
1282
+ };
1283
+ this.requestTimeout = (_j = options === null || options === void 0 ? void 0 : options.requestTimeout) !== null && _j !== void 0 ? _j : 10000; // 10 seconds
1284
+ this.featureFlagsRequestTimeoutMs = (_k = options === null || options === void 0 ? void 0 : options.featureFlagsRequestTimeoutMs) !== null && _k !== void 0 ? _k : 3000; // 3 seconds
1285
+ this.remoteConfigRequestTimeoutMs = (_l = options === null || options === void 0 ? void 0 : options.remoteConfigRequestTimeoutMs) !== null && _l !== void 0 ? _l : 3000; // 3 seconds
1286
+ this.disableGeoip = (_m = options === null || options === void 0 ? void 0 : options.disableGeoip) !== null && _m !== void 0 ? _m : true;
1287
+ this.disabled = (_o = options === null || options === void 0 ? void 0 : options.disabled) !== null && _o !== void 0 ? _o : false;
1288
+ this.historicalMigration = (_p = options === null || options === void 0 ? void 0 : options.historicalMigration) !== null && _p !== void 0 ? _p : false;
1289
+ // Init promise allows the derived class to block calls until it is ready
1290
+ this._initPromise = Promise.resolve();
1291
+ this._isInitialized = true;
1292
+ }
1293
+ logMsgIfDebug(fn) {
1294
+ if (this.isDebug) {
1295
+ fn();
1296
+ }
1297
+ }
1298
+ wrap(fn) {
1299
+ if (this.disabled) {
1300
+ this.logMsgIfDebug(() => console.warn('[PostHog] The client is disabled'));
1301
+ return;
1302
+ }
1303
+ if (this._isInitialized) {
1304
+ // NOTE: We could also check for the "opt in" status here...
1305
+ return fn();
1306
+ }
1307
+ this._initPromise.then(() => fn());
1308
+ }
1309
+ getCommonEventProperties() {
1310
+ return {
1311
+ $lib: this.getLibraryId(),
1312
+ $lib_version: this.getLibraryVersion(),
1313
+ };
1314
+ }
1315
+ get optedOut() {
1316
+ var _a;
1317
+ return (_a = this.getPersistedProperty(PostHogPersistedProperty.OptedOut)) !== null && _a !== void 0 ? _a : !this.defaultOptIn;
1318
+ }
1319
+ async optIn() {
1320
+ this.wrap(() => {
1321
+ this.setPersistedProperty(PostHogPersistedProperty.OptedOut, false);
1322
+ });
1323
+ }
1324
+ async optOut() {
1325
+ this.wrap(() => {
1326
+ this.setPersistedProperty(PostHogPersistedProperty.OptedOut, true);
1327
+ });
1328
+ }
1329
+ on(event, cb) {
1330
+ return this._events.on(event, cb);
1331
+ }
1332
+ debug(enabled = true) {
1333
+ var _a;
1334
+ (_a = this.removeDebugCallback) === null || _a === void 0 ? void 0 : _a.call(this);
1335
+ if (enabled) {
1336
+ const removeDebugCallback = this.on('*', (event, payload) => console.log('PostHog Debug', event, payload));
1337
+ this.removeDebugCallback = () => {
1338
+ removeDebugCallback();
1339
+ this.removeDebugCallback = undefined;
1340
+ };
1341
+ }
1342
+ }
1343
+ get isDebug() {
1344
+ return !!this.removeDebugCallback;
1345
+ }
1346
+ get isDisabled() {
1347
+ return this.disabled;
1348
+ }
1349
+ buildPayload(payload) {
1350
+ return {
1351
+ distinct_id: payload.distinct_id,
1352
+ event: payload.event,
1353
+ properties: {
1354
+ ...(payload.properties || {}),
1355
+ ...this.getCommonEventProperties(), // Common PH props
1356
+ },
1357
+ };
1358
+ }
1359
+ addPendingPromise(promise) {
1360
+ const promiseUUID = uuidv7();
1361
+ this.pendingPromises[promiseUUID] = promise;
1362
+ promise
1363
+ .catch(() => { })
1364
+ .finally(() => {
1365
+ delete this.pendingPromises[promiseUUID];
1366
+ });
1367
+ return promise;
1368
+ }
1369
+ /***
1370
+ *** TRACKING
1371
+ ***/
1372
+ identifyStateless(distinctId, properties, options) {
1373
+ this.wrap(() => {
1374
+ // The properties passed to identifyStateless are event properties.
1375
+ // To add person properties, pass in all person properties to the `$set` and `$set_once` keys.
1376
+ const payload = {
1377
+ ...this.buildPayload({
1378
+ distinct_id: distinctId,
1379
+ event: '$identify',
1380
+ properties,
1381
+ }),
1382
+ };
1383
+ this.enqueue('identify', payload, options);
1384
+ });
1385
+ }
1386
+ captureStateless(distinctId, event, properties, options) {
1387
+ this.wrap(() => {
1388
+ const payload = this.buildPayload({ distinct_id: distinctId, event, properties });
1389
+ this.enqueue('capture', payload, options);
1390
+ });
1391
+ }
1392
+ aliasStateless(alias, distinctId, properties, options) {
1393
+ this.wrap(() => {
1394
+ const payload = this.buildPayload({
1395
+ event: '$create_alias',
1396
+ distinct_id: distinctId,
1397
+ properties: {
1398
+ ...(properties || {}),
1399
+ distinct_id: distinctId,
1400
+ alias,
1401
+ },
1402
+ });
1403
+ this.enqueue('alias', payload, options);
1404
+ });
1405
+ }
1406
+ /***
1407
+ *** GROUPS
1408
+ ***/
1409
+ groupIdentifyStateless(groupType, groupKey, groupProperties, options, distinctId, eventProperties) {
1410
+ this.wrap(() => {
1411
+ const payload = this.buildPayload({
1412
+ distinct_id: distinctId || `$${groupType}_${groupKey}`,
1413
+ event: '$groupidentify',
1414
+ properties: {
1415
+ $group_type: groupType,
1416
+ $group_key: groupKey,
1417
+ $group_set: groupProperties || {},
1418
+ ...(eventProperties || {}),
1419
+ },
1420
+ });
1421
+ this.enqueue('capture', payload, options);
1422
+ });
1423
+ }
1424
+ async getRemoteConfig() {
1425
+ await this._initPromise;
1426
+ let host = this.host;
1427
+ if (host === 'https://us.i.posthog.com') {
1428
+ host = 'https://us-assets.i.posthog.com';
1429
+ }
1430
+ else if (host === 'https://eu.i.posthog.com') {
1431
+ host = 'https://eu-assets.i.posthog.com';
1432
+ }
1433
+ const url = `${host}/array/${this.apiKey}/config`;
1434
+ const fetchOptions = {
1435
+ method: 'GET',
1436
+ headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
1437
+ };
1438
+ // Don't retry remote config API calls
1439
+ return this.fetchWithRetry(url, fetchOptions, { retryCount: 0 }, this.remoteConfigRequestTimeoutMs)
1440
+ .then((response) => response.json())
1441
+ .catch((error) => {
1442
+ this.logMsgIfDebug(() => console.error('Remote config could not be loaded', error));
1443
+ this._events.emit('error', error);
1444
+ return undefined;
1445
+ });
1446
+ }
1447
+ /***
1448
+ *** FEATURE FLAGS
1449
+ ***/
1450
+ async getDecide(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}) {
1451
+ await this._initPromise;
1452
+ // Check if the API token is in the new flags rollout
1453
+ // This is a temporary measure to ensure that we can still use the old flags API
1454
+ // while we migrate to the new flags API
1455
+ const useFlags = isTokenInRollout(this.apiKey, NEW_FLAGS_ROLLOUT_PERCENTAGE, NEW_FLAGS_EXCLUDED_HASHES);
1456
+ const url = useFlags ? `${this.host}/flags/?v=2` : `${this.host}/decide/?v=4`;
1457
+ const fetchOptions = {
1458
+ method: 'POST',
1459
+ headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
1460
+ body: JSON.stringify({
1461
+ token: this.apiKey,
1462
+ distinct_id: distinctId,
1463
+ groups,
1464
+ person_properties: personProperties,
1465
+ group_properties: groupProperties,
1466
+ ...extraPayload,
1467
+ }),
1468
+ };
1469
+ // Don't retry /decide API calls
1470
+ return this.fetchWithRetry(url, fetchOptions, { retryCount: 0 }, this.featureFlagsRequestTimeoutMs)
1471
+ .then((response) => response.json())
1472
+ .then((response) => normalizeDecideResponse(response))
1473
+ .catch((error) => {
1474
+ this._events.emit('error', error);
1475
+ return undefined;
1476
+ });
1477
+ }
1478
+ async getFeatureFlagStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
1479
+ await this._initPromise;
1480
+ const flagDetailResponse = await this.getFeatureFlagDetailStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
1481
+ if (flagDetailResponse === undefined) {
1482
+ // If we haven't loaded flags yet, or errored out, we respond with undefined
1483
+ return {
1484
+ response: undefined,
1485
+ requestId: undefined,
1486
+ };
1487
+ }
1488
+ let response = getFeatureFlagValue(flagDetailResponse.response);
1489
+ if (response === undefined) {
1490
+ // For cases where the flag is unknown, return false
1491
+ response = false;
1492
+ }
1493
+ // If we have flags we either return the value (true or string) or false
1494
+ return {
1495
+ response,
1496
+ requestId: flagDetailResponse.requestId,
1497
+ };
1498
+ }
1499
+ async getFeatureFlagDetailStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
1500
+ await this._initPromise;
1501
+ const decideResponse = await this.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [key]);
1502
+ if (decideResponse === undefined) {
1503
+ return undefined;
1504
+ }
1505
+ const featureFlags = decideResponse.flags;
1506
+ const flagDetail = featureFlags[key];
1507
+ return {
1508
+ response: flagDetail,
1509
+ requestId: decideResponse.requestId,
1510
+ };
1511
+ }
1512
+ async getFeatureFlagPayloadStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
1513
+ await this._initPromise;
1514
+ const payloads = await this.getFeatureFlagPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [key]);
1515
+ if (!payloads) {
1516
+ return undefined;
1517
+ }
1518
+ const response = payloads[key];
1519
+ // Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
1520
+ if (response === undefined) {
1521
+ return null;
1522
+ }
1523
+ return response;
1524
+ }
1525
+ async getFeatureFlagPayloadsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
1526
+ await this._initPromise;
1527
+ const payloads = (await this.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, flagKeysToEvaluate)).payloads;
1528
+ return payloads;
1529
+ }
1530
+ async getFeatureFlagsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
1531
+ await this._initPromise;
1532
+ return await this.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, flagKeysToEvaluate);
1533
+ }
1534
+ async getFeatureFlagsAndPayloadsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
1535
+ await this._initPromise;
1536
+ const featureFlagDetails = await this.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, flagKeysToEvaluate);
1537
+ if (!featureFlagDetails) {
1538
+ return {
1539
+ flags: undefined,
1540
+ payloads: undefined,
1541
+ requestId: undefined,
1542
+ };
1543
+ }
1544
+ return {
1545
+ flags: featureFlagDetails.featureFlags,
1546
+ payloads: featureFlagDetails.featureFlagPayloads,
1547
+ requestId: featureFlagDetails.requestId,
1548
+ };
1549
+ }
1550
+ async getFeatureFlagDetailsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
1551
+ var _a;
1552
+ await this._initPromise;
1553
+ const extraPayload = {};
1554
+ if (disableGeoip !== null && disableGeoip !== void 0 ? disableGeoip : this.disableGeoip) {
1555
+ extraPayload['geoip_disable'] = true;
1556
+ }
1557
+ if (flagKeysToEvaluate) {
1558
+ extraPayload['flag_keys_to_evaluate'] = flagKeysToEvaluate;
1559
+ }
1560
+ const decideResponse = await this.getDecide(distinctId, groups, personProperties, groupProperties, extraPayload);
1561
+ if (decideResponse === undefined) {
1562
+ // We probably errored out, so return undefined
1563
+ return undefined;
1564
+ }
1565
+ // if there's an error on the decideResponse, log a console error, but don't throw an error
1566
+ if (decideResponse.errorsWhileComputingFlags) {
1567
+ console.error('[FEATURE FLAGS] Error while computing feature flags, some flags may be missing or incorrect. Learn more at https://posthog.com/docs/feature-flags/best-practices');
1568
+ }
1569
+ // Add check for quota limitation on feature flags
1570
+ if ((_a = decideResponse.quotaLimited) === null || _a === void 0 ? void 0 : _a.includes(QuotaLimitedFeature.FeatureFlags)) {
1571
+ console.warn('[FEATURE FLAGS] Feature flags quota limit exceeded - feature flags unavailable. Learn more about billing limits at https://posthog.com/docs/billing/limits-alerts');
1572
+ return {
1573
+ flags: {},
1574
+ featureFlags: {},
1575
+ featureFlagPayloads: {},
1576
+ requestId: decideResponse === null || decideResponse === void 0 ? void 0 : decideResponse.requestId,
1577
+ };
1578
+ }
1579
+ return decideResponse;
1580
+ }
1581
+ /***
1582
+ *** SURVEYS
1583
+ ***/
1584
+ async getSurveysStateless() {
1585
+ await this._initPromise;
1586
+ if (this.disableSurveys === true) {
1587
+ this.logMsgIfDebug(() => console.log('Loading surveys is disabled.'));
1588
+ return [];
1589
+ }
1590
+ const url = `${this.host}/api/surveys/?token=${this.apiKey}`;
1591
+ const fetchOptions = {
1592
+ method: 'GET',
1593
+ headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
1594
+ };
1595
+ const response = await this.fetchWithRetry(url, fetchOptions)
1596
+ .then((response) => {
1597
+ if (response.status !== 200 || !response.json) {
1598
+ const msg = `Surveys API could not be loaded: ${response.status}`;
1599
+ const error = new Error(msg);
1600
+ this.logMsgIfDebug(() => console.error(error));
1601
+ this._events.emit('error', new Error(msg));
1602
+ return undefined;
1603
+ }
1604
+ return response.json();
1605
+ })
1606
+ .catch((error) => {
1607
+ this.logMsgIfDebug(() => console.error('Surveys API could not be loaded', error));
1608
+ this._events.emit('error', error);
1609
+ return undefined;
1610
+ });
1611
+ const newSurveys = response === null || response === void 0 ? void 0 : response.surveys;
1612
+ if (newSurveys) {
1613
+ this.logMsgIfDebug(() => console.log('PostHog Debug', 'Surveys fetched from API: ', JSON.stringify(newSurveys)));
1614
+ }
1615
+ return newSurveys !== null && newSurveys !== void 0 ? newSurveys : [];
1616
+ }
1617
+ /***
1618
+ *** QUEUEING AND FLUSHING
1619
+ ***/
1620
+ enqueue(type, _message, options) {
1621
+ this.wrap(() => {
1622
+ var _a;
1623
+ if (this.optedOut) {
1624
+ this._events.emit(type, `Library is disabled. Not sending event. To re-enable, call posthog.optIn()`);
1625
+ return;
1626
+ }
1627
+ const message = {
1628
+ ..._message,
1629
+ type: type,
1630
+ library: this.getLibraryId(),
1631
+ library_version: this.getLibraryVersion(),
1632
+ timestamp: (options === null || options === void 0 ? void 0 : options.timestamp) ? options === null || options === void 0 ? void 0 : options.timestamp : currentISOTime(),
1633
+ uuid: (options === null || options === void 0 ? void 0 : options.uuid) ? options.uuid : uuidv7(),
1634
+ };
1635
+ const addGeoipDisableProperty = (_a = options === null || options === void 0 ? void 0 : options.disableGeoip) !== null && _a !== void 0 ? _a : this.disableGeoip;
1636
+ if (addGeoipDisableProperty) {
1637
+ if (!message.properties) {
1638
+ message.properties = {};
1639
+ }
1640
+ message['properties']['$geoip_disable'] = true;
1641
+ }
1642
+ if (message.distinctId) {
1643
+ message.distinct_id = message.distinctId;
1644
+ delete message.distinctId;
1645
+ }
1646
+ const queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
1647
+ if (queue.length >= this.maxQueueSize) {
1648
+ queue.shift();
1649
+ this.logMsgIfDebug(() => console.info('Queue is full, the oldest event is dropped.'));
1650
+ }
1651
+ queue.push({ message });
1652
+ this.setPersistedProperty(PostHogPersistedProperty.Queue, queue);
1653
+ this._events.emit(type, message);
1654
+ // Flush queued events if we meet the flushAt length
1655
+ if (queue.length >= this.flushAt) {
1656
+ this.flushBackground();
1657
+ }
1658
+ if (this.flushInterval && !this._flushTimer) {
1659
+ this._flushTimer = safeSetTimeout(() => this.flushBackground(), this.flushInterval);
1660
+ }
1661
+ });
1662
+ }
1663
+ clearFlushTimer() {
1664
+ if (this._flushTimer) {
1665
+ clearTimeout(this._flushTimer);
1666
+ this._flushTimer = undefined;
1667
+ }
1668
+ }
1669
+ /**
1670
+ * Helper for flushing the queue in the background
1671
+ * Avoids unnecessary promise errors
1672
+ */
1673
+ flushBackground() {
1674
+ void this.flush().catch(() => { });
1675
+ }
1676
+ async flush() {
1677
+ if (!this.flushPromise) {
1678
+ this.flushPromise = this._flush().finally(() => {
1679
+ this.flushPromise = null;
1680
+ });
1681
+ this.addPendingPromise(this.flushPromise);
1682
+ }
1683
+ return this.flushPromise;
1684
+ }
1685
+ getCustomHeaders() {
1686
+ // Don't set the user agent if we're not on a browser. The latest spec allows
1687
+ // the User-Agent header (see https://fetch.spec.whatwg.org/#terminology-headers
1688
+ // and https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader),
1689
+ // but browsers such as Chrome and Safari have not caught up.
1690
+ const customUserAgent = this.getCustomUserAgent();
1691
+ const headers = {};
1692
+ if (customUserAgent && customUserAgent !== '') {
1693
+ headers['User-Agent'] = customUserAgent;
1694
+ }
1695
+ return headers;
1696
+ }
1697
+ async _flush() {
1698
+ this.clearFlushTimer();
1699
+ await this._initPromise;
1700
+ const queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
1701
+ if (!queue.length) {
1702
+ return [];
1703
+ }
1704
+ const items = queue.slice(0, this.maxBatchSize);
1705
+ const messages = items.map((item) => item.message);
1706
+ const persistQueueChange = () => {
1707
+ const refreshedQueue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
1708
+ this.setPersistedProperty(PostHogPersistedProperty.Queue, refreshedQueue.slice(items.length));
1709
+ };
1710
+ const data = {
1711
+ api_key: this.apiKey,
1712
+ batch: messages,
1713
+ sent_at: currentISOTime(),
1714
+ };
1715
+ if (this.historicalMigration) {
1716
+ data.historical_migration = true;
1717
+ }
1718
+ const payload = JSON.stringify(data);
1719
+ const url = this.captureMode === 'form'
1720
+ ? `${this.host}/e/?ip=1&_=${currentTimestamp()}&v=${this.getLibraryVersion()}`
1721
+ : `${this.host}/batch/`;
1722
+ const fetchOptions = this.captureMode === 'form'
1723
+ ? {
1724
+ method: 'POST',
1725
+ mode: 'no-cors',
1726
+ credentials: 'omit',
1727
+ headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/x-www-form-urlencoded' },
1728
+ body: `data=${encodeURIComponent(LZString.compressToBase64(payload))}&compression=lz64`,
1729
+ }
1730
+ : {
1731
+ method: 'POST',
1732
+ headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
1733
+ body: payload,
1734
+ };
1735
+ try {
1736
+ await this.fetchWithRetry(url, fetchOptions);
1737
+ }
1738
+ catch (err) {
1739
+ // depending on the error type, eg a malformed JSON or broken queue, it'll always return an error
1740
+ // and this will be an endless loop, in this case, if the error isn't a network issue, we always remove the items from the queue
1741
+ if (!(err instanceof PostHogFetchNetworkError)) {
1742
+ persistQueueChange();
1743
+ }
1744
+ this._events.emit('error', err);
1745
+ throw err;
1746
+ }
1747
+ persistQueueChange();
1748
+ this._events.emit('flush', messages);
1749
+ return messages;
1750
+ }
1751
+ async fetchWithRetry(url, options, retryOptions, requestTimeout) {
1752
+ var _a;
1753
+ var _b;
1754
+ (_a = (_b = AbortSignal).timeout) !== null && _a !== void 0 ? _a : (_b.timeout = function timeout(ms) {
1755
+ const ctrl = new AbortController();
1756
+ setTimeout(() => ctrl.abort(), ms);
1757
+ return ctrl.signal;
1758
+ });
1759
+ return await retriable(async () => {
1760
+ let res = null;
1761
+ try {
1762
+ res = await this.fetch(url, {
1763
+ signal: AbortSignal.timeout(requestTimeout !== null && requestTimeout !== void 0 ? requestTimeout : this.requestTimeout),
1764
+ ...options,
1765
+ });
1766
+ }
1767
+ catch (e) {
1768
+ // fetch will only throw on network errors or on timeouts
1769
+ throw new PostHogFetchNetworkError(e);
1770
+ }
1771
+ // If we're in no-cors mode, we can't access the response status
1772
+ // We only throw on HTTP errors if we're not in no-cors mode
1773
+ // https://developer.mozilla.org/en-US/docs/Web/API/Request/mode#no-cors
1774
+ const isNoCors = options.mode === 'no-cors';
1775
+ if (!isNoCors && (res.status < 200 || res.status >= 400)) {
1776
+ throw new PostHogFetchHttpError(res);
1777
+ }
1778
+ return res;
1779
+ }, { ...this._retryOptions, ...retryOptions });
1780
+ }
1781
+ async shutdown(shutdownTimeoutMs = 30000) {
1782
+ // A little tricky - we want to have a max shutdown time and enforce it, even if that means we have some
1783
+ // dangling promises. We'll keep track of the timeout and resolve/reject based on that.
1784
+ await this._initPromise;
1785
+ let hasTimedOut = false;
1786
+ this.clearFlushTimer();
1787
+ const doShutdown = async () => {
1788
+ try {
1789
+ await Promise.all(Object.values(this.pendingPromises));
1790
+ while (true) {
1791
+ const queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
1792
+ if (queue.length === 0) {
1793
+ break;
1794
+ }
1795
+ // flush again to make sure we send all events, some of which might've been added
1796
+ // while we were waiting for the pending promises to resolve
1797
+ // For example, see sendFeatureFlags in posthog-node/src/posthog-node.ts::capture
1798
+ await this.flush();
1799
+ if (hasTimedOut) {
1800
+ break;
1801
+ }
1802
+ }
1803
+ }
1804
+ catch (e) {
1805
+ if (!isPostHogFetchError(e)) {
1806
+ throw e;
1807
+ }
1808
+ this.logMsgIfDebug(() => console.error('Error while shutting down PostHog', e));
1809
+ }
1810
+ };
1811
+ return Promise.race([
1812
+ new Promise((_, reject) => {
1813
+ safeSetTimeout(() => {
1814
+ this.logMsgIfDebug(() => console.error('Timed out while shutting down PostHog'));
1815
+ hasTimedOut = true;
1816
+ reject('Timeout while shutting down PostHog. Some events may not have been sent.');
1817
+ }, shutdownTimeoutMs);
1818
+ }),
1819
+ doShutdown(),
1820
+ ]);
1821
+ }
1822
+ }
1823
+ class PostHogCore extends PostHogCoreStateless {
1824
+ constructor(apiKey, options) {
1825
+ var _a, _b, _c, _d;
1826
+ // Default for stateful mode is to not disable geoip. Only override if explicitly set
1827
+ const disableGeoipOption = (_a = options === null || options === void 0 ? void 0 : options.disableGeoip) !== null && _a !== void 0 ? _a : false;
1828
+ // Default for stateful mode is to timeout at 10s. Only override if explicitly set
1829
+ const featureFlagsRequestTimeoutMs = (_b = options === null || options === void 0 ? void 0 : options.featureFlagsRequestTimeoutMs) !== null && _b !== void 0 ? _b : 10000; // 10 seconds
1830
+ super(apiKey, { ...options, disableGeoip: disableGeoipOption, featureFlagsRequestTimeoutMs });
1831
+ this.flagCallReported = {};
1832
+ this.sessionProps = {};
1833
+ this.sendFeatureFlagEvent = (_c = options === null || options === void 0 ? void 0 : options.sendFeatureFlagEvent) !== null && _c !== void 0 ? _c : true;
1834
+ this._sessionExpirationTimeSeconds = (_d = options === null || options === void 0 ? void 0 : options.sessionExpirationTimeSeconds) !== null && _d !== void 0 ? _d : 1800; // 30 minutes
1835
+ }
1836
+ setupBootstrap(options) {
1837
+ var _a;
1838
+ const bootstrap = options === null || options === void 0 ? void 0 : options.bootstrap;
1839
+ if (!bootstrap) {
1840
+ return;
1841
+ }
1842
+ // bootstrap options are only set if no persisted values are found
1843
+ // this is to prevent overwriting existing values
1844
+ if (bootstrap.distinctId) {
1845
+ if (bootstrap.isIdentifiedId) {
1846
+ const distinctId = this.getPersistedProperty(PostHogPersistedProperty.DistinctId);
1847
+ if (!distinctId) {
1848
+ this.setPersistedProperty(PostHogPersistedProperty.DistinctId, bootstrap.distinctId);
1849
+ }
1850
+ }
1851
+ else {
1852
+ const anonymousId = this.getPersistedProperty(PostHogPersistedProperty.AnonymousId);
1853
+ if (!anonymousId) {
1854
+ this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, bootstrap.distinctId);
1855
+ }
1856
+ }
1857
+ }
1858
+ const bootstrapFeatureFlags = bootstrap.featureFlags;
1859
+ const bootstrapFeatureFlagPayloads = (_a = bootstrap.featureFlagPayloads) !== null && _a !== void 0 ? _a : {};
1860
+ if (bootstrapFeatureFlags && Object.keys(bootstrapFeatureFlags).length) {
1861
+ const normalizedBootstrapFeatureFlagDetails = createDecideResponseFromFlagsAndPayloads(bootstrapFeatureFlags, bootstrapFeatureFlagPayloads);
1862
+ if (Object.keys(normalizedBootstrapFeatureFlagDetails.flags).length > 0) {
1863
+ this.setBootstrappedFeatureFlagDetails(normalizedBootstrapFeatureFlagDetails);
1864
+ const currentFeatureFlagDetails = this.getKnownFeatureFlagDetails() || { flags: {}, requestId: undefined };
1865
+ const newFeatureFlagDetails = {
1866
+ flags: {
1867
+ ...normalizedBootstrapFeatureFlagDetails.flags,
1868
+ ...currentFeatureFlagDetails.flags,
1869
+ },
1870
+ requestId: normalizedBootstrapFeatureFlagDetails.requestId,
1871
+ };
1872
+ this.setKnownFeatureFlagDetails(newFeatureFlagDetails);
1873
+ }
1874
+ }
1875
+ }
1876
+ // NOTE: Props are lazy loaded from localstorage hence the complex getter setter logic
1877
+ get props() {
1878
+ if (!this._props) {
1879
+ this._props = this.getPersistedProperty(PostHogPersistedProperty.Props);
1880
+ }
1881
+ return this._props || {};
1882
+ }
1883
+ set props(val) {
1884
+ this._props = val;
1885
+ }
1886
+ clearProps() {
1887
+ this.props = undefined;
1888
+ this.sessionProps = {};
1889
+ this.flagCallReported = {};
1890
+ }
1891
+ on(event, cb) {
1892
+ return this._events.on(event, cb);
1893
+ }
1894
+ reset(propertiesToKeep) {
1895
+ this.wrap(() => {
1896
+ const allPropertiesToKeep = [PostHogPersistedProperty.Queue, ...(propertiesToKeep || [])];
1897
+ // clean up props
1898
+ this.clearProps();
1899
+ for (const key of Object.keys(PostHogPersistedProperty)) {
1900
+ if (!allPropertiesToKeep.includes(PostHogPersistedProperty[key])) {
1901
+ this.setPersistedProperty(PostHogPersistedProperty[key], null);
1902
+ }
1903
+ }
1904
+ this.reloadFeatureFlags();
1905
+ });
1906
+ }
1907
+ getCommonEventProperties() {
1908
+ const featureFlags = this.getFeatureFlags();
1909
+ const featureVariantProperties = {};
1910
+ if (featureFlags) {
1911
+ for (const [feature, variant] of Object.entries(featureFlags)) {
1912
+ featureVariantProperties[`$feature/${feature}`] = variant;
1913
+ }
1914
+ }
1915
+ return {
1916
+ $active_feature_flags: featureFlags ? Object.keys(featureFlags) : undefined,
1917
+ ...featureVariantProperties,
1918
+ ...super.getCommonEventProperties(),
1919
+ };
1920
+ }
1921
+ enrichProperties(properties) {
1922
+ return {
1923
+ ...this.props,
1924
+ ...this.sessionProps,
1925
+ ...(properties || {}),
1926
+ ...this.getCommonEventProperties(),
1927
+ $session_id: this.getSessionId(),
1928
+ };
1929
+ }
1930
+ /**
1931
+ * * @returns {string} The stored session ID for the current session. This may be an empty string if the client is not yet fully initialized.
1932
+ */
1933
+ getSessionId() {
1934
+ if (!this._isInitialized) {
1935
+ return '';
1936
+ }
1937
+ let sessionId = this.getPersistedProperty(PostHogPersistedProperty.SessionId);
1938
+ const sessionTimestamp = this.getPersistedProperty(PostHogPersistedProperty.SessionLastTimestamp) || 0;
1939
+ if (!sessionId || Date.now() - sessionTimestamp > this._sessionExpirationTimeSeconds * 1000) {
1940
+ sessionId = uuidv7();
1941
+ this.setPersistedProperty(PostHogPersistedProperty.SessionId, sessionId);
1942
+ }
1943
+ this.setPersistedProperty(PostHogPersistedProperty.SessionLastTimestamp, Date.now());
1944
+ return sessionId;
1945
+ }
1946
+ resetSessionId() {
1947
+ this.wrap(() => {
1948
+ this.setPersistedProperty(PostHogPersistedProperty.SessionId, null);
1949
+ this.setPersistedProperty(PostHogPersistedProperty.SessionLastTimestamp, null);
1950
+ });
1951
+ }
1952
+ /**
1953
+ * * @returns {string} The stored anonymous ID. This may be an empty string if the client is not yet fully initialized.
1954
+ */
1955
+ getAnonymousId() {
1956
+ if (!this._isInitialized) {
1957
+ return '';
1958
+ }
1959
+ let anonId = this.getPersistedProperty(PostHogPersistedProperty.AnonymousId);
1960
+ if (!anonId) {
1961
+ anonId = uuidv7();
1962
+ this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, anonId);
1963
+ }
1964
+ return anonId;
1965
+ }
1966
+ /**
1967
+ * * @returns {string} The stored distinct ID. This may be an empty string if the client is not yet fully initialized.
1968
+ */
1969
+ getDistinctId() {
1970
+ if (!this._isInitialized) {
1971
+ return '';
1972
+ }
1973
+ return this.getPersistedProperty(PostHogPersistedProperty.DistinctId) || this.getAnonymousId();
1974
+ }
1975
+ async unregister(property) {
1976
+ this.wrap(() => {
1977
+ delete this.props[property];
1978
+ this.setPersistedProperty(PostHogPersistedProperty.Props, this.props);
1979
+ });
1980
+ }
1981
+ async register(properties) {
1982
+ this.wrap(() => {
1983
+ this.props = {
1984
+ ...this.props,
1985
+ ...properties,
1986
+ };
1987
+ this.setPersistedProperty(PostHogPersistedProperty.Props, this.props);
1988
+ });
1989
+ }
1990
+ registerForSession(properties) {
1991
+ this.sessionProps = {
1992
+ ...this.sessionProps,
1993
+ ...properties,
1994
+ };
1995
+ }
1996
+ unregisterForSession(property) {
1997
+ delete this.sessionProps[property];
1998
+ }
1999
+ /***
2000
+ *** TRACKING
2001
+ ***/
2002
+ identify(distinctId, properties, options) {
2003
+ this.wrap(() => {
2004
+ const previousDistinctId = this.getDistinctId();
2005
+ distinctId = distinctId || previousDistinctId;
2006
+ if (properties === null || properties === void 0 ? void 0 : properties.$groups) {
2007
+ this.groups(properties.$groups);
2008
+ }
2009
+ // promote $set and $set_once to top level
2010
+ const userPropsOnce = properties === null || properties === void 0 ? void 0 : properties.$set_once;
2011
+ properties === null || properties === void 0 ? true : delete properties.$set_once;
2012
+ // if no $set is provided we assume all properties are $set
2013
+ const userProps = (properties === null || properties === void 0 ? void 0 : properties.$set) || properties;
2014
+ const allProperties = this.enrichProperties({
2015
+ $anon_distinct_id: this.getAnonymousId(),
2016
+ $set: userProps,
2017
+ $set_once: userPropsOnce,
2018
+ });
2019
+ if (distinctId !== previousDistinctId) {
2020
+ // We keep the AnonymousId to be used by decide calls and identify to link the previousId
2021
+ this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, previousDistinctId);
2022
+ this.setPersistedProperty(PostHogPersistedProperty.DistinctId, distinctId);
2023
+ this.reloadFeatureFlags();
2024
+ }
2025
+ super.identifyStateless(distinctId, allProperties, options);
2026
+ });
2027
+ }
2028
+ capture(event, properties, options) {
2029
+ this.wrap(() => {
2030
+ const distinctId = this.getDistinctId();
2031
+ if (properties === null || properties === void 0 ? void 0 : properties.$groups) {
2032
+ this.groups(properties.$groups);
2033
+ }
2034
+ const allProperties = this.enrichProperties(properties);
2035
+ super.captureStateless(distinctId, event, allProperties, options);
2036
+ });
2037
+ }
2038
+ alias(alias) {
2039
+ this.wrap(() => {
2040
+ const distinctId = this.getDistinctId();
2041
+ const allProperties = this.enrichProperties({});
2042
+ super.aliasStateless(alias, distinctId, allProperties);
2043
+ });
2044
+ }
2045
+ autocapture(eventType, elements, properties = {}, options) {
2046
+ this.wrap(() => {
2047
+ const distinctId = this.getDistinctId();
2048
+ const payload = {
2049
+ distinct_id: distinctId,
2050
+ event: '$autocapture',
2051
+ properties: {
2052
+ ...this.enrichProperties(properties),
2053
+ $event_type: eventType,
2054
+ $elements: elements,
2055
+ },
2056
+ };
2057
+ this.enqueue('autocapture', payload, options);
2058
+ });
2059
+ }
2060
+ /***
2061
+ *** GROUPS
2062
+ ***/
2063
+ groups(groups) {
2064
+ this.wrap(() => {
2065
+ // Get persisted groups
2066
+ const existingGroups = this.props.$groups || {};
2067
+ this.register({
2068
+ $groups: {
2069
+ ...existingGroups,
2070
+ ...groups,
2071
+ },
2072
+ });
2073
+ if (Object.keys(groups).find((type) => existingGroups[type] !== groups[type])) {
2074
+ this.reloadFeatureFlags();
2075
+ }
2076
+ });
2077
+ }
2078
+ group(groupType, groupKey, groupProperties, options) {
2079
+ this.wrap(() => {
2080
+ this.groups({
2081
+ [groupType]: groupKey,
2082
+ });
2083
+ if (groupProperties) {
2084
+ this.groupIdentify(groupType, groupKey, groupProperties, options);
2085
+ }
2086
+ });
2087
+ }
2088
+ groupIdentify(groupType, groupKey, groupProperties, options) {
2089
+ this.wrap(() => {
2090
+ const distinctId = this.getDistinctId();
2091
+ const eventProperties = this.enrichProperties({});
2092
+ super.groupIdentifyStateless(groupType, groupKey, groupProperties, options, distinctId, eventProperties);
2093
+ });
2094
+ }
2095
+ /***
2096
+ * PROPERTIES
2097
+ ***/
2098
+ setPersonPropertiesForFlags(properties) {
2099
+ this.wrap(() => {
2100
+ // Get persisted person properties
2101
+ const existingProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
2102
+ this.setPersistedProperty(PostHogPersistedProperty.PersonProperties, {
2103
+ ...existingProperties,
2104
+ ...properties,
2105
+ });
2106
+ });
2107
+ }
2108
+ resetPersonPropertiesForFlags() {
2109
+ this.wrap(() => {
2110
+ this.setPersistedProperty(PostHogPersistedProperty.PersonProperties, null);
2111
+ });
2112
+ }
2113
+ /** @deprecated - Renamed to setPersonPropertiesForFlags */
2114
+ personProperties(properties) {
2115
+ return this.setPersonPropertiesForFlags(properties);
2116
+ }
2117
+ setGroupPropertiesForFlags(properties) {
2118
+ this.wrap(() => {
2119
+ // Get persisted group properties
2120
+ const existingProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) ||
2121
+ {};
2122
+ if (Object.keys(existingProperties).length !== 0) {
2123
+ Object.keys(existingProperties).forEach((groupType) => {
2124
+ existingProperties[groupType] = {
2125
+ ...existingProperties[groupType],
2126
+ ...properties[groupType],
2127
+ };
2128
+ delete properties[groupType];
2129
+ });
2130
+ }
2131
+ this.setPersistedProperty(PostHogPersistedProperty.GroupProperties, {
2132
+ ...existingProperties,
2133
+ ...properties,
2134
+ });
2135
+ });
2136
+ }
2137
+ resetGroupPropertiesForFlags() {
2138
+ this.wrap(() => {
2139
+ this.setPersistedProperty(PostHogPersistedProperty.GroupProperties, null);
2140
+ });
2141
+ }
2142
+ /** @deprecated - Renamed to setGroupPropertiesForFlags */
2143
+ groupProperties(properties) {
2144
+ this.wrap(() => {
2145
+ this.setGroupPropertiesForFlags(properties);
2146
+ });
2147
+ }
2148
+ async remoteConfigAsync() {
2149
+ await this._initPromise;
2150
+ if (this._remoteConfigResponsePromise) {
2151
+ return this._remoteConfigResponsePromise;
2152
+ }
2153
+ return this._remoteConfigAsync();
2154
+ }
2155
+ /***
2156
+ *** FEATURE FLAGS
2157
+ ***/
2158
+ async decideAsync(sendAnonDistinctId = true) {
2159
+ await this._initPromise;
2160
+ if (this._decideResponsePromise) {
2161
+ return this._decideResponsePromise;
2162
+ }
2163
+ return this._decideAsync(sendAnonDistinctId);
2164
+ }
2165
+ cacheSessionReplay(response) {
2166
+ const sessionReplay = response === null || response === void 0 ? void 0 : response.sessionRecording;
2167
+ if (sessionReplay) {
2168
+ this.setPersistedProperty(PostHogPersistedProperty.SessionReplay, sessionReplay);
2169
+ this.logMsgIfDebug(() => console.log('PostHog Debug', 'Session replay config: ', JSON.stringify(sessionReplay)));
2170
+ }
2171
+ else {
2172
+ this.logMsgIfDebug(() => console.info('PostHog Debug', 'Session replay config disabled.'));
2173
+ this.setPersistedProperty(PostHogPersistedProperty.SessionReplay, null);
2174
+ }
2175
+ }
2176
+ async _remoteConfigAsync() {
2177
+ this._remoteConfigResponsePromise = this._initPromise
2178
+ .then(() => {
2179
+ let remoteConfig = this.getPersistedProperty(PostHogPersistedProperty.RemoteConfig);
2180
+ this.logMsgIfDebug(() => console.log('PostHog Debug', 'Cached remote config: ', JSON.stringify(remoteConfig)));
2181
+ return super.getRemoteConfig().then((response) => {
2182
+ if (response) {
2183
+ const remoteConfigWithoutSurveys = { ...response };
2184
+ delete remoteConfigWithoutSurveys.surveys;
2185
+ this.logMsgIfDebug(() => console.log('PostHog Debug', 'Fetched remote config: ', JSON.stringify(remoteConfigWithoutSurveys)));
2186
+ const surveys = response.surveys;
2187
+ let hasSurveys = true;
2188
+ if (!Array.isArray(surveys)) {
2189
+ // If surveys is not an array, it means there are no surveys (its a boolean instead)
2190
+ this.logMsgIfDebug(() => console.log('PostHog Debug', 'There are no surveys.'));
2191
+ hasSurveys = false;
2192
+ }
2193
+ else {
2194
+ this.logMsgIfDebug(() => console.log('PostHog Debug', 'Surveys fetched from remote config: ', JSON.stringify(surveys)));
2195
+ }
2196
+ if (this.disableSurveys === false && hasSurveys) {
2197
+ this.setPersistedProperty(PostHogPersistedProperty.Surveys, surveys);
2198
+ }
2199
+ else {
2200
+ this.setPersistedProperty(PostHogPersistedProperty.Surveys, null);
2201
+ }
2202
+ // we cache the surveys in its own storage key
2203
+ this.setPersistedProperty(PostHogPersistedProperty.RemoteConfig, remoteConfigWithoutSurveys);
2204
+ this.cacheSessionReplay(response);
2205
+ // we only dont load flags if the remote config has no feature flags
2206
+ if (response.hasFeatureFlags === false) {
2207
+ // resetting flags to empty object
2208
+ this.setKnownFeatureFlagDetails({ flags: {} });
2209
+ this.logMsgIfDebug(() => console.warn('Remote config has no feature flags, will not load feature flags.'));
2210
+ }
2211
+ else if (this.preloadFeatureFlags !== false) {
2212
+ this.reloadFeatureFlags();
2213
+ }
2214
+ remoteConfig = response;
2215
+ }
2216
+ return remoteConfig;
2217
+ });
2218
+ })
2219
+ .finally(() => {
2220
+ this._remoteConfigResponsePromise = undefined;
2221
+ });
2222
+ return this._remoteConfigResponsePromise;
2223
+ }
2224
+ async _decideAsync(sendAnonDistinctId = true) {
2225
+ this._decideResponsePromise = this._initPromise
2226
+ .then(async () => {
2227
+ var _a;
2228
+ const distinctId = this.getDistinctId();
2229
+ const groups = this.props.$groups || {};
2230
+ const personProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
2231
+ const groupProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) ||
2232
+ {};
2233
+ const extraProperties = {
2234
+ $anon_distinct_id: sendAnonDistinctId ? this.getAnonymousId() : undefined,
2235
+ };
2236
+ const res = await super.getDecide(distinctId, groups, personProperties, groupProperties, extraProperties);
2237
+ // Add check for quota limitation on feature flags
2238
+ if ((_a = res === null || res === void 0 ? void 0 : res.quotaLimited) === null || _a === void 0 ? void 0 : _a.includes(QuotaLimitedFeature.FeatureFlags)) {
2239
+ // Unset all feature flags by setting to null
2240
+ this.setKnownFeatureFlagDetails(null);
2241
+ console.warn('[FEATURE FLAGS] Feature flags quota limit exceeded - unsetting all flags. Learn more about billing limits at https://posthog.com/docs/billing/limits-alerts');
2242
+ return res;
2243
+ }
2244
+ if (res === null || res === void 0 ? void 0 : res.featureFlags) {
2245
+ // clear flag call reported if we have new flags since they might have changed
2246
+ if (this.sendFeatureFlagEvent) {
2247
+ this.flagCallReported = {};
2248
+ }
2249
+ let newFeatureFlagDetails = res;
2250
+ if (res.errorsWhileComputingFlags) {
2251
+ // if not all flags were computed, we upsert flags instead of replacing them
2252
+ const currentFlagDetails = this.getKnownFeatureFlagDetails();
2253
+ this.logMsgIfDebug(() => console.log('PostHog Debug', 'Cached feature flags: ', JSON.stringify(currentFlagDetails)));
2254
+ newFeatureFlagDetails = {
2255
+ ...res,
2256
+ flags: { ...currentFlagDetails === null || currentFlagDetails === void 0 ? void 0 : currentFlagDetails.flags, ...res.flags },
2257
+ };
2258
+ }
2259
+ this.setKnownFeatureFlagDetails(newFeatureFlagDetails);
2260
+ // Mark that we hit the /decide endpoint so we can capture this in the $feature_flag_called event
2261
+ this.setPersistedProperty(PostHogPersistedProperty.DecideEndpointWasHit, true);
2262
+ this.cacheSessionReplay(res);
2263
+ }
2264
+ return res;
2265
+ })
2266
+ .finally(() => {
2267
+ this._decideResponsePromise = undefined;
2268
+ });
2269
+ return this._decideResponsePromise;
2270
+ }
2271
+ // We only store the flags and request id in the feature flag details storage key
2272
+ setKnownFeatureFlagDetails(decideResponse) {
2273
+ this.wrap(() => {
2274
+ var _a;
2275
+ this.setPersistedProperty(PostHogPersistedProperty.FeatureFlagDetails, decideResponse);
2276
+ this._events.emit('featureflags', getFlagValuesFromFlags((_a = decideResponse === null || decideResponse === void 0 ? void 0 : decideResponse.flags) !== null && _a !== void 0 ? _a : {}));
2277
+ });
2278
+ }
2279
+ getKnownFeatureFlagDetails() {
2280
+ const storedDetails = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlagDetails);
2281
+ if (!storedDetails) {
2282
+ // Rebuild from the stored feature flags and feature flag payloads
2283
+ const featureFlags = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlags);
2284
+ const featureFlagPayloads = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlagPayloads);
2285
+ if (featureFlags === undefined && featureFlagPayloads === undefined) {
2286
+ return undefined;
2287
+ }
2288
+ return createDecideResponseFromFlagsAndPayloads(featureFlags !== null && featureFlags !== void 0 ? featureFlags : {}, featureFlagPayloads !== null && featureFlagPayloads !== void 0 ? featureFlagPayloads : {});
2289
+ }
2290
+ return normalizeDecideResponse(storedDetails);
2291
+ }
2292
+ getKnownFeatureFlags() {
2293
+ const featureFlagDetails = this.getKnownFeatureFlagDetails();
2294
+ if (!featureFlagDetails) {
2295
+ return undefined;
2296
+ }
2297
+ return getFlagValuesFromFlags(featureFlagDetails.flags);
2298
+ }
2299
+ getKnownFeatureFlagPayloads() {
2300
+ const featureFlagDetails = this.getKnownFeatureFlagDetails();
2301
+ if (!featureFlagDetails) {
2302
+ return undefined;
2303
+ }
2304
+ return getPayloadsFromFlags(featureFlagDetails.flags);
2305
+ }
2306
+ getBootstrappedFeatureFlagDetails() {
2307
+ const details = this.getPersistedProperty(PostHogPersistedProperty.BootstrapFeatureFlagDetails);
2308
+ if (!details) {
2309
+ return undefined;
2310
+ }
2311
+ return details;
2312
+ }
2313
+ setBootstrappedFeatureFlagDetails(details) {
2314
+ this.setPersistedProperty(PostHogPersistedProperty.BootstrapFeatureFlagDetails, details);
2315
+ }
2316
+ getBootstrappedFeatureFlags() {
2317
+ const details = this.getBootstrappedFeatureFlagDetails();
2318
+ if (!details) {
2319
+ return undefined;
2320
+ }
2321
+ return getFlagValuesFromFlags(details.flags);
2322
+ }
2323
+ getBootstrappedFeatureFlagPayloads() {
2324
+ const details = this.getBootstrappedFeatureFlagDetails();
2325
+ if (!details) {
2326
+ return undefined;
2327
+ }
2328
+ return getPayloadsFromFlags(details.flags);
2329
+ }
2330
+ getFeatureFlag(key) {
2331
+ var _a, _b, _c, _d, _e, _f, _g;
2332
+ const details = this.getFeatureFlagDetails();
2333
+ if (!details) {
2334
+ // If we haven't loaded flags yet, or errored out, we respond with undefined
2335
+ return undefined;
2336
+ }
2337
+ const featureFlag = details.flags[key];
2338
+ let response = getFeatureFlagValue(featureFlag);
2339
+ if (response === undefined) {
2340
+ // For cases where the flag is unknown, return false
2341
+ response = false;
2342
+ }
2343
+ if (this.sendFeatureFlagEvent && !this.flagCallReported[key]) {
2344
+ const bootstrappedResponse = (_a = this.getBootstrappedFeatureFlags()) === null || _a === void 0 ? void 0 : _a[key];
2345
+ const bootstrappedPayload = (_b = this.getBootstrappedFeatureFlagPayloads()) === null || _b === void 0 ? void 0 : _b[key];
2346
+ this.flagCallReported[key] = true;
2347
+ this.capture('$feature_flag_called', {
2348
+ $feature_flag: key,
2349
+ $feature_flag_response: response,
2350
+ $feature_flag_id: (_c = featureFlag === null || featureFlag === void 0 ? void 0 : featureFlag.metadata) === null || _c === void 0 ? void 0 : _c.id,
2351
+ $feature_flag_version: (_d = featureFlag === null || featureFlag === void 0 ? void 0 : featureFlag.metadata) === null || _d === void 0 ? void 0 : _d.version,
2352
+ $feature_flag_reason: (_f = (_e = featureFlag === null || featureFlag === void 0 ? void 0 : featureFlag.reason) === null || _e === void 0 ? void 0 : _e.description) !== null && _f !== void 0 ? _f : (_g = featureFlag === null || featureFlag === void 0 ? void 0 : featureFlag.reason) === null || _g === void 0 ? void 0 : _g.code,
2353
+ $feature_flag_bootstrapped_response: bootstrappedResponse,
2354
+ $feature_flag_bootstrapped_payload: bootstrappedPayload,
2355
+ // If we haven't yet received a response from the /decide endpoint, we must have used the bootstrapped value
2356
+ $used_bootstrap_value: !this.getPersistedProperty(PostHogPersistedProperty.DecideEndpointWasHit),
2357
+ $feature_flag_request_id: details.requestId,
2358
+ });
2359
+ }
2360
+ // If we have flags we either return the value (true or string) or false
2361
+ return response;
2362
+ }
2363
+ getFeatureFlagPayload(key) {
2364
+ const payloads = this.getFeatureFlagPayloads();
2365
+ if (!payloads) {
2366
+ return undefined;
2367
+ }
2368
+ const response = payloads[key];
2369
+ // Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
2370
+ if (response === undefined) {
2371
+ return null;
2372
+ }
2373
+ return response;
2374
+ }
2375
+ getFeatureFlagPayloads() {
2376
+ var _a;
2377
+ return (_a = this.getFeatureFlagDetails()) === null || _a === void 0 ? void 0 : _a.featureFlagPayloads;
2378
+ }
2379
+ getFeatureFlags() {
2380
+ var _a;
2381
+ // NOTE: We don't check for _initPromise here as the function is designed to be
2382
+ // callable before the state being loaded anyways
2383
+ return (_a = this.getFeatureFlagDetails()) === null || _a === void 0 ? void 0 : _a.featureFlags;
2384
+ }
2385
+ getFeatureFlagDetails() {
2386
+ var _a;
2387
+ // NOTE: We don't check for _initPromise here as the function is designed to be
2388
+ // callable before the state being loaded anyways
2389
+ let details = this.getKnownFeatureFlagDetails();
2390
+ const overriddenFlags = this.getPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags);
2391
+ if (!overriddenFlags) {
2392
+ return details;
2393
+ }
2394
+ details = details !== null && details !== void 0 ? details : { featureFlags: {}, featureFlagPayloads: {}, flags: {} };
2395
+ const flags = (_a = details.flags) !== null && _a !== void 0 ? _a : {};
2396
+ for (const key in overriddenFlags) {
2397
+ if (!overriddenFlags[key]) {
2398
+ delete flags[key];
2399
+ }
2400
+ else {
2401
+ flags[key] = updateFlagValue(flags[key], overriddenFlags[key]);
2402
+ }
2403
+ }
2404
+ const result = {
2405
+ ...details,
2406
+ flags,
2407
+ };
2408
+ return normalizeDecideResponse(result);
2409
+ }
2410
+ getFeatureFlagsAndPayloads() {
2411
+ const flags = this.getFeatureFlags();
2412
+ const payloads = this.getFeatureFlagPayloads();
2413
+ return {
2414
+ flags,
2415
+ payloads,
2416
+ };
2417
+ }
2418
+ isFeatureEnabled(key) {
2419
+ const response = this.getFeatureFlag(key);
2420
+ if (response === undefined) {
2421
+ return undefined;
2422
+ }
2423
+ return !!response;
2424
+ }
2425
+ // Used when we want to trigger the reload but we don't care about the result
2426
+ reloadFeatureFlags(cb) {
2427
+ this.decideAsync()
2428
+ .then((res) => {
2429
+ cb === null || cb === void 0 ? void 0 : cb(undefined, res === null || res === void 0 ? void 0 : res.featureFlags);
2430
+ })
2431
+ .catch((e) => {
2432
+ cb === null || cb === void 0 ? void 0 : cb(e, undefined);
2433
+ if (!cb) {
2434
+ this.logMsgIfDebug(() => console.log('[PostHog] Error reloading feature flags', e));
2435
+ }
2436
+ });
2437
+ }
2438
+ async reloadRemoteConfigAsync() {
2439
+ return await this.remoteConfigAsync();
2440
+ }
2441
+ async reloadFeatureFlagsAsync(sendAnonDistinctId = true) {
2442
+ var _a;
2443
+ return (_a = (await this.decideAsync(sendAnonDistinctId))) === null || _a === void 0 ? void 0 : _a.featureFlags;
2444
+ }
2445
+ onFeatureFlags(cb) {
2446
+ return this.on('featureflags', async () => {
2447
+ const flags = this.getFeatureFlags();
2448
+ if (flags) {
2449
+ cb(flags);
2450
+ }
2451
+ });
2452
+ }
2453
+ onFeatureFlag(key, cb) {
2454
+ return this.on('featureflags', async () => {
2455
+ const flagResponse = this.getFeatureFlag(key);
2456
+ if (flagResponse !== undefined) {
2457
+ cb(flagResponse);
2458
+ }
2459
+ });
2460
+ }
2461
+ async overrideFeatureFlag(flags) {
2462
+ this.wrap(() => {
2463
+ if (flags === null) {
2464
+ return this.setPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags, null);
2465
+ }
2466
+ return this.setPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags, flags);
2467
+ });
2468
+ }
2469
+ /***
2470
+ *** ERROR TRACKING
2471
+ ***/
2472
+ captureException(error, additionalProperties) {
2473
+ const properties = {
2474
+ $exception_level: 'error',
2475
+ $exception_list: [
2476
+ {
2477
+ type: isError(error) ? error.name : 'Error',
2478
+ value: isError(error) ? error.message : error,
2479
+ mechanism: {
2480
+ handled: true,
2481
+ synthetic: false,
2482
+ },
2483
+ },
2484
+ ],
2485
+ ...additionalProperties,
2486
+ };
2487
+ properties.$exception_personURL = new URL(`/project/${this.apiKey}/person/${this.getDistinctId()}`, this.host).toString();
2488
+ this.capture('$exception', properties);
2489
+ }
2490
+ /**
2491
+ * Capture written user feedback for a LLM trace. Numeric values are converted to strings.
2492
+ * @param traceId The trace ID to capture feedback for.
2493
+ * @param userFeedback The feedback to capture.
2494
+ */
2495
+ captureTraceFeedback(traceId, userFeedback) {
2496
+ this.capture('$ai_feedback', {
2497
+ $ai_feedback_text: userFeedback,
2498
+ $ai_trace_id: String(traceId),
2499
+ });
2500
+ }
2501
+ /**
2502
+ * Capture a metric for a LLM trace. Numeric values are converted to strings.
2503
+ * @param traceId The trace ID to capture the metric for.
2504
+ * @param metricName The name of the metric to capture.
2505
+ * @param metricValue The value of the metric to capture.
2506
+ */
2507
+ captureTraceMetric(traceId, metricName, metricValue) {
2508
+ this.capture('$ai_metric', {
2509
+ $ai_metric_name: metricName,
2510
+ $ai_metric_value: String(metricValue),
2511
+ $ai_trace_id: String(traceId),
2512
+ });
2513
+ }
2514
+ }
2515
+
2516
+ let OptionalExpoApplication = undefined;
2517
+ try {
2518
+ // macos not supported
2519
+ OptionalExpoApplication = Platform.select({
2520
+ macos: undefined,
2521
+ default: require('expo-application')
2522
+ });
2523
+ } catch (e) {}
2524
+
2525
+ let OptionalExpoFileSystem = undefined;
2526
+ try {
2527
+ // do not try to load expo-file-system on web and macos, otherwise it will throw an error
2528
+ // Error: The method or property expo-file-system.writeAsStringAsync is not available on web
2529
+ // See https://github.com/PostHog/posthog-js-lite/issues/140
2530
+ // Once expo-file-system is supported on web/macos, we can remove this try/catch block
2531
+ // For now, use the react-native-async-storage/async-storage package instead
2532
+ OptionalExpoFileSystem = Platform.select({
2533
+ macos: undefined,
2534
+ web: undefined,
2535
+ default: require('expo-file-system')
2536
+ });
2537
+ } catch (e) {}
2538
+
2539
+ const getLegacyValues = async () => {
2540
+ // NOTE: The old react-native lib stored data in files on the filesystem.
2541
+ // This function takes care of pulling the legacy IDs to ensure we are using them if already present
2542
+ if (!OptionalExpoFileSystem || !OptionalExpoApplication) {
2543
+ return;
2544
+ }
2545
+ // legacy didn't support macos, no need to check it
2546
+ if (Platform.OS === 'ios') {
2547
+ const posthogFileDirectory = `${OptionalExpoFileSystem.documentDirectory}../Library/Application%20Support/${OptionalExpoApplication.applicationId}/`;
2548
+ const posthogDistinctIdFile = posthogFileDirectory + 'posthog.distinctId';
2549
+ const posthogAnonymousIdFile = posthogFileDirectory + 'posthog.anonymousId';
2550
+ const res = {
2551
+ distinctId: undefined,
2552
+ anonymousId: undefined
2553
+ };
2554
+ try {
2555
+ res.distinctId = JSON.parse(await OptionalExpoFileSystem.readAsStringAsync(posthogDistinctIdFile))['posthog.distinctId'];
2556
+ } catch (e) {}
2557
+ try {
2558
+ res.anonymousId = JSON.parse(await OptionalExpoFileSystem.readAsStringAsync(posthogAnonymousIdFile))['posthog.anonymousId'];
2559
+ } catch (e) {}
2560
+ return res;
2561
+ }
2562
+ };
2563
+
2564
+ const POSTHOG_STORAGE_KEY = '.posthog-rn.json';
2565
+ const POSTHOG_STORAGE_VERSION = 'v1';
2566
+ class PostHogRNStorage {
2567
+ constructor(storage) {
2568
+ var _a;
2569
+ this.memoryCache = {};
2570
+ this.storage = storage;
2571
+ const preloadResult = this.storage.getItem(POSTHOG_STORAGE_KEY);
2572
+ if (isPromise(preloadResult)) {
2573
+ this.preloadPromise = preloadResult.then(res => {
2574
+ this.populateMemoryCache(res);
2575
+ });
2576
+ (_a = this.preloadPromise) === null || _a === void 0 ? void 0 : _a.finally(() => {
2577
+ this.preloadPromise = undefined;
2578
+ });
2579
+ } else {
2580
+ this.populateMemoryCache(preloadResult);
2581
+ }
2582
+ }
2583
+ persist() {
2584
+ const payload = {
2585
+ version: POSTHOG_STORAGE_VERSION,
2586
+ content: this.memoryCache
2587
+ };
2588
+ void this.storage.setItem(POSTHOG_STORAGE_KEY, JSON.stringify(payload));
2589
+ }
2590
+ getItem(key) {
2591
+ return this.memoryCache[key];
2592
+ }
2593
+ setItem(key, value) {
2594
+ this.memoryCache[key] = value;
2595
+ this.persist();
2596
+ }
2597
+ removeItem(key) {
2598
+ delete this.memoryCache[key];
2599
+ this.persist();
2600
+ }
2601
+ clear() {
2602
+ for (const key in this.memoryCache) {
2603
+ delete this.memoryCache[key];
2604
+ }
2605
+ this.persist();
2606
+ }
2607
+ getAllKeys() {
2608
+ return Object.keys(this.memoryCache);
2609
+ }
2610
+ populateMemoryCache(res) {
2611
+ try {
2612
+ const data = res ? JSON.parse(res).content : {};
2613
+ for (const key in data) {
2614
+ this.memoryCache[key] = data[key];
2615
+ }
2616
+ } catch (e) {
2617
+ console.warn("PostHog failed to load persisted data from storage. This is likely because the storage format is. We'll reset the storage.", e);
2618
+ }
2619
+ }
2620
+ }
2621
+ class PostHogRNSyncMemoryStorage extends PostHogRNStorage {
2622
+ constructor() {
2623
+ const cache = {};
2624
+ const storage = {
2625
+ getItem: key => cache[key],
2626
+ setItem: (key, value) => {
2627
+ cache[key] = value;
2628
+ }
2629
+ };
2630
+ super(storage);
2631
+ }
2632
+ }
2633
+
2634
+ const version = "3.15.0";
2635
+
2636
+ let OptionalAsyncStorage = undefined;
2637
+ try {
2638
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
2639
+ OptionalAsyncStorage = require('@react-native-async-storage/async-storage').default;
2640
+ } catch (e) {}
2641
+
2642
+ let OptionalExpoDevice = undefined;
2643
+ try {
2644
+ // macos not supported
2645
+ OptionalExpoDevice = Platform.select({
2646
+ macos: undefined,
2647
+ default: require('expo-device')
2648
+ });
2649
+ } catch (e) {}
2650
+
2651
+ let OptionalExpoLocalization = undefined;
2652
+ try {
2653
+ // macos not supported
2654
+ OptionalExpoLocalization = Platform.select({
2655
+ macos: undefined,
2656
+ default: require('expo-localization')
2657
+ });
2658
+ } catch (e) {}
2659
+
2660
+ let OptionalReactNativeDeviceInfo = undefined;
2661
+ try {
2662
+ // macos not supported
2663
+ OptionalReactNativeDeviceInfo = Platform.select({
2664
+ macos: undefined,
2665
+ default: require('react-native-device-info') // No Web support, returns unknown
2666
+ });
2667
+ } catch (e) {}
2668
+
2669
+ let OptionalReactNativeLocalize = undefined;
2670
+ // web support requires webpack
2671
+ // https://github.com/zoontek/react-native-localize#web-support
2672
+ try {
2673
+ OptionalReactNativeLocalize = require('react-native-localize');
2674
+ } catch (e) {}
2675
+
2676
+ const getDeviceType = () => {
2677
+ let deviceType = 'Mobile';
2678
+ if (Platform.OS === 'macos' || Platform.OS === 'windows') {
2679
+ deviceType = 'Desktop';
2680
+ } else if (Platform.OS === 'web') {
2681
+ deviceType = 'Web';
2682
+ }
2683
+ return deviceType;
2684
+ };
2685
+ const currentDeviceType = getDeviceType();
2686
+ const getAppProperties = () => {
2687
+ const properties = {
2688
+ $device_type: currentDeviceType
2689
+ };
2690
+ if (OptionalExpoApplication) {
2691
+ properties.$app_build = OptionalExpoApplication.nativeBuildVersion;
2692
+ properties.$app_name = OptionalExpoApplication.applicationName;
2693
+ properties.$app_namespace = OptionalExpoApplication.applicationId;
2694
+ properties.$app_version = OptionalExpoApplication.nativeApplicationVersion;
2695
+ } else if (OptionalReactNativeDeviceInfo) {
2696
+ properties.$app_build = returnPropertyIfNotUnknown(OptionalReactNativeDeviceInfo.getBuildNumber());
2697
+ properties.$app_name = returnPropertyIfNotUnknown(OptionalReactNativeDeviceInfo.getApplicationName());
2698
+ properties.$app_namespace = returnPropertyIfNotUnknown(OptionalReactNativeDeviceInfo.getBundleId());
2699
+ properties.$app_version = returnPropertyIfNotUnknown(OptionalReactNativeDeviceInfo.getVersion());
2700
+ }
2701
+ if (OptionalExpoDevice) {
2702
+ properties.$device_manufacturer = OptionalExpoDevice.manufacturer;
2703
+ // expo-device already maps the device model identifier to a human readable name
2704
+ properties.$device_name = OptionalExpoDevice.modelName;
2705
+ // https://github.com/expo/expo/issues/6990
2706
+ // some devices return a value similar to:
2707
+ // HUAWEI/SNE-LX1/HWSNE:8.1.0/HUAWEISNE-LX1/131(C432):user/release-keys
2708
+ if (Platform.OS === 'android') {
2709
+ properties.$os_name = 'Android';
2710
+ } else {
2711
+ properties.$os_name = OptionalExpoDevice.osName;
2712
+ }
2713
+ properties.$os_version = OptionalExpoDevice.osVersion;
2714
+ } else if (OptionalReactNativeDeviceInfo) {
2715
+ properties.$device_manufacturer = returnPropertyIfNotUnknown(OptionalReactNativeDeviceInfo.getManufacturerSync());
2716
+ // react-native-device-info already maps the device model identifier to a human readable name
2717
+ properties.$device_name = returnPropertyIfNotUnknown(OptionalReactNativeDeviceInfo.getModel());
2718
+ properties.$os_name = returnPropertyIfNotUnknown(OptionalReactNativeDeviceInfo.getSystemName());
2719
+ properties.$os_version = returnPropertyIfNotUnknown(OptionalReactNativeDeviceInfo.getSystemVersion());
2720
+ }
2721
+ if (OptionalExpoLocalization) {
2722
+ properties.$locale = OptionalExpoLocalization.locale;
2723
+ properties.$timezone = OptionalExpoLocalization.timezone;
2724
+ } else if (OptionalReactNativeLocalize) {
2725
+ const localesFn = OptionalReactNativeLocalize.getLocales;
2726
+ if (localesFn) {
2727
+ const locales = localesFn();
2728
+ if (locales && locales.length > 0) {
2729
+ const languageTag = locales[0].languageTag;
2730
+ if (languageTag) {
2731
+ properties.$locale = languageTag;
2732
+ }
2733
+ }
2734
+ }
2735
+ const timezoneFn = OptionalReactNativeLocalize.getTimeZone;
2736
+ if (timezoneFn) {
2737
+ const timezone = timezoneFn();
2738
+ if (timezone) {
2739
+ properties.$timezone = timezone;
2740
+ }
2741
+ }
2742
+ }
2743
+ return properties;
2744
+ };
2745
+ // react-native-device-info returns 'unknown' if the property is not available (Web target)
2746
+ const returnPropertyIfNotUnknown = value => {
2747
+ if (value !== 'unknown') {
2748
+ return value;
2749
+ }
2750
+ return null;
2751
+ };
2752
+ const buildOptimisiticAsyncStorage = () => {
2753
+ if (OptionalExpoFileSystem) {
2754
+ const filesystem = OptionalExpoFileSystem;
2755
+ return {
2756
+ async getItem(key) {
2757
+ const uri = (filesystem.documentDirectory || '') + key;
2758
+ try {
2759
+ const stringContent = await filesystem.readAsStringAsync(uri);
2760
+ return stringContent;
2761
+ } catch (e) {
2762
+ return null;
2763
+ }
2764
+ },
2765
+ async setItem(key, value) {
2766
+ const uri = (filesystem.documentDirectory || '') + key;
2767
+ await filesystem.writeAsStringAsync(uri, value);
2768
+ }
2769
+ };
2770
+ }
2771
+ if (OptionalAsyncStorage) {
2772
+ return OptionalAsyncStorage;
2773
+ }
2774
+ throw new Error('PostHog: No storage available. Please install expo-filesystem or react-native-async-storage OR implement a custom storage provider.');
2775
+ };
2776
+
2777
+ let OptionalReactNativeNavigationWix = undefined;
2778
+ try {
2779
+ // macos/web not supported
2780
+ OptionalReactNativeNavigationWix = Platform.select({
2781
+ macos: undefined,
2782
+ web: undefined,
2783
+ default: require('react-native-navigation')
2784
+ });
2785
+ } catch (e) {}
2786
+
2787
+ /*
2788
+ * Wix Navigation (react-native-navigation)
2789
+ *
2790
+ * Wix Navigation uses a very different paradigm for rendering screens, with a more imperative / config driven approach
2791
+ * Instead of hooking into the natural React lifecycle, it provides a very different API which we can hook into and use instead.
2792
+ */
2793
+ const withReactNativeNavigation = (posthog, options = {}) => {
2794
+ if (!OptionalReactNativeNavigationWix) {
2795
+ return false;
2796
+ }
2797
+ const Navigation = OptionalReactNativeNavigationWix.Navigation;
2798
+ // Equivalent of `useNavigationTracker`
2799
+ Navigation.events().registerComponentDidAppearListener(({
2800
+ componentName,
2801
+ passProps
2802
+ }) => {
2803
+ var _a, _b, _c, _d, _e;
2804
+ if (!((_a = options.captureScreens) !== null && _a !== void 0 ? _a : true)) {
2805
+ return;
2806
+ }
2807
+ const currentRouteName = ((_c = (_b = options === null || options === void 0 ? void 0 : options.navigation) === null || _b === void 0 ? void 0 : _b.routeToName) === null || _c === void 0 ? void 0 : _c.call(_b, componentName, passProps || {})) || componentName || 'Unknown';
2808
+ if (currentRouteName) {
2809
+ const properties = (_e = (_d = options === null || options === void 0 ? void 0 : options.navigation) === null || _d === void 0 ? void 0 : _d.routeToProperties) === null || _e === void 0 ? void 0 : _e.call(_d, currentRouteName, passProps || {});
2810
+ posthog.screen(currentRouteName, properties);
2811
+ }
2812
+ });
2813
+ return true;
2814
+ };
2815
+
2816
+ let OptionalReactNativeSessionReplay = undefined;
2817
+ try {
2818
+ OptionalReactNativeSessionReplay = Platform.select({
2819
+ macos: undefined,
2820
+ web: undefined,
2821
+ default: require('posthog-react-native-session-replay') // Only Android and iOS
2822
+ });
2823
+ } catch (e) {}
2824
+
2825
+ class PostHog extends PostHogCore {
2826
+ constructor(apiKey, options) {
2827
+ var _a, _b, _c, _d;
2828
+ super(apiKey, options);
2829
+ this._appProperties = {};
2830
+ this._isInitialized = false;
2831
+ this._persistence = (_a = options === null || options === void 0 ? void 0 : options.persistence) !== null && _a !== void 0 ? _a : 'file';
2832
+ this._disableSurveys = (_b = options === null || options === void 0 ? void 0 : options.disableSurveys) !== null && _b !== void 0 ? _b : false;
2833
+ this._disableRemoteConfig = (_c = options === null || options === void 0 ? void 0 : options.disableRemoteConfig) !== null && _c !== void 0 ? _c : false;
2834
+ // Either build the app properties from the existing ones
2835
+ this._appProperties = typeof (options === null || options === void 0 ? void 0 : options.customAppProperties) === 'function' ? options.customAppProperties(getAppProperties()) : (options === null || options === void 0 ? void 0 : options.customAppProperties) || getAppProperties();
2836
+ AppState.addEventListener('change', () => {
2837
+ void this.flush();
2838
+ });
2839
+ let storagePromise;
2840
+ if (this._persistence === 'file') {
2841
+ this._storage = new PostHogRNStorage((_d = options === null || options === void 0 ? void 0 : options.customStorage) !== null && _d !== void 0 ? _d : buildOptimisiticAsyncStorage());
2842
+ storagePromise = this._storage.preloadPromise;
2843
+ } else {
2844
+ this._storage = new PostHogRNSyncMemoryStorage();
2845
+ }
2846
+ if (storagePromise) {
2847
+ storagePromise.then(() => {
2848
+ // This code is for migrating from V1 to V2 and tries its best to keep the existing anon/distinctIds
2849
+ // It only applies for async storage
2850
+ if (!this._storage.getItem(PostHogPersistedProperty.AnonymousId)) {
2851
+ void getLegacyValues().then(legacyValues => {
2852
+ var _a, _b;
2853
+ if (legacyValues === null || legacyValues === void 0 ? void 0 : legacyValues.distinctId) {
2854
+ (_a = this._storage) === null || _a === void 0 ? void 0 : _a.setItem(PostHogPersistedProperty.DistinctId, legacyValues.distinctId);
2855
+ (_b = this._storage) === null || _b === void 0 ? void 0 : _b.setItem(PostHogPersistedProperty.AnonymousId, legacyValues.anonymousId);
2856
+ }
2857
+ });
2858
+ }
2859
+ });
2860
+ }
2861
+ const initAfterStorage = () => {
2862
+ // reset session id on app restart
2863
+ const enablePersistSessionIdAcrossRestart = options === null || options === void 0 ? void 0 : options.enablePersistSessionIdAcrossRestart;
2864
+ if (!enablePersistSessionIdAcrossRestart) {
2865
+ this.setPersistedProperty(PostHogPersistedProperty.SessionId, null);
2866
+ this.setPersistedProperty(PostHogPersistedProperty.SessionLastTimestamp, null);
2867
+ }
2868
+ this.setupBootstrap(options);
2869
+ this._isInitialized = true;
2870
+ if (this._disableRemoteConfig === false) {
2871
+ this.reloadRemoteConfigAsync();
2872
+ } else {
2873
+ this.logMsgIfDebug(() => console.info('PostHog Debug', `Remote config is disabled.`));
2874
+ if ((options === null || options === void 0 ? void 0 : options.preloadFeatureFlags) !== false) {
2875
+ this.logMsgIfDebug(() => console.info('PostHog Debug', `Feature flags will be preloaded from Decide API.`));
2876
+ this.reloadFeatureFlags();
2877
+ } else {
2878
+ this.logMsgIfDebug(() => console.info('PostHog Debug', `preloadFeatureFlags is disabled.`));
2879
+ }
2880
+ }
2881
+ // this value could have been inferred from the autocapture options (captureLifecycleEvents)
2882
+ if (options === null || options === void 0 ? void 0 : options.captureNativeAppLifecycleEvents) {
2883
+ void this.captureNativeAppLifecycleEvents();
2884
+ }
2885
+ void this.persistAppVersion();
2886
+ void this.startSessionReplay(options);
2887
+ };
2888
+ // For async storage, we wait for the storage to be ready before we start the SDK
2889
+ // For sync storage we can start the SDK immediately
2890
+ if (storagePromise) {
2891
+ this._initPromise = storagePromise.then(initAfterStorage);
2892
+ } else {
2893
+ this._initPromise = Promise.resolve();
2894
+ initAfterStorage();
2895
+ }
2896
+ }
2897
+ // NOTE: This is purely a helper method for testing purposes or those who wish to be certain the SDK is fully initialised
2898
+ async ready() {
2899
+ await this._initPromise;
2900
+ }
2901
+ getPersistedProperty(key) {
2902
+ return this._storage.getItem(key);
2903
+ }
2904
+ setPersistedProperty(key, value) {
2905
+ return value !== null ? this._storage.setItem(key, value) : this._storage.removeItem(key);
2906
+ }
2907
+ fetch(url, options) {
2908
+ return fetch(url, options);
2909
+ }
2910
+ getLibraryId() {
2911
+ return 'posthog-react-native';
2912
+ }
2913
+ getLibraryVersion() {
2914
+ return version;
2915
+ }
2916
+ getCustomUserAgent() {
2917
+ if (Platform.OS === 'web') {
2918
+ return '';
2919
+ }
2920
+ return `${this.getLibraryId()}/${this.getLibraryVersion()}`;
2921
+ }
2922
+ getCommonEventProperties() {
2923
+ return {
2924
+ ...super.getCommonEventProperties(),
2925
+ ...this._appProperties,
2926
+ $screen_height: Dimensions.get('screen').height,
2927
+ $screen_width: Dimensions.get('screen').width
2928
+ };
2929
+ }
2930
+ // Custom methods
2931
+ async screen(name, properties, options) {
2932
+ await this._initPromise;
2933
+ // Screen name is good to know for all other subsequent events
2934
+ this.registerForSession({
2935
+ $screen_name: name
2936
+ });
2937
+ return this.capture('$screen', {
2938
+ ...properties,
2939
+ $screen_name: name
2940
+ }, options);
2941
+ }
2942
+ _isEnableSessionReplay() {
2943
+ var _a;
2944
+ return !this.isDisabled && ((_a = this._enableSessionReplay) !== null && _a !== void 0 ? _a : false);
2945
+ }
2946
+ _resetSessionId(reactNativeSessionReplay, sessionId) {
2947
+ // _resetSessionId is only called if reactNativeSessionReplay not undefined, but the linter wasn't happy
2948
+ if (reactNativeSessionReplay) {
2949
+ reactNativeSessionReplay.endSession();
2950
+ reactNativeSessionReplay.startSession(sessionId);
2951
+ }
2952
+ }
2953
+ getSessionId() {
2954
+ const sessionId = super.getSessionId();
2955
+ if (!this._isEnableSessionReplay()) {
2956
+ return sessionId;
2957
+ }
2958
+ // only rotate if there is a new sessionId and it is different from the current one
2959
+ if (sessionId.length > 0 && this._currentSessionId && sessionId !== this._currentSessionId) {
2960
+ if (OptionalReactNativeSessionReplay) {
2961
+ try {
2962
+ this._resetSessionId(OptionalReactNativeSessionReplay, sessionId);
2963
+ this.logMsgIfDebug(() => console.info('PostHog Debug', `Session replay started with sessionId ${sessionId}.`));
2964
+ } catch (e) {
2965
+ this.logMsgIfDebug(() => console.error('PostHog Debug', `Session replay failed to start with sessionId: ${e}.`));
2966
+ }
2967
+ }
2968
+ this._currentSessionId = sessionId;
2969
+ } else {
2970
+ this.logMsgIfDebug(() => console.log('PostHog Debug', `Session replay session id not rotated, sessionId ${sessionId} and currentSessionId ${this._currentSessionId}.`));
2971
+ }
2972
+ return sessionId;
2973
+ }
2974
+ resetSessionId() {
2975
+ super.resetSessionId();
2976
+ if (this._isEnableSessionReplay() && OptionalReactNativeSessionReplay) {
2977
+ try {
2978
+ OptionalReactNativeSessionReplay.endSession();
2979
+ this.logMsgIfDebug(() => console.info('PostHog Debug', `Session replay ended.`));
2980
+ } catch (e) {
2981
+ this.logMsgIfDebug(() => console.error('PostHog Debug', `Session replay failed to end: ${e}.`));
2982
+ }
2983
+ }
2984
+ }
2985
+ identify(distinctId, properties, options) {
2986
+ const previousDistinctId = this.getDistinctId();
2987
+ super.identify(distinctId, properties, options);
2988
+ if (this._isEnableSessionReplay() && OptionalReactNativeSessionReplay) {
2989
+ try {
2990
+ distinctId = distinctId || previousDistinctId;
2991
+ OptionalReactNativeSessionReplay.identify(distinctId, this.getAnonymousId());
2992
+ this.logMsgIfDebug(() => console.info('PostHog Debug', `Session replay identified with distinctId ${distinctId}.`));
2993
+ } catch (e) {
2994
+ this.logMsgIfDebug(() => console.error('PostHog Debug', `Session replay failed to identify: ${e}.`));
2995
+ }
2996
+ }
2997
+ }
2998
+ initReactNativeNavigation(options) {
2999
+ return withReactNativeNavigation(this, options);
3000
+ }
3001
+ async getSurveys() {
3002
+ if (this._disableSurveys === true) {
3003
+ this.logMsgIfDebug(() => console.log('Loading surveys is disabled.'));
3004
+ this.setPersistedProperty(PostHogPersistedProperty.Surveys, null);
3005
+ return [];
3006
+ }
3007
+ const surveys = this.getPersistedProperty(PostHogPersistedProperty.Surveys);
3008
+ if (surveys && surveys.length > 0) {
3009
+ this.logMsgIfDebug(() => console.log('PostHog Debug', 'Surveys fetched from storage: ', JSON.stringify(surveys)));
3010
+ return surveys;
3011
+ } else {
3012
+ this.logMsgIfDebug(() => console.log('PostHog Debug', 'No surveys found in storage'));
3013
+ }
3014
+ if (this._disableRemoteConfig === true) {
3015
+ const surveysFromApi = await super.getSurveysStateless();
3016
+ if (surveysFromApi && surveysFromApi.length > 0) {
3017
+ this.setPersistedProperty(PostHogPersistedProperty.Surveys, surveysFromApi);
3018
+ return surveysFromApi;
3019
+ }
3020
+ }
3021
+ return [];
3022
+ }
3023
+ async startSessionReplay(options) {
3024
+ var _a, _b, _c, _d, _e;
3025
+ this._enableSessionReplay = options === null || options === void 0 ? void 0 : options.enableSessionReplay;
3026
+ if (!this._isEnableSessionReplay()) {
3027
+ this.logMsgIfDebug(() => console.info('PostHog Debug', 'Session replay is not enabled.'));
3028
+ return;
3029
+ }
3030
+ const {
3031
+ maskAllTextInputs = true,
3032
+ maskAllImages = true,
3033
+ maskAllSandboxedViews = true,
3034
+ maskPhotoLibraryImages = false,
3035
+ captureLog = true,
3036
+ captureNetworkTelemetry = true,
3037
+ iOSdebouncerDelayMs = 1000,
3038
+ androidDebouncerDelayMs = 1000
3039
+ } = (_a = options === null || options === void 0 ? void 0 : options.sessionReplayConfig) !== null && _a !== void 0 ? _a : {};
3040
+ const sdkReplayConfig = {
3041
+ maskAllTextInputs,
3042
+ maskAllImages,
3043
+ maskAllSandboxedViews,
3044
+ maskPhotoLibraryImages,
3045
+ captureLog,
3046
+ captureNetworkTelemetry,
3047
+ iOSdebouncerDelayMs,
3048
+ androidDebouncerDelayMs
3049
+ };
3050
+ this.logMsgIfDebug(() => console.log('PostHog Debug', `Session replay sdk config: ${JSON.stringify(sdkReplayConfig)}`));
3051
+ // if Decide has not returned yet, we will start session replay with default config.
3052
+ const sessionReplay = (_b = this.getPersistedProperty(PostHogPersistedProperty.SessionReplay)) !== null && _b !== void 0 ? _b : {};
3053
+ const featureFlags = (_c = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlags)) !== null && _c !== void 0 ? _c : {};
3054
+ const decideFeatureFlags = (_d = featureFlags) !== null && _d !== void 0 ? _d : {};
3055
+ const decideReplayConfig = (_e = sessionReplay) !== null && _e !== void 0 ? _e : {};
3056
+ this.logMsgIfDebug(() => console.log('PostHog Debug', `Session replay decide cached config: ${JSON.stringify(decideReplayConfig)}`));
3057
+ let recordingActive = true;
3058
+ const linkedFlag = decideReplayConfig['linkedFlag'];
3059
+ if (typeof linkedFlag === 'string') {
3060
+ const value = decideFeatureFlags[linkedFlag];
3061
+ if (typeof value === 'boolean') {
3062
+ recordingActive = value;
3063
+ } else if (typeof value === 'string') {
3064
+ // if its a multi-variant flag linked to "any"
3065
+ recordingActive = true;
3066
+ } else {
3067
+ // disable recording if the flag does not exist/quota limited
3068
+ recordingActive = false;
3069
+ }
3070
+ this.logMsgIfDebug(() => console.log('PostHog Debug', `Session replay ${linkedFlag} linked flag value: ${value}`));
3071
+ } else if (linkedFlag && typeof linkedFlag === 'object') {
3072
+ const flag = linkedFlag['flag'];
3073
+ const variant = linkedFlag['variant'];
3074
+ if (flag && variant) {
3075
+ const value = decideFeatureFlags[flag];
3076
+ recordingActive = value === variant;
3077
+ this.logMsgIfDebug(() => console.log('PostHog Debug', `Session replay ${flag} linked flag variant: ${variant} and value ${value}`));
3078
+ } else {
3079
+ // disable recording if the flag does not exist/quota limited
3080
+ recordingActive = false;
3081
+ }
3082
+ }
3083
+ if (recordingActive) {
3084
+ if (OptionalReactNativeSessionReplay) {
3085
+ const sessionId = this.getSessionId();
3086
+ if (sessionId.length === 0) {
3087
+ this.logMsgIfDebug(() => console.warn('PostHog Debug', 'Session replay enabled but no sessionId found.'));
3088
+ return;
3089
+ }
3090
+ const sdkOptions = {
3091
+ apiKey: this.apiKey,
3092
+ host: this.host,
3093
+ debug: this.isDebug,
3094
+ distinctId: this.getDistinctId(),
3095
+ anonymousId: this.getAnonymousId(),
3096
+ sdkVersion: this.getLibraryVersion(),
3097
+ flushAt: this.flushAt
3098
+ };
3099
+ this.logMsgIfDebug(() => console.log('PostHog Debug', `Session replay sdk options: ${JSON.stringify(sdkOptions)}`));
3100
+ try {
3101
+ if (!(await OptionalReactNativeSessionReplay.isEnabled())) {
3102
+ await OptionalReactNativeSessionReplay.start(sessionId, sdkOptions, sdkReplayConfig, decideReplayConfig);
3103
+ this.logMsgIfDebug(() => console.info('PostHog Debug', `Session replay started with sessionId ${sessionId}.`));
3104
+ } else {
3105
+ // if somehow the SDK is already enabled with a different sessionId, we reset it
3106
+ this._resetSessionId(OptionalReactNativeSessionReplay, sessionId);
3107
+ this.logMsgIfDebug(() => console.log('PostHog Debug', `Session replay already started with sessionId ${sessionId}.`));
3108
+ }
3109
+ this._currentSessionId = sessionId;
3110
+ } catch (e) {
3111
+ this.logMsgIfDebug(() => console.error('PostHog Debug', `Session replay failed to start: ${e}.`));
3112
+ }
3113
+ } else {
3114
+ this.logMsgIfDebug(() => console.warn('PostHog Debug', 'Session replay enabled but not installed.'));
3115
+ }
3116
+ } else {
3117
+ this.logMsgIfDebug(() => console.info('PostHog Debug', 'Session replay disabled.'));
3118
+ }
3119
+ }
3120
+ async captureNativeAppLifecycleEvents() {
3121
+ var _a;
3122
+ const appBuild = this._appProperties.$app_build;
3123
+ const appVersion = this._appProperties.$app_version;
3124
+ const isMemoryPersistence = this._persistence === 'memory';
3125
+ // version and build are deprecated, but we keep them for compatibility
3126
+ // use $app_version and $app_build instead
3127
+ const properties = {
3128
+ version: appVersion,
3129
+ build: appBuild
3130
+ };
3131
+ if (!isMemoryPersistence) {
3132
+ const prevAppBuild = this.getPersistedProperty(PostHogPersistedProperty.InstalledAppBuild);
3133
+ const prevAppVersion = this.getPersistedProperty(PostHogPersistedProperty.InstalledAppVersion);
3134
+ if (!appBuild || !appVersion) {
3135
+ this.logMsgIfDebug(() => console.warn('PostHog could not track installation/update/open, as the build and version were not set. ' + 'This can happen if some dependencies are not installed correctly, or if you have provided' + 'customAppProperties but not included $app_build or $app_version.'));
3136
+ }
3137
+ if (appBuild) {
3138
+ if (!prevAppBuild) {
3139
+ // new app install
3140
+ this.capture('Application Installed', properties);
3141
+ } else if (prevAppBuild !== appBuild) {
3142
+ // app updated
3143
+ this.capture('Application Updated', {
3144
+ previous_version: prevAppVersion,
3145
+ previous_build: prevAppBuild,
3146
+ ...properties
3147
+ });
3148
+ }
3149
+ }
3150
+ } else {
3151
+ this.logMsgIfDebug(() => console.warn('PostHog was initialised with persistence set to "memory", capturing native app events (Application Installed and Application Updated) is not supported.'));
3152
+ }
3153
+ const initialUrl = (_a = await Linking.getInitialURL()) !== null && _a !== void 0 ? _a : undefined;
3154
+ this.capture('Application Opened', {
3155
+ ...properties,
3156
+ url: initialUrl
3157
+ });
3158
+ AppState.addEventListener('change', state => {
3159
+ if (state === 'active') {
3160
+ this.capture('Application Became Active');
3161
+ } else if (state === 'background') {
3162
+ this.capture('Application Backgrounded');
3163
+ }
3164
+ });
3165
+ }
3166
+ async persistAppVersion() {
3167
+ const appBuild = this._appProperties.$app_build;
3168
+ const appVersion = this._appProperties.$app_version;
3169
+ this.setPersistedProperty(PostHogPersistedProperty.InstalledAppBuild, appBuild);
3170
+ this.setPersistedProperty(PostHogPersistedProperty.InstalledAppVersion, appVersion);
3171
+ }
3172
+ }
3173
+
3174
+ let OptionalReactNativeNavigation = undefined;
3175
+ try {
3176
+ // macos not supported
3177
+ OptionalReactNativeNavigation = Platform.select({
3178
+ macos: undefined,
3179
+ // experimental support for web https://reactnavigation.org/docs/web-support/
3180
+ default: require('@react-navigation/native')
3181
+ });
3182
+ } catch (e) {}
3183
+
3184
+ const PostHogContext = /*#__PURE__*/React.createContext({
3185
+ client: undefined
3186
+ });
3187
+
3188
+ const usePostHog = () => {
3189
+ const {
3190
+ client
3191
+ } = React.useContext(PostHogContext);
3192
+ return client;
3193
+ };
3194
+
3195
+ function _useNavigationTrackerDisabled() {
3196
+ return;
3197
+ }
3198
+ function _useNavigationTracker(options, navigationRef, client) {
3199
+ const contextClient = usePostHog();
3200
+ const posthog = client || contextClient;
3201
+ if (!OptionalReactNativeNavigation) {
3202
+ // NOTE: This is taken care of by the export, but we keep this here for TS
3203
+ throw new Error('No OptionalReactNativeNavigation');
3204
+ }
3205
+ const routes = OptionalReactNativeNavigation.useNavigationState(state => state === null || state === void 0 ? void 0 : state.routes);
3206
+ // eslint-disable-next-line react-hooks/rules-of-hooks
3207
+ const navigation = navigationRef || OptionalReactNativeNavigation.useNavigation();
3208
+ const trackRoute = useCallback(() => {
3209
+ var _a, _b, _c;
3210
+ if (!navigation) {
3211
+ return;
3212
+ }
3213
+ let currentRoute = undefined;
3214
+ // NOTE: This method is not typed correctly but is available and takes care of parsing the router state correctly
3215
+ try {
3216
+ let isReady = false;
3217
+ try {
3218
+ isReady = navigation.isReady();
3219
+ } catch (error) {
3220
+ // keep compatibility with older versions of react-navigation
3221
+ isReady = true;
3222
+ }
3223
+ if (!isReady) {
3224
+ return;
3225
+ }
3226
+ currentRoute = navigation.getCurrentRoute();
3227
+ } catch (error) {
3228
+ return;
3229
+ }
3230
+ if (!currentRoute) {
3231
+ return;
3232
+ }
3233
+ const {
3234
+ state
3235
+ } = currentRoute;
3236
+ let {
3237
+ name,
3238
+ params
3239
+ } = currentRoute;
3240
+ if ((_a = state === null || state === void 0 ? void 0 : state.routes) === null || _a === void 0 ? void 0 : _a.length) {
3241
+ const route = state.routes[state.routes.length - 1];
3242
+ name = route.name;
3243
+ params = route.params;
3244
+ }
3245
+ const currentRouteName = ((_b = options === null || options === void 0 ? void 0 : options.routeToName) === null || _b === void 0 ? void 0 : _b.call(options, name, params)) || name || 'Unknown';
3246
+ if (currentRouteName) {
3247
+ const properties = (_c = options === null || options === void 0 ? void 0 : options.routeToProperties) === null || _c === void 0 ? void 0 : _c.call(options, currentRouteName, params);
3248
+ posthog.screen(currentRouteName, properties);
3249
+ }
3250
+ }, [navigation, options, posthog]);
3251
+ useEffect(() => {
3252
+ // NOTE: The navigation stacks may not be fully rendered initially. This means the first route can be missed (it doesn't update useNavigationState)
3253
+ // If missing we simply wait a tick and call it again.
3254
+ if (!routes) {
3255
+ setTimeout(trackRoute, 1);
3256
+ return;
3257
+ }
3258
+ trackRoute();
3259
+ }, [routes, trackRoute]);
3260
+ }
3261
+ const useNavigationTracker = OptionalReactNativeNavigation ? _useNavigationTracker : _useNavigationTrackerDisabled;
3262
+
3263
+ function useFeatureFlags(client) {
3264
+ const contextClient = usePostHog();
3265
+ const posthog = client || contextClient;
3266
+ const [featureFlags, setFeatureFlags] = useState(posthog.getFeatureFlags());
3267
+ useEffect(() => {
3268
+ setFeatureFlags(posthog.getFeatureFlags());
3269
+ return posthog.onFeatureFlags(flags => {
3270
+ setFeatureFlags(flags);
3271
+ });
3272
+ }, [posthog]);
3273
+ return featureFlags;
3274
+ }
3275
+
3276
+ function useFeatureFlag(flag, client) {
3277
+ const contextClient = usePostHog();
3278
+ const posthog = client || contextClient;
3279
+ const [featureFlag, setFeatureFlag] = useState(posthog.getFeatureFlag(flag));
3280
+ useEffect(() => {
3281
+ setFeatureFlag(posthog.getFeatureFlag(flag));
3282
+ return posthog.onFeatureFlags(() => {
3283
+ setFeatureFlag(posthog.getFeatureFlag(flag));
3284
+ });
3285
+ }, [posthog, flag]);
3286
+ return featureFlag;
3287
+ }
3288
+ function useFeatureFlagWithPayload(flag, client) {
3289
+ const contextClient = usePostHog();
3290
+ const posthog = client || contextClient;
3291
+ const [featureFlag, setFeatureFlag] = useState([undefined, undefined]);
3292
+ useEffect(() => {
3293
+ setFeatureFlag([posthog.getFeatureFlag(flag), posthog.getFeatureFlagPayload(flag)]);
3294
+ return posthog.onFeatureFlags(() => {
3295
+ setFeatureFlag([posthog.getFeatureFlag(flag), posthog.getFeatureFlagPayload(flag)]);
3296
+ });
3297
+ }, [posthog, flag]);
3298
+ return featureFlag;
3299
+ }
3300
+
3301
+ const flattenStyles = styles => {
3302
+ const flattened = {};
3303
+ if (Array.isArray(styles)) {
3304
+ for (const style of styles) {
3305
+ Object.assign(flattened, flattenStyles(style));
3306
+ }
3307
+ } else {
3308
+ Object.assign(flattened, styles);
3309
+ }
3310
+ return flattened;
3311
+ };
3312
+ const stringifyStyle = styles => {
3313
+ const flattened = flattenStyles(styles);
3314
+ const str = Object.keys(flattened).map(x => `${x}:${flattened[x]}`).join(';');
3315
+ return str;
3316
+ };
3317
+ const sanitiseLabel = label => {
3318
+ return label.replace(/[^a-z0-9]+/gi, '-');
3319
+ };
3320
+ const defaultPostHogLabelProp = 'ph-label';
3321
+ const autocaptureFromTouchEvent = (e, posthog, options = {}) => {
3322
+ var _a, _b;
3323
+ const {
3324
+ noCaptureProp = 'ph-no-capture',
3325
+ customLabelProp = defaultPostHogLabelProp,
3326
+ maxElementsCaptured = 20,
3327
+ ignoreLabels = [],
3328
+ propsToCapture = ['style', 'testID', 'accessibilityLabel', customLabelProp, 'children']
3329
+ } = options;
3330
+ if (!e._targetInst) {
3331
+ return;
3332
+ }
3333
+ const elements = [];
3334
+ let currentInst = e._targetInst;
3335
+ while (currentInst &&
3336
+ // maxComponentTreeSize will always be defined as we have a defaultProps. But ts needs a check so this is here.
3337
+ elements.length < maxElementsCaptured) {
3338
+ const el = {
3339
+ tag_name: ''
3340
+ };
3341
+ const props = currentInst.memoizedProps;
3342
+ if (props === null || props === void 0 ? void 0 : props[noCaptureProp]) {
3343
+ // Immediately ignore events if a no capture is in the chain
3344
+ return;
3345
+ }
3346
+ if (props) {
3347
+ // Capture only props we have said to capture. By default this is only "safe" props
3348
+ Object.keys(props).forEach(key => {
3349
+ if (!propsToCapture.includes(key)) {
3350
+ return;
3351
+ }
3352
+ const value = props[key];
3353
+ if (key === 'style') {
3354
+ el.attr__style = stringifyStyle(value);
3355
+ } else if (['string', 'number', 'boolean'].includes(typeof value)) {
3356
+ if (key === 'children') {
3357
+ el.$el_text = typeof value === 'string' ? value : JSON.stringify(value);
3358
+ } else {
3359
+ el[`attr__${key}`] = value;
3360
+ }
3361
+ }
3362
+ });
3363
+ }
3364
+ // Try and find a sensible label
3365
+ const label = typeof (props === null || props === void 0 ? void 0 : props[customLabelProp]) !== 'undefined' ? `${props[customLabelProp]}` : ((_a = currentInst.elementType) === null || _a === void 0 ? void 0 : _a.displayName) || ((_b = currentInst.elementType) === null || _b === void 0 ? void 0 : _b.name);
3366
+ if (label && !ignoreLabels.includes(label)) {
3367
+ el.tag_name = sanitiseLabel(label);
3368
+ elements.push(el);
3369
+ }
3370
+ currentInst = currentInst.return;
3371
+ }
3372
+ if (elements.length) {
3373
+ // The element that was tapped, may be a child (or grandchild of an element with a customLabelProp (default: ph-label))
3374
+ // In this case, the current labels applied obscure the customLabelProp (default: ph-label)
3375
+ // To correct this, loop over the elements in reverse, and promote the customLabelProp (default: ph-label)
3376
+ const elAttrLabelKey = `attr__${customLabelProp}`;
3377
+ let lastLabel = undefined;
3378
+ for (let i = elements.length - 1; i >= 0; i--) {
3379
+ const element = elements[i];
3380
+ if (element[elAttrLabelKey]) {
3381
+ // this element had a customLabelProp (default: ph-label) set, promote it to the lastLabel
3382
+ lastLabel = element[elAttrLabelKey];
3383
+ }
3384
+ // if lastLabel is set, update this elements tag_name
3385
+ if (lastLabel) {
3386
+ element['tag_name'] = lastLabel;
3387
+ }
3388
+ }
3389
+ posthog.autocapture('touch', elements, {
3390
+ $touch_x: e.nativeEvent.pageX,
3391
+ $touch_y: e.nativeEvent.pageY
3392
+ });
3393
+ }
3394
+ };
3395
+
3396
+ function PostHogNavigationHook({
3397
+ options,
3398
+ client
3399
+ }) {
3400
+ useNavigationTracker(options === null || options === void 0 ? void 0 : options.navigation, options === null || options === void 0 ? void 0 : options.navigationRef, client);
3401
+ return null;
3402
+ }
3403
+ const PostHogProvider = ({
3404
+ children,
3405
+ client,
3406
+ options,
3407
+ apiKey,
3408
+ autocapture,
3409
+ style,
3410
+ debug = false
3411
+ }) => {
3412
+ var _a;
3413
+ if (!client && !apiKey) {
3414
+ throw new Error('Either a PostHog client or an apiKey is required. If you want to use the PostHogProvider without a client, please provide an apiKey and the options={ disabled: true }.');
3415
+ }
3416
+ const captureAll = autocapture === true;
3417
+ const captureNone = autocapture === false;
3418
+ const posthog = useMemo(() => {
3419
+ var _a;
3420
+ if (client && apiKey) {
3421
+ console.warn('You have provided both a client and an apiKey to PostHogProvider. The apiKey will be ignored in favour of the client.');
3422
+ }
3423
+ if (client) {
3424
+ return client;
3425
+ }
3426
+ const parsedOptions = {
3427
+ ...options,
3428
+ // For backwards-compatible reasons, this information can be stored in two separate places
3429
+ // Default to true if not set
3430
+ captureNativeAppLifecycleEvents: (options === null || options === void 0 ? void 0 : options.captureNativeAppLifecycleEvents) !== undefined ? options.captureNativeAppLifecycleEvents : !captureNone && (captureAll || ((_a = autocaptureOptions === null || autocaptureOptions === void 0 ? void 0 : autocaptureOptions.captureLifecycleEvents) !== null && _a !== void 0 ? _a : true))
3431
+ };
3432
+ return new PostHog(apiKey !== null && apiKey !== void 0 ? apiKey : '', parsedOptions);
3433
+ }, [client, apiKey]); // eslint-disable-line react-hooks/exhaustive-deps
3434
+ const autocaptureOptions = useMemo(() => autocapture && typeof autocapture !== 'boolean' ? autocapture : {}, [autocapture]);
3435
+ const captureTouches = !captureNone && posthog && (captureAll || (autocaptureOptions === null || autocaptureOptions === void 0 ? void 0 : autocaptureOptions.captureTouches));
3436
+ const captureScreens = !captureNone && posthog && (captureAll || ((_a = autocaptureOptions === null || autocaptureOptions === void 0 ? void 0 : autocaptureOptions.captureScreens) !== null && _a !== void 0 ? _a : true)); // Default to true if not set
3437
+ const phLabelProp = (autocaptureOptions === null || autocaptureOptions === void 0 ? void 0 : autocaptureOptions.customLabelProp) || defaultPostHogLabelProp;
3438
+ useEffect(() => {
3439
+ posthog.debug(debug);
3440
+ }, [debug, posthog]);
3441
+ const onTouch = useCallback((type, e) => {
3442
+ // TODO: Improve this to ensure we only capture presses and not just ends of a drag for example
3443
+ if (!captureTouches) {
3444
+ return;
3445
+ }
3446
+ if (type === 'end') {
3447
+ autocaptureFromTouchEvent(e, posthog, autocaptureOptions);
3448
+ }
3449
+ }, [captureTouches, posthog, autocaptureOptions]);
3450
+ return /*#__PURE__*/React.createElement(View, {
3451
+ [phLabelProp]: 'PostHogProvider',
3452
+ // Dynamically setting customLabelProp (default: ph-label)
3453
+ style: style || {
3454
+ flex: 1
3455
+ },
3456
+ onTouchEndCapture: captureTouches ? e => onTouch('end', e) : undefined
3457
+ }, /*#__PURE__*/React.createElement(PostHogContext.Provider, {
3458
+ value: {
3459
+ client: posthog
3460
+ }
3461
+ }, captureScreens && /*#__PURE__*/React.createElement(PostHogNavigationHook, {
3462
+ options: autocaptureOptions,
3463
+ client: posthog
3464
+ }), children));
3465
+ };
3466
+
3467
+ function _extends() {
3468
+ return _extends = Object.assign ? Object.assign.bind() : function (n) {
3469
+ for (var e = 1; e < arguments.length; e++) {
3470
+ var t = arguments[e];
3471
+ for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
3472
+ }
3473
+ return n;
3474
+ }, _extends.apply(null, arguments);
3475
+ }
3476
+
3477
+ const defaultBackgroundColor = '#eeeded';
3478
+ const defaultSurveyAppearance = {
3479
+ backgroundColor: defaultBackgroundColor,
3480
+ submitButtonColor: 'black',
3481
+ submitButtonTextColor: 'white',
3482
+ ratingButtonColor: 'white',
3483
+ ratingButtonActiveColor: 'black',
3484
+ borderColor: '#c9c6c6',
3485
+ placeholder: 'Start typing...',
3486
+ displayThankYouMessage: true,
3487
+ thankYouMessageHeader: 'Thank you for your feedback!',
3488
+ position: SurveyPosition.Right,
3489
+ submitButtonText: 'Submit',
3490
+ autoDisappear: false,
3491
+ thankYouMessageDescription: '',
3492
+ thankYouMessageDescriptionContentType: SurveyQuestionDescriptionContentType.Text,
3493
+ thankYouMessageCloseButtonText: 'Close',
3494
+ surveyPopupDelaySeconds: 0
3495
+ };
3496
+ const getDisplayOrderQuestions = survey => {
3497
+ // retain the original questionIndex so we can correlate values in the webapp
3498
+ survey.questions.forEach((question, idx) => {
3499
+ question.originalQuestionIndex = idx;
3500
+ });
3501
+ // TODO: shuffle questions
3502
+ return survey.questions;
3503
+ // if (!survey.appearance?.shuffleQuestions) {
3504
+ // return survey.questions
3505
+ // }
3506
+ // return reverseIfUnshuffled(survey.questions, shuffle(survey.questions))
3507
+ };
3508
+ const hasEvents = survey => {
3509
+ var _a, _b;
3510
+ return ((_b = (_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.values) !== undefined && survey.conditions.events.values.length > 0;
3511
+ };
3512
+ // export const hasActions = (survey: Survey): boolean => {
3513
+ // return survey.conditions?.actions?.values.length !== undefined && survey.conditions.actions.values.length > 0
3514
+ // }
3515
+ const canActivateRepeatedly = survey => {
3516
+ var _a, _b;
3517
+ return !!(((_b = (_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.repeatedActivation) && hasEvents(survey));
3518
+ };
3519
+ /**
3520
+ * Use the Fisher-yates algorithm to shuffle this array
3521
+ * https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
3522
+ */
3523
+ // export const shuffle = <T>(array: T[]): T[] => {
3524
+ // return array
3525
+ // .map((a) => ({ sort: Math.floor(Math.random() * 10), value: a }))
3526
+ // .sort((a, b) => a.sort - b.sort)
3527
+ // .map((a) => a.value)
3528
+ // }
3529
+ // const reverseIfUnshuffled = <T>(unshuffled: T[], shuffled: T[]): T[] => {
3530
+ // if (unshuffled.length === shuffled.length && unshuffled.every((val, index) => val === shuffled[index])) {
3531
+ // return shuffled.reverse()
3532
+ // }
3533
+ // return shuffled
3534
+ // }
3535
+ const getDisplayOrderChoices = question => {
3536
+ // TODO: shuffle choices
3537
+ return question.choices;
3538
+ // if (!question.shuffleOptions) {
3539
+ // return question.choices
3540
+ // }
3541
+ // const displayOrderChoices = question.choices
3542
+ // let openEndedChoice = ''
3543
+ // if (question.hasOpenChoice && displayOrderChoices.length > 0) {
3544
+ // if the question has an open-ended choice, its always the last element in the choices array.
3545
+ // openEndedChoice = displayOrderChoices.pop()!
3546
+ // }
3547
+ // const shuffledOptions = reverseIfUnshuffled(displayOrderChoices, shuffle(displayOrderChoices))
3548
+ // if (question.hasOpenChoice) {
3549
+ // question.choices.push(openEndedChoice)
3550
+ // shuffledOptions.push(openEndedChoice)
3551
+ // }
3552
+ // return shuffledOptions
3553
+ };
3554
+ function getContrastingTextColor(color) {
3555
+ let rgb;
3556
+ if (color.startsWith('#')) {
3557
+ rgb = hex2rgb(color);
3558
+ }
3559
+ if (color.startsWith('rgb')) {
3560
+ rgb = color;
3561
+ }
3562
+ // otherwise it's a color name
3563
+ const nameColorToHex = nameToHex(color);
3564
+ if (nameColorToHex) {
3565
+ rgb = hex2rgb(nameColorToHex);
3566
+ }
3567
+ if (!rgb) {
3568
+ return 'black';
3569
+ }
3570
+ const colorMatch = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);
3571
+ if (colorMatch) {
3572
+ const r = parseInt(colorMatch[1], 10);
3573
+ const g = parseInt(colorMatch[2], 10);
3574
+ const b = parseInt(colorMatch[3], 10);
3575
+ const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b));
3576
+ return hsp > 127.5 ? 'black' : 'white';
3577
+ }
3578
+ return 'black';
3579
+ }
3580
+ function hex2rgb(c) {
3581
+ if (c.startsWith('#')) {
3582
+ const hexColor = c.replace(/^#/, '');
3583
+ if (!/^[0-9A-Fa-f]{6}$/.test(hexColor)) {
3584
+ return 'rgb(255, 255, 255)';
3585
+ }
3586
+ const r = parseInt(hexColor.slice(0, 2), 16);
3587
+ const g = parseInt(hexColor.slice(2, 4), 16);
3588
+ const b = parseInt(hexColor.slice(4, 6), 16);
3589
+ return `rgb(${r},${g},${b})`;
3590
+ }
3591
+ return 'rgb(255, 255, 255)';
3592
+ }
3593
+ function nameToHex(name) {
3594
+ return {
3595
+ aliceblue: '#f0f8ff',
3596
+ antiquewhite: '#faebd7',
3597
+ aqua: '#00ffff',
3598
+ aquamarine: '#7fffd4',
3599
+ azure: '#f0ffff',
3600
+ beige: '#f5f5dc',
3601
+ bisque: '#ffe4c4',
3602
+ black: '#000000',
3603
+ blanchedalmond: '#ffebcd',
3604
+ blue: '#0000ff',
3605
+ blueviolet: '#8a2be2',
3606
+ brown: '#a52a2a',
3607
+ burlywood: '#deb887',
3608
+ cadetblue: '#5f9ea0',
3609
+ chartreuse: '#7fff00',
3610
+ chocolate: '#d2691e',
3611
+ coral: '#ff7f50',
3612
+ cornflowerblue: '#6495ed',
3613
+ cornsilk: '#fff8dc',
3614
+ crimson: '#dc143c',
3615
+ cyan: '#00ffff',
3616
+ darkblue: '#00008b',
3617
+ darkcyan: '#008b8b',
3618
+ darkgoldenrod: '#b8860b',
3619
+ darkgray: '#a9a9a9',
3620
+ darkgreen: '#006400',
3621
+ darkkhaki: '#bdb76b',
3622
+ darkmagenta: '#8b008b',
3623
+ darkolivegreen: '#556b2f',
3624
+ darkorange: '#ff8c00',
3625
+ darkorchid: '#9932cc',
3626
+ darkred: '#8b0000',
3627
+ darksalmon: '#e9967a',
3628
+ darkseagreen: '#8fbc8f',
3629
+ darkslateblue: '#483d8b',
3630
+ darkslategray: '#2f4f4f',
3631
+ darkturquoise: '#00ced1',
3632
+ darkviolet: '#9400d3',
3633
+ deeppink: '#ff1493',
3634
+ deepskyblue: '#00bfff',
3635
+ dimgray: '#696969',
3636
+ dodgerblue: '#1e90ff',
3637
+ firebrick: '#b22222',
3638
+ floralwhite: '#fffaf0',
3639
+ forestgreen: '#228b22',
3640
+ fuchsia: '#ff00ff',
3641
+ gainsboro: '#dcdcdc',
3642
+ ghostwhite: '#f8f8ff',
3643
+ gold: '#ffd700',
3644
+ goldenrod: '#daa520',
3645
+ gray: '#808080',
3646
+ green: '#008000',
3647
+ greenyellow: '#adff2f',
3648
+ honeydew: '#f0fff0',
3649
+ hotpink: '#ff69b4',
3650
+ 'indianred ': '#cd5c5c',
3651
+ indigo: '#4b0082',
3652
+ ivory: '#fffff0',
3653
+ khaki: '#f0e68c',
3654
+ lavender: '#e6e6fa',
3655
+ lavenderblush: '#fff0f5',
3656
+ lawngreen: '#7cfc00',
3657
+ lemonchiffon: '#fffacd',
3658
+ lightblue: '#add8e6',
3659
+ lightcoral: '#f08080',
3660
+ lightcyan: '#e0ffff',
3661
+ lightgoldenrodyellow: '#fafad2',
3662
+ lightgrey: '#d3d3d3',
3663
+ lightgreen: '#90ee90',
3664
+ lightpink: '#ffb6c1',
3665
+ lightsalmon: '#ffa07a',
3666
+ lightseagreen: '#20b2aa',
3667
+ lightskyblue: '#87cefa',
3668
+ lightslategray: '#778899',
3669
+ lightsteelblue: '#b0c4de',
3670
+ lightyellow: '#ffffe0',
3671
+ lime: '#00ff00',
3672
+ limegreen: '#32cd32',
3673
+ linen: '#faf0e6',
3674
+ magenta: '#ff00ff',
3675
+ maroon: '#800000',
3676
+ mediumaquamarine: '#66cdaa',
3677
+ mediumblue: '#0000cd',
3678
+ mediumorchid: '#ba55d3',
3679
+ mediumpurple: '#9370d8',
3680
+ mediumseagreen: '#3cb371',
3681
+ mediumslateblue: '#7b68ee',
3682
+ mediumspringgreen: '#00fa9a',
3683
+ mediumturquoise: '#48d1cc',
3684
+ mediumvioletred: '#c71585',
3685
+ midnightblue: '#191970',
3686
+ mintcream: '#f5fffa',
3687
+ mistyrose: '#ffe4e1',
3688
+ moccasin: '#ffe4b5',
3689
+ navajowhite: '#ffdead',
3690
+ navy: '#000080',
3691
+ oldlace: '#fdf5e6',
3692
+ olive: '#808000',
3693
+ olivedrab: '#6b8e23',
3694
+ orange: '#ffa500',
3695
+ orangered: '#ff4500',
3696
+ orchid: '#da70d6',
3697
+ palegoldenrod: '#eee8aa',
3698
+ palegreen: '#98fb98',
3699
+ paleturquoise: '#afeeee',
3700
+ palevioletred: '#d87093',
3701
+ papayawhip: '#ffefd5',
3702
+ peachpuff: '#ffdab9',
3703
+ peru: '#cd853f',
3704
+ pink: '#ffc0cb',
3705
+ plum: '#dda0dd',
3706
+ powderblue: '#b0e0e6',
3707
+ purple: '#800080',
3708
+ red: '#ff0000',
3709
+ rosybrown: '#bc8f8f',
3710
+ royalblue: '#4169e1',
3711
+ saddlebrown: '#8b4513',
3712
+ salmon: '#fa8072',
3713
+ sandybrown: '#f4a460',
3714
+ seagreen: '#2e8b57',
3715
+ seashell: '#fff5ee',
3716
+ sienna: '#a0522d',
3717
+ silver: '#c0c0c0',
3718
+ skyblue: '#87ceeb',
3719
+ slateblue: '#6a5acd',
3720
+ slategray: '#708090',
3721
+ snow: '#fffafa',
3722
+ springgreen: '#00ff7f',
3723
+ steelblue: '#4682b4',
3724
+ tan: '#d2b48c',
3725
+ teal: '#008080',
3726
+ thistle: '#d8bfd8',
3727
+ tomato: '#ff6347',
3728
+ turquoise: '#40e0d0',
3729
+ violet: '#ee82ee',
3730
+ wheat: '#f5deb3',
3731
+ white: '#ffffff',
3732
+ whitesmoke: '#f5f5f5',
3733
+ yellow: '#ffff00',
3734
+ yellowgreen: '#9acd32'
3735
+ }[name.toLowerCase()];
3736
+ }
3737
+
3738
+ const SatisfiedEmoji = props => /*#__PURE__*/React.createElement(Svg, _extends({
3739
+ height: "48",
3740
+ viewBox: "0 -960 960 960",
3741
+ width: "48"
3742
+ }, props), /*#__PURE__*/React.createElement(Path, {
3743
+ d: "M626-533q22.5 0 38.25-15.75T680-587q0-22.5-15.75-38.25T626-641q-22.5 0-38.25 15.75T572-587q0 22.5 15.75 38.25T626-533Zm-292 0q22.5 0 38.25-15.75T388-587q0-22.5-15.75-38.25T334-641q-22.5 0-38.25 15.75T280-587q0 22.5 15.75 38.25T334-533Zm146 272q66 0 121.5-35.5T682-393h-52q-23 40-63 61.5T480.5-310q-46.5 0-87-21T331-393h-53q26 61 81 96.5T480-261Zm0 181q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 340q142.375 0 241.188-98.812Q820-337.625 820-480t-98.812-241.188Q622.375-820 480-820t-241.188 98.812Q140-622.375 140-480t98.812 241.188Q337.625-140 480-140Z"
3744
+ }));
3745
+ const NeutralEmoji = props => /*#__PURE__*/React.createElement(Svg, _extends({
3746
+ height: "48",
3747
+ viewBox: "0 -960 960 960",
3748
+ width: "48"
3749
+ }, props), /*#__PURE__*/React.createElement(Path, {
3750
+ d: "M626-533q22.5 0 38.25-15.75T680-587q0-22.5-15.75-38.25T626-641q-22.5 0-38.25 15.75T572-587q0 22.5 15.75 38.25T626-533Zm-292 0q22.5 0 38.25-15.75T388-587q0-22.5-15.75-38.25T334-641q-22.5 0-38.25 15.75T280-587q0 22.5 15.75 38.25T334-533Zm20 194h253v-49H354v49ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 340q142.375 0 241.188-98.812Q820-337.625 820-480t-98.812-241.188Q622.375-820 480-820t-241.188 98.812Q140-622.375 140-480t98.812 241.188Q337.625-140 480-140Z"
3751
+ }));
3752
+ const DissatisfiedEmoji = props => /*#__PURE__*/React.createElement(Svg, _extends({
3753
+ height: "48",
3754
+ viewBox: "0 -960 960 960",
3755
+ width: "48"
3756
+ }, props), /*#__PURE__*/React.createElement(Path, {
3757
+ d: "M626-533q22.5 0 38.25-15.75T680-587q0-22.5-15.75-38.25T626-641q-22.5 0-38.25 15.75T572-587q0 22.5 15.75 38.25T626-533Zm-292 0q22.5 0 38.25-15.75T388-587q0-22.5-15.75-38.25T334-641q-22.5 0-38.25 15.75T280-587q0 22.5 15.75 38.25T334-533Zm146.174 116Q413-417 358.5-379.5T278-280h53q22-42 62.173-65t87.5-23Q528-368 567.5-344.5T630-280h52q-25-63-79.826-100-54.826-37-122-37ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 340q142.375 0 241.188-98.812Q820-337.625 820-480t-98.812-241.188Q622.375-820 480-820t-241.188 98.812Q140-622.375 140-480t98.812 241.188Q337.625-140 480-140Z"
3758
+ }));
3759
+ const VeryDissatisfiedEmoji = props => /*#__PURE__*/React.createElement(Svg, _extends({
3760
+ height: "48",
3761
+ viewBox: "0 -960 960 960",
3762
+ width: "48"
3763
+ }, props), /*#__PURE__*/React.createElement(Path, {
3764
+ d: "M480-417q-67 0-121.5 37.5T278-280h404q-25-63-80-100t-122-37Zm-183-72 50-45 45 45 31-36-45-45 45-45-31-36-45 45-50-45-31 36 45 45-45 45 31 36Zm272 0 44-45 51 45 31-36-45-45 45-45-31-36-51 45-44-45-31 36 44 45-44 45 31 36ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 340q142 0 241-99t99-241q0-142-99-241t-241-99q-142 0-241 99t-99 241q0 142 99 241t241 99Z"
3765
+ }));
3766
+ const VerySatisfiedEmoji = props => /*#__PURE__*/React.createElement(Svg, _extends({
3767
+ height: "48",
3768
+ viewBox: "0 -960 960 960",
3769
+ width: "48"
3770
+ }, props), /*#__PURE__*/React.createElement(Path, {
3771
+ d: "M479.504-261Q537-261 585.5-287q48.5-26 78.5-72.4 6-11.6-.75-22.6-6.75-11-20.25-11H316.918Q303-393 296.5-382t-.5 22.6q30 46.4 78.5 72.4 48.5 26 105.004 26ZM347-578l27 27q7.636 8 17.818 8Q402-543 410-551q8-8 8-18t-8-18l-42-42q-8.8-9-20.9-9-12.1 0-21.1 9l-42 42q-8 7.636-8 17.818Q276-559 284-551q8 8 18 8t18-8l27-27Zm267 0 27 27q7.714 8 18 8t18-8q8-7.636 8-17.818Q685-579 677-587l-42-42q-8.8-9-20.9-9-12.1 0-21.1 9l-42 42q-8 7.714-8 18t8 18q7.636 8 17.818 8Q579-543 587-551l27-27ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 340q142.375 0 241.188-98.812Q820-337.625 820-480t-98.812-241.188Q622.375-820 480-820t-241.188 98.812Q140-622.375 140-480t98.812 241.188Q337.625-140 480-140Z"
3772
+ }));
3773
+ const CheckSVG = props => /*#__PURE__*/React.createElement(Svg, _extends({
3774
+ width: "16",
3775
+ height: "16",
3776
+ viewBox: "0 0 16 12"
3777
+ }, props), /*#__PURE__*/React.createElement(Path, {
3778
+ d: "M5.30769 10.6923L4.77736 11.2226C4.91801 11.3633 5.10878 11.4423 5.30769 11.4423C5.5066 11.4423 5.69737 11.3633 5.83802 11.2226L5.30769 10.6923ZM15.5303 1.53033C15.8232 1.23744 15.8232 0.762563 15.5303 0.46967C15.2374 0.176777 14.7626 0.176777 14.4697 0.46967L15.5303 1.53033ZM1.53033 5.85429C1.23744 5.56139 0.762563 5.56139 0.46967 5.85429C0.176777 6.14718 0.176777 6.62205 0.46967 6.91495L1.53033 5.85429ZM5.83802 11.2226L15.5303 1.53033L14.4697 0.46967L4.77736 10.162L5.83802 11.2226ZM0.46967 6.91495L4.77736 11.2226L5.83802 10.162L1.53033 5.85429L0.46967 6.91495Z"
3779
+ }));
3780
+ const CancelSVG = props => /*#__PURE__*/React.createElement(Svg, _extends({
3781
+ width: "12",
3782
+ height: "12",
3783
+ viewBox: "0 0 12 12",
3784
+ fill: "none"
3785
+ }, props), /*#__PURE__*/React.createElement(Path, {
3786
+ "fill-rule": "evenodd",
3787
+ "clip-rule": "evenodd",
3788
+ d: "M0.164752 0.164752C0.384422 -0.0549175 0.740578 -0.0549175 0.960248 0.164752L6 5.20451L11.0398 0.164752C11.2594 -0.0549175 11.6156 -0.0549175 11.8352 0.164752C12.0549 0.384422 12.0549 0.740578 11.8352 0.960248L6.79549 6L11.8352 11.0398C12.0549 11.2594 12.0549 11.6156 11.8352 11.8352C11.6156 12.0549 11.2594 12.0549 11.0398 11.8352L6 6.79549L0.960248 11.8352C0.740578 12.0549 0.384422 12.0549 0.164752 11.8352C-0.0549175 11.6156 -0.0549175 11.2594 0.164752 11.0398L5.20451 6L0.164752 0.960248C-0.0549175 0.740578 -0.0549175 0.384422 0.164752 0.164752Z",
3789
+ fill: "black"
3790
+ }));
3791
+
3792
+ function BottomSection({
3793
+ text,
3794
+ submitDisabled,
3795
+ appearance,
3796
+ onSubmit,
3797
+ link
3798
+ }) {
3799
+ return /*#__PURE__*/React.createElement(View, {
3800
+ style: styles$5.bottomSection
3801
+ }, /*#__PURE__*/React.createElement(TouchableOpacity, {
3802
+ style: [styles$5.button, {
3803
+ backgroundColor: appearance.submitButtonColor
3804
+ }],
3805
+ disabled: submitDisabled,
3806
+ onPress: () => {
3807
+ onSubmit();
3808
+ if (link) {
3809
+ Linking.canOpenURL(link).then(supported => {
3810
+ if (supported) {
3811
+ Linking.openURL(link);
3812
+ }
3813
+ });
3814
+ }
3815
+ }
3816
+ }, /*#__PURE__*/React.createElement(Text, {
3817
+ style: [styles$5.buttonText, {
3818
+ color: appearance.submitButtonTextColor
3819
+ }]
3820
+ }, text)));
3821
+ }
3822
+ const styles$5 = StyleSheet.create({
3823
+ bottomSection: {
3824
+ padding: 10
3825
+ },
3826
+ button: {
3827
+ padding: 10,
3828
+ borderRadius: 5,
3829
+ alignItems: 'center'
3830
+ },
3831
+ buttonText: {
3832
+ fontSize: 16
3833
+ }
3834
+ });
3835
+
3836
+ function QuestionHeader({
3837
+ question,
3838
+ description,
3839
+ descriptionContentType
3840
+ }) {
3841
+ return /*#__PURE__*/React.createElement(View, {
3842
+ style: styles$4.container
3843
+ }, /*#__PURE__*/React.createElement(Text, {
3844
+ style: styles$4.question
3845
+ }, question), description && descriptionContentType === SurveyQuestionDescriptionContentType.Text && /*#__PURE__*/React.createElement(Text, {
3846
+ style: styles$4.description
3847
+ }, description));
3848
+ }
3849
+ const styles$4 = StyleSheet.create({
3850
+ container: {
3851
+ padding: 10
3852
+ },
3853
+ question: {
3854
+ fontSize: 18,
3855
+ fontWeight: 'bold'
3856
+ },
3857
+ description: {
3858
+ fontSize: 14,
3859
+ marginTop: 5
3860
+ }
3861
+ });
3862
+
3863
+ function OpenTextQuestion({
3864
+ question,
3865
+ appearance,
3866
+ onSubmit
3867
+ }) {
3868
+ var _a;
3869
+ const [text, setText] = useState('');
3870
+ return /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(QuestionHeader, {
3871
+ question: question.question,
3872
+ description: question.description,
3873
+ descriptionContentType: question.descriptionContentType
3874
+ }), /*#__PURE__*/React.createElement(View, {
3875
+ style: styles$3.textInputContainer
3876
+ }, /*#__PURE__*/React.createElement(TextInput, {
3877
+ style: styles$3.textInput,
3878
+ multiline: true,
3879
+ numberOfLines: 4,
3880
+ placeholder: appearance.placeholder,
3881
+ onChangeText: setText,
3882
+ value: text
3883
+ })), /*#__PURE__*/React.createElement(BottomSection, {
3884
+ text: (_a = question.buttonText) !== null && _a !== void 0 ? _a : appearance.submitButtonText,
3885
+ submitDisabled: !text && !question.optional,
3886
+ appearance: appearance,
3887
+ onSubmit: () => onSubmit(text)
3888
+ }));
3889
+ }
3890
+ function LinkQuestion({
3891
+ question,
3892
+ appearance,
3893
+ onSubmit
3894
+ }) {
3895
+ var _a, _b;
3896
+ question = question;
3897
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(QuestionHeader, {
3898
+ question: question.question,
3899
+ description: question.description,
3900
+ descriptionContentType: question.descriptionContentType
3901
+ }), /*#__PURE__*/React.createElement(BottomSection, {
3902
+ text: (_b = (_a = question.buttonText) !== null && _a !== void 0 ? _a : appearance.submitButtonText) !== null && _b !== void 0 ? _b : 'Submit',
3903
+ submitDisabled: false,
3904
+ link: question.link,
3905
+ appearance: appearance,
3906
+ onSubmit: () => onSubmit('link clicked')
3907
+ }));
3908
+ }
3909
+ function RatingQuestion({
3910
+ question,
3911
+ appearance,
3912
+ onSubmit
3913
+ }) {
3914
+ var _a;
3915
+ //const starting = question.scale === 10 ? 0 : 1;
3916
+ const [rating, setRating] = useState(null);
3917
+ question = question;
3918
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(QuestionHeader, {
3919
+ question: question.question,
3920
+ description: question.description,
3921
+ descriptionContentType: question.descriptionContentType
3922
+ }), /*#__PURE__*/React.createElement(View, {
3923
+ style: styles$3.ratingSection
3924
+ }, /*#__PURE__*/React.createElement(View, {
3925
+ style: styles$3.ratingOptions
3926
+ }, question.display === SurveyRatingDisplay.Emoji && /*#__PURE__*/React.createElement(View, {
3927
+ style: styles$3.ratingOptionsEmoji
3928
+ }, (question.scale === 3 ? threeScaleEmojis : fiveScaleEmojis).map((Emoji, idx) => {
3929
+ const active = idx + 1 === rating;
3930
+ return /*#__PURE__*/React.createElement(TouchableOpacity, {
3931
+ key: idx,
3932
+ style: styles$3.ratingsEmoji,
3933
+ onPress: () => setRating(idx + 1)
3934
+ }, /*#__PURE__*/React.createElement(Emoji, {
3935
+ fill: active ? appearance.ratingButtonActiveColor : appearance.ratingButtonColor
3936
+ }));
3937
+ })), question.display === SurveyRatingDisplay.Number && /*#__PURE__*/React.createElement(View, {
3938
+ style: [styles$3.ratingOptionsNumber, {
3939
+ borderColor: appearance.borderColor
3940
+ }]
3941
+ }, getScaleNumbers(question.scale).map((number, idx) => {
3942
+ const active = rating === number;
3943
+ return /*#__PURE__*/React.createElement(RatingButton, {
3944
+ key: idx,
3945
+ index: idx,
3946
+ active: active,
3947
+ appearance: appearance,
3948
+ num: number,
3949
+ setActiveNumber: setRating
3950
+ });
3951
+ }))), /*#__PURE__*/React.createElement(View, {
3952
+ style: styles$3.ratingText
3953
+ }, /*#__PURE__*/React.createElement(Text, null, question.lowerBoundLabel), /*#__PURE__*/React.createElement(Text, null, question.upperBoundLabel))), /*#__PURE__*/React.createElement(BottomSection, {
3954
+ text: (_a = question.buttonText) !== null && _a !== void 0 ? _a : appearance.submitButtonText,
3955
+ submitDisabled: rating === null && !question.optional,
3956
+ appearance: appearance,
3957
+ onSubmit: () => onSubmit(rating)
3958
+ }));
3959
+ }
3960
+ function RatingButton({
3961
+ index,
3962
+ num,
3963
+ active,
3964
+ appearance,
3965
+ setActiveNumber
3966
+ }) {
3967
+ const backgroundColor = active ? appearance.ratingButtonActiveColor : appearance.ratingButtonColor;
3968
+ const textColor = getContrastingTextColor(backgroundColor);
3969
+ return /*#__PURE__*/React.createElement(TouchableOpacity, {
3970
+ style: [styles$3.ratingsNumber, index === 0 && {
3971
+ borderLeftWidth: 0
3972
+ }, {
3973
+ backgroundColor,
3974
+ borderColor: appearance.borderColor
3975
+ }],
3976
+ onPress: () => setActiveNumber(num)
3977
+ }, /*#__PURE__*/React.createElement(Text, {
3978
+ style: {
3979
+ color: textColor
3980
+ }
3981
+ }, num));
3982
+ }
3983
+ function MultipleChoiceQuestion({
3984
+ question,
3985
+ appearance,
3986
+ onSubmit
3987
+ }) {
3988
+ var _a;
3989
+ question = question;
3990
+ const allowMultiple = question.type === SurveyQuestionType.MultipleChoice;
3991
+ const openChoice = question.hasOpenChoice ? question.choices[question.choices.length - 1] : null;
3992
+ const choices = useMemo(() => getDisplayOrderChoices(question), [question]);
3993
+ const [selectedChoices, setSelectedChoices] = useState([]);
3994
+ const [openEndedInput, setOpenEndedInput] = useState('');
3995
+ return /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(QuestionHeader, {
3996
+ question: question.question,
3997
+ description: question.description,
3998
+ descriptionContentType: question.descriptionContentType
3999
+ }), /*#__PURE__*/React.createElement(View, {
4000
+ style: styles$3.multipleChoiceOptions
4001
+ }, choices.map((choice, idx) => {
4002
+ const isOpenChoice = choice === openChoice;
4003
+ const isSelected = selectedChoices.includes(choice);
4004
+ return /*#__PURE__*/React.createElement(Pressable, {
4005
+ key: idx,
4006
+ style: [styles$3.choiceOption, isSelected ? {
4007
+ borderColor: 'black'
4008
+ } : {}],
4009
+ onPress: () => {
4010
+ if (allowMultiple) {
4011
+ setSelectedChoices(isSelected ? selectedChoices.filter(c => c !== choice) : [...selectedChoices, choice]);
4012
+ } else {
4013
+ setSelectedChoices([choice]);
4014
+ }
4015
+ }
4016
+ }, /*#__PURE__*/React.createElement(View, {
4017
+ style: styles$3.choiceText
4018
+ }, /*#__PURE__*/React.createElement(Text, {
4019
+ style: {
4020
+ flexGrow: 1
4021
+ }
4022
+ }, choice, isOpenChoice ? ':' : ''), /*#__PURE__*/React.createElement(View, {
4023
+ style: styles$3.rightCheckArea
4024
+ }, isSelected && /*#__PURE__*/React.createElement(CheckSVG, null))), isOpenChoice && /*#__PURE__*/React.createElement(TextInput, {
4025
+ style: styles$3.openEndedInput,
4026
+ onChangeText: userValue => {
4027
+ setOpenEndedInput(userValue);
4028
+ if (!isSelected) {
4029
+ setSelectedChoices(allowMultiple ? [...selectedChoices, choice] : [choice]);
4030
+ }
4031
+ }
4032
+ }));
4033
+ })), /*#__PURE__*/React.createElement(BottomSection, {
4034
+ text: (_a = question.buttonText) !== null && _a !== void 0 ? _a : appearance.submitButtonText,
4035
+ submitDisabled: !question.optional && (selectedChoices.length === 0 || openChoice !== null && selectedChoices.includes(openChoice) && openEndedInput.length === 0),
4036
+ appearance: appearance,
4037
+ onSubmit: () => {
4038
+ // If open choice is selected, replace the choice name with the actual value entered
4039
+ const result = selectedChoices.map(c => c === openChoice ? openEndedInput : c);
4040
+ onSubmit(result.length === 1 ? result[0] : result);
4041
+ }
4042
+ }));
4043
+ }
4044
+ const threeScaleEmojis = [DissatisfiedEmoji, NeutralEmoji, SatisfiedEmoji];
4045
+ const fiveScaleEmojis = [VeryDissatisfiedEmoji, DissatisfiedEmoji, NeutralEmoji, SatisfiedEmoji, VerySatisfiedEmoji];
4046
+ const fiveScaleNumbers = [1, 2, 3, 4, 5];
4047
+ const sevenScaleNumbers = [1, 2, 3, 4, 5, 6, 7];
4048
+ const tenScaleNumbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
4049
+ function getScaleNumbers(scale) {
4050
+ switch (scale) {
4051
+ case 5:
4052
+ return fiveScaleNumbers;
4053
+ case 7:
4054
+ return sevenScaleNumbers;
4055
+ case 10:
4056
+ return tenScaleNumbers;
4057
+ default:
4058
+ return fiveScaleNumbers;
4059
+ }
4060
+ }
4061
+ const styles$3 = StyleSheet.create({
4062
+ textInputContainer: {
4063
+ padding: 10
4064
+ },
4065
+ textInput: {
4066
+ borderColor: '#ccc',
4067
+ borderWidth: 1,
4068
+ padding: 10,
4069
+ marginVertical: 10,
4070
+ backgroundColor: 'white',
4071
+ fontSize: 16
4072
+ },
4073
+ ratingSection: {
4074
+ marginVertical: 10
4075
+ },
4076
+ ratingOptions: {
4077
+ flexDirection: 'row',
4078
+ justifyContent: 'space-between'
4079
+ },
4080
+ ratingOptionsEmoji: {
4081
+ flexDirection: 'row',
4082
+ justifyContent: 'space-between',
4083
+ flexWrap: 'wrap' // Allows items to wrap to a new line
4084
+ },
4085
+ ratingsEmoji: {
4086
+ padding: 10
4087
+ },
4088
+ ratingOptionsNumber: {
4089
+ margin: 10,
4090
+ flexGrow: 1,
4091
+ flexDirection: 'row',
4092
+ justifyContent: 'space-between',
4093
+ borderRadius: 5,
4094
+ borderWidth: 1,
4095
+ overflow: 'hidden'
4096
+ },
4097
+ ratingsNumber: {
4098
+ flex: 1,
4099
+ paddingVertical: 10,
4100
+ alignItems: 'center',
4101
+ borderLeftWidth: 1
4102
+ },
4103
+ ratingText: {
4104
+ flexDirection: 'row',
4105
+ justifyContent: 'space-between',
4106
+ padding: 10
4107
+ },
4108
+ multipleChoiceOptions: {
4109
+ padding: 10
4110
+ },
4111
+ choiceOption: {
4112
+ flexDirection: 'column',
4113
+ marginVertical: 5,
4114
+ borderWidth: 1,
4115
+ borderColor: 'grey',
4116
+ borderRadius: 5,
4117
+ padding: 10,
4118
+ backgroundColor: 'white'
4119
+ },
4120
+ choiceText: {
4121
+ flexDirection: 'row'
4122
+ },
4123
+ rightCheckArea: {
4124
+ flexGrow: 0
4125
+ },
4126
+ openEndedInput: {
4127
+ padding: 5
4128
+ }
4129
+ });
4130
+
4131
+ const getSurveyInteractionProperty = (survey, action) => {
4132
+ let surveyProperty = `$survey_${action}/${survey.id}`;
4133
+ if (survey.current_iteration && survey.current_iteration > 0) {
4134
+ surveyProperty = `$survey_${action}/${survey.id}/${survey.current_iteration}`;
4135
+ }
4136
+ return surveyProperty;
4137
+ };
4138
+ const sendSurveyShownEvent = (survey, posthog) => {
4139
+ posthog.capture('survey shown', {
4140
+ $survey_name: survey.name,
4141
+ $survey_id: survey.id,
4142
+ $survey_iteration: survey.current_iteration,
4143
+ $survey_iteration_start_date: survey.current_iteration_start_date
4144
+ });
4145
+ };
4146
+ const sendSurveyEvent = (responses = {}, survey, posthog) => {
4147
+ posthog.capture('survey sent', {
4148
+ $survey_name: survey.name,
4149
+ $survey_id: survey.id,
4150
+ $survey_iteration: survey.current_iteration,
4151
+ $survey_iteration_start_date: survey.current_iteration_start_date,
4152
+ $survey_questions: survey.questions.map(question => question.question),
4153
+ ...responses,
4154
+ $set: {
4155
+ [getSurveyInteractionProperty(survey, 'responded')]: true
4156
+ }
4157
+ });
4158
+ };
4159
+ const dismissedSurveyEvent = (survey, posthog) => {
4160
+ posthog.capture('survey dismissed', {
4161
+ $survey_name: survey.name,
4162
+ $survey_id: survey.id,
4163
+ $survey_iteration: survey.current_iteration,
4164
+ $survey_iteration_start_date: survey.current_iteration_start_date,
4165
+ $set: {
4166
+ [getSurveyInteractionProperty(survey, 'dismissed')]: true
4167
+ }
4168
+ });
4169
+ };
4170
+ function Questions({
4171
+ survey,
4172
+ appearance,
4173
+ styleOverrides,
4174
+ onSubmit
4175
+ }) {
4176
+ const [questionsResponses, setQuestionsResponses] = useState({});
4177
+ const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
4178
+ const surveyQuestions = useMemo(() => getDisplayOrderQuestions(survey), [survey]);
4179
+ const posthog = usePostHog();
4180
+ const onNextButtonClick = ({
4181
+ res,
4182
+ originalQuestionIndex
4183
+ }) => {
4184
+ const responseKey = originalQuestionIndex === 0 ? `$survey_response` : `$survey_response_${originalQuestionIndex}`;
4185
+ setQuestionsResponses({
4186
+ ...questionsResponses,
4187
+ [responseKey]: res
4188
+ });
4189
+ const isLastDisplayedQuestion = originalQuestionIndex === survey.questions.length - 1;
4190
+ if (isLastDisplayedQuestion) {
4191
+ sendSurveyEvent({
4192
+ ...questionsResponses,
4193
+ [responseKey]: res
4194
+ }, survey, posthog);
4195
+ onSubmit();
4196
+ } else {
4197
+ setCurrentQuestionIndex(originalQuestionIndex + 1);
4198
+ }
4199
+ };
4200
+ const question = surveyQuestions[currentQuestionIndex];
4201
+ return /*#__PURE__*/React.createElement(ScrollView, {
4202
+ style: [styleOverrides, {
4203
+ flexGrow: 0
4204
+ }]
4205
+ }, getQuestionComponent({
4206
+ question,
4207
+ appearance,
4208
+ onSubmit: res => onNextButtonClick({
4209
+ res,
4210
+ originalQuestionIndex: question.originalQuestionIndex
4211
+ // displayQuestionIndex: currentQuestionIndex,
4212
+ })
4213
+ }));
4214
+ }
4215
+ const getQuestionComponent = props => {
4216
+ const questionComponents = {
4217
+ open: OpenTextQuestion,
4218
+ link: LinkQuestion,
4219
+ rating: RatingQuestion,
4220
+ multiple_choice: MultipleChoiceQuestion,
4221
+ single_choice: MultipleChoiceQuestion
4222
+ };
4223
+ const Component = questionComponents[props.question.type];
4224
+ return /*#__PURE__*/React.createElement(Component, _extends({
4225
+ key: props.question.originalQuestionIndex
4226
+ }, props));
4227
+ };
4228
+
4229
+ const isMatchingRegex = function (value, pattern) {
4230
+ if (!isValidRegex(pattern)) {
4231
+ return false;
4232
+ }
4233
+ try {
4234
+ return new RegExp(pattern).test(value);
4235
+ } catch (_a) {
4236
+ return false;
4237
+ }
4238
+ };
4239
+ const isValidRegex = function (str) {
4240
+ try {
4241
+ new RegExp(str);
4242
+ } catch (_a) {
4243
+ return false;
4244
+ }
4245
+ return true;
4246
+ };
4247
+ const surveyValidationMap = {
4248
+ icontains: (targets, value) => targets.some(target => value.toLowerCase().includes(target.toLowerCase())),
4249
+ not_icontains: (targets, value) => targets.every(target => !value.toLowerCase().includes(target.toLowerCase())),
4250
+ regex: (targets, value) => targets.some(target => isMatchingRegex(value, target)),
4251
+ not_regex: (targets, value) => targets.every(target => !isMatchingRegex(value, target)),
4252
+ exact: (targets, value) => targets.some(target => value === target),
4253
+ is_not: (targets, value) => targets.every(target => value !== target)
4254
+ };
4255
+ function defaultMatchType(matchType) {
4256
+ return matchType !== null && matchType !== void 0 ? matchType : SurveyMatchType.Icontains;
4257
+ }
4258
+ function doesSurveyDeviceTypesMatch(survey) {
4259
+ var _a;
4260
+ if (!((_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.deviceTypes) || survey.conditions.deviceTypes.length === 0) {
4261
+ return true;
4262
+ }
4263
+ const deviceType = currentDeviceType;
4264
+ return surveyValidationMap[defaultMatchType(survey.conditions.deviceTypesMatchType)](survey.conditions.deviceTypes, deviceType);
4265
+ }
4266
+ function getActiveMatchingSurveys(surveys, flags, seenSurveys, activatedSurveys
4267
+ // lastSeenSurveyDate: Date | undefined
4268
+ ) {
4269
+ return surveys.filter(survey => {
4270
+ var _a, _b;
4271
+ // Is Active
4272
+ if (!survey.start_date || survey.end_date) {
4273
+ return false;
4274
+ }
4275
+ // device type check
4276
+ if (!doesSurveyDeviceTypesMatch(survey)) {
4277
+ return false;
4278
+ }
4279
+ if (seenSurveys.includes(survey.id) && !canActivateRepeatedly(survey)) {
4280
+ return false;
4281
+ }
4282
+ // const surveyWaitPeriodInDays = survey.conditions?.seenSurveyWaitPeriodInDays
4283
+ // if (surveyWaitPeriodInDays && lastSeenSurveyDate) {
4284
+ // const today = new Date()
4285
+ // const diff = Math.abs(today.getTime() - lastSeenSurveyDate.getTime())
4286
+ // const diffDaysFromToday = Math.ceil(diff / (1000 * 3600 * 24))
4287
+ // if (diffDaysFromToday < surveyWaitPeriodInDays) {
4288
+ // return false
4289
+ // }
4290
+ // }
4291
+ // URL and CSS selector conditions are currently ignored
4292
+ if (!survey.linked_flag_key && !survey.targeting_flag_key && !survey.internal_targeting_flag_key && !((_a = survey.feature_flag_keys) === null || _a === void 0 ? void 0 : _a.length)) {
4293
+ // Survey is targeting All Users with no conditions
4294
+ return true;
4295
+ }
4296
+ const linkedFlagCheck = survey.linked_flag_key ? flags[survey.linked_flag_key] === true : true;
4297
+ const targetingFlagCheck = survey.targeting_flag_key ? flags[survey.targeting_flag_key] === true : true;
4298
+ const eventBasedTargetingFlagCheck = hasEvents(survey) ? activatedSurveys.has(survey.id) : true;
4299
+ const internalTargetingFlagCheck = survey.internal_targeting_flag_key && !canActivateRepeatedly(survey) ? flags[survey.internal_targeting_flag_key] === true : true;
4300
+ const flagsCheck = ((_b = survey.feature_flag_keys) === null || _b === void 0 ? void 0 : _b.length) ? survey.feature_flag_keys.every(({
4301
+ key,
4302
+ value
4303
+ }) => {
4304
+ return !key || !value || flags[value] === true;
4305
+ }) : true;
4306
+ return linkedFlagCheck && targetingFlagCheck && internalTargetingFlagCheck && eventBasedTargetingFlagCheck && flagsCheck;
4307
+ });
4308
+ }
4309
+
4310
+ function useSurveyStorage() {
4311
+ const posthogStorage = usePostHog();
4312
+ const [lastSeenSurveyDate, setLastSeenSurveyDate] = useState(undefined);
4313
+ const [seenSurveys, setSeenSurveys] = useState([]);
4314
+ useEffect(() => {
4315
+ posthogStorage.ready().then(() => {
4316
+ const lastSeenSurveyDate = posthogStorage.getPersistedProperty(PostHogPersistedProperty.SurveyLastSeenDate);
4317
+ if (typeof lastSeenSurveyDate === 'string') {
4318
+ setLastSeenSurveyDate(new Date(lastSeenSurveyDate));
4319
+ }
4320
+ const serialisedSeenSurveys = posthogStorage.getPersistedProperty(PostHogPersistedProperty.SurveysSeen);
4321
+ if (typeof serialisedSeenSurveys === 'string') {
4322
+ const parsedSeenSurveys = JSON.parse(serialisedSeenSurveys);
4323
+ if (Array.isArray(parsedSeenSurveys) && typeof parsedSeenSurveys[0] === 'string') {
4324
+ setSeenSurveys(parsedSeenSurveys);
4325
+ }
4326
+ }
4327
+ });
4328
+ }, [posthogStorage]);
4329
+ return {
4330
+ seenSurveys,
4331
+ setSeenSurvey: useCallback(surveyId => {
4332
+ setSeenSurveys(current => {
4333
+ // To keep storage bounded, only keep the last 20 seen surveys
4334
+ const newValue = [surveyId, ...current.filter(id => id !== surveyId)];
4335
+ posthogStorage.setPersistedProperty(PostHogPersistedProperty.SurveysSeen, JSON.stringify(newValue.slice(0, 20)));
4336
+ return newValue;
4337
+ });
4338
+ }, [posthogStorage]),
4339
+ lastSeenSurveyDate,
4340
+ setLastSeenSurveyDate: useCallback(date => {
4341
+ setLastSeenSurveyDate(date);
4342
+ posthogStorage.setPersistedProperty(PostHogPersistedProperty.SurveyLastSeenDate, date.toISOString());
4343
+ }, [posthogStorage])
4344
+ };
4345
+ }
4346
+
4347
+ const SURVEY_SHOWN_EVENT_NAME = 'survey shown';
4348
+ function useActivatedSurveys(posthog, surveys) {
4349
+ const [activatedSurveys, setActivatedSurveys] = useState(new Set());
4350
+ const eventMap = useMemo(() => {
4351
+ var _a, _b, _c, _d;
4352
+ const newEventMap = new Map();
4353
+ for (const survey of surveys.filter(hasEvents)) {
4354
+ for (const event of (_c = (_b = (_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.values) !== null && _c !== void 0 ? _c : []) {
4355
+ const knownSurveys = (_d = newEventMap.get(event.name)) !== null && _d !== void 0 ? _d : [];
4356
+ knownSurveys.push(survey.id);
4357
+ newEventMap.set(event.name, knownSurveys);
4358
+ }
4359
+ }
4360
+ return newEventMap;
4361
+ }, [surveys]);
4362
+ useEffect(() => {
4363
+ if (eventMap.size > 0) {
4364
+ return posthog.on('capture', payload => {
4365
+ var _a;
4366
+ if (eventMap.has(payload.event)) {
4367
+ setActivatedSurveys(current => {
4368
+ var _a;
4369
+ return new Set([...current, ...((_a = eventMap.get(payload.event)) !== null && _a !== void 0 ? _a : [])]);
4370
+ });
4371
+ } else if (payload.event === SURVEY_SHOWN_EVENT_NAME) {
4372
+ // remove survey that from activatedSurveys here.
4373
+ const surveyId = (_a = payload.properties) === null || _a === void 0 ? void 0 : _a.$survey_id;
4374
+ if (surveyId) {
4375
+ setActivatedSurveys(current => {
4376
+ if (!current.has(surveyId)) {
4377
+ return current;
4378
+ }
4379
+ const next = new Set(current);
4380
+ next.delete(surveyId);
4381
+ return next;
4382
+ });
4383
+ }
4384
+ }
4385
+ });
4386
+ }
4387
+ }, [eventMap, posthog]);
4388
+ return activatedSurveys;
4389
+ }
4390
+
4391
+ function Cancel({
4392
+ onPress,
4393
+ appearance
4394
+ }) {
4395
+ return /*#__PURE__*/React.createElement(TouchableOpacity, {
4396
+ style: [styles$2.cancelBtnWrapper, {
4397
+ borderColor: appearance.borderColor
4398
+ }],
4399
+ onPress: onPress
4400
+ }, /*#__PURE__*/React.createElement(CancelSVG, null));
4401
+ }
4402
+ const styles$2 = StyleSheet.create({
4403
+ cancelBtnWrapper: {
4404
+ width: 40,
4405
+ height: 40,
4406
+ borderRadius: 20,
4407
+ borderWidth: 1,
4408
+ justifyContent: 'center',
4409
+ alignItems: 'center',
4410
+ backgroundColor: 'white'
4411
+ }
4412
+ });
4413
+
4414
+ function ConfirmationMessage({
4415
+ appearance,
4416
+ header,
4417
+ description,
4418
+ contentType,
4419
+ onClose,
4420
+ styleOverrides,
4421
+ isModal
4422
+ }) {
4423
+ const textColor = getContrastingTextColor(appearance.backgroundColor);
4424
+ return /*#__PURE__*/React.createElement(View, {
4425
+ style: styleOverrides
4426
+ }, /*#__PURE__*/React.createElement(View, {
4427
+ style: styles$1.thankYouMessageContainer
4428
+ }, /*#__PURE__*/React.createElement(Text, {
4429
+ style: [styles$1.thankYouMessageHeader, {
4430
+ color: textColor
4431
+ }]
4432
+ }, header), description && contentType === SurveyQuestionDescriptionContentType.Text && /*#__PURE__*/React.createElement(Text, null, description)), isModal && /*#__PURE__*/React.createElement(BottomSection, {
4433
+ text: appearance.thankYouMessageCloseButtonText,
4434
+ submitDisabled: false,
4435
+ appearance: appearance,
4436
+ onSubmit: onClose
4437
+ }));
4438
+ }
4439
+ const styles$1 = StyleSheet.create({
4440
+ thankYouMessageContainer: {
4441
+ padding: 10
4442
+ },
4443
+ thankYouMessageHeader: {
4444
+ fontSize: 18,
4445
+ fontWeight: 'bold'
4446
+ }
4447
+ });
4448
+
4449
+ let OptionalRNSafeArea = undefined;
4450
+ try {
4451
+ OptionalRNSafeArea = require('react-native-safe-area-context');
4452
+ } catch (e) {}
4453
+ function createDefaultInsets() {
4454
+ // If the library isn't available, fall back to a default which should cover most devices
4455
+ return {
4456
+ top: 60,
4457
+ bottom: 30,
4458
+ left: 0,
4459
+ right: 0
4460
+ };
4461
+ }
4462
+ const useOptionalSafeAreaInsets = () => {
4463
+ var _a;
4464
+ const useSafeAreaInsets = (_a = OptionalRNSafeArea === null || OptionalRNSafeArea === void 0 ? void 0 : OptionalRNSafeArea.useSafeAreaInsets) !== null && _a !== void 0 ? _a : createDefaultInsets;
4465
+ try {
4466
+ return useSafeAreaInsets();
4467
+ } catch (err) {
4468
+ return createDefaultInsets();
4469
+ }
4470
+ };
4471
+
4472
+ function SurveyModal(props) {
4473
+ var _a;
4474
+ const {
4475
+ survey,
4476
+ appearance,
4477
+ onShow
4478
+ } = props;
4479
+ const [isSurveySent, setIsSurveySent] = useState(false);
4480
+ const onClose = useCallback(() => props.onClose(isSurveySent), [isSurveySent, props]);
4481
+ const insets = useOptionalSafeAreaInsets();
4482
+ const [isVisible] = useState(true);
4483
+ const shouldShowConfirmation = isSurveySent && appearance.thankYouMessageHeader;
4484
+ useEffect(() => {
4485
+ if (isVisible) {
4486
+ onShow();
4487
+ }
4488
+ }, [isVisible, onShow]);
4489
+ if (!isVisible) {
4490
+ return null;
4491
+ }
4492
+ return /*#__PURE__*/React.createElement(Modal, {
4493
+ animationType: "fade",
4494
+ transparent: true,
4495
+ onRequestClose: onClose,
4496
+ statusBarTranslucent: true
4497
+ }, /*#__PURE__*/React.createElement(KeyboardAvoidingView, {
4498
+ behavior: Platform.OS === 'ios' ? 'padding' : 'height',
4499
+ style: {
4500
+ flex: 1,
4501
+ justifyContent: 'flex-end'
4502
+ },
4503
+ keyboardVerticalOffset: Platform.OS === 'ios' ? 10 : 0
4504
+ }, /*#__PURE__*/React.createElement(TouchableWithoutFeedback, {
4505
+ onPress: Keyboard.dismiss,
4506
+ accessible: false
4507
+ }, /*#__PURE__*/React.createElement(View, {
4508
+ style: styles.modalBackdrop
4509
+ }, /*#__PURE__*/React.createElement(Pressable, {
4510
+ onPress: onClose,
4511
+ accessible: false
4512
+ }, /*#__PURE__*/React.createElement(View, {
4513
+ style: [styles.modalContent, {
4514
+ borderColor: appearance.borderColor,
4515
+ backgroundColor: appearance.backgroundColor,
4516
+ marginBottom: insets.bottom + 10,
4517
+ marginHorizontal: 10
4518
+ }]
4519
+ }, !shouldShowConfirmation ? /*#__PURE__*/React.createElement(Questions, {
4520
+ survey: survey,
4521
+ appearance: appearance,
4522
+ onSubmit: () => setIsSurveySent(true)
4523
+ }) : /*#__PURE__*/React.createElement(ConfirmationMessage, {
4524
+ appearance: appearance,
4525
+ header: appearance.thankYouMessageHeader,
4526
+ description: appearance.thankYouMessageDescription,
4527
+ contentType: (_a = appearance.thankYouMessageDescriptionContentType) !== null && _a !== void 0 ? _a : SurveyQuestionDescriptionContentType.Text,
4528
+ onClose: onClose,
4529
+ isModal: true
4530
+ }), /*#__PURE__*/React.createElement(View, {
4531
+ style: styles.topIconContainer
4532
+ }, /*#__PURE__*/React.createElement(Cancel, {
4533
+ onPress: onClose,
4534
+ appearance: appearance
4535
+ }))))))));
4536
+ }
4537
+ const styles = StyleSheet.create({
4538
+ modalBackdrop: {
4539
+ flex: 1,
4540
+ justifyContent: 'flex-end'
4541
+ },
4542
+ modalContent: {
4543
+ borderRadius: 10,
4544
+ borderWidth: 1,
4545
+ padding: 20,
4546
+ width: '90%',
4547
+ maxWidth: 400,
4548
+ marginHorizontal: 20
4549
+ },
4550
+ topIconContainer: {
4551
+ position: 'absolute',
4552
+ right: -20,
4553
+ top: -20
4554
+ }
4555
+ });
4556
+
4557
+ const ActiveSurveyContext = /*#__PURE__*/React.createContext(undefined);
4558
+ // export const useActiveSurvey = (): ActiveSurveyContextType => React.useContext(ActiveSurveyContext)
4559
+ // type FeedbackSurveyHook = {
4560
+ // survey: Survey
4561
+ // showSurveyModal: () => void
4562
+ // hideSurveyModal: () => void
4563
+ // }
4564
+ const FeedbackSurveyContext = /*#__PURE__*/React.createContext(undefined);
4565
+ function PostHogSurveyProvider(props) {
4566
+ var _a;
4567
+ const posthogFromHook = usePostHog();
4568
+ const posthog = (_a = props.client) !== null && _a !== void 0 ? _a : posthogFromHook;
4569
+ const {
4570
+ seenSurveys,
4571
+ setSeenSurvey,
4572
+ setLastSeenSurveyDate
4573
+ } = useSurveyStorage();
4574
+ const [surveys, setSurveys] = useState([]);
4575
+ const [activeSurvey, setActiveSurvey] = useState(undefined);
4576
+ const activatedSurveys = useActivatedSurveys(posthog, surveys);
4577
+ const flags = useFeatureFlags(posthog);
4578
+ // Load surveys once
4579
+ useEffect(() => {
4580
+ // TODO: for the first time, sometimes the surveys are not fetched from storage, so we need to fetch them from the API
4581
+ // because the remote config is still being fetched from the API
4582
+ posthog.ready().then(() => posthog.getSurveys()).then(setSurveys).catch(() => {});
4583
+ }, [posthog]);
4584
+ // Whenever state changes and there's no active survey, check if there is a new survey to show
4585
+ useEffect(() => {
4586
+ if (activeSurvey) {
4587
+ return;
4588
+ }
4589
+ const activeSurveys = getActiveMatchingSurveys(surveys, flags !== null && flags !== void 0 ? flags : {}, seenSurveys, activatedSurveys
4590
+ // lastSeenSurveyDate
4591
+ );
4592
+ const popoverSurveys = activeSurveys.filter(survey => survey.type === SurveyType.Popover);
4593
+ // TODO: sort by appearance delay, implement delay
4594
+ // const popoverSurveyQueue = sortSurveysByAppearanceDelay(popoverSurveys)
4595
+ if (popoverSurveys.length > 0) {
4596
+ setActiveSurvey(popoverSurveys[0]);
4597
+ }
4598
+ }, [activeSurvey, flags, surveys, seenSurveys, activatedSurveys]);
4599
+ // Merge survey appearance so that components and hooks can use a consistent model
4600
+ const surveyAppearance = useMemo(() => {
4601
+ var _a, _b, _c, _d, _e;
4602
+ if (props.overrideAppearanceWithDefault || !activeSurvey) {
4603
+ return {
4604
+ ...defaultSurveyAppearance,
4605
+ ...((_a = props.defaultSurveyAppearance) !== null && _a !== void 0 ? _a : {})
4606
+ };
4607
+ }
4608
+ return {
4609
+ ...defaultSurveyAppearance,
4610
+ ...((_b = props.defaultSurveyAppearance) !== null && _b !== void 0 ? _b : {}),
4611
+ ...((_c = activeSurvey.appearance) !== null && _c !== void 0 ? _c : {}),
4612
+ // If submitButtonColor is set by PostHog, ensure submitButtonTextColor is also set to contrast
4613
+ ...(((_d = activeSurvey.appearance) === null || _d === void 0 ? void 0 : _d.submitButtonColor) ? {
4614
+ submitButtonTextColor: (_e = activeSurvey.appearance.submitButtonTextColor) !== null && _e !== void 0 ? _e : getContrastingTextColor(activeSurvey.appearance.submitButtonColor)
4615
+ } : {})
4616
+ };
4617
+ }, [activeSurvey, props.defaultSurveyAppearance, props.overrideAppearanceWithDefault]);
4618
+ const activeContext = useMemo(() => {
4619
+ if (!activeSurvey) {
4620
+ return undefined;
4621
+ }
4622
+ return {
4623
+ survey: activeSurvey,
4624
+ onShow: () => {
4625
+ sendSurveyShownEvent(activeSurvey, posthog);
4626
+ setLastSeenSurveyDate(new Date());
4627
+ },
4628
+ onClose: submitted => {
4629
+ setSeenSurvey(activeSurvey.id);
4630
+ setActiveSurvey(undefined);
4631
+ if (!submitted) {
4632
+ dismissedSurveyEvent(activeSurvey, posthog);
4633
+ }
4634
+ }
4635
+ };
4636
+ }, [activeSurvey, posthog, setLastSeenSurveyDate, setSeenSurvey]);
4637
+ // Modal is shown for PopOver surveys or if automaticSurveyModal is true, and for all widget surveys
4638
+ // because these would have been invoked by the useFeedbackSurvey hook's showSurveyModal() method
4639
+ const shouldShowModal = activeContext && activeContext.survey.type === SurveyType.Popover;
4640
+ return /*#__PURE__*/React.createElement(ActiveSurveyContext.Provider, {
4641
+ value: activeContext
4642
+ }, /*#__PURE__*/React.createElement(FeedbackSurveyContext.Provider, {
4643
+ value: {
4644
+ surveys,
4645
+ activeSurvey,
4646
+ setActiveSurvey
4647
+ }
4648
+ }, props.children, shouldShowModal && /*#__PURE__*/React.createElement(SurveyModal, _extends({
4649
+ appearance: surveyAppearance
4650
+ }, activeContext))));
4651
+ }
4652
+ // function sortSurveysByAppearanceDelay(surveys: Survey[]): Survey[] {
4653
+ // return surveys.sort(
4654
+ // (a, b) => (a.appearance?.surveyPopupDelaySeconds ?? 0) - (b.appearance?.surveyPopupDelaySeconds ?? 0)
4655
+ // )
4656
+ // }
4657
+
4658
+ export { PostHog, PostHogProvider, PostHogSurveyProvider, Questions, SurveyModal, PostHog as default, useFeatureFlag, useFeatureFlagWithPayload, useFeatureFlags, useNavigationTracker, usePostHog };
4659
+ //# sourceMappingURL=index.esm.js.map