@onlyworlds/sdk 2.0.1 → 2.1.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/LICENSE +21 -21
- package/README.md +164 -172
- package/dist/index.d.mts +287 -7
- package/dist/index.d.ts +287 -7
- package/dist/index.js +178 -8
- package/dist/index.mjs +177 -8
- package/package.json +6 -2
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 OnlyWorlds
|
|
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
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2025 OnlyWorlds
|
|
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
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# OnlyWorlds TypeScript SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@onlyworlds/sdk)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A type-safe TypeScript SDK for building world-building applications with the OnlyWorlds API.
|
|
4
7
|
|
|
5
8
|
## Installation
|
|
6
9
|
|
|
7
10
|
```bash
|
|
8
11
|
npm install @onlyworlds/sdk
|
|
9
|
-
# or
|
|
10
|
-
yarn add @onlyworlds/sdk
|
|
11
12
|
```
|
|
12
13
|
|
|
13
14
|
## Quick Start
|
|
@@ -15,248 +16,239 @@ yarn add @onlyworlds/sdk
|
|
|
15
16
|
```typescript
|
|
16
17
|
import { OnlyWorldsClient } from '@onlyworlds/sdk';
|
|
17
18
|
|
|
18
|
-
// Initialize the client
|
|
19
19
|
const client = new OnlyWorldsClient({
|
|
20
20
|
apiKey: 'your-api-key',
|
|
21
|
-
apiPin: '
|
|
21
|
+
apiPin: '1234',
|
|
22
|
+
baseUrl: 'https://onlyworlds.com'
|
|
22
23
|
});
|
|
23
24
|
|
|
24
|
-
//
|
|
25
|
-
const
|
|
26
|
-
name: 'Aragorn',
|
|
27
|
-
description: 'Heir of Isildur',
|
|
28
|
-
location_id: 'uuid-of-location',
|
|
29
|
-
abilities_ids: ['uuid1', 'uuid2']
|
|
30
|
-
});
|
|
25
|
+
// Get your world (API keys are world-scoped)
|
|
26
|
+
const world = await client.worlds.get();
|
|
31
27
|
|
|
32
|
-
//
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
// Fetch characters (paginated)
|
|
29
|
+
const characters = await client.characters.list();
|
|
30
|
+
|
|
31
|
+
// Create a new location
|
|
32
|
+
const location = await client.locations.create({
|
|
33
|
+
name: 'Dragon Peak',
|
|
34
|
+
description: 'A treacherous mountain peak where dragons nest',
|
|
35
|
+
supertype: 'mountain'
|
|
37
36
|
});
|
|
38
|
-
```
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
// Get a specific element
|
|
39
|
+
const character = await client.characters.get('element-id');
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
- 🚀 **Simple API** - Intuitive methods for CRUD operations
|
|
47
|
-
- 📄 **Auto-completion** - IDE support for all fields and methods
|
|
41
|
+
// Update an element
|
|
42
|
+
await client.characters.update('element-id', {
|
|
43
|
+
name: 'Updated Name'
|
|
44
|
+
});
|
|
48
45
|
|
|
49
|
-
|
|
46
|
+
// Delete an element
|
|
47
|
+
await client.characters.delete('element-id');
|
|
48
|
+
```
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
## Features
|
|
52
51
|
|
|
53
|
-
- **
|
|
54
|
-
- **
|
|
55
|
-
- **
|
|
56
|
-
- **
|
|
52
|
+
- ✅ **Full Type Safety** - Complete TypeScript definitions for all 22 OnlyWorlds element types
|
|
53
|
+
- ✅ **Auto-Generated Types** - Types synchronized with the latest OnlyWorlds schema
|
|
54
|
+
- ✅ **CRUD Operations** - Create, read, update, and delete operations for all elements
|
|
55
|
+
- ✅ **Token Management** - Built-in support for OnlyWorlds token rating system
|
|
56
|
+
- ✅ **Branded Types** - Compile-time safety for element relationships
|
|
57
|
+
- ✅ **Zero Runtime Overhead** - Type system has no runtime cost
|
|
58
|
+
- ✅ **Modern ESM/CJS** - Supports both ES modules and CommonJS
|
|
57
59
|
|
|
58
60
|
## API Reference
|
|
59
61
|
|
|
60
|
-
###
|
|
62
|
+
### World Endpoint
|
|
63
|
+
|
|
64
|
+
The `worlds` resource is special because API keys are world-scoped (one key = one world). The endpoint returns a single `World` object directly, not a paginated list.
|
|
61
65
|
|
|
62
66
|
```typescript
|
|
63
|
-
|
|
67
|
+
// Get your world
|
|
68
|
+
const world = await client.worlds.get();
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
baseUrl: 'custom-url' // Optional, defaults to onlyworlds.com
|
|
70
|
+
// Update your world
|
|
71
|
+
const updated = await client.worlds.update({
|
|
72
|
+
description: 'A dark fantasy realm'
|
|
69
73
|
});
|
|
70
74
|
```
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
**Note**: The `worlds` resource only has `get()` and `update()` methods (no `list()`, `create()`, or `delete()`) because API keys are world-scoped.
|
|
77
|
+
|
|
78
|
+
### Element Endpoints
|
|
73
79
|
|
|
74
|
-
All element types
|
|
80
|
+
All other element types return paginated results:
|
|
75
81
|
|
|
76
82
|
```typescript
|
|
77
|
-
// List with
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
// List with pagination
|
|
84
|
+
const response = await client.characters.list({
|
|
85
|
+
limit: 10,
|
|
86
|
+
offset: 0,
|
|
87
|
+
ordering: '-created_at',
|
|
88
|
+
search: 'dragon'
|
|
83
89
|
});
|
|
84
90
|
|
|
85
|
-
//
|
|
86
|
-
|
|
91
|
+
console.log(response.count); // Total count
|
|
92
|
+
console.log(response.results); // Array of Characters
|
|
93
|
+
console.log(response.next); // URL for next page
|
|
94
|
+
console.log(response.previous); // URL for previous page
|
|
95
|
+
```
|
|
87
96
|
|
|
88
|
-
|
|
89
|
-
const newChar = await client.characters.create({
|
|
90
|
-
name: 'Gandalf',
|
|
91
|
-
description: 'A wizard'
|
|
92
|
-
});
|
|
97
|
+
## Type-Safe Relationships
|
|
93
98
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
description: 'A wizard, also known as Mithrandir'
|
|
97
|
-
});
|
|
99
|
+
```typescript
|
|
100
|
+
import { ElementId, Character, Location } from '@onlyworlds/sdk';
|
|
98
101
|
|
|
99
|
-
//
|
|
100
|
-
|
|
102
|
+
// Branded types ensure you can't mix up element IDs
|
|
103
|
+
const locationId: ElementId<'Location'> = 'some-location-id';
|
|
104
|
+
const character: Character = {
|
|
105
|
+
name: 'Aragorn',
|
|
106
|
+
location: locationId // Type-safe!
|
|
107
|
+
};
|
|
101
108
|
```
|
|
102
109
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
The SDK handles OnlyWorlds' `_id`/`_ids` pattern automatically:
|
|
110
|
+
## Token Management
|
|
106
111
|
|
|
107
|
-
|
|
108
|
-
// Creating with relationships
|
|
109
|
-
const character = await client.characters.create({
|
|
110
|
-
name: 'Frodo',
|
|
111
|
-
birthplace_id: 'location-uuid', // Single relationship
|
|
112
|
-
abilities_ids: ['uuid1', 'uuid2'], // Multi relationship
|
|
113
|
-
friends_ids: ['sam-uuid', 'merry-uuid']
|
|
114
|
-
});
|
|
112
|
+
OnlyWorlds provides a token rating system for tracking API usage and enabling AI-powered features. Users get a daily token allowance (default: 10,000 tokens) that resets every day.
|
|
115
113
|
|
|
116
|
-
|
|
117
|
-
console.log(character.birthplace.name); // "The Shire"
|
|
118
|
-
console.log(character.abilities[0].name); // "Ring Bearer"
|
|
119
|
-
```
|
|
114
|
+
### Working Reference Implementation
|
|
120
115
|
|
|
121
|
-
|
|
116
|
+
See [base-tool/src/llm/token-service.ts](https://github.com/OnlyWorlds/base-tool) for the complete working implementation that this SDK enables.
|
|
122
117
|
|
|
123
|
-
|
|
118
|
+
### Check Token Status
|
|
124
119
|
|
|
125
120
|
```typescript
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
CharacterInput,
|
|
129
|
-
Location,
|
|
130
|
-
ElementType
|
|
131
|
-
} from '@onlyworlds/sdk';
|
|
132
|
-
|
|
133
|
-
// Use in your functions
|
|
134
|
-
function createHero(data: CharacterInput): Promise<Character> {
|
|
135
|
-
return client.characters.create(data);
|
|
136
|
-
}
|
|
121
|
+
// Get current token status
|
|
122
|
+
const status = await client.tokens.getStatus();
|
|
137
123
|
|
|
138
|
-
|
|
139
|
-
console.log(
|
|
124
|
+
console.log(`Available: ${status.tokens_available_today}/${status.token_rating}`);
|
|
125
|
+
console.log(`Used today: ${status.tokens_used_today}`);
|
|
126
|
+
console.log(`Active sessions: ${status.sessions_active}`);
|
|
127
|
+
console.log(`Last reset: ${status.last_reset}`);
|
|
140
128
|
```
|
|
141
129
|
|
|
142
|
-
###
|
|
130
|
+
### Consume Tokens
|
|
143
131
|
|
|
144
|
-
|
|
132
|
+
Report token consumption when your tool uses AI features or other token-tracked services:
|
|
145
133
|
|
|
146
134
|
```typescript
|
|
147
|
-
//
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
location_id: location.id
|
|
159
|
-
})
|
|
160
|
-
)
|
|
161
|
-
);
|
|
135
|
+
// Report token usage
|
|
136
|
+
const result = await client.tokens.consume({
|
|
137
|
+
amount: 500,
|
|
138
|
+
service: 'my_worldbuilding_tool',
|
|
139
|
+
metadata: {
|
|
140
|
+
feature: 'character_generation',
|
|
141
|
+
model: 'gpt-4',
|
|
142
|
+
prompt_tokens: 300,
|
|
143
|
+
completion_tokens: 200
|
|
144
|
+
}
|
|
145
|
+
});
|
|
162
146
|
|
|
163
|
-
|
|
147
|
+
// Check if consumption succeeded
|
|
148
|
+
if (result.error) {
|
|
149
|
+
console.warn('Token warning:', result.error);
|
|
164
150
|
}
|
|
165
|
-
```
|
|
166
151
|
|
|
167
|
-
|
|
152
|
+
console.log(`Consumed ${result.tokens_consumed} tokens`);
|
|
153
|
+
console.log(`${result.tokens_remaining} tokens remaining`);
|
|
154
|
+
```
|
|
168
155
|
|
|
169
|
-
|
|
170
|
-
// Find all wizards in a specific location
|
|
171
|
-
const wizards = await client.characters.list({
|
|
172
|
-
search: 'wizard',
|
|
173
|
-
location: 'location-uuid',
|
|
174
|
-
ordering: '-level'
|
|
175
|
-
});
|
|
156
|
+
**Important**: The API allows consumption even when exceeding available tokens (tracks as debt), but returns a warning in the `error` field.
|
|
176
157
|
|
|
177
|
-
|
|
178
|
-
const recent = await client.events.list({
|
|
179
|
-
ordering: '-updated_at',
|
|
180
|
-
limit: 5
|
|
181
|
-
});
|
|
182
|
-
```
|
|
158
|
+
### Advanced: Encrypted API Key Access
|
|
183
159
|
|
|
184
|
-
|
|
160
|
+
For tools that need direct OpenAI API access using OnlyWorlds tokens:
|
|
185
161
|
|
|
186
162
|
```typescript
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
} catch (error) {
|
|
190
|
-
if (error.message.includes('404')) {
|
|
191
|
-
console.log('Character not found');
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
```
|
|
163
|
+
// Get encrypted OpenAI key (requires 100+ tokens)
|
|
164
|
+
const access = await client.tokens.getAccessKey();
|
|
195
165
|
|
|
196
|
-
|
|
166
|
+
console.log('Session ID:', access.session_id);
|
|
167
|
+
console.log('Expires:', access.expires_at);
|
|
168
|
+
console.log('Available tokens:', access.tokens_available);
|
|
197
169
|
|
|
198
|
-
|
|
170
|
+
// Decrypt the key client-side (see base-tool for full implementation)
|
|
171
|
+
// 1. Derive decryption key from world ID using SHA-256
|
|
172
|
+
// 2. Use 'fernet' npm package to decrypt
|
|
173
|
+
// 3. Use decrypted OpenAI key for direct API calls
|
|
174
|
+
// 4. Report usage with session_id
|
|
199
175
|
|
|
200
|
-
|
|
201
|
-
|
|
176
|
+
// See base-tool/src/llm/token-service.ts:99-235 for complete example
|
|
177
|
+
```
|
|
202
178
|
|
|
203
|
-
|
|
179
|
+
**Full decryption implementation** (based on base-tool):
|
|
204
180
|
|
|
205
181
|
```typescript
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
182
|
+
import { fernet } from 'fernet';
|
|
183
|
+
|
|
184
|
+
// Derive decryption key from world ID
|
|
185
|
+
async function deriveKey(worldId: string): Promise<string> {
|
|
186
|
+
const salt = 'onlyworlds-token-api-2024-public-salt';
|
|
187
|
+
const keyMaterial = `${worldId}:${salt}`;
|
|
188
|
+
const encoder = new TextEncoder();
|
|
189
|
+
const data = encoder.encode(keyMaterial);
|
|
190
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
191
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
192
|
+
const base64 = btoa(String.fromCharCode(...hashArray));
|
|
193
|
+
return base64.replace(/\+/g, '-').replace(/\//g, '_');
|
|
211
194
|
}
|
|
212
195
|
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
196
|
+
// Decrypt the API key
|
|
197
|
+
async function decryptApiKey(encryptedKey: string, worldId: string): Promise<string> {
|
|
198
|
+
const derivedKey = await deriveKey(worldId);
|
|
199
|
+
const secret = new fernet.Secret(derivedKey);
|
|
200
|
+
const token = new fernet.Token({
|
|
201
|
+
secret: secret,
|
|
202
|
+
token: encryptedKey,
|
|
203
|
+
ttl: 0 // Don't enforce TTL client-side
|
|
204
|
+
});
|
|
205
|
+
return token.decode();
|
|
218
206
|
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
## Helper Methods
|
|
222
207
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
208
|
+
// Usage
|
|
209
|
+
const world = await client.worlds.get();
|
|
210
|
+
const access = await client.tokens.getAccessKey();
|
|
211
|
+
const apiKey = await decryptApiKey(access.encrypted_key, world.id);
|
|
212
|
+
|
|
213
|
+
// Use apiKey for OpenAI API calls, then report usage:
|
|
214
|
+
await client.tokens.consume({
|
|
215
|
+
amount: tokensUsed,
|
|
216
|
+
sessionId: access.session_id,
|
|
217
|
+
service: 'direct_openai',
|
|
218
|
+
metadata: { model: 'gpt-4', /* ... */ }
|
|
229
219
|
});
|
|
230
|
-
// Result: { name: 'Test', location_id: 'uuid', abilities_ids: ['uuid1', 'uuid2'] }
|
|
231
220
|
```
|
|
232
221
|
|
|
233
|
-
|
|
222
|
+
### Session Management
|
|
234
223
|
|
|
235
|
-
|
|
236
|
-
|
|
224
|
+
```typescript
|
|
225
|
+
// Revoke a specific session
|
|
226
|
+
await client.tokens.revokeSession(sessionId);
|
|
237
227
|
|
|
238
|
-
|
|
228
|
+
// Revoke all sessions (emergency cleanup)
|
|
229
|
+
const result = await client.tokens.revokeAllSessions();
|
|
230
|
+
console.log(`Revoked ${result.sessions_revoked} sessions`);
|
|
231
|
+
```
|
|
239
232
|
|
|
240
|
-
|
|
233
|
+
### Encryption Info
|
|
241
234
|
|
|
242
|
-
|
|
243
|
-
// For development, use a proxy or CORS-enabled server
|
|
244
|
-
// Never expose API credentials in client-side code!
|
|
235
|
+
Get public encryption details (no auth required):
|
|
245
236
|
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
237
|
+
```typescript
|
|
238
|
+
const info = await client.tokens.getEncryptionInfo();
|
|
239
|
+
console.log('Algorithm:', info.algorithm);
|
|
240
|
+
console.log('Key derivation:', info.key_derivation);
|
|
241
|
+
console.log('Public salt:', info.salt);
|
|
242
|
+
console.log(info.javascript_example);
|
|
251
243
|
```
|
|
252
244
|
|
|
253
245
|
## License
|
|
254
246
|
|
|
255
|
-
MIT
|
|
247
|
+
MIT License - see [LICENSE](LICENSE) file for details
|
|
256
248
|
|
|
257
249
|
## Links
|
|
258
250
|
|
|
259
|
-
- [OnlyWorlds
|
|
260
|
-
- [
|
|
251
|
+
- [OnlyWorlds Website](https://onlyworlds.com)
|
|
252
|
+
- [Documentation](https://onlyworlds.github.io/)
|
|
261
253
|
- [NPM Package](https://www.npmjs.com/package/@onlyworlds/sdk)
|
|
262
|
-
- [
|
|
254
|
+
- [Report Issues](https://github.com/OnlyWorlds/sdk/issues)
|