@meshagent/meshagent 0.48.0 → 0.49.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [0.49.1]
2
+ - Stability
3
+
4
+ ## [0.49.0]
5
+ - Breaking: `createProject` no longer accepts inline settings; project settings are now document-based with `room_roles` support.
6
+ - Route path models now use a service-port/content-target union and support CORS, compression, index, and IAP for room-content routes.
7
+ - `RoomRole` now includes `guest`, and missing project-settings documents return `undefined`.
8
+
9
+ ## [0.48.1]
10
+ - Stability
11
+ - Added typed room-content route targets with subpath, CORS, index serving, IAP, and Brotli-by-default compression options.
12
+
1
13
  ## [0.48.0]
2
14
  - Reworked the TS/JS agent chat stack to preserve ordered threaded messages and support injected-message threads across chat clients and process handling.
3
15
  - Added chat feed widgets and virtual scrolling to the React/Tailwind UI, improving large-thread performance.
@@ -1,7 +1,8 @@
1
1
  import { ApiScope } from "./participant-token.js";
2
2
  export type ProjectRole = "member" | "admin" | "developer" | "room_creator" | "room_inventory" | "room_manager" | "session_inventory" | "agent_creator" | "agent_inventory" | "agent_manager" | "repository_creator" | "repository_inventory" | "repository_manager" | "feed_creator" | "feed_inventory" | "feed_manager" | "oauth_client_creator" | "oauth_client_inventory" | "oauth_client_manager" | "api_key_creator" | "api_key_inventory" | "api_key_manager" | "service_creator" | "service_inventory" | "service_manager" | "service_account_creator" | "service_account_inventory" | "service_account_manager" | "participant_token_creator" | "mailbox_creator" | "mailbox_inventory" | "mailbox_manager" | "route_creator" | "route_inventory" | "route_manager" | "scheduled_task_creator" | "scheduled_task_inventory" | "scheduled_task_manager" | "feed_subscription_creator" | "feed_subscription_inventory" | "feed_subscription_manager" | "llm_logger_creator" | "llm_logger_inventory" | "llm_logger_manager" | "llm_proxy_user" | "usage_reporter" | "billing_manager" | "group_manager";
3
3
  export type ResourceRole = "viewer" | "operator" | "developer" | "admin";
4
- export type RoomRole = "site_user" | ResourceRole;
4
+ export type RoomRole = "site_user" | "guest" | ResourceRole;
5
+ export type ProjectSettingsDocumentName = "openai" | "anthropic" | "otel" | "admission" | "room" | "room_roles";
5
6
  export type FeedRole = "reader" | "subscriber" | "publisher" | "manager";
6
7
  export type SecretRole = "use_proxy";
7
8
  export type AccessRole = ProjectRole | RoomRole | FeedRole | SecretRole | "list";
@@ -425,12 +426,33 @@ export interface RouteBackend {
425
426
  room?: RouteBackendTarget | null;
426
427
  agent?: RouteBackendTarget | null;
427
428
  }
