@meshagent/meshagent 0.35.5 → 0.35.7

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 (47) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/browser/containers-client.d.ts +79 -2
  3. package/dist/browser/containers-client.js +341 -19
  4. package/dist/browser/database-client.d.ts +95 -24
  5. package/dist/browser/database-client.js +150 -49
  6. package/dist/browser/messaging-client.d.ts +33 -52
  7. package/dist/browser/messaging-client.js +180 -184
  8. package/dist/browser/participant.d.ts +5 -3
  9. package/dist/browser/participant.js +9 -1
  10. package/dist/browser/room-client.js +2 -0
  11. package/dist/browser/room-event.d.ts +6 -2
  12. package/dist/browser/room-event.js +4 -2
  13. package/dist/browser/secrets-client.d.ts +86 -16
  14. package/dist/browser/secrets-client.js +243 -44
  15. package/dist/browser/storage-client.d.ts +17 -4
  16. package/dist/browser/storage-client.js +141 -30
  17. package/dist/esm/containers-client.d.ts +79 -2
  18. package/dist/esm/containers-client.js +341 -19
  19. package/dist/esm/database-client.d.ts +95 -24
  20. package/dist/esm/database-client.js +150 -49
  21. package/dist/esm/messaging-client.d.ts +33 -52
  22. package/dist/esm/messaging-client.js +179 -180
  23. package/dist/esm/participant.d.ts +5 -3
  24. package/dist/esm/participant.js +9 -1
  25. package/dist/esm/room-client.js +2 -0
  26. package/dist/esm/room-event.d.ts +6 -2
  27. package/dist/esm/room-event.js +4 -2
  28. package/dist/esm/secrets-client.d.ts +86 -16
  29. package/dist/esm/secrets-client.js +243 -44
  30. package/dist/esm/storage-client.d.ts +17 -4
  31. package/dist/esm/storage-client.js +140 -30
  32. package/dist/node/containers-client.d.ts +79 -2
  33. package/dist/node/containers-client.js +341 -19
  34. package/dist/node/database-client.d.ts +95 -24
  35. package/dist/node/database-client.js +150 -49
  36. package/dist/node/messaging-client.d.ts +33 -52
  37. package/dist/node/messaging-client.js +180 -184
  38. package/dist/node/participant.d.ts +5 -3
  39. package/dist/node/participant.js +9 -1
  40. package/dist/node/room-client.js +2 -0
  41. package/dist/node/room-event.d.ts +6 -2
  42. package/dist/node/room-event.js +4 -2
  43. package/dist/node/secrets-client.d.ts +86 -16
  44. package/dist/node/secrets-client.js +243 -44
  45. package/dist/node/storage-client.d.ts +17 -4
  46. package/dist/node/storage-client.js +141 -30
  47. package/package.json +1 -1
@@ -17,11 +17,14 @@ function toPortPairs(values) {
17
17
  }
18
18
  function toCredentials(values) {
19
19
  return values.map((entry) => ({
20
- registry: entry.registry,
20
+ registry: entry.registry ?? null,
21
21
  username: entry.username,
22
22
  password: entry.password,
23
23
  }));
24
24
  }
