@tokenite/sdk 2.5.0 → 2.7.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 +42 -0
- package/dist/client.d.ts +18 -1
- package/dist/client.js +17 -0
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +7 -0
- package/package.json +53 -54
package/README.md
CHANGED
|
@@ -193,6 +193,36 @@ switch (result.reason) {
|
|
|
193
193
|
|
|
194
194
|
`expectedState` is optional. When you provide it, a mismatch returns `{ ok: false, reason: 'invalid_state' }` even if a `code` is present — treating a stolen code paired with a forged state as a CSRF attempt.
|
|
195
195
|
|
|
196
|
+
### Vendor-agnostic calls (any provider behind one SDK)
|
|
197
|
+
|
|
198
|
+
The `/agnostic/{flavor}` route lets you keep using your favourite vendor SDK while letting the user's keys decide which provider actually runs the request. You write code once in (say) OpenAI shape; the proxy translates the request and the response so the SDK still sees its own format. The model name in the body is looked up across every provider's catalog, so a Claude model is fine in an OpenAI-shaped call.
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import OpenAI from 'openai';
|
|
202
|
+
|
|
203
|
+
const openai = new OpenAI({
|
|
204
|
+
apiKey: accessToken,
|
|
205
|
+
baseURL: tk.agnosticUrl('openai') + '/v1', // ← agnostic, OpenAI wire shape
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Same SDK, any model the user has access to — Claude here, served by
|
|
209
|
+
// the user's Anthropic key. Tokenite translates the envelope both ways.
|
|
210
|
+
const r = await openai.chat.completions.create({
|
|
211
|
+
model: 'claude-sonnet-4-6',
|
|
212
|
+
messages: [{ role: 'user', content: 'hi' }],
|
|
213
|
+
max_tokens: 256,
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The same works mirrored — Anthropic SDK naming an OpenAI model, etc. Pair it with `tk.getAccessContext()` to render a picker scoped to what the user can actually run (`models[].callableNow`).
|
|
218
|
+
|
|
219
|
+
**Caveats:**
|
|
220
|
+
- Non-streaming only. For `stream: true` keep using `tk.proxyUrl(provider)` (same-provider streaming passthrough).
|
|
221
|
+
- Pricing is the *resolved* provider's pricing (a Claude call via `/agnostic/openai` bills at Anthropic's rate). The proxy records `provider: anthropic` in your usage logs regardless of the URL.
|
|
222
|
+
- The app's `modelStrategy` still applies — a `models`-pinned app limits which slugs are valid; `tier`-pinned limits them by tier.
|
|
223
|
+
|
|
224
|
+
For provider-bound calls keep using `tk.proxyUrl()`. `agnosticUrl()` only opts into cross-provider routing — it's not a default.
|
|
225
|
+
|
|
196
226
|
### Streaming responses
|
|
197
227
|
|
|
198
228
|
`tk.call()` is for non-streaming requests. Streaming responses bypass the unified envelope and are forwarded as-is, so use any vendor SDK with `baseURL: tk.proxyUrl(...)`:
|
|
@@ -241,6 +271,10 @@ Make an authenticated, non-streaming request through the proxy. Returns a unifie
|
|
|
241
271
|
|
|
242
272
|
Get the proxy URL for a specific provider. Use as `baseURL` in a vendor SDK for streaming requests, which bypass the unified envelope.
|
|
243
273
|
|
|
274
|
+
### `.agnosticUrl(flavor: InboundFlavor) => string`
|
|
275
|
+
|
|
276
|
+
Base URL for the *agnostic* proxy route — same SDK shape (`flavor`), but the model named in the body is looked up globally across every provider. The user's keys decide which one actually runs the request; the proxy translates the request and response envelopes so your vendor SDK still sees its own shape.
|
|
277
|
+
|
|
244
278
|
### `.baseUrl`: `string`
|
|
245
279
|
|
|
246
280
|
The Tokenite dashboard base URL
|
|
@@ -394,6 +428,14 @@ export type TokenResponse = {
|
|
|
394
428
|
|
|
395
429
|
export type Provider = 'anthropic' | 'openai' | 'google' | 'grok' | 'bedrock';
|
|
396
430
|
|
|
431
|
+
/**
|
|
432
|
+
* The wire flavor a vendor SDK speaks — pick the one matching the SDK
|
|
433
|
+
* you're using. Used by `tk.agnosticUrl(flavor)` to declare "I want the
|
|
434
|
+
* shape of flavor X, but I don't care which vendor actually runs the
|
|
435
|
+
* model I name."
|
|
436
|
+
*/
|
|
437
|
+
export type InboundFlavor = 'anthropic' | 'openai' | 'gemini';
|
|
438
|
+
|
|
397
439
|
export type ProxyCallOptions = {
|
|
398
440
|
/** The user's Tokenite access token (returned by `tk.exchangeCode()`) */
|
|
399
441
|
readonly accessToken: string;
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TokeniteConfig, AuthorizeOptions, PopupOptions, PopupResult, TokenResponse, Provider, ProxyCallOptions, ProxyResponse, AccessContext, TopUpOptions, TopUpResult, CallWithRecoveryOptions } from './types.js';
|
|
1
|
+
import type { TokeniteConfig, AuthorizeOptions, PopupOptions, PopupResult, TokenResponse, Provider, ProxyCallOptions, ProxyResponse, AccessContext, InboundFlavor, TopUpOptions, TopUpResult, CallWithRecoveryOptions } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Tokenite client.
|
|
4
4
|
*
|
|
@@ -134,6 +134,23 @@ export declare const Tokenite: (config: TokeniteConfig) => {
|
|
|
134
134
|
* bypass the unified envelope.
|
|
135
135
|
*/
|
|
136
136
|
proxyUrl: (provider: Provider) => string;
|
|
137
|
+
/**
|
|
138
|
+
* Base URL for the *agnostic* proxy route — same SDK shape (`flavor`),
|
|
139
|
+
* but the model named in the body is looked up globally across every
|
|
140
|
+
* provider. The user's keys decide which one actually runs the request;
|
|
141
|
+
* the proxy translates the request and response envelopes so your
|
|
142
|
+
* vendor SDK still sees its own shape.
|
|
143
|
+
*
|
|
144
|
+
* Useful when you want to write code once against, say, the OpenAI SDK,
|
|
145
|
+
* but accept any model the user has access to. Point the SDK at:
|
|
146
|
+
*
|
|
147
|
+
* - `agnosticUrl('anthropic')` for `@anthropic-ai/sdk`
|
|
148
|
+
* - `agnosticUrl('openai') + '/v1'` for `openai`
|
|
149
|
+
* - `agnosticUrl('gemini')` for `@google/genai`
|
|
150
|
+
*
|
|
151
|
+
* Non-streaming only. For provider-bound calls keep using `proxyUrl()`.
|
|
152
|
+
*/
|
|
153
|
+
agnosticUrl: (flavor: InboundFlavor) => string;
|
|
137
154
|
/**
|
|
138
155
|
* Open a Tokenite-hosted "raise budget" popup for this app.
|
|
139
156
|
*
|
package/dist/client.js
CHANGED
|
@@ -247,6 +247,23 @@ export const Tokenite = (config) => {
|
|
|
247
247
|
* bypass the unified envelope.
|
|
248
248
|
*/
|
|
249
249
|
proxyUrl: (provider) => `${proxyBase}/${provider}`,
|
|
250
|
+
/**
|
|
251
|
+
* Base URL for the *agnostic* proxy route — same SDK shape (`flavor`),
|
|
252
|
+
* but the model named in the body is looked up globally across every
|
|
253
|
+
* provider. The user's keys decide which one actually runs the request;
|
|
254
|
+
* the proxy translates the request and response envelopes so your
|
|
255
|
+
* vendor SDK still sees its own shape.
|
|
256
|
+
*
|
|
257
|
+
* Useful when you want to write code once against, say, the OpenAI SDK,
|
|
258
|
+
* but accept any model the user has access to. Point the SDK at:
|
|
259
|
+
*
|
|
260
|
+
* - `agnosticUrl('anthropic')` for `@anthropic-ai/sdk`
|
|
261
|
+
* - `agnosticUrl('openai') + '/v1'` for `openai`
|
|
262
|
+
* - `agnosticUrl('gemini')` for `@google/genai`
|
|
263
|
+
*
|
|
264
|
+
* Non-streaming only. For provider-bound calls keep using `proxyUrl()`.
|
|
265
|
+
*/
|
|
266
|
+
agnosticUrl: (flavor) => `${proxyBase}/agnostic/${flavor}`,
|
|
250
267
|
/**
|
|
251
268
|
* Open a Tokenite-hosted "raise budget" popup for this app.
|
|
252
269
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { Tokenite } from './client.js';
|
|
2
|
-
export type { TokeniteConfig, AuthorizeOptions, OAuthPrompt, PopupOptions, PopupResult, TokenResponse, Provider, ProxyCallOptions, ProxyUsage, ProxySuccess, ProxyError, ProxyResponse, ErrorSource, ProviderInfo, ModelInfo, TierInfo, AppInfo, UserInfo, AccessContext, TopUpOptions, TopUpResult, CallWithRecoveryOptions, } from './types.js';
|
|
2
|
+
export type { TokeniteConfig, AuthorizeOptions, OAuthPrompt, PopupOptions, PopupResult, TokenResponse, Provider, ProxyCallOptions, ProxyUsage, ProxySuccess, ProxyError, ProxyResponse, ErrorSource, ProviderInfo, ModelInfo, TierInfo, InboundFlavor, AppInfo, UserInfo, AccessContext, TopUpOptions, TopUpResult, CallWithRecoveryOptions, } from './types.js';
|
|
3
3
|
export { isProxyError, isProxySuccess } from './types.js';
|
|
4
4
|
export { parseCallback } from './parse-callback.js';
|
|
5
5
|
export type { CallbackResult, CallbackSuccess, CallbackError, CallbackReason, ParseCallbackOptions, } from './parse-callback.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -133,6 +133,13 @@ export type TokenResponse = {
|
|
|
133
133
|
readonly token_type: string;
|
|
134
134
|
};
|
|
135
135
|
export type Provider = 'anthropic' | 'openai' | 'google' | 'grok' | 'bedrock';
|
|
136
|
+
/**
|
|
137
|
+
* The wire flavor a vendor SDK speaks — pick the one matching the SDK
|
|
138
|
+
* you're using. Used by `tk.agnosticUrl(flavor)` to declare "I want the
|
|
139
|
+
* shape of flavor X, but I don't care which vendor actually runs the
|
|
140
|
+
* model I name."
|
|
141
|
+
*/
|
|
142
|
+
export type InboundFlavor = 'anthropic' | 'openai' | 'gemini';
|
|
136
143
|
export type ProxyCallOptions = {
|
|
137
144
|
/** The user's Tokenite access token (returned by `tk.exchangeCode()`) */
|
|
138
145
|
readonly accessToken: string;
|
package/package.json
CHANGED
|
@@ -1,54 +1,53 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@tokenite/sdk",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "SDK for integrating \"Login with Tokenite\" into your app. Your users bring their own AI tokens — you pay nothing.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"exports": {
|
|
7
|
-
".": {
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"import": "./dist/index.js"
|
|
10
|
-
},
|
|
11
|
-
"./admin": {
|
|
12
|
-
"types": "./dist/admin/index.d.ts",
|
|
13
|
-
"import": "./dist/admin/index.js"
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"files": [
|
|
17
|
-
"dist",
|
|
18
|
-
"README.md",
|
|
19
|
-
"LICENSE"
|
|
20
|
-
],
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@tokenite/sdk",
|
|
3
|
+
"version": "2.7.0",
|
|
4
|
+
"description": "SDK for integrating \"Login with Tokenite\" into your app. Your users bring their own AI tokens — you pay nothing.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./admin": {
|
|
12
|
+
"types": "./dist/admin/index.d.ts",
|
|
13
|
+
"import": "./dist/admin/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"keywords": [
|
|
22
|
+
"tokenite",
|
|
23
|
+
"llm",
|
|
24
|
+
"ai",
|
|
25
|
+
"proxy",
|
|
26
|
+
"oauth",
|
|
27
|
+
"byok",
|
|
28
|
+
"anthropic",
|
|
29
|
+
"openai",
|
|
30
|
+
"google"
|
|
31
|
+
],
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/eran-broder/tokenite-sdk.git"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/eran-broder/tokenite-sdk#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/eran-broder/tokenite-sdk/issues"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"tsx": "^4.0.0",
|
|
46
|
+
"typescript": "^5.0.0"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsc && npm run generate-readme",
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"generate-readme": "npx tsx scripts/generate-readme.ts"
|
|
52
|
+
}
|
|
53
|
+
}
|