@amplitude/analytics-core 2.41.2 → 2.41.4-SR-2728.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 (31) hide show
  1. package/lib/cjs/remote-config/remote-config.d.ts +6 -0
  2. package/lib/cjs/remote-config/remote-config.d.ts.map +1 -1
  3. package/lib/cjs/remote-config/remote-config.js +36 -1
  4. package/lib/cjs/remote-config/remote-config.js.map +1 -1
  5. package/lib/cjs/storage/cookie.d.ts +1 -0
  6. package/lib/cjs/storage/cookie.d.ts.map +1 -1
  7. package/lib/cjs/storage/cookie.js +12 -1
  8. package/lib/cjs/storage/cookie.js.map +1 -1
  9. package/lib/cjs/utils/observable.d.ts +2 -2
  10. package/lib/cjs/utils/observable.d.ts.map +1 -1
  11. package/lib/cjs/utils/observable.js +5 -6
  12. package/lib/cjs/utils/observable.js.map +1 -1
  13. package/lib/cjs/utils/safe-stringify.d.ts.map +1 -1
  14. package/lib/cjs/utils/safe-stringify.js +3 -1
  15. package/lib/cjs/utils/safe-stringify.js.map +1 -1
  16. package/lib/esm/remote-config/remote-config.d.ts +6 -0
  17. package/lib/esm/remote-config/remote-config.d.ts.map +1 -1
  18. package/lib/esm/remote-config/remote-config.js +36 -1
  19. package/lib/esm/remote-config/remote-config.js.map +1 -1
  20. package/lib/esm/storage/cookie.d.ts +1 -0
  21. package/lib/esm/storage/cookie.d.ts.map +1 -1
  22. package/lib/esm/storage/cookie.js +12 -1
  23. package/lib/esm/storage/cookie.js.map +1 -1
  24. package/lib/esm/utils/observable.d.ts +2 -2
  25. package/lib/esm/utils/observable.d.ts.map +1 -1
  26. package/lib/esm/utils/observable.js +2 -2
  27. package/lib/esm/utils/observable.js.map +1 -1
  28. package/lib/esm/utils/safe-stringify.d.ts.map +1 -1
  29. package/lib/esm/utils/safe-stringify.js +1 -0
  30. package/lib/esm/utils/safe-stringify.js.map +1 -1
  31. package/package.json +3 -2
