@onlyworlds/sdk 2.0.2 → 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/README.md CHANGED
@@ -22,27 +22,29 @@ const client = new OnlyWorldsClient({
22
22
  baseUrl: 'https://onlyworlds.com'
23
23
  });
24
24
 
25
- // Fetch characters
26
- const characters = await client.character.list();
25
+ // Get your world (API keys are world-scoped)
26
+ const world = await client.worlds.get();
27
+
28
+ // Fetch characters (paginated)
29
+ const characters = await client.characters.list();
27
30
 
28
31
  // Create a new location
29
- const location = await client.location.create({
32
+ const location = await client.locations.create({
30
33
  name: 'Dragon Peak',
31
34
  description: 'A treacherous mountain peak where dragons nest',
32
- supertype: 'mountain',
33
- climate: 'cold'
35
+ supertype: 'mountain'
34
36
  });
35
37
 
36
38
  // Get a specific element
37
- const character = await client.character.get('element-id');
39
+ const character = await client.characters.get('element-id');
38
40
 
39
41
  // Update an element
40
- await client.character.update('element-id', {
42
+ await client.characters.update('element-id', {
41
43
  name: 'Updated Name'
42
44
  });
43
45
 
44
46
  // Delete an element
45
- await client.character.delete('element-id');
47
+ await client.characters.delete('element-id');
46
48
  ```
47
49
 
48
50
  ## Features
@@ -50,36 +52,47 @@ await client.character.delete('element-id');
50
52
  - ✅ **Full Type Safety** - Complete TypeScript definitions for all 22 OnlyWorlds element types
51
53
  - ✅ **Auto-Generated Types** - Types synchronized with the latest OnlyWorlds schema
52
54
  - ✅ **CRUD Operations** - Create, read, update, and delete operations for all elements
55
+ - ✅ **Token Management** - Built-in support for OnlyWorlds token rating system
53
56
  - ✅ **Branded Types** - Compile-time safety for element relationships
54
57
  - ✅ **Zero Runtime Overhead** - Type system has no runtime cost
55
58
  - ✅ **Modern ESM/CJS** - Supports both ES modules and CommonJS
56
59
 
57
- ## Element Types
58
-
59
- The SDK provides full support for all OnlyWorlds elements:
60
-
61
- - **Character** - People, NPCs, protagonists
62
- - **Location** - Places, regions, buildings
63
- - **Object** - Items, artifacts, tools
64
- - **Creature** - Animals, monsters, beasts
65
- - **Species** - Races, types of beings
66
- - **Event** - Historical events, occurrences
67
- - **Ability** - Skills, powers, magic
68
- - **Trait** - Characteristics, attributes
69
- - **Family** - Family groups, lineages
70
- - **Institution** - Organizations, governments
71
- - **Collective** - Groups, teams, parties
72
- - **Construct** - Buildings, structures, concepts
73
- - **Language** - Languages, dialects
74
- - **Law** - Rules, regulations, customs
75
- - **Narrative** - Stories, tales, myths
76
- - **Phenomenon** - Natural phenomena, effects
77
- - **Title** - Ranks, positions, honors
78
- - **Zone** - Areas, territories, districts
79
- - **Relation** - Relationships between elements
80
- - **Map** - Visual maps with pins/markers
81
- - **Pin** - Location markers on maps
82
- - **Marker** - Additional map annotations
60
+ ## API Reference
61
+
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.
65
+
66
+ ```typescript
67
+ // Get your world
68
+ const world = await client.worlds.get();
69
+
70
+ // Update your world
71
+ const updated = await client.worlds.update({
72
+ description: 'A dark fantasy realm'
73
+ });
74
+ ```
75
+
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
79
+
80
+ All other element types return paginated results:
81
+
82
+ ```typescript
83
+ // List with pagination
84
+ const response = await client.characters.list({
85
+ limit: 10,
86
+ offset: 0,
87
+ ordering: '-created_at',
88
+ search: 'dragon'
89
+ });
90
+
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
+ ```
83
96
 
84
97
  ## Type-Safe Relationships
85
98
 
@@ -94,23 +107,140 @@ const character: Character = {
94
107
  };
95
108
  ```
96
109
 
97
- ## Documentation
110
+ ## Token Management
111
+
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.
113
+
114
+ ### Working Reference Implementation
115
+
116
+ See [base-tool/src/llm/token-service.ts](https://github.com/OnlyWorlds/base-tool) for the complete working implementation that this SDK enables.
98
117
 
99
- For detailed documentation, examples, and API reference, visit:
118
+ ### Check Token Status
100
119
 
101
- 📚 **[https://onlyworlds.github.io/](https://onlyworlds.github.io/)**
120
+ ```typescript
121
+ // Get current token status
122
+ const status = await client.tokens.getStatus();
123
+
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}`);
128
+ ```
102
129
 
103
- ## API Authentication
130
+ ### Consume Tokens
104
131
 
105
- Get your API credentials from your OnlyWorlds account:
132
+ Report token consumption when your tool uses AI features or other token-tracked services:
106
133
 
107
- 1. Log in to [onlyworlds.com](https://onlyworlds.com)
108
- 2. Go to your world settings
109
- 3. Copy your API Key and PIN
134
+ ```typescript
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
+ });
110
146
 
111
- ## Contributing
147
+ // Check if consumption succeeded
148
+ if (result.error) {
149
+ console.warn('Token warning:', result.error);
150
+ }
112
151
 
113
- Contributions are welcome! Please feel free to submit a Pull Request.
152
+ console.log(`Consumed ${result.tokens_consumed} tokens`);
153
+ console.log(`${result.tokens_remaining} tokens remaining`);
154
+ ```
155
+
156
+ **Important**: The API allows consumption even when exceeding available tokens (tracks as debt), but returns a warning in the `error` field.
157
+
158
+ ### Advanced: Encrypted API Key Access
159
+
160
+ For tools that need direct OpenAI API access using OnlyWorlds tokens:
161
+
162
+ ```typescript
163
+ // Get encrypted OpenAI key (requires 100+ tokens)
164
+ const access = await client.tokens.getAccessKey();
165
+
166
+ console.log('Session ID:', access.session_id);
167
+ console.log('Expires:', access.expires_at);
168
+ console.log('Available tokens:', access.tokens_available);
169
+
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
175
+
176
+ // See base-tool/src/llm/token-service.ts:99-235 for complete example
177
+ ```
178
+
179
+ **Full decryption implementation** (based on base-tool):
180
+
181
+ ```typescript
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, '_');
194
+ }
195
+
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();
206
+ }
207
+
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', /* ... */ }
219
+ });
220
+ ```
221
+
222
+ ### Session Management
223
+
224
+ ```typescript
225
+ // Revoke a specific session
226
+ await client.tokens.revokeSession(sessionId);
227
+
228
+ // Revoke all sessions (emergency cleanup)
229
+ const result = await client.tokens.revokeAllSessions();
230
+ console.log(`Revoked ${result.sessions_revoked} sessions`);
231
+ ```
232
+
233
+ ### Encryption Info
234
+
235
+ Get public encryption details (no auth required):
236
+
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);
243
+ ```
114
244
 
