@usergist/feedback-react-native 0.1.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 (242) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +231 -0
  4. package/UserGistFeedback.podspec +31 -0
  5. package/UserGistFeedbackExtension.podspec +23 -0
  6. package/android/build.gradle +92 -0
  7. package/android/consumer-rules.pro +5 -0
  8. package/android/src/main/AndroidManifest.xml +31 -0
  9. package/android/src/main/java/studio/usergist/feedback/UserGistFirebaseMessagingService.kt +153 -0
  10. package/android/src/main/java/studio/usergist/feedback/UserGistPushModule.kt +344 -0
  11. package/android/src/main/java/studio/usergist/feedback/UserGistPushPackage.kt +18 -0
  12. package/dist/NativeUserGistPush.d.ts +35 -0
  13. package/dist/NativeUserGistPush.d.ts.map +1 -0
  14. package/dist/NativeUserGistPush.js +13 -0
  15. package/dist/NativeUserGistPush.js.map +1 -0
  16. package/dist/Provider.d.ts +7 -0
  17. package/dist/Provider.d.ts.map +1 -0
  18. package/dist/Provider.js +300 -0
  19. package/dist/Provider.js.map +1 -0
  20. package/dist/Push.d.ts +103 -0
  21. package/dist/Push.d.ts.map +1 -0
  22. package/dist/Push.js +225 -0
  23. package/dist/Push.js.map +1 -0
  24. package/dist/UserGist.d.ts +210 -0
  25. package/dist/UserGist.d.ts.map +1 -0
  26. package/dist/UserGist.js +1246 -0
  27. package/dist/UserGist.js.map +1 -0
  28. package/dist/index.d.ts +11 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +4 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/internal/consent.d.ts +17 -0
  33. package/dist/internal/consent.d.ts.map +1 -0
  34. package/dist/internal/consent.js +98 -0
  35. package/dist/internal/consent.js.map +1 -0
  36. package/dist/internal/context.d.ts +12 -0
  37. package/dist/internal/context.d.ts.map +1 -0
  38. package/dist/internal/context.js +70 -0
  39. package/dist/internal/context.js.map +1 -0
  40. package/dist/internal/debug.d.ts +14 -0
  41. package/dist/internal/debug.d.ts.map +1 -0
  42. package/dist/internal/debug.js +73 -0
  43. package/dist/internal/debug.js.map +1 -0
  44. package/dist/internal/engine.d.ts +93 -0
  45. package/dist/internal/engine.d.ts.map +1 -0
  46. package/dist/internal/engine.js +904 -0
  47. package/dist/internal/engine.js.map +1 -0
  48. package/dist/internal/events.d.ts +49 -0
  49. package/dist/internal/events.d.ts.map +1 -0
  50. package/dist/internal/events.js +71 -0
  51. package/dist/internal/events.js.map +1 -0
  52. package/dist/internal/frequency-cap.d.ts +15 -0
  53. package/dist/internal/frequency-cap.d.ts.map +1 -0
  54. package/dist/internal/frequency-cap.js +84 -0
  55. package/dist/internal/frequency-cap.js.map +1 -0
  56. package/dist/internal/identity.d.ts +14 -0
  57. package/dist/internal/identity.d.ts.map +1 -0
  58. package/dist/internal/identity.js +113 -0
  59. package/dist/internal/identity.js.map +1 -0
  60. package/dist/internal/inapp-matcher.d.ts +13 -0
  61. package/dist/internal/inapp-matcher.d.ts.map +1 -0
  62. package/dist/internal/inapp-matcher.js +65 -0
  63. package/dist/internal/inapp-matcher.js.map +1 -0
  64. package/dist/internal/inapp-rules-cache.d.ts +16 -0
  65. package/dist/internal/inapp-rules-cache.d.ts.map +1 -0
  66. package/dist/internal/inapp-rules-cache.js +88 -0
  67. package/dist/internal/inapp-rules-cache.js.map +1 -0
  68. package/dist/internal/instruction-dedupe.d.ts +16 -0
  69. package/dist/internal/instruction-dedupe.d.ts.map +1 -0
  70. package/dist/internal/instruction-dedupe.js +52 -0
  71. package/dist/internal/instruction-dedupe.js.map +1 -0
  72. package/dist/internal/lifecycle.d.ts +12 -0
  73. package/dist/internal/lifecycle.d.ts.map +1 -0
  74. package/dist/internal/lifecycle.js +97 -0
  75. package/dist/internal/lifecycle.js.map +1 -0
  76. package/dist/internal/modal-coordinator.d.ts +4 -0
  77. package/dist/internal/modal-coordinator.d.ts.map +1 -0
  78. package/dist/internal/modal-coordinator.js +43 -0
  79. package/dist/internal/modal-coordinator.js.map +1 -0
  80. package/dist/internal/modal-queue.d.ts +9 -0
  81. package/dist/internal/modal-queue.d.ts.map +1 -0
  82. package/dist/internal/modal-queue.js +32 -0
  83. package/dist/internal/modal-queue.js.map +1 -0
  84. package/dist/internal/mutation-queue.d.ts +23 -0
  85. package/dist/internal/mutation-queue.d.ts.map +1 -0
  86. package/dist/internal/mutation-queue.js +66 -0
  87. package/dist/internal/mutation-queue.js.map +1 -0
  88. package/dist/internal/prompt-answers.d.ts +6 -0
  89. package/dist/internal/prompt-answers.d.ts.map +1 -0
  90. package/dist/internal/prompt-answers.js +10 -0
  91. package/dist/internal/prompt-answers.js.map +1 -0
  92. package/dist/internal/prompt-flow.d.ts +8 -0
  93. package/dist/internal/prompt-flow.d.ts.map +1 -0
  94. package/dist/internal/prompt-flow.js +26 -0
  95. package/dist/internal/prompt-flow.js.map +1 -0
  96. package/dist/internal/queue.d.ts +17 -0
  97. package/dist/internal/queue.d.ts.map +1 -0
  98. package/dist/internal/queue.js +172 -0
  99. package/dist/internal/queue.js.map +1 -0
  100. package/dist/internal/requests.d.ts +22 -0
  101. package/dist/internal/requests.d.ts.map +1 -0
  102. package/dist/internal/requests.js +146 -0
  103. package/dist/internal/requests.js.map +1 -0
  104. package/dist/internal/rules-cache.d.ts +16 -0
  105. package/dist/internal/rules-cache.d.ts.map +1 -0
  106. package/dist/internal/rules-cache.js +86 -0
  107. package/dist/internal/rules-cache.js.map +1 -0
  108. package/dist/internal/storage.d.ts +36 -0
  109. package/dist/internal/storage.d.ts.map +1 -0
  110. package/dist/internal/storage.js +213 -0
  111. package/dist/internal/storage.js.map +1 -0
  112. package/dist/internal/survey-completion.d.ts +10 -0
  113. package/dist/internal/survey-completion.d.ts.map +1 -0
  114. package/dist/internal/survey-completion.js +11 -0
  115. package/dist/internal/survey-completion.js.map +1 -0
  116. package/dist/internal/survey-matcher.d.ts +21 -0
  117. package/dist/internal/survey-matcher.d.ts.map +1 -0
  118. package/dist/internal/survey-matcher.js +139 -0
  119. package/dist/internal/survey-matcher.js.map +1 -0
  120. package/dist/internal/survey-rules-cache.d.ts +17 -0
  121. package/dist/internal/survey-rules-cache.d.ts.map +1 -0
  122. package/dist/internal/survey-rules-cache.js +91 -0
  123. package/dist/internal/survey-rules-cache.js.map +1 -0
  124. package/dist/internal/survey-store.d.ts +19 -0
  125. package/dist/internal/survey-store.d.ts.map +1 -0
  126. package/dist/internal/survey-store.js +59 -0
  127. package/dist/internal/survey-store.js.map +1 -0
  128. package/dist/internal/transport.d.ts +210 -0
  129. package/dist/internal/transport.d.ts.map +1 -0
  130. package/dist/internal/transport.js +498 -0
  131. package/dist/internal/transport.js.map +1 -0
  132. package/dist/internal/trigger-matcher.d.ts +21 -0
  133. package/dist/internal/trigger-matcher.d.ts.map +1 -0
  134. package/dist/internal/trigger-matcher.js +114 -0
  135. package/dist/internal/trigger-matcher.js.map +1 -0
  136. package/dist/internal/types.d.ts +89 -0
  137. package/dist/internal/types.d.ts.map +1 -0
  138. package/dist/internal/types.js +2 -0
  139. package/dist/internal/types.js.map +1 -0
  140. package/dist/internal/user-state.d.ts +11 -0
  141. package/dist/internal/user-state.d.ts.map +1 -0
  142. package/dist/internal/user-state.js +118 -0
  143. package/dist/internal/user-state.js.map +1 -0
  144. package/dist/native/events.d.ts +27 -0
  145. package/dist/native/events.d.ts.map +1 -0
  146. package/dist/native/events.js +12 -0
  147. package/dist/native/events.js.map +1 -0
  148. package/dist/native/push-bridge.d.ts +20 -0
  149. package/dist/native/push-bridge.d.ts.map +1 -0
  150. package/dist/native/push-bridge.js +92 -0
  151. package/dist/native/push-bridge.js.map +1 -0
  152. package/dist/preview/PromptShell.d.ts +9 -0
  153. package/dist/preview/PromptShell.d.ts.map +1 -0
  154. package/dist/preview/PromptShell.js +128 -0
  155. package/dist/preview/PromptShell.js.map +1 -0
  156. package/dist/preview/SurveyShell.d.ts +15 -0
  157. package/dist/preview/SurveyShell.d.ts.map +1 -0
  158. package/dist/preview/SurveyShell.js +197 -0
  159. package/dist/preview/SurveyShell.js.map +1 -0
  160. package/dist/preview/index.d.ts +4 -0
  161. package/dist/preview/index.d.ts.map +1 -0
  162. package/dist/preview/index.js +16 -0
  163. package/dist/preview/index.js.map +1 -0
  164. package/dist/ui/InAppMessageView.d.ts +12 -0
  165. package/dist/ui/InAppMessageView.d.ts.map +1 -0
  166. package/dist/ui/InAppMessageView.js +260 -0
  167. package/dist/ui/InAppMessageView.js.map +1 -0
  168. package/dist/ui/PromptSheet.d.ts +12 -0
  169. package/dist/ui/PromptSheet.d.ts.map +1 -0
  170. package/dist/ui/PromptSheet.js +285 -0
  171. package/dist/ui/PromptSheet.js.map +1 -0
  172. package/dist/ui/QuestionImageHeader.d.ts +12 -0
  173. package/dist/ui/QuestionImageHeader.d.ts.map +1 -0
  174. package/dist/ui/QuestionImageHeader.js +22 -0
  175. package/dist/ui/QuestionImageHeader.js.map +1 -0
  176. package/dist/ui/SurveyView.d.ts +25 -0
  177. package/dist/ui/SurveyView.d.ts.map +1 -0
  178. package/dist/ui/SurveyView.js +478 -0
  179. package/dist/ui/SurveyView.js.map +1 -0
  180. package/dist/ui/animations.d.ts +4 -0
  181. package/dist/ui/animations.d.ts.map +1 -0
  182. package/dist/ui/animations.js +24 -0
  183. package/dist/ui/animations.js.map +1 -0
  184. package/dist/ui/questions/MultipleChoiceQuestion.d.ts +12 -0
  185. package/dist/ui/questions/MultipleChoiceQuestion.d.ts.map +1 -0
  186. package/dist/ui/questions/MultipleChoiceQuestion.js +41 -0
  187. package/dist/ui/questions/MultipleChoiceQuestion.js.map +1 -0
  188. package/dist/ui/questions/NpsQuestion.d.ts +14 -0
  189. package/dist/ui/questions/NpsQuestion.d.ts.map +1 -0
  190. package/dist/ui/questions/NpsQuestion.js +73 -0
  191. package/dist/ui/questions/NpsQuestion.js.map +1 -0
  192. package/dist/ui/questions/RatingQuestion.d.ts +21 -0
  193. package/dist/ui/questions/RatingQuestion.d.ts.map +1 -0
  194. package/dist/ui/questions/RatingQuestion.js +91 -0
  195. package/dist/ui/questions/RatingQuestion.js.map +1 -0
  196. package/dist/ui/questions/ShortTextQuestion.d.ts +12 -0
  197. package/dist/ui/questions/ShortTextQuestion.d.ts.map +1 -0
  198. package/dist/ui/questions/ShortTextQuestion.js +25 -0
  199. package/dist/ui/questions/ShortTextQuestion.js.map +1 -0
  200. package/dist/ui/requests/BoardView.d.ts +9 -0
  201. package/dist/ui/requests/BoardView.d.ts.map +1 -0
  202. package/dist/ui/requests/BoardView.js +270 -0
  203. package/dist/ui/requests/BoardView.js.map +1 -0
  204. package/dist/ui/requests/CommentsSection.d.ts +7 -0
  205. package/dist/ui/requests/CommentsSection.d.ts.map +1 -0
  206. package/dist/ui/requests/CommentsSection.js +254 -0
  207. package/dist/ui/requests/CommentsSection.js.map +1 -0
  208. package/dist/ui/requests/DetailView.d.ts +8 -0
  209. package/dist/ui/requests/DetailView.d.ts.map +1 -0
  210. package/dist/ui/requests/DetailView.js +206 -0
  211. package/dist/ui/requests/DetailView.js.map +1 -0
  212. package/dist/ui/requests/RequestsHost.d.ts +12 -0
  213. package/dist/ui/requests/RequestsHost.d.ts.map +1 -0
  214. package/dist/ui/requests/RequestsHost.js +58 -0
  215. package/dist/ui/requests/RequestsHost.js.map +1 -0
  216. package/dist/ui/requests/StatusPill.d.ts +6 -0
  217. package/dist/ui/requests/StatusPill.d.ts.map +1 -0
  218. package/dist/ui/requests/StatusPill.js +25 -0
  219. package/dist/ui/requests/StatusPill.js.map +1 -0
  220. package/dist/ui/requests/SubmitView.d.ts +8 -0
  221. package/dist/ui/requests/SubmitView.d.ts.map +1 -0
  222. package/dist/ui/requests/SubmitView.js +94 -0
  223. package/dist/ui/requests/SubmitView.js.map +1 -0
  224. package/dist/ui/requests/shared.d.ts +21 -0
  225. package/dist/ui/requests/shared.d.ts.map +1 -0
  226. package/dist/ui/requests/shared.js +74 -0
  227. package/dist/ui/requests/shared.js.map +1 -0
  228. package/dist/ui/survey-questions.d.ts +20 -0
  229. package/dist/ui/survey-questions.d.ts.map +1 -0
  230. package/dist/ui/survey-questions.js +211 -0
  231. package/dist/ui/survey-questions.js.map +1 -0
  232. package/dist/ui/theme.d.ts +15 -0
  233. package/dist/ui/theme.d.ts.map +1 -0
  234. package/dist/ui/theme.js +31 -0
  235. package/dist/ui/theme.js.map +1 -0
  236. package/ios/Extension/UserGistNotificationService.swift +292 -0
  237. package/ios/UserGistPush.h +16 -0
  238. package/ios/UserGistPush.mm +158 -0
  239. package/ios/UserGistPushImpl.swift +399 -0
  240. package/ios/UserGistPushSwizzle.m +168 -0
  241. package/package.json +89 -0
  242. package/react-native.config.js +16 -0
