@meshagent/meshagent 0.29.2 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/browser/agent-client.js +3 -28
  3. package/dist/browser/agent.js +6 -6
  4. package/dist/browser/containers-client.d.ts +125 -0
  5. package/dist/browser/containers-client.js +458 -0
  6. package/dist/browser/database-client.d.ts +42 -6
  7. package/dist/browser/database-client.js +610 -77
  8. package/dist/browser/developer-client.d.ts +2 -2
  9. package/dist/browser/developer-client.js +60 -15
  10. package/dist/browser/helpers.js +4 -3
  11. package/dist/browser/index.d.ts +1 -0
  12. package/dist/browser/index.js +1 -0
  13. package/dist/browser/lk-client.js +12 -3
  14. package/dist/browser/meshagent-client.d.ts +5 -0
  15. package/dist/browser/messaging-client.d.ts +1 -0
  16. package/dist/browser/messaging-client.js +52 -8
  17. package/dist/browser/queues-client.d.ts +2 -0
  18. package/dist/browser/queues-client.js +34 -7
  19. package/dist/browser/response.d.ts +28 -0
  20. package/dist/browser/response.js +76 -1
  21. package/dist/browser/room-client.d.ts +43 -1
  22. package/dist/browser/room-client.js +204 -0
  23. package/dist/browser/secrets-client.d.ts +1 -0
  24. package/dist/browser/secrets-client.js +32 -27
  25. package/dist/browser/storage-client.d.ts +22 -7
  26. package/dist/browser/storage-client.js +353 -15
  27. package/dist/browser/sync-client.d.ts +12 -13
  28. package/dist/browser/sync-client.js +263 -65
  29. package/dist/esm/agent-client.js +3 -28
  30. package/dist/esm/agent.js +6 -6
  31. package/dist/esm/containers-client.d.ts +125 -0
  32. package/dist/esm/containers-client.js +453 -0
  33. package/dist/esm/database-client.d.ts +42 -6
  34. package/dist/esm/database-client.js +611 -78
  35. package/dist/esm/developer-client.d.ts +2 -2
  36. package/dist/esm/developer-client.js +61 -16
  37. package/dist/esm/helpers.js +4 -3
  38. package/dist/esm/index.d.ts +1 -0
  39. package/dist/esm/index.js +1 -0
  40. package/dist/esm/lk-client.js +12 -3
  41. package/dist/esm/meshagent-client.d.ts +5 -0
  42. package/dist/esm/messaging-client.d.ts +1 -0
  43. package/dist/esm/messaging-client.js +52 -8
  44. package/dist/esm/queues-client.d.ts +2 -0
  45. package/dist/esm/queues-client.js +35 -8
  46. package/dist/esm/response.d.ts +28 -0
  47. package/dist/esm/response.js +73 -0
  48. package/dist/esm/room-client.d.ts +43 -1
  49. package/dist/esm/room-client.js +207 -3
  50. package/dist/esm/secrets-client.d.ts +1 -0
  51. package/dist/esm/secrets-client.js +33 -28
  52. package/dist/esm/storage-client.d.ts +22 -7
  53. package/dist/esm/storage-client.js +353 -15
  54. package/dist/esm/sync-client.d.ts +12 -13
  55. package/dist/esm/sync-client.js +263 -64
  56. package/dist/node/agent-client.js +3 -28
  57. package/dist/node/agent.js +6 -6
  58. package/dist/node/containers-client.d.ts +125 -0
  59. package/dist/node/containers-client.js +458 -0
  60. package/dist/node/database-client.d.ts +42 -6
  61. package/dist/node/database-client.js +610 -77
  62. package/dist/node/developer-client.d.ts +2 -2
  63. package/dist/node/developer-client.js +60 -15
  64. package/dist/node/helpers.js +4 -3
  65. package/dist/node/index.d.ts +1 -0
  66. package/dist/node/index.js +1 -0
  67. package/dist/node/lk-client.js +12 -3
  68. package/dist/node/meshagent-client.d.ts +5 -0
  69. package/dist/node/messaging-client.d.ts +1 -0
  70. package/dist/node/messaging-client.js +52 -8
  71. package/dist/node/queues-client.d.ts +2 -0
  72. package/dist/node/queues-client.js +34 -7
  73. package/dist/node/response.d.ts +28 -0
  74. package/dist/node/response.js +76 -1
  75. package/dist/node/room-client.d.ts +43 -1
  76. package/dist/node/room-client.js +204 -0
  77. package/dist/node/secrets-client.d.ts +1 -0
  78. package/dist/node/secrets-client.js +32 -27
  79. package/dist/node/storage-client.d.ts +22 -7
  80. package/dist/node/storage-client.js +353 -15
  81. package/dist/node/sync-client.d.ts +12 -13
  82. package/dist/node/sync-client.js +263 -65
  83. package/package.json +1 -1
