@usero/sdk 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vanilla.js CHANGED
@@ -157,7 +157,11 @@ function getGradientEnd(color) {
157
157
 
158
158
  // src/identity.ts
159
159
  var ANON_STORAGE_KEY = "usero:anonymous-id";
160
+ var SDK_SESSION_STORAGE_KEY = "usero:session-replay:sdk-session-id";
160
161
  var cachedAnonymousId = null;
162
+ var cachedSdkSessionId = null;
163
+ var currentUserId = null;
164
+ var replayStartMs = null;
161
165
  var lastIdentifyFingerprint = null;
162
166
  function generateRandomId() {
163
167
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
@@ -188,6 +192,21 @@ function safeWriteLocalStorage(key, value) {
188
192
  } catch {
189
193
  }
190
194
  }
195
+ function safeReadSessionStorage(key) {
196
+ if (typeof window === "undefined") return null;
197
+ try {
198
+ return window.sessionStorage?.getItem(key) ?? null;
199
+ } catch {
200
+ return null;
201
+ }
202
+ }
203
+ function safeWriteSessionStorage(key, value) {
204
+ if (typeof window === "undefined") return;
205
+ try {
206
+ window.sessionStorage?.setItem(key, value);
207
+ } catch {
208
+ }
209
+ }
191
210
  function getOrMintAnonymousId() {
192
211
  if (cachedAnonymousId) return cachedAnonymousId;
193
212
  const existing = safeReadLocalStorage(ANON_STORAGE_KEY);
@@ -205,8 +224,30 @@ function rotateAnonymousId() {
205
224
  cachedAnonymousId = id;
206
225
  safeWriteLocalStorage(ANON_STORAGE_KEY, id);
207
226
  lastIdentifyFingerprint = null;
227
+ currentUserId = null;
208
228
  return id;
209
229
  }
230
+ function getOrMintSdkSessionId() {
231
+ if (cachedSdkSessionId) return cachedSdkSessionId;
232
+ const existing = safeReadSessionStorage(SDK_SESSION_STORAGE_KEY);
233
+ if (existing && /^[a-z0-9-]{8,}$/i.test(existing)) {
234
+ cachedSdkSessionId = existing;
235
+ return existing;
236
+ }
237
+ const id = generateRandomId();
238
+ safeWriteSessionStorage(SDK_SESSION_STORAGE_KEY, id);
239
+ cachedSdkSessionId = id;
240
+ return id;
241
+ }
242
+ function getCurrentUserId() {
243
+ return currentUserId;
244
+ }
245
+ function publishReplayStartMs(epochMs) {
246
+ if (replayStartMs === null) replayStartMs = epochMs;
247
+ }
248
+ function getReplayStartMs() {
249
+ return replayStartMs;
250
+ }
210
251
  function fingerprintUser(anonymousId, user) {
211
252
  const traits = user.traits ?? {};
212
253
  const keys = Object.keys(traits).sort();
@@ -215,6 +256,7 @@ function fingerprintUser(anonymousId, user) {
215
256
  }
216
257
  async function identifyIfChanged(transport, user) {
217
258
  const anonymousId = getOrMintAnonymousId();
259
+ currentUserId = user.id;
218
260
  const fp = fingerprintUser(anonymousId, user);
219
261
  if (fp === lastIdentifyFingerprint) return false;
220
262
  const url = `${transport.apiUrl.replace(/\/$/, "")}/api/identify`;
@@ -903,7 +945,15 @@ function initUseroFeedbackWidget(props) {
903
945
  } else {
904
946
  resolveAndApplyGetUser();
905
947
  }
906
- }
948
+ },
949
+ // Core-owned cross-cutting identity. Every plugin reads the same
950
+ // source of truth in identity.ts, so user-test and session-replay
951
+ // agree on the per-tab sdkSessionId without importing each other.
952
+ getSdkSessionId: () => getOrMintSdkSessionId(),
953
+ getAnonymousId: () => getOrMintAnonymousId(),
954
+ getUserId: () => getCurrentUserId(),
955
+ getReplayStartMs: () => getReplayStartMs(),
956
+ publishReplayStartMs: (epochMs) => publishReplayStartMs(epochMs)
907
957
  };
908
958
  pluginContexts.set(plugin.name, ctx);
909
959
  if (plugin.onInit) {