@codetunezstudios/token-kit 0.1.0-beta.3 → 0.1.0-beta.5

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025-2026 Codetunez Studios
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 Codetunez Studios
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  SOFTWARE.
package/README.md CHANGED
@@ -1,261 +1,263 @@
1
- # @codetunezstudios/token-kit
2
-
3
- [![npm version](https://img.shields.io/npm/v/@codetunezstudios/token-kit.svg)](https://www.npmjs.com/package/@codetunezstudios/token-kit)
4
- [![license](https://img.shields.io/npm/l/@codetunezstudios/token-kit.svg)](https://github.com/codetunez-studios/token-kit/blob/main/LICENSE)
5
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.0%2B-blue)](https://www.typescriptlang.org/)
6
- [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green)](https://nodejs.org/)
7
-
8
- > **Beta** — This SDK is under active development. APIs may change before 1.0.
9
-
10
- Official TypeScript/JavaScript SDK for [token-kit](https://token-kit.com) — the AI token infrastructure platform for developers.
11
-
12
- token-kit enables developers to integrate LLM features into their applications using an end-user-funded token model. Users purchase tokens, developers consume them for AI operations.
13
-
14
- ## Features
15
-
16
- - **Simple API** — Intuitive methods for chat completions
17
- - **TypeScript First** — Full type safety and IntelliSense support
18
- - **Multiple Models** — Support for Claude, GPT-4o, Amazon Nova (more coming)
19
- - **Token Management** — Built-in balance checking and validation
20
- - **Error Handling** — Comprehensive typed error classes
21
- - **Lightweight** — Single runtime dependency (axios)
22
-
23
- ## Installation
24
-
25
- ```bash
26
- npm install @codetunezstudios/token-kit
27
- ```
28
-
29
- ```bash
30
- yarn add @codetunezstudios/token-kit
31
- ```
32
-
33
- ```bash
34
- pnpm add @codetunezstudios/token-kit
35
- ```
36
-
37
- ## Quick Start
38
-
39
- ```typescript
40
- import TokenKit from '@codetunezstudios/token-kit';
41
-
42
- // Initialize with your developer API key
43
- const tk = new TokenKit({
44
- apiKey: process.env.TOKENKIT_API_KEY!,
45
- });
46
-
47
- // Make a chat request
48
- const res = await tk.chat('user_token_here', [
49
- TokenKit.user('What is token-kit?'),
50
- ]);
51
-
52
- console.log(res.message.content);
53
- console.log('Tokens used:', res.tokensDeducted);
54
- console.log('Balance:', res.userBalance);
55
- ```
56
-
57
- ## API Reference
58
-
59
- ### Constructor
60
-
61
- ```typescript
62
- const tk = new TokenKit(config);
63
- ```
64
-
65
- | Option | Type | Required | Default | Description |
66
- |--------|------|----------|---------|-------------|
67
- | `apiKey` | `string` | Yes | | Developer API key |
68
- | `baseUrl` | `string` | No | `https://api.token-kit.com/api/v1` | API base URL |
69
- | `timeout` | `number` | No | `60000` | Request timeout (ms) |
70
-
71
- ### Methods
72
-
73
- #### `tk.chat(userToken, messages, options?)`
74
-
75
- Send a chat completion request.
76
-
77
- ```typescript
78
- const res = await tk.chat('user_token', [
79
- TokenKit.system('You are a helpful assistant.'),
80
- TokenKit.user('Explain quantum computing simply.'),
81
- ], {
82
- model: 'gpt-4o',
83
- maxTokens: 200,
84
- temperature: 0.8,
85
- });
86
- ```
87
-
88
- **Options:**
89
-
90
- | Option | Type | Default | Description |
91
- |--------|------|---------|-------------|
92
- | `model` | `string` | `gpt-4o-mini` | LLM model to use |
93
- | `maxTokens` | `number` | `500` | Max tokens in response |
94
- | `temperature` | `number` | `0.7` | Randomness (0–2) |
95
-
96
- **Returns** `ChatResponse`:
97
-
98
- ```typescript
99
- {
100
- id: string;
101
- model: string;
102
- message: { role: 'assistant'; content: string };
103
- tokensUsed: { prompt: number; completion: number; total: number };
104
- tokensDeducted: number;
105
- finishReason: string;
106
- userBalance?: number;
107
- latency?: number;
108
- }
109
- ```
110
-
111
- #### `tk.setUserToken(userToken)`
112
-
113
- Set the user token for subsequent requests so you don't have to pass it each time.
114
-
115
- ```typescript
116
- tk.setUserToken('user_token');
117
-
118
- // Now you can omit the userToken parameter
119
- const res = await tk.chat([TokenKit.user('Hello!')]);
120
- ```
121
-
122
- #### `tk.validateToken(userToken?)`
123
-
124
- Validate a user token and check balance/limits.
125
-
126
- ```typescript
127
- const info = await tk.validateToken('user_token');
128
- if (info.valid) {
129
- console.log('Balance:', info.balance);
130
- }
131
- ```
132
-
133
- #### `tk.getBalance(userToken?)`
134
-
135
- Get the current token balance.
136
-
137
- ```typescript
138
- const balance = await tk.getBalance('user_token');
139
- ```
140
-
141
- #### `tk.getModels()`
142
-
143
- List available LLM models.
144
-
145
- ```typescript
146
- const models = await tk.getModels();
147
- // ['gpt-4o-mini', 'gpt-4o', 'claude-3.5-haiku', 'claude-sonnet-4', 'nova-micro', 'nova-lite']
148
- ```
149
-
150
- ### Helper Methods
151
-
152
- ```typescript
153
- TokenKit.user('message') // { role: 'user', content: 'message' }
154
- TokenKit.system('message') // { role: 'system', content: 'message' }
155
- TokenKit.assistant('message') // { role: 'assistant', content: 'message' }
156
- ```
157
-
158
- ## Error Handling
159
-
160
- ```typescript
161
- import TokenKit, { TokenKitAPIError } from '@codetunezstudios/token-kit';
162
-
163
- try {
164
- const res = await tk.chat(userToken, messages);
165
- } catch (err) {
166
- if (err instanceof TokenKitAPIError) {
167
- console.error(err.code); // 'INSUFFICIENT_BALANCE'
168
- console.error(err.statusCode); // 402
169
- console.error(err.message); // 'Insufficient token balance'
170
- }
171
- }
172
- ```
173
-
174
- **Error codes:**
175
-
176
- | Code | Status | Description |
177
- |------|--------|-------------|
178
- | `INVALID_API_KEY` | 401 | Developer API key is invalid |
179
- | `INVALID_TOKEN` | 401 | User token is invalid or expired |
180
- | `INSUFFICIENT_BALANCE` | 402 | Not enough tokens |
181
- | `RATE_LIMIT_EXCEEDED` | 429 | Too many requests |
182
- | `DAILY_LIMIT_EXCEEDED` | 429 | Daily spending limit reached |
183
- | `MONTHLY_LIMIT_EXCEEDED` | 429 | Monthly spending limit reached |
184
- | `MODEL_NOT_SUPPORTED` | 400 | Requested model is not available |
185
- | `TIMEOUT` | 504 | Request timed out |
186
- | `NETWORK_ERROR` | 503 | Cannot reach token-kit API |
187
-
188
- ## Express Integration Example
189
-
190
- ```typescript
191
- import express from 'express';
192
- import TokenKit from '@codetunezstudios/token-kit';
193
-
194
- const app = express();
195
- const tk = new TokenKit({ apiKey: process.env.TOKENKIT_API_KEY! });
196
-
197
- app.post('/api/chat', async (req, res) => {
198
- try {
199
- const { userToken, message } = req.body;
200
- const result = await tk.chat(userToken, [TokenKit.user(message)]);
201
- res.json({ reply: result.message.content, balance: result.userBalance });
202
- } catch (err) {
203
- res.status(500).json({ error: 'Chat failed' });
204
- }
205
- });
206
- ```
207
-
208
- > **Security:** Never expose your developer API key in client-side code. Always proxy requests through your backend.
209
-
210
- ## Token Pricing
211
-
212
- Different models consume tokens at different rates:
213
-
214
- | Model | Rate | 1,000 TK tokens = |
215
- |-------|------|-------------------|
216
- | GPT-4o Mini | 1.0x | 1,000 LLM tokens |
217
- | Claude 3.5 Haiku | 1.0x | 1,000 LLM tokens |
218
- | Amazon Nova Micro | 1.0x | 1,000 LLM tokens |
219
- | Amazon Nova Lite | 1.0x | 1,000 LLM tokens |
220
- | GPT-4o | 2.0x | 500 LLM tokens |
221
- | Claude Sonnet 4 | 3.0x | 333 LLM tokens |
222
-
223
- See [token-kit.com](https://token-kit.com) for current package pricing and details.
224
-
225
- ## Requirements
226
-
227
- - Node.js >= 18
228
- - TypeScript >= 5.0 (recommended)
229
-
230
- ## Development
231
-
232
- ```bash
233
- git clone https://github.com/codetunez-studios/token-kit.git
234
- cd token-kit
235
- npm install # Install dependencies
236
- npm run build # Build (CJS + ESM + types)
237
- npm test # Run tests
238
- npm run typecheck # Type checking
239
- ```
240
-
241
- ## Contributing
242
-
243
- Contributions are welcome! Please open an issue or submit a pull request.
244
-
245
- 1. Fork the repository
246
- 2. Create your feature branch (`git checkout -b feature/my-feature`)
247
- 3. Commit your changes (`git commit -m 'Add my feature'`)
248
- 4. Push to the branch (`git push origin feature/my-feature`)
249
- 5. Open a Pull Request
250
-
251
- ## License
252
-
253
- [MIT](LICENSE) © [Codetunez Studios](https://github.com/codetunez-studios)
254
-
255
- ## Links
256
-
257
- - [token-kit Platform](https://token-kit.com)
258
- - [User Token Portal](https://ai-tokens.me)
259
- - [Documentation](https://token-kit.com/sdk)
260
- - [npm Package](https://www.npmjs.com/package/@codetunezstudios/token-kit)
261
- - [GitHub Issues](https://github.com/codetunez-studios/token-kit/issues)
1
+ # @codetunezstudios/token-kit
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@codetunezstudios/token-kit.svg)](https://www.npmjs.com/package/@codetunezstudios/token-kit)
4
+ [![license](https://img.shields.io/npm/l/@codetunezstudios/token-kit.svg)](https://github.com/codetunez-studios/token-kit/blob/main/LICENSE)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0%2B-blue)](https://www.typescriptlang.org/)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green)](https://nodejs.org/)
7
+
8
+ > **Beta** — This SDK is under active development. APIs may change before 1.0.
9
+
10
+ Official TypeScript/JavaScript SDK for [token-kit](https://token-kit.com) — an AI billing and metering platform for developers.
11
+
12
+ token-kit enables developers to integrate LLM features with prepaid user-funded credits, spend controls, and cost visibility. It is especially useful for indie developers and small teams that want AI monetization without taking uncapped provider risk.
13
+
14
+ If your users already bring their own OpenAI or Anthropic keys, that can still be a valid approach. token-kit is best when you want one billing, routing, and control layer without exposing provider key management to end-users.
15
+
16
+ ## Features
17
+
18
+ - **Simple API** — Intuitive methods for chat completions
19
+ - **TypeScript First** — Full type safety and IntelliSense support
20
+ - **Multiple Models** — Support for Claude, GPT-4o, Amazon Nova (more coming)
21
+ - **Token Management** — Built-in balance checking and validation
22
+ - **Error Handling** — Comprehensive typed error classes
23
+ - **Lightweight** — Single runtime dependency (axios)
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ npm install @codetunezstudios/token-kit
29
+ ```
30
+
31
+ ```bash
32
+ yarn add @codetunezstudios/token-kit
33
+ ```
34
+
35
+ ```bash
36
+ pnpm add @codetunezstudios/token-kit
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ```typescript
42
+ import TokenKit from '@codetunezstudios/token-kit';
43
+
44
+ // Initialize with your developer API key
45
+ const tk = new TokenKit({
46
+ apiKey: process.env.TOKENKIT_API_KEY!,
47
+ });
48
+
49
+ // Make a chat request
50
+ const res = await tk.chat('user_token_here', [
51
+ TokenKit.user('What is token-kit?'),
52
+ ]);
53
+
54
+ console.log(res.message.content);
55
+ console.log('Tokens used:', res.tokensDeducted);
56
+ console.log('Balance:', res.userBalance);
57
+ ```
58
+
59
+ ## API Reference
60
+
61
+ ### Constructor
62
+
63
+ ```typescript
64
+ const tk = new TokenKit(config);
65
+ ```
66
+
67
+ | Option | Type | Required | Default | Description |
68
+ |--------|------|----------|---------|-------------|
69
+ | `apiKey` | `string` | Yes | | Developer API key |
70
+ | `baseUrl` | `string` | No | `https://api.token-kit.com/api/v1` | API base URL |
71
+ | `timeout` | `number` | No | `60000` | Request timeout (ms) |
72
+
73
+ ### Methods
74
+
75
+ #### `tk.chat(userToken, messages, options?)`
76
+
77
+ Send a chat completion request.
78
+
79
+ ```typescript
80
+ const res = await tk.chat('user_token', [
81
+ TokenKit.system('You are a helpful assistant.'),
82
+ TokenKit.user('Explain quantum computing simply.'),
83
+ ], {
84
+ model: 'gpt-4o',
85
+ maxTokens: 200,
86
+ temperature: 0.8,
87
+ });
88
+ ```
89
+
90
+ **Options:**
91
+
92
+ | Option | Type | Default | Description |
93
+ |--------|------|---------|-------------|
94
+ | `model` | `string` | `gpt-4o-mini` | LLM model to use |
95
+ | `maxTokens` | `number` | `500` | Max tokens in response |
96
+ | `temperature` | `number` | `0.7` | Randomness (0–2) |
97
+
98
+ **Returns** `ChatResponse`:
99
+
100
+ ```typescript
101
+ {
102
+ id: string;
103
+ model: string;
104
+ message: { role: 'assistant'; content: string };
105
+ tokensUsed: { prompt: number; completion: number; total: number };
106
+ tokensDeducted: number;
107
+ finishReason: string;
108
+ userBalance?: number;
109
+ latency?: number;
110
+ }
111
+ ```
112
+
113
+ #### `tk.setUserToken(userToken)`
114
+
115
+ Set the user token for subsequent requests so you don't have to pass it each time.
116
+
117
+ ```typescript
118
+ tk.setUserToken('user_token');
119
+
120
+ // Now you can omit the userToken parameter
121
+ const res = await tk.chat([TokenKit.user('Hello!')]);
122
+ ```
123
+
124
+ #### `tk.validateToken(userToken?)`
125
+
126
+ Validate a user token and check balance/limits.
127
+
128
+ ```typescript
129
+ const info = await tk.validateToken('user_token');
130
+ if (info.valid) {
131
+ console.log('Balance:', info.balance);
132
+ }
133
+ ```
134
+
135
+ #### `tk.getBalance(userToken?)`
136
+
137
+ Get the current token balance.
138
+
139
+ ```typescript
140
+ const balance = await tk.getBalance('user_token');
141
+ ```
142
+
143
+ #### `tk.getModels()`
144
+
145
+ List available LLM models.
146
+
147
+ ```typescript
148
+ const models = await tk.getModels();
149
+ // ['gpt-4o-mini', 'gpt-4o', 'claude-3.5-haiku', 'claude-sonnet-4', 'nova-micro', 'nova-lite']
150
+ ```
151
+
152
+ ### Helper Methods
153
+
154
+ ```typescript
155
+ TokenKit.user('message') // { role: 'user', content: 'message' }
156
+ TokenKit.system('message') // { role: 'system', content: 'message' }
157
+ TokenKit.assistant('message') // { role: 'assistant', content: 'message' }
158
+ ```
159
+
160
+ ## Error Handling
161
+
162
+ ```typescript
163
+ import TokenKit, { TokenKitAPIError } from '@codetunezstudios/token-kit';
164
+
165
+ try {
166
+ const res = await tk.chat(userToken, messages);
167
+ } catch (err) {
168
+ if (err instanceof TokenKitAPIError) {
169
+ console.error(err.code); // 'INSUFFICIENT_BALANCE'
170
+ console.error(err.statusCode); // 402
171
+ console.error(err.message); // 'Insufficient token balance'
172
+ }
173
+ }
174
+ ```
175
+
176
+ **Error codes:**
177
+
178
+ | Code | Status | Description |
179
+ |------|--------|-------------|
180
+ | `INVALID_API_KEY` | 401 | Developer API key is invalid |
181
+ | `INVALID_TOKEN` | 401 | User token is invalid or expired |
182
+ | `INSUFFICIENT_BALANCE` | 402 | Not enough tokens |
183
+ | `RATE_LIMIT_EXCEEDED` | 429 | Too many requests |
184
+ | `DAILY_LIMIT_EXCEEDED` | 429 | Daily spending limit reached |
185
+ | `MONTHLY_LIMIT_EXCEEDED` | 429 | Monthly spending limit reached |
186
+ | `MODEL_NOT_SUPPORTED` | 400 | Requested model is not available |
187
+ | `TIMEOUT` | 504 | Request timed out |
188
+ | `NETWORK_ERROR` | 503 | Cannot reach token-kit API |
189
+
190
+ ## Express Integration Example
191
+
192
+ ```typescript
193
+ import express from 'express';
194
+ import TokenKit from '@codetunezstudios/token-kit';
195
+
196
+ const app = express();
197
+ const tk = new TokenKit({ apiKey: process.env.TOKENKIT_API_KEY! });
198
+
199
+ app.post('/api/chat', async (req, res) => {
200
+ try {
201
+ const { userToken, message } = req.body;
202
+ const result = await tk.chat(userToken, [TokenKit.user(message)]);
203
+ res.json({ reply: result.message.content, balance: result.userBalance });
204
+ } catch (err) {
205
+ res.status(500).json({ error: 'Chat failed' });
206
+ }
207
+ });
208
+ ```
209
+
210
+ > **Security:** Never expose your developer API key in client-side code. Always proxy requests through your backend.
211
+
212
+ ## Token Pricing
213
+
214
+ Different models consume tokens at different rates:
215
+
216
+ | Model | Rate | 1,000 TK tokens = |
217
+ |-------|------|-------------------|
218
+ | GPT-4o Mini | 1.0x | 1,000 LLM tokens |
219
+ | Claude 3.5 Haiku | 1.0x | 1,000 LLM tokens |
220
+ | Amazon Nova Micro | 1.0x | 1,000 LLM tokens |
221
+ | Amazon Nova Lite | 1.0x | 1,000 LLM tokens |
222
+ | GPT-4o | 2.0x | 500 LLM tokens |
223
+ | Claude Sonnet 4 | 3.0x | 333 LLM tokens |
224
+
225
+ See [token-kit.com](https://token-kit.com) for current package pricing and details.
226
+
227
+ ## Requirements
228
+
229
+ - Node.js >= 18
230
+ - TypeScript >= 5.0 (recommended)
231
+
232
+ ## Development
233
+
234
+ ```bash
235
+ git clone https://github.com/codetunez-studios/token-kit.git
236
+ cd token-kit
237
+ npm install # Install dependencies
238
+ npm run build # Build (CJS + ESM + types)
239
+ npm test # Run tests
240
+ npm run typecheck # Type checking
241
+ ```
242
+
243
+ ## Contributing
244
+
245
+ Contributions are welcome! Please open an issue or submit a pull request.
246
+
247
+ 1. Fork the repository
248
+ 2. Create your feature branch (`git checkout -b feature/my-feature`)
249
+ 3. Commit your changes (`git commit -m 'Add my feature'`)
250
+ 4. Push to the branch (`git push origin feature/my-feature`)
251
+ 5. Open a Pull Request
252
+
253
+ ## License
254
+
255
+ [MIT](LICENSE) © [Codetunez Studios](https://github.com/codetunez-studios)
256
+
257
+ ## Links
258
+
259
+ - [token-kit Platform](https://token-kit.com)
260
+ - [User Token Portal](https://ai-tokens.me)
261
+ - [Documentation](https://token-kit.com/sdk)
262
+ - [npm Package](https://www.npmjs.com/package/@codetunezstudios/token-kit)
263
+ - [GitHub Issues](https://github.com/codetunez-studios/token-kit/issues)
package/dist/index.d.mts CHANGED
@@ -113,6 +113,66 @@ interface TokenKitConfig {
113
113
  timeout?: number;
114
114
  }
115
115
 
116
+ /**
117
+ * Token-Kit SDK — Portal Connect Helper
118
+ *
119
+ * Opens a popup to the ai-tokens.me /connect page, listens for the
120
+ * TOKEN_KIT_TOKEN postMessage from the portal, stores the token in
121
+ * localStorage, and resolves a promise with the token string.
122
+ *
123
+ * Rejects with TokenKitConnectCancelledError if the user closes the
124
+ * popup without confirming.
125
+ *
126
+ * Usage:
127
+ * ```typescript
128
+ * import { connectViaPortal } from '@codetunezstudios/token-kit';
129
+ *
130
+ * const userToken = await connectViaPortal({ clientId: 'app_abc123...' });
131
+ * tokenKit.setUserToken(userToken);
132
+ * ```
133
+ */
134
+ interface ConnectViaPortalOptions {
135
+ /** The clientId of the developer app (created in the token-kit.com Apps dashboard). */
136
+ clientId: string;
137
+ /**
138
+ * Base URL of the Token-Kit portal.
139
+ * Defaults to 'https://ai-tokens.me'.
140
+ * Override for local development: 'http://localhost:3000'
141
+ */
142
+ portalUrl?: string;
143
+ }
144
+ /**
145
+ * Thrown by connectViaPortal() when the user closes the popup without
146
+ * clicking "Allow Access".
147
+ */
148
+ declare class TokenKitConnectCancelledError extends Error {
149
+ constructor();
150
+ }
151
+ /**
152
+ * Open a Token-Kit portal popup to acquire a user token via postMessage.
153
+ *
154
+ * Flow:
155
+ * 1. Opens `${portalUrl}/connect?appId=...&origin=...` as a 480×640 popup
156
+ * 2. Listens for `message` events filtered to the portal origin and
157
+ * `type === 'TOKEN_KIT_TOKEN'`
158
+ * 3. On receipt: stores token in localStorage, resolves with the token string
159
+ * 4. If popup is closed without a message: rejects with TokenKitConnectCancelledError
160
+ *
161
+ * @param options - Connection options
162
+ * @returns Promise that resolves with the user token string
163
+ */
164
+ declare function connectViaPortal(options: ConnectViaPortalOptions): Promise<string>;
165
+ /**
166
+ * Retrieve the most recently connected user token from localStorage.
167
+ * Returns null if no token has been stored via connectViaPortal().
168
+ */
169
+ declare function getStoredUserToken(): string | null;
170
+ /**
171
+ * Clear the stored user token from localStorage.
172
+ * Call this on logout.
173
+ */
174
+ declare function clearStoredUserToken(): void;
175
+
116
176
  /**
117
177
  * Token-Kit SDK - Main Entry Point
118
178
  * Official TypeScript SDK for Token-Kit platform
@@ -251,4 +311,4 @@ declare class TokenKit {
251
311
  static assistant(content: string): Message;
252
312
  }
253
313
 
254
- export { type ChatOptions, type ChatResponse, ENVIRONMENT_URLS, type Message, type MessageRole, type ModelInfo, type ModelsResponse, TokenKit, TokenKitAPIError, type TokenKitConfig, type TokenKitEnvironment, type TokenValidationResponse, TokenKit as default };
314
+ export { type ChatOptions, type ChatResponse, type ConnectViaPortalOptions, ENVIRONMENT_URLS, type Message, type MessageRole, type ModelInfo, type ModelsResponse, TokenKit, TokenKitAPIError, type TokenKitConfig, TokenKitConnectCancelledError, type TokenKitEnvironment, type TokenValidationResponse, clearStoredUserToken, connectViaPortal, TokenKit as default, getStoredUserToken };
package/dist/index.d.ts CHANGED
@@ -113,6 +113,66 @@ interface TokenKitConfig {
113
113
  timeout?: number;
114
114
  }
115
115
 
116
+ /**
117
+ * Token-Kit SDK — Portal Connect Helper
118
+ *
119
+ * Opens a popup to the ai-tokens.me /connect page, listens for the
120
+ * TOKEN_KIT_TOKEN postMessage from the portal, stores the token in
121
+ * localStorage, and resolves a promise with the token string.
122
+ *
123
+ * Rejects with TokenKitConnectCancelledError if the user closes the
124
+ * popup without confirming.
125
+ *
126
+ * Usage:
127
+ * ```typescript
128
+ * import { connectViaPortal } from '@codetunezstudios/token-kit';
129
+ *
130
+ * const userToken = await connectViaPortal({ clientId: 'app_abc123...' });
131
+ * tokenKit.setUserToken(userToken);
132
+ * ```
133
+ */
134
+ interface ConnectViaPortalOptions {
135
+ /** The clientId of the developer app (created in the token-kit.com Apps dashboard). */
136
+ clientId: string;
137
+ /**
138
+ * Base URL of the Token-Kit portal.
139
+ * Defaults to 'https://ai-tokens.me'.
140
+ * Override for local development: 'http://localhost:3000'
141
+ */
142
+ portalUrl?: string;
143
+ }
144
+ /**
145
+ * Thrown by connectViaPortal() when the user closes the popup without
146
+ * clicking "Allow Access".
147
+ */
148
+ declare class TokenKitConnectCancelledError extends Error {
149
+ constructor();
150
+ }
151
+ /**
152
+ * Open a Token-Kit portal popup to acquire a user token via postMessage.
153
+ *
154
+ * Flow:
155
+ * 1. Opens `${portalUrl}/connect?appId=...&origin=...` as a 480×640 popup
156
+ * 2. Listens for `message` events filtered to the portal origin and
157
+ * `type === 'TOKEN_KIT_TOKEN'`
158
+ * 3. On receipt: stores token in localStorage, resolves with the token string
159
+ * 4. If popup is closed without a message: rejects with TokenKitConnectCancelledError
160
+ *
161
+ * @param options - Connection options
162
+ * @returns Promise that resolves with the user token string
163
+ */
164
+ declare function connectViaPortal(options: ConnectViaPortalOptions): Promise<string>;
165
+ /**
166
+ * Retrieve the most recently connected user token from localStorage.
167
+ * Returns null if no token has been stored via connectViaPortal().
168
+ */
169
+ declare function getStoredUserToken(): string | null;
170
+ /**
171
+ * Clear the stored user token from localStorage.
172
+ * Call this on logout.
173
+ */
174
+ declare function clearStoredUserToken(): void;
175
+
116
176
  /**
117
177
  * Token-Kit SDK - Main Entry Point
118
178
  * Official TypeScript SDK for Token-Kit platform
@@ -251,4 +311,4 @@ declare class TokenKit {
251
311
  static assistant(content: string): Message;
252
312
  }
253
313
 
254
- export { type ChatOptions, type ChatResponse, ENVIRONMENT_URLS, type Message, type MessageRole, type ModelInfo, type ModelsResponse, TokenKit, TokenKitAPIError, type TokenKitConfig, type TokenKitEnvironment, type TokenValidationResponse, TokenKit as default };
314
+ export { type ChatOptions, type ChatResponse, type ConnectViaPortalOptions, ENVIRONMENT_URLS, type Message, type MessageRole, type ModelInfo, type ModelsResponse, TokenKit, TokenKitAPIError, type TokenKitConfig, TokenKitConnectCancelledError, type TokenKitEnvironment, type TokenValidationResponse, clearStoredUserToken, connectViaPortal, TokenKit as default, getStoredUserToken };
package/dist/index.js CHANGED
@@ -33,7 +33,11 @@ __export(index_exports, {
33
33
  ENVIRONMENT_URLS: () => ENVIRONMENT_URLS,
34
34
  TokenKit: () => TokenKit,
35
35
  TokenKitAPIError: () => TokenKitAPIError,
36
- default: () => index_default
36
+ TokenKitConnectCancelledError: () => TokenKitConnectCancelledError,
37
+ clearStoredUserToken: () => clearStoredUserToken,
38
+ connectViaPortal: () => connectViaPortal,
39
+ default: () => index_default,
40
+ getStoredUserToken: () => getStoredUserToken
37
41
  });
38
42
  module.exports = __toCommonJS(index_exports);
39
43
 
@@ -203,6 +207,67 @@ var TokenKitClient = class {
203
207
  }
204
208
  };
205
209
 
210
+ // src/connect.ts
211
+ var TokenKitConnectCancelledError = class _TokenKitConnectCancelledError extends Error {
212
+ constructor() {
213
+ super("User closed the Token-Kit connect popup without confirming.");
214
+ this.name = "TokenKitConnectCancelledError";
215
+ Object.setPrototypeOf(this, _TokenKitConnectCancelledError.prototype);
216
+ }
217
+ };
218
+ var STORAGE_KEY = "tokenkit_user_token";
219
+ async function connectViaPortal(options) {
220
+ const portalUrl = (options.portalUrl ?? "https://ai-tokens.me").replace(/\/$/, "");
221
+ const currentOrigin = encodeURIComponent(window.location.origin);
222
+ const url = `${portalUrl}/connect?clientId=${encodeURIComponent(options.clientId)}&origin=${currentOrigin}`;
223
+ const popup = window.open(
224
+ url,
225
+ "tokenkit-connect",
226
+ "width=480,height=640,scrollbars=no,resizable=no,status=no,toolbar=no,menubar=no"
227
+ );
228
+ if (!popup) {
229
+ throw new Error(
230
+ "Failed to open Token-Kit connect popup. Ensure popups are allowed for this origin, or call connectViaPortal() directly from a user gesture (e.g. button click)."
231
+ );
232
+ }
233
+ return new Promise((resolve, reject) => {
234
+ function onMessage(event) {
235
+ if (event.origin !== new URL(portalUrl).origin) return;
236
+ const data = event.data;
237
+ if (data?.type !== "TOKEN_KIT_TOKEN" || typeof data.token !== "string" || !data.token) {
238
+ return;
239
+ }
240
+ cleanup();
241
+ localStorage.setItem(STORAGE_KEY, data.token);
242
+ resolve(data.token);
243
+ }
244
+ const pollInterval = setInterval(() => {
245
+ if (popup.closed) {
246
+ cleanup();
247
+ reject(new TokenKitConnectCancelledError());
248
+ }
249
+ }, 400);
250
+ function cleanup() {
251
+ window.removeEventListener("message", onMessage);
252
+ clearInterval(pollInterval);
253
+ }
254
+ window.addEventListener("message", onMessage);
255
+ });
256
+ }
257
+ function getStoredUserToken() {
258
+ try {
259
+ return localStorage.getItem(STORAGE_KEY);
260
+ } catch {
261
+ return null;
262
+ }
263
+ }
264
+ function clearStoredUserToken() {
265
+ try {
266
+ localStorage.removeItem(STORAGE_KEY);
267
+ } catch {
268
+ }
269
+ }
270
+
206
271
  // src/index.ts
207
272
  var TokenKit = class {
208
273
  /**
@@ -367,5 +432,9 @@ var index_default = TokenKit;
367
432
  0 && (module.exports = {
368
433
  ENVIRONMENT_URLS,
369
434
  TokenKit,
370
- TokenKitAPIError
435
+ TokenKitAPIError,
436
+ TokenKitConnectCancelledError,
437
+ clearStoredUserToken,
438
+ connectViaPortal,
439
+ getStoredUserToken
371
440
  });
package/dist/index.mjs CHANGED
@@ -164,6 +164,67 @@ var TokenKitClient = class {
164
164
  }
165
165
  };
166
166
 
167
+ // src/connect.ts
168
+ var TokenKitConnectCancelledError = class _TokenKitConnectCancelledError extends Error {
169
+ constructor() {
170
+ super("User closed the Token-Kit connect popup without confirming.");
171
+ this.name = "TokenKitConnectCancelledError";
172
+ Object.setPrototypeOf(this, _TokenKitConnectCancelledError.prototype);
173
+ }
174
+ };
175
+ var STORAGE_KEY = "tokenkit_user_token";
176
+ async function connectViaPortal(options) {
177
+ const portalUrl = (options.portalUrl ?? "https://ai-tokens.me").replace(/\/$/, "");
178
+ const currentOrigin = encodeURIComponent(window.location.origin);
179
+ const url = `${portalUrl}/connect?clientId=${encodeURIComponent(options.clientId)}&origin=${currentOrigin}`;
180
+ const popup = window.open(
181
+ url,
182
+ "tokenkit-connect",
183
+ "width=480,height=640,scrollbars=no,resizable=no,status=no,toolbar=no,menubar=no"
184
+ );
185
+ if (!popup) {
186
+ throw new Error(
187
+ "Failed to open Token-Kit connect popup. Ensure popups are allowed for this origin, or call connectViaPortal() directly from a user gesture (e.g. button click)."
188
+ );
189
+ }
190
+ return new Promise((resolve, reject) => {
191
+ function onMessage(event) {
192
+ if (event.origin !== new URL(portalUrl).origin) return;
193
+ const data = event.data;
194
+ if (data?.type !== "TOKEN_KIT_TOKEN" || typeof data.token !== "string" || !data.token) {
195
+ return;
196
+ }
197
+ cleanup();
198
+ localStorage.setItem(STORAGE_KEY, data.token);
199
+ resolve(data.token);
200
+ }
201
+ const pollInterval = setInterval(() => {
202
+ if (popup.closed) {
203
+ cleanup();
204
+ reject(new TokenKitConnectCancelledError());
205
+ }
206
+ }, 400);
207
+ function cleanup() {
208
+ window.removeEventListener("message", onMessage);
209
+ clearInterval(pollInterval);
210
+ }
211
+ window.addEventListener("message", onMessage);
212
+ });
213
+ }
214
+ function getStoredUserToken() {
215
+ try {
216
+ return localStorage.getItem(STORAGE_KEY);
217
+ } catch {
218
+ return null;
219
+ }
220
+ }
221
+ function clearStoredUserToken() {
222
+ try {
223
+ localStorage.removeItem(STORAGE_KEY);
224
+ } catch {
225
+ }
226
+ }
227
+
167
228
  // src/index.ts
168
229
  var TokenKit = class {
169
230
  /**
@@ -328,5 +389,9 @@ export {
328
389
  ENVIRONMENT_URLS,
329
390
  TokenKit,
330
391
  TokenKitAPIError,
331
- index_default as default
392
+ TokenKitConnectCancelledError,
393
+ clearStoredUserToken,
394
+ connectViaPortal,
395
+ index_default as default,
396
+ getStoredUserToken
332
397
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codetunezstudios/token-kit",
3
- "version": "0.1.0-beta.3",
3
+ "version": "0.1.0-beta.5",
4
4
  "description": "Official TypeScript SDK for token-kit - AI token infrastructure for developers",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -57,7 +57,8 @@
57
57
  "access": "public"
58
58
  },
59
59
  "dependencies": {
60
- "axios": "^1.6.5"
60
+ "axios": "^1.6.5",
61
+ "jest-environment-jsdom": "^30.3.0"
61
62
  },
62
63
  "devDependencies": {
63
64
  "@types/express": "^5.0.6",