pulse-updates 1.1.1 → 1.2.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 (64) hide show
  1. package/README.md +50 -10
  2. package/SECURITY.md +42 -0
  3. package/android/src/main/java/app/pulse/updates/PulseController.kt +6 -2
  4. package/android/src/main/java/app/pulse/updates/PulseUpdatesModule.kt +25 -0
  5. package/app.plugin.js +47 -0
  6. package/ios/PulseUpdates/PulseController.swift +7 -2
  7. package/ios/PulseUpdates/PulseUpdates.m +7 -0
  8. package/ios/PulseUpdates/PulseUpdates.swift +22 -0
  9. package/lib/commonjs/NativePulseUpdates.js.map +1 -1
  10. package/lib/commonjs/PulseUpdates.js +36 -0
  11. package/lib/commonjs/PulseUpdates.js.map +1 -1
  12. package/lib/commonjs/config.js +175 -21
  13. package/lib/commonjs/config.js.map +1 -1
  14. package/lib/commonjs/decisions.js +128 -0
  15. package/lib/commonjs/decisions.js.map +1 -0
  16. package/lib/commonjs/index.js +12 -0
  17. package/lib/commonjs/index.js.map +1 -1
  18. package/lib/commonjs/init.js +153 -13
  19. package/lib/commonjs/init.js.map +1 -1
  20. package/lib/commonjs/track.js +154 -12
  21. package/lib/commonjs/track.js.map +1 -1
  22. package/lib/commonjs/usePulseUpdates.js +21 -16
  23. package/lib/commonjs/usePulseUpdates.js.map +1 -1
  24. package/lib/module/NativePulseUpdates.js.map +1 -1
  25. package/lib/module/PulseUpdates.js +33 -0
  26. package/lib/module/PulseUpdates.js.map +1 -1
  27. package/lib/module/config.js +174 -21
  28. package/lib/module/config.js.map +1 -1
  29. package/lib/module/decisions.js +122 -0
  30. package/lib/module/decisions.js.map +1 -0
  31. package/lib/module/index.js +1 -0
  32. package/lib/module/index.js.map +1 -1
  33. package/lib/module/init.js +154 -15
  34. package/lib/module/init.js.map +1 -1
  35. package/lib/module/track.js +152 -12
  36. package/lib/module/track.js.map +1 -1
  37. package/lib/module/usePulseUpdates.js +21 -16
  38. package/lib/module/usePulseUpdates.js.map +1 -1
  39. package/lib/typescript/NativePulseUpdates.d.ts +1 -0
  40. package/lib/typescript/NativePulseUpdates.d.ts.map +1 -1
  41. package/lib/typescript/PulseUpdates.d.ts +20 -0
  42. package/lib/typescript/PulseUpdates.d.ts.map +1 -1
  43. package/lib/typescript/config.d.ts +22 -0
  44. package/lib/typescript/config.d.ts.map +1 -1
  45. package/lib/typescript/decisions.d.ts +55 -0
  46. package/lib/typescript/decisions.d.ts.map +1 -0
  47. package/lib/typescript/index.d.ts +1 -0
  48. package/lib/typescript/index.d.ts.map +1 -1
  49. package/lib/typescript/init.d.ts +51 -4
  50. package/lib/typescript/init.d.ts.map +1 -1
  51. package/lib/typescript/track.d.ts +29 -1
  52. package/lib/typescript/track.d.ts.map +1 -1
  53. package/lib/typescript/usePulseUpdates.d.ts.map +1 -1
  54. package/logo.png +0 -0
  55. package/package.json +14 -3
  56. package/scripts/publish.mjs +68 -3
  57. package/src/NativePulseUpdates.ts +1 -0
  58. package/src/PulseUpdates.ts +54 -0
  59. package/src/config.ts +234 -21
  60. package/src/decisions.ts +179 -0
  61. package/src/index.ts +1 -0
  62. package/src/init.ts +227 -12
  63. package/src/track.ts +191 -13
  64. package/src/usePulseUpdates.ts +21 -16
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.initPulse = initPulse;
7
+ exports.initPulseAsync = initPulseAsync;
7
8
  var _config = require("./config");
8
9
  var _track = require("./track");
9
10
  /**
@@ -32,36 +33,65 @@ var _track = require("./track");
32
33
  */
33
34
 
34
35
  const DEVICE_ID_KEY = 'pulse.device-id';
36
+ let activeClient = null;
37
+ let stopActiveRefresh = null;
35
38
 
