@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 +92 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -16
- package/dist/index.d.ts +33 -16
- package/dist/index.js +90 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 <
|
|
515
|
+
if (password.length < MIN_PASSWORD_LENGTH) {
|
|
459
516
|
feedback.push("Use at least 12 characters");
|
|
460
|
-
|
|
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
|
|
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
|
|
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,
|
package/dist/index.cjs.map
CHANGED
|
@@ -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
|
-
|
|
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
|
|
361
|
-
type: '
|
|
362
|
-
|
|
368
|
+
interface RelayAuth {
|
|
369
|
+
type: 'relay:auth';
|
|
370
|
+
roomId: string;
|
|
363
371
|
authToken: string;
|
|
364
372
|
role: 'sender' | 'recipient';
|
|
365
373
|
}
|
|
366
|
-
interface
|
|
367
|
-
type: '
|
|
374
|
+
interface RelayAuthResult {
|
|
375
|
+
type: 'relay:auth:result';
|
|
368
376
|
success: boolean;
|
|
369
377
|
error?: string;
|
|
370
378
|
peerOnline?: boolean;
|
|
371
379
|
}
|
|
372
|
-
interface
|
|
373
|
-
type: '
|
|
380
|
+
interface RelayPeerStatus {
|
|
381
|
+
type: 'relay:peer:status';
|
|
374
382
|
online: boolean;
|
|
375
383
|
}
|
|
376
|
-
interface
|
|
377
|
-
type: '
|
|
378
|
-
|
|
384
|
+
interface RelayUsageUpdate {
|
|
385
|
+
type: 'relay:usage';
|
|
386
|
+
roomId: string;
|
|
379
387
|
usedTokens: number;
|
|
380
388
|
}
|
|
381
|
-
type
|
|
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
|
|
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
|
-
|
|
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
|
|
361
|
-
type: '
|
|
362
|
-
|
|
368
|
+
interface RelayAuth {
|
|
369
|
+
type: 'relay:auth';
|
|
370
|
+
roomId: string;
|
|
363
371
|
authToken: string;
|
|
364
372
|
role: 'sender' | 'recipient';
|
|
365
373
|
}
|
|
366
|
-
interface
|
|
367
|
-
type: '
|
|
374
|
+
interface RelayAuthResult {
|
|
375
|
+
type: 'relay:auth:result';
|
|
368
376
|
success: boolean;
|
|
369
377
|
error?: string;
|
|
370
378
|
peerOnline?: boolean;
|
|
371
379
|
}
|
|
372
|
-
interface
|
|
373
|
-
type: '
|
|
380
|
+
interface RelayPeerStatus {
|
|
381
|
+
type: 'relay:peer:status';
|
|
374
382
|
online: boolean;
|
|
375
383
|
}
|
|
376
|
-
interface
|
|
377
|
-
type: '
|
|
378
|
-
|
|
384
|
+
interface RelayUsageUpdate {
|
|
385
|
+
type: 'relay:usage';
|
|
386
|
+
roomId: string;
|
|
379
387
|
usedTokens: number;
|
|
380
388
|
}
|
|
381
|
-
type
|
|
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
|
|
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 <
|
|
450
|
+
if (password.length < MIN_PASSWORD_LENGTH) {
|
|
396
451
|
feedback.push("Use at least 12 characters");
|
|
397
|
-
|
|
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
|
|
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
|
|
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":"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","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"]}
|