@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.
@@ -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.
@@ -11200,9 +11200,76 @@ const getUntracked = (obj) => {
11200
11200
  }
11201
11201
  return null;
11202
11202
  };
11203
+ /**
11204
+ * Mark object to be tracked.
11205
+ *
11206
+ * This function marks an object that will be passed into `createProxy`
11207
+ * as marked to track or not. By default only Array and Object are marked to track,
11208
+ * so this is useful for example to mark a class instance to track or to mark a object
11209
+ * to be untracked when creating your proxy.
11210
+ *
11211
+ * @param obj - Object to mark as tracked or not.
11212
+ * @param mark - Boolean indicating whether you want to track this object or not.
11213
+ * @returns - No return.
11214
+ *
11215
+ * @example
11216
+ * import { createProxy, markToTrack, isChanged } from 'proxy-compare';
11217
+ *
11218
+ * const nested = { e: "3" }
11219
+ *
11220
+ * markToTrack(nested, false)
11221
+ *
11222
+ * const original = { a: "1", c: "2", d: nested };
11223
+ * const affected = new WeakMap();
11224
+ *
11225
+ * const proxy = createProxy(original, affected);
11226
+ *
11227
+ * proxy.d.e
11228
+ *
11229
+ * isChanged(original, { d: { e: "3" } }, affected) // true
11230
+ */
11231
+ const markToTrack = (obj, mark = true) => {
11232
+ objectsToTrack.set(obj, mark);
11233
+ };
11203
11234
 
11204
11235
  const isObject = (x) => typeof x === "object" && x !== null;
11205
11236
  const canProxyDefault = (x) => isObject(x) && !refSet.has(x) && (Array.isArray(x) || !(Symbol.iterator in x)) && !(x instanceof WeakMap) && !(x instanceof WeakSet) && !(x instanceof Error) && !(x instanceof Number) && !(x instanceof Date) && !(x instanceof String) && !(x instanceof RegExp) && !(x instanceof ArrayBuffer) && !(x instanceof Promise);
