@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 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
- ## Error Handling
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.2.0";
150
+ var VERSION = "0.3.0";
128
151
 
129
- // src/marketplace.ts
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