@meshagent/meshagent 0.41.9 → 0.42.2

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/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## [0.42.2]
2
+ - Added `ContainerExitStatus`, `RoomContainerStats`, and published build image metadata to the TypeScript container client models.
3
+ - Added `waitForExitStatus` while keeping `waitForExit` as the exit-code convenience wrapper.
4
+ - Container list parsing now preserves image IDs, runtime stats, and exit-status metadata from API responses.
5
+
6
+ ## [0.42.1]
7
+ - Stability
8
+
9
+ ## [0.42.0]
10
+ - Added project lookup by key.
11
+ - Container and room APIs now return structured `containerPort`/`hostPort` entries instead of integer port lists, which is a breaking response-shape change.
12
+ - `ContainerSpec`, `PortSpec`, and `RoutePathSpec` now support `template`, `host_port`, and `stripPrefix`, and room service URL resolution uses `host_port` when available.
13
+ - `createRoom` now serializes typed permissions, and container creation now accepts a `template` option.
14
+
15
+ ## [0.41.10]
16
+ - Stability
17
+
1
18
  ## [0.41.9]
2
19
  - Stability
3
20
 
@@ -52,15 +52,34 @@ export interface ContainerParticipantInfo {
52
52
  id: string;
53
53
  name: string;
54
54
  }
55
+ export interface RoomContainerPort {
56
+ containerPort: number;
57
+ hostPort: number;
58
+ }
59
+ export interface RoomContainerStats {
60
+ cpuUsageNanoCores?: number;
61
+ memoryUsageBytes?: number;
62
+ memoryWorkingSetBytes?: number;
63
+ timestampNs?: number;
64
+ }
55
65
  export interface RoomContainer {
56
66
  id: string;
57
67
  image: string;
68
+ imageId?: string;
58
69
  name?: string;
59
- ports: number[];
70
+ ports: RoomContainerPort[];
60
71
  startedBy: ContainerParticipantInfo;
61
72
  state: string;
62
73
  private: boolean;
63
74
  serviceId?: string;
75
+ stats?: RoomContainerStats;
76
+ exitStatus?: ContainerExitStatus;
77
+ }
78
+ export interface ContainerExitStatus {
79
+ exitCode: number;
80
+ reason?: string;
81
+ message?: string;
82
+ oomKilled?: boolean;
64
83
  }
65
84
  export interface LogProgress {
66
85
  layer?: string | null;
@@ -170,6 +189,7 @@ export declare class ContainersClient {
170
189
  credentials?: DockerSecret[];
171
190
  name?: string;
172
191
  mounts?: ContainerMountSpec;
192
+ template?: "agent" | "none";
173
193
  writableRootFs?: boolean;
174
194
  private?: boolean;
175
195
  }): Promise<string>;
@@ -206,6 +226,9 @@ export declare class ContainersClient {
206
226
  containerId: string;
207
227
  force?: boolean;
208
228
  }): Promise<void>;
229
+ waitForExitStatus(params: {
230
+ containerId: string;
231
+ }): Promise<ContainerExitStatus>;
209
232
  waitForExit(params: {
210
233
  containerId: string;
211
234
  }): Promise<number>;
@@ -504,6 +504,7 @@ class ContainersClient {
504
504
  credentials: toCredentials(params.credentials ?? []),
505
505
  name: params.name,
506
506
  mounts: params.mounts,
507
+ template: params.template,
507
508
  writable_root_fs: params.writableRootFs,
508
509
  private: params.private,
509
510
  });
@@ -617,14 +618,27 @@ class ContainersClient {
617
618
  force: params.force ?? false,
618
619
  });
619
620
  }