11237
+ const createSnapshotDefault = (target, version) => {
11238
+ const cache = snapCache.get(target);
11239
+ if ((cache == null ? void 0 : cache[0]) === version) {
11240
+ return cache[1];
11241
+ }
11242
+ const snap = Array.isArray(target) ? [] : Object.create(Object.getPrototypeOf(target));
11243
+ markToTrack(snap, true);
11244
+ snapCache.set(target, [version, snap]);
11245
+ Reflect.ownKeys(target).forEach((key) => {
11246
+ if (Object.getOwnPropertyDescriptor(snap, key)) {
11247
+ return;
11248
+ }
11249
+ const value = Reflect.get(target, key);
11250
+ const { enumerable } = Reflect.getOwnPropertyDescriptor(
11251
+ target,
11252
+ key
11253
+ );
11254
+ const desc = {
11255
+ value,
11256
+ enumerable,
11257
+ // This is intentional to avoid copying with proxy-compare.
11258
+ // It's still non-writable, so it avoids assigning a value.
11259
+ configurable: true
11260
+ };
11261
+ if (refSet.has(value)) {
11262
+ markToTrack(value, false);
11263
+ } else if (proxyStateMap.has(value)) {
11264
+ const [target2, ensureVersion] = proxyStateMap.get(
11265
+ value
11266
+ );
11267
+ desc.value = createSnapshotDefault(target2, ensureVersion());
11268
+ }
11269
+ Object.defineProperty(snap, key, desc);
11270
+ });
11271
+ return Object.preventExtensions(snap);
11272
+ };
11206
11273
  const createHandlerDefault = (isInitializing, addPropListener, removePropListener, notifyUpdate) => ({
11207
11274
  deleteProperty(target, prop) {
11208
11275
  const prevValue = Reflect.get(target, prop);
@@ -11232,11 +11299,13 @@ const createHandlerDefault = (isInitializing, addPropListener, removePropListene
11232
11299
  });
11233
11300
  const proxyStateMap = /* @__PURE__ */ new WeakMap();
11234
11301
  const refSet = /* @__PURE__ */ new WeakSet();
11302
+ const snapCache = /* @__PURE__ */ new WeakMap();
11235
11303
  const versionHolder = [1, 1];
11236
11304
  const proxyCache = /* @__PURE__ */ new WeakMap();
11237
11305
  let objectIs = Object.is;
11238
11306
  let newProxy = (target, handler) => new Proxy(target, handler);
11239
11307
  let canProxy = canProxyDefault;
11308
+ let createSnapshot = createSnapshotDefault;
11240
11309
  let createHandler = createHandlerDefault;
11241
11310
  function proxy(baseObject = {}) {
11242
11311
  if (!isObject(baseObject)) {
@@ -11377,6 +11446,14 @@ function subscribe(proxyObject, callback, notifyInSync) {
11377
11446
  removeListener();
11378
11447
  };
11379
11448
  }
11449
+ function snapshot(proxyObject) {
11450
+ const proxyState = proxyStateMap.get(proxyObject);
11451
+ if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !proxyState) {
11452
+ console.warn("Please use proxy object");
11453
+ }
11454
+ const [target, ensureVersion] = proxyState;
11455
+ return createSnapshot(target, ensureVersion());
11456
+ }
11380
11457
 
11381
11458
  // do not edit .js files directly - edit src/index.jst
11382
11459
 
@@ -11927,49 +12004,72 @@ class KokimokiStore {
11927
12004
  doc;
11928
12005
  proxy;
11929
12006
  docRoot;
12007
+ connections;
11930
12008
  constructor(roomName, defaultValue, mode = RoomSubscriptionMode.ReadWrite) {
11931
12009
  this.roomName = roomName;
11932
12010
  this.defaultValue = defaultValue;
11933
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
+ }
11934
12016
  // Construct Y doc
11935
12017
  this.doc = new Doc();
11936
12018
  this.docRoot = this.doc.getMap("root");
11937
12019
  // Construct proxy object
11938
- this.proxy = proxy(); //T["defaultValue"];
12020
+ this.proxy = proxy();
11939
12021
  // @ts-ignore
11940
12022
  bind$1(this.proxy, this.docRoot);
11941
- // // Create root proxy
11942
- // const store = this;
11943
- // // @ts-ignore
11944
- // this.root = new DeepProxy(this.proxy, {
11945
- // get() {
11946
- // return this.nest(function () {});
11947
- // },
11948
- // apply() {
11949
- // let obj: any = store.proxy;
11950
- // for (let i = 0; i < this.path.length - 1; i++) {
11951
- // obj = obj[this.path[i]];
11952
- // }
11953
- // return {
11954
- // roomName: store.roomName,
11955
- // doc: store.doc,
11956
- // path: this.path,
11957
- // obj,
11958
- // key: this.path[this.path.length - 1],
11959
- // };
11960
- // },
11961
- // });
12023
+ // Construct connections proxy
12024
+ this.connections = proxy({ clientIds: new Set() });
12025
+ // Update connections.clientIds whenever _connections changes
12026
+ let prevConnections = new Set();
12027
+ subscribe(this.proxy, () => {
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;
12036
+ }
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);
12056
+ }
12057
+ });
11962
12058
  }
11963
12059
  get() {
11964
- return this.proxy;
12060
+ return snapshot(this.proxy);
11965
12061
  }
11966
12062
  subscribe(set) {
11967
- const handler = () => set(this.proxy);
12063
+ const handler = () => set(this.get());
11968
12064
  this.doc.on("update", handler);
11969
- set(this.proxy);
12065
+ set(this.get());
11970
12066
  return () => this.doc.off("update", handler);
11971
12067
  }
11972
- async onJoin(client) { }
12068
+ async onJoin(client) {
12069
+ await client.transact([this], ([state]) => {
12070
+ state._connections[client.connectionId] = client.id;
12071
+ });
12072
+ }
11973
12073
  async onBeforeLeave(client) { }
11974
12074
  async onLeave(client) { }
11975
12075
  }
