@bananalink-test/hub 1.1.1

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 ADDED
@@ -0,0 +1,364 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let _bananalink_test_sdk_core = require("@bananalink-test/sdk-core");
3
+
4
+ //#region src/errors/BananalinkError.ts
5
+ var BananalinkError = class extends Error {
6
+ constructor(message, options) {
7
+ super(message, options);
8
+ this.name = "BananalinkError";
9
+ }
10
+ };
11
+
12
+ //#endregion
13
+ //#region src/errors/ApiError.ts
14
+ var ApiError = class extends BananalinkError {
15
+ status;
16
+ body;
17
+ constructor(status, body) {
18
+ super(`API request failed with status ${status}`);
19
+ this.name = "ApiError";
20
+ this.status = status;
21
+ this.body = body;
22
+ }
23
+ };
24
+
25
+ //#endregion
26
+ //#region src/api/fetchAgent.ts
27
+ async function fetchAgent(apiUrl, agentPairingCode) {
28
+ const response = await fetch(`${apiUrl}/agents/${encodeURIComponent(agentPairingCode)}`);
29
+ if (!response.ok) {
30
+ const body = await response.json().catch(() => null);
31
+ throw new ApiError(response.status, body);
32
+ }
33
+ const body = await response.json();
34
+ if (!isAgent(body)) throw new ApiError(response.status, body);
35
+ return body;
36
+ }
37
+ function isAgent(value) {
38
+ if (typeof value !== "object" || value === null) return false;
39
+ const record = value;
40
+ return typeof record.agentId === "string" && typeof record.agentName === "string";
41
+ }
42
+
43
+ //#endregion
44
+ //#region src/api/fetchVapidKey.ts
45
+ async function fetchVapidKey(apiUrl = "https://api.dev.banana.link") {
46
+ const response = await fetch(`${apiUrl}/push/vapid-key`);
47
+ if (!response.ok) {
48
+ const body = await response.json().catch(() => null);
49
+ throw new ApiError(response.status, body);
50
+ }
51
+ const body = await response.json();
52
+ if (typeof body !== "object" || body === null || !("publicKey" in body)) throw new ApiError(response.status, body);
53
+ const { publicKey } = body;
54
+ if (typeof publicKey !== "string" || publicKey.length === 0) throw new ApiError(response.status, body);
55
+ return { publicKey };
56
+ }
57
+
58
+ //#endregion
59
+ //#region src/api/refreshHubTokens.ts
60
+ async function refreshHubTokens(apiUrl, refreshToken) {
61
+ const response = await fetch(`${apiUrl}/hubs/tokens/refresh`, {
62
+ method: "POST",
63
+ headers: { "Content-Type": "application/json" },
64
+ body: JSON.stringify({ refreshToken })
65
+ });
66
+ if (!response.ok) {
67
+ const responseBody = await response.json().catch(() => null);
68
+ throw new ApiError(response.status, responseBody);
69
+ }
70
+ const responseBody = await response.json().catch(() => null);
71
+ if (!isTokenPair$1(responseBody)) throw new ApiError(response.status, responseBody);
72
+ return responseBody;
73
+ }
74
+ function isTokenPair$1(value) {
75
+ if (typeof value !== "object" || value === null) return false;
76
+ return "accessToken" in value && typeof value.accessToken === "string" && "refreshToken" in value && typeof value.refreshToken === "string";
77
+ }
78
+
79
+ //#endregion
80
+ //#region src/api/registerHub.ts
81
+ async function registerHub(apiUrl) {
82
+ const response = await fetch(`${apiUrl}/hubs`, { method: "POST" });
83
+ if (!response.ok) {
84
+ const responseBody = await response.json().catch(() => null);
85
+ throw new ApiError(response.status, responseBody);
86
+ }
87
+ const responseBody = await response.json().catch(() => null);
88
+ if (!isTokenPair(responseBody)) throw new ApiError(response.status, responseBody);
89
+ return responseBody;
90
+ }
91
+ function isTokenPair(value) {
92
+ if (typeof value !== "object" || value === null) return false;
93
+ return "accessToken" in value && typeof value.accessToken === "string" && "refreshToken" in value && typeof value.refreshToken === "string";
94
+ }
95
+
96
+ //#endregion
97
+ //#region src/api/deleteAgentTokens.ts
98
+ async function deleteAgentTokens(apiUrl, agentId, accessToken) {
99
+ const response = await fetch(`${apiUrl}/hubs/agents/${encodeURIComponent(agentId)}/tokens`, {
100
+ method: "DELETE",
101
+ headers: {
102
+ "Content-Type": "application/json",
103
+ Authorization: `Bearer ${accessToken}`
104
+ }
105
+ });
106
+ if (!response.ok) {
107
+ const responseBody = await response.json().catch(() => null);
108
+ throw new ApiError(response.status, responseBody);
109
+ }
110
+ }
111
+
112
+ //#endregion
113
+ //#region src/errors/BindError.ts
114
+ var BindError = class extends BananalinkError {
115
+ constructor(error) {
116
+ super(`Hub bind failed with error: ${error}`);
117
+ this.error = error;
118
+ this.name = "BindError";
119
+ }
120
+ };
121
+
122
+ //#endregion
123
+ //#region src/errors/ConnectionError.ts
124
+ var ConnectionError = class extends BananalinkError {
125
+ constructor(message, options) {
126
+ super(message, options);
127
+ this.name = "ConnectionError";
128
+ }
129
+ };
130
+
131
+ //#endregion
132
+ //#region src/errors/NotConnectedError.ts
133
+ var NotConnectedError = class extends BananalinkError {
134
+ constructor() {
135
+ super("Hub is not connected. Call connect() first.");
136
+ this.name = "NotConnectedError";
137
+ }
138
+ };
139
+
140
+ //#endregion
141
+ //#region src/ws/createConnectionRequest.ts
142
+ function createConnectionRequest(params) {
143
+ return {
144
+ agentPairingCode: params.agentPairingCode,
145
+ agent: params.agent,
146
+ async approve() {
147
+ const authorizeMessage = {
148
+ type: "authorize",
149
+ code: params.agentPairingCode
150
+ };
151
+ params.ws.send(authorizeMessage);
152
+ },
153
+ async reject() {
154
+ const rejectMessage = {
155
+ type: "reject",
156
+ code: params.agentPairingCode
157
+ };
158
+ params.ws.send(rejectMessage);
159
+ }
160
+ };
161
+ }
162
+
163
+ //#endregion
164
+ //#region src/ws/createMessageRequest.ts
165
+ function createMessageRequest(message, ws) {
166
+ return {
167
+ messageId: message.messageId,
168
+ agentId: message.agentId,
169
+ method: message.method,
170
+ payload: message.payload,
171
+ respond(status, payloadResponse) {
172
+ const response = {
173
+ type: "message_response",
174
+ msgId: message.messageId,
175
+ status,
176
+ payloadResponse
177
+ };
178
+ ws.send(response);
179
+ }
180
+ };
181
+ }
182
+
183
+ //#endregion
184
+ //#region src/ws/createTransactionRequest.ts
185
+ function createTransactionRequest(message, ws) {
186
+ const base = createMessageRequest(message, ws);
187
+ return {
188
+ ...base,
189
+ payload: base.payload[0],
190
+ approve(result) {
191
+ base.respond("approved", result);
192
+ },
193
+ reject(reason) {
194
+ base.respond("rejected", reason);
195
+ }
196
+ };
197
+ }
198
+
199
+ //#endregion
200
+ //#region src/core/BananalinkHub.ts
201
+ var BananalinkHub = class BananalinkHub {
202
+ static DEFAULT_API_URL = "https://api.dev.banana.link";
203
+ static DEFAULT_WS_URL = "wss://ws.dev.banana.link";
204
+ static BIND_RESPONSE_TIMEOUT_MILLIS = 20 * 1e3;
205
+ apiUrl;
206
+ wsUrl;
207
+ ws = null;
208
+ accessToken = null;
209
+ transactionHandler = null;
210
+ unsubscribeMessages = null;
211
+ constructor(config) {
212
+ this.apiUrl = stripTrailingSlash(config?.apiUrl ?? BananalinkHub.DEFAULT_API_URL);
213
+ this.wsUrl = stripTrailingSlash(config?.wsUrl ?? BananalinkHub.DEFAULT_WS_URL);
214
+ }
215
+ async connect(accessToken) {
216
+ if (!accessToken.trim()) throw new BananalinkError("accessToken is required");
217
+ this.disconnect();
218
+ let transportHandle;
219
+ try {
220
+ transportHandle = await this.getTransportHandle();
221
+ } catch (error) {
222
+ throw new ConnectionError("Unable to establish hub websocket connection", { cause: error });
223
+ }
224
+ try {
225
+ await this.bind(transportHandle, accessToken);
226
+ this.accessToken = accessToken;
227
+ this.ws = (0, _bananalink_test_sdk_core.createReconnectingTransport)(transportHandle, {
228
+ reconnectTransport: async () => this.getTransportHandle(),
229
+ onReconnect: async (th) => this.bind(th, accessToken),
230
+ maxReconnectAttempts: 5,
231
+ baseDelayReconnectMs: 1e3
232
+ });
233
+ } catch (error) {
234
+ transportHandle.close();
235
+ throw error;
236
+ }
237
+ this.listenForMessages(this.ws);
238
+ }
239
+ disconnect() {
240
+ this.unsubscribeMessages?.();
241
+ this.unsubscribeMessages = null;
242
+ this.ws?.close();
243
+ this.ws = null;
244
+ }
245
+ subscribePush(subscription) {
246
+ if (!this.ws) throw new NotConnectedError();
247
+ if (!subscription.endpoint.trim()) throw new BananalinkError("subscription endpoint is required");
248
+ if (!subscription.keys.auth.trim()) throw new BananalinkError("subscription keys.auth is required");
249
+ if (!subscription.keys.p256dh.trim()) throw new BananalinkError("subscription keys.p256dh is required");
250
+ const message = {
251
+ type: "subscribe_push",
252
+ subscription
253
+ };
254
+ this.ws.send(message);
255
+ }
256
+ unsubscribePush(endpoint) {
257
+ if (!this.ws) throw new NotConnectedError();
258
+ if (!endpoint.trim()) throw new BananalinkError("subscription endpoint is required");
259
+ const message = {
260
+ type: "unsubscribe_push",
261
+ endpoint
262
+ };
263
+ this.ws.send(message);
264
+ }
265
+ onTransactionRequest(handler) {
266
+ this.transactionHandler = handler;
267
+ return () => {
268
+ this.transactionHandler = null;
269
+ };
270
+ }
271
+ async getConnectionRequest(params) {
272
+ if (!this.ws) throw new NotConnectedError();
273
+ if (!params.agentPairingCode.trim()) throw new BananalinkError("agentPairingCode is required");
274
+ const agent = await fetchAgent(this.apiUrl, params.agentPairingCode);
275
+ return createConnectionRequest({
276
+ agentPairingCode: params.agentPairingCode,
277
+ agent,
278
+ ws: this.ws
279
+ });
280
+ }
281
+ async revoke(params) {
282
+ if (!params.agentId.trim()) throw new BananalinkError("agentId is required");
283
+ if (!this.accessToken) throw new BananalinkError("accessToken is required");
284
+ await deleteAgentTokens(this.apiUrl, params.agentId, this.accessToken);
285
+ }
286
+ listenForMessages(ws) {
287
+ this.unsubscribeMessages = ws.onMessage((payload) => {
288
+ if (!(0, _bananalink_test_sdk_core.isMessageRequestMessage)(payload)) return;
289
+ if (payload.method === _bananalink_test_sdk_core.MESSAGE_METHOD_SEND_TRANSACTION && this.transactionHandler) this.dispatchTransactionRequest(this.transactionHandler, payload, ws);
290
+ });
291
+ }
292
+ dispatchTransactionRequest(handler, payload, ws) {
293
+ const request = createTransactionRequest(payload, ws);
294
+ const safeReject = (error) => {
295
+ try {
296
+ const message = error instanceof Error ? error.message : String(error);
297
+ request.reject(`transaction handler failed: ${message}`);
298
+ } catch {}
299
+ };
300
+ try {
301
+ Promise.resolve(handler(request)).catch(safeReject);
302
+ } catch (error) {
303
+ safeReject(error);
304
+ }
305
+ }
306
+ async getTransportHandle() {
307
+ return await (0, _bananalink_test_sdk_core.connectWebSocket)({
308
+ url: this.wsUrl,
309
+ pingIntervalMs: 3e4,
310
+ pongTimeoutMs: 5e3,
311
+ maxReconnectAttempts: 0
312
+ });
313
+ }
314
+ async bind(ws, accessToken) {
315
+ try {
316
+ await (0, _bananalink_test_sdk_core.bindTransport)(ws, accessToken, {
317
+ timeoutMs: BananalinkHub.BIND_RESPONSE_TIMEOUT_MILLIS,
318
+ createClosedError: () => new ConnectionError("Connection closed unexpectedly while waiting for hub bind response"),
319
+ createTimeoutError: () => new ConnectionError("Timed out waiting for hub bind response")
320
+ });
321
+ } catch (error) {
322
+ if (error instanceof _bananalink_test_sdk_core.BindTransportError) throw new BindError(error.code);
323
+ throw error;
324
+ }
325
+ }
326
+ };
327
+ function stripTrailingSlash(url) {
328
+ return url.replace(/\/+$/, "");
329
+ }
330
+
331
+ //#endregion
332
+ //#region src/utils/buildSiweMessage.ts
333
+ function buildSiweMessage(params) {
334
+ const issuedAt = params.issuedAt ?? (/* @__PURE__ */ new Date()).toISOString();
335
+ return `${params.domain} wants you to sign in with your Ethereum account:\n${params.address}\n\n${params.statement}\n\nURI: ${params.uri}\nVersion: 1\nChain ID: ${params.chainId}\nNonce: ${params.nonce}\nIssued At: ${issuedAt}`;
336
+ }
337
+
338
+ //#endregion
339
+ //#region src/utils/parseDeepLink.ts
340
+ function parseDeepLink(deepLink) {
341
+ let url;
342
+ try {
343
+ url = new URL(deepLink);
344
+ } catch (error) {
345
+ throw new BananalinkError("Invalid deep link URL", { cause: error });
346
+ }
347
+ const code = url.searchParams.get("code");
348
+ if (!code) throw new BananalinkError("Invalid deep link: missing agent pairing code");
349
+ return { code };
350
+ }
351
+
352
+ //#endregion
353
+ exports.ApiError = ApiError;
354
+ exports.BananalinkError = BananalinkError;
355
+ exports.BananalinkHub = BananalinkHub;
356
+ exports.BindError = BindError;
357
+ exports.ConnectionError = ConnectionError;
358
+ exports.NotConnectedError = NotConnectedError;
359
+ exports.buildSiweMessage = buildSiweMessage;
360
+ exports.fetchAgent = fetchAgent;
361
+ exports.fetchVapidKey = fetchVapidKey;
362
+ exports.parseDeepLink = parseDeepLink;
363
+ exports.refreshHubTokens = refreshHubTokens;
364
+ exports.registerHub = registerHub;
@@ -0,0 +1,146 @@
1
+ import { Agent, Agent as Agent$1, ConnectionRequestParams, ConnectionRequestParams as ConnectionRequestParams$1, DeepLinkParams, DeepLinkParams as DeepLinkParams$1, EthSendTransactionParams, EthSendTransactionParams as EthSendTransactionParams$1, EthSendTransactionResult, EthSendTransactionResult as EthSendTransactionResult$1 } from "@bananalink-test/sdk-core";
2
+
3
+ //#region src/api/fetchAgent.d.ts
4
+ declare function fetchAgent(apiUrl: string, agentPairingCode: string): Promise<Agent$1>;
5
+ //#endregion
6
+ //#region src/api/fetchVapidKey.d.ts
7
+ declare function fetchVapidKey(apiUrl?: string): Promise<{
8
+ publicKey: string;
9
+ }>;
10
+ //#endregion
11
+ //#region src/types/TokenPair.d.ts
12
+ type TokenPair = {
13
+ accessToken: string;
14
+ refreshToken: string;
15
+ };
16
+ //#endregion
17
+ //#region src/api/refreshHubTokens.d.ts
18
+ declare function refreshHubTokens(apiUrl: string, refreshToken: string): Promise<TokenPair>;
19
+ //#endregion
20
+ //#region src/api/registerHub.d.ts
21
+ declare function registerHub(apiUrl: string): Promise<TokenPair>;
22
+ //#endregion
23
+ //#region src/types/PushSubscriptionParams.d.ts
24
+ type PushSubscriptionParams = {
25
+ endpoint: string;
26
+ keys: {
27
+ p256dh: string;
28
+ auth: string;
29
+ };
30
+ };
31
+ //#endregion
32
+ //#region src/types/RevokeParams.d.ts
33
+ interface RevokeParams {
34
+ agentId: string;
35
+ }
36
+ //#endregion
37
+ //#region src/ws/MessageRequest.d.ts
38
+ interface MessageRequest<TPayload> {
39
+ readonly messageId: string;
40
+ readonly agentId: string;
41
+ readonly method: string;
42
+ readonly payload: TPayload;
43
+ respond(status: string, payloadResponse?: unknown): void;
44
+ }
45
+ //#endregion
46
+ //#region src/ws/TransactionRequest.d.ts
47
+ interface TransactionRequest extends MessageRequest<EthSendTransactionParams$1> {
48
+ approve(result: EthSendTransactionResult$1): void;
49
+ reject(reason?: string): void;
50
+ }
51
+ //#endregion
52
+ //#region src/types/TransactionRequestHandler.d.ts
53
+ type TransactionRequestHandler = (request: TransactionRequest) => void | Promise<void>;
54
+ //#endregion
55
+ //#region src/ws/ConnectionRequest.d.ts
56
+ interface ConnectionRequest {
57
+ readonly agentPairingCode: string;
58
+ readonly agent: Agent$1;
59
+ approve(): Promise<void>;
60
+ reject(): Promise<void>;
61
+ }
62
+ //#endregion
63
+ //#region src/core/BananalinkHubConfig.d.ts
64
+ interface BananalinkHubConfig {
65
+ apiUrl?: string;
66
+ wsUrl?: string;
67
+ }
68
+ //#endregion
69
+ //#region src/core/BananalinkHub.d.ts
70
+ declare class BananalinkHub {
71
+ private static readonly DEFAULT_API_URL;
72
+ private static readonly DEFAULT_WS_URL;
73
+ private static readonly BIND_RESPONSE_TIMEOUT_MILLIS;
74
+ private readonly apiUrl;
75
+ private readonly wsUrl;
76
+ private ws;
77
+ private accessToken;
78
+ private transactionHandler;
79
+ private unsubscribeMessages;
80
+ constructor(config?: BananalinkHubConfig);
81
+ connect(accessToken: string): Promise<void>;
82
+ disconnect(): void;
83
+ subscribePush(subscription: PushSubscriptionParams): void;
84
+ unsubscribePush(endpoint: string): void;
85
+ onTransactionRequest(handler: TransactionRequestHandler): () => void;
86
+ getConnectionRequest(params: ConnectionRequestParams$1): Promise<ConnectionRequest>;
87
+ revoke(params: RevokeParams): Promise<void>;
88
+ private listenForMessages;
89
+ private dispatchTransactionRequest;
90
+ private getTransportHandle;
91
+ private bind;
92
+ }
93
+ //#endregion
94
+ //#region src/errors/BananalinkError.d.ts
95
+ declare class BananalinkError extends Error {
96
+ constructor(message: string, options?: ErrorOptions);
97
+ }
98
+ //#endregion
99
+ //#region src/errors/ApiError.d.ts
100
+ declare class ApiError extends BananalinkError {
101
+ readonly status: number;
102
+ readonly body: unknown;
103
+ constructor(status: number, body: unknown);
104
+ }
105
+ //#endregion
106
+ //#region src/errors/BindError.d.ts
107
+ declare class BindError extends BananalinkError {
108
+ readonly error: 'INVALID_JWT' | 'JWT_EXPIRED';
109
+ constructor(error: 'INVALID_JWT' | 'JWT_EXPIRED');
110
+ }
111
+ //#endregion
112
+ //#region src/errors/ConnectionError.d.ts
113
+ declare class ConnectionError extends BananalinkError {
114
+ constructor(message: string, options?: ErrorOptions);
115
+ }
116
+ //#endregion
117
+ //#region src/errors/NotConnectedError.d.ts
118
+ declare class NotConnectedError extends BananalinkError {
119
+ constructor();
120
+ }
121
+ //#endregion
122
+ //#region src/types/BuildSiweMessageParams.d.ts
123
+ interface BuildSiweMessageParams {
124
+ domain: string;
125
+ address: string;
126
+ uri: string;
127
+ statement: string;
128
+ nonce: string;
129
+ chainId: number;
130
+ issuedAt?: string;
131
+ }
132
+ //#endregion
133
+ //#region src/types/Signer.d.ts
134
+ interface Signer {
135
+ address: string;
136
+ signMessage: (message: string) => Promise<string>;
137
+ }
138
+ //#endregion
139
+ //#region src/utils/buildSiweMessage.d.ts
140
+ declare function buildSiweMessage(params: BuildSiweMessageParams): string;
141
+ //#endregion
142
+ //#region src/utils/parseDeepLink.d.ts
143
+ declare function parseDeepLink(deepLink: string): DeepLinkParams$1;
144
+ //#endregion
145
+ export { type Agent, ApiError, BananalinkError, BananalinkHub, type BananalinkHubConfig, BindError, type BuildSiweMessageParams, ConnectionError, type ConnectionRequest, type ConnectionRequestParams, type DeepLinkParams, type EthSendTransactionParams, type EthSendTransactionResult, type MessageRequest, NotConnectedError, type PushSubscriptionParams, type RevokeParams, type Signer, type TokenPair, type TransactionRequest, type TransactionRequestHandler, buildSiweMessage, fetchAgent, fetchVapidKey, parseDeepLink, refreshHubTokens, registerHub };
146
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/api/fetchAgent.ts","../src/api/fetchVapidKey.ts","../src/types/TokenPair.ts","../src/api/refreshHubTokens.ts","../src/api/registerHub.ts","../src/types/PushSubscriptionParams.ts","../src/types/RevokeParams.ts","../src/ws/MessageRequest.ts","../src/ws/TransactionRequest.ts","../src/types/TransactionRequestHandler.ts","../src/ws/ConnectionRequest.ts","../src/core/BananalinkHubConfig.ts","../src/core/BananalinkHub.ts","../src/errors/BananalinkError.ts","../src/errors/ApiError.ts","../src/errors/BindError.ts","../src/errors/ConnectionError.ts","../src/errors/NotConnectedError.ts","../src/types/BuildSiweMessageParams.ts","../src/types/Signer.ts","../src/utils/buildSiweMessage.ts","../src/utils/parseDeepLink.ts"],"mappings":";;;iBAGsB,UAAA,CAAW,MAAA,UAAgB,gBAAA,WAA2B,OAAA,CAAQ,OAAA;;;iBCD9D,aAAA,CAAc,MAAA,YAAiD,OAAA;EAAU,SAAA;AAAA;;;KCFnF,SAAA;EACV,WAAA;EACA,YAAA;AAAA;;;iBCCoB,gBAAA,CAAiB,MAAA,UAAgB,YAAA,WAAuB,OAAA,CAAQ,SAAA;;;iBCAhE,WAAA,CAAY,MAAA,WAAiB,OAAA,CAAQ,SAAA;;;KCH/C,sBAAA;EAA2B,QAAA;EAAkB,IAAA;IAAQ,MAAA;IAAgB,IAAA;EAAA;AAAA;;;UCAhE,YAAA;EACf,OAAA;AAAA;;;UCDe,cAAA;EAAA,SACN,SAAA;EAAA,SACA,OAAA;EAAA,SACA,MAAA;EAAA,SACA,OAAA,EAAS,QAAA;EAClB,OAAA,CAAQ,MAAA,UAAgB,eAAA;AAAA;;;UCFT,kBAAA,SAA2B,cAAA,CAAe,0BAAA;EACzD,OAAA,CAAQ,MAAA,EAAQ,0BAAA;EAChB,MAAA,CAAO,MAAA;AAAA;;;KCHG,yBAAA,IAA6B,OAAA,EAAS,kBAAA,YAA8B,OAAA;;;UCA/D,iBAAA;EAAA,SACN,gBAAA;EAAA,SACA,KAAA,EAAO,OAAA;EAChB,OAAA,IAAW,OAAA;EACX,MAAA,IAAU,OAAA;AAAA;;;UCNK,mBAAA;EACf,MAAA;EACA,KAAA;AAAA;;;cCyBW,aAAA;EAAA,wBACa,eAAA;EAAA,wBACA,cAAA;EAAA,wBACA,4BAAA;EAAA,iBAEP,MAAA;EAAA,iBACA,KAAA;EAAA,QACT,EAAA;EAAA,QACA,WAAA;EAAA,QACA,kBAAA;EAAA,QACA,mBAAA;cAEI,MAAA,GAAS,mBAAA;EAKf,OAAA,CAAQ,WAAA,WAAsB,OAAA;EAgCpC,UAAA,CAAA;EAOA,aAAA,CAAc,YAAA,EAAc,sBAAA;EAyB5B,eAAA,CAAgB,QAAA;EAiBhB,oBAAA,CAAqB,OAAA,EAAS,yBAAA;EAQxB,oBAAA,CAAqB,MAAA,EAAQ,yBAAA,GAA0B,OAAA,CAAQ,iBAAA;EAkB/D,MAAA,CAAO,MAAA,EAAQ,YAAA,GAAe,OAAA;EAAA,QAW5B,iBAAA;EAAA,QAYA,0BAAA;EAAA,QAqBM,kBAAA;EAAA,QASA,IAAA;AAAA;;;cC5MH,eAAA,SAAwB,KAAA;cACvB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;;;cCC5B,QAAA,SAAiB,eAAA;EAAA,SACZ,MAAA;EAAA,SACA,IAAA;cAEJ,MAAA,UAAgB,IAAA;AAAA;;;cCJjB,SAAA,SAAkB,eAAA;EAAA,SACD,KAAA;cAAA,KAAA;AAAA;;;cCDjB,eAAA,SAAwB,eAAA;cACvB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;;;cCD5B,iBAAA,SAA0B,eAAA;EAAA,WAAA,CAAA;AAAA;;;UCFtB,sBAAA;EACf,MAAA;EACA,OAAA;EACA,GAAA;EACA,SAAA;EACA,KAAA;EACA,OAAA;EACA,QAAA;AAAA;;;UCPe,MAAA;EACf,OAAA;EACA,WAAA,GAAc,OAAA,aAAoB,OAAA;AAAA;;;iBCApB,gBAAA,CAAiB,MAAA,EAAQ,sBAAA;;;iBCCzB,aAAA,CAAc,QAAA,WAAmB,gBAAA"}
@@ -0,0 +1,146 @@
1
+ import { Agent, Agent as Agent$1, ConnectionRequestParams, ConnectionRequestParams as ConnectionRequestParams$1, DeepLinkParams, DeepLinkParams as DeepLinkParams$1, EthSendTransactionParams, EthSendTransactionParams as EthSendTransactionParams$1, EthSendTransactionResult, EthSendTransactionResult as EthSendTransactionResult$1 } from "@bananalink-test/sdk-core";
2
+
3
+ //#region src/api/fetchAgent.d.ts
4
+ declare function fetchAgent(apiUrl: string, agentPairingCode: string): Promise<Agent$1>;
5
+ //#endregion
6
+ //#region src/api/fetchVapidKey.d.ts
7
+ declare function fetchVapidKey(apiUrl?: string): Promise<{
8
+ publicKey: string;
9
+ }>;
10
+ //#endregion
11
+ //#region src/types/TokenPair.d.ts
12
+ type TokenPair = {
13
+ accessToken: string;
14
+ refreshToken: string;
15
+ };
16
+ //#endregion
17
+ //#region src/api/refreshHubTokens.d.ts
18
+ declare function refreshHubTokens(apiUrl: string, refreshToken: string): Promise<TokenPair>;
19
+ //#endregion
20
+ //#region src/api/registerHub.d.ts
21
+ declare function registerHub(apiUrl: string): Promise<TokenPair>;
22
+ //#endregion
23
+ //#region src/types/PushSubscriptionParams.d.ts
24
+ type PushSubscriptionParams = {
25
+ endpoint: string;
26
+ keys: {
27
+ p256dh: string;
28
+ auth: string;
29
+ };
30
+ };
31
+ //#endregion
32
+ //#region src/types/RevokeParams.d.ts
33
+ interface RevokeParams {
34
+ agentId: string;
35
+ }
36
+ //#endregion
37
+ //#region src/ws/MessageRequest.d.ts
38
+ interface MessageRequest<TPayload> {
39
+ readonly messageId: string;
40
+ readonly agentId: string;
41
+ readonly method: string;
42
+ readonly payload: TPayload;
43
+ respond(status: string, payloadResponse?: unknown): void;
44
+ }
45
+ //#endregion
46
+ //#region src/ws/TransactionRequest.d.ts
47
+ interface TransactionRequest extends MessageRequest<EthSendTransactionParams$1> {
48
+ approve(result: EthSendTransactionResult$1): void;
49
+ reject(reason?: string): void;
50
+ }
51
+ //#endregion
52
+ //#region src/types/TransactionRequestHandler.d.ts
53
+ type TransactionRequestHandler = (request: TransactionRequest) => void | Promise<void>;
54
+ //#endregion
55
+ //#region src/ws/ConnectionRequest.d.ts
56
+ interface ConnectionRequest {
57
+ readonly agentPairingCode: string;
58
+ readonly agent: Agent$1;
59
+ approve(): Promise<void>;
60
+ reject(): Promise<void>;
61
+ }
62
+ //#endregion
63
+ //#region src/core/BananalinkHubConfig.d.ts
64
+ interface BananalinkHubConfig {
65
+ apiUrl?: string;
66
+ wsUrl?: string;
67
+ }
68
+ //#endregion
69
+ //#region src/core/BananalinkHub.d.ts
70
+ declare class BananalinkHub {
71
+ private static readonly DEFAULT_API_URL;
72
+ private static readonly DEFAULT_WS_URL;
73
+ private static readonly BIND_RESPONSE_TIMEOUT_MILLIS;
74
+ private readonly apiUrl;
75
+ private readonly wsUrl;
76
+ private ws;
77
+ private accessToken;
78
+ private transactionHandler;
79
+ private unsubscribeMessages;
80
+ constructor(config?: BananalinkHubConfig);
81
+ connect(accessToken: string): Promise<void>;
82
+ disconnect(): void;
83
+ subscribePush(subscription: PushSubscriptionParams): void;
84
+ unsubscribePush(endpoint: string): void;
85
+ onTransactionRequest(handler: TransactionRequestHandler): () => void;
86
+ getConnectionRequest(params: ConnectionRequestParams$1): Promise<ConnectionRequest>;
87
+ revoke(params: RevokeParams): Promise<void>;
88
+ private listenForMessages;
89
+ private dispatchTransactionRequest;
90
+ private getTransportHandle;
91
+ private bind;
92
+ }
93
+ //#endregion
94
+ //#region src/errors/BananalinkError.d.ts
95
+ declare class BananalinkError extends Error {
96
+ constructor(message: string, options?: ErrorOptions);
97
+ }
98
+ //#endregion
99
+ //#region src/errors/ApiError.d.ts
100
+ declare class ApiError extends BananalinkError {
101
+ readonly status: number;
102
+ readonly body: unknown;
103
+ constructor(status: number, body: unknown);
104
+ }
105
+ //#endregion
106
+ //#region src/errors/BindError.d.ts
107
+ declare class BindError extends BananalinkError {
108
+ readonly error: 'INVALID_JWT' | 'JWT_EXPIRED';
109
+ constructor(error: 'INVALID_JWT' | 'JWT_EXPIRED');
110
+ }
111
+ //#endregion
112
+ //#region src/errors/ConnectionError.d.ts
113
+ declare class ConnectionError extends BananalinkError {
114
+ constructor(message: string, options?: ErrorOptions);
115
+ }
116
+ //#endregion
117
+ //#region src/errors/NotConnectedError.d.ts
118
+ declare class NotConnectedError extends BananalinkError {
119
+ constructor();
120
+ }
121
+ //#endregion
122
+ //#region src/types/BuildSiweMessageParams.d.ts
123
+ interface BuildSiweMessageParams {
124
+ domain: string;
125
+ address: string;
126
+ uri: string;
127
+ statement: string;
128
+ nonce: string;
129
+ chainId: number;
130
+ issuedAt?: string;
131
+ }
132
+ //#endregion
133
+ //#region src/types/Signer.d.ts
134
+ interface Signer {
135
+ address: string;
136
+ signMessage: (message: string) => Promise<string>;
137
+ }
138
+ //#endregion
139
+ //#region src/utils/buildSiweMessage.d.ts
140
+ declare function buildSiweMessage(params: BuildSiweMessageParams): string;
141
+ //#endregion
142
+ //#region src/utils/parseDeepLink.d.ts
143
+ declare function parseDeepLink(deepLink: string): DeepLinkParams$1;
144
+ //#endregion
145
+ export { type Agent, ApiError, BananalinkError, BananalinkHub, type BananalinkHubConfig, BindError, type BuildSiweMessageParams, ConnectionError, type ConnectionRequest, type ConnectionRequestParams, type DeepLinkParams, type EthSendTransactionParams, type EthSendTransactionResult, type MessageRequest, NotConnectedError, type PushSubscriptionParams, type RevokeParams, type Signer, type TokenPair, type TransactionRequest, type TransactionRequestHandler, buildSiweMessage, fetchAgent, fetchVapidKey, parseDeepLink, refreshHubTokens, registerHub };
146
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/api/fetchAgent.ts","../src/api/fetchVapidKey.ts","../src/types/TokenPair.ts","../src/api/refreshHubTokens.ts","../src/api/registerHub.ts","../src/types/PushSubscriptionParams.ts","../src/types/RevokeParams.ts","../src/ws/MessageRequest.ts","../src/ws/TransactionRequest.ts","../src/types/TransactionRequestHandler.ts","../src/ws/ConnectionRequest.ts","../src/core/BananalinkHubConfig.ts","../src/core/BananalinkHub.ts","../src/errors/BananalinkError.ts","../src/errors/ApiError.ts","../src/errors/BindError.ts","../src/errors/ConnectionError.ts","../src/errors/NotConnectedError.ts","../src/types/BuildSiweMessageParams.ts","../src/types/Signer.ts","../src/utils/buildSiweMessage.ts","../src/utils/parseDeepLink.ts"],"mappings":";;;iBAGsB,UAAA,CAAW,MAAA,UAAgB,gBAAA,WAA2B,OAAA,CAAQ,OAAA;;;iBCD9D,aAAA,CAAc,MAAA,YAAiD,OAAA;EAAU,SAAA;AAAA;;;KCFnF,SAAA;EACV,WAAA;EACA,YAAA;AAAA;;;iBCCoB,gBAAA,CAAiB,MAAA,UAAgB,YAAA,WAAuB,OAAA,CAAQ,SAAA;;;iBCAhE,WAAA,CAAY,MAAA,WAAiB,OAAA,CAAQ,SAAA;;;KCH/C,sBAAA;EAA2B,QAAA;EAAkB,IAAA;IAAQ,MAAA;IAAgB,IAAA;EAAA;AAAA;;;UCAhE,YAAA;EACf,OAAA;AAAA;;;UCDe,cAAA;EAAA,SACN,SAAA;EAAA,SACA,OAAA;EAAA,SACA,MAAA;EAAA,SACA,OAAA,EAAS,QAAA;EAClB,OAAA,CAAQ,MAAA,UAAgB,eAAA;AAAA;;;UCFT,kBAAA,SAA2B,cAAA,CAAe,0BAAA;EACzD,OAAA,CAAQ,MAAA,EAAQ,0BAAA;EAChB,MAAA,CAAO,MAAA;AAAA;;;KCHG,yBAAA,IAA6B,OAAA,EAAS,kBAAA,YAA8B,OAAA;;;UCA/D,iBAAA;EAAA,SACN,gBAAA;EAAA,SACA,KAAA,EAAO,OAAA;EAChB,OAAA,IAAW,OAAA;EACX,MAAA,IAAU,OAAA;AAAA;;;UCNK,mBAAA;EACf,MAAA;EACA,KAAA;AAAA;;;cCyBW,aAAA;EAAA,wBACa,eAAA;EAAA,wBACA,cAAA;EAAA,wBACA,4BAAA;EAAA,iBAEP,MAAA;EAAA,iBACA,KAAA;EAAA,QACT,EAAA;EAAA,QACA,WAAA;EAAA,QACA,kBAAA;EAAA,QACA,mBAAA;cAEI,MAAA,GAAS,mBAAA;EAKf,OAAA,CAAQ,WAAA,WAAsB,OAAA;EAgCpC,UAAA,CAAA;EAOA,aAAA,CAAc,YAAA,EAAc,sBAAA;EAyB5B,eAAA,CAAgB,QAAA;EAiBhB,oBAAA,CAAqB,OAAA,EAAS,yBAAA;EAQxB,oBAAA,CAAqB,MAAA,EAAQ,yBAAA,GAA0B,OAAA,CAAQ,iBAAA;EAkB/D,MAAA,CAAO,MAAA,EAAQ,YAAA,GAAe,OAAA;EAAA,QAW5B,iBAAA;EAAA,QAYA,0BAAA;EAAA,QAqBM,kBAAA;EAAA,QASA,IAAA;AAAA;;;cC5MH,eAAA,SAAwB,KAAA;cACvB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;;;cCC5B,QAAA,SAAiB,eAAA;EAAA,SACZ,MAAA;EAAA,SACA,IAAA;cAEJ,MAAA,UAAgB,IAAA;AAAA;;;cCJjB,SAAA,SAAkB,eAAA;EAAA,SACD,KAAA;cAAA,KAAA;AAAA;;;cCDjB,eAAA,SAAwB,eAAA;cACvB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;;;cCD5B,iBAAA,SAA0B,eAAA;EAAA,WAAA,CAAA;AAAA;;;UCFtB,sBAAA;EACf,MAAA;EACA,OAAA;EACA,GAAA;EACA,SAAA;EACA,KAAA;EACA,OAAA;EACA,QAAA;AAAA;;;UCPe,MAAA;EACf,OAAA;EACA,WAAA,GAAc,OAAA,aAAoB,OAAA;AAAA;;;iBCApB,gBAAA,CAAiB,MAAA,EAAQ,sBAAA;;;iBCCzB,aAAA,CAAc,QAAA,WAAmB,gBAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,353 @@
1
+ import { BindTransportError, MESSAGE_METHOD_SEND_TRANSACTION, bindTransport, connectWebSocket, createReconnectingTransport, isMessageRequestMessage } from "@bananalink-test/sdk-core";
2
+
3
+ //#region src/errors/BananalinkError.ts
4
+ var BananalinkError = class extends Error {
5
+ constructor(message, options) {
6
+ super(message, options);
7
+ this.name = "BananalinkError";
8
+ }
9
+ };
10
+
11
+ //#endregion
12
+ //#region src/errors/ApiError.ts
13
+ var ApiError = class extends BananalinkError {
14
+ status;
15
+ body;
16
+ constructor(status, body) {
17
+ super(`API request failed with status ${status}`);
18
+ this.name = "ApiError";
19
+ this.status = status;
20
+ this.body = body;
21
+ }
22
+ };
23
+
24
+ //#endregion
25
+ //#region src/api/fetchAgent.ts
26
+ async function fetchAgent(apiUrl, agentPairingCode) {
27
+ const response = await fetch(`${apiUrl}/agents/${encodeURIComponent(agentPairingCode)}`);
28
+ if (!response.ok) {
29
+ const body = await response.json().catch(() => null);
30
+ throw new ApiError(response.status, body);
31
+ }
32
+ const body = await response.json();
33
+ if (!isAgent(body)) throw new ApiError(response.status, body);
34
+ return body;
35
+ }
36
+ function isAgent(value) {
37
+ if (typeof value !== "object" || value === null) return false;
38
+ const record = value;
39
+ return typeof record.agentId === "string" && typeof record.agentName === "string";
40
+ }
41
+
42
+ //#endregion
43
+ //#region src/api/fetchVapidKey.ts
44
+ async function fetchVapidKey(apiUrl = "https://api.dev.banana.link") {
45
+ const response = await fetch(`${apiUrl}/push/vapid-key`);
46
+ if (!response.ok) {
47
+ const body = await response.json().catch(() => null);
48
+ throw new ApiError(response.status, body);
49
+ }
50
+ const body = await response.json();
51
+ if (typeof body !== "object" || body === null || !("publicKey" in body)) throw new ApiError(response.status, body);
52
+ const { publicKey } = body;
53
+ if (typeof publicKey !== "string" || publicKey.length === 0) throw new ApiError(response.status, body);
54
+ return { publicKey };
55
+ }
56
+
57
+ //#endregion
58
+ //#region src/api/refreshHubTokens.ts
59
+ async function refreshHubTokens(apiUrl, refreshToken) {
60
+ const response = await fetch(`${apiUrl}/hubs/tokens/refresh`, {
61
+ method: "POST",
62
+ headers: { "Content-Type": "application/json" },
63
+ body: JSON.stringify({ refreshToken })
64
+ });
65
+ if (!response.ok) {
66
+ const responseBody = await response.json().catch(() => null);
67
+ throw new ApiError(response.status, responseBody);
68
+ }
69
+ const responseBody = await response.json().catch(() => null);
70
+ if (!isTokenPair$1(responseBody)) throw new ApiError(response.status, responseBody);
71
+ return responseBody;
72
+ }
73
+ function isTokenPair$1(value) {
74
+ if (typeof value !== "object" || value === null) return false;
75
+ return "accessToken" in value && typeof value.accessToken === "string" && "refreshToken" in value && typeof value.refreshToken === "string";
76
+ }
77
+
78
+ //#endregion
79
+ //#region src/api/registerHub.ts
80
+ async function registerHub(apiUrl) {
81
+ const response = await fetch(`${apiUrl}/hubs`, { method: "POST" });
82
+ if (!response.ok) {
83
+ const responseBody = await response.json().catch(() => null);
84
+ throw new ApiError(response.status, responseBody);
85
+ }
86
+ const responseBody = await response.json().catch(() => null);
87
+ if (!isTokenPair(responseBody)) throw new ApiError(response.status, responseBody);
88
+ return responseBody;
89
+ }
90
+ function isTokenPair(value) {
91
+ if (typeof value !== "object" || value === null) return false;
92
+ return "accessToken" in value && typeof value.accessToken === "string" && "refreshToken" in value && typeof value.refreshToken === "string";
93
+ }
94
+
95
+ //#endregion
96
+ //#region src/api/deleteAgentTokens.ts
97
+ async function deleteAgentTokens(apiUrl, agentId, accessToken) {
98
+ const response = await fetch(`${apiUrl}/hubs/agents/${encodeURIComponent(agentId)}/tokens`, {
99
+ method: "DELETE",
100
+ headers: {
101
+ "Content-Type": "application/json",
102
+ Authorization: `Bearer ${accessToken}`
103
+ }
104
+ });
105
+ if (!response.ok) {
106
+ const responseBody = await response.json().catch(() => null);
107
+ throw new ApiError(response.status, responseBody);
108
+ }
109
+ }
110
+
111
+ //#endregion
112
+ //#region src/errors/BindError.ts
113
+ var BindError = class extends BananalinkError {
114
+ constructor(error) {
115
+ super(`Hub bind failed with error: ${error}`);
116
+ this.error = error;
117
+ this.name = "BindError";
118
+ }
119
+ };
120
+
121
+ //#endregion
122
+ //#region src/errors/ConnectionError.ts
123
+ var ConnectionError = class extends BananalinkError {
124
+ constructor(message, options) {
125
+ super(message, options);
126
+ this.name = "ConnectionError";
127
+ }
128
+ };
129
+
130
+ //#endregion
131
+ //#region src/errors/NotConnectedError.ts
132
+ var NotConnectedError = class extends BananalinkError {
133
+ constructor() {
134
+ super("Hub is not connected. Call connect() first.");
135
+ this.name = "NotConnectedError";
136
+ }
137
+ };
138
+
139
+ //#endregion
140
+ //#region src/ws/createConnectionRequest.ts
141
+ function createConnectionRequest(params) {
142
+ return {
143
+ agentPairingCode: params.agentPairingCode,
144
+ agent: params.agent,
145
+ async approve() {
146
+ const authorizeMessage = {
147
+ type: "authorize",
148
+ code: params.agentPairingCode
149
+ };
150
+ params.ws.send(authorizeMessage);
151
+ },
152
+ async reject() {
153
+ const rejectMessage = {
154
+ type: "reject",
155
+ code: params.agentPairingCode
156
+ };
157
+ params.ws.send(rejectMessage);
158
+ }
159
+ };
160
+ }
161
+
162
+ //#endregion
163
+ //#region src/ws/createMessageRequest.ts
164
+ function createMessageRequest(message, ws) {
165
+ return {
166
+ messageId: message.messageId,
167
+ agentId: message.agentId,
168
+ method: message.method,
169
+ payload: message.payload,
170
+ respond(status, payloadResponse) {
171
+ const response = {
172
+ type: "message_response",
173
+ msgId: message.messageId,
174
+ status,
175
+ payloadResponse
176
+ };
177
+ ws.send(response);
178
+ }
179
+ };
180
+ }
181
+
182
+ //#endregion
183
+ //#region src/ws/createTransactionRequest.ts
184
+ function createTransactionRequest(message, ws) {
185
+ const base = createMessageRequest(message, ws);
186
+ return {
187
+ ...base,
188
+ payload: base.payload[0],
189
+ approve(result) {
190
+ base.respond("approved", result);
191
+ },
192
+ reject(reason) {
193
+ base.respond("rejected", reason);
194
+ }
195
+ };
196
+ }
197
+
198
+ //#endregion
199
+ //#region src/core/BananalinkHub.ts
200
+ var BananalinkHub = class BananalinkHub {
201
+ static DEFAULT_API_URL = "https://api.dev.banana.link";
202
+ static DEFAULT_WS_URL = "wss://ws.dev.banana.link";
203
+ static BIND_RESPONSE_TIMEOUT_MILLIS = 20 * 1e3;
204
+ apiUrl;
205
+ wsUrl;
206
+ ws = null;
207
+ accessToken = null;
208
+ transactionHandler = null;
209
+ unsubscribeMessages = null;
210
+ constructor(config) {
211
+ this.apiUrl = stripTrailingSlash(config?.apiUrl ?? BananalinkHub.DEFAULT_API_URL);
212
+ this.wsUrl = stripTrailingSlash(config?.wsUrl ?? BananalinkHub.DEFAULT_WS_URL);
213
+ }
214
+ async connect(accessToken) {
215
+ if (!accessToken.trim()) throw new BananalinkError("accessToken is required");
216
+ this.disconnect();
217
+ let transportHandle;
218
+ try {
219
+ transportHandle = await this.getTransportHandle();
220
+ } catch (error) {
221
+ throw new ConnectionError("Unable to establish hub websocket connection", { cause: error });
222
+ }
223
+ try {
224
+ await this.bind(transportHandle, accessToken);
225
+ this.accessToken = accessToken;
226
+ this.ws = createReconnectingTransport(transportHandle, {
227
+ reconnectTransport: async () => this.getTransportHandle(),
228
+ onReconnect: async (th) => this.bind(th, accessToken),
229
+ maxReconnectAttempts: 5,
230
+ baseDelayReconnectMs: 1e3
231
+ });
232
+ } catch (error) {
233
+ transportHandle.close();
234
+ throw error;
235
+ }
236
+ this.listenForMessages(this.ws);
237
+ }
238
+ disconnect() {
239
+ this.unsubscribeMessages?.();
240
+ this.unsubscribeMessages = null;
241
+ this.ws?.close();
242
+ this.ws = null;
243
+ }
244
+ subscribePush(subscription) {
245
+ if (!this.ws) throw new NotConnectedError();
246
+ if (!subscription.endpoint.trim()) throw new BananalinkError("subscription endpoint is required");
247
+ if (!subscription.keys.auth.trim()) throw new BananalinkError("subscription keys.auth is required");
248
+ if (!subscription.keys.p256dh.trim()) throw new BananalinkError("subscription keys.p256dh is required");
249
+ const message = {
250
+ type: "subscribe_push",
251
+ subscription
252
+ };
253
+ this.ws.send(message);
254
+ }
255
+ unsubscribePush(endpoint) {
256
+ if (!this.ws) throw new NotConnectedError();
257
+ if (!endpoint.trim()) throw new BananalinkError("subscription endpoint is required");
258
+ const message = {
259
+ type: "unsubscribe_push",
260
+ endpoint
261
+ };
262
+ this.ws.send(message);
263
+ }
264
+ onTransactionRequest(handler) {
265
+ this.transactionHandler = handler;
266
+ return () => {
267
+ this.transactionHandler = null;
268
+ };
269
+ }
270
+ async getConnectionRequest(params) {
271
+ if (!this.ws) throw new NotConnectedError();
272
+ if (!params.agentPairingCode.trim()) throw new BananalinkError("agentPairingCode is required");
273
+ const agent = await fetchAgent(this.apiUrl, params.agentPairingCode);
274
+ return createConnectionRequest({
275
+ agentPairingCode: params.agentPairingCode,
276
+ agent,
277
+ ws: this.ws
278
+ });
279
+ }
280
+ async revoke(params) {
281
+ if (!params.agentId.trim()) throw new BananalinkError("agentId is required");
282
+ if (!this.accessToken) throw new BananalinkError("accessToken is required");
283
+ await deleteAgentTokens(this.apiUrl, params.agentId, this.accessToken);
284
+ }
285
+ listenForMessages(ws) {
286
+ this.unsubscribeMessages = ws.onMessage((payload) => {
287
+ if (!isMessageRequestMessage(payload)) return;
288
+ if (payload.method === MESSAGE_METHOD_SEND_TRANSACTION && this.transactionHandler) this.dispatchTransactionRequest(this.transactionHandler, payload, ws);
289
+ });
290
+ }
291
+ dispatchTransactionRequest(handler, payload, ws) {
292
+ const request = createTransactionRequest(payload, ws);
293
+ const safeReject = (error) => {
294
+ try {
295
+ const message = error instanceof Error ? error.message : String(error);
296
+ request.reject(`transaction handler failed: ${message}`);
297
+ } catch {}
298
+ };
299
+ try {
300
+ Promise.resolve(handler(request)).catch(safeReject);
301
+ } catch (error) {
302
+ safeReject(error);
303
+ }
304
+ }
305
+ async getTransportHandle() {
306
+ return await connectWebSocket({
307
+ url: this.wsUrl,
308
+ pingIntervalMs: 3e4,
309
+ pongTimeoutMs: 5e3,
310
+ maxReconnectAttempts: 0
311
+ });
312
+ }
313
+ async bind(ws, accessToken) {
314
+ try {
315
+ await bindTransport(ws, accessToken, {
316
+ timeoutMs: BananalinkHub.BIND_RESPONSE_TIMEOUT_MILLIS,
317
+ createClosedError: () => new ConnectionError("Connection closed unexpectedly while waiting for hub bind response"),
318
+ createTimeoutError: () => new ConnectionError("Timed out waiting for hub bind response")
319
+ });
320
+ } catch (error) {
321
+ if (error instanceof BindTransportError) throw new BindError(error.code);
322
+ throw error;
323
+ }
324
+ }
325
+ };
326
+ function stripTrailingSlash(url) {
327
+ return url.replace(/\/+$/, "");
328
+ }
329
+
330
+ //#endregion
331
+ //#region src/utils/buildSiweMessage.ts
332
+ function buildSiweMessage(params) {
333
+ const issuedAt = params.issuedAt ?? (/* @__PURE__ */ new Date()).toISOString();
334
+ return `${params.domain} wants you to sign in with your Ethereum account:\n${params.address}\n\n${params.statement}\n\nURI: ${params.uri}\nVersion: 1\nChain ID: ${params.chainId}\nNonce: ${params.nonce}\nIssued At: ${issuedAt}`;
335
+ }
336
+
337
+ //#endregion
338
+ //#region src/utils/parseDeepLink.ts
339
+ function parseDeepLink(deepLink) {
340
+ let url;
341
+ try {
342
+ url = new URL(deepLink);
343
+ } catch (error) {
344
+ throw new BananalinkError("Invalid deep link URL", { cause: error });
345
+ }
346
+ const code = url.searchParams.get("code");
347
+ if (!code) throw new BananalinkError("Invalid deep link: missing agent pairing code");
348
+ return { code };
349
+ }
350
+
351
+ //#endregion
352
+ export { ApiError, BananalinkError, BananalinkHub, BindError, ConnectionError, NotConnectedError, buildSiweMessage, fetchAgent, fetchVapidKey, parseDeepLink, refreshHubTokens, registerHub };
353
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["isTokenPair"],"sources":["../src/errors/BananalinkError.ts","../src/errors/ApiError.ts","../src/api/fetchAgent.ts","../src/api/fetchVapidKey.ts","../src/api/refreshHubTokens.ts","../src/api/registerHub.ts","../src/api/deleteAgentTokens.ts","../src/errors/BindError.ts","../src/errors/ConnectionError.ts","../src/errors/NotConnectedError.ts","../src/ws/createConnectionRequest.ts","../src/ws/createMessageRequest.ts","../src/ws/createTransactionRequest.ts","../src/core/BananalinkHub.ts","../src/utils/buildSiweMessage.ts","../src/utils/parseDeepLink.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 ApiError extends BananalinkError {\n public readonly status: number;\n public readonly body: unknown;\n\n constructor(status: number, body: unknown) {\n super(`API request failed with status ${status}`);\n this.name = 'ApiError';\n this.status = status;\n this.body = body;\n }\n}\n","import type { Agent } from '@bananalink-test/sdk-core';\nimport { ApiError } from '../errors/ApiError.js';\n\nexport async function fetchAgent(apiUrl: string, agentPairingCode: string): Promise<Agent> {\n const response = await fetch(`${apiUrl}/agents/${encodeURIComponent(agentPairingCode)}`);\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new ApiError(response.status, body);\n }\n\n const body = await response.json();\n\n if (!isAgent(body)) {\n throw new ApiError(response.status, body);\n }\n\n return body;\n}\n\nfunction isAgent(value: unknown): value is Agent {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const record = value as Record<string, unknown>;\n\n return typeof record.agentId === 'string' && typeof record.agentName === 'string';\n}\n","import { ApiError } from '../errors/ApiError.js';\n\nexport async function fetchVapidKey(apiUrl: string = 'https://api.dev.banana.link'): Promise<{ publicKey: string }> {\n const response = await fetch(`${apiUrl}/push/vapid-key`);\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new ApiError(response.status, body);\n }\n\n const body: unknown = await response.json();\n\n if (typeof body !== 'object' || body === null || !('publicKey' in body)) {\n throw new ApiError(response.status, body);\n }\n\n const { publicKey } = body as { publicKey: unknown };\n\n if (typeof publicKey !== 'string' || publicKey.length === 0) {\n throw new ApiError(response.status, body);\n }\n\n return { publicKey };\n}\n","import { ApiError } from '../errors/ApiError.js';\nimport type { TokenPair } from '../types/TokenPair.js';\n\nexport async function refreshHubTokens(apiUrl: string, refreshToken: string): Promise<TokenPair> {\n const response = await fetch(`${apiUrl}/hubs/tokens/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken }),\n });\n\n if (!response.ok) {\n const responseBody = await response.json().catch(() => null);\n throw new ApiError(response.status, responseBody);\n }\n\n const responseBody: unknown = await response.json().catch(() => null);\n if (!isTokenPair(responseBody)) {\n throw new ApiError(response.status, responseBody);\n }\n\n return responseBody;\n}\n\nfunction isTokenPair(value: unknown): value is TokenPair {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n return (\n 'accessToken' in value &&\n typeof value.accessToken === 'string' &&\n 'refreshToken' in value &&\n typeof value.refreshToken === 'string'\n );\n}\n","import { ApiError } from '../errors/ApiError.js';\nimport type { TokenPair } from '../types/TokenPair.js';\n\nexport async function registerHub(apiUrl: string): Promise<TokenPair> {\n const response = await fetch(`${apiUrl}/hubs`, { method: 'POST' });\n\n if (!response.ok) {\n const responseBody = await response.json().catch(() => null);\n throw new ApiError(response.status, responseBody);\n }\n\n const responseBody: unknown = await response.json().catch(() => null);\n if (!isTokenPair(responseBody)) {\n throw new ApiError(response.status, responseBody);\n }\n\n return responseBody;\n}\n\nfunction isTokenPair(value: unknown): value is TokenPair {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n return (\n 'accessToken' in value &&\n typeof value.accessToken === 'string' &&\n 'refreshToken' in value &&\n typeof value.refreshToken === 'string'\n );\n}\n","import { ApiError } from '../errors/ApiError.js';\n\nexport async function deleteAgentTokens(apiUrl: string, agentId: string, accessToken: string): Promise<void> {\n const response = await fetch(`${apiUrl}/hubs/agents/${encodeURIComponent(agentId)}/tokens`, {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${accessToken}` },\n });\n\n if (!response.ok) {\n const responseBody = await response.json().catch(() => null);\n throw new ApiError(response.status, responseBody);\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class BindError extends BananalinkError {\n constructor(public readonly error: 'INVALID_JWT' | 'JWT_EXPIRED') {\n super(`Hub bind failed with error: ${error}`);\n this.name = 'BindError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class ConnectionError extends BananalinkError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'ConnectionError';\n }\n}\n","import { BananalinkError } from './BananalinkError.js';\n\nexport class NotConnectedError extends BananalinkError {\n constructor() {\n super('Hub is not connected. Call connect() first.');\n this.name = 'NotConnectedError';\n }\n}\n","import type { Agent, AuthorizeMessage, RejectMessage, TransportHandle } from '@bananalink-test/sdk-core';\nimport type { ConnectionRequest } from './ConnectionRequest.js';\n\nexport function createConnectionRequest(params: {\n agentPairingCode: string;\n agent: Agent;\n ws: TransportHandle;\n}): ConnectionRequest {\n return {\n agentPairingCode: params.agentPairingCode,\n agent: params.agent,\n\n async approve(): Promise<void> {\n const authorizeMessage: AuthorizeMessage = {\n type: 'authorize',\n code: params.agentPairingCode,\n };\n\n params.ws.send(authorizeMessage);\n },\n\n async reject(): Promise<void> {\n const rejectMessage: RejectMessage = {\n type: 'reject',\n code: params.agentPairingCode,\n };\n\n params.ws.send(rejectMessage);\n },\n };\n}\n","import type { MessageRequestMessage, MessageResponseMessage, TransportHandle } from '@bananalink-test/sdk-core';\nimport type { MessageRequest } from './MessageRequest.js';\n\nexport function createMessageRequest<TPayload>(\n message: MessageRequestMessage,\n ws: TransportHandle,\n): MessageRequest<TPayload> {\n return {\n messageId: message.messageId,\n agentId: message.agentId,\n method: message.method,\n payload: message.payload as TPayload,\n\n respond(status: string, payloadResponse?: unknown): void {\n const response: MessageResponseMessage = {\n type: 'message_response',\n msgId: message.messageId,\n status,\n payloadResponse,\n };\n\n ws.send(response);\n },\n };\n}\n","import type {\n EthSendTransactionParams,\n EthSendTransactionResult,\n MessageRequestMessage,\n TransportHandle,\n} from '@bananalink-test/sdk-core';\nimport { createMessageRequest } from './createMessageRequest.js';\nimport type { TransactionRequest } from './TransactionRequest.js';\n\nexport function createTransactionRequest(message: MessageRequestMessage, ws: TransportHandle): TransactionRequest {\n const base = createMessageRequest<EthSendTransactionParams[]>(message, ws);\n\n return {\n ...base,\n payload: base.payload[0],\n\n approve(result: EthSendTransactionResult): void {\n base.respond('approved', result);\n },\n\n reject(reason?: string): void {\n base.respond('rejected', reason);\n },\n };\n}\n","import {\n BindTransportError,\n bindTransport,\n type ConnectionRequestParams,\n connectWebSocket,\n createReconnectingTransport,\n isMessageRequestMessage,\n MESSAGE_METHOD_SEND_TRANSACTION,\n type MessageRequestMessage,\n type SubscribePushMessage,\n type TransportHandle,\n type UnsubscribePushMessage,\n} from '@bananalink-test/sdk-core';\nimport { deleteAgentTokens } from '../api/deleteAgentTokens.js';\nimport { fetchAgent } from '../api/fetchAgent.js';\nimport { BananalinkError } from '../errors/BananalinkError.js';\nimport { BindError } from '../errors/BindError.js';\nimport { ConnectionError } from '../errors/ConnectionError.js';\nimport { NotConnectedError } from '../errors/NotConnectedError.js';\nimport type { PushSubscriptionParams } from '../types/PushSubscriptionParams.js';\nimport type { RevokeParams } from '../types/RevokeParams.js';\nimport type { TransactionRequestHandler } from '../types/TransactionRequestHandler.js';\nimport type { ConnectionRequest } from '../ws/ConnectionRequest.js';\nimport { createConnectionRequest } from '../ws/createConnectionRequest.js';\nimport { createTransactionRequest } from '../ws/createTransactionRequest.js';\nimport type { BananalinkHubConfig } from './BananalinkHubConfig.js';\n\nexport class BananalinkHub {\n private static readonly DEFAULT_API_URL = 'https://api.dev.banana.link';\n private static readonly DEFAULT_WS_URL = 'wss://ws.dev.banana.link';\n private static readonly BIND_RESPONSE_TIMEOUT_MILLIS = 20 * 1000;\n\n private readonly apiUrl: string;\n private readonly wsUrl: string;\n private ws: TransportHandle | null = null;\n private accessToken: string | null = null;\n private transactionHandler: TransactionRequestHandler | null = null;\n private unsubscribeMessages: (() => void) | null = null;\n\n constructor(config?: BananalinkHubConfig) {\n this.apiUrl = stripTrailingSlash(config?.apiUrl ?? BananalinkHub.DEFAULT_API_URL);\n this.wsUrl = stripTrailingSlash(config?.wsUrl ?? BananalinkHub.DEFAULT_WS_URL);\n }\n\n async connect(accessToken: string): Promise<void> {\n if (!accessToken.trim()) {\n throw new BananalinkError('accessToken is required');\n }\n\n this.disconnect();\n\n let transportHandle: TransportHandle;\n try {\n transportHandle = await this.getTransportHandle();\n } catch (error) {\n throw new ConnectionError('Unable to establish hub websocket connection', { cause: error });\n }\n\n try {\n await this.bind(transportHandle, accessToken);\n this.accessToken = accessToken;\n\n this.ws = createReconnectingTransport(transportHandle, {\n reconnectTransport: async () => this.getTransportHandle(),\n onReconnect: async (th) => this.bind(th, accessToken),\n maxReconnectAttempts: 5,\n baseDelayReconnectMs: 1000,\n });\n } catch (error) {\n transportHandle.close();\n throw error;\n }\n\n this.listenForMessages(this.ws);\n }\n\n disconnect(): void {\n this.unsubscribeMessages?.();\n this.unsubscribeMessages = null;\n this.ws?.close();\n this.ws = null;\n }\n\n subscribePush(subscription: PushSubscriptionParams) {\n if (!this.ws) {\n throw new NotConnectedError();\n }\n\n if (!subscription.endpoint.trim()) {\n throw new BananalinkError('subscription endpoint is required');\n }\n\n if (!subscription.keys.auth.trim()) {\n throw new BananalinkError('subscription keys.auth is required');\n }\n\n if (!subscription.keys.p256dh.trim()) {\n throw new BananalinkError('subscription keys.p256dh is required');\n }\n\n const message: SubscribePushMessage = {\n type: 'subscribe_push',\n subscription,\n };\n\n this.ws.send(message);\n }\n\n unsubscribePush(endpoint: string) {\n if (!this.ws) {\n throw new NotConnectedError();\n }\n\n if (!endpoint.trim()) {\n throw new BananalinkError('subscription endpoint is required');\n }\n\n const message: UnsubscribePushMessage = {\n type: 'unsubscribe_push',\n endpoint,\n };\n\n this.ws.send(message);\n }\n\n onTransactionRequest(handler: TransactionRequestHandler): () => void {\n this.transactionHandler = handler;\n\n return () => {\n this.transactionHandler = null;\n };\n }\n\n async getConnectionRequest(params: ConnectionRequestParams): Promise<ConnectionRequest> {\n if (!this.ws) {\n throw new NotConnectedError();\n }\n\n if (!params.agentPairingCode.trim()) {\n throw new BananalinkError('agentPairingCode is required');\n }\n\n const agent = await fetchAgent(this.apiUrl, params.agentPairingCode);\n\n return createConnectionRequest({\n agentPairingCode: params.agentPairingCode,\n agent,\n ws: this.ws,\n });\n }\n\n async revoke(params: RevokeParams): Promise<void> {\n if (!params.agentId.trim()) {\n throw new BananalinkError('agentId is required');\n }\n if (!this.accessToken) {\n throw new BananalinkError('accessToken is required');\n }\n\n await deleteAgentTokens(this.apiUrl, params.agentId, this.accessToken);\n }\n\n private listenForMessages(ws: TransportHandle): void {\n this.unsubscribeMessages = ws.onMessage((payload) => {\n if (!isMessageRequestMessage(payload)) {\n return;\n }\n\n if (payload.method === MESSAGE_METHOD_SEND_TRANSACTION && this.transactionHandler) {\n this.dispatchTransactionRequest(this.transactionHandler, payload, ws);\n }\n });\n }\n\n private dispatchTransactionRequest(\n handler: TransactionRequestHandler,\n payload: MessageRequestMessage,\n ws: TransportHandle,\n ): void {\n const request = createTransactionRequest(payload, ws);\n\n const safeReject = (error: unknown): void => {\n try {\n const message = error instanceof Error ? error.message : String(error);\n request.reject(`transaction handler failed: ${message}`);\n } catch {}\n };\n\n try {\n void Promise.resolve(handler(request)).catch(safeReject);\n } catch (error: unknown) {\n safeReject(error);\n }\n }\n\n private async getTransportHandle(): Promise<TransportHandle> {\n return await connectWebSocket({\n url: this.wsUrl,\n pingIntervalMs: 30_000,\n pongTimeoutMs: 5_000,\n maxReconnectAttempts: 0,\n });\n }\n\n private async bind(ws: TransportHandle, accessToken: string): Promise<void> {\n try {\n await bindTransport(ws, accessToken, {\n timeoutMs: BananalinkHub.BIND_RESPONSE_TIMEOUT_MILLIS,\n createClosedError: () =>\n new ConnectionError('Connection closed unexpectedly while waiting for hub bind response'),\n createTimeoutError: () => new ConnectionError('Timed out waiting for hub bind response'),\n });\n } catch (error) {\n if (error instanceof BindTransportError) {\n throw new BindError(error.code);\n }\n throw error;\n }\n }\n}\n\nfunction stripTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, '');\n}\n","import type { BuildSiweMessageParams } from '../types/BuildSiweMessageParams.js';\n\nexport function buildSiweMessage(params: BuildSiweMessageParams): string {\n const issuedAt = params.issuedAt ?? new Date().toISOString();\n\n return (\n `${params.domain} wants you to sign in with your Ethereum account:\\n` +\n `${params.address}\\n` +\n `\\n` +\n `${params.statement}\\n` +\n `\\n` +\n `URI: ${params.uri}\\n` +\n `Version: 1\\n` +\n `Chain ID: ${params.chainId}\\n` +\n `Nonce: ${params.nonce}\\n` +\n `Issued At: ${issuedAt}`\n );\n}\n","import type { DeepLinkParams } from '@bananalink-test/sdk-core';\nimport { BananalinkError } from '../errors/BananalinkError.js';\n\nexport function parseDeepLink(deepLink: string): DeepLinkParams {\n let url: URL;\n\n try {\n url = new URL(deepLink);\n } catch (error) {\n throw new BananalinkError('Invalid deep link URL', { cause: error });\n }\n\n const code = url.searchParams.get('code');\n\n if (!code) {\n throw new BananalinkError('Invalid deep link: missing agent pairing code');\n }\n\n return { code };\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@bananalink-test/hub",
3
+ "version": "1.1.1",
4
+ "description": "",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "import": {
10
+ "types": "./dist/index.d.mts",
11
+ "default": "./dist/index.mjs"
12
+ },
13
+ "require": {
14
+ "types": "./dist/index.d.cts",
15
+ "default": "./dist/index.cjs"
16
+ }
17
+ }
18
+ },
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.mjs",
21
+ "types": "./dist/index.d.mts",
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "devDependencies": {
29
+ "@biomejs/biome": "2.3.15",
30
+ "tsdown": "^0.20.3",
31
+ "typescript": "^5.9.3",
32
+ "vitest": "^4.0.18"
33
+ },
34
+ "dependencies": {
35
+ "@bananalink-test/sdk-core": "0.8.1"
36
+ },
37
+ "scripts": {
38
+ "build": "tsdown",
39
+ "type-check": "tsc --noEmit",
40
+ "lint": "biome check .",
41
+ "dev": "tsdown --watch",
42
+ "test": "vitest run"
43
+ }
44
+ }