@@ -0,0 +1,213 @@
1
+ // AsyncStorage wrapper with:
2
+ // - Lazy require (no hard dep at import time)
3
+ // - Per-writeKey key prefix (multi-app safety on the same device)
4
+ // - JSON (de)serialization with graceful corruption handling
5
+ //
6
+ // We accept that AsyncStorage is a peer dep; if the host app hasn't installed
7
+ // it, the SDK degrades to an in-memory store so `track()` still works but
8
+ // nothing persists across launches.
9
+ import { reportError } from './debug.js';
10
+ let cached = null;
11
+ let checked = false;
12
+ let customAdapter = null;
13
+ /** Configure a host-owned encrypted key/value backend before `init()`. */
14
+ export function configureStorageAdapter(adapter) {
15
+ customAdapter = adapter;
16
+ }
17
+ function loadAsyncStorage() {
18
+ if (checked)
19
+ return cached;
20
+ checked = true;
21
+ try {
22
+ const mod = require('@react-native-async-storage/async-storage');
23
+ const impl = (mod && 'default' in mod ? mod.default : mod) ?? undefined;
24
+ cached = impl ?? null;
25
+ }
26
+ catch {
27
+ cached = null;
28
+ }
29
+ return cached;
30
+ }
31
+ // Small in-memory fallback
32
+ const memoryStore = new Map();
33
+ const memoryImpl = {
34
+ getItem: async (k) => memoryStore.get(k) ?? null,
35
+ setItem: async (k, v) => {
36
+ memoryStore.set(k, v);
37
+ },
38
+ removeItem: async (k) => {
39
+ memoryStore.delete(k);
40
+ },
41
+ multiRemove: async (keys) => {
42
+ for (const k of keys)
43
+ memoryStore.delete(k);
44
+ },
45
+ };
46
+ // Credential-bearing values must never silently degrade to AsyncStorage.
47
+ // When the native module is unavailable (for example Expo Go), keep them only
48
+ // in process memory and report the loss of relaunch durability.
49
+ const secureMemoryStore = new Map();
50
+ const secureMemoryImpl = {
51
+ getItem: async (k) => secureMemoryStore.get(k) ?? null,
52
+ setItem: async (k, v) => { secureMemoryStore.set(k, v); },
53
+ removeItem: async (k) => { secureMemoryStore.delete(k); },
54
+ multiRemove: async (keys) => { for (const k of keys)
55
+ secureMemoryStore.delete(k); },
56
+ };
57
+ let nativeSecureChecked = false;
58
+ let nativeSecure = null;
59
+ let warnedSecureFallback = false;
60
+ function loadNativeSecureStorage() {
61
+ if (nativeSecureChecked)
62
+ return nativeSecure;
63
+ nativeSecureChecked = true;
64
+ try {
65
+ const rn = require('react-native');
66
+ const module = rn.NativeModules?.UserGistPush;
67
+ if (!module?.secureGetItem || !module.secureSetItem || !module.secureRemoveItem) {
68
+ return null;
69
+ }
70
+ nativeSecure = {
71
+ getItem: (key) => module.secureGetItem(key),
72
+ setItem: (key, value) => module.secureSetItem(key, value),
73
+ removeItem: (key) => module.secureRemoveItem(key),
74
+ multiRemove: (keys) => module.secureMultiRemove(keys),
75
+ };
76
+ }
77
+ catch {
78
+ nativeSecure = null;
79
+ }
80
+ return nativeSecure;
81
+ }
82
+ function credentialBackend() {
83
+ if (customAdapter)
84
+ return customAdapter;
85
+ const native = loadNativeSecureStorage();
86
+ if (native)
87
+ return native;
88
+ if (!warnedSecureFallback) {
89
+ warnedSecureFallback = true;
90
+ reportError('native secure storage unavailable; subject credentials are memory-only until the app is rebuilt with the UserGist native module');
91
+ }
92
+ return secureMemoryImpl;
93
+ }
94
+ function backend() {
95
+ return customAdapter ?? loadAsyncStorage() ?? memoryImpl;
96
+ }
97
+ // Non-crypto stable hash of the writeKey → short prefix
98
+ function hashKey(input) {
99
+ let h = 5381;
100
+ for (let i = 0; i < input.length; i++) {
101
+ h = ((h * 33) ^ input.charCodeAt(i)) >>> 0;
102
+ }
103
+ return h.toString(36);
104
+ }
105
+ export function createStorageScope(writeKey) {
106
+ const prefix = `@usergist/${hashKey(writeKey)}/`;
107
+ const key = (suffix) => `${prefix}${suffix}`;
108
+ const isCredential = (suffix) => suffix === STORAGE_KEYS.subjectToken || suffix === STORAGE_KEYS.mutationQueue;
109
+ const implementation = (suffix) => isCredential(suffix) ? credentialBackend() : backend();
110
+ return {
111
+ key,
112
+ async getJson(suffix) {
113
+ try {
114
+ const impl = implementation(suffix);
115
+ let raw = await impl.getItem(key(suffix));
116
+ // One-time migration from older SDK builds that stored credentials in
117
+ // AsyncStorage. Always remove the plaintext copy, even if a native
118
+ // secure-store write fails, so migration cannot preserve credentials
119
+ // in an unencrypted backend.
120
+ if (raw == null && isCredential(suffix) && !customAdapter) {
121
+ const legacy = loadAsyncStorage();
122
+ const old = await legacy?.getItem(key(suffix));
123
+ if (old != null) {
124
+ try {
125
+ await impl.setItem(key(suffix), old);
126
+ }
127
+ finally {
128
+ await legacy?.removeItem(key(suffix));
129
+ }
130
+ raw = old;
131
+ }
132
+ }
133
+ if (raw == null)
134
+ return null;
135
+ return JSON.parse(raw);
136
+ }
137
+ catch (e) {
138
+ reportError('storage.getJson failed', e);
139
+ return null;
140
+ }
141
+ },
142
+ async setJson(suffix, value) {
143
+ try {
144
+ await implementation(suffix).setItem(key(suffix), JSON.stringify(value));
145
+ }
146
+ catch (e) {
147
+ reportError('storage.setJson failed', e);
148
+ }
149
+ },
150
+ async setJsonStrict(suffix, value) {
151
+ await implementation(suffix).setItem(key(suffix), JSON.stringify(value));
152
+ },
153
+ async remove(suffix) {
154
+ try {
155
+ await implementation(suffix).removeItem(key(suffix));
156
+ if (isCredential(suffix) && !customAdapter) {
157
+ await loadAsyncStorage()?.removeItem(key(suffix));
158
+ }
159
+ }
160
+ catch (e) {
161
+ reportError('storage.remove failed', e);
162
+ }
163
+ },
164
+ async clearAll(suffixes) {
165
+ try {
166
+ const normal = suffixes.filter((suffix) => !isCredential(suffix)).map(key);
167
+ const credentials = suffixes.filter(isCredential).map(key);
168
+ const normalImpl = backend();
169
+ const credentialImpl = credentialBackend();
170
+ if (normal.length > 0) {
171
+ if (normalImpl.multiRemove)
172
+ await normalImpl.multiRemove(normal);
173
+ else
174
+ await Promise.all(normal.map((k) => normalImpl.removeItem(k)));
175
+ }
176
+ if (credentials.length > 0) {
177
+ if (credentialImpl.multiRemove)
178
+ await credentialImpl.multiRemove(credentials);
179
+ else
180
+ await Promise.all(credentials.map((k) => credentialImpl.removeItem(k)));
181
+ if (!customAdapter) {
182
+ const legacy = loadAsyncStorage();
183
+ if (legacy?.multiRemove)
184
+ await legacy.multiRemove(credentials);
185
+ else
186
+ await Promise.all(credentials.map((k) => legacy?.removeItem(k)));
187
+ }
188
+ }
189
+ }
190
+ catch (e) {
191
+ reportError('storage.clearAll failed', e);
192
+ }
193
+ },
194
+ };
195
+ }
196
+ export const STORAGE_KEYS = {
197
+ identity: 'identity',
198
+ consent: 'consent',
199
+ queue: 'queue',
200
+ rulesCache: 'rulesCache',
201
+ surveyRulesCache: 'surveyRulesCache',
202
+ inAppRulesCache: 'inAppRulesCache',
203
+ frequencyCaps: 'frequencyCaps',
204
+ userProperties: 'userProperties',
205
+ eventHistory: 'eventHistory',
206
+ subjectToken: 'subjectToken',
207
+ mutationQueue: 'mutationQueue',
208
+ instructionCursor: 'instructionCursor',
209
+ seenInstructions: 'seenInstructions',
210
+ localInstructionDedupe: 'localInstructionDedupe',
211
+ appVersion: 'appVersion',
212
+ };
213
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/internal/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { MutationQueue } from './mutation-queue.js';
2
+ import type { MutationFlushResult } from './engine.js';
3
+ export type SurveyCompletionOutcome = 'delivered' | 'deferred' | 'rejected';
4
+ /**
5
+ * A durably queued completion is accepted by the SDK even when the network
6
+ * cannot deliver it immediately. Only a permanent server rejection should
7
+ * keep the survey on its final question.
8
+ */
9
+ export declare function surveyCompletionOutcome(mutationId: string, mutations: Pick<MutationQueue, 'has'>, result: MutationFlushResult): SurveyCompletionOutcome;
10
+ //# sourceMappingURL=survey-completion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"survey-completion.d.ts","sourceRoot":"","sources":["../../src/internal/survey-completion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAEtD,MAAM,MAAM,uBAAuB,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,CAAA;AAE3E;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,EACrC,MAAM,EAAE,mBAAmB,GAC1B,uBAAuB,CAGzB"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * A durably queued completion is accepted by the SDK even when the network
3
+ * cannot deliver it immediately. Only a permanent server rejection should
4
+ * keep the survey on its final question.
5
+ */
6
+ export function surveyCompletionOutcome(mutationId, mutations, result) {
7
+ if (result.permanentlyRejectedIds.has(mutationId))
8
+ return 'rejected';
9
+ return mutations.has(mutationId) ? 'deferred' : 'delivered';
10
+ }
11
+ //# sourceMappingURL=survey-completion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"survey-completion.js","sourceRoot":"","sources":["../../src/internal/survey-completion.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAkB,EAClB,SAAqC,EACrC,MAA2B;IAE3B,IAAI,MAAM,CAAC,sBAAsB,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAA;IACpE,OAAO,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAA;AAC7D,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { SurveyRulesCache } from './survey-rules-cache.js';
2
+ import type { FrequencyCapManager } from './frequency-cap.js';
3
+ import type { UserStateStore } from './user-state.js';
4
+ import type { ConsentManager } from './consent.js';
5
+ import type { EventBus } from './events.js';
6
+ export interface SurveyMatcher {
7
+ /** Returns the locally rendered survey id, or null when the server decides. */
8
+ readonly evaluate: (eventName: string) => string | null;
9
+ /** Commits cap/cooldown state after the survey route actually appears. */
10
+ readonly recordShown: (campaignId: string, at?: number) => void;
11
+ /** Releases process-local reservations during reset. */
12
+ readonly resetPending: () => void;
13
+ }
14
+ export declare function createSurveyMatcher(params: {
15
+ readonly rulesCache: SurveyRulesCache;
16
+ readonly frequencyCaps: FrequencyCapManager;
17
+ readonly userState: UserStateStore;
18
+ readonly consent: ConsentManager;
19
+ readonly events: EventBus;
20
+ }): SurveyMatcher;
21
+ //# sourceMappingURL=survey-matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"survey-matcher.d.ts","sourceRoot":"","sources":["../../src/internal/survey-matcher.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAG3C,MAAM,WAAW,aAAa;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACvD,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/D,wDAAwD;IACxD,QAAQ,CAAC,YAAY,EAAE,MAAM,IAAI,CAAA;CAClC;AA6BD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAA;IACrC,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAA;IAC3C,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;IAChC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;CAC1B,GAAG,aAAa,CAmGhB"}
@@ -0,0 +1,139 @@
1
+ // Client-side survey matcher. Mirror of trigger-matcher.ts for the
2
+ // survey pillar. Runs synchronously on every `track()`.
3
+ //
4
+ // Pipeline:
5
+ // 1. Look up armed surveys for eventName.
6
+ // 2. Check survey consent.
7
+ // 3. Evaluate segment locally via sdk-core.evaluateSerializedSegmentRules.
8
+ // 4. Check local frequency cap (re-using the per-prompt manager —
9
+ // campaign id stands in for prompt id).
10
+ // 5. Check cooldown against last shown time.
11
+ // 6. If all pass: emit `surveyInvite` (Provider opens it via the
12
+ // already-cached survey content) + record cap + cooldown.
13
+ //
14
+ // Server reconciles asynchronously (the offer-ledger insert from the
15
+ // trigger-engine still runs for analytics correctness).
16
+ import { evaluateSerializedSegmentRules } from '@usergist/sdk-core/mobile';
17
+ import { logTrace } from './debug.js';
18
+ // Translate the survey-side PushFrequencyCap shape into the prompt-
19
+ // style { perPromptDays, perUserDays } shape that frequency-cap
20
+ // understands. perCampaignDays = "this survey only", perPillarDays =
21
+ // "any survey".
22
+ function toPromptCaps(cap) {
23
+ return {
24
+ perPromptDays: cap.perCampaignDays,
25
+ perUserDays: cap.perPillarDays,
26
+ };
27
+ }
28
+ // In-memory cooldown ledger. Survey cooldownSeconds is finer-grained
29
+ // than the day-based per-prompt cap, so we track lastShown locally.
30
+ // Resets on app restart — that's fine; the server-side cooldown is
31
+ // still authoritative on submit.
32
+ const cooldownByCampaign = new Map();
33
+ function passesCooldown(campaignId, cooldownSeconds) {
34
+ if (!cooldownSeconds || cooldownSeconds <= 0)
35
+ return true;
36
+ const last = cooldownByCampaign.get(campaignId);
37
+ if (!last)
38
+ return true;
39
+ return Date.now() - last >= cooldownSeconds * 1000;
40
+ }
41
+ export function createSurveyMatcher(params) {
42
+ const { rulesCache, frequencyCaps, userState, consent, events } = params;
43
+ const pendingCampaignIds = new Set();
44
+ function tryFire(armed, eventName) {
45
+ if (armed.clientSideEligible === false) {
46
+ logTrace({
47
+ eventName,
48
+ promptId: armed.campaignId,
49
+ outcome: 'blocked-no-trigger',
50
+ reason: 'server-authoritative',
51
+ at: new Date().toISOString(),
52
+ });
53
+ return false;
54
+ }
55
+ if (!consent.allowsSurvey()) {
56
+ logTrace({
57
+ eventName,
58
+ promptId: armed.campaignId,
59
+ outcome: 'blocked-by-consent',
60
+ at: new Date().toISOString(),
61
+ });
62
+ return false;
63
+ }
64
+ const user = userState.buildForEval();
65
+ if (!evaluateSerializedSegmentRules(armed.segmentRules ?? null, user)) {
66
+ logTrace({
67
+ eventName,
68
+ promptId: armed.campaignId,
69
+ outcome: 'blocked-by-segment',
70
+ at: new Date().toISOString(),
71
+ });
72
+ return false;
73
+ }
74
+ if (pendingCampaignIds.has(armed.campaignId))
75
+ return false;
76
+ const cap = frequencyCaps.canShow(`survey:${armed.campaignId}`, toPromptCaps(armed.frequencyCap));
77
+ if (!cap.ok) {
78
+ logTrace({
79
+ eventName,
80
+ promptId: armed.campaignId,
81
+ outcome: 'blocked-by-cap',
82
+ reason: cap.reason,
83
+ at: new Date().toISOString(),
84
+ });
85
+ return false;
86
+ }
87
+ if (!passesCooldown(armed.campaignId, armed.cooldownSeconds)) {
88
+ logTrace({
89
+ eventName,
90
+ promptId: armed.campaignId,
91
+ outcome: 'blocked-by-cap',
92
+ reason: 'per-prompt',
93
+ at: new Date().toISOString(),
94
+ });
95
+ return false;
96
+ }
97
+ // Fire — emit `surveyInvite` so the existing Provider invite
98
+ // pipeline opens it. The Provider's openSurvey first hits the
99
+ // cache (via __internal_armedSurveyById) so there's no follow-up
100
+ // server fetch for survey content.
101
+ pendingCampaignIds.add(armed.campaignId);
102
+ events.emit('surveyInvite', {
103
+ surveyId: armed.campaignId,
104
+ name: armed.survey.name,
105
+ source: 'triggered',
106
+ });
107
+ logTrace({
108
+ eventName,
109
+ promptId: armed.campaignId,
110
+ outcome: 'fired',
111
+ at: new Date().toISOString(),
112
+ });
113
+ return true;
114
+ }
115
+ return {
116
+ evaluate(eventName) {
117
+ const candidates = rulesCache.getForEvent(eventName);
118
+ if (candidates.length === 0)
119
+ return null;
120
+ // Fire the first matching survey (one survey at a time, like
121
+ // feedback's one-prompt-at-a-time rule).
122
+ for (const armed of candidates) {
123
+ if (tryFire(armed, eventName))
124
+ return armed.campaignId;
125
+ }
126
+ return null;
127
+ },
128
+ recordShown(campaignId, at = Date.now()) {
129
+ pendingCampaignIds.delete(campaignId);
130
+ frequencyCaps.recordShown(`survey:${campaignId}`, at);
131
+ cooldownByCampaign.set(campaignId, at);
132
+ },
133
+ resetPending() {
134
+ pendingCampaignIds.clear();
135
+ cooldownByCampaign.clear();
136
+ },
137
+ };
138
+ }
139
+ //# sourceMappingURL=survey-matcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"survey-matcher.js","sourceRoot":"","sources":["../../src/internal/survey-matcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { ArmedSurvey } from '@usergist/sdk-core/mobile';
2
+ import { type StorageScope } from './storage.js';
3
+ import type { Transport } from './transport.js';
4
+ export interface SurveyRulesCache {
5
+ readonly hydrate: () => Promise<void>;
6
+ readonly refresh: (params: {
7
+ readonly anonymousId: string;
8
+ readonly externalId: string | null;
9
+ readonly force?: boolean;
10
+ }) => Promise<ReadonlyArray<ArmedSurvey>>;
11
+ readonly getForEvent: (eventName: string) => ReadonlyArray<ArmedSurvey>;
12
+ readonly getById: (campaignId: string) => ArmedSurvey | undefined;
13
+ readonly all: () => ReadonlyArray<ArmedSurvey>;
14
+ readonly clear: () => Promise<void>;
15
+ }
16
+ export declare function createSurveyRulesCache(storage: StorageScope, transport: Transport, defaultSyncMs: number): SurveyRulesCache;
17
+ //# sourceMappingURL=survey-rules-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"survey-rules-cache.d.ts","sourceRoot":"","sources":["../../src/internal/survey-rules-cache.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAE9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAG/C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE;QACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;QAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;QAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KACzB,KAAK,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAA;IACzC,QAAQ,CAAC,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,aAAa,CAAC,WAAW,CAAC,CAAA;IACvE,QAAQ,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAA;IACjE,QAAQ,CAAC,GAAG,EAAE,MAAM,aAAa,CAAC,WAAW,CAAC,CAAA;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACpC;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,MAAM,GACpB,gBAAgB,CAiFlB"}
@@ -0,0 +1,91 @@
1
+ // Armed-surveys cache (the survey-side mirror of rules-cache).
2
+ // - Pulled on app foreground, every 5 min while foregrounded, and on-demand.
3
+ // - Persisted to AsyncStorage.
4
+ // - The survey-matcher reads from here synchronously (no I/O on track()).
5
+ import { STORAGE_KEYS } from './storage.js';
6
+ import { reportError, debugLog } from './debug.js';
7
+ export function createSurveyRulesCache(storage, transport, defaultSyncMs) {
8
+ let surveys = [];
9
+ let byEvent = {};
10
+ let byId = {};
11
+ let fetchedAt = 0;
12
+ let hydrated = false;
13
+ let inflight = null;
14
+ function reindex(list) {
15
+ const event = {};
16
+ const id = {};
17
+ for (const s of list) {
18
+ const bucket = event[s.eventName] ?? [];
19
+ bucket.push(s);
20
+ event[s.eventName] = bucket;
21
+ id[s.campaignId] = s;
22
+ }
23
+ const eventOut = {};
24
+ for (const k of Object.keys(event))
25
+ eventOut[k] = event[k] ?? [];
26
+ byEvent = eventOut;
27
+ byId = id;
28
+ }
29
+ return {
30
+ async hydrate() {
31
+ if (hydrated)
32
+ return;
33
+ try {
34
+ const stored = await storage.getJson(STORAGE_KEYS.surveyRulesCache);
35
+ if (stored?.surveys) {
36
+ surveys = stored.surveys;
37
+ reindex(surveys);
38
+ fetchedAt = Date.parse(stored.fetchedAt);
39
+ }
40
+ }
41
+ catch (e) {
42
+ reportError('surveyRulesCache.hydrate failed', e);
43
+ }
44
+ hydrated = true;
45
+ },
46
+ async refresh({ anonymousId, externalId, force }) {
47
+ const now = Date.now();
48
+ if (!force && now - fetchedAt < defaultSyncMs && surveys.length > 0) {
49
+ return surveys;
50
+ }
51
+ if (inflight)
52
+ return inflight;
53
+ inflight = (async () => {
54
+ try {
55
+ const res = await transport.armedSurveys({ anonymousId, externalId });
56
+ surveys = res.surveys;
57
+ reindex(surveys);
58
+ fetchedAt = Date.now();
59
+ const cache = {
60
+ surveys,
61
+ fetchedAt: new Date(fetchedAt).toISOString(),
62
+ serverTime: res.serverTime,
63
+ nextSyncMs: res.nextSyncMs,
64
+ };
65
+ await storage.setJson(STORAGE_KEYS.surveyRulesCache, cache);
66
+ debugLog('surveyRulesCache refreshed', { count: surveys.length });
67
+ return surveys;
68
+ }
69
+ catch (e) {
70
+ reportError('surveyRulesCache.refresh failed', e);
71
+ return surveys;
72
+ }
73
+ finally {
74
+ inflight = null;
75
+ }
76
+ })();
77
+ return inflight;
78
+ },
79
+ getForEvent: (eventName) => byEvent[eventName] ?? [],
80
+ getById: (campaignId) => byId[campaignId],
81
+ all: () => surveys,
82
+ async clear() {
83
+ surveys = [];
84
+ byEvent = {};
85
+ byId = {};
86
+ fetchedAt = 0;
87
+ await storage.remove(STORAGE_KEYS.surveyRulesCache);
88
+ },
89
+ };
90
+ }
91
+ //# sourceMappingURL=survey-rules-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"survey-rules-cache.js","sourceRoot":"","sources":["../../src/internal/survey-rules-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { SurveyAnswerRecord } from '@usergist/sdk-core/mobile';
2
+ export interface PendingAttempt {
3
+ readonly surveyId: string;
4
+ readonly attemptId: string;
5
+ readonly startedAt: number;
6
+ readonly currentQuestionId: string | null;
7
+ readonly snapshot: SurveyAnswerRecord;
8
+ readonly language: string | null;
9
+ }
10
+ export interface SurveyStore {
11
+ readonly list: () => Promise<ReadonlyArray<PendingAttempt>>;
12
+ readonly upsert: (attempt: PendingAttempt) => Promise<void>;
13
+ readonly remove: (attemptId: string) => Promise<void>;
14
+ readonly updateProgress: (attemptId: string, currentQuestionId: string | null, snapshot: SurveyAnswerRecord) => Promise<void>;
15
+ readonly findForSurvey: (surveyId: string) => Promise<PendingAttempt | null>;
16
+ readonly clear: () => Promise<void>;
17
+ }
18
+ export declare function createSurveyStore(writeKey: string): SurveyStore;
19
+ //# sourceMappingURL=survey-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"survey-store.d.ts","sourceRoot":"","sources":["../../src/internal/survey-store.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAInE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;IACzC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAA;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAA;IAC3D,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,QAAQ,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrD,QAAQ,CAAC,cAAc,EAAE,CACvB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,QAAQ,EAAE,kBAAkB,KACzB,OAAO,CAAC,IAAI,CAAC,CAAA;IAClB,QAAQ,CAAC,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAA;IAC5E,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACpC;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CA4C/D"}
@@ -0,0 +1,59 @@
1
+ // Per-user, per-survey local cache of in-flight attempts.
2
+ // Used to surface the "Continue your last survey?" prompt on app resume and to
3
+ // keep an attempt recoverable when the network is flaky.
4
+ import { createStorageScope } from './storage.js';
5
+ import { reportError } from './debug.js';
6
+ const PENDING_KEY = 'surveys:pending';
7
+ export function createSurveyStore(writeKey) {
8
+ const scope = createStorageScope(writeKey);
9
+ async function list() {
10
+ try {
11
+ const arr = await scope.getJson(PENDING_KEY);
12
+ if (!Array.isArray(arr))
13
+ return [];
14
+ return arr.filter(isPending);
15
+ }
16
+ catch (err) {
17
+ reportError('survey-store.list failed', err);
18
+ return [];
19
+ }
20
+ }
21
+ return {
22
+ list,
23
+ async upsert(attempt) {
24
+ const existing = await list();
25
+ const filtered = existing.filter((a) => a.attemptId !== attempt.attemptId);
26
+ await scope.setJson(PENDING_KEY, [...filtered, attempt]);
27
+ },
28
+ async remove(attemptId) {
29
+ const existing = await list();
30
+ const next = existing.filter((a) => a.attemptId !== attemptId);
31
+ await scope.setJson(PENDING_KEY, next);
32
+ },
33
+ async updateProgress(attemptId, currentQuestionId, snapshot) {
34
+ const existing = await list();
35
+ const target = existing.find((attempt) => attempt.attemptId === attemptId);
36
+ if (!target)
37
+ return;
38
+ await scope.setJson(PENDING_KEY, existing.map((attempt) => attempt.attemptId === attemptId
39
+ ? { ...attempt, currentQuestionId, snapshot }
40
+ : attempt));
41
+ },
42
+ async findForSurvey(surveyId) {
43
+ const all = await list();
44
+ return all.find((a) => a.surveyId === surveyId) ?? null;
45
+ },
46
+ async clear() {
47
+ await scope.remove(PENDING_KEY);
48
+ },
49
+ };
50
+ }
51
+ function isPending(v) {
52
+ if (!v || typeof v !== 'object')
53
+ return false;
54
+ const x = v;
55
+ return (typeof x.surveyId === 'string' &&
56
+ typeof x.attemptId === 'string' &&
57
+ typeof x.startedAt === 'number');
58
+ }
59
+ //# sourceMappingURL=survey-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"survey-store.js","sourceRoot":"","sources":["../../src/internal/survey-store.ts"],"names":[],"mappings":"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"}