428
- export interface RoutePathSpec {
429
+ export interface RouteCorsRule {
430
+ allowedOrigins: string[];
431
+ allowedMethods?: string[];
432
+ allowedHeaders?: string[];
433
+ exposeHeaders?: string[];
434
+ maxAgeSeconds?: number;
435
+ allowCredentials?: boolean;
436
+ }
437
+ export interface RouteContentSpec {
438
+ subpath?: string;
439
+ cors?: RouteCorsRule[];
440
+ index?: boolean;
441
+ iap?: boolean;
442
+ compression?: "brotli" | "gzip" | "none";
443
+ }
444
+ interface RoutePathBase {
429
445
  path?: string;
430
446
  pathType?: "prefix" | "exact";
431
447
  stripPrefix?: boolean;
432
- targetPort: string | number;
433
448
  }
449
+ export type RoutePathSpec = RoutePathBase & ({
450
+ targetPort: string | number;
451
+ targetContent?: never;
452
+ } | {
453
+ targetContent: RouteContentSpec;
454
+ targetPort?: never;
455
+ });
434
456
  export interface RouteSpec {
435
457
  version: "v1";
436
458
  kind: "Route";
@@ -584,14 +606,17 @@ export declare class Meshagent {
584
606
  projectId: string;
585
607
  path: string;
586
608
  }): Promise<Uint8Array>;
587
- createProject(name: string, settings?: Record<string, unknown>): Promise<Record<string, unknown>>;
609
+ createProject(name: string): Promise<Record<string, unknown>>;
588
610
  addUserToProject(projectId: string, userId: string, options?: {
589
611
  roles?: ProjectRole[];
590
612
  email?: string;
591
613
  inviteRedirectUrl?: string;
592
614
  }): Promise<Record<string, unknown>>;
593
615
  removeUserFromProject(projectId: string, userId: string): Promise<Record<string, unknown>>;
594
- updateProjectSettings(projectId: string, settings: Record<string, unknown>): Promise<Record<string, unknown>>;
616
+ private projectSettingsDocumentPath;
617
+ getProjectSettingsDocument(projectId: string, name: ProjectSettingsDocumentName): Promise<Record<string, unknown> | undefined>;
618
+ setProjectSettingsDocument(projectId: string, name: ProjectSettingsDocumentName, document: Record<string, unknown>): Promise<Record<string, unknown>>;
619
+ deleteProjectSettingsDocument(projectId: string, name: ProjectSettingsDocumentName): Promise<Record<string, unknown>>;
595
620
  updateUserInProject(projectId: string, userId: string, roles: ProjectRole[]): Promise<Record<string, unknown>>;
596
621
  getUsersInProjectPage(projectId: string, options?: {
597
622
  pageSize?: number;
@@ -250,7 +250,7 @@ class Meshagent {
250
250
  return url.toString();
251
251
  }
252
252
  async request(path, options) {
253
- const { method = "GET", query, json, body, headers, action, responseType = "json" } = options;
253
+ const { method = "GET", query, json, body, headers, action, responseType = "json", returnUndefinedOnNotFound = false } = options;
254
254
  const url = this.buildUrl(path, query);
255
255
  const finalHeaders = {};
256
256
  if (this.token) {
@@ -279,6 +279,9 @@ class Meshagent {
279
279
  headers: finalHeaders,
280
280
  body: toFetchBody(requestBody),
281
281
  });
282
+ if (response.status === 404 && returnUndefinedOnNotFound) {
283
+ return undefined;
284
+ }
282
285
  if (!response.ok) {
283
286
  let message;
284
287
  try {
@@ -867,10 +870,10 @@ class Meshagent {
867
870
  responseType: "arrayBuffer",
868
871
  });
869
872
  }
870
- async createProject(name, settings) {
873
+ async createProject(name) {
871
874
  return await this.request(`/accounts/projects`, {
872
875
  method: "POST",
873
- json: { name, settings },
876
+ json: { name },
874
877
  action: "create project",
875
878
  });
876
879
  }
@@ -894,11 +897,26 @@ class Meshagent {
894
897
  action: "remove user from project",
895
898
  });
896
899
  }
897
- async updateProjectSettings(projectId, settings) {
898
- return await this.request(`/accounts/projects/${projectId}/settings`, {
900
+ projectSettingsDocumentPath(name) {
901
+ return name === "room_roles" ? "room-roles" : name;
902
+ }
903
+ async getProjectSettingsDocument(projectId, name) {
904
+ return await this.request(`/accounts/projects/${projectId}/settings/${this.projectSettingsDocumentPath(name)}`, {
905
+ action: `get ${name} project settings`,
906
+ returnUndefinedOnNotFound: true,
907
+ });
908
+ }
909
+ async setProjectSettingsDocument(projectId, name, document) {
910
+ return await this.request(`/accounts/projects/${projectId}/settings/${this.projectSettingsDocumentPath(name)}`, {
899
911
  method: "PUT",
900
- json: settings,
901
- action: "update project settings",
912
+ json: document,
913
+ action: `set ${name} project settings`,
914
+ });
915
+ }
916
+ async deleteProjectSettingsDocument(projectId, name) {
917
+ return await this.request(`/accounts/projects/${projectId}/settings/${this.projectSettingsDocumentPath(name)}`, {
918
+ method: "DELETE",
919
+ action: `delete ${name} project settings`,
902
920
  });
903
921
  }
904
922
  async updateUserInProject(projectId, userId, roles) {
@@ -693,8 +693,15 @@ class MessagingClient extends event_emitter_js_1.EventEmitter {
693
693
  break;
694
694
  }
695
695
  const event = new room_event_js_1.RoomMessageEvent({ message });
696
- this.client.emit(event);
697
- this.emit("message", event);
696
+ try {
697
+ this.client.emit(event);
698
+ this.emit("message", event);
699
+ }
700
+ finally {
701
+ if (message.type === "dismiss") {
702
+ this.client._dismiss();
703
+ }
704
+ }
698
705
  }
699
706
  _onParticipantEnabled(message) {
700
707
  const data = message.message;
@@ -78,6 +78,7 @@ export declare class RoomClient {
78
78
  private _localParticipantReady;
79
79
  private _connected;
80
80
  private _closing;
81
+ private _dismissed;
81
82
  private _localParticipant;
82
83
  private _lifecycleTask;
83
84
  private _terminalState;
@@ -169,6 +170,7 @@ export declare class RoomClient {
169
170
  private _retryProtocolConnection;
170
171
  private _reconnect;
171
172
  private _connectionLifecycle;
173
+ _dismiss(): void;
172
174
  dispose(): void;
173
175
  _sendProtocolNowait({ type, data, label, messageId, expectResponse, }: {
174
176
  type: string;
@@ -225,6 +225,7 @@ class RoomClient {
225
225
  this._localParticipantReady = new completer_js_1.Completer();
226
226
  this._connected = false;
227
227
  this._closing = false;
228
+ this._dismissed = false;
228
229
  this._localParticipant = null;
229
230
  this._lifecycleTask = null;
230
231
  this._terminalState = null;
@@ -882,7 +883,7 @@ class RoomClient {
882
883
  const deadline = this._reconnectTimeout == null ? null : Date.now() + this._reconnectTimeout;
883
884
  let firstAttempt = true;
884
885
  let retryCount = 0;
885
- while (!this._closing) {
886
+ while (!this._closing && !this._dismissed) {
886
887
  if (firstAttempt) {
887
888
  firstAttempt = false;
888
889
  if (this._reconnectTimeout == null) {
@@ -1013,7 +1014,7 @@ class RoomClient {
1013
1014
  this._completeRoomClosed();
1014
1015
  return;
1015
1016
  }
1016
- if (closeKind !== protocol_js_1.ProtocolCloseKind.ERROR) {
1017
+ if (closeKind !== protocol_js_1.ProtocolCloseKind.ERROR || this._dismissed) {
1017
1018
  this._setTerminalState({ state });
1018
1019
  }
1019
1020
  this._markDisconnected({ reason: closeReason, kind: closeKind });
@@ -1025,7 +1026,7 @@ class RoomClient {
1025
1026
  this.messaging._onRoomDisconnect({ reason: closeReason });
1026
1027
  await this._failPendingWork({ state });
1027
1028
  await this._closeProtocol(protocol);
1028
- if (closeKind === protocol_js_1.ProtocolCloseKind.ERROR) {
1029
+ if (closeKind === protocol_js_1.ProtocolCloseKind.ERROR && !this._dismissed) {
1029
1030
  if (this._reconnectTimeout === 0) {
1030
1031
  if (closeReason == null) {
1031
1032
  console.warn("room connection lost; automatic reconnect disabled");
@@ -1054,6 +1055,13 @@ class RoomClient {
1054
1055
  return;
1055
1056
  }
1056
1057
  }
1058
+ _dismiss() {
1059
+ if (this._closing || this._dismissed) {
1060
+ return;
1061
+ }
1062
+ this._dismissed = true;
1063
+ this._protocolInstance.dispose();
1064
+ }
1057
1065
  dispose() {
1058
1066
  this._closing = true;
1059
1067
  this._markDisconnected({
@@ -1,7 +1,8 @@
1
1
  import { ApiScope } from "./participant-token.js";
2
2
  export type ProjectRole = "member" | "admin" | "developer" | "room_creator" | "room_inventory" | "room_manager" | "session_inventory" | "agent_creator" | "agent_inventory" | "agent_manager" | "repository_creator" | "repository_inventory" | "repository_manager" | "feed_creator" | "feed_inventory" | "feed_manager" | "oauth_client_creator" | "oauth_client_inventory" | "oauth_client_manager" | "api_key_creator" | "api_key_inventory" | "api_key_manager" | "service_creator" | "service_inventory" | "service_manager" | "service_account_creator" | "service_account_inventory" | "service_account_manager" | "participant_token_creator" | "mailbox_creator" | "mailbox_inventory" | "mailbox_manager" | "route_creator" | "route_inventory" | "route_manager" | "scheduled_task_creator" | "scheduled_task_inventory" | "scheduled_task_manager" | "feed_subscription_creator" | "feed_subscription_inventory" | "feed_subscription_manager" | "llm_logger_creator" | "llm_logger_inventory" | "llm_logger_manager" | "llm_proxy_user" | "usage_reporter" | "billing_manager" | "group_manager";
3
3
  export type ResourceRole = "viewer" | "operator" | "developer" | "admin";
4
- export type RoomRole = "site_user" | ResourceRole;
4
+ export type RoomRole = "site_user" | "guest" | ResourceRole;
5
+ export type ProjectSettingsDocumentName = "openai" | "anthropic" | "otel" | "admission" | "room" | "room_roles";
5
6
  export type FeedRole = "reader" | "subscriber" | "publisher" | "manager";
6
7
  export type SecretRole = "use_proxy";
7
8
  export type AccessRole = ProjectRole | RoomRole | FeedRole | SecretRole | "list";
@@ -425,12 +426,33 @@ export interface RouteBackend {
425
426
  room?: RouteBackendTarget | null;
426
427
  agent?: RouteBackendTarget | null;
427
428
  }
428
- export interface RoutePathSpec {
429
+ export interface RouteCorsRule {
430
+ allowedOrigins: string[];
431
+ allowedMethods?: string[];
432
+ allowedHeaders?: string[];
433
+ exposeHeaders?: string[];
434
+ maxAgeSeconds?: number;
435
+ allowCredentials?: boolean;
436
+ }
437
+ export interface RouteContentSpec {
438
+ subpath?: string;
439
+ cors?: RouteCorsRule[];
440
+ index?: boolean;
441
+ iap?: boolean;
442
+ compression?: "brotli" | "gzip" | "none";
443
+ }
444
+ interface RoutePathBase {
429
445
  path?: string;
430
446
  pathType?: "prefix" | "exact";
431
447
  stripPrefix?: boolean;
432
- targetPort: string | number;
433
448
  }
449
+ export type RoutePathSpec = RoutePathBase & ({
450
+ targetPort: string | number;
451
+ targetContent?: never;
452
+ } | {
453
+ targetContent: RouteContentSpec;
454
+ targetPort?: never;
455
+ });
434
456
  export interface RouteSpec {
435
457
  version: "v1";
436
458
  kind: "Route";
@@ -584,14 +606,17 @@ export declare class Meshagent {
584
606
  projectId: string;
585
607
  path: string;
586
608
  }): Promise<Uint8Array>;
587
- createProject(name: string, settings?: Record<string, unknown>): Promise<Record<string, unknown>>;
609
+ createProject(name: string): Promise<Record<string, unknown>>;
588
610
  addUserToProject(projectId: string, userId: string, options?: {
589
611
  roles?: ProjectRole[];
590
612
  email?: string;
591
613
  inviteRedirectUrl?: string;
592
614
  }): Promise<Record<string, unknown>>;
593
615
  removeUserFromProject(projectId: string, userId: string): Promise<Record<string, unknown>>;
594
- updateProjectSettings(projectId: string, settings: Record<string, unknown>): Promise<Record<string, unknown>>;
616
+ private projectSettingsDocumentPath;
617
+ getProjectSettingsDocument(projectId: string, name: ProjectSettingsDocumentName): Promise<Record<string, unknown> | undefined>;
618
+ setProjectSettingsDocument(projectId: string, name: ProjectSettingsDocumentName, document: Record<string, unknown>): Promise<Record<string, unknown>>;
619
+ deleteProjectSettingsDocument(projectId: string, name: ProjectSettingsDocumentName): Promise<Record<string, unknown>>;
595
620
  updateUserInProject(projectId: string, userId: string, roles: ProjectRole[]): Promise<Record<string, unknown>>;
596
621
  getUsersInProjectPage(projectId: string, options?: {
597
622
  pageSize?: number;
@@ -245,7 +245,7 @@ export class Meshagent {
245
245
  return url.toString();
246
246
  }
247
247
  async request(path, options) {
248
- const { method = "GET", query, json, body, headers, action, responseType = "json" } = options;
248
+ const { method = "GET", query, json, body, headers, action, responseType = "json", returnUndefinedOnNotFound = false } = options;
249
249
  const url = this.buildUrl(path, query);
250
250
  const finalHeaders = {};
251
251
  if (this.token) {
@@ -274,6 +274,9 @@ export class Meshagent {
274
274
  headers: finalHeaders,
275
275
  body: toFetchBody(requestBody),
276
276
  });
277
+ if (response.status === 404 && returnUndefinedOnNotFound) {
278
+ return undefined;
279
+ }
277
280
  if (!response.ok) {
278
281
  let message;
279
282
  try {
@@ -862,10 +865,10 @@ export class Meshagent {
862
865
  responseType: "arrayBuffer",
863
866
  });
864
867
  }
865
- async createProject(name, settings) {
868
+ async createProject(name) {
866
869
  return await this.request(`/accounts/projects`, {
867
870
  method: "POST",
868
- json: { name, settings },
871
+ json: { name },
869
872
  action: "create project",
870
873
  });
871
874
  }
@@ -889,11 +892,26 @@ export class Meshagent {
889
892
  action: "remove user from project",
890
893
  });
891
894
  }
892
- async updateProjectSettings(projectId, settings) {
893
- return await this.request(`/accounts/projects/${projectId}/settings`, {
895
+ projectSettingsDocumentPath(name) {
896
+ return name === "room_roles" ? "room-roles" : name;
897
+ }
898
+ async getProjectSettingsDocument(projectId, name) {
899
+ return await this.request(`/accounts/projects/${projectId}/settings/${this.projectSettingsDocumentPath(name)}`, {
900
+ action: `get ${name} project settings`,
901
+ returnUndefinedOnNotFound: true,
902
+ });
903
+ }
904
+ async setProjectSettingsDocument(projectId, name, document) {
905
+ return await this.request(`/accounts/projects/${projectId}/settings/${this.projectSettingsDocumentPath(name)}`, {
894
906
  method: "PUT",
895
- json: settings,
896
- action: "update project settings",
907
+ json: document,
908
+ action: `set ${name} project settings`,
909
+ });
910
+ }
911
+ async deleteProjectSettingsDocument(projectId, name) {
912
+ return await this.request(`/accounts/projects/${projectId}/settings/${this.projectSettingsDocumentPath(name)}`, {
913
+ method: "DELETE",
914
+ action: `delete ${name} project settings`,
897
915
  });
898
916
  }
899
917
  async updateUserInProject(projectId, userId, roles) {
@@ -689,8 +689,15 @@ export class MessagingClient extends EventEmitter {
689
689
  break;
690
690
  }
691
691
  const event = new RoomMessageEvent({ message });
692
- this.client.emit(event);
693
- this.emit("message", event);
692
+ try {
693
+ this.client.emit(event);
694
+ this.emit("message", event);
695
+ }
696
+ finally {
697
+ if (message.type === "dismiss") {
698
+ this.client._dismiss();
699
+ }
700
+ }
694
701
  }
695
702
  _onParticipantEnabled(message) {
696
703
  const data = message.message;
@@ -78,6 +78,7 @@ export declare class RoomClient {
78
78
  private _localParticipantReady;
79
79
  private _connected;
80
80
  private _closing;
81
+ private _dismissed;
81
82
  private _localParticipant;
82
83
  private _lifecycleTask;
83
84
  private _terminalState;
@@ -169,6 +170,7 @@ export declare class RoomClient {
169
170
  private _retryProtocolConnection;
170
171
  private _reconnect;
171
172
  private _connectionLifecycle;
173
+ _dismiss(): void;
172
174
  dispose(): void;
173
175
  _sendProtocolNowait({ type, data, label, messageId, expectResponse, }: {
174
176
  type: string;
@@ -221,6 +221,7 @@ export class RoomClient {
221
221
  this._localParticipantReady = new Completer();
222
222
  this._connected = false;
223
223
  this._closing = false;
224
+ this._dismissed = false;
224
225
  this._localParticipant = null;
225
226
  this._lifecycleTask = null;
226
227
  this._terminalState = null;
@@ -878,7 +879,7 @@ export class RoomClient {
878
879
  const deadline = this._reconnectTimeout == null ? null : Date.now() + this._reconnectTimeout;
879
880
  let firstAttempt = true;
880
881
  let retryCount = 0;
881
- while (!this._closing) {
882
+ while (!this._closing && !this._dismissed) {
882
883
  if (firstAttempt) {
883
884
  firstAttempt = false;
884
885
  if (this._reconnectTimeout == null) {
@@ -1009,7 +1010,7 @@ export class RoomClient {
1009
1010
  this._completeRoomClosed();
1010
1011
  return;
1011
1012
  }
1012
- if (closeKind !== ProtocolCloseKind.ERROR) {
1013
+ if (closeKind !== ProtocolCloseKind.ERROR || this._dismissed) {
1013
1014
  this._setTerminalState({ state });
1014
1015
  }
1015
1016
  this._markDisconnected({ reason: closeReason, kind: closeKind });
@@ -1021,7 +1022,7 @@ export class RoomClient {
1021
1022
  this.messaging._onRoomDisconnect({ reason: closeReason });
1022
1023
  await this._failPendingWork({ state });
1023
1024
  await this._closeProtocol(protocol);
1024
- if (closeKind === ProtocolCloseKind.ERROR) {
1025
+ if (closeKind === ProtocolCloseKind.ERROR && !this._dismissed) {
1025
1026
  if (this._reconnectTimeout === 0) {
1026
1027
  if (closeReason == null) {
1027
1028
  console.warn("room connection lost; automatic reconnect disabled");
@@ -1050,6 +1051,13 @@ export class RoomClient {
1050
1051
  return;
1051
1052
  }
1052
1053
  }
1054
+ _dismiss() {
1055
+ if (this._closing || this._dismissed) {
1056
+ return;
1057
+ }
1058
+ this._dismissed = true;
1059
+ this._protocolInstance.dispose();
1060
+ }
1053
1061
  dispose() {
1054
1062
  this._closing = true;
1055
1063
  this._markDisconnected({
@@ -1,7 +1,8 @@
1
1
  import { ApiScope } from "./participant-token.js";
2
2
  export type ProjectRole = "member" | "admin" | "developer" | "room_creator" | "room_inventory" | "room_manager" | "session_inventory" | "agent_creator" | "agent_inventory" | "agent_manager" | "repository_creator" | "repository_inventory" | "repository_manager" | "feed_creator" | "feed_inventory" | "feed_manager" | "oauth_client_creator" | "oauth_client_inventory" | "oauth_client_manager" | "api_key_creator" | "api_key_inventory" | "api_key_manager" | "service_creator" | "service_inventory" | "service_manager" | "service_account_creator" | "service_account_inventory" | "service_account_manager" | "participant_token_creator" | "mailbox_creator" | "mailbox_inventory" | "mailbox_manager" | "route_creator" | "route_inventory" | "route_manager" | "scheduled_task_creator" | "scheduled_task_inventory" | "scheduled_task_manager" | "feed_subscription_creator" | "feed_subscription_inventory" | "feed_subscription_manager" | "llm_logger_creator" | "llm_logger_inventory" | "llm_logger_manager" | "llm_proxy_user" | "usage_reporter" | "billing_manager" | "group_manager";
3
3
  export type ResourceRole = "viewer" | "operator" | "developer" | "admin";
4
- export type RoomRole = "site_user" | ResourceRole;
4
+ export type RoomRole = "site_user" | "guest" | ResourceRole;
5
+ export type ProjectSettingsDocumentName = "openai" | "anthropic" | "otel" | "admission" | "room" | "room_roles";
5
6
  export type FeedRole = "reader" | "subscriber" | "publisher" | "manager";
6
7
  export type SecretRole = "use_proxy";
7
8
  export type AccessRole = ProjectRole | RoomRole | FeedRole | SecretRole | "list";
@@ -425,12 +426,33 @@ export interface RouteBackend {
425
426
  room?: RouteBackendTarget | null;
426
427
  agent?: RouteBackendTarget | null;
427
428
  }
428
- export interface RoutePathSpec {
429
+ export interface RouteCorsRule {
430
+ allowedOrigins: string[];
431
+ allowedMethods?: string[];
432
+ allowedHeaders?: string[];
433
+ exposeHeaders?: string[];
434
+ maxAgeSeconds?: number;
435
+ allowCredentials?: boolean;
436
+ }
437
+ export interface RouteContentSpec {
438
+ subpath?: string;
439
+ cors?: RouteCorsRule[];
440
+ index?: boolean;
441
+ iap?: boolean;
442
+ compression?: "brotli" | "gzip" | "none";
443
+ }
444
+ interface RoutePathBase {
429
445
  path?: string;
430
446
  pathType?: "prefix" | "exact";
431
447
  stripPrefix?: boolean;
432
- targetPort: string | number;
433
448
  }
449
+ export type RoutePathSpec = RoutePathBase & ({
450
+ targetPort: string | number;
451
+ targetContent?: never;
452
+ } | {
453
+ targetContent: RouteContentSpec;
454
+ targetPort?: never;
455
+ });
434
456
  export interface RouteSpec {
435
457
  version: "v1";
436
458
  kind: "Route";
@@ -584,14 +606,17 @@ export declare class Meshagent {
584
606
  projectId: string;
585
607
  path: string;
586
608
  }): Promise<Uint8Array>;
587
- createProject(name: string, settings?: Record<string, unknown>): Promise<Record<string, unknown>>;
609
+ createProject(name: string): Promise<Record<string, unknown>>;
588
610
  addUserToProject(projectId: string, userId: string, options?: {
589
611
  roles?: ProjectRole[];
590
612
  email?: string;
591
613
  inviteRedirectUrl?: string;
592
614
  }): Promise<Record<string, unknown>>;
593
615
  removeUserFromProject(projectId: string, userId: string): Promise<Record<string, unknown>>;
594
- updateProjectSettings(projectId: string, settings: Record<string, unknown>): Promise<Record<string, unknown>>;
616
+ private projectSettingsDocumentPath;
617
+ getProjectSettingsDocument(projectId: string, name: ProjectSettingsDocumentName): Promise<Record<string, unknown> | undefined>;
618
+ setProjectSettingsDocument(projectId: string, name: ProjectSettingsDocumentName, document: Record<string, unknown>): Promise<Record<string, unknown>>;
619
+ deleteProjectSettingsDocument(projectId: string, name: ProjectSettingsDocumentName): Promise<Record<string, unknown>>;
595
620
  updateUserInProject(projectId: string, userId: string, roles: ProjectRole[]): Promise<Record<string, unknown>>;
596
621
  getUsersInProjectPage(projectId: string, options?: {
597
622
  pageSize?: number;
@@ -250,7 +250,7 @@ class Meshagent {
250
250
  return url.toString();
251
251
  }
252
252
  async request(path, options) {
253
- const { method = "GET", query, json, body, headers, action, responseType = "json" } = options;
253
+ const { method = "GET", query, json, body, headers, action, responseType = "json", returnUndefinedOnNotFound = false } = options;
254
254
  const url = this.buildUrl(path, query);
255
255
  const finalHeaders = {};
256
256
  if (this.token) {
@@ -279,6 +279,9 @@ class Meshagent {
279
279
  headers: finalHeaders,
280
280
  body: toFetchBody(requestBody),
281
281
  });
282
+ if (response.status === 404 && returnUndefinedOnNotFound) {
283
+ return undefined;
284
+ }
282
285
  if (!response.ok) {
283
286
  let message;
284
287
  try {
@@ -867,10 +870,10 @@ class Meshagent {
867
870
  responseType: "arrayBuffer",
868
871
  });
869
872
  }
870
- async createProject(name, settings) {
873
+ async createProject(name) {
871
874
  return await this.request(`/accounts/projects`, {
872
875
  method: "POST",
873
- json: { name, settings },
876
+ json: { name },
874
877
  action: "create project",
875
878
  });
876
879
  }
@@ -894,11 +897,26 @@ class Meshagent {
894
897
  action: "remove user from project",
895
898
  });
896
899
  }
897
- async updateProjectSettings(projectId, settings) {
898
- return await this.request(`/accounts/projects/${projectId}/settings`, {
900
+ projectSettingsDocumentPath(name) {
901
+ return name === "room_roles" ? "room-roles" : name;
902
+ }
903
+ async getProjectSettingsDocument(projectId, name) {
904
+ return await this.request(`/accounts/projects/${projectId}/settings/${this.projectSettingsDocumentPath(name)}`, {
905
+ action: `get ${name} project settings`,
906
+ returnUndefinedOnNotFound: true,
907
+ });
908
+ }
909
+ async setProjectSettingsDocument(projectId, name, document) {
910
+ return await this.request(`/accounts/projects/${projectId}/settings/${this.projectSettingsDocumentPath(name)}`, {
899
911
  method: "PUT",
900
- json: settings,
901
- action: "update project settings",
912
+ json: document,
913
+ action: `set ${name} project settings`,
914
+ });
915
+ }
916
+ async deleteProjectSettingsDocument(projectId, name) {
917
+ return await this.request(`/accounts/projects/${projectId}/settings/${this.projectSettingsDocumentPath(name)}`, {
918
+ method: "DELETE",
919
+ action: `delete ${name} project settings`,
902
920
  });
903
921
  }
904
922
  async updateUserInProject(projectId, userId, roles) {
@@ -693,8 +693,15 @@ class MessagingClient extends event_emitter_js_1.EventEmitter {
693
693
  break;
694
694
  }
695
695
  const event = new room_event_js_1.RoomMessageEvent({ message });
696
- this.client.emit(event);
697
- this.emit("message", event);
696
+ try {
697
+ this.client.emit(event);
698
+ this.emit("message", event);
699
+ }
700
+ finally {
701
+ if (message.type === "dismiss") {
702
+ this.client._dismiss();
703
+ }
704
+ }
698
705
  }
699
706
  _onParticipantEnabled(message) {
700
707
  const data = message.message;
@@ -78,6 +78,7 @@ export declare class RoomClient {
78
78
  private _localParticipantReady;
79
79
  private _connected;
80
80
  private _closing;
81
+ private _dismissed;
81
82
  private _localParticipant;
82
83
  private _lifecycleTask;
83
84
  private _terminalState;
@@ -169,6 +170,7 @@ export declare class RoomClient {
169
170
  private _retryProtocolConnection;
170
171
  private _reconnect;
171
172
  private _connectionLifecycle;
173
+ _dismiss(): void;
172
174
  dispose(): void;
173
175
  _sendProtocolNowait({ type, data, label, messageId, expectResponse, }: {
174
176
  type: string;
@@ -225,6 +225,7 @@ class RoomClient {
225
225
  this._localParticipantReady = new completer_js_1.Completer();
226
226
  this._connected = false;
227
227
  this._closing = false;
228
+ this._dismissed = false;
228
229
  this._localParticipant = null;
229
230
  this._lifecycleTask = null;
230
231
  this._terminalState = null;
@@ -882,7 +883,7 @@ class RoomClient {
882
883
  const deadline = this._reconnectTimeout == null ? null : Date.now() + this._reconnectTimeout;
883
884
  let firstAttempt = true;
884
885
  let retryCount = 0;
885
- while (!this._closing) {
886
+ while (!this._closing && !this._dismissed) {
886
887
  if (firstAttempt) {
887
888
  firstAttempt = false;
888
889
  if (this._reconnectTimeout == null) {
@@ -1013,7 +1014,7 @@ class RoomClient {
1013
1014
  this._completeRoomClosed();
1014
1015
  return;
1015
1016
  }
1016
- if (closeKind !== protocol_js_1.ProtocolCloseKind.ERROR) {
1017
+ if (closeKind !== protocol_js_1.ProtocolCloseKind.ERROR || this._dismissed) {
1017
1018
  this._setTerminalState({ state });
1018
1019
  }
1019
1020
  this._markDisconnected({ reason: closeReason, kind: closeKind });
@@ -1025,7 +1026,7 @@ class RoomClient {
1025
1026
  this.messaging._onRoomDisconnect({ reason: closeReason });
1026
1027
  await this._failPendingWork({ state });
1027
1028
  await this._closeProtocol(protocol);
1028
- if (closeKind === protocol_js_1.ProtocolCloseKind.ERROR) {
1029
+ if (closeKind === protocol_js_1.ProtocolCloseKind.ERROR && !this._dismissed) {
1029
1030
  if (this._reconnectTimeout === 0) {
1030
1031
  if (closeReason == null) {
1031
1032
  console.warn("room connection lost; automatic reconnect disabled");
@@ -1054,6 +1055,13 @@ class RoomClient {
1054
1055
  return;
1055
1056
  }
1056
1057
  }
1058
+ _dismiss() {
1059
+ if (this._closing || this._dismissed) {
1060
+ return;
1061
+ }
1062
+ this._dismissed = true;
1063
+ this._protocolInstance.dispose();
1064
+ }
1057
1065
  dispose() {
1058
1066
  this._closing = true;
1059
1067
  this._markDisconnected({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshagent/meshagent",
3
- "version": "0.48.0",
3
+ "version": "0.49.1",
4
4
  "description": "Meshagent Client",
5
5
  "homepage": "https://github.com/meshagent/meshagent-ts",
6
6
  "scripts": {