@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 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: () => import_core3.ByokyError,
25
- ByokyErrorCode: () => import_core3.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 import_core2 = require("@byoky/core");
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 handleMessage(event) {
73
- if (event.source !== window) return;
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
- window.removeEventListener("message", handleMessage);
120
+ document.removeEventListener("byoky-message", handleEvent);
122
121
  }
123
- window.addEventListener("message", handleMessage);
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 import_core2.ByokyError.walletNotInstalled();
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, response.sessionKey),
183
- disconnect: () => this.disconnect(response.sessionKey)
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 import_core2.ByokyError(import_core2.ByokyErrorCode.UNKNOWN, "Connection request timed out")
413
+ new import_core3.ByokyError(import_core3.ByokyErrorCode.UNKNOWN, "Connection request timed out")
193
414
  );
194
415
  }, this.timeout);
195
- function handleMessage(event) {
196
- if (event.source !== window) return;
197
- if (!(0, import_core2.isByokyMessage)(event.data)) return;
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 import_core2.ByokyError(code, message));
425
+ reject(new import_core3.ByokyError(code, message));
206
426
  }
207
427
  }
208
428
  function cleanup() {
209
429
  clearTimeout(timeoutId);
210
- window.removeEventListener("message", handleMessage);
430
+ document.removeEventListener("byoky-message", handleEvent);
211
431
  }
212
- window.addEventListener("message", handleMessage);
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
- disconnect(sessionKey) {
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 import_core3 = require("@byoky/core");
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,
@@ -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 disconnect;
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 disconnect;
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 };