unwallet-client-sdk 0.15.0 → 0.17.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/dist/index.d.mts CHANGED
@@ -1,20 +1,66 @@
1
1
  declare const VALID_ENVS: readonly ["prod", "dev"];
2
-
3
2
  type Env = (typeof VALID_ENVS)[number];
4
3
  interface Config {
5
- clientID: string;
6
4
  env?: Env;
7
- }
8
- interface UnWalletConfig {
9
- frontend: UnWalletFrontendConfig;
10
- xapi: UnWalletXAPIConfig;
11
- }
12
- interface UnWalletFrontendConfig {
13
- baseURL: string;
5
+ clientID: string;
14
6
  }
15
7
  interface UnWalletXAPIConfig {
16
8
  url: string;
9
+ connectionTimeout: number;
17
10
  }
11
+
12
+ interface EIP712TypedData {
13
+ types: Record<string, Array<EIP712TypedDataField>>;
14
+ primaryType: string;
15
+ domain: EIP712TypedDataDomain;
16
+ message: Record<string, any>;
17
+ }
18
+ interface EIP712TypedDataDomain {
19
+ name?: string;
20
+ version?: string;
21
+ chainId?: number;
22
+ verifyingContract?: string;
23
+ salt?: string;
24
+ }
25
+ interface EIP712TypedDataField {
26
+ name: string;
27
+ type: string;
28
+ }
29
+
30
+ declare const VALID_UW_ERROR_CODES: readonly ["CONNECTION_TIMEOUT", "CONNECTION_FAILED", "CONNECTION_NOT_OPENED", "CONNECTION_CLOSED", "INVALID_REQUEST", "REQUEST_IN_PROGRESS", "REQUEST_REJECTED", "INVALID_RESPONSE"];
31
+ type UWErrorCode = (typeof VALID_UW_ERROR_CODES)[number];
32
+ declare class UWError extends Error {
33
+ readonly code: UWErrorCode;
34
+ constructor(code: UWErrorCode, message?: string);
35
+ }
36
+
37
+ declare const VALID_X_RESPONSE_TYPES: readonly ["connectionID", "signature", "transactionID", "error"];
38
+ type XResponseType = (typeof VALID_X_RESPONSE_TYPES)[number];
39
+ interface XResponse {
40
+ readonly type: XResponseType;
41
+ readonly value: string;
42
+ }
43
+ interface XResponseHandler {
44
+ resolve: (resp: XResponse) => void;
45
+ reject: (err: UWError) => void;
46
+ }
47
+ declare class XConnection {
48
+ private socket;
49
+ private responseHandler;
50
+ readonly id: string;
51
+ constructor(args: {
52
+ socket: WebSocket;
53
+ id: string;
54
+ });
55
+ private initListeners;
56
+ get readyState(): number;
57
+ get hasResponseHandler(): boolean;
58
+ setResponseHandler(handler: XResponseHandler | null): void;
59
+ static init(config: UnWalletXAPIConfig): Promise<XConnection>;
60
+ }
61
+
62
+ declare const VALID_AUTHORIZATION_RESPONSE_MODES: readonly ["fragment", "form_post"];
63
+ type AuthorizationResponseMode = (typeof VALID_AUTHORIZATION_RESPONSE_MODES)[number];
18
64
  interface SignResult {
19
65
  digest: string;
20
66
  signature: string;
@@ -22,19 +68,19 @@ interface SignResult {
22
68
  interface SendTransactionResult {
23
69
  transactionID: string;
24
70
  }
25
-
26
71
  declare class UnWallet {
27
- private config;
28
- private unWalletConfig;
29
- private ws;
30
- private connectionID;
31
- private resolve;
32
- private reject;
33
- constructor(config: Config, unWalletConfig: UnWalletConfig, ws: WebSocket);
34
- private initPromiseArgs;
72
+ private env;
73
+ private clientID;
74
+ private xConnection;
75
+ constructor(args: {
76
+ env: Env;
77
+ clientID: string;
78
+ xConnection: XConnection;
79
+ });
35
80
  static init(config: Config): Promise<UnWallet>;
81
+ private get unWalletConfig();
36
82
  authorize(args: {
37
- responseMode?: string;
83
+ responseMode?: AuthorizationResponseMode;
38
84
  redirectURL: string;
39
85
  nonce?: string;
40
86
  isVirtual?: boolean;
@@ -44,6 +90,10 @@ declare class UnWallet {
44
90
  message: string;
45
91
  ticketToken: string;
46
92
  }): Promise<SignResult>;
93
+ signEIP712TypedData(args: {
94
+ typedData: EIP712TypedData;
95
+ ticketToken: string;
96
+ }): Promise<SignResult>;
47
97
  sendTransaction(args: {
48
98
  chainID: number;
49
99
  toAddress: string;
@@ -51,10 +101,6 @@ declare class UnWallet {
51
101
  data?: string;
52
102
  ticketToken: string;
53
103
  }): Promise<SendTransactionResult>;
54
- private getConnectionID;
55
- private sendWSMessage;
56
- private handleWSMessage;
57
- private openWindow;
58
104
  }
59
105
 
60
- export { type Config, type SendTransactionResult, type SignResult, UnWallet };
106
+ 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,20 +1,66 @@
1
1
  declare const VALID_ENVS: readonly ["prod", "dev"];
2
-
3
2
  type Env = (typeof VALID_ENVS)[number];
4
3
  interface Config {
5
- clientID: string;
6
4
  env?: Env;
7
- }
8
- interface UnWalletConfig {
9
- frontend: UnWalletFrontendConfig;
10
- xapi: UnWalletXAPIConfig;
11
- }
12
- interface UnWalletFrontendConfig {
13
- baseURL: string;
5
+ clientID: string;
14
6
  }
15
7
  interface UnWalletXAPIConfig {
16
8
  url: string;
9
+ connectionTimeout: number;
17
10
  }
11
+
12
+ interface EIP712TypedData {
13
+ types: Record<string, Array<EIP712TypedDataField>>;
14
+ primaryType: string;
15
+ domain: EIP712TypedDataDomain;
16
+ message: Record<string, any>;
17
+ }
18
+ interface EIP712TypedDataDomain {
19
+ name?: string;
20
+ version?: string;
21
+ chainId?: number;
22
+ verifyingContract?: string;
23
+ salt?: string;
24
+ }
25
+ interface EIP712TypedDataField {
26
+ name: string;
27
+ type: string;
28
+ }
29
+
30
+ declare const VALID_UW_ERROR_CODES: readonly ["CONNECTION_TIMEOUT", "CONNECTION_FAILED", "CONNECTION_NOT_OPENED", "CONNECTION_CLOSED", "INVALID_REQUEST", "REQUEST_IN_PROGRESS", "REQUEST_REJECTED", "INVALID_RESPONSE"];
31
+ type UWErrorCode = (typeof VALID_UW_ERROR_CODES)[number];
32
+ declare class UWError extends Error {
33
+ readonly code: UWErrorCode;
34
+ constructor(code: UWErrorCode, message?: string);
35
+ }
36
+
37
+ declare const VALID_X_RESPONSE_TYPES: readonly ["connectionID", "signature", "transactionID", "error"];
38
+ type XResponseType = (typeof VALID_X_RESPONSE_TYPES)[number];
39
+ interface XResponse {
40
+ readonly type: XResponseType;
41
+ readonly value: string;
42
+ }
43
+ interface XResponseHandler {
44
+ resolve: (resp: XResponse) => void;
45
+ reject: (err: UWError) => void;
46
+ }
47
+ declare class XConnection {
48
+ private socket;
49
+ private responseHandler;
50
+ readonly id: string;
51
+ constructor(args: {
52
+ socket: WebSocket;
53
+ id: string;
54
+ });
55
+ private initListeners;
56
+ get readyState(): number;
57
+ get hasResponseHandler(): boolean;
58
+ setResponseHandler(handler: XResponseHandler | null): void;
59
+ static init(config: UnWalletXAPIConfig): Promise<XConnection>;
60
+ }
61
+
62
+ declare const VALID_AUTHORIZATION_RESPONSE_MODES: readonly ["fragment", "form_post"];
63
+ type AuthorizationResponseMode = (typeof VALID_AUTHORIZATION_RESPONSE_MODES)[number];
18
64
  interface SignResult {
19
65
  digest: string;
20
66
  signature: string;
@@ -22,19 +68,19 @@ interface SignResult {
22
68
  interface SendTransactionResult {
23
69
  transactionID: string;
24
70
  }
25
-
26
71
  declare class UnWallet {
27
- private config;
28
- private unWalletConfig;
29
- private ws;
30
- private connectionID;
31
- private resolve;
32
- private reject;
33
- constructor(config: Config, unWalletConfig: UnWalletConfig, ws: WebSocket);
34
- private initPromiseArgs;
72
+ private env;
73
+ private clientID;
74
+ private xConnection;
75
+ constructor(args: {
76
+ env: Env;
77
+ clientID: string;
78
+ xConnection: XConnection;
79
+ });
35
80
  static init(config: Config): Promise<UnWallet>;
81
+ private get unWalletConfig();
36
82
  authorize(args: {
37
- responseMode?: string;
83
+ responseMode?: AuthorizationResponseMode;
38
84
  redirectURL: string;
39
85
  nonce?: string;
40
86
  isVirtual?: boolean;
@@ -44,6 +90,10 @@ declare class UnWallet {
44
90
  message: string;
45
91
  ticketToken: string;
46
92
  }): Promise<SignResult>;
93
+ signEIP712TypedData(args: {
94
+ typedData: EIP712TypedData;
95
+ ticketToken: string;
96
+ }): Promise<SignResult>;
47
97
  sendTransaction(args: {
48
98
  chainID: number;
49
99
  toAddress: string;
@@ -51,10 +101,6 @@ declare class UnWallet {
51
101
  data?: string;
52
102
  ticketToken: string;
53
103
  }): Promise<SendTransactionResult>;
54
- private getConnectionID;
55
- private sendWSMessage;
56
- private handleWSMessage;
57
- private openWindow;
58
104
  }
59
105
 
60
- export { type Config, type SendTransactionResult, type SignResult, UnWallet };
106
+ 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,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,25 +17,46 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
33
+ UWError: () => UWError,
23
34
  UnWallet: () => UnWallet
24
35
  });
25
36
  module.exports = __toCommonJS(index_exports);
26
37
 
38
+ // src/error.ts
39
+ var _UWError = class _UWError extends Error {
40
+ constructor(code, message) {
41
+ super(message !== void 0 ? `${code}: ${message}` : code);
42
+ this.code = code;
43
+ }
44
+ };
45
+ _UWError.prototype.name = "UWError";
46
+ var UWError = _UWError;
47
+
27
48
  // src/unwallet.ts
28
49
  var import_ethers = require("ethers");
50
+ var import_omit = __toESM(require("lodash/omit"));
29
51
 
30
- // src/consts.ts
52
+ // src/config.ts
31
53
  var UNWALLET_CONFIG_PROD = {
32
54
  frontend: {
33
55
  baseURL: "https://id.unwallet.world"
34
56
  },
35
57
  xapi: {
36
- url: "wss://xapi.id.unwallet.world"
58
+ url: "wss://xapi.id.unwallet.world",
59
+ connectionTimeout: 1e4
37
60
  }
38
61
  };
39
62
  var UNWALLET_CONFIG_DEV = {
@@ -41,75 +64,186 @@ var UNWALLET_CONFIG_DEV = {
41
64
  baseURL: "http://localhost:4200"
42
65
  },
43
66
  xapi: {
44
- url: "wss://xapi.id.test.unwallet.dev"
67
+ url: "wss://xapi.id.test.unwallet.dev",
68
+ connectionTimeout: 1e4
45
69
  }
46
70
  };
71
+ function getUnWalletConfigByEnv(env) {
72
+ switch (env) {
73
+ case "prod":
74
+ return UNWALLET_CONFIG_PROD;
75
+ case "dev":
76
+ return UNWALLET_CONFIG_DEV;
77
+ }
78
+ }
47
79
 
48
- // src/unwallet.ts
49
- var UnWallet = class _UnWallet {
50
- constructor(config, unWalletConfig, ws) {
51
- this.resolve = null;
52
- this.reject = null;
53
- this.config = config;
54
- this.unWalletConfig = unWalletConfig;
55
- this.ws = ws;
56
- this.connectionID = "";
57
- this.initPromiseArgs();
58
- }
59
- initPromiseArgs() {
60
- this.resolve = () => {
61
- };
62
- this.reject = () => {
63
- };
80
+ // src/x.ts
81
+ var import_v4 = require("zod/v4");
82
+ var VALID_X_RESPONSE_TYPES = [
83
+ "connectionID",
84
+ "signature",
85
+ "transactionID",
86
+ "error"
87
+ ];
88
+ var XConnection = class _XConnection {
89
+ constructor(args) {
90
+ this.responseHandler = null;
91
+ this.socket = args.socket;
92
+ this.id = args.id;
93
+ this.initListeners();
64
94
  }
65
- static init(config) {
66
- return new Promise((resolve, reject) => {
67
- if (config.env === void 0) {
68
- config.env = "prod";
95
+ initListeners() {
96
+ this.socket.onopen = null;
97
+ this.socket.onmessage = (event) => {
98
+ if (this.responseHandler === null) {
99
+ return;
69
100
  }
70
- let unWalletConfig;
101
+ let resp;
71
102
  {
72
- switch (config.env) {
73
- case "prod":
74
- unWalletConfig = UNWALLET_CONFIG_PROD;
75
- break;
76
- case "dev":
77
- unWalletConfig = UNWALLET_CONFIG_DEV;
78
- break;
103
+ const result = safeParseMessageEventDataToXResponse(event.data);
104
+ if (!result.success) {
105
+ this.responseHandler.reject(result.error);
106
+ return;
79
107
  }
108
+ resp = result.data;
80
109
  }
81
- const ws = new WebSocket(unWalletConfig.xapi.url);
82
- {
83
- ws.onerror = () => {
84
- reject("websocket connection failed");
85
- };
86
- ws.onopen = () => {
87
- unWallet.getConnectionID();
88
- };
89
- ws.onmessage = (event) => {
90
- const msg = JSON.parse(event.data);
91
- if (msg.type === "connectionID") {
92
- unWallet.connectionID = msg.value;
93
- resolve(unWallet);
110
+ switch (resp.type) {
111
+ case "error":
112
+ switch (resp.value) {
113
+ case "rejected":
114
+ this.responseHandler.reject(new UWError("REQUEST_REJECTED"));
115
+ break;
116
+ default:
117
+ this.responseHandler.reject(
118
+ new UWError(
119
+ "INVALID_RESPONSE",
120
+ `unexpected error response value: ${resp.value}`
121
+ )
122
+ );
123
+ }
124
+ break;
125
+ default:
126
+ this.responseHandler.resolve(resp);
127
+ }
128
+ };
129
+ this.socket.onerror = null;
130
+ this.socket.onclose = (event) => {
131
+ if (this.responseHandler === null) {
132
+ return;
133
+ }
134
+ this.responseHandler.reject(
135
+ new UWError("CONNECTION_CLOSED", event.reason)
136
+ );
137
+ };
138
+ }
139
+ get readyState() {
140
+ return this.socket.readyState;
141
+ }
142
+ get hasResponseHandler() {
143
+ return this.responseHandler !== null;
144
+ }
145
+ setResponseHandler(handler) {
146
+ this.responseHandler = handler;
147
+ }
148
+ static async init(config) {
149
+ const socket = new WebSocket(config.url);
150
+ const id = await new Promise((resolve, reject) => {
151
+ setInterval(
152
+ () => reject(new UWError("CONNECTION_TIMEOUT")),
153
+ config.connectionTimeout
154
+ );
155
+ socket.onopen = () => socket.send(JSON.stringify({ action: "getConnectionID" }));
156
+ socket.onmessage = (event) => {
157
+ let resp;
158
+ {
159
+ const result = safeParseMessageEventDataToXResponse(event.data);
160
+ if (!result.success) {
161
+ reject(result.error);
94
162
  return;
95
163
  }
96
- unWallet.handleWSMessage(msg);
97
- };
164
+ resp = result.data;
165
+ }
166
+ if (resp.type !== "connectionID") {
167
+ reject(
168
+ new UWError(
169
+ "INVALID_RESPONSE",
170
+ `unexpected response type: ${resp.type}`
171
+ )
172
+ );
173
+ return;
174
+ }
175
+ resolve(resp.value);
176
+ };
177
+ socket.onerror = () => reject(new UWError("CONNECTION_FAILED"));
178
+ socket.onclose = (event) => reject(new UWError("CONNECTION_CLOSED", event.reason));
179
+ });
180
+ return new _XConnection({ socket, id });
181
+ }
182
+ };
183
+ function safeParseMessageEventDataToXResponse(data) {
184
+ const result = import_v4.z.string().refine(
185
+ (val) => {
186
+ try {
187
+ JSON.parse(val);
188
+ } catch (e) {
189
+ return false;
98
190
  }
99
- const unWallet = new _UnWallet(config, unWalletConfig, ws);
191
+ return true;
192
+ },
193
+ {
194
+ abort: true,
195
+ message: "Invalid JSON string"
196
+ }
197
+ ).transform((val) => JSON.parse(val)).pipe(
198
+ import_v4.z.object({
199
+ type: import_v4.z.enum(VALID_X_RESPONSE_TYPES),
200
+ value: import_v4.z.string()
201
+ })
202
+ ).safeParse(data);
203
+ if (!result.success) {
204
+ return {
205
+ success: false,
206
+ error: new UWError(
207
+ "INVALID_RESPONSE",
208
+ `invalid message event data: ${result.error.message}`
209
+ )
210
+ };
211
+ }
212
+ return {
213
+ success: true,
214
+ data: result.data
215
+ };
216
+ }
217
+
218
+ // src/unwallet.ts
219
+ var UnWallet = class _UnWallet {
220
+ constructor(args) {
221
+ this.env = args.env;
222
+ this.clientID = args.clientID;
223
+ this.xConnection = args.xConnection;
224
+ }
225
+ static async init(config) {
226
+ const env = config.env !== void 0 ? config.env : "prod";
227
+ return new _UnWallet({
228
+ env,
229
+ clientID: config.clientID,
230
+ xConnection: await XConnection.init(getUnWalletConfigByEnv(env).xapi)
100
231
  });
101
232
  }
233
+ get unWalletConfig() {
234
+ return getUnWalletConfigByEnv(this.env);
235
+ }
102
236
  authorize(args) {
103
- if (!args.responseMode) {
104
- args.responseMode = "fragment";
105
- }
106
- let url = new URL(
107
- `${this.unWalletConfig.frontend.baseURL}/${args.isVirtual === false ? "" : "v"}authorize`
237
+ const url = new URL(
238
+ `${this.unWalletConfig.frontend.baseURL}/${args.isVirtual !== void 0 ? args.isVirtual ? "v" : "" : "v"}authorize`
108
239
  );
109
240
  {
110
241
  url.searchParams.set("response_type", "id_token");
111
- url.searchParams.set("response_mode", args.responseMode);
112
- url.searchParams.set("client_id", this.config.clientID);
242
+ url.searchParams.set(
243
+ "response_mode",
244
+ args.responseMode !== void 0 ? args.responseMode : "fragment"
245
+ );
246
+ url.searchParams.set("client_id", this.clientID);
113
247
  url.searchParams.set("scope", "openid");
114
248
  url.searchParams.set("redirect_uri", args.redirectURL);
115
249
  if (args.nonce !== void 0) {
@@ -119,42 +253,180 @@ var UnWallet = class _UnWallet {
119
253
  url.searchParams.set("chain_id", args.chainID.toString());
120
254
  }
121
255
  }
122
- location.assign(url.toString());
256
+ location.assign(url);
123
257
  }
124
258
  sign(args) {
125
259
  return new Promise((resolve, reject) => {
126
- this.resolve = (sig) => {
127
- resolve({
128
- digest: import_ethers.ethers.sha256(import_ethers.ethers.toUtf8Bytes(args.message)),
129
- signature: sig
130
- });
131
- };
132
- this.reject = reject;
260
+ if (this.xConnection.readyState !== WebSocket.OPEN) {
261
+ reject(new UWError("CONNECTION_NOT_OPENED"));
262
+ return;
263
+ }
264
+ if (this.xConnection.hasResponseHandler) {
265
+ reject(new UWError("REQUEST_IN_PROGRESS"));
266
+ return;
267
+ }
268
+ const digest = import_ethers.ethers.sha256(import_ethers.ethers.toUtf8Bytes(args.message));
269
+ this.xConnection.setResponseHandler({
270
+ resolve: (resp) => {
271
+ this.xConnection.setResponseHandler(null);
272
+ if (resp.type !== "signature") {
273
+ reject(
274
+ new UWError(
275
+ "INVALID_RESPONSE",
276
+ `unexpected response type: ${resp.type}`
277
+ )
278
+ );
279
+ return;
280
+ }
281
+ resolve({
282
+ digest,
283
+ signature: resp.value
284
+ });
285
+ },
286
+ reject: (err) => {
287
+ this.xConnection.setResponseHandler(null);
288
+ reject(err);
289
+ }
290
+ });
133
291
  const url = new URL(`${this.unWalletConfig.frontend.baseURL}/x/sign`);
134
292
  {
135
- url.searchParams.set("connectionID", this.connectionID);
136
- url.searchParams.set("clientID", this.config.clientID);
293
+ url.searchParams.set("connectionID", this.xConnection.id);
294
+ url.searchParams.set("clientID", this.clientID);
137
295
  url.searchParams.set("message", args.message);
138
296
  url.searchParams.set("ticketToken", args.ticketToken);
139
297
  }
140
- this.openWindow(url);
298
+ openWindow(url);
299
+ });
300
+ }
301
+ signEIP712TypedData(args) {
302
+ return new Promise((resolve, reject) => {
303
+ if (this.xConnection.readyState !== WebSocket.OPEN) {
304
+ reject(new UWError("CONNECTION_NOT_OPENED"));
305
+ return;
306
+ }
307
+ if (this.xConnection.hasResponseHandler) {
308
+ reject(new UWError("REQUEST_IN_PROGRESS"));
309
+ return;
310
+ }
311
+ const types = (0, import_omit.default)(args.typedData.types, "EIP712Domain");
312
+ let primaryType;
313
+ {
314
+ try {
315
+ primaryType = import_ethers.ethers.TypedDataEncoder.getPrimaryType(types);
316
+ } catch (e) {
317
+ if (import_ethers.ethers.isError(e, "INVALID_ARGUMENT")) {
318
+ reject(
319
+ new UWError("INVALID_REQUEST", `invalid typed data: ${e.message}`)
320
+ );
321
+ return;
322
+ }
323
+ reject(e);
324
+ return;
325
+ }
326
+ }
327
+ if (primaryType !== args.typedData.primaryType) {
328
+ reject(
329
+ new UWError(
330
+ "INVALID_REQUEST",
331
+ `invalid typed data: primary type must be ${primaryType}`
332
+ )
333
+ );
334
+ return;
335
+ }
336
+ let digest;
337
+ {
338
+ try {
339
+ digest = import_ethers.ethers.TypedDataEncoder.hash(
340
+ args.typedData.domain,
341
+ types,
342
+ args.typedData.message
343
+ );
344
+ } catch (e) {
345
+ if (import_ethers.ethers.isError(e, "INVALID_ARGUMENT")) {
346
+ reject(
347
+ new UWError("INVALID_REQUEST", `invalid typed data: ${e.message}`)
348
+ );
349
+ return;
350
+ }
351
+ reject(e);
352
+ return;
353
+ }
354
+ }
355
+ this.xConnection.setResponseHandler({
356
+ resolve: (resp) => {
357
+ this.xConnection.setResponseHandler(null);
358
+ if (resp.type !== "signature") {
359
+ reject(
360
+ new UWError(
361
+ "INVALID_RESPONSE",
362
+ `unexpected response type: ${resp.type}`
363
+ )
364
+ );
365
+ return;
366
+ }
367
+ resolve({
368
+ digest,
369
+ signature: resp.value
370
+ });
371
+ },
372
+ reject: (err) => {
373
+ this.xConnection.setResponseHandler(null);
374
+ reject(err);
375
+ }
376
+ });
377
+ const url = new URL(
378
+ `${this.unWalletConfig.frontend.baseURL}/x/signEIP712TypedData`
379
+ );
380
+ {
381
+ url.searchParams.set("connectionID", this.xConnection.id);
382
+ url.searchParams.set("clientID", this.clientID);
383
+ url.searchParams.set("typedData", JSON.stringify(args.typedData));
384
+ url.searchParams.set("ticketToken", args.ticketToken);
385
+ }
386
+ openWindow(url);
141
387
  });
142
388
  }
143
389
  sendTransaction(args) {
144
390
  return new Promise((resolve, reject) => {
391
+ if (this.xConnection.readyState !== WebSocket.OPEN) {
392
+ reject(new UWError("CONNECTION_NOT_OPENED"));
393
+ return;
394
+ }
395
+ if (this.xConnection.hasResponseHandler) {
396
+ reject(new UWError("REQUEST_IN_PROGRESS"));
397
+ return;
398
+ }
145
399
  if (args.value === void 0 && args.data === void 0) {
146
- throw new Error("either value or data required");
400
+ reject(
401
+ new UWError("INVALID_REQUEST", "either value or data is required")
402
+ );
403
+ return;
147
404
  }
148
- this.resolve = (txID) => {
149
- resolve({ transactionID: txID });
150
- };
151
- this.reject = reject;
405
+ this.xConnection.setResponseHandler({
406
+ resolve: (resp) => {
407
+ this.xConnection.setResponseHandler(null);
408
+ if (resp.type !== "transactionID") {
409
+ reject(
410
+ new UWError(
411
+ "INVALID_RESPONSE",
412
+ `unexpected response type: ${resp.type}`
413
+ )
414
+ );
415
+ return;
416
+ }
417
+ resolve({ transactionID: resp.value });
418
+ },
419
+ reject: (err) => {
420
+ this.xConnection.setResponseHandler(null);
421
+ reject(err);
422
+ }
423
+ });
152
424
  const url = new URL(
153
425
  `${this.unWalletConfig.frontend.baseURL}/x/sendTransaction`
154
426
  );
155
427
  {
156
- url.searchParams.set("connectionID", this.connectionID);
157
- url.searchParams.set("clientID", this.config.clientID);
428
+ url.searchParams.set("connectionID", this.xConnection.id);
429
+ url.searchParams.set("clientID", this.clientID);
158
430
  url.searchParams.set("chainID", args.chainID.toString());
159
431
  url.searchParams.set("toAddress", args.toAddress);
160
432
  url.searchParams.set(
@@ -167,52 +439,23 @@ var UnWallet = class _UnWallet {
167
439
  );
168
440
  url.searchParams.set("ticketToken", args.ticketToken);
169
441
  }
170
- this.openWindow(url);
171
- });
172
- }
173
- getConnectionID() {
174
- this.sendWSMessage({
175
- action: "getConnectionID"
442
+ openWindow(url);
176
443
  });
177
444
  }
178
- sendWSMessage(msg) {
179
- this.ws.send(JSON.stringify(msg));
180
- }
181
- handleWSMessage(msg) {
182
- switch (msg.type) {
183
- case "signature":
184
- this.resolve(msg.value);
185
- break;
186
- case "transactionID":
187
- this.resolve(msg.value);
188
- break;
189
- case "error":
190
- switch (msg.value) {
191
- case "rejected":
192
- this.reject("canceled");
193
- break;
194
- default:
195
- throw new Error(msg.value);
196
- }
197
- break;
198
- default:
199
- throw new Error(`unexpected message type: ${msg.type}`);
200
- }
201
- this.initPromiseArgs();
202
- }
203
- openWindow(url) {
204
- const width = screen.width / 2;
205
- const height = screen.height;
206
- const left = screen.width / 4;
207
- const top = 0;
208
- window.open(
209
- url.toString(),
210
- "_blank",
211
- `width=${width},height=${height},left=${left},top=${top}`
212
- );
213
- }
214
445
  };
446
+ function openWindow(url) {
447
+ const width = screen.width / 2;
448
+ const height = screen.height;
449
+ const left = screen.width / 4;
450
+ const top = 0;
451
+ window.open(
452
+ url.toString(),
453
+ "_blank",
454
+ `width=${width},height=${height},left=${left},top=${top}`
455
+ );
456
+ }
215
457
  // Annotate the CommonJS export names for ESM import in node:
216
458
  0 && (module.exports = {
459
+ UWError,
217
460
  UnWallet
218
461
  });
package/dist/index.mjs CHANGED
@@ -1,13 +1,25 @@
1
+ // src/error.ts
2
+ var _UWError = class _UWError extends Error {
3
+ constructor(code, message) {
4
+ super(message !== void 0 ? `${code}: ${message}` : code);
5
+ this.code = code;
6
+ }
7
+ };
8
+ _UWError.prototype.name = "UWError";
9
+ var UWError = _UWError;
10
+
1
11
  // src/unwallet.ts
2
12
  import { ethers } from "ethers";
13
+ import omit from "lodash/omit";
3
14
 
4
- // src/consts.ts
15
+ // src/config.ts
5
16
  var UNWALLET_CONFIG_PROD = {
6
17
  frontend: {
7
18
  baseURL: "https://id.unwallet.world"
8
19
  },
9
20
  xapi: {
10
- url: "wss://xapi.id.unwallet.world"
21
+ url: "wss://xapi.id.unwallet.world",
22
+ connectionTimeout: 1e4
11
23
  }
12
24
  };
13
25
  var UNWALLET_CONFIG_DEV = {
@@ -15,75 +27,186 @@ var UNWALLET_CONFIG_DEV = {
15
27
  baseURL: "http://localhost:4200"
16
28
  },
17
29
  xapi: {
18
- url: "wss://xapi.id.test.unwallet.dev"
30
+ url: "wss://xapi.id.test.unwallet.dev",
31
+ connectionTimeout: 1e4
19
32
  }
20
33
  };
34
+ function getUnWalletConfigByEnv(env) {
35
+ switch (env) {
36
+ case "prod":
37
+ return UNWALLET_CONFIG_PROD;
38
+ case "dev":
39
+ return UNWALLET_CONFIG_DEV;
40
+ }
41
+ }
21
42
 
22
- // src/unwallet.ts
23
- var UnWallet = class _UnWallet {
24
- constructor(config, unWalletConfig, ws) {
25
- this.resolve = null;
26
- this.reject = null;
27
- this.config = config;
28
- this.unWalletConfig = unWalletConfig;
29
- this.ws = ws;
30
- this.connectionID = "";
31
- this.initPromiseArgs();
32
- }
33
- initPromiseArgs() {
34
- this.resolve = () => {
35
- };
36
- this.reject = () => {
37
- };
43
+ // src/x.ts
44
+ import { z } from "zod/v4";
45
+ var VALID_X_RESPONSE_TYPES = [
46
+ "connectionID",
47
+ "signature",
48
+ "transactionID",
49
+ "error"
50
+ ];
51
+ var XConnection = class _XConnection {
52
+ constructor(args) {
53
+ this.responseHandler = null;
54
+ this.socket = args.socket;
55
+ this.id = args.id;
56
+ this.initListeners();
38
57
  }
39
- static init(config) {
40
- return new Promise((resolve, reject) => {
41
- if (config.env === void 0) {
42
- config.env = "prod";
58
+ initListeners() {
59
+ this.socket.onopen = null;
60
+ this.socket.onmessage = (event) => {
61
+ if (this.responseHandler === null) {
62
+ return;
43
63
  }
44
- let unWalletConfig;
64
+ let resp;
45
65
  {
46
- switch (config.env) {
47
- case "prod":
48
- unWalletConfig = UNWALLET_CONFIG_PROD;
49
- break;
50
- case "dev":
51
- unWalletConfig = UNWALLET_CONFIG_DEV;
52
- break;
66
+ const result = safeParseMessageEventDataToXResponse(event.data);
67
+ if (!result.success) {
68
+ this.responseHandler.reject(result.error);
69
+ return;
53
70
  }
71
+ resp = result.data;
54
72
  }
55
- const ws = new WebSocket(unWalletConfig.xapi.url);
56
- {
57
- ws.onerror = () => {
58
- reject("websocket connection failed");
59
- };
60
- ws.onopen = () => {
61
- unWallet.getConnectionID();
62
- };
63
- ws.onmessage = (event) => {
64
- const msg = JSON.parse(event.data);
65
- if (msg.type === "connectionID") {
66
- unWallet.connectionID = msg.value;
67
- resolve(unWallet);
73
+ switch (resp.type) {
74
+ case "error":
75
+ switch (resp.value) {
76
+ case "rejected":
77
+ this.responseHandler.reject(new UWError("REQUEST_REJECTED"));
78
+ break;
79
+ default:
80
+ this.responseHandler.reject(
81
+ new UWError(
82
+ "INVALID_RESPONSE",
83
+ `unexpected error response value: ${resp.value}`
84
+ )
85
+ );
86
+ }
87
+ break;
88
+ default:
89
+ this.responseHandler.resolve(resp);
90
+ }
91
+ };
92
+ this.socket.onerror = null;
93
+ this.socket.onclose = (event) => {
94
+ if (this.responseHandler === null) {
95
+ return;
96
+ }
97
+ this.responseHandler.reject(
98
+ new UWError("CONNECTION_CLOSED", event.reason)
99
+ );
100
+ };
101
+ }
102
+ get readyState() {
103
+ return this.socket.readyState;
104
+ }
105
+ get hasResponseHandler() {
106
+ return this.responseHandler !== null;
107
+ }
108
+ setResponseHandler(handler) {
109
+ this.responseHandler = handler;
110
+ }
111
+ static async init(config) {
112
+ const socket = new WebSocket(config.url);
113
+ const id = await new Promise((resolve, reject) => {
114
+ setInterval(
115
+ () => reject(new UWError("CONNECTION_TIMEOUT")),
116
+ config.connectionTimeout
117
+ );
118
+ socket.onopen = () => socket.send(JSON.stringify({ action: "getConnectionID" }));
119
+ socket.onmessage = (event) => {
120
+ let resp;
121
+ {
122
+ const result = safeParseMessageEventDataToXResponse(event.data);
123
+ if (!result.success) {
124
+ reject(result.error);
68
125
  return;
69
126
  }
70
- unWallet.handleWSMessage(msg);
71
- };
127
+ resp = result.data;
128
+ }
129
+ if (resp.type !== "connectionID") {
130
+ reject(
131
+ new UWError(
132
+ "INVALID_RESPONSE",
133
+ `unexpected response type: ${resp.type}`
134
+ )
135
+ );
136
+ return;
137
+ }
138
+ resolve(resp.value);
139
+ };
140
+ socket.onerror = () => reject(new UWError("CONNECTION_FAILED"));
141
+ socket.onclose = (event) => reject(new UWError("CONNECTION_CLOSED", event.reason));
142
+ });
143
+ return new _XConnection({ socket, id });
144
+ }
145
+ };
146
+ function safeParseMessageEventDataToXResponse(data) {
147
+ const result = z.string().refine(
148
+ (val) => {
149
+ try {
150
+ JSON.parse(val);
151
+ } catch (e) {
152
+ return false;
72
153
  }
73
- const unWallet = new _UnWallet(config, unWalletConfig, ws);
154
+ return true;
155
+ },
156
+ {
157
+ abort: true,
158
+ message: "Invalid JSON string"
159
+ }
160
+ ).transform((val) => JSON.parse(val)).pipe(
161
+ z.object({
162
+ type: z.enum(VALID_X_RESPONSE_TYPES),
163
+ value: z.string()
164
+ })
165
+ ).safeParse(data);
166
+ if (!result.success) {
167
+ return {
168
+ success: false,
169
+ error: new UWError(
170
+ "INVALID_RESPONSE",
171
+ `invalid message event data: ${result.error.message}`
172
+ )
173
+ };
174
+ }
175
+ return {
176
+ success: true,
177
+ data: result.data
178
+ };
179
+ }
180
+
181
+ // src/unwallet.ts
182
+ var UnWallet = class _UnWallet {
183
+ constructor(args) {
184
+ this.env = args.env;
185
+ this.clientID = args.clientID;
186
+ this.xConnection = args.xConnection;
187
+ }
188
+ static async init(config) {
189
+ const env = config.env !== void 0 ? config.env : "prod";
190
+ return new _UnWallet({
191
+ env,
192
+ clientID: config.clientID,
193
+ xConnection: await XConnection.init(getUnWalletConfigByEnv(env).xapi)
74
194
  });
75
195
  }
196
+ get unWalletConfig() {
197
+ return getUnWalletConfigByEnv(this.env);
198
+ }
76
199
  authorize(args) {
77
- if (!args.responseMode) {
78
- args.responseMode = "fragment";
79
- }
80
- let url = new URL(
81
- `${this.unWalletConfig.frontend.baseURL}/${args.isVirtual === false ? "" : "v"}authorize`
200
+ const url = new URL(
201
+ `${this.unWalletConfig.frontend.baseURL}/${args.isVirtual !== void 0 ? args.isVirtual ? "v" : "" : "v"}authorize`
82
202
  );
83
203
  {
84
204
  url.searchParams.set("response_type", "id_token");
85
- url.searchParams.set("response_mode", args.responseMode);
86
- url.searchParams.set("client_id", this.config.clientID);
205
+ url.searchParams.set(
206
+ "response_mode",
207
+ args.responseMode !== void 0 ? args.responseMode : "fragment"
208
+ );
209
+ url.searchParams.set("client_id", this.clientID);
87
210
  url.searchParams.set("scope", "openid");
88
211
  url.searchParams.set("redirect_uri", args.redirectURL);
89
212
  if (args.nonce !== void 0) {
@@ -93,42 +216,180 @@ var UnWallet = class _UnWallet {
93
216
  url.searchParams.set("chain_id", args.chainID.toString());
94
217
  }
95
218
  }
96
- location.assign(url.toString());
219
+ location.assign(url);
97
220
  }
98
221
  sign(args) {
99
222
  return new Promise((resolve, reject) => {
100
- this.resolve = (sig) => {
101
- resolve({
102
- digest: ethers.sha256(ethers.toUtf8Bytes(args.message)),
103
- signature: sig
104
- });
105
- };
106
- this.reject = reject;
223
+ if (this.xConnection.readyState !== WebSocket.OPEN) {
224
+ reject(new UWError("CONNECTION_NOT_OPENED"));
225
+ return;
226
+ }
227
+ if (this.xConnection.hasResponseHandler) {
228
+ reject(new UWError("REQUEST_IN_PROGRESS"));
229
+ return;
230
+ }
231
+ const digest = ethers.sha256(ethers.toUtf8Bytes(args.message));
232
+ this.xConnection.setResponseHandler({
233
+ resolve: (resp) => {
234
+ this.xConnection.setResponseHandler(null);
235
+ if (resp.type !== "signature") {
236
+ reject(
237
+ new UWError(
238
+ "INVALID_RESPONSE",
239
+ `unexpected response type: ${resp.type}`
240
+ )
241
+ );
242
+ return;
243
+ }
244
+ resolve({
245
+ digest,
246
+ signature: resp.value
247
+ });
248
+ },
249
+ reject: (err) => {
250
+ this.xConnection.setResponseHandler(null);
251
+ reject(err);
252
+ }
253
+ });
107
254
  const url = new URL(`${this.unWalletConfig.frontend.baseURL}/x/sign`);
108
255
  {
109
- url.searchParams.set("connectionID", this.connectionID);
110
- url.searchParams.set("clientID", this.config.clientID);
256
+ url.searchParams.set("connectionID", this.xConnection.id);
257
+ url.searchParams.set("clientID", this.clientID);
111
258
  url.searchParams.set("message", args.message);
112
259
  url.searchParams.set("ticketToken", args.ticketToken);
113
260
  }
114
- this.openWindow(url);
261
+ openWindow(url);
262
+ });
263
+ }
264
+ signEIP712TypedData(args) {
265
+ return new Promise((resolve, reject) => {
266
+ if (this.xConnection.readyState !== WebSocket.OPEN) {
267
+ reject(new UWError("CONNECTION_NOT_OPENED"));
268
+ return;
269
+ }
270
+ if (this.xConnection.hasResponseHandler) {
271
+ reject(new UWError("REQUEST_IN_PROGRESS"));
272
+ return;
273
+ }
274
+ const types = omit(args.typedData.types, "EIP712Domain");
275
+ let primaryType;
276
+ {
277
+ try {
278
+ primaryType = ethers.TypedDataEncoder.getPrimaryType(types);
279
+ } catch (e) {
280
+ if (ethers.isError(e, "INVALID_ARGUMENT")) {
281
+ reject(
282
+ new UWError("INVALID_REQUEST", `invalid typed data: ${e.message}`)
283
+ );
284
+ return;
285
+ }
286
+ reject(e);
287
+ return;
288
+ }
289
+ }
290
+ if (primaryType !== args.typedData.primaryType) {
291
+ reject(
292
+ new UWError(
293
+ "INVALID_REQUEST",
294
+ `invalid typed data: primary type must be ${primaryType}`
295
+ )
296
+ );
297
+ return;
298
+ }
299
+ let digest;
300
+ {
301
+ try {
302
+ digest = ethers.TypedDataEncoder.hash(
303
+ args.typedData.domain,
304
+ types,
305
+ args.typedData.message
306
+ );
307
+ } catch (e) {
308
+ if (ethers.isError(e, "INVALID_ARGUMENT")) {
309
+ reject(
310
+ new UWError("INVALID_REQUEST", `invalid typed data: ${e.message}`)
311
+ );
312
+ return;
313
+ }
314
+ reject(e);
315
+ return;
316
+ }
317
+ }
318
+ this.xConnection.setResponseHandler({
319
+ resolve: (resp) => {
320
+ this.xConnection.setResponseHandler(null);
321
+ if (resp.type !== "signature") {
322
+ reject(
323
+ new UWError(
324
+ "INVALID_RESPONSE",
325
+ `unexpected response type: ${resp.type}`
326
+ )
327
+ );
328
+ return;
329
+ }
330
+ resolve({
331
+ digest,
332
+ signature: resp.value
333
+ });
334
+ },
335
+ reject: (err) => {
336
+ this.xConnection.setResponseHandler(null);
337
+ reject(err);
338
+ }
339
+ });
340
+ const url = new URL(
341
+ `${this.unWalletConfig.frontend.baseURL}/x/signEIP712TypedData`
342
+ );
343
+ {
344
+ url.searchParams.set("connectionID", this.xConnection.id);
345
+ url.searchParams.set("clientID", this.clientID);
346
+ url.searchParams.set("typedData", JSON.stringify(args.typedData));
347
+ url.searchParams.set("ticketToken", args.ticketToken);
348
+ }
349
+ openWindow(url);
115
350
  });
116
351
  }
117
352
  sendTransaction(args) {
118
353
  return new Promise((resolve, reject) => {
354
+ if (this.xConnection.readyState !== WebSocket.OPEN) {
355
+ reject(new UWError("CONNECTION_NOT_OPENED"));
356
+ return;
357
+ }
358
+ if (this.xConnection.hasResponseHandler) {
359
+ reject(new UWError("REQUEST_IN_PROGRESS"));
360
+ return;
361
+ }
119
362
  if (args.value === void 0 && args.data === void 0) {
120
- throw new Error("either value or data required");
363
+ reject(
364
+ new UWError("INVALID_REQUEST", "either value or data is required")
365
+ );
366
+ return;
121
367
  }
122
- this.resolve = (txID) => {
123
- resolve({ transactionID: txID });
124
- };
125
- this.reject = reject;
368
+ this.xConnection.setResponseHandler({
369
+ resolve: (resp) => {
370
+ this.xConnection.setResponseHandler(null);
371
+ if (resp.type !== "transactionID") {
372
+ reject(
373
+ new UWError(
374
+ "INVALID_RESPONSE",
375
+ `unexpected response type: ${resp.type}`
376
+ )
377
+ );
378
+ return;
379
+ }
380
+ resolve({ transactionID: resp.value });
381
+ },
382
+ reject: (err) => {
383
+ this.xConnection.setResponseHandler(null);
384
+ reject(err);
385
+ }
386
+ });
126
387
  const url = new URL(
127
388
  `${this.unWalletConfig.frontend.baseURL}/x/sendTransaction`
128
389
  );
129
390
  {
130
- url.searchParams.set("connectionID", this.connectionID);
131
- url.searchParams.set("clientID", this.config.clientID);
391
+ url.searchParams.set("connectionID", this.xConnection.id);
392
+ url.searchParams.set("clientID", this.clientID);
132
393
  url.searchParams.set("chainID", args.chainID.toString());
133
394
  url.searchParams.set("toAddress", args.toAddress);
134
395
  url.searchParams.set(
@@ -141,51 +402,22 @@ var UnWallet = class _UnWallet {
141
402
  );
142
403
  url.searchParams.set("ticketToken", args.ticketToken);
143
404
  }
144
- this.openWindow(url);
145
- });
146
- }
147
- getConnectionID() {
148
- this.sendWSMessage({
149
- action: "getConnectionID"
405
+ openWindow(url);
150
406
  });
151
407
  }
152
- sendWSMessage(msg) {
153
- this.ws.send(JSON.stringify(msg));
154
- }
155
- handleWSMessage(msg) {
156
- switch (msg.type) {
157
- case "signature":
158
- this.resolve(msg.value);
159
- break;
160
- case "transactionID":
161
- this.resolve(msg.value);
162
- break;
163
- case "error":
164
- switch (msg.value) {
165
- case "rejected":
166
- this.reject("canceled");
167
- break;
168
- default:
169
- throw new Error(msg.value);
170
- }
171
- break;
172
- default:
173
- throw new Error(`unexpected message type: ${msg.type}`);
174
- }
175
- this.initPromiseArgs();
176
- }
177
- openWindow(url) {
178
- const width = screen.width / 2;
179
- const height = screen.height;
180
- const left = screen.width / 4;
181
- const top = 0;
182
- window.open(
183
- url.toString(),
184
- "_blank",
185
- `width=${width},height=${height},left=${left},top=${top}`
186
- );
187
- }
188
408
  };
409
+ function openWindow(url) {
410
+ const width = screen.width / 2;
411
+ const height = screen.height;
412
+ const left = screen.width / 4;
413
+ const top = 0;
414
+ window.open(
415
+ url.toString(),
416
+ "_blank",
417
+ `width=${width},height=${height},left=${left},top=${top}`
418
+ );
419
+ }
189
420
  export {
421
+ UWError,
190
422
  UnWallet
191
423
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unwallet-client-sdk",
3
- "version": "0.15.0",
3
+ "version": "0.17.0",
4
4
  "description": "unWallet client-side SDK",
5
5
  "license": "MIT",
6
6
  "author": "SIVIRA",
@@ -29,17 +29,20 @@
29
29
  }
30
30
  },
31
31
  "dependencies": {
32
- "ethers": "6.14.0"
32
+ "ethers": "6.14.1",
33
+ "lodash": "4.17.21",
34
+ "zod": "3.25.13"
33
35
  },
34
36
  "devDependencies": {
35
37
  "@commitlint/cli": "19.8.1",
36
38
  "@commitlint/config-conventional": "19.8.1",
37
39
  "@commitlint/types": "19.8.1",
38
40
  "@tsconfig/strictest": "2.0.5",
41
+ "@types/lodash": "4.17.17",
39
42
  "commitizen": "4.3.1",
40
43
  "cz-conventional-changelog": "3.3.0",
41
44
  "husky": "9.1.7",
42
- "tsup": "8.4.0"
45
+ "tsup": "8.5.0"
43
46
  },
44
47
  "scripts": {
45
48
  "build": "tsup",