@kokimoki/app 1.16.0 → 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.
@@ -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) {
@@ -7,23 +7,15 @@ export declare class KokimokiStore<T extends object> {
7
7
  readonly defaultValue: T;
8
8
  readonly mode: RoomSubscriptionMode;
9
9
  readonly doc: Y.Doc;
10
- readonly proxy: T & {
11
- _km_connections?: {
12
- [connectionId: string]: string;
13
- };
14
- };
10
+ readonly proxy: T;
15
11
  readonly docRoot: Y.Map<unknown>;
16
12
  readonly connections: {
17
13
  clientIds: Set<string>;
18
14
  };
19
15
  constructor(roomName: string, defaultValue: T, mode?: RoomSubscriptionMode);
20
- get(): Snapshot<T & {
21
- _km_connections?: {
22
- [connectionId: string]: string;
23
- } | undefined;
24
- }>;
16
+ get(): Snapshot<T>;
25
17
  subscribe(set: (value: Snapshot<T>) => void): () => void;
26
- onJoin(client: KokimokiClient): Promise<void>;
18
+ onJoin(client: KokimokiClient<any>): Promise<void>;
27
19
  onBeforeLeave(client: KokimokiClient): Promise<void>;
28
20
  onLeave(client: KokimokiClient): Promise<void>;
29
21
  }
@@ -1,5 +1,5 @@
1
1
  import * as Y from "yjs";
2
- import { proxy, snapshot, subscribe } from "valtio/vanilla";
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 {
@@ -14,6 +14,10 @@ export class KokimokiStore {
14
14
  this.roomName = roomName;
15
15
  this.defaultValue = defaultValue;
16
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
+ }
17
21
  // Construct Y doc
18
22
  this.doc = new Y.Doc();
19
23
  this.docRoot = this.doc.getMap("root");
@@ -23,14 +27,37 @@ export class KokimokiStore {
23
27
  yjsBind(this.proxy, this.docRoot);
24
28
  // Construct connections proxy
25
29
  this.connections = proxy({ clientIds: new Set() });
26
- // Update connections.clientIds whenever _km_connections changes
30
+ // Update connections.clientIds whenever _connections changes
31
+ let prevConnections = new Set();
27
32
  subscribe(this.proxy, () => {
28
- const kmConnections = this.proxy._km_connections;
29
- if (kmConnections) {
30
- this.connections.clientIds = new Set(Object.values(kmConnections));
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;
31
41
  }
32
- else {
33
- this.connections.clientIds = new Set();
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);
34
61
  }
35
62
  });
36
63
  }
@@ -43,7 +70,11 @@ export class KokimokiStore {
43
70
  set(this.get());
44
71
  return () => this.doc.off("update", handler);
45
72
  }
46
- async onJoin(client) { }
73
+ async onJoin(client) {
74
+ await client.transact([this], ([state]) => {
75
+ state._connections[client.connectionId] = client.id;
76
+ });
77
+ }
47
78
  async onBeforeLeave(client) { }
48
79
  async onLeave(client) { }
49
80
  }
@@ -36,23 +36,15 @@ declare class KokimokiStore<T extends object> {
36
36
  readonly defaultValue: T;
37
37
  readonly mode: RoomSubscriptionMode;
38
38
  readonly doc: Y.Doc;
39
- readonly proxy: T & {
40
- _km_connections?: {
41
- [connectionId: string]: string;
42
- };
43
- };
39
+ readonly proxy: T;
44
40
  readonly docRoot: Y.Map<unknown>;
45
41
  readonly connections: {
46
42
  clientIds: Set<string>;
47
43
  };
48
44
  constructor(roomName: string, defaultValue: T, mode?: RoomSubscriptionMode);
49
- get(): Snapshot<T & {
50
- _km_connections?: {
51
- [connectionId: string]: string;
52
- } | undefined;
53
- }>;
45
+ get(): Snapshot<T>;
54
46
  subscribe(set: (value: Snapshot<T>) => void): () => void;
55
- onJoin(client: KokimokiClient): Promise<void>;
47
+ onJoin(client: KokimokiClient<any>): Promise<void>;
56
48
  onBeforeLeave(client: KokimokiClient): Promise<void>;
57
49
  onLeave(client: KokimokiClient): Promise<void>;
58
50
  }
@@ -486,7 +486,7 @@ function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
486
486
  var eventsExports = events.exports;
