@kokimoki/app 1.0.2 → 1.0.4
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-client-refactored.d.ts +10 -9
- package/dist/kokimoki-client-refactored.js +62 -90
- package/dist/kokimoki-schema.d.ts +20 -0
- package/dist/kokimoki-schema.js +43 -0
- package/dist/kokimoki-transaction.d.ts +1 -1
- package/dist/synced-schema.d.ts +56 -49
- package/dist/synced-schema.js +75 -83
- package/dist/synced-types.d.ts +0 -7
- package/dist/synced-types.js +3 -7
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/ws-message-type copy.d.ts +6 -0
- package/dist/{ws-message/ws-message-type.js → ws-message-type copy.js } +2 -0
- package/package.json +1 -1
- package/dist/kokimoki-client copy.d.ts +0 -57
- package/dist/kokimoki-client copy.js +0 -259
- package/dist/synced-store copy.d.ts +0 -7
- package/dist/synced-store copy.js +0 -9
- 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-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
|
@@ -4,10 +4,10 @@ import type { Upload } from "./types/upload";
|
|
|
4
4
|
import type { Paginated } from "./types/common";
|
|
5
5
|
import { KokimokiTransaction } from "./kokimoki-transaction";
|
|
6
6
|
import type { KokimokiStore } from "./kokimoki-store";
|
|
7
|
-
import type {
|
|
7
|
+
import type { SyncedGeneric } from "./synced-schema";
|
|
8
8
|
import { RoomSubscriptionMode } from "./room-subscription-mode";
|
|
9
|
-
declare const
|
|
10
|
-
export declare class
|
|
9
|
+
declare const KokimokiClientRefactored_base: new () => TypedEmitter<KokimokiClientEventsRefactored>;
|
|
10
|
+
export declare class KokimokiClientRefactored<ClientContextT = any> extends KokimokiClientRefactored_base {
|
|
11
11
|
readonly host: string;
|
|
12
12
|
readonly appId: string;
|
|
13
13
|
readonly code: string;
|
|
@@ -19,14 +19,15 @@ export declare class KokimokiClient<ClientContextT = any> extends KokimokiClient
|
|
|
19
19
|
private _serverTimeOffset;
|
|
20
20
|
private _clientContext?;
|
|
21
21
|
private _ws?;
|
|
22
|
-
private
|
|
23
|
-
private
|
|
24
|
-
private
|
|
25
|
-
private
|
|
22
|
+
private _subscriptions;
|
|
23
|
+
private _stores;
|
|
24
|
+
private _reqPromises;
|
|
25
|
+
private _transactionResolves;
|
|
26
|
+
private _roomHashes;
|
|
27
|
+
private _roomHashToDoc;
|
|
26
28
|
private _connected;
|
|
27
29
|
private _connectPromise?;
|
|
28
30
|
private _messageId;
|
|
29
|
-
private _reconnectTimeout;
|
|
30
31
|
constructor(host: string, appId: string, code?: string);
|
|
31
32
|
get id(): string;
|
|
32
33
|
get token(): string;
|
|
@@ -61,7 +62,7 @@ export declare class KokimokiClient<ClientContextT = any> extends KokimokiClient
|
|
|
61
62
|
}>;
|
|
62
63
|
exposeScriptingContext(context: any): Promise<void>;
|
|
63
64
|
private sendSubscriptionReq;
|
|
64
|
-
join<T extends
|
|
65
|
+
join<T extends SyncedGeneric<unknown>>(store: KokimokiStore<T>, mode?: RoomSubscriptionMode): Promise<void>;
|
|
65
66
|
transact(handler: (t: KokimokiTransaction) => void): Promise<void>;
|
|
66
67
|
}
|
|
67
68
|
export {};
|
|
@@ -6,8 +6,7 @@ import { WsMessageType } from "./ws-message-type";
|
|
|
6
6
|
import { WsMessageWriter } from "./ws-message-writer";
|
|
7
7
|
import { WsMessageReader } from "./ws-message-reader";
|
|
8
8
|
import { RoomSubscriptionMode } from "./room-subscription-mode";
|
|
9
|
-
|
|
10
|
-
export class KokimokiClient extends EventEmitter {
|
|
9
|
+
export class KokimokiClientRefactored extends EventEmitter {
|
|
11
10
|
host;
|
|
12
11
|
appId;
|
|
13
12
|
code;
|
|
@@ -19,14 +18,15 @@ export class KokimokiClient extends EventEmitter {
|
|
|
19
18
|
_serverTimeOffset = 0;
|
|
20
19
|
_clientContext;
|
|
21
20
|
_ws;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
_subscriptions = new Map();
|
|
22
|
+
_stores = new Map();
|
|
23
|
+
_reqPromises = new Map();
|
|
24
|
+
_transactionResolves = new Map();
|
|
25
|
+
_roomHashes = new Map();
|
|
26
|
+
_roomHashToDoc = new Map();
|
|
26
27
|
_connected = false;
|
|
27
28
|
_connectPromise;
|
|
28
29
|
_messageId = 0;
|
|
29
|
-
_reconnectTimeout = 0;
|
|
30
30
|
constructor(host, appId, code = "") {
|
|
31
31
|
super();
|
|
32
32
|
this.host = host;
|
|
@@ -82,17 +82,6 @@ export class KokimokiClient extends EventEmitter {
|
|
|
82
82
|
}
|
|
83
83
|
this._ws = new WebSocket(`${this._wsUrl}/apps/${this.appId}?clientVersion=${KOKIMOKI_APP_VERSION}`);
|
|
84
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
85
|
this._connectPromise = new Promise((onInit) => {
|
|
97
86
|
// Fetch the auth token
|
|
98
87
|
let clientToken = localStorage.getItem("KM_TOKEN");
|
|
@@ -104,18 +93,16 @@ export class KokimokiClient extends EventEmitter {
|
|
|
104
93
|
this._connected = false;
|
|
105
94
|
this._connectPromise = undefined;
|
|
106
95
|
this._ws = undefined;
|
|
107
|
-
if (window && window.__KOKIMOKI_WS__) {
|
|
108
|
-
delete window.__KOKIMOKI_WS__[this.appId];
|
|
109
|
-
}
|
|
110
96
|
// Clean up
|
|
111
|
-
this.
|
|
112
|
-
this.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
this._reconnectTimeout = Math.min(3, this._reconnectTimeout + 1);
|
|
97
|
+
this._reqPromises.clear();
|
|
98
|
+
this._transactionResolves.clear();
|
|
99
|
+
this._roomHashes.clear();
|
|
100
|
+
this._roomHashToDoc.clear();
|
|
101
|
+
this._subscriptions.clear();
|
|
117
102
|
// Emit disconnected event
|
|
118
103
|
this.emit("disconnected");
|
|
104
|
+
// Attempt to reconnect
|
|
105
|
+
// setTimeout(async () => await this.connect(), 2000);
|
|
119
106
|
};
|
|
120
107
|
this.ws.onmessage = (e) => {
|
|
121
108
|
console.log(`Received WS message: ${e.data}`);
|
|
@@ -140,26 +127,6 @@ export class KokimokiClient extends EventEmitter {
|
|
|
140
127
|
};
|
|
141
128
|
});
|
|
142
129
|
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
130
|
}
|
|
164
131
|
handleInitMessage(message) {
|
|
165
132
|
localStorage.setItem("KM_TOKEN", message.clientToken);
|
|
@@ -171,6 +138,8 @@ export class KokimokiClient extends EventEmitter {
|
|
|
171
138
|
Authorization: `Bearer ${this.token}`,
|
|
172
139
|
"Content-Type": "application/json",
|
|
173
140
|
});
|
|
141
|
+
this._connected = true;
|
|
142
|
+
this.emit("connected");
|
|
174
143
|
}
|
|
175
144
|
handleBinaryMessage(data) {
|
|
176
145
|
const reader = new WsMessageReader(data);
|
|
@@ -190,15 +159,10 @@ export class KokimokiClient extends EventEmitter {
|
|
|
190
159
|
handleErrorMessage(msg) {
|
|
191
160
|
const reqId = msg.readInt32();
|
|
192
161
|
const error = msg.readString();
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
subscribeReqPromise.reject(error);
|
|
198
|
-
}
|
|
199
|
-
else if (transactionPromise) {
|
|
200
|
-
this._transactionPromises.delete(reqId);
|
|
201
|
-
transactionPromise.reject(error);
|
|
162
|
+
const promise = this._reqPromises.get(reqId);
|
|
163
|
+
if (promise) {
|
|
164
|
+
this._reqPromises.delete(reqId);
|
|
165
|
+
promise.reject(error);
|
|
202
166
|
}
|
|
203
167
|
else {
|
|
204
168
|
console.warn(`Received error for unknown request ${reqId}: ${error}`);
|
|
@@ -207,9 +171,9 @@ export class KokimokiClient extends EventEmitter {
|
|
|
207
171
|
handleSubscribeResMessage(msg) {
|
|
208
172
|
const reqId = msg.readInt32();
|
|
209
173
|
const roomHash = msg.readUint32();
|
|
210
|
-
const promise = this.
|
|
174
|
+
const promise = this._reqPromises.get(reqId);
|
|
211
175
|
if (promise) {
|
|
212
|
-
this.
|
|
176
|
+
this._reqPromises.delete(reqId);
|
|
213
177
|
// In Write mode, no initial state is sent
|
|
214
178
|
if (!msg.end) {
|
|
215
179
|
promise.resolve(roomHash, msg.readUint8Array());
|
|
@@ -224,18 +188,18 @@ export class KokimokiClient extends EventEmitter {
|
|
|
224
188
|
const roomHash = msg.readUint32();
|
|
225
189
|
// Apply update if not in Write mode
|
|
226
190
|
if (!msg.end) {
|
|
227
|
-
const
|
|
228
|
-
if (
|
|
229
|
-
Y.applyUpdate(
|
|
191
|
+
const doc = this._roomHashToDoc.get(roomHash);
|
|
192
|
+
if (doc) {
|
|
193
|
+
Y.applyUpdate(doc, msg.readUint8Array(), this);
|
|
230
194
|
}
|
|
231
195
|
else {
|
|
232
196
|
console.warn(`Received update for unknown room ${roomHash}`);
|
|
233
197
|
}
|
|
234
198
|
}
|
|
235
199
|
// Check transaction resolves
|
|
236
|
-
for (const [transactionId,
|
|
200
|
+
for (const [transactionId, resolve,] of this._transactionResolves.entries()) {
|
|
237
201
|
if (appliedId >= transactionId) {
|
|
238
|
-
this.
|
|
202
|
+
this._transactionResolves.delete(transactionId);
|
|
239
203
|
resolve();
|
|
240
204
|
}
|
|
241
205
|
}
|
|
@@ -331,7 +295,7 @@ export class KokimokiClient extends EventEmitter {
|
|
|
331
295
|
// Set up sync resolver
|
|
332
296
|
const reqId = ++this._messageId;
|
|
333
297
|
return await new Promise((resolve, reject) => {
|
|
334
|
-
this.
|
|
298
|
+
this._reqPromises.set(reqId, {
|
|
335
299
|
resolve: (roomHash, initialUpdate) => {
|
|
336
300
|
resolve({ roomHash, initialUpdate });
|
|
337
301
|
},
|
|
@@ -347,25 +311,42 @@ export class KokimokiClient extends EventEmitter {
|
|
|
347
311
|
});
|
|
348
312
|
}
|
|
349
313
|
async join(store, mode = RoomSubscriptionMode.ReadWrite) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
subscription = new RoomSubscription(this, store, mode);
|
|
353
|
-
this._subscriptionsByName.set(store.roomName, subscription);
|
|
314
|
+
if (this._subscriptions.has(store.roomName)) {
|
|
315
|
+
throw new Error(`Already joined room "${store.roomName}"`);
|
|
354
316
|
}
|
|
355
|
-
|
|
356
|
-
|
|
317
|
+
this._subscriptions.set(store.roomName, mode);
|
|
318
|
+
// Send req
|
|
319
|
+
try {
|
|
357
320
|
const res = await this.sendSubscriptionReq(store.roomName, mode);
|
|
358
|
-
|
|
359
|
-
|
|
321
|
+
// Set room hash
|
|
322
|
+
this._roomHashes.set(store.roomName, res.roomHash);
|
|
323
|
+
this._roomHashToDoc.set(res.roomHash, store.doc);
|
|
324
|
+
this._stores.set(res.roomHash, store);
|
|
325
|
+
// Apply initial state
|
|
326
|
+
if (res.initialUpdate) {
|
|
327
|
+
Y.applyUpdate(store.doc, res.initialUpdate, this);
|
|
328
|
+
}
|
|
329
|
+
// Set defaults if doc is empty after sync (only possible in ReadWrite mode)
|
|
330
|
+
if (mode === RoomSubscriptionMode.ReadWrite) {
|
|
331
|
+
await this.transact((t) => {
|
|
332
|
+
for (const key in store.defaultValue) {
|
|
333
|
+
// @ts-ignore
|
|
334
|
+
if (!store.proxy.hasOwnProperty(key)) {
|
|
335
|
+
t.set(store.root[key], store.defaultValue[key]);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
catch (err) {
|
|
342
|
+
this._subscriptions.delete(store.roomName);
|
|
343
|
+
throw err;
|
|
360
344
|
}
|
|
361
345
|
}
|
|
362
346
|
async transact(handler) {
|
|
363
|
-
if (!this._connected) {
|
|
364
|
-
throw new Error("Client not connected");
|
|
365
|
-
}
|
|
366
347
|
const transaction = new KokimokiTransaction(this);
|
|
367
348
|
handler(transaction);
|
|
368
|
-
const
|
|
349
|
+
const updates = await transaction.getUpdates();
|
|
369
350
|
if (!updates.length) {
|
|
370
351
|
return;
|
|
371
352
|
}
|
|
@@ -376,28 +357,19 @@ export class KokimokiClient extends EventEmitter {
|
|
|
376
357
|
// Update and write transaction ID
|
|
377
358
|
const transactionId = ++this._messageId;
|
|
378
359
|
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
360
|
// Write updates
|
|
389
361
|
for (const { roomName, update } of updates) {
|
|
390
|
-
const
|
|
391
|
-
if (!
|
|
362
|
+
const roomHash = this._roomHashes.get(roomName);
|
|
363
|
+
if (!roomHash) {
|
|
392
364
|
throw new Error(`Cannot send update to "${roomName}" because it hasn't been joined`);
|
|
393
365
|
}
|
|
394
|
-
writer.writeUint32(
|
|
366
|
+
writer.writeUint32(roomHash);
|
|
395
367
|
writer.writeUint8Array(update);
|
|
396
368
|
}
|
|
397
369
|
const buffer = writer.getBuffer();
|
|
398
370
|
// Wait for server to apply transaction
|
|
399
|
-
await new Promise((resolve
|
|
400
|
-
this.
|
|
371
|
+
await new Promise((resolve) => {
|
|
372
|
+
this._transactionResolves.set(transactionId, resolve);
|
|
401
373
|
// Send update to server
|
|
402
374
|
try {
|
|
403
375
|
this.ws.send(buffer);
|
|
@@ -49,10 +49,30 @@ export declare namespace KokimokiSchema {
|
|
|
49
49
|
constructor(schema: T, defaultValue?: T["defaultValue"][]);
|
|
50
50
|
}
|
|
51
51
|
function list<T extends Generic<unknown>>(schema: T, defaultValue?: T["defaultValue"][]): List<T>;
|
|
52
|
+
/**
|
|
53
|
+
* Nullable
|
|
54
|
+
*/
|
|
52
55
|
class Nullable<T extends Generic<unknown>> extends Generic<T["defaultValue"] | null> {
|
|
53
56
|
schema: T;
|
|
54
57
|
defaultValue: T["defaultValue"] | null;
|
|
55
58
|
constructor(schema: T, defaultValue: T["defaultValue"] | null);
|
|
56
59
|
}
|
|
57
60
|
function nullable<T extends Generic<unknown>>(schema: T, defaultValue?: T["defaultValue"] | null): Nullable<T>;
|
|
61
|
+
class StringEnum<T extends readonly string[]> extends Generic<string> {
|
|
62
|
+
readonly options: T;
|
|
63
|
+
defaultValue: T[number];
|
|
64
|
+
constructor(options: T, defaultValue: T[number]);
|
|
65
|
+
}
|
|
66
|
+
function stringEnum<T extends readonly string[]>(options: T, defaultValue: T[number]): StringEnum<T>;
|
|
67
|
+
class StringConst<T extends string> extends Generic<string> {
|
|
68
|
+
readonly defaultValue: T;
|
|
69
|
+
constructor(defaultValue: T);
|
|
70
|
+
}
|
|
71
|
+
function stringConst<T extends string>(defaultValue: T): StringConst<T>;
|
|
72
|
+
class AnyOf<T extends readonly Generic<unknown>[]> extends Generic<T[number]["defaultValue"]> {
|
|
73
|
+
readonly schemas: T;
|
|
74
|
+
defaultValue: T[number]["defaultValue"];
|
|
75
|
+
constructor(schemas: T, defaultValue: T[number]["defaultValue"]);
|
|
76
|
+
}
|
|
77
|
+
function anyOf<T extends readonly Generic<unknown>[]>(schemas: T, defaultValue: T[number]["defaultValue"]): AnyOf<T>;
|
|
58
78
|
}
|
package/dist/kokimoki-schema.js
CHANGED
|
@@ -89,6 +89,9 @@ export var KokimokiSchema;
|
|
|
89
89
|
return new List(schema, defaultValue);
|
|
90
90
|
}
|
|
91
91
|
KokimokiSchema.list = list;
|
|
92
|
+
/**
|
|
93
|
+
* Nullable
|
|
94
|
+
*/
|
|
92
95
|
class Nullable extends Generic {
|
|
93
96
|
schema;
|
|
94
97
|
defaultValue;
|
|
@@ -103,4 +106,44 @@ export var KokimokiSchema;
|
|
|
103
106
|
return new Nullable(schema, defaultValue);
|
|
104
107
|
}
|
|
105
108
|
KokimokiSchema.nullable = nullable;
|
|
109
|
+
class StringEnum extends Generic {
|
|
110
|
+
options;
|
|
111
|
+
defaultValue;
|
|
112
|
+
constructor(options, defaultValue) {
|
|
113
|
+
super();
|
|
114
|
+
this.options = options;
|
|
115
|
+
this.defaultValue = defaultValue;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
KokimokiSchema.StringEnum = StringEnum;
|
|
119
|
+
function stringEnum(options, defaultValue) {
|
|
120
|
+
return new StringEnum(options, defaultValue);
|
|
121
|
+
}
|
|
122
|
+
KokimokiSchema.stringEnum = stringEnum;
|
|
123
|
+
class StringConst extends Generic {
|
|
124
|
+
defaultValue;
|
|
125
|
+
constructor(defaultValue) {
|
|
126
|
+
super();
|
|
127
|
+
this.defaultValue = defaultValue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
KokimokiSchema.StringConst = StringConst;
|
|
131
|
+
function stringConst(defaultValue) {
|
|
132
|
+
return new StringConst(defaultValue);
|
|
133
|
+
}
|
|
134
|
+
KokimokiSchema.stringConst = stringConst;
|
|
135
|
+
class AnyOf extends Generic {
|
|
136
|
+
schemas;
|
|
137
|
+
defaultValue;
|
|
138
|
+
constructor(schemas, defaultValue) {
|
|
139
|
+
super();
|
|
140
|
+
this.schemas = schemas;
|
|
141
|
+
this.defaultValue = defaultValue;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
KokimokiSchema.AnyOf = AnyOf;
|
|
145
|
+
function anyOf(schemas, defaultValue) {
|
|
146
|
+
return new AnyOf(schemas, defaultValue);
|
|
147
|
+
}
|
|
148
|
+
KokimokiSchema.anyOf = anyOf;
|
|
106
149
|
})(KokimokiSchema || (KokimokiSchema = {}));
|
|
@@ -10,7 +10,7 @@ export declare class KokimokiTransaction {
|
|
|
10
10
|
private _parseTarget;
|
|
11
11
|
private _parsePath;
|
|
12
12
|
private _getClone;
|
|
13
|
-
get<T>(target: T):
|
|
13
|
+
get<T>(target: T): T;
|
|
14
14
|
set<T>(target: T, value: T): void;
|
|
15
15
|
delete<T>(target: T): void;
|
|
16
16
|
push<T>(target: T[], value: T): void;
|
package/dist/synced-schema.d.ts
CHANGED
|
@@ -1,52 +1,59 @@
|
|
|
1
|
-
export declare
|
|
2
|
-
abstract
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
+
declare function syncedNumber(defaultValue?: number): SyncedNumber;
|
|
10
|
+
export declare class SyncedString extends SyncedGeneric<string> {
|
|
11
|
+
defaultValue: string;
|
|
12
|
+
constructor(defaultValue?: string);
|
|
13
|
+
}
|
|
14
|
+
declare function syncedString(defaultValue?: string): SyncedString;
|
|
15
|
+
export declare class SyncedBoolean extends SyncedGeneric<boolean> {
|
|
16
|
+
defaultValue: boolean;
|
|
17
|
+
constructor(defaultValue?: boolean);
|
|
18
|
+
}
|
|
19
|
+
declare function syncedBoolean(defaultValue?: boolean): SyncedBoolean;
|
|
20
|
+
export declare class SyncedObject<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(): {
|
|
22
26
|
[key in keyof Data]: Data[key]["defaultValue"];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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?: {
|
|
27
|
+
};
|
|
28
|
+
set defaultValue(value: {
|
|
29
|
+
[key in keyof Data]: Data[key]["defaultValue"];
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
declare function syncedObject<Data extends Record<string, SyncedGeneric<unknown>>>(schema: Data): SyncedObject<Data>;
|
|
33
|
+
export declare class SyncedMap<T extends SyncedGeneric<unknown>> {
|
|
34
|
+
schema: T;
|
|
35
|
+
defaultValue: {
|
|
44
36
|
[key: string]: T["defaultValue"];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
};
|
|
38
|
+
constructor(schema: T, defaultValue?: {
|
|
39
|
+
[key: string]: T["defaultValue"];
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
declare function syncedMap<T extends SyncedGeneric<unknown>>(schema: T, defaultValue?: {
|
|
43
|
+
[key: string]: T["defaultValue"];
|
|
44
|
+
}): SyncedMap<T>;
|
|
45
|
+
export declare class SyncedArray<T extends SyncedGeneric<unknown>> extends SyncedGeneric<T["defaultValue"][]> {
|
|
46
|
+
schema: T;
|
|
47
|
+
defaultValue: T["defaultValue"][];
|
|
48
|
+
constructor(schema: T, defaultValue?: T["defaultValue"][]);
|
|
52
49
|
}
|
|
50
|
+
declare function syncedArray<T extends SyncedGeneric<unknown>>(schema: T, defaultValue?: T["defaultValue"][]): SyncedArray<T>;
|
|
51
|
+
export declare const S: {
|
|
52
|
+
number: typeof syncedNumber;
|
|
53
|
+
string: typeof syncedString;
|
|
54
|
+
boolean: typeof syncedBoolean;
|
|
55
|
+
object: typeof syncedObject;
|
|
56
|
+
map: typeof syncedMap;
|
|
57
|
+
array: typeof syncedArray;
|
|
58
|
+
};
|
|
59
|
+
export {};
|
package/dist/synced-schema.js
CHANGED
|
@@ -1,92 +1,84 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export class SyncedGeneric {
|
|
2
|
+
}
|
|
3
|
+
export class SyncedNumber extends SyncedGeneric {
|
|
4
|
+
defaultValue;
|
|
5
|
+
constructor(defaultValue = 0) {
|
|
6
|
+
super();
|
|
7
|
+
this.defaultValue = defaultValue;
|
|
4
8
|
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
}
|
|
9
|
+
}
|
|
10
|
+
function syncedNumber(defaultValue = 0) {
|
|
11
|
+
return new SyncedNumber(defaultValue);
|
|
12
|
+
}
|
|
13
|
+
export class SyncedString extends SyncedGeneric {
|
|
14
|
+
defaultValue;
|
|
15
|
+
constructor(defaultValue = "") {
|
|
16
|
+
super();
|
|
17
|
+
this.defaultValue = defaultValue;
|
|
36
18
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
19
|
+
}
|
|
20
|
+
function syncedString(defaultValue = "") {
|
|
21
|
+
return new SyncedString(defaultValue);
|
|
22
|
+
}
|
|
23
|
+
export class SyncedBoolean extends SyncedGeneric {
|
|
24
|
+
defaultValue;
|
|
25
|
+
constructor(defaultValue = false) {
|
|
26
|
+
super();
|
|
27
|
+
this.defaultValue = defaultValue;
|
|
40
28
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
}
|
|
29
|
+
}
|
|
30
|
+
function syncedBoolean(defaultValue = false) {
|
|
31
|
+
return new SyncedBoolean(defaultValue);
|
|
32
|
+
}
|
|
33
|
+
export class SyncedObject extends SyncedGeneric {
|
|
34
|
+
fields;
|
|
35
|
+
constructor(fields) {
|
|
36
|
+
super();
|
|
37
|
+
this.fields = fields;
|
|
59
38
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
39
|
+
get defaultValue() {
|
|
40
|
+
return Object.entries(this.fields).reduce((acc, [key, field]) => {
|
|
41
|
+
acc[key] = field.defaultValue;
|
|
42
|
+
return acc;
|
|
43
|
+
}, {});
|
|
63
44
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
defaultValue;
|
|
68
|
-
constructor(schema, defaultValue = {}) {
|
|
69
|
-
this.schema = schema;
|
|
70
|
-
this.defaultValue = defaultValue;
|
|
45
|
+
set defaultValue(value) {
|
|
46
|
+
for (const [key, field] of Object.entries(this.fields)) {
|
|
47
|
+
field.defaultValue = value[key];
|
|
71
48
|
}
|
|
72
49
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.schema = schema;
|
|
84
|
-
this.defaultValue = defaultValue;
|
|
85
|
-
}
|
|
50
|
+
}
|
|
51
|
+
function syncedObject(schema) {
|
|
52
|
+
return new SyncedObject(schema);
|
|
53
|
+
}
|
|
54
|
+
export class SyncedMap {
|
|
55
|
+
schema;
|
|
56
|
+
defaultValue;
|
|
57
|
+
constructor(schema, defaultValue = {}) {
|
|
58
|
+
this.schema = schema;
|
|
59
|
+
this.defaultValue = defaultValue;
|
|
86
60
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
61
|
+
}
|
|
62
|
+
function syncedMap(schema, defaultValue = {}) {
|
|
63
|
+
return new SyncedMap(schema, defaultValue);
|
|
64
|
+
}
|
|
65
|
+
export class SyncedArray extends SyncedGeneric {
|
|
66
|
+
schema;
|
|
67
|
+
defaultValue;
|
|
68
|
+
constructor(schema, defaultValue = []) {
|
|
69
|
+
super();
|
|
70
|
+
this.schema = schema;
|
|
71
|
+
this.defaultValue = defaultValue;
|
|
90
72
|
}
|
|
91
|
-
|
|
92
|
-
|
|
73
|
+
}
|
|
74
|
+
function syncedArray(schema, defaultValue = []) {
|
|
75
|
+
return new SyncedArray(schema, defaultValue);
|
|
76
|
+
}
|
|
77
|
+
export const S = {
|
|
78
|
+
number: syncedNumber,
|
|
79
|
+
string: syncedString,
|
|
80
|
+
boolean: syncedBoolean,
|
|
81
|
+
object: syncedObject,
|
|
82
|
+
map: syncedMap,
|
|
83
|
+
array: syncedArray,
|
|
84
|
+
};
|
package/dist/synced-types.d.ts
CHANGED
|
@@ -36,10 +36,3 @@ export declare class SyncedArray<T extends SyncedGeneric<unknown>> extends Synce
|
|
|
36
36
|
constructor(schema: T, defaultValue?: T["defaultValue"][]);
|
|
37
37
|
}
|
|
38
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
|
-
};
|
package/dist/synced-types.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import * as Y from "yjs";
|
|
2
|
+
import { proxy as yjsProxy } from "valtio";
|
|
3
|
+
import { bind as yjsBind } from "valtio-yjs";
|
|
1
4
|
export class SyncedGeneric {
|
|
2
5
|
}
|
|
3
6
|
export class SyncedNumber extends SyncedGeneric {
|
|
@@ -63,10 +66,3 @@ export class SyncedArray extends SyncedGeneric {
|
|
|
63
66
|
export function syncedArray(schema, defaultValue = []) {
|
|
64
67
|
return new SyncedArray(schema, defaultValue);
|
|
65
68
|
}
|
|
66
|
-
export const S = {
|
|
67
|
-
number: syncedNumber,
|
|
68
|
-
string: syncedString,
|
|
69
|
-
boolean: syncedBoolean,
|
|
70
|
-
map: syncedMap,
|
|
71
|
-
array: syncedArray,
|
|
72
|
-
};
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const KOKIMOKI_APP_VERSION = "1.0.
|
|
1
|
+
export declare const KOKIMOKI_APP_VERSION = "1.0.4";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const KOKIMOKI_APP_VERSION = "1.0.
|
|
1
|
+
export const KOKIMOKI_APP_VERSION = "1.0.4";
|
|
@@ -2,4 +2,6 @@ export var WsMessageType;
|
|
|
2
2
|
(function (WsMessageType) {
|
|
3
3
|
WsMessageType[WsMessageType["SubscribeReq"] = 1] = "SubscribeReq";
|
|
4
4
|
WsMessageType[WsMessageType["SubscribeRes"] = 2] = "SubscribeRes";
|
|
5
|
+
WsMessageType[WsMessageType["Transaction"] = 3] = "Transaction";
|
|
6
|
+
WsMessageType[WsMessageType["RoomUpdate"] = 4] = "RoomUpdate";
|
|
5
7
|
})(WsMessageType || (WsMessageType = {}));
|
package/package.json
CHANGED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { HocuspocusProvider } from "@hocuspocus/provider";
|
|
2
|
-
import type TypedEmitter from "typed-emitter";
|
|
3
|
-
import type { SyncedStore } from "./synced-store";
|
|
4
|
-
import type { DocTypeDescription } from "@syncedstore/core/types/doc";
|
|
5
|
-
import type { KokimokiClientEvents } from "./types/events";
|
|
6
|
-
import type { Upload } from "./types/upload";
|
|
7
|
-
import type { Paginated } from "./types/common";
|
|
8
|
-
declare const KokimokiClient_base: new <T>() => TypedEmitter<KokimokiClientEvents<T>>;
|
|
9
|
-
export declare class KokimokiClient<StatelessDataT = any, ClientContextT = any> extends KokimokiClient_base<StatelessDataT> {
|
|
10
|
-
readonly host: string;
|
|
11
|
-
readonly appId: string;
|
|
12
|
-
readonly code: string;
|
|
13
|
-
private _wsUrl;
|
|
14
|
-
private _apiUrl;
|
|
15
|
-
private _id?;
|
|
16
|
-
private _token?;
|
|
17
|
-
private _apiHeaders?;
|
|
18
|
-
private _providers;
|
|
19
|
-
private _serverTimeOffset;
|
|
20
|
-
private _clientContext?;
|
|
21
|
-
private _connected;
|
|
22
|
-
private _lastPongAt;
|
|
23
|
-
constructor(host: string, appId: string, code?: string);
|
|
24
|
-
get id(): string;
|
|
25
|
-
get token(): string;
|
|
26
|
-
get apiUrl(): string;
|
|
27
|
-
get apiHeaders(): Headers;
|
|
28
|
-
get clientContext(): ClientContextT & ({} | null);
|
|
29
|
-
connect(): Promise<void>;
|
|
30
|
-
serverTimestamp(): number;
|
|
31
|
-
private receivePong;
|
|
32
|
-
private checkConnectionState;
|
|
33
|
-
setProvider<T extends DocTypeDescription>(name: string, store: SyncedStore<T>): Promise<void>;
|
|
34
|
-
removeProvider(name: string): void;
|
|
35
|
-
getProvider(name: string): HocuspocusProvider | undefined;
|
|
36
|
-
sendStatelessToClient(room: string, clientId: string, data: StatelessDataT): void;
|
|
37
|
-
sendStatelessToRoom(room: string, data: StatelessDataT, self?: boolean): void;
|
|
38
|
-
patchRoomState(room: string, update: Uint8Array): Promise<any>;
|
|
39
|
-
private createUpload;
|
|
40
|
-
private uploadChunks;
|
|
41
|
-
private completeUpload;
|
|
42
|
-
upload(name: string, blob: Blob, tags?: string[]): Promise<Upload>;
|
|
43
|
-
updateUpload(id: string, update: {
|
|
44
|
-
tags?: string[];
|
|
45
|
-
}): Promise<Upload>;
|
|
46
|
-
listUploads(filter?: {
|
|
47
|
-
clientId?: string;
|
|
48
|
-
mimeTypes?: string[];
|
|
49
|
-
tags?: string[];
|
|
50
|
-
}, skip?: number, limit?: number): Promise<Paginated<Upload>>;
|
|
51
|
-
deleteUpload(id: string): Promise<{
|
|
52
|
-
acknowledged: boolean;
|
|
53
|
-
deletedCount: number;
|
|
54
|
-
}>;
|
|
55
|
-
exposeScriptingContext(context: any): Promise<void>;
|
|
56
|
-
}
|
|
57
|
-
export {};
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import { HocuspocusProvider } from "@hocuspocus/provider";
|
|
2
|
-
import EventEmitter from "events";
|
|
3
|
-
import { KOKIMOKI_APP_VERSION } from "./version";
|
|
4
|
-
export class KokimokiClient extends EventEmitter {
|
|
5
|
-
host;
|
|
6
|
-
appId;
|
|
7
|
-
code;
|
|
8
|
-
_wsUrl;
|
|
9
|
-
_apiUrl;
|
|
10
|
-
_id;
|
|
11
|
-
_token;
|
|
12
|
-
_apiHeaders;
|
|
13
|
-
_providers = new Map();
|
|
14
|
-
_serverTimeOffset = 0;
|
|
15
|
-
_clientContext;
|
|
16
|
-
_connected = false;
|
|
17
|
-
_lastPongAt = 0;
|
|
18
|
-
constructor(host, appId, code = "") {
|
|
19
|
-
super();
|
|
20
|
-
this.host = host;
|
|
21
|
-
this.appId = appId;
|
|
22
|
-
this.code = code;
|
|
23
|
-
// Set up the URLs
|
|
24
|
-
const secure = this.host.indexOf(":") === -1;
|
|
25
|
-
this._wsUrl = `ws${secure ? "s" : ""}://${this.host}`;
|
|
26
|
-
this._apiUrl = `http${secure ? "s" : ""}://${this.host}`;
|
|
27
|
-
}
|
|
28
|
-
get id() {
|
|
29
|
-
if (!this._id) {
|
|
30
|
-
throw new Error("Client not connected");
|
|
31
|
-
}
|
|
32
|
-
return this._id;
|
|
33
|
-
}
|
|
34
|
-
get token() {
|
|
35
|
-
if (!this._token) {
|
|
36
|
-
throw new Error("Client not connected");
|
|
37
|
-
}
|
|
38
|
-
return this._token;
|
|
39
|
-
}
|
|
40
|
-
get apiUrl() {
|
|
41
|
-
if (!this._apiUrl) {
|
|
42
|
-
throw new Error("Client not connected");
|
|
43
|
-
}
|
|
44
|
-
return this._apiUrl;
|
|
45
|
-
}
|
|
46
|
-
get apiHeaders() {
|
|
47
|
-
if (!this._apiHeaders) {
|
|
48
|
-
throw new Error("Client not connected");
|
|
49
|
-
}
|
|
50
|
-
return this._apiHeaders;
|
|
51
|
-
}
|
|
52
|
-
get clientContext() {
|
|
53
|
-
if (this._clientContext === undefined) {
|
|
54
|
-
throw new Error("Client not connected");
|
|
55
|
-
}
|
|
56
|
-
return this._clientContext;
|
|
57
|
-
}
|
|
58
|
-
async connect() {
|
|
59
|
-
// Fetch the auth token
|
|
60
|
-
let clientToken = localStorage.getItem("KM_TOKEN");
|
|
61
|
-
const startTime = Date.now();
|
|
62
|
-
const res = await fetch(`${this.apiUrl}/auth/token?appId=${this.appId}&code=${this.code}&clientVersion=${KOKIMOKI_APP_VERSION}`, {
|
|
63
|
-
method: "GET",
|
|
64
|
-
headers: new Headers({
|
|
65
|
-
"Content-Type": "application/json",
|
|
66
|
-
Authorization: `Bearer ${clientToken}`,
|
|
67
|
-
}),
|
|
68
|
-
});
|
|
69
|
-
const { clientId, appToken, serverTime, token, clientContext } = await res.json();
|
|
70
|
-
const endTime = Date.now();
|
|
71
|
-
const ping = Math.round((endTime - startTime) / 2);
|
|
72
|
-
this._id = clientId;
|
|
73
|
-
this._token = appToken;
|
|
74
|
-
this._serverTimeOffset = Date.now() - serverTime - ping;
|
|
75
|
-
this._clientContext = clientContext;
|
|
76
|
-
localStorage.setItem("KM_TOKEN", token);
|
|
77
|
-
// Set up the auth headers
|
|
78
|
-
this._apiHeaders = new Headers({
|
|
79
|
-
Authorization: `Bearer ${this.token}`,
|
|
80
|
-
"Content-Type": "application/json",
|
|
81
|
-
});
|
|
82
|
-
// Ping interval
|
|
83
|
-
setInterval(() => {
|
|
84
|
-
this._providers.forEach((provider) => provider.sendStateless("ping"));
|
|
85
|
-
}, 5000);
|
|
86
|
-
// Connection state interval
|
|
87
|
-
setInterval(() => {
|
|
88
|
-
this.checkConnectionState();
|
|
89
|
-
}, 1000);
|
|
90
|
-
// Check initial connected state
|
|
91
|
-
this.receivePong();
|
|
92
|
-
}
|
|
93
|
-
serverTimestamp() {
|
|
94
|
-
return Date.now() - this._serverTimeOffset;
|
|
95
|
-
}
|
|
96
|
-
receivePong() {
|
|
97
|
-
this._lastPongAt = Date.now();
|
|
98
|
-
this.checkConnectionState();
|
|
99
|
-
}
|
|
100
|
-
checkConnectionState() {
|
|
101
|
-
const connected = this._providers.size === 0 || Date.now() - this._lastPongAt < 6000;
|
|
102
|
-
if (connected && !this._connected) {
|
|
103
|
-
this._connected = true;
|
|
104
|
-
this.emit("connected");
|
|
105
|
-
}
|
|
106
|
-
else if (!connected && this._connected) {
|
|
107
|
-
this._connected = false;
|
|
108
|
-
this.emit("disconnected");
|
|
109
|
-
// Reset connections to providers
|
|
110
|
-
this._providers.forEach(async (provider) => {
|
|
111
|
-
provider.disconnect();
|
|
112
|
-
await provider.connect();
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
// Realtime database
|
|
117
|
-
async setProvider(name, store) {
|
|
118
|
-
const provider = new HocuspocusProvider({
|
|
119
|
-
url: `${this._wsUrl}/connection`,
|
|
120
|
-
name: `${this.appId}/${name}`,
|
|
121
|
-
document: store.doc,
|
|
122
|
-
token: this.token,
|
|
123
|
-
parameters: {
|
|
124
|
-
clientVersion: KOKIMOKI_APP_VERSION,
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
// Handle incoming stateless messages
|
|
128
|
-
provider.on("stateless", (e) => {
|
|
129
|
-
if (e.payload === "pong") {
|
|
130
|
-
this.receivePong();
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
const payload = JSON.parse(e.payload);
|
|
134
|
-
this.emit("stateless", name, payload.from, payload.data);
|
|
135
|
-
});
|
|
136
|
-
// Wait for initial sync
|
|
137
|
-
await new Promise((resolve) => {
|
|
138
|
-
const handler = () => {
|
|
139
|
-
provider.off("synced", handler);
|
|
140
|
-
resolve();
|
|
141
|
-
};
|
|
142
|
-
provider.on("synced", handler);
|
|
143
|
-
});
|
|
144
|
-
this._lastPongAt = Date.now();
|
|
145
|
-
this._providers.set(name, provider);
|
|
146
|
-
this.checkConnectionState();
|
|
147
|
-
}
|
|
148
|
-
removeProvider(name) {
|
|
149
|
-
const provider = this._providers.get(name);
|
|
150
|
-
if (!provider) {
|
|
151
|
-
throw new Error(`No provider for room ${name}`);
|
|
152
|
-
}
|
|
153
|
-
provider.destroy();
|
|
154
|
-
this._providers.delete(name);
|
|
155
|
-
// Connection state can change if the removed provider was not connected or synced
|
|
156
|
-
this.checkConnectionState();
|
|
157
|
-
}
|
|
158
|
-
getProvider(name) {
|
|
159
|
-
return this._providers.get(name);
|
|
160
|
-
}
|
|
161
|
-
sendStatelessToClient(room, clientId, data) {
|
|
162
|
-
const provider = this._providers.get(room);
|
|
163
|
-
if (!provider) {
|
|
164
|
-
throw new Error(`No provider for room ${room}`);
|
|
165
|
-
}
|
|
166
|
-
provider.sendStateless(JSON.stringify({ to: clientId, data }));
|
|
167
|
-
}
|
|
168
|
-
sendStatelessToRoom(room, data, self = false) {
|
|
169
|
-
const provider = this._providers.get(room);
|
|
170
|
-
if (!provider) {
|
|
171
|
-
throw new Error(`No provider for room ${room}`);
|
|
172
|
-
}
|
|
173
|
-
provider.sendStateless(JSON.stringify({ data, self }));
|
|
174
|
-
}
|
|
175
|
-
// Send Y update to room
|
|
176
|
-
async patchRoomState(room, update) {
|
|
177
|
-
const res = await fetch(`${this._apiUrl}/rooms/${room}`, {
|
|
178
|
-
method: "PATCH",
|
|
179
|
-
headers: this.apiHeaders,
|
|
180
|
-
body: update,
|
|
181
|
-
});
|
|
182
|
-
return await res.json();
|
|
183
|
-
}
|
|
184
|
-
// Storage
|
|
185
|
-
async createUpload(name, blob, tags) {
|
|
186
|
-
const res = await fetch(`${this._apiUrl}/uploads`, {
|
|
187
|
-
method: "POST",
|
|
188
|
-
headers: this.apiHeaders,
|
|
189
|
-
body: JSON.stringify({
|
|
190
|
-
name,
|
|
191
|
-
size: blob.size,
|
|
192
|
-
mimeType: blob.type,
|
|
193
|
-
tags,
|
|
194
|
-
}),
|
|
195
|
-
});
|
|
196
|
-
return await res.json();
|
|
197
|
-
}
|
|
198
|
-
async uploadChunks(blob, chunkSize, signedUrls) {
|
|
199
|
-
return await Promise.all(signedUrls.map(async (url, index) => {
|
|
200
|
-
const start = index * chunkSize;
|
|
201
|
-
const end = Math.min(start + chunkSize, blob.size);
|
|
202
|
-
const chunk = blob.slice(start, end);
|
|
203
|
-
const res = await fetch(url, { method: "PUT", body: chunk });
|
|
204
|
-
return JSON.parse(res.headers.get("ETag") || '""');
|
|
205
|
-
}));
|
|
206
|
-
}
|
|
207
|
-
async completeUpload(id, etags) {
|
|
208
|
-
const res = await fetch(`${this._apiUrl}/uploads/${id}`, {
|
|
209
|
-
method: "PUT",
|
|
210
|
-
headers: this.apiHeaders,
|
|
211
|
-
body: JSON.stringify({ etags }),
|
|
212
|
-
});
|
|
213
|
-
return await res.json();
|
|
214
|
-
}
|
|
215
|
-
async upload(name, blob, tags = []) {
|
|
216
|
-
const { id, chunkSize, urls } = await this.createUpload(name, blob, tags);
|
|
217
|
-
const etags = await this.uploadChunks(blob, chunkSize, urls);
|
|
218
|
-
return await this.completeUpload(id, etags);
|
|
219
|
-
}
|
|
220
|
-
async updateUpload(id, update) {
|
|
221
|
-
const res = await fetch(`${this._apiUrl}/uploads/${id}`, {
|
|
222
|
-
method: "PUT",
|
|
223
|
-
headers: this.apiHeaders,
|
|
224
|
-
body: JSON.stringify(update),
|
|
225
|
-
});
|
|
226
|
-
return await res.json();
|
|
227
|
-
}
|
|
228
|
-
async listUploads(filter = {}, skip = 0, limit = 100) {
|
|
229
|
-
const url = new URL("/uploads", this._apiUrl);
|
|
230
|
-
url.searchParams.set("skip", skip.toString());
|
|
231
|
-
url.searchParams.set("limit", limit.toString());
|
|
232
|
-
if (filter.clientId) {
|
|
233
|
-
url.searchParams.set("clientId", filter.clientId);
|
|
234
|
-
}
|
|
235
|
-
if (filter.mimeTypes) {
|
|
236
|
-
url.searchParams.set("mimeTypes", filter.mimeTypes.join());
|
|
237
|
-
}
|
|
238
|
-
if (filter.tags) {
|
|
239
|
-
url.searchParams.set("tags", filter.tags.join());
|
|
240
|
-
}
|
|
241
|
-
const res = await fetch(url.href, {
|
|
242
|
-
headers: this.apiHeaders,
|
|
243
|
-
});
|
|
244
|
-
return await res.json();
|
|
245
|
-
}
|
|
246
|
-
async deleteUpload(id) {
|
|
247
|
-
const res = await fetch(`${this._apiUrl}/uploads/${id}`, {
|
|
248
|
-
method: "DELETE",
|
|
249
|
-
headers: this.apiHeaders,
|
|
250
|
-
});
|
|
251
|
-
return await res.json();
|
|
252
|
-
}
|
|
253
|
-
async exposeScriptingContext(context) {
|
|
254
|
-
// @ts-ignore
|
|
255
|
-
window.KM_SCRIPTING_CONTEXT = context;
|
|
256
|
-
// @ts-ignore
|
|
257
|
-
window.dispatchEvent(new CustomEvent("km:scriptingContextExposed"));
|
|
258
|
-
}
|
|
259
|
-
}
|
|
@@ -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/ws-message/index.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export class WsMessageReader {
|
|
2
|
-
buffer;
|
|
3
|
-
type;
|
|
4
|
-
_view;
|
|
5
|
-
_offset = 0;
|
|
6
|
-
constructor(buffer) {
|
|
7
|
-
this.buffer = buffer;
|
|
8
|
-
// Read the first 4 bytes as the message type
|
|
9
|
-
this._view = new DataView(buffer);
|
|
10
|
-
this.type = this.readInt32();
|
|
11
|
-
}
|
|
12
|
-
readInt32() {
|
|
13
|
-
const value = this._view.getInt32(this._offset, true);
|
|
14
|
-
this._offset += 4;
|
|
15
|
-
return value;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { WsMessageType } from "./ws-message-type";
|
|
2
|
-
export declare class WsMessageWriter {
|
|
3
|
-
type: WsMessageType;
|
|
4
|
-
payloadLength: number;
|
|
5
|
-
private _buffer;
|
|
6
|
-
private _view;
|
|
7
|
-
private _offset;
|
|
8
|
-
constructor(type: WsMessageType, payloadLength: number);
|
|
9
|
-
writeInt32(value: number): void;
|
|
10
|
-
writeString(value: string): void;
|
|
11
|
-
get buffer(): ArrayBuffer;
|
|
12
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export class WsMessageWriter {
|
|
2
|
-
type;
|
|
3
|
-
payloadLength;
|
|
4
|
-
_buffer;
|
|
5
|
-
_view;
|
|
6
|
-
_offset = 0;
|
|
7
|
-
constructor(type, payloadLength) {
|
|
8
|
-
this.type = type;
|
|
9
|
-
this.payloadLength = payloadLength;
|
|
10
|
-
this._buffer = new ArrayBuffer(4 + payloadLength);
|
|
11
|
-
this._view = new DataView(this._buffer);
|
|
12
|
-
// Write type
|
|
13
|
-
this.writeInt32(type);
|
|
14
|
-
}
|
|
15
|
-
writeInt32(value) {
|
|
16
|
-
this._view.setInt32(this._offset, value, true);
|
|
17
|
-
this._offset += 4;
|
|
18
|
-
}
|
|
19
|
-
writeString(value) {
|
|
20
|
-
// Write length
|
|
21
|
-
this.writeInt32(value.length);
|
|
22
|
-
// Write chars
|
|
23
|
-
for (let i = 0; i < value.length; i++) {
|
|
24
|
-
this._view.setUint8(this._offset++, value.charCodeAt(i));
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
get buffer() {
|
|
28
|
-
return this._buffer;
|
|
29
|
-
}
|
|
30
|
-
}
|
package/dist/ws-message.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export declare enum WsMessageType {
|
|
2
|
-
Subscribe = 1
|
|
3
|
-
}
|
|
4
|
-
export declare class WsMessage {
|
|
5
|
-
type: WsMessageType;
|
|
6
|
-
payloadLength: number;
|
|
7
|
-
private _buffer;
|
|
8
|
-
private _view;
|
|
9
|
-
private _offset;
|
|
10
|
-
constructor(type: WsMessageType, payloadLength: number);
|
|
11
|
-
writeInt32(value: number): void;
|
|
12
|
-
writeString(value: string): void;
|
|
13
|
-
get buffer(): ArrayBuffer;
|
|
14
|
-
}
|
package/dist/ws-message.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export var WsMessageType;
|
|
2
|
-
(function (WsMessageType) {
|
|
3
|
-
WsMessageType[WsMessageType["Subscribe"] = 1] = "Subscribe";
|
|
4
|
-
})(WsMessageType || (WsMessageType = {}));
|
|
5
|
-
export class WsMessage {
|
|
6
|
-
type;
|
|
7
|
-
payloadLength;
|
|
8
|
-
_buffer;
|
|
9
|
-
_view;
|
|
10
|
-
_offset = 0;
|
|
11
|
-
constructor(type, payloadLength) {
|
|
12
|
-
this.type = type;
|
|
13
|
-
this.payloadLength = payloadLength;
|
|
14
|
-
this._buffer = new ArrayBuffer(4 + payloadLength);
|
|
15
|
-
this._view = new DataView(this._buffer);
|
|
16
|
-
// Write type
|
|
17
|
-
this.writeInt32(type);
|
|
18
|
-
}
|
|
19
|
-
writeInt32(value) {
|
|
20
|
-
this._view.setInt32(this._offset, value, true);
|
|
21
|
-
this._offset += 4;
|
|
22
|
-
}
|
|
23
|
-
writeString(value) {
|
|
24
|
-
// Write length
|
|
25
|
-
this.writeInt32(value.length);
|
|
26
|
-
// Write chars
|
|
27
|
-
for (let i = 0; i < value.length; i++) {
|
|
28
|
-
this._view.setUint8(this._offset++, value.charCodeAt(i));
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
get buffer() {
|
|
32
|
-
return this._buffer;
|
|
33
|
-
}
|
|
34
|
-
}
|