Skip to content

Commit 8b12d04

Browse files
shanejonasrekmarks
andauthoredMay 3, 2021
feat: add createExternalExtensionProvider (#152)
* feat: add createMetaMaskExternalExtensionProvider - remove index.d.ts * break out extension code to src/extension-provider * use BaseProvider for external provider Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com>
1 parent 406c815 commit 8b12d04

12 files changed

+156
-6
lines changed
 

‎jest.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module.exports = {
1010
// statements: 100,
1111
// },
1212
// },
13+
setupFilesAfterEnv: ['./jest.setup.js'],
1314
moduleFileExtensions: ['js'],
1415
silent: true,
1516
testEnvironment: 'jsdom',

‎jest.setup.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Object.assign(global, require('jest-chrome'));

‎package.json

+7-2
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,16 @@
3939
"dependencies": {
4040
"@metamask/object-multiplex": "^1.1.0",
4141
"@metamask/safe-event-emitter": "^2.0.0",
42+
"@types/chrome": "^0.0.136",
43+
"detect-browser": "^5.2.0",
4244
"eth-rpc-errors": "^4.0.2",
45+
"extension-port-stream": "^2.0.1",
4346
"fast-deep-equal": "^2.0.1",
4447
"is-stream": "^2.0.0",
4548
"json-rpc-engine": "^6.1.0",
4649
"json-rpc-middleware-stream": "^3.0.0",
47-
"pump": "^3.0.0"
50+
"pump": "^3.0.0",
51+
"webextension-polyfill-ts": "^0.25.0"
4852
},
4953
"devDependencies": {
5054
"@metamask/eslint-config": "^6.0.0",
@@ -58,13 +62,14 @@
5862
"@typescript-eslint/eslint-plugin": "^4.10.0",
5963
"@typescript-eslint/parser": "^4.10.0",
6064
"eslint": "^7.15.0",
65+
"eslint-config-prettier": "^8.1.0",
6166
"eslint-plugin-import": "^2.20.2",
6267
"eslint-plugin-jest": "^23.18.0",
6368
"eslint-plugin-json": "^2.0.1",
6469
"eslint-plugin-node": "^11.1.0",
6570
"eslint-plugin-prettier": "^3.4.0",
66-
"eslint-config-prettier": "^8.1.0",
6771
"jest": "^26.6.3",
72+
"jest-chrome": "^0.7.1",
6873
"prettier": "^2.2.1",
6974
"typescript": "^4.1.3"
7075
}

‎src/BaseProvider.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export interface BaseProviderState {
6969
export interface JsonRpcConnection {
7070
events: SafeEventEmitter;
7171
middleware: JsonRpcMiddleware<unknown, unknown>;
72-
stream: _Readable.Duplex;
72+
stream: Duplex;
7373
}
7474

7575
export default class BaseProvider extends SafeEventEmitter {
@@ -112,7 +112,7 @@ export default class BaseProvider extends SafeEventEmitter {
112112
* listeners. Default: 100
113113
*/
114114
constructor(
115-
connectionStream: typeof Duplex,
115+
connectionStream: Duplex,
116116
{
117117
jsonRpcStreamName = 'metamask-provider',
118118
logger = console,

‎src/MetaMaskInpageProvider.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export default class MetaMaskInpageProvider extends BaseProvider {
8181
* send page metadata. Default: true
8282
*/
8383
constructor(
84-
connectionStream: typeof Duplex,
84+
connectionStream: Duplex,
8585
{
8686
jsonRpcStreamName = 'metamask-provider',
8787
logger = console,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import PortStream from 'extension-port-stream';
2+
import { detect } from 'detect-browser';
3+
import { Runtime } from 'webextension-polyfill-ts';
4+
import BaseProvider from '../BaseProvider';
5+
import config from './external-extension-config.json';
6+
7+
const browser = detect();
8+
9+
export default function createMetaMaskExternalExtensionProvider() {
10+
let provider;
11+
try {
12+
const currentMetaMaskId = getMetaMaskId();
13+
const metamaskPort = chrome.runtime.connect(
14+
currentMetaMaskId,
15+
) as Runtime.Port;
16+
const pluginStream = new PortStream(metamaskPort);
17+
provider = new BaseProvider(pluginStream);
18+
} catch (e) {
19+
console.dir(`Metamask connect error `, e);
20+
throw e;
21+
}
22+
return provider;
23+
}
24+
25+
function getMetaMaskId() {
26+
switch (browser?.name) {
27+
case 'chrome':
28+
return config.CHROME_ID;
29+
case 'firefox':
30+
return config.FIREFOX_ID;
31+
default:
32+
return config.CHROME_ID;
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"CHROME_ID": "nkbihfbeogaeaoehlefnkodbefgpgknn",
3+
"FIREFOX_ID": "webextension@metamask.io"
4+
}

‎src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import MetaMaskInpageProvider from './MetaMaskInpageProvider';
2+
import createExternalExtensionProvider from './extension-provider/createExternalExtensionProvider';
23
import BaseProvider from './BaseProvider';
34
import {
45
initializeProvider,
@@ -12,4 +13,5 @@ export {
1213
BaseProvider,
1314
setGlobalProvider,
1415
shimWeb3,
16+
createExternalExtensionProvider,
1517
};

‎src/initializeInpageProvider.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ interface InitializeProviderOptions extends MetaMaskInpageProviderOptions {
88
/**
99
* The stream used to connect to the wallet.
1010
*/
11-
connectionStream: typeof Duplex;
11+
connectionStream: Duplex;
1212

1313
/**
1414
* Whether the provider should be set as window.ethereum.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const { createExternalExtensionProvider, BaseProvider } = require('../dist');
2+
3+
describe('createExternalExtensionProvider', () => {
4+
beforeAll(() => {
5+
global.chrome.runtime.connect.mockImplementation(() => {
6+
return {
7+
onMessage: {
8+
addListener: jest.fn(),
9+
},
10+
onDisconnect: {
11+
addListener: jest.fn(),
12+
},
13+
postMessage: jest.fn(),
14+
};
15+
});
16+
});
17+
afterAll(() => {
18+
jest.restoreAllMocks();
19+
});
20+
it('can be called and not throw', () => {
21+
expect(() => createExternalExtensionProvider()).not.toThrow();
22+
});
23+
it('calls connect', () => {
24+
createExternalExtensionProvider();
25+
expect(global.chrome.runtime.connect).toHaveBeenCalled();
26+
});
27+
it('returns a MetaMaskInpageProvider', () => {
28+
const results = createExternalExtensionProvider();
29+
expect(results).toBeInstanceOf(BaseProvider);
30+
});
31+
});

‎tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"esModuleInterop": true,
55
"module": "CommonJS",
66
"moduleResolution": "node",
7+
"resolveJsonModule": true,
78
"outDir": "dist",
89
"sourceMap": true,
910
"strict": true,

‎yarn.lock

+71
Original file line numberDiff line numberDiff line change
@@ -621,18 +621,51 @@
621621
dependencies:
622622
"@babel/types" "^7.3.0"
623623

624+
"@types/chrome@^0.0.114":
625+
version "0.0.114"
626+
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.114.tgz#8ceb33fa261f4b9e307fa7344ba8182d8d410d4e"
627+
integrity sha512-i7qRr74IrxHtbnrZSKUuP5Uvd5EOKwlwJq/yp7+yTPihOXnPhNQO4Z5bqb1XTnrjdbUKEJicaVVbhcgtRijmLA==
628+
dependencies:
629+
"@types/filesystem" "*"
630+
"@types/har-format" "*"
631+
632+
"@types/chrome@^0.0.136":
633+
version "0.0.136"
634+
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.136.tgz#7c011b9f997b0156f25a140188a0c5689d3f368f"
635+
integrity sha512-XDEiRhLkMd+SB7Iw3ZUIj/fov3wLd4HyTdLltVszkgl1dBfc3Rb7oPMVZ2Mz2TLqnF7Ow+StbR8E7r9lqpb4DA==
636+
dependencies:
637+
"@types/filesystem" "*"
638+
"@types/har-format" "*"
639+
624640
"@types/color-name@^1.1.1":
625641
version "1.1.1"
626642
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
627643
integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
628644

645+
"@types/filesystem@*":
646+
version "0.0.30"
647+
resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.30.tgz#a7373a2edf34d13e298baf7ee1101f738b2efb7e"
648+
integrity sha512-NCoRgmGmLpTT9VFL6Bb6z0jQuqI3d0E5FGl7M0JOv/J5RQYo9s5aOItPYnpckx9MbYQk1APLXcF8f20Vqnf2yA==
649+
dependencies:
650+
"@types/filewriter" "*"
651+
652+
"@types/filewriter@*":
653+
version "0.0.29"
654+
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.29.tgz#a48795ecadf957f6c0d10e0c34af86c098fa5bee"
655+
integrity sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ==
656+
629657
"@types/graceful-fs@^4.1.2":
630658
version "4.1.3"
631659
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f"
632660
integrity sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ==
633661
dependencies:
634662
"@types/node" "*"
635663

664+
"@types/har-format@*":
665+
version "1.2.5"
666+
resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.5.tgz#4f6648814d0fdcb6a510e3364a9db439a753c4b1"
667+
integrity sha512-IG8AE1m2pWtPqQ7wXhFhy6Q59bwwnLwO36v5Rit2FrbXCIp8Sk8E2PfUCreyrdo17STwFSKDAkitVuVYbpEHvQ==
668+
636669
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
637670
version "2.0.3"
638671
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
@@ -1467,6 +1500,11 @@ delayed-stream@~1.0.0:
14671500
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
14681501
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
14691502

1503+
detect-browser@^5.2.0:
1504+
version "5.2.0"
1505+
resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.2.0.tgz#c9cd5afa96a6a19fda0bbe9e9be48a6b6e1e9c97"
1506+
integrity sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA==
1507+
14701508
detect-newline@^3.0.0:
14711509
version "3.1.0"
14721510
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
@@ -1912,6 +1950,13 @@ extend@~3.0.2:
19121950
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
19131951
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
19141952

1953+
extension-port-stream@^2.0.1:
1954+
version "2.0.1"
1955+
resolved "https://registry.yarnpkg.com/extension-port-stream/-/extension-port-stream-2.0.1.tgz#d374820c581418c2275d3c4439ade0b82c4cfac6"
1956+
integrity sha512-ltrv4Dh/979I04+D4Te6TFygfRSOc5EBzzlHRldWMS8v73V80qWluxH88hqF0qyUsBXTb8NmzlmSipcre6a+rg==
1957+
dependencies:
1958+
webextension-polyfill-ts "^0.22.0"
1959+
19151960
extglob@^2.0.4:
19161961
version "2.0.4"
19171962
resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
@@ -2621,6 +2666,13 @@ jest-changed-files@^26.6.2:
26212666
execa "^4.0.0"
26222667
throat "^5.0.0"
26232668

2669+
jest-chrome@^0.7.1:
2670+
version "0.7.1"
2671+
resolved "https://registry.yarnpkg.com/jest-chrome/-/jest-chrome-0.7.1.tgz#72dd7cc0367e6b24f17974fb78f59665dafd0a10"
2672+
integrity sha512-rUsDoOIxvZr4JpzyYWepE5/l0xM5VO6010g93jhbaeYwJaJGpazYIClbLtbeWg+zUxMJvLdN3iDMvT6m8wNMwA==
2673+
dependencies:
2674+
"@types/chrome" "^0.0.114"
2675+
26242676
jest-cli@^26.6.3:
26252677
version "26.6.3"
26262678
resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a"
@@ -4684,6 +4736,25 @@ walker@^1.0.7, walker@~1.0.5:
46844736
dependencies:
46854737
makeerror "1.0.x"
46864738

4739+
webextension-polyfill-ts@^0.22.0:
4740+
version "0.22.0"
4741+
resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.22.0.tgz#86cfd7bab4d9d779d98c8340983f4b691b2343f3"
4742+
integrity sha512-3P33ClMwZ/qiAT7UH1ROrkRC1KM78umlnPpRhdC/292UyoTTW9NcjJEqDsv83HbibcTB6qCtpVeuB2q2/oniHQ==
4743+
dependencies:
4744+
webextension-polyfill "^0.7.0"
4745+
4746+
webextension-polyfill-ts@^0.25.0:
4747+
version "0.25.0"
4748+
resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.25.0.tgz#fff041626365dbd0e29c40b197e989a55ec221ca"
4749+
integrity sha512-ikQhwwHYkpBu00pFaUzIKY26I6L87DeRI+Q6jBT1daZUNuu8dSrg5U9l/ZbqdaQ1M/TTSPKeAa3kolP5liuedw==
4750+
dependencies:
4751+
webextension-polyfill "^0.7.0"
4752+
4753+
webextension-polyfill@^0.7.0:
4754+
version "0.7.0"
4755+
resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.7.0.tgz#0df1120ff0266056319ce1a622b09ad8d4a56505"
4756+
integrity sha512-su48BkMLxqzTTvPSE1eWxKToPS2Tv5DLGxKexLEVpwFd6Po6N8hhSLIvG6acPAg7qERoEaDL+Y5HQJeJeml5Aw==
4757+
46874758
webidl-conversions@^5.0.0:
46884759
version "5.0.0"
46894760
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"

0 commit comments

Comments
 (0)
Please sign in to comment.