UNPKG

@eternl/cardano-dapp-connector-bridge

Version:

A postMessage bridge to connect dApps to the Eternl DApp Browser loading apps into an iframe.

218 lines (216 loc) 9.31 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.initCardanoDAppConnectorBridge = void 0; const generateUID = () => { return ('000' + ((Math.random() * 46656) | 0).toString(36)).slice(-3) + ('000' + ((Math.random() * 46656) | 0).toString(36)).slice(-3); }; /** * Initialize the Cardano DApp Connector Bridge to the Eternl wallet DApp Browser. * * @param onBridgeCreated (optional) callback function to be called when the bridge is established. */ const initCardanoDAppConnectorBridge = (onBridgeCreated) => { if (typeof window === 'undefined') { return; } const _debug = false; // set to true for debug logs. const _label = 'DAppConnectorBridge: '; // set to true for debug logs. let _walletNamespace = null; // eg. 'eternl' let _initialApiObject = null; // CIP0030 initial api object let _fullApiObject = null; // CIP0030 full api object const _bridge = { type: 'cardano-dapp-connector-bridge', source: null, origin: null }; const _requestMap = {}; const _methodMap = { // Initial 4 methods to establish connection. More endpoints will be added by the wallet. connect: 'connect', handshake: 'handshake', enable: 'enable', isEnabled: 'isEnabled', supportedExtensions: 'supportedExtensions' }; function createRequest(method) { const args = [...arguments]; if (args.length > 0) { args.shift(); } return new Promise(((resolve, reject) => { var _a, _b; const request = { payload: { type: _bridge.type, to: _walletNamespace, uid: generateUID(), method: method, args: args }, resolve: resolve, reject: reject }; _requestMap[request.payload.uid] = request; if (_debug) { console.log(_label + '_requestMap:', _requestMap); } (_a = _bridge.source) === null || _a === void 0 ? void 0 : _a.postMessage(request.payload, (_b = _bridge.origin) !== null && _b !== void 0 ? _b : '*'); })); } function generateApiFunction(method) { return function () { // @ts-ignore return createRequest(method, ...arguments); }; } function generateApiObject(obj) { const apiObj = {}; for (const key in obj) { const value = obj[key]; if (_debug) { console.log(_label + 'init: key/value:', key, value); } if (typeof value === 'string') { if (key === 'feeAddress') { apiObj[key] = value; } else { apiObj[key] = generateApiFunction(value); _methodMap[value] = value; } } else if (typeof value === 'object') { apiObj[key] = generateApiObject(value); } else { apiObj[key] = value; } } return apiObj; } function initBridge(source, origin, walletNamespace, initialApi) { var _a; if (!window.hasOwnProperty('cardano')) { window.cardano = {}; } if (window.cardano.hasOwnProperty(walletNamespace)) { console.warn('Warn: ' + _label + 'window.cardano.' + walletNamespace + ' already present, skipping initialApi creation.'); return null; } _bridge.source = source; _bridge.origin = origin; _walletNamespace = walletNamespace; const initialApiObj = { isBridge: true, // https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030 isEnabled: function () { return createRequest('isEnabled'); }, enable: function () { // @ts-ignore return createRequest('enable', ...arguments); }, apiVersion: initialApi.apiVersion, name: initialApi.name, icon: (_a = initialApi.icon) !== null && _a !== void 0 ? _a : null, supportedExtensions: initialApi.supportedExtensions, // experimental API: https://github.com/cardano-foundation/CIPs/blob/master/CIP-0030/README.md#experimental-api experimental: {} }; window.cardano[walletNamespace] = initialApiObj; if (initialApi.experimental) { initialApiObj.experimental = Object.assign({}, generateApiObject(initialApi.experimental)); } return window.cardano[walletNamespace]; } function isValidBridge(event) { if (!_initialApiObject) { if (event.data.method !== _methodMap.connect) { console.error('Error: ' + _label + 'send \'connect\' first.'); return false; } const initialApi = event.data.initialApi; if (!initialApi || !initialApi.isBridge || !initialApi.apiVersion || !initialApi.name) { console.error('Error: ' + _label + '\'connect\' is missing correct initialApi.', initialApi); return false; } if (!event.data.walletNamespace) { console.error('Error: ' + _label + '\'connect\' is missing walletNamespace.', event.data.walletNamespace); return false; } _initialApiObject = initBridge(event.source, event.origin, event.data.walletNamespace, initialApi); } if (!(_initialApiObject && window.hasOwnProperty('cardano') && window.cardano[event.data.walletNamespace] === _initialApiObject)) { console.warn('Warn: ' + _label + 'bridge not set up correctly:', _bridge, _initialApiObject, _walletNamespace); return false; } return true; } function isValidMessage(event) { if (!event.data || !event.origin || !event.source) return false; if (event.data.type !== _bridge.type) return false; if (!_methodMap.hasOwnProperty(event.data.method)) return false; if (_walletNamespace && event.data.walletNamespace !== _walletNamespace) return false; return true; } function onMessage(event) { return __awaiter(this, void 0, void 0, function* () { if (!isValidMessage(event) || !isValidBridge(event)) { return; } if (_debug) { console.log('########################'); console.log(_label + 'onMessage: got message'); console.log(_label + 'onMessage: origin:', event.origin); // console.log(_label+'onMessage: source:', payload.source) // Don't log source, might break browser security rules console.log(_label + 'onMessage: data: ', event.data); console.log('########################'); } if (event.data.method === _methodMap.connect) { const success = yield createRequest('handshake'); if (success && _initialApiObject) { if (onBridgeCreated) onBridgeCreated(_initialApiObject); } return; } if (!event.data.uid) { return; } const request = _requestMap[event.data.uid]; if (!request) return; const error = event.data.error; if (error) { request.reject(error); delete _requestMap[event.data.uid]; return; } // Bridge is set up correctly, message is valid, method is known. let response = event.data.response; if (event.data.method === _methodMap.enable) { _fullApiObject = null; if (typeof response === 'object') { _fullApiObject = Object.assign({}, generateApiObject(response)); response = _fullApiObject; if (_debug) { console.log(_label + 'onMessage: fullApiObject:', _fullApiObject); } } } request.resolve(response); delete _requestMap[event.data.uid]; }); } window.addEventListener("message", onMessage, false); }; exports.initCardanoDAppConnectorBridge = initCardanoDAppConnectorBridge;