Swap to eslint (#72)

* 626 problems (430 errors, 196 warnings)

* A start.

* < 200

* 80

* 0
This commit is contained in:
Jaco Greeff
2019-07-12 20:09:44 +02:00
committed by GitHub
parent da16a494e8
commit c70d9a0e63
59 changed files with 598 additions and 643 deletions

3
.eslintignore Normal file
View File

@@ -0,0 +1,3 @@
**/build/*
**/coverage/*
**/node_modules/*

1
.eslintrc.js Normal file
View File

@@ -0,0 +1 @@
module.exports = require('@polkadot/dev-react/config/eslint');

View File

@@ -1,3 +1,4 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const config = require('@polkadot/dev/config/jest');
module.exports = Object.assign({}, config, {

View File

@@ -19,7 +19,7 @@
"build": "NODE_ENV=production polkadot-dev-build-ts",
"build:zip": "(cd packages/extension/build && zip -r -FS ../../../master-build.zip *)",
"check": "yarn lint",
"lint": "tslint --project . && tsc --noEmit --pretty",
"lint": "eslint --ext .js,.jsx,.ts,.tsx . && tsc --noEmit --pretty",
"clean": "polkadot-dev-clean-build",
"postinstall": "polkadot-dev-yarn-only",
"test": "echo \"no tests... yet\"",

View File

@@ -8,5 +8,5 @@ import singleSource from './singleSource';
export default function initCompat (): Promise<boolean> {
return Promise.all([
singleSource()
]).then(() => true);
]).then((): boolean => true);
}

View File

@@ -3,34 +3,34 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { Signer } from '@polkadot/api/types';
import { InjectedAccount, InjectedWindow } from '../types';
import { Injected, InjectedAccount, InjectedWindow } from '../types';
// RxJs interface, only the bare-bones of what we need here
type Subscriber<T> = {
interface Subscriber<T> {
subscribe: (cb: (value: T) => void) => {
unsubscribe (): any
}
};
unsubscribe (): void;
};
}
type SingleSourceAccount = {
address: string,
assets: Array<{ assetId: number }>,
name: string
};
interface SingleSourceAccount {
address: string;
assets: { assetId: number }[];
name: string;
}
type SingleSource = {
accounts$: Subscriber<Array<SingleSourceAccount>>,
environment$: Subscriber<string>,
signer: Signer
};
interface SingleSource {
accounts$: Subscriber<SingleSourceAccount[]>;
environment$: string[];
signer: Signer;
}
type SingleWindow = Window & InjectedWindow & {
SingleSource: SingleSource
SingleSource: SingleSource;
};
// transfor the SingleSource accounts into a simple address/name array
function transformAccounts (accounts: Array<SingleSourceAccount>): Array<InjectedAccount> {
return accounts.map(({ address, name }) => ({
function transformAccounts (accounts: SingleSourceAccount[]): InjectedAccount[] {
return accounts.map(({ address, name }): InjectedAccount => ({
address,
name
}));
@@ -38,24 +38,25 @@ function transformAccounts (accounts: Array<SingleSourceAccount>): Array<Injecte
// add a compat interface of SingleSource to window.injectedWeb3
function injectSingleSource (win: SingleWindow): void {
let accounts: Array<InjectedAccount> = [];
let accounts: InjectedAccount[] = [];
// we don't yet have an accounts subscribe on the interface, simply get the
// accounts and store them, any get will resolve the last found values
win.SingleSource.accounts$.subscribe((_accounts) => {
win.SingleSource.accounts$.subscribe((_accounts): void => {
accounts = transformAccounts(_accounts);
});
// decorate the compat interface
win.injectedWeb3['SingleSource'] = {
enable: async (origin: string) => ({
// eslint-disable-next-line @typescript-eslint/no-unused-vars
enable: async (origin: string): Promise<Injected> => ({
accounts: {
get: async () =>
get: async (): Promise<InjectedAccount[]> =>
accounts,
subscribe: (cb: (accounts: Array<InjectedAccount>) => any) => {
const sub = win.SingleSource.accounts$.subscribe((accounts) =>
cb(transformAccounts(accounts))
);
subscribe: (cb: (accounts: InjectedAccount[]) => void): () => void => {
const sub = win.SingleSource.accounts$.subscribe((accounts): void => {
cb(transformAccounts(accounts));
});
return (): void => {
sub.unsubscribe();
@@ -71,8 +72,8 @@ function injectSingleSource (win: SingleWindow): void {
// returns the SingleSource instance, as per
// https://github.com/cennznet/singlesource-extension/blob/f7cb35b54e820bf46339f6b88ffede1b8e140de0/react-example/src/App.js#L19
export default function initSingleSource (): Promise<boolean> {
return new Promise((resolve) => {
window.addEventListener('load', () => {
return new Promise((resolve): void => {
window.addEventListener('load', (): void => {
const win = window as SingleWindow;
if (win.SingleSource) {

View File

@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { InjectedAccount, InjectedAccountWithMeta, InjectedExtension, InjectedWindow, Unsubcall } from './types';
import { Injected, InjectedAccount, InjectedAccountWithMeta, InjectedExtension, InjectedExtensionInfo, InjectedWindow, Unsubcall } from './types';
// our extension adaptor for other kinds of extensions
import compatInjector from './compat';
@@ -24,8 +24,8 @@ function throwError (method: string): never {
}
// internal helper to map from Array<InjectedAccount> -> Array<InjectedAccountWithMeta>
function mapAccounts (source: string, list: Array<InjectedAccount>): Array<InjectedAccountWithMeta> {
return list.map(({ address, name }) => ({
function mapAccounts (source: string, list: InjectedAccount[]): InjectedAccountWithMeta[] {
return list.map(({ address, name }): InjectedAccountWithMeta => ({
address,
meta: { name, source }
}));
@@ -35,65 +35,70 @@ function mapAccounts (source: string, list: Array<InjectedAccount>): Array<Injec
let isWeb3Injected = web3IsInjected();
// we keep the last promise created around (for queries)
let web3EnablePromise: Promise<Array<InjectedExtension>> | null = null;
let web3EnablePromise: Promise<InjectedExtension[]> | null = null;
export { isWeb3Injected, web3EnablePromise };
// enables all the providers found on the injected window interface
export function web3Enable (originName: string): Promise<Array<InjectedExtension>> {
web3EnablePromise = compatInjector().then(() =>
Promise.all(
Object.entries(win.injectedWeb3).map(([name, { enable, version }]) =>
Promise.all([
Promise.resolve({ name, version }),
enable(originName).catch((error: Error) => {
console.error(`Error initializing ${name}: ${error.message}`);
})
])
)
)
.then((values) =>
values
.filter(([, ext]) => ext)
.map(([info, ext]) => {
// if we don't have an accounts subscriber, add a single-shot version
if (ext && !ext.accounts.subscribe) {
ext.accounts.subscribe = (cb: (accounts: Array<InjectedAccount>) => any): Unsubcall => {
ext.accounts.get().then(cb).catch(console.error);
export function web3Enable (originName: string): Promise<InjectedExtension[]> {
web3EnablePromise = compatInjector()
.then((): Promise<InjectedExtension[]> =>
Promise
.all(
Object.entries(win.injectedWeb3).map(([name, { enable, version }]): Promise<[InjectedExtensionInfo, Injected | void]> =>
Promise.all([
Promise.resolve({ name, version }),
enable(originName).catch((error: Error): void => {
console.error(`Error initializing ${name}: ${error.message}`);
})
])
)
)
.then((values: [InjectedExtensionInfo, Injected | void][]): InjectedExtension[] =>
values
.filter(([, ext]): boolean => !!ext)
.map(([info, ext]): InjectedExtension => {
// if we don't have an accounts subscriber, add a single-shot version
if (ext && !ext.accounts.subscribe) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ext.accounts.subscribe = (cb: (accounts: InjectedAccount[]) => any): Unsubcall => {
ext.accounts.get().then(cb).catch(console.error);
return (): void => {
// no ubsubscribe needed, this is a single-shot
};
};
}
return (): void => {
// no ubsubscribe needed, this is a single-shot
};
};
}
return { ...info, ...ext } as InjectedExtension;
const injected: Partial<InjectedExtension> = { ...info, ...ext };
return injected as InjectedExtension;
})
)
.catch((): InjectedExtension[] => [] as InjectedExtension[])
.then((values): InjectedExtension[] => {
const names = values.map(({ name, version }): string => `${name}/${version}`);
isWeb3Injected = web3IsInjected();
console.log(`web3Enable: Enabled ${values.length} extension${values.length !== 1 ? 's' : ''}: ${names.join(', ')}`);
return values;
})
)
.catch(() => [] as Array<InjectedExtension>)
.then((values) => {
const names = values.map(({ name, version }) => `${name}/${version}`);
isWeb3Injected = web3IsInjected();
console.log(`web3Enable: Enabled ${values.length} extension${values.length !== 1 ? 's' : ''}: ${names.join(', ')}`);
return values;
})
);
);
return web3EnablePromise;
}
// retrieve all the accounts accross all providers
export async function web3Accounts (): Promise<Array<InjectedAccountWithMeta>> {
export async function web3Accounts (): Promise<InjectedAccountWithMeta[]> {
if (!web3EnablePromise) {
return throwError('web3Accounts');
}
const accounts: Array<InjectedAccountWithMeta> = [];
const accounts: InjectedAccountWithMeta[] = [];
const injected = await web3EnablePromise;
const retrieved = await Promise.all(
injected.map(async ({ accounts, name: source }) => {
injected.map(async ({ accounts, name: source }): Promise<InjectedAccountWithMeta[]> => {
try {
const list = await accounts.get();
@@ -105,57 +110,46 @@ export async function web3Accounts (): Promise<Array<InjectedAccountWithMeta>> {
})
);
retrieved.forEach((result) => accounts.push(...result));
retrieved.forEach((result): void => {
accounts.push(...result);
});
const addresses = accounts.map(({ address }) => address);
const addresses = accounts.map(({ address }): string => address);
console.log(`web3Accounts: Found ${accounts.length} address${accounts.length !== 1 ? 'es' : ''}: ${addresses.join(', ')}`);
return accounts;
}
export async function web3AccountsSubscribe (cb: (accounts: Array<InjectedAccountWithMeta>) => any): Promise<Unsubcall> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function web3AccountsSubscribe (cb: (accounts: InjectedAccountWithMeta[]) => any): Promise<Unsubcall> {
if (!web3EnablePromise) {
return throwError('web3AccountsSubscribe');
}
const accounts: { [source: string]: Array<InjectedAccount> } = {};
const accounts: Record<string, InjectedAccount[]> = {};
const triggerUpdate = (): void => {
cb(Object.entries(accounts).reduce((result, [source, list]) => {
cb(Object.entries(accounts).reduce((result, [source, list]): InjectedAccountWithMeta[] => {
result.push(...mapAccounts(source, list));
return result;
}, [] as Array<InjectedAccountWithMeta>));
}, [] as InjectedAccountWithMeta[]));
};
const unsubs = (await web3EnablePromise).map(({ accounts: { subscribe }, name: source }) =>
subscribe((result) => {
const unsubs = (await web3EnablePromise).map(({ accounts: { subscribe }, name: source }): Unsubcall =>
subscribe((result): void => {
accounts[source] = result;
triggerUpdate();
})
);
return (): void => {
unsubs.forEach((unsub) => unsub());
unsubs.forEach((unsub): void => {
unsub();
});
};
}
// find a specific provider based on an address
export async function web3FromAddress (address: string): Promise<InjectedExtension> {
if (!web3EnablePromise) {
return throwError('web3FromAddress');
}
const accounts = await web3Accounts();
const found = address && accounts.find((account) => account.address === address);
if (!found) {
throw new Error(`web3FromAddress: Unable to find injected ${address}`);
}
return web3FromSource(found.meta.source);
}
// find a specific provider based on the name
export async function web3FromSource (source: string): Promise<InjectedExtension> {
if (!web3EnablePromise) {
@@ -163,7 +157,7 @@ export async function web3FromSource (source: string): Promise<InjectedExtension
}
const sources = await web3EnablePromise;
const found = source && sources.find(({ name }) => name === source);
const found = source && sources.find(({ name }): boolean => name === source);
if (!found) {
throw new Error(`web3FromSource: Unable to find an injected ${source}`);
@@ -171,3 +165,19 @@ export async function web3FromSource (source: string): Promise<InjectedExtension
return found;
}
// find a specific provider based on an address
export async function web3FromAddress (address: string): Promise<InjectedExtension> {
if (!web3EnablePromise) {
return throwError('web3FromAddress');
}
const accounts = await web3Accounts();
const found = address && accounts.find((account): boolean => account.address === address);
if (!found) {
throw new Error(`web3FromAddress: Unable to find injected ${address}`);
}
return web3FromSource(found.meta.source);
}

View File

@@ -14,17 +14,18 @@ export interface InjectedAccount {
export interface InjectedAccountWithMeta {
address: string;
meta: {
name: string,
source: string
name: string;
source: string;
};
}
export interface InjectedAccounts {
get: () => Promise<Array<InjectedAccount>>;
subscribe: (cb: (accounts: Array<InjectedAccount>) => any) => Unsubcall;
get: () => Promise<InjectedAccount[]>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
subscribe: (cb: (accounts: InjectedAccount[]) => any) => Unsubcall;
}
export interface InjectedSigner extends Signer {}
export type InjectedSigner = Signer;
export interface InjectedExtensionInfo {
name: string;
@@ -41,10 +42,8 @@ export interface InjectedWindowProvider {
version: string;
}
export type InjectedWindow = Window & {
injectedWeb3: {
[index: string]: InjectedWindowProvider
}
};
export interface InjectedWindow extends Window {
injectedWeb3: Record<string, InjectedWindowProvider>;
}
export type InjectedExtension = InjectedExtensionInfo & Injected;

View File

@@ -11,22 +11,22 @@ import { ActionBar, Address, Link, withOnAction } from '../../components';
import { editAccount } from '../../messaging';
import { Name } from '../../partials';
type Props = {
address: string,
className?: string,
onAction: OnActionFromCtx
};
interface Props {
address: string;
className?: string;
onAction: OnActionFromCtx;
}
function Account ({ address, className, onAction }: Props) {
function Account ({ address, className, onAction }: Props): React.ReactElement<Props> {
const [isEditing, setEditing] = useState(false);
const [editedname, setName] = useState<string | null>(null);
const toggleEdit = () =>
const toggleEdit = (): void =>
setEditing(!isEditing);
const saveChanges = () => {
const saveChanges = (): void => {
if (editedname && editedname !== name) {
editAccount(address, editedname)
.then(() => onAction())
.then((): void => onAction())
.catch(console.error);
}

View File

@@ -9,18 +9,18 @@ import React from 'react';
import { Button, Header, Tip, withAccounts } from '../../components';
import Account from './Account';
type Props = {
accounts: AccountsFromCtx
};
interface Props {
accounts: AccountsFromCtx;
}
function Accounts ({ accounts }: Props) {
function Accounts ({ accounts }: Props): React.ReactElement<Props> {
return (
<div>
<Header label='accounts' />
{
(accounts.length === 0)
? <Tip header='add accounts' type='warn'>You currently don't have any accounts. Either create a new account or if you have an existing account you wish to use, import it with the seed phrase</Tip>
: accounts.map(({ address }) => (
? <Tip header='add accounts' type='warn'>You currently don&apos;t have any accounts. Either create a new account or if you have an existing account you wish to use, import it with the seed phrase</Tip>
: accounts.map(({ address }): React.ReactNode => (
<Account
address={address}
key={address}

View File

@@ -11,23 +11,23 @@ import styled from 'styled-components';
import { ActionBar, Button, Icon, IconBox, Link, Tip, defaults, withOnAction } from '../../components';
import { approveAuthRequest, rejectAuthRequest } from '../../messaging';
type Props = {
authId: string,
className?: string,
isFirst: boolean,
onAction: OnActionFromCtx,
request: MessageAuthorize,
url: string
};
interface Props {
authId: string;
className?: string;
isFirst: boolean;
onAction: OnActionFromCtx;
request: MessageAuthorize;
url: string;
}
function Request ({ authId, className, isFirst, onAction, request: { origin }, url }: Props) {
const onApprove = () =>
function Request ({ authId, className, isFirst, onAction, request: { origin }, url }: Props): React.ReactElement<Props> {
const onApprove = (): Promise<void> =>
approveAuthRequest(authId)
.then(() => onAction())
.then((): void => onAction())
.catch(console.error);
const onReject = () =>
const onReject = (): Promise<void> =>
rejectAuthRequest(authId)
.then(() => onAction())
.then((): void => onAction())
.catch(console.error);
return (

View File

@@ -9,15 +9,15 @@ import React from 'react';
import { Header, withAuthRequests } from '../../components';
import Request from './Request';
type Props = {
requests: AuthRequestsFromCtx
};
interface Props {
requests: AuthRequestsFromCtx;
}
function Authorize ({ requests }: Props) {
function Authorize ({ requests }: Props): React.ReactElement<Props> {
return (
<div>
<Header label='authorize' />
{requests.map(([id, request, url], index) => (
{requests.map(([id, request, url], index): React.ReactNode => (
<Request
authId={id}
isFirst={index === 0}

View File

@@ -10,27 +10,27 @@ import { Address, Button, Header, Loading, TextArea, withOnAction } from '../com
import { createAccount, createSeed } from '../messaging';
import { Back, Name, Password } from '../partials';
type Props = {
onAction: OnActionFromCtx
};
interface Props {
onAction: OnActionFromCtx;
}
function Create ({ onAction }: Props) {
const [account, setAccount] = useState<null | { address: string, seed: string }>(null);
function Create ({ onAction }: Props): React.ReactElement<Props> {
const [account, setAccount] = useState<null | { address: string; seed: string }>(null);
const [name, setName] = useState<string | null>(null);
const [password, setPassword] = useState<string | null>(null);
useEffect(() => {
useEffect((): void => {
createSeed()
.then(setAccount)
.catch(console.error);
}, []);
// FIXME Duplicated between here and Import.tsx
const onCreate = () => {
const onCreate = (): void => {
// this should always be the case
if (name && password && account) {
createAccount(name, password, account.seed)
.then(() => onAction('/'))
.then((): void => onAction('/'))
.catch(console.error);
}
};

View File

@@ -11,14 +11,14 @@ import { Address, Button, Header, Tip, withOnAction } from '../components';
import { forgetAccount } from '../messaging';
import { Back } from '../partials';
type Props = RouteComponentProps<{ address: string }> & {
onAction: OnActionFromCtx
};
interface Props extends RouteComponentProps<{ address: string }> {
onAction: OnActionFromCtx;
}
function Forget ({ match: { params: { address } }, onAction }: Props) {
const onClick = () =>
function Forget ({ match: { params: { address } }, onAction }: Props): React.ReactElement<Props> {
const onClick = (): Promise<void> =>
forgetAccount(address)
.then(() => onAction('/'))
.then((): void => onAction('/'))
.catch(console.error);
return (

View File

@@ -10,26 +10,26 @@ import { Address, Button, Header, TextArea, withOnAction } from '../components';
import { createAccount, validateSeed } from '../messaging';
import { Back, Name, Password } from '../partials';
type Props = {
onAction: OnActionFromCtx
};
interface Props {
onAction: OnActionFromCtx;
}
function Import ({ onAction }: Props) {
const [account, setAccount] = useState<null | { address: string, seed: string }>(null);
function Import ({ onAction }: Props): React.ReactElement<Props> {
const [account, setAccount] = useState<null | { address: string; seed: string }>(null);
const [name, setName] = useState<string | null>(null);
const [password, setPassword] = useState<string | null>(null);
const onChangeSeed = (seed: string) =>
const onChangeSeed = (seed: string): Promise<void> =>
validateSeed(seed)
.then(setAccount)
.catch(() => setAccount(null));
.catch((): void => setAccount(null));
// FIXME Duplicated between here and Create.tsx
const onCreate = () => {
const onCreate = (): void => {
// this should always be the case
if (name && password && account) {
createAccount(name, password, account.seed)
.then(() => onAction('/'))
.then((): void => onAction('/'))
.catch(console.error);
}
};

View File

@@ -9,9 +9,10 @@ import findChain from '@polkadot/extension/chains';
import { Metadata, Method, ExtrinsicEra } from '@polkadot/types';
import { formatNumber } from '@polkadot/util';
type MethodJson = {
args: { [index: string]: any }
};
interface MethodJson {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
args: Record<string, any>;
}
interface Props {
blockNumber: number;
@@ -24,7 +25,7 @@ interface Props {
url: string;
}
function renderMethod (data: string, meta?: Metadata | null) {
function renderMethod (data: string, meta?: Metadata | null): React.ReactNode {
if (!meta) {
return (
<tr>
@@ -73,7 +74,7 @@ function renderMortality (era: ExtrinsicEra, blockNumber: number): string {
return `mortal (birth #${formatNumber(mortal.birth(blockNumber))}, death #${formatNumber(mortal.death(blockNumber))})`;
}
function Details ({ blockNumber, className, genesisHash, isDecoded, era, method, nonce, url }: Props) {
function Details ({ blockNumber, className, genesisHash, isDecoded, era, method, nonce, url }: Props): React.ReactElement<Props> {
const chain = findChain(genesisHash);
const eera = new ExtrinsicEra(era);

View File

@@ -12,22 +12,22 @@ import { approveSignRequest, cancelSignRequest } from '../../messaging';
import Details from './Details';
import Unlock from './Unlock';
type Props = {
isFirst: boolean,
onAction: OnActionFromCtx,
request: MessageExtrinsicSign,
signId: string,
url: string
};
interface Props {
isFirst: boolean;
onAction: OnActionFromCtx;
request: MessageExtrinsicSign;
signId: string;
url: string;
}
function Request ({ isFirst, onAction, request: { address, blockNumber, era, genesisHash, method, nonce }, signId, url }: Props) {
const onCancel = () =>
function Request ({ isFirst, onAction, request: { address, blockNumber, era, genesisHash, method, nonce }, signId, url }: Props): React.ReactElement<Props> {
const onCancel = (): Promise<void> =>
cancelSignRequest(signId)
.then(() => onAction())
.then((): void => onAction())
.catch(console.error);
const onSign = (password: string) =>
const onSign = (password: string): Promise<void> =>
approveSignRequest(signId, password)
.then(() => onAction());
.then((): void => onAction());
return (
<Address address={address}>

View File

@@ -6,20 +6,20 @@ import React, { useState, useEffect } from 'react';
import { Button, Input } from '../../components';
type Props = {
className?: string,
onSign: (password: string) => Promise<void>
};
interface Props {
className?: string;
onSign: (password: string) => Promise<void>;
}
export default function Unlock ({ className, onSign }: Props) {
export default function Unlock ({ className, onSign }: Props): React.ReactElement<Props> {
const [error, setError] = useState('');
const [password, setPassword] = useState('');
const onClick = () =>
const onClick = (): Promise<void> =>
onSign(password)
.catch((error) => setError(error.message));
.catch((error): void => setError(error.message));
useEffect(() => {
useEffect((): void => {
if (error) {
setError('');
}

View File

@@ -9,15 +9,15 @@ import React from 'react';
import { Header, withSignRequests } from '../../components';
import Request from './Request';
type Props = {
requests: SignRequestsFromCtx
};
interface Props {
requests: SignRequestsFromCtx;
}
function Signing ({ requests }: Props) {
function Signing ({ requests }: Props): React.ReactElement<Props> {
return (
<div>
<Header label='transactions' />
{requests.map(([id, request, url], index) => (
{requests.map(([id, request, url], index): React.ReactNode => (
<Request
isFirst={index === 0}
key={id}

View File

@@ -8,11 +8,11 @@ import React from 'react';
import { Box, Button, Header, withOnAction } from '../components';
type Props = {
onAction: OnActionFromCtx
};
interface Props {
onAction: OnActionFromCtx;
}
function Welcome ({ onAction }: Props) {
function Welcome ({ onAction }: Props): React.ReactElement<Props> {
const onClick = (): void => {
window.localStorage.setItem('welcome_read', 'ok');
onAction();
@@ -26,7 +26,7 @@ function Welcome ({ onAction }: Props) {
<ul>
<li>We do not send any clicks, pageviews or events to a central server</li>
<li>We do not use any trackers or analytics</li>
<li>We don't collect keys, addresses or any information - your information never leaves this machine</li>
<li>We don&apos;t collect keys, addresses or any information - your information never leaves this machine</li>
</ul>
... we are not in the information collection business (even anonymized).
<Button

View File

@@ -19,12 +19,11 @@ import Import from './Import';
import Signing from './Signing';
import Welcome from './Welcome';
type Props = {};
export default function Popup (props: Props) {
const [accounts, setAccounts] = useState<null | Array<KeyringJson>>(null);
const [authRequests, setAuthRequests] = useState<null | Array<AuthorizeRequest>>(null);
const [signRequests, setSignRequests] = useState<null | Array<SigningRequest>>(null);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default function Popup (props: {}): React.ReactElement<{}> {
const [accounts, setAccounts] = useState<null | KeyringJson[]>(null);
const [authRequests, setAuthRequests] = useState<null | AuthorizeRequest[]>(null);
const [signRequests, setSignRequests] = useState<null | SigningRequest[]>(null);
const [isWelcomeDone, setWelcomeDone] = useState(false);
const onAction = (to?: string): void => {

View File

@@ -5,12 +5,12 @@
import React from 'react';
import styled from 'styled-components';
type Props = {
interface Props {
children: React.ReactNode;
className?: string;
};
}
function ActionBar ({ children, className }: Props) {
function ActionBar ({ children, className }: Props): React.ReactElement<Props> {
return (
<div className={className}>
{children}

View File

@@ -11,17 +11,17 @@ import Identicon from '@polkadot/ui-identicon';
import IconBox from './IconBox';
import { withAccounts } from './contexts';
type Props = {
accounts: AccountsFromCtx,
address?: string | null,
interface Props {
accounts: AccountsFromCtx;
address?: string | null;
children?: React.ReactNode;
className?: string,
name?: React.ReactNode | null,
theme?: 'polkadot' | 'substrate'
};
className?: string;
name?: React.ReactNode | null;
theme?: 'polkadot' | 'substrate';
}
function Address ({ accounts, address, children, className, name, theme = 'polkadot' }: Props) {
const account = accounts.find((account) => account.address === address);
function Address ({ accounts, address, children, className, name, theme = 'polkadot' }: Props): React.ReactElement<Props> {
const account = accounts.find((account): boolean => account.address === address);
return (
<IconBox

View File

@@ -7,12 +7,12 @@ import styled from 'styled-components';
import defaults from './defaults';
type Props = {
interface Props {
children: React.ReactNode;
className?: string;
};
}
function Box ({ children, className }: Props) {
function Box ({ children, className }: Props): React.ReactElement<Props> {
return (
<article className={className}>
{children}

View File

@@ -7,20 +7,20 @@ import styled from 'styled-components';
import defaults from './defaults';
type Props = {
interface Props {
className?: string;
children?: React.ReactNode,
isDanger?: boolean,
isDisabled?: boolean,
isSmall?: boolean,
label?: string,
onClick?: () => any,
to?: string
};
children?: React.ReactNode;
isDanger?: boolean;
isDisabled?: boolean;
isSmall?: boolean;
label?: string;
onClick?: () => void | Promise<void>;
to?: string;
}
const DISABLED_OPACITY = '0.3';
function Button ({ children, className, isDisabled, label, onClick, to }: Props) {
function Button ({ children, className, isDisabled, label, onClick, to }: Props): React.ReactElement<Props> {
const _onClick = (): void => {
if (isDisabled) {
return;
@@ -44,54 +44,26 @@ function Button ({ children, className, isDisabled, label, onClick, to }: Props)
export default styled(Button)`
box-sizing: border-box;
display: ${({ isSmall }) =>
isSmall
? 'inline-block'
: 'block'
};
display: ${({ isSmall }): string => isSmall ? 'inline-block' : 'block'};
margin: ${defaults.boxMargin};
padding: ${defaults.boxPadding};
width: ${({ isSmall }) =>
isSmall
? 'auto'
: '100%'
};
width: ${({ isSmall }): string => isSmall ? 'auto' : '100%'};
button {
background: ${({ isDanger }) =>
isDanger
? defaults.btnBgDanger
: defaults.btnBg
};
border: ${defaults.btnBorder}${({ isDanger }) =>
isDanger
? defaults.btnColorDanger
: defaults.btnColor
};
background: ${({ isDanger }): string => isDanger ? defaults.btnBgDanger : defaults.btnBg};
border: ${defaults.btnBorder}${({ isDanger }): string => isDanger ? defaults.btnColorDanger : defaults.btnColor};
border-radius: ${defaults.borderRadius};
color: ${({ isDanger }) =>
isDanger
? defaults.btnColorDanger
: defaults.btnColor
};
color: ${({ isDanger }): string => isDanger ? defaults.btnColorDanger : defaults.btnColor};
cursor: pointer;
display: block;
font-size: ${defaults.fontSize};
opacity: ${({ isDisabled }) =>
isDisabled
? DISABLED_OPACITY
: '0.8'
};
opacity: ${({ isDisabled }): string => isDisabled ? DISABLED_OPACITY : '0.8'};
padding: ${defaults.btnPadding};
text-align: center;
width: 100%;
&:hover {
opacity: ${({ isDisabled }) =>
isDisabled
? DISABLED_OPACITY
: '1.0'
};
opacity: ${({ isDisabled }): string => isDisabled ? DISABLED_OPACITY : '1.0'};
}
}
`;

View File

@@ -7,13 +7,13 @@ import styled from 'styled-components';
import defaults from './defaults';
type Props = {
children?: React.ReactNode,
className?: string,
label?: string
};
interface Props {
children?: React.ReactNode;
className?: string;
label?: string;
}
function Header ({ children, className, label }: Props) {
function Header ({ children, className, label }: Props): React.ReactElement<Props> {
return (
<h2 className={className}>
{label}{children}

View File

@@ -5,13 +5,13 @@
import React from 'react';
import styled from 'styled-components';
type Props = {
className?: string,
icon: string,
onClick?: () => any
};
interface Props {
className?: string;
icon: string;
onClick?: () => void | Promise<void>;
}
function Icon ({ className, icon, onClick }: Props) {
function Icon ({ className, icon, onClick }: Props): React.ReactElement<Props> {
return (
<div
className={`${className} icon`}
@@ -26,10 +26,9 @@ export default styled(Icon)`
background: white;
border-radius: 50%;
box-sizing: border-box;
cursor: ${({ onClick }) =>
cursor: ${({ onClick }): string =>
onClick
? 'pointer'
: 'inherit'
};
: 'inherit'};
text-align: center;
`;

View File

@@ -8,16 +8,16 @@ import styled from 'styled-components';
import Box from './Box';
import defaults from './defaults';
type Props = {
interface Props {
children?: React.ReactNode;
className?: string,
icon: React.ReactNode,
intro: React.ReactNode,
name?: React.ReactNode | null,
theme?: 'polkadot' | 'substrate'
};
className?: string;
icon: React.ReactNode;
intro: React.ReactNode;
name?: React.ReactNode | null;
theme?: 'polkadot' | 'substrate';
}
function IconBox ({ children, className, icon, intro }: Props) {
function IconBox ({ children, className, icon, intro }: Props): React.ReactElement<Props> {
return (
<div className={className}>
<Box className='details'>

View File

@@ -8,20 +8,20 @@ import styled from 'styled-components';
import Label from './Label';
import defaults from './defaults';
type Props = {
className?: string,
defaultValue?: string | null,
isError?: boolean,
isFocussed?: boolean,
isReadOnly?: boolean,
label?: string | null,
onBlur?: () => void,
onChange?: (value: string) => void,
type?: 'text' | 'password',
value?: string
};
interface Props {
className?: string;
defaultValue?: string | null;
isError?: boolean;
isFocussed?: boolean;
isReadOnly?: boolean;
label?: string | null;
onBlur?: () => void;
onChange?: (value: string) => void;
type?: 'text' | 'password';
value?: string;
}
function Input ({ className, defaultValue, label, isFocussed, isReadOnly, onBlur, onChange, type = 'text', value }: Props) {
function Input ({ className, defaultValue, label, isFocussed, isReadOnly, onBlur, onChange, type = 'text', value }: Props): React.ReactElement<Props> {
const _onChange = ({ target: { value } }: React.ChangeEvent<HTMLInputElement>): void => {
onChange && onChange(value.trim());
};
@@ -46,35 +46,17 @@ function Input ({ className, defaultValue, label, isFocussed, isReadOnly, onBlur
export default styled(Input)`
input {
background: ${({ isError, isReadOnly }) =>
isError
? defaults.box.error.background
: isReadOnly
? '#eee'
: '#fff'
};
border-color: ${({ isError }) =>
isError
? defaults.box.error.border
: defaults.inputBorder
};
background: ${({ isError, isReadOnly }): string => isError ? defaults.box.error.background : (isReadOnly ? '#eee' : '#fff')};
border-color: ${({ isError }): string => isError ? defaults.box.error.border : defaults.inputBorder};
border-radius: ${defaults.borderRadius};
border-style: solid;
border-width: 1px;
box-sizing: border-box;
color: ${({ isError }) =>
isError
? defaults.box.error.border
: defaults.color
};
color: ${({ isError }): string => isError ? defaults.box.error.border : defaults.color};
display: block;
font-family: ${defaults.fontFamily};
font-size: ${defaults.fontSize};
padding: ${({ label }) =>
label
? defaults.inputPaddingLabel
: defaults.inputPadding
};
padding: ${({ label }): string => label ? defaults.inputPaddingLabel : defaults.inputPadding};
width: 100%;
&:read-only {

View File

@@ -7,13 +7,13 @@ import styled from 'styled-components';
import defaults from './defaults';
type Props = {
children: React.ReactNode,
className?: string,
label?: string | null
};
interface Props {
children: React.ReactNode;
className?: string;
label?: string | null;
}
function Label ({ children, className, label }: Props) {
function Label ({ children, className, label }: Props): React.ReactElement<Props> {
return (
<div className={className}>
{label && <label>{label}</label>}

View File

@@ -8,15 +8,15 @@ import { Link as RouterLink } from 'react-router-dom';
import defaults from './defaults';
type Props = {
children?: React.ReactNode,
className?: string,
isDanger?: boolean,
onClick?: () => void,
to?: string
};
interface Props {
children?: React.ReactNode;
className?: string;
isDanger?: boolean;
onClick?: () => void;
to?: string;
}
function Link ({ children, className, onClick, to }: Props) {
function Link ({ children, className, onClick, to }: Props): React.ReactElement<Props> {
return (
to
? <RouterLink className={className} onClick={onClick} to={to}>{children}</RouterLink>
@@ -25,28 +25,16 @@ function Link ({ children, className, onClick, to }: Props) {
}
export default styled(Link)`
color: ${({ isDanger }) =>
isDanger
? defaults.linkColorDanger
: defaults.linkColor
};
color: ${({ isDanger }): string => isDanger ? defaults.linkColorDanger : defaults.linkColor};
opacity: 0.9;
text-decoration: none;
&:hover {
color: ${({ isDanger }) =>
isDanger
? defaults.linkColorDanger
: defaults.linkColor
};
color: ${({ isDanger }): string => isDanger ? defaults.linkColorDanger : defaults.linkColor};
opacity: 1.0;
}
&:visited {
color: ${({ isDanger }) =>
isDanger
? defaults.linkColorDanger
: defaults.linkColor
};
color: ${({ isDanger }): string => isDanger ? defaults.linkColorDanger : defaults.linkColor};
}
`;

View File

@@ -4,11 +4,11 @@
import React from 'react';
type Props = {
children?: React.ReactNode
};
interface Props {
children?: React.ReactNode;
}
export default function Loading ({ children }: Props) {
export default function Loading ({ children }: Props): React.ReactElement<Props> {
if (!children) {
return (
<div>... loading ...</div>

View File

@@ -8,17 +8,17 @@ import styled from 'styled-components';
import Label from './Label';
import defaults from './defaults';
type Props = {
className?: string,
isError?: boolean,
isFocussed?: boolean,
isReadOnly?: boolean,
label: string,
onChange?: (value: string) => void,
value?: string
};
interface Props {
className?: string;
isError?: boolean;
isFocussed?: boolean;
isReadOnly?: boolean;
label: string;
onChange?: (value: string) => void;
value?: string;
}
function TextArea ({ className, isFocussed, isReadOnly, label, onChange, value }: Props) {
function TextArea ({ className, isFocussed, isReadOnly, label, onChange, value }: Props): React.ReactElement<Props> {
const _onChange = ({ target: { value } }: React.ChangeEvent<HTMLTextAreaElement>): void => {
onChange && onChange(value.trim());
};
@@ -40,35 +40,17 @@ function TextArea ({ className, isFocussed, isReadOnly, label, onChange, value }
export default styled(TextArea)`
textarea {
background: ${({ isError, isReadOnly }) =>
isError
? defaults.box.error.background
: isReadOnly
? '#eee'
: '#fff'
};
border-color: ${({ isError }) =>
isError
? defaults.box.error.border
: defaults.inputBorder
};
background: ${({ isError, isReadOnly }): string => isError ? defaults.box.error.background : (isReadOnly ? '#eee' : '#fff')};
border-color: ${({ isError }): string => isError ? defaults.box.error.border : defaults.inputBorder};
border-radius: ${defaults.borderRadius};
border-style: solid;
border-width: 1px;
box-sizing: border-box;
color: ${({ isError }) =>
isError
? defaults.box.error.border
: defaults.color
};
color: ${({ isError }): string => isError ? defaults.box.error.border : defaults.color};
display: block;
font-family: ${defaults.fontFamily};
font-size: ${defaults.fontSize};
padding: ${({ label }) =>
label
? defaults.inputPaddingLabel
: defaults.inputPadding
};
padding: ${({ label }): string => label ? defaults.inputPaddingLabel : defaults.inputPadding};
resize: none;
width: 100%;

View File

@@ -7,26 +7,26 @@ import styled from 'styled-components';
import defaults from './defaults';
type Color = {
background: string,
border: string,
color: string
};
interface Color {
background: string;
border: string;
color: string;
}
type Type = keyof typeof defaults.box;
type Props = {
children: React.ReactNode,
className?: string,
header?: React.ReactNode,
type?: Type
};
interface Props {
children: React.ReactNode;
className?: string;
header?: React.ReactNode;
type?: Type;
}
function getColor ({ type }: Props): Color {
return defaults.box[type || 'info'] || defaults.box.info;
}
function Tip ({ children, className, header }: Props) {
function Tip ({ children, className, header }: Props): React.ReactElement<Props> {
return (
<article className={className}>
{header && <h3>{header}</h3>}
@@ -37,22 +37,14 @@ function Tip ({ children, className, header }: Props) {
// box-shadow: ${defaults.boxShadow};
export default styled(Tip)`
background: ${(props) =>
getColor(props).background
};
border-left: 0.25rem solid ${(props) =>
getColor(props).border
};
color: ${(props) =>
getColor(props).color
};
background: ${(p): string => getColor(p).background};
border-left: 0.25rem solid ${(p): string => getColor(p).border};
color: ${(p): string => getColor(p).color};
margin: 0.75rem -1rem;
padding: 1rem 1.5rem;
h3 {
color: ${(props) =>
getColor(props).border
};
color: ${(p): string => getColor(p).border};
font-weight: normal;
}
`;

View File

@@ -7,12 +7,12 @@ import styled from 'styled-components';
import defaults from './defaults';
type Props = {
interface Props {
children: React.ReactNode;
className?: string;
};
}
function View ({ children, className }: Props) {
function View ({ children, className }: Props): React.ReactElement<Props> {
return (
<main className={className}>
{children}

View File

@@ -6,7 +6,8 @@ import { AccountsFromCtx, OnActionFromCtx, AuthRequestsFromCtx, SignRequestsFrom
import React from 'react';
const noop = (to?: string) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const noop = (to?: string): void => {
// do nothing
};
@@ -23,10 +24,11 @@ export {
};
export function withAccounts<P extends { accounts: AccountsFromCtx }> (Component: React.ComponentType<P>): React.ComponentType<SubtractProps<P, { accounts: AccountsFromCtx }>> {
// eslint-disable-next-line react/display-name,@typescript-eslint/explicit-function-return-type
return (props: SubtractProps<P, { accounts: AccountsFromCtx }>) => {
return (
<AccountContext.Consumer>
{(accounts) => (
{(accounts): React.ReactNode => (
// @ts-ignore Something here with the props are going wonky
<Component
{...props}
@@ -39,10 +41,11 @@ export function withAccounts<P extends { accounts: AccountsFromCtx }> (Component
}
export function withOnAction<P extends { onAction: OnActionFromCtx }> (Component: React.ComponentType<P>): React.ComponentType<SubtractProps<P, { onAction: OnActionFromCtx }>> {
// eslint-disable-next-line react/display-name,@typescript-eslint/explicit-function-return-type
return (props: SubtractProps<P, { onAction: OnActionFromCtx }>) => {
return (
<ActionContext.Consumer>
{(onAction) => (
{(onAction): React.ReactNode => (
// @ts-ignore Something here with the props are going wonky
<Component
{...props}
@@ -55,10 +58,11 @@ export function withOnAction<P extends { onAction: OnActionFromCtx }> (Component
}
export function withAuthRequests<P extends { requests: AuthRequestsFromCtx }> (Component: React.ComponentType<P>): React.ComponentType<SubtractProps<P, { requests: AuthRequestsFromCtx }>> {
// eslint-disable-next-line react/display-name,@typescript-eslint/explicit-function-return-type
return (props: SubtractProps<P, { requests: AuthRequestsFromCtx }>) => {
return (
<AuthorizeContext.Consumer>
{(requests) => (
{(requests): React.ReactNode => (
// @ts-ignore Something here with the props are going wonky
<Component
{...props}
@@ -71,10 +75,11 @@ export function withAuthRequests<P extends { requests: AuthRequestsFromCtx }> (C
}
export function withSignRequests<P extends { requests: SignRequestsFromCtx }> (Component: React.ComponentType<P>): React.ComponentType<SubtractProps<P, { requests: SignRequestsFromCtx }>> {
// eslint-disable-next-line react/display-name,@typescript-eslint/explicit-function-return-type
return (props: SubtractProps<P, { requests: SignRequestsFromCtx }>) => {
return (
<SigningContext.Consumer>
{(requests) => (
{(requests): React.ReactNode => (
// @ts-ignore Something here with the props are going wonky
<Component
{...props}

View File

@@ -7,7 +7,7 @@ const LABEL_COLOR = '#878786';
const LINK_COLOR = '#3367d6';
const TEXT_COLOR = '#4d4e4f';
const defaults: { [index: string]: any } = {
const defaults = {
borderRadius: '0.25rem',
btnBg: TEXT_COLOR, // LINK_COLOR,
btnBgDanger: DANGER_COLOR,

View File

@@ -8,7 +8,7 @@ import { KeyringJson } from '@polkadot/ui-keyring/types';
export type OmitProps<T, K> = Pick<T, Exclude<keyof T, K>>;
export type SubtractProps<T, K> = OmitProps<T, keyof K>;
export type AccountsFromCtx = Array<KeyringJson>;
export type AccountsFromCtx = KeyringJson[];
export type OnActionFromCtx = (to?: string) => void;
export type AuthRequestsFromCtx = Array<AuthorizeRequest>;
export type SignRequestsFromCtx = Array<SigningRequest>;
export type AuthRequestsFromCtx = AuthorizeRequest[];
export type SignRequestsFromCtx = SigningRequest[];

View File

@@ -6,7 +6,7 @@
const unicode = {
BACK: '\u21E6', // &#8678;
DOWN: '\u21E9', // &#8681;
DOWN: '\u21E9', // &#8681;
FWD: '\u21E8', // &#8680;
UP: '\u21E7' // &#8679;
};

View File

@@ -8,7 +8,7 @@ import { HashRouter } from 'react-router-dom';
import { View } from './components';
export default function createView (Entry: React.ComponentType<any>, rootId: string = 'root'): void {
export default function createView (Entry: React.ComponentType, rootId: string = 'root'): void {
const rootElement = document.getElementById(rootId);
if (!rootElement) {

View File

@@ -9,22 +9,22 @@ import { KeypairType } from '@polkadot/util-crypto/types';
import extension from 'extensionizer';
import { PORT_POPUP } from '@polkadot/extension/defaults';
type Handler = {
resolve: (data: any) => void,
reject: (error: Error) => void,
subscriber?: (data: any) => void
};
interface Handler {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
resolve: (data: any) => void;
reject: (error: Error) => void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
subscriber?: (data: any) => void;
}
type Handlers = {
[index: string]: Handler
};
type Handlers = Record<string, Handler>;
const port = extension.runtime.connect({ name: PORT_POPUP });
const handlers: Handlers = {};
let idCounter = 0;
// setup a listener for messages, any incoming resolves the promise
port.onMessage.addListener((data) => {
port.onMessage.addListener((data): void => {
const handler = handlers[data.id];
if (!handler) {
@@ -45,8 +45,9 @@ port.onMessage.addListener((data) => {
}
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function sendMessage (message: MessageTypes, request: any = {}, subscriber?: (data: any) => void): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
const id = `${Date.now()}.${++idCounter}`;
handlers[id] = { resolve, reject, subscriber };
@@ -63,11 +64,11 @@ export async function forgetAccount (address: string): Promise<boolean> {
return sendMessage('accounts.forget', { address });
}
export async function getAccounts (): Promise<Array<KeyringJson>> {
export async function getAccounts (): Promise<KeyringJson[]> {
return sendMessage('accounts.list');
}
export async function getAuthRequests (): Promise<Array<AuthorizeRequest>> {
export async function getAuthRequests (): Promise<AuthorizeRequest[]> {
return sendMessage('authorize.requests');
}
@@ -79,7 +80,7 @@ export async function approveAuthRequest (id: string): Promise<boolean> {
return sendMessage('authorize.approve', { id });
}
export async function getSignRequests (): Promise<Array<SigningRequest>> {
export async function getSignRequests (): Promise<SigningRequest[]> {
return sendMessage('signing.requests');
}
@@ -95,22 +96,22 @@ export async function createAccount (name: string, password: string, suri: strin
return sendMessage('accounts.create', { name, password, suri, type });
}
export async function createSeed (length?: number, type?: KeypairType): Promise<{ address: string, seed: string }> {
export async function createSeed (length?: number, type?: KeypairType): Promise<{ address: string; seed: string }> {
return sendMessage('seed.create', { length, type });
}
export async function subscribeAccounts (cb: (accounts: Array<KeyringJson>) => void): Promise<boolean> {
export async function subscribeAccounts (cb: (accounts: KeyringJson[]) => void): Promise<boolean> {
return sendMessage('accounts.subscribe', {}, cb);
}
export async function subscribeAuthorize (cb: (accounts: Array<AuthorizeRequest>) => void): Promise<boolean> {
export async function subscribeAuthorize (cb: (accounts: AuthorizeRequest[]) => void): Promise<boolean> {
return sendMessage('authorize.subscribe', {}, cb);
}
export async function subscribeSigning (cb: (accounts: Array<SigningRequest>) => void): Promise<boolean> {
export async function subscribeSigning (cb: (accounts: SigningRequest[]) => void): Promise<boolean> {
return sendMessage('signing.subscribe', {}, cb);
}
export async function validateSeed (seed: string, type?: KeypairType): Promise<{ address: string, seed: string }> {
export async function validateSeed (seed: string, type?: KeypairType): Promise<{ address: string; seed: string }> {
return sendMessage('seed.validate', { seed, type });
}

View File

@@ -7,12 +7,12 @@ import styled from 'styled-components';
import { Link, unicode } from '../components';
type Props = {
className?: string,
to?: string
};
interface Props {
className?: string;
to?: string;
}
function Back ({ className, to = '/' }: Props) {
function Back ({ className, to = '/' }: Props): React.ReactElement<Props> {
return (
<div className={className}>
<Link to={to}>{unicode.BACK} Back</Link>

View File

@@ -8,28 +8,28 @@ import React, { useEffect, useState } from 'react';
import { Input, withAccounts } from '../components';
type Props = {
accounts: AccountsFromCtx,
address?: string,
className?: string,
defaultValue?: string | null,
isFocussed?: boolean,
label?: string | null,
onBlur?: () => void,
onChange: (name: string | null) => void
};
interface Props {
accounts: AccountsFromCtx;
address?: string;
className?: string;
defaultValue?: string | null;
isFocussed?: boolean;
label?: string | null;
onBlur?: () => void;
onChange: (name: string | null) => void;
}
const MIN_LENGTH = 3;
function Name ({ accounts, address, className, defaultValue, isFocussed, label = 'a descriptive name for this account', onBlur, onChange }: Props) {
function Name ({ accounts, address, className, defaultValue, isFocussed, label = 'a descriptive name for this account', onBlur, onChange }: Props): React.ReactElement<Props> {
const [name, setName] = useState('');
const account = accounts.find((account) => account.address === address);
const account = accounts.find((account): boolean => account.address === address);
const startValue = (account && account.meta.name) || defaultValue;
const isError = !name && startValue
? false
: (name.length < MIN_LENGTH);
useEffect(() => {
useEffect((): void => {
onChange(
name && (name.length >= MIN_LENGTH)
? name

View File

@@ -6,18 +6,18 @@ import React, { useEffect, useState } from 'react';
import { Input } from '../components';
type Props = {
isFocussed?: boolean,
onChange: (password: string | null) => void
};
interface Props {
isFocussed?: boolean;
onChange: (password: string | null) => void;
}
const MIN_LENGTH = 6;
export default function Password ({ isFocussed, onChange }: Props) {
export default function Password ({ isFocussed, onChange }: Props): React.ReactElement<Props> {
const [pass1, setPass1] = useState('');
const [pass2, setPass2] = useState('');
useEffect(() => {
useEffect((): void => {
onChange(
(pass1 && pass2 && (pass1.length >= MIN_LENGTH) && (pass1 === pass2))
? pass1

View File

@@ -4,7 +4,7 @@
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
import { KeyringJson } from '@polkadot/ui-keyring/types';
import { AuthorizeRequest, MessageTypes, MessageAccountCreate, MessageAccountEdit, MessageAuthorizeApprove, MessageAuthorizeReject, MessageExtrinsicSignApprove, MessageExtrinsicSignCancel, MessageSeedCreate, MessageSeedCreate$Response, MessageSeedValidate, MessageSeedValidate$Response, MessageAccountForget, SigningRequest } from '../types';
import { AuthorizeRequest, MessageTypes, MessageAccountCreate, MessageAccountEdit, MessageAuthorizeApprove, MessageAuthorizeReject, MessageExtrinsicSignApprove, MessageExtrinsicSignCancel, MessageSeedCreate, MessageSeedCreateResponse, MessageSeedValidate, MessageSeedValidateResponse, MessageAccountForget, SigningRequest } from '../types';
import keyring from '@polkadot/ui-keyring';
import accountsObservable from '@polkadot/ui-keyring/observable/accounts';
@@ -18,14 +18,14 @@ import { createSubscription, unsubscribe } from './subscriptions';
const SEED_DEFAULT_LENGTH = 12;
const SEED_LENGTHS = [12, 24];
function transformAccounts (accounts: SubjectInfo): Array<KeyringJson> {
return Object.values(accounts).map(({ json }) => json);
function transformAccounts (accounts: SubjectInfo): KeyringJson[] {
return Object.values(accounts).map(({ json }): KeyringJson => json);
}
export default class Extension {
state: State;
private state: State;
constructor (state: State) {
public constructor (state: State) {
this.state = state;
}
@@ -51,18 +51,18 @@ export default class Extension {
return true;
}
private accountsList (): Array<KeyringJson> {
private accountsList (): KeyringJson[] {
return transformAccounts(accountsObservable.subject.getValue());
}
// FIXME This looks very much like what we have in Tabs
private accountsSubscribe (id: string, port: chrome.runtime.Port): boolean {
const cb = createSubscription(id, port);
const subscription = accountsObservable.subject.subscribe((accounts: SubjectInfo) =>
const subscription = accountsObservable.subject.subscribe((accounts: SubjectInfo): void =>
cb(transformAccounts(accounts))
);
port.onDisconnect.addListener(() => {
port.onDisconnect.addListener((): void => {
unsubscribe(id);
subscription.unsubscribe();
});
@@ -94,18 +94,18 @@ export default class Extension {
return true;
}
private authorizeRequests (): Array<AuthorizeRequest> {
private authorizeRequests (): AuthorizeRequest[] {
return this.state.allAuthRequests;
}
// FIXME This looks very much like what we have in accounts
private authorizeSubscribe (id: string, port: chrome.runtime.Port): boolean {
const cb = createSubscription(id, port);
const subscription = this.state.authSubject.subscribe((requests: Array<AuthorizeRequest>) =>
const subscription = this.state.authSubject.subscribe((requests: AuthorizeRequest[]): void =>
cb(requests)
);
port.onDisconnect.addListener(() => {
port.onDisconnect.addListener((): void => {
unsubscribe(id);
subscription.unsubscribe();
});
@@ -113,7 +113,7 @@ export default class Extension {
return true;
}
private seedCreate ({ length = SEED_DEFAULT_LENGTH, type }: MessageSeedCreate): MessageSeedCreate$Response {
private seedCreate ({ length = SEED_DEFAULT_LENGTH, type }: MessageSeedCreate): MessageSeedCreateResponse {
const seed = mnemonicGenerate(length);
return {
@@ -122,7 +122,7 @@ export default class Extension {
};
}
private seedValidate ({ seed, type }: MessageSeedValidate): MessageSeedValidate$Response {
private seedValidate ({ seed, type }: MessageSeedValidate): MessageSeedValidateResponse {
assert(SEED_LENGTHS.includes(seed.split(' ').length), `Mnemonic needs to contain ${SEED_LENGTHS.join(', ')} words`);
assert(mnemonicValidate(seed), 'Not a valid mnemonic seed');
@@ -175,18 +175,18 @@ export default class Extension {
return true;
}
private signingRequests (): Array<SigningRequest> {
private signingRequests (): SigningRequest[] {
return this.state.allSignRequests;
}
// FIXME This looks very much like what we have in authorization
private signingSubscribe (id: string, port: chrome.runtime.Port): boolean {
const cb = createSubscription(id, port);
const subscription = this.state.signSubject.subscribe((requests: Array<SigningRequest>) =>
const subscription = this.state.signSubject.subscribe((requests: SigningRequest[]): void =>
cb(requests)
);
port.onDisconnect.addListener(() => {
port.onDisconnect.addListener((): void => {
unsubscribe(id);
subscription.unsubscribe();
});
@@ -194,7 +194,8 @@ export default class Extension {
return true;
}
async handle (id: string, type: MessageTypes, request: any, port: chrome.runtime.Port): Promise<any> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public async handle (id: string, type: MessageTypes, request: any, port: chrome.runtime.Port): Promise<any> {
switch (type) {
case 'authorize.approve':
return this.authorizeApprove(request);

View File

@@ -2,38 +2,36 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AuthorizeRequest, MessageAuthorize, MessageExtrinsicSign, MessageExtrinsicSign$Response, SigningRequest } from '../types';
import { AuthorizeRequest, MessageAuthorize, MessageExtrinsicSign, MessageExtrinsicSignResponse, SigningRequest } from '../types';
import extension from 'extensionizer';
import { BehaviorSubject } from 'rxjs';
import { assert } from '@polkadot/util';
type AuthRequest = {
id: string,
idStr: string,
request: MessageAuthorize,
resolve: (result: boolean) => void,
reject: (error: Error) => void,
url: string
};
interface AuthRequest {
id: string;
idStr: string;
request: MessageAuthorize;
resolve: (result: boolean) => void;
reject: (error: Error) => void;
url: string;
}
type AuthUrls = {
[index: string]: {
count: number,
id: string,
isAllowed: boolean,
origin: string,
url: string
}
};
type AuthUrls = Record<string, {
count: number;
id: string;
isAllowed: boolean;
origin: string;
url: string;
}>;
type SignRequest = {
id: string,
request: MessageExtrinsicSign,
resolve: (result: MessageExtrinsicSign$Response) => void,
reject: (error: Error) => void,
url: string
};
interface SignRequest {
id: string;
request: MessageExtrinsicSign;
resolve: (result: MessageExtrinsicSignResponse) => void;
reject: (error: Error) => void;
url: string;
}
let idCounter = 0;
@@ -42,44 +40,48 @@ function getId (): string {
}
export default class State {
// at the moment, we are keeping the list in memory - this should be persisted
private _authUrls: AuthUrls = {};
private _authRequests: { [index: string]: AuthRequest } = {};
private _signRequests: { [index: string]: SignRequest } = {};
private _windows: Array<number> = [];
readonly authSubject: BehaviorSubject<Array<AuthorizeRequest>> = new BehaviorSubject([] as Array<AuthorizeRequest>);
readonly signSubject: BehaviorSubject<Array<SigningRequest>> = new BehaviorSubject([] as Array<SigningRequest>);
get hasAuthRequests (): boolean {
private _authRequests: Record<string, AuthRequest> = {};
private _signRequests: Record<string, SignRequest> = {};
private _windows: number[] = [];
public readonly authSubject: BehaviorSubject<AuthorizeRequest[]> = new BehaviorSubject([] as AuthorizeRequest[]);
public readonly signSubject: BehaviorSubject<SigningRequest[]> = new BehaviorSubject([] as SigningRequest[]);
public get hasAuthRequests (): boolean {
return this.numAuthRequests === 0;
}
get hasSignRequests (): boolean {
public get hasSignRequests (): boolean {
return this.numSignRequests === 0;
}
get numAuthRequests (): number {
public get numAuthRequests (): number {
return Object.keys(this._authRequests).length;
}
get numSignRequests (): number {
public get numSignRequests (): number {
return Object.keys(this._signRequests).length;
}
get allAuthRequests (): Array<AuthorizeRequest> {
public get allAuthRequests (): AuthorizeRequest[] {
return Object
.values(this._authRequests)
.map(({ id, request, url }) => [id, request, url]);
.map(({ id, request, url }): AuthorizeRequest => [id, request, url]);
}
get allSignRequests (): Array<SigningRequest> {
public get allSignRequests (): SigningRequest[] {
return Object
.values(this._signRequests)
.map(({ id, request, url }) => [id, request, url]);
.map(({ id, request, url }): SigningRequest => [id, request, url]);
}
private popupClose (): void {
this._windows.map((id: number) =>
this._windows.forEach((id: number): void =>
extension.windows.remove(id)
);
this._windows = [];
@@ -94,14 +96,14 @@ export default class State {
type: 'popup',
url: extension.extension.getURL('popup.html'),
width: 480
}, (window?: chrome.windows.Window) => {
}, (window?: chrome.windows.Window): void => {
if (window) {
this._windows.push(window.id);
}
});
}
private authComplete = (id: string, fn: Function) => {
private authComplete = (id: string, fn: Function): (result: boolean | Error) => void => {
return (result: boolean | Error): void => {
const isAllowed = result === true;
const { idStr, request: { origin }, url } = this._authRequests[id];
@@ -121,8 +123,8 @@ export default class State {
};
}
private signComplete = (id: string, fn: Function) => {
return (result: MessageExtrinsicSign$Response | Error): void => {
private signComplete = (id: string, fn: Function): (result: MessageExtrinsicSignResponse | Error) => void => {
return (result: MessageExtrinsicSignResponse | Error): void => {
delete this._signRequests[id];
this.updateIconSign(true);
@@ -164,7 +166,7 @@ export default class State {
this.updateIcon(shouldClose);
}
async authorizeUrl (url: string, request: MessageAuthorize): Promise<boolean> {
public async authorizeUrl (url: string, request: MessageAuthorize): Promise<boolean> {
const idStr = this.stripUrl(url);
if (this._authUrls[idStr]) {
@@ -173,7 +175,7 @@ export default class State {
return true;
}
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
const id = getId();
this._authRequests[id] = {
@@ -190,7 +192,7 @@ export default class State {
});
}
isUrlAuthorized (url: string): boolean {
public isUrlAuthorized (url: string): boolean {
const entry = this._authUrls[this.stripUrl(url)];
assert(entry, `The source ${url} has not been enabled yet`);
@@ -199,18 +201,18 @@ export default class State {
return true;
}
getAuthRequest (id: string): AuthRequest {
public getAuthRequest (id: string): AuthRequest {
return this._authRequests[id];
}
getSignRequest (id: string): SignRequest {
public getSignRequest (id: string): SignRequest {
return this._signRequests[id];
}
signQueue (url: string, request: MessageExtrinsicSign): Promise<MessageExtrinsicSign$Response> {
public signQueue (url: string, request: MessageExtrinsicSign): Promise<MessageExtrinsicSignResponse> {
const id = getId();
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
this._signRequests[id] = {
id,
request,

View File

@@ -3,7 +3,7 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
import { MessageTypes, MessageAuthorize, MessageExtrinsicSign, MessageExtrinsicSign$Response } from '../types';
import { MessageTypes, MessageAuthorize, MessageExtrinsicSign, MessageExtrinsicSignResponse } from '../types';
import keyring from '@polkadot/ui-keyring';
import accountsObservable from '@polkadot/ui-keyring/observable/accounts';
@@ -12,25 +12,30 @@ import { assert } from '@polkadot/util';
import State from './State';
import { createSubscription, unsubscribe } from './subscriptions';
type Accounts = Array<{ address: string, name?: string }>;
interface Account {
address: string;
name?: string;
}
type Accounts = Account[];
function transformAccounts (accounts: SubjectInfo): Accounts {
return Object.values(accounts).map(({ json: { address, meta: { name } } }) => ({
return Object.values(accounts).map(({ json: { address, meta: { name } } }): Account => ({
address, name
}));
}
export default class Tabs {
state: State;
private state: State;
constructor (state: State) {
public constructor (state: State) {
this.state = state;
}
private authorize (url: string, request: MessageAuthorize) {
private authorize (url: string, request: MessageAuthorize): Promise<boolean> {
return this.state.authorizeUrl(url, request);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
private accountsList (url: string): Accounts {
return transformAccounts(accountsObservable.subject.getValue());
}
@@ -38,11 +43,11 @@ export default class Tabs {
// FIXME This looks very much like what we have in Extension
private accountsSubscribe (url: string, id: string, port: chrome.runtime.Port): boolean {
const cb = createSubscription(id, port);
const subscription = accountsObservable.subject.subscribe((accounts: SubjectInfo) =>
const subscription = accountsObservable.subject.subscribe((accounts: SubjectInfo): void =>
cb(transformAccounts(accounts))
);
port.onDisconnect.addListener(() => {
port.onDisconnect.addListener((): void => {
unsubscribe(id);
subscription.unsubscribe();
});
@@ -50,7 +55,7 @@ export default class Tabs {
return true;
}
private extrinsicSign (url: string, request: MessageExtrinsicSign): Promise<MessageExtrinsicSign$Response> {
private extrinsicSign (url: string, request: MessageExtrinsicSign): Promise<MessageExtrinsicSignResponse> {
const { address } = request;
const pair = keyring.getPair(address);
@@ -59,7 +64,8 @@ export default class Tabs {
return this.state.signQueue(url, request);
}
async handle (id: string, type: MessageTypes, request: any, url: string, port: chrome.runtime.Port): Promise<any> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public async handle (id: string, type: MessageTypes, request: any, url: string, port: chrome.runtime.Port): Promise<any> {
switch (type) {
case 'authorize.tab':
return this.authorize(url, request);

View File

@@ -28,12 +28,12 @@ export default function handler ({ id, message, request }: MessageRequest, port:
: tabs.handle(id, message, request, from, port);
promise
.then((response) => {
.then((response): void => {
console.log(`[out] ${source}`); // :: ${JSON.stringify(response)}`);
port.postMessage({ id, response });
})
.catch((error) => {
.catch((error): void => {
console.log(`[err] ${source}:: ${error.message}`);
port.postMessage({ id, error: error.message });

View File

@@ -2,17 +2,17 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
type Subscriptions = {
[index: string]: chrome.runtime.Port
};
type Subscriptions = Record<string, chrome.runtime.Port>;
const subscriptions: Subscriptions = {};
// return a subscription callback, that will send the data to the caller via the port
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function createSubscription (id: string, port: chrome.runtime.Port): (data: any) => void {
subscriptions[id] = port;
return (subscription: any) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (subscription: any): void => {
if (subscriptions[id]) {
port.postMessage({ id, subscription });
}

View File

@@ -17,18 +17,18 @@ import handlers from './handlers';
extension.browserAction.setBadgeBackgroundColor({ color: '#d90000' });
// listen to all messages and handle appropriately
extension.runtime.onConnect.addListener((port) => {
extension.runtime.onConnect.addListener((port): void => {
// shouldn't happen, however... only listen to what we know about
assert([PORT_CONTENT, PORT_POPUP].includes(port.name), `Unknown connection from ${port.name}`);
// message and disconnect handlers
port.onMessage.addListener((data) => handlers(data, port));
port.onDisconnect.addListener(() => console.log(`Disconnected from ${port.name}`));
port.onMessage.addListener((data): void => handlers(data, port));
port.onDisconnect.addListener((): void => console.log(`Disconnected from ${port.name}`));
});
// initial setup
cryptoWaitReady()
.then(() => {
.then((): void => {
console.log('crypto initialized');
// load all the keyring data
@@ -36,6 +36,6 @@ cryptoWaitReady()
console.log('initialization completed');
})
.catch((error) => {
.catch((error): void => {
console.error('initialization failed', error);
});

View File

@@ -10,55 +10,58 @@ export type AuthorizeRequest = [string, MessageAuthorize, string];
export type SigningRequest = [string, MessageExtrinsicSign, string];
export type MessageAuthorize = {
origin: string
};
export interface MessageAuthorize {
origin: string;
}
export type MessageAuthorizeApprove = {
export interface MessageAuthorizeApprove {
id: string;
};
}
export type MessageAuthorizeReject = {
export interface MessageAuthorizeReject {
id: string;
};
}
export type MessageRequest = {
id: string,
message: MessageTypes,
request: any
};
export interface MessageRequest {
id: string;
message: MessageTypes;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
request: any;
}
export type MessageResponse = {
error?: string,
id: string,
response?: any,
subscription?: any
};
export interface MessageResponse {
error?: string;
id: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
response?: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
subscription?: any;
}
export type MessageAccountCreate = {
name: string,
password: string,
suri: string,
type?: KeypairType
};
export interface MessageAccountCreate {
name: string;
password: string;
suri: string;
type?: KeypairType;
}
export type MessageAccountEdit= {
address: string,
name: string
};
export interface MessageAccountEdit {
address: string;
name: string;
}
export type MessageAccountForget = {
address: string
};
export interface MessageAccountForget {
address: string;
}
export type MessageExtrinsicSignApprove = {
id: string,
password: string
};
export interface MessageExtrinsicSignApprove {
id: string;
password: string;
}
export type MessageExtrinsicSignCancel = {
id: string
};
export interface MessageExtrinsicSignCancel {
id: string;
}
export interface MessageExtrinsicSign {
address: string;
@@ -70,27 +73,27 @@ export interface MessageExtrinsicSign {
nonce: string;
}
export type MessageExtrinsicSign$Response = {
id: string,
signature: string
};
export interface MessageExtrinsicSignResponse {
id: string;
signature: string;
}
export type MessageSeedCreate$Response = {
address: string,
seed: string
};
export interface MessageSeedCreateResponse {
address: string;
seed: string;
}
export type MessageSeedCreate = {
length?: 12 | 24,
type?: KeypairType
};
export interface MessageSeedCreate {
length?: 12 | 24;
type?: KeypairType;
}
export type MessageSeedValidate = {
seed: string,
type?: KeypairType
};
export interface MessageSeedValidate {
seed: string;
type?: KeypairType;
}
export type MessageSeedValidate$Response = {
address: string,
seed: string
};
export interface MessageSeedValidateResponse {
address: string;
seed: string;
}

View File

@@ -8,12 +8,12 @@ import { Metadata } from '@polkadot/types';
// curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "state_getMetadata", "params":[]}' http://localhost:9933
import alexander from './alexander';
type Chain = {
meta?: Metadata,
name: string
};
interface Chain {
meta?: Metadata;
name: string;
}
const chains: { [genesisHash: string]: Chain } = {
const chains: Record<string, Chain> = {
'0xdcd1346701ca8396496e52aa2785b1748deb6db09551b72159dcb3e08991025b': {
name: 'Alexander',
meta: new Metadata(alexander.meta)

View File

@@ -10,12 +10,12 @@ import { PORT_CONTENT } from './defaults';
const port = extension.runtime.connect({ name: PORT_CONTENT });
// send any messages from the extension back to the page
port.onMessage.addListener((data) => {
port.onMessage.addListener((data): void => {
window.postMessage({ ...data, origin: 'content' }, '*');
});
// all messages from the page, pass them to the extension
window.addEventListener('message', ({ data, source }) => {
window.addEventListener('message', ({ data, source }): void => {
// only allow messages from our window, by the inject
if (source !== window || data.origin !== 'page') {
return;

View File

@@ -8,19 +8,20 @@ import { SendRequest } from './types';
let sendRequest: SendRequest;
export default class Accounts implements InjectedAccounts {
constructor (_sendRequest: SendRequest) {
public constructor (_sendRequest: SendRequest) {
sendRequest = _sendRequest;
}
get (): Promise<Array<InjectedAccount>> {
public get (): Promise<InjectedAccount[]> {
return sendRequest('accounts.list');
}
subscribe (cb: (accounts: Array<InjectedAccount>) => any): Unsubcall {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public subscribe (cb: (accounts: InjectedAccount[]) => any): Unsubcall {
sendRequest('accounts.subscribe', null, cb)
.catch(console.error);
return () => {
return (): void => {
// FIXME we need the ability to unsubscribe
};
}

View File

@@ -9,10 +9,11 @@ import Accounts from './Accounts';
import Signer from './Signer';
export default class Injected implements InjectedInjected {
readonly accounts: Accounts;
readonly signer: Signer;
public readonly accounts: Accounts;
constructor (sendRequest: SendRequest) {
public readonly signer: Signer;
public constructor (sendRequest: SendRequest) {
this.accounts = new Accounts(sendRequest);
this.signer = new Signer(sendRequest);
}

View File

@@ -34,6 +34,7 @@ export default class Signer implements InjectedSigner {
return id;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public update (id: number, status: Hash | SubmittableResult): void {
// something
}

View File

@@ -10,19 +10,19 @@ import Injected from './Injected';
// when sending a message from the injector to the extension, we
// - create an event - this we send to the loader
// - the loader takes this event and uses port.postMessage to background
// - on resposnse, the loader creates a reponse event
// - on response, the loader creates a reponse event
// - this injector, listens on the events, maps it to the original
// - resolves/rejects the promise with the result (or sub data)
type Handler = {
resolve: (data: any) => void,
reject: (error: Error) => void,
subscriber?: (data: any) => void
};
interface Handler {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
resolve: (data: any) => void;
reject: (error: Error) => void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
subscriber?: (data: any) => void;
}
type Handlers = {
[index: string]: Handler
};
type Handlers = Record<string, Handler>;
// small helper with the typescript types, just cast window
const windowInject = window as InjectedWindow;
@@ -31,8 +31,9 @@ let idCounter = 0;
// a generic message sender that creates an event, returning a promise that will
// resolve once the event is resolved (by the response listener just below this)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function sendMessage (message: MessageTypes, request: any = null, subscriber?: (data: any) => void): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
const id = `${Date.now()}.${++idCounter}`;
handlers[id] = { resolve, reject, subscriber };
@@ -49,7 +50,7 @@ async function enable (origin: string): Promise<Injected> {
}
// setup a response listener (events created by the loader for extension responses)
window.addEventListener('message', ({ data, source }) => {
window.addEventListener('message', ({ data, source }): void => {
// only allow messages from our window, by the loader
if (source !== window || data.origin !== 'content') {
return;

View File

@@ -5,5 +5,6 @@
import { MessageTypes } from '../background/types';
export interface SendRequest {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(message: MessageTypes, request?: any, subscriber?: (data: any) => any): Promise<any>;
}

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Copyright 2019 @polkadot/extension authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
@@ -68,6 +69,7 @@ function createWebpack ({ alias = {}, context }) {
]
},
node: {
// eslint-disable-next-line @typescript-eslint/camelcase
child_process: 'empty',
dgram: 'empty',
fs: 'empty',
@@ -83,7 +85,7 @@ function createWebpack ({ alias = {}, context }) {
'process.env': {
NODE_ENV: JSON.stringify(ENV),
PKG_NAME: JSON.stringify(pkgJson.name),
PKG_VERSION: JSON.stringify(pkgJson.version),
PKG_VERSION: JSON.stringify(pkgJson.version)
}
}),
new CopyPlugin([{ from: 'public' }]),