@@ -2,8 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StorageClient = exports.FileHandle = void 0;
4
4
  const room_event_1 = require("./room-event");
5
+ const response_1 = require("./response");
5
6
  const utils_1 = require("./utils");
6
7
  const event_emitter_1 = require("./event-emitter");
8
+ const room_server_client_1 = require("./room-server-client");
7
9
  class FileHandle {
8
10
  constructor({ id }) {
9
11
  this.id = id;
@@ -11,9 +13,10 @@ class FileHandle {
11
13
  }
12
14
  exports.FileHandle = FileHandle;
13
15
  class StorageEntry {
14
- constructor({ name, isFolder }) {
16
+ constructor({ name, isFolder, size = null }) {
15
17
  this.name = name;
16
18
  this.isFolder = isFolder;
19
+ this.size = size;
17
20
  }
18
21
  nameWithoutExtension() {
19
22
  const segments = this.name
@@ -43,42 +46,377 @@ class StorageClient extends event_emitter_1.EventEmitter {
43
46
  this.client.emit(event);
44
47
  this.emit('file.deleted', event);
45
48
  }
49
+ _unexpectedResponseError(operation) {
50
+ return new room_server_client_1.RoomServerException(`unexpected return type from storage.${operation}`);
51
+ }
52
+ async _invoke(operation, input, callerContext) {
53
+ return await this.client.invoke({
54
+ toolkit: "storage",
55
+ tool: operation,
56
+ input,
57
+ callerContext,
58
+ });
59
+ }
46
60
  async list(path) {
47
- const response = (await this.client.sendRequest("storage.list", { path }));
61
+ const response = await this._invoke("list", { path });
62
+ if (!(response instanceof response_1.JsonContent)) {
63
+ throw this._unexpectedResponseError("list");
64
+ }
48
65
  const files = response.json["files"];
49
66
  const entries = files.map((f) => {
50
67
  return new StorageEntry({
51
68
  name: f["name"],
52
69
  isFolder: f["is_folder"],
70
+ size: typeof f["size"] === "number" ? f["size"] : null,
53
71
  });
54
72
  });
55
73
  entries.sort((a, b) => a.name.localeCompare(b.name));
56
74
  return entries;
57
75
  }
58
76
  async delete(path) {
59
- await this.client.sendRequest("storage.delete", { path });
60
- }
61
- async open(path, { overwrite = false }) {
62
- const response = (await this.client.sendRequest("storage.open", { path, overwrite }));
63
- return new FileHandle({ id: response.json["handle"] });
77
+ await this._invoke("delete", { path, recursive: null });
64
78
  }
65
79
  async exists(path) {
66
- const result = (await this.client.sendRequest("storage.exists", { path }));
80
+ const result = await this._invoke("exists", { path });
81
+ if (!(result instanceof response_1.JsonContent)) {
82
+ throw this._unexpectedResponseError("exists");
83
+ }
67
84
  return result.json["exists"];
68
85
  }
69
- async write(handle, bytes) {
70
- await this.client.sendRequest("storage.write", { handle: handle.id }, bytes);
86
+ _defaultUploadName(path, name) {
87
+ if (typeof name === "string" && name.length > 0) {
88
+ return name;
89
+ }
90
+ const segments = path.split("/").filter((segment) => segment.length > 0);
91
+ const lastSegment = segments.length > 0 ? segments[segments.length - 1] : undefined;
92
+ return lastSegment ?? path;
71
93
  }
72
- async close(handle) {
73
- await this.client.sendRequest("storage.close", { handle: handle.id });
94
+ async upload(path, bytes, { overwrite = false, name, mimeType = null, } = {}) {
95
+ async function* singleChunk() {
96
+ yield bytes;
97
+ }
98
+ await this.uploadStream(path, singleChunk(), {
99
+ overwrite,
100
+ size: bytes.length,
101
+ name,
102
+ mimeType,
103
+ });
104
+ }
105
+ async uploadStream(path, chunks, { overwrite = false, chunkSize = 64 * 1024, size = null, name, mimeType = null, } = {}) {
106
+ const resolvedName = this._defaultUploadName(path, name);
107
+ const input = new _StorageUploadInputStream({
108
+ path,
109
+ overwrite,
110
+ chunks,
111
+ chunkSize,
112
+ size,
113
+ name: resolvedName,
114
+ mimeType,
115
+ });
116
+ const response = await this.client.invokeStream({
117
+ toolkit: "storage",
118
+ tool: "upload",
119
+ input: input.stream(),
120
+ });
121
+ try {
122
+ for await (const chunk of response) {
123
+ if (chunk instanceof response_1.ErrorContent) {
124
+ throw new room_server_client_1.RoomServerException(chunk.text, chunk.code);
125
+ }
126
+ if (chunk instanceof response_1.ControlContent) {
127
+ if (chunk.method === "close") {
128
+ return;
129
+ }
130
+ throw this._unexpectedResponseError("upload");
131
+ }
132
+ if (!(chunk instanceof response_1.BinaryContent)) {
133
+ throw this._unexpectedResponseError("upload");
134
+ }
135
+ if (chunk.headers["kind"] !== "pull") {
136
+ throw this._unexpectedResponseError("upload");
137
+ }
138
+ input.requestNext();
139
+ }
140
+ }
141
+ finally {
142
+ input.close();
143
+ }
74
144
  }
75
145
  async download(path) {
76
- const response = (await this.client.sendRequest("storage.download", { path }));
77
- return response;
146
+ const stream = await this.downloadStream(path);
147
+ let name = null;
148
+ let mimeType = null;
149
+ let expectedSize = null;
150
+ let bytesReceived = 0;
151
+ const parts = [];
152
+ for await (const chunk of stream) {
153
+ const kind = chunk.headers["kind"];
154
+ if (kind === "start") {
155
+ const chunkName = chunk.headers["name"];
156
+ const chunkMimeType = chunk.headers["mime_type"];
157
+ const chunkSizeValue = chunk.headers["size"];
158
+ if (typeof chunkName !== "string" ||
159
+ typeof chunkMimeType !== "string" ||
160
+ typeof chunkSizeValue !== "number" ||
161
+ chunkSizeValue < 0) {
162
+ throw this._unexpectedResponseError("download");
163
+ }
164
+ name = chunkName;
165
+ mimeType = chunkMimeType;
166
+ expectedSize = chunkSizeValue;
167
+ continue;
168
+ }
169
+ if (kind !== "data") {
170
+ throw this._unexpectedResponseError("download");
171
+ }
172
+ parts.push(chunk.data);
173
+ bytesReceived += chunk.data.length;
174
+ }
175
+ if (name == null || mimeType == null || expectedSize == null || bytesReceived !== expectedSize) {
176
+ throw this._unexpectedResponseError("download");
177
+ }
178
+ const totalLength = parts.reduce((sum, chunk) => sum + chunk.length, 0);
179
+ const data = new Uint8Array(totalLength);
180
+ let offset = 0;
181
+ for (const part of parts) {
182
+ data.set(part, offset);
183
+ offset += part.length;
184
+ }
185
+ return new response_1.FileContent({ data, name, mimeType });
186
+ }
187
+ async downloadStream(path, { chunkSize = 64 * 1024, } = {}) {
188
+ const input = new _StorageDownloadInputStream({ path, chunkSize });
189
+ const response = await this.client.invokeStream({
190
+ toolkit: "storage",
191
+ tool: "download",
192
+ input: input.stream(),
193
+ });
194
+ const self = this;
195
+ return {
196
+ async *[Symbol.asyncIterator]() {
197
+ let metadataReceived = false;
198
+ let expectedSize = null;
199
+ let bytesReceived = 0;
200
+ try {
201
+ for await (const chunk of response) {
202
+ if (chunk instanceof response_1.ErrorContent) {
203
+ throw new room_server_client_1.RoomServerException(chunk.text, chunk.code);
204
+ }
205
+ if (chunk instanceof response_1.ControlContent) {
206
+ if (chunk.method === "close") {
207
+ if (!metadataReceived || expectedSize == null || bytesReceived !== expectedSize) {
208
+ throw self._unexpectedResponseError("download");
209
+ }
210
+ return;
211
+ }
212
+ throw self._unexpectedResponseError("download");
213
+ }
214
+ if (!(chunk instanceof response_1.BinaryContent)) {
215
+ throw self._unexpectedResponseError("download");
216
+ }
217
+ const kind = chunk.headers["kind"];
218
+ if (kind === "start") {
219
+ if (metadataReceived) {
220
+ throw self._unexpectedResponseError("download");
221
+ }
222
+ const chunkName = chunk.headers["name"];
223
+ const chunkMimeType = chunk.headers["mime_type"];
224
+ const chunkSizeValue = chunk.headers["size"];
225
+ if (typeof chunkName !== "string" ||
226
+ typeof chunkMimeType !== "string" ||
227
+ typeof chunkSizeValue !== "number" ||
228
+ chunkSizeValue < 0) {
229
+ throw self._unexpectedResponseError("download");
230
+ }
231
+ metadataReceived = true;
232
+ expectedSize = chunkSizeValue;
233
+ yield chunk;
234
+ if (expectedSize > 0) {
235
+ input.requestNext();
236
+ }
237
+ continue;
238
+ }
239
+ if (kind !== "data" || !metadataReceived || expectedSize == null) {
240
+ throw self._unexpectedResponseError("download");
241
+ }
242
+ bytesReceived += chunk.data.length;
243
+ if (bytesReceived > expectedSize) {
244
+ throw self._unexpectedResponseError("download");
245
+ }
246
+ yield chunk;
247
+ if (bytesReceived < expectedSize) {
248
+ input.requestNext();
249
+ }
250
+ }
251
+ }
252
+ finally {
253
+ input.close();
254
+ }
255
+ },
256
+ };
78
257
  }
79
258
  async downloadUrl(path) {
80
- const response = (await this.client.sendRequest("storage.download_url", { path }));
259
+ const response = await this._invoke("download_url", { path });
260
+ if (!(response instanceof response_1.JsonContent)) {
261
+ throw this._unexpectedResponseError("download_url");
262
+ }
81
263
  return response.json["url"];
82
264
  }
83
265
  }
84
266
  exports.StorageClient = StorageClient;
267
+ class _StorageDownloadInputStream {
268
+ constructor({ path, chunkSize }) {
269
+ this.closed = false;
270
+ this.pendingPulls = 0;
271
+ this.waitingResolver = null;
272
+ this.path = path;
273
+ this.chunkSize = chunkSize;
274
+ }
275
+ requestNext() {
276
+ if (this.closed) {
277
+ return;
278
+ }
279
+ this.pendingPulls += 1;
280
+ if (this.waitingResolver) {
281
+ const resolver = this.waitingResolver;
282
+ this.waitingResolver = null;
283
+ resolver();
284
+ }
285
+ }
286
+ close() {
287
+ if (this.closed) {
288
+ return;
289
+ }
290
+ this.closed = true;
291
+ if (this.waitingResolver) {
292
+ const resolver = this.waitingResolver;
293
+ this.waitingResolver = null;
294
+ resolver();
295
+ }
296
+ }
297
+ async *stream() {
298
+ yield new response_1.BinaryContent({
299
+ data: new Uint8Array(0),
300
+ headers: {
301
+ kind: "start",
302
+ path: this.path,
303
+ chunk_size: this.chunkSize,
304
+ },
305
+ });
306
+ while (!this.closed) {
307
+ if (this.pendingPulls === 0) {
308
+ await new Promise((resolve) => {
309
+ this.waitingResolver = resolve;
310
+ });
311
+ }
312
+ if (this.closed) {
313
+ return;
314
+ }
315
+ if (this.pendingPulls === 0) {
316
+ continue;
317
+ }
318
+ this.pendingPulls -= 1;
319
+ yield new response_1.BinaryContent({
320
+ data: new Uint8Array(0),
321
+ headers: { kind: "pull" },
322
+ });
323
+ }
324
+ }
325
+ }
326
+ class _StorageUploadInputStream {
327
+ constructor({ path, overwrite, chunks, chunkSize, size, name, mimeType, }) {
328
+ this.closed = false;
329
+ this.pendingPulls = 0;
330
+ this.waitingResolver = null;
331
+ this.pendingChunk = new Uint8Array(0);
332
+ this.pendingOffset = 0;
333
+ this.sourceExhausted = false;
334
+ this.path = path;
335
+ this.overwrite = overwrite;
336
+ this.source = chunks[Symbol.asyncIterator]();
337
+ this.chunkSize = chunkSize;
338
+ this.size = size;
339
+ this.name = name;
340
+ this.mimeType = mimeType;
341
+ }
342
+ requestNext() {
343
+ if (this.closed) {
344
+ return;
345
+ }
346
+ this.pendingPulls += 1;
347
+ if (this.waitingResolver) {
348
+ const resolver = this.waitingResolver;
349
+ this.waitingResolver = null;
350
+ resolver();
351
+ }
352
+ }
353
+ close() {
354
+ if (this.closed) {
355
+ return;
356
+ }
357
+ this.closed = true;
358
+ if (this.waitingResolver) {
359
+ const resolver = this.waitingResolver;
360
+ this.waitingResolver = null;
361
+ resolver();
362
+ }
363
+ }
364
+ async nextChunk() {
365
+ while (true) {
366
+ if (this.pendingOffset < this.pendingChunk.length) {
367
+ const start = this.pendingOffset;
368
+ const end = Math.min(start + this.chunkSize, this.pendingChunk.length);
369
+ this.pendingOffset = end;
370
+ return this.pendingChunk.slice(start, end);
371
+ }
372
+ if (this.sourceExhausted) {
373
+ return null;
374
+ }
375
+ const next = await this.source.next();
376
+ if (next.done) {
377
+ this.sourceExhausted = true;
378
+ return null;
379
+ }
380
+ if (next.value.length === 0) {
381
+ continue;
382
+ }
383
+ this.pendingChunk = next.value;
384
+ this.pendingOffset = 0;
385
+ }
386
+ }
387
+ async *stream() {
388
+ yield new response_1.BinaryContent({
389
+ data: new Uint8Array(0),
390
+ headers: {
391
+ kind: "start",
392
+ path: this.path,
393
+ overwrite: this.overwrite,
394
+ name: this.name,
395
+ mime_type: this.mimeType,
396
+ size: this.size,
397
+ },
398
+ });
399
+ while (!this.closed) {
400
+ if (this.pendingPulls === 0) {
401
+ await new Promise((resolve) => {
402
+ this.waitingResolver = resolve;
403
+ });
404
+ }
405
+ if (this.closed) {
406
+ return;
407
+ }
408
+ if (this.pendingPulls === 0) {
409
+ continue;
410
+ }
411
+ this.pendingPulls -= 1;
412
+ const chunk = await this.nextChunk();
413
+ if (chunk == null) {
414
+ return;
415
+ }
416
+ yield new response_1.BinaryContent({
417
+ data: chunk,
418
+ headers: { kind: "data" },
419
+ });
420
+ }
421
+ }
422
+ }
@@ -1,37 +1,36 @@
1
1
  import { EventEmitter } from "./event-emitter";
2
2
  import { RoomClient } from "./room-client";
3
+ import { MeshSchema } from "./schema";
3
4
  import { MeshDocument } from "./room-server-client";
4
5
  export interface SyncClientEvent {
5
6
  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
- });
7
+ doc?: MeshDocument;
8
+ status?: unknown;
15
9
  }
16
10
  export declare class SyncClient extends EventEmitter<SyncClientEvent> {
17
- private client;
11
+ private readonly client;
18
12
  private _connectingDocuments;
19
- private _changesToSync;
20
13
  private _connectedDocuments;
14
+ private _documentStreams;
21
15
  constructor({ room }: {
22
16
  room: RoomClient;
23
17
  });
18
+ private _unexpectedResponseError;
19
+ private _invoke;
24
20
  start({ onDone, onError }?: {
25
21
  onDone?: () => void;
26
22
  onError?: (error: Error) => void;
27
23
  }): void;
28
24
  dispose(): void;
29
- private _handleSync;
25
+ private _applySyncPayload;
30
26
  private _handleStatus;
31
27
  create(path: string, json?: Record<string, any>): Promise<void>;
32
- open(path: string, { create }?: {
28
+ open(path: string, { create, initialJson, schema, }?: {
33
29
  create?: boolean;
30
+ initialJson?: Record<string, any>;
31
+ schema?: MeshSchema;
34
32
  }): Promise<MeshDocument>;
35
33
  close(path: string): Promise<void>;
36
34
  sync(path: string, data: Uint8Array): Promise<void>;
35
+ private _consumeOpenStream;
37
36
  }