115
245
  ## License
116
246
 
package/dist/index.d.mts CHANGED
@@ -2711,6 +2711,272 @@ declare function createElementIds<T extends ElementType>(ids: string[]): Element
2711
2711
  */
2712
2712
  declare function createAnyElementId(id: string): AnyElementId;
2713
2713
 
2714
+ /**
2715
+ * OnlyWorlds Token Management API Types
2716
+ *
2717
+ * Types for the token rating system that provides daily token allowances
2718
+ * for API usage and AI integration features.
2719
+ */
2720
+ /**
2721
+ * Current token status for the authenticated user
2722
+ */
2723
+ interface TokenStatus {
2724
+ /** Remaining tokens available for today */
2725
+ tokens_available_today: number;
2726
+ /** User's daily token allowance (default: 10000) */
2727
+ token_rating: number;
2728
+ /** Tokens consumed so far today */
2729
+ tokens_used_today: number;
2730
+ /** Date of last reset (ISO format) */
2731
+ last_reset: string;
2732
+ /** Number of active token sessions */
2733
+ sessions_active: number;
2734
+ }
2735
+ /**
2736
+ * Response from token consumption endpoint
2737
+ */
2738
+ interface TokenConsumeResponse {
2739
+ /** Whether the consumption was successful */
2740
+ success: boolean;
2741
+ /** Actual tokens consumed */
2742
+ tokens_consumed: number;
2743
+ /** Updated token balance */
2744
+ tokens_remaining: number;
2745
+ /** User's daily allowance */
2746
+ token_rating: number;
2747
+ /** Warning message if insufficient tokens (consumption still succeeds but tracks debt) */
2748
+ error?: string | null;
2749
+ }
2750
+ /**
2751
+ * Parameters for consuming tokens
2752
+ */
2753
+ interface TokenConsumeParams {
2754
+ /** Number of tokens to consume (required) */
2755
+ amount: number;
2756
+ /** Service identifier (default: "sdk_client") */
2757
+ service?: string;
2758
+ /** Session ID from access key response (optional) */
2759
+ sessionId?: string | null;
2760
+ /** Additional metadata for analytics (optional) */
2761
+ metadata?: Record<string, any> | null;
2762
+ }
2763
+ /**
2764
+ * Response from getting encrypted access key (advanced use case)
2765
+ */
2766
+ interface AccessKeyResponse {
2767
+ /** Base64 encoded encrypted OpenAI key */
2768
+ encrypted_key: string;
2769
+ /** Key expiration timestamp (ISO format) */
2770
+ expires_at: string;
2771
+ /** Session ID for tracking usage */
2772
+ session_id: string;
2773
+ /** Current token balance */
2774
+ tokens_available: number;
2775
+ /** User's token allowance */
2776
+ token_rating: number;
2777
+ /** Encryption algorithm used */
2778
+ encryption_method: string;
2779
+ }
2780
+ /**
2781
+ * Public encryption information for client-side decryption
2782
+ */
2783
+ interface EncryptionInfo {
2784
+ /** Encryption algorithm (e.g., "Fernet") */
2785
+ algorithm: string;
2786
+ /** Key derivation method (e.g., "SHA256") */
2787
+ key_derivation: string;
2788
+ /** Public salt used in key derivation */
2789
+ salt: string;
2790
+ /** Format description */
2791
+ format: string;
2792
+ /** Human-readable description */
2793
+ description: string;
2794
+ /** Example JavaScript implementation */
2795
+ javascript_example: string;
2796
+ }
2797
+ /**
2798
+ * Response from session revocation
2799
+ */
2800
+ interface RevokeSessionResponse {
2801
+ /** Whether revocation was successful */
2802
+ success: boolean;
2803
+ /** Status message */
2804
+ message: string;
2805
+ }
2806
+ /**
2807
+ * Response from revoking all sessions
2808
+ */
2809
+ interface RevokeAllSessionsResponse {
2810
+ /** Whether revocation was successful */
2811
+ success: boolean;
2812
+ /** Number of sessions revoked */
2813
+ sessions_revoked: number;
2814
+ }
2815
+ /**
2816
+ * Game tier / subscription level
2817
+ * (affects future features, currently all tiers get same token rating)
2818
+ */
2819
+ declare enum GameTier {
2820
+ FREE = "free",
2821
+ SILVER = "silver",
2822
+ GOLD = "gold",
2823
+ PLATINUM = "platinum",
2824
+ DIAMOND = "diamond",
2825
+ DELUXE = "deluxe"
2826
+ }
2827
+
2828
+ /**
2829
+ * Token Management Resource
2830
+ *
2831
+ * Provides access to the OnlyWorlds token rating system API.
2832
+ * Based on the working implementation in base-tool/src/llm/token-service.ts
2833
+ */
2834
+
2835
+ /**
2836
+ * Token Management Resource
2837
+ *
2838
+ * Handles token status checking, consumption tracking, and encrypted key access
2839
+ * for AI integration features.
2840
+ *
2841
+ * All endpoints require authentication (API-Key + API-Pin headers).
2842
+ *
2843
+ * Example usage:
2844
+ * ```typescript
2845
+ * const client = new OnlyWorldsClient({ apiKey, apiPin });
2846
+ *
2847
+ * // Check token status
2848
+ * const status = await client.tokens.getStatus();
2849
+ * console.log(`${status.tokens_available_today}/${status.token_rating} tokens available`);
2850
+ *
2851
+ * // Consume tokens
2852
+ * await client.tokens.consume({
2853
+ * amount: 500,
2854
+ * service: 'my_tool',
2855
+ * metadata: { feature: 'chat', model: 'gpt-4' }
2856
+ * });
2857
+ * ```
2858
+ */
2859
+ declare class TokenResource {
2860
+ private client;
2861
+ constructor(client: OnlyWorldsClient);
2862
+ /**
2863
+ * Get current token status for authenticated user
2864
+ *
2865
+ * Returns daily token allowance, usage, and availability.
2866
+ * Matches base-tool's checkStatus() pattern.
2867
+ *
2868
+ * @returns Current token status
2869
+ * @example
2870
+ * ```typescript
2871
+ * const status = await client.tokens.getStatus();
2872
+ * console.log(`Available: ${status.tokens_available_today}/${status.token_rating}`);
2873
+ * console.log(`Used today: ${status.tokens_used_today}`);
2874
+ * console.log(`Active sessions: ${status.sessions_active}`);
2875
+ * ```
2876
+ */
2877
+ getStatus(): Promise<TokenStatus>;
2878
+ /**
2879
+ * Consume tokens for service usage
2880
+ *
2881
+ * Reports token consumption to track daily usage. Allows consumption even if
2882
+ * exceeds available tokens (tracks as debt), but warns via error field.
2883
+ * Matches base-tool's reportUsage() pattern.
2884
+ *
2885
+ * @param params - Token consumption parameters
2886
+ * @returns Consumption result with updated balance
2887
+ * @example
2888
+ * ```typescript
2889
+ * const result = await client.tokens.consume({
2890
+ * amount: 500,
2891
+ * service: 'worldbuilding_tool',
2892
+ * metadata: {
2893
+ * feature: 'character_generation',
2894
+ * model: 'gpt-4',
2895
+ * prompt_tokens: 300,
2896
+ * completion_tokens: 200
2897
+ * }
2898
+ * });
2899
+ *
2900
+ * if (result.error) {
2901
+ * console.warn('Token warning:', result.error);
2902
+ * }
2903
+ * console.log(`${result.tokens_remaining} tokens remaining`);
2904
+ * ```
2905
+ */
2906
+ consume(params: TokenConsumeParams): Promise<TokenConsumeResponse>;
2907
+ /**
2908
+ * Get encrypted OpenAI API key (advanced use case)
2909
+ *
2910
+ * Requires minimum 100 tokens available. Creates a 1-hour session for tracking.
2911
+ * Returns encrypted key that must be decrypted client-side using Fernet.
2912
+ *
2913
+ * See base-tool/src/llm/token-service.ts:99-155 for full implementation example
2914
+ * including client-side decryption with the 'fernet' npm package.
2915
+ *
2916
+ * @returns Encrypted access key and session info
2917
+ * @throws Error if insufficient tokens (< 100)
2918
+ * @example
2919
+ * ```typescript
2920
+ * // Get encrypted key
2921
+ * const access = await client.tokens.getAccessKey();
2922
+ *
2923
+ * // Decrypt using fernet library (see base-tool for full example)
2924
+ * // 1. Derive key from world ID using SHA-256
2925
+ * // 2. Use 'fernet' npm package to decrypt
2926
+ * // 3. Use decrypted OpenAI key for direct API calls
2927
+ * // 4. Report usage with access.session_id
2928
+ *
2929
+ * console.log('Session:', access.session_id);
2930
+ * console.log('Expires:', access.expires_at);
2931
+ * ```
2932
+ */
2933
+ getAccessKey(): Promise<AccessKeyResponse>;
2934
+ /**
2935
+ * Revoke a specific token session
2936
+ *
2937
+ * Invalidates the session ID obtained from getAccessKey().
2938
+ * Use when cleaning up or on logout.
2939
+ *
2940
+ * @param sessionId - Session ID to revoke
2941
+ * @returns Revocation result
2942
+ * @example
2943
+ * ```typescript
2944
+ * await client.tokens.revokeSession('session-id-here');
2945
+ * ```
2946
+ */
2947
+ revokeSession(sessionId: string): Promise<RevokeSessionResponse>;
2948
+ /**
2949
+ * Revoke all active sessions (emergency use)
2950
+ *
2951
+ * Invalidates all token sessions for the authenticated user.
2952
+ * Use for security cleanup or when sessions are stuck.
2953
+ *
2954
+ * @returns Revocation result with count of revoked sessions
2955
+ * @example
2956
+ * ```typescript
2957
+ * const result = await client.tokens.revokeAllSessions();
2958
+ * console.log(`Revoked ${result.sessions_revoked} sessions`);
2959
+ * ```
2960
+ */
2961
+ revokeAllSessions(): Promise<RevokeAllSessionsResponse>;
2962
+ /**
2963
+ * Get public encryption info (no auth required)
2964
+ *
2965
+ * Returns algorithm details and example code for client-side decryption.
2966
+ * Public endpoint - can be called without authentication.
2967
+ *
2968
+ * @returns Encryption algorithm and implementation details
2969
+ * @example
2970
+ * ```typescript
2971
+ * const info = await client.tokens.getEncryptionInfo();
2972
+ * console.log('Algorithm:', info.algorithm);
2973
+ * console.log('Key derivation:', info.key_derivation);
2974
+ * console.log(info.javascript_example);
2975
+ * ```
2976
+ */
2977
+ getEncryptionInfo(): Promise<EncryptionInfo>;
2978
+ }
2979
+
2714
2980
  interface OnlyWorldsConfig {
2715
2981
  apiKey: string;
2716
2982
  apiPin: string;
@@ -2742,13 +3008,32 @@ declare class Resource<T, TInput> {
2742
3008
  update(id: string, data: Partial<TInput>): Promise<T>;
2743
3009
  delete(id: string): Promise<void>;
2744
3010
  }
3011
+ /**
3012
+ * Special resource class for World endpoint
3013
+ * The /world/ endpoint returns a single World object directly (not paginated)
3014
+ * because API keys are world-scoped (one key = one world)
3015
+ */
3016
+ declare class WorldResource {
3017
+ private client;
3018
+ constructor(client: OnlyWorldsClient);
3019
+ /**
3020
+ * Get the world associated with the current API key
3021
+ * Returns the world directly (not wrapped in pagination)
3022
+ */
3023
+ get(): Promise<World>;
3024
+ /**
3025
+ * Update the current world
3026
+ */
3027
+ update(data: Partial<WorldInput>): Promise<World>;
3028
+ }
2745
3029
  /**
2746
3030
  * Main OnlyWorlds API client
2747
3031
  */
2748
3032
  declare class OnlyWorldsClient {
2749
3033
  private baseUrl;
2750
3034
  private headers;
2751
- worlds: Resource<World, WorldInput>;
3035
+ worlds: WorldResource;
3036
+ tokens: TokenResource;
2752
3037
  abilities: Resource<Ability, AbilityInput>;
2753
3038
  characters: Resource<Character, CharacterInput>;
2754
3039
  collectives: Resource<Collective, CollectiveInput>;
@@ -2779,15 +3064,10 @@ declare class OnlyWorldsClient {
2779
3064
  params?: Record<string, any>;
2780
3065
  body?: any;
2781
3066
  }): Promise<T>;
2782
- /**
2783
- * Get all worlds accessible with current credentials
2784
- * @deprecated Use client.worlds.list() instead for consistent API
2785
- */
2786
- getWorlds(): Promise<ApiResponse<World>>;
2787
3067
  /**
2788
3068
  * Helper to convert nested objects to _id/_ids format
2789
3069
  */
2790
3070
  static prepareInput<T extends Record<string, any>>(data: T): any;
2791
3071
  }
