unwallet-client-sdk 0.21.0 → 0.22.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.cjs CHANGED
@@ -6,72 +6,79 @@ var UWError = class extends Error {
6
6
  static {
7
7
  this.prototype.name = "UWError";
8
8
  }
9
- constructor(code, message) {
10
- super(message !== void 0 ? `${code}: ${message}` : code);
9
+ constructor(code, msg) {
10
+ super(msg !== void 0 ? `${code}: ${msg}` : code);
11
11
  this.code = code;
12
12
  }
13
13
  };
14
14
  //#endregion
15
15
  //#region src/config.ts
16
- function getUnWalletConfigByEnv(env) {
17
- switch (env) {
18
- case "prod": return {
19
- frontend: { baseURL: "https://id.unwallet.world" },
20
- xAPI: {
21
- url: "wss://xapi.id.unwallet.world",
22
- connectionTimeout: 1e4
23
- }
24
- };
25
- case "dev": return {
26
- frontend: { baseURL: "http://localhost:4200" },
27
- xAPI: {
28
- url: "wss://xapi.id.test.unwallet.dev",
29
- connectionTimeout: 1e4
30
- }
31
- };
16
+ const envToUnWalletConfig = {
17
+ prod: {
18
+ frontend: { origin: "https://id.unwallet.world" },
19
+ xAPI: {
20
+ url: "wss://xapi.id.unwallet.world",
21
+ connectionTimeout: 1e4
22
+ }
23
+ },
24
+ dev: {
25
+ frontend: { origin: "http://localhost:4200" },
26
+ xAPI: {
27
+ url: "wss://xapi.id.test.unwallet.dev",
28
+ connectionTimeout: 1e4
29
+ }
32
30
  }
33
- }
34
- const xRequestSchema = zod.z.object({ action: zod.z.enum(["getConnectionID"]) });
35
- zod.z.string().refine((val) => {
31
+ };
32
+ const xRequestSchema = zod.z.object({ action: zod.z.enum(["getConnectionID"]) }).readonly();
33
+ zod.z.string().transform((val, ctx) => {
36
34
  try {
37
- JSON.parse(val);
35
+ return JSON.parse(val);
38
36
  } catch {
39
- return false;
37
+ ctx.addIssue({
38
+ code: "custom",
39
+ message: "Invalid JSON string"
40
+ });
41
+ return zod.z.NEVER;
40
42
  }
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) => {
43
+ }).pipe(xRequestSchema);
44
+ const xResponseSchema = zod.z.union([
45
+ zod.z.object({
46
+ type: zod.z.literal("connectionID"),
47
+ value: zod.z.string().nonempty()
48
+ }),
49
+ zod.z.object({
50
+ type: zod.z.literal("signature"),
51
+ value: zod.z.string().refine(viem.isHex, { error: "Invalid hex" })
52
+ }),
53
+ zod.z.object({
54
+ type: zod.z.literal("transactionID"),
55
+ value: zod.z.string().nonempty()
56
+ }),
57
+ zod.z.object({
58
+ type: zod.z.literal("error"),
59
+ value: zod.z.string().nonempty()
60
+ })
61
+ ]).readonly();
62
+ const xResponsePayloadSchema = zod.z.string().transform((val, ctx) => {
56
63
  try {
57
- JSON.parse(val);
58
- } catch (e) {
59
- return false;
64
+ return JSON.parse(val);
65
+ } catch {
66
+ ctx.addIssue({
67
+ code: "custom",
68
+ message: "Invalid JSON string"
69
+ });
70
+ return zod.z.NEVER;
60
71
  }
61
- return true;
62
- }, {
63
- abort: true,
64
- message: "Invalid JSON string"
65
- }).transform((val) => JSON.parse(val)).pipe(xResponseSchema);
72
+ }).pipe(xResponseSchema);
66
73
  var XConnection = class XConnection {
67
74
  constructor(args) {
68
75
  this.responseHandler = null;
69
76
  this.id = args.id;
70
77
  this.socket = args.socket;
71
- this.options = args.options ?? {};
78
+ this.debugOptions = args.debugOptions ?? null;
72
79
  this.initListeners();
73
80
  }
74
- static async init(config, opts) {
81
+ static async init(config) {
75
82
  const socket = new WebSocket(config.url);
76
83
  const id = await new Promise((resolve, reject) => {
77
84
  const timeoutID = setTimeout(() => abortHandshake(new UWError("CONNECTION_TIMEOUT")), config.connectionTimeout);
@@ -115,14 +122,14 @@ var XConnection = class XConnection {
115
122
  return new XConnection({
116
123
  id,
117
124
  socket,
118
- options: opts
125
+ debugOptions: config.debug
119
126
  });
120
127
  }
121
128
  initListeners() {
122
129
  this.socket.onopen = null;
123
130
  this.socket.onmessage = (event) => {
124
131
  if (this.responseHandler === null) {
125
- this.options.debugHandlers?.onMessageEventDropped?.(event);
132
+ this.debugOptions?.handlers?.onMessageEventDropped?.(event);
126
133
  return;
127
134
  }
128
135
  let resp;
@@ -149,7 +156,7 @@ var XConnection = class XConnection {
149
156
  this.socket.onerror = null;
150
157
  this.socket.onclose = (event) => {
151
158
  if (this.responseHandler === null) {
152
- this.options.debugHandlers?.onCloseEventDropped?.(event);
159
+ this.debugOptions?.handlers?.onCloseEventDropped?.(event);
153
160
  return;
154
161
  }
155
162
  this.responseHandler.reject(newConnectionClosedError(event));
@@ -161,8 +168,8 @@ var XConnection = class XConnection {
161
168
  get hasResponseHandler() {
162
169
  return this.responseHandler !== null;
163
170
  }
164
- setResponseHandler(handler) {
165
- this.responseHandler = handler;
171
+ setResponseHandler(respHandler) {
172
+ this.responseHandler = respHandler;
166
173
  }
167
174
  close() {
168
175
  this.socket.close();
@@ -180,9 +187,10 @@ function safeParseXResponsePayload(data) {
180
187
  };
181
188
  }
182
189
  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);
190
+ const msgs = [];
191
+ msgs.push(`unexpected type: ${resp.type}`);
192
+ if (resp.type === "error") msgs.push(`(value: ${resp.value})`);
193
+ return new UWError("INVALID_RESPONSE", msgs.join(" "));
186
194
  }
187
195
  function newConnectionClosedError(event) {
188
196
  return new UWError("CONNECTION_CLOSED", event.reason.length > 0 ? event.reason : void 0);
@@ -200,14 +208,14 @@ var UnWallet = class UnWallet {
200
208
  return new UnWallet({
201
209
  env,
202
210
  clientID: config.clientID,
203
- xConnection: await XConnection.init(getUnWalletConfigByEnv(env).xAPI)
211
+ xConnection: await XConnection.init(envToUnWalletConfig[env].xAPI)
204
212
  });
205
213
  }
206
214
  get unWalletConfig() {
207
- return getUnWalletConfigByEnv(this.env);
215
+ return envToUnWalletConfig[this.env];
208
216
  }
209
217
  authorize(args) {
210
- const url = new URL(`${this.unWalletConfig.frontend.baseURL}/${args.isVirtual === false ? "" : "v"}authorize`);
218
+ const url = new URL(`/${args.isVirtual === false ? "" : "v"}authorize`, this.unWalletConfig.frontend.origin);
211
219
  url.searchParams.set("response_type", "id_token");
212
220
  url.searchParams.set("response_mode", args.responseMode ?? "fragment");
213
221
  url.searchParams.set("client_id", this.clientID);
@@ -217,90 +225,57 @@ var UnWallet = class UnWallet {
217
225
  if (args.chainID !== void 0) url.searchParams.set("chain_id", args.chainID.toString());
218
226
  location.assign(url);
219
227
  }
220
- sign(args) {
221
- return new Promise((resolve, reject) => {
222
- if (this.xConnection.readyState !== WebSocket.OPEN) {
223
- reject(new UWError("CONNECTION_NOT_OPENED"));
224
- return;
225
- }
226
- if (this.xConnection.hasResponseHandler) {
227
- reject(new UWError("REQUEST_IN_PROGRESS"));
228
- return;
229
- }
230
- const digest = (0, viem.sha256)((0, viem.toBytes)(args.message));
231
- this.xConnection.setResponseHandler({
232
- resolve: (resp) => {
233
- this.xConnection.setResponseHandler(null);
234
- if (resp.type !== "signature") {
235
- reject(newUnexpectedXResponseTypeError(resp));
236
- return;
237
- }
238
- resolve({
239
- digest,
240
- signature: resp.value
241
- });
242
- },
243
- reject: (err) => {
244
- this.xConnection.setResponseHandler(null);
245
- reject(err);
228
+ async sign(args) {
229
+ return {
230
+ digest: (0, viem.sha256)((0, viem.toBytes)(args.message)),
231
+ signature: await this.request({
232
+ responseType: "signature",
233
+ path: "/x/sign",
234
+ params: {
235
+ message: args.message,
236
+ ticketToken: args.ticketToken
246
237
  }
247
- });
248
- const url = new URL(`${this.unWalletConfig.frontend.baseURL}/x/sign`);
249
- url.searchParams.set("connectionID", this.xConnection.id);
250
- url.searchParams.set("clientID", this.clientID);
251
- url.searchParams.set("message", args.message);
252
- url.searchParams.set("ticketToken", args.ticketToken);
253
- openWindow(url);
254
- });
238
+ })
239
+ };
255
240
  }
256
- signEIP712TypedData(args) {
257
- return new Promise((resolve, reject) => {
258
- if (this.xConnection.readyState !== WebSocket.OPEN) {
259
- reject(new UWError("CONNECTION_NOT_OPENED"));
260
- return;
261
- }
262
- if (this.xConnection.hasResponseHandler) {
263
- reject(new UWError("REQUEST_IN_PROGRESS"));
264
- return;
265
- }
266
- const { EIP712Domain: _, ...typedDataTypes } = args.typedData.types;
267
- const typedData = {
268
- ...args.typedData,
269
- types: typedDataTypes
270
- };
271
- try {
272
- (0, viem.validateTypedData)(typedData);
273
- } catch (e) {
274
- reject(new UWError("INVALID_REQUEST", `invalid typed data: ${e instanceof viem.BaseError ? e.shortMessage : String(e)}`));
275
- return;
276
- }
277
- const digest = (0, viem.hashTypedData)(typedData);
278
- this.xConnection.setResponseHandler({
279
- resolve: (resp) => {
280
- this.xConnection.setResponseHandler(null);
281
- if (resp.type !== "signature") {
282
- reject(newUnexpectedXResponseTypeError(resp));
283
- return;
284
- }
285
- resolve({
286
- digest,
287
- signature: resp.value
288
- });
289
- },
290
- reject: (err) => {
291
- this.xConnection.setResponseHandler(null);
292
- reject(err);
241
+ async signEIP712TypedData(args) {
242
+ const { EIP712Domain: _, ...typedDataTypes } = args.typedData.types;
243
+ const typedData = {
244
+ ...args.typedData,
245
+ types: typedDataTypes
246
+ };
247
+ try {
248
+ (0, viem.validateTypedData)(typedData);
249
+ } catch (e) {
250
+ throw new UWError("INVALID_REQUEST", `invalid typed data: ${e instanceof viem.BaseError ? e.shortMessage : String(e)}`);
251
+ }
252
+ return {
253
+ digest: (0, viem.hashTypedData)(typedData),
254
+ signature: await this.request({
255
+ responseType: "signature",
256
+ path: "/x/signEIP712TypedData",
257
+ params: {
258
+ typedData: JSON.stringify(args.typedData),
259
+ ticketToken: args.ticketToken
293
260
  }
294
- });
295
- const url = new URL(`${this.unWalletConfig.frontend.baseURL}/x/signEIP712TypedData`);
296
- url.searchParams.set("connectionID", this.xConnection.id);
297
- url.searchParams.set("clientID", this.clientID);
298
- url.searchParams.set("typedData", JSON.stringify(args.typedData));
299
- url.searchParams.set("ticketToken", args.ticketToken);
300
- openWindow(url);
301
- });
261
+ })
262
+ };
263
+ }
264
+ async sendTransaction(args) {
265
+ if (args.value === void 0 && args.data === void 0) throw new UWError("INVALID_REQUEST", "either value or data is required");
266
+ return { transactionID: await this.request({
267
+ responseType: "transactionID",
268
+ path: "/x/sendTransaction",
269
+ params: {
270
+ chainID: args.chainID.toString(),
271
+ toAddress: args.toAddress,
272
+ value: args.value ?? "0x0",
273
+ data: args.data ?? "0x",
274
+ ticketToken: args.ticketToken
275
+ }
276
+ }) };
302
277
  }
303
- sendTransaction(args) {
278
+ request(args) {
304
279
  return new Promise((resolve, reject) => {
305
280
  if (this.xConnection.readyState !== WebSocket.OPEN) {
306
281
  reject(new UWError("CONNECTION_NOT_OPENED"));
@@ -310,45 +285,31 @@ var UnWallet = class UnWallet {
310
285
  reject(new UWError("REQUEST_IN_PROGRESS"));
311
286
  return;
312
287
  }
313
- if (args.value === void 0 && args.data === void 0) {
314
- reject(new UWError("INVALID_REQUEST", "either value or data is required"));
315
- return;
316
- }
317
288
  this.xConnection.setResponseHandler({
318
289
  resolve: (resp) => {
319
290
  this.xConnection.setResponseHandler(null);
320
- if (resp.type !== "transactionID") {
291
+ if (resp.type !== args.responseType) {
321
292
  reject(newUnexpectedXResponseTypeError(resp));
322
293
  return;
323
294
  }
324
- resolve({ transactionID: resp.value });
295
+ resolve(resp.value);
325
296
  },
326
297
  reject: (err) => {
327
298
  this.xConnection.setResponseHandler(null);
328
299
  reject(err);
329
300
  }
330
301
  });
331
- const url = new URL(`${this.unWalletConfig.frontend.baseURL}/x/sendTransaction`);
302
+ const url = new URL(args.path, this.unWalletConfig.frontend.origin);
332
303
  url.searchParams.set("connectionID", this.xConnection.id);
333
304
  url.searchParams.set("clientID", this.clientID);
334
- url.searchParams.set("chainID", args.chainID.toString());
335
- url.searchParams.set("toAddress", args.toAddress);
336
- url.searchParams.set("value", args.value ?? "0x0");
337
- url.searchParams.set("data", args.data ?? "0x");
338
- url.searchParams.set("ticketToken", args.ticketToken);
339
- openWindow(url);
305
+ for (const [key, value] of Object.entries(args.params)) url.searchParams.set(key, value);
306
+ window.open(url.toString());
340
307
  });
341
308
  }
342
309
  close() {
343
310
  this.xConnection.close();
344
311
  }
345
312
  };
346
- function openWindow(url) {
347
- const width = screen.width / 2;
348
- const height = screen.height;
349
- const left = screen.width / 4;
350
- window.open(url.toString(), "_blank", `width=${width},height=${height},left=${left},top=0`);
351
- }
352
313
  //#endregion
353
314
  exports.UWError = UWError;
354
315
  exports.UnWallet = UnWallet;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Address, Hex } from "viem";
1
+ import { Address, Hash, Hex } from "viem";
2
2
  import { z } from "zod";
3
3
  //#region src/config.d.ts
4
4
  type Env = "prod" | "dev";
@@ -34,91 +34,98 @@ interface EIP712TypedDataField {
34
34
  type UWErrorCode = "CONNECTION_TIMEOUT" | "CONNECTION_FAILED" | "CONNECTION_NOT_OPENED" | "CONNECTION_CLOSED" | "INVALID_REQUEST" | "REQUEST_IN_PROGRESS" | "REQUEST_REJECTED" | "INVALID_RESPONSE";
35
35
  declare class UWError extends Error {
36
36
  readonly code: UWErrorCode;
37
- constructor(code: UWErrorCode, message?: string);
37
+ constructor(code: UWErrorCode, msg?: string);
38
38
  }
39
39
  //#endregion
40
- //#region src/x.d.ts
41
- declare const xResponseSchema: z.ZodObject<{
42
- type: z.ZodEnum<{
43
- connectionID: "connectionID";
44
- error: "error";
45
- signature: "signature";
46
- transactionID: "transactionID";
47
- }>;
40
+ //#region src/xconn.d.ts
41
+ declare const xResponseSchema: z.ZodReadonly<z.ZodUnion<readonly [z.ZodObject<{
42
+ type: z.ZodLiteral<"connectionID">;
48
43
  value: z.ZodString;
49
- }, z.core.$strip>;
44
+ }, z.core.$strip>, z.ZodObject<{
45
+ type: z.ZodLiteral<"signature">;
46
+ value: z.ZodString & z.ZodType<`0x${string}`, string, z.core.$ZodTypeInternals<`0x${string}`, string>>;
47
+ }, z.core.$strip>, z.ZodObject<{
48
+ type: z.ZodLiteral<"transactionID">;
49
+ value: z.ZodString;
50
+ }, z.core.$strip>, z.ZodObject<{
51
+ type: z.ZodLiteral<"error">;
52
+ value: z.ZodString;
53
+ }, z.core.$strip>]>>;
50
54
  type XResponse = z.infer<typeof xResponseSchema>;
51
55
  type XResponseHandler = {
52
- resolve: (resp: XResponse) => void;
53
- reject: (err: UWError) => void;
56
+ readonly resolve: (resp: XResponse) => void;
57
+ readonly reject: (err: UWError) => void;
54
58
  };
55
- type XConnectionOptions = {
56
- debugHandlers?: XConnectionDebugHandlers;
59
+ type XConnectionDebugOptions = {
60
+ readonly handlers?: XConnectionDebugHandlers;
57
61
  };
58
62
  type XConnectionDebugHandlers = {
59
- onMessageEventDropped?: (event: MessageEvent) => void;
60
- onCloseEventDropped?: (event: CloseEvent) => void;
63
+ readonly onMessageEventDropped?: (event: MessageEvent) => void;
64
+ readonly onCloseEventDropped?: (event: CloseEvent) => void;
61
65
  };
62
66
  declare class XConnection {
63
67
  readonly id: string;
64
68
  private readonly socket;
65
- private readonly options;
69
+ private readonly debugOptions;
66
70
  private responseHandler;
67
71
  constructor(args: {
68
- id: string;
69
- socket: WebSocket;
70
- options?: XConnectionOptions | undefined;
72
+ readonly id: string;
73
+ readonly socket: WebSocket;
74
+ readonly debugOptions?: XConnectionDebugOptions | undefined;
71
75
  });
72
- static init(config: UnWalletXAPIConfig, opts?: XConnectionOptions): Promise<XConnection>;
76
+ static init(config: UnWalletXAPIConfig & {
77
+ readonly debug?: XConnectionDebugOptions | undefined;
78
+ }): Promise<XConnection>;
73
79
  private initListeners;
74
80
  get readyState(): number;
75
81
  get hasResponseHandler(): boolean;
76
- setResponseHandler(handler: XResponseHandler | null): void;
82
+ setResponseHandler(respHandler: XResponseHandler | null): void;
77
83
  close(): void;
78
84
  }
79
85
  //#endregion
80
86
  //#region src/unwallet.d.ts
81
87
  type AuthorizationResponseMode = "fragment" | "form_post";
82
88
  interface SignResult {
83
- digest: string;
84
- signature: string;
89
+ digest: Hash;
90
+ signature: Hex;
85
91
  }
86
92
  interface SendTransactionResult {
87
93
  transactionID: string;
88
94
  }
89
95
  declare class UnWallet {
90
- private env;
91
- private clientID;
92
- private xConnection;
96
+ private readonly env;
97
+ private readonly clientID;
98
+ private readonly xConnection;
93
99
  constructor(args: {
94
- env: Env;
95
- clientID: string;
96
- xConnection: XConnection;
100
+ readonly env: Env;
101
+ readonly clientID: string;
102
+ readonly xConnection: XConnection;
97
103
  });
98
104
  static init(config: Config): Promise<UnWallet>;
99
105
  private get unWalletConfig();
100
106
  authorize(args: {
101
- responseMode?: AuthorizationResponseMode;
102
- redirectURL: string;
103
- nonce?: string;
104
- isVirtual?: boolean;
105
- chainID?: number;
107
+ readonly responseMode?: AuthorizationResponseMode;
108
+ readonly redirectURL: string;
109
+ readonly nonce?: string;
110
+ readonly isVirtual?: boolean;
111
+ readonly chainID?: number;
106
112
  }): void;
107
113
  sign(args: {
108
- message: string;
109
- ticketToken: string;
114
+ readonly message: string;
115
+ readonly ticketToken: string;
110
116
  }): Promise<SignResult>;
111
117
  signEIP712TypedData(args: {
112
- typedData: EIP712TypedData;
113
- ticketToken: string;
118
+ readonly typedData: EIP712TypedData;
119
+ readonly ticketToken: string;
114
120
  }): Promise<SignResult>;
115
121
  sendTransaction(args: {
116
- chainID: number;
117
- toAddress: string;
118
- value?: string;
119
- data?: string;
120
- ticketToken: string;
122
+ readonly chainID: number;
123
+ readonly toAddress: string;
124
+ readonly value?: string;
125
+ readonly data?: string;
126
+ readonly ticketToken: string;
121
127
  }): Promise<SendTransactionResult>;
128
+ private request;
122
129
  close(): void;
123
130
  }
124
131
  //#endregion
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Address, Hex } from "viem";
1
+ import { Address, Hash, Hex } from "viem";
2
2
  import { z } from "zod";
3
3
  //#region src/config.d.ts
4
4
  type Env = "prod" | "dev";
@@ -34,91 +34,98 @@ interface EIP712TypedDataField {
34
34
  type UWErrorCode = "CONNECTION_TIMEOUT" | "CONNECTION_FAILED" | "CONNECTION_NOT_OPENED" | "CONNECTION_CLOSED" | "INVALID_REQUEST" | "REQUEST_IN_PROGRESS" | "REQUEST_REJECTED" | "INVALID_RESPONSE";
35
35
  declare class UWError extends Error {
36
36
  readonly code: UWErrorCode;
37
- constructor(code: UWErrorCode, message?: string);
37
+ constructor(code: UWErrorCode, msg?: string);
38
38
  }
39
39
  //#endregion
40
- //#region src/x.d.ts
41
- declare const xResponseSchema: z.ZodObject<{
42
- type: z.ZodEnum<{
43
- connectionID: "connectionID";
44
- error: "error";
45
- signature: "signature";
46
- transactionID: "transactionID";
47
- }>;
40
+ //#region src/xconn.d.ts
41
+ declare const xResponseSchema: z.ZodReadonly<z.ZodUnion<readonly [z.ZodObject<{
42
+ type: z.ZodLiteral<"connectionID">;
48
43
  value: z.ZodString;
49
- }, z.core.$strip>;
44
+ }, z.core.$strip>, z.ZodObject<{
45
+ type: z.ZodLiteral<"signature">;
46
+ value: z.ZodString & z.ZodType<`0x${string}`, string, z.core.$ZodTypeInternals<`0x${string}`, string>>;
47
+ }, z.core.$strip>, z.ZodObject<{
48
+ type: z.ZodLiteral<"transactionID">;
49
+ value: z.ZodString;
50
+ }, z.core.$strip>, z.ZodObject<{
51
+ type: z.ZodLiteral<"error">;
52
+ value: z.ZodString;
53
+ }, z.core.$strip>]>>;
50
54
  type XResponse = z.infer<typeof xResponseSchema>;
51
55
  type XResponseHandler = {
52
- resolve: (resp: XResponse) => void;
53
- reject: (err: UWError) => void;
56
+ readonly resolve: (resp: XResponse) => void;
57
+ readonly reject: (err: UWError) => void;
54
58
  };
55
- type XConnectionOptions = {
56
- debugHandlers?: XConnectionDebugHandlers;
59
+ type XConnectionDebugOptions = {
60
+ readonly handlers?: XConnectionDebugHandlers;
57
61
  };
58
62
  type XConnectionDebugHandlers = {
59
- onMessageEventDropped?: (event: MessageEvent) => void;
60
- onCloseEventDropped?: (event: CloseEvent) => void;
63
+ readonly onMessageEventDropped?: (event: MessageEvent) => void;
64
+ readonly onCloseEventDropped?: (event: CloseEvent) => void;
61
65
  };
62
66
  declare class XConnection {
63
67
  readonly id: string;
64
68
  private readonly socket;
65
- private readonly options;
69
+ private readonly debugOptions;
66
70
  private responseHandler;
67
71
  constructor(args: {
68
- id: string;
69
- socket: WebSocket;
70
- options?: XConnectionOptions | undefined;
72
+ readonly id: string;
73
+ readonly socket: WebSocket;
74
+ readonly debugOptions?: XConnectionDebugOptions | undefined;
71
75
  });
72
- static init(config: UnWalletXAPIConfig, opts?: XConnectionOptions): Promise<XConnection>;
76
+ static init(config: UnWalletXAPIConfig & {
77
+ readonly debug?: XConnectionDebugOptions | undefined;
78
+ }): Promise<XConnection>;
73
79
  private initListeners;
74
80
  get readyState(): number;
75
81
  get hasResponseHandler(): boolean;
76
- setResponseHandler(handler: XResponseHandler | null): void;
82
+ setResponseHandler(respHandler: XResponseHandler | null): void;
77
83
  close(): void;
78
84
  }
79
85
  //#endregion
80
86
  //#region src/unwallet.d.ts
81
87
  type AuthorizationResponseMode = "fragment" | "form_post";
82
88
  interface SignResult {
83
- digest: string;
84
- signature: string;
89
+ digest: Hash;
90
+ signature: Hex;
85
91
  }
86
92
  interface SendTransactionResult {
87
93
  transactionID: string;
88
94
  }
89
95
  declare class UnWallet {
90
- private env;
91
- private clientID;
92
- private xConnection;
96
+ private readonly env;
97
+ private readonly clientID;
98
+ private readonly xConnection;
93
99
  constructor(args: {
94
- env: Env;
95
- clientID: string;
96
- xConnection: XConnection;
100
+ readonly env: Env;
101
+ readonly clientID: string;
102
+ readonly xConnection: XConnection;
97
103
  });
98
104
  static init(config: Config): Promise<UnWallet>;
99
105
  private get unWalletConfig();
100
106
  authorize(args: {
101
- responseMode?: AuthorizationResponseMode;
102
- redirectURL: string;
103
- nonce?: string;
104
- isVirtual?: boolean;
105
- chainID?: number;
107
+ readonly responseMode?: AuthorizationResponseMode;
108
+ readonly redirectURL: string;
109
+ readonly nonce?: string;
110
+ readonly isVirtual?: boolean;
111
+ readonly chainID?: number;
106
112
  }): void;
107
113
  sign(args: {
108
- message: string;
109
- ticketToken: string;
114
+ readonly message: string;
115
+ readonly ticketToken: string;
110
116
  }): Promise<SignResult>;
111
117
  signEIP712TypedData(args: {
112
- typedData: EIP712TypedData;
113
- ticketToken: string;
118
+ readonly typedData: EIP712TypedData;
119
+ readonly ticketToken: string;
114
120
  }): Promise<SignResult>;
115
121
  sendTransaction(args: {
116
- chainID: number;
117
- toAddress: string;
118
- value?: string;
119
- data?: string;
120
- ticketToken: string;
122
+ readonly chainID: number;
123
+ readonly toAddress: string;
124
+ readonly value?: string;
125
+ readonly data?: string;
126
+ readonly ticketToken: string;
121
127
  }): Promise<SendTransactionResult>;
128
+ private request;
122
129
  close(): void;
123
130
  }
124
131
  //#endregion
package/dist/index.js CHANGED
@@ -1,76 +1,83 @@
1
- import { BaseError, hashTypedData, sha256, toBytes, validateTypedData } from "viem";
1
+ import { BaseError, hashTypedData, isHex, 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
5
  static {
6
6
  this.prototype.name = "UWError";
7
7
  }
8
- constructor(code, message) {
9
- super(message !== void 0 ? `${code}: ${message}` : code);
8
+ constructor(code, msg) {
9
+ super(msg !== void 0 ? `${code}: ${msg}` : code);
10
10
  this.code = code;
11
11
  }
12
12
  };
13
13
  //#endregion
14
14
  //#region src/config.ts
15
- function getUnWalletConfigByEnv(env) {
16
- switch (env) {
17
- case "prod": return {
18
- frontend: { baseURL: "https://id.unwallet.world" },
19
- xAPI: {
20
- url: "wss://xapi.id.unwallet.world",
21
- connectionTimeout: 1e4
22
- }
23
- };
24
- case "dev": return {
25
- frontend: { baseURL: "http://localhost:4200" },
26
- xAPI: {
27
- url: "wss://xapi.id.test.unwallet.dev",
28
- connectionTimeout: 1e4
29
- }
30
- };
15
+ const envToUnWalletConfig = {
16
+ prod: {
17
+ frontend: { origin: "https://id.unwallet.world" },
18
+ xAPI: {
19
+ url: "wss://xapi.id.unwallet.world",
20
+ connectionTimeout: 1e4
21
+ }
22
+ },
23
+ dev: {
24
+ frontend: { origin: "http://localhost:4200" },
25
+ xAPI: {
26
+ url: "wss://xapi.id.test.unwallet.dev",
27
+ connectionTimeout: 1e4
28
+ }
31
29
  }
32
- }
33
- const xRequestSchema = z.object({ action: z.enum(["getConnectionID"]) });
34
- z.string().refine((val) => {
30
+ };
31
+ const xRequestSchema = z.object({ action: z.enum(["getConnectionID"]) }).readonly();
32
+ z.string().transform((val, ctx) => {
35
33
  try {
36
- JSON.parse(val);
34
+ return JSON.parse(val);
37
35
  } catch {
38
- return false;
36
+ ctx.addIssue({
37
+ code: "custom",
38
+ message: "Invalid JSON string"
39
+ });
40
+ return z.NEVER;
39
41
  }
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) => {
42
+ }).pipe(xRequestSchema);
43
+ const xResponseSchema = z.union([
44
+ z.object({
45
+ type: z.literal("connectionID"),
46
+ value: z.string().nonempty()
47
+ }),
48
+ z.object({
49
+ type: z.literal("signature"),
50
+ value: z.string().refine(isHex, { error: "Invalid hex" })
51
+ }),
52
+ z.object({
53
+ type: z.literal("transactionID"),
54
+ value: z.string().nonempty()
55
+ }),
56
+ z.object({
57
+ type: z.literal("error"),
58
+ value: z.string().nonempty()
59
+ })
60
+ ]).readonly();
61
+ const xResponsePayloadSchema = z.string().transform((val, ctx) => {
55
62
  try {
56
- JSON.parse(val);
57
- } catch (e) {
58
- return false;
63
+ return JSON.parse(val);
64
+ } catch {
65
+ ctx.addIssue({
66
+ code: "custom",
67
+ message: "Invalid JSON string"
68
+ });
69
+ return z.NEVER;
59
70
  }
60
- return true;
61
- }, {
62
- abort: true,
63
- message: "Invalid JSON string"
64
- }).transform((val) => JSON.parse(val)).pipe(xResponseSchema);
71
+ }).pipe(xResponseSchema);
65
72
  var XConnection = class XConnection {
66
73
  constructor(args) {
67
74
  this.responseHandler = null;
68
75
  this.id = args.id;
69
76
  this.socket = args.socket;
70
- this.options = args.options ?? {};
77
+ this.debugOptions = args.debugOptions ?? null;
71
78
  this.initListeners();
72
79
  }
73
- static async init(config, opts) {
80
+ static async init(config) {
74
81
  const socket = new WebSocket(config.url);
75
82
  const id = await new Promise((resolve, reject) => {
76
83
  const timeoutID = setTimeout(() => abortHandshake(new UWError("CONNECTION_TIMEOUT")), config.connectionTimeout);
@@ -114,14 +121,14 @@ var XConnection = class XConnection {
114
121
  return new XConnection({
115
122
  id,
116
123
  socket,
117
- options: opts
124
+ debugOptions: config.debug
118
125
  });
119
126
  }
120
127
  initListeners() {
121
128
  this.socket.onopen = null;
122
129
  this.socket.onmessage = (event) => {
123
130
  if (this.responseHandler === null) {
124
- this.options.debugHandlers?.onMessageEventDropped?.(event);
131
+ this.debugOptions?.handlers?.onMessageEventDropped?.(event);
125
132
  return;
126
133
  }
127
134
  let resp;
@@ -148,7 +155,7 @@ var XConnection = class XConnection {
148
155
  this.socket.onerror = null;
149
156
  this.socket.onclose = (event) => {
150
157
  if (this.responseHandler === null) {
151
- this.options.debugHandlers?.onCloseEventDropped?.(event);
158
+ this.debugOptions?.handlers?.onCloseEventDropped?.(event);
152
159
  return;
153
160
  }
154
161
  this.responseHandler.reject(newConnectionClosedError(event));
@@ -160,8 +167,8 @@ var XConnection = class XConnection {
160
167
  get hasResponseHandler() {
161
168
  return this.responseHandler !== null;
162
169
  }
163
- setResponseHandler(handler) {
164
- this.responseHandler = handler;
170
+ setResponseHandler(respHandler) {
171
+ this.responseHandler = respHandler;
165
172
  }
166
173
  close() {
167
174
  this.socket.close();
@@ -179,9 +186,10 @@ function safeParseXResponsePayload(data) {
179
186
  };
180
187
  }
181
188
  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);
189
+ const msgs = [];
190
+ msgs.push(`unexpected type: ${resp.type}`);
191
+ if (resp.type === "error") msgs.push(`(value: ${resp.value})`);
192
+ return new UWError("INVALID_RESPONSE", msgs.join(" "));
185
193
  }
186
194
  function newConnectionClosedError(event) {
187
195
  return new UWError("CONNECTION_CLOSED", event.reason.length > 0 ? event.reason : void 0);
@@ -199,14 +207,14 @@ var UnWallet = class UnWallet {
199
207
  return new UnWallet({
200
208
  env,
201
209
  clientID: config.clientID,
202
- xConnection: await XConnection.init(getUnWalletConfigByEnv(env).xAPI)
210
+ xConnection: await XConnection.init(envToUnWalletConfig[env].xAPI)
203
211
  });
204
212
  }
205
213
  get unWalletConfig() {
206
- return getUnWalletConfigByEnv(this.env);
214
+ return envToUnWalletConfig[this.env];
207
215
  }
208
216
  authorize(args) {
209
- const url = new URL(`${this.unWalletConfig.frontend.baseURL}/${args.isVirtual === false ? "" : "v"}authorize`);
217
+ const url = new URL(`/${args.isVirtual === false ? "" : "v"}authorize`, this.unWalletConfig.frontend.origin);
210
218
  url.searchParams.set("response_type", "id_token");
211
219
  url.searchParams.set("response_mode", args.responseMode ?? "fragment");
212
220
  url.searchParams.set("client_id", this.clientID);
@@ -216,90 +224,57 @@ var UnWallet = class UnWallet {
216
224
  if (args.chainID !== void 0) url.searchParams.set("chain_id", args.chainID.toString());
217
225
  location.assign(url);
218
226
  }
219
- sign(args) {
220
- return new Promise((resolve, reject) => {
221
- if (this.xConnection.readyState !== WebSocket.OPEN) {
222
- reject(new UWError("CONNECTION_NOT_OPENED"));
223
- return;
224
- }
225
- if (this.xConnection.hasResponseHandler) {
226
- reject(new UWError("REQUEST_IN_PROGRESS"));
227
- return;
228
- }
229
- const digest = sha256(toBytes(args.message));
230
- this.xConnection.setResponseHandler({
231
- resolve: (resp) => {
232
- this.xConnection.setResponseHandler(null);
233
- if (resp.type !== "signature") {
234
- reject(newUnexpectedXResponseTypeError(resp));
235
- return;
236
- }
237
- resolve({
238
- digest,
239
- signature: resp.value
240
- });
241
- },
242
- reject: (err) => {
243
- this.xConnection.setResponseHandler(null);
244
- reject(err);
227
+ async sign(args) {
228
+ return {
229
+ digest: sha256(toBytes(args.message)),
230
+ signature: await this.request({
231
+ responseType: "signature",
232
+ path: "/x/sign",
233
+ params: {
234
+ message: args.message,
235
+ ticketToken: args.ticketToken
245
236
  }
246
- });
247
- const url = new URL(`${this.unWalletConfig.frontend.baseURL}/x/sign`);
248
- url.searchParams.set("connectionID", this.xConnection.id);
249
- url.searchParams.set("clientID", this.clientID);
250
- url.searchParams.set("message", args.message);
251
- url.searchParams.set("ticketToken", args.ticketToken);
252
- openWindow(url);
253
- });
237
+ })
238
+ };
254
239
  }
255
- signEIP712TypedData(args) {
256
- return new Promise((resolve, reject) => {
257
- if (this.xConnection.readyState !== WebSocket.OPEN) {
258
- reject(new UWError("CONNECTION_NOT_OPENED"));
259
- return;
260
- }
261
- if (this.xConnection.hasResponseHandler) {
262
- reject(new UWError("REQUEST_IN_PROGRESS"));
263
- return;
264
- }
265
- const { EIP712Domain: _, ...typedDataTypes } = args.typedData.types;
266
- const typedData = {
267
- ...args.typedData,
268
- types: typedDataTypes
269
- };
270
- try {
271
- validateTypedData(typedData);
272
- } catch (e) {
273
- reject(new UWError("INVALID_REQUEST", `invalid typed data: ${e instanceof BaseError ? e.shortMessage : String(e)}`));
274
- return;
275
- }
276
- const digest = hashTypedData(typedData);
277
- this.xConnection.setResponseHandler({
278
- resolve: (resp) => {
279
- this.xConnection.setResponseHandler(null);
280
- if (resp.type !== "signature") {
281
- reject(newUnexpectedXResponseTypeError(resp));
282
- return;
283
- }
284
- resolve({
285
- digest,
286
- signature: resp.value
287
- });
288
- },
289
- reject: (err) => {
290
- this.xConnection.setResponseHandler(null);
291
- reject(err);
240
+ async signEIP712TypedData(args) {
241
+ const { EIP712Domain: _, ...typedDataTypes } = args.typedData.types;
242
+ const typedData = {
243
+ ...args.typedData,
244
+ types: typedDataTypes
245
+ };
246
+ try {
247
+ validateTypedData(typedData);
248
+ } catch (e) {
249
+ throw new UWError("INVALID_REQUEST", `invalid typed data: ${e instanceof BaseError ? e.shortMessage : String(e)}`);
250
+ }
251
+ return {
252
+ digest: hashTypedData(typedData),
253
+ signature: await this.request({
254
+ responseType: "signature",
255
+ path: "/x/signEIP712TypedData",
256
+ params: {
257
+ typedData: JSON.stringify(args.typedData),
258
+ ticketToken: args.ticketToken
292
259
  }
293
- });
294
- const url = new URL(`${this.unWalletConfig.frontend.baseURL}/x/signEIP712TypedData`);
295
- url.searchParams.set("connectionID", this.xConnection.id);
296
- url.searchParams.set("clientID", this.clientID);
297
- url.searchParams.set("typedData", JSON.stringify(args.typedData));
298
- url.searchParams.set("ticketToken", args.ticketToken);
299
- openWindow(url);
300
- });
260
+ })
261
+ };
262
+ }
263
+ async sendTransaction(args) {
264
+ if (args.value === void 0 && args.data === void 0) throw new UWError("INVALID_REQUEST", "either value or data is required");
265
+ return { transactionID: await this.request({
266
+ responseType: "transactionID",
267
+ path: "/x/sendTransaction",
268
+ params: {
269
+ chainID: args.chainID.toString(),
270
+ toAddress: args.toAddress,
271
+ value: args.value ?? "0x0",
272
+ data: args.data ?? "0x",
273
+ ticketToken: args.ticketToken
274
+ }
275
+ }) };
301
276
  }
302
- sendTransaction(args) {
277
+ request(args) {
303
278
  return new Promise((resolve, reject) => {
304
279
  if (this.xConnection.readyState !== WebSocket.OPEN) {
305
280
  reject(new UWError("CONNECTION_NOT_OPENED"));
@@ -309,44 +284,30 @@ var UnWallet = class UnWallet {
309
284
  reject(new UWError("REQUEST_IN_PROGRESS"));
310
285
  return;
311
286
  }
312
- if (args.value === void 0 && args.data === void 0) {
313
- reject(new UWError("INVALID_REQUEST", "either value or data is required"));
314
- return;
315
- }
316
287
  this.xConnection.setResponseHandler({
317
288
  resolve: (resp) => {
318
289
  this.xConnection.setResponseHandler(null);
319
- if (resp.type !== "transactionID") {
290
+ if (resp.type !== args.responseType) {
320
291
  reject(newUnexpectedXResponseTypeError(resp));
321
292
  return;
322
293
  }
323
- resolve({ transactionID: resp.value });
294
+ resolve(resp.value);
324
295
  },
325
296
  reject: (err) => {
326
297
  this.xConnection.setResponseHandler(null);
327
298
  reject(err);
328
299
  }
329
300
  });
330
- const url = new URL(`${this.unWalletConfig.frontend.baseURL}/x/sendTransaction`);
301
+ const url = new URL(args.path, this.unWalletConfig.frontend.origin);
331
302
  url.searchParams.set("connectionID", this.xConnection.id);
332
303
  url.searchParams.set("clientID", this.clientID);
333
- url.searchParams.set("chainID", args.chainID.toString());
334
- url.searchParams.set("toAddress", args.toAddress);
335
- url.searchParams.set("value", args.value ?? "0x0");
336
- url.searchParams.set("data", args.data ?? "0x");
337
- url.searchParams.set("ticketToken", args.ticketToken);
338
- openWindow(url);
304
+ for (const [key, value] of Object.entries(args.params)) url.searchParams.set(key, value);
305
+ window.open(url.toString());
339
306
  });
340
307
  }
341
308
  close() {
342
309
  this.xConnection.close();
343
310
  }
344
311
  };
345
- function openWindow(url) {
346
- const width = screen.width / 2;
347
- const height = screen.height;
348
- const left = screen.width / 4;
349
- window.open(url.toString(), "_blank", `width=${width},height=${height},left=${left},top=0`);
350
- }
351
312
  //#endregion
352
313
  export { UWError, UnWallet };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unwallet-client-sdk",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "unWallet client-side SDK",
5
5
  "license": "MIT",
6
6
  "author": "SIVIRA",
@@ -29,7 +29,7 @@
29
29
  "url": "git+https://github.com/SIVIRA/unwallet-client-sdk-js.git"
30
30
  },
31
31
  "dependencies": {
32
- "viem": "2.55.10",
32
+ "viem": "2.55.11",
33
33
  "zod": "4.4.3"
34
34
  },
35
35
  "devDependencies": {