@amplitude/analytics-core 2.41.0 → 2.41.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.
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/messenger/constants.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,MAAM,CAAC,IAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAC5D,MAAM,CAAC,IAAM,mBAAmB,GAAG,8BAA8B,CAAC;AAClE,MAAM,CAAC,IAAM,wBAAwB,GAAG,kCAAkC,CAAC;AAC3E,MAAM,CAAC,IAAM,qBAAqB,GAA2B;IAC3D,EAAE,EAAE,gBAAgB;IACpB,EAAE,EAAE,mBAAmB;IACvB,OAAO,EAAE,wBAAwB;CAClC,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,IAAM,uCAAuC,GAClD,uEAAuE,CAAC","sourcesContent":["// Shared origin constants for Amplitude cross-window communication\nexport const AMPLITUDE_ORIGIN = 'https://app.amplitude.com';\nexport const AMPLITUDE_ORIGIN_EU = 'https://app.eu.amplitude.com';\nexport const AMPLITUDE_ORIGIN_STAGING = 'https://apps.stag2.amplitude.com';\nexport const AMPLITUDE_ORIGINS_MAP: Record<string, string> = {\n US: AMPLITUDE_ORIGIN,\n EU: AMPLITUDE_ORIGIN_EU,\n STAGING: AMPLITUDE_ORIGIN_STAGING,\n};\n\n// Background capture script URL (shared between autocapture and session-replay)\nexport const AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL =\n 'https://cdn.amplitude.com/libs/background-capture-1.0.0-alpha.1.js.gz';\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/messenger/constants.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,MAAM,CAAC,IAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAC5D,MAAM,CAAC,IAAM,mBAAmB,GAAG,8BAA8B,CAAC;AAClE,MAAM,CAAC,IAAM,wBAAwB,GAAG,kCAAkC,CAAC;AAC3E,MAAM,CAAC,IAAM,qBAAqB,GAA2B;IAC3D,EAAE,EAAE,gBAAgB;IACpB,EAAE,EAAE,mBAAmB;IACvB,OAAO,EAAE,wBAAwB;CAClC,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,IAAM,uCAAuC,GAClD,uEAAuE,CAAC","sourcesContent":["// Shared origin constants for Amplitude cross-window communication\nexport const AMPLITUDE_ORIGIN = 'https://app.amplitude.com';\nexport const AMPLITUDE_ORIGIN_EU = 'https://app.eu.amplitude.com';\nexport const AMPLITUDE_ORIGIN_STAGING = 'https://apps.stag2.amplitude.com';\nexport const AMPLITUDE_ORIGINS_MAP: Record<string, string> = {\n US: AMPLITUDE_ORIGIN,\n EU: AMPLITUDE_ORIGIN_EU,\n STAGING: AMPLITUDE_ORIGIN_STAGING,\n};\n\n// Background capture script URL (shared between autocapture and session-replay)\nexport const AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL =\n 'https://cdn.amplitude.com/libs/background-capture-1.0.0-alpha.2.js.gz';\n"]}
@@ -5,10 +5,16 @@ export declare class CookieStorage<T> implements Storage<T> {
5
5
  constructor(options?: CookieStorageOptions, config?: CookieStorageConfig);
6
6
  isEnabled(): Promise<boolean>;
7
7
  get(key: string): Promise<T | undefined>;
8
+ private decodeCookieValue;
9
+ private getSync;
8
10
  getRaw(key: string): Promise<string | undefined>;
11
+ private getRawSync;
9
12
  set(key: string, value: T | null): Promise<void>;
13
+ private setSync;
10
14
  remove(key: string): Promise<void>;
11
15
  reset(): Promise<void>;
16
+ static isDomainWritable(domain: string): Promise<boolean>;
17
+ private transaction;
12
18
  }