487
487
  var EventEmitter$1 = /*@__PURE__*/getDefaultExportFromCjs(eventsExports);
488
488
 
489
- const KOKIMOKI_APP_VERSION = "1.15.2";
489
+ const KOKIMOKI_APP_VERSION = "1.16.1";
490
490
 
491
491
  /**
492
492
  * Utility module to work with key-value stores.
@@ -12009,6 +12009,10 @@ class KokimokiStore {
12009
12009
  this.roomName = roomName;
12010
12010
  this.defaultValue = defaultValue;
12011
12011
  this.mode = mode;
12012
+ // "_connections" is a reserved key for tracking connections
12013
+ if ("_connections" in defaultValue) {
12014
+ throw new Error(`"_connections" is a reserved key in KokimokiStore`);
12015
+ }
12012
12016
  // Construct Y doc
12013
12017
  this.doc = new Doc();
12014
12018
  this.docRoot = this.doc.getMap("root");
@@ -12018,14 +12022,37 @@ class KokimokiStore {
12018
12022
  bind$1(this.proxy, this.docRoot);
12019
12023
  // Construct connections proxy
12020
12024
  this.connections = proxy({ clientIds: new Set() });
12021
- // Update connections.clientIds whenever _km_connections changes
12025
+ // Update connections.clientIds whenever _connections changes
12026
+ let prevConnections = new Set();
12022
12027
  subscribe(this.proxy, () => {
12023
- const kmConnections = this.proxy._km_connections;
12024
- if (kmConnections) {
12025
- this.connections.clientIds = new Set(Object.values(kmConnections));
12028
+ // @ts-ignore
12029
+ const newConnections = new Set(
12030
+ // @ts-ignore
12031
+ Object.values(this.proxy._connections || {}));
12032
+ // Update only if there are changes
12033
+ let changed = false;
12034
+ if (newConnections.size !== prevConnections.size) {
12035
+ changed = true;
12026
12036
  }
12027
- else {
12028
- this.connections.clientIds = new Set();
12037
+ if (!changed) {
12038
+ for (const id of newConnections) {
12039
+ if (!prevConnections.has(id)) {
12040
+ changed = true;
12041
+ break;
12042
+ }
12043
+ }
12044
+ }
12045
+ if (!changed) {
12046
+ for (const id of prevConnections) {
12047
+ if (!newConnections.has(id)) {
12048
+ changed = true;
12049
+ break;
12050
+ }
12051
+ }
12052
+ }
12053
+ if (changed) {
12054
+ this.connections.clientIds = newConnections;
12055
+ prevConnections = new Set(newConnections);
12029
12056
  }
12030
12057
  });
12031
12058
  }
@@ -12038,7 +12065,11 @@ class KokimokiStore {
12038
12065
  set(this.get());
12039
12066
  return () => this.doc.off("update", handler);
12040
12067
  }
12041
- async onJoin(client) { }
12068
+ async onJoin(client) {
12069
+ await client.transact([this], ([state]) => {
12070
+ state._connections[client.connectionId] = client.id;
12071
+ });
12072
+ }
12042
12073
  async onBeforeLeave(client) { }
12043
12074
  async onLeave(client) { }
12044
12075
  }
@@ -12173,6 +12204,9 @@ class RoomSubscription {
12173
12204
  // Set defaults if doc is empty after sync (only possible in ReadWrite mode)
12174
12205
  if (this.store.mode === RoomSubscriptionMode.ReadWrite) {
12175
12206
  await this.kmClient.transact([this.store], ([state]) => {
12207
+ if (!("_connections" in state)) {
12208
+ state._connections = {};
12209
+ }
12176
12210
  for (const key in this.store.defaultValue) {
12177
12211
  if (!state.hasOwnProperty(key)) {
12178
12212
  state[key] = this.store.defaultValue[key];
@@ -15242,7 +15276,7 @@ class KokimokiClient extends EventEmitter$1 {
15242
15276
  this._subscriptionsByHash.set(res.roomHash, subscription);
15243
15277
  await subscription.applyInitialResponse(res.roomHash, res.initialUpdate);
15244
15278
  // Trigger onJoin event
15245
- store.onJoin(this);
15279
+ await store.onJoin(this);
15246
15280
  }
15247
15281
  }
15248
15282
  async leave(store) {