2792
3072
 
2793
- export { type Ability, type AbilityInput, type AnyElementId, type ApiResponse, type BaseElement, type Character, type CharacterInput, type Collective, type CollectiveInput, type Construct, type ConstructInput, type Creature, type CreatureInput, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_UNICODE_ICONS, type ElementId, type ElementIds, ElementType, type Event, type EventInput, FIELD_SCHEMA, type Family, type FamilyInput, type FieldInfo, type FieldType, type Institution, type InstitutionInput, type Language, type LanguageInput, type Law, type LawInput, type ListOptions, type Location, type LocationInput, type Map, type MapInput, type Marker, type MarkerInput, type Narrative, type NarrativeInput, ONLYWORLDS_VERSION, type Object$1 as Object, type ObjectInput, OnlyWorldsClient, type OnlyWorldsConfig, type Phenomenon, type PhenomenonInput, type Pin, type PinInput, type Relation, type RelationInput, type SectionInfo, type Species, type SpeciesInput, type Title, type TitleInput, type Trait, type TraitInput, type World, type WorldInput, type Zone, type ZoneInput, createAnyElementId, createElementId, createElementIds, getElementIcon, getElementLabel, getElementSections, getElementUnicodeIcon };
3073
+ export { type Ability, type AbilityInput, type AccessKeyResponse, type AnyElementId, type ApiResponse, type BaseElement, type Character, type CharacterInput, type Collective, type CollectiveInput, type Construct, type ConstructInput, type Creature, type CreatureInput, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_UNICODE_ICONS, type ElementId, type ElementIds, ElementType, type EncryptionInfo, type Event, type EventInput, FIELD_SCHEMA, type Family, type FamilyInput, type FieldInfo, type FieldType, GameTier, type Institution, type InstitutionInput, type Language, type LanguageInput, type Law, type LawInput, type ListOptions, type Location, type LocationInput, type Map, type MapInput, type Marker, type MarkerInput, type Narrative, type NarrativeInput, ONLYWORLDS_VERSION, type Object$1 as Object, type ObjectInput, OnlyWorldsClient, type OnlyWorldsConfig, type Phenomenon, type PhenomenonInput, type Pin, type PinInput, type Relation, type RelationInput, type RevokeAllSessionsResponse, type RevokeSessionResponse, type SectionInfo, type Species, type SpeciesInput, type Title, type TitleInput, type TokenConsumeParams, type TokenConsumeResponse, type TokenStatus, type Trait, type TraitInput, type World, type WorldInput, type Zone, type ZoneInput, createAnyElementId, createElementId, createElementIds, getElementIcon, getElementLabel, getElementSections, getElementUnicodeIcon };
package/dist/index.d.ts CHANGED
@@ -2711,6 +2711,272 @@ declare function createElementIds<T extends ElementType>(ids: string[]): Element
2711
2711
  */
