bitski-provider
Advanced tools
Comparing version 2.1.0 to 3.0.0
# bitski-provider | ||
## 3.0.0 | ||
### Major Changes | ||
- [#364](https://github.com/BitskiCo/bitski-js/pull/364) [`646a99d`](https://github.com/BitskiCo/bitski-js/commit/646a99dd73273d5ee07d78983b5546be927fbe66) Thanks [@pzuraq](https://github.com/pzuraq)! - Add popup method for signing transactions | ||
## 2.1.0 | ||
@@ -4,0 +10,0 @@ |
@@ -20,2 +20,4 @@ import SafeEventEmitter from '@metamask/safe-event-emitter'; | ||
import { assert, expect } from './utils/type-utils'; | ||
import { showIframe } from './signers/iframe'; | ||
import { showPopup } from './signers/popup'; | ||
// Some eth methods result in a subscription being created, and return the id of that subscription. | ||
@@ -37,3 +39,3 @@ // We need to keep track of the subscription id and the chain id it was created on, so we can | ||
constructor(config) { | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
var _a, _b, _c, _d, _e, _f; | ||
this.engine = new JsonRpcEngine(); | ||
@@ -56,7 +58,25 @@ this.events = new SafeEventEmitter(); | ||
} | ||
this.config = Object.assign(Object.assign({}, config), { fetch: (_a = config.fetch) !== null && _a !== void 0 ? _a : fetch, additionalHeaders: Object.assign({ 'X-API-KEY': appId, 'X-CLIENT-ID': appId, 'X-CLIENT-VERSION': "bitski-provider-v2.1.0" }, ((_b = config.additionalHeaders) !== null && _b !== void 0 ? _b : {})), apiBaseUrl: (_c = config.apiBaseUrl) !== null && _c !== void 0 ? _c : BITSKI_API_BASE_URL, signerBaseUrl: (_d = config.signerBaseUrl) !== null && _d !== void 0 ? _d : BITSKI_SIGNER_BASE_URL, store: (_e = config.store) !== null && _e !== void 0 ? _e : new LocalStorageStore(), sign: (_f = config.sign) !== null && _f !== void 0 ? _f : createBrowserSigner() }); | ||
let sign = config.sign; | ||
if (config.signerMethod) { | ||
switch (config.signerMethod) { | ||
case 'popup': | ||
sign = createBrowserSigner({ showPopup }); | ||
break; | ||
case 'iframe': | ||
sign = createBrowserSigner({ showPopup: showIframe }); | ||
break; | ||
case 'redirect': | ||
if (!config.transactionCallbackUrl) { | ||
throw new Error('You must provide a transactionCallbackUrl when using the redirect sign method'); | ||
} | ||
} | ||
} | ||
if (!sign) { | ||
throw new Error('you must provide a signerMethod or custom sign function to BitskiProvider'); | ||
} | ||
this.config = Object.assign(Object.assign({}, config), { fetch: (_a = config.fetch) !== null && _a !== void 0 ? _a : fetch, additionalHeaders: Object.assign({ 'X-API-KEY': appId, 'X-CLIENT-ID': appId, 'X-CLIENT-VERSION': "bitski-provider-v3.0.0" }, ((_b = config.additionalHeaders) !== null && _b !== void 0 ? _b : {})), apiBaseUrl: (_c = config.apiBaseUrl) !== null && _c !== void 0 ? _c : BITSKI_API_BASE_URL, signerBaseUrl: (_d = config.signerBaseUrl) !== null && _d !== void 0 ? _d : BITSKI_SIGNER_BASE_URL, store: (_e = config.store) !== null && _e !== void 0 ? _e : new LocalStorageStore(), sign }); | ||
this.store = new BitskiProviderStateStore(this.config.store); | ||
// Setup the engine | ||
const engine = this.engine; | ||
(_g = config.prependMiddleware) === null || _g === void 0 ? void 0 : _g.forEach((middleware) => | ||
(_f = config.prependMiddleware) === null || _f === void 0 ? void 0 : _f.forEach((middleware) => | ||
// TODO: Need to typecast because JSON RPC engine middleware can't have | ||
@@ -63,0 +83,0 @@ // additional props on it, can get rid of this once we get rid of JSON RPC engine |
@@ -1,21 +0,4 @@ | ||
import { ethErrors } from 'eth-rpc-errors'; | ||
import { IFRAME_MESSAGE_ORIGIN_ENDS_WITH } from '../constants'; | ||
import { fetchJsonWithRetry } from '../utils/fetch'; | ||
import { Dialog } from '../components/dialog'; | ||
import { createBitskiTransaction } from '../utils/transaction'; | ||
const SIGN_REQUEST_QUEUE = []; | ||
if (typeof window !== 'undefined') { | ||
window.addEventListener('message', (event) => { | ||
// Ignore messages from the current window, and from frames that aren't on Bitski.com | ||
if (event.source === window || !event.origin.endsWith(IFRAME_MESSAGE_ORIGIN_ENDS_WITH)) { | ||
return; | ||
} | ||
const data = event.data; | ||
// Ignore message events that don't actually have data | ||
if (data === undefined || data === null) { | ||
return; | ||
} | ||
handleCallback(data); | ||
}); | ||
} | ||
import { getSignerUrl } from './shared'; | ||
/** | ||
@@ -40,16 +23,2 @@ * Responsible for submitting the Transaction object to the API | ||
}; | ||
const getSignerUrl = (transactionId, config) => { | ||
var _a, _b; | ||
const searchParams = (_a = config.signerQueryParams) !== null && _a !== void 0 ? _a : new URLSearchParams(); | ||
if (config.transactionCallbackUrl) { | ||
searchParams.set('redirectURI', config.transactionCallbackUrl); | ||
} | ||
if ((_b = config.waas) === null || _b === void 0 ? void 0 : _b.userId) { | ||
const federatedId = btoa(`${config.appId}:${config.waas.userId}`); | ||
searchParams.set('loginHint', `fa_${federatedId}`); | ||
} | ||
const searchParamsSerialized = searchParams.toString(); | ||
const searchParamsString = searchParamsSerialized !== '' ? `?${searchParamsSerialized}` : ''; | ||
return `${config.signerBaseUrl}/transactions/${transactionId}${searchParamsString}`; | ||
}; | ||
const redirectToCallbackURL = (transaction, config) => { | ||
@@ -61,54 +30,3 @@ window.location.href = getSignerUrl(transaction.id, config); | ||
}; | ||
const showIframe = (transaction, context) => { | ||
let resolve, reject; | ||
const promise = new Promise((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}); | ||
const url = getSignerUrl(transaction.id, context.config); | ||
const iframe = document.createElement('iframe'); | ||
iframe.style.position = 'absolute'; | ||
iframe.style.top = '0'; | ||
iframe.style.left = '0'; | ||
iframe.style.width = '100%'; | ||
iframe.style.height = '100%'; | ||
iframe.frameBorder = '0'; | ||
iframe.src = url; | ||
const dialog = new Dialog(iframe, true); | ||
if (SIGN_REQUEST_QUEUE.length > 0) { | ||
const lastRequest = SIGN_REQUEST_QUEUE[SIGN_REQUEST_QUEUE.length - 1]; | ||
lastRequest.promise.then(() => { | ||
dialog.open(); | ||
}); | ||
} | ||
else { | ||
dialog.open(); | ||
} | ||
SIGN_REQUEST_QUEUE.push({ | ||
resolve, | ||
reject, | ||
promise, | ||
dialog, | ||
}); | ||
return promise; | ||
}; | ||
const handleCallback = async (callback) => { | ||
const currentRequest = SIGN_REQUEST_QUEUE.shift(); | ||
if (!currentRequest) { | ||
return; | ||
} | ||
const { resolve, reject, dialog } = currentRequest; | ||
// Dismiss current dialog | ||
await dialog.close(); | ||
// Call the callback to complete the request | ||
if (callback.error) { | ||
reject(ethErrors.rpc.internal(callback.error)); | ||
} | ||
else { | ||
resolve(callback.result); | ||
} | ||
}; | ||
export default function createBrowserSigner(signerConfig) { | ||
var _a; | ||
const showPopup = (_a = signerConfig === null || signerConfig === void 0 ? void 0 : signerConfig.showPopup) !== null && _a !== void 0 ? _a : showIframe; | ||
export default function createBrowserSigner({ showPopup }) { | ||
return async (method, params, requestContext) => { | ||
@@ -123,9 +41,6 @@ const { config } = requestContext; | ||
else { | ||
// We can submit the transaction and show our authorization modal at the | ||
// same time, so they load in parallel | ||
submitTransaction(transaction, config).catch((error) => handleCallback({ error })); | ||
// Show the modal (await response) | ||
return showPopup(transaction, requestContext); | ||
return showPopup(transaction, requestContext, () => submitTransaction(transaction, config)); | ||
} | ||
}; | ||
} |
@@ -26,2 +26,4 @@ "use strict"; | ||
const type_utils_1 = require("./utils/type-utils"); | ||
const iframe_1 = require("./signers/iframe"); | ||
const popup_1 = require("./signers/popup"); | ||
// Some eth methods result in a subscription being created, and return the id of that subscription. | ||
@@ -43,3 +45,3 @@ // We need to keep track of the subscription id and the chain id it was created on, so we can | ||
constructor(config) { | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
var _a, _b, _c, _d, _e, _f; | ||
this.engine = new json_rpc_engine_1.JsonRpcEngine(); | ||
@@ -62,7 +64,25 @@ this.events = new safe_event_emitter_1.default(); | ||
} | ||
this.config = Object.assign(Object.assign({}, config), { fetch: (_a = config.fetch) !== null && _a !== void 0 ? _a : fetch, additionalHeaders: Object.assign({ 'X-API-KEY': appId, 'X-CLIENT-ID': appId, 'X-CLIENT-VERSION': "bitski-provider-v2.1.0" }, ((_b = config.additionalHeaders) !== null && _b !== void 0 ? _b : {})), apiBaseUrl: (_c = config.apiBaseUrl) !== null && _c !== void 0 ? _c : constants_1.BITSKI_API_BASE_URL, signerBaseUrl: (_d = config.signerBaseUrl) !== null && _d !== void 0 ? _d : constants_1.BITSKI_SIGNER_BASE_URL, store: (_e = config.store) !== null && _e !== void 0 ? _e : new store_1.LocalStorageStore(), sign: (_f = config.sign) !== null && _f !== void 0 ? _f : (0, browser_1.default)() }); | ||
let sign = config.sign; | ||
if (config.signerMethod) { | ||
switch (config.signerMethod) { | ||
case 'popup': | ||
sign = (0, browser_1.default)({ showPopup: popup_1.showPopup }); | ||
break; | ||
case 'iframe': | ||
sign = (0, browser_1.default)({ showPopup: iframe_1.showIframe }); | ||
break; | ||
case 'redirect': | ||
if (!config.transactionCallbackUrl) { | ||
throw new Error('You must provide a transactionCallbackUrl when using the redirect sign method'); | ||
} | ||
} | ||
} | ||
if (!sign) { | ||
throw new Error('you must provide a signerMethod or custom sign function to BitskiProvider'); | ||
} | ||
this.config = Object.assign(Object.assign({}, config), { fetch: (_a = config.fetch) !== null && _a !== void 0 ? _a : fetch, additionalHeaders: Object.assign({ 'X-API-KEY': appId, 'X-CLIENT-ID': appId, 'X-CLIENT-VERSION': "bitski-provider-v3.0.0" }, ((_b = config.additionalHeaders) !== null && _b !== void 0 ? _b : {})), apiBaseUrl: (_c = config.apiBaseUrl) !== null && _c !== void 0 ? _c : constants_1.BITSKI_API_BASE_URL, signerBaseUrl: (_d = config.signerBaseUrl) !== null && _d !== void 0 ? _d : constants_1.BITSKI_SIGNER_BASE_URL, store: (_e = config.store) !== null && _e !== void 0 ? _e : new store_1.LocalStorageStore(), sign }); | ||
this.store = new store_1.BitskiProviderStateStore(this.config.store); | ||
// Setup the engine | ||
const engine = this.engine; | ||
(_g = config.prependMiddleware) === null || _g === void 0 ? void 0 : _g.forEach((middleware) => | ||
(_f = config.prependMiddleware) === null || _f === void 0 ? void 0 : _f.forEach((middleware) => | ||
// TODO: Need to typecast because JSON RPC engine middleware can't have | ||
@@ -69,0 +89,0 @@ // additional props on it, can get rid of this once we get rid of JSON RPC engine |
import { RequestContext, SignFn } from '../types'; | ||
import { Transaction } from '../utils/transaction'; | ||
export declare type ShowSignerPopupFn = (transaction: Transaction, context: RequestContext<unknown>, submitTransaction: () => Promise<Transaction>) => Promise<string>; | ||
export interface BrowserSignerConfig { | ||
showPopup: (transaction: Transaction, context: RequestContext<unknown>) => Promise<string>; | ||
showPopup: ShowSignerPopupFn; | ||
} | ||
export default function createBrowserSigner(signerConfig?: BrowserSignerConfig): SignFn; | ||
export default function createBrowserSigner({ showPopup }: BrowserSignerConfig): SignFn; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const eth_rpc_errors_1 = require("eth-rpc-errors"); | ||
const constants_1 = require("../constants"); | ||
const fetch_1 = require("../utils/fetch"); | ||
const dialog_1 = require("../components/dialog"); | ||
const transaction_1 = require("../utils/transaction"); | ||
const SIGN_REQUEST_QUEUE = []; | ||
if (typeof window !== 'undefined') { | ||
window.addEventListener('message', (event) => { | ||
// Ignore messages from the current window, and from frames that aren't on Bitski.com | ||
if (event.source === window || !event.origin.endsWith(constants_1.IFRAME_MESSAGE_ORIGIN_ENDS_WITH)) { | ||
return; | ||
} | ||
const data = event.data; | ||
// Ignore message events that don't actually have data | ||
if (data === undefined || data === null) { | ||
return; | ||
} | ||
handleCallback(data); | ||
}); | ||
} | ||
const shared_1 = require("./shared"); | ||
/** | ||
@@ -42,18 +25,4 @@ * Responsible for submitting the Transaction object to the API | ||
}; | ||
const getSignerUrl = (transactionId, config) => { | ||
var _a, _b; | ||
const searchParams = (_a = config.signerQueryParams) !== null && _a !== void 0 ? _a : new URLSearchParams(); | ||
if (config.transactionCallbackUrl) { | ||
searchParams.set('redirectURI', config.transactionCallbackUrl); | ||
} | ||
if ((_b = config.waas) === null || _b === void 0 ? void 0 : _b.userId) { | ||
const federatedId = btoa(`${config.appId}:${config.waas.userId}`); | ||
searchParams.set('loginHint', `fa_${federatedId}`); | ||
} | ||
const searchParamsSerialized = searchParams.toString(); | ||
const searchParamsString = searchParamsSerialized !== '' ? `?${searchParamsSerialized}` : ''; | ||
return `${config.signerBaseUrl}/transactions/${transactionId}${searchParamsString}`; | ||
}; | ||
const redirectToCallbackURL = (transaction, config) => { | ||
window.location.href = getSignerUrl(transaction.id, config); | ||
window.location.href = (0, shared_1.getSignerUrl)(transaction.id, config); | ||
// return a non-resolving promise so we block until redirect | ||
@@ -63,54 +32,3 @@ // eslint-disable-next-line @typescript-eslint/no-empty-function | ||
}; | ||
const showIframe = (transaction, context) => { | ||
let resolve, reject; | ||
const promise = new Promise((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}); | ||
const url = getSignerUrl(transaction.id, context.config); | ||
const iframe = document.createElement('iframe'); | ||
iframe.style.position = 'absolute'; | ||
iframe.style.top = '0'; | ||
iframe.style.left = '0'; | ||
iframe.style.width = '100%'; | ||
iframe.style.height = '100%'; | ||
iframe.frameBorder = '0'; | ||
iframe.src = url; | ||
const dialog = new dialog_1.Dialog(iframe, true); | ||
if (SIGN_REQUEST_QUEUE.length > 0) { | ||
const lastRequest = SIGN_REQUEST_QUEUE[SIGN_REQUEST_QUEUE.length - 1]; | ||
lastRequest.promise.then(() => { | ||
dialog.open(); | ||
}); | ||
} | ||
else { | ||
dialog.open(); | ||
} | ||
SIGN_REQUEST_QUEUE.push({ | ||
resolve, | ||
reject, | ||
promise, | ||
dialog, | ||
}); | ||
return promise; | ||
}; | ||
const handleCallback = async (callback) => { | ||
const currentRequest = SIGN_REQUEST_QUEUE.shift(); | ||
if (!currentRequest) { | ||
return; | ||
} | ||
const { resolve, reject, dialog } = currentRequest; | ||
// Dismiss current dialog | ||
await dialog.close(); | ||
// Call the callback to complete the request | ||
if (callback.error) { | ||
reject(eth_rpc_errors_1.ethErrors.rpc.internal(callback.error)); | ||
} | ||
else { | ||
resolve(callback.result); | ||
} | ||
}; | ||
function createBrowserSigner(signerConfig) { | ||
var _a; | ||
const showPopup = (_a = signerConfig === null || signerConfig === void 0 ? void 0 : signerConfig.showPopup) !== null && _a !== void 0 ? _a : showIframe; | ||
function createBrowserSigner({ showPopup }) { | ||
return async (method, params, requestContext) => { | ||
@@ -125,7 +43,4 @@ const { config } = requestContext; | ||
else { | ||
// We can submit the transaction and show our authorization modal at the | ||
// same time, so they load in parallel | ||
submitTransaction(transaction, config).catch((error) => handleCallback({ error })); | ||
// Show the modal (await response) | ||
return showPopup(transaction, requestContext); | ||
return showPopup(transaction, requestContext, () => submitTransaction(transaction, config)); | ||
} | ||
@@ -132,0 +47,0 @@ }; |
@@ -46,3 +46,5 @@ import { EthChainDefinition, EthEvent, EthEventParams, EthMethod, EthMethodParams, EthRequest, EthResult } from 'eth-provider-types'; | ||
declare type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>; | ||
export declare type BitskiProviderConfig<Extra = unknown> = Optional<InternalBitskiProviderConfig<Extra>, 'apiBaseUrl' | 'signerBaseUrl' | 'fetch' | 'additionalHeaders' | 'sign' | 'getUser' | 'store'>; | ||
export declare type BitskiProviderConfig<Extra = unknown> = Optional<InternalBitskiProviderConfig<Extra>, 'apiBaseUrl' | 'signerBaseUrl' | 'fetch' | 'additionalHeaders' | 'sign' | 'getUser' | 'store'> & { | ||
signerMethod?: 'popup' | 'iframe' | 'redirect'; | ||
}; | ||
/** | ||
@@ -49,0 +51,0 @@ * Each provider request is made with a context object. The context object contains |
@@ -12,3 +12,3 @@ { | ||
}, | ||
"version": "2.1.0", | ||
"version": "3.0.0", | ||
"scripts": { | ||
@@ -15,0 +15,0 @@ "test": "jest", |
@@ -18,2 +18,3 @@ # Bitski Provider | ||
clientId: 'your-client-id', | ||
signerMethod: 'popup', | ||
}); | ||
@@ -67,2 +68,5 @@ ``` | ||
// One of the default signer methods that are included with the provider | ||
signerMethod?: 'popup' | 'iframe' | 'redirect'; | ||
// A signing function, see below for more details | ||
@@ -69,0 +73,0 @@ sign?: SignFn; |
@@ -33,4 +33,11 @@ import SafeEventEmitter from '@metamask/safe-event-emitter'; | ||
import { BitskiProviderStateStore, LocalStorageStore } from './store'; | ||
import { BitskiProviderConfig, InternalBitskiProviderConfig, RequestContext } from './types'; | ||
import { | ||
BitskiProviderConfig, | ||
InternalBitskiProviderConfig, | ||
RequestContext, | ||
SignFn, | ||
} from './types'; | ||
import { assert, expect } from './utils/type-utils'; | ||
import { showIframe } from './signers/iframe'; | ||
import { showPopup } from './signers/popup'; | ||
@@ -81,2 +88,25 @@ // global value provided by scripts/insert-package-version.mjs | ||
let sign: SignFn | undefined = config.sign; | ||
if (config.signerMethod) { | ||
switch (config.signerMethod) { | ||
case 'popup': | ||
sign = createBrowserSigner({ showPopup }); | ||
break; | ||
case 'iframe': | ||
sign = createBrowserSigner({ showPopup: showIframe }); | ||
break; | ||
case 'redirect': | ||
if (!config.transactionCallbackUrl) { | ||
throw new Error( | ||
'You must provide a transactionCallbackUrl when using the redirect sign method', | ||
); | ||
} | ||
} | ||
} | ||
if (!sign) { | ||
throw new Error('you must provide a signerMethod or custom sign function to BitskiProvider'); | ||
} | ||
this.config = { | ||
@@ -97,3 +127,3 @@ ...config, | ||
store: config.store ?? new LocalStorageStore(), | ||
sign: config.sign ?? createBrowserSigner(), | ||
sign, | ||
}; | ||
@@ -100,0 +130,0 @@ |
@@ -1,36 +0,7 @@ | ||
import { ethErrors } from 'eth-rpc-errors'; | ||
import { IFRAME_MESSAGE_ORIGIN_ENDS_WITH } from '../constants'; | ||
import { InternalBitskiProviderConfig, RequestContext, SignFn } from '../types'; | ||
import { fetchJsonWithRetry } from '../utils/fetch'; | ||
import { Dialog } from '../components/dialog'; | ||
import { createBitskiTransaction, Transaction } from '../utils/transaction'; | ||
import { showIframe } from './iframe'; | ||
import { getSignerUrl } from './shared'; | ||
// Global state, this manages the currently open signer popup. | ||
interface SignRequestState { | ||
dialog: Dialog; | ||
promise: Promise<string>; | ||
resolve: (v: string | PromiseLike<string>) => void; | ||
reject: (e: unknown) => void; | ||
} | ||
const SIGN_REQUEST_QUEUE: SignRequestState[] = []; | ||
if (typeof window !== 'undefined') { | ||
window.addEventListener('message', (event: MessageEvent) => { | ||
// Ignore messages from the current window, and from frames that aren't on Bitski.com | ||
if (event.source === window || !event.origin.endsWith(IFRAME_MESSAGE_ORIGIN_ENDS_WITH)) { | ||
return; | ||
} | ||
const data = event.data; | ||
// Ignore message events that don't actually have data | ||
if (data === undefined || data === null) { | ||
return; | ||
} | ||
handleCallback(data); | ||
}); | ||
} | ||
/** | ||
@@ -62,21 +33,2 @@ * Responsible for submitting the Transaction object to the API | ||
const getSignerUrl = (transactionId: string, config: InternalBitskiProviderConfig) => { | ||
const searchParams = config.signerQueryParams ?? new URLSearchParams(); | ||
if (config.transactionCallbackUrl) { | ||
searchParams.set('redirectURI', config.transactionCallbackUrl); | ||
} | ||
if (config.waas?.userId) { | ||
const federatedId = btoa(`${config.appId}:${config.waas.userId}`); | ||
searchParams.set('loginHint', `fa_${federatedId}`); | ||
} | ||
const searchParamsSerialized = searchParams.toString(); | ||
const searchParamsString = searchParamsSerialized !== '' ? `?${searchParamsSerialized}` : ''; | ||
return `${config.signerBaseUrl}/transactions/${transactionId}${searchParamsString}`; | ||
}; | ||
const redirectToCallbackURL = ( | ||
@@ -93,72 +45,12 @@ transaction: Transaction, | ||
const showIframe = ( | ||
export type ShowSignerPopupFn = ( | ||
transaction: Transaction, | ||
context: RequestContext<unknown>, | ||
): Promise<string> => { | ||
let resolve, reject; | ||
const promise = new Promise<string>((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}); | ||
const url = getSignerUrl(transaction.id, context.config); | ||
const iframe = document.createElement('iframe'); | ||
iframe.style.position = 'absolute'; | ||
iframe.style.top = '0'; | ||
iframe.style.left = '0'; | ||
iframe.style.width = '100%'; | ||
iframe.style.height = '100%'; | ||
iframe.frameBorder = '0'; | ||
iframe.src = url; | ||
const dialog = new Dialog(iframe, true); | ||
if (SIGN_REQUEST_QUEUE.length > 0) { | ||
const lastRequest = SIGN_REQUEST_QUEUE[SIGN_REQUEST_QUEUE.length - 1]; | ||
lastRequest.promise.then(() => { | ||
dialog.open(); | ||
}); | ||
} else { | ||
dialog.open(); | ||
} | ||
SIGN_REQUEST_QUEUE.push({ | ||
resolve, | ||
reject, | ||
promise, | ||
dialog, | ||
}); | ||
return promise; | ||
}; | ||
const handleCallback = async (callback: any): Promise<void> => { | ||
const currentRequest = SIGN_REQUEST_QUEUE.shift(); | ||
if (!currentRequest) { | ||
return; | ||
} | ||
const { resolve, reject, dialog } = currentRequest; | ||
// Dismiss current dialog | ||
await dialog.close(); | ||
// Call the callback to complete the request | ||
if (callback.error) { | ||
reject(ethErrors.rpc.internal(callback.error)); | ||
} else { | ||
resolve(callback.result); | ||
} | ||
}; | ||
submitTransaction: () => Promise<Transaction>, | ||
) => Promise<string>; | ||
export interface BrowserSignerConfig { | ||
showPopup: (transaction: Transaction, context: RequestContext<unknown>) => Promise<string>; | ||
showPopup: ShowSignerPopupFn; | ||
} | ||
export default function createBrowserSigner(signerConfig?: BrowserSignerConfig): SignFn { | ||
const showPopup = signerConfig?.showPopup ?? showIframe; | ||
export default function createBrowserSigner({ showPopup }: BrowserSignerConfig): SignFn { | ||
return async (method, params, requestContext): Promise<string> => { | ||
@@ -178,10 +70,6 @@ const { config } = requestContext; | ||
} else { | ||
// We can submit the transaction and show our authorization modal at the | ||
// same time, so they load in parallel | ||
submitTransaction(transaction, config).catch((error) => handleCallback({ error })); | ||
// Show the modal (await response) | ||
return showPopup(transaction, requestContext); | ||
return showPopup(transaction, requestContext, () => submitTransaction(transaction, config)); | ||
} | ||
}; | ||
} |
@@ -80,3 +80,5 @@ import { | ||
'apiBaseUrl' | 'signerBaseUrl' | 'fetch' | 'additionalHeaders' | 'sign' | 'getUser' | 'store' | ||
>; | ||
> & { | ||
signerMethod?: 'popup' | 'iframe' | 'redirect'; | ||
}; | ||
@@ -83,0 +85,0 @@ /** |
@@ -8,2 +8,3 @@ import { EthMethod } from 'eth-provider-types'; | ||
import { Mainnet } from '../../src/constants'; | ||
import { showIframe } from '../../src/signers/iframe'; | ||
@@ -446,3 +447,6 @@ const getAccessToken = async () => 'test-access-token'; | ||
expect.assertions(5); | ||
const provider = createTestProvider({ sign: createBrowserSigner(), getAccessToken }); | ||
const provider = createTestProvider({ | ||
sign: createBrowserSigner({ showPopup: showIframe }), | ||
getAccessToken, | ||
}); | ||
@@ -502,3 +506,3 @@ fetchMock.mockResponse(async (req) => { | ||
expect.assertions(4); | ||
const provider = createTestProvider({ sign: createBrowserSigner() }); | ||
const provider = createTestProvider({ sign: createBrowserSigner({ showPopup: showIframe }) }); | ||
@@ -559,3 +563,3 @@ fetchMock.mockResponse(async (req) => { | ||
expect.assertions(0); | ||
createTestProvider({ sign: createBrowserSigner() }); | ||
createTestProvider({ sign: createBrowserSigner({ showPopup: showIframe }) }); | ||
@@ -577,3 +581,3 @@ // Nothing should happen, no errors, etc | ||
expect.assertions(4); | ||
const provider = createTestProvider({ sign: createBrowserSigner() }); | ||
const provider = createTestProvider({ sign: createBrowserSigner({ showPopup: showIframe }) }); | ||
@@ -644,3 +648,3 @@ fetchMock.mockResponse(async (req) => { | ||
expect.assertions(4); | ||
const provider = createTestProvider({ sign: createBrowserSigner() }); | ||
const provider = createTestProvider({ sign: createBrowserSigner({ showPopup: showIframe }) }); | ||
@@ -707,3 +711,3 @@ fetchMock.mockResponse(async (req) => { | ||
expect.assertions(4); | ||
const provider = createTestProvider({ sign: createBrowserSigner() }); | ||
const provider = createTestProvider({ sign: createBrowserSigner({ showPopup: showIframe }) }); | ||
@@ -775,3 +779,3 @@ fetchMock.mockResponse(async (req) => { | ||
expect.assertions(8); | ||
const provider = createTestProvider({ sign: createBrowserSigner() }); | ||
const provider = createTestProvider({ sign: createBrowserSigner({ showPopup: showIframe }) }); | ||
@@ -852,3 +856,3 @@ fetchMock.mockResponse(async (req) => { | ||
const provider = createTestProvider({ | ||
sign: createBrowserSigner(), | ||
sign: createBrowserSigner({ showPopup: showIframe }), | ||
transactionCallbackUrl: 'https://test.com/callback', | ||
@@ -855,0 +859,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
392312
178
8189
122