@v-tilt/browser 1.4.3 → 1.4.4
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/array.full.js +1 -1
- package/dist/array.full.js.map +1 -1
- package/dist/array.js +1 -1
- package/dist/array.js.map +1 -1
- package/dist/array.no-external.js +1 -1
- package/dist/array.no-external.js.map +1 -1
- package/dist/chat.js.map +1 -1
- package/dist/extensions/chat/chat-wrapper.d.ts +1 -1
- package/dist/extensions/chat/chat.d.ts +2 -2
- package/dist/external-scripts-loader.js +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/module.no-external.js +1 -1
- package/dist/module.no-external.js.map +1 -1
- package/dist/storage.d.ts +68 -51
- package/dist/user-manager.d.ts +15 -1
- package/lib/entrypoints/external-scripts-loader.js +1 -1
- package/lib/extensions/chat/chat-wrapper.d.ts +1 -1
- package/lib/extensions/chat/chat-wrapper.js +12 -6
- package/lib/extensions/chat/chat.d.ts +2 -2
- package/lib/extensions/chat/chat.js +89 -44
- package/lib/storage.d.ts +68 -51
- package/lib/storage.js +306 -219
- package/lib/user-manager.d.ts +15 -1
- package/lib/user-manager.js +38 -6
- package/lib/vtilt.js +6 -2
- package/package.json +1 -1
package/lib/storage.js
CHANGED
|
@@ -1,194 +1,369 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Unified Storage Manager
|
|
3
|
+
* Unified Storage Manager
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Handles all storage operations for sessions and users with consistent
|
|
6
|
+
* cookie handling across different persistence methods.
|
|
7
7
|
*
|
|
8
8
|
* Storage methods:
|
|
9
|
-
* - cookie
|
|
10
|
-
* - localStorage
|
|
11
|
-
* - sessionStorage
|
|
12
|
-
* - localStorage+cookie
|
|
13
|
-
*
|
|
9
|
+
* - `cookie`: Browser cookies with cross-subdomain support
|
|
10
|
+
* - `localStorage`: Persistent local storage
|
|
11
|
+
* - `sessionStorage`: Tab-specific storage (cleared on tab close)
|
|
12
|
+
* - `localStorage+cookie`: Hybrid mode (default) - full data in localStorage,
|
|
13
|
+
* critical identity properties also in cookies for SSR support
|
|
14
|
+
* - `memory`: In-memory only (no persistence)
|
|
15
|
+
*
|
|
16
|
+
* The `localStorage+cookie` mode is designed for traditional server-side
|
|
17
|
+
* rendered websites where each page navigation reloads JavaScript:
|
|
18
|
+
* - Critical properties (anonymous_id, device_id, etc.) are stored in cookies
|
|
19
|
+
* - Cookies ensure identity persists across full page reloads
|
|
20
|
+
* - localStorage provides fast access for SPA-style navigation
|
|
21
|
+
* - Falls back to cookie-only if localStorage is unavailable
|
|
14
22
|
*/
|
|
15
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.StorageManager = exports.USER_COOKIE_MAX_AGE = exports.SESSION_COOKIE_MAX_AGE = void 0;
|
|
24
|
+
exports.StorageManager = exports.USER_COOKIE_MAX_AGE = exports.SESSION_COOKIE_MAX_AGE = exports.COOKIE_PERSISTED_PROPERTIES = void 0;
|
|
17
25
|
exports.shouldUseCrossSubdomainCookie = shouldUseCrossSubdomainCookie;
|
|
18
26
|
exports.createStorageManager = createStorageManager;
|
|
19
27
|
const constants_1 = require("./constants");
|
|
20
28
|
const globals_1 = require("./utils/globals");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Critical properties persisted to cookies in `localStorage+cookie` mode.
|
|
31
|
+
* These ensure identity survives full page reloads in traditional SSR websites.
|
|
32
|
+
*/
|
|
33
|
+
exports.COOKIE_PERSISTED_PROPERTIES = [
|
|
34
|
+
constants_1.ANONYMOUS_ID_KEY,
|
|
35
|
+
constants_1.DEVICE_ID_KEY,
|
|
36
|
+
constants_1.DISTINCT_ID_KEY,
|
|
37
|
+
constants_1.USER_STATE_KEY,
|
|
38
|
+
];
|
|
39
|
+
/** Session cookie TTL: 30 minutes */
|
|
40
|
+
exports.SESSION_COOKIE_MAX_AGE = 1800;
|
|
41
|
+
/** User cookie TTL: 1 year */
|
|
42
|
+
exports.USER_COOKIE_MAX_AGE = 31536000;
|
|
43
|
+
/** Platforms where cross-subdomain cookies are disabled */
|
|
25
44
|
const EXCLUDED_FROM_CROSS_SUBDOMAIN = [
|
|
26
45
|
"herokuapp.com",
|
|
27
46
|
"vercel.app",
|
|
28
47
|
"netlify.app",
|
|
29
48
|
];
|
|
30
49
|
/**
|
|
31
|
-
*
|
|
32
|
-
* Returns false for platforms
|
|
50
|
+
* Check if cross-subdomain cookies should be enabled.
|
|
51
|
+
* Returns false for shared hosting platforms to prevent cookie conflicts.
|
|
33
52
|
*/
|
|
34
53
|
function shouldUseCrossSubdomainCookie() {
|
|
35
54
|
var _a;
|
|
36
|
-
if (typeof document === "undefined")
|
|
55
|
+
if (typeof document === "undefined")
|
|
37
56
|
return false;
|
|
38
|
-
}
|
|
39
57
|
const hostname = (_a = document.location) === null || _a === void 0 ? void 0 : _a.hostname;
|
|
40
|
-
if (!hostname)
|
|
58
|
+
if (!hostname)
|
|
41
59
|
return false;
|
|
42
|
-
}
|
|
43
60
|
const lastTwoParts = hostname.split(".").slice(-2).join(".");
|
|
44
|
-
|
|
45
|
-
if (lastTwoParts === excluded) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return true;
|
|
61
|
+
return !EXCLUDED_FROM_CROSS_SUBDOMAIN.includes(lastTwoParts);
|
|
50
62
|
}
|
|
51
63
|
/**
|
|
52
|
-
* Get
|
|
53
|
-
*
|
|
64
|
+
* Get cookie domain for cross-subdomain cookies.
|
|
65
|
+
* @returns Domain like ".example.com" or empty string for same-origin
|
|
54
66
|
*/
|
|
55
67
|
function getCookieDomain(cross_subdomain) {
|
|
56
68
|
var _a;
|
|
57
|
-
if (!cross_subdomain)
|
|
69
|
+
if (!cross_subdomain || typeof document === "undefined")
|
|
58
70
|
return "";
|
|
59
|
-
}
|
|
60
|
-
if (typeof document === "undefined") {
|
|
61
|
-
return "";
|
|
62
|
-
}
|
|
63
71
|
const hostname = (_a = document.location) === null || _a === void 0 ? void 0 : _a.hostname;
|
|
64
|
-
if (!hostname)
|
|
72
|
+
if (!hostname)
|
|
65
73
|
return "";
|
|
66
|
-
}
|
|
67
|
-
// Match domain pattern like "example.com" from "sub.example.com"
|
|
68
74
|
const matches = hostname.match(/[a-z0-9][a-z0-9-]+\.[a-z]{2,}$/i);
|
|
69
75
|
return matches ? `.${matches[0]}` : "";
|
|
70
76
|
}
|
|
71
77
|
/**
|
|
72
78
|
* Unified Storage Manager
|
|
79
|
+
*
|
|
73
80
|
* Provides consistent storage operations across all persistence methods
|
|
81
|
+
* with automatic fallbacks and SSR support.
|
|
74
82
|
*/
|
|
75
83
|
class StorageManager {
|
|
76
84
|
constructor(options) {
|
|
77
|
-
var _a, _b;
|
|
85
|
+
var _a, _b, _c;
|
|
78
86
|
this.memoryStorage = new Map();
|
|
87
|
+
this._localStorageSupported = null;
|
|
79
88
|
this.method = options.method;
|
|
80
89
|
this.cross_subdomain =
|
|
81
90
|
(_a = options.cross_subdomain) !== null && _a !== void 0 ? _a : shouldUseCrossSubdomainCookie();
|
|
82
|
-
this.sameSite = options.sameSite
|
|
83
|
-
// Auto-detect secure flag from protocol
|
|
91
|
+
this.sameSite = (_b = options.sameSite) !== null && _b !== void 0 ? _b : "Lax";
|
|
84
92
|
this.secure =
|
|
85
|
-
(
|
|
93
|
+
(_c = options.secure) !== null && _c !== void 0 ? _c : (typeof location !== "undefined" && location.protocol === "https:");
|
|
86
94
|
}
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Storage availability checks
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
/** Check if localStorage is available (result is cached) */
|
|
99
|
+
isLocalStorageSupported() {
|
|
100
|
+
if (this._localStorageSupported !== null) {
|
|
101
|
+
return this._localStorageSupported;
|
|
102
|
+
}
|
|
103
|
+
if (typeof globals_1.window === "undefined" || !globals_1.window.localStorage) {
|
|
104
|
+
this._localStorageSupported = false;
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const testKey = "__vt_ls_test__";
|
|
109
|
+
globals_1.window.localStorage.setItem(testKey, "1");
|
|
110
|
+
const ok = globals_1.window.localStorage.getItem(testKey) === "1";
|
|
111
|
+
globals_1.window.localStorage.removeItem(testKey);
|
|
112
|
+
this._localStorageSupported = ok;
|
|
113
|
+
if (!ok) {
|
|
114
|
+
console.warn("[vTilt] localStorage unavailable, using cookies");
|
|
115
|
+
}
|
|
116
|
+
return ok;
|
|
117
|
+
}
|
|
118
|
+
catch (_a) {
|
|
119
|
+
this._localStorageSupported = false;
|
|
120
|
+
console.warn("[vTilt] localStorage unavailable, using cookies");
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Check if a key should be persisted to cookies */
|
|
125
|
+
isCriticalProperty(key) {
|
|
126
|
+
return exports.COOKIE_PERSISTED_PROPERTIES.includes(key);
|
|
127
|
+
}
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Public API
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
90
131
|
/**
|
|
91
|
-
* Get a value from storage
|
|
132
|
+
* Get a value from storage.
|
|
133
|
+
*
|
|
134
|
+
* For `localStorage+cookie` mode:
|
|
135
|
+
* - Critical properties: read cookie first (for SSR), fall back to localStorage
|
|
136
|
+
* - Non-critical properties: read from localStorage only
|
|
92
137
|
*/
|
|
93
138
|
get(key) {
|
|
94
139
|
var _a;
|
|
95
140
|
try {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
141
|
+
switch (this.method) {
|
|
142
|
+
case constants_1.PERSISTENCE_METHODS.memory:
|
|
143
|
+
return (_a = this.memoryStorage.get(key)) !== null && _a !== void 0 ? _a : null;
|
|
144
|
+
case constants_1.PERSISTENCE_METHODS.localStoragePlusCookie:
|
|
145
|
+
return this.getLocalStoragePlusCookie(key);
|
|
146
|
+
case constants_1.PERSISTENCE_METHODS.localStorage:
|
|
147
|
+
return this.getLocalStorage(key);
|
|
148
|
+
case constants_1.PERSISTENCE_METHODS.sessionStorage:
|
|
149
|
+
return this.readFromSessionStorage(key);
|
|
150
|
+
case constants_1.PERSISTENCE_METHODS.cookie:
|
|
151
|
+
default:
|
|
106
152
|
return this.getCookie(key);
|
|
107
|
-
}
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
if (this.usesSessionStorage()) {
|
|
111
|
-
return sessionStorage.getItem(key);
|
|
112
153
|
}
|
|
113
|
-
// Cookie-only mode
|
|
114
|
-
return this.getCookie(key);
|
|
115
154
|
}
|
|
116
|
-
catch (
|
|
117
|
-
console.warn(`[
|
|
155
|
+
catch (err) {
|
|
156
|
+
console.warn(`[vTilt] Storage get error for "${key}":`, err);
|
|
118
157
|
return null;
|
|
119
158
|
}
|
|
120
159
|
}
|
|
121
160
|
/**
|
|
122
|
-
* Set a value in storage
|
|
123
|
-
* @param maxAge
|
|
161
|
+
* Set a value in storage.
|
|
162
|
+
* @param maxAge Cookie max age in seconds (only for cookie-based storage)
|
|
163
|
+
*
|
|
164
|
+
* For `localStorage+cookie` mode:
|
|
165
|
+
* - All values stored in localStorage (if available)
|
|
166
|
+
* - Critical properties ALWAYS stored in cookies for SSR support
|
|
124
167
|
*/
|
|
125
168
|
set(key, value, maxAge) {
|
|
126
169
|
try {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
this.
|
|
136
|
-
|
|
137
|
-
|
|
170
|
+
switch (this.method) {
|
|
171
|
+
case constants_1.PERSISTENCE_METHODS.memory:
|
|
172
|
+
this.memoryStorage.set(key, value);
|
|
173
|
+
break;
|
|
174
|
+
case constants_1.PERSISTENCE_METHODS.localStoragePlusCookie:
|
|
175
|
+
this.setLocalStoragePlusCookie(key, value, maxAge);
|
|
176
|
+
break;
|
|
177
|
+
case constants_1.PERSISTENCE_METHODS.localStorage:
|
|
178
|
+
this.setLocalStorage(key, value);
|
|
179
|
+
break;
|
|
180
|
+
case constants_1.PERSISTENCE_METHODS.sessionStorage:
|
|
181
|
+
this.writeToSessionStorage(key, value);
|
|
182
|
+
break;
|
|
183
|
+
case constants_1.PERSISTENCE_METHODS.cookie:
|
|
184
|
+
default:
|
|
185
|
+
this.setCookie(key, value, maxAge !== null && maxAge !== void 0 ? maxAge : exports.USER_COOKIE_MAX_AGE);
|
|
138
186
|
}
|
|
139
|
-
if (this.usesSessionStorage()) {
|
|
140
|
-
sessionStorage.setItem(key, value);
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
// Cookie-only mode
|
|
144
|
-
this.setCookie(key, value, maxAge || exports.USER_COOKIE_MAX_AGE);
|
|
145
187
|
}
|
|
146
|
-
catch (
|
|
147
|
-
console.warn(`[
|
|
188
|
+
catch (err) {
|
|
189
|
+
console.warn(`[vTilt] Storage set error for "${key}":`, err);
|
|
148
190
|
}
|
|
149
191
|
}
|
|
150
|
-
/**
|
|
151
|
-
* Remove a value from storage
|
|
152
|
-
*/
|
|
192
|
+
/** Remove a value from storage */
|
|
153
193
|
remove(key) {
|
|
154
194
|
try {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
195
|
+
switch (this.method) {
|
|
196
|
+
case constants_1.PERSISTENCE_METHODS.memory:
|
|
197
|
+
this.memoryStorage.delete(key);
|
|
198
|
+
break;
|
|
199
|
+
case constants_1.PERSISTENCE_METHODS.localStoragePlusCookie:
|
|
200
|
+
this.removeLocalStoragePlusCookie(key);
|
|
201
|
+
break;
|
|
202
|
+
case constants_1.PERSISTENCE_METHODS.localStorage:
|
|
203
|
+
this.removeLocalStorage(key);
|
|
204
|
+
break;
|
|
205
|
+
case constants_1.PERSISTENCE_METHODS.sessionStorage:
|
|
206
|
+
this.removeFromSessionStorage(key);
|
|
207
|
+
break;
|
|
208
|
+
case constants_1.PERSISTENCE_METHODS.cookie:
|
|
209
|
+
default:
|
|
162
210
|
this.removeCookie(key);
|
|
163
|
-
}
|
|
164
|
-
return;
|
|
165
211
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
console.warn(`[vTilt] Storage remove error for "${key}":`, err);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// localStorage+cookie mode (hybrid)
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
getLocalStoragePlusCookie(key) {
|
|
221
|
+
if (this.isCriticalProperty(key)) {
|
|
222
|
+
// Critical: cookie takes precedence (for SSR support)
|
|
223
|
+
const cookieValue = this.getCookie(key);
|
|
224
|
+
const lsValue = this.getLocalStorage(key);
|
|
225
|
+
if (cookieValue !== null) {
|
|
226
|
+
// Sync to localStorage for faster future reads
|
|
227
|
+
if (lsValue !== cookieValue && this.isLocalStorageSupported()) {
|
|
228
|
+
try {
|
|
229
|
+
globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.localStorage.setItem(key, cookieValue);
|
|
230
|
+
}
|
|
231
|
+
catch (_a) {
|
|
232
|
+
/* ignore */
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return cookieValue;
|
|
169
236
|
}
|
|
170
|
-
|
|
237
|
+
return lsValue;
|
|
238
|
+
}
|
|
239
|
+
// Non-critical: localStorage only
|
|
240
|
+
return this.getLocalStorage(key);
|
|
241
|
+
}
|
|
242
|
+
setLocalStoragePlusCookie(key, value, maxAge) {
|
|
243
|
+
// Always try localStorage first
|
|
244
|
+
this.setLocalStorage(key, value);
|
|
245
|
+
// Critical properties MUST go to cookies (SSR support)
|
|
246
|
+
if (this.isCriticalProperty(key)) {
|
|
247
|
+
this.setCookie(key, value, maxAge !== null && maxAge !== void 0 ? maxAge : exports.USER_COOKIE_MAX_AGE);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
removeLocalStoragePlusCookie(key) {
|
|
251
|
+
this.removeLocalStorage(key);
|
|
252
|
+
if (this.isCriticalProperty(key)) {
|
|
171
253
|
this.removeCookie(key);
|
|
172
254
|
}
|
|
173
|
-
|
|
174
|
-
|
|
255
|
+
}
|
|
256
|
+
// ---------------------------------------------------------------------------
|
|
257
|
+
// localStorage operations
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
getLocalStorage(key) {
|
|
260
|
+
var _a;
|
|
261
|
+
if (!this.isLocalStorageSupported())
|
|
262
|
+
return null;
|
|
263
|
+
try {
|
|
264
|
+
return (_a = globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.localStorage.getItem(key)) !== null && _a !== void 0 ? _a : null;
|
|
265
|
+
}
|
|
266
|
+
catch (_b) {
|
|
267
|
+
return null;
|
|
175
268
|
}
|
|
176
269
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
270
|
+
setLocalStorage(key, value) {
|
|
271
|
+
if (!this.isLocalStorageSupported())
|
|
272
|
+
return;
|
|
273
|
+
try {
|
|
274
|
+
globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.localStorage.setItem(key, value);
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
console.warn("[vTilt] localStorage write error:", err);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
removeLocalStorage(key) {
|
|
281
|
+
if (!this.isLocalStorageSupported())
|
|
282
|
+
return;
|
|
283
|
+
try {
|
|
284
|
+
globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.localStorage.removeItem(key);
|
|
285
|
+
}
|
|
286
|
+
catch (_a) {
|
|
287
|
+
/* ignore */
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
// sessionStorage operations (internal)
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
readFromSessionStorage(key) {
|
|
294
|
+
var _a;
|
|
295
|
+
try {
|
|
296
|
+
return (_a = globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.sessionStorage.getItem(key)) !== null && _a !== void 0 ? _a : null;
|
|
297
|
+
}
|
|
298
|
+
catch (_b) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
writeToSessionStorage(key, value) {
|
|
303
|
+
try {
|
|
304
|
+
globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.sessionStorage.setItem(key, value);
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
console.warn("[vTilt] sessionStorage write error:", err);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
removeFromSessionStorage(key) {
|
|
311
|
+
try {
|
|
312
|
+
globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.sessionStorage.removeItem(key);
|
|
313
|
+
}
|
|
314
|
+
catch (_a) {
|
|
315
|
+
/* ignore */
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// ---------------------------------------------------------------------------
|
|
319
|
+
// Cookie operations
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
getCookie(name) {
|
|
322
|
+
if (typeof document === "undefined")
|
|
323
|
+
return null;
|
|
324
|
+
const nameEq = name + "=";
|
|
325
|
+
for (const part of document.cookie.split(";")) {
|
|
326
|
+
const trimmed = part.trim();
|
|
327
|
+
if (trimmed.startsWith(nameEq)) {
|
|
328
|
+
try {
|
|
329
|
+
return decodeURIComponent(trimmed.slice(nameEq.length));
|
|
330
|
+
}
|
|
331
|
+
catch (_a) {
|
|
332
|
+
return trimmed.slice(nameEq.length);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
setCookie(name, value, maxAge) {
|
|
339
|
+
if (typeof document === "undefined")
|
|
340
|
+
return;
|
|
341
|
+
const domain = getCookieDomain(this.cross_subdomain);
|
|
342
|
+
let cookie = `${name}=${encodeURIComponent(value)}; Max-Age=${maxAge}; path=/; SameSite=${this.sameSite}`;
|
|
343
|
+
if (this.secure)
|
|
344
|
+
cookie += "; Secure";
|
|
345
|
+
if (domain)
|
|
346
|
+
cookie += `; domain=${domain}`;
|
|
347
|
+
document.cookie = cookie;
|
|
348
|
+
}
|
|
349
|
+
removeCookie(name) {
|
|
350
|
+
if (typeof document === "undefined")
|
|
351
|
+
return;
|
|
352
|
+
const domain = getCookieDomain(this.cross_subdomain);
|
|
353
|
+
document.cookie = `${name}=; Max-Age=0; path=/${domain ? `; domain=${domain}` : ""}`;
|
|
354
|
+
// Also try without domain
|
|
355
|
+
document.cookie = `${name}=; Max-Age=0; path=/`;
|
|
356
|
+
}
|
|
357
|
+
// ---------------------------------------------------------------------------
|
|
358
|
+
// JSON helpers
|
|
359
|
+
// ---------------------------------------------------------------------------
|
|
360
|
+
/** Get JSON value with expiry check */
|
|
184
361
|
getWithExpiry(key) {
|
|
185
362
|
const raw = this.get(key);
|
|
186
|
-
if (!raw)
|
|
363
|
+
if (!raw)
|
|
187
364
|
return null;
|
|
188
|
-
}
|
|
189
365
|
try {
|
|
190
366
|
const item = JSON.parse(raw);
|
|
191
|
-
// Check expiry if set
|
|
192
367
|
if (item.expiry && Date.now() > item.expiry) {
|
|
193
368
|
this.remove(key);
|
|
194
369
|
return null;
|
|
@@ -196,14 +371,10 @@ class StorageManager {
|
|
|
196
371
|
return item.value;
|
|
197
372
|
}
|
|
198
373
|
catch (_a) {
|
|
199
|
-
// Not JSON or invalid format - return raw value if compatible
|
|
200
374
|
return null;
|
|
201
375
|
}
|
|
202
376
|
}
|
|
203
|
-
/**
|
|
204
|
-
* Set JSON value with optional expiry
|
|
205
|
-
* @param ttlMs - Time to live in milliseconds
|
|
206
|
-
*/
|
|
377
|
+
/** Set JSON value with optional TTL */
|
|
207
378
|
setWithExpiry(key, value, ttlMs) {
|
|
208
379
|
const item = {
|
|
209
380
|
value,
|
|
@@ -211,14 +382,11 @@ class StorageManager {
|
|
|
211
382
|
};
|
|
212
383
|
this.set(key, JSON.stringify(item));
|
|
213
384
|
}
|
|
214
|
-
/**
|
|
215
|
-
* Get JSON value (no expiry check)
|
|
216
|
-
*/
|
|
385
|
+
/** Get parsed JSON value */
|
|
217
386
|
getJSON(key) {
|
|
218
387
|
const raw = this.get(key);
|
|
219
|
-
if (!raw)
|
|
388
|
+
if (!raw)
|
|
220
389
|
return null;
|
|
221
|
-
}
|
|
222
390
|
try {
|
|
223
391
|
return JSON.parse(raw);
|
|
224
392
|
}
|
|
@@ -226,126 +394,45 @@ class StorageManager {
|
|
|
226
394
|
return null;
|
|
227
395
|
}
|
|
228
396
|
}
|
|
229
|
-
/**
|
|
230
|
-
* Set JSON value
|
|
231
|
-
*/
|
|
397
|
+
/** Set JSON value */
|
|
232
398
|
setJSON(key, value, maxAge) {
|
|
233
399
|
this.set(key, JSON.stringify(value), maxAge);
|
|
234
400
|
}
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
if (typeof document === "undefined") {
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
const cookies = document.cookie.split(";");
|
|
243
|
-
for (const cookie of cookies) {
|
|
244
|
-
const [key, ...valueParts] = cookie.trim().split("=");
|
|
245
|
-
if (key === name) {
|
|
246
|
-
const value = valueParts.join("="); // Handle values with = in them
|
|
247
|
-
try {
|
|
248
|
-
return decodeURIComponent(value);
|
|
249
|
-
}
|
|
250
|
-
catch (_a) {
|
|
251
|
-
return value;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
setCookie(name, value, maxAge) {
|
|
258
|
-
if (typeof document === "undefined") {
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
let cookieString = `${name}=${encodeURIComponent(value)}`;
|
|
262
|
-
cookieString += `; Max-Age=${maxAge}`;
|
|
263
|
-
cookieString += `; path=/`;
|
|
264
|
-
cookieString += `; SameSite=${this.sameSite}`;
|
|
265
|
-
if (this.secure) {
|
|
266
|
-
cookieString += `; Secure`;
|
|
267
|
-
}
|
|
268
|
-
// Auto-detect domain for cross-subdomain cookies
|
|
269
|
-
const domain = getCookieDomain(this.cross_subdomain);
|
|
270
|
-
if (domain) {
|
|
271
|
-
cookieString += `; domain=${domain}`;
|
|
272
|
-
}
|
|
273
|
-
document.cookie = cookieString;
|
|
274
|
-
}
|
|
275
|
-
removeCookie(name) {
|
|
276
|
-
if (typeof document === "undefined") {
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
// Auto-detect domain for cross-subdomain cookies
|
|
280
|
-
const domain = getCookieDomain(this.cross_subdomain);
|
|
281
|
-
// Set cookie with expired date
|
|
282
|
-
let cookieString = `${name}=; Max-Age=0; path=/`;
|
|
283
|
-
if (domain) {
|
|
284
|
-
cookieString += `; domain=${domain}`;
|
|
285
|
-
}
|
|
286
|
-
document.cookie = cookieString;
|
|
287
|
-
// Also try without domain (in case it was set without)
|
|
288
|
-
document.cookie = `${name}=; Max-Age=0; path=/`;
|
|
289
|
-
}
|
|
290
|
-
// ============================================================================
|
|
291
|
-
// Helper methods
|
|
292
|
-
// ============================================================================
|
|
293
|
-
usesLocalStorage() {
|
|
294
|
-
return (this.method === constants_1.PERSISTENCE_METHODS.localStorage ||
|
|
295
|
-
this.method === constants_1.PERSISTENCE_METHODS.localStoragePlusCookie);
|
|
296
|
-
}
|
|
297
|
-
usesSessionStorage() {
|
|
298
|
-
return this.method === constants_1.PERSISTENCE_METHODS.sessionStorage;
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Check if sessionStorage is available
|
|
302
|
-
*/
|
|
401
|
+
// ---------------------------------------------------------------------------
|
|
402
|
+
// Utility methods
|
|
403
|
+
// ---------------------------------------------------------------------------
|
|
404
|
+
/** Check if sessionStorage is available */
|
|
303
405
|
canUseSessionStorage() {
|
|
304
|
-
if (typeof globals_1.window === "undefined" || !(globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.sessionStorage))
|
|
406
|
+
if (typeof globals_1.window === "undefined" || !(globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.sessionStorage))
|
|
305
407
|
return false;
|
|
306
|
-
}
|
|
307
408
|
try {
|
|
308
|
-
const
|
|
309
|
-
globals_1.window.sessionStorage.setItem(
|
|
310
|
-
globals_1.window.sessionStorage.removeItem(
|
|
409
|
+
const k = "__vt_ss_test__";
|
|
410
|
+
globals_1.window.sessionStorage.setItem(k, "1");
|
|
411
|
+
globals_1.window.sessionStorage.removeItem(k);
|
|
311
412
|
return true;
|
|
312
413
|
}
|
|
313
414
|
catch (_a) {
|
|
314
415
|
return false;
|
|
315
416
|
}
|
|
316
417
|
}
|
|
317
|
-
/**
|
|
318
|
-
* Get direct access to sessionStorage (for window_id which always uses sessionStorage)
|
|
319
|
-
*/
|
|
418
|
+
/** Get sessionStorage instance (for window_id which always uses sessionStorage) */
|
|
320
419
|
getSessionStorage() {
|
|
321
420
|
var _a;
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return (_a = globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.sessionStorage) !== null && _a !== void 0 ? _a : null;
|
|
421
|
+
return this.canUseSessionStorage()
|
|
422
|
+
? ((_a = globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.sessionStorage) !== null && _a !== void 0 ? _a : null)
|
|
423
|
+
: null;
|
|
326
424
|
}
|
|
327
|
-
/**
|
|
328
|
-
* Update storage method at runtime
|
|
329
|
-
*/
|
|
425
|
+
/** Update storage method at runtime */
|
|
330
426
|
setMethod(method) {
|
|
331
427
|
this.method = method;
|
|
332
428
|
}
|
|
333
|
-
/**
|
|
334
|
-
* Get current storage method
|
|
335
|
-
*/
|
|
429
|
+
/** Get current storage method */
|
|
336
430
|
getMethod() {
|
|
337
431
|
return this.method;
|
|
338
432
|
}
|
|
339
433
|
}
|
|
340
434
|
exports.StorageManager = StorageManager;
|
|
341
|
-
/**
|
|
342
|
-
* Create a shared storage instance
|
|
343
|
-
* Use this for creating storage managers with consistent settings
|
|
344
|
-
*/
|
|
435
|
+
/** Factory function to create a StorageManager with default settings */
|
|
345
436
|
function createStorageManager(method, cross_subdomain) {
|
|
346
|
-
return new StorageManager({
|
|
347
|
-
method,
|
|
348
|
-
cross_subdomain,
|
|
349
|
-
sameSite: "Lax",
|
|
350
|
-
});
|
|
437
|
+
return new StorageManager({ method, cross_subdomain, sameSite: "Lax" });
|
|
351
438
|
}
|
package/lib/user-manager.d.ts
CHANGED
|
@@ -94,7 +94,21 @@ export declare class UserManager {
|
|
|
94
94
|
*/
|
|
95
95
|
update_referrer_info(): void;
|
|
96
96
|
/**
|
|
97
|
-
* Load user identity from storage
|
|
97
|
+
* Load user identity from storage.
|
|
98
|
+
*
|
|
99
|
+
* For traditional SSR websites where each page navigation reloads JavaScript,
|
|
100
|
+
* identity MUST be persisted immediately when generated to ensure the same
|
|
101
|
+
* anonymous_id is used across all page loads.
|
|
102
|
+
*
|
|
103
|
+
* Flow:
|
|
104
|
+
* 1. Load from storage (reads cookies first for critical properties in SSR mode)
|
|
105
|
+
* 2. Generate new IDs if not found
|
|
106
|
+
* 3. Immediately persist to storage (saved to both localStorage and cookies)
|
|
107
|
+
*
|
|
108
|
+
* With `localStorage+cookie` persistence (default):
|
|
109
|
+
* - Critical properties are stored in cookies for SSR compatibility
|
|
110
|
+
* - Full data is stored in localStorage for fast SPA-style access
|
|
111
|
+
* - Cookies ensure identity persists across full page reloads
|
|
98
112
|
*/
|
|
99
113
|
private loadUserIdentity;
|
|
100
114
|
/**
|