620
- async waitForExit(params) {
621
+ async waitForExitStatus(params) {
621
622
  const output = await this.invoke("wait_for_exit", {
622
623
  container_id: params.containerId,
623
624
  });
624
625
  if (!(output instanceof response_1.JsonContent) || !isRecord(output.json)) {
625
626
  throw this.unexpectedResponseError("wait_for_exit");
626
627
  }
627
- return readIntegerField(output.json, "exit_code", "wait_for_exit");
628
+ const exitCode = readIntegerField(output.json, "exit_code", "wait_for_exit");
629
+ const reason = output.json["reason"];
630
+ const message = output.json["message"];
631
+ const oomKilled = output.json["oom_killed"];
632
+ return {
633
+ exitCode,
634
+ reason: typeof reason === "string" ? reason : undefined,
635
+ message: typeof message === "string" ? message : undefined,
636
+ oomKilled: typeof oomKilled === "boolean" ? oomKilled : undefined,
637
+ };
638
+ }
639
+ async waitForExit(params) {
640
+ const status = await this.waitForExitStatus(params);
641
+ return status.exitCode;
628
642
  }
629
643
  async deleteContainer(params) {
630
644
  await this.invoke("delete_container", {
@@ -887,16 +901,62 @@ class ContainersClient {
887
901
  throw this.unexpectedResponseError("list");
888
902
  }
889
903
  const nameRaw = entry["name"];
904
+ const imageIdRaw = entry["image_id"];
890
905
  const portsRaw = entry["ports"];
891
906
  const serviceIdRaw = entry["service_id"];
892
- if (!Array.isArray(portsRaw) || !portsRaw.every((port) => typeof port === "number" && Number.isInteger(port))) {
907
+ const statsRaw = entry["stats"];
908
+ const exitStatusRaw = entry["exit_status"];
909
+ if (!Array.isArray(portsRaw) ||
910
+ !portsRaw.every((port) => {
911
+ if (!isRecord(port)) {
912
+ return false;
913
+ }
914
+ return (typeof port["container_port"] === "number" &&
915
+ Number.isInteger(port["container_port"]) &&
916
+ typeof port["host_port"] === "number" &&
917
+ Number.isInteger(port["host_port"]));
918
+ })) {
893
919
  throw this.unexpectedResponseError("list");
894
920
  }
921
+ const ports = portsRaw.map((port) => ({
922
+ containerPort: port["container_port"],
923
+ hostPort: port["host_port"],
924
+ }));
925
+ let stats;
926
+ if (isRecord(statsRaw)) {
927
+ const cpuUsageNanoCores = statsRaw["cpu_usage_nano_cores"];
928
+ const memoryUsageBytes = statsRaw["memory_usage_bytes"];
929
+ const memoryWorkingSetBytes = statsRaw["memory_working_set_bytes"];
930
+ const timestampNs = statsRaw["timestamp_ns"];
931
+ stats = {
932
+ cpuUsageNanoCores: typeof cpuUsageNanoCores === "number" ? cpuUsageNanoCores : undefined,
933
+ memoryUsageBytes: typeof memoryUsageBytes === "number" ? memoryUsageBytes : undefined,
934
+ memoryWorkingSetBytes: typeof memoryWorkingSetBytes === "number" ? memoryWorkingSetBytes : undefined,
935
+ timestampNs: typeof timestampNs === "number" ? timestampNs : undefined,
936
+ };
937
+ }
938
+ let exitStatus;
939
+ if (isRecord(exitStatusRaw)) {
940
+ const exitCode = exitStatusRaw["exit_code"];
941
+ if (typeof exitCode === "number" &&
942
+ Number.isInteger(exitCode)) {
943
+ const reason = exitStatusRaw["reason"];
944
+ const message = exitStatusRaw["message"];
945
+ const oomKilled = exitStatusRaw["oom_killed"];
946
+ exitStatus = {
947
+ exitCode,
948
+ reason: typeof reason === "string" ? reason : undefined,
949
+ message: typeof message === "string" ? message : undefined,
950
+ oomKilled: typeof oomKilled === "boolean" ? oomKilled : undefined,
951
+ };
952
+ }
953
+ }
895
954
  items.push({
896
955
  id,
897
956
  image,
957
+ imageId: typeof imageIdRaw === "string" ? imageIdRaw : undefined,
898
958
  name: typeof nameRaw === "string" ? nameRaw : undefined,
899
- ports: portsRaw,
959
+ ports,
900
960
  startedBy: {
901
961
  id: startedById,
902
962
  name: startedByName,
@@ -904,6 +964,8 @@ class ContainersClient {
904
964
  state,
905
965
  private: privateFlag,
906
966
  serviceId: typeof serviceIdRaw === "string" ? serviceIdRaw : undefined,
967
+ stats,
968
+ exitStatus,
907
969
  });
908
970
  }
909
971
  return items;
@@ -148,6 +148,7 @@ export interface ServiceMetadata {
148
148
  }
149
149
  export interface ContainerSpec {
150
150
  private?: boolean | null;
151
+ template?: "agent" | "none" | null;
151
152
  command?: string | null;
152
153
  working_dir?: string | null;
153
154
  image: string;
@@ -193,9 +194,13 @@ export interface EndpointSpec {
193
194
  }
194
195
  export interface PortSpec {
195
196
  num: "*" | number;
197
+ host_port?: number | null;
196
198
  type?: "http" | "tcp" | null;
199
+ published?: boolean | null;
200
+ public?: boolean | null;
197
201
  endpoints?: EndpointSpec[];
198
202
  liveness?: string | null;
203
+ annotations?: Record<string, string>;
199
204
  }
200
205
  export interface ServiceSpec {
201
206
  version: "v1";
@@ -221,6 +226,7 @@ export interface RouteBackend {
221
226
  export interface RoutePathSpec {
222
227
  path?: string;
223
228
  pathType?: "prefix" | "exact";
229
+ stripPrefix?: boolean;
224
230
  targetPort: string | number;
225
231
  }
226
232
  export interface RouteSpec {
@@ -432,6 +438,7 @@ export declare class Meshagent {
432
438
  updateUserProfile(userId: string, firstName: string, lastName: string): Promise<Record<string, unknown>>;
433
439
  listProjects(): Promise<Record<string, unknown>>;
434
440
  getProject(projectId: string): Promise<Record<string, unknown>>;
441
+ getProjectByKey(projectKey: string): Promise<Record<string, unknown>>;
435
442
  createApiKey(projectId: string, name: string, description: string): Promise<Record<string, unknown>>;
436
443
  deleteApiKey(projectId: string, id: string): Promise<void>;
437
444
  listApiKeys(projectId: string): Promise<Record<string, unknown>>;
@@ -842,6 +842,11 @@ class Meshagent {
842
842
  action: "get project",
843
843
  });
844
844
  }
845
+ async getProjectByKey(projectKey) {
846
+ return await this.request(`/accounts/projects/by-key/${encodeURIComponent(projectKey)}`, {
847
+ action: "get project by key",
848
+ });
849
+ }
845
850
  async createApiKey(projectId, name, description) {
846
851
  return await this.request(`/accounts/projects/${projectId}/api-keys`, {
847
852
  method: "POST",
@@ -221,7 +221,7 @@ function bracketIpv6Host(host) {
221
221
  }
222
222
  function roomServiceMcpServerUrl({ service, port, endpoint, }) {
223
223
  const endpointPath = normalizeEndpointPath(endpoint.path);
224
- const portValue = typeof port.num === "number" ? port.num : null;
224
+ const portValue = port.host_port ?? (typeof port.num === "number" ? port.num : null);
225
225
  if (service.external == null) {
226
226
  if (portValue == null) {
227
227
  return `http://localhost${endpointPath}`;
@@ -52,15 +52,34 @@ export interface ContainerParticipantInfo {
52
52
  id: string;
53
53
  name: string;
54
54
  }
55
+ export interface RoomContainerPort {
56
+ containerPort: number;
57
+ hostPort: number;
58
+ }
59
+ export interface RoomContainerStats {
60
+ cpuUsageNanoCores?: number;
61
+ memoryUsageBytes?: number;
62
+ memoryWorkingSetBytes?: number;
63
+ timestampNs?: number;
64
+ }
55
65
  export interface RoomContainer {
56
66
  id: string;
57
67
  image: string;
68
+ imageId?: string;
58
69
  name?: string;
59
- ports: number[];
70
+ ports: RoomContainerPort[];
60
71
  startedBy: ContainerParticipantInfo;
61
72
  state: string;
62
73
  private: boolean;
63
74
  serviceId?: string;
75
+ stats?: RoomContainerStats;
76
+ exitStatus?: ContainerExitStatus;
77
+ }
78
+ export interface ContainerExitStatus {
79
+ exitCode: number;
80
+ reason?: string;
81
+ message?: string;
82
+ oomKilled?: boolean;
64
83
  }
65
84
  export interface LogProgress {
66
85
  layer?: string | null;
@@ -170,6 +189,7 @@ export declare class ContainersClient {
170
189
  credentials?: DockerSecret[];
171
190
  name?: string;
172
191
  mounts?: ContainerMountSpec;
192
+ template?: "agent" | "none";
173
193
  writableRootFs?: boolean;
174
194
  private?: boolean;
175
195
  }): Promise<string>;
@@ -206,6 +226,9 @@ export declare class ContainersClient {
206
226
  containerId: string;
207
227
  force?: boolean;
208
228
  }): Promise<void>;
229
+ waitForExitStatus(params: {
230
+ containerId: string;
231
+ }): Promise<ContainerExitStatus>;
209
232
  waitForExit(params: {
210
233
  containerId: string;
211
234
  }): Promise<number>;
@@ -504,6 +504,7 @@ class ContainersClient {
504
504
  credentials: toCredentials(params.credentials ?? []),
505
505
  name: params.name,
506
506
  mounts: params.mounts,
507
+ template: params.template,
507
508
  writable_root_fs: params.writableRootFs,
508
509
  private: params.private,
509
510
  });
@@ -617,14 +618,27 @@ class ContainersClient {
617
618
  force: params.force ?? false,
618
619
  });
619
620
  }
620
- async waitForExit(params) {
621
+ async waitForExitStatus(params) {
621
622
  const output = await this.invoke("wait_for_exit", {
622
623
  container_id: params.containerId,
623
624
  });
624
625
  if (!(output instanceof response_1.JsonContent) || !isRecord(output.json)) {
625
626
  throw this.unexpectedResponseError("wait_for_exit");
626
627
  }
627
- return readIntegerField(output.json, "exit_code", "wait_for_exit");
628
+ const exitCode = readIntegerField(output.json, "exit_code", "wait_for_exit");
629
+ const reason = output.json["reason"];
630
+ const message = output.json["message"];
631
+ const oomKilled = output.json["oom_killed"];
632
+ return {
633
+ exitCode,
634
+ reason: typeof reason === "string" ? reason : undefined,
635
+ message: typeof message === "string" ? message : undefined,
636
+ oomKilled: typeof oomKilled === "boolean" ? oomKilled : undefined,
637
+ };
638
+ }
639
+ async waitForExit(params) {
640
+ const status = await this.waitForExitStatus(params);
641
+ return status.exitCode;
628
642
  }
629
643
  async deleteContainer(params) {
630
644
  await this.invoke("delete_container", {
@@ -887,16 +901,62 @@ class ContainersClient {
887
901
  throw this.unexpectedResponseError("list");
888
902
  }
889
903
  const nameRaw = entry["name"];
904
+ const imageIdRaw = entry["image_id"];
890
905
  const portsRaw = entry["ports"];
891
906
  const serviceIdRaw = entry["service_id"];
892
- if (!Array.isArray(portsRaw) || !portsRaw.every((port) => typeof port === "number" && Number.isInteger(port))) {
907
+ const statsRaw = entry["stats"];
908
+ const exitStatusRaw = entry["exit_status"];
909
+ if (!Array.isArray(portsRaw) ||
910
+ !portsRaw.every((port) => {
911
+ if (!isRecord(port)) {
912
+ return false;
913
+ }
914
+ return (typeof port["container_port"] === "number" &&
915
+ Number.isInteger(port["container_port"]) &&
916
+ typeof port["host_port"] === "number" &&
917
+ Number.isInteger(port["host_port"]));
918
+ })) {
893
919
  throw this.unexpectedResponseError("list");
894
920
  }
921
+ const ports = portsRaw.map((port) => ({
922
+ containerPort: port["container_port"],
923
+ hostPort: port["host_port"],
924
+ }));
925
+ let stats;
926
+ if (isRecord(statsRaw)) {
927
+ const cpuUsageNanoCores = statsRaw["cpu_usage_nano_cores"];
928
+ const memoryUsageBytes = statsRaw["memory_usage_bytes"];
929
+ const memoryWorkingSetBytes = statsRaw["memory_working_set_bytes"];
930
+ const timestampNs = statsRaw["timestamp_ns"];
931
+ stats = {
932
+ cpuUsageNanoCores: typeof cpuUsageNanoCores === "number" ? cpuUsageNanoCores : undefined,
933
+ memoryUsageBytes: typeof memoryUsageBytes === "number" ? memoryUsageBytes : undefined,
934
+ memoryWorkingSetBytes: typeof memoryWorkingSetBytes === "number" ? memoryWorkingSetBytes : undefined,
935
+ timestampNs: typeof timestampNs === "number" ? timestampNs : undefined,
936
+ };
937
+ }
938
+ let exitStatus;
939
+ if (isRecord(exitStatusRaw)) {
940
+ const exitCode = exitStatusRaw["exit_code"];
941
+ if (typeof exitCode === "number" &&
942
+ Number.isInteger(exitCode)) {
943
+ const reason = exitStatusRaw["reason"];
944
+ const message = exitStatusRaw["message"];
945
+ const oomKilled = exitStatusRaw["oom_killed"];
946
+ exitStatus = {
947
+ exitCode,
948
+ reason: typeof reason === "string" ? reason : undefined,
949
+ message: typeof message === "string" ? message : undefined,
950
+ oomKilled: typeof oomKilled === "boolean" ? oomKilled : undefined,
951
+ };
952
+ }
953
+ }
895
954
  items.push({
896
955
  id,
897
956
  image,
957
+ imageId: typeof imageIdRaw === "string" ? imageIdRaw : undefined,
898
958
  name: typeof nameRaw === "string" ? nameRaw : undefined,
899
- ports: portsRaw,
959
+ ports,
900
960
  startedBy: {
901
961
  id: startedById,
902
962
  name: startedByName,
@@ -904,6 +964,8 @@ class ContainersClient {
904
964
  state,
905
965
  private: privateFlag,
906
966
  serviceId: typeof serviceIdRaw === "string" ? serviceIdRaw : undefined,
967
+ stats,
968
+ exitStatus,
907
969
  });
908
970
  }
909
971
  return items;
@@ -148,6 +148,7 @@ export interface ServiceMetadata {
148
148
  }
149
149
  export interface ContainerSpec {
150
150
  private?: boolean | null;
151
+ template?: "agent" | "none" | null;
151
152
  command?: string | null;
152
153
  working_dir?: string | null;
153
154
  image: string;
@@ -193,9 +194,13 @@ export interface EndpointSpec {
193
194
  }
194
195
  export interface PortSpec {
195
196
  num: "*" | number;
197
+ host_port?: number | null;
196
198
  type?: "http" | "tcp" | null;
199
+ published?: boolean | null;
200
+ public?: boolean | null;
197
201
  endpoints?: EndpointSpec[];
198
202
  liveness?: string | null;
203
+ annotations?: Record<string, string>;
199
204
  }
200
205
  export interface ServiceSpec {
201
206
  version: "v1";
@@ -221,6 +226,7 @@ export interface RouteBackend {
221
226
  export interface RoutePathSpec {
222
227
  path?: string;
223
228
  pathType?: "prefix" | "exact";
229
+ stripPrefix?: boolean;
224
230
  targetPort: string | number;
225
231
  }
226
232
  export interface RouteSpec {
@@ -432,6 +438,7 @@ export declare class Meshagent {
432
438
  updateUserProfile(userId: string, firstName: string, lastName: string): Promise<Record<string, unknown>>;
433
439
  listProjects(): Promise<Record<string, unknown>>;
434
440
  getProject(projectId: string): Promise<Record<string, unknown>>;
441
+ getProjectByKey(projectKey: string): Promise<Record<string, unknown>>;
435
442
  createApiKey(projectId: string, name: string, description: string): Promise<Record<string, unknown>>;
436
443
  deleteApiKey(projectId: string, id: string): Promise<void>;
437
444
  listApiKeys(projectId: string): Promise<Record<string, unknown>>;
@@ -842,6 +842,11 @@ class Meshagent {
842
842
  action: "get project",
843
843
  });
844
844
  }
845
+ async getProjectByKey(projectKey) {
846
+ return await this.request(`/accounts/projects/by-key/${encodeURIComponent(projectKey)}`, {
847
+ action: "get project by key",
848
+ });
849
+ }
845
850
  async createApiKey(projectId, name, description) {
846
851
  return await this.request(`/accounts/projects/${projectId}/api-keys`, {
847
852
  method: "POST",
@@ -221,7 +221,7 @@ function bracketIpv6Host(host) {
221
221
  }
222
222
  function roomServiceMcpServerUrl({ service, port, endpoint, }) {
223
223
  const endpointPath = normalizeEndpointPath(endpoint.path);
224
- const portValue = typeof port.num === "number" ? port.num : null;
224
+ const portValue = port.host_port ?? (typeof port.num === "number" ? port.num : null);
225
225
  if (service.external == null) {
226
226
  if (portValue == null) {
227
227
  return `http://localhost${endpointPath}`;
@@ -52,15 +52,34 @@ export interface ContainerParticipantInfo {
52
52
  id: string;
53
53
  name: string;
54
54
  }
55
+ export interface RoomContainerPort {
56
+ containerPort: number;
57
+ hostPort: number;
58
+ }
59
+ export interface RoomContainerStats {
60
+ cpuUsageNanoCores?: number;
61
+ memoryUsageBytes?: number;
62
+ memoryWorkingSetBytes?: number;
63
+ timestampNs?: number;
64
+ }
55
65
  export interface RoomContainer {
56
66
  id: string;
57
67
  image: string;
68
+ imageId?: string;
58
69
  name?: string;
59
- ports: number[];
70
+ ports: RoomContainerPort[];
60
71
  startedBy: ContainerParticipantInfo;
61
72
  state: string;
62
73
  private: boolean;
63
74
  serviceId?: string;
75
+ stats?: RoomContainerStats;
76
+ exitStatus?: ContainerExitStatus;
77
+ }
78
+ export interface ContainerExitStatus {
79
+ exitCode: number;
80
+ reason?: string;
81
+ message?: string;
82
+ oomKilled?: boolean;
64
83
  }
65
84
  export interface LogProgress {
66
85
  layer?: string | null;
@@ -170,6 +189,7 @@ export declare class ContainersClient {
170
189
  credentials?: DockerSecret[];
171
190
  name?: string;
172
191
  mounts?: ContainerMountSpec;
192
+ template?: "agent" | "none";
173
193
  writableRootFs?: boolean;
174
194
  private?: boolean;
175
195
  }): Promise<string>;
@@ -206,6 +226,9 @@ export declare class ContainersClient {
206
226
  containerId: string;
207
227
  force?: boolean;
208
228
  }): Promise<void>;
229
+ waitForExitStatus(params: {
230
+ containerId: string;
231
+ }): Promise<ContainerExitStatus>;
209
232
  waitForExit(params: {
210
233
  containerId: string;
211
234
  }): Promise<number>;
@@ -504,6 +504,7 @@ class ContainersClient {
504
504
  credentials: toCredentials(params.credentials ?? []),
505
505
  name: params.name,
506
506
  mounts: params.mounts,
507
+ template: params.template,
507
508
  writable_root_fs: params.writableRootFs,
508
509
  private: params.private,
509
510
  });
@@ -617,14 +618,27 @@ class ContainersClient {
617
618
  force: params.force ?? false,
618
619
  });
619
620
  }
620
- async waitForExit(params) {
621
+ async waitForExitStatus(params) {
621
622
  const output = await this.invoke("wait_for_exit", {
622
623
  container_id: params.containerId,
623
624
  });
624
625
  if (!(output instanceof response_1.JsonContent) || !isRecord(output.json)) {
625
626
  throw this.unexpectedResponseError("wait_for_exit");
626
627
  }
627
- return readIntegerField(output.json, "exit_code", "wait_for_exit");
628
+ const exitCode = readIntegerField(output.json, "exit_code", "wait_for_exit");
629
+ const reason = output.json["reason"];
630
+ const message = output.json["message"];
631
+ const oomKilled = output.json["oom_killed"];
632
+ return {
633
+ exitCode,
634
+ reason: typeof reason === "string" ? reason : undefined,
635
+ message: typeof message === "string" ? message : undefined,
636
+ oomKilled: typeof oomKilled === "boolean" ? oomKilled : undefined,
637
+ };
638
+ }
639
+ async waitForExit(params) {
640
+ const status = await this.waitForExitStatus(params);
641
+ return status.exitCode;
628
642
  }
629
643
  async deleteContainer(params) {
630
644
  await this.invoke("delete_container", {
@@ -887,16 +901,62 @@ class ContainersClient {
887
901
  throw this.unexpectedResponseError("list");
888
902
  }
889
903
  const nameRaw = entry["name"];
904
+ const imageIdRaw = entry["image_id"];
890
905
  const portsRaw = entry["ports"];
891
906
  const serviceIdRaw = entry["service_id"];
892
- if (!Array.isArray(portsRaw) || !portsRaw.every((port) => typeof port === "number" && Number.isInteger(port))) {
907
+ const statsRaw = entry["stats"];
908
+ const exitStatusRaw = entry["exit_status"];
909
+ if (!Array.isArray(portsRaw) ||
910
+ !portsRaw.every((port) => {
911
+ if (!isRecord(port)) {
912
+ return false;
913
+ }
914
+ return (typeof port["container_port"] === "number" &&
915
+ Number.isInteger(port["container_port"]) &&
916
+ typeof port["host_port"] === "number" &&
917
+ Number.isInteger(port["host_port"]));
918
+ })) {
893
919
  throw this.unexpectedResponseError("list");
894
920
  }
921
+ const ports = portsRaw.map((port) => ({
922
+ containerPort: port["container_port"],
923
+ hostPort: port["host_port"],
924
+ }));
925
+ let stats;
926
+ if (isRecord(statsRaw)) {
927
+ const cpuUsageNanoCores = statsRaw["cpu_usage_nano_cores"];
928
+ const memoryUsageBytes = statsRaw["memory_usage_bytes"];
929
+ const memoryWorkingSetBytes = statsRaw["memory_working_set_bytes"];
930
+ const timestampNs = statsRaw["timestamp_ns"];
931
+ stats = {
932
+ cpuUsageNanoCores: typeof cpuUsageNanoCores === "number" ? cpuUsageNanoCores : undefined,
933
+ memoryUsageBytes: typeof memoryUsageBytes === "number" ? memoryUsageBytes : undefined,
934
+ memoryWorkingSetBytes: typeof memoryWorkingSetBytes === "number" ? memoryWorkingSetBytes : undefined,
935
+ timestampNs: typeof timestampNs === "number" ? timestampNs : undefined,
936
+ };
937
+ }
938
+ let exitStatus;
939
+ if (isRecord(exitStatusRaw)) {
940
+ const exitCode = exitStatusRaw["exit_code"];
941
+ if (typeof exitCode === "number" &&
942
+ Number.isInteger(exitCode)) {
943
+ const reason = exitStatusRaw["reason"];
944
+ const message = exitStatusRaw["message"];
945
+ const oomKilled = exitStatusRaw["oom_killed"];
946
+ exitStatus = {
947
+ exitCode,
948
+ reason: typeof reason === "string" ? reason : undefined,
949
+ message: typeof message === "string" ? message : undefined,
950
+ oomKilled: typeof oomKilled === "boolean" ? oomKilled : undefined,
951
+ };
952
+ }
953
+ }
895
954
  items.push({
896
955
  id,
897
956
  image,
957
+ imageId: typeof imageIdRaw === "string" ? imageIdRaw : undefined,
898
958
  name: typeof nameRaw === "string" ? nameRaw : undefined,
899
- ports: portsRaw,
959
+ ports,
900
960
  startedBy: {
901
961
  id: startedById,
902
962
  name: startedByName,
@@ -904,6 +964,8 @@ class ContainersClient {
904
964
  state,
905
965
  private: privateFlag,
906
966
  serviceId: typeof serviceIdRaw === "string" ? serviceIdRaw : undefined,
967
+ stats,
968
+ exitStatus,
907
969
  });
908
970
  }
909
971
  return items;
@@ -148,6 +148,7 @@ export interface ServiceMetadata {
148
148
  }
149
149
  export interface ContainerSpec {
150
150
  private?: boolean | null;
151
+ template?: "agent" | "none" | null;
151
152
  command?: string | null;
152
153
  working_dir?: string | null;
153
154
  image: string;
@@ -193,9 +194,13 @@ export interface EndpointSpec {
193
194
  }
194
195
  export interface PortSpec {
195
196
  num: "*" | number;
197
+ host_port?: number | null;
196
198
  type?: "http" | "tcp" | null;
199
+ published?: boolean | null;
200
+ public?: boolean | null;
197
201
  endpoints?: EndpointSpec[];
198
202
  liveness?: string | null;
203
+ annotations?: Record<string, string>;
199
204
  }
200
205
  export interface ServiceSpec {
201
206
  version: "v1";
@@ -221,6 +226,7 @@ export interface RouteBackend {
221
226
  export interface RoutePathSpec {
222
227
  path?: string;
223
228
  pathType?: "prefix" | "exact";
229
+ stripPrefix?: boolean;
224
230
  targetPort: string | number;
225
231
  }
226
232
  export interface RouteSpec {
@@ -432,6 +438,7 @@ export declare class Meshagent {
432
438
  updateUserProfile(userId: string, firstName: string, lastName: string): Promise<Record<string, unknown>>;
433
439
  listProjects(): Promise<Record<string, unknown>>;
434
440
  getProject(projectId: string): Promise<Record<string, unknown>>;
441
+ getProjectByKey(projectKey: string): Promise<Record<string, unknown>>;
435
442
  createApiKey(projectId: string, name: string, description: string): Promise<Record<string, unknown>>;
436
443
  deleteApiKey(projectId: string, id: string): Promise<void>;
437
444
  listApiKeys(projectId: string): Promise<Record<string, unknown>>;
@@ -842,6 +842,11 @@ class Meshagent {
842
842
  action: "get project",
843
843
  });
844
844
  }
845
+ async getProjectByKey(projectKey) {
846
+ return await this.request(`/accounts/projects/by-key/${encodeURIComponent(projectKey)}`, {
847
+ action: "get project by key",
848
+ });
849
+ }
845
850
  async createApiKey(projectId, name, description) {
846
851
  return await this.request(`/accounts/projects/${projectId}/api-keys`, {
847
852
  method: "POST",
@@ -221,7 +221,7 @@ function bracketIpv6Host(host) {
221
221
  }
222
222
  function roomServiceMcpServerUrl({ service, port, endpoint, }) {
223
223
  const endpointPath = normalizeEndpointPath(endpoint.path);
224
- const portValue = typeof port.num === "number" ? port.num : null;
224
+ const portValue = port.host_port ?? (typeof port.num === "number" ? port.num : null);
225
225
  if (service.external == null) {
226
226
  if (portValue == null) {
227
227
  return `http://localhost${endpointPath}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshagent/meshagent",
3
- "version": "0.41.9",
3
+ "version": "0.42.2",
4
4
  "description": "Meshagent Client",
5
5
  "homepage": "https://github.com/meshagent/meshagent-ts",
6
6
  "scripts": {