@meshagent/meshagent 0.3.1 → 0.4.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/browser/entrypoint.js +7956 -5611
  3. package/dist/browser/helpers.d.ts +10 -4
  4. package/dist/browser/helpers.js +14 -39
  5. package/dist/browser/index.d.ts +1 -0
  6. package/dist/browser/index.js +1 -0
  7. package/dist/browser/participant-token.d.ts +4 -4
  8. package/dist/browser/participant-token.js +4 -9
  9. package/dist/browser/protocol.d.ts +5 -1
  10. package/dist/browser/protocol.js +7 -2
  11. package/dist/browser/room-client.d.ts +4 -1
  12. package/dist/browser/room-client.js +2 -2
  13. package/dist/browser/sync-client.d.ts +5 -1
  14. package/dist/browser/sync-client.js +13 -2
  15. package/dist/esm/agent-client.d.ts +88 -0
  16. package/dist/esm/agent-client.js +166 -0
  17. package/dist/esm/agent.d.ts +103 -0
  18. package/dist/esm/agent.js +218 -0
  19. package/dist/esm/client.d.ts +90 -0
  20. package/dist/esm/client.js +443 -0
  21. package/dist/esm/completer.d.ts +9 -0
  22. package/dist/esm/completer.js +21 -0
  23. package/dist/esm/data-types.d.ts +44 -0
  24. package/dist/esm/data-types.js +110 -0
  25. package/dist/esm/database-client.d.ts +77 -0
  26. package/dist/esm/database-client.js +109 -0
  27. package/dist/esm/developer-client.d.ts +13 -0
  28. package/dist/esm/developer-client.js +31 -0
  29. package/dist/esm/document.d.ts +84 -0
  30. package/dist/esm/document.js +522 -0
  31. package/dist/esm/entrypoint.d.ts +49722 -0
  32. package/dist/esm/entrypoint.js +6313 -0
  33. package/dist/esm/event-emitter.d.ts +13 -0
  34. package/dist/esm/event-emitter.js +34 -0
  35. package/dist/esm/helpers.d.ts +32 -0
  36. package/dist/esm/helpers.js +46 -0
  37. package/dist/esm/index.d.ts +25 -0
  38. package/dist/esm/index.js +25 -0
  39. package/dist/esm/messaging-client.d.ts +76 -0
  40. package/dist/esm/messaging-client.js +241 -0
  41. package/dist/esm/participant-token.d.ts +36 -0
  42. package/dist/esm/participant-token.js +91 -0
  43. package/dist/esm/participant.d.ts +18 -0
  44. package/dist/esm/participant.js +36 -0
  45. package/dist/esm/protocol.d.ts +91 -0
  46. package/dist/esm/protocol.js +287 -0
  47. package/dist/esm/queues-client.d.ts +26 -0
  48. package/dist/esm/queues-client.js +42 -0
  49. package/dist/esm/requirement.d.ts +25 -0
  50. package/dist/esm/requirement.js +42 -0
  51. package/dist/esm/response.d.ts +60 -0
  52. package/dist/esm/response.js +128 -0
  53. package/dist/esm/room-client.d.ts +46 -0
  54. package/dist/esm/room-client.js +106 -0
  55. package/dist/esm/room-event.d.ts +60 -0
  56. package/dist/esm/room-event.js +72 -0
  57. package/dist/esm/room-server-client.d.ts +19 -0
  58. package/dist/esm/room-server-client.js +45 -0
  59. package/dist/esm/runtime.d.ts +6 -0
  60. package/dist/esm/runtime.js +1 -0
  61. package/dist/esm/schema.d.ts +83 -0
  62. package/dist/esm/schema.js +312 -0
  63. package/dist/esm/storage-client.d.ts +38 -0
  64. package/dist/esm/storage-client.js +79 -0
  65. package/dist/esm/stream-controller.d.ts +8 -0
  66. package/dist/esm/stream-controller.js +51 -0
  67. package/dist/esm/sync-client.d.ts +37 -0
  68. package/dist/esm/sync-client.js +125 -0
  69. package/dist/esm/utils.d.ts +14 -0
  70. package/dist/esm/utils.js +44 -0
  71. package/dist/node/entrypoint.js +9 -4
  72. package/dist/node/helpers.d.ts +10 -4
  73. package/dist/node/helpers.js +14 -39
  74. package/dist/node/index.d.ts +1 -0
  75. package/dist/node/index.js +1 -0
  76. package/dist/node/participant-token.d.ts +4 -4
  77. package/dist/node/participant-token.js +4 -9
  78. package/dist/node/protocol.d.ts +5 -1
  79. package/dist/node/protocol.js +7 -2
  80. package/dist/node/room-client.d.ts +4 -1
  81. package/dist/node/room-client.js +2 -2
  82. package/dist/node/sync-client.d.ts +5 -1
  83. package/dist/node/sync-client.js +13 -2
  84. package/package.json +4 -3
