UNPKG

hp-app-bundle-sdk

Version:

A comprehensive SDK for building mini-applications.

1,372 lines (1,355 loc) 416 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const SDK_VERSION$1 = "1.0.0"; const DEFAULT_CONFIG = { core: { autoInitialize: true, logLevel: "warn", enableAnalytics: false, apiEndpoints: { auth: "https://api.example.com/auth", payment: "https://api.example.com/payment", storage: "https://api.example.com/storage", }, platformOverrides: { android: { intentHandling: "native", backButtonBehavior: "default", encryptionLevel: "software", }, ios: { statusBarStyle: "dark", modalPresentationStyle: "fullScreen", biometricAuth: "none", }, web: { storageType: "localStorage", authRedirectStrategy: "redirect", offlineSupport: false, }, }, }, constants: { baseUrls: { authService: "https://auth.example.com", apiGateway: "", paymentService: "https://pay.example.com", }, timeouts: { apiRequest: 30000, authTokenRefresh: 300000, }, features: { useLegacyAuth: false, enableExperimental: false, }, }, }; const PLATFORM = { ANDROID: "android", IOS: "ios", WEB: "web", BROWSER: "browser", // Add browser constant }; class ConfigManager { constructor(clientConfig) { this.config = this.deepMerge(DEFAULT_CONFIG, clientConfig || {}); } deepMerge(target, source) { if (typeof target !== "object" || typeof source !== "object") { return source !== null && source !== void 0 ? source : target; } const result = { ...target }; for (const key of Object.keys(source)) { if (source[key] instanceof Object && key in target) { result[key] = this.deepMerge(target[key], source[key]); } else { result[key] = source[key]; } } return result; } getCoreConfig() { return this.config.core; } getConstants() { return this.config.constants; } getApiEndpoint(service) { var _a, _b, _c, _d; const endpoint = (_b = (_a = this.config.core) === null || _a === void 0 ? void 0 : _a.apiEndpoints) === null || _b === void 0 ? void 0 : _b[service]; if (endpoint) return endpoint; const baseUrlKey = `${service}Service`; const baseUrl = (_d = (_c = this.config.constants) === null || _c === void 0 ? void 0 : _c.baseUrls) === null || _d === void 0 ? void 0 : _d[baseUrlKey]; return baseUrl ? `${baseUrl}/api/v1` : undefined; } getTimeout(key) { var _a, _b, _c; return (_c = (_b = (_a = this.config.constants) === null || _a === void 0 ? void 0 : _a.timeouts) === null || _b === void 0 ? void 0 : _b[key]) !== null && _c !== void 0 ? _c : 30000; } getFeatureFlag(key) { var _a, _b; return !!((_b = (_a = this.config.constants) === null || _a === void 0 ? void 0 : _a.features) === null || _b === void 0 ? void 0 : _b[key]); } updateConfig(updates) { this.config = this.deepMerge(this.config, updates); } } class EventManager { constructor() { this.listeners = new Map(); } on(event, handler) { if (!this.listeners.has(event)) { this.listeners.set(event, new Set()); } const handlers = this.listeners.get(event); handlers.add(handler); // cast optional if you want return () => this.off(event, handler); } off(event, handler) { var _a; (_a = this.listeners.get(event)) === null || _a === void 0 ? void 0 : _a.delete(handler); } emit(event, detail) { var _a; const eventObj = new CustomEvent(event, { detail }); (_a = this.listeners.get(event)) === null || _a === void 0 ? void 0 : _a.forEach((handler) => { try { handler(eventObj); } catch (error) { console.error(`Error in event handler for ${event}:`, error); } }); } once(event, handler) { const onceHandler = (evt) => { this.off(event, onceHandler); handler(evt); }; this.on(event, onceHandler); } removeAllListeners(event) { if (event) { this.listeners.delete(event); } else { this.listeners.clear(); } } } class NativeBridge { constructor(miniapp, platformOverrides) { this.miniapp = miniapp; this.platformOverrides = platformOverrides; } get platform() { var _a, _b; if (typeof window === "undefined") return PLATFORM.WEB; if (window.Hamropatro_MiniApp_Interface) return PLATFORM.ANDROID; if ((_b = (_a = window.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.Hamropatro_MiniApp_Interface) return PLATFORM.IOS; return PLATFORM.WEB; } async postMessage(message) { return new Promise((resolve, reject) => { var _a, _b, _c, _d; if (this.platform === PLATFORM.WEB) { this.handleWebMessage(message).then(resolve).catch(reject); return; } if (message.result) { this.miniapp.events.once(message.result, (e) => { const response = e.detail; if (response === null || response === void 0 ? void 0 : response.error) { reject(response.error); } else { // Proper type assertion here resolve(response === null || response === void 0 ? void 0 : response.data); } }); } try { const messageString = JSON.stringify(message); if (this.platform === PLATFORM.ANDROID) { (_a = window.Hamropatro_MiniApp_Interface) === null || _a === void 0 ? void 0 : _a.postMessage(messageString); } else { (_d = (_c = (_b = window.webkit) === null || _b === void 0 ? void 0 : _b.messageHandlers) === null || _c === void 0 ? void 0 : _c.Hamropatro_MiniApp_Interface) === null || _d === void 0 ? void 0 : _d.postMessage(messageString); } } catch (error) { reject({ code: "BRIDGE_ERROR", message: "Failed to post message to native bridge", error, }); } }); } async handleWebMessage(message) { switch (message.name) { case "init": return this.handleWebInit(message.params); default: throw { code: "UNSUPPORTED_OPERATION", message: `Operation ${message.name} not supported in web`, }; } } async handleWebInit(params) { return { mini_app_id: params.miniAppId, host_version: SDK_VERSION$1, }; } } class ContactManager { constructor(miniapp, config = {}) { this.miniapp = miniapp; this.config = { requestPermissionOnInit: true, defaultFields: ["name", "phoneNumbers"], ...config, }; if (this.config.requestPermissionOnInit) { this.initialize(); } } async initialize() { try { await this.checkPermission(); } catch (error) { console.warn("Contacts permission check failed:", error); } } async checkPermission() { if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { return this.handleBrowserPermissionCheck(); } return this.handleNativePermissionCheck(); } async requestPermission() { if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { return this.handleBrowserPermissionRequest(); } return this.handleNativePermissionRequest(); } async getContacts(fields) { const fieldsToFetch = fields || this.config.defaultFields; if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { return this.handleBrowserGetContacts(fieldsToFetch); } return this.handleNativeGetContacts(fieldsToFetch); } async getContactById(id, fields) { const fieldsToFetch = fields || this.config.defaultFields; if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { const contacts = await this.getContacts(fieldsToFetch); return contacts.find((c) => c.id === id) || null; } return this.handleNativeGetContactById(id, fieldsToFetch); } async searchContacts(query, fields) { const fieldsToFetch = fields || this.config.defaultFields; if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { const contacts = await this.getContacts(fieldsToFetch); return contacts.filter((c) => c.name.toLowerCase().includes(query.toLowerCase()) || c.phoneNumbers.some((pn) => pn.number.includes(query)) || (c.emails && c.emails.some((e) => e.address.toLowerCase().includes(query.toLowerCase())))); } return this.handleNativeSearchContacts(query, fieldsToFetch); } // Browser-specific implementations async handleBrowserPermissionCheck() { if (!("contacts" in navigator)) { return { granted: false, canAskAgain: false, status: "denied", }; } try { // @ts-ignore - contacts API is experimental const status = await navigator.permissions.query({ name: "contacts" }); return { granted: status.state === "granted", canAskAgain: status.state === "prompt", status: status.state === "granted" ? "granted" : "denied", }; } catch { return { granted: false, canAskAgain: false, status: "denied", }; } } async handleBrowserPermissionRequest() { try { // @ts-ignore - contacts API is experimental const contacts = await navigator.contacts.select(["name", "email"], { multiple: true, }); return { granted: !!contacts, canAskAgain: true, status: contacts ? "granted" : "denied", }; } catch (error) { return { granted: false, canAskAgain: false, status: "denied", }; } } async handleBrowserGetContacts(fields) { try { // @ts-ignore - contacts API is experimental const contacts = await navigator.contacts.select(fields, { multiple: true, }); return contacts || []; } catch (error) { throw new Error("Failed to get contacts: " + (error instanceof Error ? error.message : String(error))); } } // Native-specific implementations async handleNativePermissionCheck() { return new Promise((resolve, reject) => { const requestObject = JSON.stringify({ name: "contacts.checkPermission", params: {}, result: "onContactsPermissionChecked", }); this.postNativeMessage(requestObject); myEventTarget.addEventListener("onContactsPermissionChecked", (e) => { const response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } async handleNativePermissionRequest() { return new Promise((resolve, reject) => { const requestObject = JSON.stringify({ name: "contacts.requestPermission", params: {}, result: "onContactsPermissionRequested", }); this.postNativeMessage(requestObject); myEventTarget.addEventListener("onContactsPermissionRequested", (e) => { const response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } async handleNativeGetContacts(fields) { return new Promise((resolve, reject) => { const requestObject = JSON.stringify({ name: "contacts.getAll", params: { fields }, result: "onContactsReceived", }); this.postNativeMessage(requestObject); myEventTarget.addEventListener("onContactsReceived", (e) => { const response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } async handleNativeGetContactById(id, fields) { return new Promise((resolve, reject) => { const requestObject = JSON.stringify({ name: "contacts.getById", params: { id, fields }, result: "onContactReceived", }); this.postNativeMessage(requestObject); myEventTarget.addEventListener("onContactReceived", (e) => { const response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } async handleNativeSearchContacts(query, fields) { return new Promise((resolve, reject) => { const requestObject = JSON.stringify({ name: "contacts.search", params: { query, fields }, result: "onContactsSearchResult", }); this.postNativeMessage(requestObject); myEventTarget.addEventListener("onContactsSearchResult", (e) => { const response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } postNativeMessage(message) { var _a, _b; if (this.miniapp.getPlatform() === PLATFORM.ANDROID) { window.Hamropatro_MiniApp_Interface.postMessage(message); } else if (this.miniapp.getPlatform() === PLATFORM.IOS) { (_b = (_a = window === null || window === void 0 ? void 0 : window.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.Hamropatro_MiniApp_Interface.postMessage(message); } else { throw new Error("Unsupported platform"); } } } const DEFAULT_CONTACTS_CONFIG = { requestPermissionOnInit: true, defaultFields: ["name", "phoneNumbers"], }; // Module implementation const ContactsModule = { name: "contacts", defaultConfig: DEFAULT_CONTACTS_CONFIG, install: (miniapp, config) => new ContactManager(miniapp, config), }; class PaymentManager { constructor(miniapp, config = {}) { this.miniapp = miniapp; this.config = { defaultCurrency: "NPR", autoVerify: true, verificationTimeout: 30000, ...config, }; } async makePayment(request) { const platform = this.miniapp.getPlatform(); const currency = request.currency || this.config.defaultCurrency; if (platform === "browser") { return this.handleBrowserPayment(request); } return this.handleNativePayment({ ...request, currency, }); } async verifyPayment(referenceId) { const platform = this.miniapp.getPlatform(); if (platform === "browser") { return this.handleBrowserVerification(referenceId); } return this.handleNativeVerification(referenceId); } async getPaymentHistory(options = {}) { const platform = this.miniapp.getPlatform(); if (platform === "browser") { return this.handleBrowserPaymentHistory(options); } return this.handleNativePaymentHistory(options); } // Browser-specific implementations async handleBrowserPayment(request) { // Implement browser payment logic (ConnectIPS, etc.) throw new Error("Browser payments not implemented"); } async handleBrowserVerification(referenceId) { // Implement browser verification logic throw new Error("Browser verification not implemented"); } async handleBrowserPaymentHistory(options) { // Implement browser payment history throw new Error("Browser payment history not implemented"); } // Native-specific implementations async handleNativePayment(request) { return new Promise((resolve, reject) => { const requestObject = JSON.stringify({ name: "makePayment", params: request, result: "onPaymentCompleted", }); this.postNativeMessage(requestObject); myEventTarget.addEventListener("onPaymentCompleted", (e) => { const response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } async handleNativeVerification(referenceId) { return new Promise((resolve, reject) => { const requestObject = JSON.stringify({ name: "verifyPayment", params: { referenceId }, result: "onPaymentVerified", }); this.postNativeMessage(requestObject); myEventTarget.addEventListener("onPaymentVerified", (e) => { const response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } async handleNativePaymentHistory(options) { return new Promise((resolve, reject) => { const requestObject = JSON.stringify({ name: "getPaymentHistory", params: options, result: "onPaymentHistoryReceived", }); this.postNativeMessage(requestObject); myEventTarget.addEventListener("onPaymentHistoryReceived", (e) => { const response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } postNativeMessage(message) { var _a, _b; const platform = this.miniapp.getPlatform(); if (platform === "android") { window.Hamropatro_MiniApp_Interface.postMessage(message); } else if (platform === "ios") { (_b = (_a = window === null || window === void 0 ? void 0 : window.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.Hamropatro_MiniApp_Interface.postMessage(message); } else { throw new Error(`Unsupported platform: ${platform}`); } } } const DEFAULT_PAYMENT_CONFIG = { defaultCurrency: "NPR", autoVerify: true, verificationTimeout: 30000, }; const PaymentModule = { name: "payment", defaultConfig: DEFAULT_PAYMENT_CONFIG, install: (miniapp, config) => new PaymentManager(miniapp, config), }; class UIManager { constructor(miniapp, config = {}) { this.miniapp = miniapp; this.config = { toastDuration: 3000, loadingText: "Loading...", alertTitle: "Alert", confirmTitle: "Confirm", ...config }; } /** * Show a toast message */ showToast(message, options) { return new Promise((resolve, reject) => { if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { // Fallback for browser console.log(`Toast: ${message}`); setTimeout(resolve, (options === null || options === void 0 ? void 0 : options.duration) || this.config.toastDuration); return; } const request = { name: "ui.showToast", params: { message, duration: (options === null || options === void 0 ? void 0 : options.duration) || this.config.toastDuration, position: (options === null || options === void 0 ? void 0 : options.position) || "bottom" }, result: "onToastShown" }; this.postNativeMessage(request, resolve, reject); }); } /** * Show an alert dialog */ showAlert(message, options) { return new Promise((resolve, reject) => { if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { // Fallback for browser window.alert(`${(options === null || options === void 0 ? void 0 : options.title) || this.config.alertTitle}: ${message}`); resolve(); return; } const request = { name: "ui.showAlert", params: { title: (options === null || options === void 0 ? void 0 : options.title) || this.config.alertTitle, message, buttonText: (options === null || options === void 0 ? void 0 : options.buttonText) || "OK" }, result: "onAlertDismissed" }; this.postNativeMessage(request, resolve, reject); }); } /** * Show a confirmation dialog */ showConfirm(message, options) { return new Promise((resolve, reject) => { if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { // Fallback for browser const result = window.confirm(`${(options === null || options === void 0 ? void 0 : options.title) || this.config.confirmTitle}: ${message}`); resolve(result); return; } const request = { name: "ui.showConfirm", params: { title: (options === null || options === void 0 ? void 0 : options.title) || this.config.confirmTitle, message, confirmText: (options === null || options === void 0 ? void 0 : options.confirmText) || "OK", cancelText: (options === null || options === void 0 ? void 0 : options.cancelText) || "Cancel" }, result: "onConfirmResponse" }; this.postNativeMessage(request, (response) => resolve((response === null || response === void 0 ? void 0 : response.confirmed) || false), reject); }); } /** * Show an action sheet (iOS) or bottom sheet (Android) */ showActionSheet(options) { return new Promise((resolve, reject) => { if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { // Fallback for browser const selected = window.prompt(`${options.title || "Select an option"}\n${options.options.join("\n")}`); resolve(selected); return; } const request = { name: "ui.showActionSheet", params: { title: options.title, options: options.options, cancelText: options.cancelText || "Cancel", destructiveIndex: options.destructiveIndex }, result: "onActionSheetSelection" }; this.postNativeMessage(request, (response) => resolve((response === null || response === void 0 ? void 0 : response.selected) || null), reject); }); } /** * Show a loading indicator */ showLoading(options) { return new Promise((resolve, reject) => { if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { // Fallback for browser console.log(`Loading: ${(options === null || options === void 0 ? void 0 : options.text) || this.config.loadingText}`); resolve(); return; } const request = { name: "ui.showLoading", params: { text: (options === null || options === void 0 ? void 0 : options.text) || this.config.loadingText, cancelable: (options === null || options === void 0 ? void 0 : options.cancelable) || false }, result: "onLoadingShown" }; this.postNativeMessage(request, resolve, reject); }); } /** * Hide the loading indicator */ hideLoading() { return new Promise((resolve, reject) => { if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { // Fallback for browser console.log("Loading hidden"); resolve(); return; } const request = { name: "ui.hideLoading", params: {}, result: "onLoadingHidden" }; this.postNativeMessage(request, resolve, reject); }); } /** * Set the navigation bar title */ setTitle(title) { return new Promise((resolve, reject) => { if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { // Fallback for browser document.title = title; resolve(); return; } const request = { name: "ui.setTitle", params: { title }, result: "onTitleSet" }; this.postNativeMessage(request, resolve, reject); }); } /** * Set navigation bar color */ setNavigationBarColor(color, textColor = "dark") { return new Promise((resolve, reject) => { if (this.miniapp.getPlatform() === PLATFORM.BROWSER) { // Fallback for browser console.log(`Navigation bar color set to ${color}, text color: ${textColor}`); resolve(); return; } const request = { name: "ui.setNavigationBarColor", params: { color, textColor }, result: "onNavigationBarColorSet" }; this.postNativeMessage(request, resolve, reject); }); } postNativeMessage(request, resolve, reject) { var _a, _b; try { const message = JSON.stringify(request); if (this.miniapp.getPlatform() === PLATFORM.ANDROID) { window.Hamropatro_MiniApp_Interface.postMessage(message); } else if (this.miniapp.getPlatform() === PLATFORM.IOS) { (_b = (_a = window === null || window === void 0 ? void 0 : window.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.Hamropatro_MiniApp_Interface.postMessage(message); } if (request.result) { myEventTarget.addEventListener(request.result, (e) => { const response = e.detail; if (response === null || response === void 0 ? void 0 : response.error) { reject(response.error); } else { resolve(response === null || response === void 0 ? void 0 : response.data); } }, { once: true }); } else { resolve(undefined); } } catch (error) { reject(error); } } } class CacheManager { constructor(miniapp) { this.miniapp = miniapp; } putCache(cacheKey, cacheValue, isLRUCache = true) { return new Promise((resolve, reject) => { var _a; if (!this.miniapp.miniAppId && !((_a = window.appBundle) === null || _a === void 0 ? void 0 : _a.appBundleId)) { reject(MINI_APP_NOT_INITIALIZED); return; } const reqObject = JSON.stringify({ name: 'putCache', params: { miniAppId: this.miniapp.miniAppId, cacheKey: cacheKey, cacheValue: cacheValue, isLRUCache: isLRUCache }, result: 'onPutCache' }); if (this.miniapp.getPlatform() === PLATFORM.ANDROID) { window.Hamropatro_MiniApp_Interface.postMessage(reqObject); } else if (this.miniapp.getPlatform() === PLATFORM.IOS) { window.webkit.messageHandlers.Hamropatro_MiniApp_Interface.postMessage(reqObject); } myEventTarget.addEventListener('onPutCache', function (e) { let response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } getCache(cacheKey, isLRUCache = true, isAnonymousUser = false) { return new Promise((resolve, reject) => { var _a; if (!this.miniapp.miniAppId && !((_a = window.appBundle) === null || _a === void 0 ? void 0 : _a.appBundleId)) { reject(MINI_APP_NOT_INITIALIZED); return; } const reqObject = JSON.stringify({ name: 'getCache', params: { miniAppId: this.miniapp.miniAppId, cacheKey: cacheKey, isLRUCache: isLRUCache, getAnonymousCache: isAnonymousUser }, result: 'onGetCache' }); if (this.miniapp.getPlatform() === PLATFORM.ANDROID) { window.Hamropatro_MiniApp_Interface.postMessage(reqObject); } else if (this.miniapp.getPlatform() === PLATFORM.IOS) { window.webkit.messageHandlers.Hamropatro_MiniApp_Interface.postMessage(reqObject); } myEventTarget.addEventListener('onGetCache_' + cacheKey, function (e) { let response = e.detail; console.log(`onGetCache_${cacheKey} => ${response}`); if (response.error) { reject(response.error); } else { let parsedData = response.data; let key = Object.keys(parsedData)[0]; resolve(parsedData[key]); } }, { once: true }); }); } clearCache(cacheKey, isLRUCache = true, isAnonymousUser = false) { return new Promise((resolve, reject) => { var _a; if (!this.miniapp.miniAppId && !((_a = window.appBundle) === null || _a === void 0 ? void 0 : _a.appBundleId)) { reject(MINI_APP_NOT_INITIALIZED); return; } const reqObject = JSON.stringify({ name: 'clearCache', params: { miniAppId: this.miniapp.miniAppId, cacheKey: cacheKey, isLRUCache: isLRUCache, getAnonymousCache: isAnonymousUser }, result: 'onClearCache' }); if (this.miniapp.getPlatform() === PLATFORM.ANDROID) { window.Hamropatro_MiniApp_Interface.postMessage(reqObject); } else if (this.miniapp.getPlatform() === PLATFORM.IOS) { window.webkit.messageHandlers.Hamropatro_MiniApp_Interface.postMessage(reqObject); } myEventTarget.addEventListener('onClearCache', function (e) { let response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } clearAllCache(isLRUCache = true) { return new Promise((resolve, reject) => { var _a; if (!this.miniapp.miniAppId && !((_a = window.appBundle) === null || _a === void 0 ? void 0 : _a.appBundleId)) { reject(MINI_APP_NOT_INITIALIZED); return; } const reqObject = JSON.stringify({ name: 'clearAllCache', params: { miniAppId: this.miniapp.miniAppId, isLRUCache: isLRUCache }, result: 'onClearAllCache' }); if (this.miniapp.getPlatform() === PLATFORM.ANDROID) { window.Hamropatro_MiniApp_Interface.postMessage(reqObject); } else if (this.miniapp.getPlatform() === PLATFORM.IOS) { window.webkit.messageHandlers.Hamropatro_MiniApp_Interface.postMessage(reqObject); } myEventTarget.addEventListener('onClearAllCache', function (e) { let response = e.detail; if (response.error) { reject(response.error); } else { resolve(response.data); } }, { once: true }); }); } // Additional convenience methods async putJson(key, value, isLRUCache = true) { return this.putCache(key, JSON.stringify(value), isLRUCache); } async getJson(key, isLRUCache = true, isAnonymousUser = false) { const result = await this.getCache(key, isLRUCache, isAnonymousUser); return result ? JSON.parse(result) : null; } } const getDefaultsFromPostinstall = () => (undefined); /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const stringToByteArray$1 = function (str) { // TODO(user): Use native implementations if/when available const out = []; let p = 0; for (let i = 0; i < str.length; i++) { let c = str.charCodeAt(i); if (c < 128) { out[p++] = c; } else if (c < 2048) { out[p++] = (c >> 6) | 192; out[p++] = (c & 63) | 128; } else if ((c & 0xfc00) === 0xd800 && i + 1 < str.length && (str.charCodeAt(i + 1) & 0xfc00) === 0xdc00) { // Surrogate Pair c = 0x10000 + ((c & 0x03ff) << 10) + (str.charCodeAt(++i) & 0x03ff); out[p++] = (c >> 18) | 240; out[p++] = ((c >> 12) & 63) | 128; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } else { out[p++] = (c >> 12) | 224; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } } return out; }; /** * Turns an array of numbers into the string given by the concatenation of the * characters to which the numbers correspond. * @param bytes Array of numbers representing characters. * @return Stringification of the array. */ const byteArrayToString = function (bytes) { // TODO(user): Use native implementations if/when available const out = []; let pos = 0, c = 0; while (pos < bytes.length) { const c1 = bytes[pos++]; if (c1 < 128) { out[c++] = String.fromCharCode(c1); } else if (c1 > 191 && c1 < 224) { const c2 = bytes[pos++]; out[c++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); } else if (c1 > 239 && c1 < 365) { // Surrogate Pair const c2 = bytes[pos++]; const c3 = bytes[pos++]; const c4 = bytes[pos++]; const u = (((c1 & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63)) - 0x10000; out[c++] = String.fromCharCode(0xd800 + (u >> 10)); out[c++] = String.fromCharCode(0xdc00 + (u & 1023)); } else { const c2 = bytes[pos++]; const c3 = bytes[pos++]; out[c++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); } } return out.join(''); }; // We define it as an object literal instead of a class because a class compiled down to es5 can't // be treeshaked. https://github.com/rollup/rollup/issues/1691 // Static lookup maps, lazily populated by init_() // TODO(dlarocque): Define this as a class, since we no longer target ES5. const base64 = { /** * Maps bytes to characters. */ byteToCharMap_: null, /** * Maps characters to bytes. */ charToByteMap_: null, /** * Maps bytes to websafe characters. * @private */ byteToCharMapWebSafe_: null, /** * Maps websafe characters to bytes. * @private */ charToByteMapWebSafe_: null, /** * Our default alphabet, shared between * ENCODED_VALS and ENCODED_VALS_WEBSAFE */ ENCODED_VALS_BASE: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789', /** * Our default alphabet. Value 64 (=) is special; it means "nothing." */ get ENCODED_VALS() { return this.ENCODED_VALS_BASE + '+/='; }, /** * Our websafe alphabet. */ get ENCODED_VALS_WEBSAFE() { return this.ENCODED_VALS_BASE + '-_.'; }, /** * Whether this browser supports the atob and btoa functions. This extension * started at Mozilla but is now implemented by many browsers. We use the * ASSUME_* variables to avoid pulling in the full useragent detection library * but still allowing the standard per-browser compilations. * */ HAS_NATIVE_SUPPORT: typeof atob === 'function', /** * Base64-encode an array of bytes. * * @param input An array of bytes (numbers with * value in [0, 255]) to encode. * @param webSafe Boolean indicating we should use the * alternative alphabet. * @return The base64 encoded string. */ encodeByteArray(input, webSafe) { if (!Array.isArray(input)) { throw Error('encodeByteArray takes an array as a parameter'); } this.init_(); const byteToCharMap = webSafe ? this.byteToCharMapWebSafe_ : this.byteToCharMap_; const output = []; for (let i = 0; i < input.length; i += 3) { const byte1 = input[i]; const haveByte2 = i + 1 < input.length; const byte2 = haveByte2 ? input[i + 1] : 0; const haveByte3 = i + 2 < input.length; const byte3 = haveByte3 ? input[i + 2] : 0; const outByte1 = byte1 >> 2; const outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4); let outByte3 = ((byte2 & 0x0f) << 2) | (byte3 >> 6); let outByte4 = byte3 & 0x3f; if (!haveByte3) { outByte4 = 64; if (!haveByte2) { outByte3 = 64; } } output.push(byteToCharMap[outByte1], byteToCharMap[outByte2], byteToCharMap[outByte3], byteToCharMap[outByte4]); } return output.join(''); }, /** * Base64-encode a string. * * @param input A string to encode. * @param webSafe If true, we should use the * alternative alphabet. * @return The base64 encoded string. */ encodeString(input, webSafe) { // Shortcut for Mozilla browsers that implement // a native base64 encoder in the form of "btoa/atob" if (this.HAS_NATIVE_SUPPORT && !webSafe) { return btoa(input); } return this.encodeByteArray(stringToByteArray$1(input), webSafe); }, /** * Base64-decode a string. * * @param input to decode. * @param webSafe True if we should use the * alternative alphabet. * @return string representing the decoded value. */ decodeString(input, webSafe) { // Shortcut for Mozilla browsers that implement // a native base64 encoder in the form of "btoa/atob" if (this.HAS_NATIVE_SUPPORT && !webSafe) { return atob(input); } return byteArrayToString(this.decodeStringToByteArray(input, webSafe)); }, /** * Base64-decode a string. * * In base-64 decoding, groups of four characters are converted into three * bytes. If the encoder did not apply padding, the input length may not * be a multiple of 4. * * In this case, the last group will have fewer than 4 characters, and * padding will be inferred. If the group has one or two characters, it decodes * to one byte. If the group has three characters, it decodes to two bytes. * * @param input Input to decode. * @param webSafe True if we should use the web-safe alphabet. * @return bytes representing the decoded value. */ decodeStringToByteArray(input, webSafe) { this.init_(); const charToByteMap = webSafe ? this.charToByteMapWebSafe_ : this.charToByteMap_; const output = []; for (let i = 0; i < input.length;) { const byte1 = charToByteMap[input.charAt(i++)]; const haveByte2 = i < input.length; const byte2 = haveByte2 ? charToByteMap[input.charAt(i)] : 0; ++i; const haveByte3 = i < input.length; const byte3 = haveByte3 ? charToByteMap[input.charAt(i)] : 64; ++i; const haveByte4 = i < input.length; const byte4 = haveByte4 ? charToByteMap[input.charAt(i)] : 64; ++i; if (byte1 == null || byte2 == null || byte3 == null || byte4 == null) { throw new DecodeBase64StringError(); } const outByte1 = (byte1 << 2) | (byte2 >> 4); output.push(outByte1); if (byte3 !== 64) { const outByte2 = ((byte2 << 4) & 0xf0) | (byte3 >> 2); output.push(outByte2); if (byte4 !== 64) { const outByte3 = ((byte3 << 6) & 0xc0) | byte4; output.push(outByte3); } } } return output; }, /** * Lazy static initialization function. Called before * accessing any of the static map variables. * @private */ init_() { if (!this.byteToCharMap_) { this.byteToCharMap_ = {}; this.charToByteMap_ = {}; this.byteToCharMapWebSafe_ = {}; this.charToByteMapWebSafe_ = {}; // We want quick mappings back and forth, so we precompute two maps. for (let i = 0; i < this.ENCODED_VALS.length; i++) { this.byteToCharMap_[i] = this.ENCODED_VALS.charAt(i); this.charToByteMap_[this.byteToCharMap_[i]] = i; this.byteToCharMapWebSafe_[i] = this.ENCODED_VALS_WEBSAFE.charAt(i); this.charToByteMapWebSafe_[this.byteToCharMapWebSafe_[i]] = i; // Be forgiving when decoding and correctly decode both encodings. if (i >= this.ENCODED_VALS_BASE.length) { this.charToByteMap_[this.ENCODED_VALS_WEBSAFE.charAt(i)] = i; this.charToByteMapWebSafe_[this.ENCODED_VALS.charAt(i)] = i; } } } } }; /** * An error encountered while decoding base64 string. */ class DecodeBase64StringError extends Error { constructor() { super(...arguments); this.name = 'DecodeBase64StringError'; } } /** * URL-safe base64 encoding */ const base64Encode = function (str) { const utf8Bytes = stringToByteArray$1(str); return base64.encodeByteArray(utf8Bytes, true); }; /** * URL-safe base64 encoding (without "." padding in the end). * e.g. Used in JSON Web Token (JWT) parts. */ const base64urlEncodeWithoutPadding = function (str) { // Use base64url encoding and remove padding in the end (dot characters). return base64Encode(str).replace(/\./g, ''); }; /** * URL-safe base64 decoding * * NOTE: DO NOT use the global atob() function - it does NOT support the * base64Url variant encoding. * * @param str To be decoded * @return Decoded result, if possible */ const base64Decode = function (str) { try { return base64.decodeString(str, true); } catch (e) { console.error('base64Decode failed: ', e); } return null; }; /** * @license * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Polyfill for `globalThis` object. * @returns the `globalThis` object for the given environment. * @public */ function getGlobal() { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } throw new Error('Unable to locate global object.'); } /** * @license * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const getDefaultsFromGlobal = () => getGlobal().__FIREBASE_DEFAULTS__; /** * Attempt to read defaults from a JSON string provided to * process(.)env(.)__FIREBASE_DEFAULTS__ or a JSON file whose path is in * process(.)env(.)__FIREBASE_DEFAULTS_PATH__ * The dots are in parens because certain compilers (Vite?) cannot * handle seeing that variable in comments. * See https://github.com/firebase/firebase-js-sdk/issues/6838 */ const getDefaultsFromEnvVariable = () => { if (typeof process === 'undefined' || typeof process.env === 'undefined') { return; } const defaultsJsonString = process.env.__FIREBASE_DEFAULTS__; if (defaultsJsonString) { return JSON.parse(defaultsJsonString); } }; const getDefaultsFromCookie = () => { if (typeof document === 'undefined') { return; } let match; try { match = document.cookie.match(/__FIREBASE_DEFAULTS__=([^;]+)/); } catch (e) { // Some environments such as Angular Universal SSR have a // `document` object but error on accessing `document.cookie`. return; } const decoded = match && base64Decode(match[1]); return decoded && JSON.parse(decoded); }; /** * Get the __FIREBASE_DEFAULTS__ object. It checks in order: * (1) if such an object exists as a property of `globalThis` * (2) if such an object was provided on a shell environment variable * (3) if such an object exists in a cookie * @public */ const getDefaults = () => { try { return (getDefa