@@ -91,6 +91,7 @@ export declare class RemoteConfigClient implements IRemoteConfigClient {
91
91
  callbackInfos: CallbackInfo[];
92
92
  lastSuccessfulFetch: number | null;
93
93
  fetchPromise: Promise<RemoteConfigInfo> | null;
94
+ isLastFetchInvalidApiKey: boolean;
94
95
  constructor(apiKey: string, logger: ILogger, serverZone?: ServerZoneType, serverUrl?: string);
95
96
  subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string;
96
97
  unsubscribe(id: string): boolean;
@@ -125,6 +126,11 @@ export declare class RemoteConfigClient implements IRemoteConfigClient {
125
126
  * and the attempt is considered failed (and may be retried if retries remain).
126
127
  * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,
127
128
  * so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).
129
+ * Retry behavior by status code:
130
+ * - 401: invalid API key (stop retries and disable future updateConfigs calls).
131
+ * - 429: retry up to max retries.
132
+ * - other 4xx: no retry.
133
+ * - 5xx and network failures: retry up to max retries.
128
134
  * @returns the remote config info. null if failed to fetch or the response is not valid JSON.
129
135
  */
130
136
  fetch(retries?: number, timeout?: number): Promise<RemoteConfigInfo>;
@@ -1 +1 @@
1
- {"version":3,"file":"remote-config.d.ts","sourceRoot":"","sources":["../../../src/remote-config/remote-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remote-config.d.ts","sourceRoot":"","sources":["../../../src/remote-config/remote-config.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,10 @@ var uuid_1 = require("../utils/uuid");
7
7
  exports.US_SERVER_URL = 'https://sr-client-cfg.amplitude.com/config';
8
8
  exports.EU_SERVER_URL = 'https://sr-client-cfg.eu.amplitude.com/config';
9
9
  exports.DEFAULT_MAX_RETRIES = 3;
10
+ var CODE_STATUS = {
11
+ INVALID_API_KEY: 401,
12
+ RATE_LIMIT: 429,
13
+ };
10
14
  /**
11
15
  * The default timeout for fetch in milliseconds.
12
16
  * Linear backoff policy: timeout / retry times is the interval between fetch retry.
@@ -26,6 +30,8 @@ var RemoteConfigClient = /** @class */ (function () {
26
30
  this.lastSuccessfulFetch = null;
27
31
  // Store the in-flight fetch promise for deduplication.
28
32
  this.fetchPromise = null;
33
+ // Used to skip periodic updateConfigs calls when API key is invalid.
34
+ this.isLastFetchInvalidApiKey = false;
29
35
  this.apiKey = apiKey;
30
36
  this.serverUrl = serverUrl || (serverZone === 'US' ? exports.US_SERVER_URL : exports.EU_SERVER_URL);
31
37
  this.logger = logger;
@@ -94,6 +100,16 @@ var RemoteConfigClient = /** @class */ (function () {
94
100
  if (this.fetchPromise) {
95
101
  return this.fetchPromise;
96
102
  }
103
+ if (this.isLastFetchInvalidApiKey) {
104
+ this.logger.debug('Remote config client skipping fetch: Invalid API key');
105
+ this.fetchPromise = Promise.resolve({
106
+ remoteConfig: null,
107
+ lastFetch: new Date(),
108
+ }).finally(function () {
109
+ _this.fetchPromise = null;
110
+ });
111
+ return this.fetchPromise;
112
+ }
97
113
  this.fetchPromise = this.fetch()
98
114
  .then(function (result) {
99
115
  // Update last successful fetch time if we got a valid config
@@ -231,6 +247,11 @@ var RemoteConfigClient = /** @class */ (function () {
231
247
  * and the attempt is considered failed (and may be retried if retries remain).
232
248
  * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,
233
249
  * so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).
250
+ * Retry behavior by status code:
251
+ * - 401: invalid API key (stop retries and disable future updateConfigs calls).
252
+ * - 429: retry up to max retries.
253
+ * - other 4xx: no retry.
254
+ * - 5xx and network failures: retry up to max retries.
234
255
  * @returns the remote config info. null if failed to fetch or the response is not valid JSON.
235
256
  */
236
257
  RemoteConfigClient.prototype.fetch = function (retries, timeout) {
@@ -248,10 +269,11 @@ var RemoteConfigClient = /** @class */ (function () {
248
269
  lastFetch: new Date(),
249
270
  };
250
271
  _loop_1 = function (attempt) {
251
- var abortController, timeoutId, res, body, remoteConfig, error_2;
272
+ var shouldRetry, abortController, timeoutId, res, body, remoteConfig, error_2;
252
273
  return tslib_1.__generator(this, function (_b) {
253
274
  switch (_b.label) {
254
275
  case 0:
276
+ shouldRetry = true;
255
277
  abortController = new AbortController();
256
278
  timeoutId = setTimeout(function () { return abortController.abort(); }, timeout);
257
279
  _b.label = 1;
@@ -271,6 +293,14 @@ var RemoteConfigClient = /** @class */ (function () {
271
293
  case 3:
272
294
  body = _b.sent();
273
295
  this_1.logger.debug("Remote config client fetch with retry time ".concat(retries, " failed with ").concat(res.status, ": ").concat(body));
296
+ if (res.status === CODE_STATUS.INVALID_API_KEY) {
297
+ this_1.logger.error("Remote config client fetch failed with ".concat(CODE_STATUS.INVALID_API_KEY, ". Invalid API key; future fetches will be skipped."));
298
+ this_1.isLastFetchInvalidApiKey = true;
299
+ shouldRetry = false;
300
+ }
301
+ else if (res.status >= 400 && res.status < 500 && res.status !== CODE_STATUS.RATE_LIMIT) {
302
+ shouldRetry = false;
303
+ }
274
304
  return [3 /*break*/, 6];
275
305
  case 4: return [4 /*yield*/, res.json()];
276
306
  case 5:
@@ -295,6 +325,9 @@ var RemoteConfigClient = /** @class */ (function () {
295
325
  clearTimeout(timeoutId);
296
326
  return [7 /*endfinally*/];
297
327
  case 9:
328
+ if (!shouldRetry) {
329
+ return [2 /*return*/, "break"];
330
+ }
298
331
  if (!(attempt < retries - 1)) return [3 /*break*/, 11];
299
332
  return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, _this.getJitterDelay(interval)); })];
300
333
  case 10:
@@ -314,6 +347,8 @@ var RemoteConfigClient = /** @class */ (function () {
314
347
  state_1 = _a.sent();
315
348
  if (typeof state_1 === "object")
316
349
  return [2 /*return*/, state_1.value];
350
+ if (state_1 === "break")
351
+ return [3 /*break*/, 4];
317
352
  _a.label = 3;
318
353
  case 3:
319
354
  attempt++;
@@ -1 +1 @@
1
- {"version":3,"file":"remote-config.js","sourceRoot":"","sources":["../../../src/remote-config/remote-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { ServerZoneType } from '../types/server-zone';\nimport { ILogger } from '../logger';\nimport { RemoteConfigLocalStorage } from './remote-config-localstorage';\nimport { UUID } from '../utils/uuid';\n\n/**\n * Modes for receiving remote config updates:\n * - `'all'` – Optimized for both speed and freshness. Returns the fastest response first\n * (cache or remote), then always waits for and returns the remote response to ensure\n * the most up-to-date config. Callback may be called once (if remote wins) or twice\n * (cache first, then remote).\n * - `{ timeout: number }` – Prefers remote data but with a fallback strategy. Waits for\n * a remote response until the specified timeout (in milliseconds), then falls back to\n * cached data if available. Callback is called exactly once.\n */\nexport type DeliveryMode = 'all' | { timeout: number };\n\n/**\n * Sources of returned remote config:\n * - `cache` - Fetched from local storage.\n * - `remote` - Fetched from remote.\n */\nexport type Source = 'cache' | 'remote';\n\nexport const US_SERVER_URL = 'https://sr-client-cfg.amplitude.com/config';\nexport const EU_SERVER_URL = 'https://sr-client-cfg.eu.amplitude.com/config';\nexport const DEFAULT_MAX_RETRIES = 3;\n\n/**\n * The default timeout for fetch in milliseconds.\n * Linear backoff policy: timeout / retry times is the interval between fetch retry.\n */\nconst DEFAULT_TIMEOUT = 1000;\n\n/**\n * The minimum time between fetches in milliseconds.\n * This prevents too many requests from being sent in a short period of time.\n */\nconst DEFAULT_MIN_TIME_BETWEEN_FETCHES = 5 * 60 * 1000; // 5 minutes\n\nexport interface RemoteConfig {\n [key: string]: any;\n}\n\nexport interface RemoteConfigInfo {\n remoteConfig: RemoteConfig | null;\n // Timestamp of when the remote config was fetched.\n lastFetch: Date;\n}\n\nexport interface RemoteConfigStorage {\n /**\n * Fetch remote config from storage asynchronously.\n */\n fetchConfig(): Promise<RemoteConfigInfo>;\n\n /**\n * Set remote config to storage asynchronously.\n */\n setConfig(config: RemoteConfigInfo): Promise<boolean>;\n}\n\n/**\n * Information about each callback registered by `RemoteConfigClient.subscribe()`,\n * managed internally by `RemoteConfigClient`.\n */\nexport interface CallbackInfo {\n id: string;\n key?: string;\n deliveryMode: DeliveryMode;\n callback: RemoteConfigCallback;\n lastCallback?: Date;\n}\n\n/**\n * Callback used in `RemoteConfigClient.subscribe()`.\n * This function is called when the remote config is fetched.\n */\ntype RemoteConfigCallback = (remoteConfig: RemoteConfig | null, source: Source, lastFetch: Date) => void;\n\nexport interface IRemoteConfigClient {\n /**\n * Subscribe for updates to remote config.\n * Callback is guaranteed to be called at least once,\n * Whether we are able to fetch a config or not.\n *\n * @param key - a string containing a series of period delimited keys to filter the returned config.\n * Ie, {a: {b: {c: ...}}} would return {b: {c: ...}} for \"a\" or {c: ...} for \"a.b\".\n * Set to `undefined` to subscribe all keys.\n * @param deliveryMode - how the initial callback is sent.\n * @param callback - a block that will be called when remote config is fetched.\n * @return id - identification of the subscribe and can be used to unsubscribe from updates.\n */\n subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string;\n\n /**\n * Unsubscribe a callback from receiving future updates.\n *\n * @param id - identification of the callback that you want to unsubscribe.\n * It's the return value of subscribe().\n * @return boolean - whether the callback is removed.\n */\n unsubscribe(id: string): boolean;\n\n /**\n * Request the remote config client to fetch from remote, update cache, and callback.\n */\n updateConfigs(): void;\n}\n\nexport class RemoteConfigClient implements IRemoteConfigClient {\n static readonly CONFIG_GROUP = 'browser';\n\n readonly apiKey: string;\n readonly serverUrl: string;\n readonly logger: ILogger;\n readonly storage: RemoteConfigStorage;\n // Registered callbackInfos by subscribe().\n callbackInfos: CallbackInfo[] = [];\n // Track the last successful fetch time for throttling (timestamp in milliseconds).\n lastSuccessfulFetch: number | null = null;\n // Store the in-flight fetch promise for deduplication.\n fetchPromise: Promise<RemoteConfigInfo> | null = null;\n\n constructor(apiKey: string, logger: ILogger, serverZone: ServerZoneType = 'US', serverUrl?: string) {\n this.apiKey = apiKey;\n this.serverUrl = serverUrl || (serverZone === 'US' ? US_SERVER_URL : EU_SERVER_URL);\n this.logger = logger;\n this.storage = new RemoteConfigLocalStorage(apiKey, logger);\n }\n\n subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string {\n const id = UUID();\n const callbackInfo = {\n id: id,\n key: key,\n deliveryMode: deliveryMode,\n callback: callback,\n };\n this.callbackInfos.push(callbackInfo);\n\n if (deliveryMode === 'all') {\n void this.subscribeAll(callbackInfo);\n } else {\n void this.subscribeWaitForRemote(callbackInfo, deliveryMode.timeout);\n }\n\n return id;\n }\n\n unsubscribe(id: string): boolean {\n const index = this.callbackInfos.findIndex((callbackInfo) => callbackInfo.id === id);\n if (index === -1) {\n this.logger.debug(`Remote config client unsubscribe failed because callback with id ${id} doesn't exist.`);\n return false;\n }\n\n this.callbackInfos.splice(index, 1);\n this.logger.debug(`Remote config client unsubscribe succeeded removing callback with id ${id}.`);\n return true;\n }\n\n async updateConfigs() {\n // Check if we need to throttle based on last successful fetch time\n if (this.lastSuccessfulFetch) {\n const timeSinceLastFetch = Date.now() - this.lastSuccessfulFetch;\n if (timeSinceLastFetch < DEFAULT_MIN_TIME_BETWEEN_FETCHES) {\n this.logger.debug('Remote config client skipping updateConfigs: Too recent');\n return;\n }\n }\n\n const result = await this.getOrCreateFetchPromise();\n void this.storage.setConfig(result);\n this.callbackInfos.forEach((callbackInfo) => {\n this.sendCallback(callbackInfo, result, 'remote');\n });\n }\n\n /**\n * Get the in-flight fetch promise or create a new one.\n * This ensures multiple subscribe calls share the same network request.\n */\n getOrCreateFetchPromise(): Promise<RemoteConfigInfo> {\n if (this.fetchPromise) {\n return this.fetchPromise;\n }\n\n this.fetchPromise = this.fetch()\n .then((result) => {\n // Update last successful fetch time if we got a valid config\n if (result.remoteConfig !== null) {\n this.lastSuccessfulFetch = Date.now();\n }\n return result;\n })\n .finally(() => {\n // Clear the promise after it settles (success or failure)\n this.fetchPromise = null;\n });\n\n return this.fetchPromise;\n }\n\n /**\n * Send remote first. If it's already complete, we can skip the cached response.\n * - if remote is fetched first, no cache fetch.\n * - if cache is fetched first, still fetching remote.\n */\n async subscribeAll(callbackInfo: CallbackInfo) {\n const remotePromise = this.getOrCreateFetchPromise().then((result) => {\n this.logger.debug(`Remote config client subscription all mode fetched from remote: ${JSON.stringify(result)}`);\n this.sendCallback(callbackInfo, result, 'remote');\n void this.storage.setConfig(result);\n });\n\n const cachePromise = this.storage.fetchConfig().then((result) => {\n return result;\n });\n\n // Wait for the first result to resolve\n const result = await Promise.race([remotePromise, cachePromise]);\n\n // If cache is fetched first, wait for remote.\n if (result !== undefined) {\n this.logger.debug(`Remote config client subscription all mode fetched from cache: ${JSON.stringify(result)}`);\n // Skip sending callback if cache is empty (first time user).\n if (result.remoteConfig !== null) {\n this.sendCallback(callbackInfo, result, 'cache');\n } else {\n this.logger.debug('Remote config client skips sending callback because cache is empty (first time user).');\n }\n }\n await remotePromise;\n }\n\n /**\n * Waits for a remote response until the given timeout, then return a cached copy, if available.\n */\n async subscribeWaitForRemote(callbackInfo: CallbackInfo, timeout: number) {\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => {\n reject('Timeout exceeded');\n }, timeout);\n });\n\n try {\n const result: RemoteConfigInfo = (await Promise.race([\n this.getOrCreateFetchPromise(),\n timeoutPromise,\n ])) as RemoteConfigInfo;\n\n this.logger.debug('Remote config client subscription wait for remote mode returns from remote.');\n this.sendCallback(callbackInfo, result, 'remote');\n void this.storage.setConfig(result);\n } catch (error) {\n this.logger.debug(\n 'Remote config client subscription wait for remote mode exceeded timeout. Try to fetch from cache.',\n );\n const result = await this.storage.fetchConfig();\n if (result.remoteConfig !== null) {\n this.logger.debug('Remote config client subscription wait for remote mode returns a cached copy.');\n this.sendCallback(callbackInfo, result, 'cache');\n } else {\n this.logger.debug('Remote config client subscription wait for remote mode failed to fetch cache.');\n this.sendCallback(callbackInfo, result, 'remote');\n }\n }\n }\n\n /**\n * Call the callback with filtered remote config based on key.\n * @param remoteConfigInfo - the whole remote config object without filtering by key.\n */\n sendCallback(callbackInfo: CallbackInfo, remoteConfigInfo: RemoteConfigInfo, source: Source) {\n callbackInfo.lastCallback = new Date();\n\n let filteredConfig: RemoteConfig | null;\n if (callbackInfo.key) {\n // Filter remote config by key.\n // For example, if remote config is {a: {b: {c: 1}}},\n // if key = 'a', filter result is {b: {c: 1}};\n // if key = 'a.b', filter result is {c: 1}\n filteredConfig = callbackInfo.key.split('.').reduce((config, key) => {\n if (config === null) {\n return config;\n }\n\n return key in config ? (config[key] as RemoteConfig) : null;\n }, remoteConfigInfo.remoteConfig);\n } else {\n filteredConfig = remoteConfigInfo.remoteConfig;\n }\n\n callbackInfo.callback(filteredConfig, source, remoteConfigInfo.lastFetch);\n }\n\n /**\n * Fetch remote config from remote.\n * @param retries - the number of retries. default is 3.\n * @param timeout - the timeout in milliseconds. Default is 1000.\n * This timeout serves two purposes:\n * 1. It determines how long to wait for each remote config fetch request before aborting it.\n * If the fetch does not complete within the specified timeout, the request is cancelled using AbortController,\n * and the attempt is considered failed (and may be retried if retries remain).\n * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,\n * so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).\n * @returns the remote config info. null if failed to fetch or the response is not valid JSON.\n */\n async fetch(retries: number = DEFAULT_MAX_RETRIES, timeout: number = DEFAULT_TIMEOUT): Promise<RemoteConfigInfo> {\n const interval = timeout / retries;\n const failedRemoteConfigInfo: RemoteConfigInfo = {\n remoteConfig: null,\n lastFetch: new Date(),\n };\n\n for (let attempt = 0; attempt < retries; attempt++) {\n // Create AbortController for request timeout\n const abortController = new AbortController();\n const timeoutId = setTimeout(() => abortController.abort(), timeout);\n\n try {\n const res = await fetch(this.getUrlParams(), {\n method: 'GET',\n headers: {\n Accept: '*/*',\n },\n signal: abortController.signal,\n });\n\n // Handle unsuccessful fetch\n if (!res.ok) {\n const body = await res.text();\n this.logger.debug(`Remote config client fetch with retry time ${retries} failed with ${res.status}: ${body}`);\n } else {\n // Handle successful fetch\n const remoteConfig: RemoteConfig = (await res.json()) as RemoteConfig;\n return {\n remoteConfig: remoteConfig,\n lastFetch: new Date(),\n };\n }\n } catch (error) {\n // Handle rejects when the request fails, for example, a network error or timeout\n if (error instanceof Error && error.name === 'AbortError') {\n this.logger.debug(`Remote config client fetch with retry time ${retries} timed out after ${timeout}ms`);\n } else {\n this.logger.debug(`Remote config client fetch with retry time ${retries} is rejected because: `, error);\n }\n } finally {\n // Clear the timeout since request completed or failed\n clearTimeout(timeoutId);\n }\n\n // Linear backoff:\n // wait for the specified interval before the next attempt\n // except after the last attempt.\n if (attempt < retries - 1) {\n await new Promise((resolve) => setTimeout(resolve, this.getJitterDelay(interval)));\n }\n }\n\n return failedRemoteConfigInfo;\n }\n\n /**\n * Return jitter in the bound of [0,baseDelay) and then floor round.\n */\n getJitterDelay(baseDelay: number): number {\n return Math.floor(Math.random() * baseDelay);\n }\n\n getUrlParams(): string {\n // URL encode the API key to handle special characters\n const encodedApiKey = encodeURIComponent(this.apiKey);\n\n const urlParams = new URLSearchParams();\n urlParams.append('config_group', RemoteConfigClient.CONFIG_GROUP);\n\n return `${this.serverUrl}/${encodedApiKey}?${urlParams.toString()}`;\n }\n}\n"]}
1
+ {"version":3,"file":"remote-config.js","sourceRoot":"","sources":["../../../src/remote-config/remote-config.ts"],"names":[],"mappings":";;;;AAEA,2EAAwE;AACxE,sCAAqC;AAqBxB,QAAA,aAAa,GAAG,4CAA4C,CAAC;AAC7D,QAAA,aAAa,GAAG,+CAA+C,CAAC;AAChE,QAAA,mBAAmB,GAAG,CAAC,CAAC;AACrC,IAAM,WAAW,GAAG;IAClB,eAAe,EAAE,GAAG;IACpB,UAAU,EAAE,GAAG;CACP,CAAC;AAEX;;;GAGG;AACH,IAAM,eAAe,GAAG,IAAI,CAAC;AAE7B;;;GAGG;AACH,IAAM,gCAAgC,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;AAwEpE;IAgBE,4BAAY,MAAc,EAAE,MAAe,EAAE,UAAiC,EAAE,SAAkB;QAArD,2BAAA,EAAA,iBAAiC;QAT9E,2CAA2C;QAC3C,kBAAa,GAAmB,EAAE,CAAC;QACnC,mFAAmF;QACnF,wBAAmB,GAAkB,IAAI,CAAC;QAC1C,uDAAuD;QACvD,iBAAY,GAAqC,IAAI,CAAC;QACtD,qEAAqE;QACrE,6BAAwB,GAAG,KAAK,CAAC;QAG/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,SAAS,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,qBAAa,CAAC,CAAC,CAAC,qBAAa,CAAC,CAAC;QACpF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,IAAI,qDAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9D,CAAC;IAED,sCAAS,GAAT,UAAU,GAAuB,EAAE,YAA0B,EAAE,QAA8B;QAC3F,IAAM,EAAE,GAAG,IAAA,WAAI,GAAE,CAAC;QAClB,IAAM,YAAY,GAAG;YACnB,EAAE,EAAE,EAAE;YACN,GAAG,EAAE,GAAG;YACR,YAAY,EAAE,YAAY;YAC1B,QAAQ,EAAE,QAAQ;SACnB,CAAC;QACF,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAEtC,IAAI,YAAY,KAAK,KAAK,EAAE;YAC1B,KAAK,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;SACtC;aAAM;YACL,KAAK,IAAI,CAAC,sBAAsB,CAAC,YAAY,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;SACtE;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,wCAAW,GAAX,UAAY,EAAU;QACpB,IAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,UAAC,YAAY,IAAK,OAAA,YAAY,CAAC,EAAE,KAAK,EAAE,EAAtB,CAAsB,CAAC,CAAC;QACrF,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2EAAoE,EAAE,oBAAiB,CAAC,CAAC;YAC3G,OAAO,KAAK,CAAC;SACd;QAED,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+EAAwE,EAAE,MAAG,CAAC,CAAC;QACjG,OAAO,IAAI,CAAC;IACd,CAAC;IAEK,0CAAa,GAAnB;;;;;;;wBACE,mEAAmE;wBACnE,IAAI,IAAI,CAAC,mBAAmB,EAAE;4BACtB,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,mBAAmB,CAAC;4BACjE,IAAI,kBAAkB,GAAG,gCAAgC,EAAE;gCACzD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;gCAC7E,sBAAO;6BACR;yBACF;wBAEc,qBAAM,IAAI,CAAC,uBAAuB,EAAE,EAAA;;wBAA7C,MAAM,GAAG,SAAoC;wBACnD,KAAK,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;wBACpC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,UAAC,YAAY;4BACtC,KAAI,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;wBACpD,CAAC,CAAC,CAAC;;;;;KACJ;IAED;;;OAGG;IACH,oDAAuB,GAAvB;QAAA,iBA8BC;QA7BC,IAAI,IAAI,CAAC,YAAY,EAAE;YACrB,OAAO,IAAI,CAAC,YAAY,CAAC;SAC1B;QAED,IAAI,IAAI,CAAC,wBAAwB,EAAE;YACjC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;YAC1E,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;gBAClC,YAAY,EAAE,IAAI;gBAClB,SAAS,EAAE,IAAI,IAAI,EAAE;aACtB,CAAC,CAAC,OAAO,CAAC;gBACT,KAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YAC3B,CAAC,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,YAAY,CAAC;SAC1B;QAED,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,EAAE;aAC7B,IAAI,CAAC,UAAC,MAAM;YACX,6DAA6D;YAC7D,IAAI,MAAM,CAAC,YAAY,KAAK,IAAI,EAAE;gBAChC,KAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;aACvC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;aACD,OAAO,CAAC;YACP,0DAA0D;YAC1D,KAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC,CAAC,CAAC;QAEL,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACG,yCAAY,GAAlB,UAAmB,YAA0B;;;;;;;wBACrC,aAAa,GAAG,IAAI,CAAC,uBAAuB,EAAE,CAAC,IAAI,CAAC,UAAC,MAAM;4BAC/D,KAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0EAAmE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAE,CAAC,CAAC;4BAC/G,KAAI,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;4BAClD,KAAK,KAAI,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;wBACtC,CAAC,CAAC,CAAC;wBAEG,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,UAAC,MAAM;4BAC1D,OAAO,MAAM,CAAC;wBAChB,CAAC,CAAC,CAAC;wBAGY,qBAAM,OAAO,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,EAAA;;wBAA1D,MAAM,GAAG,SAAiD;wBAEhE,8CAA8C;wBAC9C,IAAI,MAAM,KAAK,SAAS,EAAE;4BACxB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yEAAkE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAE,CAAC,CAAC;4BAC9G,6DAA6D;4BAC7D,IAAI,MAAM,CAAC,YAAY,KAAK,IAAI,EAAE;gCAChC,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;6BAClD;iCAAM;gCACL,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uFAAuF,CAAC,CAAC;6BAC5G;yBACF;wBACD,qBAAM,aAAa,EAAA;;wBAAnB,SAAmB,CAAC;;;;;KACrB;IAED;;OAEG;IACG,mDAAsB,GAA5B,UAA6B,YAA0B,EAAE,OAAe;;;;;;wBAChE,cAAc,GAAG,IAAI,OAAO,CAAC,UAAC,CAAC,EAAE,MAAM;4BAC3C,UAAU,CAAC;gCACT,MAAM,CAAC,kBAAkB,CAAC,CAAC;4BAC7B,CAAC,EAAE,OAAO,CAAC,CAAC;wBACd,CAAC,CAAC,CAAC;;;;wBAGiC,qBAAM,OAAO,CAAC,IAAI,CAAC;gCACnD,IAAI,CAAC,uBAAuB,EAAE;gCAC9B,cAAc;6BACf,CAAC,EAAA;;wBAHI,MAAM,GAAqB,CAAC,SAGhC,CAAqB;wBAEvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;wBACjG,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;wBAClD,KAAK,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;;;;wBAEpC,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,mGAAmG,CACpG,CAAC;wBACa,qBAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAA;;wBAAzC,MAAM,GAAG,SAAgC;wBAC/C,IAAI,MAAM,CAAC,YAAY,KAAK,IAAI,EAAE;4BAChC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+EAA+E,CAAC,CAAC;4BACnG,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;yBAClD;6BAAM;4BACL,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+EAA+E,CAAC,CAAC;4BACnG,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;yBACnD;;;;;;KAEJ;IAED;;;OAGG;IACH,yCAAY,GAAZ,UAAa,YAA0B,EAAE,gBAAkC,EAAE,MAAc;QACzF,YAAY,CAAC,YAAY,GAAG,IAAI,IAAI,EAAE,CAAC;QAEvC,IAAI,cAAmC,CAAC;QACxC,IAAI,YAAY,CAAC,GAAG,EAAE;YACpB,+BAA+B;YAC/B,qDAAqD;YACrD,8CAA8C;YAC9C,0CAA0C;YAC1C,cAAc,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,UAAC,MAAM,EAAE,GAAG;gBAC9D,IAAI,MAAM,KAAK,IAAI,EAAE;oBACnB,OAAO,MAAM,CAAC;iBACf;gBAED,OAAO,GAAG,IAAI,MAAM,CAAC,CAAC,CAAE,MAAM,CAAC,GAAG,CAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;YAC9D,CAAC,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;SACnC;aAAM;YACL,cAAc,GAAG,gBAAgB,CAAC,YAAY,CAAC;SAChD;QAED,YAAY,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC5E,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACG,kCAAK,GAAX,UAAY,OAAqC,EAAE,OAAiC;QAAxE,wBAAA,EAAA,UAAkB,2BAAmB;QAAE,wBAAA,EAAA,yBAAiC;;;;;;;wBAC5E,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;wBAC7B,sBAAsB,GAAqB;4BAC/C,YAAY,EAAE,IAAI;4BAClB,SAAS,EAAE,IAAI,IAAI,EAAE;yBACtB,CAAC;4CAEO,OAAO;;;;;wCACV,WAAW,GAAG,IAAI,CAAC;wCAEjB,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;wCACxC,SAAS,GAAG,UAAU,CAAC,cAAM,OAAA,eAAe,CAAC,KAAK,EAAE,EAAvB,CAAuB,EAAE,OAAO,CAAC,CAAC;;;;wCAGvD,qBAAM,KAAK,CAAC,OAAK,YAAY,EAAE,EAAE;gDAC3C,MAAM,EAAE,KAAK;gDACb,OAAO,EAAE;oDACP,MAAM,EAAE,KAAK;iDACd;gDACD,MAAM,EAAE,eAAe,CAAC,MAAM;6CAC/B,CAAC,EAAA;;wCANI,GAAG,GAAG,SAMV;6CAGE,CAAC,GAAG,CAAC,EAAE,EAAP,wBAAO;wCACI,qBAAM,GAAG,CAAC,IAAI,EAAE,EAAA;;wCAAvB,IAAI,GAAG,SAAgB;wCAC7B,OAAK,MAAM,CAAC,KAAK,CAAC,qDAA8C,OAAO,0BAAgB,GAAG,CAAC,MAAM,eAAK,IAAI,CAAE,CAAC,CAAC;wCAE9G,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,eAAe,EAAE;4CAC9C,OAAK,MAAM,CAAC,KAAK,CACf,iDAA0C,WAAW,CAAC,eAAe,uDAAoD,CAC1H,CAAC;4CACF,OAAK,wBAAwB,GAAG,IAAI,CAAC;4CACrC,WAAW,GAAG,KAAK,CAAC;yCACrB;6CAAM,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,UAAU,EAAE;4CACzF,WAAW,GAAG,KAAK,CAAC;yCACrB;;4CAGmC,qBAAM,GAAG,CAAC,IAAI,EAAE,EAAA;;wCAA9C,YAAY,GAAiB,CAAC,SAAgB,CAAiB;uEAC9D;oDACL,YAAY,EAAE,YAAY;oDAC1B,SAAS,EAAE,IAAI,IAAI,EAAE;iDACtB;;;;wCAGH,iFAAiF;wCACjF,IAAI,OAAK,YAAY,KAAK,IAAI,OAAK,CAAC,IAAI,KAAK,YAAY,EAAE;4CACzD,OAAK,MAAM,CAAC,KAAK,CAAC,qDAA8C,OAAO,8BAAoB,OAAO,OAAI,CAAC,CAAC;yCACzG;6CAAM;4CACL,OAAK,MAAM,CAAC,KAAK,CAAC,qDAA8C,OAAO,2BAAwB,EAAE,OAAK,CAAC,CAAC;yCACzG;;;wCAED,sDAAsD;wCACtD,YAAY,CAAC,SAAS,CAAC,CAAC;;;wCAG1B,IAAI,CAAC,WAAW,EAAE;;yCAEjB;6CAKG,CAAA,OAAO,GAAG,OAAO,GAAG,CAAC,CAAA,EAArB,yBAAqB;wCACvB,qBAAM,IAAI,OAAO,CAAC,UAAC,OAAO,IAAK,OAAA,UAAU,CAAC,OAAO,EAAE,KAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,EAAlD,CAAkD,CAAC,EAAA;;wCAAlF,SAAkF,CAAC;;;;;;;wBAzD9E,OAAO,GAAG,CAAC;;;6BAAE,CAAA,OAAO,GAAG,OAAO,CAAA;sDAA9B,OAAO;;;;;;;;;wBAAyB,OAAO,EAAE,CAAA;;4BA6DlD,sBAAO,sBAAsB,EAAC;;;;KAC/B;IAED;;OAEG;IACH,2CAAc,GAAd,UAAe,SAAiB;QAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IAC/C,CAAC;IAED,yCAAY,GAAZ;QACE,sDAAsD;QACtD,IAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEtD,IAAM,SAAS,GAAG,IAAI,eAAe,EAAE,CAAC;QACxC,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAC;QAElE,OAAO,UAAG,IAAI,CAAC,SAAS,cAAI,aAAa,cAAI,SAAS,CAAC,QAAQ,EAAE,CAAE,CAAC;IACtE,CAAC;IA9Se,+BAAY,GAAG,SAAS,CAAC;IA+S3C,yBAAC;CAAA,AAhTD,IAgTC;AAhTY,gDAAkB","sourcesContent":["import { ServerZoneType } from '../types/server-zone';\nimport { ILogger } from '../logger';\nimport { RemoteConfigLocalStorage } from './remote-config-localstorage';\nimport { UUID } from '../utils/uuid';\n\n/**\n * Modes for receiving remote config updates:\n * - `'all'` – Optimized for both speed and freshness. Returns the fastest response first\n * (cache or remote), then always waits for and returns the remote response to ensure\n * the most up-to-date config. Callback may be called once (if remote wins) or twice\n * (cache first, then remote).\n * - `{ timeout: number }` – Prefers remote data but with a fallback strategy. Waits for\n * a remote response until the specified timeout (in milliseconds), then falls back to\n * cached data if available. Callback is called exactly once.\n */\nexport type DeliveryMode = 'all' | { timeout: number };\n\n/**\n * Sources of returned remote config:\n * - `cache` - Fetched from local storage.\n * - `remote` - Fetched from remote.\n */\nexport type Source = 'cache' | 'remote';\n\nexport const US_SERVER_URL = 'https://sr-client-cfg.amplitude.com/config';\nexport const EU_SERVER_URL = 'https://sr-client-cfg.eu.amplitude.com/config';\nexport const DEFAULT_MAX_RETRIES = 3;\nconst CODE_STATUS = {\n INVALID_API_KEY: 401,\n RATE_LIMIT: 429,\n} as const;\n\n/**\n * The default timeout for fetch in milliseconds.\n * Linear backoff policy: timeout / retry times is the interval between fetch retry.\n */\nconst DEFAULT_TIMEOUT = 1000;\n\n/**\n * The minimum time between fetches in milliseconds.\n * This prevents too many requests from being sent in a short period of time.\n */\nconst DEFAULT_MIN_TIME_BETWEEN_FETCHES = 5 * 60 * 1000; // 5 minutes\n\nexport interface RemoteConfig {\n [key: string]: any;\n}\n\nexport interface RemoteConfigInfo {\n remoteConfig: RemoteConfig | null;\n // Timestamp of when the remote config was fetched.\n lastFetch: Date;\n}\n\nexport interface RemoteConfigStorage {\n /**\n * Fetch remote config from storage asynchronously.\n */\n fetchConfig(): Promise<RemoteConfigInfo>;\n\n /**\n * Set remote config to storage asynchronously.\n */\n setConfig(config: RemoteConfigInfo): Promise<boolean>;\n}\n\n/**\n * Information about each callback registered by `RemoteConfigClient.subscribe()`,\n * managed internally by `RemoteConfigClient`.\n */\nexport interface CallbackInfo {\n id: string;\n key?: string;\n deliveryMode: DeliveryMode;\n callback: RemoteConfigCallback;\n lastCallback?: Date;\n}\n\n/**\n * Callback used in `RemoteConfigClient.subscribe()`.\n * This function is called when the remote config is fetched.\n */\ntype RemoteConfigCallback = (remoteConfig: RemoteConfig | null, source: Source, lastFetch: Date) => void;\n\nexport interface IRemoteConfigClient {\n /**\n * Subscribe for updates to remote config.\n * Callback is guaranteed to be called at least once,\n * Whether we are able to fetch a config or not.\n *\n * @param key - a string containing a series of period delimited keys to filter the returned config.\n * Ie, {a: {b: {c: ...}}} would return {b: {c: ...}} for \"a\" or {c: ...} for \"a.b\".\n * Set to `undefined` to subscribe all keys.\n * @param deliveryMode - how the initial callback is sent.\n * @param callback - a block that will be called when remote config is fetched.\n * @return id - identification of the subscribe and can be used to unsubscribe from updates.\n */\n subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string;\n\n /**\n * Unsubscribe a callback from receiving future updates.\n *\n * @param id - identification of the callback that you want to unsubscribe.\n * It's the return value of subscribe().\n * @return boolean - whether the callback is removed.\n */\n unsubscribe(id: string): boolean;\n\n /**\n * Request the remote config client to fetch from remote, update cache, and callback.\n */\n updateConfigs(): void;\n}\n\nexport class RemoteConfigClient implements IRemoteConfigClient {\n static readonly CONFIG_GROUP = 'browser';\n\n readonly apiKey: string;\n readonly serverUrl: string;\n readonly logger: ILogger;\n readonly storage: RemoteConfigStorage;\n // Registered callbackInfos by subscribe().\n callbackInfos: CallbackInfo[] = [];\n // Track the last successful fetch time for throttling (timestamp in milliseconds).\n lastSuccessfulFetch: number | null = null;\n // Store the in-flight fetch promise for deduplication.\n fetchPromise: Promise<RemoteConfigInfo> | null = null;\n // Used to skip periodic updateConfigs calls when API key is invalid.\n isLastFetchInvalidApiKey = false;\n\n constructor(apiKey: string, logger: ILogger, serverZone: ServerZoneType = 'US', serverUrl?: string) {\n this.apiKey = apiKey;\n this.serverUrl = serverUrl || (serverZone === 'US' ? US_SERVER_URL : EU_SERVER_URL);\n this.logger = logger;\n this.storage = new RemoteConfigLocalStorage(apiKey, logger);\n }\n\n subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string {\n const id = UUID();\n const callbackInfo = {\n id: id,\n key: key,\n deliveryMode: deliveryMode,\n callback: callback,\n };\n this.callbackInfos.push(callbackInfo);\n\n if (deliveryMode === 'all') {\n void this.subscribeAll(callbackInfo);\n } else {\n void this.subscribeWaitForRemote(callbackInfo, deliveryMode.timeout);\n }\n\n return id;\n }\n\n unsubscribe(id: string): boolean {\n const index = this.callbackInfos.findIndex((callbackInfo) => callbackInfo.id === id);\n if (index === -1) {\n this.logger.debug(`Remote config client unsubscribe failed because callback with id ${id} doesn't exist.`);\n return false;\n }\n\n this.callbackInfos.splice(index, 1);\n this.logger.debug(`Remote config client unsubscribe succeeded removing callback with id ${id}.`);\n return true;\n }\n\n async updateConfigs() {\n // Check if we need to throttle based on last successful fetch time\n if (this.lastSuccessfulFetch) {\n const timeSinceLastFetch = Date.now() - this.lastSuccessfulFetch;\n if (timeSinceLastFetch < DEFAULT_MIN_TIME_BETWEEN_FETCHES) {\n this.logger.debug('Remote config client skipping updateConfigs: Too recent');\n return;\n }\n }\n\n const result = await this.getOrCreateFetchPromise();\n void this.storage.setConfig(result);\n this.callbackInfos.forEach((callbackInfo) => {\n this.sendCallback(callbackInfo, result, 'remote');\n });\n }\n\n /**\n * Get the in-flight fetch promise or create a new one.\n * This ensures multiple subscribe calls share the same network request.\n */\n getOrCreateFetchPromise(): Promise<RemoteConfigInfo> {\n if (this.fetchPromise) {\n return this.fetchPromise;\n }\n\n if (this.isLastFetchInvalidApiKey) {\n this.logger.debug('Remote config client skipping fetch: Invalid API key');\n this.fetchPromise = Promise.resolve({\n remoteConfig: null,\n lastFetch: new Date(),\n }).finally(() => {\n this.fetchPromise = null;\n });\n return this.fetchPromise;\n }\n\n this.fetchPromise = this.fetch()\n .then((result) => {\n // Update last successful fetch time if we got a valid config\n if (result.remoteConfig !== null) {\n this.lastSuccessfulFetch = Date.now();\n }\n return result;\n })\n .finally(() => {\n // Clear the promise after it settles (success or failure)\n this.fetchPromise = null;\n });\n\n return this.fetchPromise;\n }\n\n /**\n * Send remote first. If it's already complete, we can skip the cached response.\n * - if remote is fetched first, no cache fetch.\n * - if cache is fetched first, still fetching remote.\n */\n async subscribeAll(callbackInfo: CallbackInfo) {\n const remotePromise = this.getOrCreateFetchPromise().then((result) => {\n this.logger.debug(`Remote config client subscription all mode fetched from remote: ${JSON.stringify(result)}`);\n this.sendCallback(callbackInfo, result, 'remote');\n void this.storage.setConfig(result);\n });\n\n const cachePromise = this.storage.fetchConfig().then((result) => {\n return result;\n });\n\n // Wait for the first result to resolve\n const result = await Promise.race([remotePromise, cachePromise]);\n\n // If cache is fetched first, wait for remote.\n if (result !== undefined) {\n this.logger.debug(`Remote config client subscription all mode fetched from cache: ${JSON.stringify(result)}`);\n // Skip sending callback if cache is empty (first time user).\n if (result.remoteConfig !== null) {\n this.sendCallback(callbackInfo, result, 'cache');\n } else {\n this.logger.debug('Remote config client skips sending callback because cache is empty (first time user).');\n }\n }\n await remotePromise;\n }\n\n /**\n * Waits for a remote response until the given timeout, then return a cached copy, if available.\n */\n async subscribeWaitForRemote(callbackInfo: CallbackInfo, timeout: number) {\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => {\n reject('Timeout exceeded');\n }, timeout);\n });\n\n try {\n const result: RemoteConfigInfo = (await Promise.race([\n this.getOrCreateFetchPromise(),\n timeoutPromise,\n ])) as RemoteConfigInfo;\n\n this.logger.debug('Remote config client subscription wait for remote mode returns from remote.');\n this.sendCallback(callbackInfo, result, 'remote');\n void this.storage.setConfig(result);\n } catch (error) {\n this.logger.debug(\n 'Remote config client subscription wait for remote mode exceeded timeout. Try to fetch from cache.',\n );\n const result = await this.storage.fetchConfig();\n if (result.remoteConfig !== null) {\n this.logger.debug('Remote config client subscription wait for remote mode returns a cached copy.');\n this.sendCallback(callbackInfo, result, 'cache');\n } else {\n this.logger.debug('Remote config client subscription wait for remote mode failed to fetch cache.');\n this.sendCallback(callbackInfo, result, 'remote');\n }\n }\n }\n\n /**\n * Call the callback with filtered remote config based on key.\n * @param remoteConfigInfo - the whole remote config object without filtering by key.\n */\n sendCallback(callbackInfo: CallbackInfo, remoteConfigInfo: RemoteConfigInfo, source: Source) {\n callbackInfo.lastCallback = new Date();\n\n let filteredConfig: RemoteConfig | null;\n if (callbackInfo.key) {\n // Filter remote config by key.\n // For example, if remote config is {a: {b: {c: 1}}},\n // if key = 'a', filter result is {b: {c: 1}};\n // if key = 'a.b', filter result is {c: 1}\n filteredConfig = callbackInfo.key.split('.').reduce((config, key) => {\n if (config === null) {\n return config;\n }\n\n return key in config ? (config[key] as RemoteConfig) : null;\n }, remoteConfigInfo.remoteConfig);\n } else {\n filteredConfig = remoteConfigInfo.remoteConfig;\n }\n\n callbackInfo.callback(filteredConfig, source, remoteConfigInfo.lastFetch);\n }\n\n /**\n * Fetch remote config from remote.\n * @param retries - the number of retries. default is 3.\n * @param timeout - the timeout in milliseconds. Default is 1000.\n * This timeout serves two purposes:\n * 1. It determines how long to wait for each remote config fetch request before aborting it.\n * If the fetch does not complete within the specified timeout, the request is cancelled using AbortController,\n * and the attempt is considered failed (and may be retried if retries remain).\n * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,\n * so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).\n * Retry behavior by status code:\n * - 401: invalid API key (stop retries and disable future updateConfigs calls).\n * - 429: retry up to max retries.\n * - other 4xx: no retry.\n * - 5xx and network failures: retry up to max retries.\n * @returns the remote config info. null if failed to fetch or the response is not valid JSON.\n */\n async fetch(retries: number = DEFAULT_MAX_RETRIES, timeout: number = DEFAULT_TIMEOUT): Promise<RemoteConfigInfo> {\n const interval = timeout / retries;\n const failedRemoteConfigInfo: RemoteConfigInfo = {\n remoteConfig: null,\n lastFetch: new Date(),\n };\n\n for (let attempt = 0; attempt < retries; attempt++) {\n let shouldRetry = true;\n // Create AbortController for request timeout\n const abortController = new AbortController();\n const timeoutId = setTimeout(() => abortController.abort(), timeout);\n\n try {\n const res = await fetch(this.getUrlParams(), {\n method: 'GET',\n headers: {\n Accept: '*/*',\n },\n signal: abortController.signal,\n });\n\n // Handle unsuccessful fetch\n if (!res.ok) {\n const body = await res.text();\n this.logger.debug(`Remote config client fetch with retry time ${retries} failed with ${res.status}: ${body}`);\n\n if (res.status === CODE_STATUS.INVALID_API_KEY) {\n this.logger.error(\n `Remote config client fetch failed with ${CODE_STATUS.INVALID_API_KEY}. Invalid API key; future fetches will be skipped.`,\n );\n this.isLastFetchInvalidApiKey = true;\n shouldRetry = false;\n } else if (res.status >= 400 && res.status < 500 && res.status !== CODE_STATUS.RATE_LIMIT) {\n shouldRetry = false;\n }\n } else {\n // Handle successful fetch\n const remoteConfig: RemoteConfig = (await res.json()) as RemoteConfig;\n return {\n remoteConfig: remoteConfig,\n lastFetch: new Date(),\n };\n }\n } catch (error) {\n // Handle rejects when the request fails, for example, a network error or timeout\n if (error instanceof Error && error.name === 'AbortError') {\n this.logger.debug(`Remote config client fetch with retry time ${retries} timed out after ${timeout}ms`);\n } else {\n this.logger.debug(`Remote config client fetch with retry time ${retries} is rejected because: `, error);\n }\n } finally {\n // Clear the timeout since request completed or failed\n clearTimeout(timeoutId);\n }\n\n if (!shouldRetry) {\n break;\n }\n\n // Linear backoff:\n // wait for the specified interval before the next attempt\n // except after the last attempt.\n if (attempt < retries - 1) {\n await new Promise((resolve) => setTimeout(resolve, this.getJitterDelay(interval)));\n }\n }\n\n return failedRemoteConfigInfo;\n }\n\n /**\n * Return jitter in the bound of [0,baseDelay) and then floor round.\n */\n getJitterDelay(baseDelay: number): number {\n return Math.floor(Math.random() * baseDelay);\n }\n\n getUrlParams(): string {\n // URL encode the API key to handle special characters\n const encodedApiKey = encodeURIComponent(this.apiKey);\n\n const urlParams = new URLSearchParams();\n urlParams.append('config_group', RemoteConfigClient.CONFIG_GROUP);\n\n return `${this.serverUrl}/${encodedApiKey}?${urlParams.toString()}`;\n }\n}\n"]}
@@ -2,6 +2,7 @@ import { Storage, CookieStorageOptions, CookieStorageConfig } from '../types/sto
2
2
  export declare class CookieStorage<T> implements Storage<T> {
3
3
  options: CookieStorageOptions;
4
4
  config: CookieStorageConfig;
5
+ private static cachedTlds;
5
6
  constructor(options?: CookieStorageOptions, config?: CookieStorageConfig);
6
7
  isEnabled(): Promise<boolean>;
7
8
  get(key: string): Promise<T | undefined>;
@@ -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;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
+ {"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;IAE5B,OAAO,CAAC,MAAM,CAAC,UAAU,CAA+B;gBAE5C,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;YA+BjD,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"}
@@ -256,6 +256,9 @@ var CookieStorage = /** @class */ (function () {
256
256
  return tslib_1.__generator(this, function (_a) {
257
257
  switch (_a.label) {
258
258
  case 0:
259
+ if (CookieStorage.cachedTlds[domain]) {
260
+ return [2 /*return*/, true];
261
+ }
259
262
  options = {
260
263
  domain: '.' + domain,
261
264
  };
@@ -265,9 +268,16 @@ var CookieStorage = /** @class */ (function () {
265
268
  case 1:
266
269
  _a.trys.push([1, 3, , 4]);
267
270
  return [4 /*yield*/, storage.transaction(storageKey, function (storageSync) {
271
+ if (CookieStorage.cachedTlds[domain]) {
272
+ return true;
273
+ }
268
274
  try {
269
275
  storageSync.set(1);
270
- return storageSync.get();
276
+ var result = !!storageSync.get();
277
+ if (result) {
278
+ CookieStorage.cachedTlds[domain] = true;
279
+ }
280
+ return result;
271
281
  }
272
282
  finally {
273
283
  storageSync.set(null);
@@ -312,6 +322,7 @@ var CookieStorage = /** @class */ (function () {
312
322
  });
313
323
  });
314
324
  };
325
+ CookieStorage.cachedTlds = {};
315
326
  return CookieStorage;
316
327
  }());
317
328
  exports.CookieStorage = CookieStorage;
@@ -1 +1 @@
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"]}
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 private static cachedTlds: Record<string, boolean> = {};\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 if (CookieStorage.cachedTlds[domain]) {\n return true;\n }\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 if (CookieStorage.cachedTlds[domain]) {\n return true;\n }\n try {\n storageSync.set(1);\n const result = !!storageSync.get();\n if (result) {\n CookieStorage.cachedTlds[domain] = true;\n }\n return result;\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"]}
@@ -1,5 +1,5 @@
1
- export { Observable } from 'zen-observable-ts';
2
- import { Observable as ZenObservable } from 'zen-observable-ts';
1
+ import ZenObservable from 'zen-observable';
2
+ export { ZenObservable as Observable };
3
3
  /**
4
4
  * asyncMap operator for Zen Observable
5
5
  *
@@ -1 +1 @@
1
- {"version":3,"file":"observable.d.ts","sourceRoot":"","sources":["../../../src/utils/observable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,EAAE,UAAU,IAAI,aAAa,EAA0B,MAAM,mBAAmB,CAAC;AAExF;;;;;GAKG;AACH,iBAAS,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAoBpG;AAED,KAAK,cAAc,GAAG;IACpB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF;;;;;;;GAOG;AACH,iBAAS,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAgD/F;AAGD,iBAAS,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAkDhE;AAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"observable.d.ts","sourceRoot":"","sources":["../../../src/utils/observable.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,aAAa,IAAI,UAAU,EAAE,CAAC;AAgBvC;;;;;GAKG;AACH,iBAAS,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAoBpG;AAED,KAAK,cAAc,GAAG;IACpB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAIF;;;;;;;GAOG;AACH,iBAAS,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAgD/F;AAGD,iBAAS,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAkDhE;AAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC"}
@@ -2,9 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.merge = exports.multicast = exports.asyncMap = exports.Observable = void 0;
4
4
  var tslib_1 = require("tslib");
5
- var zen_observable_ts_1 = require("zen-observable-ts");
6
- Object.defineProperty(exports, "Observable", { enumerable: true, get: function () { return zen_observable_ts_1.Observable; } });
7
- var zen_observable_ts_2 = require("zen-observable-ts");
5
+ var zen_observable_1 = tslib_1.__importDefault(require("zen-observable"));
6
+ exports.Observable = zen_observable_1.default;
8
7
  /**
9
8
  * asyncMap operator for Zen Observable
10
9
  *
@@ -12,7 +11,7 @@ var zen_observable_ts_2 = require("zen-observable-ts");
12
11
  * emitting the resolved values in the same order they arrive.
13
12
  */
14
13
  function asyncMap(observable, fn) {
15
- return new zen_observable_ts_2.Observable(function (observer) {
14
+ return new zen_observable_1.default(function (observer) {
16
15
  observable.subscribe({
17
16
  next: function (value) {
18
17
  fn(value)
@@ -40,7 +39,7 @@ exports.asyncMap = asyncMap;
40
39
  * @returns Unsubscribable cleanup function
41
40
  */
42
41
  function merge(sourceA, sourceB) {
43
- return new zen_observable_ts_2.Observable(function (observer) {
42
+ return new zen_observable_1.default(function (observer) {
44
43
  var closed = false;
45
44
  var subscriptions = new Set();
46
45
  var cleanup = function () {
@@ -106,7 +105,7 @@ function multicast(source) {
106
105
  subscription = null;
107
106
  observers.clear();
108
107
  }
109
- return new zen_observable_ts_2.Observable(function (observer) {
108
+ return new zen_observable_1.default(function (observer) {
110
109
  observers.add(observer);
111
110
  if (subscription === null) {
112
111
  subscription = source.subscribe({
@@ -1 +1 @@
1
- {"version":3,"file":"observable.js","sourceRoot":"","sources":["../../../src/utils/observable.ts"],"names":[],"mappings":"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","sourcesContent":["export { Observable } from 'zen-observable-ts';\n\nimport { Observable as ZenObservable, Observer, Subscription } from 'zen-observable-ts';\n\n/**\n * asyncMap operator for Zen Observable\n *\n * Maps each value emitted by the source Observable using an async function,\n * emitting the resolved values in the same order they arrive.\n */\nfunction asyncMap<T, R>(observable: ZenObservable<T>, fn: (value: T) => Promise<R>): ZenObservable<R> {\n return new ZenObservable(\n (observer: { next: (value: R) => void; error: (error: any) => void; complete: () => void }) => {\n observable.subscribe({\n next: (value: T) => {\n fn(value)\n .then((result: R) => {\n return observer.next(result);\n })\n .catch((error: any) => observer.error(error));\n },\n error: (error: any) => {\n observer.error(error);\n },\n complete: () => {\n observer.complete();\n },\n });\n },\n );\n}\n\ntype Unsubscribable = {\n unsubscribe: () => void;\n};\n\n/**\n * merge operator for Zen Observable\n *\n * Merges two observables into a single observable, emitting values from both sources in the order they arrive.\n * @param sourceA Observable to merge\n * @param sourceB Observable to merge\n * @returns Unsubscribable cleanup function\n */\nfunction merge<A, B>(sourceA: ZenObservable<A>, sourceB: ZenObservable<B>): ZenObservable<A | B> {\n return new ZenObservable<A | B>((observer) => {\n let closed = false;\n\n const subscriptions: Set<Unsubscribable> = new Set();\n\n const cleanup = (): void => {\n closed = true;\n for (const sub of subscriptions) {\n try {\n sub.unsubscribe();\n } catch {\n /* do nothing */\n }\n }\n subscriptions.clear();\n };\n\n const subscribeTo = <T>(source: ZenObservable<T>) => {\n const sub = source.subscribe({\n next(value: T) {\n if (!closed) observer.next(value as A | B);\n },\n error(err) {\n if (!closed) {\n closed = true;\n observer.error(err);\n cleanup();\n }\n },\n complete() {\n subscriptions.delete(sub);\n if (!closed && subscriptions.size === 0) {\n observer.complete();\n cleanup();\n closed = true;\n }\n },\n });\n\n subscriptions.add(sub);\n };\n\n subscribeTo(sourceA);\n subscribeTo(sourceB);\n\n return cleanup;\n });\n}\n\n// function share() {\nfunction multicast<T>(source: ZenObservable<T>): ZenObservable<T> {\n const observers: Set<Observer<T>> = new Set();\n let subscription: Subscription | null = null;\n\n function cleanup() {\n /* istanbul ignore next */\n subscription?.unsubscribe();\n subscription = null;\n observers.clear();\n }\n\n return new ZenObservable<T>((observer) => {\n observers.add(observer);\n\n if (subscription === null) {\n subscription = source.subscribe({\n next(value) {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.next?.(value);\n }\n },\n error(err) {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.error?.(err);\n }\n cleanup();\n },\n complete() {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.complete?.();\n }\n cleanup();\n },\n });\n }\n\n // Return unsubscribe function for this observer\n return () => {\n observers.delete(observer);\n\n // If no observers left, unsubscribe from the source\n if (observers.size === 0 && subscription) {\n subscription.unsubscribe();\n subscription = null;\n }\n };\n });\n}\n\nexport { asyncMap, multicast, merge, Unsubscribable };\n"]}
1
+ {"version":3,"file":"observable.js","sourceRoot":"","sources":["../../../src/utils/observable.ts"],"names":[],"mappings":"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","sourcesContent":["import ZenObservable from 'zen-observable';\n\nexport { ZenObservable as Observable };\n\n/** Subscription type for zen-observable */\ninterface Subscription {\n closed: boolean;\n unsubscribe(): void;\n}\n\n/** Observer type for zen-observable */\ninterface Observer<T> {\n start?(subscription: Subscription): unknown;\n next?(value: T): void;\n error?(errorValue: unknown): void;\n complete?(): void;\n}\n\n/**\n * asyncMap operator for Zen Observable\n *\n * Maps each value emitted by the source Observable using an async function,\n * emitting the resolved values in the same order they arrive.\n */\nfunction asyncMap<T, R>(observable: ZenObservable<T>, fn: (value: T) => Promise<R>): ZenObservable<R> {\n return new ZenObservable(\n (observer: { next: (value: R) => void; error: (error: any) => void; complete: () => void }) => {\n observable.subscribe({\n next: (value: T) => {\n fn(value)\n .then((result: R) => {\n return observer.next(result);\n })\n .catch((error: any) => observer.error(error));\n },\n error: (error: any) => {\n observer.error(error);\n },\n complete: () => {\n observer.complete();\n },\n });\n },\n );\n}\n\ntype Unsubscribable = {\n unsubscribe: () => void;\n};\n\ntype ZenObserver<A, B> = { next: (v: A | B) => void; error: (e: unknown) => void; complete: () => void };\n\n/**\n * merge operator for Zen Observable\n *\n * Merges two observables into a single observable, emitting values from both sources in the order they arrive.\n * @param sourceA Observable to merge\n * @param sourceB Observable to merge\n * @returns Unsubscribable cleanup function\n */\nfunction merge<A, B>(sourceA: ZenObservable<A>, sourceB: ZenObservable<B>): ZenObservable<A | B> {\n return new ZenObservable<A | B>((observer: ZenObserver<A, B>) => {\n let closed = false;\n\n const subscriptions: Set<Unsubscribable> = new Set();\n\n const cleanup = (): void => {\n closed = true;\n for (const sub of subscriptions) {\n try {\n sub.unsubscribe();\n } catch {\n /* do nothing */\n }\n }\n subscriptions.clear();\n };\n\n const subscribeTo = <T>(source: ZenObservable<T>) => {\n const sub = source.subscribe({\n next(value: T) {\n if (!closed) observer.next(value as A | B);\n },\n error(err: unknown) {\n if (!closed) {\n closed = true;\n observer.error(err);\n cleanup();\n }\n },\n complete() {\n subscriptions.delete(sub);\n if (!closed && subscriptions.size === 0) {\n observer.complete();\n cleanup();\n closed = true;\n }\n },\n });\n\n subscriptions.add(sub);\n };\n\n subscribeTo(sourceA);\n subscribeTo(sourceB);\n\n return cleanup;\n });\n}\n\n// function share() {\nfunction multicast<T>(source: ZenObservable<T>): ZenObservable<T> {\n const observers: Set<Observer<T>> = new Set();\n let subscription: Subscription | null = null;\n\n function cleanup() {\n /* istanbul ignore next */\n subscription?.unsubscribe();\n subscription = null;\n observers.clear();\n }\n\n return new ZenObservable<T>((observer: Observer<T>) => {\n observers.add(observer);\n\n if (subscription === null) {\n subscription = source.subscribe({\n next(value: T) {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.next?.(value);\n }\n },\n error(err: unknown) {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.error?.(err);\n }\n cleanup();\n },\n complete() {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.complete?.();\n }\n cleanup();\n },\n });\n }\n\n // Return unsubscribe function for this observer\n return () => {\n observers.delete(observer);\n\n // If no observers left, unsubscribe from the source\n if (observers.size === 0 && subscription) {\n subscription.unsubscribe();\n subscription = null;\n }\n };\n });\n}\n\nexport { asyncMap, multicast, merge, Unsubscribable };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"safe-stringify.d.ts","sourceRoot":"","sources":["../../../src/utils/safe-stringify.ts"],"names":[],"mappings":"AAKA,KAAK,mBAAmB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,KAAK,MAAM,CAAC;AAC7F,QAAA,MAAM,iBAAiB,EAAE,mBACqD,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"safe-stringify.d.ts","sourceRoot":"","sources":["../../../src/utils/safe-stringify.ts"],"names":[],"mappings":"AAKA,KAAK,mBAAmB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,KAAK,MAAM,CAAC;AAE7F,QAAA,MAAM,iBAAiB,EAAE,mBACqD,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.safeJsonStringify = void 0;
4
+ var tslib_1 = require("tslib");
4
5
  /* eslint-disable @typescript-eslint/no-unsafe-assignment */
5
6
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
6
- var safeJsonStringifyModule = require("safe-json-stringify");
7
+ var safeJsonStringifyModule = tslib_1.__importStar(require("safe-json-stringify"));
8
+ /* istanbul ignore next */
7
9
  var safeJsonStringify = safeJsonStringifyModule.default || safeJsonStringifyModule;
8
10
  exports.safeJsonStringify = safeJsonStringify;
9
11
  //# sourceMappingURL=safe-stringify.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"safe-stringify.js","sourceRoot":"","sources":["../../../src/utils/safe-stringify.ts"],"names":[],"mappings":";;;AAAA,4DAA4D;AAC5D,+DAA+D;AAC/D,6DAA+D;AAI/D,IAAM,iBAAiB,GACpB,uBAA+B,CAAC,OAAO,IAAK,uBAA+B,CAAC;AAEtE,8CAAiB","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport * as safeJsonStringifyModule from 'safe-json-stringify';\n\n// do a simple, typed re-export of \"safe-json-stringify\"\ntype SafeJsonStringifyFn = (data: object, replacer?: any, space?: string | number) => string;\nconst safeJsonStringify: SafeJsonStringifyFn =\n (safeJsonStringifyModule as any).default || (safeJsonStringifyModule as any);\n\nexport { safeJsonStringify };\n"]}
1
+ {"version":3,"file":"safe-stringify.js","sourceRoot":"","sources":["../../../src/utils/safe-stringify.ts"],"names":[],"mappings":";;;;AAAA,4DAA4D;AAC5D,+DAA+D;AAC/D,mFAA+D;AAI/D,0BAA0B;AAC1B,IAAM,iBAAiB,GACpB,uBAA+B,CAAC,OAAO,IAAK,uBAA+B,CAAC;AAEtE,8CAAiB","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport * as safeJsonStringifyModule from 'safe-json-stringify';\n\n// do a simple, typed re-export of \"safe-json-stringify\"\ntype SafeJsonStringifyFn = (data: object, replacer?: any, space?: string | number) => string;\n/* istanbul ignore next */\nconst safeJsonStringify: SafeJsonStringifyFn =\n (safeJsonStringifyModule as any).default || (safeJsonStringifyModule as any);\n\nexport { safeJsonStringify };\n"]}
@@ -91,6 +91,7 @@ export declare class RemoteConfigClient implements IRemoteConfigClient {
91
91
  callbackInfos: CallbackInfo[];
92
92
  lastSuccessfulFetch: number | null;
93
93
  fetchPromise: Promise<RemoteConfigInfo> | null;
94
+ isLastFetchInvalidApiKey: boolean;
94
95
  constructor(apiKey: string, logger: ILogger, serverZone?: ServerZoneType, serverUrl?: string);
95
96
  subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string;
96
97
  unsubscribe(id: string): boolean;
@@ -125,6 +126,11 @@ export declare class RemoteConfigClient implements IRemoteConfigClient {
125
126
  * and the attempt is considered failed (and may be retried if retries remain).
126
127
  * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,
127
128
  * so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).
129
+ * Retry behavior by status code:
130
+ * - 401: invalid API key (stop retries and disable future updateConfigs calls).
131
+ * - 429: retry up to max retries.
132
+ * - other 4xx: no retry.
133
+ * - 5xx and network failures: retry up to max retries.
128
134
  * @returns the remote config info. null if failed to fetch or the response is not valid JSON.
129
135
  */
130
136
  fetch(retries?: number, timeout?: number): Promise<RemoteConfigInfo>;
@@ -1 +1 @@
1
- {"version":3,"file":"remote-config.d.ts","sourceRoot":"","sources":["../../../src/remote-config/remote-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remote-config.d.ts","sourceRoot":"","sources":["../../../src/remote-config/remote-config.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,10 @@ import { UUID } from '../utils/uuid';
4
4
  export var US_SERVER_URL = 'https://sr-client-cfg.amplitude.com/config';
5
5
  export var EU_SERVER_URL = 'https://sr-client-cfg.eu.amplitude.com/config';
6
6
  export var DEFAULT_MAX_RETRIES = 3;
7
+ var CODE_STATUS = {
8
+ INVALID_API_KEY: 401,
9
+ RATE_LIMIT: 429,
10
+ };
7
11
  /**
8
12
  * The default timeout for fetch in milliseconds.
9
13
  * Linear backoff policy: timeout / retry times is the interval between fetch retry.
@@ -23,6 +27,8 @@ var RemoteConfigClient = /** @class */ (function () {
23
27
  this.lastSuccessfulFetch = null;
24
28
  // Store the in-flight fetch promise for deduplication.
25
29
  this.fetchPromise = null;
30
+ // Used to skip periodic updateConfigs calls when API key is invalid.
31
+ this.isLastFetchInvalidApiKey = false;
26
32
  this.apiKey = apiKey;
27
33
  this.serverUrl = serverUrl || (serverZone === 'US' ? US_SERVER_URL : EU_SERVER_URL);
28
34
  this.logger = logger;
@@ -91,6 +97,16 @@ var RemoteConfigClient = /** @class */ (function () {
91
97
  if (this.fetchPromise) {
92
98
  return this.fetchPromise;
93
99
  }
100
+ if (this.isLastFetchInvalidApiKey) {
101
+ this.logger.debug('Remote config client skipping fetch: Invalid API key');
102
+ this.fetchPromise = Promise.resolve({
103
+ remoteConfig: null,
104
+ lastFetch: new Date(),
105
+ }).finally(function () {
106
+ _this.fetchPromise = null;
107
+ });
108
+ return this.fetchPromise;
109
+ }
94
110
  this.fetchPromise = this.fetch()
95
111
  .then(function (result) {
96
112
  // Update last successful fetch time if we got a valid config
@@ -228,6 +244,11 @@ var RemoteConfigClient = /** @class */ (function () {
228
244
  * and the attempt is considered failed (and may be retried if retries remain).
229
245
  * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,
230
246
  * so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).
247
+ * Retry behavior by status code:
248
+ * - 401: invalid API key (stop retries and disable future updateConfigs calls).
249
+ * - 429: retry up to max retries.
250
+ * - other 4xx: no retry.
251
+ * - 5xx and network failures: retry up to max retries.
231
252
  * @returns the remote config info. null if failed to fetch or the response is not valid JSON.
232
253
  */
233
254
  RemoteConfigClient.prototype.fetch = function (retries, timeout) {
@@ -245,10 +266,11 @@ var RemoteConfigClient = /** @class */ (function () {
245
266
  lastFetch: new Date(),
246
267
  };
247
268
  _loop_1 = function (attempt) {
248
- var abortController, timeoutId, res, body, remoteConfig, error_2;
269
+ var shouldRetry, abortController, timeoutId, res, body, remoteConfig, error_2;
249
270
  return __generator(this, function (_b) {
250
271
  switch (_b.label) {
251
272
  case 0:
273
+ shouldRetry = true;
252
274
  abortController = new AbortController();
253
275
  timeoutId = setTimeout(function () { return abortController.abort(); }, timeout);
254
276
  _b.label = 1;
@@ -268,6 +290,14 @@ var RemoteConfigClient = /** @class */ (function () {
268
290
  case 3:
269
291
  body = _b.sent();
270
292
  this_1.logger.debug("Remote config client fetch with retry time ".concat(retries, " failed with ").concat(res.status, ": ").concat(body));
293
+ if (res.status === CODE_STATUS.INVALID_API_KEY) {
294
+ this_1.logger.error("Remote config client fetch failed with ".concat(CODE_STATUS.INVALID_API_KEY, ". Invalid API key; future fetches will be skipped."));
295
+ this_1.isLastFetchInvalidApiKey = true;
296
+ shouldRetry = false;
297
+ }
298
+ else if (res.status >= 400 && res.status < 500 && res.status !== CODE_STATUS.RATE_LIMIT) {
299
+ shouldRetry = false;
300
+ }
271
301
  return [3 /*break*/, 6];
272
302
  case 4: return [4 /*yield*/, res.json()];
273
303
  case 5:
@@ -292,6 +322,9 @@ var RemoteConfigClient = /** @class */ (function () {
292
322
  clearTimeout(timeoutId);
293
323
  return [7 /*endfinally*/];
294
324
  case 9:
325
+ if (!shouldRetry) {
326
+ return [2 /*return*/, "break"];
327
+ }
295
328
  if (!(attempt < retries - 1)) return [3 /*break*/, 11];
296
329
  return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, _this.getJitterDelay(interval)); })];
297
330
  case 10:
@@ -311,6 +344,8 @@ var RemoteConfigClient = /** @class */ (function () {
311
344
  state_1 = _a.sent();
312
345
  if (typeof state_1 === "object")
313
346
  return [2 /*return*/, state_1.value];
347
+ if (state_1 === "break")
348
+ return [3 /*break*/, 4];
314
349
  _a.label = 3;
315
350
  case 3:
316
351
  attempt++;
@@ -1 +1 @@
1
- {"version":3,"file":"remote-config.js","sourceRoot":"","sources":["../../../src/remote-config/remote-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { ServerZoneType } from '../types/server-zone';\nimport { ILogger } from '../logger';\nimport { RemoteConfigLocalStorage } from './remote-config-localstorage';\nimport { UUID } from '../utils/uuid';\n\n/**\n * Modes for receiving remote config updates:\n * - `'all'` – Optimized for both speed and freshness. Returns the fastest response first\n * (cache or remote), then always waits for and returns the remote response to ensure\n * the most up-to-date config. Callback may be called once (if remote wins) or twice\n * (cache first, then remote).\n * - `{ timeout: number }` – Prefers remote data but with a fallback strategy. Waits for\n * a remote response until the specified timeout (in milliseconds), then falls back to\n * cached data if available. Callback is called exactly once.\n */\nexport type DeliveryMode = 'all' | { timeout: number };\n\n/**\n * Sources of returned remote config:\n * - `cache` - Fetched from local storage.\n * - `remote` - Fetched from remote.\n */\nexport type Source = 'cache' | 'remote';\n\nexport const US_SERVER_URL = 'https://sr-client-cfg.amplitude.com/config';\nexport const EU_SERVER_URL = 'https://sr-client-cfg.eu.amplitude.com/config';\nexport const DEFAULT_MAX_RETRIES = 3;\n\n/**\n * The default timeout for fetch in milliseconds.\n * Linear backoff policy: timeout / retry times is the interval between fetch retry.\n */\nconst DEFAULT_TIMEOUT = 1000;\n\n/**\n * The minimum time between fetches in milliseconds.\n * This prevents too many requests from being sent in a short period of time.\n */\nconst DEFAULT_MIN_TIME_BETWEEN_FETCHES = 5 * 60 * 1000; // 5 minutes\n\nexport interface RemoteConfig {\n [key: string]: any;\n}\n\nexport interface RemoteConfigInfo {\n remoteConfig: RemoteConfig | null;\n // Timestamp of when the remote config was fetched.\n lastFetch: Date;\n}\n\nexport interface RemoteConfigStorage {\n /**\n * Fetch remote config from storage asynchronously.\n */\n fetchConfig(): Promise<RemoteConfigInfo>;\n\n /**\n * Set remote config to storage asynchronously.\n */\n setConfig(config: RemoteConfigInfo): Promise<boolean>;\n}\n\n/**\n * Information about each callback registered by `RemoteConfigClient.subscribe()`,\n * managed internally by `RemoteConfigClient`.\n */\nexport interface CallbackInfo {\n id: string;\n key?: string;\n deliveryMode: DeliveryMode;\n callback: RemoteConfigCallback;\n lastCallback?: Date;\n}\n\n/**\n * Callback used in `RemoteConfigClient.subscribe()`.\n * This function is called when the remote config is fetched.\n */\ntype RemoteConfigCallback = (remoteConfig: RemoteConfig | null, source: Source, lastFetch: Date) => void;\n\nexport interface IRemoteConfigClient {\n /**\n * Subscribe for updates to remote config.\n * Callback is guaranteed to be called at least once,\n * Whether we are able to fetch a config or not.\n *\n * @param key - a string containing a series of period delimited keys to filter the returned config.\n * Ie, {a: {b: {c: ...}}} would return {b: {c: ...}} for \"a\" or {c: ...} for \"a.b\".\n * Set to `undefined` to subscribe all keys.\n * @param deliveryMode - how the initial callback is sent.\n * @param callback - a block that will be called when remote config is fetched.\n * @return id - identification of the subscribe and can be used to unsubscribe from updates.\n */\n subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string;\n\n /**\n * Unsubscribe a callback from receiving future updates.\n *\n * @param id - identification of the callback that you want to unsubscribe.\n * It's the return value of subscribe().\n * @return boolean - whether the callback is removed.\n */\n unsubscribe(id: string): boolean;\n\n /**\n * Request the remote config client to fetch from remote, update cache, and callback.\n */\n updateConfigs(): void;\n}\n\nexport class RemoteConfigClient implements IRemoteConfigClient {\n static readonly CONFIG_GROUP = 'browser';\n\n readonly apiKey: string;\n readonly serverUrl: string;\n readonly logger: ILogger;\n readonly storage: RemoteConfigStorage;\n // Registered callbackInfos by subscribe().\n callbackInfos: CallbackInfo[] = [];\n // Track the last successful fetch time for throttling (timestamp in milliseconds).\n lastSuccessfulFetch: number | null = null;\n // Store the in-flight fetch promise for deduplication.\n fetchPromise: Promise<RemoteConfigInfo> | null = null;\n\n constructor(apiKey: string, logger: ILogger, serverZone: ServerZoneType = 'US', serverUrl?: string) {\n this.apiKey = apiKey;\n this.serverUrl = serverUrl || (serverZone === 'US' ? US_SERVER_URL : EU_SERVER_URL);\n this.logger = logger;\n this.storage = new RemoteConfigLocalStorage(apiKey, logger);\n }\n\n subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string {\n const id = UUID();\n const callbackInfo = {\n id: id,\n key: key,\n deliveryMode: deliveryMode,\n callback: callback,\n };\n this.callbackInfos.push(callbackInfo);\n\n if (deliveryMode === 'all') {\n void this.subscribeAll(callbackInfo);\n } else {\n void this.subscribeWaitForRemote(callbackInfo, deliveryMode.timeout);\n }\n\n return id;\n }\n\n unsubscribe(id: string): boolean {\n const index = this.callbackInfos.findIndex((callbackInfo) => callbackInfo.id === id);\n if (index === -1) {\n this.logger.debug(`Remote config client unsubscribe failed because callback with id ${id} doesn't exist.`);\n return false;\n }\n\n this.callbackInfos.splice(index, 1);\n this.logger.debug(`Remote config client unsubscribe succeeded removing callback with id ${id}.`);\n return true;\n }\n\n async updateConfigs() {\n // Check if we need to throttle based on last successful fetch time\n if (this.lastSuccessfulFetch) {\n const timeSinceLastFetch = Date.now() - this.lastSuccessfulFetch;\n if (timeSinceLastFetch < DEFAULT_MIN_TIME_BETWEEN_FETCHES) {\n this.logger.debug('Remote config client skipping updateConfigs: Too recent');\n return;\n }\n }\n\n const result = await this.getOrCreateFetchPromise();\n void this.storage.setConfig(result);\n this.callbackInfos.forEach((callbackInfo) => {\n this.sendCallback(callbackInfo, result, 'remote');\n });\n }\n\n /**\n * Get the in-flight fetch promise or create a new one.\n * This ensures multiple subscribe calls share the same network request.\n */\n getOrCreateFetchPromise(): Promise<RemoteConfigInfo> {\n if (this.fetchPromise) {\n return this.fetchPromise;\n }\n\n this.fetchPromise = this.fetch()\n .then((result) => {\n // Update last successful fetch time if we got a valid config\n if (result.remoteConfig !== null) {\n this.lastSuccessfulFetch = Date.now();\n }\n return result;\n })\n .finally(() => {\n // Clear the promise after it settles (success or failure)\n this.fetchPromise = null;\n });\n\n return this.fetchPromise;\n }\n\n /**\n * Send remote first. If it's already complete, we can skip the cached response.\n * - if remote is fetched first, no cache fetch.\n * - if cache is fetched first, still fetching remote.\n */\n async subscribeAll(callbackInfo: CallbackInfo) {\n const remotePromise = this.getOrCreateFetchPromise().then((result) => {\n this.logger.debug(`Remote config client subscription all mode fetched from remote: ${JSON.stringify(result)}`);\n this.sendCallback(callbackInfo, result, 'remote');\n void this.storage.setConfig(result);\n });\n\n const cachePromise = this.storage.fetchConfig().then((result) => {\n return result;\n });\n\n // Wait for the first result to resolve\n const result = await Promise.race([remotePromise, cachePromise]);\n\n // If cache is fetched first, wait for remote.\n if (result !== undefined) {\n this.logger.debug(`Remote config client subscription all mode fetched from cache: ${JSON.stringify(result)}`);\n // Skip sending callback if cache is empty (first time user).\n if (result.remoteConfig !== null) {\n this.sendCallback(callbackInfo, result, 'cache');\n } else {\n this.logger.debug('Remote config client skips sending callback because cache is empty (first time user).');\n }\n }\n await remotePromise;\n }\n\n /**\n * Waits for a remote response until the given timeout, then return a cached copy, if available.\n */\n async subscribeWaitForRemote(callbackInfo: CallbackInfo, timeout: number) {\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => {\n reject('Timeout exceeded');\n }, timeout);\n });\n\n try {\n const result: RemoteConfigInfo = (await Promise.race([\n this.getOrCreateFetchPromise(),\n timeoutPromise,\n ])) as RemoteConfigInfo;\n\n this.logger.debug('Remote config client subscription wait for remote mode returns from remote.');\n this.sendCallback(callbackInfo, result, 'remote');\n void this.storage.setConfig(result);\n } catch (error) {\n this.logger.debug(\n 'Remote config client subscription wait for remote mode exceeded timeout. Try to fetch from cache.',\n );\n const result = await this.storage.fetchConfig();\n if (result.remoteConfig !== null) {\n this.logger.debug('Remote config client subscription wait for remote mode returns a cached copy.');\n this.sendCallback(callbackInfo, result, 'cache');\n } else {\n this.logger.debug('Remote config client subscription wait for remote mode failed to fetch cache.');\n this.sendCallback(callbackInfo, result, 'remote');\n }\n }\n }\n\n /**\n * Call the callback with filtered remote config based on key.\n * @param remoteConfigInfo - the whole remote config object without filtering by key.\n */\n sendCallback(callbackInfo: CallbackInfo, remoteConfigInfo: RemoteConfigInfo, source: Source) {\n callbackInfo.lastCallback = new Date();\n\n let filteredConfig: RemoteConfig | null;\n if (callbackInfo.key) {\n // Filter remote config by key.\n // For example, if remote config is {a: {b: {c: 1}}},\n // if key = 'a', filter result is {b: {c: 1}};\n // if key = 'a.b', filter result is {c: 1}\n filteredConfig = callbackInfo.key.split('.').reduce((config, key) => {\n if (config === null) {\n return config;\n }\n\n return key in config ? (config[key] as RemoteConfig) : null;\n }, remoteConfigInfo.remoteConfig);\n } else {\n filteredConfig = remoteConfigInfo.remoteConfig;\n }\n\n callbackInfo.callback(filteredConfig, source, remoteConfigInfo.lastFetch);\n }\n\n /**\n * Fetch remote config from remote.\n * @param retries - the number of retries. default is 3.\n * @param timeout - the timeout in milliseconds. Default is 1000.\n * This timeout serves two purposes:\n * 1. It determines how long to wait for each remote config fetch request before aborting it.\n * If the fetch does not complete within the specified timeout, the request is cancelled using AbortController,\n * and the attempt is considered failed (and may be retried if retries remain).\n * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,\n * so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).\n * @returns the remote config info. null if failed to fetch or the response is not valid JSON.\n */\n async fetch(retries: number = DEFAULT_MAX_RETRIES, timeout: number = DEFAULT_TIMEOUT): Promise<RemoteConfigInfo> {\n const interval = timeout / retries;\n const failedRemoteConfigInfo: RemoteConfigInfo = {\n remoteConfig: null,\n lastFetch: new Date(),\n };\n\n for (let attempt = 0; attempt < retries; attempt++) {\n // Create AbortController for request timeout\n const abortController = new AbortController();\n const timeoutId = setTimeout(() => abortController.abort(), timeout);\n\n try {\n const res = await fetch(this.getUrlParams(), {\n method: 'GET',\n headers: {\n Accept: '*/*',\n },\n signal: abortController.signal,\n });\n\n // Handle unsuccessful fetch\n if (!res.ok) {\n const body = await res.text();\n this.logger.debug(`Remote config client fetch with retry time ${retries} failed with ${res.status}: ${body}`);\n } else {\n // Handle successful fetch\n const remoteConfig: RemoteConfig = (await res.json()) as RemoteConfig;\n return {\n remoteConfig: remoteConfig,\n lastFetch: new Date(),\n };\n }\n } catch (error) {\n // Handle rejects when the request fails, for example, a network error or timeout\n if (error instanceof Error && error.name === 'AbortError') {\n this.logger.debug(`Remote config client fetch with retry time ${retries} timed out after ${timeout}ms`);\n } else {\n this.logger.debug(`Remote config client fetch with retry time ${retries} is rejected because: `, error);\n }\n } finally {\n // Clear the timeout since request completed or failed\n clearTimeout(timeoutId);\n }\n\n // Linear backoff:\n // wait for the specified interval before the next attempt\n // except after the last attempt.\n if (attempt < retries - 1) {\n await new Promise((resolve) => setTimeout(resolve, this.getJitterDelay(interval)));\n }\n }\n\n return failedRemoteConfigInfo;\n }\n\n /**\n * Return jitter in the bound of [0,baseDelay) and then floor round.\n */\n getJitterDelay(baseDelay: number): number {\n return Math.floor(Math.random() * baseDelay);\n }\n\n getUrlParams(): string {\n // URL encode the API key to handle special characters\n const encodedApiKey = encodeURIComponent(this.apiKey);\n\n const urlParams = new URLSearchParams();\n urlParams.append('config_group', RemoteConfigClient.CONFIG_GROUP);\n\n return `${this.serverUrl}/${encodedApiKey}?${urlParams.toString()}`;\n }\n}\n"]}
1
+ {"version":3,"file":"remote-config.js","sourceRoot":"","sources":["../../../src/remote-config/remote-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { ServerZoneType } from '../types/server-zone';\nimport { ILogger } from '../logger';\nimport { RemoteConfigLocalStorage } from './remote-config-localstorage';\nimport { UUID } from '../utils/uuid';\n\n/**\n * Modes for receiving remote config updates:\n * - `'all'` – Optimized for both speed and freshness. Returns the fastest response first\n * (cache or remote), then always waits for and returns the remote response to ensure\n * the most up-to-date config. Callback may be called once (if remote wins) or twice\n * (cache first, then remote).\n * - `{ timeout: number }` – Prefers remote data but with a fallback strategy. Waits for\n * a remote response until the specified timeout (in milliseconds), then falls back to\n * cached data if available. Callback is called exactly once.\n */\nexport type DeliveryMode = 'all' | { timeout: number };\n\n/**\n * Sources of returned remote config:\n * - `cache` - Fetched from local storage.\n * - `remote` - Fetched from remote.\n */\nexport type Source = 'cache' | 'remote';\n\nexport const US_SERVER_URL = 'https://sr-client-cfg.amplitude.com/config';\nexport const EU_SERVER_URL = 'https://sr-client-cfg.eu.amplitude.com/config';\nexport const DEFAULT_MAX_RETRIES = 3;\nconst CODE_STATUS = {\n INVALID_API_KEY: 401,\n RATE_LIMIT: 429,\n} as const;\n\n/**\n * The default timeout for fetch in milliseconds.\n * Linear backoff policy: timeout / retry times is the interval between fetch retry.\n */\nconst DEFAULT_TIMEOUT = 1000;\n\n/**\n * The minimum time between fetches in milliseconds.\n * This prevents too many requests from being sent in a short period of time.\n */\nconst DEFAULT_MIN_TIME_BETWEEN_FETCHES = 5 * 60 * 1000; // 5 minutes\n\nexport interface RemoteConfig {\n [key: string]: any;\n}\n\nexport interface RemoteConfigInfo {\n remoteConfig: RemoteConfig | null;\n // Timestamp of when the remote config was fetched.\n lastFetch: Date;\n}\n\nexport interface RemoteConfigStorage {\n /**\n * Fetch remote config from storage asynchronously.\n */\n fetchConfig(): Promise<RemoteConfigInfo>;\n\n /**\n * Set remote config to storage asynchronously.\n */\n setConfig(config: RemoteConfigInfo): Promise<boolean>;\n}\n\n/**\n * Information about each callback registered by `RemoteConfigClient.subscribe()`,\n * managed internally by `RemoteConfigClient`.\n */\nexport interface CallbackInfo {\n id: string;\n key?: string;\n deliveryMode: DeliveryMode;\n callback: RemoteConfigCallback;\n lastCallback?: Date;\n}\n\n/**\n * Callback used in `RemoteConfigClient.subscribe()`.\n * This function is called when the remote config is fetched.\n */\ntype RemoteConfigCallback = (remoteConfig: RemoteConfig | null, source: Source, lastFetch: Date) => void;\n\nexport interface IRemoteConfigClient {\n /**\n * Subscribe for updates to remote config.\n * Callback is guaranteed to be called at least once,\n * Whether we are able to fetch a config or not.\n *\n * @param key - a string containing a series of period delimited keys to filter the returned config.\n * Ie, {a: {b: {c: ...}}} would return {b: {c: ...}} for \"a\" or {c: ...} for \"a.b\".\n * Set to `undefined` to subscribe all keys.\n * @param deliveryMode - how the initial callback is sent.\n * @param callback - a block that will be called when remote config is fetched.\n * @return id - identification of the subscribe and can be used to unsubscribe from updates.\n */\n subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string;\n\n /**\n * Unsubscribe a callback from receiving future updates.\n *\n * @param id - identification of the callback that you want to unsubscribe.\n * It's the return value of subscribe().\n * @return boolean - whether the callback is removed.\n */\n unsubscribe(id: string): boolean;\n\n /**\n * Request the remote config client to fetch from remote, update cache, and callback.\n */\n updateConfigs(): void;\n}\n\nexport class RemoteConfigClient implements IRemoteConfigClient {\n static readonly CONFIG_GROUP = 'browser';\n\n readonly apiKey: string;\n readonly serverUrl: string;\n readonly logger: ILogger;\n readonly storage: RemoteConfigStorage;\n // Registered callbackInfos by subscribe().\n callbackInfos: CallbackInfo[] = [];\n // Track the last successful fetch time for throttling (timestamp in milliseconds).\n lastSuccessfulFetch: number | null = null;\n // Store the in-flight fetch promise for deduplication.\n fetchPromise: Promise<RemoteConfigInfo> | null = null;\n // Used to skip periodic updateConfigs calls when API key is invalid.\n isLastFetchInvalidApiKey = false;\n\n constructor(apiKey: string, logger: ILogger, serverZone: ServerZoneType = 'US', serverUrl?: string) {\n this.apiKey = apiKey;\n this.serverUrl = serverUrl || (serverZone === 'US' ? US_SERVER_URL : EU_SERVER_URL);\n this.logger = logger;\n this.storage = new RemoteConfigLocalStorage(apiKey, logger);\n }\n\n subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string {\n const id = UUID();\n const callbackInfo = {\n id: id,\n key: key,\n deliveryMode: deliveryMode,\n callback: callback,\n };\n this.callbackInfos.push(callbackInfo);\n\n if (deliveryMode === 'all') {\n void this.subscribeAll(callbackInfo);\n } else {\n void this.subscribeWaitForRemote(callbackInfo, deliveryMode.timeout);\n }\n\n return id;\n }\n\n unsubscribe(id: string): boolean {\n const index = this.callbackInfos.findIndex((callbackInfo) => callbackInfo.id === id);\n if (index === -1) {\n this.logger.debug(`Remote config client unsubscribe failed because callback with id ${id} doesn't exist.`);\n return false;\n }\n\n this.callbackInfos.splice(index, 1);\n this.logger.debug(`Remote config client unsubscribe succeeded removing callback with id ${id}.`);\n return true;\n }\n\n async updateConfigs() {\n // Check if we need to throttle based on last successful fetch time\n if (this.lastSuccessfulFetch) {\n const timeSinceLastFetch = Date.now() - this.lastSuccessfulFetch;\n if (timeSinceLastFetch < DEFAULT_MIN_TIME_BETWEEN_FETCHES) {\n this.logger.debug('Remote config client skipping updateConfigs: Too recent');\n return;\n }\n }\n\n const result = await this.getOrCreateFetchPromise();\n void this.storage.setConfig(result);\n this.callbackInfos.forEach((callbackInfo) => {\n this.sendCallback(callbackInfo, result, 'remote');\n });\n }\n\n /**\n * Get the in-flight fetch promise or create a new one.\n * This ensures multiple subscribe calls share the same network request.\n */\n getOrCreateFetchPromise(): Promise<RemoteConfigInfo> {\n if (this.fetchPromise) {\n return this.fetchPromise;\n }\n\n if (this.isLastFetchInvalidApiKey) {\n this.logger.debug('Remote config client skipping fetch: Invalid API key');\n this.fetchPromise = Promise.resolve({\n remoteConfig: null,\n lastFetch: new Date(),\n }).finally(() => {\n this.fetchPromise = null;\n });\n return this.fetchPromise;\n }\n\n this.fetchPromise = this.fetch()\n .then((result) => {\n // Update last successful fetch time if we got a valid config\n if (result.remoteConfig !== null) {\n this.lastSuccessfulFetch = Date.now();\n }\n return result;\n })\n .finally(() => {\n // Clear the promise after it settles (success or failure)\n this.fetchPromise = null;\n });\n\n return this.fetchPromise;\n }\n\n /**\n * Send remote first. If it's already complete, we can skip the cached response.\n * - if remote is fetched first, no cache fetch.\n * - if cache is fetched first, still fetching remote.\n */\n async subscribeAll(callbackInfo: CallbackInfo) {\n const remotePromise = this.getOrCreateFetchPromise().then((result) => {\n this.logger.debug(`Remote config client subscription all mode fetched from remote: ${JSON.stringify(result)}`);\n this.sendCallback(callbackInfo, result, 'remote');\n void this.storage.setConfig(result);\n });\n\n const cachePromise = this.storage.fetchConfig().then((result) => {\n return result;\n });\n\n // Wait for the first result to resolve\n const result = await Promise.race([remotePromise, cachePromise]);\n\n // If cache is fetched first, wait for remote.\n if (result !== undefined) {\n this.logger.debug(`Remote config client subscription all mode fetched from cache: ${JSON.stringify(result)}`);\n // Skip sending callback if cache is empty (first time user).\n if (result.remoteConfig !== null) {\n this.sendCallback(callbackInfo, result, 'cache');\n } else {\n this.logger.debug('Remote config client skips sending callback because cache is empty (first time user).');\n }\n }\n await remotePromise;\n }\n\n /**\n * Waits for a remote response until the given timeout, then return a cached copy, if available.\n */\n async subscribeWaitForRemote(callbackInfo: CallbackInfo, timeout: number) {\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => {\n reject('Timeout exceeded');\n }, timeout);\n });\n\n try {\n const result: RemoteConfigInfo = (await Promise.race([\n this.getOrCreateFetchPromise(),\n timeoutPromise,\n ])) as RemoteConfigInfo;\n\n this.logger.debug('Remote config client subscription wait for remote mode returns from remote.');\n this.sendCallback(callbackInfo, result, 'remote');\n void this.storage.setConfig(result);\n } catch (error) {\n this.logger.debug(\n 'Remote config client subscription wait for remote mode exceeded timeout. Try to fetch from cache.',\n );\n const result = await this.storage.fetchConfig();\n if (result.remoteConfig !== null) {\n this.logger.debug('Remote config client subscription wait for remote mode returns a cached copy.');\n this.sendCallback(callbackInfo, result, 'cache');\n } else {\n this.logger.debug('Remote config client subscription wait for remote mode failed to fetch cache.');\n this.sendCallback(callbackInfo, result, 'remote');\n }\n }\n }\n\n /**\n * Call the callback with filtered remote config based on key.\n * @param remoteConfigInfo - the whole remote config object without filtering by key.\n */\n sendCallback(callbackInfo: CallbackInfo, remoteConfigInfo: RemoteConfigInfo, source: Source) {\n callbackInfo.lastCallback = new Date();\n\n let filteredConfig: RemoteConfig | null;\n if (callbackInfo.key) {\n // Filter remote config by key.\n // For example, if remote config is {a: {b: {c: 1}}},\n // if key = 'a', filter result is {b: {c: 1}};\n // if key = 'a.b', filter result is {c: 1}\n filteredConfig = callbackInfo.key.split('.').reduce((config, key) => {\n if (config === null) {\n return config;\n }\n\n return key in config ? (config[key] as RemoteConfig) : null;\n }, remoteConfigInfo.remoteConfig);\n } else {\n filteredConfig = remoteConfigInfo.remoteConfig;\n }\n\n callbackInfo.callback(filteredConfig, source, remoteConfigInfo.lastFetch);\n }\n\n /**\n * Fetch remote config from remote.\n * @param retries - the number of retries. default is 3.\n * @param timeout - the timeout in milliseconds. Default is 1000.\n * This timeout serves two purposes:\n * 1. It determines how long to wait for each remote config fetch request before aborting it.\n * If the fetch does not complete within the specified timeout, the request is cancelled using AbortController,\n * and the attempt is considered failed (and may be retried if retries remain).\n * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,\n * so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).\n * Retry behavior by status code:\n * - 401: invalid API key (stop retries and disable future updateConfigs calls).\n * - 429: retry up to max retries.\n * - other 4xx: no retry.\n * - 5xx and network failures: retry up to max retries.\n * @returns the remote config info. null if failed to fetch or the response is not valid JSON.\n */\n async fetch(retries: number = DEFAULT_MAX_RETRIES, timeout: number = DEFAULT_TIMEOUT): Promise<RemoteConfigInfo> {\n const interval = timeout / retries;\n const failedRemoteConfigInfo: RemoteConfigInfo = {\n remoteConfig: null,\n lastFetch: new Date(),\n };\n\n for (let attempt = 0; attempt < retries; attempt++) {\n let shouldRetry = true;\n // Create AbortController for request timeout\n const abortController = new AbortController();\n const timeoutId = setTimeout(() => abortController.abort(), timeout);\n\n try {\n const res = await fetch(this.getUrlParams(), {\n method: 'GET',\n headers: {\n Accept: '*/*',\n },\n signal: abortController.signal,\n });\n\n // Handle unsuccessful fetch\n if (!res.ok) {\n const body = await res.text();\n this.logger.debug(`Remote config client fetch with retry time ${retries} failed with ${res.status}: ${body}`);\n\n if (res.status === CODE_STATUS.INVALID_API_KEY) {\n this.logger.error(\n `Remote config client fetch failed with ${CODE_STATUS.INVALID_API_KEY}. Invalid API key; future fetches will be skipped.`,\n );\n this.isLastFetchInvalidApiKey = true;\n shouldRetry = false;\n } else if (res.status >= 400 && res.status < 500 && res.status !== CODE_STATUS.RATE_LIMIT) {\n shouldRetry = false;\n }\n } else {\n // Handle successful fetch\n const remoteConfig: RemoteConfig = (await res.json()) as RemoteConfig;\n return {\n remoteConfig: remoteConfig,\n lastFetch: new Date(),\n };\n }\n } catch (error) {\n // Handle rejects when the request fails, for example, a network error or timeout\n if (error instanceof Error && error.name === 'AbortError') {\n this.logger.debug(`Remote config client fetch with retry time ${retries} timed out after ${timeout}ms`);\n } else {\n this.logger.debug(`Remote config client fetch with retry time ${retries} is rejected because: `, error);\n }\n } finally {\n // Clear the timeout since request completed or failed\n clearTimeout(timeoutId);\n }\n\n if (!shouldRetry) {\n break;\n }\n\n // Linear backoff:\n // wait for the specified interval before the next attempt\n // except after the last attempt.\n if (attempt < retries - 1) {\n await new Promise((resolve) => setTimeout(resolve, this.getJitterDelay(interval)));\n }\n }\n\n return failedRemoteConfigInfo;\n }\n\n /**\n * Return jitter in the bound of [0,baseDelay) and then floor round.\n */\n getJitterDelay(baseDelay: number): number {\n return Math.floor(Math.random() * baseDelay);\n }\n\n getUrlParams(): string {\n // URL encode the API key to handle special characters\n const encodedApiKey = encodeURIComponent(this.apiKey);\n\n const urlParams = new URLSearchParams();\n urlParams.append('config_group', RemoteConfigClient.CONFIG_GROUP);\n\n return `${this.serverUrl}/${encodedApiKey}?${urlParams.toString()}`;\n }\n}\n"]}
@@ -2,6 +2,7 @@ import { Storage, CookieStorageOptions, CookieStorageConfig } from '../types/sto
2
2
  export declare class CookieStorage<T> implements Storage<T> {
3
3
  options: CookieStorageOptions;
4
4
  config: CookieStorageConfig;
5
+ private static cachedTlds;
5
6
  constructor(options?: CookieStorageOptions, config?: CookieStorageConfig);
6
7
  isEnabled(): Promise<boolean>;
7
8
  get(key: string): Promise<T | undefined>;
@@ -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;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
+ {"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;IAE5B,OAAO,CAAC,MAAM,CAAC,UAAU,CAA+B;gBAE5C,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;YA+BjD,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"}
@@ -253,6 +253,9 @@ var CookieStorage = /** @class */ (function () {
253
253
  return __generator(this, function (_a) {
254
254
  switch (_a.label) {
255
255
  case 0:
256
+ if (CookieStorage.cachedTlds[domain]) {
257
+ return [2 /*return*/, true];
258
+ }
256
259
  options = {
257
260
  domain: '.' + domain,
258
261
  };
@@ -262,9 +265,16 @@ var CookieStorage = /** @class */ (function () {
262
265
  case 1:
263
266
  _a.trys.push([1, 3, , 4]);
264
267
  return [4 /*yield*/, storage.transaction(storageKey, function (storageSync) {
268
+ if (CookieStorage.cachedTlds[domain]) {
269
+ return true;
270
+ }
265
271
  try {
266
272
  storageSync.set(1);
267
- return storageSync.get();
273
+ var result = !!storageSync.get();
274
+ if (result) {
275
+ CookieStorage.cachedTlds[domain] = true;
276
+ }
277
+ return result;
268
278
  }
269
279
  finally {
270
280
  storageSync.set(null);
@@ -309,6 +319,7 @@ var CookieStorage = /** @class */ (function () {
309
319
  });
310
320
  });
311
321
  };
322
+ CookieStorage.cachedTlds = {};
312
323
  return CookieStorage;
313
324
  }());
314
325
  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, 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"]}
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 private static cachedTlds: Record<string, boolean> = {};\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 if (CookieStorage.cachedTlds[domain]) {\n return true;\n }\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 if (CookieStorage.cachedTlds[domain]) {\n return true;\n }\n try {\n storageSync.set(1);\n const result = !!storageSync.get();\n if (result) {\n CookieStorage.cachedTlds[domain] = true;\n }\n return result;\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"]}
@@ -1,5 +1,5 @@
1
- export { Observable } from 'zen-observable-ts';
2
- import { Observable as ZenObservable } from 'zen-observable-ts';
1
+ import ZenObservable from 'zen-observable';
2
+ export { ZenObservable as Observable };
3
3
  /**
4
4
  * asyncMap operator for Zen Observable
5
5
  *
@@ -1 +1 @@
1
- {"version":3,"file":"observable.d.ts","sourceRoot":"","sources":["../../../src/utils/observable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,EAAE,UAAU,IAAI,aAAa,EAA0B,MAAM,mBAAmB,CAAC;AAExF;;;;;GAKG;AACH,iBAAS,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAoBpG;AAED,KAAK,cAAc,GAAG;IACpB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF;;;;;;;GAOG;AACH,iBAAS,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAgD/F;AAGD,iBAAS,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAkDhE;AAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"observable.d.ts","sourceRoot":"","sources":["../../../src/utils/observable.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,aAAa,IAAI,UAAU,EAAE,CAAC;AAgBvC;;;;;GAKG;AACH,iBAAS,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAoBpG;AAED,KAAK,cAAc,GAAG;IACpB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAIF;;;;;;;GAOG;AACH,iBAAS,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAgD/F;AAGD,iBAAS,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAkDhE;AAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { __values } from "tslib";
2
- export { Observable } from 'zen-observable-ts';
3
- import { Observable as ZenObservable } from 'zen-observable-ts';
2
+ import ZenObservable from 'zen-observable';
3
+ export { ZenObservable as Observable };
4
4
  /**
5
5
  * asyncMap operator for Zen Observable
6
6
  *
@@ -1 +1 @@
1
- {"version":3,"file":"observable.js","sourceRoot":"","sources":["../../../src/utils/observable.ts"],"names":[],"mappings":"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","sourcesContent":["export { Observable } from 'zen-observable-ts';\n\nimport { Observable as ZenObservable, Observer, Subscription } from 'zen-observable-ts';\n\n/**\n * asyncMap operator for Zen Observable\n *\n * Maps each value emitted by the source Observable using an async function,\n * emitting the resolved values in the same order they arrive.\n */\nfunction asyncMap<T, R>(observable: ZenObservable<T>, fn: (value: T) => Promise<R>): ZenObservable<R> {\n return new ZenObservable(\n (observer: { next: (value: R) => void; error: (error: any) => void; complete: () => void }) => {\n observable.subscribe({\n next: (value: T) => {\n fn(value)\n .then((result: R) => {\n return observer.next(result);\n })\n .catch((error: any) => observer.error(error));\n },\n error: (error: any) => {\n observer.error(error);\n },\n complete: () => {\n observer.complete();\n },\n });\n },\n );\n}\n\ntype Unsubscribable = {\n unsubscribe: () => void;\n};\n\n/**\n * merge operator for Zen Observable\n *\n * Merges two observables into a single observable, emitting values from both sources in the order they arrive.\n * @param sourceA Observable to merge\n * @param sourceB Observable to merge\n * @returns Unsubscribable cleanup function\n */\nfunction merge<A, B>(sourceA: ZenObservable<A>, sourceB: ZenObservable<B>): ZenObservable<A | B> {\n return new ZenObservable<A | B>((observer) => {\n let closed = false;\n\n const subscriptions: Set<Unsubscribable> = new Set();\n\n const cleanup = (): void => {\n closed = true;\n for (const sub of subscriptions) {\n try {\n sub.unsubscribe();\n } catch {\n /* do nothing */\n }\n }\n subscriptions.clear();\n };\n\n const subscribeTo = <T>(source: ZenObservable<T>) => {\n const sub = source.subscribe({\n next(value: T) {\n if (!closed) observer.next(value as A | B);\n },\n error(err) {\n if (!closed) {\n closed = true;\n observer.error(err);\n cleanup();\n }\n },\n complete() {\n subscriptions.delete(sub);\n if (!closed && subscriptions.size === 0) {\n observer.complete();\n cleanup();\n closed = true;\n }\n },\n });\n\n subscriptions.add(sub);\n };\n\n subscribeTo(sourceA);\n subscribeTo(sourceB);\n\n return cleanup;\n });\n}\n\n// function share() {\nfunction multicast<T>(source: ZenObservable<T>): ZenObservable<T> {\n const observers: Set<Observer<T>> = new Set();\n let subscription: Subscription | null = null;\n\n function cleanup() {\n /* istanbul ignore next */\n subscription?.unsubscribe();\n subscription = null;\n observers.clear();\n }\n\n return new ZenObservable<T>((observer) => {\n observers.add(observer);\n\n if (subscription === null) {\n subscription = source.subscribe({\n next(value) {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.next?.(value);\n }\n },\n error(err) {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.error?.(err);\n }\n cleanup();\n },\n complete() {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.complete?.();\n }\n cleanup();\n },\n });\n }\n\n // Return unsubscribe function for this observer\n return () => {\n observers.delete(observer);\n\n // If no observers left, unsubscribe from the source\n if (observers.size === 0 && subscription) {\n subscription.unsubscribe();\n subscription = null;\n }\n };\n });\n}\n\nexport { asyncMap, multicast, merge, Unsubscribable };\n"]}
1
+ {"version":3,"file":"observable.js","sourceRoot":"","sources":["../../../src/utils/observable.ts"],"names":[],"mappings":"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","sourcesContent":["import ZenObservable from 'zen-observable';\n\nexport { ZenObservable as Observable };\n\n/** Subscription type for zen-observable */\ninterface Subscription {\n closed: boolean;\n unsubscribe(): void;\n}\n\n/** Observer type for zen-observable */\ninterface Observer<T> {\n start?(subscription: Subscription): unknown;\n next?(value: T): void;\n error?(errorValue: unknown): void;\n complete?(): void;\n}\n\n/**\n * asyncMap operator for Zen Observable\n *\n * Maps each value emitted by the source Observable using an async function,\n * emitting the resolved values in the same order they arrive.\n */\nfunction asyncMap<T, R>(observable: ZenObservable<T>, fn: (value: T) => Promise<R>): ZenObservable<R> {\n return new ZenObservable(\n (observer: { next: (value: R) => void; error: (error: any) => void; complete: () => void }) => {\n observable.subscribe({\n next: (value: T) => {\n fn(value)\n .then((result: R) => {\n return observer.next(result);\n })\n .catch((error: any) => observer.error(error));\n },\n error: (error: any) => {\n observer.error(error);\n },\n complete: () => {\n observer.complete();\n },\n });\n },\n );\n}\n\ntype Unsubscribable = {\n unsubscribe: () => void;\n};\n\ntype ZenObserver<A, B> = { next: (v: A | B) => void; error: (e: unknown) => void; complete: () => void };\n\n/**\n * merge operator for Zen Observable\n *\n * Merges two observables into a single observable, emitting values from both sources in the order they arrive.\n * @param sourceA Observable to merge\n * @param sourceB Observable to merge\n * @returns Unsubscribable cleanup function\n */\nfunction merge<A, B>(sourceA: ZenObservable<A>, sourceB: ZenObservable<B>): ZenObservable<A | B> {\n return new ZenObservable<A | B>((observer: ZenObserver<A, B>) => {\n let closed = false;\n\n const subscriptions: Set<Unsubscribable> = new Set();\n\n const cleanup = (): void => {\n closed = true;\n for (const sub of subscriptions) {\n try {\n sub.unsubscribe();\n } catch {\n /* do nothing */\n }\n }\n subscriptions.clear();\n };\n\n const subscribeTo = <T>(source: ZenObservable<T>) => {\n const sub = source.subscribe({\n next(value: T) {\n if (!closed) observer.next(value as A | B);\n },\n error(err: unknown) {\n if (!closed) {\n closed = true;\n observer.error(err);\n cleanup();\n }\n },\n complete() {\n subscriptions.delete(sub);\n if (!closed && subscriptions.size === 0) {\n observer.complete();\n cleanup();\n closed = true;\n }\n },\n });\n\n subscriptions.add(sub);\n };\n\n subscribeTo(sourceA);\n subscribeTo(sourceB);\n\n return cleanup;\n });\n}\n\n// function share() {\nfunction multicast<T>(source: ZenObservable<T>): ZenObservable<T> {\n const observers: Set<Observer<T>> = new Set();\n let subscription: Subscription | null = null;\n\n function cleanup() {\n /* istanbul ignore next */\n subscription?.unsubscribe();\n subscription = null;\n observers.clear();\n }\n\n return new ZenObservable<T>((observer: Observer<T>) => {\n observers.add(observer);\n\n if (subscription === null) {\n subscription = source.subscribe({\n next(value: T) {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.next?.(value);\n }\n },\n error(err: unknown) {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.error?.(err);\n }\n cleanup();\n },\n complete() {\n for (const obs of observers) {\n /* istanbul ignore next */\n obs.complete?.();\n }\n cleanup();\n },\n });\n }\n\n // Return unsubscribe function for this observer\n return () => {\n observers.delete(observer);\n\n // If no observers left, unsubscribe from the source\n if (observers.size === 0 && subscription) {\n subscription.unsubscribe();\n subscription = null;\n }\n };\n });\n}\n\nexport { asyncMap, multicast, merge, Unsubscribable };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"safe-stringify.d.ts","sourceRoot":"","sources":["../../../src/utils/safe-stringify.ts"],"names":[],"mappings":"AAKA,KAAK,mBAAmB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,KAAK,MAAM,CAAC;AAC7F,QAAA,MAAM,iBAAiB,EAAE,mBACqD,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"safe-stringify.d.ts","sourceRoot":"","sources":["../../../src/utils/safe-stringify.ts"],"names":[],"mappings":"AAKA,KAAK,mBAAmB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,KAAK,MAAM,CAAC;AAE7F,QAAA,MAAM,iBAAiB,EAAE,mBACqD,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3
3
  import * as safeJsonStringifyModule from 'safe-json-stringify';
4
+ /* istanbul ignore next */
4
5
  var safeJsonStringify = safeJsonStringifyModule.default || safeJsonStringifyModule;
5
6
  export { safeJsonStringify };
6
7
  //# sourceMappingURL=safe-stringify.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"safe-stringify.js","sourceRoot":"","sources":["../../../src/utils/safe-stringify.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,+DAA+D;AAC/D,OAAO,KAAK,uBAAuB,MAAM,qBAAqB,CAAC;AAI/D,IAAM,iBAAiB,GACpB,uBAA+B,CAAC,OAAO,IAAK,uBAA+B,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,CAAC","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport * as safeJsonStringifyModule from 'safe-json-stringify';\n\n// do a simple, typed re-export of \"safe-json-stringify\"\ntype SafeJsonStringifyFn = (data: object, replacer?: any, space?: string | number) => string;\nconst safeJsonStringify: SafeJsonStringifyFn =\n (safeJsonStringifyModule as any).default || (safeJsonStringifyModule as any);\n\nexport { safeJsonStringify };\n"]}
1
+ {"version":3,"file":"safe-stringify.js","sourceRoot":"","sources":["../../../src/utils/safe-stringify.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,+DAA+D;AAC/D,OAAO,KAAK,uBAAuB,MAAM,qBAAqB,CAAC;AAI/D,0BAA0B;AAC1B,IAAM,iBAAiB,GACpB,uBAA+B,CAAC,OAAO,IAAK,uBAA+B,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,CAAC","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport * as safeJsonStringifyModule from 'safe-json-stringify';\n\n// do a simple, typed re-export of \"safe-json-stringify\"\ntype SafeJsonStringifyFn = (data: object, replacer?: any, space?: string | number) => string;\n/* istanbul ignore next */\nconst safeJsonStringify: SafeJsonStringifyFn =\n (safeJsonStringifyModule as any).default || (safeJsonStringifyModule as any);\n\nexport { safeJsonStringify };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amplitude/analytics-core",
3
- "version": "2.41.2",
3
+ "version": "2.41.4-SR-2728.0",
4
4
  "description": "",
5
5
  "author": "Amplitude Inc",
6
6
  "homepage": "https://github.com/amplitude/Amplitude-TypeScript",
@@ -22,9 +22,10 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@amplitude/analytics-connector": "^1.6.4",
25
+ "@types/zen-observable": "0.8.3",
25
26
  "safe-json-stringify": "1.2.0",
26
27
  "tslib": "^2.4.1",
27
- "zen-observable-ts": "^1.1.0"
28
+ "zen-observable": "0.10.0"
28
29
  },
29
30
  "files": [
30
31
  "lib"