@kokimoki/app 1.17.0 → 2.0.1

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.
Files changed (71) hide show
  1. package/dist/core/index.d.ts +3 -0
  2. package/dist/core/index.js +3 -0
  3. package/dist/core/kokimoki-client.d.ts +361 -0
  4. package/dist/core/kokimoki-client.js +819 -0
  5. package/dist/core/room-subscription-mode.d.ts +5 -0
  6. package/dist/core/room-subscription-mode.js +6 -0
  7. package/dist/core/room-subscription.d.ts +15 -0
  8. package/dist/core/room-subscription.js +53 -0
  9. package/dist/fields.d.ts +110 -0
  10. package/dist/fields.js +158 -0
  11. package/dist/index.d.ts +4 -8
  12. package/dist/index.js +4 -9
  13. package/dist/kokimoki-ai.d.ts +153 -0
  14. package/dist/kokimoki-ai.js +164 -0
  15. package/dist/kokimoki-awareness.d.ts +14 -13
  16. package/dist/kokimoki-awareness.js +41 -33
  17. package/dist/kokimoki-client-refactored.d.ts +80 -0
  18. package/dist/kokimoki-client-refactored.js +400 -0
  19. package/dist/kokimoki-client.d.ts +282 -76
  20. package/dist/kokimoki-client.js +295 -232
  21. package/dist/kokimoki-leaderboard.d.ts +175 -0
  22. package/dist/kokimoki-leaderboard.js +203 -0
  23. package/dist/kokimoki-schema.d.ts +113 -0
  24. package/dist/kokimoki-schema.js +162 -0
  25. package/dist/kokimoki-storage.d.ts +156 -0
  26. package/dist/kokimoki-storage.js +208 -0
  27. package/dist/kokimoki.min.d.ts +775 -110
  28. package/dist/kokimoki.min.js +4088 -2408
  29. package/dist/kokimoki.min.js.map +1 -1
  30. package/dist/llms.txt +657 -0
  31. package/dist/message-queue.d.ts +8 -0
  32. package/dist/message-queue.js +19 -0
  33. package/dist/protocol/ws-message/index.d.ts +3 -0
  34. package/dist/protocol/ws-message/index.js +3 -0
  35. package/dist/protocol/ws-message/reader.d.ts +11 -0
  36. package/dist/protocol/ws-message/reader.js +36 -0
  37. package/dist/protocol/ws-message/type.d.ts +11 -0
  38. package/dist/protocol/ws-message/type.js +12 -0
  39. package/dist/protocol/ws-message/writer.d.ts +9 -0
  40. package/dist/protocol/ws-message/writer.js +45 -0
  41. package/dist/services/index.d.ts +3 -0
  42. package/dist/services/index.js +3 -0
  43. package/dist/services/kokimoki-ai.d.ts +153 -0
  44. package/dist/services/kokimoki-ai.js +164 -0
  45. package/dist/services/kokimoki-leaderboard.d.ts +175 -0
  46. package/dist/services/kokimoki-leaderboard.js +203 -0
  47. package/dist/services/kokimoki-storage.d.ts +155 -0
  48. package/dist/services/kokimoki-storage.js +208 -0
  49. package/dist/stores/index.d.ts +3 -0
  50. package/dist/stores/index.js +3 -0
  51. package/dist/stores/kokimoki-local-store.d.ts +11 -0
  52. package/dist/stores/kokimoki-local-store.js +40 -0
  53. package/dist/stores/kokimoki-store.d.ts +22 -0
  54. package/dist/stores/kokimoki-store.js +117 -0
  55. package/dist/stores/kokimoki-transaction.d.ts +18 -0
  56. package/dist/stores/kokimoki-transaction.js +143 -0
  57. package/dist/synced-schema.d.ts +74 -0
  58. package/dist/synced-schema.js +83 -0
  59. package/dist/synced-store.d.ts +10 -0
  60. package/dist/synced-store.js +9 -0
  61. package/dist/synced-types.d.ts +47 -0
  62. package/dist/synced-types.js +67 -0
  63. package/dist/types/index.d.ts +3 -0
  64. package/dist/types/index.js +3 -0
  65. package/dist/utils/valtio.d.ts +7 -0
  66. package/dist/utils/valtio.js +6 -0
  67. package/dist/version.d.ts +1 -1
  68. package/dist/version.js +2 -1
  69. package/dist/ws-message-type copy.d.ts +6 -0
  70. package/dist/ws-message-type copy.js +7 -0
  71. package/package.json +4 -3
@@ -1,6 +1,9 @@
1
1
  import TypedEmitter from 'typed-emitter';
2
- import * as Y from 'yjs';
3
2
  import { Snapshot } from 'valtio/vanilla';
3
+ import * as Y from 'yjs';
4
+ export { proxy, ref, snapshot, subscribe, useSnapshot } from 'valtio';
5
+ export { derive, underive } from 'derive-valtio';
6
+ export { devtools, subscribeKey, useProxy, watch } from 'valtio/utils';
4
7
 
