UNPKG

@circle-apps/sdk

Version:

Official SDK for Celia Mini Apps integration

353 lines (351 loc) 14.5 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CeliaSDK = void 0; class CeliaSDK { constructor() { var _a, _b; this.isInitialized = false; if (typeof window === "undefined") { throw new Error("CeliaSDK can only be used in a browser environment"); } // Check both WebView and user agent this.isWebView = !!(window.ReactNativeWebView || ((_b = (_a = window.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.reactNativeWebView)); this.isCircleMiniApp = true; if (!this.isWebView) { console.warn("CeliaSDK is not running in a WebView. Some features may not be available."); return; } this.initialize().catch((error) => { console.error("Failed to initialize CeliaSDK:", error); // Error is already logged, no need to emit an event }); } verifyEnvironment() { var _a, _b; const isWebView = !!(window.ReactNativeWebView || ((_b = (_a = window.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.reactNativeWebView)); return { isWebView, isCircleMiniApp: true, isValid: isWebView, }; } initialize() { return __awaiter(this, void 0, void 0, function* () { if (this.isInitialized) return; try { const { isValid } = this.verifyEnvironment(); if (!isValid) { throw new Error(`Invalid environment. CeliaSDK must run in a WebView`); } yield this.injectBridge(); this.setupMessageListener(); this.isInitialized = true; } catch (error) { console.error("Failed to initialize CeliaSDK:", error); throw error; } }); } authenticate(options) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { try { if (!options || !options.appID) { throw new Error("App ID is required for authentication"); } const callbackId = Date.now().toString(); this.setupCallback(callbackId, resolve, reject); this.postMessage({ type: "AUTHENTICATE", payload: { appID: options.appID, callbackId, }, }); } catch (error) { reject(error); } }); }); } share(options) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { try { const callbackId = Date.now().toString(); this.setupCallback(callbackId, resolve, reject); this.postMessage({ type: "SHARE", payload: Object.assign(Object.assign({}, options), { callbackId }), }); } catch (error) { reject(error); } }); }); } showAd(options) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { try { if (!options || !options.type) { throw new Error("Ad type is required"); } // For banner ads, redirect to showBannerAd method if (options.type === 'banner') { if (!options.containerId) { throw new Error("Container ID is required for banner ads"); } return this.showBannerAd({ containerId: options.containerId, size: options.size, unitId: options.adUnitId, requestOptions: options.requestOptions, }).then(resolve).catch(reject); } const callbackId = Date.now().toString(); this.setupCallback(callbackId, resolve, reject); this.postMessage({ type: "SHOW_AD", payload: Object.assign(Object.assign({ adType: options.type }, options), { callbackId }), }); } catch (error) { reject(error); } }); }); } showBannerAd(options) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { try { if (!options || !options.containerId) { throw new Error("Container ID is required for banner ads"); } const callbackId = Date.now().toString(); this.setupCallback(callbackId, resolve, reject); this.postMessage({ type: "SHOW_BANNER_AD", payload: { containerId: options.containerId, size: options.size || 'ANCHORED_ADAPTIVE_BANNER', unitId: options.unitId, requestOptions: options.requestOptions, callbackId, }, }); } catch (error) { reject(error); } }); }); } hideBannerAd(options) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { try { if (!options || !options.containerId) { throw new Error("Container ID is required to hide banner ad"); } const callbackId = Date.now().toString(); this.setupCallback(callbackId, resolve, reject); this.postMessage({ type: "HIDE_BANNER_AD", payload: { containerId: options.containerId, callbackId, }, }); } catch (error) { reject(error); } }); }); } getLanguage() { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { try { // First check if language has been eagerly injected if (typeof window !== "undefined") { // Check for cached language in window object if (window._celiaAppLanguage) { return resolve({ language: window._celiaAppLanguage }); } // Check for cached language in celiaMini object if (window.celiaMini && window.celiaMini._cachedLanguage) { return resolve({ language: window.celiaMini._cachedLanguage }); } // Set up a one-time event listener for language ready event const languageReadyHandler = (event) => { window.removeEventListener("celiaLanguageReady", languageReadyHandler); return resolve(event.detail); }; window.addEventListener("celiaLanguageReady", languageReadyHandler); } // If no cached language found, request it from native side const callbackId = Date.now().toString(); this.setupCallback(callbackId, resolve, reject); this.postMessage({ type: "GET_LANGUAGE", payload: { callbackId, }, }); } catch (error) { reject(error); } }); }); } setupCallback(callbackId, resolve, reject) { if (!window._celiaMiniCallbacks) { window._celiaMiniCallbacks = {}; } window._celiaMiniCallbacks[callbackId] = { resolve, reject, timeout: setTimeout(() => { var _a; reject(new Error("Operation timed out")); (_a = window._celiaMiniCallbacks) === null || _a === void 0 ? true : delete _a[callbackId]; }, 30000), // 30 second timeout }; } postMessage(message) { if (!window.ReactNativeWebView) { throw new Error("ReactNativeWebView is not available"); } window.ReactNativeWebView.postMessage(JSON.stringify({ type: "FROM_WEBVIEW", payload: message, })); } injectBridge() { return new Promise((resolve) => { if (typeof window === "undefined") { resolve(); return; } // If bridge already exists, resolve immediately if (window.ReactNativeWebView) { resolve(); return; } // Create a script to inject the bridge const script = document.createElement("script"); script.text = ` (function() { if (!window.ReactNativeWebView) { window.ReactNativeWebView = { postMessage: function(message) { try { const payload = typeof message === 'string' ? message : JSON.stringify(message); window.postMessage(JSON.stringify({ type: 'FROM_WEBVIEW', payload: typeof message === 'string' ? JSON.parse(message) : message }), '*'); return true; } catch (e) { console.error('Failed to post message:', e); return false; } } }; } // Notify that the bridge is ready if (window.dispatchEvent) { window.dispatchEvent(new Event('celia:bridgeReady')); } })(); `; const onBridgeReady = () => { document.removeEventListener("celia:bridgeReady", onBridgeReady); resolve(); }; // Set a timeout in case the bridge never initializes const timeoutId = setTimeout(() => { document.removeEventListener("celia:bridgeReady", onBridgeReady); console.warn("Bridge initialization timed out"); resolve(); // Resolve anyway to prevent hanging }, 2000); // 2 second timeout document.addEventListener("celia:bridgeReady", onBridgeReady, { once: true, }); document.head.appendChild(script); }); } setupMessageListener() { if (typeof window === "undefined") { // Return a no-op cleanup function return () => { }; } const handleMessage = (event) => { var _a; try { // Handle both direct messages and wrapped messages let message; try { message = typeof event.data === "string" ? JSON.parse(event.data) : event.data; } catch (e) { console.warn("Failed to parse message:", event.data); return; } // Check if this is a wrapped message const payload = message.type === "FROM_WEBVIEW" ? message.payload : message; if (!payload || !payload.type) return; // Handle callback responses if (payload.callbackId && ((_a = window._celiaMiniCallbacks) === null || _a === void 0 ? void 0 : _a[payload.callbackId])) { const { resolve, reject } = window._celiaMiniCallbacks[payload.callbackId]; clearTimeout(window._celiaMiniCallbacks[payload.callbackId].timeout); if (payload.error) { reject(new Error(payload.error)); } else { resolve(payload); } delete window._celiaMiniCallbacks[payload.callbackId]; } // Events are now handled through callbacks } catch (error) { console.error("Error handling message:", error, event.data); } }; window.addEventListener("message", handleMessage); return () => { window.removeEventListener("message", handleMessage); }; } handleIncomingEvent(_event, _payload) { // Events are now handled through callbacks } } exports.CeliaSDK = CeliaSDK; // Export the class exports.default = CeliaSDK;