25
+ function toMountList(values) {
26
+ return values.map((entry) => entry);
27
+ }
25
28
  function readStringField(data, field, operation) {
26
29
  const value = data[field];
27
30
  if (typeof value !== "string") {
@@ -29,29 +32,126 @@ function readStringField(data, field, operation) {
29
32
  }
30
33
  return value;
31
34
  }
32
- function decodeJsonStatus(data) {
33
- const text = new TextDecoder().decode(data);
35
+ function readIntegerField(data, field, operation) {
36
+ const value = data[field];
37
+ if (typeof value !== "number" || !Number.isInteger(value)) {
38
+ throw new RoomServerException(`unexpected return type from containers.${operation}`);
39
+ }
40
+ return value;
41
+ }
42
+ function readOptionalIntegerField(data, field, operation) {
43
+ const value = data[field];
44
+ if (value === undefined || value === null) {
45
+ return undefined;
46
+ }
47
+ if (typeof value !== "number" || !Number.isInteger(value)) {
48
+ throw new RoomServerException(`unexpected return type from containers.${operation}`);
49
+ }
50
+ return value;
51
+ }
52
+ function decodeUtf8(data, operation) {
53
+ try {
54
+ return new TextDecoder("utf-8", { fatal: true }).decode(data);
55
+ }
56
+ catch {
57
+ throw new RoomServerException(`containers.${operation} returned invalid UTF-8 data`);
58
+ }
59
+ }
60
+ function decodeJsonStatus(data, operation) {
61
+ const text = decodeUtf8(data, operation);
34
62
  let parsed;
35
63
  try {
36
64
  parsed = JSON.parse(text);
37
65
  }
38
66
  catch {
39
- throw new RoomServerException("containers.exec returned an invalid status payload");
67
+ throw new RoomServerException(`containers.${operation} returned an invalid status payload`);
40
68
  }
41
69
  if (!isRecord(parsed)) {
42
- throw new RoomServerException("containers.exec returned an invalid status payload");
70
+ throw new RoomServerException(`containers.${operation} returned an invalid status payload`);
43
71
  }
44
72
  const status = parsed["status"];
45
73
  if (typeof status !== "number" || !Number.isInteger(status)) {
46
- throw new RoomServerException("containers.exec returned an invalid status payload");
74
+ throw new RoomServerException(`containers.${operation} returned an invalid status payload`);
47
75
  }
48
76
  return status;
49
77
  }
78
+ function normalizeImageLabels(labelsRaw, operation) {
79
+ if (Array.isArray(labelsRaw)) {
80
+ const labels = {};
81
+ for (const entry of labelsRaw) {
82
+ if (!isRecord(entry)) {
83
+ throw new RoomServerException(`unexpected return type from containers.${operation}`);
84
+ }
85
+ const key = entry["key"];
86
+ const value = entry["value"];
87
+ if (typeof key !== "string" || typeof value !== "string") {
88
+ throw new RoomServerException(`unexpected return type from containers.${operation}`);
89
+ }
90
+ labels[key] = value;
91
+ }
92
+ return labels;
93
+ }
94
+ if (isRecord(labelsRaw)) {
95
+ const labels = {};
96
+ for (const [key, value] of Object.entries(labelsRaw)) {
97
+ if (typeof value !== "string") {
98
+ throw new RoomServerException(`unexpected return type from containers.${operation}`);
99
+ }
100
+ labels[key] = value;
101
+ }
102
+ return labels;
103
+ }
104
+ if (labelsRaw === undefined || labelsRaw === null) {
105
+ return {};
106
+ }
107
+ throw new RoomServerException(`unexpected return type from containers.${operation}`);
108
+ }
109
+ function parseImportedImage(data, operation) {
110
+ const resolvedRef = data["resolved_ref"];
111
+ const refsRaw = data["refs"];
112
+ if (typeof resolvedRef !== "string" || !Array.isArray(refsRaw) || refsRaw.some((entry) => typeof entry !== "string")) {
113
+ throw new RoomServerException(`unexpected return type from containers.${operation}`);
114
+ }
115
+ return {
116
+ resolvedRef,
117
+ refs: refsRaw,
118
+ };
119
+ }
120
+ function parseBuildJob(data, operation) {
121
+ const id = readStringField(data, "id", operation);
122
+ const tag = readStringField(data, "tag", operation);
123
+ const status = readStringField(data, "status", operation);
124
+ if (!["queued", "running", "failed", "cancelled", "succeeded"].includes(status)) {
125
+ throw new RoomServerException(`unexpected return type from containers.${operation}`);
126
+ }
127
+ return {
128
+ id,
129
+ tag,
130
+ status: status,
131
+ exitCode: readOptionalIntegerField(data, "exit_code", operation),
132
+ };
133
+ }
134
+ function buildRequestPayload(params) {
135
+ return {
136
+ tag: params.tag,
137
+ mounts: toMountList(params.mounts),
138
+ context_path: params.contextPath,
139
+ dockerfile_path: params.dockerfilePath ?? null,
140
+ private: params.private ?? false,
141
+ credentials: toCredentials(params.credentials ?? []),
142
+ context_archive_path: params.contextArchivePath ?? null,
143
+ context_archive_ref: params.contextArchiveRef ?? null,
144
+ context_archive_mount_path: params.contextArchiveMountPath ?? null,
145
+ context_archive_arch: params.contextArchiveArch ?? null,
146
+ };
147
+ }
50
148
  export class ExecSession {
51
149
  constructor(params) {
52
150
  this.previousOutput = [];
151
+ this.previousError = [];
53
152
  this.resultCompleter = new Completer();
54
153
  this.outputController = new StreamController();
154
+ this.errorController = new StreamController();
55
155
  this.queuedInput = [];
56
156
  this.inputClosed = false;
57
157
  this.closed = false;
@@ -62,6 +162,7 @@ export class ExecSession {
62
162
  this.tty = params.tty;
63
163
  this.result = this.resultCompleter.fut;
64
164
  this.output = this.outputController.stream;
165
+ this.stderr = this.errorController.stream;
65
166
  }
66
167
  async *inputStream() {
67
168
  yield new BinaryContent({
@@ -116,6 +217,7 @@ export class ExecSession {
116
217
  this.closed = true;
117
218
  this.closeInputStream();
118
219
  this.outputController.close();
220
+ this.errorController.close();
119
221
  }
120
222
  closeError(error) {
121
223
  if (!this.resultCompleter.completed) {
@@ -124,11 +226,16 @@ export class ExecSession {
124
226
  this.closed = true;
125
227
  this.closeInputStream();
126
228
  this.outputController.close();
229
+ this.errorController.close();
127
230
  }
128
231
  addOutput(data) {
129
232
  this.previousOutput.push(data);
130
233
  this.outputController.add(data);
131
234
  }
235
+ addError(data) {
236
+ this.previousError.push(data);
237
+ this.errorController.add(data);
238
+ }
132
239
  get isClosed() {
133
240
  return this.closed;
134
241
  }
@@ -171,7 +278,7 @@ export class ContainersClient {
171
278
  }
172
279
  async listImages() {
173
280
  const output = await this.invoke("list_images", {});
174
- if (!(output instanceof JsonContent)) {
281
+ if (!(output instanceof JsonContent) || !isRecord(output.json)) {
175
282
  throw this.unexpectedResponseError("list_images");
176
283
  }
177
284
  const imagesRaw = output.json["images"];
@@ -195,17 +302,65 @@ export class ContainersClient {
195
302
  id,
196
303
  tags: normalizedTags,
197
304
  size: typeof size === "number" ? size : undefined,
198
- labels: isRecord(labelsRaw) ? labelsRaw : {},
305
+ labels: normalizeImageLabels(labelsRaw, "list_images"),
199
306
  });
200
307
  }
201
308
  return images;
202
309
  }
310
+ async deleteImage(params) {
311
+ await this.invoke("delete_image", {
312
+ image: params.image,
313
+ });
314
+ }
203
315
  async pullImage(params) {
204
316
  await this.invoke("pull_image", {
205
317
  tag: params.tag,
206
318
  credentials: toCredentials(params.credentials ?? []),
207
319
  });
208
320
  }
321
+ async pushImage(params) {
322
+ const output = await this.invoke("push_image", {
323
+ tag: params.tag,
324
+ credentials: toCredentials(params.credentials ?? []),
325
+ private: params.private ?? false,
326
+ });
327
+ if (!(output instanceof JsonContent) || !isRecord(output.json)) {
328
+ throw this.unexpectedResponseError("push_image");
329
+ }
330
+ return readStringField(output.json, "container_id", "push_image");
331
+ }
332
+ async load(params) {
333
+ const output = await this.invoke("load", {
334
+ archive_path: params.archivePath,
335
+ });
336
+ if (!(output instanceof JsonContent) || !isRecord(output.json)) {
337
+ throw this.unexpectedResponseError("load");
338
+ }
339
+ return parseImportedImage(output.json, "load");
340
+ }
341
+ async loadImage(params) {
342
+ const output = await this.invoke("load_image", {
343
+ mounts: toMountList(params.mounts),
344
+ archive_path: params.archivePath,
345
+ private: params.private ?? false,
346
+ });
347
+ if (!(output instanceof JsonContent) || !isRecord(output.json)) {
348
+ throw this.unexpectedResponseError("load_image");
349
+ }
350
+ return readStringField(output.json, "container_id", "load_image");
351
+ }
352
+ async saveImage(params) {
353
+ const output = await this.invoke("save_image", {
354
+ tag: params.tag,
355
+ mounts: toMountList(params.mounts),
356
+ archive_path: params.archivePath,
357
+ private: params.private ?? false,
358
+ });
359
+ if (!(output instanceof JsonContent) || !isRecord(output.json)) {
360
+ throw this.unexpectedResponseError("save_image");
361
+ }
362
+ return readStringField(output.json, "container_id", "save_image");
363
+ }
209
364
  async run(params) {
210
365
  const output = await this.invoke("run", {
211
366
  image: params.image,
@@ -228,6 +383,46 @@ export class ContainersClient {
228
383
  }
229
384
  return readStringField(output.json, "container_id", "run");
230
385
  }
386
+ async startBuild(params) {
387
+ const output = await this.invoke("start_build", buildRequestPayload(params));
388
+ if (!(output instanceof JsonContent) || !isRecord(output.json)) {
389
+ throw this.unexpectedResponseError("start_build");
390
+ }
391
+ return readStringField(output.json, "build_id", "start_build");
392
+ }
393
+ async build(params) {
394
+ const output = await this.invoke("build", buildRequestPayload(params));
395
+ if (!(output instanceof JsonContent) || !isRecord(output.json)) {
396
+ throw this.unexpectedResponseError("build");
397
+ }
398
+ return readStringField(output.json, "build_id", "build");
399
+ }
400
+ async listBuilds() {
401
+ const output = await this.invoke("list_builds", {});
402
+ if (!(output instanceof JsonContent) || !isRecord(output.json)) {
403
+ throw this.unexpectedResponseError("list_builds");
404
+ }
405
+ const buildsRaw = output.json["builds"];
406
+ if (!Array.isArray(buildsRaw)) {
407
+ throw this.unexpectedResponseError("list_builds");
408
+ }
409
+ return buildsRaw.map((entry) => {
410
+ if (!isRecord(entry)) {
411
+ throw this.unexpectedResponseError("list_builds");
412
+ }
413
+ return parseBuildJob(entry, "list_builds");
414
+ });
415
+ }
416
+ async cancelBuild(params) {
417
+ await this.invoke("cancel_build", {
418
+ build_id: params.buildId,
419
+ });
420
+ }
421
+ async deleteBuild(params) {
422
+ await this.invoke("delete_build", {
423
+ build_id: params.buildId,
424
+ });
425
+ }
231
426
  async runService(params) {
232
427
  const output = await this.invoke("run_service", {
233
428
  service_id: params.serviceId,
@@ -257,6 +452,12 @@ export class ContainersClient {
257
452
  if (chunk instanceof ErrorContent) {
258
453
  throw new RoomServerException(chunk.text, chunk.code);
259
454
  }
455
+ if (chunk instanceof ControlContent) {
456
+ if (chunk.method === "close") {
457
+ break;
458
+ }
459
+ throw this.unexpectedResponseError("exec");
460
+ }
260
461
  if (!(chunk instanceof BinaryContent)) {
261
462
  throw this.unexpectedResponseError("exec");
262
463
  }
@@ -268,8 +469,12 @@ export class ContainersClient {
268
469
  session.addOutput(chunk.data);
269
470
  continue;
270
471
  }
472
+ if (channel === 2) {
473
+ session.addError(chunk.data);
474
+ continue;
475
+ }
271
476
  if (channel === 3) {
272
- session.close(decodeJsonStatus(chunk.data));
477
+ session.close(decodeJsonStatus(chunk.data, "exec"));
273
478
  return;
274
479
  }
275
480
  }
@@ -283,7 +488,7 @@ export class ContainersClient {
283
488
  async stop(params) {
284
489
  await this.invoke("stop_container", {
285
490
  container_id: params.containerId,
286
- force: params.force ?? true,
491
+ force: params.force ?? false,
287
492
  });
288
493
  }
289
494
  async waitForExit(params) {
@@ -293,11 +498,7 @@ export class ContainersClient {
293
498
  if (!(output instanceof JsonContent) || !isRecord(output.json)) {
294
499
  throw this.unexpectedResponseError("wait_for_exit");
295
500
  }
296
- const exitCode = output.json["exit_code"];
297
- if (typeof exitCode !== "number" || !Number.isInteger(exitCode)) {
298
- throw this.unexpectedResponseError("wait_for_exit");
299
- }
300
- return exitCode;
501
+ return readIntegerField(output.json, "exit_code", "wait_for_exit");
301
502
  }
302
503
  async deleteContainer(params) {
303
504
  await this.invoke("delete_container", {
@@ -338,13 +539,20 @@ export class ContainersClient {
338
539
  input: inputStream(),
339
540
  })
340
541
  .then(async (stream) => {
341
- const decoder = new TextDecoder();
342
542
  for await (const chunk of stream) {
343
543
  if (chunk instanceof ErrorContent) {
344
544
  throw new RoomServerException(chunk.text, chunk.code);
345
545
  }
346
546
  if (chunk instanceof ControlContent) {
347
- continue;
547
+ if (chunk.method === "close") {
548
+ closeInputStream();
549
+ streamController.close();
550
+ if (!result.completed) {
551
+ result.complete();
552
+ }
553
+ return;
554
+ }
555
+ throw this.unexpectedResponseError("logs");
348
556
  }
349
557
  if (!(chunk instanceof BinaryContent)) {
350
558
  throw this.unexpectedResponseError("logs");
@@ -356,11 +564,125 @@ export class ContainersClient {
356
564
  if (channel !== 1) {
357
565
  continue;
358
566
  }
359
- streamController.add(decoder.decode(chunk.data));
567
+ streamController.add(decodeUtf8(chunk.data, "logs"));
568
+ }
569
+ closeInputStream();
570
+ streamController.close();
571
+ if (!result.completed) {
572
+ result.complete();
573
+ }
574
+ })
575
+ .catch((error) => {
576
+ closeInputStream();
577
+ streamController.close();
578
+ if (!result.completed) {
579
+ result.completeError(error);
580
+ }
581
+ });
582
+ const outputStream = {
583
+ [Symbol.asyncIterator]() {
584
+ const it = streamController.stream[Symbol.asyncIterator]();
585
+ return {
586
+ async next() {
587
+ return await it.next();
588
+ },
589
+ async return(value) {
590
+ closeInputStream();
591
+ return await it.return?.(value) ?? { done: true, value };
592
+ },
593
+ async throw(e) {
594
+ closeInputStream();
595
+ if (it.throw) {
596
+ return await it.throw(e);
597
+ }
598
+ throw e;
599
+ },
600
+ };
601
+ },
602
+ };
603
+ return {
604
+ stream: outputStream,
605
+ result: result.fut,
606
+ cancel: async () => {
607
+ closeInputStream();
608
+ await result.fut.catch(() => undefined);
609
+ },
610
+ };
611
+ }
612
+ getBuildLogs(params) {
613
+ const requestId = uuidv4();
614
+ const closeInput = new Completer();
615
+ const streamController = new StreamController();
616
+ const result = new Completer();
617
+ let inputClosed = false;
618
+ const closeInputStream = () => {
619
+ if (inputClosed) {
620
+ return;
621
+ }
622
+ inputClosed = true;
623
+ if (!closeInput.completed) {
624
+ closeInput.complete();
625
+ }
626
+ };
627
+ const inputStream = async function* () {
628
+ yield new BinaryContent({
629
+ data: new Uint8Array(0),
630
+ headers: {
631
+ kind: "start",
632
+ request_id: requestId,
633
+ build_id: params.buildId,
634
+ follow: params.follow ?? true,
635
+ },
636
+ });
637
+ await closeInput.fut;
638
+ };
639
+ this.room
640
+ .invokeStream({
641
+ toolkit: "containers",
642
+ tool: "get_build_logs",
643
+ input: inputStream(),
644
+ })
645
+ .then(async (stream) => {
646
+ for await (const chunk of stream) {
647
+ if (chunk instanceof ErrorContent) {
648
+ throw new RoomServerException(chunk.text, chunk.code);
649
+ }
650
+ if (chunk instanceof ControlContent) {
651
+ if (chunk.method === "close") {
652
+ closeInputStream();
653
+ streamController.close();
654
+ if (!result.completed) {
655
+ result.complete(null);
656
+ }
657
+ return;
658
+ }
659
+ throw this.unexpectedResponseError("get_build_logs");
660
+ }
661
+ if (!(chunk instanceof BinaryContent)) {
662
+ throw this.unexpectedResponseError("get_build_logs");
663
+ }
664
+ const channel = chunk.headers["channel"];
665
+ if (typeof channel !== "number") {
666
+ throw new RoomServerException("containers.get_build_logs returned a chunk without a valid channel");
667
+ }
668
+ if (channel === 1) {
669
+ streamController.add(decodeUtf8(chunk.data, "get_build_logs"));
670
+ continue;
671
+ }
672
+ if (channel === 3) {
673
+ closeInputStream();
674
+ streamController.close();
675
+ if (!result.completed) {
676
+ result.complete(decodeJsonStatus(chunk.data, "get_build_logs"));
677
+ }
678
+ return;
679
+ }
360
680
  }
361
681
  closeInputStream();
362
682
  streamController.close();
363
- result.complete();
683
+ if (!result.completed) {
684
+ result.complete(null);
685
+ }
364
686
  })
365
687
  .catch((error) => {
366
688
  closeInputStream();