"use strict"; var __webpack_require__ = {}; (()=>{ __webpack_require__.d = (exports1, definition)=>{ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, { enumerable: true, get: definition[key] }); }; })(); (()=>{ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop); })(); (()=>{ __webpack_require__.r = (exports1)=>{ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, { value: 'Module' }); Object.defineProperty(exports1, '__esModule', { value: true }); }; })(); var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { PackageType: ()=>PackageType, PushType: ()=>PushType, DynamicConfigClient: ()=>DynamicConfigClient, RequestCache: ()=>RequestCache, getBrowserCrypto: ()=>getBrowserCrypto, ProductCode: ()=>ProductCode }); function _define_property(obj, key, value) { if (key in obj) Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); else obj[key] = value; return obj; } const MIN_CACHE_DURATION = 300000; class RequestCache { generateCacheKey(params) { return params.filter(([, value])=>null != value && '' !== value).sort(([a], [b])=>a.localeCompare(b)).map(([key, value])=>`${key}=${value}`).join('&'); } get(params) { const key = this.generateCacheKey(params); const cached = this._cache.get(key); if (cached && cached.expire > Date.now()) return { success: true, value: cached.value }; if (cached) { this._cache.delete(key); const timer = this._timers.get(key); if (timer) { clearTimeout(timer); this._timers.delete(key); } } return { success: false, value: null }; } set(params, value) { const key = this.generateCacheKey(params); const existingTimer = this._timers.get(key); if (existingTimer) clearTimeout(existingTimer); this._cache.set(key, { value, expire: Date.now() + this._cacheDuration }); const timer = setTimeout(()=>{ this._cache.delete(key); this._timers.delete(key); }, this._cacheDuration); this._timers.set(key, timer); } clear(params) { if (params) { const key = this.generateCacheKey(params); const timer = this._timers.get(key); if (timer) { clearTimeout(timer); this._timers.delete(key); } this._cache.delete(key); } else { this._timers.forEach((timer)=>clearTimeout(timer)); this._timers.clear(); this._cache.clear(); } } dispose() { this.clear(); } constructor(cacheDuration = MIN_CACHE_DURATION){ _define_property(this, "_cache", new Map()); _define_property(this, "_timers", new Map()); _define_property(this, "_cacheDuration", void 0); this._cacheDuration = Math.max(cacheDuration, MIN_CACHE_DURATION); } } const decodeBase64 = (base64)=>Uint8Array.from(atob(base64), (c)=>c.charCodeAt(0)); const getBrowserCrypto = ()=>{ var _globalThis_crypto, _window_crypto; if ('undefined' != typeof globalThis && (null == (_globalThis_crypto = globalThis.crypto) ? void 0 : _globalThis_crypto.subtle)) return globalThis.crypto; if ('undefined' != typeof window && (null == (_window_crypto = window.crypto) ? void 0 : _window_crypto.subtle)) return window.crypto; return null; }; const decompressGzip = async (data)=>{ const ds = new DecompressionStream('gzip'); const blob = new Blob([ data.slice().buffer ]); const decompressedStream = blob.stream().pipeThrough(ds); return new Response(decompressedStream).text(); }; const decodeConfig = async (base64, key, iv, crypto)=>{ const encrypted = decodeBase64(base64); const keyData = new TextEncoder().encode(key); const ivData = new TextEncoder().encode(iv); const cryptoKey = await crypto.subtle.importKey('raw', keyData, { name: 'AES-CTR' }, false, [ 'decrypt' ]); const decrypted = await crypto.subtle.decrypt({ name: 'AES-CTR', counter: ivData, length: 128 }, cryptoKey, encrypted.buffer); const decompressedText = await decompressGzip(new Uint8Array(decrypted)); return JSON.parse(decompressedText); }; const ProductCode = { TRAE: 'TRAE', SOLO_Lite: 'SOLO_Lite', SOLO_Web: 'SOLO_Web', REMOTE_AGENT: 'REMOTE_AGENT' }; const PackageType = { LOCAL_CN: 'local_cn', DEV_CN: 'dev_cn', ALPHA_CN: 'alpha_cn', BETA_CN: 'beta_cn', STABLE_CN: 'stable_cn', LOCAL_I18N: 'local_i18n', DEV_I18N: 'dev_i18n', ALPHA_I18N: 'alpha_i18n', BETA_I18N: 'beta_i18n', STABLE_I18N: 'stable_i18n', BOE: 'boe', PROD: 'prod' }; const PushType = { CONFIG_UPDATE: 'configUpdate', DEVICE_LOG: 'deviceLog', AUDIT_RESULT: 'auditResult' }; function client_define_property(obj, key, value) { if (key in obj) Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); else obj[key] = value; return obj; } const CONFIG_QUERY_PATH = '/icube/api/v1/native/config/query'; function wrapGlobalFetch() { if ('undefined' != typeof globalThis && globalThis.fetch) return async (url, init)=>{ const response = await globalThis.fetch(url, init); return { status: response.status, json: ()=>response.json(), headers: { get: (name)=>response.headers.get(name) } }; }; } class DynamicConfigClient { get endpoint() { return this._endpoint; } set endpoint(value) { this._endpoint = value; this._cache.clear(); if (this._pendingRefreshTimer) { clearTimeout(this._pendingRefreshTimer); this._pendingRefreshTimer = null; } this._lastQueryParams = null; } get defaultHeaders() { return { ...this._defaultHeaders }; } get lastQueryParams() { return this._lastQueryParams ? { ...this._lastQueryParams } : null; } async queryConfig(params) { var _this__logger; this._lastQueryParams = params; const queryParams = this.buildQueryParams(params); const cacheResult = this._cache.get(queryParams); if (null == cacheResult ? void 0 : cacheResult.success) { var _this__logger1; null == (_this__logger1 = this._logger) || _this__logger1.info('[DynamicConfigClient] cache hit'); return cacheResult.value; } const url = this.buildUrl(queryParams); const cacheKey = url; const cachedEtag = this._etagCache.get(cacheKey); const headers = this.buildHeaders(params.headers, null == cachedEtag ? void 0 : cachedEtag.etag); null == (_this__logger = this._logger) || _this__logger.info('[DynamicConfigClient] request url:', url); try { var _this__logger2, _this__logger3, _response_headers, _response_headers1; const response = await this._fetch(url, { method: 'GET', headers }); null == (_this__logger2 = this._logger) || _this__logger2.info('[DynamicConfigClient] response status:', response.status); if (304 === response.status && cachedEtag) { var _this__logger4; null == (_this__logger4 = this._logger) || _this__logger4.info('[DynamicConfigClient] 304 Not Modified, using cached data'); this._cache.set(queryParams, cachedEtag.data); return cachedEtag.data; } const result = await response.json(); const isSuccess = 0 === result.code || true === result.success; null == (_this__logger3 = this._logger) || _this__logger3.info('[DynamicConfigClient] response result:', { code: result.code, success: result.success, message: result.message, hasData: !!result.data, isSuccess }); if (200 !== response.status) throw new Error(result.message || `HTTP ${response.status}`); if (!isSuccess) throw new Error(result.message || 'Request failed'); if ('string' == typeof (null == result ? void 0 : result.data)) try { result.data = await decodeConfig(result.data, this._key, this._iv, this._crypto); } catch (error) { try { result.data = JSON.parse(result.data); } catch {} } const etag = (null == (_response_headers = response.headers) ? void 0 : _response_headers.get('etag')) || (null == (_response_headers1 = response.headers) ? void 0 : _response_headers1.get('ETag')); if (etag) { var _this__logger5; this._etagCache.set(cacheKey, { etag, data: result }); null == (_this__logger5 = this._logger) || _this__logger5.info('[DynamicConfigClient] cached etag:', etag); } this._cache.set(queryParams, result); return result; } catch (error) { var _this__logger6; null == (_this__logger6 = this._logger) || _this__logger6.error('[DynamicConfigClient] fetch error:', error); throw error; } } handleEvent(event, data) { if (event === PushType.CONFIG_UPDATE) this.scheduleConfigRefresh(); if (this._onEvent) this._onEvent(event, data); } scheduleConfigRefresh() { if (this._pendingRefreshTimer) clearTimeout(this._pendingRefreshTimer); if (this._refreshRandomDelay <= 0) return void this.doConfigRefresh(); const delay = Math.floor(Math.random() * this._refreshRandomDelay); this._pendingRefreshTimer = setTimeout(()=>{ this.doConfigRefresh(); this._pendingRefreshTimer = null; }, delay); } async doConfigRefresh() { this._cache.clear(); if (!this._lastQueryParams) return; const result = await this.queryConfig(this._lastQueryParams); if (this._onConfigRefresh) this._onConfigRefresh(result); } async refresh() { this._cache.clear(); if (!this._lastQueryParams) return null; return await this.queryConfig(this._lastQueryParams); } buildQueryParams(params) { const { headers: _, ...rest } = params; return Object.entries(rest).filter(([, value])=>null != value && '' !== value).map(([key, value])=>[ key, String(value) ]); } buildUrl(params) { const queryString = params.filter(([, value])=>null != value && '' !== value).map(([key, value])=>`${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&'); return `${this._endpoint}${CONFIG_QUERY_PATH}${queryString ? `?${queryString}` : ''}`; } buildHeaders(requestHeaders, etag) { const headers = { 'Content-Type': 'application/json', ...this._defaultHeaders, ...requestHeaders }; if (etag) headers['If-None-Match'] = etag; return headers; } clearCache() { this._cache.clear(); this._etagCache.clear(); } dispose() { if (this._pendingRefreshTimer) { clearTimeout(this._pendingRefreshTimer); this._pendingRefreshTimer = null; } this._cache.dispose(); this._onConfigRefresh = null; this._onEvent = null; this._lastQueryParams = null; this._key = ''; this._iv = ''; } constructor(options){ var _options_id; client_define_property(this, "_endpoint", void 0); client_define_property(this, "_fetch", void 0); client_define_property(this, "_crypto", void 0); client_define_property(this, "_defaultHeaders", void 0); client_define_property(this, "_cache", void 0); client_define_property(this, "_refreshRandomDelay", void 0); client_define_property(this, "_logger", null); client_define_property(this, "_onConfigRefresh", null); client_define_property(this, "_onEvent", null); client_define_property(this, "_lastQueryParams", null); client_define_property(this, "_pendingRefreshTimer", null); client_define_property(this, "_key", void 0); client_define_property(this, "_iv", void 0); client_define_property(this, "_etagCache", new Map()); this._endpoint = options.endpoint.replace(/\/$/, ''); this._fetch = options.fetch || wrapGlobalFetch(); this._defaultHeaders = options.defaultHeaders || {}; this._cache = new RequestCache(); this._refreshRandomDelay = options.refreshRandomDelay ?? 0; this._logger = options.logger || null; this._onConfigRefresh = options.onConfigRefresh || null; this._onEvent = options.onEvent || null; const [key, iv] = null == options ? void 0 : null == (_options_id = options.id) ? void 0 : _options_id.split('::'); this._key = key; this._iv = iv; if (!key || !iv) throw new Error('id is not valid. Please provide a valid id.'); const crypto = options.crypto || getBrowserCrypto(); if (!crypto) throw new Error('crypto is not available. Please provide a crypto implementation or ensure Web Crypto API / Node.js crypto module is available.'); this._crypto = crypto; if (!this._fetch) throw new Error('fetch is not available. Please provide a fetch implementation.'); } } exports.DynamicConfigClient = __webpack_exports__.DynamicConfigClient; exports.PackageType = __webpack_exports__.PackageType; exports.ProductCode = __webpack_exports__.ProductCode; exports.PushType = __webpack_exports__.PushType; exports.RequestCache = __webpack_exports__.RequestCache; exports.getBrowserCrypto = __webpack_exports__.getBrowserCrypto; for(var __webpack_i__ in __webpack_exports__)if (-1 === [ "DynamicConfigClient", "PackageType", "ProductCode", "PushType", "RequestCache", "getBrowserCrypto" ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__]; Object.defineProperty(exports, '__esModule', { value: true });