@solana-mobile/mobile-wallet-adapter-protocol 0.0.1-alpha.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.
@@ -0,0 +1,466 @@
1
+ /*! *****************************************************************************
2
+ Copyright (c) Microsoft Corporation.
3
+
4
+ Permission to use, copy, modify, and/or distribute this software for any
5
+ purpose with or without fee is hereby granted.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13
+ PERFORMANCE OF THIS SOFTWARE.
14
+ ***************************************************************************** */
15
+
16
+ function __awaiter(thisArg, _arguments, P, generator) {
17
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
18
+ return new (P || (P = Promise))(function (resolve, reject) {
19
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
21
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
22
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
23
+ });
24
+ }
25
+
26
+ function createHelloReq(ecdhPublicKey, associationKeypairPrivateKey) {
27
+ return __awaiter(this, void 0, void 0, function* () {
28
+ const publicKeyBuffer = yield crypto.subtle.exportKey('raw', ecdhPublicKey);
29
+ const signatureBuffer = yield crypto.subtle.sign({ hash: 'SHA-256', name: 'ECDSA' }, associationKeypairPrivateKey, publicKeyBuffer);
30
+ const response = new Uint8Array(publicKeyBuffer.byteLength + signatureBuffer.byteLength);
31
+ response.set(new Uint8Array(publicKeyBuffer), 0);
32
+ response.set(new Uint8Array(signatureBuffer), publicKeyBuffer.byteLength);
33
+ return response;
34
+ });
35
+ }
36
+
37
+ class SolanaMobileWalletAdapterSecureContextRequiredError extends Error {
38
+ constructor() {
39
+ super('The mobile wallet adapter protocol must be used in a secure context (`https`).');
40
+ this.name = 'SolanaMobileWalletAdapterSecureContextRequiredError';
41
+ }
42
+ }
43
+ class SolanaMobileWalletAdapterForbiddenWalletBaseURLError extends Error {
44
+ constructor() {
45
+ super('Base URLs supplied by wallets must be valid `https` URLs');
46
+ this.name = 'SolanaMobileWalletAdapterForbiddenWalletBaseURLError';
47
+ }
48
+ }
49
+ class SolanaMobileWalletAdapterWalletNotInstalledError extends Error {
50
+ constructor() {
51
+ super(`Found no installed wallet that supports the mobile wallet protocol.`);
52
+ this.name = 'SolanaMobileWalletAdapterWalletNotInstalledError';
53
+ }
54
+ }
55
+ class SolanaMobileWalletAdapterProtocolSessionEstablishmentError extends Error {
56
+ constructor(port) {
57
+ super(`Failed to connect to the wallet websocket on port ${port}.`);
58
+ this.name = 'SolanaMobileWalletAdapterProtocolSessionEstablishmentError';
59
+ }
60
+ }
61
+ class SolanaMobileWalletAdapterProtocolAssociationPortOutOfRangeError extends Error {
62
+ constructor(port) {
63
+ super(`Association port number must be between 49152 and 65535. ${port} given.`);
64
+ this.name = 'SolanaMobileWalletAdapterProtocolAssociationPortOutOfRangeError';
65
+ }
66
+ }
67
+ class SolanaMobileWalletAdapterProtocolSessionClosedError extends Error {
68
+ constructor(code, reason) {
69
+ super(`The wallet session dropped unexpectedly (${code}: ${reason}).`);
70
+ this.name = 'SolanaMobileWalletAdapterProtocolSessionClosedError';
71
+ }
72
+ }
73
+ class SolanaMobileWalletAdapterProtocolReauthorizeError extends Error {
74
+ constructor() {
75
+ super('The auth token provided has gone stale and needs reauthorization.');
76
+ this.name = 'SolanaMobileWalletAdapterProtocolReauthorizeError';
77
+ }
78
+ }
79
+ // Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
80
+ const SolanaMobileWalletAdapterProtocolError = {
81
+ ERROR_REAUTHORIZE: -1,
82
+ ERROR_AUTHORIZATION_FAILED: -2,
83
+ ERROR_INVALID_PAYLOAD: -3,
84
+ ERROR_NOT_SIGNED: -4,
85
+ ERROR_NOT_COMMITTED: -5,
86
+ ERROR_ATTEST_ORIGIN_ANDROID: -100,
87
+ };
88
+ class SolanaMobileWalletAdapterProtocolJsonRpcError extends Error {
89
+ constructor(...args) {
90
+ const [jsonRpcMessageId, code, message, data] = args;
91
+ super(message);
92
+ this.code = code;
93
+ this.data = data;
94
+ this.jsonRpcMessageId = jsonRpcMessageId;
95
+ this.name = 'SolanaNativeWalletAdapterJsonRpcError';
96
+ }
97
+ }
98
+
99
+ function generateAssociationKeypair() {
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ return yield crypto.subtle.generateKey({
102
+ name: 'ECDSA',
103
+ namedCurve: 'P-256',
104
+ }, false /* extractable */, ['sign'] /* keyUsages */);
105
+ });
106
+ }
107
+
108
+ function generateECDHKeypair() {
109
+ return __awaiter(this, void 0, void 0, function* () {
110
+ return yield crypto.subtle.generateKey({
111
+ name: 'ECDH',
112
+ namedCurve: 'P-256',
113
+ }, false /* extractable */, ['deriveKey', 'deriveBits'] /* keyUsages */);
114
+ });
115
+ }
116
+
117
+ const INITIALIZATION_VECTOR_BYTES = 12;
118
+ function encryptJsonRpcMessage(jsonRpcMessage, sharedSecret) {
119
+ return __awaiter(this, void 0, void 0, function* () {
120
+ const plaintext = JSON.stringify(jsonRpcMessage);
121
+ const initializationVector = new Uint8Array(INITIALIZATION_VECTOR_BYTES);
122
+ crypto.getRandomValues(initializationVector);
123
+ const ciphertext = yield crypto.subtle.encrypt(getAlgorithmParams(initializationVector), sharedSecret, Buffer.from(plaintext));
124
+ const response = new Uint8Array(initializationVector.byteLength + ciphertext.byteLength);
125
+ response.set(new Uint8Array(initializationVector), 0);
126
+ response.set(new Uint8Array(ciphertext), initializationVector.byteLength);
127
+ return response;
128
+ });
129
+ }
130
+ function decryptJsonRpcMessage(message, sharedSecret) {
131
+ return __awaiter(this, void 0, void 0, function* () {
132
+ const initializationVector = message.slice(0, INITIALIZATION_VECTOR_BYTES);
133
+ const ciphertext = message.slice(INITIALIZATION_VECTOR_BYTES);
134
+ const plaintextBuffer = yield crypto.subtle.decrypt(getAlgorithmParams(initializationVector), sharedSecret, ciphertext);
135
+ const plaintext = getUtf8Decoder().decode(plaintextBuffer);
136
+ const jsonRpcMessage = JSON.parse(plaintext);
137
+ if (Object.hasOwnProperty.call(jsonRpcMessage, 'error')) {
138
+ throw new SolanaMobileWalletAdapterProtocolJsonRpcError(jsonRpcMessage.id, jsonRpcMessage.error.code, jsonRpcMessage.error.message);
139
+ }
140
+ return jsonRpcMessage;
141
+ });
142
+ }
143
+ function getAlgorithmParams(initializationVector) {
144
+ return {
145
+ iv: initializationVector,
146
+ name: 'AES-GCM',
147
+ tagLength: 128, // 16 byte tag => 128 bits
148
+ };
149
+ }
150
+ let _utf8Decoder;
151
+ function getUtf8Decoder() {
152
+ if (_utf8Decoder === undefined) {
153
+ _utf8Decoder = new TextDecoder('utf-8');
154
+ }
155
+ return _utf8Decoder;
156
+ }
157
+
158
+ function parseHelloRsp(payloadBuffer, // The X9.62-encoded wallet endpoint ephemeral ECDH public keypoint.
159
+ associationPublicKey, ecdhPrivateKey) {
160
+ return __awaiter(this, void 0, void 0, function* () {
161
+ const [associationPublicKeyBuffer, walletPublicKey] = yield Promise.all([
162
+ crypto.subtle.exportKey('raw', associationPublicKey),
163
+ crypto.subtle.importKey('raw', payloadBuffer, { name: 'ECDH', namedCurve: 'P-256' }, false /* extractable */, [] /* keyUsages */),
164
+ ]);
165
+ const sharedSecret = yield crypto.subtle.deriveBits({ name: 'ECDH', public: walletPublicKey }, ecdhPrivateKey, 256);
166
+ const ecdhSecretKey = yield crypto.subtle.importKey('raw', sharedSecret, 'HKDF', false /* extractable */, ['deriveKey'] /* keyUsages */);
167
+ const aesKeyMaterialVal = yield crypto.subtle.deriveKey({
168
+ name: 'HKDF',
169
+ hash: 'SHA-256',
170
+ salt: new Uint8Array(associationPublicKeyBuffer),
171
+ info: new Uint8Array(),
172
+ }, ecdhSecretKey, { name: 'AES-GCM', length: 128 }, false /* extractable */, ['encrypt', 'decrypt']);
173
+ return aesKeyMaterialVal;
174
+ });
175
+ }
176
+
177
+ function getRandomAssociationPort() {
178
+ return assertAssociationPort(49152 + Math.floor(Math.random() * (65535 - 49152 + 1)));
179
+ }
180
+ function assertAssociationPort(port) {
181
+ if (port < 49152 || port > 65535) {
182
+ throw new SolanaMobileWalletAdapterProtocolAssociationPortOutOfRangeError(port);
183
+ }
184
+ return port;
185
+ }
186
+
187
+ // https://stackoverflow.com/a/9458996/802047
188
+ function arrayBufferToBase64String(buffer) {
189
+ let binary = '';
190
+ const bytes = new Uint8Array(buffer);
191
+ const len = bytes.byteLength;
192
+ for (let ii = 0; ii < len; ii++) {
193
+ binary += String.fromCharCode(bytes[ii]);
194
+ }
195
+ return window.btoa(binary);
196
+ }
197
+
198
+ function getStringWithURLUnsafeCharactersReplaced(unsafeBase64EncodedString) {
199
+ return unsafeBase64EncodedString.replace(/[/+=]/g, (m) => ({
200
+ '/': '_',
201
+ '+': '-',
202
+ '=': '.',
203
+ }[m]));
204
+ }
205
+
206
+ const INTENT_NAME = 'solana-wallet';
207
+ function getPathParts(pathString) {
208
+ return (pathString
209
+ // Strip leading and trailing slashes
210
+ .replace(/(^\/+|\/+$)/g, '')
211
+ // Return an array of directories
212
+ .split('/'));
213
+ }
214
+ function getIntentURL(methodPathname, intentUrlBase) {
215
+ let baseUrl = null;
216
+ if (intentUrlBase) {
217
+ try {
218
+ baseUrl = new URL(intentUrlBase);
219
+ }
220
+ catch (_a) { } // eslint-disable-line no-empty
221
+ if ((baseUrl === null || baseUrl === void 0 ? void 0 : baseUrl.protocol) !== 'https:') {
222
+ throw new SolanaMobileWalletAdapterForbiddenWalletBaseURLError();
223
+ }
224
+ }
225
+ baseUrl || (baseUrl = new URL(`${INTENT_NAME}:/`));
226
+ const pathname = methodPathname.startsWith('/')
227
+ ? // Method is an absolute path. Replace it wholesale.
228
+ methodPathname
229
+ : // Method is a relative path. Merge it with the existing one.
230
+ [...getPathParts(baseUrl.pathname), ...getPathParts(methodPathname)].join('/');
231
+ return new URL(pathname, baseUrl);
232
+ }
233
+ function getAssociateAndroidIntentURL(associationPublicKey, putativePort, associationURLBase) {
234
+ return __awaiter(this, void 0, void 0, function* () {
235
+ const associationPort = assertAssociationPort(putativePort);
236
+ const exportedKey = yield crypto.subtle.exportKey('raw', associationPublicKey);
237
+ const encodedKey = arrayBufferToBase64String(exportedKey);
238
+ const url = getIntentURL('v1/associate/local', associationURLBase);
239
+ url.searchParams.set('association', getStringWithURLUnsafeCharactersReplaced(encodedKey));
240
+ url.searchParams.set('port', `${associationPort}`);
241
+ return url;
242
+ });
243
+ }
244
+
245
+ // Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
246
+ const Browser = {
247
+ Firefox: 0,
248
+ Other: 1,
249
+ };
250
+ function assertUnreachable(x) {
251
+ return x;
252
+ }
253
+ function getBrowser() {
254
+ return navigator.userAgent.indexOf('Firefox/') !== -1 ? Browser.Firefox : Browser.Other;
255
+ }
256
+ function getDetectionPromise() {
257
+ // Chrome and others silently fail if a custom protocol is not supported.
258
+ // For these, we wait to see if the browser is navigated away from in
259
+ // a reasonable amount of time (ie. the native wallet opened).
260
+ return new Promise((resolve, reject) => {
261
+ function cleanup() {
262
+ clearTimeout(timeoutId);
263
+ window.removeEventListener('blur', handleBlur);
264
+ }
265
+ function handleBlur() {
266
+ cleanup();
267
+ resolve();
268
+ }
269
+ window.addEventListener('blur', handleBlur);
270
+ const timeoutId = setTimeout(() => {
271
+ cleanup();
272
+ reject();
273
+ }, 2000);
274
+ });
275
+ }
276
+ let _frame = null;
277
+ function launchUrlThroughHiddenFrame(url) {
278
+ if (_frame == null) {
279
+ _frame = document.createElement('iframe');
280
+ _frame.style.display = 'none';
281
+ document.body.appendChild(_frame);
282
+ }
283
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
284
+ _frame.contentWindow.location.href = url.toString();
285
+ }
286
+ function startSession(associationPublicKey, associationURLBase) {
287
+ return __awaiter(this, void 0, void 0, function* () {
288
+ const randomAssociationPort = getRandomAssociationPort();
289
+ const associationUrl = yield getAssociateAndroidIntentURL(associationPublicKey, randomAssociationPort, associationURLBase);
290
+ if (associationUrl.protocol === 'https:') {
291
+ // The association URL is an Android 'App Link' or iOS 'Universal Link'.
292
+ // These are regular web URLs that are designed to launch an app if it
293
+ // is installed or load the actual target webpage if not.
294
+ window.location.assign(associationUrl);
295
+ }
296
+ else {
297
+ // The association URL has a custom protocol (eg. `solana-wallet:`)
298
+ try {
299
+ const browser = getBrowser();
300
+ switch (browser) {
301
+ case Browser.Firefox:
302
+ // If a custom protocol is not supported in Firefox, it throws.
303
+ launchUrlThroughHiddenFrame(associationUrl);
304
+ // If we reached this line, it's supported.
305
+ break;
306
+ case Browser.Other: {
307
+ const detectionPromise = getDetectionPromise();
308
+ window.location.assign(associationUrl);
309
+ yield detectionPromise;
310
+ break;
311
+ }
312
+ default:
313
+ assertUnreachable(browser);
314
+ }
315
+ }
316
+ catch (e) {
317
+ throw new SolanaMobileWalletAdapterWalletNotInstalledError();
318
+ }
319
+ }
320
+ return randomAssociationPort;
321
+ });
322
+ }
323
+
324
+ const WEBSOCKET_CONNECTION_CONFIG = {
325
+ maxAttempts: 34,
326
+ /**
327
+ * 300 milliseconds is a generally accepted threshold for what someone
328
+ * would consider an acceptable response time for a user interface
329
+ * after having performed a low-attention tapping task. We set the
330
+ * interval at which we wait for the wallet to set up the websocket at
331
+ * half this, as per the Nyquist frequency.
332
+ */
333
+ retryDelayMs: 150,
334
+ };
335
+ const WEBSOCKET_PROTOCOL = 'com.solana.mobilewalletadapter.v1';
336
+ function assertSecureContext() {
337
+ if (typeof window === 'undefined' || window.isSecureContext !== true) {
338
+ throw new SolanaMobileWalletAdapterSecureContextRequiredError();
339
+ }
340
+ }
341
+ function withLocalWallet(callback, config) {
342
+ return __awaiter(this, void 0, void 0, function* () {
343
+ assertSecureContext();
344
+ const associationKeypair = yield generateAssociationKeypair();
345
+ const sessionPort = yield startSession(associationKeypair.publicKey, config === null || config === void 0 ? void 0 : config.baseUri);
346
+ const websocketURL = `ws://localhost:${sessionPort}/solana-wallet`;
347
+ let nextJsonRpcMessageId = 1;
348
+ let state = { __type: 'disconnected' };
349
+ return new Promise((resolve, reject) => {
350
+ let attempts = 0;
351
+ let socket;
352
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
353
+ const jsonRpcResponsePromises = {};
354
+ const handleOpen = () => __awaiter(this, void 0, void 0, function* () {
355
+ if (state.__type !== 'connecting') {
356
+ console.warn('Expected adapter state to be `connecting` at the moment the websocket opens. ' +
357
+ `Got \`${state.__type}\`.`);
358
+ return;
359
+ }
360
+ const { associationKeypair } = state;
361
+ socket.removeEventListener('open', handleOpen);
362
+ const ecdhKeypair = yield generateECDHKeypair();
363
+ socket.send(yield createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey));
364
+ state = {
365
+ __type: 'hello_req_sent',
366
+ associationPublicKey: associationKeypair.publicKey,
367
+ ecdhPrivateKey: ecdhKeypair.privateKey,
368
+ };
369
+ });
370
+ const handleClose = (evt) => {
371
+ if (evt.wasClean) {
372
+ state = { __type: 'disconnected' };
373
+ }
374
+ else {
375
+ reject(new SolanaMobileWalletAdapterProtocolSessionClosedError(evt.code, evt.reason));
376
+ }
377
+ disposeSocket();
378
+ };
379
+ const handleError = (_evt) => __awaiter(this, void 0, void 0, function* () {
380
+ disposeSocket();
381
+ if (++attempts >= WEBSOCKET_CONNECTION_CONFIG.maxAttempts) {
382
+ reject(new SolanaMobileWalletAdapterProtocolSessionEstablishmentError(sessionPort));
383
+ }
384
+ else {
385
+ yield new Promise((resolve) => {
386
+ retryWaitTimeoutId = window.setTimeout(resolve, WEBSOCKET_CONNECTION_CONFIG.retryDelayMs);
387
+ });
388
+ attemptSocketConnection();
389
+ }
390
+ });
391
+ const handleMessage = (evt) => __awaiter(this, void 0, void 0, function* () {
392
+ const responseBuffer = yield evt.data.arrayBuffer();
393
+ switch (state.__type) {
394
+ case 'connected':
395
+ try {
396
+ const jsonRpcMessage = yield decryptJsonRpcMessage(responseBuffer, state.sharedSecret);
397
+ const responsePromise = jsonRpcResponsePromises[jsonRpcMessage.id];
398
+ delete jsonRpcResponsePromises[jsonRpcMessage.id];
399
+ responsePromise.resolve(jsonRpcMessage.result);
400
+ }
401
+ catch (e) {
402
+ if (e instanceof SolanaMobileWalletAdapterProtocolJsonRpcError) {
403
+ const responsePromise = jsonRpcResponsePromises[e.jsonRpcMessageId];
404
+ delete jsonRpcResponsePromises[e.jsonRpcMessageId];
405
+ responsePromise.reject(e);
406
+ }
407
+ else {
408
+ throw e;
409
+ }
410
+ }
411
+ break;
412
+ case 'hello_req_sent': {
413
+ const sharedSecret = yield parseHelloRsp(responseBuffer, state.associationPublicKey, state.ecdhPrivateKey);
414
+ state = { __type: 'connected', sharedSecret };
415
+ const wallet = (method, params) => __awaiter(this, void 0, void 0, function* () {
416
+ const id = nextJsonRpcMessageId++;
417
+ socket.send(yield encryptJsonRpcMessage({
418
+ id,
419
+ jsonrpc: '2.0',
420
+ method,
421
+ params,
422
+ }, sharedSecret));
423
+ return new Promise((resolve, reject) => {
424
+ jsonRpcResponsePromises[id] = { resolve, reject };
425
+ });
426
+ });
427
+ try {
428
+ resolve(yield callback(wallet));
429
+ }
430
+ catch (e) {
431
+ reject(e);
432
+ }
433
+ finally {
434
+ disposeSocket();
435
+ socket.close();
436
+ }
437
+ break;
438
+ }
439
+ }
440
+ });
441
+ let disposeSocket;
442
+ let retryWaitTimeoutId;
443
+ const attemptSocketConnection = () => {
444
+ if (disposeSocket) {
445
+ disposeSocket();
446
+ }
447
+ state = { __type: 'connecting', associationKeypair };
448
+ socket = new WebSocket(websocketURL, [WEBSOCKET_PROTOCOL]);
449
+ socket.addEventListener('open', handleOpen);
450
+ socket.addEventListener('close', handleClose);
451
+ socket.addEventListener('error', handleError);
452
+ socket.addEventListener('message', handleMessage);
453
+ disposeSocket = () => {
454
+ window.clearTimeout(retryWaitTimeoutId);
455
+ socket.removeEventListener('open', handleOpen);
456
+ socket.removeEventListener('close', handleClose);
457
+ socket.removeEventListener('error', handleError);
458
+ socket.removeEventListener('message', handleMessage);
459
+ };
460
+ };
461
+ attemptSocketConnection();
462
+ });
463
+ });
464
+ }
465
+
466
+ export { SolanaMobileWalletAdapterForbiddenWalletBaseURLError, SolanaMobileWalletAdapterProtocolAssociationPortOutOfRangeError, SolanaMobileWalletAdapterProtocolError, SolanaMobileWalletAdapterProtocolJsonRpcError, SolanaMobileWalletAdapterProtocolReauthorizeError, SolanaMobileWalletAdapterProtocolSessionClosedError, SolanaMobileWalletAdapterProtocolSessionEstablishmentError, SolanaMobileWalletAdapterSecureContextRequiredError, SolanaMobileWalletAdapterWalletNotInstalledError, withLocalWallet };
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Properties that wallets may present to users when an app
3
+ * asks for authorization to execute privileged methods (see
4
+ * {@link PrivilegedMethods}).
5
+ */
6
+ type AppIdentity = Readonly<{
7
+ uri?: string;
8
+ icon?: string;
9
+ name?: string;
10
+ }>;
11
+ /**
12
+ * An ephemeral elliptic-curve keypair on the P-256 curve.
13
+ * This public key is used to create the association token.
14
+ * The private key is used during session establishment.
15
+ */
16
+ type AssociationKeypair = CryptoKeyPair;
17
+ /**
18
+ * The context returned from a wallet after having authorized a given
19
+ * account for use with a given application. You can cache this and
20
+ * use it later to invoke privileged methods.
21
+ */
22
+ type AuthorizationResult = Readonly<{
23
+ authToken: string;
24
+ publicKey: string;
25
+ walletUriBase: string;
26
+ }>;
27
+ type AuthToken = string;
28
+ type Base58EncodedSignature = string;
29
+ type Base64EncodedMessage = string;
30
+ type Base64EncodedSignedMessage = string;
31
+ type Base64EncodedSignedTransaction = string;
32
+ type Base64EncodedTransaction = string;
33
+ interface MobileWallet {
34
+ (method: "authorize", params: {
35
+ identity: AppIdentity;
36
+ }): Promise<Readonly<{
37
+ auth_token: AuthToken;
38
+ pub_key: string;
39
+ wallet_uri_base: string;
40
+ }>>;
41
+ (method: "clone_authorization", params: {
42
+ auth_token: AuthToken;
43
+ }): Promise<Readonly<{
44
+ auth_token: AuthToken;
45
+ }>>;
46
+ (method: "deauthorize", params: {
47
+ auth_token: AuthToken;
48
+ }): Promise<Readonly<Record<string, never>>>;
49
+ (method: "reauthorize", params: {
50
+ auth_token: AuthToken;
51
+ }): Promise<Readonly<{
52
+ auth_token: AuthToken;
53
+ }>>;
54
+ (method: "sign_message", params: {
55
+ auth_token: AuthToken;
56
+ payloads: Base64EncodedMessage[];
57
+ }): Promise<Readonly<{
58
+ signed_payloads: Base64EncodedSignedMessage[];
59
+ }>>;
60
+ (method: "sign_transaction", params: {
61
+ auth_token: AuthToken;
62
+ payloads: Base64EncodedTransaction[];
63
+ }): Promise<Readonly<{
64
+ signed_payloads: Base64EncodedSignedTransaction[];
65
+ }>>;
66
+ (method: "sign_and_send_transaction", params: {
67
+ auth_token: AuthToken;
68
+ commitment: "confirmed" | "finalized" | "processed";
69
+ payloads: Base64EncodedTransaction[];
70
+ }): Promise<Readonly<{
71
+ signatures: Base58EncodedSignature[];
72
+ }>>;
73
+ }
74
+ type Config = Readonly<{
75
+ baseUri?: string;
76
+ }>;
77
+ declare function withLocalWallet<TReturn>(callback: (wallet: MobileWallet) => TReturn, config?: Config): Promise<TReturn>;
78
+ declare class SolanaMobileWalletAdapterSecureContextRequiredError extends Error {
79
+ constructor();
80
+ }
81
+ declare class SolanaMobileWalletAdapterForbiddenWalletBaseURLError extends Error {
82
+ constructor();
83
+ }
84
+ declare class SolanaMobileWalletAdapterWalletNotInstalledError extends Error {
85
+ constructor();
86
+ }
87
+ declare class SolanaMobileWalletAdapterProtocolSessionEstablishmentError extends Error {
88
+ constructor(port: number);
89
+ }
90
+ declare class SolanaMobileWalletAdapterProtocolAssociationPortOutOfRangeError extends Error {
91
+ constructor(port: number);
92
+ }
93
+ declare class SolanaMobileWalletAdapterProtocolSessionClosedError extends Error {
94
+ constructor(code: number, reason: string);
95
+ }
96
+ declare class SolanaMobileWalletAdapterProtocolReauthorizeError extends Error {
97
+ constructor();
98
+ }
99
+ type JSONRPCErrorCode = number;
100
+ // Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
101
+ declare const SolanaMobileWalletAdapterProtocolError: {
102
+ readonly ERROR_REAUTHORIZE: -1;
103
+ readonly ERROR_AUTHORIZATION_FAILED: -2;
104
+ readonly ERROR_INVALID_PAYLOAD: -3;
105
+ readonly ERROR_NOT_SIGNED: -4;
106
+ readonly ERROR_NOT_COMMITTED: -5;
107
+ readonly ERROR_ATTEST_ORIGIN_ANDROID: -100;
108
+ };
109
+ type SolanaMobileWalletAdapterProtocolErrorEnum = (typeof SolanaMobileWalletAdapterProtocolError)[keyof typeof SolanaMobileWalletAdapterProtocolError];
110
+ type ErrorDataTypeMap = {
111
+ [SolanaMobileWalletAdapterProtocolError.ERROR_ATTEST_ORIGIN_ANDROID]: {
112
+ attest_origin_uri: string;
113
+ challenge: string;
114
+ context: string;
115
+ };
116
+ };
117
+ declare class SolanaMobileWalletAdapterProtocolJsonRpcError<TErrorCode extends keyof ErrorDataTypeMap> extends Error {
118
+ data: ErrorDataTypeMap[TErrorCode] extends Record<string, unknown> ? ErrorDataTypeMap[TErrorCode] : undefined;
119
+ code: SolanaMobileWalletAdapterProtocolErrorEnum | JSONRPCErrorCode;
120
+ jsonRpcMessageId: number;
121
+ constructor(...args: ErrorDataTypeMap[TErrorCode] extends Record<string, unknown> ? [
122
+ jsonRpcMessageId: number,
123
+ code: SolanaMobileWalletAdapterProtocolErrorEnum | JSONRPCErrorCode,
124
+ message: string,
125
+ data: ErrorDataTypeMap[TErrorCode]
126
+ ] : [
127
+ jsonRpcMessageId: number,
128
+ code: SolanaMobileWalletAdapterProtocolErrorEnum | JSONRPCErrorCode,
129
+ message: string
130
+ ]);
131
+ }
132
+ export { withLocalWallet, SolanaMobileWalletAdapterSecureContextRequiredError, SolanaMobileWalletAdapterForbiddenWalletBaseURLError, SolanaMobileWalletAdapterWalletNotInstalledError, SolanaMobileWalletAdapterProtocolSessionEstablishmentError, SolanaMobileWalletAdapterProtocolAssociationPortOutOfRangeError, SolanaMobileWalletAdapterProtocolSessionClosedError, SolanaMobileWalletAdapterProtocolReauthorizeError, SolanaMobileWalletAdapterProtocolError, SolanaMobileWalletAdapterProtocolJsonRpcError, AppIdentity, AssociationKeypair, AuthorizationResult, AuthToken, MobileWallet };
133
+ //# sourceMappingURL=index.browser.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.browser.d.mts","sourceRoot":"","sources":["../../src/index.ts","../../src/createHelloReq.ts","../../src/errors.ts","../../src/generateAssociationKeypair.ts","../../src/generateECDHKeypair.ts","../../src/parseHelloRsp.ts","../../src/jsonRpcMessage.ts","../../src/associationPort.ts","../../src/arrayBufferToBase64String.ts","../../src/getStringWithURLUnsafeBase64CharactersReplaced.ts","../../src/getAssociateAndroidIntentURL.ts","../../src/startSession.ts","../../src/types.ts","../../src/withLocalWallet.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,2jBAA8B,CAA0B"}