unwallet-client-sdk 0.20.1 → 0.21.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 +2 -0
- package/dist/index.cjs +100 -50
- package/dist/index.d.cts +26 -10
- package/dist/index.d.ts +26 -10
- package/dist/index.js +101 -51
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# unWallet client-side SDK
|
|
2
2
|
|
|
3
3
|
[](https://npm.im/unwallet-client-sdk)
|
|
4
|
+
[](https://github.com/SIVIRA/unwallet-client-sdk-js/actions/workflows/test.yaml)
|
|
5
|
+
[](https://codecov.io/gh/SIVIRA/unwallet-client-sdk-js)
|
|
4
6
|
|
|
5
7
|
:warning: This SDK works correctly only on web browsers.
|
|
6
8
|
|
package/dist/index.cjs
CHANGED
|
@@ -3,13 +3,13 @@ let viem = require("viem");
|
|
|
3
3
|
let zod = require("zod");
|
|
4
4
|
//#region src/error.ts
|
|
5
5
|
var UWError = class extends Error {
|
|
6
|
+
static {
|
|
7
|
+
this.prototype.name = "UWError";
|
|
8
|
+
}
|
|
6
9
|
constructor(code, message) {
|
|
7
10
|
super(message !== void 0 ? `${code}: ${message}` : code);
|
|
8
11
|
this.code = code;
|
|
9
12
|
}
|
|
10
|
-
static {
|
|
11
|
-
this.prototype.name = "UWError";
|
|
12
|
-
}
|
|
13
13
|
};
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/config.ts
|
|
@@ -17,71 +17,117 @@ function getUnWalletConfigByEnv(env) {
|
|
|
17
17
|
switch (env) {
|
|
18
18
|
case "prod": return {
|
|
19
19
|
frontend: { baseURL: "https://id.unwallet.world" },
|
|
20
|
-
|
|
20
|
+
xAPI: {
|
|
21
21
|
url: "wss://xapi.id.unwallet.world",
|
|
22
22
|
connectionTimeout: 1e4
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
25
|
case "dev": return {
|
|
26
26
|
frontend: { baseURL: "http://localhost:4200" },
|
|
27
|
-
|
|
27
|
+
xAPI: {
|
|
28
28
|
url: "wss://xapi.id.test.unwallet.dev",
|
|
29
29
|
connectionTimeout: 1e4
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
const xRequestSchema = zod.z.object({ action: zod.z.enum(["getConnectionID"]) });
|
|
35
|
+
zod.z.string().refine((val) => {
|
|
36
|
+
try {
|
|
37
|
+
JSON.parse(val);
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}, {
|
|
43
|
+
abort: true,
|
|
44
|
+
message: "Invalid JSON string"
|
|
45
|
+
}).transform((val) => JSON.parse(val)).pipe(xRequestSchema);
|
|
46
|
+
const xResponseSchema = zod.z.object({
|
|
47
|
+
type: zod.z.enum([
|
|
48
|
+
"connectionID",
|
|
49
|
+
"signature",
|
|
50
|
+
"transactionID",
|
|
51
|
+
"error"
|
|
52
|
+
]),
|
|
53
|
+
value: zod.z.string()
|
|
54
|
+
});
|
|
55
|
+
const xResponsePayloadSchema = zod.z.string().refine((val) => {
|
|
56
|
+
try {
|
|
57
|
+
JSON.parse(val);
|
|
58
|
+
} catch (e) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}, {
|
|
63
|
+
abort: true,
|
|
64
|
+
message: "Invalid JSON string"
|
|
65
|
+
}).transform((val) => JSON.parse(val)).pipe(xResponseSchema);
|
|
42
66
|
var XConnection = class XConnection {
|
|
43
67
|
constructor(args) {
|
|
44
68
|
this.responseHandler = null;
|
|
45
|
-
this.socket = args.socket;
|
|
46
69
|
this.id = args.id;
|
|
70
|
+
this.socket = args.socket;
|
|
71
|
+
this.options = args.options ?? {};
|
|
47
72
|
this.initListeners();
|
|
48
73
|
}
|
|
49
|
-
static async init(config) {
|
|
74
|
+
static async init(config, opts) {
|
|
50
75
|
const socket = new WebSocket(config.url);
|
|
51
76
|
const id = await new Promise((resolve, reject) => {
|
|
52
|
-
|
|
77
|
+
const timeoutID = setTimeout(() => abortHandshake(new UWError("CONNECTION_TIMEOUT")), config.connectionTimeout);
|
|
78
|
+
const detachListeners = () => {
|
|
79
|
+
socket.onopen = null;
|
|
80
|
+
socket.onmessage = null;
|
|
81
|
+
socket.onerror = null;
|
|
82
|
+
socket.onclose = null;
|
|
83
|
+
};
|
|
84
|
+
const completeHandshake = (id) => {
|
|
85
|
+
clearTimeout(timeoutID);
|
|
86
|
+
detachListeners();
|
|
87
|
+
resolve(id);
|
|
88
|
+
};
|
|
89
|
+
const abortHandshake = (err) => {
|
|
90
|
+
clearTimeout(timeoutID);
|
|
91
|
+
detachListeners();
|
|
92
|
+
socket.close();
|
|
93
|
+
reject(err);
|
|
94
|
+
};
|
|
53
95
|
socket.onopen = () => socket.send(JSON.stringify({ action: "getConnectionID" }));
|
|
54
96
|
socket.onmessage = (event) => {
|
|
55
97
|
let resp;
|
|
56
98
|
{
|
|
57
|
-
const result =
|
|
99
|
+
const result = safeParseXResponsePayload(event.data);
|
|
58
100
|
if (!result.success) {
|
|
59
|
-
|
|
101
|
+
abortHandshake(result.error);
|
|
60
102
|
return;
|
|
61
103
|
}
|
|
62
104
|
resp = result.data;
|
|
63
105
|
}
|
|
64
106
|
if (resp.type !== "connectionID") {
|
|
65
|
-
|
|
107
|
+
abortHandshake(newUnexpectedXResponseTypeError(resp));
|
|
66
108
|
return;
|
|
67
109
|
}
|
|
68
|
-
|
|
110
|
+
completeHandshake(resp.value);
|
|
69
111
|
};
|
|
70
|
-
socket.onerror = () =>
|
|
71
|
-
socket.onclose = (event) =>
|
|
112
|
+
socket.onerror = () => abortHandshake(new UWError("CONNECTION_FAILED"));
|
|
113
|
+
socket.onclose = (event) => abortHandshake(newConnectionClosedError(event));
|
|
72
114
|
});
|
|
73
115
|
return new XConnection({
|
|
74
116
|
id,
|
|
75
|
-
socket
|
|
117
|
+
socket,
|
|
118
|
+
options: opts
|
|
76
119
|
});
|
|
77
120
|
}
|
|
78
121
|
initListeners() {
|
|
79
122
|
this.socket.onopen = null;
|
|
80
123
|
this.socket.onmessage = (event) => {
|
|
81
|
-
if (this.responseHandler === null)
|
|
124
|
+
if (this.responseHandler === null) {
|
|
125
|
+
this.options.debugHandlers?.onMessageEventDropped?.(event);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
82
128
|
let resp;
|
|
83
129
|
{
|
|
84
|
-
const result =
|
|
130
|
+
const result = safeParseXResponsePayload(event.data);
|
|
85
131
|
if (!result.success) {
|
|
86
132
|
this.responseHandler.reject(result.error);
|
|
87
133
|
return;
|
|
@@ -94,7 +140,7 @@ var XConnection = class XConnection {
|
|
|
94
140
|
case "rejected":
|
|
95
141
|
this.responseHandler.reject(new UWError("REQUEST_REJECTED"));
|
|
96
142
|
break;
|
|
97
|
-
default: this.responseHandler.reject(new UWError("INVALID_RESPONSE", `unexpected error
|
|
143
|
+
default: this.responseHandler.reject(new UWError("INVALID_RESPONSE", `unexpected error value: ${resp.value}`));
|
|
98
144
|
}
|
|
99
145
|
break;
|
|
100
146
|
default: this.responseHandler.resolve(resp);
|
|
@@ -102,8 +148,11 @@ var XConnection = class XConnection {
|
|
|
102
148
|
};
|
|
103
149
|
this.socket.onerror = null;
|
|
104
150
|
this.socket.onclose = (event) => {
|
|
105
|
-
if (this.responseHandler === null)
|
|
106
|
-
|
|
151
|
+
if (this.responseHandler === null) {
|
|
152
|
+
this.options.debugHandlers?.onCloseEventDropped?.(event);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
this.responseHandler.reject(newConnectionClosedError(event));
|
|
107
156
|
};
|
|
108
157
|
}
|
|
109
158
|
get readyState() {
|
|
@@ -115,31 +164,29 @@ var XConnection = class XConnection {
|
|
|
115
164
|
setResponseHandler(handler) {
|
|
116
165
|
this.responseHandler = handler;
|
|
117
166
|
}
|
|
167
|
+
close() {
|
|
168
|
+
this.socket.close();
|
|
169
|
+
}
|
|
118
170
|
};
|
|
119
|
-
function
|
|
120
|
-
const result =
|
|
121
|
-
try {
|
|
122
|
-
JSON.parse(val);
|
|
123
|
-
} catch (e) {
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
return true;
|
|
127
|
-
}, {
|
|
128
|
-
abort: true,
|
|
129
|
-
message: "Invalid JSON string"
|
|
130
|
-
}).transform((val) => JSON.parse(val)).pipe(zod.z.object({
|
|
131
|
-
type: zod.z.enum(X_RESPONSE_TYPES),
|
|
132
|
-
value: zod.z.string()
|
|
133
|
-
})).safeParse(data);
|
|
171
|
+
function safeParseXResponsePayload(data) {
|
|
172
|
+
const result = xResponsePayloadSchema.safeParse(data);
|
|
134
173
|
if (!result.success) return {
|
|
135
174
|
success: false,
|
|
136
|
-
error: new UWError("INVALID_RESPONSE", `invalid
|
|
175
|
+
error: new UWError("INVALID_RESPONSE", `invalid payload: ${zod.z.prettifyError(result.error)}`)
|
|
137
176
|
};
|
|
138
177
|
return {
|
|
139
178
|
success: true,
|
|
140
179
|
data: result.data
|
|
141
180
|
};
|
|
142
181
|
}
|
|
182
|
+
function newUnexpectedXResponseTypeError(resp) {
|
|
183
|
+
let msg = `unexpected type: ${resp.type}`;
|
|
184
|
+
if (resp.type === "error") msg += ` (value: ${resp.value})`;
|
|
185
|
+
return new UWError("INVALID_RESPONSE", msg);
|
|
186
|
+
}
|
|
187
|
+
function newConnectionClosedError(event) {
|
|
188
|
+
return new UWError("CONNECTION_CLOSED", event.reason.length > 0 ? event.reason : void 0);
|
|
189
|
+
}
|
|
143
190
|
//#endregion
|
|
144
191
|
//#region src/unwallet.ts
|
|
145
192
|
var UnWallet = class UnWallet {
|
|
@@ -153,14 +200,14 @@ var UnWallet = class UnWallet {
|
|
|
153
200
|
return new UnWallet({
|
|
154
201
|
env,
|
|
155
202
|
clientID: config.clientID,
|
|
156
|
-
xConnection: await XConnection.init(getUnWalletConfigByEnv(env).
|
|
203
|
+
xConnection: await XConnection.init(getUnWalletConfigByEnv(env).xAPI)
|
|
157
204
|
});
|
|
158
205
|
}
|
|
159
206
|
get unWalletConfig() {
|
|
160
207
|
return getUnWalletConfigByEnv(this.env);
|
|
161
208
|
}
|
|
162
209
|
authorize(args) {
|
|
163
|
-
const url = new URL(`${this.unWalletConfig.frontend.baseURL}/${args.isVirtual
|
|
210
|
+
const url = new URL(`${this.unWalletConfig.frontend.baseURL}/${args.isVirtual === false ? "" : "v"}authorize`);
|
|
164
211
|
url.searchParams.set("response_type", "id_token");
|
|
165
212
|
url.searchParams.set("response_mode", args.responseMode ?? "fragment");
|
|
166
213
|
url.searchParams.set("client_id", this.clientID);
|
|
@@ -185,7 +232,7 @@ var UnWallet = class UnWallet {
|
|
|
185
232
|
resolve: (resp) => {
|
|
186
233
|
this.xConnection.setResponseHandler(null);
|
|
187
234
|
if (resp.type !== "signature") {
|
|
188
|
-
reject(
|
|
235
|
+
reject(newUnexpectedXResponseTypeError(resp));
|
|
189
236
|
return;
|
|
190
237
|
}
|
|
191
238
|
resolve({
|
|
@@ -224,7 +271,7 @@ var UnWallet = class UnWallet {
|
|
|
224
271
|
try {
|
|
225
272
|
(0, viem.validateTypedData)(typedData);
|
|
226
273
|
} catch (e) {
|
|
227
|
-
reject(new UWError("INVALID_REQUEST", `invalid typed data: ${e.
|
|
274
|
+
reject(new UWError("INVALID_REQUEST", `invalid typed data: ${e instanceof viem.BaseError ? e.shortMessage : String(e)}`));
|
|
228
275
|
return;
|
|
229
276
|
}
|
|
230
277
|
const digest = (0, viem.hashTypedData)(typedData);
|
|
@@ -232,7 +279,7 @@ var UnWallet = class UnWallet {
|
|
|
232
279
|
resolve: (resp) => {
|
|
233
280
|
this.xConnection.setResponseHandler(null);
|
|
234
281
|
if (resp.type !== "signature") {
|
|
235
|
-
reject(
|
|
282
|
+
reject(newUnexpectedXResponseTypeError(resp));
|
|
236
283
|
return;
|
|
237
284
|
}
|
|
238
285
|
resolve({
|
|
@@ -271,7 +318,7 @@ var UnWallet = class UnWallet {
|
|
|
271
318
|
resolve: (resp) => {
|
|
272
319
|
this.xConnection.setResponseHandler(null);
|
|
273
320
|
if (resp.type !== "transactionID") {
|
|
274
|
-
reject(
|
|
321
|
+
reject(newUnexpectedXResponseTypeError(resp));
|
|
275
322
|
return;
|
|
276
323
|
}
|
|
277
324
|
resolve({ transactionID: resp.value });
|
|
@@ -292,6 +339,9 @@ var UnWallet = class UnWallet {
|
|
|
292
339
|
openWindow(url);
|
|
293
340
|
});
|
|
294
341
|
}
|
|
342
|
+
close() {
|
|
343
|
+
this.xConnection.close();
|
|
344
|
+
}
|
|
295
345
|
};
|
|
296
346
|
function openWindow(url) {
|
|
297
347
|
const width = screen.width / 2;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Address, Hex } from "viem";
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
//#region src/config.d.ts
|
|
3
4
|
type Env = "prod" | "dev";
|
|
4
5
|
interface Config {
|
|
@@ -37,29 +38,43 @@ declare class UWError extends Error {
|
|
|
37
38
|
}
|
|
38
39
|
//#endregion
|
|
39
40
|
//#region src/x.d.ts
|
|
40
|
-
declare const
|
|
41
|
-
type
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
declare const xResponseSchema: z.ZodObject<{
|
|
42
|
+
type: z.ZodEnum<{
|
|
43
|
+
connectionID: "connectionID";
|
|
44
|
+
error: "error";
|
|
45
|
+
signature: "signature";
|
|
46
|
+
transactionID: "transactionID";
|
|
47
|
+
}>;
|
|
48
|
+
value: z.ZodString;
|
|
49
|
+
}, z.core.$strip>;
|
|
50
|
+
type XResponse = z.infer<typeof xResponseSchema>;
|
|
51
|
+
type XResponseHandler = {
|
|
47
52
|
resolve: (resp: XResponse) => void;
|
|
48
53
|
reject: (err: UWError) => void;
|
|
49
|
-
}
|
|
54
|
+
};
|
|
55
|
+
type XConnectionOptions = {
|
|
56
|
+
debugHandlers?: XConnectionDebugHandlers;
|
|
57
|
+
};
|
|
58
|
+
type XConnectionDebugHandlers = {
|
|
59
|
+
onMessageEventDropped?: (event: MessageEvent) => void;
|
|
60
|
+
onCloseEventDropped?: (event: CloseEvent) => void;
|
|
61
|
+
};
|
|
50
62
|
declare class XConnection {
|
|
51
63
|
readonly id: string;
|
|
52
|
-
private socket;
|
|
64
|
+
private readonly socket;
|
|
65
|
+
private readonly options;
|
|
53
66
|
private responseHandler;
|
|
54
67
|
constructor(args: {
|
|
55
68
|
id: string;
|
|
56
69
|
socket: WebSocket;
|
|
70
|
+
options?: XConnectionOptions | undefined;
|
|
57
71
|
});
|
|
58
|
-
static init(config: UnWalletXAPIConfig): Promise<XConnection>;
|
|
72
|
+
static init(config: UnWalletXAPIConfig, opts?: XConnectionOptions): Promise<XConnection>;
|
|
59
73
|
private initListeners;
|
|
60
74
|
get readyState(): number;
|
|
61
75
|
get hasResponseHandler(): boolean;
|
|
62
76
|
setResponseHandler(handler: XResponseHandler | null): void;
|
|
77
|
+
close(): void;
|
|
63
78
|
}
|
|
64
79
|
//#endregion
|
|
65
80
|
//#region src/unwallet.d.ts
|
|
@@ -104,6 +119,7 @@ declare class UnWallet {
|
|
|
104
119
|
data?: string;
|
|
105
120
|
ticketToken: string;
|
|
106
121
|
}): Promise<SendTransactionResult>;
|
|
122
|
+
close(): void;
|
|
107
123
|
}
|
|
108
124
|
//#endregion
|
|
109
125
|
export { type AuthorizationResponseMode, type Config, type EIP712TypedData, type EIP712TypedDataDomain, type EIP712TypedDataField, type Env, type SendTransactionResult, type SignResult, UWError, type UWErrorCode, UnWallet };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Address, Hex } from "viem";
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
//#region src/config.d.ts
|
|
3
4
|
type Env = "prod" | "dev";
|
|
4
5
|
interface Config {
|
|
@@ -37,29 +38,43 @@ declare class UWError extends Error {
|
|
|
37
38
|
}
|
|
38
39
|
//#endregion
|
|
39
40
|
//#region src/x.d.ts
|
|
40
|
-
declare const
|
|
41
|
-
type
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
declare const xResponseSchema: z.ZodObject<{
|
|
42
|
+
type: z.ZodEnum<{
|
|
43
|
+
connectionID: "connectionID";
|
|
44
|
+
error: "error";
|
|
45
|
+
signature: "signature";
|
|
46
|
+
transactionID: "transactionID";
|
|
47
|
+
}>;
|
|
48
|
+
value: z.ZodString;
|
|
49
|
+
}, z.core.$strip>;
|
|
50
|
+
type XResponse = z.infer<typeof xResponseSchema>;
|
|
51
|
+
type XResponseHandler = {
|
|
47
52
|
resolve: (resp: XResponse) => void;
|
|
48
53
|
reject: (err: UWError) => void;
|
|
49
|
-
}
|
|
54
|
+
};
|
|
55
|
+
type XConnectionOptions = {
|
|
56
|
+
debugHandlers?: XConnectionDebugHandlers;
|
|
57
|
+
};
|
|
58
|
+
type XConnectionDebugHandlers = {
|
|
59
|
+
onMessageEventDropped?: (event: MessageEvent) => void;
|
|
60
|
+
onCloseEventDropped?: (event: CloseEvent) => void;
|
|
61
|
+
};
|
|
50
62
|
declare class XConnection {
|
|
51
63
|
readonly id: string;
|
|
52
|
-
private socket;
|
|
64
|
+
private readonly socket;
|
|
65
|
+
private readonly options;
|
|
53
66
|
private responseHandler;
|
|
54
67
|
constructor(args: {
|
|
55
68
|
id: string;
|
|
56
69
|
socket: WebSocket;
|
|
70
|
+
options?: XConnectionOptions | undefined;
|
|
57
71
|
});
|
|
58
|
-
static init(config: UnWalletXAPIConfig): Promise<XConnection>;
|
|
72
|
+
static init(config: UnWalletXAPIConfig, opts?: XConnectionOptions): Promise<XConnection>;
|
|
59
73
|
private initListeners;
|
|
60
74
|
get readyState(): number;
|
|
61
75
|
get hasResponseHandler(): boolean;
|
|
62
76
|
setResponseHandler(handler: XResponseHandler | null): void;
|
|
77
|
+
close(): void;
|
|
63
78
|
}
|
|
64
79
|
//#endregion
|
|
65
80
|
//#region src/unwallet.d.ts
|
|
@@ -104,6 +119,7 @@ declare class UnWallet {
|
|
|
104
119
|
data?: string;
|
|
105
120
|
ticketToken: string;
|
|
106
121
|
}): Promise<SendTransactionResult>;
|
|
122
|
+
close(): void;
|
|
107
123
|
}
|
|
108
124
|
//#endregion
|
|
109
125
|
export { type AuthorizationResponseMode, type Config, type EIP712TypedData, type EIP712TypedDataDomain, type EIP712TypedDataField, type Env, type SendTransactionResult, type SignResult, UWError, type UWErrorCode, UnWallet };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { hashTypedData, sha256, toBytes, validateTypedData } from "viem";
|
|
1
|
+
import { BaseError, hashTypedData, sha256, toBytes, validateTypedData } from "viem";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
//#region src/error.ts
|
|
4
4
|
var UWError = class extends Error {
|
|
5
|
+
static {
|
|
6
|
+
this.prototype.name = "UWError";
|
|
7
|
+
}
|
|
5
8
|
constructor(code, message) {
|
|
6
9
|
super(message !== void 0 ? `${code}: ${message}` : code);
|
|
7
10
|
this.code = code;
|
|
8
11
|
}
|
|
9
|
-
static {
|
|
10
|
-
this.prototype.name = "UWError";
|
|
11
|
-
}
|
|
12
12
|
};
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region src/config.ts
|
|
@@ -16,71 +16,117 @@ function getUnWalletConfigByEnv(env) {
|
|
|
16
16
|
switch (env) {
|
|
17
17
|
case "prod": return {
|
|
18
18
|
frontend: { baseURL: "https://id.unwallet.world" },
|
|
19
|
-
|
|
19
|
+
xAPI: {
|
|
20
20
|
url: "wss://xapi.id.unwallet.world",
|
|
21
21
|
connectionTimeout: 1e4
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
case "dev": return {
|
|
25
25
|
frontend: { baseURL: "http://localhost:4200" },
|
|
26
|
-
|
|
26
|
+
xAPI: {
|
|
27
27
|
url: "wss://xapi.id.test.unwallet.dev",
|
|
28
28
|
connectionTimeout: 1e4
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
const xRequestSchema = z.object({ action: z.enum(["getConnectionID"]) });
|
|
34
|
+
z.string().refine((val) => {
|
|
35
|
+
try {
|
|
36
|
+
JSON.parse(val);
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
}, {
|
|
42
|
+
abort: true,
|
|
43
|
+
message: "Invalid JSON string"
|
|
44
|
+
}).transform((val) => JSON.parse(val)).pipe(xRequestSchema);
|
|
45
|
+
const xResponseSchema = z.object({
|
|
46
|
+
type: z.enum([
|
|
47
|
+
"connectionID",
|
|
48
|
+
"signature",
|
|
49
|
+
"transactionID",
|
|
50
|
+
"error"
|
|
51
|
+
]),
|
|
52
|
+
value: z.string()
|
|
53
|
+
});
|
|
54
|
+
const xResponsePayloadSchema = z.string().refine((val) => {
|
|
55
|
+
try {
|
|
56
|
+
JSON.parse(val);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}, {
|
|
62
|
+
abort: true,
|
|
63
|
+
message: "Invalid JSON string"
|
|
64
|
+
}).transform((val) => JSON.parse(val)).pipe(xResponseSchema);
|
|
41
65
|
var XConnection = class XConnection {
|
|
42
66
|
constructor(args) {
|
|
43
67
|
this.responseHandler = null;
|
|
44
|
-
this.socket = args.socket;
|
|
45
68
|
this.id = args.id;
|
|
69
|
+
this.socket = args.socket;
|
|
70
|
+
this.options = args.options ?? {};
|
|
46
71
|
this.initListeners();
|
|
47
72
|
}
|
|
48
|
-
static async init(config) {
|
|
73
|
+
static async init(config, opts) {
|
|
49
74
|
const socket = new WebSocket(config.url);
|
|
50
75
|
const id = await new Promise((resolve, reject) => {
|
|
51
|
-
|
|
76
|
+
const timeoutID = setTimeout(() => abortHandshake(new UWError("CONNECTION_TIMEOUT")), config.connectionTimeout);
|
|
77
|
+
const detachListeners = () => {
|
|
78
|
+
socket.onopen = null;
|
|
79
|
+
socket.onmessage = null;
|
|
80
|
+
socket.onerror = null;
|
|
81
|
+
socket.onclose = null;
|
|
82
|
+
};
|
|
83
|
+
const completeHandshake = (id) => {
|
|
84
|
+
clearTimeout(timeoutID);
|
|
85
|
+
detachListeners();
|
|
86
|
+
resolve(id);
|
|
87
|
+
};
|
|
88
|
+
const abortHandshake = (err) => {
|
|
89
|
+
clearTimeout(timeoutID);
|
|
90
|
+
detachListeners();
|
|
91
|
+
socket.close();
|
|
92
|
+
reject(err);
|
|
93
|
+
};
|
|
52
94
|
socket.onopen = () => socket.send(JSON.stringify({ action: "getConnectionID" }));
|
|
53
95
|
socket.onmessage = (event) => {
|
|
54
96
|
let resp;
|
|
55
97
|
{
|
|
56
|
-
const result =
|
|
98
|
+
const result = safeParseXResponsePayload(event.data);
|
|
57
99
|
if (!result.success) {
|
|
58
|
-
|
|
100
|
+
abortHandshake(result.error);
|
|
59
101
|
return;
|
|
60
102
|
}
|
|
61
103
|
resp = result.data;
|
|
62
104
|
}
|
|
63
105
|
if (resp.type !== "connectionID") {
|
|
64
|
-
|
|
106
|
+
abortHandshake(newUnexpectedXResponseTypeError(resp));
|
|
65
107
|
return;
|
|
66
108
|
}
|
|
67
|
-
|
|
109
|
+
completeHandshake(resp.value);
|
|
68
110
|
};
|
|
69
|
-
socket.onerror = () =>
|
|
70
|
-
socket.onclose = (event) =>
|
|
111
|
+
socket.onerror = () => abortHandshake(new UWError("CONNECTION_FAILED"));
|
|
112
|
+
socket.onclose = (event) => abortHandshake(newConnectionClosedError(event));
|
|
71
113
|
});
|
|
72
114
|
return new XConnection({
|
|
73
115
|
id,
|
|
74
|
-
socket
|
|
116
|
+
socket,
|
|
117
|
+
options: opts
|
|
75
118
|
});
|
|
76
119
|
}
|
|
77
120
|
initListeners() {
|
|
78
121
|
this.socket.onopen = null;
|
|
79
122
|
this.socket.onmessage = (event) => {
|
|
80
|
-
if (this.responseHandler === null)
|
|
123
|
+
if (this.responseHandler === null) {
|
|
124
|
+
this.options.debugHandlers?.onMessageEventDropped?.(event);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
81
127
|
let resp;
|
|
82
128
|
{
|
|
83
|
-
const result =
|
|
129
|
+
const result = safeParseXResponsePayload(event.data);
|
|
84
130
|
if (!result.success) {
|
|
85
131
|
this.responseHandler.reject(result.error);
|
|
86
132
|
return;
|
|
@@ -93,7 +139,7 @@ var XConnection = class XConnection {
|
|
|
93
139
|
case "rejected":
|
|
94
140
|
this.responseHandler.reject(new UWError("REQUEST_REJECTED"));
|
|
95
141
|
break;
|
|
96
|
-
default: this.responseHandler.reject(new UWError("INVALID_RESPONSE", `unexpected error
|
|
142
|
+
default: this.responseHandler.reject(new UWError("INVALID_RESPONSE", `unexpected error value: ${resp.value}`));
|
|
97
143
|
}
|
|
98
144
|
break;
|
|
99
145
|
default: this.responseHandler.resolve(resp);
|
|
@@ -101,8 +147,11 @@ var XConnection = class XConnection {
|
|
|
101
147
|
};
|
|
102
148
|
this.socket.onerror = null;
|
|
103
149
|
this.socket.onclose = (event) => {
|
|
104
|
-
if (this.responseHandler === null)
|
|
105
|
-
|
|
150
|
+
if (this.responseHandler === null) {
|
|
151
|
+
this.options.debugHandlers?.onCloseEventDropped?.(event);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
this.responseHandler.reject(newConnectionClosedError(event));
|
|
106
155
|
};
|
|
107
156
|
}
|
|
108
157
|
get readyState() {
|
|
@@ -114,31 +163,29 @@ var XConnection = class XConnection {
|
|
|
114
163
|
setResponseHandler(handler) {
|
|
115
164
|
this.responseHandler = handler;
|
|
116
165
|
}
|
|
166
|
+
close() {
|
|
167
|
+
this.socket.close();
|
|
168
|
+
}
|
|
117
169
|
};
|
|
118
|
-
function
|
|
119
|
-
const result =
|
|
120
|
-
try {
|
|
121
|
-
JSON.parse(val);
|
|
122
|
-
} catch (e) {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
return true;
|
|
126
|
-
}, {
|
|
127
|
-
abort: true,
|
|
128
|
-
message: "Invalid JSON string"
|
|
129
|
-
}).transform((val) => JSON.parse(val)).pipe(z.object({
|
|
130
|
-
type: z.enum(X_RESPONSE_TYPES),
|
|
131
|
-
value: z.string()
|
|
132
|
-
})).safeParse(data);
|
|
170
|
+
function safeParseXResponsePayload(data) {
|
|
171
|
+
const result = xResponsePayloadSchema.safeParse(data);
|
|
133
172
|
if (!result.success) return {
|
|
134
173
|
success: false,
|
|
135
|
-
error: new UWError("INVALID_RESPONSE", `invalid
|
|
174
|
+
error: new UWError("INVALID_RESPONSE", `invalid payload: ${z.prettifyError(result.error)}`)
|
|
136
175
|
};
|
|
137
176
|
return {
|
|
138
177
|
success: true,
|
|
139
178
|
data: result.data
|
|
140
179
|
};
|
|
141
180
|
}
|
|
181
|
+
function newUnexpectedXResponseTypeError(resp) {
|
|
182
|
+
let msg = `unexpected type: ${resp.type}`;
|
|
183
|
+
if (resp.type === "error") msg += ` (value: ${resp.value})`;
|
|
184
|
+
return new UWError("INVALID_RESPONSE", msg);
|
|
185
|
+
}
|
|
186
|
+
function newConnectionClosedError(event) {
|
|
187
|
+
return new UWError("CONNECTION_CLOSED", event.reason.length > 0 ? event.reason : void 0);
|
|
188
|
+
}
|
|
142
189
|
//#endregion
|
|
143
190
|
//#region src/unwallet.ts
|
|
144
191
|
var UnWallet = class UnWallet {
|
|
@@ -152,14 +199,14 @@ var UnWallet = class UnWallet {
|
|
|
152
199
|
return new UnWallet({
|
|
153
200
|
env,
|
|
154
201
|
clientID: config.clientID,
|
|
155
|
-
xConnection: await XConnection.init(getUnWalletConfigByEnv(env).
|
|
202
|
+
xConnection: await XConnection.init(getUnWalletConfigByEnv(env).xAPI)
|
|
156
203
|
});
|
|
157
204
|
}
|
|
158
205
|
get unWalletConfig() {
|
|
159
206
|
return getUnWalletConfigByEnv(this.env);
|
|
160
207
|
}
|
|
161
208
|
authorize(args) {
|
|
162
|
-
const url = new URL(`${this.unWalletConfig.frontend.baseURL}/${args.isVirtual
|
|
209
|
+
const url = new URL(`${this.unWalletConfig.frontend.baseURL}/${args.isVirtual === false ? "" : "v"}authorize`);
|
|
163
210
|
url.searchParams.set("response_type", "id_token");
|
|
164
211
|
url.searchParams.set("response_mode", args.responseMode ?? "fragment");
|
|
165
212
|
url.searchParams.set("client_id", this.clientID);
|
|
@@ -184,7 +231,7 @@ var UnWallet = class UnWallet {
|
|
|
184
231
|
resolve: (resp) => {
|
|
185
232
|
this.xConnection.setResponseHandler(null);
|
|
186
233
|
if (resp.type !== "signature") {
|
|
187
|
-
reject(
|
|
234
|
+
reject(newUnexpectedXResponseTypeError(resp));
|
|
188
235
|
return;
|
|
189
236
|
}
|
|
190
237
|
resolve({
|
|
@@ -223,7 +270,7 @@ var UnWallet = class UnWallet {
|
|
|
223
270
|
try {
|
|
224
271
|
validateTypedData(typedData);
|
|
225
272
|
} catch (e) {
|
|
226
|
-
reject(new UWError("INVALID_REQUEST", `invalid typed data: ${e.
|
|
273
|
+
reject(new UWError("INVALID_REQUEST", `invalid typed data: ${e instanceof BaseError ? e.shortMessage : String(e)}`));
|
|
227
274
|
return;
|
|
228
275
|
}
|
|
229
276
|
const digest = hashTypedData(typedData);
|
|
@@ -231,7 +278,7 @@ var UnWallet = class UnWallet {
|
|
|
231
278
|
resolve: (resp) => {
|
|
232
279
|
this.xConnection.setResponseHandler(null);
|
|
233
280
|
if (resp.type !== "signature") {
|
|
234
|
-
reject(
|
|
281
|
+
reject(newUnexpectedXResponseTypeError(resp));
|
|
235
282
|
return;
|
|
236
283
|
}
|
|
237
284
|
resolve({
|
|
@@ -270,7 +317,7 @@ var UnWallet = class UnWallet {
|
|
|
270
317
|
resolve: (resp) => {
|
|
271
318
|
this.xConnection.setResponseHandler(null);
|
|
272
319
|
if (resp.type !== "transactionID") {
|
|
273
|
-
reject(
|
|
320
|
+
reject(newUnexpectedXResponseTypeError(resp));
|
|
274
321
|
return;
|
|
275
322
|
}
|
|
276
323
|
resolve({ transactionID: resp.value });
|
|
@@ -291,6 +338,9 @@ var UnWallet = class UnWallet {
|
|
|
291
338
|
openWindow(url);
|
|
292
339
|
});
|
|
293
340
|
}
|
|
341
|
+
close() {
|
|
342
|
+
this.xConnection.close();
|
|
343
|
+
}
|
|
294
344
|
};
|
|
295
345
|
function openWindow(url) {
|
|
296
346
|
const width = screen.width / 2;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unwallet-client-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "unWallet client-side SDK",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SIVIRA",
|
|
@@ -37,10 +37,14 @@
|
|
|
37
37
|
"@commitlint/config-conventional": "21.2.0",
|
|
38
38
|
"@commitlint/types": "21.2.0",
|
|
39
39
|
"@tsconfig/strictest": "2.0.8",
|
|
40
|
+
"@vitest/coverage-v8": "4.1.10",
|
|
40
41
|
"czg": "1.13.1",
|
|
41
42
|
"husky": "9.1.7",
|
|
42
|
-
"
|
|
43
|
-
"
|
|
43
|
+
"msw": "2.15.0",
|
|
44
|
+
"publint": "0.3.23",
|
|
45
|
+
"tsdown": "0.22.14",
|
|
46
|
+
"typescript": "7.0.2",
|
|
47
|
+
"vitest": "4.1.10"
|
|
44
48
|
},
|
|
45
49
|
"scripts": {}
|
|
46
50
|
}
|