@kokimoki/app 1.8.3 → 1.10.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.
package/dist/index.d.ts CHANGED
@@ -2,9 +2,7 @@ export * from "./types/common";
2
2
  export * from "./types/events";
3
3
  export * from "./types/upload";
4
4
  export * from "./kokimoki-client";
5
- export * from "./kokimoki-schema";
6
5
  export * from "./kokimoki-store";
7
- export * from "./kokimoki-queue";
8
6
  export * from "./room-subscription";
9
7
  export * from "./room-subscription-mode";
10
8
  export * from "./kokimoki-awareness";
package/dist/index.js CHANGED
@@ -2,9 +2,8 @@ export * from "./types/common";
2
2
  export * from "./types/events";
3
3
  export * from "./types/upload";
4
4
  export * from "./kokimoki-client";
5
- export * from "./kokimoki-schema";
6
5
  export * from "./kokimoki-store";
7
- export * from "./kokimoki-queue";
6
+ // export * from "./kokimoki-queue";
8
7
  export * from "./room-subscription";
9
8
  export * from "./room-subscription-mode";
10
9
  export * from "./kokimoki-awareness";
@@ -1,22 +1,24 @@
1
1
  import { KokimokiStore } from "./kokimoki-store";
2
- import { KokimokiSchema as S } from "./kokimoki-schema";
3
2
  import { RoomSubscriptionMode } from "./room-subscription-mode";
4
3
  import type { KokimokiClient } from "./kokimoki-client";
