@kokimoki/app 1.15.2 → 1.16.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/kokimoki-awareness.d.ts +3 -5
- package/dist/kokimoki-awareness.js +5 -40
- package/dist/kokimoki-client.d.ts +9 -6
- package/dist/kokimoki-client.js +7 -2
- package/dist/kokimoki-local-store.d.ts +1 -1
- package/dist/kokimoki-store.d.ts +8 -4
- package/dist/kokimoki-store.js +50 -27
- package/dist/kokimoki-transaction.d.ts +1 -1
- package/dist/kokimoki.min.d.ts +20 -16
- package/dist/kokimoki.min.js +142 -69
- package/dist/kokimoki.min.js.map +1 -1
- package/dist/room-subscription.js +3 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -2
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import { KokimokiStore } from "./kokimoki-store";
|
|
2
2
|
import { RoomSubscriptionMode } from "./room-subscription-mode";
|
|
3
3
|
import type { KokimokiClient } from "./kokimoki-client";
|
|
4
|
+
import type { Snapshot } from "valtio/vanilla";
|
|
4
5
|
export declare class KokimokiAwareness<DataT> extends KokimokiStore<{
|
|
5
6
|
[connectionId: string]: {
|
|
6
7
|
clientId: string;
|
|
7
|
-
lastPing: number;
|
|
8
8
|
data: DataT;
|
|
9
9
|
};
|
|
10
10
|
}> {
|
|
11
11
|
private _data;
|
|
12
|
-
private _pingInterval;
|
|
13
12
|
private _kmClients;
|
|
14
|
-
constructor(roomName: string, _data: DataT, mode?: RoomSubscriptionMode
|
|
13
|
+
constructor(roomName: string, _data: DataT, mode?: RoomSubscriptionMode);
|
|
15
14
|
onJoin(client: KokimokiClient<any>): Promise<void>;
|
|
16
|
-
onBeforeLeave(client: KokimokiClient<any>): Promise<void>;
|
|
17
15
|
onLeave(client: KokimokiClient<any>): Promise<void>;
|
|
18
16
|
getClients(): {
|
|
19
|
-
[clientId: string]: DataT
|
|
17
|
+
[clientId: string]: Snapshot<DataT>;
|
|
20
18
|
};
|
|
21
19
|
setData(data: DataT): Promise<void>;
|
|
22
20
|
}
|
|
@@ -2,64 +2,29 @@ import { KokimokiStore } from "./kokimoki-store";
|
|
|
2
2
|
import { RoomSubscriptionMode } from "./room-subscription-mode";
|
|
3
3
|
export class KokimokiAwareness extends KokimokiStore {
|
|
4
4
|
_data;
|
|
5
|
-
_pingInterval = null;
|
|
6
5
|
_kmClients = new Set();
|
|
7
|
-
constructor(roomName, _data, mode = RoomSubscriptionMode.ReadWrite
|
|
6
|
+
constructor(roomName, _data, mode = RoomSubscriptionMode.ReadWrite) {
|
|
8
7
|
super(`/a/${roomName}`, {}, mode);
|
|
9
8
|
this._data = _data;
|
|
10
|
-
this._pingInterval = setInterval(async () => {
|
|
11
|
-
const kmClients = Array.from(this._kmClients);
|
|
12
|
-
await Promise.all(kmClients.map(async (client) => {
|
|
13
|
-
try {
|
|
14
|
-
await client.transact([this], ([state]) => {
|
|
15
|
-
const timestamp = client.serverTimestamp();
|
|
16
|
-
// Update self
|
|
17
|
-
if (state[client.connectionId]) {
|
|
18
|
-
state[client.connectionId].lastPing = timestamp;
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
state[client.connectionId] = {
|
|
22
|
-
clientId: client.id,
|
|
23
|
-
lastPing: timestamp,
|
|
24
|
-
data: this._data,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
// Delete clients that haven't pinged in a while
|
|
28
|
-
for (const connectionId in state) {
|
|
29
|
-
const { lastPing } = state[connectionId];
|
|
30
|
-
if (!lastPing || timestamp - lastPing > pingTimeout * 2) {
|
|
31
|
-
delete state[connectionId];
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
catch (e) { }
|
|
37
|
-
}));
|
|
38
|
-
}, pingTimeout);
|
|
39
9
|
}
|
|
40
10
|
async onJoin(client) {
|
|
41
11
|
this._kmClients.add(client);
|
|
42
12
|
await client.transact([this], ([state]) => {
|
|
43
13
|
state[client.connectionId] = {
|
|
44
14
|
clientId: client.id,
|
|
45
|
-
lastPing: client.serverTimestamp(),
|
|
46
15
|
data: this._data,
|
|
47
16
|
};
|
|
48
17
|
});
|
|
49
18
|
}
|
|
50
|
-
async onBeforeLeave(client) {
|
|
51
|
-
await client.transact([this], ([state]) => {
|
|
52
|
-
delete state[client.connectionId];
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
19
|
async onLeave(client) {
|
|
56
20
|
this._kmClients.delete(client);
|
|
57
21
|
}
|
|
58
22
|
getClients() {
|
|
59
23
|
const clients = {};
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
24
|
+
const connections = this.get();
|
|
25
|
+
for (const connectionId in connections) {
|
|
26
|
+
clients[connections[connectionId].clientId] =
|
|
27
|
+
connections[connectionId].data;
|
|
63
28
|
}
|
|
64
29
|
return clients;
|
|
65
30
|
}
|
|
@@ -5,7 +5,10 @@ import type { Paginated } from "./types/common";
|
|
|
5
5
|
import { KokimokiStore } from "./kokimoki-store";
|
|
6
6
|
import { KokimokiAwareness } from "./kokimoki-awareness";
|
|
7
7
|
import { KokimokiLocalStore } from "./kokimoki-local-store";
|
|
8
|
-
type
|
|
8
|
+
type Mutable<T> = {
|
|
9
|
+
-readonly [K in keyof T]: T[K] extends object ? Mutable<T[K]> : T[K];
|
|
10
|
+
};
|
|
11
|
+
type StoreValue<S> = S extends KokimokiStore<infer U> ? Mutable<U> : never;
|
|
9
12
|
declare const KokimokiClient_base: new () => TypedEmitter<KokimokiClientEvents>;
|
|
10
13
|
export declare class KokimokiClient<ClientContextT = any> extends KokimokiClient_base {
|
|
11
14
|
readonly host: string;
|
|
@@ -71,16 +74,16 @@ export declare class KokimokiClient<ClientContextT = any> extends KokimokiClient
|
|
|
71
74
|
exposeScriptingContext(context: any): Promise<void>;
|
|
72
75
|
private sendSubscribeReq;
|
|
73
76
|
private sendUnsubscribeReq;
|
|
74
|
-
join<T>(store: KokimokiStore<T>): Promise<void>;
|
|
75
|
-
leave<T>(store: KokimokiStore<T>): Promise<void>;
|
|
77
|
+
join<T extends object>(store: KokimokiStore<T>): Promise<void>;
|
|
78
|
+
leave<T extends object>(store: KokimokiStore<T>): Promise<void>;
|
|
76
79
|
transact<TStores extends readonly KokimokiStore<any>[], ReturnT = void>(stores: [...TStores], handler: (proxies: {
|
|
77
80
|
[K in keyof TStores]: StoreValue<TStores[K]>;
|
|
78
81
|
}) => ReturnT | Promise<ReturnT>): Promise<ReturnT>;
|
|
79
82
|
close(): Promise<void>;
|
|
80
|
-
getRoomHash<T>(store: KokimokiStore<T>): number;
|
|
83
|
+
getRoomHash<T extends object>(store: KokimokiStore<T>): number;
|
|
81
84
|
/** Initializers */
|
|
82
|
-
store<T>(name: string, defaultState: T, autoJoin?: boolean): KokimokiStore<T>;
|
|
83
|
-
localStore<T>(name: string, defaultState: T): KokimokiLocalStore<T>;
|
|
85
|
+
store<T extends object>(name: string, defaultState: T, autoJoin?: boolean): KokimokiStore<T>;
|
|
86
|
+
localStore<T extends object>(name: string, defaultState: T): KokimokiLocalStore<T>;
|
|
84
87
|
awareness<T>(name: string, initialData: T, autoJoin?: boolean): KokimokiAwareness<T>;
|
|
85
88
|
/**
|
|
86
89
|
* Add a new entry to a leaderboard
|
package/dist/kokimoki-client.js
CHANGED
|
@@ -461,7 +461,7 @@ export class KokimokiClient extends EventEmitter {
|
|
|
461
461
|
this._subscriptionsByHash.set(res.roomHash, subscription);
|
|
462
462
|
await subscription.applyInitialResponse(res.roomHash, res.initialUpdate);
|
|
463
463
|
// Trigger onJoin event
|
|
464
|
-
store.onJoin(this);
|
|
464
|
+
await store.onJoin(this);
|
|
465
465
|
}
|
|
466
466
|
}
|
|
467
467
|
async leave(store) {
|
|
@@ -718,7 +718,12 @@ export class KokimokiClient extends EventEmitter {
|
|
|
718
718
|
const res = await fetch(`${this._apiUrl}/ai/chat`, {
|
|
719
719
|
method: "POST",
|
|
720
720
|
headers: this.apiHeaders,
|
|
721
|
-
body: JSON.stringify({
|
|
721
|
+
body: JSON.stringify({
|
|
722
|
+
systemPrompt,
|
|
723
|
+
userPrompt,
|
|
724
|
+
temperature,
|
|
725
|
+
maxTokens,
|
|
726
|
+
}),
|
|
722
727
|
});
|
|
723
728
|
if (!res.ok) {
|
|
724
729
|
throw await res.json();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { KokimokiStore } from "./kokimoki-store";
|
|
2
|
-
export declare class KokimokiLocalStore<T> extends KokimokiStore<T> {
|
|
2
|
+
export declare class KokimokiLocalStore<T extends object> extends KokimokiStore<T> {
|
|
3
3
|
private readonly localRoomName;
|
|
4
4
|
private _stateKey?;
|
|
5
5
|
private get stateKey();
|
package/dist/kokimoki-store.d.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import * as Y from "yjs";
|
|
2
|
+
import { Snapshot } from "valtio/vanilla";
|
|
2
3
|
import { RoomSubscriptionMode } from "./room-subscription-mode";
|
|
3
4
|
import type { KokimokiClient } from "./kokimoki-client";
|
|
4
|
-
export declare class KokimokiStore<T> {
|
|
5
|
+
export declare class KokimokiStore<T extends object> {
|
|
5
6
|
readonly roomName: string;
|
|
6
7
|
readonly defaultValue: T;
|
|
7
8
|
readonly mode: RoomSubscriptionMode;
|
|
8
9
|
readonly doc: Y.Doc;
|
|
9
10
|
readonly proxy: T;
|
|
10
11
|
readonly docRoot: Y.Map<unknown>;
|
|
12
|
+
readonly connections: {
|
|
13
|
+
clientIds: Set<string>;
|
|
14
|
+
};
|
|
11
15
|
constructor(roomName: string, defaultValue: T, mode?: RoomSubscriptionMode);
|
|
12
|
-
get(): T
|
|
13
|
-
subscribe(set: (value: T) => void): () => void;
|
|
14
|
-
onJoin(client: KokimokiClient): Promise<void>;
|
|
16
|
+
get(): Snapshot<T>;
|
|
17
|
+
subscribe(set: (value: Snapshot<T>) => void): () => void;
|
|
18
|
+
onJoin(client: KokimokiClient<any>): Promise<void>;
|
|
15
19
|
onBeforeLeave(client: KokimokiClient): Promise<void>;
|
|
16
20
|
onLeave(client: KokimokiClient): Promise<void>;
|
|
17
21
|
}
|
package/dist/kokimoki-store.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Y from "yjs";
|
|
2
|
-
import { proxy
|
|
2
|
+
import { snapshot, proxy, subscribe } from "valtio/vanilla";
|
|
3
3
|
import { bind as yjsBind } from "valtio-yjs";
|
|
4
4
|
import { RoomSubscriptionMode } from "./room-subscription-mode";
|
|
5
5
|
export class KokimokiStore {
|
|
@@ -9,49 +9,72 @@ export class KokimokiStore {
|
|
|
9
9
|
doc;
|
|
10
10
|
proxy;
|
|
11
11
|
docRoot;
|
|
12
|
+
connections;
|
|
12
13
|
constructor(roomName, defaultValue, mode = RoomSubscriptionMode.ReadWrite) {
|
|
13
14
|
this.roomName = roomName;
|
|
14
15
|
this.defaultValue = defaultValue;
|
|
15
16
|
this.mode = mode;
|
|
17
|
+
// "_connections" is a reserved key for tracking connections
|
|
18
|
+
if ("_connections" in defaultValue) {
|
|
19
|
+
throw new Error(`"_connections" is a reserved key in KokimokiStore`);
|
|
20
|
+
}
|
|
16
21
|
// Construct Y doc
|
|
17
22
|
this.doc = new Y.Doc();
|
|
18
23
|
this.docRoot = this.doc.getMap("root");
|
|
19
24
|
// Construct proxy object
|
|
20
|
-
this.proxy =
|
|
25
|
+
this.proxy = proxy();
|
|
21
26
|
// @ts-ignore
|
|
22
27
|
yjsBind(this.proxy, this.docRoot);
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
28
|
+
// Construct connections proxy
|
|
29
|
+
this.connections = proxy({ clientIds: new Set() });
|
|
30
|
+
// Update connections.clientIds whenever _connections changes
|
|
31
|
+
let prevConnections = new Set();
|
|
32
|
+
subscribe(this.proxy, () => {
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
const newConnections = new Set(
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
Object.values(this.proxy._connections || {}));
|
|
37
|
+
// Update only if there are changes
|
|
38
|
+
let changed = false;
|
|
39
|
+
if (newConnections.size !== prevConnections.size) {
|
|
40
|
+
changed = true;
|
|
41
|
+
}
|
|
42
|
+
if (!changed) {
|
|
43
|
+
for (const id of newConnections) {
|
|
44
|
+
if (!prevConnections.has(id)) {
|
|
45
|
+
changed = true;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!changed) {
|
|
51
|
+
for (const id of prevConnections) {
|
|
52
|
+
if (!newConnections.has(id)) {
|
|
53
|
+
changed = true;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (changed) {
|
|
59
|
+
this.connections.clientIds = newConnections;
|
|
60
|
+
prevConnections = new Set(newConnections);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
44
63
|
}
|
|
45
64
|
get() {
|
|
46
|
-
return this.proxy;
|
|
65
|
+
return snapshot(this.proxy);
|
|
47
66
|
}
|
|
48
67
|
subscribe(set) {
|
|
49
|
-
const handler = () => set(this.
|
|
68
|
+
const handler = () => set(this.get());
|
|
50
69
|
this.doc.on("update", handler);
|
|
51
|
-
set(this.
|
|
70
|
+
set(this.get());
|
|
52
71
|
return () => this.doc.off("update", handler);
|
|
53
72
|
}
|
|
54
|
-
async onJoin(client) {
|
|
73
|
+
async onJoin(client) {
|
|
74
|
+
await client.transact([this], ([state]) => {
|
|
75
|
+
state._connections[client.connectionId] = client.id;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
55
78
|
async onBeforeLeave(client) { }
|
|
56
79
|
async onLeave(client) { }
|
|
57
80
|
}
|
package/dist/kokimoki.min.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import TypedEmitter from 'typed-emitter';
|
|
2
2
|
import * as Y from 'yjs';
|
|
3
|
+
import { Snapshot } from 'valtio/vanilla';
|
|
3
4
|
|
|
4
5
|
interface Paginated<T> {
|
|
5
6
|
items: T[];
|
|
@@ -30,17 +31,20 @@ declare enum RoomSubscriptionMode {
|
|
|
30
31
|
ReadWrite = "b"
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
declare class KokimokiStore<T> {
|
|
34
|
+
declare class KokimokiStore<T extends object> {
|
|
34
35
|
readonly roomName: string;
|
|
35
36
|
readonly defaultValue: T;
|
|
36
37
|
readonly mode: RoomSubscriptionMode;
|
|
37
38
|
readonly doc: Y.Doc;
|
|
38
39
|
readonly proxy: T;
|
|
39
40
|
readonly docRoot: Y.Map<unknown>;
|
|
41
|
+
readonly connections: {
|
|
42
|
+
clientIds: Set<string>;
|
|
43
|
+
};
|
|
40
44
|
constructor(roomName: string, defaultValue: T, mode?: RoomSubscriptionMode);
|
|
41
|
-
get(): T
|
|
42
|
-
subscribe(set: (value: T) => void): () => void;
|
|
43
|
-
onJoin(client: KokimokiClient): Promise<void>;
|
|
45
|
+
get(): Snapshot<T>;
|
|
46
|
+
subscribe(set: (value: Snapshot<T>) => void): () => void;
|
|
47
|
+
onJoin(client: KokimokiClient<any>): Promise<void>;
|
|
44
48
|
onBeforeLeave(client: KokimokiClient): Promise<void>;
|
|
45
49
|
onLeave(client: KokimokiClient): Promise<void>;
|
|
46
50
|
}
|
|
@@ -48,24 +52,21 @@ declare class KokimokiStore<T> {
|
|
|
48
52
|
declare class KokimokiAwareness<DataT> extends KokimokiStore<{
|
|
49
53
|
[connectionId: string]: {
|
|
50
54
|
clientId: string;
|
|
51
|
-
lastPing: number;
|
|
52
55
|
data: DataT;
|
|
53
56
|
};
|
|
54
57
|
}> {
|
|
55
58
|
private _data;
|
|
56
|
-
private _pingInterval;
|
|
57
59
|
private _kmClients;
|
|
58
|
-
constructor(roomName: string, _data: DataT, mode?: RoomSubscriptionMode
|
|
60
|
+
constructor(roomName: string, _data: DataT, mode?: RoomSubscriptionMode);
|
|
59
61
|
onJoin(client: KokimokiClient<any>): Promise<void>;
|
|
60
|
-
onBeforeLeave(client: KokimokiClient<any>): Promise<void>;
|
|
61
62
|
onLeave(client: KokimokiClient<any>): Promise<void>;
|
|
62
63
|
getClients(): {
|
|
63
|
-
[clientId: string]: DataT
|
|
64
|
+
[clientId: string]: Snapshot<DataT>;
|
|
64
65
|
};
|
|
65
66
|
setData(data: DataT): Promise<void>;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
declare class KokimokiLocalStore<T> extends KokimokiStore<T> {
|
|
69
|
+
declare class KokimokiLocalStore<T extends object> extends KokimokiStore<T> {
|
|
69
70
|
private readonly localRoomName;
|
|
70
71
|
private _stateKey?;
|
|
71
72
|
private get stateKey();
|
|
@@ -76,7 +77,10 @@ declare class KokimokiLocalStore<T> extends KokimokiStore<T> {
|
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
type
|
|
80
|
+
type Mutable<T> = {
|
|
81
|
+
-readonly [K in keyof T]: T[K] extends object ? Mutable<T[K]> : T[K];
|
|
82
|
+
};
|
|
83
|
+
type StoreValue<S> = S extends KokimokiStore<infer U> ? Mutable<U> : never;
|
|
80
84
|
declare const KokimokiClient_base: new () => TypedEmitter<KokimokiClientEvents>;
|
|
81
85
|
declare class KokimokiClient<ClientContextT = any> extends KokimokiClient_base {
|
|
82
86
|
readonly host: string;
|
|
@@ -142,16 +146,16 @@ declare class KokimokiClient<ClientContextT = any> extends KokimokiClient_base {
|
|
|
142
146
|
exposeScriptingContext(context: any): Promise<void>;
|
|
143
147
|
private sendSubscribeReq;
|
|
144
148
|
private sendUnsubscribeReq;
|
|
145
|
-
join<T>(store: KokimokiStore<T>): Promise<void>;
|
|
146
|
-
leave<T>(store: KokimokiStore<T>): Promise<void>;
|
|
149
|
+
join<T extends object>(store: KokimokiStore<T>): Promise<void>;
|
|
150
|
+
leave<T extends object>(store: KokimokiStore<T>): Promise<void>;
|
|
147
151
|
transact<TStores extends readonly KokimokiStore<any>[], ReturnT = void>(stores: [...TStores], handler: (proxies: {
|
|
148
152
|
[K in keyof TStores]: StoreValue<TStores[K]>;
|
|
149
153
|
}) => ReturnT | Promise<ReturnT>): Promise<ReturnT>;
|
|
150
154
|
close(): Promise<void>;
|
|
151
|
-
getRoomHash<T>(store: KokimokiStore<T>): number;
|
|
155
|
+
getRoomHash<T extends object>(store: KokimokiStore<T>): number;
|
|
152
156
|
/** Initializers */
|
|
153
|
-
store<T>(name: string, defaultState: T, autoJoin?: boolean): KokimokiStore<T>;
|
|
154
|
-
localStore<T>(name: string, defaultState: T): KokimokiLocalStore<T>;
|
|
157
|
+
store<T extends object>(name: string, defaultState: T, autoJoin?: boolean): KokimokiStore<T>;
|
|
158
|
+
localStore<T extends object>(name: string, defaultState: T): KokimokiLocalStore<T>;
|
|
155
159
|
awareness<T>(name: string, initialData: T, autoJoin?: boolean): KokimokiAwareness<T>;
|
|
156
160
|
/**
|
|
157
161
|
* Add a new entry to a leaderboard
|