@bananalink-test/client 0.0.0 → 0.1.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
@@ -91,11 +91,19 @@ async function verifyJwt(jwt, jwks) {
91
91
  const { payload } = await (0, jose.jwtVerify)(jwt, jwks, {
92
92
  algorithms: ["ES256"],
93
93
  issuer: "bananalink",
94
- requiredClaims: ["sub", "aud"]
94
+ requiredClaims: [
95
+ "sub",
96
+ "aud",
97
+ "message",
98
+ "signature"
99
+ ]
95
100
  });
96
101
  return {
97
102
  address: payload.sub,
98
- dappId: Array.isArray(payload.aud) ? payload.aud[0] : payload.aud
103
+ dappId: Array.isArray(payload.aud) ? payload.aud[0] : payload.aud,
104
+ message: payload.message,
105
+ signature: payload.signature,
106
+ jwt
99
107
  };
100
108
  } catch {
101
109
  return null;
@@ -147,7 +155,8 @@ var BananalinkSession = class BananalinkSession {
147
155
  static PONG_TIMEOUT_MILLIS = 5 * 1e3;
148
156
  pingTimer = null;
149
157
  pongTimer = null;
150
- constructor(ws) {
158
+ constructor(sessionClaims, ws) {
159
+ this.sessionClaims = sessionClaims;
151
160
  this.ws = ws;
152
161
  this.ws.addEventListener("message", (event) => {
153
162
  const { type } = JSON.parse(event.data);
@@ -211,10 +220,15 @@ var BananalinkConnection = class BananalinkConnection {
211
220
  const msg = JSON.parse(event.data);
212
221
  clearTimeout(authTimeout);
213
222
  ws.removeEventListener("message", onMessage);
214
- if (msg.type === "authorized") {
223
+ if (BananalinkConnection.isAuthorizedMessage(msg)) {
215
224
  BananalinkConnection.bind(ws, msg.accessToken);
216
- resolve(new BananalinkSession(ws));
217
- } else if (msg.type === "rejected") {
225
+ resolve(new BananalinkSession({
226
+ address: msg.address,
227
+ message: msg.message,
228
+ signature: msg.signature,
229
+ accessToken: msg.accessToken
230
+ }, ws));
231
+ } else if (BananalinkConnection.isRejectedMessage(msg)) {
218
232
  ws.close();
219
233
  reject(new ConnectionRejectedError());
220
234
  }
@@ -239,6 +253,12 @@ var BananalinkConnection = class BananalinkConnection {
239
253
  jwt
240
254
  }));
241
255
  }
256
+ static isAuthorizedMessage(payload) {
257
+ return typeof payload === "object" && payload !== null && "type" in payload && payload.type === "authorized" && "accessToken" in payload && typeof payload.accessToken === "string" && "refreshToken" in payload && typeof payload.refreshToken === "string" && "message" in payload && typeof payload.message === "string" && "signature" in payload && typeof payload.signature === "string" && "address" in payload && typeof payload.address === "string";
258
+ }
259
+ static isRejectedMessage(payload) {
260
+ return typeof payload === "object" && payload !== null && "type" in payload && payload.type === "rejected";
261
+ }
242
262
  };
243
263
 
244
264
  //#endregion
package/dist/index.d.cts CHANGED
@@ -14,16 +14,28 @@ type Dapp = {
14
14
  type JwtPayload = {
15
15
  address: string;
16
16
  dappId: string;
17
+ message: string;
18
+ signature: string;
19
+ jwt: string;
20
+ };
21
+ //#endregion
22
+ //#region src/types/SessionClaims.d.ts
23
+ type SessionClaims = {
24
+ address: string;
25
+ message: string;
26
+ signature: string;
27
+ accessToken: string;
17
28
  };
18
29
  //#endregion
19
30
  //#region src/core/BananalinkSession.d.ts
20
31
  declare class BananalinkSession {
32
+ readonly sessionClaims: SessionClaims;
21
33
  private readonly ws;
22
34
  private static readonly PING_INTERVAL_MILLIS;
23
35
  private static readonly PONG_TIMEOUT_MILLIS;
24
36
  private pingTimer;
25
37
  private pongTimer;
26
- constructor(ws: WebSocket);
38
+ constructor(sessionClaims: SessionClaims, ws: WebSocket);
27
39
  close(): void;
28
40
  private startPing;
29
41
  private ping;
@@ -53,6 +65,8 @@ declare class BananalinkConnection {
53
65
  get connectionUrl(): string;
54
66
  get authorized(): boolean;
55
67
  private static bind;
68
+ private static isAuthorizedMessage;
69
+ private static isRejectedMessage;
56
70
  }
57
71
  //#endregion
58
72
  //#region src/core/BananalinkClient.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/Dapp.ts","../src/types/JwtPayload.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/utils/displayBananalinkQR.ts"],"mappings":";KAAY,IAAA;EACV,MAAA;EACA,QAAA;EACA,eAAA;EACA,aAAA;EACA,MAAA;EACA,GAAA;EACA,KAAA;EACA,OAAA;AAAA;;;KCRU,UAAA;EAAe,OAAA;EAAiB,MAAA;AAAA;;;cCA/B,iBAAA;EAAA,iBAOkB,EAAA;EAAA,wBANL,oBAAA;EAAA,wBACA,mBAAA;EAAA,QAEhB,SAAA;EAAA,QACA,SAAA;cAEqB,EAAA,EAAI,SAAA;EAW1B,KAAA,CAAA;EAAA,QAKC,SAAA;EAAA,QAIA,IAAA;EAAA,QASA,UAAA;AAAA;;;KC7BL,iBAAA;EAAsB,UAAA,EAAY,UAAA;EAAY,MAAA;AAAA;AAAA,cAEtC,oBAAA;EAAA,wBACa,mBAAA;EAAA,iBACP,KAAA;EAAA,iBACA,GAAA;EAAA,iBACA,MAAA;EAAA,iBACA,cAAA;EAAA,iBACA,KAAA;cAEL,IAAA;IACV,KAAA;IACA,GAAA,EAAK,iBAAA;IACL,MAAA;IACA,cAAA;IACA,KAAA;EAAA;EASW,UAAA,CAAA,GAAc,OAAA,CAAQ,iBAAA;EAAA,IA2CxB,aAAA,CAAA;EAAA,IASA,UAAA,CAAA;EAAA,eAKI,IAAA;AAAA;;;cC9EJ,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,IAAA;EAAA;EAcK,OAAA,CAAQ,IAAA;IAAS,GAAA;EAAA,IAAgB,OAAA,CAAQ,oBAAA;EAAA,QAsBxC,aAAA;EAAA,QAIA,mBAAA;AAAA;;;cC7DH,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;;;iBCCQ,mBAAA,CAAoB,GAAA,WAAc,OAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/Dapp.ts","../src/types/JwtPayload.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/utils/displayBananalinkQR.ts"],"mappings":";KAAY,IAAA;EACV,MAAA;EACA,QAAA;EACA,eAAA;EACA,aAAA;EACA,MAAA;EACA,GAAA;EACA,KAAA;EACA,OAAA;AAAA;;;KCRU,UAAA;EAAe,OAAA;EAAiB,MAAA;EAAgB,OAAA;EAAiB,SAAA;EAAmB,GAAA;AAAA;;;KCApF,aAAA;EAAkB,OAAA;EAAiB,OAAA;EAAiB,SAAA;EAAmB,WAAA;AAAA;;;cCEtE,iBAAA;EAAA,SAQO,aAAA,EAAe,aAAA;EAAA,iBACd,EAAA;EAAA,wBARK,oBAAA;EAAA,wBACA,mBAAA;EAAA,QAEhB,SAAA;EAAA,QACA,SAAA;cAGU,aAAA,EAAe,aAAA,EACd,EAAA,EAAI,SAAA;EAYhB,KAAA,CAAA;EAAA,QAKC,SAAA;EAAA,QAIA,IAAA;EAAA,QASA,UAAA;AAAA;;;KChCL,iBAAA;EAAsB,UAAA,EAAY,UAAA;EAAY,MAAA;AAAA;AAAA,cAEtC,oBAAA;EAAA,wBACa,mBAAA;EAAA,iBACP,KAAA;EAAA,iBACA,GAAA;EAAA,iBACA,MAAA;EAAA,iBACA,cAAA;EAAA,iBACA,KAAA;cAEL,IAAA;IACV,KAAA;IACA,GAAA,EAAK,iBAAA;IACL,MAAA;IACA,cAAA;IACA,KAAA;EAAA;EASW,UAAA,CAAA,GAAc,OAAA,CAAQ,iBAAA;EAAA,IAqDxB,aAAA,CAAA;EAAA,IASA,UAAA,CAAA;EAAA,eAKI,IAAA;EAAA,eAIA,mBAAA;EAAA,eAmBA,iBAAA;AAAA;;;cCjHJ,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,IAAA;EAAA;EAcK,OAAA,CAAQ,IAAA;IAAS,GAAA;EAAA,IAAgB,OAAA,CAAQ,oBAAA;EAAA,QAsBxC,aAAA;EAAA,QAIA,mBAAA;AAAA;;;cC7DH,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;;;iBCCQ,mBAAA,CAAoB,GAAA,WAAc,OAAA"}
package/dist/index.d.mts CHANGED
@@ -14,16 +14,28 @@ type Dapp = {
14
14
  type JwtPayload = {
15
15
  address: string;
16
16
  dappId: string;
17
+ message: string;
18
+ signature: string;
19
+ jwt: string;
20
+ };
21
+ //#endregion
22
+ //#region src/types/SessionClaims.d.ts
23
+ type SessionClaims = {
24
+ address: string;
25
+ message: string;
26
+ signature: string;
27
+ accessToken: string;
17
28
  };
18
29
  //#endregion
19
30
  //#region src/core/BananalinkSession.d.ts
20
31
  declare class BananalinkSession {
32
+ readonly sessionClaims: SessionClaims;
21
33
  private readonly ws;
22
34
  private static readonly PING_INTERVAL_MILLIS;
23
35
  private static readonly PONG_TIMEOUT_MILLIS;
24
36
  private pingTimer;
25
37
  private pongTimer;
26
- constructor(ws: WebSocket);
38
+ constructor(sessionClaims: SessionClaims, ws: WebSocket);
27
39
  close(): void;
28
40
  private startPing;
29
41
  private ping;
@@ -53,6 +65,8 @@ declare class BananalinkConnection {
53
65
  get connectionUrl(): string;
54
66
  get authorized(): boolean;
55
67
  private static bind;
68
+ private static isAuthorizedMessage;
69
+ private static isRejectedMessage;
56
70
  }
57
71
  //#endregion
58
72
  //#region src/core/BananalinkClient.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/Dapp.ts","../src/types/JwtPayload.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/utils/displayBananalinkQR.ts"],"mappings":";KAAY,IAAA;EACV,MAAA;EACA,QAAA;EACA,eAAA;EACA,aAAA;EACA,MAAA;EACA,GAAA;EACA,KAAA;EACA,OAAA;AAAA;;;KCRU,UAAA;EAAe,OAAA;EAAiB,MAAA;AAAA;;;cCA/B,iBAAA;EAAA,iBAOkB,EAAA;EAAA,wBANL,oBAAA;EAAA,wBACA,mBAAA;EAAA,QAEhB,SAAA;EAAA,QACA,SAAA;cAEqB,EAAA,EAAI,SAAA;EAW1B,KAAA,CAAA;EAAA,QAKC,SAAA;EAAA,QAIA,IAAA;EAAA,QASA,UAAA;AAAA;;;KC7BL,iBAAA;EAAsB,UAAA,EAAY,UAAA;EAAY,MAAA;AAAA;AAAA,cAEtC,oBAAA;EAAA,wBACa,mBAAA;EAAA,iBACP,KAAA;EAAA,iBACA,GAAA;EAAA,iBACA,MAAA;EAAA,iBACA,cAAA;EAAA,iBACA,KAAA;cAEL,IAAA;IACV,KAAA;IACA,GAAA,EAAK,iBAAA;IACL,MAAA;IACA,cAAA;IACA,KAAA;EAAA;EASW,UAAA,CAAA,GAAc,OAAA,CAAQ,iBAAA;EAAA,IA2CxB,aAAA,CAAA;EAAA,IASA,UAAA,CAAA;EAAA,eAKI,IAAA;AAAA;;;cC9EJ,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,IAAA;EAAA;EAcK,OAAA,CAAQ,IAAA;IAAS,GAAA;EAAA,IAAgB,OAAA,CAAQ,oBAAA;EAAA,QAsBxC,aAAA;EAAA,QAIA,mBAAA;AAAA;;;cC7DH,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;;;iBCCQ,mBAAA,CAAoB,GAAA,WAAc,OAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/Dapp.ts","../src/types/JwtPayload.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/utils/displayBananalinkQR.ts"],"mappings":";KAAY,IAAA;EACV,MAAA;EACA,QAAA;EACA,eAAA;EACA,aAAA;EACA,MAAA;EACA,GAAA;EACA,KAAA;EACA,OAAA;AAAA;;;KCRU,UAAA;EAAe,OAAA;EAAiB,MAAA;EAAgB,OAAA;EAAiB,SAAA;EAAmB,GAAA;AAAA;;;KCApF,aAAA;EAAkB,OAAA;EAAiB,OAAA;EAAiB,SAAA;EAAmB,WAAA;AAAA;;;cCEtE,iBAAA;EAAA,SAQO,aAAA,EAAe,aAAA;EAAA,iBACd,EAAA;EAAA,wBARK,oBAAA;EAAA,wBACA,mBAAA;EAAA,QAEhB,SAAA;EAAA,QACA,SAAA;cAGU,aAAA,EAAe,aAAA,EACd,EAAA,EAAI,SAAA;EAYhB,KAAA,CAAA;EAAA,QAKC,SAAA;EAAA,QAIA,IAAA;EAAA,QASA,UAAA;AAAA;;;KChCL,iBAAA;EAAsB,UAAA,EAAY,UAAA;EAAY,MAAA;AAAA;AAAA,cAEtC,oBAAA;EAAA,wBACa,mBAAA;EAAA,iBACP,KAAA;EAAA,iBACA,GAAA;EAAA,iBACA,MAAA;EAAA,iBACA,cAAA;EAAA,iBACA,KAAA;cAEL,IAAA;IACV,KAAA;IACA,GAAA,EAAK,iBAAA;IACL,MAAA;IACA,cAAA;IACA,KAAA;EAAA;EASW,UAAA,CAAA,GAAc,OAAA,CAAQ,iBAAA;EAAA,IAqDxB,aAAA,CAAA;EAAA,IASA,UAAA,CAAA;EAAA,eAKI,IAAA;EAAA,eAIA,mBAAA;EAAA,eAmBA,iBAAA;AAAA;;;cCjHJ,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,IAAA;EAAA;EAcK,OAAA,CAAQ,IAAA;IAAS,GAAA;EAAA,IAAgB,OAAA,CAAQ,oBAAA;EAAA,QAsBxC,aAAA;EAAA,QAIA,mBAAA;AAAA;;;cC7DH,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;;;iBCCQ,mBAAA,CAAoB,GAAA,WAAc,OAAA"}
package/dist/index.mjs CHANGED
@@ -62,11 +62,19 @@ async function verifyJwt(jwt, jwks) {
62
62
  const { payload } = await jwtVerify(jwt, jwks, {
63
63
  algorithms: ["ES256"],
64
64
  issuer: "bananalink",
65
- requiredClaims: ["sub", "aud"]
65
+ requiredClaims: [
66
+ "sub",
67
+ "aud",
68
+ "message",
69
+ "signature"
70
+ ]
66
71
  });
67
72
  return {
68
73
  address: payload.sub,
69
- dappId: Array.isArray(payload.aud) ? payload.aud[0] : payload.aud
74
+ dappId: Array.isArray(payload.aud) ? payload.aud[0] : payload.aud,
75
+ message: payload.message,
76
+ signature: payload.signature,
77
+ jwt
70
78
  };
71
79
  } catch {
72
80
  return null;
@@ -118,7 +126,8 @@ var BananalinkSession = class BananalinkSession {
118
126
  static PONG_TIMEOUT_MILLIS = 5 * 1e3;
119
127
  pingTimer = null;
120
128
  pongTimer = null;
121
- constructor(ws) {
129
+ constructor(sessionClaims, ws) {
130
+ this.sessionClaims = sessionClaims;
122
131
  this.ws = ws;
123
132
  this.ws.addEventListener("message", (event) => {
124
133
  const { type } = JSON.parse(event.data);
@@ -182,10 +191,15 @@ var BananalinkConnection = class BananalinkConnection {
182
191
  const msg = JSON.parse(event.data);
183
192
  clearTimeout(authTimeout);
184
193
  ws.removeEventListener("message", onMessage);
185
- if (msg.type === "authorized") {
194
+ if (BananalinkConnection.isAuthorizedMessage(msg)) {
186
195
  BananalinkConnection.bind(ws, msg.accessToken);
187
- resolve(new BananalinkSession(ws));
188
- } else if (msg.type === "rejected") {
196
+ resolve(new BananalinkSession({
197
+ address: msg.address,
198
+ message: msg.message,
199
+ signature: msg.signature,
200
+ accessToken: msg.accessToken
201
+ }, ws));
202
+ } else if (BananalinkConnection.isRejectedMessage(msg)) {
189
203
  ws.close();
190
204
  reject(new ConnectionRejectedError());
191
205
  }
@@ -210,6 +224,12 @@ var BananalinkConnection = class BananalinkConnection {
210
224
  jwt
211
225
  }));
212
226
  }
227
+ static isAuthorizedMessage(payload) {
228
+ return typeof payload === "object" && payload !== null && "type" in payload && payload.type === "authorized" && "accessToken" in payload && typeof payload.accessToken === "string" && "refreshToken" in payload && typeof payload.refreshToken === "string" && "message" in payload && typeof payload.message === "string" && "signature" in payload && typeof payload.signature === "string" && "address" in payload && typeof payload.address === "string";
229
+ }
230
+ static isRejectedMessage(payload) {
231
+ return typeof payload === "object" && payload !== null && "type" in payload && payload.type === "rejected";
232
+ }
213
233
  };
214
234
 
215
235
  //#endregion
@@ -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/jwt/createBananalinkJwks.ts","../src/jwt/verifyJwt.ts","../src/utils/isValidUrl.ts","../src/errors/ConnectionRejectedError.ts","../src/errors/ConnectionTimeoutError.ts","../src/errors/InvalidConnectionStateError.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 { DappApiError } from '../errors/DappApiError.js';\nimport type { CreateDappInstanceResponse } from '../types/CreateDappInstanceResponse.js';\nimport type { Dapp } from '../types/Dapp.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 { 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(jwt, jwks, {\n algorithms: ['ES256'],\n issuer: 'bananalink',\n requiredClaims: ['sub', 'aud'],\n });\n return {\n address: payload.sub as string,\n dappId: Array.isArray(payload.aud) ? payload.aud[0] : (payload.aud as string),\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","export class BananalinkSession {\n private static readonly PING_INTERVAL_MILLIS = 30 * 1000;\n private static readonly PONG_TIMEOUT_MILLIS = 5 * 1000;\n\n private pingTimer: ReturnType<typeof setInterval> | null = null;\n private pongTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(private readonly ws: WebSocket) {\n this.ws.addEventListener('message', (event) => {\n const { type } = JSON.parse(event.data);\n if (type === 'pong' && this.pongTimer) {\n clearTimeout(this.pongTimer);\n this.pongTimer = null;\n }\n });\n this.startPing();\n }\n\n public close(): void {\n this.stopTimers();\n this.ws.close();\n }\n\n private startPing(): void {\n this.pingTimer = setInterval(() => this.ping(), BananalinkSession.PING_INTERVAL_MILLIS);\n }\n\n private ping(): void {\n if (this.ws.readyState !== WebSocket.OPEN) {\n this.close();\n return;\n }\n this.ws.send(JSON.stringify({ type: 'ping' }));\n this.pongTimer = setTimeout(() => this.close(), BananalinkSession.PONG_TIMEOUT_MILLIS);\n }\n\n private stopTimers(): void {\n if (this.pingTimer !== null) {\n clearInterval(this.pingTimer);\n }\n if (this.pongTimer !== null) {\n clearTimeout(this.pongTimer);\n }\n this.pingTimer = null;\n this.pongTimer = null;\n }\n}\n","import { BananalinkError } from '../errors/BananalinkError.js';\nimport { ConnectionRejectedError } from '../errors/ConnectionRejectedError.js';\nimport { ConnectionTimeoutError } from '../errors/ConnectionTimeoutError.js';\nimport { InvalidConnectionStateError } from '../errors/InvalidConnectionStateError.js';\nimport type { JwtPayload } from '../types/JwtPayload.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 = 60 * 1000;\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\n constructor(opts: {\n wsUrl: string;\n jwt: BananalinkDappJwt;\n dappId: string;\n dappInstanceId: string | null;\n nonce: string | null;\n }) {\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 }\n\n public async getSession(): Promise<BananalinkSession> {\n if (this.jwt) {\n throw new BananalinkError('Recovering a lost dapp connection is not yet implemented');\n }\n\n const dappInstanceId = this.dappInstanceId;\n if (!dappInstanceId) {\n throw new InvalidConnectionStateError(\n 'Cannot get session without authorizing the dapp instance or providing a valid JWT',\n );\n }\n\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(`${this.wsUrl}?dappInstanceId=${encodeURIComponent(dappInstanceId)}`);\n\n const authTimeout = setTimeout(() => {\n ws.close();\n reject(new ConnectionTimeoutError());\n }, BananalinkConnection.AUTH_TIMEOUT_MILLIS);\n\n const onMessage = (event: MessageEvent): void => {\n const msg = JSON.parse(event.data);\n\n // cheating, but we don't expect any other type of message at this point\n clearTimeout(authTimeout);\n ws.removeEventListener('message', onMessage);\n\n if (msg.type === 'authorized') {\n BananalinkConnection.bind(ws, msg.accessToken);\n resolve(new BananalinkSession(ws));\n } else if (msg.type === 'rejected') {\n ws.close();\n reject(new ConnectionRejectedError());\n }\n };\n\n // TODO: abstract in a transport interface\n ws.addEventListener('message', onMessage);\n ws.addEventListener('error', () => {});\n ws.addEventListener('close', () => {});\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 get authorized(): boolean {\n // TODO: handle revocation\n return this.jwt !== undefined;\n }\n\n private static bind(ws: WebSocket, jwt: string) {\n ws.send(JSON.stringify({ type: 'bind', jwt: jwt }));\n }\n}\n","import { createDappInstance } from '../api/createDappInstance.js';\nimport { InvalidConfigError } from '../errors/InvalidConfigError.js';\nimport { createBananalinkJwks } from '../jwt/createBananalinkJwks.js';\nimport { verifyJwt } from '../jwt/verifyJwt.js';\nimport type { CreateDappInstanceResponse } from '../types/CreateDappInstanceResponse.js';\nimport type { Dapp } from '../types/Dapp.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 const jwtPayload = await (rawJwt ? this.getJwtPayload(rawJwt) : Promise.resolve(null));\n if (!jwtPayload || !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 wsUrl: this.wsUrl,\n });\n }\n return new BananalinkConnection({\n jwt: { jwtPayload, rawJwt },\n dappId: this.dapp.dappId,\n dappInstanceId: null,\n nonce: null,\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/jwt/createBananalinkJwks.ts","../src/jwt/verifyJwt.ts","../src/utils/isValidUrl.ts","../src/errors/ConnectionRejectedError.ts","../src/errors/ConnectionTimeoutError.ts","../src/errors/InvalidConnectionStateError.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 { DappApiError } from '../errors/DappApiError.js';\nimport type { CreateDappInstanceResponse } from '../types/CreateDappInstanceResponse.js';\nimport type { Dapp } from '../types/Dapp.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 { 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 type { SessionClaims } from '../types/SessionClaims.js';\n\nexport class BananalinkSession {\n private static readonly PING_INTERVAL_MILLIS = 30 * 1000;\n private static readonly PONG_TIMEOUT_MILLIS = 5 * 1000;\n\n private pingTimer: ReturnType<typeof setInterval> | null = null;\n private pongTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(\n public readonly sessionClaims: SessionClaims,\n private readonly ws: WebSocket,\n ) {\n this.ws.addEventListener('message', (event) => {\n const { type } = JSON.parse(event.data);\n if (type === 'pong' && this.pongTimer) {\n clearTimeout(this.pongTimer);\n this.pongTimer = null;\n }\n });\n this.startPing();\n }\n\n public close(): void {\n this.stopTimers();\n this.ws.close();\n }\n\n private startPing(): void {\n this.pingTimer = setInterval(() => this.ping(), BananalinkSession.PING_INTERVAL_MILLIS);\n }\n\n private ping(): void {\n if (this.ws.readyState !== WebSocket.OPEN) {\n this.close();\n return;\n }\n this.ws.send(JSON.stringify({ type: 'ping' }));\n this.pongTimer = setTimeout(() => this.close(), BananalinkSession.PONG_TIMEOUT_MILLIS);\n }\n\n private stopTimers(): void {\n if (this.pingTimer !== null) {\n clearInterval(this.pingTimer);\n }\n if (this.pongTimer !== null) {\n clearTimeout(this.pongTimer);\n }\n this.pingTimer = null;\n this.pongTimer = null;\n }\n}\n","import { BananalinkError } from '../errors/BananalinkError.js';\nimport { ConnectionRejectedError } from '../errors/ConnectionRejectedError.js';\nimport { ConnectionTimeoutError } from '../errors/ConnectionTimeoutError.js';\nimport { InvalidConnectionStateError } from '../errors/InvalidConnectionStateError.js';\nimport type { AuthorizedMessage } from '../types/AuthorizedMessage.js';\nimport type { JwtPayload } from '../types/JwtPayload.js';\nimport type { RejectedMessage } from '../types/RejectedMessage.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 = 60 * 1000;\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\n constructor(opts: {\n wsUrl: string;\n jwt: BananalinkDappJwt;\n dappId: string;\n dappInstanceId: string | null;\n nonce: string | null;\n }) {\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 }\n\n public async getSession(): Promise<BananalinkSession> {\n if (this.jwt) {\n throw new BananalinkError('Recovering a lost dapp connection is not yet implemented');\n }\n\n const dappInstanceId = this.dappInstanceId;\n if (!dappInstanceId) {\n throw new InvalidConnectionStateError(\n 'Cannot get session without authorizing the dapp instance or providing a valid JWT',\n );\n }\n\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(`${this.wsUrl}?dappInstanceId=${encodeURIComponent(dappInstanceId)}`);\n\n const authTimeout = setTimeout(() => {\n ws.close();\n reject(new ConnectionTimeoutError());\n }, BananalinkConnection.AUTH_TIMEOUT_MILLIS);\n\n const onMessage = (event: MessageEvent): void => {\n const msg = JSON.parse(event.data);\n\n // cheating, but we don't expect any other type of message at this point\n clearTimeout(authTimeout);\n ws.removeEventListener('message', onMessage);\n\n if (BananalinkConnection.isAuthorizedMessage(msg)) {\n BananalinkConnection.bind(ws, msg.accessToken);\n resolve(\n new BananalinkSession(\n {\n address: msg.address,\n message: msg.message,\n signature: msg.signature,\n accessToken: msg.accessToken,\n },\n ws,\n ),\n );\n } else if (BananalinkConnection.isRejectedMessage(msg)) {\n ws.close();\n reject(new ConnectionRejectedError());\n }\n };\n\n // TODO: abstract in a transport interface\n ws.addEventListener('message', onMessage);\n ws.addEventListener('error', () => {});\n ws.addEventListener('close', () => {});\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 get authorized(): boolean {\n // TODO: handle revocation\n return this.jwt !== undefined;\n }\n\n private static bind(ws: WebSocket, jwt: string) {\n ws.send(JSON.stringify({ type: 'bind', jwt: jwt }));\n }\n\n private static isAuthorizedMessage(payload: unknown): payload is AuthorizedMessage {\n return (\n typeof payload === 'object' &&\n payload !== null &&\n 'type' in payload &&\n payload.type === 'authorized' &&\n 'accessToken' in payload &&\n typeof payload.accessToken === 'string' &&\n 'refreshToken' in payload &&\n typeof payload.refreshToken === 'string' &&\n 'message' in payload &&\n typeof payload.message === 'string' &&\n 'signature' in payload &&\n typeof payload.signature === 'string' &&\n 'address' in payload &&\n typeof payload.address === 'string'\n );\n }\n\n private static isRejectedMessage(payload: unknown): payload is RejectedMessage {\n return typeof payload === 'object' && payload !== null && 'type' in payload && payload.type === 'rejected';\n }\n}\n","import { createDappInstance } from '../api/createDappInstance.js';\nimport { InvalidConfigError } from '../errors/InvalidConfigError.js';\nimport { createBananalinkJwks } from '../jwt/createBananalinkJwks.js';\nimport { verifyJwt } from '../jwt/verifyJwt.js';\nimport type { CreateDappInstanceResponse } from '../types/CreateDappInstanceResponse.js';\nimport type { Dapp } from '../types/Dapp.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 const jwtPayload = await (rawJwt ? this.getJwtPayload(rawJwt) : Promise.resolve(null));\n if (!jwtPayload || !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 wsUrl: this.wsUrl,\n });\n }\n return new BananalinkConnection({\n jwt: { jwtPayload, rawJwt },\n dappId: this.dapp.dappId,\n dappInstanceId: null,\n nonce: null,\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananalink-test/client",
3
- "version": "0.0.0",
3
+ "version": "0.1.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "sideEffects": false,