All files account-creator.ts

93.54% Statements 29/31
83.33% Branches 15/18
91.66% Functions 11/12
96.42% Lines 27/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 7632x                       1x         3x 3x       3x                         3x 3x 3x 3x 3x   3x 3x 1x   2x   2x 2x     3x   3x 1x 1x             3x   3x       3x 3x   3x 3x   1x  
export interface AccountCreationOptions {
    /** Fully built account creation service URL, query string included. */
    url: string
}
 
export interface AccountCreationPayload {
    /** Name of the account that was created. */
    sa: string
    /** Permission the keys were assigned to, e.g. "active". */
    sp: string
}
 
export class AccountCreator {
    private popupWindow?: Window
    private origin: string
    private popupStatusInterval?: ReturnType<typeof setInterval>
 
    constructor(public readonly options: AccountCreationOptions) {
        this.origin = new URL(options.url).origin
    }
 
    async createAccount(): Promise<AccountCreationPayload> {
        this.popupWindow = window.open(
            this.options.url,
            'targetWindow',
            `toolbar=no,
            location=no,
            status=no,
            menubar=no,
            scrollbars=yes,
            resizable=yes,
            width=400,
            height=600`
        )!
 
        return new Promise((resolve, reject) => {
            const finish = (complete: () => void) => {
                window.removeEventListener('message', listener)
                this.closeDialog()
                complete()
            }
            const listener = (event: MessageEvent) => {
                if (event.origin !== this.origin) {
                    return
                }
                Iif (event.data?.error) {
                    finish(() => reject(new Error(event.data.error)))
                } else if (event.data?.sa && event.data?.sp) {
                    finish(() => resolve(event.data))
                }
            }
            window.addEventListener('message', listener)
 
            this.popupStatusInterval = setInterval(() => {
                if (this.popupWindow && this.popupWindow.closed) {
                    finish(() => reject(new Error('Popup window closed')))
                }
            }, 500)
        })
    }
 
    closeDialog() {
        this.popupWindow?.close()
 
        this.cleanup()
    }
 
    cleanup() {
        if (this.popupStatusInterval) {
            clearInterval(this.popupStatusInterval)
        }
        this.popupStatusInterval = undefined
        this.popupWindow = undefined
    }
}