UNPKG

@open-game-system/app-bridge-web

Version:

Web-specific implementation of the app-bridge ecosystem

176 lines (175 loc) 6.3 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { createWebBridge: () => createWebBridge }); module.exports = __toCommonJS(src_exports); var import_fast_json_patch = require("fast-json-patch"); function createWebBridge() { const stateByStore = /* @__PURE__ */ new Map(); const stores = /* @__PURE__ */ new Map(); const stateListeners = /* @__PURE__ */ new Map(); const storeListeners = /* @__PURE__ */ new Set(); const notifyStateListeners = (storeKey) => { const listeners = stateListeners.get(storeKey); if (listeners && stateByStore.has(storeKey)) { const state = stateByStore.get(storeKey); listeners.forEach((listener) => listener(state)); } }; const notifyStoreListeners = () => { storeListeners.forEach((listener) => listener()); }; if (typeof window !== "undefined" && window.ReactNativeWebView) { console.log("[Web Bridge] ReactNativeWebView detected. Adding message listener and sending BRIDGE_READY."); window.ReactNativeWebView.postMessage(JSON.stringify({ type: "BRIDGE_READY" })); const messageHandler = (event) => { try { const message = JSON.parse(event.data); if (message.type === "STATE_INIT") { if (message.data === null) { stateByStore.delete(message.storeKey); } else { stateByStore.set(message.storeKey, message.data); } notifyStateListeners(message.storeKey); notifyStoreListeners(); } else if (message.type === "STATE_UPDATE") { if (message.data === null) { stateByStore.delete(message.storeKey); notifyStateListeners(message.storeKey); notifyStoreListeners(); } else if (message.operations) { const currentState = stateByStore.get( message.storeKey ); if (currentState) { const result = (0, import_fast_json_patch.applyPatch)(currentState, message.operations); stateByStore.set( message.storeKey, result.newDocument ); notifyStateListeners(message.storeKey); } } } } catch (error) { console.error("[Web Bridge] Error handling message:", error); } }; window.addEventListener("message", messageHandler); } else { console.warn("[Web Bridge] ReactNativeWebView NOT detected."); } return { /** * Check if the bridge is supported * For web bridge, this checks if ReactNativeWebView is available */ isSupported: () => typeof window !== "undefined" && !!window.ReactNativeWebView, /** * Get a store by its key * Returns undefined if the store doesn't exist */ getStore: (storeKey) => { if (!stateByStore.has(storeKey)) return void 0; let store = stores.get(storeKey); if (!store) { const storeImpl = { getSnapshot: () => stateByStore.get(storeKey), subscribe: (listener) => { if (!stateListeners.has(storeKey)) { stateListeners.set(storeKey, /* @__PURE__ */ new Set()); } const listeners = stateListeners.get(storeKey); listeners.add(listener); if (stateByStore.has(storeKey)) { listener(stateByStore.get(storeKey)); } return () => { listeners.delete(listener); }; }, dispatch: async (event) => { console.log(`[Web Bridge] Dispatching event for store ${String(storeKey)}:`, event); if (!window.ReactNativeWebView) { console.warn( "[Web Bridge] Cannot dispatch events: ReactNativeWebView not available" ); return; } const message = { type: "EVENT", storeKey, event }; console.log("[Web Bridge] Sending message to native:", message); window.ReactNativeWebView.postMessage(JSON.stringify(message)); }, reset: () => { console.warn("[Web Bridge] Reset operation not supported in web bridge"); }, // Add 'on' method to satisfy the interface on: (eventType, _listener) => { console.warn(`[Web Bridge] store.on("${eventType}", ...) was called, but listeners added on the web side are not executed. Add listeners on the native side or via the store's 'on' config.`); return () => { }; } }; stores.set(storeKey, storeImpl); store = storeImpl; } return store; }, /** * Set or remove a store for a given key */ setStore: (key, store) => { if (store === void 0) { stores.delete(key); stateByStore.delete(key); } else { stores.set(key, store); const snapshot = store.getSnapshot(); if (snapshot !== void 0) { stateByStore.set(key, snapshot); } } notifyStoreListeners(); }, /** * Subscribe to store availability changes * Returns an unsubscribe function */ subscribe: (listener) => { storeListeners.add(listener); return () => { storeListeners.delete(listener); }; } }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { createWebBridge }); //# sourceMappingURL=index.js.map