aisubs 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/auth.d.ts CHANGED
@@ -66,6 +66,8 @@ export declare class SubscriptionAuth {
66
66
  details(provider: ProviderId, account?: string, signal?: AbortSignal): Promise<SubscriptionAccountDetails>;
67
67
  fetch(provider: ProviderId, input: string | URL | Request, init?: RequestInit, account?: string): Promise<Response>;
68
68
  proxy(provider: ProviderId, account: string, path: string, init?: RequestInit): Promise<Response>;
69
+ /** Build an authorized direct-provider request for transports such as WebSocket. */
70
+ authorizeProxyRequest(provider: ProviderId, account: string, path: string, init?: RequestInit): Promise<Request>;
69
71
  getUsage(provider: ProviderId, account?: string, callerSignal?: AbortSignal): Promise<ProviderUsage | null>;
70
72
  getModels(provider: ProviderId, account?: string, callerSignal?: AbortSignal): Promise<ProviderModels | null>;
71
73
  account(provider: ProviderId, account: string): SubscriptionAccount;
package/dist/auth.js CHANGED
@@ -19,6 +19,11 @@ function normalizeAccountKey(value) {
19
19
  }
20
20
  return account;
21
21
  }
22
+ function createRequest(input, init) {
23
+ return new Request(input, init?.body instanceof ReadableStream
24
+ ? { ...init, duplex: "half" }
25
+ : init);
26
+ }
22
27
  function credentialKey(provider, accountKey) {
23
28
  if (accountKey === DEFAULT_ACCOUNT)
24
29
  return provider;
@@ -375,7 +380,7 @@ export class SubscriptionAuth {
375
380
  }
376
381
  async fetch(provider, input, init, account = DEFAULT_ACCOUNT) {
377
382
  const adapter = this.adapter(provider);
378
- const original = new Request(input, init);
383
+ const original = createRequest(input, init);
379
384
  const accountKey = normalizeAccountKey(account);
380
385
  const send = async (credential) => {
381
386
  const authorized = await adapter.authorize(original.clone(), credential);
@@ -400,7 +405,7 @@ export class SubscriptionAuth {
400
405
  const accountKey = normalizeAccountKey(account);
401
406
  const credential = await this.credential(provider, accountKey);
402
407
  if (adapter.proxy) {
403
- const local = new Request(`http://aisubs.local/${path.replace(/^\//, "")}`, init);
408
+ const local = createRequest(`http://aisubs.local/${path.replace(/^\//, "")}`, init);
404
409
  let response = await adapter.proxy(local.clone(), credential);
405
410
  if (response.status === 401) {
406
411
  await response.body?.cancel();
@@ -416,6 +421,22 @@ export class SubscriptionAuth {
416
421
  const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
417
422
  return this.fetch(provider, new URL(path, base), init, accountKey);
418
423
  }
424
+ /** Build an authorized direct-provider request for transports such as WebSocket. */
425
+ async authorizeProxyRequest(provider, account, path, init) {
426
+ const adapter = this.adapter(provider);
427
+ const accountKey = normalizeAccountKey(account);
428
+ if (adapter.proxy) {
429
+ throw new Error(`${provider} does not expose a direct transport endpoint`);
430
+ }
431
+ const credential = await this.credential(provider, accountKey);
432
+ const baseUrl = typeof adapter.proxyBaseUrl === "function"
433
+ ? adapter.proxyBaseUrl(credential)
434
+ : adapter.proxyBaseUrl;
435
+ if (!baseUrl)
436
+ throw new Error(`${provider} does not expose a direct API endpoint`);
437
+ const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
438
+ return adapter.authorize(createRequest(new URL(path, base), init), credential);
439
+ }
419
440
  async getUsage(provider, account = DEFAULT_ACCOUNT, callerSignal) {
420
441
  const adapter = this.adapter(provider);
421
442
  if (!adapter.getUsage)
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import { claudeProvider } from "./providers/claude.js";
8
8
  import { copilotProvider } from "./providers/copilot.js";
9
9
  import { grokProvider } from "./providers/grok.js";
10
10
  import { openCodeGoProvider, openCodeZenProvider } from "./providers/opencode.js";
11
- import { defaultAiSubsDataDir, FileCredentialStore } from "./store.js";
11
+ import { defaultAiSubsDataDir, FileApiKeyStore, FileCredentialStore } from "./store.js";
12
12
  const DEFAULT_DASHBOARD_PORT = 4319;
13
13
  function usage() {
14
14
  console.log(`AI Subs
@@ -62,6 +62,7 @@ async function main() {
62
62
  if (!Number.isInteger(port) || port < 0 || port > 65535)
63
63
  throw new Error("Invalid port");
64
64
  const store = new FileCredentialStore(join(dataDirectory, "credentials.json"));
65
+ const apiKeys = new FileApiKeyStore(join(dataDirectory, "api-key"));
65
66
  const auth = createSubscriptionAuth({
66
67
  store,
67
68
  providers: [
@@ -73,14 +74,16 @@ async function main() {
73
74
  openCodeZenProvider(),
74
75
  ],
75
76
  });
76
- const dashboard = await createSubscriptionAuthDashboardServer({ auth, port });
77
- console.log(`AI Subs is running at ${dashboard.url}`);
78
- console.log(`Credentials: ${store.file}`);
79
- console.log(`Control API key: ${dashboard.apiKey}`);
80
- console.log(`Dashboard link: ${dashboard.bootstrapUrl}`);
77
+ const dashboard = await createSubscriptionAuthDashboardServer({
78
+ auth,
79
+ apiKey: await apiKeys.readOrCreate(),
80
+ regenerateApiKey: () => apiKeys.regenerate(),
81
+ port,
82
+ });
83
+ console.log(`AI Subs is running at \u001b]8;;${dashboard.url}\u0007${dashboard.url}\u001b]8;;\u0007`);
81
84
  console.log("Press Ctrl+C to stop.");
82
85
  if (shouldOpen)
83
- openBrowser(dashboard.bootstrapUrl);
86
+ openBrowser(dashboard.url);
84
87
  let closing = false;
85
88
  const close = async () => {
86
89
  if (closing)
@@ -0,0 +1,14 @@
1
+ import type { SubscriptionAuth } from "./auth.js";
2
+ import type { ProviderId } from "./types.js";
3
+ export type WireProtocol = "responses" | "chat/completions" | "messages" | "google";
4
+ export declare class CompatibilityError extends Error {
5
+ readonly code: string;
6
+ readonly status: number;
7
+ constructor(message: string, code?: string, status?: number);
8
+ }
9
+ export declare function requestProtocol(path: string): {
10
+ protocol: WireProtocol;
11
+ model?: string;
12
+ stream?: boolean;
13
+ } | null;
14
+ export declare function proxyCompatible(auth: SubscriptionAuth, provider: ProviderId, account: string, path: string, body: Buffer, headers: Headers, signal?: AbortSignal): Promise<Response | null>;