@trezor/connect-mobile 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -0
- package/lib/index.d.ts +33 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +162 -0
- package/lib/index.js.map +1 -0
- package/package.json +30 -0
- package/src/index.ts +214 -0
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @trezor/connect-mobile
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.org/package/@trezor/connect-mobile)
|
|
4
|
+
|
|
5
|
+
The `@trezor/connect-mobile` package provides an implementation of `@trezor/connect` which uses deep links to communicate with the Trezor Suite Lite app.
|
|
6
|
+
|
|
7
|
+
## 🚧 BETA version, work in progress 🚧
|
|
8
|
+
|
|
9
|
+
Currently the library is still under development, only supports read-only methods and does not communicate with the production Suite Lite app.
|
|
10
|
+
|
|
11
|
+
To run a dev version of the Suite mobile app follow the instructions in [@suite-native/app](https://github.com/trezor/trezor-suite/blob/develop/suite-native/app/README.md)
|
|
12
|
+
|
|
13
|
+
## Using the Library
|
|
14
|
+
|
|
15
|
+
To use the library, you need to initialize it with the `deeplinkOpen` and `deeplinkCallbackUrl` settings.
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import TrezorConnect from '@trezor/connect-mobile';
|
|
19
|
+
|
|
20
|
+
TrezorConnect.init({
|
|
21
|
+
manifest: {
|
|
22
|
+
email: 'developer@xyz.com',
|
|
23
|
+
appUrl: 'http://your.application.com',
|
|
24
|
+
},
|
|
25
|
+
deeplinkOpen: url => {
|
|
26
|
+
// eslint-disable-next-line no-console
|
|
27
|
+
console.log('deeplinkOpen', url);
|
|
28
|
+
Linking.openURL(url);
|
|
29
|
+
},
|
|
30
|
+
deeplinkCallbackUrl: Linking.createURL('/connect'),
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
To receive the deep link callback, you need to add a listener which will call `TrezorConnect.handleDeeplink` with the deep link URL.
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const subscription = Linking.addEventListener('url', event => {
|
|
39
|
+
TrezorConnect.handleDeeplink(event.url);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return () => subscription?.remove();
|
|
43
|
+
}, []);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Example
|
|
47
|
+
|
|
48
|
+
The [Connect mobile example](https://github.com/trezor/trezor-suite/tree/develop/packages/connect-examples/mobile-expo) shows how to use the library in a React Native + Expo app.
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import EventEmitter from 'events';
|
|
2
|
+
import type { CallMethodPayload } from '@trezor/connect/lib/events/call';
|
|
3
|
+
import { ConnectFactoryDependencies } from '@trezor/connect/lib/factory';
|
|
4
|
+
import type { TrezorConnect as TrezorConnectType } from '@trezor/connect/lib/types';
|
|
5
|
+
import type { ConnectSettingsPublic, Manifest, Response } from '@trezor/connect/lib/types';
|
|
6
|
+
import { Login } from '@trezor/connect/lib/types/api/requestLogin';
|
|
7
|
+
export declare class TrezorConnectDeeplink implements ConnectFactoryDependencies {
|
|
8
|
+
eventEmitter: EventEmitter<[never]>;
|
|
9
|
+
private _settings;
|
|
10
|
+
private messagePromises;
|
|
11
|
+
private messageID;
|
|
12
|
+
constructor();
|
|
13
|
+
manifest(manifest: Manifest): void;
|
|
14
|
+
init(settings: Partial<ConnectSettingsPublic>): Promise<void>;
|
|
15
|
+
call(params: CallMethodPayload): Promise<any>;
|
|
16
|
+
requestLogin(): Response<Login>;
|
|
17
|
+
uiResponse(): void;
|
|
18
|
+
renderWebUSBButton(): void;
|
|
19
|
+
disableWebUSB(): void;
|
|
20
|
+
requestWebUSBDevice(): void;
|
|
21
|
+
cancel(error?: string): void;
|
|
22
|
+
dispose(): Promise<undefined>;
|
|
23
|
+
handleDeeplink(url: string): void;
|
|
24
|
+
private resolveMessagePromises;
|
|
25
|
+
private buildUrl;
|
|
26
|
+
private buildCallbackUrl;
|
|
27
|
+
}
|
|
28
|
+
declare const TrezorConnect: TrezorConnectType & {
|
|
29
|
+
handleDeeplink: (url: string) => void;
|
|
30
|
+
};
|
|
31
|
+
export default TrezorConnect;
|
|
32
|
+
export * from '@trezor/connect/lib/exports';
|
|
33
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAIlC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAW,MAAM,6BAA6B,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,KAAK,EAER,qBAAqB,EACrB,QAAQ,EACR,QAAQ,EACX,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,4CAA4C,CAAC;AAGnE,qBAAa,qBAAsB,YAAW,0BAA0B;IAC7D,YAAY,wBAAsB;IACzC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,eAAe,CAAqC;IAC5D,OAAO,CAAC,SAAS,CAAK;;IAWf,QAAQ,CAAC,QAAQ,EAAE,QAAQ;IAU3B,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAa7C,IAAI,CAAC,MAAM,EAAE,iBAAiB;IAsB9B,YAAY,IAAI,QAAQ,CAAC,KAAK,CAAC;IAI/B,UAAU;IAIV,kBAAkB;IAElB,aAAa;IAIb,mBAAmB;IAInB,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM;IAOrB,OAAO;IAOP,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAqDxC,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,gBAAgB;CAY3B;AAGD,QAAA,MAAM,aAAa,EAAE,iBAAiB,GAAG;IACrC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAgBzC,CAAC;AAGF,eAAe,aAAa,CAAC;AAC7B,cAAc,6BAA6B,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TrezorConnectDeeplink = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const events_1 = tslib_1.__importDefault(require("events"));
|
|
6
|
+
const ERRORS = tslib_1.__importStar(require("@trezor/connect/lib/constants/errors"));
|
|
7
|
+
const connectSettings_1 = require("@trezor/connect/lib/data/connectSettings");
|
|
8
|
+
const factory_1 = require("@trezor/connect/lib/factory");
|
|
9
|
+
const utils_1 = require("@trezor/utils");
|
|
10
|
+
class TrezorConnectDeeplink {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.eventEmitter = new events_1.default();
|
|
13
|
+
this.messagePromises = {};
|
|
14
|
+
this.messageID = 0;
|
|
15
|
+
this._settings = Object.assign(Object.assign({}, (0, connectSettings_1.parseConnectSettings)()), { deeplinkOpen: () => {
|
|
16
|
+
throw ERRORS.TypedError('Init_NotInitialized');
|
|
17
|
+
} });
|
|
18
|
+
}
|
|
19
|
+
manifest(manifest) {
|
|
20
|
+
this._settings = Object.assign(Object.assign({}, this._settings), (0, connectSettings_1.parseConnectSettings)(Object.assign(Object.assign({}, this._settings), { manifest })));
|
|
21
|
+
}
|
|
22
|
+
init(settings) {
|
|
23
|
+
if (!settings.deeplinkOpen) {
|
|
24
|
+
throw new Error('TrezorConnect native requires "deeplinkOpen" setting.');
|
|
25
|
+
}
|
|
26
|
+
this._settings = Object.assign(Object.assign({}, (0, connectSettings_1.parseConnectSettings)(Object.assign(Object.assign({}, this._settings), settings))), { deeplinkOpen: settings.deeplinkOpen, deeplinkCallbackUrl: settings.deeplinkCallbackUrl });
|
|
27
|
+
return Promise.resolve();
|
|
28
|
+
}
|
|
29
|
+
call(params) {
|
|
30
|
+
this.messageID++;
|
|
31
|
+
this.messagePromises[this.messageID] = (0, utils_1.createDeferred)();
|
|
32
|
+
const { method } = params, restParams = tslib_1.__rest(params, ["method"]);
|
|
33
|
+
if (!this._settings) {
|
|
34
|
+
throw new Error('TrezorConnect not initialized.');
|
|
35
|
+
}
|
|
36
|
+
if (!this._settings.deeplinkOpen) {
|
|
37
|
+
throw new Error('TrezorConnect native requires "deeplinkOpen" setting.');
|
|
38
|
+
}
|
|
39
|
+
if (!this._settings.deeplinkCallbackUrl) {
|
|
40
|
+
throw new Error('TrezorConnect native requires "deeplinkCallbackUrl" setting.');
|
|
41
|
+
}
|
|
42
|
+
const callbackUrl = this.buildCallbackUrl(this._settings.deeplinkCallbackUrl, {
|
|
43
|
+
id: this.messageID,
|
|
44
|
+
});
|
|
45
|
+
const url = this.buildUrl(method, restParams, callbackUrl);
|
|
46
|
+
this._settings.deeplinkOpen(url);
|
|
47
|
+
return this.messagePromises[this.messageID].promise;
|
|
48
|
+
}
|
|
49
|
+
requestLogin() {
|
|
50
|
+
throw ERRORS.TypedError('Method_InvalidPackage');
|
|
51
|
+
}
|
|
52
|
+
uiResponse() {
|
|
53
|
+
throw ERRORS.TypedError('Method_InvalidPackage');
|
|
54
|
+
}
|
|
55
|
+
renderWebUSBButton() { }
|
|
56
|
+
disableWebUSB() {
|
|
57
|
+
throw ERRORS.TypedError('Method_InvalidPackage');
|
|
58
|
+
}
|
|
59
|
+
requestWebUSBDevice() {
|
|
60
|
+
throw ERRORS.TypedError('Method_InvalidPackage');
|
|
61
|
+
}
|
|
62
|
+
cancel(error) {
|
|
63
|
+
this.resolveMessagePromises({
|
|
64
|
+
success: false,
|
|
65
|
+
error,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
dispose() {
|
|
69
|
+
this.eventEmitter.removeAllListeners();
|
|
70
|
+
this._settings = (0, connectSettings_1.parseConnectSettings)();
|
|
71
|
+
return Promise.resolve(undefined);
|
|
72
|
+
}
|
|
73
|
+
handleDeeplink(url) {
|
|
74
|
+
let id;
|
|
75
|
+
let parsedUrl;
|
|
76
|
+
try {
|
|
77
|
+
parsedUrl = new URL(url);
|
|
78
|
+
id = parsedUrl.searchParams.get('id');
|
|
79
|
+
if (!id || isNaN(Number(id)))
|
|
80
|
+
throw new Error('Missing `id` parameter.');
|
|
81
|
+
id = Number(id);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
this.resolveMessagePromises({
|
|
85
|
+
success: false,
|
|
86
|
+
error,
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (!this.messagePromises[id]) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const responseParam = parsedUrl.searchParams.get('response');
|
|
94
|
+
if (!responseParam) {
|
|
95
|
+
this.messagePromises[id].resolve({
|
|
96
|
+
id,
|
|
97
|
+
success: false,
|
|
98
|
+
error: 'The provided url is missing `response` parameter.',
|
|
99
|
+
});
|
|
100
|
+
delete this.messagePromises[id];
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
let parsedParams;
|
|
104
|
+
try {
|
|
105
|
+
parsedParams = JSON.parse(responseParam);
|
|
106
|
+
}
|
|
107
|
+
catch (_a) { }
|
|
108
|
+
if (!parsedParams) {
|
|
109
|
+
this.messagePromises[id].resolve({
|
|
110
|
+
id,
|
|
111
|
+
success: false,
|
|
112
|
+
error: 'Error parsing deeplink params.',
|
|
113
|
+
});
|
|
114
|
+
delete this.messagePromises[id];
|
|
115
|
+
}
|
|
116
|
+
const { success, payload } = parsedParams;
|
|
117
|
+
this.messagePromises[id].resolve({ id, payload, success });
|
|
118
|
+
delete this.messagePromises[id];
|
|
119
|
+
}
|
|
120
|
+
resolveMessagePromises(resolvePayload) {
|
|
121
|
+
Object.keys(this.messagePromises).forEach(id => {
|
|
122
|
+
this.messagePromises[id].resolve({
|
|
123
|
+
id,
|
|
124
|
+
payload: resolvePayload,
|
|
125
|
+
});
|
|
126
|
+
delete this.messagePromises[id];
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
buildUrl(method, params, callback) {
|
|
130
|
+
return `${this._settings.deeplinkUrl}?method=${method}¶ms=${encodeURIComponent(JSON.stringify(params))}&callback=${encodeURIComponent(callback)}`;
|
|
131
|
+
}
|
|
132
|
+
buildCallbackUrl(url, params) {
|
|
133
|
+
try {
|
|
134
|
+
const urlWithParams = new URL(url);
|
|
135
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
136
|
+
urlWithParams.searchParams.set(key, value.toString());
|
|
137
|
+
});
|
|
138
|
+
return urlWithParams.toString();
|
|
139
|
+
}
|
|
140
|
+
catch (_a) {
|
|
141
|
+
throw new Error('Provided "deeplinkCallbackUrl" is not valid.');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.TrezorConnectDeeplink = TrezorConnectDeeplink;
|
|
146
|
+
const impl = new TrezorConnectDeeplink();
|
|
147
|
+
const TrezorConnect = Object.assign(Object.assign({}, (0, factory_1.factory)({
|
|
148
|
+
eventEmitter: impl.eventEmitter,
|
|
149
|
+
init: impl.init.bind(impl),
|
|
150
|
+
call: impl.call.bind(impl),
|
|
151
|
+
manifest: impl.manifest.bind(impl),
|
|
152
|
+
requestLogin: impl.requestLogin.bind(impl),
|
|
153
|
+
uiResponse: impl.uiResponse.bind(impl),
|
|
154
|
+
renderWebUSBButton: impl.renderWebUSBButton.bind(impl),
|
|
155
|
+
disableWebUSB: impl.disableWebUSB.bind(impl),
|
|
156
|
+
requestWebUSBDevice: impl.requestWebUSBDevice.bind(impl),
|
|
157
|
+
cancel: impl.cancel.bind(impl),
|
|
158
|
+
dispose: impl.dispose.bind(impl),
|
|
159
|
+
})), { handleDeeplink: impl.handleDeeplink.bind(impl) });
|
|
160
|
+
exports.default = TrezorConnect;
|
|
161
|
+
tslib_1.__exportStar(require("@trezor/connect/lib/exports"), exports);
|
|
162
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,4DAAkC;AAElC,qFAA+D;AAC/D,8EAAgF;AAEhF,yDAAkF;AASlF,yCAAyD;AAEzD,MAAa,qBAAqB;IAM9B;QALO,iBAAY,GAAG,IAAI,gBAAY,EAAE,CAAC;QAEjC,oBAAe,GAAkC,EAAE,CAAC;QACpD,cAAS,GAAG,CAAC,CAAC;QAGlB,IAAI,CAAC,SAAS,mCACP,IAAA,sCAAoB,GAAE,KACzB,YAAY,EAAE,GAAG,EAAE;gBACf,MAAM,MAAM,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC;YACnD,CAAC,GACJ,CAAC;IACN,CAAC;IAEM,QAAQ,CAAC,QAAkB;QAC9B,IAAI,CAAC,SAAS,mCACP,IAAI,CAAC,SAAS,GACd,IAAA,sCAAoB,kCAChB,IAAI,CAAC,SAAS,KACjB,QAAQ,IACV,CACL,CAAC;IACN,CAAC;IAEM,IAAI,CAAC,QAAwC;QAChD,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,CAAC,SAAS,mCACP,IAAA,sCAAoB,kCAAM,IAAI,CAAC,SAAS,GAAK,QAAQ,EAAG,KAC3D,YAAY,EAAE,QAAQ,CAAC,YAAY,EACnC,mBAAmB,EAAE,QAAQ,CAAC,mBAAmB,GACpD,CAAC;QAEF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;IAEM,IAAI,CAAC,MAAyB;QACjC,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAA,sBAAc,GAAE,CAAC;QACxD,MAAM,EAAE,MAAM,KAAoB,MAAM,EAArB,UAAU,kBAAK,MAAM,EAAlC,UAAyB,CAAS,CAAC;QACzC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,mBAAmB,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,mBAAmB,EAAE;YAC1E,EAAE,EAAE,IAAI,CAAC,SAAS;SACrB,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;QAC3D,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAEjC,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC;IACxD,CAAC;IAEM,YAAY;QACf,MAAM,MAAM,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAAC;IACrD,CAAC;IAEM,UAAU;QACb,MAAM,MAAM,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAAC;IACrD,CAAC;IAEM,kBAAkB,KAAI,CAAC;IAEvB,aAAa;QAChB,MAAM,MAAM,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAAC;IACrD,CAAC;IAEM,mBAAmB;QACtB,MAAM,MAAM,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAAC;IACrD,CAAC;IAEM,MAAM,CAAC,KAAc;QACxB,IAAI,CAAC,sBAAsB,CAAC;YACxB,OAAO,EAAE,KAAK;YACd,KAAK;SACR,CAAC,CAAC;IACP,CAAC;IAEM,OAAO;QACV,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,IAAA,sCAAoB,GAAE,CAAC;QAExC,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAEM,cAAc,CAAC,GAAW;QAC7B,IAAI,EAAE,CAAC;QACP,IAAI,SAAS,CAAC;QACd,IAAI,CAAC;YACD,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YACzB,EAAE,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,CAAC,EAAE,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YACzE,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,sBAAsB,CAAC;gBACxB,OAAO,EAAE,KAAK;gBACd,KAAK;aACR,CAAC,CAAC;YAEH,OAAO;QACX,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,CAAC;YAE5B,OAAO;QACX,CAAC;QAED,MAAM,aAAa,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC7D,IAAI,CAAC,aAAa,EAAE,CAAC;YACjB,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;gBAC7B,EAAE;gBACF,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,mDAAmD;aAC7D,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;YAEhC,OAAO;QACX,CAAC;QAED,IAAI,YAAY,CAAC;QACjB,IAAI,CAAC;YACD,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC7C,CAAC;QAAC,WAAM,CAAC,CAAA,CAAC;QAEV,IAAI,CAAC,YAAY,EAAE,CAAC;YAChB,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;gBAC7B,EAAE;gBACF,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,gCAAgC;aAC1C,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC;QAC1C,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAEO,sBAAsB,CAAC,cAAmC;QAC9D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;YAC3C,IAAI,CAAC,eAAe,CAAC,EAAS,CAAC,CAAC,OAAO,CAAC;gBACpC,EAAE;gBACF,OAAO,EAAE,cAAc;aAC1B,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,eAAe,CAAC,EAAS,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,QAAQ,CAAC,MAAc,EAAE,MAAW,EAAE,QAAgB;QAC1D,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,WAAW,MAAM,WAAW,kBAAkB,CAC9E,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CACzB,aAAa,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;IACjD,CAAC;IAEO,gBAAgB,CAAC,GAAW,EAAE,MAAuC;QACzE,IAAI,CAAC;YACD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YACnC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;gBAC5C,aAAa,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC1D,CAAC,CAAC,CAAC;YAEH,OAAO,aAAa,CAAC,QAAQ,EAAE,CAAC;QACpC,CAAC;QAAC,WAAM,CAAC;YACL,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QACpE,CAAC;IACL,CAAC;CACJ;AA7KD,sDA6KC;AAED,MAAM,IAAI,GAAG,IAAI,qBAAqB,EAAE,CAAC;AACzC,MAAM,aAAa,mCAGZ,IAAA,iBAAO,EAAC;IACP,YAAY,EAAE,IAAI,CAAC,YAAY;IAC/B,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IAC1B,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IAC1B,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;IAClC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;IAC1C,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;IACtC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;IACtD,aAAa,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;IAC5C,mBAAmB,EAAE,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;IACxD,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;IAC9B,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;CACnC,CAAC,KACF,cAAc,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GACjD,CAAC;AAGF,kBAAe,aAAa,CAAC;AAC7B,sEAA4C"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@trezor/connect-mobile",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"license": "See LICENSE.md in repo root",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"main": "lib/index.js"
|
|
9
|
+
},
|
|
10
|
+
"npmPublishAccess": "public",
|
|
11
|
+
"files": [
|
|
12
|
+
"lib/"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"lint:js": "yarn g:eslint '**/*.{ts,tsx,js}'",
|
|
16
|
+
"depcheck": "yarn g:depcheck",
|
|
17
|
+
"type-check": "yarn g:tsc --build",
|
|
18
|
+
"build:lib": "yarn g:rimraf ./lib && yarn g:tsc --build tsconfig.lib.json && ../../scripts/replace-imports.sh ./lib"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"tsx": "^4.16.3"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@trezor/connect": "workspace:^",
|
|
25
|
+
"@trezor/utils": "workspace:^"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"tslib": "^2.6.2"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import EventEmitter from 'events';
|
|
2
|
+
|
|
3
|
+
import * as ERRORS from '@trezor/connect/src/constants/errors';
|
|
4
|
+
import { parseConnectSettings } from '@trezor/connect/src/data/connectSettings';
|
|
5
|
+
import type { CallMethodPayload } from '@trezor/connect/src/events/call';
|
|
6
|
+
import { ConnectFactoryDependencies, factory } from '@trezor/connect/src/factory';
|
|
7
|
+
import type { TrezorConnect as TrezorConnectType } from '@trezor/connect/src/types';
|
|
8
|
+
import type {
|
|
9
|
+
ConnectSettings,
|
|
10
|
+
ConnectSettingsPublic,
|
|
11
|
+
Manifest,
|
|
12
|
+
Response,
|
|
13
|
+
} from '@trezor/connect/src/types';
|
|
14
|
+
import { Login } from '@trezor/connect/src/types/api/requestLogin';
|
|
15
|
+
import { Deferred, createDeferred } from '@trezor/utils';
|
|
16
|
+
|
|
17
|
+
export class TrezorConnectDeeplink implements ConnectFactoryDependencies {
|
|
18
|
+
public eventEmitter = new EventEmitter();
|
|
19
|
+
private _settings: ConnectSettings;
|
|
20
|
+
private messagePromises: Record<number, Deferred<any>> = {};
|
|
21
|
+
private messageID = 0;
|
|
22
|
+
|
|
23
|
+
public constructor() {
|
|
24
|
+
this._settings = {
|
|
25
|
+
...parseConnectSettings(),
|
|
26
|
+
deeplinkOpen: () => {
|
|
27
|
+
throw ERRORS.TypedError('Init_NotInitialized');
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public manifest(manifest: Manifest) {
|
|
33
|
+
this._settings = {
|
|
34
|
+
...this._settings,
|
|
35
|
+
...parseConnectSettings({
|
|
36
|
+
...this._settings,
|
|
37
|
+
manifest,
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public init(settings: Partial<ConnectSettingsPublic>) {
|
|
43
|
+
if (!settings.deeplinkOpen) {
|
|
44
|
+
throw new Error('TrezorConnect native requires "deeplinkOpen" setting.');
|
|
45
|
+
}
|
|
46
|
+
this._settings = {
|
|
47
|
+
...parseConnectSettings({ ...this._settings, ...settings }),
|
|
48
|
+
deeplinkOpen: settings.deeplinkOpen,
|
|
49
|
+
deeplinkCallbackUrl: settings.deeplinkCallbackUrl,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return Promise.resolve();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public call(params: CallMethodPayload) {
|
|
56
|
+
this.messageID++;
|
|
57
|
+
this.messagePromises[this.messageID] = createDeferred();
|
|
58
|
+
const { method, ...restParams } = params;
|
|
59
|
+
if (!this._settings) {
|
|
60
|
+
throw new Error('TrezorConnect not initialized.');
|
|
61
|
+
}
|
|
62
|
+
if (!this._settings.deeplinkOpen) {
|
|
63
|
+
throw new Error('TrezorConnect native requires "deeplinkOpen" setting.');
|
|
64
|
+
}
|
|
65
|
+
if (!this._settings.deeplinkCallbackUrl) {
|
|
66
|
+
throw new Error('TrezorConnect native requires "deeplinkCallbackUrl" setting.');
|
|
67
|
+
}
|
|
68
|
+
const callbackUrl = this.buildCallbackUrl(this._settings.deeplinkCallbackUrl, {
|
|
69
|
+
id: this.messageID,
|
|
70
|
+
});
|
|
71
|
+
const url = this.buildUrl(method, restParams, callbackUrl);
|
|
72
|
+
this._settings.deeplinkOpen(url);
|
|
73
|
+
|
|
74
|
+
return this.messagePromises[this.messageID].promise;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public requestLogin(): Response<Login> {
|
|
78
|
+
throw ERRORS.TypedError('Method_InvalidPackage');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public uiResponse() {
|
|
82
|
+
throw ERRORS.TypedError('Method_InvalidPackage');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public renderWebUSBButton() {}
|
|
86
|
+
|
|
87
|
+
public disableWebUSB() {
|
|
88
|
+
throw ERRORS.TypedError('Method_InvalidPackage');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public requestWebUSBDevice() {
|
|
92
|
+
throw ERRORS.TypedError('Method_InvalidPackage');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public cancel(error?: string) {
|
|
96
|
+
this.resolveMessagePromises({
|
|
97
|
+
success: false,
|
|
98
|
+
error,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public dispose() {
|
|
103
|
+
this.eventEmitter.removeAllListeners();
|
|
104
|
+
this._settings = parseConnectSettings();
|
|
105
|
+
|
|
106
|
+
return Promise.resolve(undefined);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public handleDeeplink(url: string): void {
|
|
110
|
+
let id;
|
|
111
|
+
let parsedUrl;
|
|
112
|
+
try {
|
|
113
|
+
parsedUrl = new URL(url);
|
|
114
|
+
id = parsedUrl.searchParams.get('id');
|
|
115
|
+
if (!id || isNaN(Number(id))) throw new Error('Missing `id` parameter.');
|
|
116
|
+
id = Number(id);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
this.resolveMessagePromises({
|
|
119
|
+
success: false,
|
|
120
|
+
error,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!this.messagePromises[id]) {
|
|
127
|
+
// Most likely old ID, ignore
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const responseParam = parsedUrl.searchParams.get('response');
|
|
132
|
+
if (!responseParam) {
|
|
133
|
+
this.messagePromises[id].resolve({
|
|
134
|
+
id,
|
|
135
|
+
success: false,
|
|
136
|
+
error: 'The provided url is missing `response` parameter.',
|
|
137
|
+
});
|
|
138
|
+
delete this.messagePromises[id];
|
|
139
|
+
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let parsedParams;
|
|
144
|
+
try {
|
|
145
|
+
parsedParams = JSON.parse(responseParam);
|
|
146
|
+
} catch {}
|
|
147
|
+
|
|
148
|
+
if (!parsedParams) {
|
|
149
|
+
this.messagePromises[id].resolve({
|
|
150
|
+
id,
|
|
151
|
+
success: false,
|
|
152
|
+
error: 'Error parsing deeplink params.',
|
|
153
|
+
});
|
|
154
|
+
delete this.messagePromises[id];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const { success, payload } = parsedParams;
|
|
158
|
+
this.messagePromises[id].resolve({ id, payload, success });
|
|
159
|
+
delete this.messagePromises[id];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private resolveMessagePromises(resolvePayload: Record<string, any>) {
|
|
163
|
+
Object.keys(this.messagePromises).forEach(id => {
|
|
164
|
+
this.messagePromises[id as any].resolve({
|
|
165
|
+
id,
|
|
166
|
+
payload: resolvePayload,
|
|
167
|
+
});
|
|
168
|
+
delete this.messagePromises[id as any];
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private buildUrl(method: string, params: any, callback: string) {
|
|
173
|
+
return `${this._settings.deeplinkUrl}?method=${method}¶ms=${encodeURIComponent(
|
|
174
|
+
JSON.stringify(params),
|
|
175
|
+
)}&callback=${encodeURIComponent(callback)}`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private buildCallbackUrl(url: string, params: Record<string, string | number>) {
|
|
179
|
+
try {
|
|
180
|
+
const urlWithParams = new URL(url);
|
|
181
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
182
|
+
urlWithParams.searchParams.set(key, value.toString());
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return urlWithParams.toString();
|
|
186
|
+
} catch {
|
|
187
|
+
throw new Error('Provided "deeplinkCallbackUrl" is not valid.');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const impl = new TrezorConnectDeeplink();
|
|
193
|
+
const TrezorConnect: TrezorConnectType & {
|
|
194
|
+
handleDeeplink: (url: string) => void;
|
|
195
|
+
} = {
|
|
196
|
+
...factory({
|
|
197
|
+
eventEmitter: impl.eventEmitter,
|
|
198
|
+
init: impl.init.bind(impl),
|
|
199
|
+
call: impl.call.bind(impl),
|
|
200
|
+
manifest: impl.manifest.bind(impl),
|
|
201
|
+
requestLogin: impl.requestLogin.bind(impl),
|
|
202
|
+
uiResponse: impl.uiResponse.bind(impl),
|
|
203
|
+
renderWebUSBButton: impl.renderWebUSBButton.bind(impl),
|
|
204
|
+
disableWebUSB: impl.disableWebUSB.bind(impl),
|
|
205
|
+
requestWebUSBDevice: impl.requestWebUSBDevice.bind(impl),
|
|
206
|
+
cancel: impl.cancel.bind(impl),
|
|
207
|
+
dispose: impl.dispose.bind(impl),
|
|
208
|
+
}),
|
|
209
|
+
handleDeeplink: impl.handleDeeplink.bind(impl),
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// eslint-disable-next-line import/no-default-export
|
|
213
|
+
export default TrezorConnect;
|
|
214
|
+
export * from '@trezor/connect/src/exports';
|