UNPKG

dreams-web-sdk

Version:
324 lines (319 loc) 12.2 kB
var partnerEvents; (function (partnerEvents) { // It's really unfortunate that we call this event "accountProvisioned", // when what we mean is "accountProvisionInitiated". But that's the current // name that is being used by the dreams backend partnerEvents["accountProvisionInitiated"] = "accountProvisioned"; partnerEvents["investmentAccountProvisionInitiated"] = "investmentAccountProvisionInitiated"; partnerEvents["updateToken"] = "updateToken"; partnerEvents["navigateTo"] = "navigateTo"; partnerEvents["transferConsentSucceeded"] = "onTransferConsentSucceeded"; partnerEvents["transferConsentCancelled"] = "onTransferConsentCancelled"; partnerEvents["accountRequestedFailed"] = "onAccountRequestedFailed"; partnerEvents["accountRequestedSucceeded"] = "onAccountRequestedSucceeded"; })(partnerEvents || (partnerEvents = {})); var partnerEvents$1 = partnerEvents; class MessageHandler { constructor(iframe, apiUrl, callbacks) { this.listen = () => window.addEventListener('message', this.onMessage); /* * This method handles all possible messages coming from dreams app. * For each type of message an appropriate function defined in the callbacks has to be added. * Check {@linkcode ClientCallbacks}. */ this.onMessage = async message => { console.debug('onMessage: ', message); const event = this.parseEvent(message); if (!event) return; switch (event.event) { case 'onIdTokenDidExpire': this.onIdTokenDidExpire(event); break; case 'onAccountProvisionRequested': this.onAccountProvisionRequested(event); break; case 'onInvestmentAccountProvisionRequested': this.onInvestmentAccountProvisionRequested(event); break; case 'onInvestmentSellRequested': this.onInvestmentSellRequested(event); break; case 'onExitRequested': await this.callbacks.onExitRequested(event); break; case 'onShare': this.onShare(event); break; case 'onTransferConsentRequested': this.onTransferConsentRequested(event); break; case 'onAccountRequested': this.onAccountRequested(event); break; default: console.warn('Unknown event type:', event); } }; /** * You can use this method if you need to manually update the token. */ this.postUpdateToken = message => { const event = { event: partnerEvents$1.updateToken, message }; this.postMessage(event); }; /** * You can use this method if you need to manually inform the dreams app that account provision has been initiated. */ this.postAccountProvisionInitiated = message => { const event = { event: partnerEvents$1.accountProvisionInitiated, message }; this.postMessage(event); }; /** * You can use this method if you need to manually inform the dreams app that investment account provision has been initiated. * AccountId is a shared id of a newly provisioned account. Whenever dreams will make a request to transfer money * to/from an account it will use this value to refer to that account. */ this.postInvestmentAccountProvisionInitiated = message => { const event = { event: partnerEvents$1.investmentAccountProvisionInitiated, message }; this.postMessage(event); }; this.postTransferConsentRequestSucceeded = message => { const event = { event: partnerEvents$1.transferConsentSucceeded, message }; this.postMessage(event); }; this.postTransferConsentRequestCancelled = message => { const event = { event: partnerEvents$1.transferConsentCancelled, message }; this.postMessage(event); }; this.postAccountRequestFailed = message => { const event = { event: partnerEvents$1.accountRequestedFailed, message }; this.postMessage(event); }; this.postAccountRequestSucceeded = message => { const event = { event: partnerEvents$1.accountRequestedSucceeded, message }; this.postMessage(event); }; /** * @param location the part of the dreams app where you want to take the user to. You have to only pass the path. */ this.navigateTo = location => { const event = { event: partnerEvents$1.navigateTo, message: { location } }; this.postMessage(event); }; this.onIdTokenDidExpire = async event => { if (!this.callbacks.onIdTokenDidExpire) return; try { const token = await this.callbacks.onIdTokenDidExpire(event); const msg = { requestId: event.message.requestId, idToken: token }; this.postUpdateToken(msg); } catch (err) { console.error('onIdTokenDidExpire error: ', err); } }; this.onAccountProvisionRequested = async event => { if (!this.callbacks.onAccountProvisionRequested) return; try { await this.callbacks.onAccountProvisionRequested(event); this.postAccountProvisionInitiated(event.message); } catch (err) { console.error('onAccountProvisionRequested error: ', err); } }; this.onInvestmentAccountProvisionRequested = async event => { if (!this.callbacks.onInvestmentAccountProvisionRequested) return; try { await this.callbacks.onInvestmentAccountProvisionRequested(event); this.postInvestmentAccountProvisionInitiated(event.message); } catch (err) { console.error('onInvestmentAccountProvisionRequested error: ', err); } }; this.onInvestmentSellRequested = async event => { if (!this.callbacks.onInvestmentSellRequested) return; try { await this.callbacks.onInvestmentSellRequested(event); } catch (err) { console.error('onInvestmentSellRequested error: ', err); } }; this.onShare = async event => { if (this.callbacks.onShare) await this.callbacks.onShare(event); }; this.onTransferConsentRequested = async event => { if (!this.callbacks.onTransferConsentRequested) { return; } try { const transferConsentData = await this.callbacks.onTransferConsentRequested(event); if (transferConsentData) { this.postTransferConsentRequestSucceeded(transferConsentData); } } catch (err) { this.postTransferConsentRequestCancelled(err); console.error('onTransferConsentRequested error', err); } }; this.postMessage = message => { console.debug('postMessage', message); if (this.iframe.contentWindow) { this.iframe.contentWindow.postMessage(JSON.stringify(message), this.apiUrl); } else { console.error('iframe has no content window!', this.iframe); } }; this.parseEvent = message => { try { return JSON.parse(message.data); } catch (error) { console.error(error); return null; } }; this.validateParams = apiUrl => { if (!apiUrl) throw Error('Invalid parameters: dreamsApiEndpoint must be specified'); }; this.validateParams(apiUrl); this.iframe = iframe; this.apiUrl = apiUrl; this.callbacks = callbacks; } async onAccountRequested(event) { if (!this.callbacks.onAccountRequested) { return; } try { const accountRequestedResult = await this.callbacks.onAccountRequested(event); this.postAccountRequestSucceeded(accountRequestedResult); } catch (err) { this.postAccountRequestFailed(err); console.error('onAccountRequested error: ', err); } } } const iframeName = 'dreams-web-sdk-iframe'; const createForm = (endpoint, tokenProps = { type: 'hidden', name: 'token', value: '' }, localeProps = { type: 'hidden', name: 'locale', value: 'en' }) => { const form = document.createElement('form'); form.setAttribute('target', iframeName); form.setAttribute('method', 'POST'); form.setAttribute('action', endpoint); form.setAttribute('class', 'hidden'); const formInputLocale = document.createElement('input'); formInputLocale.setAttribute('type', localeProps.type); formInputLocale.setAttribute('name', localeProps.name); formInputLocale.setAttribute('value', localeProps.value); const formInputToken = document.createElement('input'); formInputToken.setAttribute('type', tokenProps.type); formInputToken.setAttribute('name', tokenProps.name); formInputToken.setAttribute('value', tokenProps.value); const formInputLocation = document.createElement('input'); formInputLocation.setAttribute('type', 'hidden'); formInputLocation.setAttribute('name', 'location'); formInputLocation.setAttribute('value', ''); const formInputTheme = document.createElement('input'); formInputTheme.setAttribute('type', 'hidden'); formInputTheme.setAttribute('name', 'theme'); formInputTheme.setAttribute('value', ''); form.appendChild(formInputLocale); form.appendChild(formInputToken); form.appendChild(formInputLocation); form.appendChild(formInputTheme); return form; }; const createIFrame = (className = iframeName) => { const iframe = document.createElement('iframe'); iframe.setAttribute('name', iframeName); iframe.setAttribute('class', className); return iframe; }; /** * DreamSDK is an utility class responsible for setting up and listening * to messages being exchanged between the your context and Dreams iframe. * * ```typescript * const sdk = new DreamsSDK('https://dreams.api.endpoint'); * sdk.setup(callbacks); * sdk.start(jwk_token, locale); * ``` */ class DreamsSDK { constructor(apiUrl) { this.apiUrl = apiUrl; } /** * @param callbacks as time goes this object might contain more keys. Think about that when writing your code. * @param containerId you are free to specify your value if that's needed. Otherwise, leave the default. * @param iframeClassName if you want the iframe to have a specific class, you can do it via this param. */ setup(callbacks, containerId = 'dreams-web-sdk-container', iframeClassName = iframeName) { if (!this.apiUrl) throw Error('there is no api url specified!'); const dreamDiv = document.getElementById(containerId); if (!dreamDiv) throw Error("can't find dreams web sdk container"); const formTargetUrl = `${this.apiUrl}/users/verify_token`; this.form = createForm(formTargetUrl); this.iframe = createIFrame(iframeClassName); dreamDiv.appendChild(this.form); dreamDiv.appendChild(this.iframe); this.messageHandler = new MessageHandler(this.iframe, this.apiUrl, callbacks); return this.messageHandler; } /** * @param token jwk token for the user * @param locale determines the localization configuration that will be applied. * @param location path to which the user will be redirected to after the token is verified * @param theme determines the color theme that will be applied to the app */ start(token, locale, location, theme) { if (!this.iframe) throw Error('there is no iframe specified!'); if (!this.form) throw Error('there is no form specified!'); if (!this.messageHandler) throw Error('there is no message handler specified!'); const tokenInput = this.form.querySelector("input[name='token']"); if (tokenInput) tokenInput.setAttribute('value', token); const localeInput = this.form.querySelector("input[name='locale']"); if (localeInput) localeInput.setAttribute('value', locale); const locationInput = this.form.querySelector("input[name='location']"); if (location) locationInput.setAttribute('value', location); const themeInput = this.form.querySelector("input[name='theme']"); if (theme) themeInput.setAttribute('value', theme); this.messageHandler.listen(); this.form.submit(); } } export { MessageHandler, DreamsSDK as default }; //# sourceMappingURL=dreams-web-sdk.js.map