aisubs 0.2.0 → 0.3.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/CHANGELOG.md +29 -0
- package/README.md +177 -46
- package/dist/account-key.js +1 -1
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +21 -4
- package/dist/compatibility.d.ts +14 -0
- package/dist/compatibility.js +1515 -0
- package/dist/dashboard/assets/index-BJDbjHnw.css +2 -0
- package/dist/dashboard/assets/index-DJBtdmoj.js +84 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard.d.ts +4 -2
- package/dist/dashboard.js +209 -88
- package/dist/http.d.ts +9 -6
- package/dist/http.js +374 -278
- package/dist/providers/chatgpt.js +2 -0
- package/dist/providers/claude.js +2 -0
- package/dist/providers/copilot.js +20 -2
- package/dist/providers/grok.js +2 -2
- package/dist/realtime.d.ts +6 -0
- package/dist/realtime.js +165 -0
- package/dist/store.js +27 -1
- package/dist/usage.js +1 -1
- package/examples/direct.mjs +31 -8
- package/examples/server.mjs +11 -1
- package/package.json +11 -1
- package/public/aisubs-dashboard.png +0 -0
- package/scripts/codex-catalog.mjs +203 -0
- package/dist/dashboard/assets/index-DYe3pr2a.css +0 -2
- package/dist/dashboard/assets/index-V-AoOW2F.js +0 -83
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.3.1 - 2026-08-20
|
|
4
|
+
|
|
5
|
+
- Add dashboard-managed Codex Desktop integration with callable model discovery,
|
|
6
|
+
`provider/model` routing, and an option to restore the official Codex provider.
|
|
7
|
+
- Harden concurrent token refresh, reauthentication account selection, credential
|
|
8
|
+
file validation, Realtime startup, and development-server shutdown behavior.
|
|
9
|
+
- Fix stale dashboard data, failed-action feedback, provider-specific examples,
|
|
10
|
+
Codex configuration errors, model deduplication, and protocol compatibility
|
|
11
|
+
edge cases.
|
|
12
|
+
- Remove redundant tests and unsafe internal type erasure while retaining focused
|
|
13
|
+
regression coverage for the corrected behavior.
|
|
14
|
+
|
|
15
|
+
## 0.3.0 - 2026-08-16
|
|
16
|
+
|
|
17
|
+
- Add a universal OpenAI-compatible Chat Completions surface with translation
|
|
18
|
+
to supported native Responses, Anthropic Messages, and Google
|
|
19
|
+
`generateContent` endpoints.
|
|
20
|
+
- Add native OpenAI Realtime WebSocket tunnelling and account-scoped model
|
|
21
|
+
discovery with capability metadata.
|
|
22
|
+
- Add Claude, OpenCode Go, and OpenCode Zen to the dashboard and examples;
|
|
23
|
+
improve provider model metadata and usage reporting.
|
|
24
|
+
- Document desktop-client and SDK setup, local-key handling, compatibility
|
|
25
|
+
behavior, and cross-protocol streaming limits.
|
|
26
|
+
|
|
27
|
+
## 0.2.0 - 2026-08-15
|
|
28
|
+
|
|
29
|
+
- Previous release.
|
package/README.md
CHANGED
|
@@ -6,13 +6,27 @@
|
|
|
6
6
|
</table>
|
|
7
7
|
|
|
8
8
|
AISubs connects provider accounts once and exposes each account through a local,
|
|
9
|
-
account-scoped API.
|
|
10
|
-
|
|
9
|
+
account-scoped API. Every generative account has an OpenAI-compatible surface,
|
|
10
|
+
while native Responses, Anthropic Messages, Google `generateContent`, Realtime,
|
|
11
|
+
and provider-specific endpoints remain available. Use it from an SDK, cURL, or
|
|
12
|
+
an app that accepts a custom API base URL.
|
|
11
13
|
|
|
12
14
|
<p align="center">
|
|
13
15
|
<img src="./public/aisubs-dashboard.png" alt="AI Subs dashboard with provider connections and local API access" width="100%" />
|
|
14
16
|
</p>
|
|
15
17
|
|
|
18
|
+
<p align="center">
|
|
19
|
+
<img src="./public/aisubs-chatgpt-account.png" alt="AISubs ChatGPT demo account details" width="100%" />
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
<img src="./public/aisubs-copilot-account.png" alt="AISubs GitHub Copilot demo account details" width="100%" />
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
<p align="center">
|
|
27
|
+
<img src="./public/aisubs-grok-account.png" alt="AISubs Grok demo account details" width="100%" />
|
|
28
|
+
</p>
|
|
29
|
+
|
|
16
30
|
> Credentials, API keys, and requests remain on your computer. AISubs collects no
|
|
17
31
|
> telemetry or analytics. The dashboard keeps up to 200 redacted account request logs in memory for debugging.
|
|
18
32
|
|
|
@@ -35,6 +49,11 @@ key: reveal it, copy it, or deliberately regenerate it there.
|
|
|
35
49
|
The default URL is `http://127.0.0.1:4319`. Credentials and the API key are stored
|
|
36
50
|
under `~/.aisubs` and reused on later starts.
|
|
37
51
|
|
|
52
|
+
Supported subscription/account providers are ChatGPT, Claude, GitHub Copilot,
|
|
53
|
+
Grok, OpenCode Go, and OpenCode Zen. Google `generateContent` is a supported
|
|
54
|
+
wire protocol only for Google models surfaced by one of those connected
|
|
55
|
+
providers; AISubs does not connect or claim a Google subscription account.
|
|
56
|
+
|
|
38
57
|
## Use an account from any compatible app
|
|
39
58
|
|
|
40
59
|
Open an account in the dashboard and copy its base URL:
|
|
@@ -61,37 +80,128 @@ export OPENAI_API_KEY="aisubs_..."
|
|
|
61
80
|
AISubs removes its local key before forwarding a request and adds only the
|
|
62
81
|
selected account's provider credential.
|
|
63
82
|
|
|
64
|
-
|
|
83
|
+
## Desktop app examples
|
|
84
|
+
|
|
85
|
+
Keep AISubs running, then give the app the three values from the connected
|
|
86
|
+
account: its base URL, the AISubs API key, and an exact model ID.
|
|
87
|
+
|
|
88
|
+
### [Handy](https://handy.computer/download) (macOS)
|
|
89
|
+
|
|
90
|
+
Open **Post Process** and set:
|
|
91
|
+
|
|
92
|
+
| Handy field | Value |
|
|
93
|
+
| ----------- | -------------------------------------------------------- |
|
|
94
|
+
| Provider | `Custom` |
|
|
95
|
+
| Base URL | `http://127.0.0.1:4319/aisubs/chatgpt/default/v1` |
|
|
96
|
+
| API Key | Your `aisubs_...` key from the AISubs dashboard |
|
|
97
|
+
| Model | An exact Dashboard model ID, for example `gpt-5.6-terra` |
|
|
98
|
+
|
|
99
|
+
Click Handy’s refresh button beside **Model**, select the model, then choose a
|
|
100
|
+
prompt and test it. Replace `chatgpt/default` with the provider and account
|
|
101
|
+
segment copied from your AISubs dashboard when using a different account.
|
|
102
|
+
|
|
103
|
+
### [Raycast](https://www.raycast.com/download) AI custom provider
|
|
104
|
+
|
|
105
|
+
Create or edit `~/.config/raycast/ai/providers.yaml` and add a provider like
|
|
106
|
+
this. Keep the API key private—use the value from your AISubs dashboard, never
|
|
107
|
+
one copied from an example or screenshot.
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
providers:
|
|
111
|
+
- id: ai-subs
|
|
112
|
+
name: AI Subs
|
|
113
|
+
base_url: http://127.0.0.1:4319/aisubs/chatgpt/default/v1
|
|
114
|
+
api_keys:
|
|
115
|
+
default: aisubs_REPLACE_WITH_YOUR_DASHBOARD_KEY
|
|
116
|
+
models:
|
|
117
|
+
- id: gpt-5.6-terra
|
|
118
|
+
name: AISubs GPT-5.6 Terra
|
|
119
|
+
context: 272000
|
|
120
|
+
description: ChatGPT subscription via AISubs
|
|
121
|
+
abilities:
|
|
122
|
+
vision:
|
|
123
|
+
supported: true
|
|
124
|
+
system_message:
|
|
125
|
+
supported: true
|
|
126
|
+
tools:
|
|
127
|
+
supported: true
|
|
128
|
+
reasoning_effort:
|
|
129
|
+
supported: true
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Restart Raycast after saving. Replace the base URL, model ID, context, and
|
|
133
|
+
abilities with the values shown for your connected account. Do not enable an
|
|
134
|
+
ability that the selected model does not report.
|
|
135
|
+
|
|
136
|
+
[Cline](https://cline.bot/) also accepts a custom OpenAI-compatible endpoint;
|
|
137
|
+
use the same base URL, local AISubs key, and model ID. Exact settings labels can
|
|
138
|
+
change between client releases, so the account dashboard remains the source of
|
|
139
|
+
truth for the three values.
|
|
140
|
+
|
|
141
|
+
### Codex Desktop
|
|
142
|
+
|
|
143
|
+
AISubs can make callable models from connected non-ChatGPT accounts available in
|
|
144
|
+
Codex Desktop through one local Responses endpoint. Keep AISubs running, connect
|
|
145
|
+
the accounts you want to use, then:
|
|
146
|
+
|
|
147
|
+
1. Open **Configure Codex** on the AISubs dashboard.
|
|
148
|
+
2. Choose **Use AISubs models in Codex**.
|
|
149
|
+
3. Fully restart Codex Desktop.
|
|
150
|
+
4. Select a model named `provider/model`, such as `copilot/MODEL_ID`.
|
|
151
|
+
|
|
152
|
+
Configuration writes `~/.codex/aisubs-catalog.json` and updates the root settings,
|
|
153
|
+
AISubs provider, and `AISUBS_API_KEY` entry in `~/.codex/config.toml`. Both files
|
|
154
|
+
are created with user-private permissions when they do not already exist. The key
|
|
155
|
+
is stored in that Codex config so Codex can authenticate to the localhost AISubs
|
|
156
|
+
server; do not share the file.
|
|
157
|
+
|
|
158
|
+
The generated catalog intentionally excludes ChatGPT models so Codex continues to
|
|
159
|
+
treat official OpenAI models as native when official mode is active. Choose
|
|
160
|
+
**Restore official Codex models** in the same dialog, then restart Codex Desktop,
|
|
161
|
+
to remove the AISubs provider and catalog selection. AISubs saves the pre-restore
|
|
162
|
+
config as `~/.codex/config.toml.aisubs-backup` if that backup does not already
|
|
163
|
+
exist.
|
|
164
|
+
|
|
165
|
+
If multiple connected accounts expose the same `provider/model`, the router uses
|
|
166
|
+
the first connected account that reports it. Regenerating the AISubs API key
|
|
167
|
+
invalidates the old Codex configuration; run **Configure Codex** again and restart
|
|
168
|
+
Codex Desktop. Configuration refuses to overwrite the catalog when no callable
|
|
169
|
+
non-ChatGPT model can be discovered.
|
|
65
170
|
|
|
66
|
-
|
|
67
|
-
provides a focused, non-streaming text Chat Completions adapter for ChatGPT
|
|
68
|
-
accounts so apps such as [Handy](https://github.com/cjpais/Handy) can use them.
|
|
69
|
-
|
|
70
|
-
| Provider/model protocol | Base URL | Supported request path |
|
|
71
|
-
| ---------------------------------- | --------------------------- | --------------------------------------- |
|
|
72
|
-
| OpenAI Responses | Account URL ending in `/v1` | `POST /responses` |
|
|
73
|
-
| OpenAI-compatible Chat Completions | Account URL ending in `/v1` | `POST /chat/completions` |
|
|
74
|
-
| Anthropic Messages | Account URL ending in `/v1` | `POST /messages` |
|
|
75
|
-
| Google generateContent | Account URL ending in `/v1` | `POST /models/MODEL_ID:generateContent` |
|
|
76
|
-
| Model discovery | Account URL ending in `/v1` | `GET /models` |
|
|
77
|
-
|
|
78
|
-
Embeddings are intentionally not exposed. The ChatGPT compatibility adapter
|
|
79
|
-
supports text messages and JSON-schema response formats; tools, images, audio,
|
|
80
|
-
and streaming Chat Completions remain native-Responses-only features.
|
|
81
|
-
|
|
82
|
-
### Handy
|
|
83
|
-
|
|
84
|
-
Choose **Custom** in Handy and copy these values from the ChatGPT account page:
|
|
85
|
-
|
|
86
|
-
```text
|
|
87
|
-
Base URL: http://127.0.0.1:4319/aisubs/chatgpt/ACCOUNT/v1
|
|
88
|
-
API key: the persistent key shown on the AISubs dashboard
|
|
89
|
-
Model: an exact model ID shown for the account
|
|
90
|
-
```
|
|
171
|
+
### Compatibility contract
|
|
91
172
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
173
|
+
Use Chat Completions when an app offers only an “OpenAI-compatible” provider.
|
|
174
|
+
AISubs discovers the selected model's native protocol and translates the
|
|
175
|
+
request and response when necessary. Calling a model's native protocol remains
|
|
176
|
+
a pass-through, which preserves provider-specific fields and streaming events.
|
|
177
|
+
|
|
178
|
+
| Integration path | Example full URL | Request example |
|
|
179
|
+
| ---------------------------------- | -------------------------------------------------------------------------------------- | --------------------------------------- |
|
|
180
|
+
| OpenAI Responses | `http://127.0.0.1:4319/aisubs/chatgpt/default/v1/responses` | `POST /responses` |
|
|
181
|
+
| OpenAI-compatible Chat Completions | `http://127.0.0.1:4319/aisubs/chatgpt/default/v1/chat/completions` | `POST /chat/completions` |
|
|
182
|
+
| Anthropic Messages | `http://127.0.0.1:4319/aisubs/claude/default/v1/messages` | `POST /messages` |
|
|
183
|
+
| Google generateContent | `http://127.0.0.1:4319/aisubs/opencode-zen/default/v1/models/MODEL_ID:generateContent` | `POST /models/MODEL_ID:generateContent` |
|
|
184
|
+
| Model discovery | `http://127.0.0.1:4319/aisubs/chatgpt/default/v1/models` | `GET /models` |
|
|
185
|
+
| Model details | `http://127.0.0.1:4319/aisubs/chatgpt/default/v1/models/MODEL_ID` | `GET /models/MODEL_ID` |
|
|
186
|
+
| OpenAI Realtime | `ws://127.0.0.1:4319/aisubs/PROVIDER/ACCOUNT/v1/realtime?model=MODEL_ID` | WebSocket |
|
|
187
|
+
|
|
188
|
+
Replace the provider, account (`default`), and model ID with the values shown
|
|
189
|
+
for your connected account in the AISubs dashboard.
|
|
190
|
+
|
|
191
|
+
Cross-protocol translation covers text and system messages, streaming, function
|
|
192
|
+
tools and tool results, image/file/audio input where both protocols support it,
|
|
193
|
+
JSON-schema output, reasoning effort, stop conditions, and usage including
|
|
194
|
+
cached and reasoning tokens. If a feature has no safe equivalent, AISubs returns
|
|
195
|
+
an explicit `unsupported_feature` error instead of silently dropping it.
|
|
196
|
+
|
|
197
|
+
Provider-native routes—including embeddings, image/audio generation, batches,
|
|
198
|
+
files, and Realtime—are forwarded when that connected provider exposes them.
|
|
199
|
+
AISubs cannot add a capability that the provider, subscription, or selected
|
|
200
|
+
model does not have. Native requests preserve provider-specific cache controls;
|
|
201
|
+
translated requests preserve shared fields and cache-usage counters. Other than
|
|
202
|
+
Responses-to-Chat streaming, cross-protocol streams may be emitted after the
|
|
203
|
+
native response completes; use the native endpoint when event-level streaming
|
|
204
|
+
or provider-specific fields matter.
|
|
95
205
|
|
|
96
206
|
## SDK examples
|
|
97
207
|
|
|
@@ -102,7 +212,7 @@ export AISUBS_API_KEY="aisubs_..."
|
|
|
102
212
|
```
|
|
103
213
|
|
|
104
214
|
<details>
|
|
105
|
-
<summary><strong>Official OpenAI JavaScript SDK
|
|
215
|
+
<summary><strong>Official OpenAI JavaScript SDK: Responses and Chat Completions</strong></summary>
|
|
106
216
|
|
|
107
217
|
Install:
|
|
108
218
|
|
|
@@ -131,8 +241,8 @@ const stream = await client.responses.create({
|
|
|
131
241
|
for await (const event of stream) console.log(event);
|
|
132
242
|
```
|
|
133
243
|
|
|
134
|
-
Chat Completions uses the same client with
|
|
135
|
-
|
|
244
|
+
Chat Completions uses the same client with any generative model. AISubs
|
|
245
|
+
translates to the selected model's native protocol when needed:
|
|
136
246
|
|
|
137
247
|
```js
|
|
138
248
|
const response = await client.chat.completions.create({
|
|
@@ -206,16 +316,17 @@ const result = streamText({
|
|
|
206
316
|
for await (const text of result.textStream) process.stdout.write(text);
|
|
207
317
|
```
|
|
208
318
|
|
|
209
|
-
For Chat Completions, install
|
|
210
|
-
with the same account base URL,
|
|
319
|
+
For the universal Chat Completions surface, install
|
|
320
|
+
`@ai-sdk/openai-compatible`, create the provider with the same account base URL,
|
|
321
|
+
and select the model with `provider("MODEL_ID")`.
|
|
211
322
|
|
|
212
323
|
</details>
|
|
213
324
|
|
|
214
325
|
<details>
|
|
215
|
-
<summary><strong>TanStack AI
|
|
326
|
+
<summary><strong>TanStack AI: Chat Completions</strong></summary>
|
|
216
327
|
|
|
217
|
-
TanStack's generic compatibility adapter targets Chat Completions.
|
|
218
|
-
|
|
328
|
+
TanStack's generic compatibility adapter targets Chat Completions. AISubs
|
|
329
|
+
translates it to the selected model's native protocol.
|
|
219
330
|
|
|
220
331
|
```bash
|
|
221
332
|
nub install @tanstack/ai @tanstack/ai-openai
|
|
@@ -271,7 +382,7 @@ print(response.choices[0].message.content)
|
|
|
271
382
|
</details>
|
|
272
383
|
|
|
273
384
|
<details>
|
|
274
|
-
<summary><strong>cURL
|
|
385
|
+
<summary><strong>cURL: Responses, Chat Completions, Anthropic, and Google</strong></summary>
|
|
275
386
|
|
|
276
387
|
```bash
|
|
277
388
|
curl "http://127.0.0.1:4319/aisubs/chatgpt/personal/v1/responses" \
|
|
@@ -313,7 +424,9 @@ curl "http://127.0.0.1:4319/aisubs/opencode-zen/lab/v1/models/MODEL_ID_FROM_DASH
|
|
|
313
424
|
## Direct AISubs SDK
|
|
314
425
|
|
|
315
426
|
Use the in-process SDK when AISubs is part of your trusted Node.js backend. It
|
|
316
|
-
needs no local server
|
|
427
|
+
needs no local server, AISubs API key, or app-specific integration. Direct SDK
|
|
428
|
+
requests use the provider-native endpoint; the local server is the surface that
|
|
429
|
+
adds cross-protocol compatibility for third-party clients.
|
|
317
430
|
|
|
318
431
|
Install the package in a project:
|
|
319
432
|
|
|
@@ -337,8 +450,12 @@ if (!(await account.status()).authenticated) {
|
|
|
337
450
|
}
|
|
338
451
|
|
|
339
452
|
const catalog = await account.getModels();
|
|
340
|
-
const
|
|
341
|
-
if (!
|
|
453
|
+
const selected = catalog?.models.find((item) => item.selectable !== false);
|
|
454
|
+
if (!selected) throw new Error("No selectable model is available");
|
|
455
|
+
|
|
456
|
+
// ChatGPT models are native Responses models. Other providers report their
|
|
457
|
+
// native endpoint in selected.endpoints; use the matching native SDK adapter.
|
|
458
|
+
const model = selected.id;
|
|
342
459
|
|
|
343
460
|
const response = await account.proxy("responses", {
|
|
344
461
|
method: "POST",
|
|
@@ -354,6 +471,11 @@ Available provider factories are `chatGptProvider()`, `claudeProvider()`,
|
|
|
354
471
|
`copilotProvider()`, `grokProvider()`, `openCodeGoProvider()`, and
|
|
355
472
|
`openCodeZenProvider()`.
|
|
356
473
|
|
|
474
|
+
`getModels()` is cached for five minutes and `getUsage()` for 15 seconds by
|
|
475
|
+
default, with concurrent calls deduplicated. Account changes invalidate both.
|
|
476
|
+
Pass `modelsCacheTtlMs` or `usageCacheTtlMs` to `createSubscriptionAuth()` when
|
|
477
|
+
an in-process application needs different metadata freshness.
|
|
478
|
+
|
|
357
479
|
Useful account methods:
|
|
358
480
|
|
|
359
481
|
| Method | Purpose |
|
|
@@ -536,17 +658,26 @@ GET /v1/usage/:provider?account=work
|
|
|
536
658
|
GET /v1/models/:provider?account=work
|
|
537
659
|
GET /v1/api-key # dashboard session only
|
|
538
660
|
POST /v1/api-key/regenerate # dashboard session only
|
|
661
|
+
POST /v1/codex/configure # dashboard session only
|
|
662
|
+
POST /v1/codex/restore-official # dashboard session only
|
|
663
|
+
GET /aisubs-codex/v1/models
|
|
664
|
+
POST /aisubs-codex/v1/responses
|
|
539
665
|
* /aisubs/:provider/:account/v1/*
|
|
540
666
|
```
|
|
541
667
|
|
|
542
|
-
The provider and account routes
|
|
543
|
-
or `x-api-key: AISUBS_API_KEY`.
|
|
544
|
-
|
|
668
|
+
The provider and account routes accept `Authorization: Bearer AISUBS_API_KEY`
|
|
669
|
+
or `x-api-key: AISUBS_API_KEY`. A Google-protocol client can instead put that
|
|
670
|
+
same local AISubs key in `x-goog-api-key` or `?key=`; this does not represent a
|
|
671
|
+
Google credential or subscription. Local credentials are removed from headers
|
|
672
|
+
and query strings before proxying. Regenerating the key immediately invalidates
|
|
673
|
+
the old key.
|
|
545
674
|
|
|
546
675
|
## Storage and security
|
|
547
676
|
|
|
548
677
|
- Credentials: `~/.aisubs/credentials.json`.
|
|
549
678
|
- Persistent local API key: `~/.aisubs/api-key`.
|
|
679
|
+
- Optional Codex catalog: `~/.codex/aisubs-catalog.json`.
|
|
680
|
+
- Codex integration stores the local AISubs key in the user-private Codex config.
|
|
550
681
|
- State directories and files use private permissions where the platform supports them.
|
|
551
682
|
- Provider credentials are attached only after provider-host allowlist validation.
|
|
552
683
|
- Local authorization, cookie, origin, and proxy headers are never forwarded.
|
package/dist/account-key.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function nextAccountKey(sessions, provider) {
|
|
2
2
|
const used = new Set(sessions
|
|
3
|
-
.filter((session) => session.provider === provider && session.authenticated)
|
|
3
|
+
.filter((session) => session.provider === provider && (session.authenticated || session.reauthRequired))
|
|
4
4
|
.map((session) => session.accountKey));
|
|
5
5
|
if (!used.has("default"))
|
|
6
6
|
return "default";
|
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
|
@@ -171,7 +171,7 @@ export class SubscriptionAuth {
|
|
|
171
171
|
delete providerOptions.replace;
|
|
172
172
|
const login = await adapter.startLogin(abort.signal, providerOptions);
|
|
173
173
|
const id = crypto.randomUUID();
|
|
174
|
-
|
|
174
|
+
let record;
|
|
175
175
|
const promise = login.complete
|
|
176
176
|
.then(async (credential) => {
|
|
177
177
|
const saved = await this.store.modify(scope, (current) => {
|
|
@@ -194,7 +194,7 @@ export class SubscriptionAuth {
|
|
|
194
194
|
throw error;
|
|
195
195
|
});
|
|
196
196
|
void promise.catch(() => { });
|
|
197
|
-
|
|
197
|
+
record = {
|
|
198
198
|
id,
|
|
199
199
|
provider,
|
|
200
200
|
accountKey,
|
|
@@ -203,7 +203,7 @@ export class SubscriptionAuth {
|
|
|
203
203
|
error: null,
|
|
204
204
|
abort,
|
|
205
205
|
promise,
|
|
206
|
-
}
|
|
206
|
+
};
|
|
207
207
|
this.attempts.set(id, record);
|
|
208
208
|
void promise.then(() => this.expireLoginAttempt(id), () => this.expireLoginAttempt(id));
|
|
209
209
|
return {
|
|
@@ -300,7 +300,8 @@ export class SubscriptionAuth {
|
|
|
300
300
|
throw new Error(`Not authenticated with ${provider} account ${accountKey}`);
|
|
301
301
|
if (this.generation(scope) !== epoch)
|
|
302
302
|
return current;
|
|
303
|
-
if (current.
|
|
303
|
+
if (current.expiresAt > Date.now() &&
|
|
304
|
+
(current.accessToken !== observed.accessToken || current.expiresAt > observed.expiresAt)) {
|
|
304
305
|
return current;
|
|
305
306
|
}
|
|
306
307
|
const abort = new AbortController();
|
|
@@ -421,6 +422,22 @@ export class SubscriptionAuth {
|
|
|
421
422
|
const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
422
423
|
return this.fetch(provider, new URL(path, base), init, accountKey);
|
|
423
424
|
}
|
|
425
|
+
/** Build an authorized direct-provider request for transports such as WebSocket. */
|
|
426
|
+
async authorizeProxyRequest(provider, account, path, init) {
|
|
427
|
+
const adapter = this.adapter(provider);
|
|
428
|
+
const accountKey = normalizeAccountKey(account);
|
|
429
|
+
if (adapter.proxy) {
|
|
430
|
+
throw new Error(`${provider} does not expose a direct transport endpoint`);
|
|
431
|
+
}
|
|
432
|
+
const credential = await this.credential(provider, accountKey);
|
|
433
|
+
const baseUrl = typeof adapter.proxyBaseUrl === "function"
|
|
434
|
+
? adapter.proxyBaseUrl(credential)
|
|
435
|
+
: adapter.proxyBaseUrl;
|
|
436
|
+
if (!baseUrl)
|
|
437
|
+
throw new Error(`${provider} does not expose a direct API endpoint`);
|
|
438
|
+
const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
439
|
+
return adapter.authorize(createRequest(new URL(path, base), init), credential);
|
|
440
|
+
}
|
|
424
441
|
async getUsage(provider, account = DEFAULT_ACCOUNT, callerSignal) {
|
|
425
442
|
const adapter = this.adapter(provider);
|
|
426
443
|
if (!adapter.getUsage)
|
|
@@ -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>;
|