@byoky/sdk 0.1.0 → 0.3.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 +299 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -4
- package/dist/index.d.ts +28 -4
- package/dist/index.js +302 -20
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +223 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +28 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.js +202 -0
- package/dist/server.js.map +1 -0
- package/package.json +6 -1
package/dist/index.cjs
CHANGED
|
@@ -21,8 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
Byoky: () => Byoky,
|
|
24
|
-
ByokyError: () =>
|
|
25
|
-
ByokyErrorCode: () =>
|
|
24
|
+
ByokyError: () => import_core4.ByokyError,
|
|
25
|
+
ByokyErrorCode: () => import_core4.ByokyErrorCode,
|
|
26
26
|
createProxyFetch: () => createProxyFetch,
|
|
27
27
|
getStoreUrl: () => getStoreUrl,
|
|
28
28
|
isExtensionInstalled: () => isExtensionInstalled
|
|
@@ -30,7 +30,7 @@ __export(index_exports, {
|
|
|
30
30
|
module.exports = __toCommonJS(index_exports);
|
|
31
31
|
|
|
32
32
|
// src/byoky.ts
|
|
33
|
-
var
|
|
33
|
+
var import_core3 = require("@byoky/core");
|
|
34
34
|
|
|
35
35
|
// src/detect.ts
|
|
36
36
|
var import_core = require("@byoky/core");
|
|
@@ -69,9 +69,8 @@ function createProxyFetch(providerId, sessionKey) {
|
|
|
69
69
|
cleanup();
|
|
70
70
|
reject(new Error("Proxy request timed out"));
|
|
71
71
|
}, 12e4);
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
const data = event.data;
|
|
72
|
+
function handleEvent(event) {
|
|
73
|
+
const data = event.detail ?? event.data;
|
|
75
74
|
if (data?.requestId !== requestId) return;
|
|
76
75
|
switch (data.type) {
|
|
77
76
|
case "BYOKY_PROXY_RESPONSE_META":
|
|
@@ -118,9 +117,9 @@ function createProxyFetch(providerId, sessionKey) {
|
|
|
118
117
|
}
|
|
119
118
|
function cleanup() {
|
|
120
119
|
clearTimeout(timeout);
|
|
121
|
-
|
|
120
|
+
document.removeEventListener("byoky-message", handleEvent);
|
|
122
121
|
}
|
|
123
|
-
|
|
122
|
+
document.addEventListener("byoky-message", handleEvent);
|
|
124
123
|
window.postMessage(
|
|
125
124
|
{
|
|
126
125
|
type: "BYOKY_PROXY_REQUEST",
|
|
@@ -162,6 +161,185 @@ async function readBody(body) {
|
|
|
162
161
|
return void 0;
|
|
163
162
|
}
|
|
164
163
|
|
|
164
|
+
// src/relay-client.ts
|
|
165
|
+
var import_core2 = require("@byoky/core");
|
|
166
|
+
function createRelayClient(wsUrl, sessionKey, providers) {
|
|
167
|
+
let status = "connecting";
|
|
168
|
+
const closeCallbacks = /* @__PURE__ */ new Set();
|
|
169
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
170
|
+
let ws;
|
|
171
|
+
let pingInterval;
|
|
172
|
+
try {
|
|
173
|
+
const parsed = new URL(wsUrl);
|
|
174
|
+
const isSecure = parsed.protocol === "wss:";
|
|
175
|
+
const isLocalWs = parsed.protocol === "ws:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
|
|
176
|
+
if (!isSecure && !isLocalWs) {
|
|
177
|
+
status = "disconnected";
|
|
178
|
+
return {
|
|
179
|
+
get status() {
|
|
180
|
+
return status;
|
|
181
|
+
},
|
|
182
|
+
close() {
|
|
183
|
+
},
|
|
184
|
+
onClose(cb) {
|
|
185
|
+
cb("Insecure WebSocket URL rejected \u2014 use wss:// for non-localhost connections");
|
|
186
|
+
return () => {
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
status = "disconnected";
|
|
193
|
+
return {
|
|
194
|
+
get status() {
|
|
195
|
+
return status;
|
|
196
|
+
},
|
|
197
|
+
close() {
|
|
198
|
+
},
|
|
199
|
+
onClose(cb) {
|
|
200
|
+
cb("Invalid WebSocket URL");
|
|
201
|
+
return () => {
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
ws = new WebSocket(wsUrl);
|
|
208
|
+
} catch {
|
|
209
|
+
status = "disconnected";
|
|
210
|
+
return {
|
|
211
|
+
get status() {
|
|
212
|
+
return status;
|
|
213
|
+
},
|
|
214
|
+
close() {
|
|
215
|
+
},
|
|
216
|
+
onClose(cb) {
|
|
217
|
+
cb("Failed to create WebSocket");
|
|
218
|
+
return () => {
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
ws.onopen = () => {
|
|
224
|
+
status = "connected";
|
|
225
|
+
const relayId = `relay_${crypto.randomUUID().replace(/-/g, "")}`;
|
|
226
|
+
ws.send(JSON.stringify({
|
|
227
|
+
type: "relay:hello",
|
|
228
|
+
sessionId: relayId,
|
|
229
|
+
providers
|
|
230
|
+
}));
|
|
231
|
+
pingInterval = setInterval(() => {
|
|
232
|
+
if (ws.readyState === import_core2.WS_READY_STATE.OPEN) {
|
|
233
|
+
ws.send(JSON.stringify({ type: "relay:ping", ts: Date.now() }));
|
|
234
|
+
}
|
|
235
|
+
}, 3e4);
|
|
236
|
+
};
|
|
237
|
+
ws.onmessage = (event) => {
|
|
238
|
+
const msg = (0, import_core2.parseRelayMessage)(event.data);
|
|
239
|
+
if (!msg) return;
|
|
240
|
+
switch (msg.type) {
|
|
241
|
+
case "relay:request":
|
|
242
|
+
handleRequest(msg);
|
|
243
|
+
break;
|
|
244
|
+
case "relay:ping":
|
|
245
|
+
ws.send(JSON.stringify({ type: "relay:pong", ts: msg.ts }));
|
|
246
|
+
break;
|
|
247
|
+
case "relay:pong":
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
ws.onclose = (event) => {
|
|
252
|
+
cleanup(event.reason || "WebSocket closed");
|
|
253
|
+
};
|
|
254
|
+
ws.onerror = () => {
|
|
255
|
+
cleanup("WebSocket error");
|
|
256
|
+
};
|
|
257
|
+
async function handleRequest(req) {
|
|
258
|
+
const { requestId, providerId, url, method, headers, body } = req;
|
|
259
|
+
const controller = new AbortController();
|
|
260
|
+
inFlight.set(requestId, controller);
|
|
261
|
+
try {
|
|
262
|
+
const proxyFetch = createProxyFetch(providerId, sessionKey);
|
|
263
|
+
const response = await proxyFetch(url, {
|
|
264
|
+
method,
|
|
265
|
+
headers,
|
|
266
|
+
body,
|
|
267
|
+
signal: controller.signal
|
|
268
|
+
});
|
|
269
|
+
const responseHeaders = {};
|
|
270
|
+
response.headers.forEach((value, key) => {
|
|
271
|
+
responseHeaders[key] = value;
|
|
272
|
+
});
|
|
273
|
+
send({
|
|
274
|
+
type: "relay:response:meta",
|
|
275
|
+
requestId,
|
|
276
|
+
status: response.status,
|
|
277
|
+
statusText: response.statusText,
|
|
278
|
+
headers: responseHeaders
|
|
279
|
+
});
|
|
280
|
+
if (response.body) {
|
|
281
|
+
const reader = response.body.getReader();
|
|
282
|
+
const decoder = new TextDecoder();
|
|
283
|
+
while (true) {
|
|
284
|
+
const { done, value } = await reader.read();
|
|
285
|
+
if (done) break;
|
|
286
|
+
if (controller.signal.aborted) break;
|
|
287
|
+
send({
|
|
288
|
+
type: "relay:response:chunk",
|
|
289
|
+
requestId,
|
|
290
|
+
chunk: decoder.decode(value, { stream: true })
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
send({ type: "relay:response:done", requestId });
|
|
295
|
+
} catch (err) {
|
|
296
|
+
send({
|
|
297
|
+
type: "relay:response:error",
|
|
298
|
+
requestId,
|
|
299
|
+
error: {
|
|
300
|
+
code: err instanceof import_core2.ByokyError ? err.code : "PROXY_ERROR",
|
|
301
|
+
message: err instanceof Error ? err.message : "Unknown error"
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
} finally {
|
|
305
|
+
inFlight.delete(requestId);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function send(msg) {
|
|
309
|
+
if (ws.readyState === import_core2.WS_READY_STATE.OPEN) {
|
|
310
|
+
ws.send(JSON.stringify(msg));
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
function cleanup(reason) {
|
|
314
|
+
if (status === "disconnected") return;
|
|
315
|
+
status = "disconnected";
|
|
316
|
+
if (pingInterval) clearInterval(pingInterval);
|
|
317
|
+
for (const controller of inFlight.values()) {
|
|
318
|
+
controller.abort();
|
|
319
|
+
}
|
|
320
|
+
inFlight.clear();
|
|
321
|
+
for (const cb of closeCallbacks) cb(reason);
|
|
322
|
+
closeCallbacks.clear();
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
get status() {
|
|
326
|
+
return status;
|
|
327
|
+
},
|
|
328
|
+
close() {
|
|
329
|
+
if (ws.readyState === import_core2.WS_READY_STATE.OPEN || ws.readyState === import_core2.WS_READY_STATE.CONNECTING) {
|
|
330
|
+
ws.close(1e3, "Client closed");
|
|
331
|
+
}
|
|
332
|
+
cleanup("Client closed");
|
|
333
|
+
},
|
|
334
|
+
onClose(callback) {
|
|
335
|
+
closeCallbacks.add(callback);
|
|
336
|
+
return () => {
|
|
337
|
+
closeCallbacks.delete(callback);
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
165
343
|
// src/byoky.ts
|
|
166
344
|
var Byoky = class {
|
|
167
345
|
timeout;
|
|
@@ -169,18 +347,61 @@ var Byoky = class {
|
|
|
169
347
|
this.timeout = options.timeout ?? 6e4;
|
|
170
348
|
}
|
|
171
349
|
async connect(request = {}) {
|
|
350
|
+
if (typeof window === "undefined") {
|
|
351
|
+
throw new import_core3.ByokyError(
|
|
352
|
+
import_core3.ByokyErrorCode.UNKNOWN,
|
|
353
|
+
"Byoky SDK requires a browser environment. On the server, use your API key directly."
|
|
354
|
+
);
|
|
355
|
+
}
|
|
172
356
|
if (!isExtensionInstalled()) {
|
|
173
357
|
const storeUrl = getStoreUrl();
|
|
174
358
|
if (storeUrl) {
|
|
175
359
|
window.open(storeUrl, "_blank");
|
|
176
360
|
}
|
|
177
|
-
throw
|
|
361
|
+
throw import_core3.ByokyError.walletNotInstalled();
|
|
178
362
|
}
|
|
179
363
|
const response = await this.sendConnectRequest(request);
|
|
364
|
+
return this.buildSession(response);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Reconnect to an existing session using previously stored response data.
|
|
368
|
+
* Returns null if the session is no longer valid.
|
|
369
|
+
*/
|
|
370
|
+
async reconnect(savedResponse) {
|
|
371
|
+
if (typeof window === "undefined") return null;
|
|
372
|
+
if (!isExtensionInstalled()) return null;
|
|
373
|
+
const connected = await this.querySessionStatus(savedResponse.sessionKey);
|
|
374
|
+
if (!connected) return null;
|
|
375
|
+
return this.buildSession(savedResponse);
|
|
376
|
+
}
|
|
377
|
+
buildSession(response) {
|
|
378
|
+
const sessionKey = response.sessionKey;
|
|
379
|
+
const disconnectCallbacks = /* @__PURE__ */ new Set();
|
|
380
|
+
function handleRevocation(event) {
|
|
381
|
+
const msg = event.detail;
|
|
382
|
+
if (msg?.type === "BYOKY_SESSION_REVOKED" && msg.payload?.sessionKey === sessionKey) {
|
|
383
|
+
for (const cb of disconnectCallbacks) cb();
|
|
384
|
+
disconnectCallbacks.clear();
|
|
385
|
+
document.removeEventListener("byoky-message", handleRevocation);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
document.addEventListener("byoky-message", handleRevocation);
|
|
180
389
|
return {
|
|
181
390
|
...response,
|
|
182
|
-
createFetch: (providerId) => createProxyFetch(providerId,
|
|
183
|
-
|
|
391
|
+
createFetch: (providerId) => createProxyFetch(providerId, sessionKey),
|
|
392
|
+
createRelay: (wsUrl) => createRelayClient(wsUrl, sessionKey, response.providers),
|
|
393
|
+
disconnect: () => {
|
|
394
|
+
document.removeEventListener("byoky-message", handleRevocation);
|
|
395
|
+
this.sendDisconnect(sessionKey);
|
|
396
|
+
},
|
|
397
|
+
isConnected: () => this.querySessionStatus(sessionKey),
|
|
398
|
+
getUsage: () => this.querySessionUsage(sessionKey),
|
|
399
|
+
onDisconnect: (callback) => {
|
|
400
|
+
disconnectCallbacks.add(callback);
|
|
401
|
+
return () => {
|
|
402
|
+
disconnectCallbacks.delete(callback);
|
|
403
|
+
};
|
|
404
|
+
}
|
|
184
405
|
};
|
|
185
406
|
}
|
|
186
407
|
sendConnectRequest(request) {
|
|
@@ -189,27 +410,26 @@ var Byoky = class {
|
|
|
189
410
|
const timeoutId = setTimeout(() => {
|
|
190
411
|
cleanup();
|
|
191
412
|
reject(
|
|
192
|
-
new
|
|
413
|
+
new import_core3.ByokyError(import_core3.ByokyErrorCode.UNKNOWN, "Connection request timed out")
|
|
193
414
|
);
|
|
194
415
|
}, this.timeout);
|
|
195
|
-
function
|
|
196
|
-
|
|
197
|
-
if (!
|
|
198
|
-
const msg = event.data;
|
|
416
|
+
function handleEvent(event) {
|
|
417
|
+
const msg = event.detail;
|
|
418
|
+
if (typeof msg?.type !== "string" || !msg.type.startsWith("BYOKY_")) return;
|
|
199
419
|
if (msg.requestId !== requestId) return;
|
|
200
420
|
cleanup();
|
|
201
421
|
if (msg.type === "BYOKY_CONNECT_RESPONSE") {
|
|
202
422
|
resolve(msg.payload);
|
|
203
423
|
} else if (msg.type === "BYOKY_ERROR") {
|
|
204
424
|
const { code, message } = msg.payload;
|
|
205
|
-
reject(new
|
|
425
|
+
reject(new import_core3.ByokyError(code, message));
|
|
206
426
|
}
|
|
207
427
|
}
|
|
208
428
|
function cleanup() {
|
|
209
429
|
clearTimeout(timeoutId);
|
|
210
|
-
|
|
430
|
+
document.removeEventListener("byoky-message", handleEvent);
|
|
211
431
|
}
|
|
212
|
-
|
|
432
|
+
document.addEventListener("byoky-message", handleEvent);
|
|
213
433
|
window.postMessage(
|
|
214
434
|
{
|
|
215
435
|
type: "BYOKY_CONNECT_REQUEST",
|
|
@@ -221,16 +441,74 @@ var Byoky = class {
|
|
|
221
441
|
);
|
|
222
442
|
});
|
|
223
443
|
}
|
|
224
|
-
|
|
444
|
+
sendDisconnect(sessionKey) {
|
|
225
445
|
window.postMessage(
|
|
226
446
|
{ type: "BYOKY_DISCONNECT", payload: { sessionKey } },
|
|
227
447
|
"*"
|
|
228
448
|
);
|
|
229
449
|
}
|
|
450
|
+
querySessionStatus(sessionKey) {
|
|
451
|
+
return new Promise((resolve) => {
|
|
452
|
+
const requestId = crypto.randomUUID();
|
|
453
|
+
const timeout = setTimeout(() => {
|
|
454
|
+
cleanup();
|
|
455
|
+
resolve(false);
|
|
456
|
+
}, 5e3);
|
|
457
|
+
function handleEvent(event) {
|
|
458
|
+
const msg = event.detail;
|
|
459
|
+
if (msg?.requestId !== requestId) return;
|
|
460
|
+
if (msg.type === "BYOKY_SESSION_STATUS_RESPONSE") {
|
|
461
|
+
cleanup();
|
|
462
|
+
resolve(!!msg.payload?.connected);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
function cleanup() {
|
|
466
|
+
clearTimeout(timeout);
|
|
467
|
+
document.removeEventListener("byoky-message", handleEvent);
|
|
468
|
+
}
|
|
469
|
+
document.addEventListener("byoky-message", handleEvent);
|
|
470
|
+
window.postMessage({
|
|
471
|
+
type: "BYOKY_SESSION_STATUS",
|
|
472
|
+
requestId,
|
|
473
|
+
payload: { sessionKey }
|
|
474
|
+
}, "*");
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
querySessionUsage(sessionKey) {
|
|
478
|
+
return new Promise((resolve, reject) => {
|
|
479
|
+
const requestId = crypto.randomUUID();
|
|
480
|
+
const timeout = setTimeout(() => {
|
|
481
|
+
cleanup();
|
|
482
|
+
reject(new Error("Usage query timed out"));
|
|
483
|
+
}, 5e3);
|
|
484
|
+
function handleEvent(event) {
|
|
485
|
+
const msg = event.detail;
|
|
486
|
+
if (msg?.requestId !== requestId) return;
|
|
487
|
+
if (msg.type === "BYOKY_SESSION_USAGE_RESPONSE") {
|
|
488
|
+
cleanup();
|
|
489
|
+
if (msg.payload) {
|
|
490
|
+
resolve(msg.payload);
|
|
491
|
+
} else {
|
|
492
|
+
reject(new Error("Session not found"));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function cleanup() {
|
|
497
|
+
clearTimeout(timeout);
|
|
498
|
+
document.removeEventListener("byoky-message", handleEvent);
|
|
499
|
+
}
|
|
500
|
+
document.addEventListener("byoky-message", handleEvent);
|
|
501
|
+
window.postMessage({
|
|
502
|
+
type: "BYOKY_SESSION_USAGE",
|
|
503
|
+
requestId,
|
|
504
|
+
payload: { sessionKey }
|
|
505
|
+
}, "*");
|
|
506
|
+
});
|
|
507
|
+
}
|
|
230
508
|
};
|
|
231
509
|
|
|
232
510
|
// src/index.ts
|
|
233
|
-
var
|
|
511
|
+
var import_core4 = require("@byoky/core");
|
|
234
512
|
// Annotate the CommonJS export names for ESM import in node:
|
|
235
513
|
0 && (module.exports = {
|
|
236
514
|
Byoky,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/byoky.ts","../src/detect.ts","../src/proxy-fetch.ts"],"sourcesContent":["export { Byoky } from './byoky.js';\nexport type { ByokySession, ByokyOptions } from './byoky.js';\nexport { isExtensionInstalled, getStoreUrl } from './detect.js';\nexport { createProxyFetch } from './proxy-fetch.js';\nexport {\n type ConnectRequest,\n type ConnectResponse,\n type ProviderRequirement,\n ByokyError,\n ByokyErrorCode,\n} from '@byoky/core';\n","import type { ConnectRequest, ConnectResponse } from '@byoky/core';\nimport { ByokyError, ByokyErrorCode, isByokyMessage } from '@byoky/core';\nimport { isExtensionInstalled, getStoreUrl } from './detect.js';\nimport { createProxyFetch } from './proxy-fetch.js';\n\nexport interface ByokySession extends ConnectResponse {\n createFetch(providerId: string): typeof fetch;\n disconnect(): void;\n}\n\nexport interface ByokyOptions {\n timeout?: number;\n}\n\nexport class Byoky {\n private timeout: number;\n\n constructor(options: ByokyOptions = {}) {\n this.timeout = options.timeout ?? 60_000;\n }\n\n async connect(request: ConnectRequest = {}): Promise<ByokySession> {\n if (!isExtensionInstalled()) {\n const storeUrl = getStoreUrl();\n if (storeUrl) {\n window.open(storeUrl, '_blank');\n }\n throw ByokyError.walletNotInstalled();\n }\n\n const response = await this.sendConnectRequest(request);\n\n return {\n ...response,\n createFetch: (providerId: string) =>\n createProxyFetch(providerId, response.sessionKey),\n disconnect: () => this.disconnect(response.sessionKey),\n };\n }\n\n private sendConnectRequest(\n request: ConnectRequest,\n ): Promise<ConnectResponse> {\n return new Promise<ConnectResponse>((resolve, reject) => {\n const requestId = crypto.randomUUID();\n\n const timeoutId = setTimeout(() => {\n cleanup();\n reject(\n new ByokyError(ByokyErrorCode.UNKNOWN, 'Connection request timed out'),\n );\n }, this.timeout);\n\n function handleMessage(event: MessageEvent) {\n if (event.source !== window) return;\n if (!isByokyMessage(event.data)) return;\n\n const msg = event.data;\n if (msg.requestId !== requestId) return;\n\n cleanup();\n\n if (msg.type === 'BYOKY_CONNECT_RESPONSE') {\n resolve(msg.payload as ConnectResponse);\n } else if (msg.type === 'BYOKY_ERROR') {\n const { code, message } = msg.payload as {\n code: string;\n message: string;\n };\n reject(new ByokyError(code as ByokyErrorCode, message));\n }\n }\n\n function cleanup() {\n clearTimeout(timeoutId);\n window.removeEventListener('message', handleMessage);\n }\n\n window.addEventListener('message', handleMessage);\n\n window.postMessage(\n {\n type: 'BYOKY_CONNECT_REQUEST',\n id: requestId,\n requestId,\n payload: request,\n },\n '*',\n );\n });\n }\n\n private disconnect(sessionKey: string): void {\n window.postMessage(\n { type: 'BYOKY_DISCONNECT', payload: { sessionKey } },\n '*',\n );\n }\n}\n","import { BYOKY_PROVIDER_KEY } from '@byoky/core';\n\nexport function isExtensionInstalled(): boolean {\n return typeof window !== 'undefined' && BYOKY_PROVIDER_KEY in window;\n}\n\nexport function getStoreUrl(): string | null {\n if (typeof navigator === 'undefined') return null;\n\n const ua = navigator.userAgent.toLowerCase();\n\n if (ua.includes('chrome') && !ua.includes('edg')) {\n return 'https://chrome.google.com/webstore/detail/byoky/TODO_EXTENSION_ID';\n }\n if (ua.includes('firefox')) {\n return 'https://addons.mozilla.org/en-US/firefox/addon/byoky/';\n }\n if (ua.includes('safari') && !ua.includes('chrome')) {\n return 'https://apps.apple.com/app/byoky/TODO_APP_ID';\n }\n return null;\n}\n","export function createProxyFetch(\n providerId: string,\n sessionKey: string,\n): typeof fetch {\n return async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.toString()\n : input.url;\n\n const method = init?.method ?? 'GET';\n const headers = init?.headers\n ? Object.fromEntries(new Headers(init.headers).entries())\n : {};\n const body = init?.body ? await readBody(init.body) : undefined;\n\n const requestId = crypto.randomUUID();\n\n return new Promise<Response>((resolve, reject) => {\n const { readable, writable } = new TransformStream<Uint8Array>();\n const writer = writable.getWriter();\n const encoder = new TextEncoder();\n let resolved = false;\n\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error('Proxy request timed out'));\n }, 120_000);\n\n function handleMessage(event: MessageEvent) {\n if (event.source !== window) return;\n const data = event.data;\n if (data?.requestId !== requestId) return;\n\n switch (data.type) {\n case 'BYOKY_PROXY_RESPONSE_META':\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n resolve(\n new Response(readable, {\n status: data.status,\n statusText: data.statusText,\n headers: new Headers(data.headers),\n }),\n );\n }\n break;\n\n case 'BYOKY_PROXY_RESPONSE_CHUNK':\n writer.write(encoder.encode(data.chunk)).catch(() => {});\n break;\n\n case 'BYOKY_PROXY_RESPONSE_DONE':\n writer.close().catch(() => {});\n cleanup();\n break;\n\n case 'BYOKY_PROXY_RESPONSE_ERROR': {\n const errResponse = new Response(\n JSON.stringify({ error: data.error }),\n {\n status: data.status || 500,\n headers: { 'content-type': 'application/json' },\n },\n );\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n resolve(errResponse);\n }\n writer.close().catch(() => {});\n cleanup();\n break;\n }\n }\n }\n\n function cleanup() {\n clearTimeout(timeout);\n window.removeEventListener('message', handleMessage);\n }\n\n window.addEventListener('message', handleMessage);\n\n window.postMessage(\n {\n type: 'BYOKY_PROXY_REQUEST',\n requestId,\n sessionKey,\n providerId,\n url,\n method,\n headers,\n body,\n },\n '*',\n );\n });\n };\n}\n\nasync function readBody(body: BodyInit): Promise<string | undefined> {\n if (typeof body === 'string') return body;\n if (body instanceof ArrayBuffer) return new TextDecoder().decode(body);\n if (body instanceof Blob) return body.text();\n if (body instanceof URLSearchParams) return body.toString();\n if (body instanceof ReadableStream) {\n const reader = body.getReader();\n const chunks: Uint8Array[] = [];\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n const total = chunks.reduce((acc, c) => acc + c.length, 0);\n const combined = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n return new TextDecoder().decode(combined);\n }\n return undefined;\n}\n"],"mappings":"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","names":["import_core","import_core"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/byoky.ts","../src/detect.ts","../src/proxy-fetch.ts","../src/relay-client.ts"],"sourcesContent":["export { Byoky } from './byoky.js';\nexport type { ByokySession, ByokyOptions } from './byoky.js';\nexport { isExtensionInstalled, getStoreUrl } from './detect.js';\nexport { createProxyFetch } from './proxy-fetch.js';\nexport type { RelayConnection } from './relay-client.js';\nexport {\n type ConnectRequest,\n type ConnectResponse,\n type ProviderRequirement,\n type SessionUsage,\n ByokyError,\n ByokyErrorCode,\n} from '@byoky/core';\n","import type { ConnectRequest, ConnectResponse, SessionUsage } from '@byoky/core';\nimport { ByokyError, ByokyErrorCode, isByokyMessage } from '@byoky/core';\nimport { isExtensionInstalled, getStoreUrl } from './detect.js';\nimport { createProxyFetch } from './proxy-fetch.js';\nimport { createRelayClient, type RelayConnection } from './relay-client.js';\n\nexport interface ByokySession extends ConnectResponse {\n /** Create a fetch function that proxies requests through the wallet for the given provider. */\n createFetch(providerId: string): typeof fetch;\n /** Open a relay channel so a backend server can make LLM calls through this session. */\n createRelay(wsUrl: string): RelayConnection;\n /** Disconnect this session from the wallet. */\n disconnect(): void;\n /** Check if this session is still connected and valid. */\n isConnected(): Promise<boolean>;\n /** Get token usage stats for this session only. */\n getUsage(): Promise<SessionUsage>;\n /** Register a callback for when the wallet revokes this session. */\n onDisconnect(callback: () => void): () => void;\n}\n\nexport interface ByokyOptions {\n timeout?: number;\n}\n\nexport class Byoky {\n private timeout: number;\n\n constructor(options: ByokyOptions = {}) {\n this.timeout = options.timeout ?? 60_000;\n }\n\n async connect(request: ConnectRequest = {}): Promise<ByokySession> {\n if (typeof window === 'undefined') {\n throw new ByokyError(\n ByokyErrorCode.UNKNOWN,\n 'Byoky SDK requires a browser environment. On the server, use your API key directly.',\n );\n }\n\n if (!isExtensionInstalled()) {\n const storeUrl = getStoreUrl();\n if (storeUrl) {\n window.open(storeUrl, '_blank');\n }\n throw ByokyError.walletNotInstalled();\n }\n\n const response = await this.sendConnectRequest(request);\n return this.buildSession(response);\n }\n\n /**\n * Reconnect to an existing session using previously stored response data.\n * Returns null if the session is no longer valid.\n */\n async reconnect(savedResponse: ConnectResponse): Promise<ByokySession | null> {\n if (typeof window === 'undefined') return null;\n if (!isExtensionInstalled()) return null;\n\n const connected = await this.querySessionStatus(savedResponse.sessionKey);\n if (!connected) return null;\n\n return this.buildSession(savedResponse);\n }\n\n private buildSession(response: ConnectResponse): ByokySession {\n const sessionKey = response.sessionKey;\n const disconnectCallbacks = new Set<() => void>();\n\n function handleRevocation(event: Event) {\n const msg = (event as CustomEvent).detail;\n if (msg?.type === 'BYOKY_SESSION_REVOKED' && msg.payload?.sessionKey === sessionKey) {\n for (const cb of disconnectCallbacks) cb();\n disconnectCallbacks.clear();\n document.removeEventListener('byoky-message', handleRevocation);\n }\n }\n document.addEventListener('byoky-message', handleRevocation);\n\n return {\n ...response,\n createFetch: (providerId: string) =>\n createProxyFetch(providerId, sessionKey),\n createRelay: (wsUrl: string) =>\n createRelayClient(wsUrl, sessionKey, response.providers),\n disconnect: () => {\n document.removeEventListener('byoky-message', handleRevocation);\n this.sendDisconnect(sessionKey);\n },\n isConnected: () => this.querySessionStatus(sessionKey),\n getUsage: () => this.querySessionUsage(sessionKey),\n onDisconnect: (callback: () => void) => {\n disconnectCallbacks.add(callback);\n return () => { disconnectCallbacks.delete(callback); };\n },\n };\n }\n\n private sendConnectRequest(\n request: ConnectRequest,\n ): Promise<ConnectResponse> {\n return new Promise<ConnectResponse>((resolve, reject) => {\n const requestId = crypto.randomUUID();\n\n const timeoutId = setTimeout(() => {\n cleanup();\n reject(\n new ByokyError(ByokyErrorCode.UNKNOWN, 'Connection request timed out'),\n );\n }, this.timeout);\n\n function handleEvent(event: Event) {\n const msg = (event as CustomEvent).detail;\n if (typeof msg?.type !== 'string' || !msg.type.startsWith('BYOKY_')) return;\n if (msg.requestId !== requestId) return;\n\n cleanup();\n\n if (msg.type === 'BYOKY_CONNECT_RESPONSE') {\n resolve(msg.payload as ConnectResponse);\n } else if (msg.type === 'BYOKY_ERROR') {\n const { code, message } = msg.payload as {\n code: string;\n message: string;\n };\n reject(new ByokyError(code as ByokyErrorCode, message));\n }\n }\n\n function cleanup() {\n clearTimeout(timeoutId);\n document.removeEventListener('byoky-message', handleEvent);\n }\n\n document.addEventListener('byoky-message', handleEvent);\n\n window.postMessage(\n {\n type: 'BYOKY_CONNECT_REQUEST',\n id: requestId,\n requestId,\n payload: request,\n },\n '*',\n );\n });\n }\n\n private sendDisconnect(sessionKey: string): void {\n window.postMessage(\n { type: 'BYOKY_DISCONNECT', payload: { sessionKey } },\n '*',\n );\n }\n\n private querySessionStatus(sessionKey: string): Promise<boolean> {\n return new Promise((resolve) => {\n const requestId = crypto.randomUUID();\n const timeout = setTimeout(() => { cleanup(); resolve(false); }, 5000);\n\n function handleEvent(event: Event) {\n const msg = (event as CustomEvent).detail;\n if (msg?.requestId !== requestId) return;\n if (msg.type === 'BYOKY_SESSION_STATUS_RESPONSE') {\n cleanup();\n resolve(!!msg.payload?.connected);\n }\n }\n\n function cleanup() {\n clearTimeout(timeout);\n document.removeEventListener('byoky-message', handleEvent);\n }\n\n document.addEventListener('byoky-message', handleEvent);\n window.postMessage({\n type: 'BYOKY_SESSION_STATUS',\n requestId,\n payload: { sessionKey },\n }, '*');\n });\n }\n\n private querySessionUsage(sessionKey: string): Promise<SessionUsage> {\n return new Promise((resolve, reject) => {\n const requestId = crypto.randomUUID();\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error('Usage query timed out'));\n }, 5000);\n\n function handleEvent(event: Event) {\n const msg = (event as CustomEvent).detail;\n if (msg?.requestId !== requestId) return;\n if (msg.type === 'BYOKY_SESSION_USAGE_RESPONSE') {\n cleanup();\n if (msg.payload) {\n resolve(msg.payload as SessionUsage);\n } else {\n reject(new Error('Session not found'));\n }\n }\n }\n\n function cleanup() {\n clearTimeout(timeout);\n document.removeEventListener('byoky-message', handleEvent);\n }\n\n document.addEventListener('byoky-message', handleEvent);\n window.postMessage({\n type: 'BYOKY_SESSION_USAGE',\n requestId,\n payload: { sessionKey },\n }, '*');\n });\n }\n}\n","import { BYOKY_PROVIDER_KEY } from '@byoky/core';\n\nexport function isExtensionInstalled(): boolean {\n return typeof window !== 'undefined' && BYOKY_PROVIDER_KEY in window;\n}\n\nexport function getStoreUrl(): string | null {\n if (typeof navigator === 'undefined') return null;\n\n const ua = navigator.userAgent.toLowerCase();\n\n if (ua.includes('chrome') && !ua.includes('edg')) {\n return 'https://chrome.google.com/webstore/detail/byoky/TODO_EXTENSION_ID';\n }\n if (ua.includes('firefox')) {\n return 'https://addons.mozilla.org/en-US/firefox/addon/byoky/';\n }\n if (ua.includes('safari') && !ua.includes('chrome')) {\n return 'https://apps.apple.com/app/byoky/TODO_APP_ID';\n }\n return null;\n}\n","export function createProxyFetch(\n providerId: string,\n sessionKey: string,\n): typeof fetch {\n return async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.toString()\n : input.url;\n\n const method = init?.method ?? 'GET';\n const headers = init?.headers\n ? Object.fromEntries(new Headers(init.headers).entries())\n : {};\n const body = init?.body ? await readBody(init.body) : undefined;\n\n const requestId = crypto.randomUUID();\n\n return new Promise<Response>((resolve, reject) => {\n const { readable, writable } = new TransformStream<Uint8Array>();\n const writer = writable.getWriter();\n const encoder = new TextEncoder();\n let resolved = false;\n\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error('Proxy request timed out'));\n }, 120_000);\n\n function handleEvent(event: Event) {\n const data = (event as CustomEvent).detail ?? (event as MessageEvent).data;\n if (data?.requestId !== requestId) return;\n\n switch (data.type) {\n case 'BYOKY_PROXY_RESPONSE_META':\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n resolve(\n new Response(readable, {\n status: data.status,\n statusText: data.statusText,\n headers: new Headers(data.headers),\n }),\n );\n }\n break;\n\n case 'BYOKY_PROXY_RESPONSE_CHUNK':\n writer.write(encoder.encode(data.chunk)).catch(() => {});\n break;\n\n case 'BYOKY_PROXY_RESPONSE_DONE':\n writer.close().catch(() => {});\n cleanup();\n break;\n\n case 'BYOKY_PROXY_RESPONSE_ERROR': {\n const errResponse = new Response(\n JSON.stringify({ error: data.error }),\n {\n status: data.status || 500,\n headers: { 'content-type': 'application/json' },\n },\n );\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n resolve(errResponse);\n }\n writer.close().catch(() => {});\n cleanup();\n break;\n }\n }\n }\n\n function cleanup() {\n clearTimeout(timeout);\n document.removeEventListener('byoky-message', handleEvent);\n }\n\n document.addEventListener('byoky-message', handleEvent);\n\n window.postMessage(\n {\n type: 'BYOKY_PROXY_REQUEST',\n requestId,\n sessionKey,\n providerId,\n url,\n method,\n headers,\n body,\n },\n '*',\n );\n });\n };\n}\n\nasync function readBody(body: BodyInit): Promise<string | undefined> {\n if (typeof body === 'string') return body;\n if (body instanceof ArrayBuffer) return new TextDecoder().decode(body);\n if (body instanceof Blob) return body.text();\n if (body instanceof URLSearchParams) return body.toString();\n if (body instanceof ReadableStream) {\n const reader = body.getReader();\n const chunks: Uint8Array[] = [];\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n const total = chunks.reduce((acc, c) => acc + c.length, 0);\n const combined = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n return new TextDecoder().decode(combined);\n }\n return undefined;\n}\n","import type {\n AuthMethod,\n RelayMessage,\n RelayRequest,\n} from '@byoky/core';\nimport {\n ByokyError,\n parseRelayMessage,\n WS_READY_STATE,\n} from '@byoky/core';\nimport { createProxyFetch } from './proxy-fetch.js';\n\nexport interface RelayConnection {\n readonly status: 'connecting' | 'connected' | 'disconnected';\n close(): void;\n onClose(callback: (reason?: string) => void): () => void;\n}\n\nexport function createRelayClient(\n wsUrl: string,\n sessionKey: string,\n providers: Record<string, { available: boolean; authMethod: AuthMethod }>,\n): RelayConnection {\n let status: 'connecting' | 'connected' | 'disconnected' = 'connecting';\n const closeCallbacks = new Set<(reason?: string) => void>();\n const inFlight = new Map<string, AbortController>();\n\n let ws: WebSocket;\n let pingInterval: ReturnType<typeof setInterval> | undefined;\n\n try {\n const parsed = new URL(wsUrl);\n const isSecure = parsed.protocol === 'wss:';\n const isLocalWs = parsed.protocol === 'ws:' &&\n (parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1');\n if (!isSecure && !isLocalWs) {\n status = 'disconnected';\n return {\n get status() { return status; },\n close() {},\n onClose(cb) { cb('Insecure WebSocket URL rejected — use wss:// for non-localhost connections'); return () => {}; },\n };\n }\n } catch {\n status = 'disconnected';\n return {\n get status() { return status; },\n close() {},\n onClose(cb) { cb('Invalid WebSocket URL'); return () => {}; },\n };\n }\n\n try {\n ws = new WebSocket(wsUrl);\n } catch {\n status = 'disconnected';\n return {\n get status() { return status; },\n close() {},\n onClose(cb) { cb('Failed to create WebSocket'); return () => {}; },\n };\n }\n\n ws.onopen = () => {\n status = 'connected';\n\n // Send hello with a relay-specific ID (never expose the real session key to the relay server)\n const relayId = `relay_${crypto.randomUUID().replace(/-/g, '')}`;\n ws.send(JSON.stringify({\n type: 'relay:hello',\n sessionId: relayId,\n providers,\n }));\n\n // Keepalive ping every 30s\n pingInterval = setInterval(() => {\n if (ws.readyState === WS_READY_STATE.OPEN) {\n ws.send(JSON.stringify({ type: 'relay:ping', ts: Date.now() }));\n }\n }, 30_000);\n };\n\n ws.onmessage = (event) => {\n const msg = parseRelayMessage(event.data);\n if (!msg) return;\n\n switch (msg.type) {\n case 'relay:request':\n handleRequest(msg);\n break;\n case 'relay:ping':\n ws.send(JSON.stringify({ type: 'relay:pong', ts: msg.ts }));\n break;\n case 'relay:pong':\n // Keepalive response, nothing to do\n break;\n }\n };\n\n ws.onclose = (event) => {\n cleanup(event.reason || 'WebSocket closed');\n };\n\n ws.onerror = () => {\n cleanup('WebSocket error');\n };\n\n async function handleRequest(req: RelayRequest) {\n const { requestId, providerId, url, method, headers, body } = req;\n const controller = new AbortController();\n inFlight.set(requestId, controller);\n\n try {\n const proxyFetch = createProxyFetch(providerId, sessionKey);\n const response = await proxyFetch(url, {\n method,\n headers,\n body,\n signal: controller.signal,\n });\n\n // Send response metadata\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n\n send({\n type: 'relay:response:meta',\n requestId,\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n\n // Stream the body\n if (response.body) {\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (controller.signal.aborted) break;\n\n send({\n type: 'relay:response:chunk',\n requestId,\n chunk: decoder.decode(value, { stream: true }),\n });\n }\n }\n\n send({ type: 'relay:response:done', requestId });\n } catch (err) {\n send({\n type: 'relay:response:error',\n requestId,\n error: {\n code: err instanceof ByokyError ? err.code : 'PROXY_ERROR',\n message: err instanceof Error ? err.message : 'Unknown error',\n },\n });\n } finally {\n inFlight.delete(requestId);\n }\n }\n\n function send(msg: RelayMessage) {\n if (ws.readyState === WS_READY_STATE.OPEN) {\n ws.send(JSON.stringify(msg));\n }\n }\n\n function cleanup(reason?: string) {\n if (status === 'disconnected') return;\n status = 'disconnected';\n\n if (pingInterval) clearInterval(pingInterval);\n\n // Abort all in-flight requests\n for (const controller of inFlight.values()) {\n controller.abort();\n }\n inFlight.clear();\n\n for (const cb of closeCallbacks) cb(reason);\n closeCallbacks.clear();\n }\n\n return {\n get status() { return status; },\n close() {\n if (ws.readyState === WS_READY_STATE.OPEN || ws.readyState === WS_READY_STATE.CONNECTING) {\n ws.close(1000, 'Client closed');\n }\n cleanup('Client closed');\n },\n onClose(callback: (reason?: string) => void) {\n closeCallbacks.add(callback);\n return () => { closeCallbacks.delete(callback); };\n },\n };\n}\n"],"mappings":"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","names":["import_core","import_core","import_core"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
import { ConnectRequest, ConnectResponse } from '@byoky/core';
|
|
2
|
-
export { ByokyError, ByokyErrorCode, ConnectRequest, ConnectResponse, ProviderRequirement } from '@byoky/core';
|
|
1
|
+
import { ConnectRequest, ConnectResponse, SessionUsage } from '@byoky/core';
|
|
2
|
+
export { ByokyError, ByokyErrorCode, ConnectRequest, ConnectResponse, ProviderRequirement, SessionUsage } from '@byoky/core';
|
|
3
|
+
|
|
4
|
+
interface RelayConnection {
|
|
5
|
+
readonly status: 'connecting' | 'connected' | 'disconnected';
|
|
6
|
+
close(): void;
|
|
7
|
+
onClose(callback: (reason?: string) => void): () => void;
|
|
8
|
+
}
|
|
3
9
|
|
|
4
10
|
interface ByokySession extends ConnectResponse {
|
|
11
|
+
/** Create a fetch function that proxies requests through the wallet for the given provider. */
|
|
5
12
|
createFetch(providerId: string): typeof fetch;
|
|
13
|
+
/** Open a relay channel so a backend server can make LLM calls through this session. */
|
|
14
|
+
createRelay(wsUrl: string): RelayConnection;
|
|
15
|
+
/** Disconnect this session from the wallet. */
|
|
6
16
|
disconnect(): void;
|
|
17
|
+
/** Check if this session is still connected and valid. */
|
|
18
|
+
isConnected(): Promise<boolean>;
|
|
19
|
+
/** Get token usage stats for this session only. */
|
|
20
|
+
getUsage(): Promise<SessionUsage>;
|
|
21
|
+
/** Register a callback for when the wallet revokes this session. */
|
|
22
|
+
onDisconnect(callback: () => void): () => void;
|
|
7
23
|
}
|
|
8
24
|
interface ByokyOptions {
|
|
9
25
|
timeout?: number;
|
|
@@ -12,8 +28,16 @@ declare class Byoky {
|
|
|
12
28
|
private timeout;
|
|
13
29
|
constructor(options?: ByokyOptions);
|
|
14
30
|
connect(request?: ConnectRequest): Promise<ByokySession>;
|
|
31
|
+
/**
|
|
32
|
+
* Reconnect to an existing session using previously stored response data.
|
|
33
|
+
* Returns null if the session is no longer valid.
|
|
34
|
+
*/
|
|
35
|
+
reconnect(savedResponse: ConnectResponse): Promise<ByokySession | null>;
|
|
36
|
+
private buildSession;
|
|
15
37
|
private sendConnectRequest;
|
|
16
|
-
private
|
|
38
|
+
private sendDisconnect;
|
|
39
|
+
private querySessionStatus;
|
|
40
|
+
private querySessionUsage;
|
|
17
41
|
}
|
|
18
42
|
|
|
19
43
|
declare function isExtensionInstalled(): boolean;
|
|
@@ -21,4 +45,4 @@ declare function getStoreUrl(): string | null;
|
|
|
21
45
|
|
|
22
46
|
declare function createProxyFetch(providerId: string, sessionKey: string): typeof fetch;
|
|
23
47
|
|
|
24
|
-
export { Byoky, type ByokyOptions, type ByokySession, createProxyFetch, getStoreUrl, isExtensionInstalled };
|
|
48
|
+
export { Byoky, type ByokyOptions, type ByokySession, type RelayConnection, createProxyFetch, getStoreUrl, isExtensionInstalled };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
import { ConnectRequest, ConnectResponse } from '@byoky/core';
|
|
2
|
-
export { ByokyError, ByokyErrorCode, ConnectRequest, ConnectResponse, ProviderRequirement } from '@byoky/core';
|
|
1
|
+
import { ConnectRequest, ConnectResponse, SessionUsage } from '@byoky/core';
|
|
2
|
+
export { ByokyError, ByokyErrorCode, ConnectRequest, ConnectResponse, ProviderRequirement, SessionUsage } from '@byoky/core';
|
|
3
|
+
|
|
4
|
+
interface RelayConnection {
|
|
5
|
+
readonly status: 'connecting' | 'connected' | 'disconnected';
|
|
6
|
+
close(): void;
|
|
7
|
+
onClose(callback: (reason?: string) => void): () => void;
|
|
8
|
+
}
|
|
3
9
|
|
|
4
10
|
interface ByokySession extends ConnectResponse {
|
|
11
|
+
/** Create a fetch function that proxies requests through the wallet for the given provider. */
|
|
5
12
|
createFetch(providerId: string): typeof fetch;
|
|
13
|
+
/** Open a relay channel so a backend server can make LLM calls through this session. */
|
|
14
|
+
createRelay(wsUrl: string): RelayConnection;
|
|
15
|
+
/** Disconnect this session from the wallet. */
|
|
6
16
|
disconnect(): void;
|
|
17
|
+
/** Check if this session is still connected and valid. */
|
|
18
|
+
isConnected(): Promise<boolean>;
|
|
19
|
+
/** Get token usage stats for this session only. */
|
|
20
|
+
getUsage(): Promise<SessionUsage>;
|
|
21
|
+
/** Register a callback for when the wallet revokes this session. */
|
|
22
|
+
onDisconnect(callback: () => void): () => void;
|
|
7
23
|
}
|
|
8
24
|
interface ByokyOptions {
|
|
9
25
|
timeout?: number;
|
|
@@ -12,8 +28,16 @@ declare class Byoky {
|
|
|
12
28
|
private timeout;
|
|
13
29
|
constructor(options?: ByokyOptions);
|
|
14
30
|
connect(request?: ConnectRequest): Promise<ByokySession>;
|
|
31
|
+
/**
|
|
32
|
+
* Reconnect to an existing session using previously stored response data.
|
|
33
|
+
* Returns null if the session is no longer valid.
|
|
34
|
+
*/
|
|
35
|
+
reconnect(savedResponse: ConnectResponse): Promise<ByokySession | null>;
|
|
36
|
+
private buildSession;
|
|
15
37
|
private sendConnectRequest;
|
|
16
|
-
private
|
|
38
|
+
private sendDisconnect;
|
|
39
|
+
private querySessionStatus;
|
|
40
|
+
private querySessionUsage;
|
|
17
41
|
}
|
|
18
42
|
|
|
19
43
|
declare function isExtensionInstalled(): boolean;
|
|
@@ -21,4 +45,4 @@ declare function getStoreUrl(): string | null;
|
|
|
21
45
|
|
|
22
46
|
declare function createProxyFetch(providerId: string, sessionKey: string): typeof fetch;
|
|
23
47
|
|
|
24
|
-
export { Byoky, type ByokyOptions, type ByokySession, createProxyFetch, getStoreUrl, isExtensionInstalled };
|
|
48
|
+
export { Byoky, type ByokyOptions, type ByokySession, type RelayConnection, createProxyFetch, getStoreUrl, isExtensionInstalled };
|