diff --git a/package-lock.json b/package-lock.json index f04e265..7275f93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "@types/lodash.omit": "4.5.9", "husky": "^8.0.3", "lint-staged": "^13.2.3", - "prettier": "^2.8.4", + "prettier": "3.3.3", "process": "^0.11.10", "rimraf": "^3.0.2", "stream-browserify": "^3.0.0", @@ -5638,15 +5638,16 @@ } }, "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, + "license": "MIT", "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -11253,9 +11254,9 @@ } }, "prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true }, "pretty-format": { diff --git a/package.json b/package.json index 7d38a14..05f8e26 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@types/lodash.omit": "4.5.9", "husky": "^8.0.3", "lint-staged": "^13.2.3", - "prettier": "^2.8.4", + "prettier": "3.3.3", "process": "^0.11.10", "rimraf": "^3.0.2", "stream-browserify": "^3.0.0", diff --git a/src/adapters/BaseAdapter.ts b/src/adapters/BaseAdapter.ts index 2aa13d9..c92afbf 100644 --- a/src/adapters/BaseAdapter.ts +++ b/src/adapters/BaseAdapter.ts @@ -2,6 +2,7 @@ import { Params, Requests } from '../request'; import { SatsConnectAdapter } from './satsConnectAdapter'; import { request } from '../request'; import { RpcResult } from '../types'; +import { AddListener, WalletEvent } from 'src/provider'; class BaseAdapter extends SatsConnectAdapter { id = ''; @@ -17,6 +18,10 @@ class BaseAdapter extends SatsConnectAdapter { ): Promise> => { return request(method, params, this.id); }; + + addListener: AddListener = (..._args) => { + throw new Error('Method not supported for `BaseAdapter`.'); + }; } export { BaseAdapter }; diff --git a/src/adapters/satsConnectAdapter.ts b/src/adapters/satsConnectAdapter.ts index 9534ec4..57d781e 100644 --- a/src/adapters/satsConnectAdapter.ts +++ b/src/adapters/satsConnectAdapter.ts @@ -1,6 +1,7 @@ import { getRunesApiClient, RunesApi } from '../runes/api'; import { Params, Requests } from '../request'; import { RpcErrorCode, RpcResult } from '../types'; +import { AddListener, WalletEvent } from 'src/provider'; abstract class SatsConnectAdapter { abstract readonly id: string; @@ -358,6 +359,8 @@ abstract class SatsConnectAdapter { } } + abstract addListener: AddListener; + protected abstract requestInternal( method: Method, params: Params diff --git a/src/adapters/xverse.ts b/src/adapters/xverse.ts index 533c419..40f3ce9 100644 --- a/src/adapters/xverse.ts +++ b/src/adapters/xverse.ts @@ -1,8 +1,9 @@ -import { Params, Requests } from '../request'; +import { addListener, Params, Requests } from '../request'; import { SatsConnectAdapter } from './satsConnectAdapter'; import { request } from '../request'; import { RpcResult } from '../types'; import { DefaultAdaptersInfo } from '.'; +import { AddListener, WalletEvent } from 'src/provider/types'; class XverseAdapter extends SatsConnectAdapter { id = DefaultAdaptersInfo.xverse.id; @@ -13,6 +14,16 @@ class XverseAdapter extends SatsConnectAdapter { ): Promise> => { return request(method, params, this.id); }; + + addListener: AddListener = (event, cb) => { + return addListener( + event, + // The types of the `addListener` function being called here are not + // entirely accurate. + cb as any, + this.id + ); + }; } export { XverseAdapter }; diff --git a/src/capabilities/index.ts b/src/capabilities/index.ts index cc2f54c..6f70fe5 100644 --- a/src/capabilities/index.ts +++ b/src/capabilities/index.ts @@ -36,6 +36,7 @@ const extractOrValidateCapabilities = ( createInscription: validateCapability('createInscription'), createRepeatInscriptions: validateCapability('createRepeatInscriptions'), signMultipleTransactions: validateCapability('signMultipleTransactions'), + addListener: validateCapability('addListener'), }; return Object.entries(capabilityMap).reduce((acc, [capability, value]) => { diff --git a/src/provider/types.ts b/src/provider/types.ts index 376d191..20aa457 100644 --- a/src/provider/types.ts +++ b/src/provider/types.ts @@ -16,6 +16,29 @@ import type { SignTransactionResponse, } from '../transactions'; import { RpcResponse } from '../types'; +import * as v from 'valibot'; + +// accountChange +export const accountChangeEventName = 'accountChange'; +export const accountChangeSchema = v.object({ + type: v.literal(accountChangeEventName), +}); +export type AccountChangeEvent = v.InferOutput; + +// networkChange +export const networkChangeEventName = 'networkChange'; +export const networkChangeSchema = v.object({ + type: v.literal(networkChangeEventName), +}); +export type NetworkChangeEvent = v.InferOutput; + +export const walletEventSchema = v.variant('type', [accountChangeSchema, networkChangeSchema]); +export type WalletEvent = v.InferOutput; + +export type AddListener = ( + eventName: WalletEventName, + cb: (event: Extract) => void +) => () => void; interface BaseBitcoinProvider { request: ( @@ -30,6 +53,7 @@ interface BaseBitcoinProvider { createInscription: (request: string) => Promise; createRepeatInscriptions: (request: string) => Promise; signMultipleTransactions: (request: string) => Promise; + addListener: AddListener; } export type Capability = keyof BaseBitcoinProvider; diff --git a/src/request/index.ts b/src/request/index.ts index 708f704..a68a3c2 100644 --- a/src/request/index.ts +++ b/src/request/index.ts @@ -1,4 +1,4 @@ -import { getProviderById } from '../provider'; +import { AddListener, getProviderById, WalletEvent } from '../provider'; import { RpcErrorCode, RpcResult, @@ -50,4 +50,20 @@ export const request = async ( }; }; +export const addListener = ( + event: Parameters[0], + cb: Parameters[1], + providerId?: string +): ReturnType => { + let provider = window.XverseProviders?.BitcoinProvider || window.BitcoinProvider; + if (providerId) { + provider = getProviderById(providerId); + } + if (!provider) { + throw new Error('no wallet provider was found'); + } + + return provider.addListener(event, cb); +}; + export * from './types';