5
- export declare class KokimokiAwareness<Data extends S.Generic<unknown>> extends KokimokiStore<S.Dict<S.Struct<{
6
- clientId: S.String;
7
- lastPing: S.Number;
8
- data: Data;
9
- }>>> {
10
- readonly dataSchema: Data;
4
+ import { ZodType } from "zod";
5
+ export declare class KokimokiAwareness<DataT> extends KokimokiStore<{
6
+ [connectionId: string]: {
7
+ clientId: string;
8
+ lastPing: number;
9
+ data: DataT;
10
+ };
11
+ }> {
12
+ readonly dataSchema: ZodType<DataT>;
11
13
  private _data;
12
14
  private _pingInterval;
13
15
  private _kmClients;
14
- constructor(roomName: string, dataSchema: Data, _data: Data["defaultValue"], mode?: RoomSubscriptionMode, pingTimeout?: number);
16
+ constructor(roomName: string, dataSchema: ZodType<DataT>, _data: DataT, mode?: RoomSubscriptionMode, pingTimeout?: number);
15
17
  onJoin(client: KokimokiClient<any>): Promise<void>;
16
18
  onBeforeLeave(client: KokimokiClient<any>): Promise<void>;
17
19
  onLeave(client: KokimokiClient<any>): Promise<void>;
18
20
  getClients(): {
19
- [clientId: string]: Data["defaultValue"];
21
+ [clientId: string]: DataT;
20
22
  };
21
- setData(data: Data["defaultValue"]): Promise<void>;
23
+ setData(data: DataT): Promise<void>;
22
24
  }
@@ -1,15 +1,17 @@
1
1
  import { KokimokiStore } from "./kokimoki-store";
2
- import { KokimokiSchema as S } from "./kokimoki-schema";
3
2
  import { RoomSubscriptionMode } from "./room-subscription-mode";
3
+ import { z } from "zod";
4
4
  export class KokimokiAwareness extends KokimokiStore {
5
5
  dataSchema;
6
6
  _data;
7
7
  _pingInterval = null;
8
8
  _kmClients = new Set();
9
9
  constructor(roomName, dataSchema, _data, mode = RoomSubscriptionMode.ReadWrite, pingTimeout = 3000) {
10
- super(`/a/${roomName}`, S.dict(S.struct({
11
- clientId: S.string(),
12
- lastPing: S.number(),
10
+ super(`/a/${roomName}`,
11
+ // @ts-ignore
12
+ z.record(z.string(), z.object({
13
+ clientId: z.string(),
14
+ lastPing: z.number(),
13
15
  data: dataSchema,
14
16
  })), mode);
15
17
  this.dataSchema = dataSchema;
@@ -18,24 +20,24 @@ export class KokimokiAwareness extends KokimokiStore {
18
20
  const kmClients = Array.from(this._kmClients);
19
21
  await Promise.all(kmClients.map(async (client) => {
20
22
  try {
21
- await client.transact((t) => {
23
+ await client.transact([this], ([state]) => {
22
24
  const timestamp = client.serverTimestamp();
23
25
  // Update self
24
- if (this.proxy[client.connectionId]) {
25
- t.set(this.root[client.connectionId].lastPing, timestamp);
26
+ if (state[client.connectionId]) {
27
+ state[client.connectionId].lastPing = timestamp;
26
28
  }
27
29
  else {
28
- t.set(this.root[client.connectionId], {
30
+ state[client.connectionId] = {
29
31
  clientId: client.id,
30
32
  lastPing: timestamp,
31
33
  data: this._data,
32
- });
34
+ };
33
35
  }
34
36
  // Delete clients that haven't pinged in a while
35
- for (const connectionId in this.proxy) {
36
- const { lastPing } = this.proxy[connectionId];
37
+ for (const connectionId in state) {
38
+ const { lastPing } = state[connectionId];
37
39
  if (!lastPing || timestamp - lastPing > pingTimeout * 2) {
38
- t.delete(this.root[connectionId]);
40
+ delete state[connectionId];
39
41
  }
40
42
  }
41
43
  });
@@ -46,17 +48,17 @@ export class KokimokiAwareness extends KokimokiStore {
46
48
  }
47
49
  async onJoin(client) {
48
50
  this._kmClients.add(client);
49
- await client.transact((t) => {
50
- t.set(this.root[client.connectionId], {
51
+ await client.transact([this], ([state]) => {
52
+ state[client.connectionId] = {
51
53
  clientId: client.id,
52
54
  lastPing: client.serverTimestamp(),
53
55
  data: this._data,
54
- });
56
+ };
55
57
  });
56
58
  }
57
59
  async onBeforeLeave(client) {
58
- await client.transact((t) => {
59
- t.delete(this.root[client.connectionId]);
60
+ await client.transact([this], ([state]) => {
61
+ delete state[client.connectionId];
60
62
  });
61
63
  }
62
64
  async onLeave(client) {
@@ -74,8 +76,8 @@ export class KokimokiAwareness extends KokimokiStore {
74
76
  this._data = data;
75
77
  const kmClients = Array.from(this._kmClients);
76
78
  await Promise.all(kmClients.map(async (client) => {
77
- await client.transact((t) => {
78
- t.set(this.root[client.connectionId].data, this._data);
79
+ await client.transact([this], ([state]) => {
80
+ state[client.connectionId].data = this._data;
79
81
  });
80
82
  }));
81
83
  }
@@ -2,14 +2,10 @@ import type TypedEmitter from "typed-emitter";
2
2
  import type { KokimokiClientEvents } from "./types/events";
3
3
  import type { Upload } from "./types/upload";
4
4
  import type { Paginated } from "./types/common";
5
- import { KokimokiTransaction } from "./kokimoki-transaction";
6
5
  import { KokimokiStore } from "./kokimoki-store";
7
- import type { KokimokiSchema as S } from "./kokimoki-schema";
8
- import type { RoomSubscriptionMode } from "./room-subscription-mode";
9
- import { KokimokiQueue } from "./kokimoki-queue";
10
6
  import { KokimokiAwareness } from "./kokimoki-awareness";
11
- import { KokimokiReqRes } from "./kokimoki-req-res";
12
7
  import { KokimokiLocalStore } from "./kokimoki-local-store";
8
+ import { ZodType } from "zod";
13
9
  declare const KokimokiClient_base: new () => TypedEmitter<KokimokiClientEvents>;
14
10
  export declare class KokimokiClient<ClientContextT = any> extends KokimokiClient_base {
15
11
  readonly host: string;
@@ -75,17 +71,17 @@ export declare class KokimokiClient<ClientContextT = any> extends KokimokiClient
75
71
  exposeScriptingContext(context: any): Promise<void>;
76
72
  private sendSubscribeReq;
77
73
  private sendUnsubscribeReq;
78
- join<T extends S.Generic<unknown>>(store: KokimokiStore<T>): Promise<void>;
79
- leave<T extends S.Generic<unknown>>(store: KokimokiStore<T>): Promise<void>;
80
- transact<ReturnT = void>(handler: (t: KokimokiTransaction) => ReturnT | Promise<ReturnT>): Promise<ReturnT>;
74
+ join<T>(store: KokimokiStore<T>): Promise<void>;
75
+ leave<T>(store: KokimokiStore<T>): Promise<void>;
76
+ transact<T extends unknown[], ReturnT = void>(stores: {
77
+ [K in keyof T]: KokimokiStore<T[K]>;
78
+ }, handler: (proxies: T) => ReturnT | Promise<ReturnT>): Promise<ReturnT>;
81
79
  close(): Promise<void>;
82
- getRoomHash<T extends S.Generic<unknown>>(store: KokimokiStore<T>): number;
80
+ getRoomHash<T extends ZodType>(store: KokimokiStore<T>): number;
83
81
  /** Initializers */
84
- store<T extends S.Generic<unknown>>(name: string, schema: T, autoJoin?: boolean): KokimokiStore<T, T["defaultValue"]>;
85
- localStore<T extends S.Generic<unknown>>(name: string, schema: T): KokimokiLocalStore<T>;
86
- queue<T extends S.Generic<unknown>>(name: string, schema: T, mode: RoomSubscriptionMode, autoJoin?: boolean): KokimokiQueue<T>;
87
- awareness<T extends S.Generic<unknown>>(name: string, dataSchema: T, initialData?: T["defaultValue"], autoJoin?: boolean): KokimokiAwareness<T>;
88
- reqRes<Req extends S.Generic<unknown>, Res extends S.Generic<unknown>>(serviceName: string, reqSchema: Req, resSchema: Res, handleRequest: (payload: Req["defaultValue"]) => Promise<Res["defaultValue"]>): KokimokiReqRes<Req, Res>;
82
+ store<T extends ZodType>(name: string, schema: T, autoJoin?: boolean): KokimokiStore<T>;
83
+ localStore<T>(name: string, schema: ZodType<T>): KokimokiLocalStore<T>;
84
+ awareness<T>(name: string, dataSchema: ZodType<T>, initialData?: T, autoJoin?: boolean): KokimokiAwareness<T>;
89
85
  /**
90
86
  * Add a new entry to a leaderboard
91
87
  * @param leaderboardName
@@ -130,5 +126,11 @@ export declare class KokimokiClient<ClientContextT = any> extends KokimokiClient
130
126
  score: number;
131
127
  metadata: MetadataT;
132
128
  }>;
129
+ /**
130
+ * Send app data via webhook
131
+ */
132
+ sendWebhook<T>(event: string, data: T): Promise<{
133
+ jobId: string;
134
+ }>;
133
135
  }
134
136
  export {};
@@ -7,9 +7,9 @@ import { WsMessageType } from "./ws-message-type";
7
7
  import { WsMessageWriter } from "./ws-message-writer";
8
8
  import { WsMessageReader } from "./ws-message-reader";
9
9
  import { RoomSubscription } from "./room-subscription";
10
- import { KokimokiQueue } from "./kokimoki-queue";
10
+ // import { KokimokiQueue } from "./kokimoki-queue";
11
11
  import { KokimokiAwareness } from "./kokimoki-awareness";
12
- import { KokimokiReqRes } from "./kokimoki-req-res";
12
+ // import { KokimokiReqRes } from "./kokimoki-req-res";
13
13
  import { KokimokiLocalStore } from "./kokimoki-local-store";
14
14
  export class KokimokiClient extends EventEmitter {
15
15
  host;
@@ -476,12 +476,13 @@ export class KokimokiClient extends EventEmitter {
476
476
  store.onLeave(this);
477
477
  }
478
478
  }
479
- async transact(handler) {
479
+ async transact(stores, handler) {
480
480
  // if (!this._connected) {
481
481
  // throw new Error("Client not connected");
482
482
  // }
483
- const transaction = new KokimokiTransaction(this);
484
- const returnValue = await handler(transaction);
483
+ const transaction = new KokimokiTransaction(stores);
484
+ // @ts-ignore
485
+ const returnValue = await handler(transaction.getProxies());
485
486
  const { updates, consumedMessages } = await transaction.getUpdates();
486
487
  if (!updates.length) {
487
488
  return returnValue;
@@ -585,18 +586,23 @@ export class KokimokiClient extends EventEmitter {
585
586
  .catch(() => { });
586
587
  return store;
587
588
  }
588
- // queue
589
- queue(name, schema, mode, autoJoin = true) {
590
- const queue = new KokimokiQueue(name, schema, mode);
591
- if (autoJoin) {
592
- this.join(queue)
593
- .then(() => { })
594
- .catch(() => { });
595
- }
596
- return queue;
597
- }
589
+ // // queue
590
+ // queue<T extends S.Generic<unknown>>(
591
+ // name: string,
592
+ // schema: T,
593
+ // mode: RoomSubscriptionMode,
594
+ // autoJoin = true
595
+ // ) {
596
+ // const queue = new KokimokiQueue<T>(name, schema, mode);
597
+ // if (autoJoin) {
598
+ // this.join(queue)
599
+ // .then(() => {})
600
+ // .catch(() => {});
601
+ // }
602
+ // return queue;
603
+ // }
598
604
  // awareness
599
- awareness(name, dataSchema, initialData = dataSchema.defaultValue, autoJoin = true) {
605
+ awareness(name, dataSchema, initialData = dataSchema.parse({}), autoJoin = true) {
600
606
  const awareness = new KokimokiAwareness(name, dataSchema, initialData);
601
607
  if (autoJoin) {
602
608
  this.join(awareness)
@@ -605,10 +611,23 @@ export class KokimokiClient extends EventEmitter {
605
611
  }
606
612
  return awareness;
607
613
  }
608
- // req-res
609
- reqRes(serviceName, reqSchema, resSchema, handleRequest) {
610
- return new KokimokiReqRes(this, serviceName, reqSchema, resSchema, handleRequest);
611
- }
614
+ // // req-res
615
+ // reqRes<Req extends S.Generic<unknown>, Res extends S.Generic<unknown>>(
616
+ // serviceName: string,
617
+ // reqSchema: Req,
618
+ // resSchema: Res,
619
+ // handleRequest: (
620
+ // payload: Req["defaultValue"]
621
+ // ) => Promise<Res["defaultValue"]>
622
+ // ) {
623
+ // return new KokimokiReqRes(
624
+ // this,
625
+ // serviceName,
626
+ // reqSchema,
627
+ // resSchema,
628
+ // handleRequest
629
+ // );
630
+ // }
612
631
  /**
613
632
  * Add a new entry to a leaderboard
614
633
  * @param leaderboardName
@@ -681,4 +700,15 @@ export class KokimokiClient extends EventEmitter {
681
700
  });
682
701
  return await res.json();
683
702
  }
703
+ /**
704
+ * Send app data via webhook
705
+ */
706
+ async sendWebhook(event, data) {
707
+ const res = await fetch(`${this._apiUrl}/webhooks`, {
708
+ method: "POST",
709
+ headers: this.apiHeaders,
710
+ body: JSON.stringify({ event, data }),
711
+ });
712
+ return await res.json();
713
+ }
684
714
  }
@@ -1,10 +1,10 @@
1
1
  import { KokimokiStore } from "./kokimoki-store";
2
- import type { KokimokiSchema as S } from "./kokimoki-schema";
3
- export declare class KokimokiLocalStore<Data extends S.Generic<unknown>> extends KokimokiStore<Data> {
2
+ import { ZodType } from "zod";
3
+ export declare class KokimokiLocalStore<Data> extends KokimokiStore<Data> {
4
4
  private readonly localRoomName;
5
5
  private _stateKey?;
6
6
  private get stateKey();
7
- constructor(localRoomName: string, schema: Data);
7
+ constructor(localRoomName: string, schema: ZodType<Data>);
8
8
  getInitialUpdate(appId: string, clientId: string): {
9
9
  roomHash: number;
10
10
  initialUpdate: Uint8Array | undefined;
@@ -1,31 +0,0 @@
1
- import { KokimokiStore } from "./kokimoki-store";
2
- import { KokimokiSchema as S } from "./kokimoki-schema";
3
- import type TypedEventEmitter from "typed-emitter";
4
- import type { RoomSubscriptionMode } from "./room-subscription-mode";
5
- export declare class KokimokiQueue<Req extends S.Generic<unknown>> extends KokimokiStore<S.Dict<Req>> {
6
- readonly payloadSchema: Req;
7
- private _emitter;
8
- readonly on: <E extends "messages">(event: E, listener: {
9
- messages: (messages: {
10
- id: string;
11
- payload: Req["defaultValue"];
12
- }[]) => void;
13
- }[E]) => TypedEventEmitter<{
14
- messages: (messages: {
15
- id: string;
16
- payload: Req["defaultValue"];
17
- }[]) => void;
18
- }>;
19
- readonly off: <E extends "messages">(event: E, listener: {
20
- messages: (messages: {
21
- id: string;
22
- payload: Req["defaultValue"];
23
- }[]) => void;
24
- }[E]) => TypedEventEmitter<{
25
- messages: (messages: {
26
- id: string;
27
- payload: Req["defaultValue"];
28
- }[]) => void;
29
- }>;
30
- constructor(roomName: string, payloadSchema: Req, mode: RoomSubscriptionMode);
31
- }
@@ -1,27 +1,38 @@
1
- import EventEmitter from "events";
2
- import { KokimokiStore } from "./kokimoki-store";
3
- import { KokimokiSchema as S } from "./kokimoki-schema";
4
- export class KokimokiQueue extends KokimokiStore {
5
- payloadSchema;
6
- _emitter = new EventEmitter();
7
- on = this._emitter.on.bind(this._emitter);
8
- off = this._emitter.off.bind(this._emitter);
9
- constructor(roomName, payloadSchema, mode) {
10
- super(`/q/${roomName}`, S.dict(payloadSchema), mode);
11
- this.payloadSchema = payloadSchema;
12
- const emittedMessageIds = new Set();
13
- this.doc.on("update", () => {
14
- const newMessages = [];
15
- for (const id in this.proxy) {
16
- if (emittedMessageIds.has(id)) {
17
- continue;
18
- }
19
- emittedMessageIds.add(id);
20
- newMessages.push({ id, payload: this.proxy[id] });
21
- }
22
- if (newMessages.length > 0) {
23
- this._emitter.emit("messages", newMessages);
24
- }
25
- });
26
- }
27
- }
1
+ "use strict";
2
+ // import EventEmitter from "events";
3
+ // import { KokimokiStore } from "./kokimoki-store";
4
+ // import { KokimokiSchema as S } from "./kokimoki-schema";
5
+ // import type TypedEventEmitter from "typed-emitter";
6
+ // import type { RoomSubscriptionMode } from "./room-subscription-mode";
7
+ // export class KokimokiQueue<
8
+ // Req extends S.Generic<unknown>
9
+ // > extends KokimokiStore<S.Dict<Req>> {
10
+ // private _emitter = new EventEmitter() as TypedEventEmitter<{
11
+ // messages: (
12
+ // messages: { id: string; payload: Req["defaultValue"] }[]
13
+ // ) => void;
14
+ // }>;
15
+ // public readonly on = this._emitter.on.bind(this._emitter);
16
+ // public readonly off = this._emitter.off.bind(this._emitter);
17
+ // constructor(
18
+ // roomName: string,
19
+ // public readonly payloadSchema: Req,
20
+ // mode: RoomSubscriptionMode
21
+ // ) {
22
+ // super(`/q/${roomName}`, S.dict(payloadSchema), mode);
23
+ // const emittedMessageIds = new Set<string>();
24
+ // this.doc.on("update", () => {
25
+ // const newMessages: { id: string; payload: Req["defaultValue"] }[] = [];
26
+ // for (const id in this.proxy) {
27
+ // if (emittedMessageIds.has(id)) {
28
+ // continue;
29
+ // }
30
+ // emittedMessageIds.add(id);
31
+ // newMessages.push({ id, payload: this.proxy[id] });
32
+ // }
33
+ // if (newMessages.length > 0) {
34
+ // this._emitter.emit("messages", newMessages);
35
+ // }
36
+ // });
37
+ // }
38
+ // }
@@ -1,20 +0,0 @@
1
- import type { KokimokiClient } from "./kokimoki-client";
2
- import { KokimokiSchema as S } from "./kokimoki-schema";
3
- export declare class KokimokiReqRes<Req extends S.Generic<unknown>, Res extends S.Generic<unknown>> {
4
- private kmClient;
5
- readonly serviceName: string;
6
- readonly reqSchema: Req;
7
- readonly resSchema: Res;
8
- private handleRequest;
9
- private _reqQueueSchema;
10
- private _resQueueSchema;
11
- private _reqQueues;
12
- private _resQueues;
13
- private _reqPromises;
14
- private _getReqQueue;
15
- private _getResQueue;
16
- constructor(kmClient: KokimokiClient, serviceName: string, reqSchema: Req, resSchema: Res, handleRequest: (payload: Req["defaultValue"]) => Promise<Res["defaultValue"]>);
17
- private handleRequests;
18
- private handleResponses;
19
- send(toClientId: string, payload: Req["defaultValue"], timeout?: number): Promise<Res["defaultValue"]>;
20
- }