@kokimoki/app 1.0.2 → 1.0.5
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-schema.d.ts +6 -0
- package/dist/kokimoki-schema.js +14 -0
- package/dist/kokimoki-transaction.d.ts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
- package/dist/kokimoki-client copy.d.ts +0 -57
- package/dist/kokimoki-client copy.js +0 -259
- package/dist/kokimoki-client-refactored.d.ts +0 -67
- package/dist/kokimoki-client-refactored.js +0 -422
- package/dist/message-queue.d.ts +0 -8
- package/dist/message-queue.js +0 -19
- package/dist/synced-schema.d.ts +0 -52
- package/dist/synced-schema.js +0 -92
- package/dist/synced-store copy.d.ts +0 -7
- package/dist/synced-store copy.js +0 -9
- package/dist/synced-store.d.ts +0 -7
- package/dist/synced-store.js +0 -9
- package/dist/synced-types.d.ts +0 -45
- package/dist/synced-types.js +0 -72
- package/dist/ws-message/index.d.ts +0 -3
- package/dist/ws-message/index.js +0 -3
- package/dist/ws-message/ws-message-reader.d.ts +0 -9
- package/dist/ws-message/ws-message-reader.js +0 -17
- package/dist/ws-message/ws-message-type.d.ts +0 -4
- package/dist/ws-message/ws-message-type.js +0 -5
- package/dist/ws-message/ws-message-writer.d.ts +0 -12
- package/dist/ws-message/ws-message-writer.js +0 -30
- package/dist/ws-message.d.ts +0 -14
- package/dist/ws-message.js +0 -34
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
import EventEmitter from "events";
|
|
2
|
-
import { KOKIMOKI_APP_VERSION } from "./version";
|
|
3
|
-
import * as Y from "yjs";
|
|
4
|
-
import { KokimokiTransaction } from "./kokimoki-transaction";
|
|
5
|
-
import { WsMessageType } from "./ws-message-type";
|
|
6
|
-
import { WsMessageWriter } from "./ws-message-writer";
|
|
7
|
-
import { WsMessageReader } from "./ws-message-reader";
|
|
8
|
-
import { RoomSubscriptionMode } from "./room-subscription-mode";
|
|
9
|
-
import { RoomSubscription } from "./room-subscription";
|
|
10
|
-
export class KokimokiClient extends EventEmitter {
|
|
11
|
-
host;
|
|
12
|
-
appId;
|
|
13
|
-
code;
|
|
14
|
-
_wsUrl;
|
|
15
|
-
_apiUrl;
|
|
16
|
-
_id;
|
|
17
|
-
_token;
|
|
18
|
-
_apiHeaders;
|
|
19
|
-
_serverTimeOffset = 0;
|
|
20
|
-
_clientContext;
|
|
21
|
-
_ws;
|
|
22
|
-
_subscriptionsByName = new Map();
|
|
23
|
-
_subscriptionsByHash = new Map();
|
|
24
|
-
_subscribeReqPromises = new Map();
|
|
25
|
-
_transactionPromises = new Map();
|
|
26
|
-
_connected = false;
|
|
27
|
-
_connectPromise;
|
|
28
|
-
_messageId = 0;
|
|
29
|
-
_reconnectTimeout = 0;
|
|
30
|
-
constructor(host, appId, code = "") {
|
|
31
|
-
super();
|
|
32
|
-
this.host = host;
|
|
33
|
-
this.appId = appId;
|
|
34
|
-
this.code = code;
|
|
35
|
-
// Set up the URLs
|
|
36
|
-
const secure = this.host.indexOf(":") === -1;
|
|
37
|
-
this._wsUrl = `ws${secure ? "s" : ""}://${this.host}`;
|
|
38
|
-
this._apiUrl = `http${secure ? "s" : ""}://${this.host}`;
|
|
39
|
-
}
|
|
40
|
-
get id() {
|
|
41
|
-
if (!this._id) {
|
|
42
|
-
throw new Error("Client not connected");
|
|
43
|
-
}
|
|
44
|
-
return this._id;
|
|
45
|
-
}
|
|
46
|
-
get token() {
|
|
47
|
-
if (!this._token) {
|
|
48
|
-
throw new Error("Client not connected");
|
|
49
|
-
}
|
|
50
|
-
return this._token;
|
|
51
|
-
}
|
|
52
|
-
get apiUrl() {
|
|
53
|
-
if (!this._apiUrl) {
|
|
54
|
-
throw new Error("Client not connected");
|
|
55
|
-
}
|
|
56
|
-
return this._apiUrl;
|
|
57
|
-
}
|
|
58
|
-
get apiHeaders() {
|
|
59
|
-
if (!this._apiHeaders) {
|
|
60
|
-
throw new Error("Client not connected");
|
|
61
|
-
}
|
|
62
|
-
return this._apiHeaders;
|
|
63
|
-
}
|
|
64
|
-
get clientContext() {
|
|
65
|
-
if (this._clientContext === undefined) {
|
|
66
|
-
throw new Error("Client not connected");
|
|
67
|
-
}
|
|
68
|
-
return this._clientContext;
|
|
69
|
-
}
|
|
70
|
-
get connected() {
|
|
71
|
-
return this._connected;
|
|
72
|
-
}
|
|
73
|
-
get ws() {
|
|
74
|
-
if (!this._ws) {
|
|
75
|
-
throw new Error("Not connected");
|
|
76
|
-
}
|
|
77
|
-
return this._ws;
|
|
78
|
-
}
|
|
79
|
-
async connect() {
|
|
80
|
-
if (this._connectPromise) {
|
|
81
|
-
return await this._connectPromise;
|
|
82
|
-
}
|
|
83
|
-
this._ws = new WebSocket(`${this._wsUrl}/apps/${this.appId}?clientVersion=${KOKIMOKI_APP_VERSION}`);
|
|
84
|
-
this._ws.binaryType = "arraybuffer";
|
|
85
|
-
// Close previous connection in hot-reload scenarios
|
|
86
|
-
if (window) {
|
|
87
|
-
if (!window.__KOKIMOKI_WS__) {
|
|
88
|
-
window.__KOKIMOKI_WS__ = {};
|
|
89
|
-
}
|
|
90
|
-
if (this.appId in window.__KOKIMOKI_WS__) {
|
|
91
|
-
window.__KOKIMOKI_WS__[this.appId].close();
|
|
92
|
-
}
|
|
93
|
-
window.__KOKIMOKI_WS__[this.appId] = this._ws;
|
|
94
|
-
}
|
|
95
|
-
// Wait for connection
|
|
96
|
-
this._connectPromise = new Promise((onInit) => {
|
|
97
|
-
// Fetch the auth token
|
|
98
|
-
let clientToken = localStorage.getItem("KM_TOKEN");
|
|
99
|
-
// Send the app token on first connect
|
|
100
|
-
this.ws.onopen = () => {
|
|
101
|
-
this.ws.send(JSON.stringify({ type: "auth", code: this.code, token: clientToken }));
|
|
102
|
-
};
|
|
103
|
-
this.ws.onclose = () => {
|
|
104
|
-
this._connected = false;
|
|
105
|
-
this._connectPromise = undefined;
|
|
106
|
-
this._ws = undefined;
|
|
107
|
-
if (window && window.__KOKIMOKI_WS__) {
|
|
108
|
-
delete window.__KOKIMOKI_WS__[this.appId];
|
|
109
|
-
}
|
|
110
|
-
// Clean up
|
|
111
|
-
this._subscribeReqPromises.clear();
|
|
112
|
-
this._transactionPromises.clear();
|
|
113
|
-
// Attempt to reconnect
|
|
114
|
-
console.log(`[Kokimoki] Connection lost, attempting to reconnect in ${this._reconnectTimeout} seconds...`);
|
|
115
|
-
setTimeout(async () => await this.connect(), this._reconnectTimeout * 1000);
|
|
116
|
-
this._reconnectTimeout = Math.min(3, this._reconnectTimeout + 1);
|
|
117
|
-
// Emit disconnected event
|
|
118
|
-
this.emit("disconnected");
|
|
119
|
-
};
|
|
120
|
-
this.ws.onmessage = (e) => {
|
|
121
|
-
console.log(`Received WS message: ${e.data}`);
|
|
122
|
-
// Handle JSON messages
|
|
123
|
-
if (typeof e.data === "string") {
|
|
124
|
-
const message = JSON.parse(e.data);
|
|
125
|
-
switch (message.type) {
|
|
126
|
-
case "serverTime": {
|
|
127
|
-
this._serverTimeOffset = Date.now() - message.serverTime;
|
|
128
|
-
console.log(`Server time offset: ${this._serverTimeOffset}`);
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
case "init":
|
|
132
|
-
this.handleInitMessage(message);
|
|
133
|
-
onInit();
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
// Handle binary messages
|
|
139
|
-
this.handleBinaryMessage(e.data);
|
|
140
|
-
};
|
|
141
|
-
});
|
|
142
|
-
await this._connectPromise;
|
|
143
|
-
this._connected = true;
|
|
144
|
-
// Connection established
|
|
145
|
-
console.log(`[Kokimoki] Client id: ${this.id}`);
|
|
146
|
-
console.log(`[Kokimoki] Client context:`, this.clientContext);
|
|
147
|
-
// Restore subscriptions if reconnected
|
|
148
|
-
const roomNames = Array.from(this._subscriptionsByName.keys()).map((name) => `"${name}"`);
|
|
149
|
-
if (roomNames.length) {
|
|
150
|
-
console.log(`[Kokimoki] Restoring subscriptions: ${roomNames}`);
|
|
151
|
-
}
|
|
152
|
-
for (const subscription of this._subscriptionsByName.values()) {
|
|
153
|
-
try {
|
|
154
|
-
await this.join(subscription.store);
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
console.error(`[Kokimoki] Failed to restore subscription for "${subscription.roomName}":`, err);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
// Emit connected event
|
|
161
|
-
this._reconnectTimeout = 0;
|
|
162
|
-
this.emit("connected");
|
|
163
|
-
}
|
|
164
|
-
handleInitMessage(message) {
|
|
165
|
-
localStorage.setItem("KM_TOKEN", message.clientToken);
|
|
166
|
-
this._id = message.clientId;
|
|
167
|
-
this._token = message.appToken;
|
|
168
|
-
this._clientContext = message.clientContext;
|
|
169
|
-
// Set up the auth headers
|
|
170
|
-
this._apiHeaders = new Headers({
|
|
171
|
-
Authorization: `Bearer ${this.token}`,
|
|
172
|
-
"Content-Type": "application/json",
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
handleBinaryMessage(data) {
|
|
176
|
-
const reader = new WsMessageReader(data);
|
|
177
|
-
const type = reader.readInt32();
|
|
178
|
-
switch (type) {
|
|
179
|
-
case WsMessageType.SubscribeRes:
|
|
180
|
-
this.handleSubscribeResMessage(reader);
|
|
181
|
-
break;
|
|
182
|
-
case WsMessageType.RoomUpdate:
|
|
183
|
-
this.handleRoomUpdateMessage(reader);
|
|
184
|
-
break;
|
|
185
|
-
case WsMessageType.Error:
|
|
186
|
-
this.handleErrorMessage(reader);
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
handleErrorMessage(msg) {
|
|
191
|
-
const reqId = msg.readInt32();
|
|
192
|
-
const error = msg.readString();
|
|
193
|
-
const subscribeReqPromise = this._subscribeReqPromises.get(reqId);
|
|
194
|
-
const transactionPromise = this._transactionPromises.get(reqId);
|
|
195
|
-
if (subscribeReqPromise) {
|
|
196
|
-
this._subscribeReqPromises.delete(reqId);
|
|
197
|
-
subscribeReqPromise.reject(error);
|
|
198
|
-
}
|
|
199
|
-
else if (transactionPromise) {
|
|
200
|
-
this._transactionPromises.delete(reqId);
|
|
201
|
-
transactionPromise.reject(error);
|
|
202
|
-
}
|
|
203
|
-
else {
|
|
204
|
-
console.warn(`Received error for unknown request ${reqId}: ${error}`);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
handleSubscribeResMessage(msg) {
|
|
208
|
-
const reqId = msg.readInt32();
|
|
209
|
-
const roomHash = msg.readUint32();
|
|
210
|
-
const promise = this._subscribeReqPromises.get(reqId);
|
|
211
|
-
if (promise) {
|
|
212
|
-
this._subscribeReqPromises.delete(reqId);
|
|
213
|
-
// In Write mode, no initial state is sent
|
|
214
|
-
if (!msg.end) {
|
|
215
|
-
promise.resolve(roomHash, msg.readUint8Array());
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
promise.resolve(roomHash);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
handleRoomUpdateMessage(msg) {
|
|
223
|
-
const appliedId = msg.readInt32();
|
|
224
|
-
const roomHash = msg.readUint32();
|
|
225
|
-
// Apply update if not in Write mode
|
|
226
|
-
if (!msg.end) {
|
|
227
|
-
const subscription = this._subscriptionsByHash.get(roomHash);
|
|
228
|
-
if (subscription) {
|
|
229
|
-
Y.applyUpdate(subscription.store.doc, msg.readUint8Array(), this);
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
console.warn(`Received update for unknown room ${roomHash}`);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
// Check transaction resolves
|
|
236
|
-
for (const [transactionId, { resolve },] of this._transactionPromises.entries()) {
|
|
237
|
-
if (appliedId >= transactionId) {
|
|
238
|
-
this._transactionPromises.delete(transactionId);
|
|
239
|
-
resolve();
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
serverTimestamp() {
|
|
244
|
-
return Date.now() - this._serverTimeOffset;
|
|
245
|
-
}
|
|
246
|
-
// Send Y update to room
|
|
247
|
-
async patchRoomState(room, update) {
|
|
248
|
-
const res = await fetch(`${this._apiUrl}/rooms/${room}`, {
|
|
249
|
-
method: "PATCH",
|
|
250
|
-
headers: this.apiHeaders,
|
|
251
|
-
body: update,
|
|
252
|
-
});
|
|
253
|
-
return await res.json();
|
|
254
|
-
}
|
|
255
|
-
// Storage
|
|
256
|
-
async createUpload(name, blob, tags) {
|
|
257
|
-
const res = await fetch(`${this._apiUrl}/uploads`, {
|
|
258
|
-
method: "POST",
|
|
259
|
-
headers: this.apiHeaders,
|
|
260
|
-
body: JSON.stringify({
|
|
261
|
-
name,
|
|
262
|
-
size: blob.size,
|
|
263
|
-
mimeType: blob.type,
|
|
264
|
-
tags,
|
|
265
|
-
}),
|
|
266
|
-
});
|
|
267
|
-
return await res.json();
|
|
268
|
-
}
|
|
269
|
-
async uploadChunks(blob, chunkSize, signedUrls) {
|
|
270
|
-
return await Promise.all(signedUrls.map(async (url, index) => {
|
|
271
|
-
const start = index * chunkSize;
|
|
272
|
-
const end = Math.min(start + chunkSize, blob.size);
|
|
273
|
-
const chunk = blob.slice(start, end);
|
|
274
|
-
const res = await fetch(url, { method: "PUT", body: chunk });
|
|
275
|
-
return JSON.parse(res.headers.get("ETag") || '""');
|
|
276
|
-
}));
|
|
277
|
-
}
|
|
278
|
-
async completeUpload(id, etags) {
|
|
279
|
-
const res = await fetch(`${this._apiUrl}/uploads/${id}`, {
|
|
280
|
-
method: "PUT",
|
|
281
|
-
headers: this.apiHeaders,
|
|
282
|
-
body: JSON.stringify({ etags }),
|
|
283
|
-
});
|
|
284
|
-
return await res.json();
|
|
285
|
-
}
|
|
286
|
-
async upload(name, blob, tags = []) {
|
|
287
|
-
const { id, chunkSize, urls } = await this.createUpload(name, blob, tags);
|
|
288
|
-
const etags = await this.uploadChunks(blob, chunkSize, urls);
|
|
289
|
-
return await this.completeUpload(id, etags);
|
|
290
|
-
}
|
|
291
|
-
async updateUpload(id, update) {
|
|
292
|
-
const res = await fetch(`${this._apiUrl}/uploads/${id}`, {
|
|
293
|
-
method: "PUT",
|
|
294
|
-
headers: this.apiHeaders,
|
|
295
|
-
body: JSON.stringify(update),
|
|
296
|
-
});
|
|
297
|
-
return await res.json();
|
|
298
|
-
}
|
|
299
|
-
async listUploads(filter = {}, skip = 0, limit = 100) {
|
|
300
|
-
const url = new URL("/uploads", this._apiUrl);
|
|
301
|
-
url.searchParams.set("skip", skip.toString());
|
|
302
|
-
url.searchParams.set("limit", limit.toString());
|
|
303
|
-
if (filter.clientId) {
|
|
304
|
-
url.searchParams.set("clientId", filter.clientId);
|
|
305
|
-
}
|
|
306
|
-
if (filter.mimeTypes) {
|
|
307
|
-
url.searchParams.set("mimeTypes", filter.mimeTypes.join());
|
|
308
|
-
}
|
|
309
|
-
if (filter.tags) {
|
|
310
|
-
url.searchParams.set("tags", filter.tags.join());
|
|
311
|
-
}
|
|
312
|
-
const res = await fetch(url.href, {
|
|
313
|
-
headers: this.apiHeaders,
|
|
314
|
-
});
|
|
315
|
-
return await res.json();
|
|
316
|
-
}
|
|
317
|
-
async deleteUpload(id) {
|
|
318
|
-
const res = await fetch(`${this._apiUrl}/uploads/${id}`, {
|
|
319
|
-
method: "DELETE",
|
|
320
|
-
headers: this.apiHeaders,
|
|
321
|
-
});
|
|
322
|
-
return await res.json();
|
|
323
|
-
}
|
|
324
|
-
async exposeScriptingContext(context) {
|
|
325
|
-
// @ts-ignore
|
|
326
|
-
window.KM_SCRIPTING_CONTEXT = context;
|
|
327
|
-
// @ts-ignore
|
|
328
|
-
window.dispatchEvent(new CustomEvent("km:scriptingContextExposed"));
|
|
329
|
-
}
|
|
330
|
-
async sendSubscriptionReq(roomName, mode) {
|
|
331
|
-
// Set up sync resolver
|
|
332
|
-
const reqId = ++this._messageId;
|
|
333
|
-
return await new Promise((resolve, reject) => {
|
|
334
|
-
this._subscribeReqPromises.set(reqId, {
|
|
335
|
-
resolve: (roomHash, initialUpdate) => {
|
|
336
|
-
resolve({ roomHash, initialUpdate });
|
|
337
|
-
},
|
|
338
|
-
reject,
|
|
339
|
-
});
|
|
340
|
-
// Send subscription request
|
|
341
|
-
const msg = new WsMessageWriter();
|
|
342
|
-
msg.writeInt32(WsMessageType.SubscribeReq);
|
|
343
|
-
msg.writeInt32(reqId);
|
|
344
|
-
msg.writeString(roomName);
|
|
345
|
-
msg.writeChar(mode);
|
|
346
|
-
this.ws.send(msg.getBuffer());
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
async join(store, mode = RoomSubscriptionMode.ReadWrite) {
|
|
350
|
-
let subscription = this._subscriptionsByName.get(store.roomName);
|
|
351
|
-
if (!subscription) {
|
|
352
|
-
subscription = new RoomSubscription(this, store, mode);
|
|
353
|
-
this._subscriptionsByName.set(store.roomName, subscription);
|
|
354
|
-
}
|
|
355
|
-
// Send subscription request if connected to server
|
|
356
|
-
if (!subscription.joined) {
|
|
357
|
-
const res = await this.sendSubscriptionReq(store.roomName, mode);
|
|
358
|
-
this._subscriptionsByHash.set(res.roomHash, subscription);
|
|
359
|
-
await subscription.applyInitialResponse(res.roomHash, res.initialUpdate);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
async transact(handler) {
|
|
363
|
-
if (!this._connected) {
|
|
364
|
-
throw new Error("Client not connected");
|
|
365
|
-
}
|
|
366
|
-
const transaction = new KokimokiTransaction(this);
|
|
367
|
-
handler(transaction);
|
|
368
|
-
const { updates, consumedMessages } = await transaction.getUpdates();
|
|
369
|
-
if (!updates.length) {
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
// Construct buffer
|
|
373
|
-
const writer = new WsMessageWriter();
|
|
374
|
-
// Write message type
|
|
375
|
-
writer.writeInt32(WsMessageType.Transaction);
|
|
376
|
-
// Update and write transaction ID
|
|
377
|
-
const transactionId = ++this._messageId;
|
|
378
|
-
writer.writeInt32(transactionId);
|
|
379
|
-
// Write room hashes where messages were consumed
|
|
380
|
-
writer.writeInt32(consumedMessages.size);
|
|
381
|
-
for (const roomName of consumedMessages) {
|
|
382
|
-
const subscription = this._subscriptionsByName.get(roomName);
|
|
383
|
-
if (!subscription) {
|
|
384
|
-
throw new Error(`Cannot consume message in "${roomName}" because it hasn't been joined`);
|
|
385
|
-
}
|
|
386
|
-
writer.writeUint32(subscription.roomHash);
|
|
387
|
-
}
|
|
388
|
-
// Write updates
|
|
389
|
-
for (const { roomName, update } of updates) {
|
|
390
|
-
const subscription = this._subscriptionsByName.get(roomName);
|
|
391
|
-
if (!subscription) {
|
|
392
|
-
throw new Error(`Cannot send update to "${roomName}" because it hasn't been joined`);
|
|
393
|
-
}
|
|
394
|
-
writer.writeUint32(subscription.roomHash);
|
|
395
|
-
writer.writeUint8Array(update);
|
|
396
|
-
}
|
|
397
|
-
const buffer = writer.getBuffer();
|
|
398
|
-
// Wait for server to apply transaction
|
|
399
|
-
await new Promise((resolve, reject) => {
|
|
400
|
-
this._transactionPromises.set(transactionId, { resolve, reject });
|
|
401
|
-
// Send update to server
|
|
402
|
-
try {
|
|
403
|
-
this.ws.send(buffer);
|
|
404
|
-
}
|
|
405
|
-
catch (e) {
|
|
406
|
-
// Not connected
|
|
407
|
-
console.log("Failed to send update to server:", e);
|
|
408
|
-
// TODO: merge updates or something
|
|
409
|
-
throw e;
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
/* // Reset doc in Write-only mode
|
|
413
|
-
for (const { roomName, update } of updates) {
|
|
414
|
-
const mode = this._subscriptions.get(roomName);
|
|
415
|
-
|
|
416
|
-
if (mode === RoomSubscriptionMode.Write) {
|
|
417
|
-
// @ts-ignore
|
|
418
|
-
// this._stores.get(this._roomHashes.get(roomName)!)!.doc = new Y.Doc();
|
|
419
|
-
}
|
|
420
|
-
} */
|
|
421
|
-
}
|
|
422
|
-
}
|
package/dist/message-queue.d.ts
DELETED
package/dist/message-queue.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import EventEmitter from "events";
|
|
2
|
-
import { SyncedStore } from "./synced-store";
|
|
3
|
-
import Y from "yjs";
|
|
4
|
-
export class MessageQueue extends SyncedStore {
|
|
5
|
-
name;
|
|
6
|
-
constructor(name) {
|
|
7
|
-
super({ messages: [] });
|
|
8
|
-
this.name = name;
|
|
9
|
-
}
|
|
10
|
-
async push(message) {
|
|
11
|
-
// Construct Y update to push the message to the queue
|
|
12
|
-
const id = crypto.randomUUID();
|
|
13
|
-
const ydoc = new Y.Doc();
|
|
14
|
-
const map = ydoc.getMap("messages");
|
|
15
|
-
map.set(id, message);
|
|
16
|
-
const update = Y.encodeStateAsUpdate(ydoc);
|
|
17
|
-
return update;
|
|
18
|
-
}
|
|
19
|
-
}
|
package/dist/synced-schema.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
export declare namespace S {
|
|
2
|
-
abstract class Generic<T> {
|
|
3
|
-
abstract get defaultValue(): T;
|
|
4
|
-
abstract set defaultValue(value: T);
|
|
5
|
-
}
|
|
6
|
-
class Number extends Generic<number> {
|
|
7
|
-
defaultValue: number;
|
|
8
|
-
constructor(defaultValue?: number);
|
|
9
|
-
}
|
|
10
|
-
function number(defaultValue?: number): Number;
|
|
11
|
-
class String extends Generic<string> {
|
|
12
|
-
defaultValue: string;
|
|
13
|
-
constructor(defaultValue?: string);
|
|
14
|
-
}
|
|
15
|
-
function string(defaultValue?: string): String;
|
|
16
|
-
class Boolean extends Generic<boolean> {
|
|
17
|
-
defaultValue: boolean;
|
|
18
|
-
constructor(defaultValue?: boolean);
|
|
19
|
-
}
|
|
20
|
-
function boolean(defaultValue?: boolean): Boolean;
|
|
21
|
-
class Struct<Data extends Record<string, Generic<unknown>>> extends Generic<{
|
|
22
|
-
[key in keyof Data]: Data[key]["defaultValue"];
|
|
23
|
-
}> {
|
|
24
|
-
fields: Data;
|
|
25
|
-
constructor(fields: Data);
|
|
26
|
-
get defaultValue(): {
|
|
27
|
-
[key in keyof Data]: Data[key]["defaultValue"];
|
|
28
|
-
};
|
|
29
|
-
set defaultValue(value: {
|
|
30
|
-
[key in keyof Data]: Data[key]["defaultValue"];
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
function struct<Data extends Record<string, Generic<unknown>>>(schema: Data): Struct<Data>;
|
|
34
|
-
class Dict<T extends Generic<unknown>> {
|
|
35
|
-
schema: T;
|
|
36
|
-
defaultValue: {
|
|
37
|
-
[key: string]: T["defaultValue"];
|
|
38
|
-
};
|
|
39
|
-
constructor(schema: T, defaultValue?: {
|
|
40
|
-
[key: string]: T["defaultValue"];
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
function dict<T extends Generic<unknown>>(schema: T, defaultValue?: {
|
|
44
|
-
[key: string]: T["defaultValue"];
|
|
45
|
-
}): Dict<T>;
|
|
46
|
-
class List<T extends Generic<unknown>> extends Generic<T["defaultValue"][]> {
|
|
47
|
-
schema: T;
|
|
48
|
-
defaultValue: T["defaultValue"][];
|
|
49
|
-
constructor(schema: T, defaultValue?: T["defaultValue"][]);
|
|
50
|
-
}
|
|
51
|
-
function list<T extends Generic<unknown>>(schema: T, defaultValue?: T["defaultValue"][]): List<T>;
|
|
52
|
-
}
|
package/dist/synced-schema.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
export var S;
|
|
2
|
-
(function (S) {
|
|
3
|
-
class Generic {
|
|
4
|
-
}
|
|
5
|
-
S.Generic = Generic;
|
|
6
|
-
class Number extends Generic {
|
|
7
|
-
defaultValue;
|
|
8
|
-
constructor(defaultValue = 0) {
|
|
9
|
-
super();
|
|
10
|
-
this.defaultValue = defaultValue;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
S.Number = Number;
|
|
14
|
-
function number(defaultValue = 0) {
|
|
15
|
-
return new Number(defaultValue);
|
|
16
|
-
}
|
|
17
|
-
S.number = number;
|
|
18
|
-
class String extends Generic {
|
|
19
|
-
defaultValue;
|
|
20
|
-
constructor(defaultValue = "") {
|
|
21
|
-
super();
|
|
22
|
-
this.defaultValue = defaultValue;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
S.String = String;
|
|
26
|
-
function string(defaultValue = "") {
|
|
27
|
-
return new String(defaultValue);
|
|
28
|
-
}
|
|
29
|
-
S.string = string;
|
|
30
|
-
class Boolean extends Generic {
|
|
31
|
-
defaultValue;
|
|
32
|
-
constructor(defaultValue = false) {
|
|
33
|
-
super();
|
|
34
|
-
this.defaultValue = defaultValue;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
S.Boolean = Boolean;
|
|
38
|
-
function boolean(defaultValue = false) {
|
|
39
|
-
return new Boolean(defaultValue);
|
|
40
|
-
}
|
|
41
|
-
S.boolean = boolean;
|
|
42
|
-
class Struct extends Generic {
|
|
43
|
-
fields;
|
|
44
|
-
constructor(fields) {
|
|
45
|
-
super();
|
|
46
|
-
this.fields = fields;
|
|
47
|
-
}
|
|
48
|
-
get defaultValue() {
|
|
49
|
-
return Object.entries(this.fields).reduce((acc, [key, field]) => {
|
|
50
|
-
acc[key] = field.defaultValue;
|
|
51
|
-
return acc;
|
|
52
|
-
}, {});
|
|
53
|
-
}
|
|
54
|
-
set defaultValue(value) {
|
|
55
|
-
for (const [key, field] of Object.entries(this.fields)) {
|
|
56
|
-
field.defaultValue = value[key];
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
S.Struct = Struct;
|
|
61
|
-
function struct(schema) {
|
|
62
|
-
return new Struct(schema);
|
|
63
|
-
}
|
|
64
|
-
S.struct = struct;
|
|
65
|
-
class Dict {
|
|
66
|
-
schema;
|
|
67
|
-
defaultValue;
|
|
68
|
-
constructor(schema, defaultValue = {}) {
|
|
69
|
-
this.schema = schema;
|
|
70
|
-
this.defaultValue = defaultValue;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
S.Dict = Dict;
|
|
74
|
-
function dict(schema, defaultValue = {}) {
|
|
75
|
-
return new Dict(schema, defaultValue);
|
|
76
|
-
}
|
|
77
|
-
S.dict = dict;
|
|
78
|
-
class List extends Generic {
|
|
79
|
-
schema;
|
|
80
|
-
defaultValue;
|
|
81
|
-
constructor(schema, defaultValue = []) {
|
|
82
|
-
super();
|
|
83
|
-
this.schema = schema;
|
|
84
|
-
this.defaultValue = defaultValue;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
S.List = List;
|
|
88
|
-
function list(schema, defaultValue = []) {
|
|
89
|
-
return new List(schema, defaultValue);
|
|
90
|
-
}
|
|
91
|
-
S.list = list;
|
|
92
|
-
})(S || (S = {}));
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type * as Y from "yjs";
|
|
2
|
-
import type { DocTypeDescription, MappedTypeDescription } from "@syncedstore/core/types/doc";
|
|
3
|
-
export declare class SyncedStore<T extends DocTypeDescription> {
|
|
4
|
-
readonly data: MappedTypeDescription<T>;
|
|
5
|
-
readonly doc: Y.Doc;
|
|
6
|
-
constructor(initialState: T);
|
|
7
|
-
}
|
package/dist/synced-store.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type * as Y from "yjs";
|
|
2
|
-
import type { DocTypeDescription, MappedTypeDescription } from "@syncedstore/core/types/doc";
|
|
3
|
-
export declare class SyncedStore<T extends DocTypeDescription> {
|
|
4
|
-
readonly data: MappedTypeDescription<T>;
|
|
5
|
-
readonly doc: Y.Doc;
|
|
6
|
-
constructor(initialState: T);
|
|
7
|
-
}
|
package/dist/synced-store.js
DELETED
package/dist/synced-types.d.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
export declare abstract class SyncedGeneric<T> {
|
|
2
|
-
abstract get defaultValue(): T;
|
|
3
|
-
abstract set defaultValue(value: T);
|
|
4
|
-
}
|
|
5
|
-
export declare class SyncedNumber extends SyncedGeneric<number> {
|
|
6
|
-
defaultValue: number;
|
|
7
|
-
constructor(defaultValue?: number);
|
|
8
|
-
}
|
|
9
|
-
export declare function syncedNumber(defaultValue?: number): SyncedNumber;
|
|
10
|
-
export declare class SyncedString extends SyncedGeneric<string> {
|
|
11
|
-
defaultValue: string;
|
|
12
|
-
constructor(defaultValue?: string);
|
|
13
|
-
}
|
|
14
|
-
export declare function syncedString(defaultValue?: string): SyncedString;
|
|
15
|
-
export declare class SyncedBoolean extends SyncedGeneric<boolean> {
|
|
16
|
-
defaultValue: boolean;
|
|
17
|
-
constructor(defaultValue?: boolean);
|
|
18
|
-
}
|
|
19
|
-
export declare function syncedBoolean(defaultValue?: boolean): SyncedBoolean;
|
|
20
|
-
export declare class SyncedMap<Data extends Record<string, SyncedGeneric<unknown>>> extends SyncedGeneric<{
|
|
21
|
-
[key in keyof Data]: Data[key]["defaultValue"];
|
|
22
|
-
}> {
|
|
23
|
-
fields: Data;
|
|
24
|
-
constructor(fields: Data);
|
|
25
|
-
get defaultValue(): {
|
|
26
|
-
[key in keyof Data]: Data[key]["defaultValue"];
|
|
27
|
-
};
|
|
28
|
-
set defaultValue(value: {
|
|
29
|
-
[key in keyof Data]: Data[key]["defaultValue"];
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
export declare function syncedMap<T extends Record<string, SyncedGeneric<unknown>>>(schema: T): SyncedMap<T>;
|
|
33
|
-
export declare class SyncedArray<T extends SyncedGeneric<unknown>> extends SyncedGeneric<T["defaultValue"][]> {
|
|
34
|
-
schema: T;
|
|
35
|
-
defaultValue: T["defaultValue"][];
|
|
36
|
-
constructor(schema: T, defaultValue?: T["defaultValue"][]);
|
|
37
|
-
}
|
|
38
|
-
export declare function syncedArray<T extends SyncedGeneric<unknown>>(schema: T, defaultValue?: T["defaultValue"][]): SyncedArray<T>;
|
|
39
|
-
export declare const S: {
|
|
40
|
-
number: typeof syncedNumber;
|
|
41
|
-
string: typeof syncedString;
|
|
42
|
-
boolean: typeof syncedBoolean;
|
|
43
|
-
map: typeof syncedMap;
|
|
44
|
-
array: typeof syncedArray;
|
|
45
|
-
};
|