@0xsequence/dapp-client 0.0.0-20250910142613
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/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +11 -0
- package/LICENSE +202 -0
- package/README.md +238 -0
- package/dist/ChainSessionManager.d.ts +203 -0
- package/dist/ChainSessionManager.d.ts.map +1 -0
- package/dist/ChainSessionManager.js +742 -0
- package/dist/DappClient.d.ts +409 -0
- package/dist/DappClient.d.ts.map +1 -0
- package/dist/DappClient.js +667 -0
- package/dist/DappTransport.d.ts +47 -0
- package/dist/DappTransport.d.ts.map +1 -0
- package/dist/DappTransport.js +443 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/types/index.d.ts +168 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +25 -0
- package/dist/utils/constants.d.ts +6 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +5 -0
- package/dist/utils/errors.d.ts +28 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +54 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +135 -0
- package/dist/utils/storage.d.ts +64 -0
- package/dist/utils/storage.d.ts.map +1 -0
- package/dist/utils/storage.js +196 -0
- package/eslint.config.mjs +4 -0
- package/package.json +38 -0
- package/src/ChainSessionManager.ts +978 -0
- package/src/DappClient.ts +801 -0
- package/src/DappTransport.ts +518 -0
- package/src/index.ts +47 -0
- package/src/types/index.ts +218 -0
- package/src/utils/constants.ts +5 -0
- package/src/utils/errors.ts +62 -0
- package/src/utils/index.ts +158 -0
- package/src/utils/storage.ts +272 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { PopupModeOptions, SendRequestOptions, SequenceSessionStorage, TransportMode } from './types/index.js';
|
|
2
|
+
export declare class DappTransport {
|
|
3
|
+
readonly walletUrl: string;
|
|
4
|
+
readonly mode: TransportMode;
|
|
5
|
+
private walletWindow;
|
|
6
|
+
private connectionState;
|
|
7
|
+
private readyPromise;
|
|
8
|
+
private readyPromiseResolve;
|
|
9
|
+
private readyPromiseReject;
|
|
10
|
+
private initId;
|
|
11
|
+
private handshakeTimeoutId;
|
|
12
|
+
private closeCheckIntervalId;
|
|
13
|
+
private sessionId;
|
|
14
|
+
private pendingRequests;
|
|
15
|
+
private messageQueue;
|
|
16
|
+
private readonly requestTimeoutMs;
|
|
17
|
+
private readonly handshakeTimeoutMs;
|
|
18
|
+
private readonly sequenceSessionStorage;
|
|
19
|
+
private readonly redirectActionHandler?;
|
|
20
|
+
readonly walletOrigin: string;
|
|
21
|
+
constructor(walletUrl: string, mode?: TransportMode, popupModeOptions?: PopupModeOptions, sequenceSessionStorage?: SequenceSessionStorage, redirectActionHandler?: (url: string) => void);
|
|
22
|
+
get isWalletOpen(): boolean;
|
|
23
|
+
get isReady(): boolean;
|
|
24
|
+
sendRequest<TResponse = any, TRequest = any>(action: string, redirectUrl: string, payload?: TRequest, options?: SendRequestOptions): Promise<TResponse>;
|
|
25
|
+
getRequestRedirectUrl(action: string, payload: any, redirectUrl: string, path?: string): Promise<string>;
|
|
26
|
+
getRedirectResponse<TResponse = any>(cleanState?: boolean, url?: string): Promise<{
|
|
27
|
+
payload: TResponse;
|
|
28
|
+
action: string;
|
|
29
|
+
} | {
|
|
30
|
+
error: any;
|
|
31
|
+
action: string;
|
|
32
|
+
} | null>;
|
|
33
|
+
openWallet(path?: string): Promise<void>;
|
|
34
|
+
closeWallet(): void;
|
|
35
|
+
destroy(): void;
|
|
36
|
+
private handleMessage;
|
|
37
|
+
private handleWalletReadyMessage;
|
|
38
|
+
private handleResponseMessage;
|
|
39
|
+
private postMessageToWallet;
|
|
40
|
+
private _resetConnection;
|
|
41
|
+
private _handlePreConnectionFailure;
|
|
42
|
+
private _handleDetectedClosure;
|
|
43
|
+
private clearPendingRequests;
|
|
44
|
+
private clearTimeouts;
|
|
45
|
+
private generateId;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=DappTransport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DappTransport.d.ts","sourceRoot":"","sources":["../src/DappTransport.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EAEtB,aAAa,EAEd,MAAM,kBAAkB,CAAA;AAUzB,qBAAa,aAAa;aAoBN,SAAS,EAAE,MAAM;IACjC,QAAQ,CAAC,IAAI,EAAE,aAAa;IApB9B,OAAO,CAAC,YAAY,CAAgC;IACpD,OAAO,CAAC,eAAe,CAAgD;IACvE,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,mBAAmB,CAAsC;IACjE,OAAO,CAAC,kBAAkB,CAAkD;IAC5E,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,kBAAkB,CAAgC;IAC1D,OAAO,CAAC,oBAAoB,CAAgC;IAC5D,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,eAAe,CAAoC;IAC3D,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IACzC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAQ;IAC3C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAwB;IAC/D,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAuB;IAE9D,SAAgB,YAAY,EAAE,MAAM,CAAA;gBAGlB,SAAS,EAAE,MAAM,EACxB,IAAI,GAAE,aAAmC,EAClD,gBAAgB,GAAE,gBAAqB,EACvC,sBAAsB,CAAC,EAAE,sBAAsB,EAC/C,qBAAqB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI;IA+B/C,IAAI,YAAY,IAAI,OAAO,CAG1B;IAED,IAAI,OAAO,IAAI,OAAO,CAGrB;IAEK,WAAW,CAAC,SAAS,GAAG,GAAG,EAAE,QAAQ,GAAG,GAAG,EAC/C,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,QAAQ,EAClB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,SAAS,CAAC;IA0CR,qBAAqB,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,GAAG,EACZ,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC;IAuBL,mBAAmB,CAAC,SAAS,GAAG,GAAG,EAC9C,UAAU,GAAE,OAAc,EAC1B,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC;QAAE,OAAO,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,KAAK,EAAE,GAAG,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAyEnF,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6DxC,WAAW,IAAI,IAAI;IAgB1B,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,aAAa,CAuCpB;IAED,OAAO,CAAC,wBAAwB;IAiChC,OAAO,CAAC,qBAAqB;IAc7B,OAAO,CAAC,mBAAmB;IAkD3B,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,2BAA2B;IAInC,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,UAAU;CAGnB"}
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { jsonReplacers, jsonRevivers } from './utils/index.js';
|
|
3
|
+
import { MessageType, TransportMode, WalletSize, } from './types/index.js';
|
|
4
|
+
var ConnectionState;
|
|
5
|
+
(function (ConnectionState) {
|
|
6
|
+
ConnectionState["DISCONNECTED"] = "DISCONNECTED";
|
|
7
|
+
ConnectionState["CONNECTING"] = "CONNECTING";
|
|
8
|
+
ConnectionState["CONNECTED"] = "CONNECTED";
|
|
9
|
+
})(ConnectionState || (ConnectionState = {}));
|
|
10
|
+
const REDIRECT_REQUEST_KEY = 'dapp-redirect-request';
|
|
11
|
+
export class DappTransport {
|
|
12
|
+
walletUrl;
|
|
13
|
+
mode;
|
|
14
|
+
walletWindow = undefined;
|
|
15
|
+
connectionState = ConnectionState.DISCONNECTED;
|
|
16
|
+
readyPromise = undefined;
|
|
17
|
+
readyPromiseResolve = undefined;
|
|
18
|
+
readyPromiseReject = undefined;
|
|
19
|
+
initId = undefined;
|
|
20
|
+
handshakeTimeoutId = undefined;
|
|
21
|
+
closeCheckIntervalId = undefined;
|
|
22
|
+
sessionId = undefined;
|
|
23
|
+
pendingRequests = new Map();
|
|
24
|
+
messageQueue = [];
|
|
25
|
+
requestTimeoutMs;
|
|
26
|
+
handshakeTimeoutMs;
|
|
27
|
+
sequenceSessionStorage;
|
|
28
|
+
redirectActionHandler;
|
|
29
|
+
walletOrigin;
|
|
30
|
+
constructor(walletUrl, mode = TransportMode.POPUP, popupModeOptions = {}, sequenceSessionStorage, redirectActionHandler) {
|
|
31
|
+
this.walletUrl = walletUrl;
|
|
32
|
+
this.mode = mode;
|
|
33
|
+
try {
|
|
34
|
+
this.walletOrigin = new URL(walletUrl).origin;
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
console.error('[DApp] Invalid walletUrl provided:', walletUrl, e);
|
|
38
|
+
throw new Error(`Invalid walletUrl: ${walletUrl}`);
|
|
39
|
+
}
|
|
40
|
+
if (!this.walletOrigin || this.walletOrigin === 'null' || this.walletOrigin === '*') {
|
|
41
|
+
console.error('[DApp] Could not determine a valid wallet origin from the URL:', walletUrl);
|
|
42
|
+
throw new Error('Invalid wallet origin derived from walletUrl.');
|
|
43
|
+
}
|
|
44
|
+
if (sequenceSessionStorage) {
|
|
45
|
+
this.sequenceSessionStorage = sequenceSessionStorage;
|
|
46
|
+
}
|
|
47
|
+
else if (typeof window !== 'undefined' && window.sessionStorage) {
|
|
48
|
+
this.sequenceSessionStorage = window.sessionStorage;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
throw new Error('A storage implementation must be provided for non-browser environments.');
|
|
52
|
+
}
|
|
53
|
+
this.requestTimeoutMs = popupModeOptions.requestTimeoutMs ?? 300000;
|
|
54
|
+
this.handshakeTimeoutMs = popupModeOptions.handshakeTimeoutMs ?? 15000;
|
|
55
|
+
if (this.mode === TransportMode.POPUP) {
|
|
56
|
+
window.addEventListener('message', this.handleMessage);
|
|
57
|
+
}
|
|
58
|
+
this.redirectActionHandler = redirectActionHandler;
|
|
59
|
+
}
|
|
60
|
+
get isWalletOpen() {
|
|
61
|
+
if (this.mode === TransportMode.REDIRECT)
|
|
62
|
+
return false;
|
|
63
|
+
return !!this.walletWindow && !this.walletWindow.closed;
|
|
64
|
+
}
|
|
65
|
+
get isReady() {
|
|
66
|
+
if (this.mode === TransportMode.REDIRECT)
|
|
67
|
+
return false;
|
|
68
|
+
return this.connectionState === ConnectionState.CONNECTED;
|
|
69
|
+
}
|
|
70
|
+
async sendRequest(action, redirectUrl, payload, options = {}) {
|
|
71
|
+
if (this.mode === TransportMode.REDIRECT) {
|
|
72
|
+
const url = await this.getRequestRedirectUrl(action, payload, redirectUrl, options.path);
|
|
73
|
+
if (this.redirectActionHandler) {
|
|
74
|
+
this.redirectActionHandler(url);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
console.info('[DappTransport] No redirectActionHandler provided. Using window.location.href to navigate.');
|
|
78
|
+
window.location.href = url;
|
|
79
|
+
}
|
|
80
|
+
return new Promise(() => { });
|
|
81
|
+
}
|
|
82
|
+
if (this.connectionState !== ConnectionState.CONNECTED) {
|
|
83
|
+
await this.openWallet(options.path);
|
|
84
|
+
}
|
|
85
|
+
if (!this.isWalletOpen || this.connectionState !== ConnectionState.CONNECTED) {
|
|
86
|
+
throw new Error('Wallet connection is not available or failed to establish.');
|
|
87
|
+
}
|
|
88
|
+
const id = this.generateId();
|
|
89
|
+
const message = {
|
|
90
|
+
id,
|
|
91
|
+
type: MessageType.REQUEST,
|
|
92
|
+
action,
|
|
93
|
+
payload,
|
|
94
|
+
};
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
const timeout = options.timeout ?? this.requestTimeoutMs;
|
|
97
|
+
const timer = window.setTimeout(() => {
|
|
98
|
+
if (this.pendingRequests.has(id)) {
|
|
99
|
+
this.pendingRequests.delete(id);
|
|
100
|
+
reject(new Error(`Request '${action}' (ID: ${id}) timed out after ${timeout}ms.`));
|
|
101
|
+
}
|
|
102
|
+
}, timeout);
|
|
103
|
+
this.pendingRequests.set(id, { resolve, reject, timer, action });
|
|
104
|
+
this.postMessageToWallet(message);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async getRequestRedirectUrl(action, payload, redirectUrl, path) {
|
|
108
|
+
const id = this.generateId();
|
|
109
|
+
const request = { id, action, timestamp: Date.now() };
|
|
110
|
+
try {
|
|
111
|
+
await this.sequenceSessionStorage.setItem(REDIRECT_REQUEST_KEY, JSON.stringify(request, jsonReplacers));
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
console.error('Failed to set redirect request in storage', e);
|
|
115
|
+
throw new Error('Could not save redirect state to storage. Redirect flow is unavailable.');
|
|
116
|
+
}
|
|
117
|
+
const serializedPayload = btoa(JSON.stringify(payload || {}, jsonReplacers));
|
|
118
|
+
const fullWalletUrl = path ? `${this.walletUrl}${path}` : this.walletUrl;
|
|
119
|
+
const url = new URL(fullWalletUrl);
|
|
120
|
+
url.searchParams.set('action', action);
|
|
121
|
+
url.searchParams.set('payload', serializedPayload);
|
|
122
|
+
url.searchParams.set('id', id);
|
|
123
|
+
url.searchParams.set('redirectUrl', redirectUrl);
|
|
124
|
+
url.searchParams.set('mode', 'redirect');
|
|
125
|
+
return url.toString();
|
|
126
|
+
}
|
|
127
|
+
async getRedirectResponse(cleanState = true, url) {
|
|
128
|
+
const params = new URLSearchParams(url ? new URL(url).search : window.location.search);
|
|
129
|
+
const responseId = params.get('id');
|
|
130
|
+
if (!responseId)
|
|
131
|
+
return null;
|
|
132
|
+
let originalRequest;
|
|
133
|
+
try {
|
|
134
|
+
const storedRequest = await this.sequenceSessionStorage.getItem(REDIRECT_REQUEST_KEY);
|
|
135
|
+
if (!storedRequest) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
originalRequest = JSON.parse(storedRequest, jsonRevivers);
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
console.error('Failed to parse redirect request from storage', e);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
if (originalRequest.id !== responseId) {
|
|
145
|
+
console.error(`Mismatched ID in redirect response. Expected ${originalRequest.id}, got ${responseId}.`);
|
|
146
|
+
if (cleanState) {
|
|
147
|
+
await this.sequenceSessionStorage.removeItem(REDIRECT_REQUEST_KEY);
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
const responsePayloadB64 = params.get('payload');
|
|
152
|
+
const responseErrorB64 = params.get('error');
|
|
153
|
+
const isBrowser = typeof window !== 'undefined' && window.history;
|
|
154
|
+
if (cleanState) {
|
|
155
|
+
await this.sequenceSessionStorage.removeItem(REDIRECT_REQUEST_KEY);
|
|
156
|
+
if (isBrowser && !url) {
|
|
157
|
+
const cleanUrl = new URL(window.location.href);
|
|
158
|
+
['id', 'payload', 'error', 'mode'].forEach((p) => cleanUrl.searchParams.delete(p));
|
|
159
|
+
history.replaceState({}, document.title, cleanUrl.toString());
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (responseErrorB64) {
|
|
163
|
+
try {
|
|
164
|
+
return {
|
|
165
|
+
error: JSON.parse(atob(responseErrorB64), jsonRevivers),
|
|
166
|
+
action: originalRequest.action,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
console.error('Failed to parse error from redirect response', e);
|
|
171
|
+
return {
|
|
172
|
+
error: 'Failed to parse error from redirect',
|
|
173
|
+
action: originalRequest.action,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (responsePayloadB64) {
|
|
178
|
+
try {
|
|
179
|
+
return {
|
|
180
|
+
payload: JSON.parse(atob(responsePayloadB64), jsonRevivers),
|
|
181
|
+
action: originalRequest.action,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
console.error('Failed to parse payload from redirect response', e);
|
|
186
|
+
return {
|
|
187
|
+
error: 'Failed to parse payload from redirect',
|
|
188
|
+
action: originalRequest.action,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
error: "Redirect response missing 'payload' or 'error'",
|
|
194
|
+
action: originalRequest.action,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
openWallet(path) {
|
|
198
|
+
if (this.mode === TransportMode.REDIRECT) {
|
|
199
|
+
throw new Error("`openWallet` is not available in 'redirect' mode.");
|
|
200
|
+
}
|
|
201
|
+
if (this.connectionState !== ConnectionState.DISCONNECTED) {
|
|
202
|
+
if (this.isWalletOpen)
|
|
203
|
+
this.walletWindow?.focus();
|
|
204
|
+
return this.readyPromise || Promise.resolve();
|
|
205
|
+
}
|
|
206
|
+
this.connectionState = ConnectionState.CONNECTING;
|
|
207
|
+
this.clearPendingRequests(new Error('Wallet connection reset during open.'));
|
|
208
|
+
this.messageQueue = [];
|
|
209
|
+
this.clearTimeouts();
|
|
210
|
+
this.readyPromise = new Promise((resolve, reject) => {
|
|
211
|
+
this.readyPromiseResolve = resolve;
|
|
212
|
+
this.readyPromiseReject = reject;
|
|
213
|
+
});
|
|
214
|
+
this.readyPromise.catch(() => { });
|
|
215
|
+
this.initId = this.generateId();
|
|
216
|
+
const fullWalletUrl = path ? `${this.walletUrl}${path}` : this.walletUrl;
|
|
217
|
+
this.sessionId = this.generateId();
|
|
218
|
+
const urlWithParams = new URL(fullWalletUrl);
|
|
219
|
+
urlWithParams.searchParams.set('dappOrigin', window.location.origin);
|
|
220
|
+
urlWithParams.searchParams.set('sessionId', this.sessionId);
|
|
221
|
+
try {
|
|
222
|
+
const openedWindow = window.open(urlWithParams.toString(), 'Wallet', `width=${WalletSize.width},height=${WalletSize.height},scrollbars=yes,resizable=yes`);
|
|
223
|
+
this.walletWindow = openedWindow || undefined;
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
const openError = new Error(`Failed to open wallet window: ${error instanceof Error ? error.message : String(error)}`);
|
|
227
|
+
this._handlePreConnectionFailure(openError);
|
|
228
|
+
return Promise.reject(openError);
|
|
229
|
+
}
|
|
230
|
+
if (!this.walletWindow) {
|
|
231
|
+
const error = new Error('Failed to open wallet window. Please check your pop-up blocker settings.');
|
|
232
|
+
this._handlePreConnectionFailure(error);
|
|
233
|
+
return Promise.reject(error);
|
|
234
|
+
}
|
|
235
|
+
this.handshakeTimeoutId = window.setTimeout(() => {
|
|
236
|
+
if (this.connectionState === ConnectionState.CONNECTING) {
|
|
237
|
+
const timeoutError = new Error(`Wallet handshake timed out after ${this.handshakeTimeoutMs}ms.`);
|
|
238
|
+
this._handlePreConnectionFailure(timeoutError);
|
|
239
|
+
}
|
|
240
|
+
}, this.handshakeTimeoutMs);
|
|
241
|
+
this.closeCheckIntervalId = window.setInterval(() => {
|
|
242
|
+
if (!this.isWalletOpen) {
|
|
243
|
+
if (this.connectionState === ConnectionState.CONNECTING)
|
|
244
|
+
this._handlePreConnectionFailure(new Error('Wallet window was closed before becoming ready.'));
|
|
245
|
+
else if (this.connectionState === ConnectionState.CONNECTED)
|
|
246
|
+
this._handleDetectedClosure();
|
|
247
|
+
}
|
|
248
|
+
}, 500);
|
|
249
|
+
return this.readyPromise;
|
|
250
|
+
}
|
|
251
|
+
closeWallet() {
|
|
252
|
+
if (this.mode === TransportMode.REDIRECT) {
|
|
253
|
+
console.warn("[DApp] `closeWallet` is not available in 'redirect' mode. Use window.location.href to navigate away.");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (this.connectionState === ConnectionState.DISCONNECTED)
|
|
257
|
+
return;
|
|
258
|
+
if (this.isWalletOpen)
|
|
259
|
+
this.walletWindow?.close();
|
|
260
|
+
this.connectionState = ConnectionState.DISCONNECTED;
|
|
261
|
+
this.readyPromise = undefined;
|
|
262
|
+
this.readyPromiseResolve = undefined;
|
|
263
|
+
this.readyPromiseReject = undefined;
|
|
264
|
+
this._resetConnection(new Error('Wallet closed intentionally by DApp.'), 'Wallet closed intentionally by DApp.');
|
|
265
|
+
}
|
|
266
|
+
destroy() {
|
|
267
|
+
if (this.mode === TransportMode.POPUP) {
|
|
268
|
+
window.removeEventListener('message', this.handleMessage);
|
|
269
|
+
if (this.isWalletOpen) {
|
|
270
|
+
this.walletWindow?.close();
|
|
271
|
+
}
|
|
272
|
+
this._resetConnection(new Error('Transport destroyed.'), 'Destroying transport...');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
handleMessage = (event) => {
|
|
276
|
+
if (event.origin !== this.walletOrigin) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const isPotentiallyValidSource = this.walletWindow && (event.source === this.walletWindow || !this.walletWindow.closed);
|
|
280
|
+
if (!isPotentiallyValidSource && event.data?.type !== MessageType.WALLET_OPENED) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const message = event.data;
|
|
284
|
+
if (!message ||
|
|
285
|
+
typeof message !== 'object' ||
|
|
286
|
+
!message.id ||
|
|
287
|
+
!message.type ||
|
|
288
|
+
(message.type === MessageType.WALLET_OPENED && !message.sessionId)) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
switch (message.type) {
|
|
293
|
+
case MessageType.WALLET_OPENED:
|
|
294
|
+
this.handleWalletReadyMessage(message);
|
|
295
|
+
break;
|
|
296
|
+
case MessageType.RESPONSE:
|
|
297
|
+
this.handleResponseMessage(message);
|
|
298
|
+
break;
|
|
299
|
+
case MessageType.REQUEST:
|
|
300
|
+
case MessageType.INIT:
|
|
301
|
+
default:
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
console.error(`[DApp] Error processing received message (Type: ${message.type}, ID: ${message.id}):`, error);
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
handleWalletReadyMessage(message) {
|
|
310
|
+
if (this.connectionState !== ConnectionState.CONNECTING) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (message.sessionId !== this.sessionId) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (this.handshakeTimeoutId !== undefined) {
|
|
317
|
+
window.clearTimeout(this.handshakeTimeoutId);
|
|
318
|
+
this.handshakeTimeoutId = undefined;
|
|
319
|
+
}
|
|
320
|
+
const initMessage = {
|
|
321
|
+
id: this.initId,
|
|
322
|
+
type: MessageType.INIT,
|
|
323
|
+
sessionId: this.sessionId,
|
|
324
|
+
};
|
|
325
|
+
this.postMessageToWallet(initMessage);
|
|
326
|
+
this.connectionState = ConnectionState.CONNECTED;
|
|
327
|
+
if (this.readyPromiseResolve) {
|
|
328
|
+
this.readyPromiseResolve();
|
|
329
|
+
}
|
|
330
|
+
this.messageQueue.forEach((queuedMsg) => {
|
|
331
|
+
this.postMessageToWallet(queuedMsg);
|
|
332
|
+
});
|
|
333
|
+
this.messageQueue = [];
|
|
334
|
+
}
|
|
335
|
+
handleResponseMessage(message) {
|
|
336
|
+
const pending = this.pendingRequests.get(message.id);
|
|
337
|
+
if (pending) {
|
|
338
|
+
window.clearTimeout(pending.timer);
|
|
339
|
+
this.pendingRequests.delete(message.id);
|
|
340
|
+
if (message.error) {
|
|
341
|
+
const error = new Error(`Wallet responded with error: ${JSON.stringify(message.error)}`);
|
|
342
|
+
pending.reject(error);
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
pending.resolve(message.payload);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
postMessageToWallet(message) {
|
|
350
|
+
if (!this.isWalletOpen) {
|
|
351
|
+
if (message.type === MessageType.INIT &&
|
|
352
|
+
this.connectionState === ConnectionState.CONNECTING &&
|
|
353
|
+
message.id === this.initId) {
|
|
354
|
+
this._handlePreConnectionFailure(new Error('Failed to send INIT: Wallet window closed unexpectedly.'));
|
|
355
|
+
}
|
|
356
|
+
else if (message.type === MessageType.REQUEST) {
|
|
357
|
+
const pendingReq = this.pendingRequests.get(message.id);
|
|
358
|
+
if (pendingReq) {
|
|
359
|
+
window.clearTimeout(pendingReq.timer);
|
|
360
|
+
this.pendingRequests.delete(message.id);
|
|
361
|
+
pendingReq.reject(new Error(`Failed to send request '${pendingReq.action}': Wallet window closed.`));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (this.connectionState !== ConnectionState.CONNECTED && message.type !== MessageType.INIT) {
|
|
367
|
+
this.messageQueue.push(message);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
try {
|
|
371
|
+
this.walletWindow?.postMessage(message, this.walletOrigin);
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
const rejectionError = error instanceof Error ? error : new Error('Failed to send message to wallet due to unknown error');
|
|
375
|
+
if (message.type === MessageType.INIT &&
|
|
376
|
+
this.connectionState === ConnectionState.CONNECTING &&
|
|
377
|
+
message.id === this.initId) {
|
|
378
|
+
this._handlePreConnectionFailure(rejectionError);
|
|
379
|
+
}
|
|
380
|
+
else if (message.type === MessageType.REQUEST) {
|
|
381
|
+
const pendingReq = this.pendingRequests.get(message.id);
|
|
382
|
+
if (pendingReq) {
|
|
383
|
+
window.clearTimeout(pendingReq.timer);
|
|
384
|
+
this.pendingRequests.delete(message.id);
|
|
385
|
+
pendingReq.reject(rejectionError);
|
|
386
|
+
}
|
|
387
|
+
this._handleDetectedClosure();
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
this._handleDetectedClosure();
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
_resetConnection(reason, logMessage) {
|
|
395
|
+
console.log(`[DApp] ${logMessage}`);
|
|
396
|
+
if (this.readyPromiseReject) {
|
|
397
|
+
this.readyPromiseReject(reason);
|
|
398
|
+
}
|
|
399
|
+
this.clearTimeouts();
|
|
400
|
+
this.clearPendingRequests(reason);
|
|
401
|
+
this.connectionState = ConnectionState.DISCONNECTED;
|
|
402
|
+
this.walletWindow = undefined;
|
|
403
|
+
this.readyPromise = undefined;
|
|
404
|
+
this.readyPromiseResolve = undefined;
|
|
405
|
+
this.readyPromiseReject = undefined;
|
|
406
|
+
this.initId = undefined;
|
|
407
|
+
this.sessionId = undefined;
|
|
408
|
+
this.messageQueue = [];
|
|
409
|
+
}
|
|
410
|
+
_handlePreConnectionFailure(error) {
|
|
411
|
+
this._resetConnection(error, `Connection failure: ${error.message}`);
|
|
412
|
+
}
|
|
413
|
+
_handleDetectedClosure() {
|
|
414
|
+
if (this.connectionState === ConnectionState.CONNECTED) {
|
|
415
|
+
const reason = new Error('Wallet connection terminated unexpectedly.');
|
|
416
|
+
this._resetConnection(reason, 'Wallet connection terminated unexpectedly after ready.');
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
clearPendingRequests(reason) {
|
|
420
|
+
if (this.pendingRequests.size > 0) {
|
|
421
|
+
const requestsToClear = new Map(this.pendingRequests);
|
|
422
|
+
this.pendingRequests.clear();
|
|
423
|
+
requestsToClear.forEach((pending) => {
|
|
424
|
+
window.clearTimeout(pending.timer);
|
|
425
|
+
const errorToSend = reason instanceof Error ? reason : new Error(`Operation failed: ${reason}`);
|
|
426
|
+
pending.reject(errorToSend);
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
clearTimeouts() {
|
|
431
|
+
if (this.handshakeTimeoutId !== undefined) {
|
|
432
|
+
window.clearTimeout(this.handshakeTimeoutId);
|
|
433
|
+
this.handshakeTimeoutId = undefined;
|
|
434
|
+
}
|
|
435
|
+
if (this.closeCheckIntervalId !== undefined) {
|
|
436
|
+
window.clearInterval(this.closeCheckIntervalId);
|
|
437
|
+
this.closeCheckIntervalId = undefined;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
generateId() {
|
|
441
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).substring(2, 9)}`;
|
|
442
|
+
}
|
|
443
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { DappClient } from './DappClient.js';
|
|
2
|
+
export type { DappClientEventListener } from './DappClient.js';
|
|
3
|
+
export type { LoginMethod, GuardConfig, Transaction, SignatureSuccessResponse, ChainSessionManagerEvent, SequenceSessionStorage, RandomPrivateKeyFn, Session, SignMessagePayload, AddExplicitSessionPayload, CreateNewSessionPayload, SignTypedDataPayload, ConnectSuccessResponsePayload, ModifySessionSuccessResponsePayload, ModifySessionPayload, DappClientWalletActionEventListener, DappClientExplicitSessionEventListener, TransactionRequest, SendWalletTransactionPayload, SendWalletTransactionSuccessResponse, WalletActionResponse, } from './types/index.js';
|
|
4
|
+
export { RequestActionType, TransportMode } from './types/index.js';
|
|
5
|
+
export { FeeOptionError, TransactionError, AddExplicitSessionError, ConnectionError, InitializationError, SigningError, ModifyExplicitSessionError, } from './utils/errors.js';
|
|
6
|
+
export { getExplorerUrl, jsonReplacers, jsonRevivers } from './utils/index.js';
|
|
7
|
+
export type { SequenceStorage, ExplicitSessionData, ImplicitSessionData, PendingRequestContext, PendingPayload, } from './utils/storage.js';
|
|
8
|
+
export { WebStorage } from './utils/storage.js';
|
|
9
|
+
export { Permission, Extensions, SessionConfig } from '@0xsequence/wallet-primitives';
|
|
10
|
+
export { Signers, Wallet, Utils, Relayer } from '@0xsequence/wallet-core';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAC9D,YAAY,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,kBAAkB,EAClB,OAAO,EACP,kBAAkB,EAClB,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,6BAA6B,EAC7B,mCAAmC,EACnC,oBAAoB,EACpB,mCAAmC,EACnC,sCAAsC,EACtC,kBAAkB,EAClB,4BAA4B,EAC5B,oCAAoC,EACpC,oBAAoB,GACrB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,mBAAmB,EACnB,YAAY,EACZ,0BAA0B,GAC3B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC9E,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAE/C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AACrF,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { DappClient } from './DappClient.js';
|
|
2
|
+
export { RequestActionType, TransportMode } from './types/index.js';
|
|
3
|
+
export { FeeOptionError, TransactionError, AddExplicitSessionError, ConnectionError, InitializationError, SigningError, ModifyExplicitSessionError, } from './utils/errors.js';
|
|
4
|
+
export { getExplorerUrl, jsonReplacers, jsonRevivers } from './utils/index.js';
|
|
5
|
+
export { WebStorage } from './utils/storage.js';
|
|
6
|
+
export { Permission, Extensions, SessionConfig } from '@0xsequence/wallet-primitives';
|
|
7
|
+
export { Signers, Wallet, Utils, Relayer } from '@0xsequence/wallet-core';
|