@byoky/core 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +469 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +238 -2
- package/dist/index.d.ts +238 -2
- package/dist/index.js +449 -2
- package/dist/index.js.map +1 -1
- package/package.json +20 -9
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ interface OAuthConfig {
|
|
|
12
12
|
authorizationUrl: string;
|
|
13
13
|
tokenUrl: string;
|
|
14
14
|
scopes: string[];
|
|
15
|
+
extraAuthParams?: Record<string, string>;
|
|
15
16
|
}
|
|
16
17
|
interface CredentialBase {
|
|
17
18
|
id: string;
|
|
@@ -55,6 +56,9 @@ interface SessionProvider {
|
|
|
55
56
|
credentialId: string;
|
|
56
57
|
available: boolean;
|
|
57
58
|
authMethod: AuthMethod;
|
|
59
|
+
giftId?: string;
|
|
60
|
+
giftRelayUrl?: string;
|
|
61
|
+
giftAuthToken?: string;
|
|
58
62
|
}
|
|
59
63
|
interface ConnectRequest {
|
|
60
64
|
providers?: ProviderRequirement[];
|
|
@@ -99,13 +103,23 @@ interface ProxyResponseError {
|
|
|
99
103
|
message: string;
|
|
100
104
|
};
|
|
101
105
|
}
|
|
102
|
-
type MessageType = 'BYOKY_CONNECT_REQUEST' | 'BYOKY_CONNECT_RESPONSE' | 'BYOKY_DISCONNECT' | 'BYOKY_PROXY_REQUEST' | 'BYOKY_PROXY_RESPONSE_META' | 'BYOKY_PROXY_RESPONSE_CHUNK' | 'BYOKY_PROXY_RESPONSE_DONE' | 'BYOKY_PROXY_RESPONSE_ERROR' | 'BYOKY_ERROR';
|
|
106
|
+
type MessageType = 'BYOKY_CONNECT_REQUEST' | 'BYOKY_CONNECT_RESPONSE' | 'BYOKY_DISCONNECT' | 'BYOKY_PROXY_REQUEST' | 'BYOKY_PROXY_RESPONSE_META' | 'BYOKY_PROXY_RESPONSE_CHUNK' | 'BYOKY_PROXY_RESPONSE_DONE' | 'BYOKY_PROXY_RESPONSE_ERROR' | 'BYOKY_SESSION_STATUS' | 'BYOKY_SESSION_STATUS_RESPONSE' | 'BYOKY_SESSION_USAGE' | 'BYOKY_SESSION_USAGE_RESPONSE' | 'BYOKY_SESSION_REVOKED' | 'BYOKY_ERROR';
|
|
103
107
|
interface ByokyMessage {
|
|
104
108
|
type: MessageType;
|
|
105
109
|
id: string;
|
|
106
110
|
requestId?: string;
|
|
107
111
|
payload: unknown;
|
|
108
112
|
}
|
|
113
|
+
interface SessionUsage {
|
|
114
|
+
requests: number;
|
|
115
|
+
inputTokens: number;
|
|
116
|
+
outputTokens: number;
|
|
117
|
+
byProvider: Record<string, {
|
|
118
|
+
requests: number;
|
|
119
|
+
inputTokens: number;
|
|
120
|
+
outputTokens: number;
|
|
121
|
+
}>;
|
|
122
|
+
}
|
|
109
123
|
declare enum ByokyErrorCode {
|
|
110
124
|
WALLET_NOT_INSTALLED = "WALLET_NOT_INSTALLED",
|
|
111
125
|
USER_REJECTED = "USER_REJECTED",
|
|
@@ -116,6 +130,8 @@ declare enum ByokyErrorCode {
|
|
|
116
130
|
INVALID_KEY = "INVALID_KEY",
|
|
117
131
|
TOKEN_EXPIRED = "TOKEN_EXPIRED",
|
|
118
132
|
PROXY_ERROR = "PROXY_ERROR",
|
|
133
|
+
RELAY_CONNECTION_FAILED = "RELAY_CONNECTION_FAILED",
|
|
134
|
+
RELAY_DISCONNECTED = "RELAY_DISCONNECTED",
|
|
119
135
|
UNKNOWN = "UNKNOWN"
|
|
120
136
|
}
|
|
121
137
|
interface RequestLogEntry {
|
|
@@ -128,6 +144,9 @@ interface RequestLogEntry {
|
|
|
128
144
|
status: number;
|
|
129
145
|
timestamp: number;
|
|
130
146
|
error?: string;
|
|
147
|
+
inputTokens?: number;
|
|
148
|
+
outputTokens?: number;
|
|
149
|
+
model?: string;
|
|
131
150
|
}
|
|
132
151
|
interface PendingApproval {
|
|
133
152
|
id: string;
|
|
@@ -136,6 +155,15 @@ interface PendingApproval {
|
|
|
136
155
|
providers: ProviderRequirement[];
|
|
137
156
|
timestamp: number;
|
|
138
157
|
}
|
|
158
|
+
interface TrustedSite {
|
|
159
|
+
origin: string;
|
|
160
|
+
trustedAt: number;
|
|
161
|
+
}
|
|
162
|
+
interface TokenAllowance {
|
|
163
|
+
origin: string;
|
|
164
|
+
totalLimit?: number;
|
|
165
|
+
providerLimits?: Record<string, number>;
|
|
166
|
+
}
|
|
139
167
|
|
|
140
168
|
declare function deriveKey(password: string, salt: Uint8Array): Promise<CryptoKey>;
|
|
141
169
|
declare function encrypt(plaintext: string, password: string): Promise<string>;
|
|
@@ -156,6 +184,8 @@ declare class ByokyError extends Error {
|
|
|
156
184
|
static quotaExceeded(providerId: string): ByokyError;
|
|
157
185
|
static invalidKey(providerId: string): ByokyError;
|
|
158
186
|
static tokenExpired(providerId: string): ByokyError;
|
|
187
|
+
static relayConnectionFailed(reason?: string): ByokyError;
|
|
188
|
+
static relayDisconnected(): ByokyError;
|
|
159
189
|
}
|
|
160
190
|
|
|
161
191
|
declare const BYOKY_PROVIDER_KEY = "__byoky__";
|
|
@@ -170,4 +200,210 @@ declare const PROVIDERS: Record<string, ProviderConfig>;
|
|
|
170
200
|
declare function getProvider(id: string): ProviderConfig | undefined;
|
|
171
201
|
declare function getProviderIds(): string[];
|
|
172
202
|
|
|
173
|
-
|
|
203
|
+
/** Minimal WebSocket interface — compatible with browser WebSocket and `ws` library. */
|
|
204
|
+
interface WebSocketLike {
|
|
205
|
+
readonly readyState: number;
|
|
206
|
+
send(data: string): void;
|
|
207
|
+
close(code?: number, reason?: string): void;
|
|
208
|
+
onopen: ((event: unknown) => void) | null;
|
|
209
|
+
onmessage: ((event: {
|
|
210
|
+
data: unknown;
|
|
211
|
+
}) => void) | null;
|
|
212
|
+
onclose: ((event: {
|
|
213
|
+
code: number;
|
|
214
|
+
reason: string;
|
|
215
|
+
}) => void) | null;
|
|
216
|
+
onerror: ((event: unknown) => void) | null;
|
|
217
|
+
}
|
|
218
|
+
declare const WS_READY_STATE: {
|
|
219
|
+
readonly CONNECTING: 0;
|
|
220
|
+
readonly OPEN: 1;
|
|
221
|
+
readonly CLOSING: 2;
|
|
222
|
+
readonly CLOSED: 3;
|
|
223
|
+
};
|
|
224
|
+
interface RelayHello {
|
|
225
|
+
type: 'relay:hello';
|
|
226
|
+
sessionId: string;
|
|
227
|
+
providers: Record<string, {
|
|
228
|
+
available: boolean;
|
|
229
|
+
authMethod: AuthMethod;
|
|
230
|
+
}>;
|
|
231
|
+
}
|
|
232
|
+
interface RelayRequest {
|
|
233
|
+
type: 'relay:request';
|
|
234
|
+
requestId: string;
|
|
235
|
+
providerId: string;
|
|
236
|
+
url: string;
|
|
237
|
+
method: string;
|
|
238
|
+
headers: Record<string, string>;
|
|
239
|
+
body?: string;
|
|
240
|
+
}
|
|
241
|
+
interface RelayResponseMeta {
|
|
242
|
+
type: 'relay:response:meta';
|
|
243
|
+
requestId: string;
|
|
244
|
+
status: number;
|
|
245
|
+
statusText: string;
|
|
246
|
+
headers: Record<string, string>;
|
|
247
|
+
}
|
|
248
|
+
interface RelayResponseChunk {
|
|
249
|
+
type: 'relay:response:chunk';
|
|
250
|
+
requestId: string;
|
|
251
|
+
chunk: string;
|
|
252
|
+
}
|
|
253
|
+
interface RelayResponseDone {
|
|
254
|
+
type: 'relay:response:done';
|
|
255
|
+
requestId: string;
|
|
256
|
+
}
|
|
257
|
+
interface RelayResponseError {
|
|
258
|
+
type: 'relay:response:error';
|
|
259
|
+
requestId: string;
|
|
260
|
+
error: {
|
|
261
|
+
code: string;
|
|
262
|
+
message: string;
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
interface RelayPing {
|
|
266
|
+
type: 'relay:ping';
|
|
267
|
+
ts: number;
|
|
268
|
+
}
|
|
269
|
+
interface RelayPong {
|
|
270
|
+
type: 'relay:pong';
|
|
271
|
+
ts: number;
|
|
272
|
+
}
|
|
273
|
+
type RelayMessage = RelayHello | RelayRequest | RelayResponseMeta | RelayResponseChunk | RelayResponseDone | RelayResponseError | RelayPing | RelayPong;
|
|
274
|
+
declare function parseRelayMessage(data: unknown): RelayMessage | null;
|
|
275
|
+
declare function sendRelayMessage(ws: WebSocketLike, msg: RelayMessage): void;
|
|
276
|
+
|
|
277
|
+
interface PasswordStrength {
|
|
278
|
+
score: 0 | 1 | 2 | 3 | 4;
|
|
279
|
+
label: 'Too weak' | 'Weak' | 'Fair' | 'Strong' | 'Very strong';
|
|
280
|
+
feedback: string[];
|
|
281
|
+
}
|
|
282
|
+
declare function checkPasswordStrength(password: string): PasswordStrength;
|
|
283
|
+
declare const MIN_PASSWORD_LENGTH = 12;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Validate that a proxy request URL targets the registered provider's base URL.
|
|
287
|
+
* Prevents API key exfiltration by rejecting requests to arbitrary domains.
|
|
288
|
+
*/
|
|
289
|
+
declare function validateProxyUrl(providerId: string, url: string): boolean;
|
|
290
|
+
/**
|
|
291
|
+
* Build the real auth headers for a provider API request.
|
|
292
|
+
* Strips any fake session-key headers and injects the real API key.
|
|
293
|
+
*/
|
|
294
|
+
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
|
+
declare function parseModel(body?: string): string | undefined;
|
|
299
|
+
/**
|
|
300
|
+
* Parse token usage from a provider API response body.
|
|
301
|
+
* Handles both regular JSON responses and SSE streaming responses.
|
|
302
|
+
*/
|
|
303
|
+
declare function parseUsage(providerId: string, body: string): {
|
|
304
|
+
inputTokens: number;
|
|
305
|
+
outputTokens: number;
|
|
306
|
+
} | undefined;
|
|
307
|
+
/**
|
|
308
|
+
* Extract token usage from a parsed provider response object.
|
|
309
|
+
*/
|
|
310
|
+
declare function extractUsageFromParsed(providerId: string, parsed: Record<string, unknown>): {
|
|
311
|
+
inputTokens: number;
|
|
312
|
+
outputTokens: number;
|
|
313
|
+
} | undefined;
|
|
314
|
+
/**
|
|
315
|
+
* Check whether a request is allowed given token allowances and usage history.
|
|
316
|
+
* Pure computation — no storage access.
|
|
317
|
+
*/
|
|
318
|
+
declare function computeAllowanceCheck(allowance: TokenAllowance | undefined, entries: Pick<RequestLogEntry, 'providerId' | 'inputTokens' | 'outputTokens'>[], providerId: string): {
|
|
319
|
+
allowed: boolean;
|
|
320
|
+
reason?: string;
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
interface Gift {
|
|
324
|
+
id: string;
|
|
325
|
+
credentialId: string;
|
|
326
|
+
providerId: string;
|
|
327
|
+
label: string;
|
|
328
|
+
authToken: string;
|
|
329
|
+
maxTokens: number;
|
|
330
|
+
usedTokens: number;
|
|
331
|
+
expiresAt: number;
|
|
332
|
+
createdAt: number;
|
|
333
|
+
active: boolean;
|
|
334
|
+
relayUrl: string;
|
|
335
|
+
}
|
|
336
|
+
interface GiftLink {
|
|
337
|
+
v: 1;
|
|
338
|
+
id: string;
|
|
339
|
+
p: string;
|
|
340
|
+
n: string;
|
|
341
|
+
s: string;
|
|
342
|
+
t: string;
|
|
343
|
+
m: number;
|
|
344
|
+
e: number;
|
|
345
|
+
r: string;
|
|
346
|
+
}
|
|
347
|
+
interface GiftedCredential {
|
|
348
|
+
id: string;
|
|
349
|
+
giftId: string;
|
|
350
|
+
providerId: string;
|
|
351
|
+
providerName: string;
|
|
352
|
+
senderLabel: string;
|
|
353
|
+
authToken: string;
|
|
354
|
+
maxTokens: number;
|
|
355
|
+
usedTokens: number;
|
|
356
|
+
expiresAt: number;
|
|
357
|
+
relayUrl: string;
|
|
358
|
+
createdAt: number;
|
|
359
|
+
}
|
|
360
|
+
interface GiftRelayAuth {
|
|
361
|
+
type: 'gift:auth';
|
|
362
|
+
giftId: string;
|
|
363
|
+
authToken: string;
|
|
364
|
+
role: 'sender' | 'recipient';
|
|
365
|
+
}
|
|
366
|
+
interface GiftRelayAuthResult {
|
|
367
|
+
type: 'gift:auth:result';
|
|
368
|
+
success: boolean;
|
|
369
|
+
error?: string;
|
|
370
|
+
peerOnline?: boolean;
|
|
371
|
+
}
|
|
372
|
+
interface GiftRelayPeerStatus {
|
|
373
|
+
type: 'gift:peer:status';
|
|
374
|
+
online: boolean;
|
|
375
|
+
}
|
|
376
|
+
interface GiftRelayUsageUpdate {
|
|
377
|
+
type: 'gift:usage';
|
|
378
|
+
giftId: string;
|
|
379
|
+
usedTokens: number;
|
|
380
|
+
}
|
|
381
|
+
type GiftRelayMessage = GiftRelayAuth | GiftRelayAuthResult | GiftRelayPeerStatus | GiftRelayUsageUpdate;
|
|
382
|
+
declare function encodeGiftLink(link: GiftLink): string;
|
|
383
|
+
declare function decodeGiftLink(encoded: string): GiftLink | null;
|
|
384
|
+
declare function giftLinkToUrl(encoded: string): string;
|
|
385
|
+
declare function validateGiftLink(link: GiftLink): {
|
|
386
|
+
valid: boolean;
|
|
387
|
+
reason?: string;
|
|
388
|
+
};
|
|
389
|
+
declare function isGiftExpired(gift: {
|
|
390
|
+
expiresAt: number;
|
|
391
|
+
}): boolean;
|
|
392
|
+
declare function isGiftBudgetExhausted(gift: {
|
|
393
|
+
usedTokens: number;
|
|
394
|
+
maxTokens: number;
|
|
395
|
+
}): boolean;
|
|
396
|
+
declare function giftBudgetRemaining(gift: {
|
|
397
|
+
usedTokens: number;
|
|
398
|
+
maxTokens: number;
|
|
399
|
+
}): number;
|
|
400
|
+
declare function giftBudgetPercent(gift: {
|
|
401
|
+
usedTokens: number;
|
|
402
|
+
maxTokens: number;
|
|
403
|
+
}): number;
|
|
404
|
+
declare function createGiftLink(gift: Gift): {
|
|
405
|
+
encoded: string;
|
|
406
|
+
link: GiftLink;
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
export { type ApiKeyCredential, type AuthMethod, BYOKY_MESSAGE_PREFIX, BYOKY_PROVIDER_KEY, ByokyError, ByokyErrorCode, type ByokyMessage, type ConnectRequest, type ConnectResponse, type Credential, type CredentialBase, type CredentialMeta, type Gift, type GiftLink, type GiftRelayAuth, type GiftRelayAuthResult, type GiftRelayMessage, type GiftRelayPeerStatus, type GiftRelayUsageUpdate, type GiftedCredential, MIN_PASSWORD_LENGTH, type MessageType, type OAuthConfig, type OAuthCredential, PROVIDERS, type PasswordStrength, type PendingApproval, type ProviderConfig, type ProviderId, type ProviderRequirement, type ProxyRequest, type ProxyResponseChunk, type ProxyResponseError, type ProxyResponseMeta, type RelayHello, type RelayMessage, type RelayPing, type RelayPong, type RelayRequest, type RelayResponseChunk, type RelayResponseDone, type RelayResponseError, type RelayResponseMeta, type RequestLogEntry, type Session, type SessionProvider, type SessionUsage, type TokenAllowance, type TrustedSite, WS_READY_STATE, type WebSocketLike, buildHeaders, checkPasswordStrength, computeAllowanceCheck, createConnectRequest, createConnectResponse, createErrorMessage, createGiftLink, createMessage, decodeGiftLink, decrypt, deriveKey, encodeGiftLink, encrypt, extractUsageFromParsed, getProvider, getProviderIds, giftBudgetPercent, giftBudgetRemaining, giftLinkToUrl, hashPassword, isByokyMessage, isGiftBudgetExhausted, isGiftExpired, maskKey, parseModel, parseRelayMessage, parseUsage, sendRelayMessage, validateGiftLink, validateProxyUrl, verifyPassword };
|