2712
2712
  declare function createAnyElementId(id: string): AnyElementId;
2713
2713
 
2714
+ /**
2715
+ * OnlyWorlds Token Management API Types
2716
+ *
2717
+ * Types for the token rating system that provides daily token allowances
2718
+ * for API usage and AI integration features.
2719
+ */
2720
+ /**
2721
+ * Current token status for the authenticated user
2722
+ */
2723
+ interface TokenStatus {
2724
+ /** Remaining tokens available for today */
2725
+ tokens_available_today: number;
2726
+ /** User's daily token allowance (default: 10000) */
2727
+ token_rating: number;
2728
+ /** Tokens consumed so far today */
2729
+ tokens_used_today: number;
2730
+ /** Date of last reset (ISO format) */
2731
+ last_reset: string;
2732
+ /** Number of active token sessions */
2733
+ sessions_active: number;
2734
+ }
2735
+ /**
2736
+ * Response from token consumption endpoint
2737
+ */
2738
+ interface TokenConsumeResponse {
2739
+ /** Whether the consumption was successful */
2740
+ success: boolean;
2741
+ /** Actual tokens consumed */
2742
+ tokens_consumed: number;
2743
+ /** Updated token balance */
2744
+ tokens_remaining: number;
2745
+ /** User's daily allowance */
2746
+ token_rating: number;
2747
+ /** Warning message if insufficient tokens (consumption still succeeds but tracks debt) */
2748
+ error?: string | null;
2749
+ }
2750
+ /**
2751
+ * Parameters for consuming tokens
2752
+ */
2753
+ interface TokenConsumeParams {
2754
+ /** Number of tokens to consume (required) */
2755
+ amount: number;
2756
+ /** Service identifier (default: "sdk_client") */
2757
+ service?: string;
2758
+ /** Session ID from access key response (optional) */
2759
+ sessionId?: string | null;
2760
+ /** Additional metadata for analytics (optional) */
2761
+ metadata?: Record<string, any> | null;
2762
+ }
2763
+ /**
2764
+ * Response from getting encrypted access key (advanced use case)
2765
+ */
2766
+ interface AccessKeyResponse {
2767
+ /** Base64 encoded encrypted OpenAI key */
2768
+ encrypted_key: string;
2769
+ /** Key expiration timestamp (ISO format) */
2770
+ expires_at: string;
2771
+ /** Session ID for tracking usage */
2772
+ session_id: string;
2773
+ /** Current token balance */
2774
+ tokens_available: number;
2775
+ /** User's token allowance */
2776
+ token_rating: number;
2777
+ /** Encryption algorithm used */
2778
+ encryption_method: string;
2779
+ }
2780
+ /**
2781
+ * Public encryption information for client-side decryption
2782
+ */
2783
+ interface EncryptionInfo {
2784
+ /** Encryption algorithm (e.g., "Fernet") */
2785
+ algorithm: string;
2786
+ /** Key derivation method (e.g., "SHA256") */
2787
+ key_derivation: string;
2788
+ /** Public salt used in key derivation */
2789
+ salt: string;
2790
+ /** Format description */
2791
+ format: string;
2792
+ /** Human-readable description */
2793
+ description: string;
2794
+ /** Example JavaScript implementation */
2795
+ javascript_example: string;
2796
+ }
2797
+ /**
2798
+ * Response from session revocation
2799
+ */
2800
+ interface RevokeSessionResponse {
2801
+ /** Whether revocation was successful */
2802
+ success: boolean;
2803
+ /** Status message */
2804
+ message: string;
2805
+ }
2806
+ /**
2807
+ * Response from revoking all sessions
2808
+ */
2809
+ interface RevokeAllSessionsResponse {
2810
+ /** Whether revocation was successful */
2811
+ success: boolean;
2812
+ /** Number of sessions revoked */
2813
+ sessions_revoked: number;
2814
+ }
2815
+ /**
2816
+ * Game tier / subscription level
2817
+ * (affects future features, currently all tiers get same token rating)
2818
+ */
2819
+ declare enum GameTier {
2820
+ FREE = "free",
2821
+ SILVER = "silver",
2822
+ GOLD = "gold",
2823
+ PLATINUM = "platinum",
2824
+ DIAMOND = "diamond",
2825
+ DELUXE = "deluxe"
2826
+ }
2827
+
2828
+ /**
2829
+ * Token Management Resource
2830
+ *
2831
+ * Provides access to the OnlyWorlds token rating system API.
2832
+ * Based on the working implementation in base-tool/src/llm/token-service.ts
2833
+ */
2834
+
2835
+ /**
2836
+ * Token Management Resource
2837
+ *
2838
+ * Handles token status checking, consumption tracking, and encrypted key access
2839
+ * for AI integration features.
2840
+ *
2841
+ * All endpoints require authentication (API-Key + API-Pin headers).
2842
+ *
2843
+ * Example usage:
2844
+ * ```typescript
2845
+ * const client = new OnlyWorldsClient({ apiKey, apiPin });
2846
+ *
2847
+ * // Check token status
2848
+ * const status = await client.tokens.getStatus();
2849
+ * console.log(`${status.tokens_available_today}/${status.token_rating} tokens available`);
2850
+ *
2851
+ * // Consume tokens
2852
+ * await client.tokens.consume({
2853
+ * amount: 500,
2854
+ * service: 'my_tool',
2855
+ * metadata: { feature: 'chat', model: 'gpt-4' }
2856
+ * });
2857
+ * ```
2858
+ */
2859
+ declare class TokenResource {
2860
+ private client;
2861
+ constructor(client: OnlyWorldsClient);
2862
+ /**
2863
+ * Get current token status for authenticated user
2864
+ *
2865
+ * Returns daily token allowance, usage, and availability.
2866
+ * Matches base-tool's checkStatus() pattern.
2867
+ *
2868
+ * @returns Current token status
2869
+ * @example
2870
+ * ```typescript
2871
+ * const status = await client.tokens.getStatus();
2872
+ * console.log(`Available: ${status.tokens_available_today}/${status.token_rating}`);
2873
+ * console.log(`Used today: ${status.tokens_used_today}`);
2874
+ * console.log(`Active sessions: ${status.sessions_active}`);
2875
+ * ```
2876
+ */
2877
+ getStatus(): Promise<TokenStatus>;
2878
+ /**
2879
+ * Consume tokens for service usage
2880
+ *
2881
+ * Reports token consumption to track daily usage. Allows consumption even if
2882
+ * exceeds available tokens (tracks as debt), but warns via error field.
2883
+ * Matches base-tool's reportUsage() pattern.
2884
+ *
2885
+ * @param params - Token consumption parameters
2886
+ * @returns Consumption result with updated balance
2887
+ * @example
2888
+ * ```typescript
2889
+ * const result = await client.tokens.consume({
2890
+ * amount: 500,
2891
+ * service: 'worldbuilding_tool',
2892
+ * metadata: {
2893
+ * feature: 'character_generation',
2894
+ * model: 'gpt-4',
2895
+ * prompt_tokens: 300,
2896
+ * completion_tokens: 200
2897
+ * }
2898
+ * });
2899
+ *
2900
+ * if (result.error) {
2901
+ * console.warn('Token warning:', result.error);
2902
+ * }
2903
+ * console.log(`${result.tokens_remaining} tokens remaining`);
2904
+ * ```
2905
+ */
2906
+ consume(params: TokenConsumeParams): Promise<TokenConsumeResponse>;
2907
+ /**
2908
+ * Get encrypted OpenAI API key (advanced use case)
2909
+ *
2910
+ * Requires minimum 100 tokens available. Creates a 1-hour session for tracking.
2911
+ * Returns encrypted key that must be decrypted client-side using Fernet.
2912
+ *
2913
+ * See base-tool/src/llm/token-service.ts:99-155 for full implementation example
2914
+ * including client-side decryption with the 'fernet' npm package.
2915
+ *
2916
+ * @returns Encrypted access key and session info
2917
+ * @throws Error if insufficient tokens (< 100)
2918
+ * @example
2919
+ * ```typescript
2920
+ * // Get encrypted key
2921
+ * const access = await client.tokens.getAccessKey();
2922
+ *
2923
+ * // Decrypt using fernet library (see base-tool for full example)
2924
+ * // 1. Derive key from world ID using SHA-256
2925
+ * // 2. Use 'fernet' npm package to decrypt
2926
+ * // 3. Use decrypted OpenAI key for direct API calls
2927
+ * // 4. Report usage with access.session_id
2928
+ *
2929
+ * console.log('Session:', access.session_id);
2930
+ * console.log('Expires:', access.expires_at);
2931
+ * ```
2932
+ */
2933
+ getAccessKey(): Promise<AccessKeyResponse>;
2934
+ /**
2935
+ * Revoke a specific token session
2936
+ *
2937
+ * Invalidates the session ID obtained from getAccessKey().
2938
+ * Use when cleaning up or on logout.
2939
+ *
2940
+ * @param sessionId - Session ID to revoke
2941
+ * @returns Revocation result
2942
+ * @example
2943
+ * ```typescript
2944
+ * await client.tokens.revokeSession('session-id-here');
2945
+ * ```
2946
+ */
2947
+ revokeSession(sessionId: string): Promise<RevokeSessionResponse>;
2948
+ /**
2949
+ * Revoke all active sessions (emergency use)
2950
+ *
2951
+ * Invalidates all token sessions for the authenticated user.
2952
+ * Use for security cleanup or when sessions are stuck.
2953
+ *
2954
+ * @returns Revocation result with count of revoked sessions
2955
+ * @example
2956
+ * ```typescript
2957
+ * const result = await client.tokens.revokeAllSessions();
2958
+ * console.log(`Revoked ${result.sessions_revoked} sessions`);
2959
+ * ```
2960
+ */
2961
+ revokeAllSessions(): Promise<RevokeAllSessionsResponse>;
2962
+ /**
2963
+ * Get public encryption info (no auth required)
2964
+ *
2965
+ * Returns algorithm details and example code for client-side decryption.
2966
+ * Public endpoint - can be called without authentication.
2967
+ *
2968
+ * @returns Encryption algorithm and implementation details
2969
+ * @example
2970
+ * ```typescript
2971
+ * const info = await client.tokens.getEncryptionInfo();
2972
+ * console.log('Algorithm:', info.algorithm);
2973
+ * console.log('Key derivation:', info.key_derivation);
2974
+ * console.log(info.javascript_example);
2975
+ * ```
2976
+ */
2977
+ getEncryptionInfo(): Promise<EncryptionInfo>;
2978
+ }
2979
+
2714
2980
  interface OnlyWorldsConfig {
2715
2981
  apiKey: string;
2716
2982
  apiPin: string;
@@ -2742,13 +3008,32 @@ declare class Resource<T, TInput> {
2742
3008
  update(id: string, data: Partial<TInput>): Promise<T>;
2743
3009
  delete(id: string): Promise<void>;
2744
3010
  }
3011
+ /**
3012
+ * Special resource class for World endpoint
3013
+ * The /world/ endpoint returns a single World object directly (not paginated)
3014
+ * because API keys are world-scoped (one key = one world)
3015
+ */
3016
+ declare class WorldResource {
3017
+ private client;
3018
+ constructor(client: OnlyWorldsClient);
3019
+ /**
3020
+ * Get the world associated with the current API key
3021
+ * Returns the world directly (not wrapped in pagination)
3022
+ */
3023
+ get(): Promise<World>;
3024
+ /**
3025
+ * Update the current world
3026
+ */
3027
+ update(data: Partial<WorldInput>): Promise<World>;
3028
+ }
2745
3029
  /**
2746
3030
  * Main OnlyWorlds API client
2747
3031
  */
2748
3032
  declare class OnlyWorldsClient {
2749
3033
  private baseUrl;
2750
3034
  private headers;
2751
- worlds: Resource<World, WorldInput>;
3035
+ worlds: WorldResource;
3036
+ tokens: TokenResource;
2752
3037
  abilities: Resource<Ability, AbilityInput>;
2753
3038
  characters: Resource<Character, CharacterInput>;
2754
3039
  collectives: Resource<Collective, CollectiveInput>;
@@ -2779,15 +3064,10 @@ declare class OnlyWorldsClient {
2779
3064
  params?: Record<string, any>;
2780
3065
  body?: any;
2781
3066
  }): Promise<T>;
2782
- /**
2783
- * Get all worlds accessible with current credentials
2784
- * @deprecated Use client.worlds.list() instead for consistent API
2785
- */
2786
- getWorlds(): Promise<ApiResponse<World>>;
2787
3067
  /**
2788
3068
  * Helper to convert nested objects to _id/_ids format
2789
3069
  */
2790
3070
  static prepareInput<T extends Record<string, any>>(data: T): any;
2791
3071
  }