@@ -12104,6 +12204,9 @@ class RoomSubscription {
12104
12204
  // Set defaults if doc is empty after sync (only possible in ReadWrite mode)
12105
12205
  if (this.store.mode === RoomSubscriptionMode.ReadWrite) {
12106
12206
  await this.kmClient.transact([this.store], ([state]) => {
12207
+ if (!("_connections" in state)) {
12208
+ state._connections = {};
12209
+ }
12107
12210
  for (const key in this.store.defaultValue) {
12108
12211
  if (!state.hasOwnProperty(key)) {
12109
12212
  state[key] = this.store.defaultValue[key];
@@ -12120,64 +12223,29 @@ class RoomSubscription {
12120
12223
 
12121
12224
  class KokimokiAwareness extends KokimokiStore {
12122
12225
  _data;
12123
- _pingInterval = null;
12124
12226
  _kmClients = new Set();
12125
- constructor(roomName, _data, mode = RoomSubscriptionMode.ReadWrite, pingTimeout = 3000) {
12227
+ constructor(roomName, _data, mode = RoomSubscriptionMode.ReadWrite) {
12126
12228
  super(`/a/${roomName}`, {}, mode);
12127
12229
  this._data = _data;
12128
- this._pingInterval = setInterval(async () => {
12129
- const kmClients = Array.from(this._kmClients);
12130
- await Promise.all(kmClients.map(async (client) => {
12131
- try {
12132
- await client.transact([this], ([state]) => {
12133
- const timestamp = client.serverTimestamp();
12134
- // Update self
12135
- if (state[client.connectionId]) {
12136
- state[client.connectionId].lastPing = timestamp;
12137
- }
12138
- else {
12139
- state[client.connectionId] = {
12140
- clientId: client.id,
12141
- lastPing: timestamp,
12142
- data: this._data,
12143
- };
12144
- }
12145
- // Delete clients that haven't pinged in a while
12146
- for (const connectionId in state) {
12147
- const { lastPing } = state[connectionId];
12148
- if (!lastPing || timestamp - lastPing > pingTimeout * 2) {
12149
- delete state[connectionId];
12150
- }
12151
- }
12152
- });
12153
- }
12154
- catch (e) { }
12155
- }));
12156
- }, pingTimeout);
12157
12230
  }
12158
12231
  async onJoin(client) {
12159
12232
  this._kmClients.add(client);
12160
12233
  await client.transact([this], ([state]) => {
12161
12234
  state[client.connectionId] = {
12162
12235
  clientId: client.id,
12163
- lastPing: client.serverTimestamp(),
12164
12236
  data: this._data,
12165
12237
  };
12166
12238
  });
12167
12239
  }
12168
- async onBeforeLeave(client) {
12169
- await client.transact([this], ([state]) => {
12170
- delete state[client.connectionId];
12171
- });
12172
- }
12173
12240
  async onLeave(client) {
12174
12241
  this._kmClients.delete(client);
12175
12242
  }
12176
12243
  getClients() {
12177
12244
  const clients = {};
12178
- for (const connectionId in this.proxy) {
12179
- clients[this.proxy[connectionId].clientId] =
12180
- this.proxy[connectionId].data;
12245
+ const connections = this.get();
12246
+ for (const connectionId in connections) {
12247
+ clients[connections[connectionId].clientId] =
12248
+ connections[connectionId].data;
12181
12249
  }
12182
12250
  return clients;
12183
12251
  }
@@ -15208,7 +15276,7 @@ class KokimokiClient extends EventEmitter$1 {
15208
15276
  this._subscriptionsByHash.set(res.roomHash, subscription);
15209
15277
  await subscription.applyInitialResponse(res.roomHash, res.initialUpdate);
15210
15278
  // Trigger onJoin event
15211
- store.onJoin(this);
15279
+ await store.onJoin(this);
15212
15280
  }
15213
15281
  }
15214
15282
  async leave(store) {
@@ -15465,7 +15533,12 @@ class KokimokiClient extends EventEmitter$1 {
15465
15533
  const res = await fetch(`${this._apiUrl}/ai/chat`, {
15466
15534
  method: "POST",
15467
15535
  headers: this.apiHeaders,
15468
- body: JSON.stringify({ systemPrompt, userPrompt, temperature, maxTokens }),
15536
+ body: JSON.stringify({
15537
+ systemPrompt,
15538
+ userPrompt,
15539
+ temperature,
15540
+ maxTokens,
15541
+ }),
15469
15542
  });
15470
15543
  if (!res.ok) {
15471
15544
  throw await res.json();