@@ -0,0 +1,312 @@
1
+ export class MeshSchemaValidationException extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "MeshSchemaValidationException";
5
+ }
6
+ }
7
+ export var SimpleValue;
8
+ (function (SimpleValue) {
9
+ SimpleValue["number"] = "number";
10
+ SimpleValue["string"] = "string";
11
+ SimpleValue["nullValue"] = "null";
12
+ SimpleValue["boolean"] = "boolean";
13
+ })(SimpleValue || (SimpleValue = {}));
14
+ (function (SimpleValue) {
15
+ function fromString(val) {
16
+ switch (val) {
17
+ case "number":
18
+ return SimpleValue.number;
19
+ case "string":
20
+ return SimpleValue.string;
21
+ case "null":
22
+ return SimpleValue.nullValue;
23
+ case "boolean":
24
+ return SimpleValue.boolean;
25
+ default:
26
+ return null;
27
+ }
28
+ }
29
+ SimpleValue.fromString = fromString;
30
+ })(SimpleValue || (SimpleValue = {}));
31
+ export class ElementProperty {
32
+ constructor({ name, description }) {
33
+ this.name = name;
34
+ this.description = description;
35
+ }
36
+ }
37
+ export class ValueProperty extends ElementProperty {
38
+ constructor({ name, description, type, enumValues }) {
39
+ super({ name, description });
40
+ this.type = type;
41
+ this.enumValues = enumValues;
42
+ }
43
+ validate(_) {
44
+ }
45
+ toJson() {
46
+ const obj = {
47
+ [this.name]: {
48
+ type: this.type,
49
+ },
50
+ };
51
+ if (this.description) {
52
+ obj[this.name].description = this.description;
53
+ }
54
+ if (this.enumValues) {
55
+ obj[this.name].enum = this.enumValues;
56
+ }
57
+ return obj;
58
+ }
59
+ }
60
+ export class ChildProperty extends ElementProperty {
61
+ constructor({ name, description, childTagNames, ordered = false }) {
62
+ super({ name, description });
63
+ this._childTagNames = childTagNames;
64
+ this.ordered = ordered;
65
+ }
66
+ validate(schema) {
67
+ for (const item of this._childTagNames) {
68
+ schema.element(item);
69
+ }
70
+ }
71
+ isTagAllowed(tagName) {
72
+ return this._childTagNames.includes(tagName);
73
+ }
74
+ get childTagNames() {
75
+ return this._childTagNames;
76
+ }
77
+ toJson() {
78
+ const base = {};
79
+ if (this.description) {
80
+ base["description"] = this.description;
81
+ }
82
+ if (this.ordered) {
83
+ return {
84
+ [this.name]: {
85
+ ...base,
86
+ type: "array",
87
+ prefixItems: this._childTagNames.map((p) => ({ $ref: `#/$defs/${p}` })),
88
+ items: false,
89
+ },
90
+ };
91
+ }
92
+ else {
93
+ return {
94
+ [this.name]: {
95
+ ...base,
96
+ type: "array",
97
+ items: {
98
+ anyOf: this._childTagNames.map((p) => ({ $ref: `#/$defs/${p}` })),
99
+ },
100
+ },
101
+ };
102
+ }
103
+ }
104
+ }
105
+ export class ElementType {
106
+ constructor(params) {
107
+ this._propertyLookup = new Map();
108
+ this._tagName = params.tagName;
109
+ this._description = params.description;
110
+ this._properties = [...params.properties];
111
+ for (const p of this._properties) {
112
+ if (p instanceof ChildProperty) {
113
+ if (this._childPropertyName) {
114
+ throw new MeshSchemaValidationException("Only one child property is allowed");
115
+ }
116
+ this._childPropertyName = p.name;
117
+ }
118
+ if (this._propertyLookup.has(p.name)) {
119
+ throw new MeshSchemaValidationException(`Duplicate property ${p.name}`);
120
+ }
121
+ this._propertyLookup.set(p.name, p);
122
+ }
123
+ }
124
+ static fromJson(json) {
125
+ const description = json["description"];
126
+ const propertiesMap = json["properties"];
127
+ if (!propertiesMap || Object.keys(propertiesMap).length === 0) {
128
+ throw new MeshSchemaValidationException("Invalid schema json: no properties found");
129
+ }
130
+ const [tagName, typeJson] = Object.entries(propertiesMap)[0];
131
+ if (!typeJson || typeof typeJson !== "object") {
132
+ throw new MeshSchemaValidationException("typeJson must be an object");
133
+ }
134
+ const innerProps = typeJson["properties"];
135
+ const resultProps = [];
136
+ for (const [propName, pVal] of Object.entries(innerProps)) {
137
+ const pMap = pVal;
138
+ const propDescription = pMap["description"];
139
+ const pType = pMap["type"];
140
+ if (pType === "array") {
141
+ if (pMap["prefixItems"]) {
142
+ const prefixItems = pMap["prefixItems"];
143
+ const childTagNames = [];
144
+ for (const refObj of prefixItems) {
145
+ const refStr = refObj["$ref"];
146
+ const prefix = "#/$defs/";
147
+ const childTagName = refStr.startsWith(prefix)
148
+ ? refStr.substring(prefix.length)
149
+ : refStr;
150
+ childTagNames.push(childTagName);
151
+ }
152
+ resultProps.push(new ChildProperty({
153
+ name: propName,
154
+ description: propDescription,
155
+ childTagNames,
156
+ ordered: true,
157
+ }));
158
+ }
159
+ else if (pMap["items"] &&
160
+ typeof pMap["items"] === "object" &&
161
+ pMap["items"]["anyOf"]) {
162
+ const anyOf = pMap["items"]["anyOf"];
163
+ const childTagNames = [];
164
+ for (const refObj of anyOf) {
165
+ const refStr = refObj["$ref"];
166
+ const prefix = "#/$defs/";
167
+ const childTagName = refStr.startsWith(prefix)
168
+ ? refStr.substring(prefix.length)
169
+ : refStr;
170
+ childTagNames.push(childTagName);
171
+ }
172
+ resultProps.push(new ChildProperty({
173
+ name: propName,
174
+ description: propDescription,
175
+ childTagNames,
176
+ ordered: false,
177
+ }));
178
+ }
179
+ else {
180
+ throw new MeshSchemaValidationException("Invalid array type encountered");
181
+ }
182
+ }
183
+ else {
184
+ const valTypeStr = pType;
185
+ const valType = SimpleValue.fromString(valTypeStr);
186
+ if (!valType) {
187
+ throw new MeshSchemaValidationException(`Invalid value type: ${valTypeStr}`);
188
+ }
189
+ const enumVal = pMap["enum"];
190
+ resultProps.push(new ValueProperty({
191
+ name: propName,
192
+ description: propDescription,
193
+ type: valType,
194
+ enumValues: enumVal,
195
+ }));
196
+ }
197
+ }
198
+ return new ElementType({ tagName, description, properties: resultProps });
199
+ }
200
+ toJson() {
201
+ const props = {};
202
+ const required = [];
203
+ for (const p of this._properties) {
204
+ required.push(p.name);
205
+ const pJson = p.toJson();
206
+ const propValue = pJson[p.name];
207
+ props[p.name] = propValue;
208
+ }
209
+ return {
210
+ type: "object",
211
+ additionalProperties: false,
212
+ description: this._description,
213
+ required: [this._tagName],
214
+ properties: {
215
+ [this._tagName]: {
216
+ type: "object",
217
+ additionalProperties: false,
218
+ required,
219
+ properties: props,
220
+ },
221
+ },
222
+ };
223
+ }
224
+ validate(schema) {
225
+ for (const p of this._properties) {
226
+ p.validate(schema);
227
+ }
228
+ }
229
+ get childPropertyName() {
230
+ return this._childPropertyName;
231
+ }
232
+ get tagName() {
233
+ return this._tagName;
234
+ }
235
+ get description() {
236
+ return this._description;
237
+ }
238
+ get properties() {
239
+ return this._properties;
240
+ }
241
+ property(name) {
242
+ const found = this._propertyLookup.get(name);
243
+ if (!found) {
244
+ throw new Error(`Property is not in schema: ${name}`);
245
+ }
246
+ return found;
247
+ }
248
+ }
249
+ export class MeshSchema {
250
+ constructor(params) {
251
+ this.elementsByTagName = {};
252
+ const { rootTagName, elements } = params;
253
+ this._rootTagName = rootTagName;
254
+ this._elements = elements;
255
+ for (const t of elements) {
256
+ if (this.elementsByTagName[t.tagName]) {
257
+ throw new MeshSchemaValidationException(`${t.tagName} was found more than once`);
258
+ }
259
+ this.elementsByTagName[t.tagName] = t;
260
+ }
261
+ if (!this.elementsByTagName[rootTagName]) {
262
+ throw new MeshSchemaValidationException(`${rootTagName} was not found in tags`);
263
+ }
264
+ this.validate();
265
+ }
266
+ static fromJson(json) {
267
+ const elements = [];
268
+ const rootTagRef = json["$root_tag_ref"];
269
+ const prefix = "#/$defs/";
270
+ const rootTagName = rootTagRef.startsWith(prefix)
271
+ ? rootTagRef.substring(prefix.length)
272
+ : rootTagRef;
273
+ const defs = json["$defs"];
274
+ for (const elementJson of Object.values(defs)) {
275
+ elements.push(ElementType.fromJson(elementJson));
276
+ }
277
+ return new MeshSchema({ rootTagName, elements });
278
+ }
279
+ toJson() {
280
+ const defs = {};
281
+ for (const t of this._elements) {
282
+ defs[t.tagName] = t.toJson();
283
+ }
284
+ const rootElementJson = this.root.toJson();
285
+ const result = {
286
+ "$root_tag_ref": `#/$defs/${this._rootTagName}`,
287
+ "$defs": defs,
288
+ };
289
+ for (const [k, v] of Object.entries(rootElementJson)) {
290
+ result[k] = v;
291
+ }
292
+ return result;
293
+ }
294
+ element(name) {
295
+ const el = this.elementsByTagName[name];
296
+ if (!el) {
297
+ throw new MeshSchemaValidationException(`Element not found: ${name}`);
298
+ }
299
+ return el;
300
+ }
301
+ validate() {
302
+ for (const e of this._elements) {
303
+ e.validate(this);
304
+ }
305
+ }
306
+ get root() {
307
+ return this.elementsByTagName[this._rootTagName];
308
+ }
309
+ get elements() {
310
+ return this._elements;
311
+ }
312
+ }
@@ -0,0 +1,38 @@
1
+ import { RoomClient } from "./room-client";
2
+ import { RoomEvent } from "./room-event";
3
+ import { FileResponse } from "./response";
4
+ import { EventEmitter } from "./event-emitter";
5
+ export declare class FileHandle {
6
+ id: number;
7
+ constructor({ id }: {
8
+ id: number;
9
+ });
10
+ }
11
+ declare class StorageEntry {
12
+ name: string;
13
+ isFolder: boolean;
14
+ constructor({ name, isFolder }: {
15
+ name: string;
16
+ isFolder: boolean;
17
+ });
18
+ nameWithoutExtension(): string;
19
+ }
20
+ export declare class StorageClient extends EventEmitter<RoomEvent> {
21
+ private client;
22
+ constructor({ room }: {
23
+ room: RoomClient;
24
+ });
25
+ private _handleFileUpdated;
26
+ private _handleFileDeleted;
27
+ list(path: string): Promise<StorageEntry[]>;
28
+ delete(path: string): Promise<void>;
29
+ open(path: string, { overwrite }: {
30
+ overwrite: boolean;
31
+ }): Promise<FileHandle>;
32
+ exists(path: string): Promise<boolean>;
33
+ write(handle: FileHandle, bytes: Uint8Array): Promise<void>;
34
+ close(handle: FileHandle): Promise<void>;
35
+ download(path: string): Promise<FileResponse>;
36
+ downloadUrl(path: string): Promise<string>;
37
+ }
38
+ export {};
@@ -0,0 +1,79 @@
1
+ import { FileDeletedEvent, FileUpdatedEvent } from "./room-event";
2
+ import { unpackMessage } from "./utils";
3
+ import { EventEmitter } from "./event-emitter";
4
+ export class FileHandle {
5
+ constructor({ id }) {
6
+ this.id = id;
7
+ }
8
+ }
9
+ class StorageEntry {
10
+ constructor({ name, isFolder }) {
11
+ this.name = name;
12
+ this.isFolder = isFolder;
13
+ }
14
+ nameWithoutExtension() {
15
+ const segments = this.name
16
+ .replace(/^\/+/, '')
17
+ .replace(/\/+$/, '')
18
+ .split(/\/+/);
19
+ return (segments[segments.length - 1] || "")
20
+ .replace(/\.[^/.]+$/, "");
21
+ }
22
+ }
23
+ export class StorageClient extends EventEmitter {
24
+ constructor({ room }) {
25
+ super();
26
+ this.client = room;
27
+ this.client.protocol.addHandler("storage.file.deleted", this._handleFileDeleted.bind(this));
28
+ this.client.protocol.addHandler("storage.file.updated", this._handleFileUpdated.bind(this));
29
+ }
30
+ async _handleFileUpdated(protocol, messageId, type, bytes) {
31
+ const [data, _] = unpackMessage(bytes || new Uint8Array());
32
+ const event = new FileUpdatedEvent({ path: data["path"] });
33
+ this.client.emit(event);
34
+ this.emit('file.updated', event);
35
+ }
36
+ async _handleFileDeleted(protocol, messageId, type, bytes) {
37
+ const [data, _] = unpackMessage(bytes || new Uint8Array());
38
+ const event = new FileDeletedEvent({ path: data["path"] });
39
+ this.client.emit(event);
40
+ this.emit('file.deleted', event);
41
+ }
42
+ async list(path) {
43
+ const response = (await this.client.sendRequest("storage.list", { path }));
44
+ const files = response.json["files"];
45
+ const entries = files.map((f) => {
46
+ return new StorageEntry({
47
+ name: f["name"],
48
+ isFolder: f["is_folder"],
49
+ });
50
+ });
51
+ entries.sort((a, b) => a.name.localeCompare(b.name));
52
+ return entries;
53
+ }
54
+ async delete(path) {
55
+ await this.client.sendRequest("storage.delete", { path });
56
+ }
57
+ async open(path, { overwrite = false }) {
58
+ const response = (await this.client.sendRequest("storage.open", { path, overwrite }));
59
+ return new FileHandle({ id: response.json["handle"] });
60
+ }
61
+ async exists(path) {
62
+ const result = (await this.client.sendRequest("storage.exists", { path }));
63
+ return result.json["exists"];
64
+ }
65
+ async write(handle, bytes) {
66
+ await this.client.sendRequest("storage.write", { handle: handle.id }, bytes);
67
+ }
68
+ async close(handle) {
69
+ await this.client.sendRequest("storage.close", { handle: handle.id });
70
+ }
71
+ async download(path) {
72
+ const response = (await this.client.sendRequest("storage.download", { path }));
73
+ return response;
74
+ }
75
+ async downloadUrl(path) {
76
+ const response = (await this.client.sendRequest("storage.download_url", { path }));
77
+ return response.json["url"];
78
+ }
79
+ }
@@ -0,0 +1,8 @@
1
+ export declare class StreamController<T> {
2
+ private closed;
3
+ get stream(): AsyncIterable<T>;
4
+ private queue;
5
+ private waiters;
6
+ add(value: T): void;
7
+ close(): void;
8
+ }
@@ -0,0 +1,51 @@
1
+ export class StreamController {
2
+ constructor() {
3
+ this.closed = false;
4
+ this.queue = [];
5
+ this.waiters = [];
6
+ }
7
+ get stream() {
8
+ const self = this;
9
+ return {
10
+ [Symbol.asyncIterator]() {
11
+ return {
12
+ async next() {
13
+ if (self.queue.length > 0) {
14
+ return {
15
+ done: false,
16
+ value: self.queue.shift()
17
+ };
18
+ }
19
+ if (self.closed) {
20
+ return {
21
+ done: true,
22
+ value: undefined
23
+ };
24
+ }
25
+ return new Promise((resolve) => {
26
+ self.waiters.push(resolve);
27
+ });
28
+ },
29
+ };
30
+ },
31
+ };
32
+ }
33
+ add(value) {
34
+ if (this.closed)
35
+ return;
36
+ if (this.waiters.length > 0) {
37
+ const waiter = this.waiters.shift();
38
+ waiter({ done: false, value });
39
+ }
40
+ else {
41
+ this.queue.push(value);
42
+ }
43
+ }
44
+ close() {
45
+ this.closed = true;
46
+ while (this.waiters.length > 0) {
47
+ const waiter = this.waiters.shift();
48
+ waiter({ done: true, value: undefined });
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,37 @@
1
+ import { EventEmitter } from "./event-emitter";
2
+ import { RoomClient } from "./room-client";
3
+ import { MeshDocument } from "./room-server-client";
4
+ export interface SyncClientEvent {
5
+ type: string;
6
+ doc: MeshDocument;
7
+ }
8
+ export declare class QueuedSync {
9
+ path: string;
10
+ base64: string;
11
+ constructor({ path, base64 }: {
12
+ path: string;
13
+ base64: string;
14
+ });
15
+ }
16
+ export declare class SyncClient extends EventEmitter<SyncClientEvent> {
17
+ private client;
18
+ private _connectingDocuments;
19
+ private _changesToSync;
20
+ private _connectedDocuments;
21
+ constructor({ room }: {
22
+ room: RoomClient;
23
+ });
24
+ start({ onDone, onError }?: {
25
+ onDone?: () => void;
26
+ onError?: (error: Error) => void;
27
+ }): void;
28
+ dispose(): void;
29
+ private _handleSync;
30
+ private _handleStatus;
31
+ create(path: string, json?: Record<string, any>): Promise<void>;
32
+ open(path: string, { create }?: {
33
+ create?: boolean;
34
+ }): Promise<MeshDocument>;
35
+ close(path: string): Promise<void>;
36
+ sync(path: string, data: Uint8Array): Promise<void>;
37
+ }
@@ -0,0 +1,125 @@
1
+ import { EventEmitter } from "./event-emitter";
2
+ import { MeshSchema } from "./schema";
3
+ import { StreamController } from "./stream-controller";
4
+ import { MeshDocument, RoomServerException } from "./room-server-client";
5
+ import { splitMessageHeader, splitMessagePayload, decoder, encoder, RefCount } from "./utils";
6
+ import { unregisterDocument, applyBackendChanges } from "./runtime";
7
+ import { Completer } from "./completer";
8
+ ;
9
+ export class QueuedSync {
10
+ constructor({ path, base64 }) {
11
+ this.path = path;
12
+ this.base64 = base64;
13
+ }
14
+ }
15
+ export class SyncClient extends EventEmitter {
16
+ constructor({ room }) {
17
+ super();
18
+ this._connectingDocuments = {};
19
+ this._changesToSync = new StreamController();
20
+ this._connectedDocuments = {};
21
+ this.client = room;
22
+ this.client.protocol.addHandler("room.sync", this._handleSync.bind(this));
23
+ this.client.protocol.addHandler("room.status", this._handleStatus.bind(this));
24
+ }
25
+ start({ onDone, onError } = {}) {
26
+ this.client.protocol.start({ onDone, onError });
27
+ (async () => {
28
+ for await (const message of this._changesToSync.stream) {
29
+ await this.client.sendRequest("room.sync", { path: message.path }, encoder.encode(message.base64));
30
+ }
31
+ })();
32
+ }
33
+ dispose() {
34
+ super.dispose();
35
+ this._changesToSync.close();
36
+ }
37
+ async _handleSync(protocol, messageId, data, bytes) {
38
+ const headerStr = splitMessageHeader(bytes || new Uint8Array());
39
+ const payload = splitMessagePayload(bytes || new Uint8Array());
40
+ const header = JSON.parse(headerStr);
41
+ const path = header["path"];
42
+ const isConnecting = this._connectingDocuments[path];
43
+ if (isConnecting) {
44
+ await isConnecting;
45
+ }
46
+ if (this._connectedDocuments[path]) {
47
+ const rc = this._connectedDocuments[path];
48
+ const doc = rc.ref;
49
+ const base64 = decoder.decode(payload);
50
+ applyBackendChanges(doc.id, base64);
51
+ this.emit("synced", { type: "sync", doc });
52
+ if (!doc.isSynchronized) {
53
+ doc.setSynchronizedComplete();
54
+ }
55
+ }
56
+ else {
57
+ throw new RoomServerException(`received change for a document that is not connected: ${path}`);
58
+ }
59
+ }
60
+ async _handleStatus(protocol, messageId, data, bytes) {
61
+ const headerStr = splitMessageHeader(bytes || new Uint8Array());
62
+ const header = JSON.parse(headerStr);
63
+ this.emit("status", header.status);
64
+ }
65
+ async create(path, json) {
66
+ await this.client.sendRequest("room.create", { path, json });
67
+ }
68
+ async open(path, { create = true } = {}) {
69
+ const pending = this._connectingDocuments[path];
70
+ if (pending) {
71
+ await pending;
72
+ }
73
+ if (this._connectedDocuments[path]) {
74
+ const rc = this._connectedDocuments[path];
75
+ rc.count++;
76
+ return rc.ref;
77
+ }
78
+ const c = new Completer();
79
+ this._connectingDocuments[path] = c.fut;
80
+ try {
81
+ const result = (await this.client.sendRequest("room.connect", { path, create }));
82
+ const schema = MeshSchema.fromJson(result.json["schema"]);
83
+ const doc = new MeshDocument({
84
+ schema,
85
+ sendChangesToBackend: (base64Str) => {
86
+ this._changesToSync.add({ path, base64: base64Str });
87
+ },
88
+ });
89
+ const rc = new RefCount(doc);
90
+ this._connectedDocuments[path] = rc;
91
+ this.emit("connected", { type: "connect", doc });
92
+ c.complete();
93
+ return doc;
94
+ }
95
+ catch (err) {
96
+ c.completeError(err);
97
+ throw err;
98
+ }
99
+ finally {
100
+ delete this._connectingDocuments[path];
101
+ }
102
+ }
103
+ async close(path) {
104
+ const pending = this._connectingDocuments[path];
105
+ if (pending) {
106
+ await pending;
107
+ await new Promise(resolve => setTimeout(resolve, 50));
108
+ }
109
+ const rc = this._connectedDocuments[path];
110
+ if (!rc) {
111
+ throw new RoomServerException(`Not connected to ${path}`);
112
+ }
113
+ const doc = rc.ref;
114
+ rc.count--;
115
+ if (rc.count === 0) {
116
+ delete this._connectedDocuments[path];
117
+ await this.client.sendRequest("room.disconnect", { path });
118
+ unregisterDocument(doc.id);
119
+ }
120
+ this.emit("closed", { type: "close", doc });
121
+ }
122
+ async sync(path, data) {
123
+ await this.client.sendRequest("room.sync", { path }, data);
124
+ }
125
+ }
@@ -0,0 +1,14 @@
1
+ import { TextDecoder, TextEncoder } from "@kayahr/text-encoding";
2
+ declare const encoder: TextEncoder;
3
+ declare const decoder: TextDecoder;
4
+ export { encoder, decoder };
5
+ export declare function splitMessagePayload(packet: Uint8Array): Uint8Array;
6
+ export declare function splitMessageHeader(packet: Uint8Array): string;
7
+ export declare function unpackMessage(packet: Uint8Array): [Record<string, any>, Uint8Array];
8
+ export declare function packMessage(request: Record<string, any>, data?: Uint8Array): Uint8Array;
9
+ export declare function mergeUint8Arrays(...arrays: Uint8Array[]): Uint8Array;
10
+ export declare class RefCount<T> {
11
+ ref: T;
12
+ count: number;
13
+ constructor(ref: T);
14
+ }