2792
3072
 
2793
- export { type Ability, type AbilityInput, type AnyElementId, type ApiResponse, type BaseElement, type Character, type CharacterInput, type Collective, type CollectiveInput, type Construct, type ConstructInput, type Creature, type CreatureInput, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_UNICODE_ICONS, type ElementId, type ElementIds, ElementType, type Event, type EventInput, FIELD_SCHEMA, type Family, type FamilyInput, type FieldInfo, type FieldType, type Institution, type InstitutionInput, type Language, type LanguageInput, type Law, type LawInput, type ListOptions, type Location, type LocationInput, type Map, type MapInput, type Marker, type MarkerInput, type Narrative, type NarrativeInput, ONLYWORLDS_VERSION, type Object$1 as Object, type ObjectInput, OnlyWorldsClient, type OnlyWorldsConfig, type Phenomenon, type PhenomenonInput, type Pin, type PinInput, type Relation, type RelationInput, type SectionInfo, type Species, type SpeciesInput, type Title, type TitleInput, type Trait, type TraitInput, type World, type WorldInput, type Zone, type ZoneInput, createAnyElementId, createElementId, createElementIds, getElementIcon, getElementLabel, getElementSections, getElementUnicodeIcon };
3073
+ export { type Ability, type AbilityInput, type AccessKeyResponse, type AnyElementId, type ApiResponse, type BaseElement, type Character, type CharacterInput, type Collective, type CollectiveInput, type Construct, type ConstructInput, type Creature, type CreatureInput, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_UNICODE_ICONS, type ElementId, type ElementIds, ElementType, type EncryptionInfo, type Event, type EventInput, FIELD_SCHEMA, type Family, type FamilyInput, type FieldInfo, type FieldType, GameTier, type Institution, type InstitutionInput, type Language, type LanguageInput, type Law, type LawInput, type ListOptions, type Location, type LocationInput, type Map, type MapInput, type Marker, type MarkerInput, type Narrative, type NarrativeInput, ONLYWORLDS_VERSION, type Object$1 as Object, type ObjectInput, OnlyWorldsClient, type OnlyWorldsConfig, type Phenomenon, type PhenomenonInput, type Pin, type PinInput, type Relation, type RelationInput, type RevokeAllSessionsResponse, type RevokeSessionResponse, type SectionInfo, type Species, type SpeciesInput, type Title, type TitleInput, type TokenConsumeParams, type TokenConsumeResponse, type TokenStatus, type Trait, type TraitInput, type World, type WorldInput, type Zone, type ZoneInput, createAnyElementId, createElementId, createElementIds, getElementIcon, getElementLabel, getElementSections, getElementUnicodeIcon };
package/dist/index.js CHANGED
@@ -26,6 +26,7 @@ __export(index_exports, {
26
26
  ELEMENT_UNICODE_ICONS: () => ELEMENT_UNICODE_ICONS,
27
27
  ElementType: () => ElementType,
28
28
  FIELD_SCHEMA: () => FIELD_SCHEMA,
29
+ GameTier: () => GameTier,
29
30
  ONLYWORLDS_VERSION: () => ONLYWORLDS_VERSION,
30
31
  OnlyWorldsClient: () => OnlyWorldsClient,
31
32
  createAnyElementId: () => createAnyElementId,
@@ -38,6 +39,151 @@ __export(index_exports, {
38
39
  });
39
40
  module.exports = __toCommonJS(index_exports);
40
41
 
42
+ // src/token-resource.ts
43
+ var TokenResource = class {
44
+ constructor(client) {
45
+ this.client = client;
46
+ }
47
+ /**
48
+ * Get current token status for authenticated user
49
+ *
50
+ * Returns daily token allowance, usage, and availability.
51
+ * Matches base-tool's checkStatus() pattern.
52
+ *
53
+ * @returns Current token status
54
+ * @example
55
+ * ```typescript
56
+ * const status = await client.tokens.getStatus();
57
+ * console.log(`Available: ${status.tokens_available_today}/${status.token_rating}`);
58
+ * console.log(`Used today: ${status.tokens_used_today}`);
59
+ * console.log(`Active sessions: ${status.sessions_active}`);
60
+ * ```
61
+ */
62
+ async getStatus() {
63
+ return this.client.request("GET", "/tokens/status/");
64
+ }
65
+ /**
66
+ * Consume tokens for service usage
67
+ *
68
+ * Reports token consumption to track daily usage. Allows consumption even if
69
+ * exceeds available tokens (tracks as debt), but warns via error field.
70
+ * Matches base-tool's reportUsage() pattern.
71
+ *
72
+ * @param params - Token consumption parameters
73
+ * @returns Consumption result with updated balance
74
+ * @example
75
+ * ```typescript
76
+ * const result = await client.tokens.consume({
77
+ * amount: 500,
78
+ * service: 'worldbuilding_tool',
79
+ * metadata: {
80
+ * feature: 'character_generation',
81
+ * model: 'gpt-4',
82
+ * prompt_tokens: 300,
83
+ * completion_tokens: 200
84
+ * }
85
+ * });
86
+ *
87
+ * if (result.error) {
88
+ * console.warn('Token warning:', result.error);
89
+ * }
90
+ * console.log(`${result.tokens_remaining} tokens remaining`);
91
+ * ```
92
+ */
93
+ async consume(params) {
94
+ return this.client.request("POST", "/tokens/consume/", {
95
+ body: {
96
+ amount: params.amount,
97
+ service: params.service || "sdk_client",
98
+ session_id: params.sessionId ?? null,
99
+ metadata: params.metadata ?? null
100
+ }
101
+ });
102
+ }
103
+ /**
104
+ * Get encrypted OpenAI API key (advanced use case)
105
+ *
106
+ * Requires minimum 100 tokens available. Creates a 1-hour session for tracking.
107
+ * Returns encrypted key that must be decrypted client-side using Fernet.
108
+ *
109
+ * See base-tool/src/llm/token-service.ts:99-155 for full implementation example
110
+ * including client-side decryption with the 'fernet' npm package.
111
+ *
112
+ * @returns Encrypted access key and session info
113
+ * @throws Error if insufficient tokens (< 100)
114
+ * @example
115
+ * ```typescript
116
+ * // Get encrypted key
117
+ * const access = await client.tokens.getAccessKey();
118
+ *
119
+ * // Decrypt using fernet library (see base-tool for full example)
120
+ * // 1. Derive key from world ID using SHA-256
121
+ * // 2. Use 'fernet' npm package to decrypt
122
+ * // 3. Use decrypted OpenAI key for direct API calls
123
+ * // 4. Report usage with access.session_id
124
+ *
125
+ * console.log('Session:', access.session_id);
126
+ * console.log('Expires:', access.expires_at);
127
+ * ```
128
+ */
129
+ async getAccessKey() {
130
+ return this.client.request("GET", "/tokens/access-key/");
131
+ }
132
+ /**
133
+ * Revoke a specific token session
134
+ *
135
+ * Invalidates the session ID obtained from getAccessKey().
136
+ * Use when cleaning up or on logout.
137
+ *
138
+ * @param sessionId - Session ID to revoke
139
+ * @returns Revocation result
140
+ * @example
141
+ * ```typescript
142
+ * await client.tokens.revokeSession('session-id-here');
143
+ * ```
144
+ */
145
+ async revokeSession(sessionId) {
146
+ return this.client.request(
147
+ "POST",
148
+ `/tokens/revoke-session/?session_id=${encodeURIComponent(sessionId)}`
149
+ );
150
+ }
151
+ /**
152
+ * Revoke all active sessions (emergency use)
153
+ *
154
+ * Invalidates all token sessions for the authenticated user.
155
+ * Use for security cleanup or when sessions are stuck.
156
+ *
157
+ * @returns Revocation result with count of revoked sessions
158
+ * @example
159
+ * ```typescript
160
+ * const result = await client.tokens.revokeAllSessions();
161
+ * console.log(`Revoked ${result.sessions_revoked} sessions`);
162
+ * ```
163
+ */
164
+ async revokeAllSessions() {
165
+ return this.client.request("POST", "/tokens/revoke-all-sessions/");
166
+ }
167
+ /**
168
+ * Get public encryption info (no auth required)
169
+ *
170
+ * Returns algorithm details and example code for client-side decryption.
171
+ * Public endpoint - can be called without authentication.
172
+ *
173
+ * @returns Encryption algorithm and implementation details
174
+ * @example
175
+ * ```typescript
176
+ * const info = await client.tokens.getEncryptionInfo();
177
+ * console.log('Algorithm:', info.algorithm);
178
+ * console.log('Key derivation:', info.key_derivation);
179
+ * console.log(info.javascript_example);
180
+ * ```
181
+ */
182
+ async getEncryptionInfo() {
183
+ return this.client.request("GET", "/tokens/encryption-info/");
184
+ }
185
+ };
186
+
41
187
  // src/client.ts
42
188
  var Resource = class {
43
189
  constructor(client, elementType) {
@@ -60,6 +206,24 @@ var Resource = class {
60
206
  return this.client.request("DELETE", `/${this.elementType}/${id}/`);
61
207
  }
62
208
  };
209
+ var WorldResource = class {
210
+ constructor(client) {
211
+ this.client = client;
212
+ }
213
+ /**
214
+ * Get the world associated with the current API key
215
+ * Returns the world directly (not wrapped in pagination)
216
+ */
217
+ async get() {
218
+ return this.client.request("GET", "/world/");
219
+ }
220
+ /**
221
+ * Update the current world
222
+ */
223
+ async update(data) {
224
+ return this.client.request("PATCH", "/world/", { body: data });
225
+ }
226
+ };
63
227
  var OnlyWorldsClient = class {
64
228
  constructor(config) {
65
229
  this.baseUrl = config.baseUrl || "https://www.onlyworlds.com/api/worldapi";
@@ -68,7 +232,8 @@ var OnlyWorldsClient = class {
68
232
  "API-Key": config.apiKey,
69
233
  "API-Pin": config.apiPin
70
234
  };
71
- this.worlds = new Resource(this, "world");
235
+ this.worlds = new WorldResource(this);
236
+ this.tokens = new TokenResource(this);
72
237
  this.abilities = new Resource(this, "ability");
73
238
  this.characters = new Resource(this, "character");
74
239
  this.collectives = new Resource(this, "collective");
@@ -133,13 +298,6 @@ var OnlyWorldsClient = class {
133
298
  }
134
299
  return response.json();
135
300
  }
136
- /**
137
- * Get all worlds accessible with current credentials
138
- * @deprecated Use client.worlds.list() instead for consistent API
139
- */
140
- async getWorlds() {
141
- return this.request("GET", "/world/");
142
- }
143
301
  /**
144
302
  * Helper to convert nested objects to _id/_ids format
145
303
  */
@@ -974,6 +1132,17 @@ function createElementIds(ids) {
974
1132
  function createAnyElementId(id) {
975
1133
  return id;
976
1134
  }
1135
+
1136
+ // src/token-types.ts
1137
+ var GameTier = /* @__PURE__ */ ((GameTier2) => {
1138
+ GameTier2["FREE"] = "free";
1139
+ GameTier2["SILVER"] = "silver";
1140
+ GameTier2["GOLD"] = "gold";
1141
+ GameTier2["PLATINUM"] = "platinum";
1142
+ GameTier2["DIAMOND"] = "diamond";
1143
+ GameTier2["DELUXE"] = "deluxe";
1144
+ return GameTier2;
1145
+ })(GameTier || {});
977
1146
  // Annotate the CommonJS export names for ESM import in node:
978
1147
  0 && (module.exports = {
979
1148
  ELEMENT_ICONS,
@@ -982,6 +1151,7 @@ function createAnyElementId(id) {
982
1151
  ELEMENT_UNICODE_ICONS,
983
1152
  ElementType,
984
1153
  FIELD_SCHEMA,
1154
+ GameTier,
985
1155
  ONLYWORLDS_VERSION,
986
1156
  OnlyWorldsClient,
987
1157
  createAnyElementId,
package/dist/index.mjs CHANGED
@@ -1,3 +1,148 @@
1
+ // src/token-resource.ts
2
+ var TokenResource = class {
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ /**
7
+ * Get current token status for authenticated user
8
+ *
9
+ * Returns daily token allowance, usage, and availability.
10
+ * Matches base-tool's checkStatus() pattern.
11
+ *
12
+ * @returns Current token status
13
+ * @example
14
+ * ```typescript
15
+ * const status = await client.tokens.getStatus();
16
+ * console.log(`Available: ${status.tokens_available_today}/${status.token_rating}`);
17
+ * console.log(`Used today: ${status.tokens_used_today}`);
18
+ * console.log(`Active sessions: ${status.sessions_active}`);
19
+ * ```
20
+ */
21
+ async getStatus() {
22
+ return this.client.request("GET", "/tokens/status/");
23
+ }
24
+ /**
25
+ * Consume tokens for service usage
26
+ *
27
+ * Reports token consumption to track daily usage. Allows consumption even if
28
+ * exceeds available tokens (tracks as debt), but warns via error field.
29
+ * Matches base-tool's reportUsage() pattern.
30
+ *
31
+ * @param params - Token consumption parameters
32
+ * @returns Consumption result with updated balance
33
+ * @example
34
+ * ```typescript
35
+ * const result = await client.tokens.consume({
36
+ * amount: 500,
37
+ * service: 'worldbuilding_tool',
38
+ * metadata: {
39
+ * feature: 'character_generation',
40
+ * model: 'gpt-4',
41
+ * prompt_tokens: 300,
42
+ * completion_tokens: 200
43
+ * }
44
+ * });
45
+ *
46
+ * if (result.error) {
47
+ * console.warn('Token warning:', result.error);
48
+ * }
49
+ * console.log(`${result.tokens_remaining} tokens remaining`);
50
+ * ```
51
+ */
52
+ async consume(params) {
53
+ return this.client.request("POST", "/tokens/consume/", {
54
+ body: {
55
+ amount: params.amount,
56
+ service: params.service || "sdk_client",
57
+ session_id: params.sessionId ?? null,
58
+ metadata: params.metadata ?? null
59
+ }
60
+ });
61
+ }
62
+ /**
63
+ * Get encrypted OpenAI API key (advanced use case)
64
+ *
65
+ * Requires minimum 100 tokens available. Creates a 1-hour session for tracking.
66
+ * Returns encrypted key that must be decrypted client-side using Fernet.
67
+ *
68
+ * See base-tool/src/llm/token-service.ts:99-155 for full implementation example
69
+ * including client-side decryption with the 'fernet' npm package.
70
+ *
71
+ * @returns Encrypted access key and session info
72
+ * @throws Error if insufficient tokens (< 100)
73
+ * @example
74
+ * ```typescript
75
+ * // Get encrypted key
76
+ * const access = await client.tokens.getAccessKey();
77
+ *
78
+ * // Decrypt using fernet library (see base-tool for full example)
79
+ * // 1. Derive key from world ID using SHA-256
80
+ * // 2. Use 'fernet' npm package to decrypt
81
+ * // 3. Use decrypted OpenAI key for direct API calls
82
+ * // 4. Report usage with access.session_id
83
+ *
84
+ * console.log('Session:', access.session_id);
85
+ * console.log('Expires:', access.expires_at);
86
+ * ```
87
+ */
88
+ async getAccessKey() {
89
+ return this.client.request("GET", "/tokens/access-key/");
90
+ }
91
+ /**
92
+ * Revoke a specific token session
93
+ *
94
+ * Invalidates the session ID obtained from getAccessKey().
95
+ * Use when cleaning up or on logout.
96
+ *
97
+ * @param sessionId - Session ID to revoke
98
+ * @returns Revocation result
99
+ * @example
100
+ * ```typescript
101
+ * await client.tokens.revokeSession('session-id-here');
102
+ * ```
103
+ */
104
+ async revokeSession(sessionId) {
105
+ return this.client.request(
106
+ "POST",
107
+ `/tokens/revoke-session/?session_id=${encodeURIComponent(sessionId)}`
108
+ );
109
+ }
110
+ /**
111
+ * Revoke all active sessions (emergency use)
112
+ *
113
+ * Invalidates all token sessions for the authenticated user.
114
+ * Use for security cleanup or when sessions are stuck.
115
+ *
116
+ * @returns Revocation result with count of revoked sessions
117
+ * @example
118
+ * ```typescript
119
+ * const result = await client.tokens.revokeAllSessions();
120
+ * console.log(`Revoked ${result.sessions_revoked} sessions`);
121
+ * ```
122
+ */
123
+ async revokeAllSessions() {
124
+ return this.client.request("POST", "/tokens/revoke-all-sessions/");
125
+ }
126
+ /**
127
+ * Get public encryption info (no auth required)
128
+ *
129
+ * Returns algorithm details and example code for client-side decryption.
130
+ * Public endpoint - can be called without authentication.
131
+ *
132
+ * @returns Encryption algorithm and implementation details
133
+ * @example
134
+ * ```typescript
135
+ * const info = await client.tokens.getEncryptionInfo();
136
+ * console.log('Algorithm:', info.algorithm);
137
+ * console.log('Key derivation:', info.key_derivation);
138
+ * console.log(info.javascript_example);
139
+ * ```
140
+ */
141
+ async getEncryptionInfo() {
142
+ return this.client.request("GET", "/tokens/encryption-info/");
143
+ }
144
+ };
145
+
1
146
  // src/client.ts
2
147
  var Resource = class {
3
148
  constructor(client, elementType) {
@@ -20,6 +165,24 @@ var Resource = class {
20
165
  return this.client.request("DELETE", `/${this.elementType}/${id}/`);
21
166
  }
22
167
  };
168
+ var WorldResource = class {
169
+ constructor(client) {
170
+ this.client = client;
171
+ }
172
+ /**
173
+ * Get the world associated with the current API key
174
+ * Returns the world directly (not wrapped in pagination)
175
+ */
176
+ async get() {
177
+ return this.client.request("GET", "/world/");
178
+ }
179
+ /**
180
+ * Update the current world
181
+ */
182
+ async update(data) {
183
+ return this.client.request("PATCH", "/world/", { body: data });
184
+ }
185
+ };
23
186
  var OnlyWorldsClient = class {
24
187
  constructor(config) {
25
188
  this.baseUrl = config.baseUrl || "https://www.onlyworlds.com/api/worldapi";
@@ -28,7 +191,8 @@ var OnlyWorldsClient = class {
28
191
  "API-Key": config.apiKey,
29
192
  "API-Pin": config.apiPin
30
193
  };
31
- this.worlds = new Resource(this, "world");
194
+ this.worlds = new WorldResource(this);
195
+ this.tokens = new TokenResource(this);
32
196
  this.abilities = new Resource(this, "ability");
33
197
  this.characters = new Resource(this, "character");
34
198
  this.collectives = new Resource(this, "collective");
@@ -93,13 +257,6 @@ var OnlyWorldsClient = class {
93
257
  }
94
258
  return response.json();
95
259
  }
96
- /**
97
- * Get all worlds accessible with current credentials
98
- * @deprecated Use client.worlds.list() instead for consistent API
99
- */
100
- async getWorlds() {
101
- return this.request("GET", "/world/");
102
- }
103
260
  /**
104
261
  * Helper to convert nested objects to _id/_ids format
105
262
  */
@@ -934,6 +1091,17 @@ function createElementIds(ids) {
934
1091
  function createAnyElementId(id) {
935
1092
  return id;
936
1093
  }
1094
+
1095
+ // src/token-types.ts
1096
+ var GameTier = /* @__PURE__ */ ((GameTier2) => {
1097
+ GameTier2["FREE"] = "free";
1098
+ GameTier2["SILVER"] = "silver";
1099
+ GameTier2["GOLD"] = "gold";
1100
+ GameTier2["PLATINUM"] = "platinum";
1101
+ GameTier2["DIAMOND"] = "diamond";
1102
+ GameTier2["DELUXE"] = "deluxe";
1103
+ return GameTier2;
1104
+ })(GameTier || {});
937
1105
  export {
938
1106
  ELEMENT_ICONS,
939
1107
  ELEMENT_LABELS,
@@ -941,6 +1109,7 @@ export {
941
1109
  ELEMENT_UNICODE_ICONS,
942
1110
  ElementType,
943
1111
  FIELD_SCHEMA,
1112
+ GameTier,
944
1113
  ONLYWORLDS_VERSION,
945
1114
  OnlyWorldsClient,
946
1115
  createAnyElementId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlyworlds/sdk",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "TypeScript SDK for the OnlyWorlds API - build world-building applications with type safety",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",