36
39
  /** Wires config and events, and returns the context the two share. */
37
40
  function initPulse(opts) {
41
+ // Reconfiguration is synchronous. Calling the old async dispose without awaiting
42
+ // it lets its eventual flush tear down the brand-new tracker — exactly the race a
43
+ // fast app switch or test setup triggers. Persist the old outbox, stop its refresh,
44
+ // then configure the new app in one uninterrupted turn.
45
+ stopActiveRefresh?.();
46
+ (0, _track.disposeTracking)();
47
+ activeClient = null;
48
+ stopActiveRefresh = null;
38
49
  const base = opts.apiUrl.replace(/\/+$/, '');
39
50
  const slug = opts.appSlug.trim();
40
51
  const configUrl = `${base}/pulse/config/${slug}`;
41
52
  const trackUrl = `${base}/pulse/track/${slug}`;
42
- const deviceId = opts.deviceId?.trim() || resolveDeviceId(opts.storage);
53
+ const deviceStorageKey = `pulse.${slug}.device-id`;
54
+ let deviceId = opts.deviceId?.trim() || resolveDeviceId(opts.storage, deviceStorageKey);
43
55
  const platform = detectPlatform();
44
56
  const osVersion = detectOsVersion();
57
+ const appVersion = opts.appVersion ?? detectAppVersion();
58
+ const language = opts.language ?? detectLanguage();
59
+ let userId;
60
+ let userAttributes;
61
+ let consentOverride = typeof opts.analyticsConsent === 'boolean' ? opts.analyticsConsent : undefined;
62
+ const hasConsent = () => consentOverride ?? (typeof opts.analyticsConsent === 'function' ? opts.analyticsConsent() : true);
45
63
  const getContext = () => ({
46
64
  platform,
47
65
  osVersion,
48
- appVersion: opts.appVersion,
66
+ appVersion,
67
+ language,
49
68
  deviceId,
50
- userId: opts.getUserId?.(),
51
- userAttributes: opts.getUserAttributes?.()
69
+ userId: userId ?? opts.getUserId?.(),
70
+ userAttributes: userAttributes ?? opts.getUserAttributes?.()
52
71
  });
53
72
  (0, _config.configureConfig)({
54
73
  url: configUrl,
55
74
  defaults: opts.defaults,
56
75
  storage: opts.storage,
76
+ storageKey: `pulse.${slug}.config.v1`,
57
77
  getContext,
58
78
  pollIntervalMs: opts.pollIntervalMs,
59
- onError: opts.onError
79
+ onError: opts.onError,
80
+ signingPublicKey: opts.signingPublicKey,
81
+ signingKeyId: opts.signingKeyId,
82
+ requireSignature: opts.requireConfigSignature,
83
+ verifySignature: opts.verifyConfigSignature ?? (opts.requireConfigSignature && !opts.signingPublicKey ? verifyWithNativeKey : undefined)
60
84
  });
61
85
  (0, _track.configureTracking)({
62
86
  url: trackUrl,
63
87
  getContext,
64
88
  flushIntervalMs: opts.flushIntervalMs,
89
+ storage: opts.storage,
90
+ storageKey: `pulse.${slug}.events.v1`,
91
+ hasConsent,
92
+ propertyAllowlist: opts.eventPropertyAllowlist,
93
+ redactProperties: opts.redactEventProperties,
94
+ appState: opts.appState,
65
95
  onIgnored: opts.onIgnoredEvents,
66
96
  onError: opts.onError
67
97
  });
@@ -71,7 +101,7 @@ function initPulse(opts) {
71
101
  // simply does not match this install — which reads as "the rollout did nothing".
72
102
  // Without storage the id is new on every launch, so the arm is re-dealt each time
73
103
  // and no experiment can mean anything.
74
- if (!opts.appVersion) {
104
+ if (!appVersion) {
75
105
  opts.onError?.(new Error('Pulse: no appVersion given — version targeting and version slices will not match this install'));
76
106
  }
77
107
  if (!opts.storage && !opts.deviceId) {
@@ -82,12 +112,84 @@ function initPulse(opts) {
82
112
  // the first response is the launch that runs on defaults, and defaults are the
83
113
  // off position of every flag.
84
114
  void (0, _config.fetchConfig)();
85
- (0, _config.startConfigAutoRefresh)(opts.appState);
86
- return {
87
- deviceId,
115
+ const stopRefresh = (0, _config.startConfigAutoRefresh)(opts.appState);
116
+ const client = {
117
+ get deviceId() {
118
+ return deviceId;
119
+ },
88
120
  configUrl,
89
- trackUrl
121
+ trackUrl,
122
+ track: _track.track,
123
+ flush: _track.flushEvents,
124
+ setUser: (nextUserId, attributes) => {
125
+ userId = nextUserId?.trim() || undefined;
126
+ userAttributes = sanitizeAttributes(attributes);
127
+ },
128
+ clearUser: () => {
129
+ userId = undefined;
130
+ userAttributes = undefined;
131
+ },
132
+ setAnalyticsConsent: granted => {
133
+ consentOverride = granted;
134
+ },
135
+ resetInstallId: () => {
136
+ deviceId = randomId();
137
+ try {
138
+ opts.storage?.set(deviceStorageKey, deviceId);
139
+ } catch {/* memory-only fallback */}
140
+ return deviceId;
141
+ },
142
+ health: () => ({
143
+ appSlug: slug,
144
+ deviceId,
145
+ config: (0, _config.getConfigInfo)(),
146
+ events: (0, _track.getTrackingInfo)(),
147
+ analyticsConsent: hasConsent()
148
+ }),
149
+ config: {
150
+ boolean: _config.getConfigBoolean,
151
+ number: _config.getConfigNumber,
152
+ string: _config.getConfigString,
153
+ json: _config.getConfigJson,
154
+ refresh: _config.fetchConfig
155
+ },
156
+ dispose: async () => {
157
+ stopRefresh();
158
+ if (activeClient !== client) return;
159
+ await (0, _track.flushEvents)();
160
+ // Another init may have taken ownership while this network flush was pending.
161
+ if (activeClient === client) {
162
+ (0, _track.disposeTracking)();
163
+ activeClient = null;
164
+ stopActiveRefresh = null;
165
+ }
166
+ }
167
+ };
168
+ activeClient = client;
169
+ stopActiveRefresh = stopRefresh;
170
+ return client;
171
+ }
172
+
173
+ /**
174
+ * AsyncStorage-friendly one-call setup. It preloads only Pulse's three app-scoped
175
+ * records, then exposes the same synchronous hot-path API as initPulse.
176
+ */
177
+ async function initPulseAsync(opts) {
178
+ const slug = opts.appSlug.trim();
179
+ const keys = [`pulse.${slug}.device-id`, `pulse.${slug}.config.v1`, `pulse.${slug}.events.v1`, DEVICE_ID_KEY];
180
+ const loaded = await Promise.all(keys.map(async key => [key, await opts.storage.getItem(key)]));
181
+ const memory = new Map(loaded.filter(entry => entry[1] !== null));
182
+ const storage = {
183
+ getString: key => memory.get(key),
184
+ set: (key, value) => {
185
+ memory.set(key, value);
186
+ void opts.storage.setItem(key, value);
187
+ }
90
188
  };
189
+ return initPulse({
190
+ ...opts,
191
+ storage
192
+ });
91
193
  }
92
194
 
93
195
  /**
@@ -97,18 +199,23 @@ function initPulse(opts) {
97
199
  * arm is a hash of it, so every launch would be a fresh coin toss and no experiment
98
200
  * could mean anything. Said out loud through onError rather than hidden.
99
201
  */
100
- function resolveDeviceId(storage) {
202
+ function resolveDeviceId(storage, key = DEVICE_ID_KEY) {
101
203
  if (!storage) return randomId();
102
204
  try {
103
- const existing = storage.getString(DEVICE_ID_KEY);
205
+ const existing = storage.getString(key) ?? storage.getString(DEVICE_ID_KEY);
104
206
  if (existing) return existing;
105
207
  const minted = randomId();
106
- storage.set(DEVICE_ID_KEY, minted);
208
+ storage.set(key, minted);
107
209
  return minted;
108
210
  } catch {
109
211
  return randomId();
110
212
  }
111
213
  }
214
+ function sanitizeAttributes(attributes) {
215
+ if (!attributes) return undefined;
216
+ const clean = Object.fromEntries(Object.entries(attributes).filter(([key, value]) => key.trim() !== '' && typeof value === 'string').slice(0, 50));
217
+ return Object.keys(clean).length > 0 ? clean : undefined;
218
+ }
112
219
  function randomId() {
113
220
  const bytes = new Uint8Array(16);
114
221
  const crypto = globalThis.crypto;
@@ -147,4 +254,37 @@ function detectOsVersion() {
147
254
  return undefined;
148
255
  }
149
256
  }
257
+ function detectAppVersion() {
258
+ try {
259
+ // Optional by design: most RN apps already carry this package, plain JS hosts do not.
260
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
261
+ const loaded = require('react-native-device-info');
262
+ return loaded.default?.getVersion?.() ?? loaded.getVersion?.();
263
+ } catch {
264
+ return undefined;
265
+ }
266
+ }
267
+ async function verifyWithNativeKey(canonicalPayload, signature) {
268
+ try {
269
+ // Kept lazy so init/config remain usable in Node, web and test hosts without RN.
270
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
271
+ const updates = require('./PulseUpdates');
272
+ return (await updates.verifyConfigSignatureAsync?.(canonicalPayload, signature)) ?? false;
273
+ } catch {
274
+ return false;
275
+ }
276
+ }
277
+ function detectLanguage() {
278
+ try {
279
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
280
+ const localize = require('react-native-localize');
281
+ return localize.getLocales?.()[0]?.languageTag;
282
+ } catch {
283
+ try {
284
+ return Intl.DateTimeFormat().resolvedOptions().locale;
285
+ } catch {
286
+ return undefined;
287
+ }
288
+ }
289
+ }
150
290
  //# sourceMappingURL=init.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_config","require","_track","DEVICE_ID_KEY","initPulse","opts","base","apiUrl","replace","slug","appSlug","trim","configUrl","trackUrl","deviceId","resolveDeviceId","storage","platform","detectPlatform","osVersion","detectOsVersion","getContext","appVersion","userId","getUserId","userAttributes","getUserAttributes","configureConfig","url","defaults","pollIntervalMs","onError","configureTracking","flushIntervalMs","onIgnored","onIgnoredEvents","Error","fetchConfig","startConfigAutoRefresh","appState","randomId","existing","getString","minted","set","bytes","Uint8Array","crypto","globalThis","getRandomValues","i","length","Math","floor","random","hex","Array","from","b","toString","padStart","join","slice","rn","Platform","OS","undefined","version","Version","String"],"sourceRoot":"../../src","sources":["init.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_config","require","_track","DEVICE_ID_KEY","activeClient","stopActiveRefresh","initPulse","opts","disposeTracking","base","apiUrl","replace","slug","appSlug","trim","configUrl","trackUrl","deviceStorageKey","deviceId","resolveDeviceId","storage","platform","detectPlatform","osVersion","detectOsVersion","appVersion","detectAppVersion","language","detectLanguage","userId","userAttributes","consentOverride","analyticsConsent","undefined","hasConsent","getContext","getUserId","getUserAttributes","configureConfig","url","defaults","storageKey","pollIntervalMs","onError","signingPublicKey","signingKeyId","requireSignature","requireConfigSignature","verifySignature","verifyConfigSignature","verifyWithNativeKey","configureTracking","flushIntervalMs","propertyAllowlist","eventPropertyAllowlist","redactProperties","redactEventProperties","appState","onIgnored","onIgnoredEvents","Error","fetchConfig","stopRefresh","startConfigAutoRefresh","client","track","flush","flushEvents","setUser","nextUserId","attributes","sanitizeAttributes","clearUser","setAnalyticsConsent","granted","resetInstallId","randomId","set","health","config","getConfigInfo","events","getTrackingInfo","boolean","getConfigBoolean","number","getConfigNumber","string","getConfigString","json","getConfigJson","refresh","dispose","initPulseAsync","keys","loaded","Promise","all","map","key","getItem","memory","Map","filter","entry","getString","get","value","setItem","existing","minted","clean","Object","fromEntries","entries","slice","length","bytes","Uint8Array","crypto","globalThis","getRandomValues","i","Math","floor","random","hex","Array","from","b","toString","padStart","join","rn","Platform","OS","version","Version","String","default","getVersion","canonicalPayload","signature","updates","verifyConfigSignatureAsync","localize","getLocales","languageTag","Intl","DateTimeFormat","resolvedOptions","locale"],"sourceRoot":"../../src","sources":["init.ts"],"mappings":"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","ignoreList":[]}
@@ -4,7 +4,9 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.configureTracking = configureTracking;
7
+ exports.disposeTracking = disposeTracking;
7
8
  exports.flushEvents = flushEvents;
9
+ exports.getTrackingInfo = getTrackingInfo;
8
10
  exports.pendingEventCount = pendingEventCount;
9
11
  exports.stopTracking = stopTracking;
10
12
  exports.track = track;
@@ -33,10 +35,16 @@ exports.track = track;
33
35
  const DEFAULT_FLUSH_MS = 10_000;
34
36
  const DEFAULT_MAX_BATCH = 100;
35
37
  const DEFAULT_MAX_QUEUE = 500;
38
+ const DEFAULT_TIMEOUT_MS = 10_000;
39
+ const DEFAULT_MAX_ATTEMPTS = 10;
40
+ const DEFAULT_STORAGE_KEY = 'pulse.events.v1';
36
41
  let options = null;
37
42
  let queue = [];
38
43
  let timer = null;
39
44
  let sending = false;
45
+ let nextAttemptAt = 0;
46
+ let lifecycleSubscription = null;
47
+ let trackingGeneration = 0;
40
48
 
41
49
  /** Turns a config url into the track url; leaves an explicit track url alone. */
42
50
  function trackUrl(url) {
@@ -44,8 +52,14 @@ function trackUrl(url) {
44
52
  return trimmed.includes('/pulse/config/') ? trimmed.replace('/pulse/config/', '/pulse/track/') : trimmed;
45
53
  }
46
54
  function configureTracking(opts) {
55
+ disposeTracking();
47
56
  options = opts;
57
+ queue = readQueue(opts);
58
+ nextAttemptAt = 0;
48
59
  startTimer();
60
+ lifecycleSubscription = opts.appState?.addEventListener('change', state => {
61
+ if (state !== 'active') void flushEvents();
62
+ }) ?? null;
49
63
  }
50
64
 
51
65
  /**
@@ -55,18 +69,32 @@ function configureTracking(opts) {
55
69
  */
56
70
  function track(event, props, time) {
57
71
  if (!options || !event) return;
72
+ if (options.hasConsent?.() === false) {
73
+ options.onDropped?.(1, 'no-consent');
74
+ return;
75
+ }
58
76
  const flat = {};
77
+ const allow = options.propertyAllowlist ? new Set(options.propertyAllowlist) : null;
78
+ const redact = new Set(options.redactProperties ?? []);
59
79
  for (const [key, value] of Object.entries(props ?? {})) {
60
80
  if (value === null || value === undefined) continue;
61
- flat[key] = typeof value === 'string' ? value : String(value);
81
+ if (allow && !allow.has(key)) continue;
82
+ flat[key] = redact.has(key) ? '[REDACTED]' : typeof value === 'string' ? value : String(value);
62
83
  }
63
84
  queue.push({
85
+ id: randomEventId(),
64
86
  event,
65
87
  time: (time ?? new Date()).toISOString(),
66
- props: flat
88
+ props: flat,
89
+ attempts: 0
67
90
  });
68
91
  const maxQueue = options.maxQueue ?? DEFAULT_MAX_QUEUE;
69
- if (queue.length > maxQueue) queue = queue.slice(queue.length - maxQueue);
92
+ if (queue.length > maxQueue) {
93
+ const dropped = queue.length - maxQueue;
94
+ queue = queue.slice(dropped);
95
+ options.onDropped?.(dropped, 'queue-full');
96
+ }
97
+ persistQueue();
70
98
  if (queue.length >= (options.maxBatch ?? DEFAULT_MAX_BATCH)) void flushEvents();
71
99
  }
72
100
 
@@ -78,8 +106,9 @@ function track(event, props, time) {
78
106
  * after launch, when the first events of a session are the ones a funnel needs most.
79
107
  */
80
108
  async function flushEvents() {
81
- if (!options || sending || queue.length === 0) return 0;
109
+ if (!options || sending || queue.length === 0 || Date.now() < nextAttemptAt) return 0;
82
110
  const opts = options;
111
+ const requestGeneration = trackingGeneration;
83
112
  const ctx = opts.getContext?.() ?? {};
84
113
 
85
114
  // Without a device id the server cannot put the event in an arm, and an empty id
@@ -88,7 +117,10 @@ async function flushEvents() {
88
117
  if (!ctx.deviceId) return 0;
89
118
  const batch = queue.slice(0, opts.maxBatch ?? DEFAULT_MAX_BATCH);
90
119
  queue = queue.slice(batch.length);
120
+ persistQueue();
91
121
  sending = true;
122
+ const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
123
+ const timeout = controller ? setTimeout(() => controller.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS) : null;
92
124
  try {
93
125
  const response = await fetch(trackUrl(opts.url), {
94
126
  method: 'POST',
@@ -101,27 +133,37 @@ async function flushEvents() {
101
133
  platform: ctx.platform,
102
134
  appVersion: ctx.appVersion,
103
135
  events: batch.map(e => ({
136
+ id: e.id,
104
137
  event: e.event,
105
138
  time: e.time,
106
139
  props: e.props
107
140
  }))
108
- })
141
+ }),
142
+ signal: controller?.signal
109
143
  });
110
144
  if (!response.ok) {
111
145
  // Rate limited or briefly down: keep the events, try on the next tick.
112
- queue = [...batch, ...queue];
146
+ if (requestGeneration === trackingGeneration && options === opts) {
147
+ requeueWithBackoff(batch, response.status);
148
+ } else {
149
+ restoreStaleBatch(opts, batch, response.status);
150
+ }
113
151
  if (response.status !== 429) opts.onError?.(new Error(`Pulse track failed: ${response.status}`));
114
152
  return 0;
115
153
  }
116
154
  const body = await response.json();
155
+ if (requestGeneration !== trackingGeneration || options !== opts) return body.accepted ?? 0;
117
156
  if (body.ignored && body.ignored.length > 0) opts.onIgnored?.(body.ignored);
157
+ nextAttemptAt = 0;
158
+ persistQueue();
118
159
  return body.accepted ?? 0;
119
160
  } catch (error) {
120
- queue = [...batch, ...queue];
161
+ if (requestGeneration === trackingGeneration && options === opts) requeueWithBackoff(batch);else restoreStaleBatch(opts, batch);
121
162
  opts.onError?.(error);
122
163
  return 0;
123
164
  } finally {
124
- sending = false;
165
+ if (timeout) clearTimeout(timeout);
166
+ if (requestGeneration === trackingGeneration) sending = false;
125
167
  }
126
168
  }
127
169
 
@@ -129,14 +171,31 @@ async function flushEvents() {
129
171
  function pendingEventCount() {
130
172
  return queue.length;
131
173
  }
174
+ function getTrackingInfo() {
175
+ return {
176
+ queueDepth: queue.length,
177
+ sending,
178
+ nextAttemptAt
179
+ };
180
+ }
181
+
182
+ /** Stop timers and listeners while preserving the durable outbox. */
183
+ function disposeTracking() {
184
+ trackingGeneration += 1;
185
+ if (timer) clearInterval(timer);
186
+ timer = null;
187
+ lifecycleSubscription?.remove();
188
+ lifecycleSubscription = null;
189
+ persistQueue();
190
+ options = null;
191
+ sending = false;
192
+ }
132
193
  function stopTracking() {
133
- if (timer) {
134
- clearInterval(timer);
135
- timer = null;
136
- }
194
+ disposeTracking();
137
195
  options = null;
138
196
  queue = [];
139
197
  sending = false;
198
+ nextAttemptAt = 0;
140
199
  }
141
200
  function startTimer() {
142
201
  if (timer) clearInterval(timer);
@@ -146,4 +205,87 @@ function startTimer() {
146
205
  // and a CLI importing this should still be able to exit.
147
206
  timer.unref?.();
148
207
  }
208
+ function requeueWithBackoff(batch, status) {
209
+ if (!options) return;
210
+ const maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
211
+ const retryable = [];
212
+ let dropped = 0;
213
+ for (const event of batch) {
214
+ const next = {
215
+ ...event,
216
+ attempts: event.attempts + 1
217
+ };
218
+ if (next.attempts >= maxAttempts && status !== 429) dropped++;else retryable.push(next);
219
+ }
220
+ queue = [...retryable, ...queue];
221
+ if (dropped > 0) options.onDropped?.(dropped, 'max-attempts');
222
+ const attempts = retryable.reduce((max, event) => Math.max(max, event.attempts), 1);
223
+ const base = Math.min(60_000, 1_000 * 2 ** Math.min(attempts - 1, 6));
224
+ nextAttemptAt = Date.now() + base + Math.floor(Math.random() * Math.max(1, base / 4));
225
+ persistQueue();
226
+ }
227
+
228
+ /**
229
+ * An old request may fail after another app has been configured. Its rows belong in
230
+ * the old app's outbox, never in the new app's in-memory queue. When the same app was
231
+ * merely reconfigured, merge them back into the live queue so it need not restart to
232
+ * see them; otherwise persist directly under the captured app-scoped key.
233
+ */
234
+ function restoreStaleBatch(opts, batch, status) {
235
+ const maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
236
+ const retryable = [];
237
+ let dropped = 0;
238
+ for (const event of batch) {
239
+ const next = {
240
+ ...event,
241
+ attempts: event.attempts + 1
242
+ };
243
+ if (next.attempts >= maxAttempts && status !== 429) dropped++;else retryable.push(next);
244
+ }
245
+ if (dropped > 0) opts.onDropped?.(dropped, 'max-attempts');
246
+ if (retryable.length === 0) return;
247
+ const currentOptions = options;
248
+ const sameOutbox = currentOptions?.storage === opts.storage && currentOptions !== null && storageKey(currentOptions) === storageKey(opts);
249
+ if (sameOutbox) {
250
+ queue = [...retryable, ...queue].slice(-(options?.maxQueue ?? DEFAULT_MAX_QUEUE));
251
+ persistQueue();
252
+ return;
253
+ }
254
+ if (!opts.storage) return;
255
+ try {
256
+ const stored = readQueue(opts);
257
+ const restored = [...retryable, ...stored].slice(-(opts.maxQueue ?? DEFAULT_MAX_QUEUE));
258
+ opts.storage.set(storageKey(opts), JSON.stringify(restored));
259
+ } catch {
260
+ // Best effort only; a telemetry recovery must not affect the new app session.
261
+ }
262
+ }
263
+ function storageKey(opts) {
264
+ return opts.storageKey?.trim() || DEFAULT_STORAGE_KEY;
265
+ }
266
+ function readQueue(opts) {
267
+ if (!opts.storage) return [];
268
+ try {
269
+ const raw = opts.storage.getString(storageKey(opts));
270
+ if (!raw) return [];
271
+ const parsed = JSON.parse(raw);
272
+ if (!Array.isArray(parsed)) return [];
273
+ return parsed.filter(item => Boolean(item && typeof item === 'object' && typeof item.id === 'string' && typeof item.event === 'string' && typeof item.time === 'string' && typeof item.props === 'object' && typeof item.attempts === 'number')).slice(-(opts.maxQueue ?? DEFAULT_MAX_QUEUE));
274
+ } catch {
275
+ return [];
276
+ }
277
+ }
278
+ function persistQueue() {
279
+ if (!options?.storage) return;
280
+ try {
281
+ options.storage.set(storageKey(options), JSON.stringify(queue));
282
+ } catch {
283
+ // Telemetry persistence must never become an app failure.
284
+ }
285
+ }
286
+ function randomEventId() {
287
+ const cryptoLike = globalThis.crypto;
288
+ if (typeof cryptoLike?.randomUUID === 'function') return cryptoLike.randomUUID();
289
+ return `evt-${Date.now()}-${Math.random().toString(36).slice(2, 14)}`;
290
+ }
149
291
  //# sourceMappingURL=track.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["DEFAULT_FLUSH_MS","DEFAULT_MAX_BATCH","DEFAULT_MAX_QUEUE","options","queue","timer","sending","trackUrl","url","trimmed","replace","includes","configureTracking","opts","startTimer","track","event","props","time","flat","key","value","Object","entries","undefined","String","push","Date","toISOString","maxQueue","length","slice","maxBatch","flushEvents","ctx","getContext","deviceId","batch","response","fetch","method","headers","body","JSON","stringify","userId","platform","appVersion","events","map","e","ok","status","onError","Error","json","ignored","onIgnored","accepted","error","pendingEventCount","stopTracking","clearInterval","every","flushIntervalMs","setInterval","unref"],"sourceRoot":"../../src","sources":["track.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["DEFAULT_FLUSH_MS","DEFAULT_MAX_BATCH","DEFAULT_MAX_QUEUE","DEFAULT_TIMEOUT_MS","DEFAULT_MAX_ATTEMPTS","DEFAULT_STORAGE_KEY","options","queue","timer","sending","nextAttemptAt","lifecycleSubscription","trackingGeneration","trackUrl","url","trimmed","replace","includes","configureTracking","opts","disposeTracking","readQueue","startTimer","appState","addEventListener","state","flushEvents","track","event","props","time","hasConsent","onDropped","flat","allow","propertyAllowlist","Set","redact","redactProperties","key","value","Object","entries","undefined","has","String","push","id","randomEventId","Date","toISOString","attempts","maxQueue","length","dropped","slice","persistQueue","maxBatch","now","requestGeneration","ctx","getContext","deviceId","batch","controller","AbortController","timeout","setTimeout","abort","timeoutMs","response","fetch","method","headers","body","JSON","stringify","userId","platform","appVersion","events","map","e","signal","ok","requeueWithBackoff","status","restoreStaleBatch","onError","Error","json","accepted","ignored","onIgnored","error","clearTimeout","pendingEventCount","getTrackingInfo","queueDepth","clearInterval","remove","stopTracking","every","flushIntervalMs","setInterval","unref","maxAttempts","retryable","next","reduce","max","Math","base","min","floor","random","currentOptions","sameOutbox","storage","storageKey","stored","restored","set","trim","raw","getString","parsed","parse","Array","isArray","filter","item","Boolean","cryptoLike","globalThis","crypto","randomUUID","toString"],"sourceRoot":"../../src","sources":["track.ts"],"mappings":"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","ignoreList":[]}
@@ -8,6 +8,7 @@ var _react = require("react");
8
8
  var PulseUpdates = _interopRequireWildcard(require("./PulseUpdates"));
9
9
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
10
10
  function usePulseUpdates() {
11
+ const [nativeState, setNativeState] = (0, _react.useState)(PulseUpdates.getUpdatesState);
11
12
  const [isChecking, setIsChecking] = (0, _react.useState)(false);
12
13
  const [isDownloading, setIsDownloading] = (0, _react.useState)(false);
13
14
  const [availableUpdate, setAvailableUpdate] = (0, _react.useState)(null);
@@ -16,10 +17,14 @@ function usePulseUpdates() {
16
17
 
17
18
  // Refresh state on mount to get latest values after configure
18
19
  (0, _react.useEffect)(() => {
19
- PulseUpdates.refreshStateAsync().catch(() => {});
20
+ const unsubscribe = PulseUpdates.onUpdatesStateChange(() => {
21
+ setNativeState(PulseUpdates.getUpdatesState());
22
+ });
23
+ void PulseUpdates.refreshStateAsync();
24
+ return unsubscribe;
20
25
  }, []);
21
26
  (0, _react.useEffect)(() => {
22
- if (!PulseUpdates.isEnabled) return;
27
+ if (!nativeState.isEnabled) return;
23
28
  const subscription = PulseUpdates.addUpdateListener(event => {
24
29
  switch (event.type) {
25
30
  case 'updateAvailable':
@@ -37,9 +42,9 @@ function usePulseUpdates() {
37
42
  }
38
43
  });
39
44
  return () => subscription.remove();
40
- }, []);
45
+ }, [nativeState.isEnabled]);
41
46
  const checkForUpdate = (0, _react.useCallback)(async () => {
42
- if (!PulseUpdates.isEnabled) {
47
+ if (!nativeState.isEnabled) {
43
48
  return {
44
49
  isAvailable: false
45
50
  };
@@ -64,9 +69,9 @@ function usePulseUpdates() {
64
69
  } finally {
65
70
  setIsChecking(false);
66
71
  }
67
- }, []);
72
+ }, [nativeState.isEnabled]);
68
73
  const downloadUpdate = (0, _react.useCallback)(async () => {
69
- if (!PulseUpdates.isEnabled) {
74
+ if (!nativeState.isEnabled) {
70
75
  return {
71
76
  isNew: false
72
77
  };
@@ -88,21 +93,21 @@ function usePulseUpdates() {
88
93
  } finally {
89
94
  setIsDownloading(false);
90
95
  }
91
- }, []);
96
+ }, [nativeState.isEnabled]);
92
97
  const reload = (0, _react.useCallback)(async () => {
93
- if (!PulseUpdates.isEnabled) return;
98
+ if (!nativeState.isEnabled) return;
94
99
  await PulseUpdates.reloadAsync();
95
- }, []);
100
+ }, [nativeState.isEnabled]);
96
101
  return {
97
- isEnabled: PulseUpdates.isEnabled,
102
+ isEnabled: nativeState.isEnabled,
98
103
  isChecking,
99
104
  isDownloading,
100
- updateId: PulseUpdates.updateId,
101
- runtimeVersion: PulseUpdates.runtimeVersion,
102
- channel: PulseUpdates.channel,
103
- manifest: PulseUpdates.manifest,
104
- isEmbeddedLaunch: PulseUpdates.isEmbeddedLaunch,
105
- createdAt: PulseUpdates.createdAt,
105
+ updateId: nativeState.updateId,
106
+ runtimeVersion: nativeState.runtimeVersion,
107
+ channel: nativeState.channel,
108
+ manifest: nativeState.manifest,
109
+ isEmbeddedLaunch: nativeState.isEmbeddedLaunch,
110
+ createdAt: nativeState.createdAt,
106
111
  build: PulseUpdates.getUpdateBuild(),
107
112
  availableUpdate,
108
113
  downloadedUpdate,