5
8
  interface Paginated<T> {
6
9
  items: T[];
@@ -25,10 +28,484 @@ interface Upload {
25
28
  tags: string[];
26
29
  }
27
30
 
28
- declare enum RoomSubscriptionMode {
29
- Read = "r",
30
- Write = "w",
31
- ReadWrite = "b"
31
+ /**
32
+ * Kokimoki AI Integration Service
33
+ *
34
+ * Provides built-in AI capabilities for game applications without requiring API keys or setup.
35
+ * Includes text generation, structured JSON output, and image modification.
36
+ *
37
+ * **Key Features:**
38
+ * - Multiple AI models (GPT-4, GPT-5, Gemini variants)
39
+ * - Text generation with configurable creativity (temperature)
40
+ * - Structured JSON output for game data
41
+ * - AI-powered image modifications
42
+ * - No API keys or configuration required
43
+ *
44
+ * **Common Use Cases:**
45
+ * - Generate dynamic game content (quests, dialogues, stories)
46
+ * - Create AI opponents or NPCs with personalities
47
+ * - Generate quiz questions or trivia
48
+ * - Create game assets (character stats, item descriptions)
49
+ * - Transform user-uploaded images
50
+ * - Generate procedural content
51
+ *
52
+ * Access via `kmClient.ai`
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * // Generate story text
57
+ * const story = await kmClient.ai.chat({
58
+ * systemPrompt: 'You are a fantasy story writer',
59
+ * userPrompt: 'Write a short quest description',
60
+ * temperature: 0.8
61
+ * });
62
+ *
63
+ * // Generate structured game data
64
+ * interface Enemy {
65
+ * name: string;
66
+ * health: number;
67
+ * attack: number;
68
+ * }
69
+ * const enemy = await kmClient.ai.generateJson<Enemy>({
70
+ * userPrompt: 'Create a level 5 goblin warrior'
71
+ * });
72
+ *
73
+ * // Transform image
74
+ * const modified = await kmClient.ai.modifyImage(
75
+ * imageUrl,
76
+ * 'Make it look like pixel art'
77
+ * );
78
+ * ```
79
+ */
80
+ declare class KokimokiAiService {
81
+ private readonly client;
82
+ constructor(client: KokimokiClient);
83
+ /**
84
+ * Generate a chat response from the AI model.
85
+ *
86
+ * Sends a chat request to the AI service and returns the generated response.
87
+ * Supports multiple AI models including GPT and Gemini variants with configurable
88
+ * parameters for fine-tuning the response behavior.
89
+ *
90
+ * @param req The chat request parameters.
91
+ * @param req.model Optional. The AI model to use. Defaults to server-side default if not specified.
92
+ * Available models:
93
+ * - `gpt-4o`: OpenAI GPT-4 Optimized
94
+ * - `gpt-4o-mini`: Smaller, faster GPT-4 variant
95
+ * - `gpt-5`: OpenAI GPT-5 (latest)
96
+ * - `gpt-5-mini`: Smaller GPT-5 variant
97
+ * - `gpt-5-nano`: Smallest GPT-5 variant for lightweight tasks
98
+ * - `gemini-2.5-flash-lite`: Google Gemini lite variant
99
+ * - `gemini-2.5-flash`: Google Gemini fast variant
100
+ * @param req.systemPrompt Optional. The system message that sets the behavior and context for the AI.
101
+ * This helps define the AI's role, personality, and constraints.
102
+ * @param req.userPrompt The user's message or question to send to the AI.
103
+ * @param req.temperature Optional. Controls randomness in the response (0.0 to 1.0).
104
+ * Lower values make output more focused and deterministic,
105
+ * higher values make it more creative and varied.
106
+ * @param req.maxTokens Optional. The maximum number of tokens to generate in the response.
107
+ * Controls the length of the AI's output.
108
+ *
109
+ * @returns A promise that resolves to an object containing the AI-generated response.
110
+ * @returns {string} content The text content of the AI's response.
111
+ *
112
+ * @throws An error object if the API request fails.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * const response = await client.ai.chat({
117
+ * model: "gpt-4o",
118
+ * systemPrompt: "You are a helpful coding assistant.",
119
+ * userPrompt: "Explain what TypeScript is in one sentence.",
120
+ * temperature: 0.7,
121
+ * maxTokens: 100
122
+ * });
123
+ * console.log(response.content);
124
+ * ```
125
+ */
126
+ chat(req: {
127
+ model?: "gpt-4o" | "gpt-4o-mini" | "gpt-5" | "gpt-5-mini" | "gpt-5-nano" | "gemini-2.5-flash-lite" | "gemini-2.5-flash";
128
+ systemPrompt?: string;
129
+ userPrompt: string;
130
+ temperature?: number;
131
+ maxTokens?: number;
132
+ responseMimeType?: string;
133
+ }): Promise<{
134
+ content: string;
135
+ }>;
136
+ /**
137
+ * Generate structured JSON output from the AI model.
138
+ *
139
+ * Sends a chat request to the AI service with the expectation of receiving
140
+ * a JSON-formatted response. This is useful for scenarios where the output
141
+ * needs to be parsed or processed programmatically.
142
+ *
143
+ * @param req The chat request parameters.
144
+ * @param req.model Optional. The AI model to use. Defaults to server-side default if not specified.
145
+ * Available models:
146
+ * - `gpt-4o`: OpenAI GPT-4 Optimized
147
+ * - `gpt-4o-mini`: Smaller, faster GPT-4 variant
148
+ * - `gpt-5`: OpenAI GPT-5 (latest)
149
+ * - `gpt-5-mini`: Smaller GPT-5 variant
150
+ * - `gpt-5-nano`: Smallest GPT-5 variant for lightweight tasks
151
+ * - `gemini-2.5-flash-lite`: Google Gemini lite variant
152
+ * - `gemini-2.5-flash`: Google Gemini fast variant
153
+ * @param req.systemPrompt Optional. The system message that sets the behavior and context for the AI.
154
+ * This helps define the AI's role, personality, and constraints.
155
+ * @param req.userPrompt The user's message or question to send to the AI.
156
+ * @param req.temperature Optional. Controls randomness in the response (0.0 to 1.0).
157
+ * Lower values make output more focused and deterministic,
158
+ * higher values make it more creative and varied.
159
+ * @param req.maxTokens Optional. The maximum number of tokens to generate in the response.
160
+ * Controls the length of the AI's output.
161
+ *
162
+ * @returns A promise that resolves to the parsed JSON object generated by the AI.
163
+ *
164
+ * @throws An error object if the API request fails or if the response is not valid JSON.
165
+ */
166
+ generateJson<T extends object>(req: {
167
+ model?: "gpt-4o" | "gpt-4o-mini" | "gpt-5" | "gpt-5-mini" | "gpt-5-nano" | "gemini-2.5-flash-lite" | "gemini-2.5-flash";
168
+ systemPrompt?: string;
169
+ userPrompt: string;
170
+ temperature?: number;
171
+ maxTokens?: number;
172
+ }): Promise<T>;
173
+ /**
174
+ * Modify an image using the AI service.
175
+ * @param baseImageUrl The URL of the base image to modify.
176
+ * @param prompt The modification prompt to apply to the image.
177
+ * @param tags Optional. Tags to associate with the image.
178
+ * @returns A promise that resolves to the modified image upload information.
179
+ */
180
+ modifyImage(baseImageUrl: string, prompt: string, tags?: string[]): Promise<Upload>;
181
+ }
182
+
183
+ /**
184
+ * Kokimoki Leaderboard Service
185
+ *
186
+ * Provides efficient player ranking and score tracking with database indexes and optimized queries.
187
+ * Ideal for games with large numbers of players and competitive scoring.
188
+ *
189
+ * **Key Features:**
190
+ * - Efficient ranking with database indexes
191
+ * - Support for ascending (lowest-is-best) and descending (highest-is-best) sorting
192
+ * - Pagination for large leaderboards
193
+ * - Public and private metadata for entries
194
+ * - Insert (preserve all attempts) or upsert (keep latest only) modes
195
+ *
196
+ * **When to use Leaderboard API vs Global Store:**
197
+ *
198
+ * Use the **Leaderboard API** when:
199
+ * - You have a large number of entries (hundreds to thousands of players)
200
+ * - You need efficient ranking and sorting with database indexes
201
+ * - You want pagination and optimized queries for top scores
202
+ * - Memory and network efficiency are important
203
+ *
204
+ * Use a **Global Store** when:
205
+ * - You have a small number of players (typically under 100)
206
+ * - You need real-time updates and live leaderboard changes
207
+ * - You want to combine player scores with other game state
208
+ * - The leaderboard is temporary (session-based or reset frequently)
209
+ *
210
+ * Access via `kmClient.leaderboard`
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * // Submit a high score
215
+ * const { rank } = await kmClient.leaderboard.upsertEntry(
216
+ * 'high-scores',
217
+ * 'desc',
218
+ * 1500,
219
+ * { playerName: 'Alice' },
220
+ * {}
221
+ * );
222
+ *
223
+ * // Get top 10
224
+ * const { items } = await kmClient.leaderboard.listEntries('high-scores', 'desc', 0, 10);
225
+ *
226
+ * // Get player's best
227
+ * const best = await kmClient.leaderboard.getBestEntry('high-scores', 'desc');
228
+ * ```
229
+ */
230
+ declare class KokimokiLeaderboardService {
231
+ private readonly client;
232
+ constructor(client: KokimokiClient);
233
+ /**
234
+ * Add a new entry to a leaderboard.
235
+ *
236
+ * Creates a new entry each time it's called, preserving all attempts. Use this when you want
237
+ * to track every score submission (e.g., all game attempts).
238
+ *
239
+ * @param leaderboardName The name of the leaderboard to add the entry to
240
+ * @param sortDir Sort direction: "asc" for lowest-is-best (e.g., completion time),
241
+ * "desc" for highest-is-best (e.g., points)
242
+ * @param score The numeric score value
243
+ * @param metadata Public metadata visible to all players (e.g., player name, level)
244
+ * @param privateMetadata Private metadata only accessible via API calls (e.g., session ID)
245
+ * @returns A promise resolving to an object with the entry's rank
246
+ *
247
+ * @example
248
+ * ```typescript
249
+ * const { rank } = await kmClient.leaderboard.insertEntry(
250
+ * 'high-scores',
251
+ * 'desc',
252
+ * 1500,
253
+ * { playerName: 'Alice', level: 10 },
254
+ * { sessionId: 'abc123' }
255
+ * );
256
+ * console.log(`New rank: ${rank}`);
257
+ * ```
258
+ */
259
+ insertEntry<MetadataT, PrivateMetadataT>(leaderboardName: string, sortDir: "asc" | "desc", score: number, metadata: MetadataT, privateMetadata: PrivateMetadataT): Promise<{
260
+ rank: number;
261
+ }>;
262
+ /**
263
+ * Add or update the latest entry for the current client in a leaderboard.
264
+ *
265
+ * Replaces the previous entry if one exists for this client. Use this when you only want
266
+ * to keep the latest or best score per player (e.g., daily high score).
267
+ *
268
+ * @param leaderboardName The name of the leaderboard to upsert the entry in
269
+ * @param sortDir Sort direction: "asc" for lowest-is-best (e.g., completion time),
270
+ * "desc" for highest-is-best (e.g., points)
271
+ * @param score The numeric score value
272
+ * @param metadata Public metadata visible to all players (e.g., player name, completion time)
273
+ * @param privateMetadata Private metadata only accessible via API calls (e.g., device ID)
274
+ * @returns A promise resolving to an object with the entry's updated rank
275
+ *
276
+ * @example
277
+ * ```typescript
278
+ * const { rank } = await kmClient.leaderboard.upsertEntry(
279
+ * 'daily-scores',
280
+ * 'desc',
281
+ * 2000,
282
+ * { playerName: 'Bob', completionTime: 120 },
283
+ * { deviceId: 'xyz789' }
284
+ * );
285
+ * console.log(`Updated rank: ${rank}`);
286
+ * ```
287
+ */
288
+ upsertEntry<MetadataT, PrivateMetadataT>(leaderboardName: string, sortDir: "asc" | "desc", score: number, metadata: MetadataT, privateMetadata: PrivateMetadataT): Promise<{
289
+ rank: number;
290
+ }>;
291
+ /**
292
+ * List entries in a leaderboard with pagination.
293
+ *
294
+ * Retrieves a sorted list of leaderboard entries. Use skip and limit parameters for
295
+ * pagination (e.g., showing top 10, or implementing "load more" functionality).
296
+ *
297
+ * @param leaderboardName The name of the leaderboard to query
298
+ * @param sortDir Sort direction: "asc" for lowest-is-best (e.g., completion time),
299
+ * "desc" for highest-is-best (e.g., points)
300
+ * @param skip Number of entries to skip for pagination (default: 0)
301
+ * @param limit Maximum number of entries to return (default: 100)
302
+ * @returns A promise resolving to a paginated list of entries with rank, score, and metadata
303
+ *
304
+ * @example
305
+ * ```typescript
306
+ * // Get top 10 scores
307
+ * const { items, total } = await kmClient.leaderboard.listEntries(
308
+ * 'weekly-scores',
309
+ * 'desc',
310
+ * 0,
311
+ * 10
312
+ * );
313
+ *
314
+ * items.forEach(entry => {
315
+ * console.log(`Rank ${entry.rank}: ${entry.metadata.playerName} - ${entry.score}`);
316
+ * });
317
+ * ```
318
+ */
319
+ listEntries<MetadataT>(leaderboardName: string, sortDir: "asc" | "desc", skip?: number, limit?: number): Promise<Paginated<{
320
+ rank: number;
321
+ score: number;
322
+ metadata: MetadataT;
323
+ }>>;
324
+ /**
325
+ * Get the best entry for a specific client in a leaderboard.
326
+ *
327
+ * Retrieves the highest-ranked entry for a client based on the sort direction.
328
+ * Defaults to the current client if no clientId is provided.
329
+ *
330
+ * @param leaderboardName The name of the leaderboard to query
331
+ * @param sortDir Sort direction: "asc" for lowest-is-best (e.g., completion time),
332
+ * "desc" for highest-is-best (e.g., points)
333
+ * @param clientId The client ID to get the best entry for (optional, defaults to current client)
334
+ * @returns A promise resolving to the best entry with rank, score, and metadata
335
+ *
336
+ * @example
337
+ * ```typescript
338
+ * // Get current client's best entry
339
+ * const myBest = await kmClient.leaderboard.getBestEntry('all-time-high', 'desc');
340
+ * console.log(`My best: Rank ${myBest.rank}, Score ${myBest.score}`);
341
+ *
342
+ * // Get another player's best entry
343
+ * const otherBest = await kmClient.leaderboard.getBestEntry(
344
+ * 'all-time-high',
345
+ * 'desc',
346
+ * 'other-client-id'
347
+ * );
348
+ * ```
349
+ */
350
+ getBestEntry<MetadataT>(leaderboardName: string, sortDir: "asc" | "desc", clientId?: string): Promise<{
351
+ rank: number;
352
+ score: number;
353
+ metadata: MetadataT;
354
+ }>;
355
+ }
356
+
357
+ /**
358
+ * Kokimoki Storage Service
359
+ *
360
+ * Provides file upload and management capabilities for game applications. Ideal for media files
361
+ * (images, videos, audio) and other data not suitable for real-time stores (JSON, text files).
362
+ *
363
+ * **Key Features:**
364
+ * - Upload files to cloud storage with CDN delivery
365
+ * - Tag-based organization and filtering
366
+ * - Query uploads by client, MIME type, or tags
367
+ * - Pagination support for large collections
368
+ * - Public CDN URLs for direct access
369
+ *
370
+ * **Common Use Cases:**
371
+ * - Player avatars and profile images
372
+ * - Game screenshots and replays
373
+ * - User-generated content
374
+ * - Asset uploads (levels, maps, custom skins)
375
+ * - JSON configuration files
376
+ *
377
+ * Access via `kmClient.storage`
378
+ *
379
+ * @example
380
+ * ```typescript
381
+ * // Upload an image
382
+ * const upload = await kmClient.storage.upload('avatar.jpg', imageBlob, ['profile']);
383
+ *
384
+ * // Query user's uploads
385
+ * const myUploads = await kmClient.storage.listUploads({
386
+ * clientId: kmClient.id
387
+ * });
388
+ *
389
+ * // Use in store
390
+ * await kmClient.transact([store], (state) => {
391
+ * state.playerAvatar = upload.url;
392
+ * });
393
+ * ```
394
+ */
395
+ declare class KokimokiStorageService {
396
+ private readonly client;
397
+ constructor(client: KokimokiClient);
398
+ private createUpload;
399
+ private uploadChunks;
400
+ private completeUpload;
401
+ /**
402
+ * Upload a file to cloud storage.
403
+ *
404
+ * Uploads a file (Blob) to Kokimoki storage and returns an Upload object with a public CDN URL.
405
+ * Files are automatically chunked for efficient upload. The returned URL can be used directly
406
+ * in your application (e.g., in img tags or store state).
407
+ *
408
+ * @param name The filename for the upload
409
+ * @param blob The Blob object containing the file data
410
+ * @param tags Optional array of tags for organizing and filtering uploads (default: [])
411
+ * @returns A promise resolving to the Upload object with CDN URL and metadata
412
+ *
413
+ * @example
414
+ * ```typescript
415
+ * // Upload image with tags
416
+ * const upload = await kmClient.storage.upload(
417
+ * 'avatar.jpg',
418
+ * imageBlob,
419
+ * ['profile', 'avatar']
420
+ * );
421
+ *
422
+ * // Use the CDN URL
423
+ * console.log(upload.url); // https://cdn.kokimoki.com/...
424
+ *
425
+ * // Store in game state
426
+ * await kmClient.transact([store], (state) => {
427
+ * state.players[kmClient.id].avatar = upload.url;
428
+ * });
429
+ * ```
430
+ */
431
+ upload(name: string, blob: Blob, tags?: string[]): Promise<Upload>;
432
+ /**
433
+ * Update metadata for an existing upload.
434
+ *
435
+ * Allows you to replace the tags associated with an upload. Useful for reorganizing
436
+ * or recategorizing uploaded files.
437
+ *
438
+ * @param id The upload ID to update
439
+ * @param update Object containing the new tags array
440
+ * @returns A promise resolving to the updated Upload object
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * // Update tags
445
+ * const updated = await kmClient.storage.updateUpload(upload.id, {
446
+ * tags: ['archived', 'old-profile']
447
+ * });
448
+ * ```
449
+ */
450
+ updateUpload(id: string, update: {
451
+ tags?: string[];
452
+ }): Promise<Upload>;
453
+ /**
454
+ * Query uploaded files with filtering and pagination.
455
+ *
456
+ * Retrieves a list of uploads matching the specified criteria. Supports filtering by
457
+ * client (uploader), MIME types, and tags. Use pagination for large collections.
458
+ *
459
+ * @param filter Optional filter criteria
460
+ * @param filter.clientId Filter by uploader's client ID
461
+ * @param filter.mimeTypes Filter by MIME types (e.g., ['image/jpeg', 'image/png'])
462
+ * @param filter.tags Filter by tags (all specified tags must match)
463
+ * @param skip Number of results to skip for pagination (default: 0)
464
+ * @param limit Maximum number of results to return (default: 100)
465
+ * @returns A promise resolving to paginated Upload results with total count
466
+ *
467
+ * @example
468
+ * ```typescript
469
+ * // Get current user's images
470
+ * const myImages = await kmClient.storage.listUploads({
471
+ * clientId: kmClient.id,
472
+ * mimeTypes: ['image/jpeg', 'image/png']
473
+ * });
474
+ *
475
+ * // Get all profile avatars
476
+ * const avatars = await kmClient.storage.listUploads({
477
+ * tags: ['profile', 'avatar']
478
+ * });
479
+ *
480
+ * // Pagination
481
+ * const page2 = await kmClient.storage.listUploads({}, 10, 10);
482
+ * ```
483
+ */
484
+ listUploads(filter?: {
485
+ clientId?: string;
486
+ mimeTypes?: string[];
487
+ tags?: string[];
488
+ }, skip?: number, limit?: number): Promise<Paginated<Upload>>;
489
+ /**
490
+ * Permanently delete an uploaded file.
491
+ *
492
+ * Removes the file from cloud storage and the CDN. The URL will no longer be accessible.
493
+ * This operation cannot be undone.
494
+ *
495
+ * @param id The upload ID to delete
496
+ * @returns A promise resolving to deletion confirmation
497
+ *
498
+ * @example
499
+ * ```typescript
500
+ * // Delete an upload
501
+ * const result = await kmClient.storage.deleteUpload(upload.id);
502
+ * console.log(`Deleted: ${result.deletedCount} file(s)`);
503
+ * ```
504
+ */
505
+ deleteUpload(id: string): Promise<{
506
+ acknowledged: boolean;
507
+ deletedCount: number;
508
+ }>;
32
509
  }
33
510
 
34
511
  declare class KokimokiStore<T extends object> {
@@ -47,25 +524,8 @@ declare class KokimokiStore<T extends object> {
47
524
  get(): Snapshot<T>;
48
525
  subscribe(set: (value: Snapshot<T>) => void): () => void;
49
526
  onJoin(client: KokimokiClient<any>): Promise<void>;
50
- onBeforeLeave(client: KokimokiClient): Promise<void>;
51
- onLeave(client: KokimokiClient): Promise<void>;
52
- }
53
-
54
- declare class KokimokiAwareness<DataT> extends KokimokiStore<{
55
- [connectionId: string]: {
56
- clientId: string;
57
- data: DataT;
58
- };
59
- }> {
60
- private _data;
61
- private _kmClients;
62
- constructor(roomName: string, _data: DataT, mode?: RoomSubscriptionMode);
63
- onJoin(client: KokimokiClient<any>): Promise<void>;
64
- onLeave(client: KokimokiClient<any>): Promise<void>;
65
- getClients(): {
66
- [clientId: string]: Snapshot<DataT>;
67
- };
68
- setData(data: DataT): Promise<void>;
527
+ onBeforeLeave(_client: KokimokiClient): Promise<void>;
528
+ onLeave(_client: KokimokiClient): Promise<void>;
69
529
  }
70
530
 
71
531
  declare class KokimokiLocalStore<T extends object> extends KokimokiStore<T> {
@@ -75,7 +535,7 @@ declare class KokimokiLocalStore<T extends object> extends KokimokiStore<T> {
75
535
  constructor(localRoomName: string, defaultState: T);
76
536
  getInitialUpdate(appId: string, clientId: string): {
77
537
  roomHash: number;
78
- initialUpdate: Uint8Array | undefined;
538
+ initialUpdate: Uint8Array<ArrayBufferLike> | undefined;
79
539
  };
80
540
  }
81
541
 
@@ -83,7 +543,162 @@ type Mutable<T> = {
83
543
  -readonly [K in keyof T]: T[K] extends object ? Mutable<T[K]> : T[K];
84
544
  };
85
545
  type StoreValue<S> = S extends KokimokiStore<infer U> ? Mutable<U> : never;
86
- declare const KokimokiClient_base: new () => TypedEmitter<KokimokiClientEvents>;
546
+ declare const KokimokiClient_base: {
547
+ new (): TypedEmitter<KokimokiClientEvents>;
548
+ };
549
+ /**
550
+ * Kokimoki Client - Real-time Collaborative Game Development SDK
551
+ *
552
+ * The main entry point for building multiplayer games and collaborative applications.
553
+ * Provides real-time state synchronization, AI integration, cloud storage, leaderboards,
554
+ * and more - all without complex backend setup.
555
+ *
556
+ * **Core Capabilities:**
557
+ * - **Real-time Stores**: Synchronized state with automatic conflict resolution (powered by Valtio + Y.js)
558
+ * - **Atomic Transactions**: Update multiple stores consistently with automatic batching
559
+ * - **AI Integration**: Built-in text generation, structured JSON output, and image modification
560
+ * - **Cloud Storage**: File uploads with CDN delivery and tag-based organization
561
+ * - **Leaderboards**: Efficient player ranking with database indexes and pagination
562
+ * - **Presence Tracking**: Real-time connection status for all players
563
+ * - **Time Sync**: Server-synchronized timestamps across all clients
564
+ * - **Webhooks**: Send data to external services for backend processing
565
+ *
566
+ * **Quick Start:**
567
+ * ```typescript
568
+ * import { KokimokiClient } from '@kokimoki/app';
569
+ *
570
+ * // Initialize the client
571
+ * const kmClient = new KokimokiClient(
572
+ * 'your-host.kokimoki.com',
573
+ * 'your-app-id',
574
+ * 'optional-access-code'
575
+ * );
576
+ *
577
+ * // Connect to the server
578
+ * await kmClient.connect();
579
+ *
580
+ * // Create a synchronized store
581
+ * interface GameState {
582
+ * players: Record<string, { name: string; score: number }>;
583
+ * round: number;
584
+ * }
585
+ *
586
+ * const gameStore = kmClient.store<GameState>('game', {
587
+ * players: {},
588
+ * round: 1
589
+ * });
590
+ *
591
+ * // Update state atomically
592
+ * await kmClient.transact([gameStore], ([game]) => {
593
+ * game.players[kmClient.id] = { name: 'Player 1', score: 0 };
594
+ * game.round = 2;
595
+ * });
596
+ *
597
+ * // Use in React components with Valtio
598
+ * import { useSnapshot } from 'valtio';
599
+ *
600
+ * function GameComponent() {
601
+ * const game = useSnapshot(gameStore.proxy);
602
+ * return <div>Round: {game.round}</div>;
603
+ * }
604
+ * ```
605
+ *
606
+ * **Key Features:**
607
+ *
608
+ * **1. Real-time State Management**
609
+ * - Create global stores shared across all players: `kmClient.store()`
610
+ * - Create local stores for client-side data: `kmClient.localStore()`
611
+ * - Automatic synchronization and conflict resolution
612
+ * - Use `useSnapshot()` from Valtio for reactive React components
613
+ *
614
+ * **2. Atomic Transactions**
615
+ * ```typescript
616
+ * // Update multiple stores atomically
617
+ * await kmClient.transact([playerStore, gameStore], ([player, game]) => {
618
+ * player.score += 10;
619
+ * game.lastUpdate = kmClient.serverTimestamp();
620
+ * });
621
+ * ```
622
+ *
623
+ * **3. AI Integration (No API keys required)**
624
+ * ```typescript
625
+ * // Generate text
626
+ * const story = await kmClient.ai.chat({
627
+ * model: 'gpt-4o',
628
+ * userPrompt: 'Write a quest description',
629
+ * temperature: 0.8
630
+ * });
631
+ *
632
+ * // Generate structured data
633
+ * interface Quest { title: string; reward: number; }
634
+ * const quest = await kmClient.ai.generateJson<Quest>({
635
+ * userPrompt: 'Create a level 5 quest'
636
+ * });
637
+ *
638
+ * // Modify images
639
+ * const modified = await kmClient.ai.modifyImage(url, 'Make it pixel art');
640
+ * ```
641
+ *
642
+ * **4. Cloud Storage**
643
+ * ```typescript
644
+ * // Upload files with tags
645
+ * const upload = await kmClient.storage.upload('avatar.jpg', blob, ['profile']);
646
+ *
647
+ * // Query uploads
648
+ * const images = await kmClient.storage.listUploads({
649
+ * clientId: kmClient.id,
650
+ * mimeTypes: ['image/jpeg', 'image/png']
651
+ * });
652
+ * ```
653
+ *
654
+ * **5. Leaderboards**
655
+ * ```typescript
656
+ * // Submit score (replaces previous entry)
657
+ * await kmClient.leaderboard.upsertEntry(
658
+ * 'high-scores',
659
+ * 'desc',
660
+ * 1500,
661
+ * { playerName: 'Alice' },
662
+ * {}
663
+ * );
664
+ *
665
+ * // Get top 10
666
+ * const top10 = await kmClient.leaderboard.listEntries('high-scores', 'desc', 0, 10);
667
+ * ```
668
+ *
669
+ * **6. Presence Tracking**
670
+ * ```typescript
671
+ * // Track online players
672
+ * const onlineClientIds = useSnapshot(gameStore.connections).clientIds;
673
+ * const isPlayerOnline = onlineClientIds.has(playerId);
674
+ * ```
675
+ *
676
+ * **Best Practices:**
677
+ * - Always use `kmClient.serverTimestamp()` for time-sensitive operations
678
+ * - Prefer Records over Arrays: `Record<string, T>` with timestamp keys
679
+ * - Use `kmClient.transact()` for all state updates to ensure atomicity
680
+ * - Tag uploads for easy filtering and organization
681
+ * - Use local stores for client-side settings and preferences
682
+ * - Leverage TypeScript generics for type-safe stores
683
+ *
684
+ * **Events:**
685
+ * - `connected`: Fired when client connects/reconnects to server
686
+ * - `disconnected`: Fired when connection is lost
687
+ *
688
+ * @template ClientContextT The type of client context data (custom user data from your backend)
689
+ *
690
+ * @example
691
+ * ```typescript
692
+ * // Listen for connection events
693
+ * kmClient.on('connected', () => {
694
+ * console.log('Connected to Kokimoki!');
695
+ * });
696
+ *
697
+ * kmClient.on('disconnected', () => {
698
+ * console.log('Connection lost, will auto-reconnect...');
699
+ * });
700
+ * ```
701
+ */
87
702
  declare class KokimokiClient<ClientContextT = any> extends KokimokiClient_base {
88
703
  readonly host: string;
89
704
  readonly appId: string;
@@ -110,6 +725,9 @@ declare class KokimokiClient<ClientContextT = any> extends KokimokiClient_base {
110
725
  private _pingInterval;
111
726
  private _clientTokenKey;
112
727
  private _editorContext;
728
+ private _ai?;
729
+ private _storage?;
730
+ private _leaderboard?;
113
731
  constructor(host: string, appId: string, code?: string);
114
732
  get id(): string;
115
733
  get connectionId(): string;
@@ -117,9 +735,24 @@ declare class KokimokiClient<ClientContextT = any> extends KokimokiClient_base {
117
735
  get apiUrl(): string;
118
736
  get apiHeaders(): Headers;
119
737
  get clientContext(): ClientContextT & ({} | null);
738
+ /**
739
+ * Indicates whether the client is currently connected to the server.
740
+ */
120
741
  get connected(): boolean;
121
742
  get ws(): WebSocket;
743
+ /**
744
+ * Indicates whether the client is running in editor/development mode.
745
+ */
122
746
  get isEditor(): boolean;
747
+ /**
748
+ * Establishes a connection to the Kokimoki server.
749
+ *
750
+ * Handles authentication, WebSocket setup, and automatic reconnection.
751
+ * If already connecting, returns the existing connection promise.
752
+ *
753
+ * @returns A promise that resolves when the connection is established.
754
+ * @throws Error if the connection fails.
755
+ */
123
756
  connect(): Promise<void>;
124
757
  private handleInitMessage;
125
758
  private handleBinaryMessage;
@@ -127,119 +760,151 @@ declare class KokimokiClient<ClientContextT = any> extends KokimokiClient_base {
127
760
  private handleSubscribeResMessage;
128
761
  private handleUnsubscribeResMessage;
129
762
  private handleRoomUpdateMessage;
763
+ /**
764
+ * Gets the current server timestamp, accounting for client-server time offset.
765
+ *
766
+ * @returns The current server timestamp in milliseconds.
767
+ */
130
768
  serverTimestamp(): number;
769
+ /**
770
+ * Sends a Y.js update to a specific room.
771
+ *
772
+ * @param room - The name of the room to update.
773
+ * @param update - The Y.js update as a Uint8Array.
774
+ * @returns A promise that resolves with the server response.
775
+ */
131
776
  patchRoomState(room: string, update: Uint8Array): Promise<any>;
132
- private createUpload;
133
- private uploadChunks;
134
- private completeUpload;
135
- upload(name: string, blob: Blob, tags?: string[]): Promise<Upload>;
136
- updateUpload(id: string, update: {
137
- tags?: string[];
138
- }): Promise<Upload>;
139
- listUploads(filter?: {
140
- clientId?: string;
141
- mimeTypes?: string[];
142
- tags?: string[];
143
- }, skip?: number, limit?: number): Promise<Paginated<Upload>>;
144
- deleteUpload(id: string): Promise<{
145
- acknowledged: boolean;
146
- deletedCount: number;
147
- }>;
148
- exposeScriptingContext(context: any): Promise<void>;
149
777
  private sendSubscribeReq;
150
778
  private sendUnsubscribeReq;
779
+ /**
780
+ * Joins a store by subscribing to its corresponding room.
781
+ *
782
+ * If already joined, this method does nothing. For local stores, initializes
783
+ * the store locally. For remote stores, sends a subscription request to the server.
784
+ *
785
+ * @param store - The KokimokiStore to join.
786
+ * @template T - The type of the store's state object.
787
+ */
151
788
  join<T extends object>(store: KokimokiStore<T>): Promise<void>;
789
+ /**
790
+ * Leaves a store by unsubscribing from its corresponding room.
791
+ *
792
+ * Triggers the store's `onBeforeLeave` and `onLeave` lifecycle hooks.
793
+ *
794
+ * @param store - The KokimokiStore to leave.
795
+ * @template T - The type of the store's state object.
796
+ */
152
797
  leave<T extends object>(store: KokimokiStore<T>): Promise<void>;
798
+ /**
799
+ * Executes a transaction across one or more stores.
800
+ *
801
+ * Provides proxies to the stores that track changes. All changes are batched
802
+ * and sent to the server atomically. The transaction ensures consistency across
803
+ * multiple stores.
804
+ *
805
+ * @param stores - Array of stores to include in the transaction.
806
+ * @param handler - Function that receives store proxies and performs modifications.
807
+ * @returns A promise that resolves with the return value of the handler.
808
+ * @template TStores - Tuple type of the stores array.
809
+ * @template ReturnT - The return type of the handler function.
810
+ *
811
+ * @example
812
+ * ```ts
813
+ * await client.transact([playerStore, gameStore], ([player, game]) => {
814
+ * player.score += 10;
815
+ * game.lastUpdate = Date.now();
816
+ * });
817
+ * ```
818
+ */
153
819
  transact<TStores extends readonly KokimokiStore<any>[], ReturnT = void>(stores: [...TStores], handler: (proxies: {
154
820
  [K in keyof TStores]: StoreValue<TStores[K]>;
155
821
  }) => ReturnT | Promise<ReturnT>): Promise<ReturnT>;
156
- close(): Promise<void>;
157
- getRoomHash<T extends object>(store: KokimokiStore<T>): number;
158
- /** Initializers */
159
- store<T extends object>(name: string, defaultState: T, autoJoin?: boolean): KokimokiStore<T>;
160
- localStore<T extends object>(name: string, defaultState: T): KokimokiLocalStore<T>;
161
- awareness<T>(name: string, initialData: T, autoJoin?: boolean): KokimokiAwareness<T>;
162
822
  /**
163
- * Add a new entry to a leaderboard
164
- * @param leaderboardName
165
- * @param score
166
- * @param metadata
167
- * @returns
823
+ * Closes the client connection and cleans up resources.
824
+ *
825
+ * Disables automatic reconnection, closes the WebSocket, and clears all intervals.
168
826
  */
169
- insertLeaderboardEntry<MetadataT, PrivateMetadataT>(leaderboardName: string, sortDir: "asc" | "desc", score: number, metadata: MetadataT, privateMetadata: PrivateMetadataT): Promise<{
170
- rank: number;
171
- }>;
827
+ close(): Promise<void>;
172
828
  /**
173
- * Add or update latest entry to a leaderboard
174
- * @param leaderboardName
175
- * @param score
176
- * @param metadata
177
- * @param privateMetadata Can only be read using the leaderboard API
178
- * @returns
829
+ * Gets the internal room hash identifier for a store.
830
+ *
831
+ * @param store - The store to get the room hash for.
832
+ * @returns The room hash as a number.
833
+ * @throws Error if the store hasn't been joined.
834
+ * @template T - The type of the store's state object.
179
835
  */
180
- upsertLeaderboardEntry<MetadataT, PrivateMetadataT>(leaderboardName: string, sortDir: "asc" | "desc", score: number, metadata: MetadataT, privateMetadata: PrivateMetadataT): Promise<{
181
- rank: number;
182
- }>;
836
+ getRoomHash<T extends object>(store: KokimokiStore<T>): number;
183
837
  /**
184
- * List entries in a leaderboard
185
- * @param leaderboardName
186
- * @param skip
187
- * @param limit
188
- * @returns
838
+ * Creates a new remote store synchronized with the server.
839
+ *
840
+ * @param name - The name of the room/store.
841
+ * @param defaultState - The initial state of the store.
842
+ * @param autoJoin - Whether to automatically join the store (default: true).
843
+ * @returns A new KokimokiStore instance.
844
+ * @template T - The type of the store's state object.
845
+ *
846
+ * @example
847
+ * ```ts
848
+ * const gameStore = client.store('game', { players: [], score: 0 });
849
+ * ```
189
850
  */
190
- listLeaderboardEntries<MetadataT>(leaderboardName: string, sortDir: "asc" | "desc", skip?: number, limit?: number): Promise<Paginated<{
191
- rank: number;
192
- score: number;
193
- metadata: MetadataT;
194
- }>>;
851
+ store<T extends object>(name: string, defaultState: T, autoJoin?: boolean): KokimokiStore<T>;
195
852
  /**
196
- * Get best entry in leaderboard for a client, defaults to current client
197
- * @param leaderboardName
198
- * @param sortDir
199
- * @param clientId
853
+ * Creates a new local store that persists only in the client's browser.
854
+ *
855
+ * Local stores are automatically joined and are not synchronized with the server.
856
+ * Data is stored locally per client and app.
857
+ *
858
+ * @param name - The name of the local store.
859
+ * @param defaultState - The initial state of the store.
860
+ * @returns A new KokimokiLocalStore instance.
861
+ * @template T - The type of the store's state object.
862
+ *
863
+ * @example
864
+ * ```ts
865
+ * const settingsStore = client.localStore('settings', { volume: 0.5, theme: 'dark' });
866
+ * ```
200
867
  */
201
- getBestLeaderboardEntry<MetadataT>(leaderboardName: string, sortDir: "asc" | "desc", clientId?: string): Promise<{
202
- rank: number;
203
- score: number;
204
- metadata: MetadataT;
205
- }>;
868
+ localStore<T extends object>(name: string, defaultState: T): KokimokiLocalStore<T>;
206
869
  /**
207
- * Send app data via webhook
870
+ * Sends app data to the server via webhook for external processing.
871
+ *
872
+ * @param event - The name of the webhook event.
873
+ * @param data - The data to send with the webhook.
874
+ * @returns A promise that resolves with the job ID.
875
+ * @template T - The type of the data being sent.
876
+ *
877
+ * @example
878
+ * ```ts
879
+ * await client.sendWebhook('game-ended', { winner: 'player1', score: 100 });
880
+ * ```
208
881
  */
209
882
  sendWebhook<T>(event: string, data: T): Promise<{
210
883
  jobId: string;
211
884
  }>;
212
885
  /**
213
- * Generic AI chat endpoint: send a system prompt (and optional user prompt) to get a response.
886
+ * Access AI capabilities including text generation, structured JSON output, and image modification.
214
887
  */
215
- chat(systemPrompt: string, userPrompt?: string, temperature?: number, maxTokens?: number): Promise<{
216
- content: string;
217
- }>;
888
+ get ai(): KokimokiAiService;
218
889
  /**
219
- * Use AI to apply prompt to an image
890
+ * Access file upload and management for media files, images, and user-generated content.
220
891
  */
221
- transformImage(baseImageUrl: string, prompt: string, tags?: string[]): Promise<Upload>;
892
+ get storage(): KokimokiStorageService;
222
893
  /**
223
- * Load app config - optionally translated to any language
894
+ * Access player ranking and score tracking with efficient queries and pagination.
224
895
  */
225
- getConfig<T>(language?: string): Promise<{
226
- status: "processing" | "failed" | "completed";
227
- config: T;
228
- }>;
896
+ get leaderboard(): KokimokiLeaderboardService;
897
+ }
898
+
899
+ declare enum RoomSubscriptionMode {
900
+ Read = "r",
901
+ Write = "w",
902
+ ReadWrite = "b"
229
903
  }
230
904
 
231
- declare class RoomSubscription {
232
- private kmClient;
233
- readonly store: KokimokiStore<any>;
234
- private _joined;
235
- private _roomHash?;
236
- private _onDisconnect;
237
- constructor(kmClient: KokimokiClient, store: KokimokiStore<any>);
238
- get roomName(): string;
239
- get roomHash(): number;
240
- get joined(): boolean;
241
- applyInitialResponse(roomHash: number, initialUpdate?: Uint8Array): Promise<void>;
242
- close(): void;
905
+ declare module "valtio" {
906
+ function useSnapshot<T extends object>(p: T): T;
243
907
  }
244
908
 
245
- export { KokimokiAwareness, KokimokiClient, type KokimokiClientEvents, KokimokiStore, type Paginated, RoomSubscription, RoomSubscriptionMode, type Upload };
909
+ export { KokimokiClient, KokimokiStore };
910
+ export type { KokimokiClientEvents, Paginated, Upload };