@onlist/sdk 0.2.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/README.md +144 -2
- package/dist/index.cjs +276 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +401 -11
- package/dist/index.d.ts +401 -11
- package/dist/index.js +266 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,15 @@ const client = new Onlist();
|
|
|
44
44
|
const client = new Onlist();
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
For the [Account API](#account-api) there is a second, optional credential —
|
|
48
|
+
a management key, read from the `managementKey` parameter or
|
|
49
|
+
`ONLIST_MANAGEMENT_KEY`, falling back to your API key:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
const client = new Onlist({ managementKey: "mgmt_..." });
|
|
53
|
+
// export ONLIST_MANAGEMENT_KEY=mgmt_...
|
|
54
|
+
```
|
|
55
|
+
|
|
47
56
|
## Provider Routing
|
|
48
57
|
|
|
49
58
|
Route requests to specific providers on the Onlist marketplace:
|
|
@@ -151,8 +160,121 @@ for (const app of apps.apps) {
|
|
|
151
160
|
}
|
|
152
161
|
```
|
|
153
162
|
|
|
154
|
-
##
|
|
163
|
+
## Account API
|
|
164
|
+
|
|
165
|
+
Balance, API key management, per-call costs and daily usage. These endpoints
|
|
166
|
+
are OpenRouter-compatible: same paths, same field names.
|
|
167
|
+
|
|
168
|
+
Most of them need a **management key** (`mgmt_...`), which you create at
|
|
169
|
+
[onlist.io/management-keys](https://onlist.io/management-keys). It is a
|
|
170
|
+
separate credential from your inference key and cannot make model calls:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
const client = new Onlist({ apiKey: "sk-...", managementKey: "mgmt_..." });
|
|
174
|
+
// or set ONLIST_API_KEY and ONLIST_MANAGEMENT_KEY
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
If you pass only `apiKey`, it is used for the account endpoints too. That
|
|
178
|
+
matches OpenRouter's single-keyhole shape, and the server returns
|
|
179
|
+
`PermissionDeniedError` where a management key is actually required.
|
|
180
|
+
|
|
181
|
+
### Credits
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
const credits = await client.credits.get();
|
|
185
|
+
console.log(`$${(credits.total_credits - credits.total_usage).toFixed(4)} remaining`);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### API keys
|
|
155
189
|
|
|
190
|
+
```typescript
|
|
191
|
+
// Create — `.key` is the plaintext secret, returned exactly once
|
|
192
|
+
const created = await client.apiKeys.create("ci-runner", { limit: 5, limit_reset: "daily" });
|
|
193
|
+
console.log(created.key);
|
|
194
|
+
|
|
195
|
+
// List — fixed pages of 100, no total; read until you get a short page
|
|
196
|
+
const keys = await client.apiKeys.list({ offset: 0, include_disabled: true });
|
|
197
|
+
|
|
198
|
+
// Read one
|
|
199
|
+
const key = await client.apiKeys.get(created.data.hash);
|
|
200
|
+
|
|
201
|
+
// Update — omitted fields are left unchanged, `null` clears the value
|
|
202
|
+
await client.apiKeys.update(key.hash, { limit: null }); // remove the spend cap
|
|
203
|
+
await client.apiKeys.update(key.hash, { disabled: true }); // stop it spending
|
|
204
|
+
|
|
205
|
+
await client.apiKeys.delete(key.hash);
|
|
206
|
+
|
|
207
|
+
// Describe the credential this client is holding
|
|
208
|
+
const me = await client.apiKeys.current();
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`update()` distinguishes three states. An omitted (or `undefined`) field is
|
|
212
|
+
left alone; an explicit `null` clears the value. Because of that, `name` and
|
|
213
|
+
`disabled` do not accept `null` at all — the server reads `{"name": null}` as
|
|
214
|
+
an empty name and `{"disabled": null}` as `false`, which would re-enable a
|
|
215
|
+
key you only meant to leave alone.
|
|
216
|
+
|
|
217
|
+
`limit_reset` accepts `"daily"`, `"weekly"`, or `null` for a lifetime total.
|
|
218
|
+
|
|
219
|
+
### Generation
|
|
220
|
+
|
|
221
|
+
What one call cost, and where it went. This one also accepts a plain
|
|
222
|
+
inference key, which can look up the calls it made itself:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
const { data, response } = await client.chat.completions
|
|
226
|
+
.create({ model: "deepseek/deepseek-chat", messages: [{ role: "user", content: "Hi" }] })
|
|
227
|
+
.withResponse();
|
|
228
|
+
|
|
229
|
+
const gen = await client.generations.get(response.headers.get("X-Oneapi-Request-Id")!);
|
|
230
|
+
console.log(`${gen.provider_name}: $${gen.total_cost}, ${gen.latency}ms to first token`);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Activity
|
|
234
|
+
|
|
235
|
+
Daily usage grouped by model and provider, covering the last 30 complete UTC
|
|
236
|
+
days. Today is excluded, so the same query always returns the same numbers:
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
for (const row of await client.activity.list()) {
|
|
240
|
+
console.log(`${row.date} ${row.model} ${row.requests} req $${row.usage}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Narrow to one day or one key
|
|
244
|
+
await client.activity.list({ date: "2026-09-05" });
|
|
245
|
+
await client.activity.list({ api_key_hash: "42" });
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Sign in with Onlist
|
|
249
|
+
|
|
250
|
+
Let your users authorize your app and get their own inference key, without
|
|
251
|
+
ever pasting one. This is the OAuth PKCE flow, compatible with OpenRouter's:
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import { Onlist, exchangeAuthCode, generatePkce } from "@onlist/sdk";
|
|
255
|
+
|
|
256
|
+
const { verifier, challenge } = await generatePkce();
|
|
257
|
+
|
|
258
|
+
window.location.href =
|
|
259
|
+
"https://onlist.io/auth" +
|
|
260
|
+
"?callback_url=https://yourapp.com/callback" +
|
|
261
|
+
`&code_challenge=${challenge}&code_challenge_method=S256`;
|
|
262
|
+
|
|
263
|
+
// ...user approves, your callback receives ?code=...
|
|
264
|
+
|
|
265
|
+
const result = await exchangeAuthCode(code, { codeVerifier: verifier });
|
|
266
|
+
const client = new Onlist({ apiKey: result.key }); // scoped to that user
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
`exchangeAuthCode()` is a standalone function, not a client method, because
|
|
270
|
+
an app running this flow has no API key yet — that is the whole point of it —
|
|
271
|
+
and constructing `Onlist` requires one. If you already have a client,
|
|
272
|
+
`client.oauth.exchange()` does the same thing.
|
|
273
|
+
|
|
274
|
+
The code is single-use and is consumed even when the verifier does not match,
|
|
275
|
+
so a failed exchange means restarting the browser flow.
|
|
276
|
+
|
|
277
|
+
## Error Handling
|
|
156
278
|
OpenAI-compatible calls (`chat.completions`, `embeddings`, etc.) throw standard `openai` errors. Marketplace calls throw `onlist` errors:
|
|
157
279
|
|
|
158
280
|
```typescript
|
|
@@ -181,9 +303,25 @@ try {
|
|
|
181
303
|
}
|
|
182
304
|
```
|
|
183
305
|
|
|
306
|
+
Account endpoints throw the same family, plus `BadRequestError` (400) and
|
|
307
|
+
`PermissionDeniedError` (403). The server's message is passed through
|
|
308
|
+
unchanged:
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
import { PermissionDeniedError } from "@onlist/sdk";
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
await client.credits.get();
|
|
315
|
+
} catch (e) {
|
|
316
|
+
if (e instanceof PermissionDeniedError) {
|
|
317
|
+
console.log(e.message); // "Only management keys can perform this operation"
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
184
322
|
## Retry Configuration
|
|
185
323
|
|
|
186
|
-
Marketplace API calls automatically retry on transient failures (408, 429, 5xx) with exponential backoff:
|
|
324
|
+
Marketplace and account API calls automatically retry on transient failures (408, 429, 5xx) with exponential backoff:
|
|
187
325
|
|
|
188
326
|
```typescript
|
|
189
327
|
const client = new Onlist({
|
|
@@ -192,6 +330,10 @@ const client = new Onlist({
|
|
|
192
330
|
});
|
|
193
331
|
```
|
|
194
332
|
|
|
333
|
+
Only `GET` requests are retried. Creating a key or exchanging an
|
|
334
|
+
authorization code is never replayed: a duplicate key or a burnt code is
|
|
335
|
+
worse than surfacing the transient error.
|
|
336
|
+
|
|
195
337
|
## Migration from OpenAI
|
|
196
338
|
|
|
197
339
|
Replace the `openai` import with `onlist`:
|
package/dist/index.cjs
CHANGED
|
@@ -31,7 +31,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
APIError: () => APIError,
|
|
34
|
+
AccountActivity: () => AccountActivity,
|
|
35
|
+
AccountApiKeys: () => AccountApiKeys,
|
|
36
|
+
AccountCredits: () => AccountCredits,
|
|
37
|
+
AccountGenerations: () => AccountGenerations,
|
|
38
|
+
AccountOAuth: () => AccountOAuth,
|
|
34
39
|
AuthenticationError: () => AuthenticationError,
|
|
40
|
+
BadRequestError: () => BadRequestError,
|
|
35
41
|
InsufficientBalanceError: () => InsufficientBalanceError,
|
|
36
42
|
Marketplace: () => Marketplace,
|
|
37
43
|
MarketplaceModels: () => MarketplaceModels,
|
|
@@ -40,9 +46,12 @@ __export(index_exports, {
|
|
|
40
46
|
NotFoundError: () => NotFoundError,
|
|
41
47
|
Onlist: () => Onlist,
|
|
42
48
|
OnlistError: () => OnlistError,
|
|
49
|
+
PermissionDeniedError: () => PermissionDeniedError,
|
|
43
50
|
ProviderError: () => ProviderError,
|
|
44
51
|
RateLimitError: () => RateLimitError,
|
|
45
|
-
VERSION: () => VERSION
|
|
52
|
+
VERSION: () => VERSION,
|
|
53
|
+
exchangeAuthCode: () => exchangeAuthCode,
|
|
54
|
+
generatePkce: () => generatePkce
|
|
46
55
|
});
|
|
47
56
|
module.exports = __toCommonJS(index_exports);
|
|
48
57
|
|
|
@@ -102,6 +111,18 @@ var NotFoundError = class extends APIError {
|
|
|
102
111
|
this.name = "NotFoundError";
|
|
103
112
|
}
|
|
104
113
|
};
|
|
114
|
+
var BadRequestError = class extends APIError {
|
|
115
|
+
constructor(message = "Bad request", opts) {
|
|
116
|
+
super(message, { status: 400, ...opts });
|
|
117
|
+
this.name = "BadRequestError";
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var PermissionDeniedError = class extends APIError {
|
|
121
|
+
constructor(message = "Permission denied", opts) {
|
|
122
|
+
super(message, { status: 403, ...opts });
|
|
123
|
+
this.name = "PermissionDeniedError";
|
|
124
|
+
}
|
|
125
|
+
};
|
|
105
126
|
function raiseForStatus(status, body) {
|
|
106
127
|
let error = {};
|
|
107
128
|
if (body && typeof body === "object" && "error" in body) {
|
|
@@ -115,8 +136,10 @@ function raiseForStatus(status, body) {
|
|
|
115
136
|
const code = typeof error.code === "string" ? error.code : null;
|
|
116
137
|
const param = typeof error.param === "string" ? error.param : null;
|
|
117
138
|
const opts = { status, type, code, param, body };
|
|
139
|
+
if (status === 400) throw new BadRequestError(message, opts);
|
|
118
140
|
if (status === 401) throw new AuthenticationError(message, opts);
|
|
119
141
|
if (status === 402) throw new InsufficientBalanceError(message, opts);
|
|
142
|
+
if (status === 403) throw new PermissionDeniedError(message, opts);
|
|
120
143
|
if (status === 404) throw new NotFoundError(message, opts);
|
|
121
144
|
if (status === 429) throw new RateLimitError(message, opts);
|
|
122
145
|
if (code && code.startsWith("no_provider")) throw new ProviderError(message, opts);
|
|
@@ -124,9 +147,9 @@ function raiseForStatus(status, body) {
|
|
|
124
147
|
}
|
|
125
148
|
|
|
126
149
|
// src/version.ts
|
|
127
|
-
var VERSION = "0.
|
|
150
|
+
var VERSION = "0.3.0";
|
|
128
151
|
|
|
129
|
-
// src/
|
|
152
|
+
// src/http.ts
|
|
130
153
|
var DEFAULT_TIMEOUT = 3e4;
|
|
131
154
|
var DEFAULT_MAX_RETRIES = 2;
|
|
132
155
|
var INITIAL_RETRY_DELAY = 500;
|
|
@@ -162,6 +185,223 @@ function retryDelay(attempt, retryAfterHeader) {
|
|
|
162
185
|
const jitter = base * JITTER_FACTOR * (2 * Math.random() - 1);
|
|
163
186
|
return Math.max(0, base + jitter);
|
|
164
187
|
}
|
|
188
|
+
function buildFetchInit(opts, init) {
|
|
189
|
+
const headers = {
|
|
190
|
+
"User-Agent": `onlist-js/${VERSION}`,
|
|
191
|
+
Accept: "application/json",
|
|
192
|
+
...init?.headers
|
|
193
|
+
};
|
|
194
|
+
if (opts.apiKey) {
|
|
195
|
+
headers["Authorization"] = `Bearer ${opts.apiKey}`;
|
|
196
|
+
}
|
|
197
|
+
const signal = AbortSignal.timeout(opts.timeout ?? DEFAULT_TIMEOUT);
|
|
198
|
+
return { ...init, headers, signal };
|
|
199
|
+
}
|
|
200
|
+
async function fetchWithRetry(opts, path, init) {
|
|
201
|
+
const url = `${opts.baseURL.replace(/\/$/, "")}${path}`;
|
|
202
|
+
const fetchInit = buildFetchInit(opts, init);
|
|
203
|
+
const method = (init?.method ?? "GET").toUpperCase();
|
|
204
|
+
const maxRetries = method === "GET" ? opts.maxRetries ?? DEFAULT_MAX_RETRIES : 0;
|
|
205
|
+
let lastError;
|
|
206
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
207
|
+
try {
|
|
208
|
+
const response = await fetch(url, fetchInit);
|
|
209
|
+
if (response.ok || !RETRYABLE_STATUSES.has(response.status) || attempt === maxRetries) {
|
|
210
|
+
return response;
|
|
211
|
+
}
|
|
212
|
+
const delay = retryDelay(attempt, response.headers.get("Retry-After"));
|
|
213
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
214
|
+
} catch (err) {
|
|
215
|
+
lastError = err;
|
|
216
|
+
if (attempt === maxRetries) break;
|
|
217
|
+
const delay = retryDelay(attempt, null);
|
|
218
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
throw lastError;
|
|
222
|
+
}
|
|
223
|
+
function jsonBody(value) {
|
|
224
|
+
return {
|
|
225
|
+
body: JSON.stringify(value),
|
|
226
|
+
headers: { "Content-Type": "application/json" }
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/account.ts
|
|
231
|
+
function unwrap(body) {
|
|
232
|
+
if (body && typeof body === "object" && "data" in body) {
|
|
233
|
+
return body.data;
|
|
234
|
+
}
|
|
235
|
+
return body;
|
|
236
|
+
}
|
|
237
|
+
function base64url(bytes) {
|
|
238
|
+
let binary = "";
|
|
239
|
+
for (const b of bytes) binary += String.fromCharCode(b);
|
|
240
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
241
|
+
}
|
|
242
|
+
async function generatePkce() {
|
|
243
|
+
const raw = new Uint8Array(32);
|
|
244
|
+
crypto.getRandomValues(raw);
|
|
245
|
+
const verifier = base64url(raw);
|
|
246
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
|
|
247
|
+
return { verifier, challenge: base64url(new Uint8Array(digest)) };
|
|
248
|
+
}
|
|
249
|
+
var DEFAULT_BASE_URL = "https://onlist.io";
|
|
250
|
+
async function exchangeAuthCode(code, opts) {
|
|
251
|
+
const resource = new AccountOAuth({
|
|
252
|
+
baseURL: opts?.baseURL ?? DEFAULT_BASE_URL,
|
|
253
|
+
timeout: opts?.timeout
|
|
254
|
+
});
|
|
255
|
+
return resource.exchange(code, opts?.codeVerifier ?? "");
|
|
256
|
+
}
|
|
257
|
+
var AccountCredits = class {
|
|
258
|
+
constructor(_opts) {
|
|
259
|
+
this._opts = _opts;
|
|
260
|
+
}
|
|
261
|
+
_opts;
|
|
262
|
+
/** Get lifetime credits purchased and credits used, in USD. */
|
|
263
|
+
async get() {
|
|
264
|
+
const resp = await fetchWithRetry(this._opts, "/api/v1/credits");
|
|
265
|
+
return unwrap(await parseResponse(resp));
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
var AccountGenerations = class {
|
|
269
|
+
constructor(_opts) {
|
|
270
|
+
this._opts = _opts;
|
|
271
|
+
}
|
|
272
|
+
_opts;
|
|
273
|
+
/**
|
|
274
|
+
* Look up one call by request ID.
|
|
275
|
+
*
|
|
276
|
+
* @param requestId The value of the `X-Oneapi-Request-Id` response header
|
|
277
|
+
* from the original call.
|
|
278
|
+
*/
|
|
279
|
+
async get(requestId) {
|
|
280
|
+
const search = new URLSearchParams({ id: requestId });
|
|
281
|
+
const resp = await fetchWithRetry(this._opts, `/api/v1/generation?${search}`);
|
|
282
|
+
return unwrap(await parseResponse(resp));
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
var AccountApiKeys = class {
|
|
286
|
+
constructor(_opts) {
|
|
287
|
+
this._opts = _opts;
|
|
288
|
+
}
|
|
289
|
+
_opts;
|
|
290
|
+
/** Describe the credential this client is using. */
|
|
291
|
+
async current() {
|
|
292
|
+
const resp = await fetchWithRetry(this._opts, "/api/v1/key");
|
|
293
|
+
return unwrap(await parseResponse(resp));
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* List inference keys.
|
|
297
|
+
*
|
|
298
|
+
* Pages are a fixed 100 keys and no total is returned: request
|
|
299
|
+
* `offset += 100` until you get a short page.
|
|
300
|
+
*/
|
|
301
|
+
async list(params) {
|
|
302
|
+
const search = new URLSearchParams();
|
|
303
|
+
search.set("offset", String(params?.offset ?? 0));
|
|
304
|
+
search.set("include_disabled", String(params?.include_disabled ?? false));
|
|
305
|
+
const resp = await fetchWithRetry(this._opts, `/api/v1/keys?${search}`);
|
|
306
|
+
return unwrap(await parseResponse(resp)) ?? [];
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Create an inference key.
|
|
310
|
+
*
|
|
311
|
+
* The plaintext secret is on `.key` of the result and is never retrievable
|
|
312
|
+
* again.
|
|
313
|
+
*
|
|
314
|
+
* @param name Display name for the key. Required.
|
|
315
|
+
*/
|
|
316
|
+
async create(name, params) {
|
|
317
|
+
const body = { name };
|
|
318
|
+
if (params?.limit !== void 0) body.limit = params.limit;
|
|
319
|
+
if (params?.limit_reset !== void 0) body.limit_reset = params.limit_reset;
|
|
320
|
+
if (params?.expires_at !== void 0) body.expires_at = params.expires_at;
|
|
321
|
+
const resp = await fetchWithRetry(this._opts, "/api/v1/keys", {
|
|
322
|
+
method: "POST",
|
|
323
|
+
...jsonBody(body)
|
|
324
|
+
});
|
|
325
|
+
return await parseResponse(resp);
|
|
326
|
+
}
|
|
327
|
+
/** Get one inference key by its `hash`. */
|
|
328
|
+
async get(hash) {
|
|
329
|
+
const resp = await fetchWithRetry(this._opts, `/api/v1/keys/${encodePath(hash)}`);
|
|
330
|
+
return unwrap(await parseResponse(resp));
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Update an inference key. Omitted fields are left unchanged.
|
|
334
|
+
*
|
|
335
|
+
* For `limit`, `limit_reset` and `expires_at`, passing `null` clears the
|
|
336
|
+
* value; leaving the field out leaves it alone.
|
|
337
|
+
*/
|
|
338
|
+
async update(hash, patch) {
|
|
339
|
+
const body = {};
|
|
340
|
+
if (patch.name !== void 0) body.name = patch.name;
|
|
341
|
+
if (patch.disabled !== void 0) body.disabled = patch.disabled;
|
|
342
|
+
if (patch.limit !== void 0) body.limit = patch.limit;
|
|
343
|
+
if (patch.limit_reset !== void 0) body.limit_reset = patch.limit_reset;
|
|
344
|
+
if (patch.expires_at !== void 0) body.expires_at = patch.expires_at;
|
|
345
|
+
const resp = await fetchWithRetry(this._opts, `/api/v1/keys/${encodePath(hash)}`, {
|
|
346
|
+
method: "PATCH",
|
|
347
|
+
...jsonBody(body)
|
|
348
|
+
});
|
|
349
|
+
return unwrap(await parseResponse(resp));
|
|
350
|
+
}
|
|
351
|
+
/** Delete an inference key. Resolves to `true` on success. */
|
|
352
|
+
async delete(hash) {
|
|
353
|
+
const resp = await fetchWithRetry(this._opts, `/api/v1/keys/${encodePath(hash)}`, {
|
|
354
|
+
method: "DELETE"
|
|
355
|
+
});
|
|
356
|
+
const data = unwrap(await parseResponse(resp));
|
|
357
|
+
return Boolean(data?.deleted);
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
var AccountActivity = class {
|
|
361
|
+
constructor(_opts) {
|
|
362
|
+
this._opts = _opts;
|
|
363
|
+
}
|
|
364
|
+
_opts;
|
|
365
|
+
/**
|
|
366
|
+
* List usage grouped by day, model and provider.
|
|
367
|
+
*
|
|
368
|
+
* Covers the last 30 complete UTC days; today is excluded.
|
|
369
|
+
*/
|
|
370
|
+
async list(params) {
|
|
371
|
+
const search = new URLSearchParams();
|
|
372
|
+
if (params?.date) search.set("date", params.date);
|
|
373
|
+
if (params?.api_key_hash) search.set("api_key_hash", params.api_key_hash);
|
|
374
|
+
const qs = search.toString();
|
|
375
|
+
const resp = await fetchWithRetry(this._opts, `/api/v1/activity${qs ? `?${qs}` : ""}`);
|
|
376
|
+
return unwrap(await parseResponse(resp)) ?? [];
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
var AccountOAuth = class {
|
|
380
|
+
constructor(_opts) {
|
|
381
|
+
this._opts = _opts;
|
|
382
|
+
}
|
|
383
|
+
_opts;
|
|
384
|
+
/**
|
|
385
|
+
* Exchange an authorization code for a new inference key.
|
|
386
|
+
*
|
|
387
|
+
* Unauthenticated, and single-use: the code is consumed even when the
|
|
388
|
+
* verifier turns out to be wrong, so a failure means restarting the
|
|
389
|
+
* browser flow.
|
|
390
|
+
*
|
|
391
|
+
* @param code The `code` query parameter from the callback URL.
|
|
392
|
+
* @param codeVerifier The verifier from {@link generatePkce}. Required
|
|
393
|
+
* whenever the authorization request carried a challenge.
|
|
394
|
+
*/
|
|
395
|
+
async exchange(code, codeVerifier = "") {
|
|
396
|
+
const resp = await fetchWithRetry(this._opts, "/api/v1/auth/keys", {
|
|
397
|
+
method: "POST",
|
|
398
|
+
...jsonBody({ code, code_verifier: codeVerifier })
|
|
399
|
+
});
|
|
400
|
+
return await parseResponse(resp);
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// src/marketplace.ts
|
|
165
405
|
var MarketplaceModels = class {
|
|
166
406
|
constructor(_opts) {
|
|
167
407
|
this._opts = _opts;
|
|
@@ -253,40 +493,6 @@ var Marketplace = class {
|
|
|
253
493
|
this.rankings = new MarketplaceRankings(opts);
|
|
254
494
|
}
|
|
255
495
|
};
|
|
256
|
-
function buildFetchInit(opts, init) {
|
|
257
|
-
const headers = {
|
|
258
|
-
"User-Agent": `onlist-js/${VERSION}`,
|
|
259
|
-
Accept: "application/json",
|
|
260
|
-
...init?.headers
|
|
261
|
-
};
|
|
262
|
-
if (opts.apiKey) {
|
|
263
|
-
headers["Authorization"] = `Bearer ${opts.apiKey}`;
|
|
264
|
-
}
|
|
265
|
-
const signal = AbortSignal.timeout(opts.timeout ?? DEFAULT_TIMEOUT);
|
|
266
|
-
return { ...init, headers, signal };
|
|
267
|
-
}
|
|
268
|
-
async function fetchWithRetry(opts, path, init) {
|
|
269
|
-
const url = `${opts.baseURL.replace(/\/$/, "")}${path}`;
|
|
270
|
-
const fetchInit = buildFetchInit(opts, init);
|
|
271
|
-
const maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
272
|
-
let lastError;
|
|
273
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
274
|
-
try {
|
|
275
|
-
const response = await fetch(url, fetchInit);
|
|
276
|
-
if (response.ok || !RETRYABLE_STATUSES.has(response.status) || attempt === maxRetries) {
|
|
277
|
-
return response;
|
|
278
|
-
}
|
|
279
|
-
const delay = retryDelay(attempt, response.headers.get("Retry-After"));
|
|
280
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
281
|
-
} catch (err) {
|
|
282
|
-
lastError = err;
|
|
283
|
-
if (attempt === maxRetries) break;
|
|
284
|
-
const delay = retryDelay(attempt, null);
|
|
285
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
throw lastError;
|
|
289
|
-
}
|
|
290
496
|
|
|
291
497
|
// src/client.ts
|
|
292
498
|
var BASE_URL = "https://onlist.io/v1";
|
|
@@ -294,6 +500,18 @@ var MARKETPLACE_BASE_URL = "https://onlist.io";
|
|
|
294
500
|
var Onlist = class extends import_openai.default {
|
|
295
501
|
/** Access to marketplace data: models, providers, and rankings. */
|
|
296
502
|
marketplace;
|
|
503
|
+
/** Account balance. */
|
|
504
|
+
credits;
|
|
505
|
+
/** Cost and timing for individual calls. */
|
|
506
|
+
generations;
|
|
507
|
+
/** Inference key management. */
|
|
508
|
+
apiKeys;
|
|
509
|
+
/** Daily usage rollups. */
|
|
510
|
+
activity;
|
|
511
|
+
/** Sign in with Onlist — the PKCE code exchange. */
|
|
512
|
+
oauth;
|
|
513
|
+
/** The credential the account API is using. */
|
|
514
|
+
managementKey;
|
|
297
515
|
constructor(opts) {
|
|
298
516
|
const apiKey = opts?.apiKey ?? (typeof process !== "undefined" ? process.env?.ONLIST_API_KEY ?? process.env?.OPENAI_API_KEY : void 0) ?? void 0;
|
|
299
517
|
const baseURL = opts?.baseURL ?? BASE_URL;
|
|
@@ -313,12 +531,29 @@ var Onlist = class extends import_openai.default {
|
|
|
313
531
|
baseURL: marketplaceBase,
|
|
314
532
|
maxRetries: opts?.maxRetries
|
|
315
533
|
});
|
|
534
|
+
this.managementKey = opts?.managementKey ?? (typeof process !== "undefined" ? process.env?.ONLIST_MANAGEMENT_KEY : void 0) ?? this.apiKey ?? void 0;
|
|
535
|
+
const accountOpts = {
|
|
536
|
+
apiKey: this.managementKey,
|
|
537
|
+
baseURL: marketplaceBase,
|
|
538
|
+
maxRetries: opts?.maxRetries
|
|
539
|
+
};
|
|
540
|
+
this.credits = new AccountCredits(accountOpts);
|
|
541
|
+
this.generations = new AccountGenerations(accountOpts);
|
|
542
|
+
this.apiKeys = new AccountApiKeys(accountOpts);
|
|
543
|
+
this.activity = new AccountActivity(accountOpts);
|
|
544
|
+
this.oauth = new AccountOAuth(accountOpts);
|
|
316
545
|
}
|
|
317
546
|
};
|
|
318
547
|
// Annotate the CommonJS export names for ESM import in node:
|
|
319
548
|
0 && (module.exports = {
|
|
320
549
|
APIError,
|
|
550
|
+
AccountActivity,
|
|
551
|
+
AccountApiKeys,
|
|
552
|
+
AccountCredits,
|
|
553
|
+
AccountGenerations,
|
|
554
|
+
AccountOAuth,
|
|
321
555
|
AuthenticationError,
|
|
556
|
+
BadRequestError,
|
|
322
557
|
InsufficientBalanceError,
|
|
323
558
|
Marketplace,
|
|
324
559
|
MarketplaceModels,
|
|
@@ -327,8 +562,11 @@ var Onlist = class extends import_openai.default {
|
|
|
327
562
|
NotFoundError,
|
|
328
563
|
Onlist,
|
|
329
564
|
OnlistError,
|
|
565
|
+
PermissionDeniedError,
|
|
330
566
|
ProviderError,
|
|
331
567
|
RateLimitError,
|
|
332
|
-
VERSION
|
|
568
|
+
VERSION,
|
|
569
|
+
exchangeAuthCode,
|
|
570
|
+
generatePkce
|
|
333
571
|
});
|
|
334
572
|
//# sourceMappingURL=index.cjs.map
|