13
19
  /**
14
20
  * Decodes a cookie value that was encoded with btoa(encodeURIComponent(...)).
@@ -1 +1 @@
1
- {"version":3,"file":"cookie.d.ts","sourceRoot":"","sources":["../../../src/storage/cookie.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAsBtF,qBAAa,aAAa,CAAC,CAAC,CAAE,YAAW,OAAO,CAAC,CAAC,CAAC;IACjD,OAAO,EAAE,oBAAoB,CAAC;IAC9B,MAAM,EAAE,mBAAmB,CAAC;gBAEhB,OAAO,CAAC,EAAE,oBAAoB,EAAE,MAAM,GAAE,mBAAwB;IAKtE,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IA2C7B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAmBxC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IA6DhD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAkChD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAoBD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,UAAW,MAAM,KAAG,MAAM,GAAG,SAE1D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,YAAa,MAAM,GAAG,SAAS,WAAW,MAAM,GAAG,SAAS,KAAG,OAUxF,CAAC"}
1
+ {"version":3,"file":"cookie.d.ts","sourceRoot":"","sources":["../../../src/storage/cookie.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAe,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AA2BnG,qBAAa,aAAa,CAAC,CAAC,CAAE,YAAW,OAAO,CAAC,CAAC,CAAC;IACjD,OAAO,EAAE,oBAAoB,CAAC;IAC9B,MAAM,EAAE,mBAAmB,CAAC;gBAEhB,OAAO,CAAC,EAAE,oBAAoB,EAAE,MAAM,GAAE,mBAAwB;IAKtE,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAwC7B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAK9C,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,OAAO;IAKT,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAiCtD,OAAO,CAAC,UAAU;IAiCZ,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD,OAAO,CAAC,OAAO;IAkCT,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;WAIf,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAqBjD,WAAW;CAsB1B;AAoBD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,UAAW,MAAM,KAAG,MAAM,GAAG,SAE1D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,YAAa,MAAM,GAAG,SAAS,WAAW,MAAM,GAAG,SAAS,KAAG,OAUxF,CAAC"}
@@ -1,6 +1,11 @@
1
1
  import { __assign, __awaiter, __generator, __values } from "tslib";
2
2
  import { getGlobalScope } from '../global-scope';
3
- import { UUID } from '../utils/uuid';
3
+ /* istanbul ignore next */
4
+ var getLocks = function () {
5
+ var _a;
6
+ var globalScope = getGlobalScope();
7
+ return (_a = globalScope === null || globalScope === void 0 ? void 0 : globalScope.navigator) === null || _a === void 0 ? void 0 : _a.locks;
8
+ };
4
9
  var CookieStorage = /** @class */ (function () {
5
10
  function CookieStorage(options, config) {
6
11
  if (config === void 0) { config = {}; }
@@ -8,211 +13,221 @@ var CookieStorage = /** @class */ (function () {
8
13
  this.config = config;
9
14
  }
10
15
  CookieStorage.prototype.isEnabled = function () {
11
- var _a, _b;
12
16
  return __awaiter(this, void 0, void 0, function () {
13
- var globalScope, testValue, testCookieOptions, testStorage, testKey, value, e_1, errMessage;
14
- return __generator(this, function (_c) {
15
- switch (_c.label) {
17
+ var testKey, testCookieOptions, testStorage, testValue;
18
+ var _this = this;
19
+ return __generator(this, function (_a) {
20
+ switch (_a.label) {
16
21
  case 0:
17
- globalScope = getGlobalScope();
18
- /* istanbul ignore if */
19
- if (!globalScope || !globalScope.document) {
20
- return [2 /*return*/, false];
21
- }
22
- testValue = String(Date.now());
23
- testCookieOptions = __assign(__assign({}, this.options), { expirationDays: 0.003 });
22
+ testKey = 'AMP_TEST';
23
+ testCookieOptions = __assign({}, this.options);
24
24
  testStorage = new CookieStorage(testCookieOptions);
25
- testKey = "AMP_TEST_".concat(UUID().substring(0, 8));
26
- _c.label = 1;
27
- case 1:
28
- _c.trys.push([1, 4, 5, 7]);
29
- return [4 /*yield*/, testStorage.set(testKey, testValue)];
30
- case 2:
31
- _c.sent();
32
- return [4 /*yield*/, testStorage.get(testKey)];
33
- case 3:
34
- value = _c.sent();
35
- /* istanbul ignore next */
36
- if (value !== testValue && this.config.diagnosticsClient) {
37
- (_a = this.config.diagnosticsClient) === null || _a === void 0 ? void 0 : _a.recordEvent('cookies.isEnabled.failure', {
38
- reason: 'Test Value mismatch',
39
- testKey: testKey,
40
- testValue: testValue,
41
- });
42
- }
43
- return [2 /*return*/, value === testValue];
44
- case 4:
45
- e_1 = _c.sent();
46
- /* istanbul ignore next */
47
- if (this.config.diagnosticsClient) {
48
- errMessage = e_1 instanceof Error ? e_1.message : String(e_1);
49
- (_b = this.config.diagnosticsClient) === null || _b === void 0 ? void 0 : _b.recordEvent('cookies.isEnabled.failure', {
50
- reason: 'Cookie getter/setter failed',
51
- testKey: testKey,
52
- testValue: testValue,
53
- error: errMessage,
54
- });
55
- }
56
- return [2 /*return*/, false];
57
- case 5: return [4 /*yield*/, testStorage.remove(testKey)];
58
- case 6:
59
- _c.sent();
60
- return [7 /*endfinally*/];
61
- case 7: return [2 /*return*/];
25
+ testValue = String(Date.now());
26
+ return [4 /*yield*/, testStorage.transaction(testKey, function (storage) {
27
+ var _a, _b;
28
+ try {
29
+ storage.set(testValue);
30
+ var value = storage.get();
31
+ var result = value === testValue;
32
+ /* istanbul ignore next */
33
+ if (!result && _this.config.diagnosticsClient) {
34
+ (_a = _this.config.diagnosticsClient) === null || _a === void 0 ? void 0 : _a.recordEvent('cookies.isEnabled.failure', {
35
+ reason: 'Test Value mismatch',
36
+ testKey: testKey,
37
+ testValue: testValue,
38
+ sync: true,
39
+ });
40
+ }
41
+ return result;
42
+ }
43
+ catch (e) {
44
+ /* istanbul ignore next */
45
+ if (_this.config.diagnosticsClient) {
46
+ var errMessage = e instanceof Error ? e.message : String(e);
47
+ (_b = _this.config.diagnosticsClient) === null || _b === void 0 ? void 0 : _b.recordEvent('cookies.isEnabled.failure', {
48
+ reason: 'Cookie getter/setter failed',
49
+ testKey: testKey,
50
+ testValue: testValue,
51
+ error: errMessage,
52
+ sync: true,
53
+ });
54
+ }
55
+ return false;
56
+ }
57
+ finally {
58
+ // clean-up the AMP_TEST cookie behind us
59
+ storage.set(null);
60
+ }
61
+ })];
62
+ case 1: return [2 /*return*/, _a.sent()];
62
63
  }
63
64
  });
64
65
  });
65
66
  };
66
67
  CookieStorage.prototype.get = function (key) {
67
68
  return __awaiter(this, void 0, void 0, function () {
68
- var value, decodedValue;
69
+ var value;
69
70
  return __generator(this, function (_a) {
70
71
  switch (_a.label) {
71
72
  case 0: return [4 /*yield*/, this.getRaw(key)];
72
73
  case 1:
73
74
  value = _a.sent();
74
- if (!value) {
75
- return [2 /*return*/, undefined];
76
- }
77
- try {
78
- decodedValue = decodeCookieValue(value);
79
- if (decodedValue === undefined) {
80
- console.error("Amplitude Logger [Error]: Failed to decode cookie value for key: ".concat(key, ", value: ").concat(value));
81
- return [2 /*return*/, undefined];
82
- }
83
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
84
- return [2 /*return*/, JSON.parse(decodedValue)];
85
- }
86
- catch (_b) {
87
- console.error("Amplitude Logger [Error]: Failed to parse cookie value for key: ".concat(key, ", value: ").concat(value));
88
- return [2 /*return*/, undefined];
89
- }
90
- return [2 /*return*/];
75
+ return [2 /*return*/, this.decodeCookieValue(key, value)];
91
76
  }
92
77
  });
93
78
  });
94
79
  };
80
+ CookieStorage.prototype.decodeCookieValue = function (key, value) {
81
+ if (!value) {
82
+ return undefined;
83
+ }
84
+ try {
85
+ var decodedValue = decodeCookieValue(value);
86
+ if (decodedValue === undefined) {
87
+ console.error("Amplitude Logger [Error]: Failed to decode cookie value for key: ".concat(key, ", value: ").concat(value));
88
+ return undefined;
89
+ }
90
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
91
+ return JSON.parse(decodedValue);
92
+ }
93
+ catch (_a) {
94
+ console.error("Amplitude Logger [Error]: Failed to parse cookie value for key: ".concat(key, ", value: ").concat(value));
95
+ return undefined;
96
+ }
97
+ };
98
+ CookieStorage.prototype.getSync = function (key) {
99
+ var value = this.getRawSync(key);
100
+ return this.decodeCookieValue(key, value);
101
+ };
95
102
  CookieStorage.prototype.getRaw = function (key) {
96
- var _a, _b, _c, _d;
103
+ var _a, _b;
97
104
  return __awaiter(this, void 0, void 0, function () {
98
- var globalScope, globalScopeWithCookiesStore, cookieStore, cookies_2, cookies_1, cookies_1_1, cookie, ignoreError_1, cookies, match, duplicateResolverFn;
99
- var e_2, _e;
100
- var _this = this;
101
- return __generator(this, function (_f) {
102
- switch (_f.label) {
105
+ var globalScope, globalScopeWithCookiesStore, cookieStore, cookies, cookies_1, cookies_1_1, cookie, ignoreError_1;
106
+ var e_1, _c;
107
+ return __generator(this, function (_d) {
108
+ switch (_d.label) {
103
109
  case 0:
104
110
  globalScope = getGlobalScope();
105
111
  globalScopeWithCookiesStore = globalScope;
106
- _f.label = 1;
112
+ _d.label = 1;
107
113
  case 1:
108
- _f.trys.push([1, 4, , 5]);
114
+ _d.trys.push([1, 4, , 5]);
109
115
  cookieStore = globalScopeWithCookiesStore === null || globalScopeWithCookiesStore === void 0 ? void 0 : globalScopeWithCookiesStore.cookieStore;
110
116
  if (!cookieStore) return [3 /*break*/, 3];
111
117
  return [4 /*yield*/, cookieStore.getAll(key)];
112
118
  case 2:
113
- cookies_2 = _f.sent();
114
- if (cookies_2) {
119
+ cookies = _d.sent();
120
+ if (cookies) {
115
121
  /* istanbul ignore if */
116
- if (cookies_2.length > 1) {
122
+ if (cookies.length > 1) {
117
123
  (_a = this.config.diagnosticsClient) === null || _a === void 0 ? void 0 : _a.recordEvent('cookies.duplicate', {
118
- cookies: cookies_2.map(function (cookie) { return cookie.domain; }),
124
+ cookies: cookies.map(function (cookie) { return cookie.domain; }),
119
125
  });
120
126
  (_b = this.config.diagnosticsClient) === null || _b === void 0 ? void 0 : _b.increment('cookies.duplicate.occurrence.cookieStore');
121
127
  }
122
128
  try {
123
- for (cookies_1 = __values(cookies_2), cookies_1_1 = cookies_1.next(); !cookies_1_1.done; cookies_1_1 = cookies_1.next()) {
129
+ for (cookies_1 = __values(cookies), cookies_1_1 = cookies_1.next(); !cookies_1_1.done; cookies_1_1 = cookies_1.next()) {
124
130
  cookie = cookies_1_1.value;
125
131
  if (isDomainEqual(cookie.domain, this.options.domain)) {
126
132
  return [2 /*return*/, cookie.value];
127
133
  }
128
134
  }
129
135
  }
130
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
136
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
131
137
  finally {
132
138
  try {
133
- if (cookies_1_1 && !cookies_1_1.done && (_e = cookies_1.return)) _e.call(cookies_1);
139
+ if (cookies_1_1 && !cookies_1_1.done && (_c = cookies_1.return)) _c.call(cookies_1);
134
140
  }
135
- finally { if (e_2) throw e_2.error; }
141
+ finally { if (e_1) throw e_1.error; }
136
142
  }
137
143
  }
138
- _f.label = 3;
144
+ _d.label = 3;
139
145
  case 3: return [3 /*break*/, 5];
140
146
  case 4:
141
- ignoreError_1 = _f.sent();
147
+ ignoreError_1 = _d.sent();
142
148
  return [3 /*break*/, 5];
143
- case 5:
144
- cookies = ((_d = (_c = globalScope === null || globalScope === void 0 ? void 0 : globalScope.document) === null || _c === void 0 ? void 0 : _c.cookie.split('; ')) !== null && _d !== void 0 ? _d : []).filter(function (c) { return c.indexOf(key + '=') === 0; });
145
- match = undefined;
146
- duplicateResolverFn = this.config.duplicateResolverFn;
147
- if (typeof duplicateResolverFn === 'function' && cookies.length > 1) {
148
- match = cookies.find(function (c) {
149
- var _a;
150
- try {
151
- var res = duplicateResolverFn(c.substring(key.length + 1));
152
- if (!res) {
153
- (_a = _this.config.diagnosticsClient) === null || _a === void 0 ? void 0 : _a.increment('cookies.duplicate.occurrence.document.cookie');
154
- }
155
- return res;
156
- }
157
- catch (ignoreError) {
158
- /* istanbul ignore next */
159
- return false;
160
- }
161
- });
162
- }
163
- // if match was not found, just get the first one that matches the key
164
- if (!match) {
165
- match = cookies[0];
166
- }
167
- if (!match) {
168
- return [2 /*return*/, undefined];
169
- }
170
- return [2 /*return*/, match.substring(key.length + 1)];
149
+ case 5: return [2 /*return*/, this.getRawSync(key)];
171
150
  }
172
151
  });
173
152
  });
174
153
  };
175
- CookieStorage.prototype.set = function (key, value) {
176
- var _a;
177
- return __awaiter(this, void 0, void 0, function () {
178
- var expirationDays, expires, expireDate, date, str, globalScope, errorMessage;
179
- return __generator(this, function (_b) {
154
+ CookieStorage.prototype.getRawSync = function (key) {
155
+ var _this = this;
156
+ var _a, _b;
157
+ var globalScope = getGlobalScope();
158
+ var cookies = ((_b = (_a = globalScope === null || globalScope === void 0 ? void 0 : globalScope.document) === null || _a === void 0 ? void 0 : _a.cookie.split('; ')) !== null && _b !== void 0 ? _b : []).filter(function (c) { return c.indexOf(key + '=') === 0; });
159
+ var match = undefined;
160
+ // if matcher function is provided, use it to de-duplicate when there's more than one cookie
161
+ /* istanbul ignore if */
162
+ var duplicateResolverFn = this.config.duplicateResolverFn;
163
+ if (typeof duplicateResolverFn === 'function' && cookies.length > 1) {
164
+ match = cookies.find(function (c) {
165
+ var _a;
180
166
  try {
181
- expirationDays = (_a = this.options.expirationDays) !== null && _a !== void 0 ? _a : 0;
182
- expires = value !== null ? expirationDays : -1;
183
- expireDate = undefined;
184
- if (expires) {
185
- date = new Date();
186
- date.setTime(date.getTime() + expires * 24 * 60 * 60 * 1000);
187
- expireDate = date;
188
- }
189
- str = "".concat(key, "=").concat(btoa(encodeURIComponent(JSON.stringify(value))));
190
- if (expireDate) {
191
- str += "; expires=".concat(expireDate.toUTCString());
192
- }
193
- str += '; path=/';
194
- if (this.options.domain) {
195
- str += "; domain=".concat(this.options.domain);
196
- }
197
- if (this.options.secure) {
198
- str += '; Secure';
199
- }
200
- if (this.options.sameSite) {
201
- str += "; SameSite=".concat(this.options.sameSite);
202
- }
203
- globalScope = getGlobalScope();
204
- if (globalScope) {
205
- globalScope.document.cookie = str;
167
+ var res = duplicateResolverFn(c.substring(key.length + 1));
168
+ if (!res) {
169
+ (_a = _this.config.diagnosticsClient) === null || _a === void 0 ? void 0 : _a.increment('cookies.duplicate.occurrence.document.cookie');
206
170
  }
171
+ return res;
207
172
  }
208
- catch (error) {
209
- errorMessage = error instanceof Error ? error.message : String(error);
210
- console.error("Amplitude Logger [Error]: Failed to set cookie for key: ".concat(key, ". Error: ").concat(errorMessage));
173
+ catch (ignoreError) {
174
+ /* istanbul ignore next */
175
+ return false;
211
176
  }
177
+ });
178
+ }
179
+ // if match was not found, just get the first one that matches the key
180
+ if (!match) {
181
+ match = cookies[0];
182
+ }
183
+ if (!match) {
184
+ return undefined;
185
+ }
186
+ return match.substring(key.length + 1);
187
+ };
188
+ CookieStorage.prototype.set = function (key, value) {
189
+ return __awaiter(this, void 0, void 0, function () {
190
+ return __generator(this, function (_a) {
191
+ this.setSync(key, value);
212
192
  return [2 /*return*/];
213
193
  });
214
194
  });
215
195
  };
196
+ CookieStorage.prototype.setSync = function (key, value) {
197
+ var _a;
198
+ try {
199
+ var expirationDays = (_a = this.options.expirationDays) !== null && _a !== void 0 ? _a : 0;
200
+ var expires = value !== null ? expirationDays : -1;
201
+ var expireDate = undefined;
202
+ if (expires) {
203
+ var date = new Date();
204
+ date.setTime(date.getTime() + expires * 24 * 60 * 60 * 1000);
205
+ expireDate = date;
206
+ }
207
+ var str = "".concat(key, "=").concat(btoa(encodeURIComponent(JSON.stringify(value))));
208
+ if (expireDate) {
209
+ str += "; expires=".concat(expireDate.toUTCString());
210
+ }
211
+ str += '; path=/';
212
+ if (this.options.domain) {
213
+ str += "; domain=".concat(this.options.domain);
214
+ }
215
+ if (this.options.secure) {
216
+ str += '; Secure';
217
+ }
218
+ if (this.options.sameSite) {
219
+ str += "; SameSite=".concat(this.options.sameSite);
220
+ }
221
+ var globalScope = getGlobalScope();
222
+ if (globalScope) {
223
+ globalScope.document.cookie = str;
224
+ }
225
+ }
226
+ catch (error) {
227
+ var errorMessage = error instanceof Error ? error.message : String(error);
228
+ console.error("Amplitude Logger [Error]: Failed to set cookie for key: ".concat(key, ". Error: ").concat(errorMessage));
229
+ }
230
+ };
216
231
  CookieStorage.prototype.remove = function (key) {
217
232
  return __awaiter(this, void 0, void 0, function () {
218
233
  return __generator(this, function (_a) {
@@ -232,6 +247,68 @@ var CookieStorage = /** @class */ (function () {
232
247
  });
233
248
  });
234
249
  };
250
+ CookieStorage.isDomainWritable = function (domain) {
251
+ return __awaiter(this, void 0, void 0, function () {
252
+ var options, storageKey, storage, res, error_1;
253
+ return __generator(this, function (_a) {
254
+ switch (_a.label) {
255
+ case 0:
256
+ options = {
257
+ domain: '.' + domain,
258
+ };
259
+ storageKey = 'AMP_TLDTEST';
260
+ storage = new CookieStorage(options);
261
+ _a.label = 1;
262
+ case 1:
263
+ _a.trys.push([1, 3, , 4]);
264
+ return [4 /*yield*/, storage.transaction(storageKey, function (storageSync) {
265
+ try {
266
+ storageSync.set(1);
267
+ return storageSync.get();
268
+ }
269
+ finally {
270
+ storageSync.set(null);
271
+ }
272
+ })];
273
+ case 2:
274
+ res = _a.sent();
275
+ return [2 /*return*/, !!res];
276
+ case 3:
277
+ error_1 = _a.sent();
278
+ return [2 /*return*/, false];
279
+ case 4: return [2 /*return*/];
280
+ }
281
+ });
282
+ });
283
+ };
284
+ CookieStorage.prototype.transaction = function (key, callback) {
285
+ return __awaiter(this, void 0, void 0, function () {
286
+ var locks, callbackWrapper;
287
+ var _this = this;
288
+ return __generator(this, function (_a) {
289
+ switch (_a.label) {
290
+ case 0:
291
+ locks = getLocks();
292
+ callbackWrapper = function () {
293
+ // construct a sync storage object that is scoped to
294
+ // Cookie with name <key>
295
+ var storageSync = {
296
+ get: function () { return _this.getSync(key); },
297
+ set: function (value) { return _this.setSync(key, value); },
298
+ };
299
+ return callback(storageSync);
300
+ };
301
+ // if 'locks' is missing, it is a legacy browser, just call the callback directly
302
+ // and settle for a transaction that isn't isolated across tabs
303
+ if (!locks) {
304
+ return [2 /*return*/, callbackWrapper()];
305
+ }
306
+ return [4 /*yield*/, locks.request("com.amplitude:cookie-lock:".concat(key), callbackWrapper)];
307
+ case 1: return [2 /*return*/, (_a.sent())];
308
+ }
309
+ });
310
+ });
311
+ };
235
312
  return CookieStorage;
236
313
  }());
237
314
  export { CookieStorage };
@@ -1 +1 @@
1
- {"version":3,"file":"cookie.js","sourceRoot":"","sources":["../../../src/storage/cookie.ts"],"names":[],"mappings":"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","sourcesContent":["import { Storage, CookieStorageOptions, CookieStorageConfig } from '../types/storage';\nimport { getGlobalScope } from '../global-scope';\nimport { UUID } from '../utils/uuid';\n\n// CookieStore is a Web API not included in standard TypeScript lib types\n// https://developer.mozilla.org/en-US/docs/Web/API/CookieStore\ninterface CookieStoreSetOptions {\n name: string;\n value: string;\n expires?: number;\n domain?: string;\n sameSite?: 'strict' | 'lax' | 'none';\n}\n\ninterface CookieStore {\n getAll(key: string): Promise<CookieStoreSetOptions[] | undefined>;\n}\n\ntype GlobalScopeWithCookieStore = {\n cookieStore?: CookieStore;\n} & typeof global;\n\nexport class CookieStorage<T> implements Storage<T> {\n options: CookieStorageOptions;\n config: CookieStorageConfig;\n\n constructor(options?: CookieStorageOptions, config: CookieStorageConfig = {}) {\n this.options = { ...options };\n this.config = config;\n }\n\n async isEnabled(): Promise<boolean> {\n const globalScope = getGlobalScope();\n /* istanbul ignore if */\n if (!globalScope || !globalScope.document) {\n return false;\n }\n\n const testValue = String(Date.now());\n const testCookieOptions = {\n ...this.options,\n expirationDays: 0.003, // expire in ~5 minutes\n };\n const testStorage = new CookieStorage<string>(testCookieOptions);\n const testKey = `AMP_TEST_${UUID().substring(0, 8)}`;\n try {\n await testStorage.set(testKey, testValue);\n const value = await testStorage.get(testKey);\n /* istanbul ignore next */\n if (value !== testValue && this.config.diagnosticsClient) {\n this.config.diagnosticsClient?.recordEvent('cookies.isEnabled.failure', {\n reason: 'Test Value mismatch',\n testKey,\n testValue,\n });\n }\n return value === testValue;\n } catch (e) {\n /* istanbul ignore next */\n if (this.config.diagnosticsClient) {\n const errMessage = e instanceof Error ? e.message : String(e);\n this.config.diagnosticsClient?.recordEvent('cookies.isEnabled.failure', {\n reason: 'Cookie getter/setter failed',\n testKey,\n testValue,\n error: errMessage,\n });\n }\n return false;\n } finally {\n await testStorage.remove(testKey);\n }\n }\n\n async get(key: string): Promise<T | undefined> {\n const value = await this.getRaw(key);\n if (!value) {\n return undefined;\n }\n try {\n const decodedValue = decodeCookieValue(value);\n if (decodedValue === undefined) {\n console.error(`Amplitude Logger [Error]: Failed to decode cookie value for key: ${key}, value: ${value}`);\n return undefined;\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return JSON.parse(decodedValue);\n } catch {\n console.error(`Amplitude Logger [Error]: Failed to parse cookie value for key: ${key}, value: ${value}`);\n return undefined;\n }\n }\n\n async getRaw(key: string): Promise<string | undefined> {\n const globalScope = getGlobalScope();\n\n // use CookieStore if available and enabled\n const globalScopeWithCookiesStore = globalScope as GlobalScopeWithCookieStore;\n try {\n const cookieStore = globalScopeWithCookiesStore?.cookieStore;\n if (cookieStore) {\n const cookies = await cookieStore.getAll(key);\n if (cookies) {\n /* istanbul ignore if */\n if (cookies.length > 1) {\n this.config.diagnosticsClient?.recordEvent('cookies.duplicate', {\n cookies: cookies.map((cookie) => cookie.domain),\n });\n this.config.diagnosticsClient?.increment('cookies.duplicate.occurrence.cookieStore');\n }\n\n for (const cookie of cookies) {\n if (isDomainEqual(cookie.domain, this.options.domain)) {\n return cookie.value;\n }\n }\n }\n }\n } catch (ignoreError) {\n /* istanbul ignore next */\n // if cookieStore had a surprise failure, fallback to document.cookie\n }\n\n const cookies = (globalScope?.document?.cookie.split('; ') ?? []).filter((c) => c.indexOf(key + '=') === 0);\n let match: string | undefined = undefined;\n\n // if matcher function is provided, use it to de-duplicate when there's more than one cookie\n /* istanbul ignore if */\n const duplicateResolverFn = this.config.duplicateResolverFn;\n if (typeof duplicateResolverFn === 'function' && cookies.length > 1) {\n match = cookies.find((c) => {\n try {\n const res = duplicateResolverFn(c.substring(key.length + 1));\n if (!res) {\n this.config.diagnosticsClient?.increment('cookies.duplicate.occurrence.document.cookie');\n }\n return res;\n } catch (ignoreError) {\n /* istanbul ignore next */\n return false;\n }\n });\n }\n\n // if match was not found, just get the first one that matches the key\n if (!match) {\n match = cookies[0];\n }\n if (!match) {\n return undefined;\n }\n return match.substring(key.length + 1);\n }\n\n async set(key: string, value: T | null): Promise<void> {\n try {\n const expirationDays = this.options.expirationDays ?? 0;\n const expires = value !== null ? expirationDays : -1;\n let expireDate: Date | undefined = undefined;\n if (expires) {\n const date = new Date();\n date.setTime(date.getTime() + expires * 24 * 60 * 60 * 1000);\n expireDate = date;\n }\n let str = `${key}=${btoa(encodeURIComponent(JSON.stringify(value)))}`;\n if (expireDate) {\n str += `; expires=${expireDate.toUTCString()}`;\n }\n str += '; path=/';\n if (this.options.domain) {\n str += `; domain=${this.options.domain}`;\n }\n if (this.options.secure) {\n str += '; Secure';\n }\n if (this.options.sameSite) {\n str += `; SameSite=${this.options.sameSite}`;\n }\n const globalScope = getGlobalScope();\n if (globalScope) {\n globalScope.document.cookie = str;\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(`Amplitude Logger [Error]: Failed to set cookie for key: ${key}. Error: ${errorMessage}`);\n }\n }\n\n async remove(key: string): Promise<void> {\n await this.set(key, null);\n }\n\n async reset(): Promise<void> {\n return;\n }\n}\n\nconst decodeCookiesAsDefault = (value: string): string | undefined => {\n try {\n return decodeURIComponent(atob(value));\n } catch {\n return undefined;\n }\n};\n\nconst decodeCookiesWithDoubleUrlEncoding = (value: string): string | undefined => {\n // Modern Ruby (v7+) automatically encodes cookies with URL encoding by\n // https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html\n try {\n return decodeURIComponent(atob(decodeURIComponent(value)));\n } catch {\n return undefined;\n }\n};\n\n/**\n * Decodes a cookie value that was encoded with btoa(encodeURIComponent(...)).\n * Handles both standard encoding and double URL encoding (used by Ruby Rails v7+).\n */\nexport const decodeCookieValue = (value: string): string | undefined => {\n return decodeCookiesAsDefault(value) ?? decodeCookiesWithDoubleUrlEncoding(value);\n};\n\n/**\n * Compares two domain strings for equality, ignoring leading dots.\n * This is useful for comparing cookie domains since \".example.com\" and \"example.com\"\n * are effectively equivalent for cookie scoping.\n */\nexport const isDomainEqual = (domain1: string | undefined, domain2: string | undefined): boolean => {\n if (domain1 === '' && domain2 === '') {\n return true;\n }\n if (!domain1 || !domain2) {\n return false;\n }\n const normalized1 = domain1.startsWith('.') ? domain1.substring(1) : domain1;\n const normalized2 = domain2.startsWith('.') ? domain2.substring(1) : domain2;\n return normalized1.toLowerCase() === normalized2.toLowerCase();\n};\n"]}
1
+ {"version":3,"file":"cookie.js","sourceRoot":"","sources":["../../../src/storage/cookie.ts"],"names":[],"mappings":"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","sourcesContent":["import { Storage, StorageSync, CookieStorageOptions, CookieStorageConfig } from '../types/storage';\nimport { getGlobalScope } from '../global-scope';\n\n// CookieStore is a Web API not included in standard TypeScript lib types\n// https://developer.mozilla.org/en-US/docs/Web/API/CookieStore\ninterface CookieStoreSetOptions {\n name: string;\n value: string;\n expires?: number;\n domain?: string;\n sameSite?: 'strict' | 'lax' | 'none';\n}\n\ninterface CookieStore {\n getAll(key: string): Promise<CookieStoreSetOptions[] | undefined>;\n}\n\ntype GlobalScopeWithCookieStore = {\n cookieStore?: CookieStore;\n} & typeof global;\n\n/* istanbul ignore next */\nconst getLocks = (): typeof global.navigator.locks | undefined => {\n const globalScope = getGlobalScope();\n return globalScope?.navigator?.locks;\n};\n\nexport class CookieStorage<T> implements Storage<T> {\n options: CookieStorageOptions;\n config: CookieStorageConfig;\n\n constructor(options?: CookieStorageOptions, config: CookieStorageConfig = {}) {\n this.options = { ...options };\n this.config = config;\n }\n\n async isEnabled(): Promise<boolean> {\n const testKey = 'AMP_TEST';\n const testCookieOptions = { ...this.options };\n const testStorage = new CookieStorage<string>(testCookieOptions);\n const testValue = String(Date.now());\n return await testStorage.transaction<boolean>(testKey, (storage: StorageSync<string>) => {\n try {\n storage.set(testValue);\n const value = storage.get();\n const result = value === testValue;\n /* istanbul ignore next */\n if (!result && this.config.diagnosticsClient) {\n this.config.diagnosticsClient?.recordEvent('cookies.isEnabled.failure', {\n reason: 'Test Value mismatch',\n testKey,\n testValue,\n sync: true,\n });\n }\n return result;\n } catch (e) {\n /* istanbul ignore next */\n if (this.config.diagnosticsClient) {\n const errMessage = e instanceof Error ? e.message : String(e);\n this.config.diagnosticsClient?.recordEvent('cookies.isEnabled.failure', {\n reason: 'Cookie getter/setter failed',\n testKey,\n testValue,\n error: errMessage,\n sync: true,\n });\n }\n return false;\n } finally {\n // clean-up the AMP_TEST cookie behind us\n storage.set(null);\n }\n });\n }\n\n async get(key: string): Promise<T | undefined> {\n const value = await this.getRaw(key);\n return this.decodeCookieValue(key, value);\n }\n\n private decodeCookieValue(key: string, value: string | undefined): T | undefined {\n if (!value) {\n return undefined;\n }\n try {\n const decodedValue = decodeCookieValue(value);\n if (decodedValue === undefined) {\n console.error(`Amplitude Logger [Error]: Failed to decode cookie value for key: ${key}, value: ${value}`);\n return undefined;\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return JSON.parse(decodedValue);\n } catch {\n console.error(`Amplitude Logger [Error]: Failed to parse cookie value for key: ${key}, value: ${value}`);\n return undefined;\n }\n }\n\n private getSync(key: string): T | undefined {\n const value = this.getRawSync(key);\n return this.decodeCookieValue(key, value);\n }\n\n async getRaw(key: string): Promise<string | undefined> {\n const globalScope = getGlobalScope();\n\n // use CookieStore if available and enabled\n const globalScopeWithCookiesStore = globalScope as GlobalScopeWithCookieStore;\n try {\n const cookieStore = globalScopeWithCookiesStore?.cookieStore;\n if (cookieStore) {\n const cookies = await cookieStore.getAll(key);\n if (cookies) {\n /* istanbul ignore if */\n if (cookies.length > 1) {\n this.config.diagnosticsClient?.recordEvent('cookies.duplicate', {\n cookies: cookies.map((cookie) => cookie.domain),\n });\n this.config.diagnosticsClient?.increment('cookies.duplicate.occurrence.cookieStore');\n }\n\n for (const cookie of cookies) {\n if (isDomainEqual(cookie.domain, this.options.domain)) {\n return cookie.value;\n }\n }\n }\n }\n } catch (ignoreError) {\n /* istanbul ignore next */\n // if cookieStore had a surprise failure, fallback to document.cookie\n }\n\n return this.getRawSync(key);\n }\n\n private getRawSync(key: string): string | undefined {\n const globalScope = getGlobalScope();\n const cookies = (globalScope?.document?.cookie.split('; ') ?? []).filter((c) => c.indexOf(key + '=') === 0);\n let match: string | undefined = undefined;\n\n // if matcher function is provided, use it to de-duplicate when there's more than one cookie\n /* istanbul ignore if */\n const duplicateResolverFn = this.config.duplicateResolverFn;\n if (typeof duplicateResolverFn === 'function' && cookies.length > 1) {\n match = cookies.find((c) => {\n try {\n const res = duplicateResolverFn(c.substring(key.length + 1));\n if (!res) {\n this.config.diagnosticsClient?.increment('cookies.duplicate.occurrence.document.cookie');\n }\n return res;\n } catch (ignoreError) {\n /* istanbul ignore next */\n return false;\n }\n });\n }\n\n // if match was not found, just get the first one that matches the key\n if (!match) {\n match = cookies[0];\n }\n if (!match) {\n return undefined;\n }\n return match.substring(key.length + 1);\n }\n\n async set(key: string, value: T | null): Promise<void> {\n this.setSync(key, value);\n }\n\n private setSync(key: string, value: T | null): void {\n try {\n const expirationDays = this.options.expirationDays ?? 0;\n const expires = value !== null ? expirationDays : -1;\n let expireDate: Date | undefined = undefined;\n if (expires) {\n const date = new Date();\n date.setTime(date.getTime() + expires * 24 * 60 * 60 * 1000);\n expireDate = date;\n }\n let str = `${key}=${btoa(encodeURIComponent(JSON.stringify(value)))}`;\n if (expireDate) {\n str += `; expires=${expireDate.toUTCString()}`;\n }\n str += '; path=/';\n if (this.options.domain) {\n str += `; domain=${this.options.domain}`;\n }\n if (this.options.secure) {\n str += '; Secure';\n }\n if (this.options.sameSite) {\n str += `; SameSite=${this.options.sameSite}`;\n }\n const globalScope = getGlobalScope();\n if (globalScope) {\n globalScope.document.cookie = str;\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(`Amplitude Logger [Error]: Failed to set cookie for key: ${key}. Error: ${errorMessage}`);\n }\n }\n\n async remove(key: string): Promise<void> {\n await this.set(key, null);\n }\n\n async reset(): Promise<void> {\n return;\n }\n\n static async isDomainWritable(domain: string): Promise<boolean> {\n const options = {\n domain: '.' + domain,\n };\n const storageKey = 'AMP_TLDTEST';\n const storage = new CookieStorage<number>(options);\n try {\n const res = await storage.transaction(storageKey, (storageSync) => {\n try {\n storageSync.set(1);\n return storageSync.get();\n } finally {\n storageSync.set(null);\n }\n });\n return !!res;\n } catch (error) {\n return false;\n }\n }\n\n private async transaction<ReturnType>(\n key: string,\n callback: (storageSync: StorageSync<T>) => ReturnType,\n ): Promise<ReturnType> {\n const locks = getLocks();\n const callbackWrapper = () => {\n // construct a sync storage object that is scoped to\n // Cookie with name <key>\n const storageSync: StorageSync<T> = {\n get: () => this.getSync(key),\n set: (value: T | null) => this.setSync(key, value),\n };\n return callback(storageSync);\n };\n\n // if 'locks' is missing, it is a legacy browser, just call the callback directly\n // and settle for a transaction that isn't isolated across tabs\n if (!locks) {\n return callbackWrapper();\n }\n return (await locks.request(`com.amplitude:cookie-lock:${key}`, callbackWrapper)) as ReturnType;\n }\n}\n\nconst decodeCookiesAsDefault = (value: string): string | undefined => {\n try {\n return decodeURIComponent(atob(value));\n } catch {\n return undefined;\n }\n};\n\nconst decodeCookiesWithDoubleUrlEncoding = (value: string): string | undefined => {\n // Modern Ruby (v7+) automatically encodes cookies with URL encoding by\n // https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html\n try {\n return decodeURIComponent(atob(decodeURIComponent(value)));\n } catch {\n return undefined;\n }\n};\n\n/**\n * Decodes a cookie value that was encoded with btoa(encodeURIComponent(...)).\n * Handles both standard encoding and double URL encoding (used by Ruby Rails v7+).\n */\nexport const decodeCookieValue = (value: string): string | undefined => {\n return decodeCookiesAsDefault(value) ?? decodeCookiesWithDoubleUrlEncoding(value);\n};\n\n/**\n * Compares two domain strings for equality, ignoring leading dots.\n * This is useful for comparing cookie domains since \".example.com\" and \"example.com\"\n * are effectively equivalent for cookie scoping.\n */\nexport const isDomainEqual = (domain1: string | undefined, domain2: string | undefined): boolean => {\n if (domain1 === '' && domain2 === '') {\n return true;\n }\n if (!domain1 || !domain2) {\n return false;\n }\n const normalized1 = domain1.startsWith('.') ? domain1.substring(1) : domain1;\n const normalized2 = domain2.startsWith('.') ? domain2.substring(1) : domain2;\n return normalized1.toLowerCase() === normalized2.toLowerCase();\n};\n"]}
@@ -7,6 +7,10 @@ export interface Storage<T> {
7
7
  remove(key: string): Promise<void>;
8
8
  reset(): Promise<void>;
9
9
  }
10
+ export interface StorageSync<T> {
11
+ get: () => T | undefined;
12
+ set: (value: T | null) => void;
13
+ }
10
14
  export interface CookieStorageOptions {
11
15
  domain?: string;
12
16
  expirationDays?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/types/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,iBAAiB,CAAC,EAAE,kBAAkB,CAAC;CACxC;AAED,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,cAAc,GAAG,gBAAgB,GAAG,MAAM,CAAC"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/types/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACzB,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,iBAAiB,CAAC,EAAE,kBAAkB,CAAC;CACxC;AAED,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,cAAc,GAAG,gBAAgB,GAAG,MAAM,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/types/storage.ts"],"names":[],"mappings":"","sourcesContent":["import { IDiagnosticsClient } from '../diagnostics/diagnostics-client';\n\nexport interface Storage<T> {\n isEnabled(): Promise<boolean>;\n get(key: string): Promise<T | undefined>;\n getRaw(key: string): Promise<string | undefined>;\n set(key: string, value: T): Promise<void>;\n remove(key: string): Promise<void>;\n reset(): Promise<void>;\n}\n\nexport interface CookieStorageOptions {\n domain?: string;\n expirationDays?: number;\n sameSite?: string;\n secure?: boolean;\n}\n\n/**\n * Configuration for CookieStorage behavior.\n * Separated from options to keep storage-specific config distinct from cookie attributes.\n */\nexport interface CookieStorageConfig {\n /**\n * Function to resolve duplicate cookies when multiple cookies with the same key exist.\n * Returns true if the cookie value should be used, false otherwise.\n */\n duplicateResolverFn?: (value: string) => boolean;\n diagnosticsClient?: IDiagnosticsClient;\n}\n\nexport type IdentityStorageType = 'cookie' | 'localStorage' | 'sessionStorage' | 'none';\n"]}
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/types/storage.ts"],"names":[],"mappings":"","sourcesContent":["import { IDiagnosticsClient } from '../diagnostics/diagnostics-client';\n\nexport interface Storage<T> {\n isEnabled(): Promise<boolean>;\n get(key: string): Promise<T | undefined>;\n getRaw(key: string): Promise<string | undefined>;\n set(key: string, value: T): Promise<void>;\n remove(key: string): Promise<void>;\n reset(): Promise<void>;\n}\n\nexport interface StorageSync<T> {\n get: () => T | undefined;\n set: (value: T | null) => void;\n}\n\nexport interface CookieStorageOptions {\n domain?: string;\n expirationDays?: number;\n sameSite?: string;\n secure?: boolean;\n}\n\n/**\n * Configuration for CookieStorage behavior.\n * Separated from options to keep storage-specific config distinct from cookie attributes.\n */\nexport interface CookieStorageConfig {\n /**\n * Function to resolve duplicate cookies when multiple cookies with the same key exist.\n * Returns true if the cookie value should be used, false otherwise.\n */\n duplicateResolverFn?: (value: string) => boolean;\n diagnosticsClient?: IDiagnosticsClient;\n}\n\nexport type IdentityStorageType = 'cookie' | 'localStorage' | 'sessionStorage' | 'none';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amplitude/analytics-core",
3
- "version": "2.41.0",
3
+ "version": "2.41.2",
4
4
  "description": "",
5
5
  "author": "Amplitude Inc",
6
6
  "homepage": "https://github.com/amplitude/Amplitude-TypeScript",