@kokimoki/app 3.0.0 → 3.1.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.
- package/dist/core/kokimoki-client.d.ts +52 -0
- package/dist/core/kokimoki-client.js +37 -0
- package/dist/core/room-subscription-mode.d.ts +1 -5
- package/dist/core/room-subscription-mode.js +3 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/services/kokimoki-i18n.d.ts +6 -3
- package/dist/services/kokimoki-i18n.js +13 -6
- package/dist/stores/kokimoki-store.d.ts +10 -1
- package/dist/stores/kokimoki-store.js +10 -1
- package/dist/types/env.d.ts +10 -0
- package/dist/utils/kokimoki-client.d.ts +7 -3
- package/dist/utils/kokimoki-client.js +7 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/kokimoki-sdk.instructions.md +39 -0
- package/package.json +1 -1
|
@@ -2,6 +2,33 @@ import type TypedEmitter from "typed-emitter";
|
|
|
2
2
|
import { KokimokiAiService, KokimokiI18nService, KokimokiLeaderboardService, KokimokiStorageService } from "../services";
|
|
3
3
|
import { KokimokiLocalStore, KokimokiStore } from "../stores";
|
|
4
4
|
import type { KokimokiClientEvents, KokimokiEnv } from "../types";
|
|
5
|
+
/**
|
|
6
|
+
* Reserved store name for the App Meta store.
|
|
7
|
+
* Stores with the `__km/` prefix are reserved for SDK internal use.
|
|
8
|
+
*/
|
|
9
|
+
export declare const APP_META_STORE_NAME = "__km/app-meta";
|
|
10
|
+
/**
|
|
11
|
+
* State type for the App Meta store.
|
|
12
|
+
* Used by the server to inject meta tags into the HTML response.
|
|
13
|
+
*
|
|
14
|
+
* All fields are optional - missing fields will fall back to defaults in index.html.
|
|
15
|
+
*/
|
|
16
|
+
export interface AppMetaState {
|
|
17
|
+
/** HTML lang attribute (e.g., 'en', 'et', 'de') */
|
|
18
|
+
lang?: string;
|
|
19
|
+
/** Document title (browser tab) */
|
|
20
|
+
title?: string;
|
|
21
|
+
/** Meta description */
|
|
22
|
+
description?: string;
|
|
23
|
+
/** Open Graph title (defaults to title if not set) */
|
|
24
|
+
ogTitle?: string;
|
|
25
|
+
/** Open Graph description (defaults to description if not set) */
|
|
26
|
+
ogDescription?: string;
|
|
27
|
+
/** Open Graph image URL */
|
|
28
|
+
ogImage?: string;
|
|
29
|
+
/** Favicon URL */
|
|
30
|
+
favicon?: string;
|
|
31
|
+
}
|
|
5
32
|
type Mutable<T> = {
|
|
6
33
|
-readonly [K in keyof T]: T[K] extends object ? Mutable<T[K]> : T[K];
|
|
7
34
|
};
|
|
@@ -183,6 +210,7 @@ export declare class KokimokiClient<ClientContextT = any> extends KokimokiClient
|
|
|
183
210
|
private _i18n?;
|
|
184
211
|
private _storage?;
|
|
185
212
|
private _leaderboard?;
|
|
213
|
+
private _metaStore?;
|
|
186
214
|
/**
|
|
187
215
|
* Dev mode config - set when running in dev frame with ?key= param
|
|
188
216
|
*/
|
|
@@ -203,6 +231,30 @@ export declare class KokimokiClient<ClientContextT = any> extends KokimokiClient
|
|
|
203
231
|
* The deploy code slug.
|
|
204
232
|
*/
|
|
205
233
|
readonly code: string;
|
|
234
|
+
/**
|
|
235
|
+
* Built-in App Meta store for managing HTML meta tags.
|
|
236
|
+
*
|
|
237
|
+
* This store is automatically joined when the client connects.
|
|
238
|
+
* The server uses this store to inject meta tags into the HTML response
|
|
239
|
+
* for proper SEO and social sharing previews.
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* import { useSnapshot } from 'valtio';
|
|
244
|
+
*
|
|
245
|
+
* const kmClient = getKmClient();
|
|
246
|
+
*
|
|
247
|
+
* // Read meta state
|
|
248
|
+
* const { title, description } = useSnapshot(kmClient.metaStore.proxy);
|
|
249
|
+
*
|
|
250
|
+
* // Update meta via transaction
|
|
251
|
+
* await kmClient.transact([kmClient.metaStore], ([meta]) => {
|
|
252
|
+
* meta.title = 'My Game';
|
|
253
|
+
* meta.description = 'An awesome multiplayer game';
|
|
254
|
+
* });
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
get metaStore(): KokimokiStore<AppMetaState>;
|
|
206
258
|
constructor(env?: KokimokiEnv);
|
|
207
259
|
get id(): string;
|
|
208
260
|
get connectionId(): string;
|
|
@@ -7,6 +7,11 @@ import { initDevMode } from "../utils/kokimoki-dev";
|
|
|
7
7
|
import { getKmEnv } from "../utils/kokimoki-env";
|
|
8
8
|
import { KOKIMOKI_APP_VERSION } from "../version";
|
|
9
9
|
import { RoomSubscription } from "./room-subscription";
|
|
10
|
+
/**
|
|
11
|
+
* Reserved store name for the App Meta store.
|
|
12
|
+
* Stores with the `__km/` prefix are reserved for SDK internal use.
|
|
13
|
+
*/
|
|
14
|
+
export const APP_META_STORE_NAME = "__km/app-meta";
|
|
10
15
|
/**
|
|
11
16
|
* Kokimoki Client - Real-time Collaborative Game Development SDK
|
|
12
17
|
*
|
|
@@ -183,6 +188,7 @@ export class KokimokiClient extends EventEmitter {
|
|
|
183
188
|
_i18n;
|
|
184
189
|
_storage;
|
|
185
190
|
_leaderboard;
|
|
191
|
+
_metaStore;
|
|
186
192
|
/**
|
|
187
193
|
* Dev mode config - set when running in dev frame with ?key= param
|
|
188
194
|
*/
|
|
@@ -203,6 +209,35 @@ export class KokimokiClient extends EventEmitter {
|
|
|
203
209
|
* The deploy code slug.
|
|
204
210
|
*/
|
|
205
211
|
code;
|
|
212
|
+
/**
|
|
213
|
+
* Built-in App Meta store for managing HTML meta tags.
|
|
214
|
+
*
|
|
215
|
+
* This store is automatically joined when the client connects.
|
|
216
|
+
* The server uses this store to inject meta tags into the HTML response
|
|
217
|
+
* for proper SEO and social sharing previews.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```typescript
|
|
221
|
+
* import { useSnapshot } from 'valtio';
|
|
222
|
+
*
|
|
223
|
+
* const kmClient = getKmClient();
|
|
224
|
+
*
|
|
225
|
+
* // Read meta state
|
|
226
|
+
* const { title, description } = useSnapshot(kmClient.metaStore.proxy);
|
|
227
|
+
*
|
|
228
|
+
* // Update meta via transaction
|
|
229
|
+
* await kmClient.transact([kmClient.metaStore], ([meta]) => {
|
|
230
|
+
* meta.title = 'My Game';
|
|
231
|
+
* meta.description = 'An awesome multiplayer game';
|
|
232
|
+
* });
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
get metaStore() {
|
|
236
|
+
if (!this._metaStore) {
|
|
237
|
+
throw new Error("Client not connected");
|
|
238
|
+
}
|
|
239
|
+
return this._metaStore;
|
|
240
|
+
}
|
|
206
241
|
constructor(env = getKmEnv()) {
|
|
207
242
|
super();
|
|
208
243
|
this._env = env;
|
|
@@ -443,6 +478,8 @@ export class KokimokiClient extends EventEmitter {
|
|
|
443
478
|
console.error(`[Kokimoki] Failed to restore subscription for "${subscription.roomName}":`, err);
|
|
444
479
|
}
|
|
445
480
|
}
|
|
481
|
+
// Auto-join the built-in meta store with defaults from config
|
|
482
|
+
this._metaStore = this.store(APP_META_STORE_NAME, this._env.defaultAppMeta ?? {});
|
|
446
483
|
// Emit connected event
|
|
447
484
|
this._reconnectTimeout = 0;
|
|
448
485
|
this.emit("connected");
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
RoomSubscriptionMode["Write"] = "w";
|
|
5
|
-
RoomSubscriptionMode["ReadWrite"] = "b";
|
|
6
|
-
})(RoomSubscriptionMode || (RoomSubscriptionMode = {}));
|
|
1
|
+
// Re-export from stores to maintain backwards compatibility
|
|
2
|
+
// The enum is defined in kokimoki-store.ts to avoid circular dependencies
|
|
3
|
+
export { RoomSubscriptionMode } from "../stores/kokimoki-store";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { KokimokiClient } from "./core";
|
|
2
|
+
export { APP_META_STORE_NAME } from "./core/kokimoki-client";
|
|
3
|
+
export type { AppMetaState } from "./core/kokimoki-client";
|
|
2
4
|
export { KokimokiStore } from "./stores";
|
|
3
5
|
export type { KokimokiClientEvents, KokimokiEnv, Paginated, PollOptions, Upload, } from "./types";
|
|
4
6
|
export type { AllLanguagesStatus, I18nOptions, LanguageStatus, NamespaceStatus, RequestTranslationResult, TranslationStatus, } from "./services/kokimoki-i18n";
|
package/dist/index.js
CHANGED
|
@@ -124,7 +124,7 @@ export declare class KokimokiI18nService {
|
|
|
124
124
|
*
|
|
125
125
|
* Must call `createI18n()` first to set up the instance.
|
|
126
126
|
*
|
|
127
|
-
* @param lng - The language code to initialize with (e.g., 'en', 'de')
|
|
127
|
+
* @param lng - The language code to initialize with (e.g., 'en', 'de'). If not provided, reads from the HTML element's lang attribute.
|
|
128
128
|
* @returns Promise that resolves when i18n is ready
|
|
129
129
|
*
|
|
130
130
|
* @example
|
|
@@ -132,11 +132,14 @@ export declare class KokimokiI18nService {
|
|
|
132
132
|
* // Create instance first
|
|
133
133
|
* const i18n = kmClient.i18n.createI18n({ use: [initReactI18next] });
|
|
134
134
|
*
|
|
135
|
-
* // Then initialize
|
|
135
|
+
* // Then initialize (reads lang from <html> element if not specified)
|
|
136
|
+
* await kmClient.i18n.init();
|
|
137
|
+
*
|
|
138
|
+
* // Or with explicit language
|
|
136
139
|
* await kmClient.i18n.init('en');
|
|
137
140
|
* ```
|
|
138
141
|
*/
|
|
139
|
-
init(lng
|
|
142
|
+
init(lng?: string): Promise<void>;
|
|
140
143
|
/**
|
|
141
144
|
* Get the URL for a translation namespace.
|
|
142
145
|
*
|
|
@@ -96,7 +96,7 @@ export class KokimokiI18nService {
|
|
|
96
96
|
*
|
|
97
97
|
* Must call `createI18n()` first to set up the instance.
|
|
98
98
|
*
|
|
99
|
-
* @param lng - The language code to initialize with (e.g., 'en', 'de')
|
|
99
|
+
* @param lng - The language code to initialize with (e.g., 'en', 'de'). If not provided, reads from the HTML element's lang attribute.
|
|
100
100
|
* @returns Promise that resolves when i18n is ready
|
|
101
101
|
*
|
|
102
102
|
* @example
|
|
@@ -104,7 +104,10 @@ export class KokimokiI18nService {
|
|
|
104
104
|
* // Create instance first
|
|
105
105
|
* const i18n = kmClient.i18n.createI18n({ use: [initReactI18next] });
|
|
106
106
|
*
|
|
107
|
-
* // Then initialize
|
|
107
|
+
* // Then initialize (reads lang from <html> element if not specified)
|
|
108
|
+
* await kmClient.i18n.init();
|
|
109
|
+
*
|
|
110
|
+
* // Or with explicit language
|
|
108
111
|
* await kmClient.i18n.init('en');
|
|
109
112
|
* ```
|
|
110
113
|
*/
|
|
@@ -115,20 +118,24 @@ export class KokimokiI18nService {
|
|
|
115
118
|
if (this.initPromise) {
|
|
116
119
|
return this.initPromise;
|
|
117
120
|
}
|
|
121
|
+
// Default to HTML lang attribute if not provided
|
|
122
|
+
const language = lng ?? document.documentElement.lang ?? "en";
|
|
118
123
|
const env = getKmEnv();
|
|
119
124
|
const namespaces = env.i18nNamespaces ?? [];
|
|
120
|
-
const fallbackLng = this.options.fallbackLng ??
|
|
125
|
+
const fallbackLng = this.options.fallbackLng ?? language;
|
|
121
126
|
const defaultNS = this.options.defaultNS;
|
|
122
127
|
this.initPromise = this.instance.init({
|
|
123
|
-
lng,
|
|
128
|
+
lng: language,
|
|
124
129
|
fallbackLng,
|
|
125
130
|
ns: namespaces,
|
|
126
131
|
defaultNS,
|
|
132
|
+
// Wait for backend to load translations before resolving
|
|
133
|
+
initImmediate: false,
|
|
127
134
|
backend: {
|
|
128
135
|
// i18next-http-backend passes lng as array, extract first element
|
|
129
136
|
loadPath: (lngs, ns) => {
|
|
130
|
-
const
|
|
131
|
-
return this.getNamespaceUrl(
|
|
137
|
+
const lang = Array.isArray(lngs) ? lngs[0] : lngs;
|
|
138
|
+
return this.getNamespaceUrl(lang, ns);
|
|
132
139
|
},
|
|
133
140
|
},
|
|
134
141
|
interpolation: {
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { Snapshot } from "valtio/vanilla";
|
|
2
2
|
import * as Y from "yjs";
|
|
3
|
-
import {
|
|
3
|
+
import type { KokimokiClient } from "../core";
|
|
4
|
+
/**
|
|
5
|
+
* Mode for room subscription - determines read/write permissions.
|
|
6
|
+
* Re-exported here to avoid circular dependency issues.
|
|
7
|
+
*/
|
|
8
|
+
export declare enum RoomSubscriptionMode {
|
|
9
|
+
Read = "r",
|
|
10
|
+
Write = "w",
|
|
11
|
+
ReadWrite = "b"
|
|
12
|
+
}
|
|
4
13
|
export declare class KokimokiStore<T extends object> {
|
|
5
14
|
readonly roomName: string;
|
|
6
15
|
readonly defaultValue: T;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { bind as yjsBind } from "valtio-yjs";
|
|
2
2
|
import { proxy, snapshot, subscribe } from "valtio/vanilla";
|
|
3
3
|
import * as Y from "yjs";
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Mode for room subscription - determines read/write permissions.
|
|
6
|
+
* Re-exported here to avoid circular dependency issues.
|
|
7
|
+
*/
|
|
8
|
+
export var RoomSubscriptionMode;
|
|
9
|
+
(function (RoomSubscriptionMode) {
|
|
10
|
+
RoomSubscriptionMode["Read"] = "r";
|
|
11
|
+
RoomSubscriptionMode["Write"] = "w";
|
|
12
|
+
RoomSubscriptionMode["ReadWrite"] = "b";
|
|
13
|
+
})(RoomSubscriptionMode || (RoomSubscriptionMode = {}));
|
|
5
14
|
export class KokimokiStore {
|
|
6
15
|
roomName;
|
|
7
16
|
defaultValue;
|
package/dist/types/env.d.ts
CHANGED
|
@@ -33,4 +33,14 @@ export interface KokimokiEnv {
|
|
|
33
33
|
i18nPath?: string;
|
|
34
34
|
/** Build URL for dev mode (S3 URL where AI translations are stored) */
|
|
35
35
|
buildUrl?: string;
|
|
36
|
+
/** Default app meta values from kokimoki.config.ts */
|
|
37
|
+
defaultAppMeta?: {
|
|
38
|
+
lang?: string;
|
|
39
|
+
title?: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
ogTitle?: string;
|
|
42
|
+
ogDescription?: string;
|
|
43
|
+
ogImage?: string;
|
|
44
|
+
favicon?: string;
|
|
45
|
+
};
|
|
36
46
|
}
|
|
@@ -5,6 +5,10 @@ import { KokimokiClient } from "../core";
|
|
|
5
5
|
* Creates and caches a single KokimokiClient instance for the application.
|
|
6
6
|
* This is the recommended way to access the client throughout your app.
|
|
7
7
|
*
|
|
8
|
+
* The client includes a built-in `metaStore` for managing HTML meta tags.
|
|
9
|
+
* If `defaultAppMeta` is configured in kokimoki.config.ts, it will be used
|
|
10
|
+
* as the initial state for the metaStore when the client connects.
|
|
11
|
+
*
|
|
8
12
|
* @typeParam T - The client context type for storing custom data per client
|
|
9
13
|
* @returns The singleton KokimokiClient instance
|
|
10
14
|
*
|
|
@@ -22,9 +26,9 @@ import { KokimokiClient } from "../core";
|
|
|
22
26
|
* // Create stores
|
|
23
27
|
* const gameStore = kmClient.store<GameState>('game', initialState);
|
|
24
28
|
*
|
|
25
|
-
* //
|
|
26
|
-
* await kmClient.transact([
|
|
27
|
-
*
|
|
29
|
+
* // Access the built-in meta store
|
|
30
|
+
* await kmClient.transact([kmClient.metaStore], ([meta]) => {
|
|
31
|
+
* meta.title = 'My Game';
|
|
28
32
|
* });
|
|
29
33
|
* ```
|
|
30
34
|
*/
|
|
@@ -6,6 +6,10 @@ let _kmClient;
|
|
|
6
6
|
* Creates and caches a single KokimokiClient instance for the application.
|
|
7
7
|
* This is the recommended way to access the client throughout your app.
|
|
8
8
|
*
|
|
9
|
+
* The client includes a built-in `metaStore` for managing HTML meta tags.
|
|
10
|
+
* If `defaultAppMeta` is configured in kokimoki.config.ts, it will be used
|
|
11
|
+
* as the initial state for the metaStore when the client connects.
|
|
12
|
+
*
|
|
9
13
|
* @typeParam T - The client context type for storing custom data per client
|
|
10
14
|
* @returns The singleton KokimokiClient instance
|
|
11
15
|
*
|
|
@@ -23,9 +27,9 @@ let _kmClient;
|
|
|
23
27
|
* // Create stores
|
|
24
28
|
* const gameStore = kmClient.store<GameState>('game', initialState);
|
|
25
29
|
*
|
|
26
|
-
* //
|
|
27
|
-
* await kmClient.transact([
|
|
28
|
-
*
|
|
30
|
+
* // Access the built-in meta store
|
|
31
|
+
* await kmClient.transact([kmClient.metaStore], ([meta]) => {
|
|
32
|
+
* meta.title = 'My Game';
|
|
29
33
|
* });
|
|
30
34
|
* ```
|
|
31
35
|
*/
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const KOKIMOKI_APP_VERSION = "3.
|
|
1
|
+
export declare const KOKIMOKI_APP_VERSION = "3.1.1";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated file. Do not edit manually.
|
|
2
|
-
export const KOKIMOKI_APP_VERSION = '3.
|
|
2
|
+
export const KOKIMOKI_APP_VERSION = '3.1.1';
|
|
@@ -219,3 +219,42 @@ const PlayerList = () => {
|
|
|
219
219
|
- Use `useSnapshot(store.connections)` to get reactive updates
|
|
220
220
|
- Players can have multiple browser tabs open, but all share the same `clientId`
|
|
221
221
|
- A player is considered online if their `clientId` is in the `clientIds` set
|
|
222
|
+
|
|
223
|
+
## App Meta Store
|
|
224
|
+
|
|
225
|
+
The SDK provides a built-in `metaStore` on the client for managing HTML meta tags. The server uses this store to inject meta tags (title, description, Open Graph, favicon) into the HTML response for proper SEO and social sharing previews.
|
|
226
|
+
|
|
227
|
+
### Reserved Store Names
|
|
228
|
+
|
|
229
|
+
Store names with the `__km/` prefix are reserved for SDK internal use. Do not create stores with this prefix.
|
|
230
|
+
|
|
231
|
+
### Using App Meta
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
import { getKmClient } from "@kokimoki/app";
|
|
235
|
+
import { useSnapshot } from "valtio";
|
|
236
|
+
|
|
237
|
+
const kmClient = getKmClient();
|
|
238
|
+
|
|
239
|
+
// Read meta state anywhere
|
|
240
|
+
const { title, description } = useSnapshot(kmClient.metaStore.proxy);
|
|
241
|
+
|
|
242
|
+
// Update meta via transaction
|
|
243
|
+
await kmClient.transact([kmClient.metaStore], ([meta]) => {
|
|
244
|
+
meta.title = "My Game";
|
|
245
|
+
meta.description = "An awesome multiplayer game";
|
|
246
|
+
meta.ogImage = "https://example.com/og-image.png";
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### App Meta Fields
|
|
251
|
+
|
|
252
|
+
| Field | Description |
|
|
253
|
+
| --------------- | -------------------------------------------------- |
|
|
254
|
+
| `lang` | HTML lang attribute (e.g., 'en', 'et', 'de') |
|
|
255
|
+
| `title` | Document title (browser tab) |
|
|
256
|
+
| `description` | Meta description |
|
|
257
|
+
| `ogTitle` | Open Graph title (defaults to `title` if not set) |
|
|
258
|
+
| `ogDescription` | Open Graph description (defaults to `description`) |
|
|
259
|
+
| `ogImage` | Open Graph image URL |
|
|
260
|
+
| `favicon` | Favicon URL |
|