@kokimoki/app 1.1.0 → 1.2.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.
@@ -2,14 +2,23 @@ import { KokimokiStore } from "./kokimoki-store";
2
2
  import { KokimokiSchema as S } from "./kokimoki-schema";
3
3
  import { RoomSubscriptionMode } from "./room-subscription-mode";
4
4
  import type { KokimokiClient } from "./kokimoki-client";
5
- export declare class KokimokiAwareness extends KokimokiStore<S.Dict<S.Struct<{
5
+ export declare class KokimokiAwareness<Data extends S.Generic<unknown>> extends KokimokiStore<S.Dict<S.Struct<{
6
6
  clientId: S.String;
7
7
  lastPing: S.Number;
8
- }>>> {
8
+ data: Data;
9
+ }>>, {
10
+ [clientId: string]: Data["defaultValue"];
11
+ }> {
12
+ readonly dataSchema: Data;
13
+ readonly data: Data["defaultValue"];
9
14
  private _pingInterval;
10
15
  private _kmClients;
11
- constructor(roomName: string, mode?: RoomSubscriptionMode, pingTimeout?: number);
16
+ constructor(roomName: string, dataSchema: Data, data: Data["defaultValue"], mode?: RoomSubscriptionMode, pingTimeout?: number);
12
17
  onJoin(client: KokimokiClient<any>): Promise<void>;
13
18
  onBeforeLeave(client: KokimokiClient<any>): Promise<void>;
14
19
  onLeave(client: KokimokiClient<any>): Promise<void>;
20
+ private getConnectedClients;
21
+ subscribe(set: (value: {
22
+ [clientId: string]: Data["defaultValue"];
23
+ }) => void): () => void;
15
24
  }
@@ -1,35 +1,36 @@
1
1
  import { KokimokiStore } from "./kokimoki-store";
2
2
  import { KokimokiSchema as S } from "./kokimoki-schema";
3
3
  import { RoomSubscriptionMode } from "./room-subscription-mode";
4
- export class KokimokiAwareness
5
- // <Data extends S.Generic<unknown>>
6
- extends KokimokiStore {
4
+ export class KokimokiAwareness extends KokimokiStore {
5
+ dataSchema;
6
+ data;
7
7
  _pingInterval = null;
8
8
  _kmClients = new Set();
9
- // private _data: Data["defaultValue"];
10
- constructor(roomName,
11
- // public readonly dataSchema: Data,
12
- // initialData: Data["defaultValue"],
13
- mode = RoomSubscriptionMode.ReadWrite, pingTimeout = 2500) {
9
+ constructor(roomName, dataSchema, data, mode = RoomSubscriptionMode.ReadWrite, pingTimeout = 2500) {
14
10
  super(`/a/${roomName}`, S.dict(S.struct({
15
11
  clientId: S.string(),
16
12
  lastPing: S.number(),
17
- // data: dataSchema,
13
+ data: dataSchema,
18
14
  })), mode);
19
- // this._data = initialData;
15
+ this.dataSchema = dataSchema;
16
+ this.data = data;
20
17
  this._pingInterval = setInterval(async () => {
21
18
  const kmClients = Array.from(this._kmClients);
22
19
  await Promise.all(kmClients.map(async (client) => {
23
20
  try {
24
21
  await client.transact((t) => {
25
22
  const timestamp = client.serverTimestamp();
26
- // Update self last ping
27
- t.set(this.root[client.connectionId].lastPing, timestamp);
28
- /* if (!this.proxy[client.connectionId]) {
29
- t.set(this.root[client.connectionId].data, this._data);
30
- } else {
31
- this._data = this.proxy[client.connectionId].data;
32
- } */
23
+ // Update self
24
+ if (this.proxy[client.connectionId]) {
25
+ t.set(this.root[client.connectionId].lastPing, timestamp);
26
+ }
27
+ else {
28
+ t.set(this.root[client.connectionId], {
29
+ clientId: client.id,
30
+ lastPing: timestamp,
31
+ data: this.data,
32
+ });
33
+ }
33
34
  // Delete clients that haven't pinged in a while
34
35
  for (const connectionId in this.proxy) {
35
36
  const { lastPing } = this.proxy[connectionId];
@@ -49,7 +50,7 @@ export class KokimokiAwareness
49
50
  t.set(this.root[client.connectionId], {
50
51
  clientId: client.id,
51
52
  lastPing: client.serverTimestamp(),
52
- // data: this._data,
53
+ data: this.data,
53
54
  });
54
55
  });
55
56
  }
@@ -61,4 +62,37 @@ export class KokimokiAwareness
61
62
  async onLeave(client) {
62
63
  this._kmClients.delete(client);
63
64
  }
65
+ getConnectedClients() {
66
+ const clients = {};
67
+ for (const clientId in this.proxy) {
68
+ clients[clientId] = this.proxy[clientId].data;
69
+ }
70
+ return clients;
71
+ }
72
+ subscribe(set) {
73
+ let prevConnectionIds = {};
74
+ const handler = () => {
75
+ // Do nothing if only pings have changed
76
+ let changed = false;
77
+ const newConnectionIds = {};
78
+ for (const connectionId in this.proxy) {
79
+ newConnectionIds[connectionId] = true;
80
+ if (!prevConnectionIds[connectionId]) {
81
+ changed = true;
82
+ }
83
+ }
84
+ for (const connectionId in prevConnectionIds) {
85
+ if (!newConnectionIds[connectionId]) {
86
+ changed = true;
87
+ }
88
+ }
89
+ if (changed) {
90
+ set(this.getConnectedClients());
91
+ prevConnectionIds = newConnectionIds;
92
+ }
93
+ };
94
+ this.doc.on("update", handler);
95
+ set(this.getConnectedClients());
96
+ return () => this.doc.off("update", handler);
97
+ }
64
98
  }
@@ -11,6 +11,7 @@ export declare class KokimokiStore<T extends S.Generic<unknown>, SubscribeT = T[
11
11
  readonly defaultValue: T["defaultValue"];
12
12
  readonly docRoot: Y.Map<unknown>;
13
13
  constructor(roomName: string, schema: T, mode?: RoomSubscriptionMode);
14
+ get(): T["defaultValue"];
14
15
  subscribe(set: (value: SubscribeT) => void): () => void;
15
16
  onJoin(client: KokimokiClient): Promise<void>;
16
17
  onBeforeLeave(client: KokimokiClient): Promise<void>;
@@ -45,6 +45,9 @@ export class KokimokiStore {
45
45
  // Set default value
46
46
  this.defaultValue = schema.defaultValue;
47
47
  }
48
+ get() {
49
+ return this.proxy;
50
+ }
48
51
  subscribe(set) {
49
52
  // @ts-ignore
50
53
  const handler = () => set(this.proxy);
@@ -220,6 +220,7 @@ declare class KokimokiStore<T extends KokimokiSchema.Generic<unknown>, Subscribe
220
220
  readonly defaultValue: T["defaultValue"];
221
221
  readonly docRoot: Y.Map<unknown>;
222
222
  constructor(roomName: string, schema: T, mode?: RoomSubscriptionMode);
223
+ get(): T["defaultValue"];
223
224
  subscribe(set: (value: SubscribeT) => void): () => void;
224
225
  onJoin(client: KokimokiClient): Promise<void>;
225
226
  onBeforeLeave(client: KokimokiClient): Promise<void>;
@@ -363,16 +364,25 @@ declare class RoomSubscription {
363
364
  close(): void;
364
365
  }
365
366
 
366
- declare class KokimokiAwareness extends KokimokiStore<KokimokiSchema.Dict<KokimokiSchema.Struct<{
367
+ declare class KokimokiAwareness<Data extends KokimokiSchema.Generic<unknown>> extends KokimokiStore<KokimokiSchema.Dict<KokimokiSchema.Struct<{
367
368
  clientId: KokimokiSchema.String;
368
369
  lastPing: KokimokiSchema.Number;
369
- }>>> {
370
+ data: Data;
371
+ }>>, {
372
+ [clientId: string]: Data["defaultValue"];
373
+ }> {
374
+ readonly dataSchema: Data;
375
+ readonly data: Data["defaultValue"];
370
376
  private _pingInterval;
371
377
  private _kmClients;
372
- constructor(roomName: string, mode?: RoomSubscriptionMode, pingTimeout?: number);
378
+ constructor(roomName: string, dataSchema: Data, data: Data["defaultValue"], mode?: RoomSubscriptionMode, pingTimeout?: number);
373
379
  onJoin(client: KokimokiClient<any>): Promise<void>;
374
380
  onBeforeLeave(client: KokimokiClient<any>): Promise<void>;
375
381
  onLeave(client: KokimokiClient<any>): Promise<void>;
382
+ private getConnectedClients;
383
+ subscribe(set: (value: {
384
+ [clientId: string]: Data["defaultValue"];
385
+ }) => void): () => void;
376
386
  }
377
387
 
378
388
  export { BooleanField, ConstField, EnumField, Field, type FieldOptions, FloatField, Form, FormArray, FormGroup, ImageField, IntegerField, KokimokiAwareness, KokimokiClient, type KokimokiClientEvents, KokimokiQueue, KokimokiSchema, KokimokiStore, type Paginated, RoomSubscription, RoomSubscriptionMode, TextField, type Upload };
@@ -634,7 +634,7 @@ function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
634
634
  var eventsExports = events.exports;
635
635
  var EventEmitter$1 = /*@__PURE__*/getDefaultExportFromCjs(eventsExports);
636
636
 
637
- const KOKIMOKI_APP_VERSION = "1.1.0";
637
+ const KOKIMOKI_APP_VERSION = "1.2.0";
638
638
 
639
639
  /**
640
640
  * Utility module to work with key-value stores.
@@ -12448,6 +12448,9 @@ class KokimokiStore {
12448
12448
  // Set default value
12449
12449
  this.defaultValue = schema.defaultValue;
12450
12450
  }
12451
+ get() {
12452
+ return this.proxy;
12453
+ }
12451
12454
  subscribe(set) {
12452
12455
  // @ts-ignore
12453
12456
  const handler = () => set(this.proxy);
@@ -12489,35 +12492,36 @@ class KokimokiQueue extends KokimokiStore {
12489
12492
  }
12490
12493
  }
12491
12494
 
12492
- class KokimokiAwareness
12493
- // <Data extends S.Generic<unknown>>
12494
- extends KokimokiStore {
12495
+ class KokimokiAwareness extends KokimokiStore {
12496
+ dataSchema;
12497
+ data;
12495
12498
  _pingInterval = null;
12496
12499
  _kmClients = new Set();
12497
- // private _data: Data["defaultValue"];
12498
- constructor(roomName,
12499
- // public readonly dataSchema: Data,
12500
- // initialData: Data["defaultValue"],
12501
- mode = RoomSubscriptionMode.ReadWrite, pingTimeout = 2500) {
12500
+ constructor(roomName, dataSchema, data, mode = RoomSubscriptionMode.ReadWrite, pingTimeout = 2500) {
12502
12501
  super(`/a/${roomName}`, KokimokiSchema.dict(KokimokiSchema.struct({
12503
12502
  clientId: KokimokiSchema.string(),
12504
12503
  lastPing: KokimokiSchema.number(),
12505
- // data: dataSchema,
12504
+ data: dataSchema,
12506
12505
  })), mode);
12507
- // this._data = initialData;
12506
+ this.dataSchema = dataSchema;
12507
+ this.data = data;
12508
12508
  this._pingInterval = setInterval(async () => {
12509
12509
  const kmClients = Array.from(this._kmClients);
12510
12510
  await Promise.all(kmClients.map(async (client) => {
12511
12511
  try {
12512
12512
  await client.transact((t) => {
12513
12513
  const timestamp = client.serverTimestamp();
12514
- // Update self last ping
12515
- t.set(this.root[client.connectionId].lastPing, timestamp);
12516
- /* if (!this.proxy[client.connectionId]) {
12517
- t.set(this.root[client.connectionId].data, this._data);
12518
- } else {
12519
- this._data = this.proxy[client.connectionId].data;
12520
- } */
12514
+ // Update self
12515
+ if (this.proxy[client.connectionId]) {
12516
+ t.set(this.root[client.connectionId].lastPing, timestamp);
12517
+ }
12518
+ else {
12519
+ t.set(this.root[client.connectionId], {
12520
+ clientId: client.id,
12521
+ lastPing: timestamp,
12522
+ data: this.data,
12523
+ });
12524
+ }
12521
12525
  // Delete clients that haven't pinged in a while
12522
12526
  for (const connectionId in this.proxy) {
12523
12527
  const { lastPing } = this.proxy[connectionId];
@@ -12537,7 +12541,7 @@ class KokimokiAwareness
12537
12541
  t.set(this.root[client.connectionId], {
12538
12542
  clientId: client.id,
12539
12543
  lastPing: client.serverTimestamp(),
12540
- // data: this._data,
12544
+ data: this.data,
12541
12545
  });
12542
12546
  });
12543
12547
  }
@@ -12549,6 +12553,39 @@ class KokimokiAwareness
12549
12553
  async onLeave(client) {
12550
12554
  this._kmClients.delete(client);
12551
12555
  }
12556
+ getConnectedClients() {
12557
+ const clients = {};
12558
+ for (const clientId in this.proxy) {
12559
+ clients[clientId] = this.proxy[clientId].data;
12560
+ }
12561
+ return clients;
12562
+ }
12563
+ subscribe(set) {
12564
+ let prevConnectionIds = {};
12565
+ const handler = () => {
12566
+ // Do nothing if only pings have changed
12567
+ let changed = false;
12568
+ const newConnectionIds = {};
12569
+ for (const connectionId in this.proxy) {
12570
+ newConnectionIds[connectionId] = true;
12571
+ if (!prevConnectionIds[connectionId]) {
12572
+ changed = true;
12573
+ }
12574
+ }
12575
+ for (const connectionId in prevConnectionIds) {
12576
+ if (!newConnectionIds[connectionId]) {
12577
+ changed = true;
12578
+ }
12579
+ }
12580
+ if (changed) {
12581
+ set(this.getConnectedClients());
12582
+ prevConnectionIds = newConnectionIds;
12583
+ }
12584
+ };
12585
+ this.doc.on("update", handler);
12586
+ set(this.getConnectedClients());
12587
+ return () => this.doc.off("update", handler);
12588
+ }
12552
12589
  }
12553
12590
 
12554
12591
  export { BooleanField, ConstField, EnumField, Field, FloatField, Form, FormArray, FormGroup, ImageField, IntegerField, KokimokiAwareness, KokimokiClient, KokimokiQueue, KokimokiSchema, KokimokiStore, RoomSubscription, RoomSubscriptionMode, TextField };