@bananalink-test/client 0.8.1 → 0.9.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
@@ -221,6 +221,8 @@ var SessionClosedError = class extends BananalinkError {
221
221
  //#region src/core/BananalinkSession.ts
222
222
  var BananalinkSession = class BananalinkSession {
223
223
  static REQUEST_TIMEOUT_MS = 600 * 1e3;
224
+ static CREATE_DAPP_MESSAGE_MAX_ATTEMPTS = 3;
225
+ static CREATE_DAPP_MESSAGE_BASE_DELAY_MS = 1e3;
224
226
  pendingRequests = /* @__PURE__ */ new Map();
225
227
  stopListening;
226
228
  stopListeningOnClose;
@@ -244,10 +246,10 @@ var BananalinkSession = class BananalinkSession {
244
246
  }
245
247
  async request({ method, params, timeoutMs = BananalinkSession.REQUEST_TIMEOUT_MS }) {
246
248
  if (this.closed) throw new SessionClosedError();
247
- const { messageId } = await createDappMessage(this.apiUrl, this.sessionClaims.accessToken, {
249
+ const { messageId } = await (0, _bananalink_test_sdk_core.withBackoff)(async () => await createDappMessage(this.apiUrl, this.sessionClaims.accessToken, {
248
250
  method,
249
251
  payload: params
250
- });
252
+ }), BananalinkSession.CREATE_DAPP_MESSAGE_MAX_ATTEMPTS, BananalinkSession.CREATE_DAPP_MESSAGE_BASE_DELAY_MS);
251
253
  if (this.closed) throw new SessionClosedError();
252
254
  return new Promise((resolve, reject) => {
253
255
  let timeout;
@@ -366,7 +368,7 @@ var BananalinkConnection = class BananalinkConnection {
366
368
  async resumeSession(jwt, abortSignal) {
367
369
  return await this.openSession(async () => ({
368
370
  ...jwt.jwtPayload,
369
- accessToken: jwt.rawJwt
371
+ accessToken: jwt.accessToken
370
372
  }), abortSignal);
371
373
  }
372
374
  async waitForAuthorization(abortSignal) {
@@ -388,13 +390,13 @@ var BananalinkConnection = class BananalinkConnection {
388
390
  throw new BananalinkError("Unable to establish dapp websocket connection", { cause: error });
389
391
  }
390
392
  }
391
- async bind(ws, jwt, abortSignal) {
393
+ async bind(ws, accessToken, abortSignal) {
392
394
  const bindPromise = this.raceEvent(ws, (payload, resolve, reject) => {
393
395
  if ((0, _bananalink_test_sdk_core.isBindResponseMessage)(payload)) payload.type === "bind_success" ? resolve() : reject(new InvalidJwtError());
394
396
  }, BananalinkConnection.BIND_RESPONSE_TIMEOUT_MILLIS, abortSignal);
395
397
  ws.send({
396
398
  type: "bind",
397
- jwt
399
+ jwt: accessToken
398
400
  });
399
401
  await bindPromise;
400
402
  }
@@ -445,8 +447,8 @@ var BananalinkClient = class BananalinkClient {
445
447
  this.jwks = createBananalinkJwks(this.apiUrl);
446
448
  }
447
449
  async connect(opts) {
448
- const rawJwt = opts?.jwt;
449
- if (!rawJwt) {
450
+ const accessToken = opts?.accessToken;
451
+ if (!accessToken) {
450
452
  const { dappInstanceId, nonce } = await this.connectDappInstance();
451
453
  return new BananalinkConnection({
452
454
  jwt: void 0,
@@ -457,12 +459,12 @@ var BananalinkClient = class BananalinkClient {
457
459
  wsUrl: this.wsUrl
458
460
  });
459
461
  }
460
- const jwtPayload = await this.getJwtPayload(rawJwt);
462
+ const jwtPayload = await this.getJwtPayload(accessToken);
461
463
  if (!jwtPayload) throw new InvalidJwtError();
462
464
  return new BananalinkConnection({
463
465
  jwt: {
464
466
  jwtPayload,
465
- rawJwt
467
+ accessToken
466
468
  },
467
469
  dappId: this.dapp.dappId,
468
470
  dappInstanceId: null,
@@ -471,8 +473,8 @@ var BananalinkClient = class BananalinkClient {
471
473
  wsUrl: this.wsUrl
472
474
  });
473
475
  }
474
- async getJwtPayload(rawJwt) {
475
- return await verifyJwt(rawJwt, this.jwks);
476
+ async getJwtPayload(accessToken) {
477
+ return await verifyJwt(accessToken, this.jwks);
476
478
  }
477
479
  async connectDappInstance() {
478
480
  return await createDappInstance(this.apiUrl, this.dapp);
package/dist/index.d.cts CHANGED
@@ -1,5 +1,10 @@
1
1
  import { Dapp, Dapp as Dapp$1, EthSendTransactionParams, EthSendTransactionParams as EthSendTransactionParams$1, EthSendTransactionResult, TransportHandle } from "@bananalink-test/sdk-core";
2
2
 
3
+ //#region src/types/ConnectOpts.d.ts
4
+ type ConnectOpts = {
5
+ accessToken?: string;
6
+ };
7
+ //#endregion
3
8
  //#region src/types/JwtPayload.d.ts
4
9
  type JwtPayload = {
5
10
  address: string;
@@ -40,6 +45,8 @@ declare class BananalinkSession {
40
45
  private readonly ws;
41
46
  private readonly apiUrl;
42
47
  private static readonly REQUEST_TIMEOUT_MS;
48
+ private static readonly CREATE_DAPP_MESSAGE_MAX_ATTEMPTS;
49
+ private static readonly CREATE_DAPP_MESSAGE_BASE_DELAY_MS;
43
50
  private readonly pendingRequests;
44
51
  private readonly stopListening;
45
52
  private readonly stopListeningOnClose;
@@ -64,7 +71,7 @@ declare class BananalinkSession {
64
71
  //#region src/core/BananalinkConnection.d.ts
65
72
  type BananalinkDappJwt = {
66
73
  jwtPayload: JwtPayload;
67
- rawJwt: string;
74
+ accessToken: string;
68
75
  } | undefined;
69
76
  declare class BananalinkConnection {
70
77
  private static readonly AUTH_TIMEOUT_MILLIS;
@@ -109,9 +116,7 @@ declare class BananalinkClient {
109
116
  wsUrl?: string;
110
117
  dapp: Dapp$1;
111
118
  });
112
- connect(opts?: {
113
- jwt: string;
114
- }): Promise<BananalinkConnection>;
119
+ connect(opts?: ConnectOpts): Promise<BananalinkConnection>;
115
120
  private getJwtPayload;
116
121
  private connectDappInstance;
117
122
  }
@@ -177,5 +182,5 @@ declare class SessionClosedError extends BananalinkError {
177
182
  //#region src/utils/displayBananalinkQR.d.ts
178
183
  declare function displayBananalinkQR(url: string): Promise<string>;
179
184
  //#endregion
180
- export { BananalinkClient, BananalinkConnection, BananalinkError, BananalinkSession, ConnectionRejectedError, ConnectionTimeoutError, type Dapp, DappApiError, type EthSendTransactionParams, type EthSendTransactionResult, InvalidConfigError, InvalidConnectionStateError, InvalidJwtError, PendingSessionAbortedError, type Request, type RequestMap, type RequestParams, RequestRejectedError, type RequestResult, RequestTimeoutError, SessionClosedError, displayBananalinkQR };
185
+ export { BananalinkClient, BananalinkConnection, BananalinkError, BananalinkSession, type ConnectOpts, ConnectionRejectedError, ConnectionTimeoutError, type Dapp, DappApiError, type EthSendTransactionParams, type EthSendTransactionResult, InvalidConfigError, InvalidConnectionStateError, InvalidJwtError, PendingSessionAbortedError, type Request, type RequestMap, type RequestParams, RequestRejectedError, type RequestResult, RequestTimeoutError, SessionClosedError, displayBananalinkQR };
181
186
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/JwtPayload.ts","../src/types/RequestMap.ts","../src/types/Request.ts","../src/types/RequestParams.ts","../src/types/RequestResult.ts","../src/types/SessionClaims.ts","../src/core/BananalinkSession.ts","../src/core/BananalinkConnection.ts","../src/core/BananalinkClient.ts","../src/errors/BananalinkError.ts","../src/errors/ConnectionRejectedError.ts","../src/errors/ConnectionTimeoutError.ts","../src/errors/DappApiError.ts","../src/errors/InvalidConfigError.ts","../src/errors/InvalidConnectionStateError.ts","../src/errors/InvalidJwtError.ts","../src/errors/PendingSessionAbortedError.ts","../src/errors/RequestRejectedError.ts","../src/errors/RequestTimeoutError.ts","../src/errors/SessionClosedError.ts","../src/utils/displayBananalinkQR.ts"],"mappings":";;;KAAY,UAAA;EAAe,OAAA;EAAiB,MAAA;EAAgB,OAAA;EAAiB,SAAA;EAAmB,GAAA;AAAA;;;KCEpF,UAAA;EACV,mBAAA;IAAuB,MAAA,GAAS,0BAAA;IAA2B,MAAA;EAAA;AAAA;;;KCDjD,OAAA,SAAgB,UAAA;;;KCAhB,aAAA,iBAA8B,UAAA,IAAc,UAAA,CAAW,CAAA;;;KCAvD,aAAA,iBAA8B,UAAA,IAAc,UAAA,CAAW,CAAA;;;KCFvD,aAAA;EAAkB,OAAA;EAAiB,OAAA;EAAiB,SAAA;EAAmB,WAAA;AAAA;;;cCatE,iBAAA;EAAA,SAiBO,aAAA,EAAe,aAAA;EAAA,iBACd,EAAA;EAAA,iBACA,MAAA;EAAA,wBAlBK,kBAAA;EAAA,iBACP,eAAA;EAAA,iBACA,aAAA;EAAA,iBACA,oBAAA;EAAA,QACT,MAAA;EAAA,wBAEgB,eAAA;cAUN,aAAA,EAAe,aAAA,EACd,EAAA,EAAI,eAAA,EACJ,MAAA;EAcN,OAAA,WAAkB,OAAA,CAAA,CAAA;IAC7B,MAAA;IACA,MAAA;IACA;EAAA;IAEA,MAAA,EAAQ,CAAA;IACR,MAAA,GAAS,aAAA,CAAc,CAAA;IACvB,SAAA;EAAA,IACE,OAAA,CAAQ,aAAA,CAAc,CAAA;EAyCnB,KAAA,CAAA;EAAA,QAQC,qBAAA;EAAA,QASA,OAAA;EAAA,QAMA,wBAAA;AAAA;;;KClGL,iBAAA;EAAsB,UAAA,EAAY,UAAA;EAAY,MAAA;AAAA;AAAA,cAEtC,oBAAA;EAAA,wBACa,mBAAA;EAAA,wBACA,4BAAA;EAAA,iBACP,MAAA;EAAA,iBACA,KAAA;EAAA,iBACA,GAAA;EAAA,iBACA,MAAA;EAAA,iBACA,cAAA;EAAA,iBACA,KAAA;EAAA,QACT,qBAAA;EAAA,QACA,6BAAA;cAEI,IAAA;IACV,MAAA;IACA,KAAA;IACA,GAAA,EAAK,iBAAA;IACL,MAAA;IACA,cAAA;IACA,KAAA;EAAA;EAAA,IAeS,aAAA,CAAA;EASJ,mBAAA,CAAA;EAIM,UAAA,CAAA,GAAc,OAAA,CAAQ,iBAAA;EAAA,QAgBrB,WAAA;EAAA,QA6BA,aAAA;EAAA,QAOA,oBAAA;EAAA,QAgBA,kBAAA;EAAA,QAcA,IAAA;EAAA,QAgBA,SAAA;AAAA;;;cC5JH,gBAAA;EAAA,iBACM,MAAA;EAAA,iBACA,KAAA;EAAA,iBACA,IAAA;EAAA,iBACA,IAAA;EAAA,wBACO,0BAAA;EAAA,wBACA,yBAAA;cAEZ,MAAA;IACV,MAAA;IACA,KAAA;IACA,IAAA,EAAM,MAAA;EAAA;EAcK,OAAA,CAAQ,IAAA;IAAS,GAAA;EAAA,IAAgB,OAAA,CAAQ,oBAAA;EAAA,QA6BxC,aAAA;EAAA,QAIA,mBAAA;AAAA;;;cCpEH,eAAA,SAAwB,KAAA;cACvB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;;;cCC5B,uBAAA,SAAgC,eAAA;EAAA,WAAA,CAAA;AAAA;;;cCAhC,sBAAA,SAA+B,eAAA;EAAA,WAAA,CAAA;AAAA;;;cCA/B,YAAA,SAAqB,eAAA;EAAA,SAGd,UAAA;cADhB,OAAA,UACgB,UAAA;AAAA;;;cCHP,kBAAA,SAA2B,eAAA;cAC1B,OAAA;AAAA;;;cCDD,2BAAA,SAAoC,eAAA;cACnC,OAAA;AAAA;;;cCDD,eAAA,SAAwB,eAAA;EAAA,WAAA,CAAA;AAAA;;;cCAxB,0BAAA,SAAmC,eAAA;EAAA,WAAA,CAAA;AAAA;;;cCAnC,oBAAA,SAA6B,eAAA;EAAA,SACZ,SAAA;cAAA,SAAA;AAAA;;;cCAjB,mBAAA,SAA4B,eAAA;EAAA,SACX,MAAA,EAAQ,OAAA;cAAR,MAAA,EAAQ,OAAA;AAAA;;;cCFzB,kBAAA,SAA2B,eAAA;EAAA,WAAA,CAAA;AAAA;;;iBCElB,mBAAA,CAAoB,GAAA,WAAc,OAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/ConnectOpts.ts","../src/types/JwtPayload.ts","../src/types/RequestMap.ts","../src/types/Request.ts","../src/types/RequestParams.ts","../src/types/RequestResult.ts","../src/types/SessionClaims.ts","../src/core/BananalinkSession.ts","../src/core/BananalinkConnection.ts","../src/core/BananalinkClient.ts","../src/errors/BananalinkError.ts","../src/errors/ConnectionRejectedError.ts","../src/errors/ConnectionTimeoutError.ts","../src/errors/DappApiError.ts","../src/errors/InvalidConfigError.ts","../src/errors/InvalidConnectionStateError.ts","../src/errors/InvalidJwtError.ts","../src/errors/PendingSessionAbortedError.ts","../src/errors/RequestRejectedError.ts","../src/errors/RequestTimeoutError.ts","../src/errors/SessionClosedError.ts","../src/utils/displayBananalinkQR.ts"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,10 @@
1
1
  import { Dapp, Dapp as Dapp$1, EthSendTransactionParams, EthSendTransactionParams as EthSendTransactionParams$1, EthSendTransactionResult, TransportHandle } from "@bananalink-test/sdk-core";
2
2
 
3
+ //#region src/types/ConnectOpts.d.ts
4
+ type ConnectOpts = {
5
+ accessToken?: string;
6
+ };
7
+ //#endregion
3
8
  //#region src/types/JwtPayload.d.ts
4
9
  type JwtPayload = {
5
10
  address: string;
@@ -40,6 +45,8 @@ declare class BananalinkSession {
40
45
  private readonly ws;
41
46
  private readonly apiUrl;
42
47
  private static readonly REQUEST_TIMEOUT_MS;
48
+ private static readonly CREATE_DAPP_MESSAGE_MAX_ATTEMPTS;
49
+ private static readonly CREATE_DAPP_MESSAGE_BASE_DELAY_MS;
43
50
  private readonly pendingRequests;
44
51
  private readonly stopListening;
45
52
  private readonly stopListeningOnClose;
@@ -64,7 +71,7 @@ declare class BananalinkSession {
64
71
  //#region src/core/BananalinkConnection.d.ts
65
72
  type BananalinkDappJwt = {
66
73
  jwtPayload: JwtPayload;
67
- rawJwt: string;
74
+ accessToken: string;
68
75
  } | undefined;
69
76
  declare class BananalinkConnection {
70
77
  private static readonly AUTH_TIMEOUT_MILLIS;
@@ -109,9 +116,7 @@ declare class BananalinkClient {
109
116
  wsUrl?: string;
110
117
  dapp: Dapp$1;
111
118
  });
112
- connect(opts?: {
113
- jwt: string;
114
- }): Promise<BananalinkConnection>;
119
+ connect(opts?: ConnectOpts): Promise<BananalinkConnection>;
115
120
  private getJwtPayload;
116
121
  private connectDappInstance;
117
122
  }
@@ -177,5 +182,5 @@ declare class SessionClosedError extends BananalinkError {
177
182
  //#region src/utils/displayBananalinkQR.d.ts
178
183
  declare function displayBananalinkQR(url: string): Promise<string>;
179
184
  //#endregion
180
- export { BananalinkClient, BananalinkConnection, BananalinkError, BananalinkSession, ConnectionRejectedError, ConnectionTimeoutError, type Dapp, DappApiError, type EthSendTransactionParams, type EthSendTransactionResult, InvalidConfigError, InvalidConnectionStateError, InvalidJwtError, PendingSessionAbortedError, type Request, type RequestMap, type RequestParams, RequestRejectedError, type RequestResult, RequestTimeoutError, SessionClosedError, displayBananalinkQR };
185
+ export { BananalinkClient, BananalinkConnection, BananalinkError, BananalinkSession, type ConnectOpts, ConnectionRejectedError, ConnectionTimeoutError, type Dapp, DappApiError, type EthSendTransactionParams, type EthSendTransactionResult, InvalidConfigError, InvalidConnectionStateError, InvalidJwtError, PendingSessionAbortedError, type Request, type RequestMap, type RequestParams, RequestRejectedError, type RequestResult, RequestTimeoutError, SessionClosedError, displayBananalinkQR };
181
186
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/JwtPayload.ts","../src/types/RequestMap.ts","../src/types/Request.ts","../src/types/RequestParams.ts","../src/types/RequestResult.ts","../src/types/SessionClaims.ts","../src/core/BananalinkSession.ts","../src/core/BananalinkConnection.ts","../src/core/BananalinkClient.ts","../src/errors/BananalinkError.ts","../src/errors/ConnectionRejectedError.ts","../src/errors/ConnectionTimeoutError.ts","../src/errors/DappApiError.ts","../src/errors/InvalidConfigError.ts","../src/errors/InvalidConnectionStateError.ts","../src/errors/InvalidJwtError.ts","../src/errors/PendingSessionAbortedError.ts","../src/errors/RequestRejectedError.ts","../src/errors/RequestTimeoutError.ts","../src/errors/SessionClosedError.ts","../src/utils/displayBananalinkQR.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/ConnectOpts.ts","../src/types/JwtPayload.ts","../src/types/RequestMap.ts","../src/types/Request.ts","../src/types/RequestParams.ts","../src/types/RequestResult.ts","../src/types/SessionClaims.ts","../src/core/BananalinkSession.ts","../src/core/BananalinkConnection.ts","../src/core/BananalinkClient.ts","../src/errors/BananalinkError.ts","../src/errors/ConnectionRejectedError.ts","../src/errors/ConnectionTimeoutError.ts","../src/errors/DappApiError.ts","../src/errors/InvalidConfigError.ts","../src/errors/InvalidConnectionStateError.ts","../src/errors/InvalidJwtError.ts","../src/errors/PendingSessionAbortedError.ts","../src/errors/RequestRejectedError.ts","../src/errors/RequestTimeoutError.ts","../src/errors/SessionClosedError.ts","../src/utils/displayBananalinkQR.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRemoteJWKSet, jwtVerify } from "jose";
2
- import { connectWebSocket, createReconnectingTransport, isAuthorizedMessage, isBindResponseMessage, isMessageResponseMessage, isRejectedMessage } from "@bananalink-test/sdk-core";
2
+ import { connectWebSocket, createReconnectingTransport, isAuthorizedMessage, isBindResponseMessage, isMessageResponseMessage, isRejectedMessage, withBackoff } from "@bananalink-test/sdk-core";
3
3
  import QRCode from "qrcode";
4
4
 
5
5
  //#region src/errors/BananalinkError.ts
@@ -192,6 +192,8 @@ var SessionClosedError = class extends BananalinkError {
192
192
  //#region src/core/BananalinkSession.ts
193
193
  var BananalinkSession = class BananalinkSession {
194
194
  static REQUEST_TIMEOUT_MS = 600 * 1e3;
195
+ static CREATE_DAPP_MESSAGE_MAX_ATTEMPTS = 3;
196
+ static CREATE_DAPP_MESSAGE_BASE_DELAY_MS = 1e3;
195
197
  pendingRequests = /* @__PURE__ */ new Map();
196
198
  stopListening;
197
199
  stopListeningOnClose;
@@ -215,10 +217,10 @@ var BananalinkSession = class BananalinkSession {
215
217
  }
216
218
  async request({ method, params, timeoutMs = BananalinkSession.REQUEST_TIMEOUT_MS }) {
217
219
  if (this.closed) throw new SessionClosedError();
218
- const { messageId } = await createDappMessage(this.apiUrl, this.sessionClaims.accessToken, {
220
+ const { messageId } = await withBackoff(async () => await createDappMessage(this.apiUrl, this.sessionClaims.accessToken, {
219
221
  method,
220
222
  payload: params
221
- });
223
+ }), BananalinkSession.CREATE_DAPP_MESSAGE_MAX_ATTEMPTS, BananalinkSession.CREATE_DAPP_MESSAGE_BASE_DELAY_MS);
222
224
  if (this.closed) throw new SessionClosedError();
223
225
  return new Promise((resolve, reject) => {
224
226
  let timeout;
@@ -337,7 +339,7 @@ var BananalinkConnection = class BananalinkConnection {
337
339
  async resumeSession(jwt, abortSignal) {
338
340
  return await this.openSession(async () => ({
339
341
  ...jwt.jwtPayload,
340
- accessToken: jwt.rawJwt
342
+ accessToken: jwt.accessToken
341
343
  }), abortSignal);
342
344
  }
343
345
  async waitForAuthorization(abortSignal) {
@@ -359,13 +361,13 @@ var BananalinkConnection = class BananalinkConnection {
359
361
  throw new BananalinkError("Unable to establish dapp websocket connection", { cause: error });
360
362
  }
361
363
  }
362
- async bind(ws, jwt, abortSignal) {
364
+ async bind(ws, accessToken, abortSignal) {
363
365
  const bindPromise = this.raceEvent(ws, (payload, resolve, reject) => {
364
366
  if (isBindResponseMessage(payload)) payload.type === "bind_success" ? resolve() : reject(new InvalidJwtError());
365
367
  }, BananalinkConnection.BIND_RESPONSE_TIMEOUT_MILLIS, abortSignal);
366
368
  ws.send({
367
369
  type: "bind",
368
- jwt
370
+ jwt: accessToken
369
371
  });
370
372
  await bindPromise;
371
373
  }
@@ -416,8 +418,8 @@ var BananalinkClient = class BananalinkClient {
416
418
  this.jwks = createBananalinkJwks(this.apiUrl);
417
419
  }
418
420
  async connect(opts) {
419
- const rawJwt = opts?.jwt;
420
- if (!rawJwt) {
421
+ const accessToken = opts?.accessToken;
422
+ if (!accessToken) {
421
423
  const { dappInstanceId, nonce } = await this.connectDappInstance();
422
424
  return new BananalinkConnection({
423
425
  jwt: void 0,
@@ -428,12 +430,12 @@ var BananalinkClient = class BananalinkClient {
428
430
  wsUrl: this.wsUrl
429
431
  });
430
432
  }
431
- const jwtPayload = await this.getJwtPayload(rawJwt);
433
+ const jwtPayload = await this.getJwtPayload(accessToken);
432
434
  if (!jwtPayload) throw new InvalidJwtError();
433
435
  return new BananalinkConnection({
434
436
  jwt: {
435
437
  jwtPayload,
436
- rawJwt
438
+ accessToken
437
439
  },
438
440
  dappId: this.dapp.dappId,
439
441
  dappInstanceId: null,
@@ -442,8 +444,8 @@ var BananalinkClient = class BananalinkClient {
442
444
  wsUrl: this.wsUrl
443
445
  });
444
446
  }
445
- async getJwtPayload(rawJwt) {
446
- return await verifyJwt(rawJwt, this.jwks);
447
+ async getJwtPayload(accessToken) {
448
+ return await verifyJwt(accessToken, this.jwks);
447
449
  }
448
450
  async connectDappInstance() {
449
451
  return await createDappInstance(this.apiUrl, this.dapp);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/errors/BananalinkError.ts","../src/errors/DappApiError.ts","../src/api/createDappInstance.ts","../src/errors/InvalidConfigError.ts","../src/errors/InvalidJwtError.ts","../src/jwt/createBananalinkJwks.ts","../src/jwt/verifyJwt.ts","../src/utils/isValidUrl.ts","../src/errors/ConnectionRejectedError.ts","../src/errors/ConnectionTimeoutError.ts","../src/errors/InvalidConnectionStateError.ts","../src/errors/PendingSessionAbortedError.ts","../src/api/createDappMessage.ts","../src/errors/RequestRejectedError.ts","../src/errors/RequestTimeoutError.ts","../src/errors/SessionClosedError.ts","../src/core/BananalinkSession.ts","../src/core/BananalinkConnection.ts","../src/core/BananalinkClient.ts","../src/errors/InvalidUrlError.ts","../src/utils/displayBananalinkQR.ts"],"sourcesContent":["export class BananalinkError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'BananalinkError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class DappApiError extends BananalinkError {\n constructor(\n message: string,\n public readonly statusCode: number,\n ) {\n super(message);\n this.name = 'DappApiError';\n }\n}\n","import type { CreateDappInstanceResponse, Dapp } from '@bananalink-test/sdk-core';\nimport { DappApiError } from '../errors/DappApiError.js';\n\nfunction isCreateDappInstanceResponse(body: unknown): body is CreateDappInstanceResponse {\n return (\n typeof body === 'object' &&\n body !== null &&\n 'dappInstanceId' in body &&\n typeof body.dappInstanceId === 'string' &&\n 'nonce' in body &&\n typeof body.nonce === 'string'\n );\n}\n\nexport async function createDappInstance(apiUrl: string, params: Dapp): Promise<CreateDappInstanceResponse> {\n const response = await fetch(`${apiUrl}/dapps`, {\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n body: JSON.stringify(params),\n });\n if (response.ok) {\n const body = await response.json().catch(() => {\n throw new DappApiError('Invalid JSON response from bananalink API', response.status);\n });\n if (!isCreateDappInstanceResponse(body)) {\n throw new DappApiError('Unexpected response shape from bananalink API', response.status);\n }\n return body;\n }\n throw new DappApiError('Failed to create dapp instance', response.status);\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class InvalidConfigError extends BananalinkError {\n constructor(message: string) {\n super(message);\n this.name = 'InvalidConfigError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class InvalidJwtError extends BananalinkError {\n constructor() {\n super('Invalid Bananalink dapp jwt');\n }\n}\n","import { createRemoteJWKSet, type JWTVerifyGetKey } from 'jose';\n\nexport function createBananalinkJwks(apiUrl: string): JWTVerifyGetKey {\n const url = new URL(`${apiUrl}/.well-known/jwks.json`);\n return createRemoteJWKSet(url);\n}\n","import { type JWTVerifyGetKey, jwtVerify } from 'jose';\nimport type { JwtPayload } from '../types/JwtPayload.js';\n\nexport async function verifyJwt(jwt: string, jwks: JWTVerifyGetKey): Promise<JwtPayload | null> {\n try {\n const { payload } = await jwtVerify<{ message: string; signature: string }>(jwt, jwks, {\n algorithms: ['ES256'],\n issuer: 'bananalink',\n requiredClaims: ['sub', 'aud', 'message', 'signature'],\n });\n return {\n address: payload.sub as string,\n dappId: Array.isArray(payload.aud) ? payload.aud[0] : (payload.aud as string),\n message: payload.message,\n signature: payload.signature,\n jwt,\n };\n } catch {\n return null;\n }\n}\n","export function isValidUrl(url: string, protocols: string[]): boolean {\n try {\n const parsed = new URL(url);\n return protocols.includes(parsed.protocol.replace(':', ''));\n } catch {\n return false;\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class ConnectionRejectedError extends BananalinkError {\n constructor() {\n super('Dapp connection attempt was rejected by the wallet');\n this.name = 'ConnectionRejectedError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class ConnectionTimeoutError extends BananalinkError {\n constructor() {\n super('Dapp connection attempt timed out');\n this.name = 'ConnectionTimeoutError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class InvalidConnectionStateError extends BananalinkError {\n constructor(message: string) {\n super(message);\n this.name = 'InvalidConnectionStateError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class PendingSessionAbortedError extends BananalinkError {\n constructor() {\n super('Pending session was intentionally aborted');\n this.name = 'PendingSessionAbortedError';\n }\n}\n","import { DappApiError } from '../errors/DappApiError.js';\n\nfunction isCreateDappMessageResponse(body: unknown): body is { messageId: string } {\n return typeof body === 'object' && body !== null && 'messageId' in body && typeof body.messageId === 'string';\n}\n\nexport async function createDappMessage(\n apiUrl: string,\n accessToken: string,\n params: {\n method: string;\n payload: unknown;\n },\n): Promise<{ messageId: string }> {\n const response = await fetch(`${apiUrl}/dapps/messages`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(params),\n });\n if (response.ok) {\n const body = await response.json().catch(() => {\n throw new DappApiError('Invalid JSON response from bananalink API', response.status);\n });\n if (!isCreateDappMessageResponse(body)) {\n throw new DappApiError('Unexpected response shape from bananalink API', response.status);\n }\n return body;\n }\n throw new DappApiError('Failed to create dapp message', response.status);\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class RequestRejectedError extends BananalinkError {\n constructor(public readonly messageId: string) {\n super(`Request rejected by wallet (messageId: ${messageId})`);\n this.name = 'RequestRejectedError';\n }\n}\n","import type { Request } from '../types/Request.js';\nimport { BananalinkError } from './BananalinkError.js';\n\nexport class RequestTimeoutError extends BananalinkError {\n constructor(public readonly method: Request) {\n super(`Timeout reached for request ${method}`);\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class SessionClosedError extends BananalinkError {\n constructor() {\n super('Session is closed');\n }\n}\n","import { isMessageResponseMessage, type MessageResponseMessage, type TransportHandle } from '@bananalink-test/sdk-core';\nimport { createDappMessage } from '../api/createDappMessage.js';\nimport { BananalinkError } from '../errors/BananalinkError.js';\nimport { RequestRejectedError } from '../errors/RequestRejectedError.js';\nimport { RequestTimeoutError } from '../errors/RequestTimeoutError.js';\nimport { SessionClosedError } from '../errors/SessionClosedError.js';\nimport type { PendingMessageRequest } from '../types/PendingMessageRequest.js';\nimport type { Request } from '../types/Request.js';\nimport type { RequestParams } from '../types/RequestParams.js';\nimport type { RequestResult } from '../types/RequestResult.js';\nimport type { RequestResultHandler } from '../types/RequestResultHandler.js';\nimport type { SessionClaims } from '../types/SessionClaims.js';\n\nexport class BananalinkSession {\n private static readonly REQUEST_TIMEOUT_MS = 10 * 60 * 1000;\n private readonly pendingRequests = new Map<string, PendingMessageRequest>();\n private readonly stopListening: () => void;\n private readonly stopListeningOnClose: () => void;\n private closed: boolean;\n\n private static readonly RESULT_HANDLERS: { [T in Request]: RequestResultHandler<T> } = {\n eth_sendTransaction: (result) => {\n if (typeof result === 'object' && result !== null && 'txHash' in result && typeof result.txHash === 'string') {\n return result.txHash;\n }\n throw new BananalinkError(`Unexpected eth_sendTransaction result: ${result}`);\n },\n };\n\n constructor(\n public readonly sessionClaims: SessionClaims,\n private readonly ws: TransportHandle,\n private readonly apiUrl: string,\n ) {\n this.stopListening = this.ws.onMessage((payload) => {\n if (isMessageResponseMessage(payload)) {\n this.handleMessageResponse(payload);\n }\n });\n this.stopListeningOnClose = this.ws.onClose(() => {\n this.cleanup();\n this.closed = true;\n });\n this.closed = false;\n }\n\n public async request<T extends Request>({\n method,\n params,\n timeoutMs = BananalinkSession.REQUEST_TIMEOUT_MS,\n }: {\n method: T;\n params?: RequestParams<T>;\n timeoutMs?: number;\n }): Promise<RequestResult<T>> {\n if (this.closed) {\n throw new SessionClosedError();\n }\n const { messageId } = await createDappMessage(this.apiUrl, this.sessionClaims.accessToken, {\n method,\n payload: params,\n });\n\n if (this.closed) {\n throw new SessionClosedError();\n }\n\n return new Promise<RequestResult<T>>((resolve, reject) => {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n if (timeoutMs > 0) {\n timeout = setTimeout(() => {\n this.pendingRequests.delete(messageId);\n reject(new RequestTimeoutError(method));\n }, timeoutMs);\n }\n\n this.pendingRequests.set(messageId, {\n timeout,\n handle: (messageResponse: MessageResponseMessage) => {\n if (messageResponse.status === 'rejected') {\n reject(new RequestRejectedError(messageId));\n return;\n }\n const resultHandler = BananalinkSession.RESULT_HANDLERS[method];\n try {\n resolve(resultHandler(messageResponse.payloadResponse));\n } catch (error: unknown) {\n reject(new BananalinkError(`Failed resolving request response, ${error}`));\n }\n },\n reject,\n });\n });\n }\n\n public close(): void {\n this.cleanup();\n if (!this.ws.closed) {\n this.ws.close();\n }\n this.closed = true;\n }\n\n private handleMessageResponse(messageResponseMessage: MessageResponseMessage): void {\n const pending = this.pendingRequests.get(messageResponseMessage.msgId);\n if (!pending) return;\n\n this.pendingRequests.delete(messageResponseMessage.msgId);\n clearTimeout(pending.timeout);\n pending.handle(messageResponseMessage);\n }\n\n private cleanup(): void {\n this.rejectAllPendingRequests();\n this.stopListening();\n this.stopListeningOnClose();\n }\n\n private rejectAllPendingRequests(): void {\n for (const [, pending] of this.pendingRequests) {\n clearTimeout(pending.timeout);\n // TODO: propagate error or throw generic one\n pending.reject(new Error('Pending requests rejected'));\n }\n this.pendingRequests.clear();\n }\n}\n","import {\n type AuthorizedMessage,\n type BindMessage,\n connectWebSocket,\n createReconnectingTransport,\n isAuthorizedMessage,\n isBindResponseMessage,\n isRejectedMessage,\n type TransportHandle,\n} from '@bananalink-test/sdk-core';\nimport { BananalinkError } from '../errors/BananalinkError.js';\nimport { ConnectionRejectedError } from '../errors/ConnectionRejectedError.js';\nimport { ConnectionTimeoutError } from '../errors/ConnectionTimeoutError.js';\nimport { InvalidConnectionStateError } from '../errors/InvalidConnectionStateError.js';\nimport { InvalidJwtError } from '../errors/InvalidJwtError.js';\nimport { PendingSessionAbortedError } from '../errors/PendingSessionAbortedError.js';\nimport type { JwtPayload } from '../types/JwtPayload.js';\nimport type { SessionClaims } from '../types/SessionClaims.js';\nimport { BananalinkSession } from './BananalinkSession.js';\n\ntype BananalinkDappJwt = { jwtPayload: JwtPayload; rawJwt: string } | undefined;\n\nexport class BananalinkConnection {\n private static readonly AUTH_TIMEOUT_MILLIS = 10 * 60 * 1000;\n private static readonly BIND_RESPONSE_TIMEOUT_MILLIS = 20 * 1000;\n private readonly apiUrl: string;\n private readonly wsUrl: string;\n private readonly jwt: BananalinkDappJwt;\n private readonly dappId: string;\n private readonly dappInstanceId: string | null;\n private readonly nonce: string | null;\n private pendingSessionPromise: Promise<BananalinkSession> | null = null;\n private pendingSessionAbortController: AbortController | null = null;\n\n constructor(opts: {\n apiUrl: string;\n wsUrl: string;\n jwt: BananalinkDappJwt;\n dappId: string;\n dappInstanceId: string | null;\n nonce: string | null;\n }) {\n this.apiUrl = opts.apiUrl;\n this.wsUrl = opts.wsUrl;\n this.jwt = opts.jwt;\n this.dappId = opts.dappId;\n this.dappInstanceId = opts.dappInstanceId;\n this.nonce = opts.nonce;\n if (!this.dappInstanceId && !this.jwt) {\n throw new InvalidConnectionStateError(\n 'Cannot get session without authorizing a dapp instance or providing a valid JWT',\n );\n }\n }\n\n public get connectionUrl(): string {\n if (!this.dappInstanceId || !this.nonce) {\n throw new InvalidConnectionStateError('Cannot get connection URL without a dapp instance');\n }\n const dappInstanceId = this.dappInstanceId;\n const nonce = this.nonce;\n return `bananalink://?dappId=${encodeURIComponent(this.dappId)}&dappInstanceId=${encodeURIComponent(dappInstanceId)}&nonce=${encodeURIComponent(nonce)}`;\n }\n\n public abortPendingSession(): void {\n this.pendingSessionAbortController?.abort();\n }\n\n public async getSession(): Promise<BananalinkSession> {\n if (this.pendingSessionPromise) {\n return this.pendingSessionPromise;\n }\n this.pendingSessionAbortController = new AbortController();\n this.pendingSessionPromise = (\n this.jwt\n ? this.resumeSession(this.jwt, this.pendingSessionAbortController.signal)\n : this.waitForAuthorization(this.pendingSessionAbortController.signal)\n ).finally(() => {\n this.pendingSessionPromise = null;\n this.pendingSessionAbortController = null;\n });\n return this.pendingSessionPromise;\n }\n\n private async openSession(\n getSessionClaims: (transportHandle: TransportHandle) => Promise<SessionClaims>,\n abortSignal: AbortSignal,\n ) {\n const transportHandle = await this.getTransportHandle(this.dappInstanceId);\n const onAbort = (): void => transportHandle.close();\n abortSignal.addEventListener('abort', onAbort, { once: true });\n if (abortSignal.aborted) {\n transportHandle.close();\n throw new PendingSessionAbortedError();\n }\n try {\n const sessionClaims = await getSessionClaims(transportHandle);\n await this.bind(transportHandle, sessionClaims.accessToken, abortSignal);\n const transport = createReconnectingTransport(transportHandle, {\n reconnectTransport: async () => this.getTransportHandle(null),\n onReconnect: async (th) => this.bind(th, sessionClaims.accessToken),\n maxReconnectAttempts: 5,\n baseDelayReconnectMs: 1000,\n });\n return new BananalinkSession(sessionClaims, transport, this.apiUrl);\n } catch (error) {\n transportHandle.close();\n throw error;\n } finally {\n abortSignal.removeEventListener('abort', onAbort);\n }\n }\n\n private async resumeSession(\n jwt: NonNullable<BananalinkDappJwt>,\n abortSignal: AbortSignal,\n ): Promise<BananalinkSession> {\n return await this.openSession(async () => ({ ...jwt.jwtPayload, accessToken: jwt.rawJwt }), abortSignal);\n }\n\n private async waitForAuthorization(abortSignal: AbortSignal): Promise<BananalinkSession> {\n return await this.openSession(\n async (transportHandle: TransportHandle) =>\n await this.raceEvent<AuthorizedMessage>(\n transportHandle,\n (payload, resolve, reject) => {\n if (isAuthorizedMessage(payload)) resolve(payload);\n if (isRejectedMessage(payload)) reject(new ConnectionRejectedError());\n },\n BananalinkConnection.AUTH_TIMEOUT_MILLIS,\n abortSignal,\n ),\n abortSignal,\n );\n }\n\n private async getTransportHandle(dappInstanceId?: string | null): Promise<TransportHandle> {\n const url = `${this.wsUrl}${dappInstanceId != null ? `?dappInstanceId=${encodeURIComponent(dappInstanceId)}` : ''}`;\n try {\n return await connectWebSocket({\n url,\n pingIntervalMs: 30_000,\n pongTimeoutMs: 5_000,\n maxReconnectAttempts: 0,\n });\n } catch (error) {\n throw new BananalinkError('Unable to establish dapp websocket connection', { cause: error });\n }\n }\n\n private async bind(ws: TransportHandle, jwt: string, abortSignal?: AbortSignal): Promise<void> {\n const bindPromise = this.raceEvent<void>(\n ws,\n (payload, resolve, reject) => {\n if (isBindResponseMessage(payload)) {\n // TODO: handle different error cases for either invalid or expired jwt\n payload.type === 'bind_success' ? resolve() : reject(new InvalidJwtError());\n }\n },\n BananalinkConnection.BIND_RESPONSE_TIMEOUT_MILLIS,\n abortSignal,\n );\n ws.send({ type: 'bind', jwt } as BindMessage);\n await bindPromise;\n }\n\n private async raceEvent<T>(\n transportHandle: TransportHandle,\n eventHandler: (\n payload: unknown,\n resolve: (t: T | PromiseLike<T>) => void,\n reject: (error: BananalinkError) => void,\n ) => void,\n timeoutMs: number,\n abortSignal?: AbortSignal,\n ): Promise<T> {\n const disposers: (() => void)[] = [];\n\n const cleanup = (): void => {\n for (const disposer of disposers) {\n disposer();\n }\n };\n\n const promises: Promise<T>[] = [];\n\n promises.push(\n new Promise<T>((resolve, reject) => {\n const stopListeningMessages = transportHandle.onMessage((payload) => eventHandler(payload, resolve, reject));\n const stopListeningClose = transportHandle.onClose(() =>\n reject(new BananalinkError('Connection closed unexpectedly')),\n );\n disposers.push(stopListeningMessages, stopListeningClose);\n }),\n );\n\n promises.push(\n new Promise<T>((_resolve, reject) => {\n const timer = setTimeout(() => reject(new ConnectionTimeoutError()), timeoutMs);\n disposers.push(() => clearTimeout(timer));\n }),\n );\n\n if (abortSignal !== undefined) {\n promises.push(\n new Promise<T>((_resolve, reject) => {\n if (abortSignal.aborted) reject(new PendingSessionAbortedError());\n const onAbort = (): void => reject(new PendingSessionAbortedError());\n abortSignal.addEventListener('abort', onAbort, { once: true });\n disposers.push(() => abortSignal.removeEventListener('abort', onAbort));\n }),\n );\n }\n\n try {\n return await Promise.race(promises);\n } finally {\n cleanup();\n }\n }\n}\n","import type { CreateDappInstanceResponse, Dapp } from '@bananalink-test/sdk-core';\nimport { createDappInstance } from '../api/createDappInstance.js';\nimport { InvalidConfigError } from '../errors/InvalidConfigError.js';\nimport { InvalidJwtError } from '../errors/InvalidJwtError.js';\nimport { createBananalinkJwks } from '../jwt/createBananalinkJwks.js';\nimport { verifyJwt } from '../jwt/verifyJwt.js';\nimport type { JwtPayload } from '../types/JwtPayload.js';\nimport { isValidUrl } from '../utils/isValidUrl.js';\nimport { BananalinkConnection } from './BananalinkConnection.js';\n\nexport class BananalinkClient {\n private readonly apiUrl: string;\n private readonly wsUrl: string;\n private readonly jwks: ReturnType<typeof createBananalinkJwks>;\n private readonly dapp: Dapp;\n private static readonly DEFAULT_BANANALINK_API_URL = 'https://tfr9p2mn4i.execute-api.us-east-2.amazonaws.com';\n private static readonly DEFAULT_BANANALINK_WS_URL = 'wss://yb47qomkt3.execute-api.us-east-2.amazonaws.com/v1';\n\n constructor(config: {\n apiUrl?: string;\n wsUrl?: string;\n dapp: Dapp;\n }) {\n this.apiUrl = config.apiUrl ?? BananalinkClient.DEFAULT_BANANALINK_API_URL;\n this.wsUrl = config.wsUrl ?? BananalinkClient.DEFAULT_BANANALINK_WS_URL;\n if (!isValidUrl(this.apiUrl, ['http', 'https'])) {\n throw new InvalidConfigError(`Invalid apiUrl: \"${this.apiUrl}\". Must use http or https.`);\n }\n if (!isValidUrl(this.wsUrl, ['ws', 'wss'])) {\n throw new InvalidConfigError(`Invalid wsUrl: \"${this.wsUrl}\". Must use ws or wss.`);\n }\n this.dapp = config.dapp;\n this.jwks = createBananalinkJwks(this.apiUrl);\n }\n\n public async connect(opts?: { jwt: string }): Promise<BananalinkConnection> {\n const rawJwt = opts?.jwt;\n if (!rawJwt) {\n const { dappInstanceId, nonce } = await this.connectDappInstance();\n return new BananalinkConnection({\n jwt: undefined,\n dappId: this.dapp.dappId,\n dappInstanceId,\n nonce,\n apiUrl: this.apiUrl,\n wsUrl: this.wsUrl,\n });\n }\n\n const jwtPayload = await this.getJwtPayload(rawJwt);\n if (!jwtPayload) {\n throw new InvalidJwtError();\n }\n\n return new BananalinkConnection({\n jwt: { jwtPayload, rawJwt },\n dappId: this.dapp.dappId,\n dappInstanceId: null,\n nonce: null,\n apiUrl: this.apiUrl,\n wsUrl: this.wsUrl,\n });\n }\n\n private async getJwtPayload(rawJwt: string): Promise<JwtPayload | null> {\n return await verifyJwt(rawJwt, this.jwks);\n }\n\n private async connectDappInstance(): Promise<CreateDappInstanceResponse> {\n return await createDappInstance(this.apiUrl, this.dapp);\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class InvalidUrlError extends BananalinkError {\n constructor(public readonly url: string) {\n super(`${url} is not a valid url`);\n }\n}\n","import QRCode from 'qrcode';\nimport { InvalidUrlError } from '../errors/InvalidUrlError.js';\nimport { isValidUrl } from './isValidUrl.js';\n\nexport async function displayBananalinkQR(url: string): Promise<string> {\n if (!isValidUrl(url, ['bananalink'])) {\n throw new InvalidUrlError(url);\n }\n return QRCode.toDataURL(url);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/errors/BananalinkError.ts","../src/errors/DappApiError.ts","../src/api/createDappInstance.ts","../src/errors/InvalidConfigError.ts","../src/errors/InvalidJwtError.ts","../src/jwt/createBananalinkJwks.ts","../src/jwt/verifyJwt.ts","../src/utils/isValidUrl.ts","../src/errors/ConnectionRejectedError.ts","../src/errors/ConnectionTimeoutError.ts","../src/errors/InvalidConnectionStateError.ts","../src/errors/PendingSessionAbortedError.ts","../src/api/createDappMessage.ts","../src/errors/RequestRejectedError.ts","../src/errors/RequestTimeoutError.ts","../src/errors/SessionClosedError.ts","../src/core/BananalinkSession.ts","../src/core/BananalinkConnection.ts","../src/core/BananalinkClient.ts","../src/errors/InvalidUrlError.ts","../src/utils/displayBananalinkQR.ts"],"sourcesContent":["export class BananalinkError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'BananalinkError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class DappApiError extends BananalinkError {\n constructor(\n message: string,\n public readonly statusCode: number,\n ) {\n super(message);\n this.name = 'DappApiError';\n }\n}\n","import type { CreateDappInstanceResponse, Dapp } from '@bananalink-test/sdk-core';\nimport { DappApiError } from '../errors/DappApiError.js';\n\nfunction isCreateDappInstanceResponse(body: unknown): body is CreateDappInstanceResponse {\n return (\n typeof body === 'object' &&\n body !== null &&\n 'dappInstanceId' in body &&\n typeof body.dappInstanceId === 'string' &&\n 'nonce' in body &&\n typeof body.nonce === 'string'\n );\n}\n\nexport async function createDappInstance(apiUrl: string, params: Dapp): Promise<CreateDappInstanceResponse> {\n const response = await fetch(`${apiUrl}/dapps`, {\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n body: JSON.stringify(params),\n });\n if (response.ok) {\n const body = await response.json().catch(() => {\n throw new DappApiError('Invalid JSON response from bananalink API', response.status);\n });\n if (!isCreateDappInstanceResponse(body)) {\n throw new DappApiError('Unexpected response shape from bananalink API', response.status);\n }\n return body;\n }\n throw new DappApiError('Failed to create dapp instance', response.status);\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class InvalidConfigError extends BananalinkError {\n constructor(message: string) {\n super(message);\n this.name = 'InvalidConfigError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class InvalidJwtError extends BananalinkError {\n constructor() {\n super('Invalid Bananalink dapp jwt');\n }\n}\n","import { createRemoteJWKSet, type JWTVerifyGetKey } from 'jose';\n\nexport function createBananalinkJwks(apiUrl: string): JWTVerifyGetKey {\n const url = new URL(`${apiUrl}/.well-known/jwks.json`);\n return createRemoteJWKSet(url);\n}\n","import { type JWTVerifyGetKey, jwtVerify } from 'jose';\nimport type { JwtPayload } from '../types/JwtPayload.js';\n\nexport async function verifyJwt(jwt: string, jwks: JWTVerifyGetKey): Promise<JwtPayload | null> {\n try {\n const { payload } = await jwtVerify<{ message: string; signature: string }>(jwt, jwks, {\n algorithms: ['ES256'],\n issuer: 'bananalink',\n requiredClaims: ['sub', 'aud', 'message', 'signature'],\n });\n return {\n address: payload.sub as string,\n dappId: Array.isArray(payload.aud) ? payload.aud[0] : (payload.aud as string),\n message: payload.message,\n signature: payload.signature,\n jwt,\n };\n } catch {\n return null;\n }\n}\n","export function isValidUrl(url: string, protocols: string[]): boolean {\n try {\n const parsed = new URL(url);\n return protocols.includes(parsed.protocol.replace(':', ''));\n } catch {\n return false;\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class ConnectionRejectedError extends BananalinkError {\n constructor() {\n super('Dapp connection attempt was rejected by the wallet');\n this.name = 'ConnectionRejectedError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class ConnectionTimeoutError extends BananalinkError {\n constructor() {\n super('Dapp connection attempt timed out');\n this.name = 'ConnectionTimeoutError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class InvalidConnectionStateError extends BananalinkError {\n constructor(message: string) {\n super(message);\n this.name = 'InvalidConnectionStateError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class PendingSessionAbortedError extends BananalinkError {\n constructor() {\n super('Pending session was intentionally aborted');\n this.name = 'PendingSessionAbortedError';\n }\n}\n","import { DappApiError } from '../errors/DappApiError.js';\n\nfunction isCreateDappMessageResponse(body: unknown): body is { messageId: string } {\n return typeof body === 'object' && body !== null && 'messageId' in body && typeof body.messageId === 'string';\n}\n\nexport async function createDappMessage(\n apiUrl: string,\n accessToken: string,\n params: {\n method: string;\n payload: unknown;\n },\n): Promise<{ messageId: string }> {\n const response = await fetch(`${apiUrl}/dapps/messages`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(params),\n });\n if (response.ok) {\n const body = await response.json().catch(() => {\n throw new DappApiError('Invalid JSON response from bananalink API', response.status);\n });\n if (!isCreateDappMessageResponse(body)) {\n throw new DappApiError('Unexpected response shape from bananalink API', response.status);\n }\n return body;\n }\n throw new DappApiError('Failed to create dapp message', response.status);\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class RequestRejectedError extends BananalinkError {\n constructor(public readonly messageId: string) {\n super(`Request rejected by wallet (messageId: ${messageId})`);\n this.name = 'RequestRejectedError';\n }\n}\n","import type { Request } from '../types/Request.js';\nimport { BananalinkError } from './BananalinkError.js';\n\nexport class RequestTimeoutError extends BananalinkError {\n constructor(public readonly method: Request) {\n super(`Timeout reached for request ${method}`);\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class SessionClosedError extends BananalinkError {\n constructor() {\n super('Session is closed');\n }\n}\n","import {\n isMessageResponseMessage,\n type MessageResponseMessage,\n type TransportHandle,\n withBackoff,\n} from '@bananalink-test/sdk-core';\nimport { createDappMessage } from '../api/createDappMessage.js';\nimport { BananalinkError } from '../errors/BananalinkError.js';\nimport { RequestRejectedError } from '../errors/RequestRejectedError.js';\nimport { RequestTimeoutError } from '../errors/RequestTimeoutError.js';\nimport { SessionClosedError } from '../errors/SessionClosedError.js';\nimport type { PendingMessageRequest } from '../types/PendingMessageRequest.js';\nimport type { Request } from '../types/Request.js';\nimport type { RequestParams } from '../types/RequestParams.js';\nimport type { RequestResult } from '../types/RequestResult.js';\nimport type { RequestResultHandler } from '../types/RequestResultHandler.js';\nimport type { SessionClaims } from '../types/SessionClaims.js';\n\nexport class BananalinkSession {\n private static readonly REQUEST_TIMEOUT_MS = 10 * 60 * 1000;\n private static readonly CREATE_DAPP_MESSAGE_MAX_ATTEMPTS = 3;\n private static readonly CREATE_DAPP_MESSAGE_BASE_DELAY_MS = 1000;\n private readonly pendingRequests = new Map<string, PendingMessageRequest>();\n private readonly stopListening: () => void;\n private readonly stopListeningOnClose: () => void;\n private closed: boolean;\n\n private static readonly RESULT_HANDLERS: { [T in Request]: RequestResultHandler<T> } = {\n eth_sendTransaction: (result) => {\n if (typeof result === 'object' && result !== null && 'txHash' in result && typeof result.txHash === 'string') {\n return result.txHash;\n }\n throw new BananalinkError(`Unexpected eth_sendTransaction result: ${result}`);\n },\n };\n\n constructor(\n public readonly sessionClaims: SessionClaims,\n private readonly ws: TransportHandle,\n private readonly apiUrl: string,\n ) {\n this.stopListening = this.ws.onMessage((payload) => {\n if (isMessageResponseMessage(payload)) {\n this.handleMessageResponse(payload);\n }\n });\n this.stopListeningOnClose = this.ws.onClose(() => {\n this.cleanup();\n this.closed = true;\n });\n this.closed = false;\n }\n\n public async request<T extends Request>({\n method,\n params,\n timeoutMs = BananalinkSession.REQUEST_TIMEOUT_MS,\n }: {\n method: T;\n params?: RequestParams<T>;\n timeoutMs?: number;\n }): Promise<RequestResult<T>> {\n if (this.closed) {\n throw new SessionClosedError();\n }\n\n const { messageId } = await withBackoff(\n async () =>\n await createDappMessage(this.apiUrl, this.sessionClaims.accessToken, {\n method,\n payload: params,\n }),\n BananalinkSession.CREATE_DAPP_MESSAGE_MAX_ATTEMPTS,\n BananalinkSession.CREATE_DAPP_MESSAGE_BASE_DELAY_MS,\n );\n\n if (this.closed) {\n throw new SessionClosedError();\n }\n\n return new Promise<RequestResult<T>>((resolve, reject) => {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n if (timeoutMs > 0) {\n timeout = setTimeout(() => {\n this.pendingRequests.delete(messageId);\n reject(new RequestTimeoutError(method));\n }, timeoutMs);\n }\n\n this.pendingRequests.set(messageId, {\n timeout,\n handle: (messageResponse: MessageResponseMessage) => {\n if (messageResponse.status === 'rejected') {\n reject(new RequestRejectedError(messageId));\n return;\n }\n const resultHandler = BananalinkSession.RESULT_HANDLERS[method];\n try {\n resolve(resultHandler(messageResponse.payloadResponse));\n } catch (error: unknown) {\n reject(new BananalinkError(`Failed resolving request response, ${error}`));\n }\n },\n reject,\n });\n });\n }\n\n public close(): void {\n this.cleanup();\n if (!this.ws.closed) {\n this.ws.close();\n }\n this.closed = true;\n }\n\n private handleMessageResponse(messageResponseMessage: MessageResponseMessage): void {\n const pending = this.pendingRequests.get(messageResponseMessage.msgId);\n if (!pending) return;\n\n this.pendingRequests.delete(messageResponseMessage.msgId);\n clearTimeout(pending.timeout);\n pending.handle(messageResponseMessage);\n }\n\n private cleanup(): void {\n this.rejectAllPendingRequests();\n this.stopListening();\n this.stopListeningOnClose();\n }\n\n private rejectAllPendingRequests(): void {\n for (const [, pending] of this.pendingRequests) {\n clearTimeout(pending.timeout);\n // TODO: propagate error or throw generic one\n pending.reject(new Error('Pending requests rejected'));\n }\n this.pendingRequests.clear();\n }\n}\n","import {\n type AuthorizedMessage,\n type BindMessage,\n connectWebSocket,\n createReconnectingTransport,\n isAuthorizedMessage,\n isBindResponseMessage,\n isRejectedMessage,\n type TransportHandle,\n} from '@bananalink-test/sdk-core';\nimport { BananalinkError } from '../errors/BananalinkError.js';\nimport { ConnectionRejectedError } from '../errors/ConnectionRejectedError.js';\nimport { ConnectionTimeoutError } from '../errors/ConnectionTimeoutError.js';\nimport { InvalidConnectionStateError } from '../errors/InvalidConnectionStateError.js';\nimport { InvalidJwtError } from '../errors/InvalidJwtError.js';\nimport { PendingSessionAbortedError } from '../errors/PendingSessionAbortedError.js';\nimport type { JwtPayload } from '../types/JwtPayload.js';\nimport type { SessionClaims } from '../types/SessionClaims.js';\nimport { BananalinkSession } from './BananalinkSession.js';\n\ntype BananalinkDappJwt = { jwtPayload: JwtPayload; accessToken: string } | undefined;\n\nexport class BananalinkConnection {\n private static readonly AUTH_TIMEOUT_MILLIS = 10 * 60 * 1000;\n private static readonly BIND_RESPONSE_TIMEOUT_MILLIS = 20 * 1000;\n private readonly apiUrl: string;\n private readonly wsUrl: string;\n private readonly jwt: BananalinkDappJwt;\n private readonly dappId: string;\n private readonly dappInstanceId: string | null;\n private readonly nonce: string | null;\n private pendingSessionPromise: Promise<BananalinkSession> | null = null;\n private pendingSessionAbortController: AbortController | null = null;\n\n constructor(opts: {\n apiUrl: string;\n wsUrl: string;\n jwt: BananalinkDappJwt;\n dappId: string;\n dappInstanceId: string | null;\n nonce: string | null;\n }) {\n this.apiUrl = opts.apiUrl;\n this.wsUrl = opts.wsUrl;\n this.jwt = opts.jwt;\n this.dappId = opts.dappId;\n this.dappInstanceId = opts.dappInstanceId;\n this.nonce = opts.nonce;\n if (!this.dappInstanceId && !this.jwt) {\n throw new InvalidConnectionStateError(\n 'Cannot get session without authorizing a dapp instance or providing a valid JWT',\n );\n }\n }\n\n public get connectionUrl(): string {\n if (!this.dappInstanceId || !this.nonce) {\n throw new InvalidConnectionStateError('Cannot get connection URL without a dapp instance');\n }\n const dappInstanceId = this.dappInstanceId;\n const nonce = this.nonce;\n return `bananalink://?dappId=${encodeURIComponent(this.dappId)}&dappInstanceId=${encodeURIComponent(dappInstanceId)}&nonce=${encodeURIComponent(nonce)}`;\n }\n\n public abortPendingSession(): void {\n this.pendingSessionAbortController?.abort();\n }\n\n public async getSession(): Promise<BananalinkSession> {\n if (this.pendingSessionPromise) {\n return this.pendingSessionPromise;\n }\n this.pendingSessionAbortController = new AbortController();\n this.pendingSessionPromise = (\n this.jwt\n ? this.resumeSession(this.jwt, this.pendingSessionAbortController.signal)\n : this.waitForAuthorization(this.pendingSessionAbortController.signal)\n ).finally(() => {\n this.pendingSessionPromise = null;\n this.pendingSessionAbortController = null;\n });\n return this.pendingSessionPromise;\n }\n\n private async openSession(\n getSessionClaims: (transportHandle: TransportHandle) => Promise<SessionClaims>,\n abortSignal: AbortSignal,\n ) {\n const transportHandle = await this.getTransportHandle(this.dappInstanceId);\n const onAbort = (): void => transportHandle.close();\n abortSignal.addEventListener('abort', onAbort, { once: true });\n if (abortSignal.aborted) {\n transportHandle.close();\n throw new PendingSessionAbortedError();\n }\n try {\n const sessionClaims = await getSessionClaims(transportHandle);\n await this.bind(transportHandle, sessionClaims.accessToken, abortSignal);\n const transport = createReconnectingTransport(transportHandle, {\n reconnectTransport: async () => this.getTransportHandle(null),\n onReconnect: async (th) => this.bind(th, sessionClaims.accessToken),\n maxReconnectAttempts: 5,\n baseDelayReconnectMs: 1000,\n });\n return new BananalinkSession(sessionClaims, transport, this.apiUrl);\n } catch (error) {\n transportHandle.close();\n throw error;\n } finally {\n abortSignal.removeEventListener('abort', onAbort);\n }\n }\n\n private async resumeSession(\n jwt: NonNullable<BananalinkDappJwt>,\n abortSignal: AbortSignal,\n ): Promise<BananalinkSession> {\n return await this.openSession(async () => ({ ...jwt.jwtPayload, accessToken: jwt.accessToken }), abortSignal);\n }\n\n private async waitForAuthorization(abortSignal: AbortSignal): Promise<BananalinkSession> {\n return await this.openSession(\n async (transportHandle: TransportHandle) =>\n await this.raceEvent<AuthorizedMessage>(\n transportHandle,\n (payload, resolve, reject) => {\n if (isAuthorizedMessage(payload)) resolve(payload);\n if (isRejectedMessage(payload)) reject(new ConnectionRejectedError());\n },\n BananalinkConnection.AUTH_TIMEOUT_MILLIS,\n abortSignal,\n ),\n abortSignal,\n );\n }\n\n private async getTransportHandle(dappInstanceId?: string | null): Promise<TransportHandle> {\n const url = `${this.wsUrl}${dappInstanceId != null ? `?dappInstanceId=${encodeURIComponent(dappInstanceId)}` : ''}`;\n try {\n return await connectWebSocket({\n url,\n pingIntervalMs: 30_000,\n pongTimeoutMs: 5_000,\n maxReconnectAttempts: 0,\n });\n } catch (error) {\n throw new BananalinkError('Unable to establish dapp websocket connection', { cause: error });\n }\n }\n\n private async bind(ws: TransportHandle, accessToken: string, abortSignal?: AbortSignal): Promise<void> {\n const bindPromise = this.raceEvent<void>(\n ws,\n (payload, resolve, reject) => {\n if (isBindResponseMessage(payload)) {\n // TODO: handle different error cases for either invalid or expired jwt\n payload.type === 'bind_success' ? resolve() : reject(new InvalidJwtError());\n }\n },\n BananalinkConnection.BIND_RESPONSE_TIMEOUT_MILLIS,\n abortSignal,\n );\n ws.send({ type: 'bind', jwt: accessToken } as BindMessage);\n await bindPromise;\n }\n\n private async raceEvent<T>(\n transportHandle: TransportHandle,\n eventHandler: (\n payload: unknown,\n resolve: (t: T | PromiseLike<T>) => void,\n reject: (error: BananalinkError) => void,\n ) => void,\n timeoutMs: number,\n abortSignal?: AbortSignal,\n ): Promise<T> {\n const disposers: (() => void)[] = [];\n\n const cleanup = (): void => {\n for (const disposer of disposers) {\n disposer();\n }\n };\n\n const promises: Promise<T>[] = [];\n\n promises.push(\n new Promise<T>((resolve, reject) => {\n const stopListeningMessages = transportHandle.onMessage((payload) => eventHandler(payload, resolve, reject));\n const stopListeningClose = transportHandle.onClose(() =>\n reject(new BananalinkError('Connection closed unexpectedly')),\n );\n disposers.push(stopListeningMessages, stopListeningClose);\n }),\n );\n\n promises.push(\n new Promise<T>((_resolve, reject) => {\n const timer = setTimeout(() => reject(new ConnectionTimeoutError()), timeoutMs);\n disposers.push(() => clearTimeout(timer));\n }),\n );\n\n if (abortSignal !== undefined) {\n promises.push(\n new Promise<T>((_resolve, reject) => {\n if (abortSignal.aborted) reject(new PendingSessionAbortedError());\n const onAbort = (): void => reject(new PendingSessionAbortedError());\n abortSignal.addEventListener('abort', onAbort, { once: true });\n disposers.push(() => abortSignal.removeEventListener('abort', onAbort));\n }),\n );\n }\n\n try {\n return await Promise.race(promises);\n } finally {\n cleanup();\n }\n }\n}\n","import type { CreateDappInstanceResponse, Dapp } from '@bananalink-test/sdk-core';\nimport { createDappInstance } from '../api/createDappInstance.js';\nimport { InvalidConfigError } from '../errors/InvalidConfigError.js';\nimport { InvalidJwtError } from '../errors/InvalidJwtError.js';\nimport { createBananalinkJwks } from '../jwt/createBananalinkJwks.js';\nimport { verifyJwt } from '../jwt/verifyJwt.js';\nimport type { ConnectOpts } from '../types/ConnectOpts.js';\nimport type { JwtPayload } from '../types/JwtPayload.js';\nimport { isValidUrl } from '../utils/isValidUrl.js';\nimport { BananalinkConnection } from './BananalinkConnection.js';\n\nexport class BananalinkClient {\n private readonly apiUrl: string;\n private readonly wsUrl: string;\n private readonly jwks: ReturnType<typeof createBananalinkJwks>;\n private readonly dapp: Dapp;\n private static readonly DEFAULT_BANANALINK_API_URL = 'https://tfr9p2mn4i.execute-api.us-east-2.amazonaws.com';\n private static readonly DEFAULT_BANANALINK_WS_URL = 'wss://yb47qomkt3.execute-api.us-east-2.amazonaws.com/v1';\n\n constructor(config: {\n apiUrl?: string;\n wsUrl?: string;\n dapp: Dapp;\n }) {\n this.apiUrl = config.apiUrl ?? BananalinkClient.DEFAULT_BANANALINK_API_URL;\n this.wsUrl = config.wsUrl ?? BananalinkClient.DEFAULT_BANANALINK_WS_URL;\n if (!isValidUrl(this.apiUrl, ['http', 'https'])) {\n throw new InvalidConfigError(`Invalid apiUrl: \"${this.apiUrl}\". Must use http or https.`);\n }\n if (!isValidUrl(this.wsUrl, ['ws', 'wss'])) {\n throw new InvalidConfigError(`Invalid wsUrl: \"${this.wsUrl}\". Must use ws or wss.`);\n }\n this.dapp = config.dapp;\n this.jwks = createBananalinkJwks(this.apiUrl);\n }\n\n public async connect(opts?: ConnectOpts): Promise<BananalinkConnection> {\n const accessToken = opts?.accessToken;\n if (!accessToken) {\n const { dappInstanceId, nonce } = await this.connectDappInstance();\n return new BananalinkConnection({\n jwt: undefined,\n dappId: this.dapp.dappId,\n dappInstanceId,\n nonce,\n apiUrl: this.apiUrl,\n wsUrl: this.wsUrl,\n });\n }\n\n const jwtPayload = await this.getJwtPayload(accessToken);\n if (!jwtPayload) {\n throw new InvalidJwtError();\n }\n\n return new BananalinkConnection({\n jwt: { jwtPayload, accessToken },\n dappId: this.dapp.dappId,\n dappInstanceId: null,\n nonce: null,\n apiUrl: this.apiUrl,\n wsUrl: this.wsUrl,\n });\n }\n\n private async getJwtPayload(accessToken: string): Promise<JwtPayload | null> {\n return await verifyJwt(accessToken, this.jwks);\n }\n\n private async connectDappInstance(): Promise<CreateDappInstanceResponse> {\n return await createDappInstance(this.apiUrl, this.dapp);\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class InvalidUrlError extends BananalinkError {\n constructor(public readonly url: string) {\n super(`${url} is not a valid url`);\n }\n}\n","import QRCode from 'qrcode';\nimport { InvalidUrlError } from '../errors/InvalidUrlError.js';\nimport { isValidUrl } from './isValidUrl.js';\n\nexport async function displayBananalinkQR(url: string): Promise<string> {\n if (!isValidUrl(url, ['bananalink'])) {\n throw new InvalidUrlError(url);\n }\n return QRCode.toDataURL(url);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananalink-test/client",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "sideEffects": false,