@byoky/core 0.4.0 → 0.4.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 CHANGED
@@ -36,9 +36,11 @@ __export(index_exports, {
36
36
  createGiftLink: () => createGiftLink,
37
37
  createMessage: () => createMessage,
38
38
  decodeGiftLink: () => decodeGiftLink,
39
+ decodePairPayload: () => decodePairPayload,
39
40
  decrypt: () => decrypt,
40
41
  deriveKey: () => deriveKey,
41
42
  encodeGiftLink: () => encodeGiftLink,
43
+ encodePairPayload: () => encodePairPayload,
42
44
  encrypt: () => encrypt,
43
45
  extractUsageFromParsed: () => extractUsageFromParsed,
44
46
  getProvider: () => getProvider,
@@ -388,8 +390,10 @@ var WS_READY_STATE = {
388
390
  CLOSING: 2,
389
391
  CLOSED: 3
390
392
  };
393
+ var MAX_RELAY_MESSAGE_SIZE = 1048576;
391
394
  function parseRelayMessage(data) {
392
395
  try {
396
+ if (typeof data === "string" && data.length > MAX_RELAY_MESSAGE_SIZE) return null;
393
397
  const raw = typeof data === "string" ? JSON.parse(data) : data;
394
398
  if (!raw || typeof raw !== "object" || typeof raw.type !== "string" || !raw.type.startsWith("relay:")) {
395
399
  return null;
@@ -408,13 +412,21 @@ function parseRelayMessage(data) {
408
412
  if (typeof raw.requestId !== "string" || typeof raw.chunk !== "string") return null;
409
413
  break;
410
414
  case "relay:response:done":
415
+ if (typeof raw.requestId !== "string") return null;
416
+ break;
411
417
  case "relay:response:error":
412
418
  if (typeof raw.requestId !== "string") return null;
419
+ if (raw.error && (typeof raw.error !== "object" || typeof raw.error.code !== "string" || typeof raw.error.message !== "string")) return null;
413
420
  break;
414
421
  case "relay:ping":
415
422
  case "relay:pong":
416
423
  if (typeof raw.ts !== "number") return null;
417
424
  break;
425
+ case "relay:pair:hello":
426
+ if (!raw.providers || typeof raw.providers !== "object") return null;
427
+ break;
428
+ case "relay:pair:ack":
429
+ break;
418
430
  default:
419
431
  return null;
420
432
  }
@@ -450,16 +462,59 @@ var COMMON_PASSWORDS = /* @__PURE__ */ new Set([
450
462
  "shadow123",
451
463
  "michael1",
452
464
  "jordan123",
453
- "superman1"
465
+ "superman1",
466
+ "password123",
467
+ "admin12345",
468
+ "letmein123",
469
+ "p@ssw0rd",
470
+ "p@ssw0rd1",
471
+ "qwerty1234",
472
+ "changeme12",
473
+ "welcome123",
474
+ "1234567890",
475
+ "baseball1",
476
+ "starwars12",
477
+ "whatever1",
478
+ "passw0rd1",
479
+ "mustang12",
480
+ "access1234",
481
+ "charlie123",
482
+ "donald1234",
483
+ "maggie1234",
484
+ "master1234",
485
+ "michael123",
486
+ "jennifer1",
487
+ "hunter1234",
488
+ "thomas1234",
489
+ "corvette12",
490
+ "robert1234",
491
+ "summer1234",
492
+ "george1234",
493
+ "harley1234",
494
+ "cheese1234",
495
+ "computer1",
496
+ "internet1",
497
+ "secret1234",
498
+ "diamond1",
499
+ "chicken123",
500
+ "pepper1234",
501
+ "jessica123",
502
+ "hannah1234",
503
+ "ginger1234",
504
+ "joshua1234",
505
+ "abcdefgh1",
506
+ "qwertyuiop",
507
+ "asdfghjkl1",
508
+ "zxcvbnm123",
509
+ "1q2w3e4r5t",
510
+ "passpass1"
454
511
  ]);
455
512
  function checkPasswordStrength(password) {
456
513
  const feedback = [];
457
514
  let score = 0;
458
- if (password.length < 12) {
515
+ if (password.length < MIN_PASSWORD_LENGTH) {
459
516
  feedback.push("Use at least 12 characters");
460
- if (password.length < 8) {
461
- return { score: 0, label: "Too weak", feedback };
462
- }
517
+ return { score: 0, label: "Too weak", feedback };
463
518
  } else {
464
519
  score++;
465
520
  if (password.length >= 16) score++;
@@ -553,8 +608,9 @@ function buildHeaders(providerId, requestHeaders, apiKey, authMethod = "api_key"
553
608
  }
554
609
  return headers;
555
610
  }
611
+ var MAX_BODY_PARSE_SIZE = 10485760;
556
612
  function parseModel(body) {
557
- if (!body) return void 0;
613
+ if (!body || body.length > MAX_BODY_PARSE_SIZE) return void 0;
558
614
  try {
559
615
  const parsed = JSON.parse(body);
560
616
  return parsed.model ?? void 0;
@@ -584,25 +640,28 @@ function parseUsage(providerId, body) {
584
640
  return void 0;
585
641
  }
586
642
  }
643
+ function sanitizeTokenCounts(input, output) {
644
+ const i = Math.max(0, Math.floor(input));
645
+ const o = Math.max(0, Math.floor(output));
646
+ if (!Number.isFinite(i) || !Number.isFinite(o)) return void 0;
647
+ return { inputTokens: i, outputTokens: o };
648
+ }
587
649
  function extractUsageFromParsed(providerId, parsed) {
588
650
  if (providerId === "anthropic") {
589
651
  const usage2 = parsed.usage;
590
652
  if (usage2?.input_tokens != null && usage2?.output_tokens != null) {
591
- return { inputTokens: usage2.input_tokens, outputTokens: usage2.output_tokens };
653
+ return sanitizeTokenCounts(usage2.input_tokens, usage2.output_tokens);
592
654
  }
593
655
  }
594
656
  if (providerId === "gemini") {
595
657
  const meta = parsed.usageMetadata;
596
658
  if (meta?.promptTokenCount != null) {
597
- return {
598
- inputTokens: meta.promptTokenCount,
599
- outputTokens: meta.candidatesTokenCount ?? 0
600
- };
659
+ return sanitizeTokenCounts(meta.promptTokenCount, meta.candidatesTokenCount ?? 0);
601
660
  }
602
661
  }
603
662
  const usage = parsed.usage;
604
663
  if (usage?.prompt_tokens != null && usage?.completion_tokens != null) {
605
- return { inputTokens: usage.prompt_tokens, outputTokens: usage.completion_tokens };
664
+ return sanitizeTokenCounts(usage.prompt_tokens, usage.completion_tokens);
606
665
  }
607
666
  return void 0;
608
667
  }
@@ -631,8 +690,10 @@ function encodeGiftLink(link) {
631
690
  const bytes = new TextEncoder().encode(json);
632
691
  return base64UrlEncode(bytes);
633
692
  }
693
+ var MAX_GIFT_LINK_SIZE = 8192;
634
694
  function decodeGiftLink(encoded) {
635
695
  try {
696
+ if (encoded.length > MAX_GIFT_LINK_SIZE) return null;
636
697
  const clean = encoded.replace(/^byoky:\/\/gift\//, "");
637
698
  const bytes = base64UrlDecode(clean);
638
699
  const json = new TextDecoder().decode(bytes);
@@ -692,6 +753,23 @@ function createGiftLink(gift) {
692
753
  };
693
754
  return { encoded: encodeGiftLink(link), link };
694
755
  }
756
+ function encodePairPayload(payload) {
757
+ const json = JSON.stringify(payload);
758
+ const bytes = new TextEncoder().encode(json);
759
+ return base64UrlEncode(bytes);
760
+ }
761
+ function decodePairPayload(encoded) {
762
+ try {
763
+ if (encoded.length > 2048) return null;
764
+ const bytes = base64UrlDecode(encoded);
765
+ const json = new TextDecoder().decode(bytes);
766
+ const parsed = JSON.parse(json);
767
+ if (parsed.v !== 1) return null;
768
+ return parsed;
769
+ } catch {
770
+ return null;
771
+ }
772
+ }
695
773
  function base64UrlEncode(bytes) {
696
774
  let binary = "";
697
775
  for (const byte of bytes) binary += String.fromCharCode(byte);
@@ -722,9 +800,11 @@ function base64UrlDecode(str) {
722
800
  createGiftLink,
723
801
  createMessage,
724
802
  decodeGiftLink,
803
+ decodePairPayload,
725
804
  decrypt,
726
805
  deriveKey,
727
806
  encodeGiftLink,
807
+ encodePairPayload,
728
808
  encrypt,
729
809
  extractUsageFromParsed,
730
810
  getProvider,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/crypto.ts","../src/errors.ts","../src/protocol.ts","../src/providers.ts","../src/relay.ts","../src/password-strength.ts","../src/proxy-utils.ts","../src/gift.ts"],"sourcesContent":["export * from './types.js';\nexport * from './crypto.js';\nexport * from './errors.js';\nexport * from './protocol.js';\nexport * from './providers.js';\nexport * from './relay.js';\nexport * from './password-strength.js';\nexport * from './proxy-utils.js';\nexport * from './gift.js';\n","export type ProviderId = 'anthropic' | 'openai' | 'gemini' | (string & {});\n\nexport type AuthMethod = 'api_key' | 'oauth';\n\nexport interface ProviderConfig {\n id: ProviderId;\n name: string;\n authMethods: AuthMethod[];\n baseUrl: string;\n oauthConfig?: OAuthConfig;\n}\n\nexport interface OAuthConfig {\n clientId: string;\n authorizationUrl: string;\n tokenUrl: string;\n scopes: string[];\n extraAuthParams?: Record<string, string>;\n}\n\n// --- Credentials ---\n\nexport interface CredentialBase {\n id: string;\n providerId: ProviderId;\n label: string;\n authMethod: AuthMethod;\n createdAt: number;\n lastUsedAt?: number;\n}\n\nexport interface ApiKeyCredential extends CredentialBase {\n authMethod: 'api_key';\n encryptedKey: string;\n}\n\nexport interface OAuthCredential extends CredentialBase {\n authMethod: 'oauth';\n encryptedAccessToken: string;\n encryptedRefreshToken?: string;\n expiresAt?: number;\n}\n\nexport type Credential = ApiKeyCredential | OAuthCredential;\n\nexport interface CredentialMeta {\n id: string;\n providerId: ProviderId;\n label: string;\n authMethod: AuthMethod;\n createdAt: number;\n lastUsedAt?: number;\n maskedKey?: string;\n}\n\n// --- Sessions ---\n\nexport interface Session {\n id: string;\n sessionKey: string;\n appOrigin: string;\n appName?: string;\n providers: SessionProvider[];\n createdAt: number;\n expiresAt: number;\n}\n\nexport interface SessionProvider {\n providerId: ProviderId;\n credentialId: string;\n available: boolean;\n authMethod: AuthMethod;\n giftId?: string;\n giftRelayUrl?: string;\n giftAuthToken?: string;\n}\n\n// --- Connect ---\n\nexport interface ConnectRequest {\n providers?: ProviderRequirement[];\n capabilities?: string[];\n}\n\nexport interface ProviderRequirement {\n id: ProviderId;\n required: boolean;\n}\n\nexport interface ConnectResponse {\n sessionKey: string;\n proxyUrl: string;\n providers: Record<\n string,\n {\n available: boolean;\n authMethod: AuthMethod;\n }\n >;\n}\n\n// --- Proxy ---\n\nexport interface ProxyRequest {\n requestId: string;\n sessionKey: string;\n providerId: string;\n url: string;\n method: string;\n headers: Record<string, string>;\n body?: string;\n}\n\nexport interface ProxyResponseMeta {\n requestId: string;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n}\n\nexport interface ProxyResponseChunk {\n requestId: string;\n chunk: string;\n}\n\nexport interface ProxyResponseError {\n requestId: string;\n status: number;\n error: { code: string; message: string };\n}\n\n// --- Protocol messages ---\n\nexport type MessageType =\n | 'BYOKY_CONNECT_REQUEST'\n | 'BYOKY_CONNECT_RESPONSE'\n | 'BYOKY_DISCONNECT'\n | 'BYOKY_PROXY_REQUEST'\n | 'BYOKY_PROXY_RESPONSE_META'\n | 'BYOKY_PROXY_RESPONSE_CHUNK'\n | 'BYOKY_PROXY_RESPONSE_DONE'\n | 'BYOKY_PROXY_RESPONSE_ERROR'\n | 'BYOKY_SESSION_STATUS'\n | 'BYOKY_SESSION_STATUS_RESPONSE'\n | 'BYOKY_SESSION_USAGE'\n | 'BYOKY_SESSION_USAGE_RESPONSE'\n | 'BYOKY_SESSION_REVOKED'\n | 'BYOKY_ERROR';\n\nexport interface ByokyMessage {\n type: MessageType;\n id: string;\n requestId?: string;\n payload: unknown;\n}\n\n// --- Session queries ---\n\nexport interface SessionUsage {\n requests: number;\n inputTokens: number;\n outputTokens: number;\n byProvider: Record<string, {\n requests: number;\n inputTokens: number;\n outputTokens: number;\n }>;\n}\n\n// --- Errors ---\n\nexport enum ByokyErrorCode {\n WALLET_NOT_INSTALLED = 'WALLET_NOT_INSTALLED',\n USER_REJECTED = 'USER_REJECTED',\n PROVIDER_UNAVAILABLE = 'PROVIDER_UNAVAILABLE',\n SESSION_EXPIRED = 'SESSION_EXPIRED',\n RATE_LIMITED = 'RATE_LIMITED',\n QUOTA_EXCEEDED = 'QUOTA_EXCEEDED',\n INVALID_KEY = 'INVALID_KEY',\n TOKEN_EXPIRED = 'TOKEN_EXPIRED',\n PROXY_ERROR = 'PROXY_ERROR',\n RELAY_CONNECTION_FAILED = 'RELAY_CONNECTION_FAILED',\n RELAY_DISCONNECTED = 'RELAY_DISCONNECTED',\n UNKNOWN = 'UNKNOWN',\n}\n\n// --- Request log ---\n\nexport interface RequestLogEntry {\n id: string;\n sessionId: string;\n appOrigin: string;\n providerId: ProviderId;\n url: string;\n method: string;\n status: number;\n timestamp: number;\n error?: string;\n inputTokens?: number;\n outputTokens?: number;\n model?: string;\n}\n\n// --- Pending approval ---\n\nexport interface PendingApproval {\n id: string;\n appOrigin: string;\n appName?: string;\n providers: ProviderRequirement[];\n timestamp: number;\n}\n\n// --- Trusted sites ---\n\nexport interface TrustedSite {\n origin: string;\n trustedAt: number;\n}\n\n// --- Token allowances ---\n\nexport interface TokenAllowance {\n origin: string;\n totalLimit?: number;\n providerLimits?: Record<string, number>;\n}\n","const SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst KEY_LENGTH = 256;\nconst ITERATIONS = 600_000;\n\nexport async function deriveKey(\n password: string,\n salt: Uint8Array,\n): Promise<CryptoKey> {\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(password),\n 'PBKDF2',\n false,\n ['deriveKey'],\n );\n\n return crypto.subtle.deriveKey(\n { name: 'PBKDF2', salt: salt as BufferSource, iterations: ITERATIONS, hash: 'SHA-256' },\n keyMaterial,\n { name: 'AES-GCM', length: KEY_LENGTH },\n false,\n ['encrypt', 'decrypt'],\n );\n}\n\nexport async function encrypt(\n plaintext: string,\n password: string,\n): Promise<string> {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n const key = await deriveKey(password, salt);\n\n const ciphertext = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv },\n key,\n new TextEncoder().encode(plaintext),\n );\n\n const combined = new Uint8Array(\n salt.length + iv.length + new Uint8Array(ciphertext).length,\n );\n combined.set(salt, 0);\n combined.set(iv, salt.length);\n combined.set(new Uint8Array(ciphertext), salt.length + iv.length);\n\n return btoa(String.fromCharCode(...combined));\n}\n\nexport async function decrypt(\n encrypted: string,\n password: string,\n): Promise<string> {\n const combined = Uint8Array.from(atob(encrypted), (c) => c.charCodeAt(0));\n\n const salt = combined.slice(0, SALT_LENGTH);\n const iv = combined.slice(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const ciphertext = combined.slice(SALT_LENGTH + IV_LENGTH);\n\n const key = await deriveKey(password, salt);\n\n const plaintext = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv },\n key,\n ciphertext,\n );\n\n return new TextDecoder().decode(plaintext);\n}\n\nasync function deriveRawHash(\n password: string,\n salt: Uint8Array,\n): Promise<Uint8Array> {\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(password),\n 'PBKDF2',\n false,\n ['deriveBits'],\n );\n\n const bits = await crypto.subtle.deriveBits(\n { name: 'PBKDF2', salt: salt as BufferSource, iterations: ITERATIONS, hash: 'SHA-256' },\n keyMaterial,\n KEY_LENGTH,\n );\n\n return new Uint8Array(bits);\n}\n\nexport async function hashPassword(password: string): Promise<string> {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const hash = await deriveRawHash(password, salt);\n\n const combined = new Uint8Array(salt.length + hash.length);\n combined.set(salt, 0);\n combined.set(hash, salt.length);\n\n return btoa(String.fromCharCode(...combined));\n}\n\nexport async function verifyPassword(\n password: string,\n storedHash: string,\n): Promise<boolean> {\n const combined = Uint8Array.from(atob(storedHash), (c) => c.charCodeAt(0));\n const salt = combined.slice(0, SALT_LENGTH);\n const originalHash = combined.slice(SALT_LENGTH);\n\n const newHash = await deriveRawHash(password, salt);\n\n if (originalHash.length !== newHash.length) return false;\n let result = 0;\n for (let i = 0; i < originalHash.length; i++) {\n result |= originalHash[i] ^ newHash[i];\n }\n return result === 0;\n}\n\nexport function maskKey(key: string): string {\n if (key.length <= 8) return '****';\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n}\n","import { ByokyErrorCode } from './types.js';\n\nexport class ByokyError extends Error {\n constructor(\n public readonly code: ByokyErrorCode,\n message: string,\n public readonly details?: Record<string, unknown>,\n ) {\n super(message);\n this.name = 'ByokyError';\n }\n\n static walletNotInstalled() {\n return new ByokyError(\n ByokyErrorCode.WALLET_NOT_INSTALLED,\n 'byoky wallet extension is not installed',\n );\n }\n\n static userRejected() {\n return new ByokyError(\n ByokyErrorCode.USER_REJECTED,\n 'User rejected the connection request',\n );\n }\n\n static providerUnavailable(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.PROVIDER_UNAVAILABLE,\n `Provider \"${providerId}\" is not available`,\n { providerId },\n );\n }\n\n static sessionExpired() {\n return new ByokyError(\n ByokyErrorCode.SESSION_EXPIRED,\n 'Session has expired — please reconnect',\n );\n }\n\n static rateLimited(retryAfter?: number) {\n return new ByokyError(\n ByokyErrorCode.RATE_LIMITED,\n `Rate limit exceeded${retryAfter ? ` — retry after ${retryAfter}s` : ''}`,\n { retryAfter },\n );\n }\n\n static quotaExceeded(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.QUOTA_EXCEEDED,\n `Quota exceeded for ${providerId} — check your billing`,\n { providerId },\n );\n }\n\n static invalidKey(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.INVALID_KEY,\n `Invalid API key for ${providerId}`,\n { providerId },\n );\n }\n\n static tokenExpired(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.TOKEN_EXPIRED,\n `OAuth token expired for ${providerId} — re-authentication required`,\n { providerId },\n );\n }\n\n static relayConnectionFailed(reason?: string) {\n return new ByokyError(\n ByokyErrorCode.RELAY_CONNECTION_FAILED,\n `Relay connection failed${reason ? `: ${reason}` : ''}`,\n );\n }\n\n static relayDisconnected() {\n return new ByokyError(\n ByokyErrorCode.RELAY_DISCONNECTED,\n 'Relay connection was closed',\n );\n }\n}\n","import type {\n ByokyMessage,\n ConnectRequest,\n ConnectResponse,\n MessageType,\n} from './types.js';\n\nexport const BYOKY_PROVIDER_KEY = '__byoky__';\nexport const BYOKY_MESSAGE_PREFIX = 'BYOKY_';\n\nexport function createMessage(\n type: MessageType,\n payload: unknown,\n requestId?: string,\n): ByokyMessage {\n return {\n type,\n id: crypto.randomUUID(),\n requestId,\n payload,\n };\n}\n\nexport function isByokyMessage(data: unknown): data is ByokyMessage {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'type' in data &&\n typeof (data as ByokyMessage).type === 'string' &&\n (data as ByokyMessage).type.startsWith(BYOKY_MESSAGE_PREFIX)\n );\n}\n\nexport function createConnectRequest(request: ConnectRequest): ByokyMessage {\n return createMessage('BYOKY_CONNECT_REQUEST', request);\n}\n\nexport function createConnectResponse(\n response: ConnectResponse,\n requestId: string,\n): ByokyMessage {\n return createMessage('BYOKY_CONNECT_RESPONSE', response, requestId);\n}\n\nexport function createErrorMessage(\n code: string,\n message: string,\n requestId?: string,\n): ByokyMessage {\n return createMessage('BYOKY_ERROR', { code, message }, requestId);\n}\n","import type { ProviderConfig } from './types.js';\n\nexport const PROVIDERS: Record<string, ProviderConfig> = {\n anthropic: {\n id: 'anthropic',\n name: 'Anthropic',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://api.anthropic.com',\n },\n openai: {\n id: 'openai',\n name: 'OpenAI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.openai.com',\n },\n gemini: {\n id: 'gemini',\n name: 'Google Gemini',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://generativelanguage.googleapis.com',\n oauthConfig: {\n clientId: '699663966637-gr4d994198r4g6jvip25ffg85kree6ck.apps.googleusercontent.com',\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n scopes: ['https://www.googleapis.com/auth/generative-language'],\n extraAuthParams: { access_type: 'offline', prompt: 'consent' },\n },\n },\n mistral: {\n id: 'mistral',\n name: 'Mistral',\n authMethods: ['api_key'],\n baseUrl: 'https://api.mistral.ai',\n },\n cohere: {\n id: 'cohere',\n name: 'Cohere',\n authMethods: ['api_key'],\n baseUrl: 'https://api.cohere.com',\n },\n xai: {\n id: 'xai',\n name: 'xAI (Grok)',\n authMethods: ['api_key'],\n baseUrl: 'https://api.x.ai',\n },\n deepseek: {\n id: 'deepseek',\n name: 'DeepSeek',\n authMethods: ['api_key'],\n baseUrl: 'https://api.deepseek.com',\n },\n perplexity: {\n id: 'perplexity',\n name: 'Perplexity',\n authMethods: ['api_key'],\n baseUrl: 'https://api.perplexity.ai',\n },\n groq: {\n id: 'groq',\n name: 'Groq',\n authMethods: ['api_key'],\n baseUrl: 'https://api.groq.com',\n },\n together: {\n id: 'together',\n name: 'Together AI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.together.xyz',\n },\n fireworks: {\n id: 'fireworks',\n name: 'Fireworks AI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.fireworks.ai',\n },\n replicate: {\n id: 'replicate',\n name: 'Replicate',\n authMethods: ['api_key'],\n baseUrl: 'https://api.replicate.com',\n },\n openrouter: {\n id: 'openrouter',\n name: 'OpenRouter',\n authMethods: ['api_key'],\n baseUrl: 'https://openrouter.ai/api',\n },\n huggingface: {\n id: 'huggingface',\n name: 'Hugging Face',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://api-inference.huggingface.co',\n oauthConfig: {\n clientId: '031aeb11-725b-498a-93f9-d3599d84f57c',\n authorizationUrl: 'https://huggingface.co/oauth/authorize',\n tokenUrl: 'https://huggingface.co/oauth/token',\n scopes: ['inference-api'],\n },\n },\n azure_openai: {\n id: 'azure_openai',\n name: 'Azure OpenAI',\n authMethods: ['api_key'],\n baseUrl: 'https://YOUR_RESOURCE.openai.azure.com',\n },\n};\n\nexport function getProvider(id: string): ProviderConfig | undefined {\n return PROVIDERS[id];\n}\n\nexport function getProviderIds(): string[] {\n return Object.keys(PROVIDERS);\n}\n","import type { AuthMethod } from './types.js';\n\n/** Minimal WebSocket interface — compatible with browser WebSocket and `ws` library. */\nexport interface WebSocketLike {\n readonly readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n onclose: ((event: { code: number; reason: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n}\n\nexport const WS_READY_STATE = {\n CONNECTING: 0,\n OPEN: 1,\n CLOSING: 2,\n CLOSED: 3,\n} as const;\n\n// --- Relay message types ---\n\nexport interface RelayHello {\n type: 'relay:hello';\n sessionId: string;\n providers: Record<string, { available: boolean; authMethod: AuthMethod }>;\n}\n\nexport interface RelayRequest {\n type: 'relay:request';\n requestId: string;\n providerId: string;\n url: string;\n method: string;\n headers: Record<string, string>;\n body?: string;\n}\n\nexport interface RelayResponseMeta {\n type: 'relay:response:meta';\n requestId: string;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n}\n\nexport interface RelayResponseChunk {\n type: 'relay:response:chunk';\n requestId: string;\n chunk: string;\n}\n\nexport interface RelayResponseDone {\n type: 'relay:response:done';\n requestId: string;\n}\n\nexport interface RelayResponseError {\n type: 'relay:response:error';\n requestId: string;\n error: { code: string; message: string };\n}\n\nexport interface RelayPing {\n type: 'relay:ping';\n ts: number;\n}\n\nexport interface RelayPong {\n type: 'relay:pong';\n ts: number;\n}\n\nexport type RelayMessage =\n | RelayHello\n | RelayRequest\n | RelayResponseMeta\n | RelayResponseChunk\n | RelayResponseDone\n | RelayResponseError\n | RelayPing\n | RelayPong;\n\nexport function parseRelayMessage(data: unknown): RelayMessage | null {\n try {\n const raw = typeof data === 'string' ? JSON.parse(data) : data;\n if (!raw || typeof raw !== 'object' || typeof raw.type !== 'string' || !raw.type.startsWith('relay:')) {\n return null;\n }\n\n // Validate required fields per message type\n switch (raw.type) {\n case 'relay:hello':\n if (typeof raw.sessionId !== 'string') return null;\n break;\n case 'relay:request':\n if (typeof raw.requestId !== 'string' || typeof raw.providerId !== 'string' ||\n typeof raw.url !== 'string' || typeof raw.method !== 'string') return null;\n break;\n case 'relay:response:meta':\n if (typeof raw.requestId !== 'string' || typeof raw.status !== 'number') return null;\n break;\n case 'relay:response:chunk':\n if (typeof raw.requestId !== 'string' || typeof raw.chunk !== 'string') return null;\n break;\n case 'relay:response:done':\n case 'relay:response:error':\n if (typeof raw.requestId !== 'string') return null;\n break;\n case 'relay:ping':\n case 'relay:pong':\n if (typeof raw.ts !== 'number') return null;\n break;\n default:\n return null;\n }\n\n return raw as RelayMessage;\n } catch {\n return null;\n }\n}\n\nexport function sendRelayMessage(ws: WebSocketLike, msg: RelayMessage): void {\n if (ws.readyState === WS_READY_STATE.OPEN) {\n ws.send(JSON.stringify(msg));\n }\n}\n","export interface PasswordStrength {\n score: 0 | 1 | 2 | 3 | 4;\n label: 'Too weak' | 'Weak' | 'Fair' | 'Strong' | 'Very strong';\n feedback: string[];\n}\n\nconst COMMON_PASSWORDS = new Set([\n 'password', '12345678', 'qwerty12', 'letmein12', 'welcome1',\n 'monkey12', 'dragon12', 'master12', 'abc12345', 'password1',\n 'password12', 'iloveyou1', 'sunshine1', 'trustno1', 'princess1',\n 'football1', 'shadow123', 'michael1', 'jordan123', 'superman1',\n]);\n\nexport function checkPasswordStrength(password: string): PasswordStrength {\n const feedback: string[] = [];\n let score = 0;\n\n if (password.length < 12) {\n feedback.push('Use at least 12 characters');\n if (password.length < 8) {\n return { score: 0, label: 'Too weak', feedback };\n }\n } else {\n score++;\n if (password.length >= 16) score++;\n }\n\n if (COMMON_PASSWORDS.has(password.toLowerCase())) {\n feedback.push('This is a commonly used password');\n return { score: 0, label: 'Too weak', feedback };\n }\n\n // Check character diversity\n const hasLower = /[a-z]/.test(password);\n const hasUpper = /[A-Z]/.test(password);\n const hasDigit = /\\d/.test(password);\n const hasSymbol = /[^a-zA-Z0-9]/.test(password);\n const charTypes = [hasLower, hasUpper, hasDigit, hasSymbol].filter(Boolean).length;\n\n if (charTypes < 2) {\n feedback.push('Mix uppercase, lowercase, numbers, and symbols');\n } else if (charTypes >= 3) {\n score++;\n }\n if (charTypes >= 4) {\n score++;\n }\n\n // Check for repeated characters (e.g. aaaaaa)\n if (/(.)\\1{3,}/.test(password)) {\n feedback.push('Avoid repeated characters');\n score = Math.max(0, score - 1);\n }\n\n // Check for sequential patterns (e.g. 123456, abcdef)\n if (/(?:012|123|234|345|456|567|678|789|abc|bcd|cde|def)/i.test(password)) {\n feedback.push('Avoid sequential patterns');\n score = Math.max(0, score - 1);\n }\n\n const capped = Math.min(4, Math.max(0, score)) as 0 | 1 | 2 | 3 | 4;\n const labels: Record<number, PasswordStrength['label']> = {\n 0: 'Too weak',\n 1: 'Weak',\n 2: 'Fair',\n 3: 'Strong',\n 4: 'Very strong',\n };\n\n if (feedback.length === 0 && capped < 3) {\n feedback.push('Add more character variety or length');\n }\n\n return { score: capped, label: labels[capped], feedback };\n}\n\nexport const MIN_PASSWORD_LENGTH = 12;\n","import type { RequestLogEntry, TokenAllowance } from './types.js';\nimport { PROVIDERS } from './providers.js';\n\n/**\n * Validate that a proxy request URL targets the registered provider's base URL.\n * Prevents API key exfiltration by rejecting requests to arbitrary domains.\n */\nexport function validateProxyUrl(providerId: string, url: string): boolean {\n const provider = PROVIDERS[providerId];\n if (!provider) return false;\n try {\n const target = new URL(url);\n if (target.protocol !== 'https:') return false;\n const base = new URL(provider.baseUrl);\n return target.origin === base.origin;\n } catch {\n return false;\n }\n}\n\n/**\n * Build the real auth headers for a provider API request.\n * Strips any fake session-key headers and injects the real API key.\n */\nexport function buildHeaders(\n providerId: string,\n requestHeaders: Record<string, string>,\n apiKey: string,\n authMethod: string = 'api_key',\n): Record<string, string> {\n // Normalize header keys to lowercase to prevent case-sensitive bypass\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(requestHeaders)) {\n headers[key.toLowerCase()] = value;\n }\n\n // Remove any auth headers the SDK might have set (they're fake session keys)\n delete headers['authorization'];\n delete headers['x-api-key'];\n delete headers['api-key'];\n\n // Strip browser/SDK headers that can trigger rejection from provider APIs\n delete headers['origin'];\n delete headers['referer'];\n // Remove SDK telemetry headers that leak the real client environment\n for (const key of Object.keys(headers)) {\n if (key.startsWith('x-stainless-')) delete headers[key];\n }\n delete headers['sec-fetch-mode'];\n delete headers['accept-language'];\n delete headers['accept-encoding'];\n // Always strip content-length — fetch() recalculates it from the actual body,\n // and the body may have been modified (e.g. system prompt injection)\n delete headers['content-length'];\n\n if (providerId === 'anthropic') {\n if (authMethod === 'oauth') {\n headers['authorization'] = `Bearer ${apiKey}`;\n headers['user-agent'] = 'claude-cli/2.1.76';\n headers['x-app'] = 'cli';\n headers['accept'] = 'application/json';\n headers['anthropic-beta'] = 'claude-code-20250219,oauth-2025-04-20,fine-grained-tool-streaming-2025-05-14,interleaved-thinking-2025-05-14';\n headers['anthropic-dangerous-direct-browser-access'] = 'true';\n } else {\n headers['x-api-key'] = apiKey;\n }\n headers['anthropic-version'] = headers['anthropic-version'] ?? '2023-06-01';\n } else if (providerId === 'azure_openai') {\n headers['api-key'] = apiKey;\n } else {\n headers['authorization'] = `Bearer ${apiKey}`;\n }\n\n return headers;\n}\n\n/**\n * Parse the model name from a request body (JSON).\n */\nexport function parseModel(body?: string): string | undefined {\n if (!body) return undefined;\n try {\n const parsed = JSON.parse(body);\n return parsed.model ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Parse token usage from a provider API response body.\n * Handles both regular JSON responses and SSE streaming responses.\n */\nexport function parseUsage(\n providerId: string,\n body: string,\n): { inputTokens: number; outputTokens: number } | undefined {\n try {\n // For streaming responses (SSE), try to find usage in the last data chunk\n if (body.includes('data: ')) {\n const lines = body.split('\\n').filter((l) => l.startsWith('data: ') && !l.includes('[DONE]'));\n // Anthropic streaming: message_stop event has usage in a preceding message_delta\n // OpenAI streaming: last chunk may include usage\n for (let i = lines.length - 1; i >= 0; i--) {\n const json = lines[i].replace('data: ', '');\n try {\n const parsed = JSON.parse(json);\n const usage = extractUsageFromParsed(providerId, parsed);\n if (usage) return usage;\n } catch {\n continue;\n }\n }\n return undefined;\n }\n\n const parsed = JSON.parse(body);\n return extractUsageFromParsed(providerId, parsed);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Extract token usage from a parsed provider response object.\n */\nexport function extractUsageFromParsed(\n providerId: string,\n parsed: Record<string, unknown>,\n): { inputTokens: number; outputTokens: number } | undefined {\n // Anthropic: { usage: { input_tokens, output_tokens } }\n if (providerId === 'anthropic') {\n const usage = parsed.usage as Record<string, number> | undefined;\n if (usage?.input_tokens != null && usage?.output_tokens != null) {\n return { inputTokens: usage.input_tokens, outputTokens: usage.output_tokens };\n }\n }\n\n // Gemini: { usageMetadata: { promptTokenCount, candidatesTokenCount } }\n if (providerId === 'gemini') {\n const meta = parsed.usageMetadata as Record<string, number> | undefined;\n if (meta?.promptTokenCount != null) {\n return {\n inputTokens: meta.promptTokenCount,\n outputTokens: meta.candidatesTokenCount ?? 0,\n };\n }\n }\n\n // OpenAI-compatible (openai, groq, together, deepseek, xai, perplexity, fireworks, openrouter, mistral, azure_openai):\n // { usage: { prompt_tokens, completion_tokens } }\n const usage = parsed.usage as Record<string, number> | undefined;\n if (usage?.prompt_tokens != null && usage?.completion_tokens != null) {\n return { inputTokens: usage.prompt_tokens, outputTokens: usage.completion_tokens };\n }\n\n return undefined;\n}\n\n/**\n * Check whether a request is allowed given token allowances and usage history.\n * Pure computation — no storage access.\n */\nexport function computeAllowanceCheck(\n allowance: TokenAllowance | undefined,\n entries: Pick<RequestLogEntry, 'providerId' | 'inputTokens' | 'outputTokens'>[],\n providerId: string,\n): { allowed: boolean; reason?: string } {\n if (!allowance) return { allowed: true };\n\n let totalUsed = 0;\n const byProvider: Record<string, number> = {};\n for (const entry of entries) {\n const tokens = (entry.inputTokens ?? 0) + (entry.outputTokens ?? 0);\n totalUsed += tokens;\n byProvider[entry.providerId] = (byProvider[entry.providerId] ?? 0) + tokens;\n }\n\n if (allowance.totalLimit != null && totalUsed >= allowance.totalLimit) {\n return { allowed: false, reason: `Token allowance exceeded for ${allowance.origin}` };\n }\n\n const providerLimit = allowance.providerLimits?.[providerId];\n if (providerLimit != null && (byProvider[providerId] ?? 0) >= providerLimit) {\n return { allowed: false, reason: `Token allowance for ${providerId} exceeded` };\n }\n\n return { allowed: true };\n}\n","import { PROVIDERS } from './providers.js';\n\n// --- Gift (sender side) ---\n\nexport interface Gift {\n id: string;\n credentialId: string;\n providerId: string;\n label: string;\n authToken: string;\n maxTokens: number;\n usedTokens: number;\n expiresAt: number;\n createdAt: number;\n active: boolean;\n relayUrl: string;\n}\n\n// --- Gift link (shareable payload) ---\n\nexport interface GiftLink {\n v: 1;\n id: string;\n p: string; // providerId\n n: string; // provider display name\n s: string; // sender label\n t: string; // auth token\n m: number; // max tokens\n e: number; // expires at (unix ms)\n r: string; // relay URL\n}\n\n// --- Gifted credential (recipient side) ---\n\nexport interface GiftedCredential {\n id: string;\n giftId: string;\n providerId: string;\n providerName: string;\n senderLabel: string;\n authToken: string;\n maxTokens: number;\n usedTokens: number;\n expiresAt: number;\n relayUrl: string;\n createdAt: number;\n}\n\n// --- Gift relay protocol ---\n\nexport interface GiftRelayAuth {\n type: 'gift:auth';\n giftId: string;\n authToken: string;\n role: 'sender' | 'recipient';\n}\n\nexport interface GiftRelayAuthResult {\n type: 'gift:auth:result';\n success: boolean;\n error?: string;\n peerOnline?: boolean;\n}\n\nexport interface GiftRelayPeerStatus {\n type: 'gift:peer:status';\n online: boolean;\n}\n\nexport interface GiftRelayUsageUpdate {\n type: 'gift:usage';\n giftId: string;\n usedTokens: number;\n}\n\nexport type GiftRelayMessage =\n | GiftRelayAuth\n | GiftRelayAuthResult\n | GiftRelayPeerStatus\n | GiftRelayUsageUpdate;\n\n// --- Encoding / decoding ---\n\nexport function encodeGiftLink(link: GiftLink): string {\n const json = JSON.stringify(link);\n const bytes = new TextEncoder().encode(json);\n return base64UrlEncode(bytes);\n}\n\nexport function decodeGiftLink(encoded: string): GiftLink | null {\n try {\n const clean = encoded.replace(/^byoky:\\/\\/gift\\//, '');\n const bytes = base64UrlDecode(clean);\n const json = new TextDecoder().decode(bytes);\n const parsed = JSON.parse(json);\n if (parsed.v !== 1) return null;\n return parsed as GiftLink;\n } catch {\n return null;\n }\n}\n\nexport function giftLinkToUrl(encoded: string): string {\n return `byoky://gift/${encoded}`;\n}\n\n// --- Validation ---\n\nexport function validateGiftLink(link: GiftLink): { valid: boolean; reason?: string } {\n if (link.v !== 1) return { valid: false, reason: 'Unsupported gift version' };\n if (!link.id || typeof link.id !== 'string') return { valid: false, reason: 'Missing gift ID' };\n if (!link.p || typeof link.p !== 'string') return { valid: false, reason: 'Missing provider' };\n if (!link.t || typeof link.t !== 'string') return { valid: false, reason: 'Missing auth token' };\n if (!link.r || typeof link.r !== 'string') return { valid: false, reason: 'Missing relay URL' };\n if (typeof link.m !== 'number' || link.m <= 0) return { valid: false, reason: 'Invalid token budget' };\n if (typeof link.e !== 'number' || link.e <= Date.now()) return { valid: false, reason: 'Gift has expired' };\n\n try {\n const url = new URL(link.r);\n if (url.protocol !== 'ws:' && url.protocol !== 'wss:') {\n return { valid: false, reason: 'Relay URL must use ws:// or wss://' };\n }\n } catch {\n return { valid: false, reason: 'Invalid relay URL' };\n }\n\n return { valid: true };\n}\n\nexport function isGiftExpired(gift: { expiresAt: number }): boolean {\n return gift.expiresAt <= Date.now();\n}\n\nexport function isGiftBudgetExhausted(gift: { usedTokens: number; maxTokens: number }): boolean {\n return gift.usedTokens >= gift.maxTokens;\n}\n\nexport function giftBudgetRemaining(gift: { usedTokens: number; maxTokens: number }): number {\n return Math.max(0, gift.maxTokens - gift.usedTokens);\n}\n\nexport function giftBudgetPercent(gift: { usedTokens: number; maxTokens: number }): number {\n if (gift.maxTokens === 0) return 100;\n return Math.min(100, Math.round((gift.usedTokens / gift.maxTokens) * 100));\n}\n\nexport function createGiftLink(gift: Gift): { encoded: string; link: GiftLink } {\n const provider = PROVIDERS[gift.providerId];\n const link: GiftLink = {\n v: 1,\n id: gift.id,\n p: gift.providerId,\n n: provider?.name ?? gift.providerId,\n s: gift.label,\n t: gift.authToken,\n m: gift.maxTokens,\n e: gift.expiresAt,\n r: gift.relayUrl,\n };\n return { encoded: encodeGiftLink(link), link };\n}\n\n// --- Base64url helpers ---\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction base64UrlDecode(str: string): Uint8Array {\n const padded = str.replace(/-/g, '+').replace(/_/g, '/');\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n"],"mappings":"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","names":["ByokyErrorCode","parsed","usage"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/crypto.ts","../src/errors.ts","../src/protocol.ts","../src/providers.ts","../src/relay.ts","../src/password-strength.ts","../src/proxy-utils.ts","../src/gift.ts"],"sourcesContent":["export * from './types.js';\nexport * from './crypto.js';\nexport * from './errors.js';\nexport * from './protocol.js';\nexport * from './providers.js';\nexport * from './relay.js';\nexport * from './password-strength.js';\nexport * from './proxy-utils.js';\nexport * from './gift.js';\n","export type ProviderId = 'anthropic' | 'openai' | 'gemini' | (string & {});\n\nexport type AuthMethod = 'api_key' | 'oauth';\n\nexport interface ProviderConfig {\n id: ProviderId;\n name: string;\n authMethods: AuthMethod[];\n baseUrl: string;\n oauthConfig?: OAuthConfig;\n}\n\nexport interface OAuthConfig {\n clientId: string;\n authorizationUrl: string;\n tokenUrl: string;\n scopes: string[];\n extraAuthParams?: Record<string, string>;\n}\n\n// --- Credentials ---\n\nexport interface CredentialBase {\n id: string;\n providerId: ProviderId;\n label: string;\n authMethod: AuthMethod;\n createdAt: number;\n lastUsedAt?: number;\n}\n\nexport interface ApiKeyCredential extends CredentialBase {\n authMethod: 'api_key';\n encryptedKey: string;\n}\n\nexport interface OAuthCredential extends CredentialBase {\n authMethod: 'oauth';\n encryptedAccessToken: string;\n encryptedRefreshToken?: string;\n expiresAt?: number;\n}\n\nexport type Credential = ApiKeyCredential | OAuthCredential;\n\nexport interface CredentialMeta {\n id: string;\n providerId: ProviderId;\n label: string;\n authMethod: AuthMethod;\n createdAt: number;\n lastUsedAt?: number;\n maskedKey?: string;\n}\n\n// --- Sessions ---\n\nexport interface Session {\n id: string;\n sessionKey: string;\n appOrigin: string;\n appName?: string;\n providers: SessionProvider[];\n createdAt: number;\n expiresAt: number;\n}\n\nexport interface SessionProvider {\n providerId: ProviderId;\n credentialId: string;\n available: boolean;\n authMethod: AuthMethod;\n giftId?: string;\n giftRelayUrl?: string;\n giftAuthToken?: string;\n}\n\n// --- Connect ---\n\nexport interface ConnectRequest {\n providers?: ProviderRequirement[];\n capabilities?: string[];\n}\n\nexport interface ProviderRequirement {\n id: ProviderId;\n required: boolean;\n}\n\nexport interface ConnectResponse {\n sessionKey: string;\n proxyUrl: string;\n providers: Record<\n string,\n {\n available: boolean;\n authMethod: AuthMethod;\n }\n >;\n}\n\n// --- Proxy ---\n\nexport interface ProxyRequest {\n requestId: string;\n sessionKey: string;\n providerId: string;\n url: string;\n method: string;\n headers: Record<string, string>;\n body?: string;\n}\n\nexport interface ProxyResponseMeta {\n requestId: string;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n}\n\nexport interface ProxyResponseChunk {\n requestId: string;\n chunk: string;\n}\n\nexport interface ProxyResponseError {\n requestId: string;\n status: number;\n error: { code: string; message: string };\n}\n\n// --- Protocol messages ---\n\nexport type MessageType =\n | 'BYOKY_CONNECT_REQUEST'\n | 'BYOKY_CONNECT_RESPONSE'\n | 'BYOKY_DISCONNECT'\n | 'BYOKY_PROXY_REQUEST'\n | 'BYOKY_PROXY_RESPONSE_META'\n | 'BYOKY_PROXY_RESPONSE_CHUNK'\n | 'BYOKY_PROXY_RESPONSE_DONE'\n | 'BYOKY_PROXY_RESPONSE_ERROR'\n | 'BYOKY_SESSION_STATUS'\n | 'BYOKY_SESSION_STATUS_RESPONSE'\n | 'BYOKY_SESSION_USAGE'\n | 'BYOKY_SESSION_USAGE_RESPONSE'\n | 'BYOKY_SESSION_REVOKED'\n | 'BYOKY_ERROR';\n\nexport interface ByokyMessage {\n type: MessageType;\n id: string;\n requestId?: string;\n payload: unknown;\n}\n\n// --- Session queries ---\n\nexport interface SessionUsage {\n requests: number;\n inputTokens: number;\n outputTokens: number;\n byProvider: Record<string, {\n requests: number;\n inputTokens: number;\n outputTokens: number;\n }>;\n}\n\n// --- Errors ---\n\nexport enum ByokyErrorCode {\n WALLET_NOT_INSTALLED = 'WALLET_NOT_INSTALLED',\n USER_REJECTED = 'USER_REJECTED',\n PROVIDER_UNAVAILABLE = 'PROVIDER_UNAVAILABLE',\n SESSION_EXPIRED = 'SESSION_EXPIRED',\n RATE_LIMITED = 'RATE_LIMITED',\n QUOTA_EXCEEDED = 'QUOTA_EXCEEDED',\n INVALID_KEY = 'INVALID_KEY',\n TOKEN_EXPIRED = 'TOKEN_EXPIRED',\n PROXY_ERROR = 'PROXY_ERROR',\n RELAY_CONNECTION_FAILED = 'RELAY_CONNECTION_FAILED',\n RELAY_DISCONNECTED = 'RELAY_DISCONNECTED',\n UNKNOWN = 'UNKNOWN',\n}\n\n// --- Request log ---\n\nexport interface RequestLogEntry {\n id: string;\n sessionId: string;\n appOrigin: string;\n providerId: ProviderId;\n url: string;\n method: string;\n status: number;\n timestamp: number;\n error?: string;\n inputTokens?: number;\n outputTokens?: number;\n model?: string;\n}\n\n// --- Pending approval ---\n\nexport interface PendingApproval {\n id: string;\n appOrigin: string;\n appName?: string;\n providers: ProviderRequirement[];\n timestamp: number;\n}\n\n// --- Trusted sites ---\n\nexport interface TrustedSite {\n origin: string;\n trustedAt: number;\n allowedProviders?: string[];\n}\n\n// --- Token allowances ---\n\nexport interface TokenAllowance {\n origin: string;\n totalLimit?: number;\n providerLimits?: Record<string, number>;\n}\n","const SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst KEY_LENGTH = 256;\nconst ITERATIONS = 600_000;\n\nexport async function deriveKey(\n password: string,\n salt: Uint8Array,\n): Promise<CryptoKey> {\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(password),\n 'PBKDF2',\n false,\n ['deriveKey'],\n );\n\n return crypto.subtle.deriveKey(\n { name: 'PBKDF2', salt: salt as BufferSource, iterations: ITERATIONS, hash: 'SHA-256' },\n keyMaterial,\n { name: 'AES-GCM', length: KEY_LENGTH },\n false,\n ['encrypt', 'decrypt'],\n );\n}\n\nexport async function encrypt(\n plaintext: string,\n password: string,\n): Promise<string> {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n const key = await deriveKey(password, salt);\n\n const ciphertext = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv },\n key,\n new TextEncoder().encode(plaintext),\n );\n\n const combined = new Uint8Array(\n salt.length + iv.length + new Uint8Array(ciphertext).length,\n );\n combined.set(salt, 0);\n combined.set(iv, salt.length);\n combined.set(new Uint8Array(ciphertext), salt.length + iv.length);\n\n return btoa(String.fromCharCode(...combined));\n}\n\nexport async function decrypt(\n encrypted: string,\n password: string,\n): Promise<string> {\n const combined = Uint8Array.from(atob(encrypted), (c) => c.charCodeAt(0));\n\n const salt = combined.slice(0, SALT_LENGTH);\n const iv = combined.slice(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const ciphertext = combined.slice(SALT_LENGTH + IV_LENGTH);\n\n const key = await deriveKey(password, salt);\n\n const plaintext = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv },\n key,\n ciphertext,\n );\n\n return new TextDecoder().decode(plaintext);\n}\n\nasync function deriveRawHash(\n password: string,\n salt: Uint8Array,\n): Promise<Uint8Array> {\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(password),\n 'PBKDF2',\n false,\n ['deriveBits'],\n );\n\n const bits = await crypto.subtle.deriveBits(\n { name: 'PBKDF2', salt: salt as BufferSource, iterations: ITERATIONS, hash: 'SHA-256' },\n keyMaterial,\n KEY_LENGTH,\n );\n\n return new Uint8Array(bits);\n}\n\nexport async function hashPassword(password: string): Promise<string> {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const hash = await deriveRawHash(password, salt);\n\n const combined = new Uint8Array(salt.length + hash.length);\n combined.set(salt, 0);\n combined.set(hash, salt.length);\n\n return btoa(String.fromCharCode(...combined));\n}\n\nexport async function verifyPassword(\n password: string,\n storedHash: string,\n): Promise<boolean> {\n const combined = Uint8Array.from(atob(storedHash), (c) => c.charCodeAt(0));\n const salt = combined.slice(0, SALT_LENGTH);\n const originalHash = combined.slice(SALT_LENGTH);\n\n const newHash = await deriveRawHash(password, salt);\n\n if (originalHash.length !== newHash.length) return false;\n let result = 0;\n for (let i = 0; i < originalHash.length; i++) {\n result |= originalHash[i] ^ newHash[i];\n }\n return result === 0;\n}\n\nexport function maskKey(key: string): string {\n if (key.length <= 8) return '****';\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n}\n","import { ByokyErrorCode } from './types.js';\n\nexport class ByokyError extends Error {\n constructor(\n public readonly code: ByokyErrorCode,\n message: string,\n public readonly details?: Record<string, unknown>,\n ) {\n super(message);\n this.name = 'ByokyError';\n }\n\n static walletNotInstalled() {\n return new ByokyError(\n ByokyErrorCode.WALLET_NOT_INSTALLED,\n 'byoky wallet extension is not installed',\n );\n }\n\n static userRejected() {\n return new ByokyError(\n ByokyErrorCode.USER_REJECTED,\n 'User rejected the connection request',\n );\n }\n\n static providerUnavailable(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.PROVIDER_UNAVAILABLE,\n `Provider \"${providerId}\" is not available`,\n { providerId },\n );\n }\n\n static sessionExpired() {\n return new ByokyError(\n ByokyErrorCode.SESSION_EXPIRED,\n 'Session has expired — please reconnect',\n );\n }\n\n static rateLimited(retryAfter?: number) {\n return new ByokyError(\n ByokyErrorCode.RATE_LIMITED,\n `Rate limit exceeded${retryAfter ? ` — retry after ${retryAfter}s` : ''}`,\n { retryAfter },\n );\n }\n\n static quotaExceeded(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.QUOTA_EXCEEDED,\n `Quota exceeded for ${providerId} — check your billing`,\n { providerId },\n );\n }\n\n static invalidKey(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.INVALID_KEY,\n `Invalid API key for ${providerId}`,\n { providerId },\n );\n }\n\n static tokenExpired(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.TOKEN_EXPIRED,\n `OAuth token expired for ${providerId} — re-authentication required`,\n { providerId },\n );\n }\n\n static relayConnectionFailed(reason?: string) {\n return new ByokyError(\n ByokyErrorCode.RELAY_CONNECTION_FAILED,\n `Relay connection failed${reason ? `: ${reason}` : ''}`,\n );\n }\n\n static relayDisconnected() {\n return new ByokyError(\n ByokyErrorCode.RELAY_DISCONNECTED,\n 'Relay connection was closed',\n );\n }\n}\n","import type {\n ByokyMessage,\n ConnectRequest,\n ConnectResponse,\n MessageType,\n} from './types.js';\n\nexport const BYOKY_PROVIDER_KEY = '__byoky__';\nexport const BYOKY_MESSAGE_PREFIX = 'BYOKY_';\n\nexport function createMessage(\n type: MessageType,\n payload: unknown,\n requestId?: string,\n): ByokyMessage {\n return {\n type,\n id: crypto.randomUUID(),\n requestId,\n payload,\n };\n}\n\nexport function isByokyMessage(data: unknown): data is ByokyMessage {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'type' in data &&\n typeof (data as ByokyMessage).type === 'string' &&\n (data as ByokyMessage).type.startsWith(BYOKY_MESSAGE_PREFIX)\n );\n}\n\nexport function createConnectRequest(request: ConnectRequest): ByokyMessage {\n return createMessage('BYOKY_CONNECT_REQUEST', request);\n}\n\nexport function createConnectResponse(\n response: ConnectResponse,\n requestId: string,\n): ByokyMessage {\n return createMessage('BYOKY_CONNECT_RESPONSE', response, requestId);\n}\n\nexport function createErrorMessage(\n code: string,\n message: string,\n requestId?: string,\n): ByokyMessage {\n return createMessage('BYOKY_ERROR', { code, message }, requestId);\n}\n","import type { ProviderConfig } from './types.js';\n\nexport const PROVIDERS: Record<string, ProviderConfig> = {\n anthropic: {\n id: 'anthropic',\n name: 'Anthropic',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://api.anthropic.com',\n },\n openai: {\n id: 'openai',\n name: 'OpenAI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.openai.com',\n },\n gemini: {\n id: 'gemini',\n name: 'Google Gemini',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://generativelanguage.googleapis.com',\n oauthConfig: {\n clientId: '699663966637-gr4d994198r4g6jvip25ffg85kree6ck.apps.googleusercontent.com',\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n scopes: ['https://www.googleapis.com/auth/generative-language'],\n extraAuthParams: { access_type: 'offline', prompt: 'consent' },\n },\n },\n mistral: {\n id: 'mistral',\n name: 'Mistral',\n authMethods: ['api_key'],\n baseUrl: 'https://api.mistral.ai',\n },\n cohere: {\n id: 'cohere',\n name: 'Cohere',\n authMethods: ['api_key'],\n baseUrl: 'https://api.cohere.com',\n },\n xai: {\n id: 'xai',\n name: 'xAI (Grok)',\n authMethods: ['api_key'],\n baseUrl: 'https://api.x.ai',\n },\n deepseek: {\n id: 'deepseek',\n name: 'DeepSeek',\n authMethods: ['api_key'],\n baseUrl: 'https://api.deepseek.com',\n },\n perplexity: {\n id: 'perplexity',\n name: 'Perplexity',\n authMethods: ['api_key'],\n baseUrl: 'https://api.perplexity.ai',\n },\n groq: {\n id: 'groq',\n name: 'Groq',\n authMethods: ['api_key'],\n baseUrl: 'https://api.groq.com',\n },\n together: {\n id: 'together',\n name: 'Together AI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.together.xyz',\n },\n fireworks: {\n id: 'fireworks',\n name: 'Fireworks AI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.fireworks.ai',\n },\n replicate: {\n id: 'replicate',\n name: 'Replicate',\n authMethods: ['api_key'],\n baseUrl: 'https://api.replicate.com',\n },\n openrouter: {\n id: 'openrouter',\n name: 'OpenRouter',\n authMethods: ['api_key'],\n baseUrl: 'https://openrouter.ai/api',\n },\n huggingface: {\n id: 'huggingface',\n name: 'Hugging Face',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://api-inference.huggingface.co',\n oauthConfig: {\n clientId: '031aeb11-725b-498a-93f9-d3599d84f57c',\n authorizationUrl: 'https://huggingface.co/oauth/authorize',\n tokenUrl: 'https://huggingface.co/oauth/token',\n scopes: ['inference-api'],\n },\n },\n azure_openai: {\n id: 'azure_openai',\n name: 'Azure OpenAI',\n authMethods: ['api_key'],\n baseUrl: 'https://YOUR_RESOURCE.openai.azure.com',\n },\n};\n\nexport function getProvider(id: string): ProviderConfig | undefined {\n return PROVIDERS[id];\n}\n\nexport function getProviderIds(): string[] {\n return Object.keys(PROVIDERS);\n}\n","import type { AuthMethod } from './types.js';\n\n/** Minimal WebSocket interface — compatible with browser WebSocket and `ws` library. */\nexport interface WebSocketLike {\n readonly readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n onclose: ((event: { code: number; reason: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n}\n\nexport const WS_READY_STATE = {\n CONNECTING: 0,\n OPEN: 1,\n CLOSING: 2,\n CLOSED: 3,\n} as const;\n\n// --- Relay message types ---\n\nexport interface RelayHello {\n type: 'relay:hello';\n sessionId: string;\n providers: Record<string, { available: boolean; authMethod: AuthMethod }>;\n}\n\nexport interface RelayRequest {\n type: 'relay:request';\n requestId: string;\n providerId: string;\n url: string;\n method: string;\n headers: Record<string, string>;\n body?: string;\n}\n\nexport interface RelayResponseMeta {\n type: 'relay:response:meta';\n requestId: string;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n}\n\nexport interface RelayResponseChunk {\n type: 'relay:response:chunk';\n requestId: string;\n chunk: string;\n}\n\nexport interface RelayResponseDone {\n type: 'relay:response:done';\n requestId: string;\n}\n\nexport interface RelayResponseError {\n type: 'relay:response:error';\n requestId: string;\n error: { code: string; message: string };\n}\n\nexport interface RelayPing {\n type: 'relay:ping';\n ts: number;\n}\n\nexport interface RelayPong {\n type: 'relay:pong';\n ts: number;\n}\n\nexport interface RelayPairHello {\n type: 'relay:pair:hello';\n providers: Record<string, { available: boolean; authMethod: AuthMethod }>;\n}\n\nexport interface RelayPairAck {\n type: 'relay:pair:ack';\n}\n\nexport type RelayMessage =\n | RelayHello\n | RelayRequest\n | RelayResponseMeta\n | RelayResponseChunk\n | RelayResponseDone\n | RelayResponseError\n | RelayPing\n | RelayPong\n | RelayPairHello\n | RelayPairAck;\n\nconst MAX_RELAY_MESSAGE_SIZE = 1_048_576; // 1 MB\n\nexport function parseRelayMessage(data: unknown): RelayMessage | null {\n try {\n if (typeof data === 'string' && data.length > MAX_RELAY_MESSAGE_SIZE) return null;\n const raw = typeof data === 'string' ? JSON.parse(data) : data;\n if (!raw || typeof raw !== 'object' || typeof raw.type !== 'string' || !raw.type.startsWith('relay:')) {\n return null;\n }\n\n // Validate required fields per message type\n switch (raw.type) {\n case 'relay:hello':\n if (typeof raw.sessionId !== 'string') return null;\n break;\n case 'relay:request':\n if (typeof raw.requestId !== 'string' || typeof raw.providerId !== 'string' ||\n typeof raw.url !== 'string' || typeof raw.method !== 'string') return null;\n break;\n case 'relay:response:meta':\n if (typeof raw.requestId !== 'string' || typeof raw.status !== 'number') return null;\n break;\n case 'relay:response:chunk':\n if (typeof raw.requestId !== 'string' || typeof raw.chunk !== 'string') return null;\n break;\n case 'relay:response:done':\n if (typeof raw.requestId !== 'string') return null;\n break;\n case 'relay:response:error':\n if (typeof raw.requestId !== 'string') return null;\n if (raw.error && (typeof raw.error !== 'object' || typeof raw.error.code !== 'string' || typeof raw.error.message !== 'string')) return null;\n break;\n case 'relay:ping':\n case 'relay:pong':\n if (typeof raw.ts !== 'number') return null;\n break;\n case 'relay:pair:hello':\n if (!raw.providers || typeof raw.providers !== 'object') return null;\n break;\n case 'relay:pair:ack':\n break;\n default:\n return null;\n }\n\n return raw as RelayMessage;\n } catch {\n return null;\n }\n}\n\nexport function sendRelayMessage(ws: WebSocketLike, msg: RelayMessage): void {\n if (ws.readyState === WS_READY_STATE.OPEN) {\n ws.send(JSON.stringify(msg));\n }\n}\n","export interface PasswordStrength {\n score: 0 | 1 | 2 | 3 | 4;\n label: 'Too weak' | 'Weak' | 'Fair' | 'Strong' | 'Very strong';\n feedback: string[];\n}\n\nconst COMMON_PASSWORDS = new Set([\n 'password', '12345678', 'qwerty12', 'letmein12', 'welcome1',\n 'monkey12', 'dragon12', 'master12', 'abc12345', 'password1',\n 'password12', 'iloveyou1', 'sunshine1', 'trustno1', 'princess1',\n 'football1', 'shadow123', 'michael1', 'jordan123', 'superman1',\n 'password123', 'admin12345', 'letmein123', 'p@ssw0rd', 'p@ssw0rd1',\n 'qwerty1234', 'changeme12', 'welcome123', '1234567890', 'baseball1',\n 'starwars12', 'whatever1', 'passw0rd1', 'mustang12', 'access1234',\n 'charlie123', 'donald1234', 'maggie1234', 'master1234', 'michael123',\n 'jennifer1', 'hunter1234', 'thomas1234', 'corvette12', 'robert1234',\n 'summer1234', 'george1234', 'harley1234', 'cheese1234', 'computer1',\n 'internet1', 'secret1234', 'diamond1', 'chicken123', 'pepper1234',\n 'jessica123', 'hannah1234', 'ginger1234', 'joshua1234', 'abcdefgh1',\n 'qwertyuiop', 'asdfghjkl1', 'zxcvbnm123', '1q2w3e4r5t', 'passpass1',\n]);\n\nexport function checkPasswordStrength(password: string): PasswordStrength {\n const feedback: string[] = [];\n let score = 0;\n\n if (password.length < MIN_PASSWORD_LENGTH) {\n feedback.push('Use at least 12 characters');\n return { score: 0, label: 'Too weak', feedback };\n } else {\n score++;\n if (password.length >= 16) score++;\n }\n\n if (COMMON_PASSWORDS.has(password.toLowerCase())) {\n feedback.push('This is a commonly used password');\n return { score: 0, label: 'Too weak', feedback };\n }\n\n // Check character diversity\n const hasLower = /[a-z]/.test(password);\n const hasUpper = /[A-Z]/.test(password);\n const hasDigit = /\\d/.test(password);\n const hasSymbol = /[^a-zA-Z0-9]/.test(password);\n const charTypes = [hasLower, hasUpper, hasDigit, hasSymbol].filter(Boolean).length;\n\n if (charTypes < 2) {\n feedback.push('Mix uppercase, lowercase, numbers, and symbols');\n } else if (charTypes >= 3) {\n score++;\n }\n if (charTypes >= 4) {\n score++;\n }\n\n // Check for repeated characters (e.g. aaaaaa)\n if (/(.)\\1{3,}/.test(password)) {\n feedback.push('Avoid repeated characters');\n score = Math.max(0, score - 1);\n }\n\n // Check for sequential patterns (e.g. 123456, abcdef)\n if (/(?:012|123|234|345|456|567|678|789|abc|bcd|cde|def)/i.test(password)) {\n feedback.push('Avoid sequential patterns');\n score = Math.max(0, score - 1);\n }\n\n const capped = Math.min(4, Math.max(0, score)) as 0 | 1 | 2 | 3 | 4;\n const labels: Record<number, PasswordStrength['label']> = {\n 0: 'Too weak',\n 1: 'Weak',\n 2: 'Fair',\n 3: 'Strong',\n 4: 'Very strong',\n };\n\n if (feedback.length === 0 && capped < 3) {\n feedback.push('Add more character variety or length');\n }\n\n return { score: capped, label: labels[capped], feedback };\n}\n\nexport const MIN_PASSWORD_LENGTH = 12;\n","import type { RequestLogEntry, TokenAllowance } from './types.js';\nimport { PROVIDERS } from './providers.js';\n\n/**\n * Validate that a proxy request URL targets the registered provider's base URL.\n * Prevents API key exfiltration by rejecting requests to arbitrary domains.\n */\nexport function validateProxyUrl(providerId: string, url: string): boolean {\n const provider = PROVIDERS[providerId];\n if (!provider) return false;\n try {\n const target = new URL(url);\n if (target.protocol !== 'https:') return false;\n const base = new URL(provider.baseUrl);\n return target.origin === base.origin;\n } catch {\n return false;\n }\n}\n\n/**\n * Build the real auth headers for a provider API request.\n * Strips any fake session-key headers and injects the real API key.\n */\nexport function buildHeaders(\n providerId: string,\n requestHeaders: Record<string, string>,\n apiKey: string,\n authMethod: string = 'api_key',\n): Record<string, string> {\n // Normalize header keys to lowercase to prevent case-sensitive bypass\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(requestHeaders)) {\n headers[key.toLowerCase()] = value;\n }\n\n // Remove any auth headers the SDK might have set (they're fake session keys)\n delete headers['authorization'];\n delete headers['x-api-key'];\n delete headers['api-key'];\n\n // Strip browser/SDK headers that can trigger rejection from provider APIs\n delete headers['origin'];\n delete headers['referer'];\n // Remove SDK telemetry headers that leak the real client environment\n for (const key of Object.keys(headers)) {\n if (key.startsWith('x-stainless-')) delete headers[key];\n }\n delete headers['sec-fetch-mode'];\n delete headers['accept-language'];\n delete headers['accept-encoding'];\n // Always strip content-length — fetch() recalculates it from the actual body,\n // and the body may have been modified (e.g. system prompt injection)\n delete headers['content-length'];\n\n if (providerId === 'anthropic') {\n if (authMethod === 'oauth') {\n headers['authorization'] = `Bearer ${apiKey}`;\n headers['user-agent'] = 'claude-cli/2.1.76';\n headers['x-app'] = 'cli';\n headers['accept'] = 'application/json';\n headers['anthropic-beta'] = 'claude-code-20250219,oauth-2025-04-20,fine-grained-tool-streaming-2025-05-14,interleaved-thinking-2025-05-14';\n headers['anthropic-dangerous-direct-browser-access'] = 'true';\n } else {\n headers['x-api-key'] = apiKey;\n }\n headers['anthropic-version'] = headers['anthropic-version'] ?? '2023-06-01';\n } else if (providerId === 'azure_openai') {\n headers['api-key'] = apiKey;\n } else {\n headers['authorization'] = `Bearer ${apiKey}`;\n }\n\n return headers;\n}\n\n/**\n * Parse the model name from a request body (JSON).\n */\nconst MAX_BODY_PARSE_SIZE = 10_485_760; // 10 MB\n\nexport function parseModel(body?: string): string | undefined {\n if (!body || body.length > MAX_BODY_PARSE_SIZE) return undefined;\n try {\n const parsed = JSON.parse(body);\n return parsed.model ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Parse token usage from a provider API response body.\n * Handles both regular JSON responses and SSE streaming responses.\n */\nexport function parseUsage(\n providerId: string,\n body: string,\n): { inputTokens: number; outputTokens: number } | undefined {\n try {\n // For streaming responses (SSE), try to find usage in the last data chunk\n if (body.includes('data: ')) {\n const lines = body.split('\\n').filter((l) => l.startsWith('data: ') && !l.includes('[DONE]'));\n // Anthropic streaming: message_stop event has usage in a preceding message_delta\n // OpenAI streaming: last chunk may include usage\n for (let i = lines.length - 1; i >= 0; i--) {\n const json = lines[i].replace('data: ', '');\n try {\n const parsed = JSON.parse(json);\n const usage = extractUsageFromParsed(providerId, parsed);\n if (usage) return usage;\n } catch {\n continue;\n }\n }\n return undefined;\n }\n\n const parsed = JSON.parse(body);\n return extractUsageFromParsed(providerId, parsed);\n } catch {\n return undefined;\n }\n}\n\nfunction sanitizeTokenCounts(\n input: number,\n output: number,\n): { inputTokens: number; outputTokens: number } | undefined {\n const i = Math.max(0, Math.floor(input));\n const o = Math.max(0, Math.floor(output));\n if (!Number.isFinite(i) || !Number.isFinite(o)) return undefined;\n return { inputTokens: i, outputTokens: o };\n}\n\n/**\n * Extract token usage from a parsed provider response object.\n */\nexport function extractUsageFromParsed(\n providerId: string,\n parsed: Record<string, unknown>,\n): { inputTokens: number; outputTokens: number } | undefined {\n // Anthropic: { usage: { input_tokens, output_tokens } }\n if (providerId === 'anthropic') {\n const usage = parsed.usage as Record<string, number> | undefined;\n if (usage?.input_tokens != null && usage?.output_tokens != null) {\n return sanitizeTokenCounts(usage.input_tokens, usage.output_tokens);\n }\n }\n\n // Gemini: { usageMetadata: { promptTokenCount, candidatesTokenCount } }\n if (providerId === 'gemini') {\n const meta = parsed.usageMetadata as Record<string, number> | undefined;\n if (meta?.promptTokenCount != null) {\n return sanitizeTokenCounts(meta.promptTokenCount, meta.candidatesTokenCount ?? 0);\n }\n }\n\n // OpenAI-compatible (openai, groq, together, deepseek, xai, perplexity, fireworks, openrouter, mistral, azure_openai):\n // { usage: { prompt_tokens, completion_tokens } }\n const usage = parsed.usage as Record<string, number> | undefined;\n if (usage?.prompt_tokens != null && usage?.completion_tokens != null) {\n return sanitizeTokenCounts(usage.prompt_tokens, usage.completion_tokens);\n }\n\n return undefined;\n}\n\n/**\n * Check whether a request is allowed given token allowances and usage history.\n * Pure computation — no storage access.\n */\nexport function computeAllowanceCheck(\n allowance: TokenAllowance | undefined,\n entries: Pick<RequestLogEntry, 'providerId' | 'inputTokens' | 'outputTokens'>[],\n providerId: string,\n): { allowed: boolean; reason?: string } {\n if (!allowance) return { allowed: true };\n\n let totalUsed = 0;\n const byProvider: Record<string, number> = {};\n for (const entry of entries) {\n const tokens = (entry.inputTokens ?? 0) + (entry.outputTokens ?? 0);\n totalUsed += tokens;\n byProvider[entry.providerId] = (byProvider[entry.providerId] ?? 0) + tokens;\n }\n\n if (allowance.totalLimit != null && totalUsed >= allowance.totalLimit) {\n return { allowed: false, reason: `Token allowance exceeded for ${allowance.origin}` };\n }\n\n const providerLimit = allowance.providerLimits?.[providerId];\n if (providerLimit != null && (byProvider[providerId] ?? 0) >= providerLimit) {\n return { allowed: false, reason: `Token allowance for ${providerId} exceeded` };\n }\n\n return { allowed: true };\n}\n","import { PROVIDERS } from './providers.js';\n\n// --- Gift (sender side) ---\n\nexport interface Gift {\n id: string;\n credentialId: string;\n providerId: string;\n label: string;\n authToken: string;\n maxTokens: number;\n usedTokens: number;\n expiresAt: number;\n createdAt: number;\n active: boolean;\n relayUrl: string;\n}\n\n// --- Gift link (shareable payload) ---\n\nexport interface GiftLink {\n v: 1;\n id: string;\n p: string; // providerId\n n: string; // provider display name\n s: string; // sender label\n t: string; // auth token\n m: number; // max tokens\n e: number; // expires at (unix ms)\n r: string; // relay URL\n}\n\n// --- Gifted credential (recipient side) ---\n\nexport interface GiftedCredential {\n id: string;\n giftId: string;\n providerId: string;\n providerName: string;\n senderLabel: string;\n authToken: string;\n maxTokens: number;\n usedTokens: number;\n expiresAt: number;\n relayUrl: string;\n createdAt: number;\n}\n\n// --- Relay protocol ---\n\nexport interface RelayAuth {\n type: 'relay:auth';\n roomId: string;\n authToken: string;\n role: 'sender' | 'recipient';\n}\n\nexport interface RelayAuthResult {\n type: 'relay:auth:result';\n success: boolean;\n error?: string;\n peerOnline?: boolean;\n}\n\nexport interface RelayPeerStatus {\n type: 'relay:peer:status';\n online: boolean;\n}\n\nexport interface RelayUsageUpdate {\n type: 'relay:usage';\n roomId: string;\n usedTokens: number;\n}\n\nexport type RelayProtocolMessage =\n | RelayAuth\n | RelayAuthResult\n | RelayPeerStatus\n | RelayUsageUpdate;\n\n// --- Encoding / decoding ---\n\nexport function encodeGiftLink(link: GiftLink): string {\n const json = JSON.stringify(link);\n const bytes = new TextEncoder().encode(json);\n return base64UrlEncode(bytes);\n}\n\nconst MAX_GIFT_LINK_SIZE = 8_192; // 8 KB\n\nexport function decodeGiftLink(encoded: string): GiftLink | null {\n try {\n if (encoded.length > MAX_GIFT_LINK_SIZE) return null;\n const clean = encoded.replace(/^byoky:\\/\\/gift\\//, '');\n const bytes = base64UrlDecode(clean);\n const json = new TextDecoder().decode(bytes);\n const parsed = JSON.parse(json);\n if (parsed.v !== 1) return null;\n return parsed as GiftLink;\n } catch {\n return null;\n }\n}\n\nexport function giftLinkToUrl(encoded: string): string {\n return `byoky://gift/${encoded}`;\n}\n\n// --- Validation ---\n\nexport function validateGiftLink(link: GiftLink): { valid: boolean; reason?: string } {\n if (link.v !== 1) return { valid: false, reason: 'Unsupported gift version' };\n if (!link.id || typeof link.id !== 'string') return { valid: false, reason: 'Missing gift ID' };\n if (!link.p || typeof link.p !== 'string') return { valid: false, reason: 'Missing provider' };\n if (!link.t || typeof link.t !== 'string') return { valid: false, reason: 'Missing auth token' };\n if (!link.r || typeof link.r !== 'string') return { valid: false, reason: 'Missing relay URL' };\n if (typeof link.m !== 'number' || link.m <= 0) return { valid: false, reason: 'Invalid token budget' };\n if (typeof link.e !== 'number' || link.e <= Date.now()) return { valid: false, reason: 'Gift has expired' };\n\n try {\n const url = new URL(link.r);\n if (url.protocol !== 'ws:' && url.protocol !== 'wss:') {\n return { valid: false, reason: 'Relay URL must use ws:// or wss://' };\n }\n } catch {\n return { valid: false, reason: 'Invalid relay URL' };\n }\n\n return { valid: true };\n}\n\nexport function isGiftExpired(gift: { expiresAt: number }): boolean {\n return gift.expiresAt <= Date.now();\n}\n\nexport function isGiftBudgetExhausted(gift: { usedTokens: number; maxTokens: number }): boolean {\n return gift.usedTokens >= gift.maxTokens;\n}\n\nexport function giftBudgetRemaining(gift: { usedTokens: number; maxTokens: number }): number {\n return Math.max(0, gift.maxTokens - gift.usedTokens);\n}\n\nexport function giftBudgetPercent(gift: { usedTokens: number; maxTokens: number }): number {\n if (gift.maxTokens === 0) return 100;\n return Math.min(100, Math.round((gift.usedTokens / gift.maxTokens) * 100));\n}\n\nexport function createGiftLink(gift: Gift): { encoded: string; link: GiftLink } {\n const provider = PROVIDERS[gift.providerId];\n const link: GiftLink = {\n v: 1,\n id: gift.id,\n p: gift.providerId,\n n: provider?.name ?? gift.providerId,\n s: gift.label,\n t: gift.authToken,\n m: gift.maxTokens,\n e: gift.expiresAt,\n r: gift.relayUrl,\n };\n return { encoded: encodeGiftLink(link), link };\n}\n\n// --- Pairing payload (mobile wallet relay connect) ---\n\nexport interface PairPayload {\n v: 1;\n r: string; // relay URL (wss://...)\n id: string; // room ID\n t: string; // auth token\n o: string; // app origin\n}\n\nexport function encodePairPayload(payload: PairPayload): string {\n const json = JSON.stringify(payload);\n const bytes = new TextEncoder().encode(json);\n return base64UrlEncode(bytes);\n}\n\nexport function decodePairPayload(encoded: string): PairPayload | null {\n try {\n if (encoded.length > 2048) return null;\n const bytes = base64UrlDecode(encoded);\n const json = new TextDecoder().decode(bytes);\n const parsed = JSON.parse(json);\n if (parsed.v !== 1) return null;\n return parsed as PairPayload;\n } catch {\n return null;\n }\n}\n\n// --- Base64url helpers ---\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction base64UrlDecode(str: string): Uint8Array {\n const padded = str.replace(/-/g, '+').replace(/_/g, '/');\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n"],"mappings":"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","names":["ByokyErrorCode","parsed","usage"]}
package/dist/index.d.cts CHANGED
@@ -158,6 +158,7 @@ interface PendingApproval {
158
158
  interface TrustedSite {
159
159
  origin: string;
160
160
  trustedAt: number;
161
+ allowedProviders?: string[];
161
162
  }
162
163
  interface TokenAllowance {
163
164
  origin: string;
@@ -270,7 +271,17 @@ interface RelayPong {
270
271
  type: 'relay:pong';
271
272
  ts: number;
272
273
  }
273
- type RelayMessage = RelayHello | RelayRequest | RelayResponseMeta | RelayResponseChunk | RelayResponseDone | RelayResponseError | RelayPing | RelayPong;
274
+ interface RelayPairHello {
275
+ type: 'relay:pair:hello';
276
+ providers: Record<string, {
277
+ available: boolean;
278
+ authMethod: AuthMethod;
279
+ }>;
280
+ }
281
+ interface RelayPairAck {
282
+ type: 'relay:pair:ack';
283
+ }
284
+ type RelayMessage = RelayHello | RelayRequest | RelayResponseMeta | RelayResponseChunk | RelayResponseDone | RelayResponseError | RelayPing | RelayPong | RelayPairHello | RelayPairAck;
274
285
  declare function parseRelayMessage(data: unknown): RelayMessage | null;
275
286
  declare function sendRelayMessage(ws: WebSocketLike, msg: RelayMessage): void;
276
287
 
@@ -292,9 +303,6 @@ declare function validateProxyUrl(providerId: string, url: string): boolean;
292
303
  * Strips any fake session-key headers and injects the real API key.
293
304
  */
294
305
  declare function buildHeaders(providerId: string, requestHeaders: Record<string, string>, apiKey: string, authMethod?: string): Record<string, string>;
295
- /**
296
- * Parse the model name from a request body (JSON).
297
- */
298
306
  declare function parseModel(body?: string): string | undefined;
299
307
  /**
300
308
  * Parse token usage from a provider API response body.
@@ -357,28 +365,28 @@ interface GiftedCredential {
357
365
  relayUrl: string;
358
366
  createdAt: number;
359
367
  }
360
- interface GiftRelayAuth {
361
- type: 'gift:auth';
362
- giftId: string;
368
+ interface RelayAuth {
369
+ type: 'relay:auth';
370
+ roomId: string;
363
371
  authToken: string;
364
372
  role: 'sender' | 'recipient';
365
373
  }
366
- interface GiftRelayAuthResult {
367
- type: 'gift:auth:result';
374
+ interface RelayAuthResult {
375
+ type: 'relay:auth:result';
368
376
  success: boolean;
369
377
  error?: string;
370
378
  peerOnline?: boolean;
371
379
  }
372
- interface GiftRelayPeerStatus {
373
- type: 'gift:peer:status';
380
+ interface RelayPeerStatus {
381
+ type: 'relay:peer:status';
374
382
  online: boolean;
375
383
  }
376
- interface GiftRelayUsageUpdate {
377
- type: 'gift:usage';
378
- giftId: string;
384
+ interface RelayUsageUpdate {
385
+ type: 'relay:usage';
386
+ roomId: string;
379
387
  usedTokens: number;
380
388
  }
381
- type GiftRelayMessage = GiftRelayAuth | GiftRelayAuthResult | GiftRelayPeerStatus | GiftRelayUsageUpdate;
389
+ type RelayProtocolMessage = RelayAuth | RelayAuthResult | RelayPeerStatus | RelayUsageUpdate;
382
390
  declare function encodeGiftLink(link: GiftLink): string;
383
391
  declare function decodeGiftLink(encoded: string): GiftLink | null;
384
392
  declare function giftLinkToUrl(encoded: string): string;
@@ -405,5 +413,14 @@ declare function createGiftLink(gift: Gift): {
405
413
  encoded: string;
406
414
  link: GiftLink;
407
415
  };
416
+ interface PairPayload {
417
+ v: 1;
418
+ r: string;
419
+ id: string;
420
+ t: string;
421
+ o: string;
422
+ }
423
+ declare function encodePairPayload(payload: PairPayload): string;
424
+ declare function decodePairPayload(encoded: string): PairPayload | null;
408
425
 
409
- export { type ApiKeyCredential, type AuthMethod, BYOKY_MESSAGE_PREFIX, BYOKY_PROVIDER_KEY, ByokyError, ByokyErrorCode, type ByokyMessage, type ConnectRequest, type ConnectResponse, type Credential, type CredentialBase, type CredentialMeta, type Gift, type GiftLink, type GiftRelayAuth, type GiftRelayAuthResult, type GiftRelayMessage, type GiftRelayPeerStatus, type GiftRelayUsageUpdate, type GiftedCredential, MIN_PASSWORD_LENGTH, type MessageType, type OAuthConfig, type OAuthCredential, PROVIDERS, type PasswordStrength, type PendingApproval, type ProviderConfig, type ProviderId, type ProviderRequirement, type ProxyRequest, type ProxyResponseChunk, type ProxyResponseError, type ProxyResponseMeta, type RelayHello, type RelayMessage, type RelayPing, type RelayPong, type RelayRequest, type RelayResponseChunk, type RelayResponseDone, type RelayResponseError, type RelayResponseMeta, type RequestLogEntry, type Session, type SessionProvider, type SessionUsage, type TokenAllowance, type TrustedSite, WS_READY_STATE, type WebSocketLike, buildHeaders, checkPasswordStrength, computeAllowanceCheck, createConnectRequest, createConnectResponse, createErrorMessage, createGiftLink, createMessage, decodeGiftLink, decrypt, deriveKey, encodeGiftLink, encrypt, extractUsageFromParsed, getProvider, getProviderIds, giftBudgetPercent, giftBudgetRemaining, giftLinkToUrl, hashPassword, isByokyMessage, isGiftBudgetExhausted, isGiftExpired, maskKey, parseModel, parseRelayMessage, parseUsage, sendRelayMessage, validateGiftLink, validateProxyUrl, verifyPassword };
426
+ export { type ApiKeyCredential, type AuthMethod, BYOKY_MESSAGE_PREFIX, BYOKY_PROVIDER_KEY, ByokyError, ByokyErrorCode, type ByokyMessage, type ConnectRequest, type ConnectResponse, type Credential, type CredentialBase, type CredentialMeta, type Gift, type GiftLink, type GiftedCredential, MIN_PASSWORD_LENGTH, type MessageType, type OAuthConfig, type OAuthCredential, PROVIDERS, type PairPayload, type PasswordStrength, type PendingApproval, type ProviderConfig, type ProviderId, type ProviderRequirement, type ProxyRequest, type ProxyResponseChunk, type ProxyResponseError, type ProxyResponseMeta, type RelayAuth, type RelayAuthResult, type RelayHello, type RelayMessage, type RelayPairAck, type RelayPairHello, type RelayPeerStatus, type RelayPing, type RelayPong, type RelayProtocolMessage, type RelayRequest, type RelayResponseChunk, type RelayResponseDone, type RelayResponseError, type RelayResponseMeta, type RelayUsageUpdate, type RequestLogEntry, type Session, type SessionProvider, type SessionUsage, type TokenAllowance, type TrustedSite, WS_READY_STATE, type WebSocketLike, buildHeaders, checkPasswordStrength, computeAllowanceCheck, createConnectRequest, createConnectResponse, createErrorMessage, createGiftLink, createMessage, decodeGiftLink, decodePairPayload, decrypt, deriveKey, encodeGiftLink, encodePairPayload, encrypt, extractUsageFromParsed, getProvider, getProviderIds, giftBudgetPercent, giftBudgetRemaining, giftLinkToUrl, hashPassword, isByokyMessage, isGiftBudgetExhausted, isGiftExpired, maskKey, parseModel, parseRelayMessage, parseUsage, sendRelayMessage, validateGiftLink, validateProxyUrl, verifyPassword };
package/dist/index.d.ts CHANGED
@@ -158,6 +158,7 @@ interface PendingApproval {
158
158
  interface TrustedSite {
159
159
  origin: string;
160
160
  trustedAt: number;
161
+ allowedProviders?: string[];
161
162
  }
162
163
  interface TokenAllowance {
163
164
  origin: string;
@@ -270,7 +271,17 @@ interface RelayPong {
270
271
  type: 'relay:pong';
271
272
  ts: number;
272
273
  }
273
- type RelayMessage = RelayHello | RelayRequest | RelayResponseMeta | RelayResponseChunk | RelayResponseDone | RelayResponseError | RelayPing | RelayPong;
274
+ interface RelayPairHello {
275
+ type: 'relay:pair:hello';
276
+ providers: Record<string, {
277
+ available: boolean;
278
+ authMethod: AuthMethod;
279
+ }>;
280
+ }
281
+ interface RelayPairAck {
282
+ type: 'relay:pair:ack';
283
+ }
284
+ type RelayMessage = RelayHello | RelayRequest | RelayResponseMeta | RelayResponseChunk | RelayResponseDone | RelayResponseError | RelayPing | RelayPong | RelayPairHello | RelayPairAck;
274
285
  declare function parseRelayMessage(data: unknown): RelayMessage | null;
275
286
  declare function sendRelayMessage(ws: WebSocketLike, msg: RelayMessage): void;
276
287
 
@@ -292,9 +303,6 @@ declare function validateProxyUrl(providerId: string, url: string): boolean;
292
303
  * Strips any fake session-key headers and injects the real API key.
293
304
  */
294
305
  declare function buildHeaders(providerId: string, requestHeaders: Record<string, string>, apiKey: string, authMethod?: string): Record<string, string>;
295
- /**
296
- * Parse the model name from a request body (JSON).
297
- */
298
306
  declare function parseModel(body?: string): string | undefined;
299
307
  /**
300
308
  * Parse token usage from a provider API response body.
@@ -357,28 +365,28 @@ interface GiftedCredential {
357
365
  relayUrl: string;
358
366
  createdAt: number;
359
367
  }
360
- interface GiftRelayAuth {
361
- type: 'gift:auth';
362
- giftId: string;
368
+ interface RelayAuth {
369
+ type: 'relay:auth';
370
+ roomId: string;
363
371
  authToken: string;
364
372
  role: 'sender' | 'recipient';
365
373
  }
366
- interface GiftRelayAuthResult {
367
- type: 'gift:auth:result';
374
+ interface RelayAuthResult {
375
+ type: 'relay:auth:result';
368
376
  success: boolean;
369
377
  error?: string;
370
378
  peerOnline?: boolean;
371
379
  }
372
- interface GiftRelayPeerStatus {
373
- type: 'gift:peer:status';
380
+ interface RelayPeerStatus {
381
+ type: 'relay:peer:status';
374
382
  online: boolean;
375
383
  }
376
- interface GiftRelayUsageUpdate {
377
- type: 'gift:usage';
378
- giftId: string;
384
+ interface RelayUsageUpdate {
385
+ type: 'relay:usage';
386
+ roomId: string;
379
387
  usedTokens: number;
380
388
  }
381
- type GiftRelayMessage = GiftRelayAuth | GiftRelayAuthResult | GiftRelayPeerStatus | GiftRelayUsageUpdate;
389
+ type RelayProtocolMessage = RelayAuth | RelayAuthResult | RelayPeerStatus | RelayUsageUpdate;
382
390
  declare function encodeGiftLink(link: GiftLink): string;
383
391
  declare function decodeGiftLink(encoded: string): GiftLink | null;
384
392
  declare function giftLinkToUrl(encoded: string): string;
@@ -405,5 +413,14 @@ declare function createGiftLink(gift: Gift): {
405
413
  encoded: string;
406
414
  link: GiftLink;
407
415
  };
416
+ interface PairPayload {
417
+ v: 1;
418
+ r: string;
419
+ id: string;
420
+ t: string;
421
+ o: string;
422
+ }
423
+ declare function encodePairPayload(payload: PairPayload): string;
424
+ declare function decodePairPayload(encoded: string): PairPayload | null;
408
425
 
409
- export { type ApiKeyCredential, type AuthMethod, BYOKY_MESSAGE_PREFIX, BYOKY_PROVIDER_KEY, ByokyError, ByokyErrorCode, type ByokyMessage, type ConnectRequest, type ConnectResponse, type Credential, type CredentialBase, type CredentialMeta, type Gift, type GiftLink, type GiftRelayAuth, type GiftRelayAuthResult, type GiftRelayMessage, type GiftRelayPeerStatus, type GiftRelayUsageUpdate, type GiftedCredential, MIN_PASSWORD_LENGTH, type MessageType, type OAuthConfig, type OAuthCredential, PROVIDERS, type PasswordStrength, type PendingApproval, type ProviderConfig, type ProviderId, type ProviderRequirement, type ProxyRequest, type ProxyResponseChunk, type ProxyResponseError, type ProxyResponseMeta, type RelayHello, type RelayMessage, type RelayPing, type RelayPong, type RelayRequest, type RelayResponseChunk, type RelayResponseDone, type RelayResponseError, type RelayResponseMeta, type RequestLogEntry, type Session, type SessionProvider, type SessionUsage, type TokenAllowance, type TrustedSite, WS_READY_STATE, type WebSocketLike, buildHeaders, checkPasswordStrength, computeAllowanceCheck, createConnectRequest, createConnectResponse, createErrorMessage, createGiftLink, createMessage, decodeGiftLink, decrypt, deriveKey, encodeGiftLink, encrypt, extractUsageFromParsed, getProvider, getProviderIds, giftBudgetPercent, giftBudgetRemaining, giftLinkToUrl, hashPassword, isByokyMessage, isGiftBudgetExhausted, isGiftExpired, maskKey, parseModel, parseRelayMessage, parseUsage, sendRelayMessage, validateGiftLink, validateProxyUrl, verifyPassword };
426
+ export { type ApiKeyCredential, type AuthMethod, BYOKY_MESSAGE_PREFIX, BYOKY_PROVIDER_KEY, ByokyError, ByokyErrorCode, type ByokyMessage, type ConnectRequest, type ConnectResponse, type Credential, type CredentialBase, type CredentialMeta, type Gift, type GiftLink, type GiftedCredential, MIN_PASSWORD_LENGTH, type MessageType, type OAuthConfig, type OAuthCredential, PROVIDERS, type PairPayload, type PasswordStrength, type PendingApproval, type ProviderConfig, type ProviderId, type ProviderRequirement, type ProxyRequest, type ProxyResponseChunk, type ProxyResponseError, type ProxyResponseMeta, type RelayAuth, type RelayAuthResult, type RelayHello, type RelayMessage, type RelayPairAck, type RelayPairHello, type RelayPeerStatus, type RelayPing, type RelayPong, type RelayProtocolMessage, type RelayRequest, type RelayResponseChunk, type RelayResponseDone, type RelayResponseError, type RelayResponseMeta, type RelayUsageUpdate, type RequestLogEntry, type Session, type SessionProvider, type SessionUsage, type TokenAllowance, type TrustedSite, WS_READY_STATE, type WebSocketLike, buildHeaders, checkPasswordStrength, computeAllowanceCheck, createConnectRequest, createConnectResponse, createErrorMessage, createGiftLink, createMessage, decodeGiftLink, decodePairPayload, decrypt, deriveKey, encodeGiftLink, encodePairPayload, encrypt, extractUsageFromParsed, getProvider, getProviderIds, giftBudgetPercent, giftBudgetRemaining, giftLinkToUrl, hashPassword, isByokyMessage, isGiftBudgetExhausted, isGiftExpired, maskKey, parseModel, parseRelayMessage, parseUsage, sendRelayMessage, validateGiftLink, validateProxyUrl, verifyPassword };
package/dist/index.js CHANGED
@@ -325,8 +325,10 @@ var WS_READY_STATE = {
325
325
  CLOSING: 2,
326
326
  CLOSED: 3
327
327
  };
328
+ var MAX_RELAY_MESSAGE_SIZE = 1048576;
328
329
  function parseRelayMessage(data) {
329
330
  try {
331
+ if (typeof data === "string" && data.length > MAX_RELAY_MESSAGE_SIZE) return null;
330
332
  const raw = typeof data === "string" ? JSON.parse(data) : data;
331
333
  if (!raw || typeof raw !== "object" || typeof raw.type !== "string" || !raw.type.startsWith("relay:")) {
332
334
  return null;
@@ -345,13 +347,21 @@ function parseRelayMessage(data) {
345
347
  if (typeof raw.requestId !== "string" || typeof raw.chunk !== "string") return null;
346
348
  break;
347
349
  case "relay:response:done":
350
+ if (typeof raw.requestId !== "string") return null;
351
+ break;
348
352
  case "relay:response:error":
349
353
  if (typeof raw.requestId !== "string") return null;
354
+ if (raw.error && (typeof raw.error !== "object" || typeof raw.error.code !== "string" || typeof raw.error.message !== "string")) return null;
350
355
  break;
351
356
  case "relay:ping":
352
357
  case "relay:pong":
353
358
  if (typeof raw.ts !== "number") return null;
354
359
  break;
360
+ case "relay:pair:hello":
361
+ if (!raw.providers || typeof raw.providers !== "object") return null;
362
+ break;
363
+ case "relay:pair:ack":
364
+ break;
355
365
  default:
356
366
  return null;
357
367
  }
@@ -387,16 +397,59 @@ var COMMON_PASSWORDS = /* @__PURE__ */ new Set([
387
397
  "shadow123",
388
398
  "michael1",
389
399
  "jordan123",
390
- "superman1"
400
+ "superman1",
401
+ "password123",
402
+ "admin12345",
403
+ "letmein123",
404
+ "p@ssw0rd",
405
+ "p@ssw0rd1",
406
+ "qwerty1234",
407
+ "changeme12",
408
+ "welcome123",
409
+ "1234567890",
410
+ "baseball1",
411
+ "starwars12",
412
+ "whatever1",
413
+ "passw0rd1",
414
+ "mustang12",
415
+ "access1234",
416
+ "charlie123",
417
+ "donald1234",
418
+ "maggie1234",
419
+ "master1234",
420
+ "michael123",
421
+ "jennifer1",
422
+ "hunter1234",
423
+ "thomas1234",
424
+ "corvette12",
425
+ "robert1234",
426
+ "summer1234",
427
+ "george1234",
428
+ "harley1234",
429
+ "cheese1234",
430
+ "computer1",
431
+ "internet1",
432
+ "secret1234",
433
+ "diamond1",
434
+ "chicken123",
435
+ "pepper1234",
436
+ "jessica123",
437
+ "hannah1234",
438
+ "ginger1234",
439
+ "joshua1234",
440
+ "abcdefgh1",
441
+ "qwertyuiop",
442
+ "asdfghjkl1",
443
+ "zxcvbnm123",
444
+ "1q2w3e4r5t",
445
+ "passpass1"
391
446
  ]);
392
447
  function checkPasswordStrength(password) {
393
448
  const feedback = [];
394
449
  let score = 0;
395
- if (password.length < 12) {
450
+ if (password.length < MIN_PASSWORD_LENGTH) {
396
451
  feedback.push("Use at least 12 characters");
397
- if (password.length < 8) {
398
- return { score: 0, label: "Too weak", feedback };
399
- }
452
+ return { score: 0, label: "Too weak", feedback };
400
453
  } else {
401
454
  score++;
402
455
  if (password.length >= 16) score++;
@@ -490,8 +543,9 @@ function buildHeaders(providerId, requestHeaders, apiKey, authMethod = "api_key"
490
543
  }
491
544
  return headers;
492
545
  }
546
+ var MAX_BODY_PARSE_SIZE = 10485760;
493
547
  function parseModel(body) {
494
- if (!body) return void 0;
548
+ if (!body || body.length > MAX_BODY_PARSE_SIZE) return void 0;
495
549
  try {
496
550
  const parsed = JSON.parse(body);
497
551
  return parsed.model ?? void 0;
@@ -521,25 +575,28 @@ function parseUsage(providerId, body) {
521
575
  return void 0;
522
576
  }
523
577
  }
578
+ function sanitizeTokenCounts(input, output) {
579
+ const i = Math.max(0, Math.floor(input));
580
+ const o = Math.max(0, Math.floor(output));
581
+ if (!Number.isFinite(i) || !Number.isFinite(o)) return void 0;
582
+ return { inputTokens: i, outputTokens: o };
583
+ }
524
584
  function extractUsageFromParsed(providerId, parsed) {
525
585
  if (providerId === "anthropic") {
526
586
  const usage2 = parsed.usage;
527
587
  if (usage2?.input_tokens != null && usage2?.output_tokens != null) {
528
- return { inputTokens: usage2.input_tokens, outputTokens: usage2.output_tokens };
588
+ return sanitizeTokenCounts(usage2.input_tokens, usage2.output_tokens);
529
589
  }
530
590
  }
531
591
  if (providerId === "gemini") {
532
592
  const meta = parsed.usageMetadata;
533
593
  if (meta?.promptTokenCount != null) {
534
- return {
535
- inputTokens: meta.promptTokenCount,
536
- outputTokens: meta.candidatesTokenCount ?? 0
537
- };
594
+ return sanitizeTokenCounts(meta.promptTokenCount, meta.candidatesTokenCount ?? 0);
538
595
  }
539
596
  }
540
597
  const usage = parsed.usage;
541
598
  if (usage?.prompt_tokens != null && usage?.completion_tokens != null) {
542
- return { inputTokens: usage.prompt_tokens, outputTokens: usage.completion_tokens };
599
+ return sanitizeTokenCounts(usage.prompt_tokens, usage.completion_tokens);
543
600
  }
544
601
  return void 0;
545
602
  }
@@ -568,8 +625,10 @@ function encodeGiftLink(link) {
568
625
  const bytes = new TextEncoder().encode(json);
569
626
  return base64UrlEncode(bytes);
570
627
  }
628
+ var MAX_GIFT_LINK_SIZE = 8192;
571
629
  function decodeGiftLink(encoded) {
572
630
  try {
631
+ if (encoded.length > MAX_GIFT_LINK_SIZE) return null;
573
632
  const clean = encoded.replace(/^byoky:\/\/gift\//, "");
574
633
  const bytes = base64UrlDecode(clean);
575
634
  const json = new TextDecoder().decode(bytes);
@@ -629,6 +688,23 @@ function createGiftLink(gift) {
629
688
  };
630
689
  return { encoded: encodeGiftLink(link), link };
631
690
  }
691
+ function encodePairPayload(payload) {
692
+ const json = JSON.stringify(payload);
693
+ const bytes = new TextEncoder().encode(json);
694
+ return base64UrlEncode(bytes);
695
+ }
696
+ function decodePairPayload(encoded) {
697
+ try {
698
+ if (encoded.length > 2048) return null;
699
+ const bytes = base64UrlDecode(encoded);
700
+ const json = new TextDecoder().decode(bytes);
701
+ const parsed = JSON.parse(json);
702
+ if (parsed.v !== 1) return null;
703
+ return parsed;
704
+ } catch {
705
+ return null;
706
+ }
707
+ }
632
708
  function base64UrlEncode(bytes) {
633
709
  let binary = "";
634
710
  for (const byte of bytes) binary += String.fromCharCode(byte);
@@ -658,9 +734,11 @@ export {
658
734
  createGiftLink,
659
735
  createMessage,
660
736
  decodeGiftLink,
737
+ decodePairPayload,
661
738
  decrypt,
662
739
  deriveKey,
663
740
  encodeGiftLink,
741
+ encodePairPayload,
664
742
  encrypt,
665
743
  extractUsageFromParsed,
666
744
  getProvider,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/crypto.ts","../src/errors.ts","../src/protocol.ts","../src/providers.ts","../src/relay.ts","../src/password-strength.ts","../src/proxy-utils.ts","../src/gift.ts"],"sourcesContent":["export type ProviderId = 'anthropic' | 'openai' | 'gemini' | (string & {});\n\nexport type AuthMethod = 'api_key' | 'oauth';\n\nexport interface ProviderConfig {\n id: ProviderId;\n name: string;\n authMethods: AuthMethod[];\n baseUrl: string;\n oauthConfig?: OAuthConfig;\n}\n\nexport interface OAuthConfig {\n clientId: string;\n authorizationUrl: string;\n tokenUrl: string;\n scopes: string[];\n extraAuthParams?: Record<string, string>;\n}\n\n// --- Credentials ---\n\nexport interface CredentialBase {\n id: string;\n providerId: ProviderId;\n label: string;\n authMethod: AuthMethod;\n createdAt: number;\n lastUsedAt?: number;\n}\n\nexport interface ApiKeyCredential extends CredentialBase {\n authMethod: 'api_key';\n encryptedKey: string;\n}\n\nexport interface OAuthCredential extends CredentialBase {\n authMethod: 'oauth';\n encryptedAccessToken: string;\n encryptedRefreshToken?: string;\n expiresAt?: number;\n}\n\nexport type Credential = ApiKeyCredential | OAuthCredential;\n\nexport interface CredentialMeta {\n id: string;\n providerId: ProviderId;\n label: string;\n authMethod: AuthMethod;\n createdAt: number;\n lastUsedAt?: number;\n maskedKey?: string;\n}\n\n// --- Sessions ---\n\nexport interface Session {\n id: string;\n sessionKey: string;\n appOrigin: string;\n appName?: string;\n providers: SessionProvider[];\n createdAt: number;\n expiresAt: number;\n}\n\nexport interface SessionProvider {\n providerId: ProviderId;\n credentialId: string;\n available: boolean;\n authMethod: AuthMethod;\n giftId?: string;\n giftRelayUrl?: string;\n giftAuthToken?: string;\n}\n\n// --- Connect ---\n\nexport interface ConnectRequest {\n providers?: ProviderRequirement[];\n capabilities?: string[];\n}\n\nexport interface ProviderRequirement {\n id: ProviderId;\n required: boolean;\n}\n\nexport interface ConnectResponse {\n sessionKey: string;\n proxyUrl: string;\n providers: Record<\n string,\n {\n available: boolean;\n authMethod: AuthMethod;\n }\n >;\n}\n\n// --- Proxy ---\n\nexport interface ProxyRequest {\n requestId: string;\n sessionKey: string;\n providerId: string;\n url: string;\n method: string;\n headers: Record<string, string>;\n body?: string;\n}\n\nexport interface ProxyResponseMeta {\n requestId: string;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n}\n\nexport interface ProxyResponseChunk {\n requestId: string;\n chunk: string;\n}\n\nexport interface ProxyResponseError {\n requestId: string;\n status: number;\n error: { code: string; message: string };\n}\n\n// --- Protocol messages ---\n\nexport type MessageType =\n | 'BYOKY_CONNECT_REQUEST'\n | 'BYOKY_CONNECT_RESPONSE'\n | 'BYOKY_DISCONNECT'\n | 'BYOKY_PROXY_REQUEST'\n | 'BYOKY_PROXY_RESPONSE_META'\n | 'BYOKY_PROXY_RESPONSE_CHUNK'\n | 'BYOKY_PROXY_RESPONSE_DONE'\n | 'BYOKY_PROXY_RESPONSE_ERROR'\n | 'BYOKY_SESSION_STATUS'\n | 'BYOKY_SESSION_STATUS_RESPONSE'\n | 'BYOKY_SESSION_USAGE'\n | 'BYOKY_SESSION_USAGE_RESPONSE'\n | 'BYOKY_SESSION_REVOKED'\n | 'BYOKY_ERROR';\n\nexport interface ByokyMessage {\n type: MessageType;\n id: string;\n requestId?: string;\n payload: unknown;\n}\n\n// --- Session queries ---\n\nexport interface SessionUsage {\n requests: number;\n inputTokens: number;\n outputTokens: number;\n byProvider: Record<string, {\n requests: number;\n inputTokens: number;\n outputTokens: number;\n }>;\n}\n\n// --- Errors ---\n\nexport enum ByokyErrorCode {\n WALLET_NOT_INSTALLED = 'WALLET_NOT_INSTALLED',\n USER_REJECTED = 'USER_REJECTED',\n PROVIDER_UNAVAILABLE = 'PROVIDER_UNAVAILABLE',\n SESSION_EXPIRED = 'SESSION_EXPIRED',\n RATE_LIMITED = 'RATE_LIMITED',\n QUOTA_EXCEEDED = 'QUOTA_EXCEEDED',\n INVALID_KEY = 'INVALID_KEY',\n TOKEN_EXPIRED = 'TOKEN_EXPIRED',\n PROXY_ERROR = 'PROXY_ERROR',\n RELAY_CONNECTION_FAILED = 'RELAY_CONNECTION_FAILED',\n RELAY_DISCONNECTED = 'RELAY_DISCONNECTED',\n UNKNOWN = 'UNKNOWN',\n}\n\n// --- Request log ---\n\nexport interface RequestLogEntry {\n id: string;\n sessionId: string;\n appOrigin: string;\n providerId: ProviderId;\n url: string;\n method: string;\n status: number;\n timestamp: number;\n error?: string;\n inputTokens?: number;\n outputTokens?: number;\n model?: string;\n}\n\n// --- Pending approval ---\n\nexport interface PendingApproval {\n id: string;\n appOrigin: string;\n appName?: string;\n providers: ProviderRequirement[];\n timestamp: number;\n}\n\n// --- Trusted sites ---\n\nexport interface TrustedSite {\n origin: string;\n trustedAt: number;\n}\n\n// --- Token allowances ---\n\nexport interface TokenAllowance {\n origin: string;\n totalLimit?: number;\n providerLimits?: Record<string, number>;\n}\n","const SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst KEY_LENGTH = 256;\nconst ITERATIONS = 600_000;\n\nexport async function deriveKey(\n password: string,\n salt: Uint8Array,\n): Promise<CryptoKey> {\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(password),\n 'PBKDF2',\n false,\n ['deriveKey'],\n );\n\n return crypto.subtle.deriveKey(\n { name: 'PBKDF2', salt: salt as BufferSource, iterations: ITERATIONS, hash: 'SHA-256' },\n keyMaterial,\n { name: 'AES-GCM', length: KEY_LENGTH },\n false,\n ['encrypt', 'decrypt'],\n );\n}\n\nexport async function encrypt(\n plaintext: string,\n password: string,\n): Promise<string> {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n const key = await deriveKey(password, salt);\n\n const ciphertext = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv },\n key,\n new TextEncoder().encode(plaintext),\n );\n\n const combined = new Uint8Array(\n salt.length + iv.length + new Uint8Array(ciphertext).length,\n );\n combined.set(salt, 0);\n combined.set(iv, salt.length);\n combined.set(new Uint8Array(ciphertext), salt.length + iv.length);\n\n return btoa(String.fromCharCode(...combined));\n}\n\nexport async function decrypt(\n encrypted: string,\n password: string,\n): Promise<string> {\n const combined = Uint8Array.from(atob(encrypted), (c) => c.charCodeAt(0));\n\n const salt = combined.slice(0, SALT_LENGTH);\n const iv = combined.slice(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const ciphertext = combined.slice(SALT_LENGTH + IV_LENGTH);\n\n const key = await deriveKey(password, salt);\n\n const plaintext = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv },\n key,\n ciphertext,\n );\n\n return new TextDecoder().decode(plaintext);\n}\n\nasync function deriveRawHash(\n password: string,\n salt: Uint8Array,\n): Promise<Uint8Array> {\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(password),\n 'PBKDF2',\n false,\n ['deriveBits'],\n );\n\n const bits = await crypto.subtle.deriveBits(\n { name: 'PBKDF2', salt: salt as BufferSource, iterations: ITERATIONS, hash: 'SHA-256' },\n keyMaterial,\n KEY_LENGTH,\n );\n\n return new Uint8Array(bits);\n}\n\nexport async function hashPassword(password: string): Promise<string> {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const hash = await deriveRawHash(password, salt);\n\n const combined = new Uint8Array(salt.length + hash.length);\n combined.set(salt, 0);\n combined.set(hash, salt.length);\n\n return btoa(String.fromCharCode(...combined));\n}\n\nexport async function verifyPassword(\n password: string,\n storedHash: string,\n): Promise<boolean> {\n const combined = Uint8Array.from(atob(storedHash), (c) => c.charCodeAt(0));\n const salt = combined.slice(0, SALT_LENGTH);\n const originalHash = combined.slice(SALT_LENGTH);\n\n const newHash = await deriveRawHash(password, salt);\n\n if (originalHash.length !== newHash.length) return false;\n let result = 0;\n for (let i = 0; i < originalHash.length; i++) {\n result |= originalHash[i] ^ newHash[i];\n }\n return result === 0;\n}\n\nexport function maskKey(key: string): string {\n if (key.length <= 8) return '****';\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n}\n","import { ByokyErrorCode } from './types.js';\n\nexport class ByokyError extends Error {\n constructor(\n public readonly code: ByokyErrorCode,\n message: string,\n public readonly details?: Record<string, unknown>,\n ) {\n super(message);\n this.name = 'ByokyError';\n }\n\n static walletNotInstalled() {\n return new ByokyError(\n ByokyErrorCode.WALLET_NOT_INSTALLED,\n 'byoky wallet extension is not installed',\n );\n }\n\n static userRejected() {\n return new ByokyError(\n ByokyErrorCode.USER_REJECTED,\n 'User rejected the connection request',\n );\n }\n\n static providerUnavailable(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.PROVIDER_UNAVAILABLE,\n `Provider \"${providerId}\" is not available`,\n { providerId },\n );\n }\n\n static sessionExpired() {\n return new ByokyError(\n ByokyErrorCode.SESSION_EXPIRED,\n 'Session has expired — please reconnect',\n );\n }\n\n static rateLimited(retryAfter?: number) {\n return new ByokyError(\n ByokyErrorCode.RATE_LIMITED,\n `Rate limit exceeded${retryAfter ? ` — retry after ${retryAfter}s` : ''}`,\n { retryAfter },\n );\n }\n\n static quotaExceeded(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.QUOTA_EXCEEDED,\n `Quota exceeded for ${providerId} — check your billing`,\n { providerId },\n );\n }\n\n static invalidKey(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.INVALID_KEY,\n `Invalid API key for ${providerId}`,\n { providerId },\n );\n }\n\n static tokenExpired(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.TOKEN_EXPIRED,\n `OAuth token expired for ${providerId} — re-authentication required`,\n { providerId },\n );\n }\n\n static relayConnectionFailed(reason?: string) {\n return new ByokyError(\n ByokyErrorCode.RELAY_CONNECTION_FAILED,\n `Relay connection failed${reason ? `: ${reason}` : ''}`,\n );\n }\n\n static relayDisconnected() {\n return new ByokyError(\n ByokyErrorCode.RELAY_DISCONNECTED,\n 'Relay connection was closed',\n );\n }\n}\n","import type {\n ByokyMessage,\n ConnectRequest,\n ConnectResponse,\n MessageType,\n} from './types.js';\n\nexport const BYOKY_PROVIDER_KEY = '__byoky__';\nexport const BYOKY_MESSAGE_PREFIX = 'BYOKY_';\n\nexport function createMessage(\n type: MessageType,\n payload: unknown,\n requestId?: string,\n): ByokyMessage {\n return {\n type,\n id: crypto.randomUUID(),\n requestId,\n payload,\n };\n}\n\nexport function isByokyMessage(data: unknown): data is ByokyMessage {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'type' in data &&\n typeof (data as ByokyMessage).type === 'string' &&\n (data as ByokyMessage).type.startsWith(BYOKY_MESSAGE_PREFIX)\n );\n}\n\nexport function createConnectRequest(request: ConnectRequest): ByokyMessage {\n return createMessage('BYOKY_CONNECT_REQUEST', request);\n}\n\nexport function createConnectResponse(\n response: ConnectResponse,\n requestId: string,\n): ByokyMessage {\n return createMessage('BYOKY_CONNECT_RESPONSE', response, requestId);\n}\n\nexport function createErrorMessage(\n code: string,\n message: string,\n requestId?: string,\n): ByokyMessage {\n return createMessage('BYOKY_ERROR', { code, message }, requestId);\n}\n","import type { ProviderConfig } from './types.js';\n\nexport const PROVIDERS: Record<string, ProviderConfig> = {\n anthropic: {\n id: 'anthropic',\n name: 'Anthropic',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://api.anthropic.com',\n },\n openai: {\n id: 'openai',\n name: 'OpenAI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.openai.com',\n },\n gemini: {\n id: 'gemini',\n name: 'Google Gemini',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://generativelanguage.googleapis.com',\n oauthConfig: {\n clientId: '699663966637-gr4d994198r4g6jvip25ffg85kree6ck.apps.googleusercontent.com',\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n scopes: ['https://www.googleapis.com/auth/generative-language'],\n extraAuthParams: { access_type: 'offline', prompt: 'consent' },\n },\n },\n mistral: {\n id: 'mistral',\n name: 'Mistral',\n authMethods: ['api_key'],\n baseUrl: 'https://api.mistral.ai',\n },\n cohere: {\n id: 'cohere',\n name: 'Cohere',\n authMethods: ['api_key'],\n baseUrl: 'https://api.cohere.com',\n },\n xai: {\n id: 'xai',\n name: 'xAI (Grok)',\n authMethods: ['api_key'],\n baseUrl: 'https://api.x.ai',\n },\n deepseek: {\n id: 'deepseek',\n name: 'DeepSeek',\n authMethods: ['api_key'],\n baseUrl: 'https://api.deepseek.com',\n },\n perplexity: {\n id: 'perplexity',\n name: 'Perplexity',\n authMethods: ['api_key'],\n baseUrl: 'https://api.perplexity.ai',\n },\n groq: {\n id: 'groq',\n name: 'Groq',\n authMethods: ['api_key'],\n baseUrl: 'https://api.groq.com',\n },\n together: {\n id: 'together',\n name: 'Together AI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.together.xyz',\n },\n fireworks: {\n id: 'fireworks',\n name: 'Fireworks AI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.fireworks.ai',\n },\n replicate: {\n id: 'replicate',\n name: 'Replicate',\n authMethods: ['api_key'],\n baseUrl: 'https://api.replicate.com',\n },\n openrouter: {\n id: 'openrouter',\n name: 'OpenRouter',\n authMethods: ['api_key'],\n baseUrl: 'https://openrouter.ai/api',\n },\n huggingface: {\n id: 'huggingface',\n name: 'Hugging Face',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://api-inference.huggingface.co',\n oauthConfig: {\n clientId: '031aeb11-725b-498a-93f9-d3599d84f57c',\n authorizationUrl: 'https://huggingface.co/oauth/authorize',\n tokenUrl: 'https://huggingface.co/oauth/token',\n scopes: ['inference-api'],\n },\n },\n azure_openai: {\n id: 'azure_openai',\n name: 'Azure OpenAI',\n authMethods: ['api_key'],\n baseUrl: 'https://YOUR_RESOURCE.openai.azure.com',\n },\n};\n\nexport function getProvider(id: string): ProviderConfig | undefined {\n return PROVIDERS[id];\n}\n\nexport function getProviderIds(): string[] {\n return Object.keys(PROVIDERS);\n}\n","import type { AuthMethod } from './types.js';\n\n/** Minimal WebSocket interface — compatible with browser WebSocket and `ws` library. */\nexport interface WebSocketLike {\n readonly readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n onclose: ((event: { code: number; reason: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n}\n\nexport const WS_READY_STATE = {\n CONNECTING: 0,\n OPEN: 1,\n CLOSING: 2,\n CLOSED: 3,\n} as const;\n\n// --- Relay message types ---\n\nexport interface RelayHello {\n type: 'relay:hello';\n sessionId: string;\n providers: Record<string, { available: boolean; authMethod: AuthMethod }>;\n}\n\nexport interface RelayRequest {\n type: 'relay:request';\n requestId: string;\n providerId: string;\n url: string;\n method: string;\n headers: Record<string, string>;\n body?: string;\n}\n\nexport interface RelayResponseMeta {\n type: 'relay:response:meta';\n requestId: string;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n}\n\nexport interface RelayResponseChunk {\n type: 'relay:response:chunk';\n requestId: string;\n chunk: string;\n}\n\nexport interface RelayResponseDone {\n type: 'relay:response:done';\n requestId: string;\n}\n\nexport interface RelayResponseError {\n type: 'relay:response:error';\n requestId: string;\n error: { code: string; message: string };\n}\n\nexport interface RelayPing {\n type: 'relay:ping';\n ts: number;\n}\n\nexport interface RelayPong {\n type: 'relay:pong';\n ts: number;\n}\n\nexport type RelayMessage =\n | RelayHello\n | RelayRequest\n | RelayResponseMeta\n | RelayResponseChunk\n | RelayResponseDone\n | RelayResponseError\n | RelayPing\n | RelayPong;\n\nexport function parseRelayMessage(data: unknown): RelayMessage | null {\n try {\n const raw = typeof data === 'string' ? JSON.parse(data) : data;\n if (!raw || typeof raw !== 'object' || typeof raw.type !== 'string' || !raw.type.startsWith('relay:')) {\n return null;\n }\n\n // Validate required fields per message type\n switch (raw.type) {\n case 'relay:hello':\n if (typeof raw.sessionId !== 'string') return null;\n break;\n case 'relay:request':\n if (typeof raw.requestId !== 'string' || typeof raw.providerId !== 'string' ||\n typeof raw.url !== 'string' || typeof raw.method !== 'string') return null;\n break;\n case 'relay:response:meta':\n if (typeof raw.requestId !== 'string' || typeof raw.status !== 'number') return null;\n break;\n case 'relay:response:chunk':\n if (typeof raw.requestId !== 'string' || typeof raw.chunk !== 'string') return null;\n break;\n case 'relay:response:done':\n case 'relay:response:error':\n if (typeof raw.requestId !== 'string') return null;\n break;\n case 'relay:ping':\n case 'relay:pong':\n if (typeof raw.ts !== 'number') return null;\n break;\n default:\n return null;\n }\n\n return raw as RelayMessage;\n } catch {\n return null;\n }\n}\n\nexport function sendRelayMessage(ws: WebSocketLike, msg: RelayMessage): void {\n if (ws.readyState === WS_READY_STATE.OPEN) {\n ws.send(JSON.stringify(msg));\n }\n}\n","export interface PasswordStrength {\n score: 0 | 1 | 2 | 3 | 4;\n label: 'Too weak' | 'Weak' | 'Fair' | 'Strong' | 'Very strong';\n feedback: string[];\n}\n\nconst COMMON_PASSWORDS = new Set([\n 'password', '12345678', 'qwerty12', 'letmein12', 'welcome1',\n 'monkey12', 'dragon12', 'master12', 'abc12345', 'password1',\n 'password12', 'iloveyou1', 'sunshine1', 'trustno1', 'princess1',\n 'football1', 'shadow123', 'michael1', 'jordan123', 'superman1',\n]);\n\nexport function checkPasswordStrength(password: string): PasswordStrength {\n const feedback: string[] = [];\n let score = 0;\n\n if (password.length < 12) {\n feedback.push('Use at least 12 characters');\n if (password.length < 8) {\n return { score: 0, label: 'Too weak', feedback };\n }\n } else {\n score++;\n if (password.length >= 16) score++;\n }\n\n if (COMMON_PASSWORDS.has(password.toLowerCase())) {\n feedback.push('This is a commonly used password');\n return { score: 0, label: 'Too weak', feedback };\n }\n\n // Check character diversity\n const hasLower = /[a-z]/.test(password);\n const hasUpper = /[A-Z]/.test(password);\n const hasDigit = /\\d/.test(password);\n const hasSymbol = /[^a-zA-Z0-9]/.test(password);\n const charTypes = [hasLower, hasUpper, hasDigit, hasSymbol].filter(Boolean).length;\n\n if (charTypes < 2) {\n feedback.push('Mix uppercase, lowercase, numbers, and symbols');\n } else if (charTypes >= 3) {\n score++;\n }\n if (charTypes >= 4) {\n score++;\n }\n\n // Check for repeated characters (e.g. aaaaaa)\n if (/(.)\\1{3,}/.test(password)) {\n feedback.push('Avoid repeated characters');\n score = Math.max(0, score - 1);\n }\n\n // Check for sequential patterns (e.g. 123456, abcdef)\n if (/(?:012|123|234|345|456|567|678|789|abc|bcd|cde|def)/i.test(password)) {\n feedback.push('Avoid sequential patterns');\n score = Math.max(0, score - 1);\n }\n\n const capped = Math.min(4, Math.max(0, score)) as 0 | 1 | 2 | 3 | 4;\n const labels: Record<number, PasswordStrength['label']> = {\n 0: 'Too weak',\n 1: 'Weak',\n 2: 'Fair',\n 3: 'Strong',\n 4: 'Very strong',\n };\n\n if (feedback.length === 0 && capped < 3) {\n feedback.push('Add more character variety or length');\n }\n\n return { score: capped, label: labels[capped], feedback };\n}\n\nexport const MIN_PASSWORD_LENGTH = 12;\n","import type { RequestLogEntry, TokenAllowance } from './types.js';\nimport { PROVIDERS } from './providers.js';\n\n/**\n * Validate that a proxy request URL targets the registered provider's base URL.\n * Prevents API key exfiltration by rejecting requests to arbitrary domains.\n */\nexport function validateProxyUrl(providerId: string, url: string): boolean {\n const provider = PROVIDERS[providerId];\n if (!provider) return false;\n try {\n const target = new URL(url);\n if (target.protocol !== 'https:') return false;\n const base = new URL(provider.baseUrl);\n return target.origin === base.origin;\n } catch {\n return false;\n }\n}\n\n/**\n * Build the real auth headers for a provider API request.\n * Strips any fake session-key headers and injects the real API key.\n */\nexport function buildHeaders(\n providerId: string,\n requestHeaders: Record<string, string>,\n apiKey: string,\n authMethod: string = 'api_key',\n): Record<string, string> {\n // Normalize header keys to lowercase to prevent case-sensitive bypass\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(requestHeaders)) {\n headers[key.toLowerCase()] = value;\n }\n\n // Remove any auth headers the SDK might have set (they're fake session keys)\n delete headers['authorization'];\n delete headers['x-api-key'];\n delete headers['api-key'];\n\n // Strip browser/SDK headers that can trigger rejection from provider APIs\n delete headers['origin'];\n delete headers['referer'];\n // Remove SDK telemetry headers that leak the real client environment\n for (const key of Object.keys(headers)) {\n if (key.startsWith('x-stainless-')) delete headers[key];\n }\n delete headers['sec-fetch-mode'];\n delete headers['accept-language'];\n delete headers['accept-encoding'];\n // Always strip content-length — fetch() recalculates it from the actual body,\n // and the body may have been modified (e.g. system prompt injection)\n delete headers['content-length'];\n\n if (providerId === 'anthropic') {\n if (authMethod === 'oauth') {\n headers['authorization'] = `Bearer ${apiKey}`;\n headers['user-agent'] = 'claude-cli/2.1.76';\n headers['x-app'] = 'cli';\n headers['accept'] = 'application/json';\n headers['anthropic-beta'] = 'claude-code-20250219,oauth-2025-04-20,fine-grained-tool-streaming-2025-05-14,interleaved-thinking-2025-05-14';\n headers['anthropic-dangerous-direct-browser-access'] = 'true';\n } else {\n headers['x-api-key'] = apiKey;\n }\n headers['anthropic-version'] = headers['anthropic-version'] ?? '2023-06-01';\n } else if (providerId === 'azure_openai') {\n headers['api-key'] = apiKey;\n } else {\n headers['authorization'] = `Bearer ${apiKey}`;\n }\n\n return headers;\n}\n\n/**\n * Parse the model name from a request body (JSON).\n */\nexport function parseModel(body?: string): string | undefined {\n if (!body) return undefined;\n try {\n const parsed = JSON.parse(body);\n return parsed.model ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Parse token usage from a provider API response body.\n * Handles both regular JSON responses and SSE streaming responses.\n */\nexport function parseUsage(\n providerId: string,\n body: string,\n): { inputTokens: number; outputTokens: number } | undefined {\n try {\n // For streaming responses (SSE), try to find usage in the last data chunk\n if (body.includes('data: ')) {\n const lines = body.split('\\n').filter((l) => l.startsWith('data: ') && !l.includes('[DONE]'));\n // Anthropic streaming: message_stop event has usage in a preceding message_delta\n // OpenAI streaming: last chunk may include usage\n for (let i = lines.length - 1; i >= 0; i--) {\n const json = lines[i].replace('data: ', '');\n try {\n const parsed = JSON.parse(json);\n const usage = extractUsageFromParsed(providerId, parsed);\n if (usage) return usage;\n } catch {\n continue;\n }\n }\n return undefined;\n }\n\n const parsed = JSON.parse(body);\n return extractUsageFromParsed(providerId, parsed);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Extract token usage from a parsed provider response object.\n */\nexport function extractUsageFromParsed(\n providerId: string,\n parsed: Record<string, unknown>,\n): { inputTokens: number; outputTokens: number } | undefined {\n // Anthropic: { usage: { input_tokens, output_tokens } }\n if (providerId === 'anthropic') {\n const usage = parsed.usage as Record<string, number> | undefined;\n if (usage?.input_tokens != null && usage?.output_tokens != null) {\n return { inputTokens: usage.input_tokens, outputTokens: usage.output_tokens };\n }\n }\n\n // Gemini: { usageMetadata: { promptTokenCount, candidatesTokenCount } }\n if (providerId === 'gemini') {\n const meta = parsed.usageMetadata as Record<string, number> | undefined;\n if (meta?.promptTokenCount != null) {\n return {\n inputTokens: meta.promptTokenCount,\n outputTokens: meta.candidatesTokenCount ?? 0,\n };\n }\n }\n\n // OpenAI-compatible (openai, groq, together, deepseek, xai, perplexity, fireworks, openrouter, mistral, azure_openai):\n // { usage: { prompt_tokens, completion_tokens } }\n const usage = parsed.usage as Record<string, number> | undefined;\n if (usage?.prompt_tokens != null && usage?.completion_tokens != null) {\n return { inputTokens: usage.prompt_tokens, outputTokens: usage.completion_tokens };\n }\n\n return undefined;\n}\n\n/**\n * Check whether a request is allowed given token allowances and usage history.\n * Pure computation — no storage access.\n */\nexport function computeAllowanceCheck(\n allowance: TokenAllowance | undefined,\n entries: Pick<RequestLogEntry, 'providerId' | 'inputTokens' | 'outputTokens'>[],\n providerId: string,\n): { allowed: boolean; reason?: string } {\n if (!allowance) return { allowed: true };\n\n let totalUsed = 0;\n const byProvider: Record<string, number> = {};\n for (const entry of entries) {\n const tokens = (entry.inputTokens ?? 0) + (entry.outputTokens ?? 0);\n totalUsed += tokens;\n byProvider[entry.providerId] = (byProvider[entry.providerId] ?? 0) + tokens;\n }\n\n if (allowance.totalLimit != null && totalUsed >= allowance.totalLimit) {\n return { allowed: false, reason: `Token allowance exceeded for ${allowance.origin}` };\n }\n\n const providerLimit = allowance.providerLimits?.[providerId];\n if (providerLimit != null && (byProvider[providerId] ?? 0) >= providerLimit) {\n return { allowed: false, reason: `Token allowance for ${providerId} exceeded` };\n }\n\n return { allowed: true };\n}\n","import { PROVIDERS } from './providers.js';\n\n// --- Gift (sender side) ---\n\nexport interface Gift {\n id: string;\n credentialId: string;\n providerId: string;\n label: string;\n authToken: string;\n maxTokens: number;\n usedTokens: number;\n expiresAt: number;\n createdAt: number;\n active: boolean;\n relayUrl: string;\n}\n\n// --- Gift link (shareable payload) ---\n\nexport interface GiftLink {\n v: 1;\n id: string;\n p: string; // providerId\n n: string; // provider display name\n s: string; // sender label\n t: string; // auth token\n m: number; // max tokens\n e: number; // expires at (unix ms)\n r: string; // relay URL\n}\n\n// --- Gifted credential (recipient side) ---\n\nexport interface GiftedCredential {\n id: string;\n giftId: string;\n providerId: string;\n providerName: string;\n senderLabel: string;\n authToken: string;\n maxTokens: number;\n usedTokens: number;\n expiresAt: number;\n relayUrl: string;\n createdAt: number;\n}\n\n// --- Gift relay protocol ---\n\nexport interface GiftRelayAuth {\n type: 'gift:auth';\n giftId: string;\n authToken: string;\n role: 'sender' | 'recipient';\n}\n\nexport interface GiftRelayAuthResult {\n type: 'gift:auth:result';\n success: boolean;\n error?: string;\n peerOnline?: boolean;\n}\n\nexport interface GiftRelayPeerStatus {\n type: 'gift:peer:status';\n online: boolean;\n}\n\nexport interface GiftRelayUsageUpdate {\n type: 'gift:usage';\n giftId: string;\n usedTokens: number;\n}\n\nexport type GiftRelayMessage =\n | GiftRelayAuth\n | GiftRelayAuthResult\n | GiftRelayPeerStatus\n | GiftRelayUsageUpdate;\n\n// --- Encoding / decoding ---\n\nexport function encodeGiftLink(link: GiftLink): string {\n const json = JSON.stringify(link);\n const bytes = new TextEncoder().encode(json);\n return base64UrlEncode(bytes);\n}\n\nexport function decodeGiftLink(encoded: string): GiftLink | null {\n try {\n const clean = encoded.replace(/^byoky:\\/\\/gift\\//, '');\n const bytes = base64UrlDecode(clean);\n const json = new TextDecoder().decode(bytes);\n const parsed = JSON.parse(json);\n if (parsed.v !== 1) return null;\n return parsed as GiftLink;\n } catch {\n return null;\n }\n}\n\nexport function giftLinkToUrl(encoded: string): string {\n return `byoky://gift/${encoded}`;\n}\n\n// --- Validation ---\n\nexport function validateGiftLink(link: GiftLink): { valid: boolean; reason?: string } {\n if (link.v !== 1) return { valid: false, reason: 'Unsupported gift version' };\n if (!link.id || typeof link.id !== 'string') return { valid: false, reason: 'Missing gift ID' };\n if (!link.p || typeof link.p !== 'string') return { valid: false, reason: 'Missing provider' };\n if (!link.t || typeof link.t !== 'string') return { valid: false, reason: 'Missing auth token' };\n if (!link.r || typeof link.r !== 'string') return { valid: false, reason: 'Missing relay URL' };\n if (typeof link.m !== 'number' || link.m <= 0) return { valid: false, reason: 'Invalid token budget' };\n if (typeof link.e !== 'number' || link.e <= Date.now()) return { valid: false, reason: 'Gift has expired' };\n\n try {\n const url = new URL(link.r);\n if (url.protocol !== 'ws:' && url.protocol !== 'wss:') {\n return { valid: false, reason: 'Relay URL must use ws:// or wss://' };\n }\n } catch {\n return { valid: false, reason: 'Invalid relay URL' };\n }\n\n return { valid: true };\n}\n\nexport function isGiftExpired(gift: { expiresAt: number }): boolean {\n return gift.expiresAt <= Date.now();\n}\n\nexport function isGiftBudgetExhausted(gift: { usedTokens: number; maxTokens: number }): boolean {\n return gift.usedTokens >= gift.maxTokens;\n}\n\nexport function giftBudgetRemaining(gift: { usedTokens: number; maxTokens: number }): number {\n return Math.max(0, gift.maxTokens - gift.usedTokens);\n}\n\nexport function giftBudgetPercent(gift: { usedTokens: number; maxTokens: number }): number {\n if (gift.maxTokens === 0) return 100;\n return Math.min(100, Math.round((gift.usedTokens / gift.maxTokens) * 100));\n}\n\nexport function createGiftLink(gift: Gift): { encoded: string; link: GiftLink } {\n const provider = PROVIDERS[gift.providerId];\n const link: GiftLink = {\n v: 1,\n id: gift.id,\n p: gift.providerId,\n n: provider?.name ?? gift.providerId,\n s: gift.label,\n t: gift.authToken,\n m: gift.maxTokens,\n e: gift.expiresAt,\n r: gift.relayUrl,\n };\n return { encoded: encodeGiftLink(link), link };\n}\n\n// --- Base64url helpers ---\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction base64UrlDecode(str: string): Uint8Array {\n const padded = str.replace(/-/g, '+').replace(/_/g, '/');\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n"],"mappings":";AA2KO,IAAK,iBAAL,kBAAKA,oBAAL;AACL,EAAAA,gBAAA,0BAAuB;AACvB,EAAAA,gBAAA,mBAAgB;AAChB,EAAAA,gBAAA,0BAAuB;AACvB,EAAAA,gBAAA,qBAAkB;AAClB,EAAAA,gBAAA,kBAAe;AACf,EAAAA,gBAAA,oBAAiB;AACjB,EAAAA,gBAAA,iBAAc;AACd,EAAAA,gBAAA,mBAAgB;AAChB,EAAAA,gBAAA,iBAAc;AACd,EAAAA,gBAAA,6BAA0B;AAC1B,EAAAA,gBAAA,wBAAqB;AACrB,EAAAA,gBAAA,aAAU;AAZA,SAAAA;AAAA,GAAA;;;AC3KZ,IAAM,cAAc;AACpB,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,aAAa;AAEnB,eAAsB,UACpB,UACA,MACoB;AACpB,QAAM,cAAc,MAAM,OAAO,OAAO;AAAA,IACtC;AAAA,IACA,IAAI,YAAY,EAAE,OAAO,QAAQ;AAAA,IACjC;AAAA,IACA;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,SAAO,OAAO,OAAO;AAAA,IACnB,EAAE,MAAM,UAAU,MAA4B,YAAY,YAAY,MAAM,UAAU;AAAA,IACtF;AAAA,IACA,EAAE,MAAM,WAAW,QAAQ,WAAW;AAAA,IACtC;AAAA,IACA,CAAC,WAAW,SAAS;AAAA,EACvB;AACF;AAEA,eAAsB,QACpB,WACA,UACiB;AACjB,QAAM,OAAO,OAAO,gBAAgB,IAAI,WAAW,WAAW,CAAC;AAC/D,QAAM,KAAK,OAAO,gBAAgB,IAAI,WAAW,SAAS,CAAC;AAC3D,QAAM,MAAM,MAAM,UAAU,UAAU,IAAI;AAE1C,QAAM,aAAa,MAAM,OAAO,OAAO;AAAA,IACrC,EAAE,MAAM,WAAW,GAAG;AAAA,IACtB;AAAA,IACA,IAAI,YAAY,EAAE,OAAO,SAAS;AAAA,EACpC;AAEA,QAAM,WAAW,IAAI;AAAA,IACnB,KAAK,SAAS,GAAG,SAAS,IAAI,WAAW,UAAU,EAAE;AAAA,EACvD;AACA,WAAS,IAAI,MAAM,CAAC;AACpB,WAAS,IAAI,IAAI,KAAK,MAAM;AAC5B,WAAS,IAAI,IAAI,WAAW,UAAU,GAAG,KAAK,SAAS,GAAG,MAAM;AAEhE,SAAO,KAAK,OAAO,aAAa,GAAG,QAAQ,CAAC;AAC9C;AAEA,eAAsB,QACpB,WACA,UACiB;AACjB,QAAM,WAAW,WAAW,KAAK,KAAK,SAAS,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAExE,QAAM,OAAO,SAAS,MAAM,GAAG,WAAW;AAC1C,QAAM,KAAK,SAAS,MAAM,aAAa,cAAc,SAAS;AAC9D,QAAM,aAAa,SAAS,MAAM,cAAc,SAAS;AAEzD,QAAM,MAAM,MAAM,UAAU,UAAU,IAAI;AAE1C,QAAM,YAAY,MAAM,OAAO,OAAO;AAAA,IACpC,EAAE,MAAM,WAAW,GAAG;AAAA,IACtB;AAAA,IACA;AAAA,EACF;AAEA,SAAO,IAAI,YAAY,EAAE,OAAO,SAAS;AAC3C;AAEA,eAAe,cACb,UACA,MACqB;AACrB,QAAM,cAAc,MAAM,OAAO,OAAO;AAAA,IACtC;AAAA,IACA,IAAI,YAAY,EAAE,OAAO,QAAQ;AAAA,IACjC;AAAA,IACA;AAAA,IACA,CAAC,YAAY;AAAA,EACf;AAEA,QAAM,OAAO,MAAM,OAAO,OAAO;AAAA,IAC/B,EAAE,MAAM,UAAU,MAA4B,YAAY,YAAY,MAAM,UAAU;AAAA,IACtF;AAAA,IACA;AAAA,EACF;AAEA,SAAO,IAAI,WAAW,IAAI;AAC5B;AAEA,eAAsB,aAAa,UAAmC;AACpE,QAAM,OAAO,OAAO,gBAAgB,IAAI,WAAW,WAAW,CAAC;AAC/D,QAAM,OAAO,MAAM,cAAc,UAAU,IAAI;AAE/C,QAAM,WAAW,IAAI,WAAW,KAAK,SAAS,KAAK,MAAM;AACzD,WAAS,IAAI,MAAM,CAAC;AACpB,WAAS,IAAI,MAAM,KAAK,MAAM;AAE9B,SAAO,KAAK,OAAO,aAAa,GAAG,QAAQ,CAAC;AAC9C;AAEA,eAAsB,eACpB,UACA,YACkB;AAClB,QAAM,WAAW,WAAW,KAAK,KAAK,UAAU,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AACzE,QAAM,OAAO,SAAS,MAAM,GAAG,WAAW;AAC1C,QAAM,eAAe,SAAS,MAAM,WAAW;AAE/C,QAAM,UAAU,MAAM,cAAc,UAAU,IAAI;AAElD,MAAI,aAAa,WAAW,QAAQ,OAAQ,QAAO;AACnD,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,cAAU,aAAa,CAAC,IAAI,QAAQ,CAAC;AAAA,EACvC;AACA,SAAO,WAAW;AACpB;AAEO,SAAS,QAAQ,KAAqB;AAC3C,MAAI,IAAI,UAAU,EAAG,QAAO;AAC5B,SAAO,GAAG,IAAI,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;AAC9C;;;AC1HO,IAAM,aAAN,MAAM,oBAAmB,MAAM;AAAA,EACpC,YACkB,MAChB,SACgB,SAChB;AACA,UAAM,OAAO;AAJG;AAEA;AAGhB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,OAAO,qBAAqB;AAC1B,WAAO,IAAI;AAAA;AAAA,MAET;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,eAAe;AACpB,WAAO,IAAI;AAAA;AAAA,MAET;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,oBAAoB,YAAoB;AAC7C,WAAO,IAAI;AAAA;AAAA,MAET,aAAa,UAAU;AAAA,MACvB,EAAE,WAAW;AAAA,IACf;AAAA,EACF;AAAA,EAEA,OAAO,iBAAiB;AACtB,WAAO,IAAI;AAAA;AAAA,MAET;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,YAAY,YAAqB;AACtC,WAAO,IAAI;AAAA;AAAA,MAET,sBAAsB,aAAa,uBAAkB,UAAU,MAAM,EAAE;AAAA,MACvE,EAAE,WAAW;AAAA,IACf;AAAA,EACF;AAAA,EAEA,OAAO,cAAc,YAAoB;AACvC,WAAO,IAAI;AAAA;AAAA,MAET,sBAAsB,UAAU;AAAA,MAChC,EAAE,WAAW;AAAA,IACf;AAAA,EACF;AAAA,EAEA,OAAO,WAAW,YAAoB;AACpC,WAAO,IAAI;AAAA;AAAA,MAET,uBAAuB,UAAU;AAAA,MACjC,EAAE,WAAW;AAAA,IACf;AAAA,EACF;AAAA,EAEA,OAAO,aAAa,YAAoB;AACtC,WAAO,IAAI;AAAA;AAAA,MAET,2BAA2B,UAAU;AAAA,MACrC,EAAE,WAAW;AAAA,IACf;AAAA,EACF;AAAA,EAEA,OAAO,sBAAsB,QAAiB;AAC5C,WAAO,IAAI;AAAA;AAAA,MAET,0BAA0B,SAAS,KAAK,MAAM,KAAK,EAAE;AAAA,IACvD;AAAA,EACF;AAAA,EAEA,OAAO,oBAAoB;AACzB,WAAO,IAAI;AAAA;AAAA,MAET;AAAA,IACF;AAAA,EACF;AACF;;;AC/EO,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AAE7B,SAAS,cACd,MACA,SACA,WACc;AACd,SAAO;AAAA,IACL;AAAA,IACA,IAAI,OAAO,WAAW;AAAA,IACtB;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,eAAe,MAAqC;AAClE,SACE,OAAO,SAAS,YAChB,SAAS,QACT,UAAU,QACV,OAAQ,KAAsB,SAAS,YACtC,KAAsB,KAAK,WAAW,oBAAoB;AAE/D;AAEO,SAAS,qBAAqB,SAAuC;AAC1E,SAAO,cAAc,yBAAyB,OAAO;AACvD;AAEO,SAAS,sBACd,UACA,WACc;AACd,SAAO,cAAc,0BAA0B,UAAU,SAAS;AACpE;AAEO,SAAS,mBACd,MACA,SACA,WACc;AACd,SAAO,cAAc,eAAe,EAAE,MAAM,QAAQ,GAAG,SAAS;AAClE;;;AChDO,IAAM,YAA4C;AAAA,EACvD,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,WAAW,OAAO;AAAA,IAChC,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,WAAW,OAAO;AAAA,IAChC,SAAS;AAAA,IACT,aAAa;AAAA,MACX,UAAU;AAAA,MACV,kBAAkB;AAAA,MAClB,UAAU;AAAA,MACV,QAAQ,CAAC,qDAAqD;AAAA,MAC9D,iBAAiB,EAAE,aAAa,WAAW,QAAQ,UAAU;AAAA,IAC/D;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,YAAY;AAAA,IACV,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,MAAM;AAAA,IACJ,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,YAAY;AAAA,IACV,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AAAA,EACA,aAAa;AAAA,IACX,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,WAAW,OAAO;AAAA,IAChC,SAAS;AAAA,IACT,aAAa;AAAA,MACX,UAAU;AAAA,MACV,kBAAkB;AAAA,MAClB,UAAU;AAAA,MACV,QAAQ,CAAC,eAAe;AAAA,IAC1B;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,CAAC,SAAS;AAAA,IACvB,SAAS;AAAA,EACX;AACF;AAEO,SAAS,YAAY,IAAwC;AAClE,SAAO,UAAU,EAAE;AACrB;AAEO,SAAS,iBAA2B;AACzC,SAAO,OAAO,KAAK,SAAS;AAC9B;;;ACrGO,IAAM,iBAAiB;AAAA,EAC5B,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AACV;AAiEO,SAAS,kBAAkB,MAAoC;AACpE,MAAI;AACF,UAAM,MAAM,OAAO,SAAS,WAAW,KAAK,MAAM,IAAI,IAAI;AAC1D,QAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,OAAO,IAAI,SAAS,YAAY,CAAC,IAAI,KAAK,WAAW,QAAQ,GAAG;AACrG,aAAO;AAAA,IACT;AAGA,YAAQ,IAAI,MAAM;AAAA,MAChB,KAAK;AACH,YAAI,OAAO,IAAI,cAAc,SAAU,QAAO;AAC9C;AAAA,MACF,KAAK;AACH,YAAI,OAAO,IAAI,cAAc,YAAY,OAAO,IAAI,eAAe,YAC/D,OAAO,IAAI,QAAQ,YAAY,OAAO,IAAI,WAAW,SAAU,QAAO;AAC1E;AAAA,MACF,KAAK;AACH,YAAI,OAAO,IAAI,cAAc,YAAY,OAAO,IAAI,WAAW,SAAU,QAAO;AAChF;AAAA,MACF,KAAK;AACH,YAAI,OAAO,IAAI,cAAc,YAAY,OAAO,IAAI,UAAU,SAAU,QAAO;AAC/E;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,YAAI,OAAO,IAAI,cAAc,SAAU,QAAO;AAC9C;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,YAAI,OAAO,IAAI,OAAO,SAAU,QAAO;AACvC;AAAA,MACF;AACE,eAAO;AAAA,IACX;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,iBAAiB,IAAmB,KAAyB;AAC3E,MAAI,GAAG,eAAe,eAAe,MAAM;AACzC,OAAG,KAAK,KAAK,UAAU,GAAG,CAAC;AAAA,EAC7B;AACF;;;ACzHA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC/B;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAa;AAAA,EACjD;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAAY;AAAA,EAChD;AAAA,EAAc;AAAA,EAAa;AAAA,EAAa;AAAA,EAAY;AAAA,EACpD;AAAA,EAAa;AAAA,EAAa;AAAA,EAAY;AAAA,EAAa;AACrD,CAAC;AAEM,SAAS,sBAAsB,UAAoC;AACxE,QAAM,WAAqB,CAAC;AAC5B,MAAI,QAAQ;AAEZ,MAAI,SAAS,SAAS,IAAI;AACxB,aAAS,KAAK,4BAA4B;AAC1C,QAAI,SAAS,SAAS,GAAG;AACvB,aAAO,EAAE,OAAO,GAAG,OAAO,YAAY,SAAS;AAAA,IACjD;AAAA,EACF,OAAO;AACL;AACA,QAAI,SAAS,UAAU,GAAI;AAAA,EAC7B;AAEA,MAAI,iBAAiB,IAAI,SAAS,YAAY,CAAC,GAAG;AAChD,aAAS,KAAK,kCAAkC;AAChD,WAAO,EAAE,OAAO,GAAG,OAAO,YAAY,SAAS;AAAA,EACjD;AAGA,QAAM,WAAW,QAAQ,KAAK,QAAQ;AACtC,QAAM,WAAW,QAAQ,KAAK,QAAQ;AACtC,QAAM,WAAW,KAAK,KAAK,QAAQ;AACnC,QAAM,YAAY,eAAe,KAAK,QAAQ;AAC9C,QAAM,YAAY,CAAC,UAAU,UAAU,UAAU,SAAS,EAAE,OAAO,OAAO,EAAE;AAE5E,MAAI,YAAY,GAAG;AACjB,aAAS,KAAK,gDAAgD;AAAA,EAChE,WAAW,aAAa,GAAG;AACzB;AAAA,EACF;AACA,MAAI,aAAa,GAAG;AAClB;AAAA,EACF;AAGA,MAAI,YAAY,KAAK,QAAQ,GAAG;AAC9B,aAAS,KAAK,2BAA2B;AACzC,YAAQ,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAA,EAC/B;AAGA,MAAI,uDAAuD,KAAK,QAAQ,GAAG;AACzE,aAAS,KAAK,2BAA2B;AACzC,YAAQ,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAA,EAC/B;AAEA,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;AAC7C,QAAM,SAAoD;AAAA,IACxD,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AAEA,MAAI,SAAS,WAAW,KAAK,SAAS,GAAG;AACvC,aAAS,KAAK,sCAAsC;AAAA,EACtD;AAEA,SAAO,EAAE,OAAO,QAAQ,OAAO,OAAO,MAAM,GAAG,SAAS;AAC1D;AAEO,IAAM,sBAAsB;;;ACrE5B,SAAS,iBAAiB,YAAoB,KAAsB;AACzE,QAAM,WAAW,UAAU,UAAU;AACrC,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,QAAI,OAAO,aAAa,SAAU,QAAO;AACzC,UAAM,OAAO,IAAI,IAAI,SAAS,OAAO;AACrC,WAAO,OAAO,WAAW,KAAK;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,aACd,YACA,gBACA,QACA,aAAqB,WACG;AAExB,QAAM,UAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,cAAc,GAAG;AACzD,YAAQ,IAAI,YAAY,CAAC,IAAI;AAAA,EAC/B;AAGA,SAAO,QAAQ,eAAe;AAC9B,SAAO,QAAQ,WAAW;AAC1B,SAAO,QAAQ,SAAS;AAGxB,SAAO,QAAQ,QAAQ;AACvB,SAAO,QAAQ,SAAS;AAExB,aAAW,OAAO,OAAO,KAAK,OAAO,GAAG;AACtC,QAAI,IAAI,WAAW,cAAc,EAAG,QAAO,QAAQ,GAAG;AAAA,EACxD;AACA,SAAO,QAAQ,gBAAgB;AAC/B,SAAO,QAAQ,iBAAiB;AAChC,SAAO,QAAQ,iBAAiB;AAGhC,SAAO,QAAQ,gBAAgB;AAE/B,MAAI,eAAe,aAAa;AAC9B,QAAI,eAAe,SAAS;AAC1B,cAAQ,eAAe,IAAI,UAAU,MAAM;AAC3C,cAAQ,YAAY,IAAI;AACxB,cAAQ,OAAO,IAAI;AACnB,cAAQ,QAAQ,IAAI;AACpB,cAAQ,gBAAgB,IAAI;AAC5B,cAAQ,2CAA2C,IAAI;AAAA,IACzD,OAAO;AACL,cAAQ,WAAW,IAAI;AAAA,IACzB;AACA,YAAQ,mBAAmB,IAAI,QAAQ,mBAAmB,KAAK;AAAA,EACjE,WAAW,eAAe,gBAAgB;AACxC,YAAQ,SAAS,IAAI;AAAA,EACvB,OAAO;AACL,YAAQ,eAAe,IAAI,UAAU,MAAM;AAAA,EAC7C;AAEA,SAAO;AACT;AAKO,SAAS,WAAW,MAAmC;AAC5D,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,WAAO,OAAO,SAAS;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,WACd,YACA,MAC2D;AAC3D,MAAI;AAEF,QAAI,KAAK,SAAS,QAAQ,GAAG;AAC3B,YAAM,QAAQ,KAAK,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ,KAAK,CAAC,EAAE,SAAS,QAAQ,CAAC;AAG5F,eAAS,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;AAC1C,cAAM,OAAO,MAAM,CAAC,EAAE,QAAQ,UAAU,EAAE;AAC1C,YAAI;AACF,gBAAMC,UAAS,KAAK,MAAM,IAAI;AAC9B,gBAAM,QAAQ,uBAAuB,YAAYA,OAAM;AACvD,cAAI,MAAO,QAAO;AAAA,QACpB,QAAQ;AACN;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,WAAO,uBAAuB,YAAY,MAAM;AAAA,EAClD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,uBACd,YACA,QAC2D;AAE3D,MAAI,eAAe,aAAa;AAC9B,UAAMC,SAAQ,OAAO;AACrB,QAAIA,QAAO,gBAAgB,QAAQA,QAAO,iBAAiB,MAAM;AAC/D,aAAO,EAAE,aAAaA,OAAM,cAAc,cAAcA,OAAM,cAAc;AAAA,IAC9E;AAAA,EACF;AAGA,MAAI,eAAe,UAAU;AAC3B,UAAM,OAAO,OAAO;AACpB,QAAI,MAAM,oBAAoB,MAAM;AAClC,aAAO;AAAA,QACL,aAAa,KAAK;AAAA,QAClB,cAAc,KAAK,wBAAwB;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAIA,QAAM,QAAQ,OAAO;AACrB,MAAI,OAAO,iBAAiB,QAAQ,OAAO,qBAAqB,MAAM;AACpE,WAAO,EAAE,aAAa,MAAM,eAAe,cAAc,MAAM,kBAAkB;AAAA,EACnF;AAEA,SAAO;AACT;AAMO,SAAS,sBACd,WACA,SACA,YACuC;AACvC,MAAI,CAAC,UAAW,QAAO,EAAE,SAAS,KAAK;AAEvC,MAAI,YAAY;AAChB,QAAM,aAAqC,CAAC;AAC5C,aAAW,SAAS,SAAS;AAC3B,UAAM,UAAU,MAAM,eAAe,MAAM,MAAM,gBAAgB;AACjE,iBAAa;AACb,eAAW,MAAM,UAAU,KAAK,WAAW,MAAM,UAAU,KAAK,KAAK;AAAA,EACvE;AAEA,MAAI,UAAU,cAAc,QAAQ,aAAa,UAAU,YAAY;AACrE,WAAO,EAAE,SAAS,OAAO,QAAQ,gCAAgC,UAAU,MAAM,GAAG;AAAA,EACtF;AAEA,QAAM,gBAAgB,UAAU,iBAAiB,UAAU;AAC3D,MAAI,iBAAiB,SAAS,WAAW,UAAU,KAAK,MAAM,eAAe;AAC3E,WAAO,EAAE,SAAS,OAAO,QAAQ,uBAAuB,UAAU,YAAY;AAAA,EAChF;AAEA,SAAO,EAAE,SAAS,KAAK;AACzB;;;ACzGO,SAAS,eAAe,MAAwB;AACrD,QAAM,OAAO,KAAK,UAAU,IAAI;AAChC,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,IAAI;AAC3C,SAAO,gBAAgB,KAAK;AAC9B;AAEO,SAAS,eAAe,SAAkC;AAC/D,MAAI;AACF,UAAM,QAAQ,QAAQ,QAAQ,qBAAqB,EAAE;AACrD,UAAM,QAAQ,gBAAgB,KAAK;AACnC,UAAM,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AAC3C,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI,OAAO,MAAM,EAAG,QAAO;AAC3B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,cAAc,SAAyB;AACrD,SAAO,gBAAgB,OAAO;AAChC;AAIO,SAAS,iBAAiB,MAAqD;AACpF,MAAI,KAAK,MAAM,EAAG,QAAO,EAAE,OAAO,OAAO,QAAQ,2BAA2B;AAC5E,MAAI,CAAC,KAAK,MAAM,OAAO,KAAK,OAAO,SAAU,QAAO,EAAE,OAAO,OAAO,QAAQ,kBAAkB;AAC9F,MAAI,CAAC,KAAK,KAAK,OAAO,KAAK,MAAM,SAAU,QAAO,EAAE,OAAO,OAAO,QAAQ,mBAAmB;AAC7F,MAAI,CAAC,KAAK,KAAK,OAAO,KAAK,MAAM,SAAU,QAAO,EAAE,OAAO,OAAO,QAAQ,qBAAqB;AAC/F,MAAI,CAAC,KAAK,KAAK,OAAO,KAAK,MAAM,SAAU,QAAO,EAAE,OAAO,OAAO,QAAQ,oBAAoB;AAC9F,MAAI,OAAO,KAAK,MAAM,YAAY,KAAK,KAAK,EAAG,QAAO,EAAE,OAAO,OAAO,QAAQ,uBAAuB;AACrG,MAAI,OAAO,KAAK,MAAM,YAAY,KAAK,KAAK,KAAK,IAAI,EAAG,QAAO,EAAE,OAAO,OAAO,QAAQ,mBAAmB;AAE1G,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,KAAK,CAAC;AAC1B,QAAI,IAAI,aAAa,SAAS,IAAI,aAAa,QAAQ;AACrD,aAAO,EAAE,OAAO,OAAO,QAAQ,qCAAqC;AAAA,IACtE;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,OAAO,OAAO,QAAQ,oBAAoB;AAAA,EACrD;AAEA,SAAO,EAAE,OAAO,KAAK;AACvB;AAEO,SAAS,cAAc,MAAsC;AAClE,SAAO,KAAK,aAAa,KAAK,IAAI;AACpC;AAEO,SAAS,sBAAsB,MAA0D;AAC9F,SAAO,KAAK,cAAc,KAAK;AACjC;AAEO,SAAS,oBAAoB,MAAyD;AAC3F,SAAO,KAAK,IAAI,GAAG,KAAK,YAAY,KAAK,UAAU;AACrD;AAEO,SAAS,kBAAkB,MAAyD;AACzF,MAAI,KAAK,cAAc,EAAG,QAAO;AACjC,SAAO,KAAK,IAAI,KAAK,KAAK,MAAO,KAAK,aAAa,KAAK,YAAa,GAAG,CAAC;AAC3E;AAEO,SAAS,eAAe,MAAiD;AAC9E,QAAM,WAAW,UAAU,KAAK,UAAU;AAC1C,QAAM,OAAiB;AAAA,IACrB,GAAG;AAAA,IACH,IAAI,KAAK;AAAA,IACT,GAAG,KAAK;AAAA,IACR,GAAG,UAAU,QAAQ,KAAK;AAAA,IAC1B,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,EACV;AACA,SAAO,EAAE,SAAS,eAAe,IAAI,GAAG,KAAK;AAC/C;AAIA,SAAS,gBAAgB,OAA2B;AAClD,MAAI,SAAS;AACb,aAAW,QAAQ,MAAO,WAAU,OAAO,aAAa,IAAI;AAC5D,SAAO,KAAK,MAAM,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,EAAE;AAC/E;AAEA,SAAS,gBAAgB,KAAyB;AAChD,QAAM,SAAS,IAAI,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AACvD,QAAM,SAAS,KAAK,MAAM;AAC1B,QAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAC1C,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAK,OAAM,CAAC,IAAI,OAAO,WAAW,CAAC;AACtE,SAAO;AACT;","names":["ByokyErrorCode","parsed","usage"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/crypto.ts","../src/errors.ts","../src/protocol.ts","../src/providers.ts","../src/relay.ts","../src/password-strength.ts","../src/proxy-utils.ts","../src/gift.ts"],"sourcesContent":["export type ProviderId = 'anthropic' | 'openai' | 'gemini' | (string & {});\n\nexport type AuthMethod = 'api_key' | 'oauth';\n\nexport interface ProviderConfig {\n id: ProviderId;\n name: string;\n authMethods: AuthMethod[];\n baseUrl: string;\n oauthConfig?: OAuthConfig;\n}\n\nexport interface OAuthConfig {\n clientId: string;\n authorizationUrl: string;\n tokenUrl: string;\n scopes: string[];\n extraAuthParams?: Record<string, string>;\n}\n\n// --- Credentials ---\n\nexport interface CredentialBase {\n id: string;\n providerId: ProviderId;\n label: string;\n authMethod: AuthMethod;\n createdAt: number;\n lastUsedAt?: number;\n}\n\nexport interface ApiKeyCredential extends CredentialBase {\n authMethod: 'api_key';\n encryptedKey: string;\n}\n\nexport interface OAuthCredential extends CredentialBase {\n authMethod: 'oauth';\n encryptedAccessToken: string;\n encryptedRefreshToken?: string;\n expiresAt?: number;\n}\n\nexport type Credential = ApiKeyCredential | OAuthCredential;\n\nexport interface CredentialMeta {\n id: string;\n providerId: ProviderId;\n label: string;\n authMethod: AuthMethod;\n createdAt: number;\n lastUsedAt?: number;\n maskedKey?: string;\n}\n\n// --- Sessions ---\n\nexport interface Session {\n id: string;\n sessionKey: string;\n appOrigin: string;\n appName?: string;\n providers: SessionProvider[];\n createdAt: number;\n expiresAt: number;\n}\n\nexport interface SessionProvider {\n providerId: ProviderId;\n credentialId: string;\n available: boolean;\n authMethod: AuthMethod;\n giftId?: string;\n giftRelayUrl?: string;\n giftAuthToken?: string;\n}\n\n// --- Connect ---\n\nexport interface ConnectRequest {\n providers?: ProviderRequirement[];\n capabilities?: string[];\n}\n\nexport interface ProviderRequirement {\n id: ProviderId;\n required: boolean;\n}\n\nexport interface ConnectResponse {\n sessionKey: string;\n proxyUrl: string;\n providers: Record<\n string,\n {\n available: boolean;\n authMethod: AuthMethod;\n }\n >;\n}\n\n// --- Proxy ---\n\nexport interface ProxyRequest {\n requestId: string;\n sessionKey: string;\n providerId: string;\n url: string;\n method: string;\n headers: Record<string, string>;\n body?: string;\n}\n\nexport interface ProxyResponseMeta {\n requestId: string;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n}\n\nexport interface ProxyResponseChunk {\n requestId: string;\n chunk: string;\n}\n\nexport interface ProxyResponseError {\n requestId: string;\n status: number;\n error: { code: string; message: string };\n}\n\n// --- Protocol messages ---\n\nexport type MessageType =\n | 'BYOKY_CONNECT_REQUEST'\n | 'BYOKY_CONNECT_RESPONSE'\n | 'BYOKY_DISCONNECT'\n | 'BYOKY_PROXY_REQUEST'\n | 'BYOKY_PROXY_RESPONSE_META'\n | 'BYOKY_PROXY_RESPONSE_CHUNK'\n | 'BYOKY_PROXY_RESPONSE_DONE'\n | 'BYOKY_PROXY_RESPONSE_ERROR'\n | 'BYOKY_SESSION_STATUS'\n | 'BYOKY_SESSION_STATUS_RESPONSE'\n | 'BYOKY_SESSION_USAGE'\n | 'BYOKY_SESSION_USAGE_RESPONSE'\n | 'BYOKY_SESSION_REVOKED'\n | 'BYOKY_ERROR';\n\nexport interface ByokyMessage {\n type: MessageType;\n id: string;\n requestId?: string;\n payload: unknown;\n}\n\n// --- Session queries ---\n\nexport interface SessionUsage {\n requests: number;\n inputTokens: number;\n outputTokens: number;\n byProvider: Record<string, {\n requests: number;\n inputTokens: number;\n outputTokens: number;\n }>;\n}\n\n// --- Errors ---\n\nexport enum ByokyErrorCode {\n WALLET_NOT_INSTALLED = 'WALLET_NOT_INSTALLED',\n USER_REJECTED = 'USER_REJECTED',\n PROVIDER_UNAVAILABLE = 'PROVIDER_UNAVAILABLE',\n SESSION_EXPIRED = 'SESSION_EXPIRED',\n RATE_LIMITED = 'RATE_LIMITED',\n QUOTA_EXCEEDED = 'QUOTA_EXCEEDED',\n INVALID_KEY = 'INVALID_KEY',\n TOKEN_EXPIRED = 'TOKEN_EXPIRED',\n PROXY_ERROR = 'PROXY_ERROR',\n RELAY_CONNECTION_FAILED = 'RELAY_CONNECTION_FAILED',\n RELAY_DISCONNECTED = 'RELAY_DISCONNECTED',\n UNKNOWN = 'UNKNOWN',\n}\n\n// --- Request log ---\n\nexport interface RequestLogEntry {\n id: string;\n sessionId: string;\n appOrigin: string;\n providerId: ProviderId;\n url: string;\n method: string;\n status: number;\n timestamp: number;\n error?: string;\n inputTokens?: number;\n outputTokens?: number;\n model?: string;\n}\n\n// --- Pending approval ---\n\nexport interface PendingApproval {\n id: string;\n appOrigin: string;\n appName?: string;\n providers: ProviderRequirement[];\n timestamp: number;\n}\n\n// --- Trusted sites ---\n\nexport interface TrustedSite {\n origin: string;\n trustedAt: number;\n allowedProviders?: string[];\n}\n\n// --- Token allowances ---\n\nexport interface TokenAllowance {\n origin: string;\n totalLimit?: number;\n providerLimits?: Record<string, number>;\n}\n","const SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst KEY_LENGTH = 256;\nconst ITERATIONS = 600_000;\n\nexport async function deriveKey(\n password: string,\n salt: Uint8Array,\n): Promise<CryptoKey> {\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(password),\n 'PBKDF2',\n false,\n ['deriveKey'],\n );\n\n return crypto.subtle.deriveKey(\n { name: 'PBKDF2', salt: salt as BufferSource, iterations: ITERATIONS, hash: 'SHA-256' },\n keyMaterial,\n { name: 'AES-GCM', length: KEY_LENGTH },\n false,\n ['encrypt', 'decrypt'],\n );\n}\n\nexport async function encrypt(\n plaintext: string,\n password: string,\n): Promise<string> {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n const key = await deriveKey(password, salt);\n\n const ciphertext = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv },\n key,\n new TextEncoder().encode(plaintext),\n );\n\n const combined = new Uint8Array(\n salt.length + iv.length + new Uint8Array(ciphertext).length,\n );\n combined.set(salt, 0);\n combined.set(iv, salt.length);\n combined.set(new Uint8Array(ciphertext), salt.length + iv.length);\n\n return btoa(String.fromCharCode(...combined));\n}\n\nexport async function decrypt(\n encrypted: string,\n password: string,\n): Promise<string> {\n const combined = Uint8Array.from(atob(encrypted), (c) => c.charCodeAt(0));\n\n const salt = combined.slice(0, SALT_LENGTH);\n const iv = combined.slice(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const ciphertext = combined.slice(SALT_LENGTH + IV_LENGTH);\n\n const key = await deriveKey(password, salt);\n\n const plaintext = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv },\n key,\n ciphertext,\n );\n\n return new TextDecoder().decode(plaintext);\n}\n\nasync function deriveRawHash(\n password: string,\n salt: Uint8Array,\n): Promise<Uint8Array> {\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(password),\n 'PBKDF2',\n false,\n ['deriveBits'],\n );\n\n const bits = await crypto.subtle.deriveBits(\n { name: 'PBKDF2', salt: salt as BufferSource, iterations: ITERATIONS, hash: 'SHA-256' },\n keyMaterial,\n KEY_LENGTH,\n );\n\n return new Uint8Array(bits);\n}\n\nexport async function hashPassword(password: string): Promise<string> {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const hash = await deriveRawHash(password, salt);\n\n const combined = new Uint8Array(salt.length + hash.length);\n combined.set(salt, 0);\n combined.set(hash, salt.length);\n\n return btoa(String.fromCharCode(...combined));\n}\n\nexport async function verifyPassword(\n password: string,\n storedHash: string,\n): Promise<boolean> {\n const combined = Uint8Array.from(atob(storedHash), (c) => c.charCodeAt(0));\n const salt = combined.slice(0, SALT_LENGTH);\n const originalHash = combined.slice(SALT_LENGTH);\n\n const newHash = await deriveRawHash(password, salt);\n\n if (originalHash.length !== newHash.length) return false;\n let result = 0;\n for (let i = 0; i < originalHash.length; i++) {\n result |= originalHash[i] ^ newHash[i];\n }\n return result === 0;\n}\n\nexport function maskKey(key: string): string {\n if (key.length <= 8) return '****';\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n}\n","import { ByokyErrorCode } from './types.js';\n\nexport class ByokyError extends Error {\n constructor(\n public readonly code: ByokyErrorCode,\n message: string,\n public readonly details?: Record<string, unknown>,\n ) {\n super(message);\n this.name = 'ByokyError';\n }\n\n static walletNotInstalled() {\n return new ByokyError(\n ByokyErrorCode.WALLET_NOT_INSTALLED,\n 'byoky wallet extension is not installed',\n );\n }\n\n static userRejected() {\n return new ByokyError(\n ByokyErrorCode.USER_REJECTED,\n 'User rejected the connection request',\n );\n }\n\n static providerUnavailable(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.PROVIDER_UNAVAILABLE,\n `Provider \"${providerId}\" is not available`,\n { providerId },\n );\n }\n\n static sessionExpired() {\n return new ByokyError(\n ByokyErrorCode.SESSION_EXPIRED,\n 'Session has expired — please reconnect',\n );\n }\n\n static rateLimited(retryAfter?: number) {\n return new ByokyError(\n ByokyErrorCode.RATE_LIMITED,\n `Rate limit exceeded${retryAfter ? ` — retry after ${retryAfter}s` : ''}`,\n { retryAfter },\n );\n }\n\n static quotaExceeded(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.QUOTA_EXCEEDED,\n `Quota exceeded for ${providerId} — check your billing`,\n { providerId },\n );\n }\n\n static invalidKey(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.INVALID_KEY,\n `Invalid API key for ${providerId}`,\n { providerId },\n );\n }\n\n static tokenExpired(providerId: string) {\n return new ByokyError(\n ByokyErrorCode.TOKEN_EXPIRED,\n `OAuth token expired for ${providerId} — re-authentication required`,\n { providerId },\n );\n }\n\n static relayConnectionFailed(reason?: string) {\n return new ByokyError(\n ByokyErrorCode.RELAY_CONNECTION_FAILED,\n `Relay connection failed${reason ? `: ${reason}` : ''}`,\n );\n }\n\n static relayDisconnected() {\n return new ByokyError(\n ByokyErrorCode.RELAY_DISCONNECTED,\n 'Relay connection was closed',\n );\n }\n}\n","import type {\n ByokyMessage,\n ConnectRequest,\n ConnectResponse,\n MessageType,\n} from './types.js';\n\nexport const BYOKY_PROVIDER_KEY = '__byoky__';\nexport const BYOKY_MESSAGE_PREFIX = 'BYOKY_';\n\nexport function createMessage(\n type: MessageType,\n payload: unknown,\n requestId?: string,\n): ByokyMessage {\n return {\n type,\n id: crypto.randomUUID(),\n requestId,\n payload,\n };\n}\n\nexport function isByokyMessage(data: unknown): data is ByokyMessage {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'type' in data &&\n typeof (data as ByokyMessage).type === 'string' &&\n (data as ByokyMessage).type.startsWith(BYOKY_MESSAGE_PREFIX)\n );\n}\n\nexport function createConnectRequest(request: ConnectRequest): ByokyMessage {\n return createMessage('BYOKY_CONNECT_REQUEST', request);\n}\n\nexport function createConnectResponse(\n response: ConnectResponse,\n requestId: string,\n): ByokyMessage {\n return createMessage('BYOKY_CONNECT_RESPONSE', response, requestId);\n}\n\nexport function createErrorMessage(\n code: string,\n message: string,\n requestId?: string,\n): ByokyMessage {\n return createMessage('BYOKY_ERROR', { code, message }, requestId);\n}\n","import type { ProviderConfig } from './types.js';\n\nexport const PROVIDERS: Record<string, ProviderConfig> = {\n anthropic: {\n id: 'anthropic',\n name: 'Anthropic',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://api.anthropic.com',\n },\n openai: {\n id: 'openai',\n name: 'OpenAI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.openai.com',\n },\n gemini: {\n id: 'gemini',\n name: 'Google Gemini',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://generativelanguage.googleapis.com',\n oauthConfig: {\n clientId: '699663966637-gr4d994198r4g6jvip25ffg85kree6ck.apps.googleusercontent.com',\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n scopes: ['https://www.googleapis.com/auth/generative-language'],\n extraAuthParams: { access_type: 'offline', prompt: 'consent' },\n },\n },\n mistral: {\n id: 'mistral',\n name: 'Mistral',\n authMethods: ['api_key'],\n baseUrl: 'https://api.mistral.ai',\n },\n cohere: {\n id: 'cohere',\n name: 'Cohere',\n authMethods: ['api_key'],\n baseUrl: 'https://api.cohere.com',\n },\n xai: {\n id: 'xai',\n name: 'xAI (Grok)',\n authMethods: ['api_key'],\n baseUrl: 'https://api.x.ai',\n },\n deepseek: {\n id: 'deepseek',\n name: 'DeepSeek',\n authMethods: ['api_key'],\n baseUrl: 'https://api.deepseek.com',\n },\n perplexity: {\n id: 'perplexity',\n name: 'Perplexity',\n authMethods: ['api_key'],\n baseUrl: 'https://api.perplexity.ai',\n },\n groq: {\n id: 'groq',\n name: 'Groq',\n authMethods: ['api_key'],\n baseUrl: 'https://api.groq.com',\n },\n together: {\n id: 'together',\n name: 'Together AI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.together.xyz',\n },\n fireworks: {\n id: 'fireworks',\n name: 'Fireworks AI',\n authMethods: ['api_key'],\n baseUrl: 'https://api.fireworks.ai',\n },\n replicate: {\n id: 'replicate',\n name: 'Replicate',\n authMethods: ['api_key'],\n baseUrl: 'https://api.replicate.com',\n },\n openrouter: {\n id: 'openrouter',\n name: 'OpenRouter',\n authMethods: ['api_key'],\n baseUrl: 'https://openrouter.ai/api',\n },\n huggingface: {\n id: 'huggingface',\n name: 'Hugging Face',\n authMethods: ['api_key', 'oauth'],\n baseUrl: 'https://api-inference.huggingface.co',\n oauthConfig: {\n clientId: '031aeb11-725b-498a-93f9-d3599d84f57c',\n authorizationUrl: 'https://huggingface.co/oauth/authorize',\n tokenUrl: 'https://huggingface.co/oauth/token',\n scopes: ['inference-api'],\n },\n },\n azure_openai: {\n id: 'azure_openai',\n name: 'Azure OpenAI',\n authMethods: ['api_key'],\n baseUrl: 'https://YOUR_RESOURCE.openai.azure.com',\n },\n};\n\nexport function getProvider(id: string): ProviderConfig | undefined {\n return PROVIDERS[id];\n}\n\nexport function getProviderIds(): string[] {\n return Object.keys(PROVIDERS);\n}\n","import type { AuthMethod } from './types.js';\n\n/** Minimal WebSocket interface — compatible with browser WebSocket and `ws` library. */\nexport interface WebSocketLike {\n readonly readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n onclose: ((event: { code: number; reason: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n}\n\nexport const WS_READY_STATE = {\n CONNECTING: 0,\n OPEN: 1,\n CLOSING: 2,\n CLOSED: 3,\n} as const;\n\n// --- Relay message types ---\n\nexport interface RelayHello {\n type: 'relay:hello';\n sessionId: string;\n providers: Record<string, { available: boolean; authMethod: AuthMethod }>;\n}\n\nexport interface RelayRequest {\n type: 'relay:request';\n requestId: string;\n providerId: string;\n url: string;\n method: string;\n headers: Record<string, string>;\n body?: string;\n}\n\nexport interface RelayResponseMeta {\n type: 'relay:response:meta';\n requestId: string;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n}\n\nexport interface RelayResponseChunk {\n type: 'relay:response:chunk';\n requestId: string;\n chunk: string;\n}\n\nexport interface RelayResponseDone {\n type: 'relay:response:done';\n requestId: string;\n}\n\nexport interface RelayResponseError {\n type: 'relay:response:error';\n requestId: string;\n error: { code: string; message: string };\n}\n\nexport interface RelayPing {\n type: 'relay:ping';\n ts: number;\n}\n\nexport interface RelayPong {\n type: 'relay:pong';\n ts: number;\n}\n\nexport interface RelayPairHello {\n type: 'relay:pair:hello';\n providers: Record<string, { available: boolean; authMethod: AuthMethod }>;\n}\n\nexport interface RelayPairAck {\n type: 'relay:pair:ack';\n}\n\nexport type RelayMessage =\n | RelayHello\n | RelayRequest\n | RelayResponseMeta\n | RelayResponseChunk\n | RelayResponseDone\n | RelayResponseError\n | RelayPing\n | RelayPong\n | RelayPairHello\n | RelayPairAck;\n\nconst MAX_RELAY_MESSAGE_SIZE = 1_048_576; // 1 MB\n\nexport function parseRelayMessage(data: unknown): RelayMessage | null {\n try {\n if (typeof data === 'string' && data.length > MAX_RELAY_MESSAGE_SIZE) return null;\n const raw = typeof data === 'string' ? JSON.parse(data) : data;\n if (!raw || typeof raw !== 'object' || typeof raw.type !== 'string' || !raw.type.startsWith('relay:')) {\n return null;\n }\n\n // Validate required fields per message type\n switch (raw.type) {\n case 'relay:hello':\n if (typeof raw.sessionId !== 'string') return null;\n break;\n case 'relay:request':\n if (typeof raw.requestId !== 'string' || typeof raw.providerId !== 'string' ||\n typeof raw.url !== 'string' || typeof raw.method !== 'string') return null;\n break;\n case 'relay:response:meta':\n if (typeof raw.requestId !== 'string' || typeof raw.status !== 'number') return null;\n break;\n case 'relay:response:chunk':\n if (typeof raw.requestId !== 'string' || typeof raw.chunk !== 'string') return null;\n break;\n case 'relay:response:done':\n if (typeof raw.requestId !== 'string') return null;\n break;\n case 'relay:response:error':\n if (typeof raw.requestId !== 'string') return null;\n if (raw.error && (typeof raw.error !== 'object' || typeof raw.error.code !== 'string' || typeof raw.error.message !== 'string')) return null;\n break;\n case 'relay:ping':\n case 'relay:pong':\n if (typeof raw.ts !== 'number') return null;\n break;\n case 'relay:pair:hello':\n if (!raw.providers || typeof raw.providers !== 'object') return null;\n break;\n case 'relay:pair:ack':\n break;\n default:\n return null;\n }\n\n return raw as RelayMessage;\n } catch {\n return null;\n }\n}\n\nexport function sendRelayMessage(ws: WebSocketLike, msg: RelayMessage): void {\n if (ws.readyState === WS_READY_STATE.OPEN) {\n ws.send(JSON.stringify(msg));\n }\n}\n","export interface PasswordStrength {\n score: 0 | 1 | 2 | 3 | 4;\n label: 'Too weak' | 'Weak' | 'Fair' | 'Strong' | 'Very strong';\n feedback: string[];\n}\n\nconst COMMON_PASSWORDS = new Set([\n 'password', '12345678', 'qwerty12', 'letmein12', 'welcome1',\n 'monkey12', 'dragon12', 'master12', 'abc12345', 'password1',\n 'password12', 'iloveyou1', 'sunshine1', 'trustno1', 'princess1',\n 'football1', 'shadow123', 'michael1', 'jordan123', 'superman1',\n 'password123', 'admin12345', 'letmein123', 'p@ssw0rd', 'p@ssw0rd1',\n 'qwerty1234', 'changeme12', 'welcome123', '1234567890', 'baseball1',\n 'starwars12', 'whatever1', 'passw0rd1', 'mustang12', 'access1234',\n 'charlie123', 'donald1234', 'maggie1234', 'master1234', 'michael123',\n 'jennifer1', 'hunter1234', 'thomas1234', 'corvette12', 'robert1234',\n 'summer1234', 'george1234', 'harley1234', 'cheese1234', 'computer1',\n 'internet1', 'secret1234', 'diamond1', 'chicken123', 'pepper1234',\n 'jessica123', 'hannah1234', 'ginger1234', 'joshua1234', 'abcdefgh1',\n 'qwertyuiop', 'asdfghjkl1', 'zxcvbnm123', '1q2w3e4r5t', 'passpass1',\n]);\n\nexport function checkPasswordStrength(password: string): PasswordStrength {\n const feedback: string[] = [];\n let score = 0;\n\n if (password.length < MIN_PASSWORD_LENGTH) {\n feedback.push('Use at least 12 characters');\n return { score: 0, label: 'Too weak', feedback };\n } else {\n score++;\n if (password.length >= 16) score++;\n }\n\n if (COMMON_PASSWORDS.has(password.toLowerCase())) {\n feedback.push('This is a commonly used password');\n return { score: 0, label: 'Too weak', feedback };\n }\n\n // Check character diversity\n const hasLower = /[a-z]/.test(password);\n const hasUpper = /[A-Z]/.test(password);\n const hasDigit = /\\d/.test(password);\n const hasSymbol = /[^a-zA-Z0-9]/.test(password);\n const charTypes = [hasLower, hasUpper, hasDigit, hasSymbol].filter(Boolean).length;\n\n if (charTypes < 2) {\n feedback.push('Mix uppercase, lowercase, numbers, and symbols');\n } else if (charTypes >= 3) {\n score++;\n }\n if (charTypes >= 4) {\n score++;\n }\n\n // Check for repeated characters (e.g. aaaaaa)\n if (/(.)\\1{3,}/.test(password)) {\n feedback.push('Avoid repeated characters');\n score = Math.max(0, score - 1);\n }\n\n // Check for sequential patterns (e.g. 123456, abcdef)\n if (/(?:012|123|234|345|456|567|678|789|abc|bcd|cde|def)/i.test(password)) {\n feedback.push('Avoid sequential patterns');\n score = Math.max(0, score - 1);\n }\n\n const capped = Math.min(4, Math.max(0, score)) as 0 | 1 | 2 | 3 | 4;\n const labels: Record<number, PasswordStrength['label']> = {\n 0: 'Too weak',\n 1: 'Weak',\n 2: 'Fair',\n 3: 'Strong',\n 4: 'Very strong',\n };\n\n if (feedback.length === 0 && capped < 3) {\n feedback.push('Add more character variety or length');\n }\n\n return { score: capped, label: labels[capped], feedback };\n}\n\nexport const MIN_PASSWORD_LENGTH = 12;\n","import type { RequestLogEntry, TokenAllowance } from './types.js';\nimport { PROVIDERS } from './providers.js';\n\n/**\n * Validate that a proxy request URL targets the registered provider's base URL.\n * Prevents API key exfiltration by rejecting requests to arbitrary domains.\n */\nexport function validateProxyUrl(providerId: string, url: string): boolean {\n const provider = PROVIDERS[providerId];\n if (!provider) return false;\n try {\n const target = new URL(url);\n if (target.protocol !== 'https:') return false;\n const base = new URL(provider.baseUrl);\n return target.origin === base.origin;\n } catch {\n return false;\n }\n}\n\n/**\n * Build the real auth headers for a provider API request.\n * Strips any fake session-key headers and injects the real API key.\n */\nexport function buildHeaders(\n providerId: string,\n requestHeaders: Record<string, string>,\n apiKey: string,\n authMethod: string = 'api_key',\n): Record<string, string> {\n // Normalize header keys to lowercase to prevent case-sensitive bypass\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(requestHeaders)) {\n headers[key.toLowerCase()] = value;\n }\n\n // Remove any auth headers the SDK might have set (they're fake session keys)\n delete headers['authorization'];\n delete headers['x-api-key'];\n delete headers['api-key'];\n\n // Strip browser/SDK headers that can trigger rejection from provider APIs\n delete headers['origin'];\n delete headers['referer'];\n // Remove SDK telemetry headers that leak the real client environment\n for (const key of Object.keys(headers)) {\n if (key.startsWith('x-stainless-')) delete headers[key];\n }\n delete headers['sec-fetch-mode'];\n delete headers['accept-language'];\n delete headers['accept-encoding'];\n // Always strip content-length — fetch() recalculates it from the actual body,\n // and the body may have been modified (e.g. system prompt injection)\n delete headers['content-length'];\n\n if (providerId === 'anthropic') {\n if (authMethod === 'oauth') {\n headers['authorization'] = `Bearer ${apiKey}`;\n headers['user-agent'] = 'claude-cli/2.1.76';\n headers['x-app'] = 'cli';\n headers['accept'] = 'application/json';\n headers['anthropic-beta'] = 'claude-code-20250219,oauth-2025-04-20,fine-grained-tool-streaming-2025-05-14,interleaved-thinking-2025-05-14';\n headers['anthropic-dangerous-direct-browser-access'] = 'true';\n } else {\n headers['x-api-key'] = apiKey;\n }\n headers['anthropic-version'] = headers['anthropic-version'] ?? '2023-06-01';\n } else if (providerId === 'azure_openai') {\n headers['api-key'] = apiKey;\n } else {\n headers['authorization'] = `Bearer ${apiKey}`;\n }\n\n return headers;\n}\n\n/**\n * Parse the model name from a request body (JSON).\n */\nconst MAX_BODY_PARSE_SIZE = 10_485_760; // 10 MB\n\nexport function parseModel(body?: string): string | undefined {\n if (!body || body.length > MAX_BODY_PARSE_SIZE) return undefined;\n try {\n const parsed = JSON.parse(body);\n return parsed.model ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Parse token usage from a provider API response body.\n * Handles both regular JSON responses and SSE streaming responses.\n */\nexport function parseUsage(\n providerId: string,\n body: string,\n): { inputTokens: number; outputTokens: number } | undefined {\n try {\n // For streaming responses (SSE), try to find usage in the last data chunk\n if (body.includes('data: ')) {\n const lines = body.split('\\n').filter((l) => l.startsWith('data: ') && !l.includes('[DONE]'));\n // Anthropic streaming: message_stop event has usage in a preceding message_delta\n // OpenAI streaming: last chunk may include usage\n for (let i = lines.length - 1; i >= 0; i--) {\n const json = lines[i].replace('data: ', '');\n try {\n const parsed = JSON.parse(json);\n const usage = extractUsageFromParsed(providerId, parsed);\n if (usage) return usage;\n } catch {\n continue;\n }\n }\n return undefined;\n }\n\n const parsed = JSON.parse(body);\n return extractUsageFromParsed(providerId, parsed);\n } catch {\n return undefined;\n }\n}\n\nfunction sanitizeTokenCounts(\n input: number,\n output: number,\n): { inputTokens: number; outputTokens: number } | undefined {\n const i = Math.max(0, Math.floor(input));\n const o = Math.max(0, Math.floor(output));\n if (!Number.isFinite(i) || !Number.isFinite(o)) return undefined;\n return { inputTokens: i, outputTokens: o };\n}\n\n/**\n * Extract token usage from a parsed provider response object.\n */\nexport function extractUsageFromParsed(\n providerId: string,\n parsed: Record<string, unknown>,\n): { inputTokens: number; outputTokens: number } | undefined {\n // Anthropic: { usage: { input_tokens, output_tokens } }\n if (providerId === 'anthropic') {\n const usage = parsed.usage as Record<string, number> | undefined;\n if (usage?.input_tokens != null && usage?.output_tokens != null) {\n return sanitizeTokenCounts(usage.input_tokens, usage.output_tokens);\n }\n }\n\n // Gemini: { usageMetadata: { promptTokenCount, candidatesTokenCount } }\n if (providerId === 'gemini') {\n const meta = parsed.usageMetadata as Record<string, number> | undefined;\n if (meta?.promptTokenCount != null) {\n return sanitizeTokenCounts(meta.promptTokenCount, meta.candidatesTokenCount ?? 0);\n }\n }\n\n // OpenAI-compatible (openai, groq, together, deepseek, xai, perplexity, fireworks, openrouter, mistral, azure_openai):\n // { usage: { prompt_tokens, completion_tokens } }\n const usage = parsed.usage as Record<string, number> | undefined;\n if (usage?.prompt_tokens != null && usage?.completion_tokens != null) {\n return sanitizeTokenCounts(usage.prompt_tokens, usage.completion_tokens);\n }\n\n return undefined;\n}\n\n/**\n * Check whether a request is allowed given token allowances and usage history.\n * Pure computation — no storage access.\n */\nexport function computeAllowanceCheck(\n allowance: TokenAllowance | undefined,\n entries: Pick<RequestLogEntry, 'providerId' | 'inputTokens' | 'outputTokens'>[],\n providerId: string,\n): { allowed: boolean; reason?: string } {\n if (!allowance) return { allowed: true };\n\n let totalUsed = 0;\n const byProvider: Record<string, number> = {};\n for (const entry of entries) {\n const tokens = (entry.inputTokens ?? 0) + (entry.outputTokens ?? 0);\n totalUsed += tokens;\n byProvider[entry.providerId] = (byProvider[entry.providerId] ?? 0) + tokens;\n }\n\n if (allowance.totalLimit != null && totalUsed >= allowance.totalLimit) {\n return { allowed: false, reason: `Token allowance exceeded for ${allowance.origin}` };\n }\n\n const providerLimit = allowance.providerLimits?.[providerId];\n if (providerLimit != null && (byProvider[providerId] ?? 0) >= providerLimit) {\n return { allowed: false, reason: `Token allowance for ${providerId} exceeded` };\n }\n\n return { allowed: true };\n}\n","import { PROVIDERS } from './providers.js';\n\n// --- Gift (sender side) ---\n\nexport interface Gift {\n id: string;\n credentialId: string;\n providerId: string;\n label: string;\n authToken: string;\n maxTokens: number;\n usedTokens: number;\n expiresAt: number;\n createdAt: number;\n active: boolean;\n relayUrl: string;\n}\n\n// --- Gift link (shareable payload) ---\n\nexport interface GiftLink {\n v: 1;\n id: string;\n p: string; // providerId\n n: string; // provider display name\n s: string; // sender label\n t: string; // auth token\n m: number; // max tokens\n e: number; // expires at (unix ms)\n r: string; // relay URL\n}\n\n// --- Gifted credential (recipient side) ---\n\nexport interface GiftedCredential {\n id: string;\n giftId: string;\n providerId: string;\n providerName: string;\n senderLabel: string;\n authToken: string;\n maxTokens: number;\n usedTokens: number;\n expiresAt: number;\n relayUrl: string;\n createdAt: number;\n}\n\n// --- Relay protocol ---\n\nexport interface RelayAuth {\n type: 'relay:auth';\n roomId: string;\n authToken: string;\n role: 'sender' | 'recipient';\n}\n\nexport interface RelayAuthResult {\n type: 'relay:auth:result';\n success: boolean;\n error?: string;\n peerOnline?: boolean;\n}\n\nexport interface RelayPeerStatus {\n type: 'relay:peer:status';\n online: boolean;\n}\n\nexport interface RelayUsageUpdate {\n type: 'relay:usage';\n roomId: string;\n usedTokens: number;\n}\n\nexport type RelayProtocolMessage =\n | RelayAuth\n | RelayAuthResult\n | RelayPeerStatus\n | RelayUsageUpdate;\n\n// --- Encoding / decoding ---\n\nexport function encodeGiftLink(link: GiftLink): string {\n const json = JSON.stringify(link);\n const bytes = new TextEncoder().encode(json);\n return base64UrlEncode(bytes);\n}\n\nconst MAX_GIFT_LINK_SIZE = 8_192; // 8 KB\n\nexport function decodeGiftLink(encoded: string): GiftLink | null {\n try {\n if (encoded.length > MAX_GIFT_LINK_SIZE) return null;\n const clean = encoded.replace(/^byoky:\\/\\/gift\\//, '');\n const bytes = base64UrlDecode(clean);\n const json = new TextDecoder().decode(bytes);\n const parsed = JSON.parse(json);\n if (parsed.v !== 1) return null;\n return parsed as GiftLink;\n } catch {\n return null;\n }\n}\n\nexport function giftLinkToUrl(encoded: string): string {\n return `byoky://gift/${encoded}`;\n}\n\n// --- Validation ---\n\nexport function validateGiftLink(link: GiftLink): { valid: boolean; reason?: string } {\n if (link.v !== 1) return { valid: false, reason: 'Unsupported gift version' };\n if (!link.id || typeof link.id !== 'string') return { valid: false, reason: 'Missing gift ID' };\n if (!link.p || typeof link.p !== 'string') return { valid: false, reason: 'Missing provider' };\n if (!link.t || typeof link.t !== 'string') return { valid: false, reason: 'Missing auth token' };\n if (!link.r || typeof link.r !== 'string') return { valid: false, reason: 'Missing relay URL' };\n if (typeof link.m !== 'number' || link.m <= 0) return { valid: false, reason: 'Invalid token budget' };\n if (typeof link.e !== 'number' || link.e <= Date.now()) return { valid: false, reason: 'Gift has expired' };\n\n try {\n const url = new URL(link.r);\n if (url.protocol !== 'ws:' && url.protocol !== 'wss:') {\n return { valid: false, reason: 'Relay URL must use ws:// or wss://' };\n }\n } catch {\n return { valid: false, reason: 'Invalid relay URL' };\n }\n\n return { valid: true };\n}\n\nexport function isGiftExpired(gift: { expiresAt: number }): boolean {\n return gift.expiresAt <= Date.now();\n}\n\nexport function isGiftBudgetExhausted(gift: { usedTokens: number; maxTokens: number }): boolean {\n return gift.usedTokens >= gift.maxTokens;\n}\n\nexport function giftBudgetRemaining(gift: { usedTokens: number; maxTokens: number }): number {\n return Math.max(0, gift.maxTokens - gift.usedTokens);\n}\n\nexport function giftBudgetPercent(gift: { usedTokens: number; maxTokens: number }): number {\n if (gift.maxTokens === 0) return 100;\n return Math.min(100, Math.round((gift.usedTokens / gift.maxTokens) * 100));\n}\n\nexport function createGiftLink(gift: Gift): { encoded: string; link: GiftLink } {\n const provider = PROVIDERS[gift.providerId];\n const link: GiftLink = {\n v: 1,\n id: gift.id,\n p: gift.providerId,\n n: provider?.name ?? gift.providerId,\n s: gift.label,\n t: gift.authToken,\n m: gift.maxTokens,\n e: gift.expiresAt,\n r: gift.relayUrl,\n };\n return { encoded: encodeGiftLink(link), link };\n}\n\n// --- Pairing payload (mobile wallet relay connect) ---\n\nexport interface PairPayload {\n v: 1;\n r: string; // relay URL (wss://...)\n id: string; // room ID\n t: string; // auth token\n o: string; // app origin\n}\n\nexport function encodePairPayload(payload: PairPayload): string {\n const json = JSON.stringify(payload);\n const bytes = new TextEncoder().encode(json);\n return base64UrlEncode(bytes);\n}\n\nexport function decodePairPayload(encoded: string): PairPayload | null {\n try {\n if (encoded.length > 2048) return null;\n const bytes = base64UrlDecode(encoded);\n const json = new TextDecoder().decode(bytes);\n const parsed = JSON.parse(json);\n if (parsed.v !== 1) return null;\n return parsed as PairPayload;\n } catch {\n return null;\n }\n}\n\n// --- Base64url helpers ---\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction base64UrlDecode(str: string): Uint8Array {\n const padded = str.replace(/-/g, '+').replace(/_/g, '/');\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n"],"mappings":"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","names":["ByokyErrorCode","parsed","usage"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byoky/core",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",