@tokenite/sdk 1.0.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.
@@ -0,0 +1,9 @@
1
+ export const createConnectionsApi = (client) => ({
2
+ list: () => client.request('GET', '/api/connections'),
3
+ stats: (id) => client.request('GET', `/api/connections/${id}/stats`),
4
+ setBudget: (id, budgetLimit) => client.request('PATCH', `/api/connections/${id}/budget`, { budget_limit: budgetLimit }),
5
+ suspend: (id) => client.request('POST', `/api/connections/${id}/suspend`),
6
+ resume: (id) => client.request('POST', `/api/connections/${id}/resume`),
7
+ revoke: (id) => client.request('DELETE', `/api/connections/${id}`),
8
+ });
9
+ //# sourceMappingURL=connections.js.map
@@ -0,0 +1,88 @@
1
+ export type TokeniteAdminConfig = {
2
+ readonly apiKey: string;
3
+ readonly baseUrl?: string;
4
+ readonly accountId?: string;
5
+ };
6
+ export declare const TokeniteAdmin: (config: TokeniteAdminConfig) => {
7
+ auth: {
8
+ register: (input: import("./types.js").RegisterUserInput) => Promise<import("./types.js").RegisterUserResult>;
9
+ login: (input: import("./types.js").LoginInput) => Promise<import("./types.js").LoginResult>;
10
+ me: () => Promise<import("./types.js").Me>;
11
+ createToken: (input: import("./types.js").CreateTokenInput) => Promise<import("./types.js").CreatedPat>;
12
+ listTokens: () => Promise<import("./types.js").PatRecord[]>;
13
+ revokeToken: (tokenId: string) => Promise<{
14
+ ok: true;
15
+ }>;
16
+ };
17
+ accounts: {
18
+ list: () => Promise<import("./types.js").AccountRecord[]>;
19
+ create: (input: import("./types.js").CreateAccountInput) => Promise<import("./types.js").AccountRecord>;
20
+ get: (id: string) => Promise<import("./types.js").AccountRecord & {
21
+ role: "owner" | "member";
22
+ }>;
23
+ update: (id: string, input: import("./types.js").UpdateAccountInput) => Promise<import("./types.js").AccountRecord>;
24
+ delete: (id: string) => Promise<{
25
+ ok: true;
26
+ }>;
27
+ invite: (accountId: string, input: import("./types.js").CreateInvitationInput) => Promise<import("./types.js").InvitationWithClaim>;
28
+ invitations: (accountId: string) => Promise<import("./types.js").InvitationRecord[]>;
29
+ cancelInvite: (accountId: string, invitationId: string) => Promise<{
30
+ ok: true;
31
+ }>;
32
+ members: (accountId: string) => Promise<import("./types.js").MemberRecord[]>;
33
+ updateMember: (accountId: string, userId: string, input: import("./types.js").UpdateMemberInput) => Promise<import("./types.js").MemberRecord>;
34
+ removeMember: (accountId: string, userId: string) => Promise<{
35
+ ok: true;
36
+ }>;
37
+ leave: (accountId: string) => Promise<{
38
+ ok: true;
39
+ }>;
40
+ claim: (input: import("./types.js").ClaimInvitationInput) => Promise<import("./types.js").ClaimInvitationResult>;
41
+ };
42
+ apps: {
43
+ create: (input: import("./types.js").CreateAppInput) => Promise<import("./types.js").CreatedApp>;
44
+ list: () => Promise<import("./types.js").AppRecord[]>;
45
+ get: (id: string) => Promise<import("./types.js").AppRecord>;
46
+ update: (id: string, input: import("./types.js").UpdateAppInput) => Promise<import("./types.js").AppRecord>;
47
+ rotateSecret: (id: string) => Promise<{
48
+ appSecret: string;
49
+ }>;
50
+ delete: (id: string) => Promise<{
51
+ ok: true;
52
+ }>;
53
+ };
54
+ keys: {
55
+ add: (input: import("./types.js").AddApiKeyInput) => Promise<import("./types.js").ApiKeyRecord>;
56
+ list: () => Promise<import("./types.js").ApiKeyRecord[]>;
57
+ remove: (id: string) => Promise<{
58
+ ok: true;
59
+ }>;
60
+ };
61
+ oauth: {
62
+ authorize: (input: import("./types.js").AuthorizeInput) => Promise<import("./types.js").AuthorizeResult>;
63
+ exchange: (input: import("./types.js").ExchangeInput) => Promise<import("./types.js").ExchangeResult>;
64
+ };
65
+ connections: {
66
+ list: () => Promise<import("./types.js").ConnectionRecord[]>;
67
+ stats: (id: string) => Promise<import("./types.js").ConnectionStats>;
68
+ setBudget: (id: string, budgetLimit: number) => Promise<{
69
+ ok: true;
70
+ }>;
71
+ suspend: (id: string) => Promise<{
72
+ ok: true;
73
+ }>;
74
+ resume: (id: string) => Promise<{
75
+ ok: true;
76
+ }>;
77
+ revoke: (id: string) => Promise<{
78
+ ok: true;
79
+ }>;
80
+ };
81
+ spending: {
82
+ list: (filters?: import("./types.js").SpendingFilters) => Promise<import("./types.js").SpendingEntry[]>;
83
+ };
84
+ };
85
+ export { AdminClientError } from './client.js';
86
+ export type { AdminClient, AdminClientConfig } from './client.js';
87
+ export type * from './types.js';
88
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,22 @@
1
+ import { createAdminClient } from './client.js';
2
+ import { createAuthApi } from './auth.js';
3
+ import { createAccountsApi } from './accounts.js';
4
+ import { createAppsApi } from './apps.js';
5
+ import { createKeysApi } from './keys.js';
6
+ import { createOAuthApi } from './oauth.js';
7
+ import { createConnectionsApi } from './connections.js';
8
+ import { createSpendingApi } from './spending.js';
9
+ export const TokeniteAdmin = (config) => {
10
+ const client = createAdminClient(config);
11
+ return {
12
+ auth: createAuthApi(client),
13
+ accounts: createAccountsApi(client),
14
+ apps: createAppsApi(client),
15
+ keys: createKeysApi(client),
16
+ oauth: createOAuthApi(client),
17
+ connections: createConnectionsApi(client),
18
+ spending: createSpendingApi(client),
19
+ };
20
+ };
21
+ export { AdminClientError } from './client.js';
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,10 @@
1
+ import type { AdminClient } from './client.js';
2
+ import type { ApiKeyRecord, AddApiKeyInput } from './types.js';
3
+ export declare const createKeysApi: (client: AdminClient) => {
4
+ add: (input: AddApiKeyInput) => Promise<ApiKeyRecord>;
5
+ list: () => Promise<ApiKeyRecord[]>;
6
+ remove: (id: string) => Promise<{
7
+ ok: true;
8
+ }>;
9
+ };
10
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1,6 @@
1
+ export const createKeysApi = (client) => ({
2
+ add: (input) => client.request('POST', '/api/keys', input),
3
+ list: () => client.request('GET', '/api/keys'),
4
+ remove: (id) => client.request('DELETE', `/api/keys/${id}`),
5
+ });
6
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1,7 @@
1
+ import type { AdminClient } from './client.js';
2
+ import type { AuthorizeInput, AuthorizeResult, ExchangeInput, ExchangeResult } from './types.js';
3
+ export declare const createOAuthApi: (client: AdminClient) => {
4
+ authorize: (input: AuthorizeInput) => Promise<AuthorizeResult>;
5
+ exchange: (input: ExchangeInput) => Promise<ExchangeResult>;
6
+ };
7
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1,15 @@
1
+ export const createOAuthApi = (client) => ({
2
+ authorize: (input) => client.request('POST', '/api/oauth/authorize', {
3
+ client_id: input.clientId,
4
+ redirect_uri: input.redirectUri,
5
+ budget_limit: input.budgetLimit,
6
+ ...(input.state ? { state: input.state } : {}),
7
+ }),
8
+ exchange: (input) => client.request('POST', '/api/oauth/token', {
9
+ code: input.code,
10
+ client_id: input.clientId,
11
+ client_secret: input.clientSecret,
12
+ redirect_uri: input.redirectUri,
13
+ }),
14
+ });
15
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1,6 @@
1
+ import type { AdminClient } from './client.js';
2
+ import type { SpendingFilters, SpendingEntry } from './types.js';
3
+ export declare const createSpendingApi: (client: AdminClient) => {
4
+ list: (filters?: SpendingFilters) => Promise<SpendingEntry[]>;
5
+ };
6
+ //# sourceMappingURL=spending.d.ts.map
@@ -0,0 +1,19 @@
1
+ const buildQuery = (filters) => {
2
+ const params = new URLSearchParams();
3
+ if (filters.appId)
4
+ params.set('appId', filters.appId);
5
+ if (filters.from)
6
+ params.set('from', filters.from);
7
+ if (filters.to)
8
+ params.set('to', filters.to);
9
+ if (filters.limit !== undefined)
10
+ params.set('limit', String(filters.limit));
11
+ if (filters.offset !== undefined)
12
+ params.set('offset', String(filters.offset));
13
+ const qs = params.toString();
14
+ return qs ? `?${qs}` : '';
15
+ };
16
+ export const createSpendingApi = (client) => ({
17
+ list: (filters = {}) => client.request('GET', `/api/spending${buildQuery(filters)}`),
18
+ });
19
+ //# sourceMappingURL=spending.js.map
@@ -0,0 +1,197 @@
1
+ import type { Provider } from '../types.js';
2
+ export type ModelStrategy = 'any' | 'tier' | 'models';
3
+ export type RequiredTier = 'cheap' | 'fast' | 'smart' | 'reasoning';
4
+ export type AppRecord = {
5
+ readonly id: string;
6
+ readonly builderId: string;
7
+ readonly name: string;
8
+ readonly callbackUrl: string;
9
+ readonly requiredProviders: readonly Provider[];
10
+ readonly preferredProviders: readonly Provider[];
11
+ readonly allowSubstitution: boolean;
12
+ readonly allowedModels?: readonly string[];
13
+ readonly modelStrategy: ModelStrategy;
14
+ readonly requiredTier?: RequiredTier;
15
+ readonly allowsManagedAgents?: boolean;
16
+ readonly websiteUrl?: string;
17
+ readonly description?: string;
18
+ readonly iconUrl?: string;
19
+ readonly createdAt: string;
20
+ };
21
+ export type CreatedApp = AppRecord & {
22
+ readonly appSecret: string;
23
+ };
24
+ export type CreateAppInput = {
25
+ readonly name: string;
26
+ readonly callbackUrl: string;
27
+ readonly requiredProviders: readonly Provider[];
28
+ readonly preferredProviders?: readonly Provider[];
29
+ readonly allowSubstitution?: boolean;
30
+ readonly allowedModels?: readonly string[];
31
+ readonly modelStrategy?: ModelStrategy;
32
+ readonly requiredTier?: RequiredTier;
33
+ readonly allowsManagedAgents?: boolean;
34
+ readonly websiteUrl?: string;
35
+ readonly description?: string;
36
+ readonly iconUrl?: string;
37
+ };
38
+ export type UpdateAppInput = Partial<CreateAppInput>;
39
+ export type ApiKeyRecord = {
40
+ readonly id: string;
41
+ readonly userId: string;
42
+ readonly provider: Provider;
43
+ readonly keyHint: string;
44
+ readonly isActive: boolean;
45
+ readonly createdAt: string;
46
+ };
47
+ export type AddApiKeyInput = {
48
+ readonly apiKey: string;
49
+ readonly provider?: Provider;
50
+ };
51
+ export type AuthorizeInput = {
52
+ readonly clientId: string;
53
+ readonly redirectUri: string;
54
+ readonly budgetLimit: number;
55
+ readonly state?: string;
56
+ };
57
+ export type AuthorizeResult = {
58
+ readonly redirect_to: string;
59
+ readonly code: string;
60
+ };
61
+ export type ExchangeInput = {
62
+ readonly code: string;
63
+ readonly clientId: string;
64
+ readonly clientSecret: string;
65
+ readonly redirectUri: string;
66
+ };
67
+ export type ExchangeResult = {
68
+ readonly access_token: string;
69
+ readonly token_type: string;
70
+ };
71
+ export type ConnectionRecord = {
72
+ readonly id: string;
73
+ readonly appId: string;
74
+ readonly appName: string;
75
+ readonly appWebsiteUrl: string | null;
76
+ readonly appDescription: string | null;
77
+ readonly appIconUrl: string | null;
78
+ readonly budgetLimit: number;
79
+ readonly budgetSpent: number;
80
+ readonly isSuspended: boolean;
81
+ readonly createdAt: string;
82
+ };
83
+ export type ConnectionStats = {
84
+ readonly totalRequests: number;
85
+ readonly totalTokens: number;
86
+ readonly totalCost: number;
87
+ };
88
+ export type SpendingFilters = {
89
+ readonly appId?: string;
90
+ readonly from?: string;
91
+ readonly to?: string;
92
+ readonly limit?: number;
93
+ readonly offset?: number;
94
+ };
95
+ export type SpendingEntry = {
96
+ readonly id: string;
97
+ readonly appName: string;
98
+ readonly provider: string;
99
+ readonly model: string;
100
+ readonly inputTokens: number;
101
+ readonly outputTokens: number;
102
+ readonly costUsd: number;
103
+ readonly platformFeeUsd: number;
104
+ readonly createdAt: string;
105
+ };
106
+ export type RegisterUserInput = {
107
+ readonly email: string;
108
+ readonly password: string;
109
+ };
110
+ export type RegisterUserResult = {
111
+ readonly userId: string;
112
+ readonly token: string;
113
+ };
114
+ export type LoginInput = RegisterUserInput;
115
+ export type LoginResult = {
116
+ readonly token: string;
117
+ };
118
+ export type Me = {
119
+ readonly userId: string;
120
+ readonly email: string;
121
+ };
122
+ export type CreateTokenInput = {
123
+ readonly name: string;
124
+ };
125
+ export type PatRecord = {
126
+ readonly id: string;
127
+ readonly name: string;
128
+ readonly keyHint: string;
129
+ readonly createdAt: string;
130
+ readonly lastUsedAt: string | null;
131
+ };
132
+ export type CreatedPat = PatRecord & {
133
+ readonly token: string;
134
+ };
135
+ export type AccountType = 'personal' | 'business';
136
+ export type PoolResetPeriod = 'monthly' | null;
137
+ export type AccountRecord = {
138
+ readonly id: string;
139
+ readonly type: AccountType;
140
+ readonly name: string;
141
+ readonly ownerUserId: string;
142
+ readonly poolBudgetLimitUsd: number | null;
143
+ readonly poolBudgetSpentUsd: number;
144
+ readonly poolResetPeriod: PoolResetPeriod;
145
+ readonly poolLastResetAt: string | null;
146
+ readonly deletedAt: string | null;
147
+ readonly createdAt: string;
148
+ /** Present on /api/accounts list responses; absent on bare account records. */
149
+ readonly role?: 'owner' | 'member';
150
+ };
151
+ export type CreateAccountInput = {
152
+ readonly type: 'business';
153
+ readonly name: string;
154
+ };
155
+ export type UpdateAccountInput = {
156
+ readonly name?: string;
157
+ readonly poolBudgetLimitUsd?: number | null;
158
+ readonly poolResetPeriod?: PoolResetPeriod;
159
+ };
160
+ export type InvitationRecord = {
161
+ readonly id: string;
162
+ readonly accountId: string;
163
+ readonly email: string;
164
+ readonly role: 'owner' | 'member';
165
+ readonly invitedByUserId: string;
166
+ readonly expiresAt: string;
167
+ readonly acceptedAt: string | null;
168
+ readonly createdAt: string;
169
+ };
170
+ export type InvitationWithClaim = InvitationRecord & {
171
+ readonly claimUrl: string;
172
+ };
173
+ export type CreateInvitationInput = {
174
+ readonly email: string;
175
+ readonly role?: 'owner' | 'member';
176
+ };
177
+ export type MemberRecord = {
178
+ readonly accountId: string;
179
+ readonly userId: string;
180
+ readonly email: string;
181
+ readonly role: 'owner' | 'member';
182
+ readonly monthlyCapUsd: number | null;
183
+ readonly joinedAt: string;
184
+ readonly mtdSpendUsd: number;
185
+ };
186
+ export type UpdateMemberInput = {
187
+ readonly role?: 'owner' | 'member';
188
+ readonly monthlyCapUsd?: number | null;
189
+ };
190
+ export type ClaimInvitationInput = {
191
+ readonly token: string;
192
+ };
193
+ export type ClaimInvitationResult = {
194
+ readonly accountId: string;
195
+ readonly role: 'owner' | 'member';
196
+ };
197
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,120 @@
1
+ import type { TokeniteConfig, AuthorizeOptions, PopupOptions, PopupResult, TokenResponse, Provider, ProxyCallOptions, ProxyResponse, AllowedProvidersResponse } from './types.js';
2
+ /**
3
+ * Tokenite client.
4
+ *
5
+ * Two ways to obtain an access token:
6
+ *
7
+ * **Modal (single-page apps)** — open an iframe consent screen and
8
+ * receive an OAuth authorization code. The code must be exchanged
9
+ * server-side because the exchange requires `clientSecret`:
10
+ * ```typescript
11
+ * const { code } = await tk.popup({ suggestedBudget: 5 });
12
+ * await fetch('/api/auth/exchange', {
13
+ * method: 'POST',
14
+ * body: JSON.stringify({ code }),
15
+ * });
16
+ * ```
17
+ *
18
+ * **Redirect (server-side)** — classic OAuth bounce:
19
+ * ```typescript
20
+ * res.redirect(tk.getAuthorizeUrl());
21
+ * // ...later in /callback:
22
+ * const { access_token } = await tk.exchangeCode(req.query.code);
23
+ * ```
24
+ *
25
+ * Once you have the access token, call the LLM through the proxy:
26
+ * ```typescript
27
+ * const result = await tk.call({
28
+ * accessToken,
29
+ * provider: 'anthropic',
30
+ * path: '/v1/messages',
31
+ * body: { model: 'claude-3-5-sonnet-latest', max_tokens: 1024, messages: [...] },
32
+ * });
33
+ * if (isProxyError(result)) console.error(result.error);
34
+ * else console.log(result.data);
35
+ * ```
36
+ *
37
+ * For streaming responses, use a vendor SDK with `baseURL: tk.proxyUrl(...)`
38
+ * — streams bypass the unified envelope and are forwarded as-is.
39
+ */
40
+ export declare const Tokenite: (config: TokeniteConfig) => {
41
+ /**
42
+ * Build the authorization URL for a full-page redirect.
43
+ * Supports optional suggested budget that pre-fills the consent screen.
44
+ */
45
+ getAuthorizeUrl: (options?: AuthorizeOptions) => string;
46
+ /**
47
+ * Open the consent screen and resolve with an OAuth authorization
48
+ * code when the user approves. The code must then be exchanged
49
+ * server-side via `tk.exchangeCode(code)` (the exchange requires
50
+ * `clientSecret`, which must never run in browser code).
51
+ *
52
+ * Two presentation modes:
53
+ *
54
+ * - `mode: 'iframe'` (default) — overlay an iframe modal in the
55
+ * current window. Cleaner UX, but the consent screen's host must
56
+ * allow being framed (no `X-Frame-Options: DENY`).
57
+ * - `mode: 'window'` — open a separate browser popup window via
58
+ * `window.open`. Works regardless of frame policy.
59
+ *
60
+ * ```typescript
61
+ * const { code } = await tk.popup({ suggestedBudget: 5 });
62
+ * await fetch('/api/auth/exchange', {
63
+ * method: 'POST',
64
+ * body: JSON.stringify({ code }),
65
+ * });
66
+ * ```
67
+ */
68
+ popup: (options?: PopupOptions) => Promise<PopupResult>;
69
+ /**
70
+ * Exchange an authorization code for an access token.
71
+ * Call this server-side in your callback handler.
72
+ * Requires clientSecret to be set in config.
73
+ */
74
+ exchangeCode: (code: string) => Promise<TokenResponse>;
75
+ /**
76
+ * Make an authenticated, non-streaming request through the proxy.
77
+ * Returns a unified envelope: `ProxySuccess` on success, `ProxyError`
78
+ * on failure. Narrow the result with `isProxyError` / `isProxySuccess`.
79
+ *
80
+ * For streaming responses, use a vendor SDK with `baseURL: tk.proxyUrl(...)`
81
+ * — streams bypass the envelope and are forwarded as-is.
82
+ *
83
+ * ```typescript
84
+ * const result = await tk.call({
85
+ * accessToken,
86
+ * provider: 'anthropic',
87
+ * path: '/v1/messages',
88
+ * body: { model: 'claude-3-5-sonnet-latest', max_tokens: 1024, messages: [...] },
89
+ * });
90
+ * ```
91
+ */
92
+ call: (options: ProxyCallOptions) => Promise<ProxyResponse>;
93
+ /**
94
+ * Fetch the access context for an access token: which app it belongs
95
+ * to and which providers the user has authorised it to call.
96
+ *
97
+ * The returned `providers` list is exactly the set that will succeed
98
+ * through `tk.call()` (budget permitting). Use it to render a picker,
99
+ * gate UI, or detect that the user is missing a required provider.
100
+ *
101
+ * ```typescript
102
+ * const { app, providers } = await tk.getAllowedProviders(accessToken);
103
+ * for (const p of providers) {
104
+ * console.log(p.displayName, p.logoUrl);
105
+ * }
106
+ * ```
107
+ */
108
+ getAllowedProviders: (accessToken: string) => Promise<AllowedProvidersResponse>;
109
+ /**
110
+ * Get the proxy URL for a specific provider.
111
+ * Use as `baseURL` in a vendor SDK for streaming requests, which
112
+ * bypass the unified envelope.
113
+ */
114
+ proxyUrl: (provider: Provider) => string;
115
+ /** The Tokenite dashboard base URL */
116
+ baseUrl: string;
117
+ /** The Tokenite proxy base URL */
118
+ proxyBase: string;
119
+ };
120
+ //# sourceMappingURL=client.d.ts.map