@meshagent/meshagent 0.53.1 → 0.53.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,7 @@
1
+ ## [0.53.2]
2
+ - Added project profile views, inheritance updates, typed profile models, and sysadmin global user search and profile administration.
3
+ - Project updates now use project-local overrides and require `user_profile_editor`; global profile access is self-only and global annotations require sysadmin APIs.
4
+
1
5
  ## [0.53.1]
2
6
  - Stability
3
7
 
@@ -6,8 +10,10 @@
6
10
  - Added the `user_profile_editor` project role and support for partial profile updates with metadata, annotations, and project ID options.
7
11
 
8
12
  ## [Unreleased]
13
+ - Added project-scoped profile reads and writes, `project`/`user`/`merged` views, and typed inheritance fields. Project user listings default to merged profiles.
14
+ - Added sysadmin global user search, profile reads, and profile updates.
9
15
  - Added user profile metadata and string annotations to project-member models, plus `metadata`, `annotations`, and `projectId` options on `updateUserProfile`. Omitted fields are preserved; supplied maps replace their previous contents.
10
- - Added `user_profile_editor` to project role types and parsing. Project owners and admins inherit profile editing; ordinary users can edit their own names and metadata.
16
+ - Added `user_profile_editor` to project role types and parsing. Project owners and admins inherit project profile editing; ordinary users can edit their own global names and metadata.
11
17
 
12
18
  ## [0.52.4]
13
19
  - Stability
@@ -126,6 +126,20 @@ export interface ResourcePolicyPage {
126
126
  accessGrants: ProjectRoomGrant[];
127
127
  continuationToken?: string | null;
128
128
  }
129
+ export type UserProfileView = "project" | "user" | "merged";
130
+ export type UserProfileField = "first_name" | "last_name" | "metadata" | "annotations";
131
+ export interface UserProfile {
132
+ id: string;
133
+ email: string;
134
+ first_name: string | null;
135
+ last_name: string | null;
136
+ metadata: Record<string, unknown>;
137
+ annotations: Record<string, string>;
138
+ }
139
+ export interface UserProfilesPage {
140
+ users: UserProfile[];
141
+ continuation_token: string | null;
142
+ }
129
143
  export interface ProjectMember {
130
144
  id: string;
131
145
  email: string;
@@ -659,14 +673,28 @@ export declare class Meshagent {
659
673
  continuationToken?: string;
660
674
  filter?: string;
661
675
  email?: string;
676
+ view?: UserProfileView;
662
677
  }): Promise<ProjectMembersPage>;
663
- getUsersInProject(projectId: string): Promise<ProjectMember[]>;
664
- getUserProfile(userId: string): Promise<Record<string, unknown>>;
665
- updateUserProfile(userId: string, firstName?: string, lastName?: string, options?: {
678
+ getUsersInProject(projectId: string, options?: {
679
+ view?: UserProfileView;
680
+ }): Promise<ProjectMember[]>;
681
+ getUserProfile(userId: string, options?: {
682
+ projectId?: string;
683
+ view?: UserProfileView;
684
+ }): Promise<Record<string, unknown>>;
685
+ updateUserProfile(userId: string, firstName?: string | null, lastName?: string | null, options?: {
666
686
  metadata?: Record<string, unknown>;
667
687
  annotations?: Record<string, string>;
668
688
  projectId?: string;
689
+ inherit?: UserProfileField[];
669
690
  }): Promise<Record<string, unknown>>;
691
+ searchSysadminUsers(options?: {
692
+ filter?: string;
693
+ pageSize?: number;
694
+ continuationToken?: string;
695
+ }): Promise<UserProfilesPage>;
696
+ getSysadminUserProfile(userId: string): Promise<UserProfile>;
697
+ updateSysadminUserProfile(userId: string, fields: Partial<Pick<UserProfile, UserProfileField>>): Promise<Record<string, unknown>>;
670
698
  listProjects(): Promise<Record<string, unknown>>;
671
699
  getProject(projectId: string): Promise<Record<string, unknown>>;
672
700
  getProjectByKey(projectKey: string): Promise<Record<string, unknown>>;
@@ -1001,36 +1001,69 @@ class Meshagent {
1001
1001
  });
1002
1002
  }
1003
1003
  async getUsersInProjectPage(projectId, options = {}) {
1004
- const { pageSize = 100, continuationToken, filter, email } = options;
1004
+ const { pageSize = 100, continuationToken, filter, email, view = "merged" } = options;
1005
1005
  const data = await this.request(`/accounts/projects/${projectId}/users`, {
1006
- query: { page_size: pageSize, continuation_token: continuationToken, filter, email },
1006
+ query: { page_size: pageSize, continuation_token: continuationToken, filter, email, view },
1007
1007
  action: "fetch project users",
1008
1008
  });
1009
1009
  const users = Array.isArray(data?.users) ? data.users : [];
1010
1010
  return { users: users.map((user) => this.parseProjectMember(user)), continuationToken: data?.continuation_token ?? null };
1011
1011
  }
1012
- async getUsersInProject(projectId) {
1013
- const page = await this.getUsersInProjectPage(projectId);
1012
+ async getUsersInProject(projectId, options = {}) {
1013
+ const page = await this.getUsersInProjectPage(projectId, options);
1014
1014
  return page.users;
1015
1015
  }
1016
- async getUserProfile(userId) {
1017
- return await this.request(`/accounts/profiles/${userId}`, {
1016
+ async getUserProfile(userId, options = {}) {
1017
+ if (options.projectId === undefined && options.view === "project") {
1018
+ throw new Error("projectId is required for the project view");
1019
+ }
1020
+ const userPath = encodeURIComponent(userId);
1021
+ const path = options.projectId === undefined
1022
+ ? `/accounts/profiles/${userPath}`
1023
+ : `/accounts/projects/${encodeURIComponent(options.projectId)}/users/${userPath}/profile`;
1024
+ return await this.request(path, {
1025
+ query: options.projectId === undefined ? undefined : { view: options.view ?? "merged" },
1018
1026
  action: "fetch user profile",
1019
1027
  });
1020
1028
  }
1021
1029
  async updateUserProfile(userId, firstName, lastName, options = {}) {
1022
- const query = options.projectId === undefined ? "" : `?project_id=${encodeURIComponent(options.projectId)}`;
1023
- return await this.request(`/accounts/profiles/${encodeURIComponent(userId)}${query}`, {
1030
+ if (options.projectId === undefined && options.inherit !== undefined) {
1031
+ throw new Error("projectId is required to inherit profile fields");
1032
+ }
1033
+ const userPath = encodeURIComponent(userId);
1034
+ const path = options.projectId === undefined
1035
+ ? `/accounts/profiles/${userPath}`
1036
+ : `/accounts/projects/${encodeURIComponent(options.projectId)}/users/${userPath}/profile`;
1037
+ return await this.request(path, {
1024
1038
  method: "PUT",
1025
1039
  json: {
1026
1040
  ...(firstName !== undefined ? { first_name: firstName } : {}),
1027
1041
  ...(lastName !== undefined ? { last_name: lastName } : {}),
1028
1042
  ...(options.metadata !== undefined ? { metadata: options.metadata } : {}),
1029
1043
  ...(options.annotations !== undefined ? { annotations: options.annotations } : {}),
1044
+ ...(options.inherit !== undefined ? { inherit: options.inherit } : {}),
1030
1045
  },
1031
1046
  action: "update user profile",
1032
1047
  });
1033
1048
  }
1049
+ async searchSysadminUsers(options = {}) {
1050
+ return await this.request(`/accounts/sysadmin/users`, {
1051
+ query: { filter: options.filter, page_size: options.pageSize ?? 100, continuation_token: options.continuationToken },
1052
+ action: "search global users",
1053
+ });
1054
+ }
1055
+ async getSysadminUserProfile(userId) {
1056
+ return await this.request(`/accounts/sysadmin/users/${encodeURIComponent(userId)}`, {
1057
+ action: "fetch global user profile",
1058
+ });
1059
+ }
1060
+ async updateSysadminUserProfile(userId, fields) {
1061
+ return await this.request(`/accounts/sysadmin/users/${encodeURIComponent(userId)}`, {
1062
+ method: "PUT",
1063
+ json: fields,
1064
+ action: "update global user profile",
1065
+ });
1066
+ }
1034
1067
  async listProjects() {
1035
1068
  return await this.request(`/accounts/projects`, {
1036
1069
  action: "list projects",
@@ -126,6 +126,20 @@ export interface ResourcePolicyPage {
126
126
  accessGrants: ProjectRoomGrant[];
127
127
  continuationToken?: string | null;
128
128
  }
129
+ export type UserProfileView = "project" | "user" | "merged";
130
+ export type UserProfileField = "first_name" | "last_name" | "metadata" | "annotations";
131
+ export interface UserProfile {
132
+ id: string;
133
+ email: string;
134
+ first_name: string | null;
135
+ last_name: string | null;
136
+ metadata: Record<string, unknown>;
137
+ annotations: Record<string, string>;
138
+ }
139
+ export interface UserProfilesPage {
140
+ users: UserProfile[];
141
+ continuation_token: string | null;
142
+ }
129
143
  export interface ProjectMember {
130
144
  id: string;
131
145
  email: string;
@@ -659,14 +673,28 @@ export declare class Meshagent {
659
673
  continuationToken?: string;
660
674
  filter?: string;
661
675
  email?: string;
676
+ view?: UserProfileView;
662
677
  }): Promise<ProjectMembersPage>;
663
- getUsersInProject(projectId: string): Promise<ProjectMember[]>;
664
- getUserProfile(userId: string): Promise<Record<string, unknown>>;
665
- updateUserProfile(userId: string, firstName?: string, lastName?: string, options?: {
678
+ getUsersInProject(projectId: string, options?: {
679
+ view?: UserProfileView;
680
+ }): Promise<ProjectMember[]>;
681
+ getUserProfile(userId: string, options?: {
682
+ projectId?: string;
683
+ view?: UserProfileView;
684
+ }): Promise<Record<string, unknown>>;
685
+ updateUserProfile(userId: string, firstName?: string | null, lastName?: string | null, options?: {
666
686
  metadata?: Record<string, unknown>;
667
687
  annotations?: Record<string, string>;
668
688
  projectId?: string;
689
+ inherit?: UserProfileField[];
669
690
  }): Promise<Record<string, unknown>>;
691
+ searchSysadminUsers(options?: {
692
+ filter?: string;
693
+ pageSize?: number;
694
+ continuationToken?: string;
695
+ }): Promise<UserProfilesPage>;
696
+ getSysadminUserProfile(userId: string): Promise<UserProfile>;
697
+ updateSysadminUserProfile(userId: string, fields: Partial<Pick<UserProfile, UserProfileField>>): Promise<Record<string, unknown>>;
670
698
  listProjects(): Promise<Record<string, unknown>>;
671
699
  getProject(projectId: string): Promise<Record<string, unknown>>;
672
700
  getProjectByKey(projectKey: string): Promise<Record<string, unknown>>;
@@ -996,36 +996,69 @@ export class Meshagent {
996
996
  });
997
997
  }
998
998
  async getUsersInProjectPage(projectId, options = {}) {
999
- const { pageSize = 100, continuationToken, filter, email } = options;
999
+ const { pageSize = 100, continuationToken, filter, email, view = "merged" } = options;
1000
1000
  const data = await this.request(`/accounts/projects/${projectId}/users`, {
1001
- query: { page_size: pageSize, continuation_token: continuationToken, filter, email },
1001
+ query: { page_size: pageSize, continuation_token: continuationToken, filter, email, view },
1002
1002
  action: "fetch project users",
1003
1003
  });
1004
1004
  const users = Array.isArray(data?.users) ? data.users : [];
1005
1005
  return { users: users.map((user) => this.parseProjectMember(user)), continuationToken: data?.continuation_token ?? null };
1006
1006
  }
1007
- async getUsersInProject(projectId) {
1008
- const page = await this.getUsersInProjectPage(projectId);
1007
+ async getUsersInProject(projectId, options = {}) {
1008
+ const page = await this.getUsersInProjectPage(projectId, options);
1009
1009
  return page.users;
1010
1010
  }
1011
- async getUserProfile(userId) {
1012
- return await this.request(`/accounts/profiles/${userId}`, {
1011
+ async getUserProfile(userId, options = {}) {
1012
+ if (options.projectId === undefined && options.view === "project") {
1013
+ throw new Error("projectId is required for the project view");
1014
+ }
1015
+ const userPath = encodeURIComponent(userId);
1016
+ const path = options.projectId === undefined
1017
+ ? `/accounts/profiles/${userPath}`
1018
+ : `/accounts/projects/${encodeURIComponent(options.projectId)}/users/${userPath}/profile`;
1019
+ return await this.request(path, {
1020
+ query: options.projectId === undefined ? undefined : { view: options.view ?? "merged" },
1013
1021
  action: "fetch user profile",
1014
1022
  });
1015
1023
  }
1016
1024
  async updateUserProfile(userId, firstName, lastName, options = {}) {
1017
- const query = options.projectId === undefined ? "" : `?project_id=${encodeURIComponent(options.projectId)}`;
1018
- return await this.request(`/accounts/profiles/${encodeURIComponent(userId)}${query}`, {
1025
+ if (options.projectId === undefined && options.inherit !== undefined) {
1026
+ throw new Error("projectId is required to inherit profile fields");
1027
+ }
1028
+ const userPath = encodeURIComponent(userId);
1029
+ const path = options.projectId === undefined
1030
+ ? `/accounts/profiles/${userPath}`
1031
+ : `/accounts/projects/${encodeURIComponent(options.projectId)}/users/${userPath}/profile`;
1032
+ return await this.request(path, {
1019
1033
  method: "PUT",
1020
1034
  json: {
1021
1035
  ...(firstName !== undefined ? { first_name: firstName } : {}),
1022
1036
  ...(lastName !== undefined ? { last_name: lastName } : {}),
1023
1037
  ...(options.metadata !== undefined ? { metadata: options.metadata } : {}),
1024
1038
  ...(options.annotations !== undefined ? { annotations: options.annotations } : {}),
1039
+ ...(options.inherit !== undefined ? { inherit: options.inherit } : {}),
1025
1040
  },
1026
1041
  action: "update user profile",
1027
1042
  });
1028
1043
  }
1044
+ async searchSysadminUsers(options = {}) {
1045
+ return await this.request(`/accounts/sysadmin/users`, {
1046
+ query: { filter: options.filter, page_size: options.pageSize ?? 100, continuation_token: options.continuationToken },
1047
+ action: "search global users",
1048
+ });
1049
+ }
1050
+ async getSysadminUserProfile(userId) {
1051
+ return await this.request(`/accounts/sysadmin/users/${encodeURIComponent(userId)}`, {
1052
+ action: "fetch global user profile",
1053
+ });
1054
+ }
1055
+ async updateSysadminUserProfile(userId, fields) {
1056
+ return await this.request(`/accounts/sysadmin/users/${encodeURIComponent(userId)}`, {
1057
+ method: "PUT",
1058
+ json: fields,
1059
+ action: "update global user profile",
1060
+ });
1061
+ }
1029
1062
  async listProjects() {
1030
1063
  return await this.request(`/accounts/projects`, {
1031
1064
  action: "list projects",
@@ -126,6 +126,20 @@ export interface ResourcePolicyPage {
126
126
  accessGrants: ProjectRoomGrant[];
127
127
  continuationToken?: string | null;
128
128
  }
129
+ export type UserProfileView = "project" | "user" | "merged";
130
+ export type UserProfileField = "first_name" | "last_name" | "metadata" | "annotations";
131
+ export interface UserProfile {
132
+ id: string;
133
+ email: string;
134
+ first_name: string | null;
135
+ last_name: string | null;
136
+ metadata: Record<string, unknown>;
137
+ annotations: Record<string, string>;
138
+ }
139
+ export interface UserProfilesPage {
140
+ users: UserProfile[];
141
+ continuation_token: string | null;
142
+ }
129
143
  export interface ProjectMember {
130
144
  id: string;
131
145
  email: string;
@@ -659,14 +673,28 @@ export declare class Meshagent {
659
673
  continuationToken?: string;
660
674
  filter?: string;
661
675
  email?: string;
676
+ view?: UserProfileView;
662
677
  }): Promise<ProjectMembersPage>;
663
- getUsersInProject(projectId: string): Promise<ProjectMember[]>;
664
- getUserProfile(userId: string): Promise<Record<string, unknown>>;
665
- updateUserProfile(userId: string, firstName?: string, lastName?: string, options?: {
678
+ getUsersInProject(projectId: string, options?: {
679
+ view?: UserProfileView;
680
+ }): Promise<ProjectMember[]>;
681
+ getUserProfile(userId: string, options?: {
682
+ projectId?: string;
683
+ view?: UserProfileView;
684
+ }): Promise<Record<string, unknown>>;
685
+ updateUserProfile(userId: string, firstName?: string | null, lastName?: string | null, options?: {
666
686
  metadata?: Record<string, unknown>;
667
687
  annotations?: Record<string, string>;
668
688
  projectId?: string;
689
+ inherit?: UserProfileField[];
669
690
  }): Promise<Record<string, unknown>>;
691
+ searchSysadminUsers(options?: {
692
+ filter?: string;
693
+ pageSize?: number;
694
+ continuationToken?: string;
695
+ }): Promise<UserProfilesPage>;
696
+ getSysadminUserProfile(userId: string): Promise<UserProfile>;
697
+ updateSysadminUserProfile(userId: string, fields: Partial<Pick<UserProfile, UserProfileField>>): Promise<Record<string, unknown>>;
670
698
  listProjects(): Promise<Record<string, unknown>>;
671
699
  getProject(projectId: string): Promise<Record<string, unknown>>;
672
700
  getProjectByKey(projectKey: string): Promise<Record<string, unknown>>;
@@ -1001,36 +1001,69 @@ class Meshagent {
1001
1001
  });
1002
1002
  }
1003
1003
  async getUsersInProjectPage(projectId, options = {}) {
1004
- const { pageSize = 100, continuationToken, filter, email } = options;
1004
+ const { pageSize = 100, continuationToken, filter, email, view = "merged" } = options;
1005
1005
  const data = await this.request(`/accounts/projects/${projectId}/users`, {
1006
- query: { page_size: pageSize, continuation_token: continuationToken, filter, email },
1006
+ query: { page_size: pageSize, continuation_token: continuationToken, filter, email, view },
1007
1007
  action: "fetch project users",
1008
1008
  });
1009
1009
  const users = Array.isArray(data?.users) ? data.users : [];
1010
1010
  return { users: users.map((user) => this.parseProjectMember(user)), continuationToken: data?.continuation_token ?? null };
1011
1011
  }
1012
- async getUsersInProject(projectId) {
1013
- const page = await this.getUsersInProjectPage(projectId);
1012
+ async getUsersInProject(projectId, options = {}) {
1013
+ const page = await this.getUsersInProjectPage(projectId, options);
1014
1014
  return page.users;
1015
1015
  }
1016
- async getUserProfile(userId) {
1017
- return await this.request(`/accounts/profiles/${userId}`, {
1016
+ async getUserProfile(userId, options = {}) {
1017
+ if (options.projectId === undefined && options.view === "project") {
1018
+ throw new Error("projectId is required for the project view");
1019
+ }
1020
+ const userPath = encodeURIComponent(userId);
1021
+ const path = options.projectId === undefined
1022
+ ? `/accounts/profiles/${userPath}`
1023
+ : `/accounts/projects/${encodeURIComponent(options.projectId)}/users/${userPath}/profile`;
1024
+ return await this.request(path, {
1025
+ query: options.projectId === undefined ? undefined : { view: options.view ?? "merged" },
1018
1026
  action: "fetch user profile",
1019
1027
  });
1020
1028
  }
1021
1029
  async updateUserProfile(userId, firstName, lastName, options = {}) {
1022
- const query = options.projectId === undefined ? "" : `?project_id=${encodeURIComponent(options.projectId)}`;
1023
- return await this.request(`/accounts/profiles/${encodeURIComponent(userId)}${query}`, {
1030
+ if (options.projectId === undefined && options.inherit !== undefined) {
1031
+ throw new Error("projectId is required to inherit profile fields");
1032
+ }
1033
+ const userPath = encodeURIComponent(userId);
1034
+ const path = options.projectId === undefined
1035
+ ? `/accounts/profiles/${userPath}`
1036
+ : `/accounts/projects/${encodeURIComponent(options.projectId)}/users/${userPath}/profile`;
1037
+ return await this.request(path, {
1024
1038
  method: "PUT",
1025
1039
  json: {
1026
1040
  ...(firstName !== undefined ? { first_name: firstName } : {}),
1027
1041
  ...(lastName !== undefined ? { last_name: lastName } : {}),
1028
1042
  ...(options.metadata !== undefined ? { metadata: options.metadata } : {}),
1029
1043
  ...(options.annotations !== undefined ? { annotations: options.annotations } : {}),
1044
+ ...(options.inherit !== undefined ? { inherit: options.inherit } : {}),
1030
1045
  },
1031
1046
  action: "update user profile",
1032
1047
  });
1033
1048
  }
1049
+ async searchSysadminUsers(options = {}) {
1050
+ return await this.request(`/accounts/sysadmin/users`, {
1051
+ query: { filter: options.filter, page_size: options.pageSize ?? 100, continuation_token: options.continuationToken },
1052
+ action: "search global users",
1053
+ });
1054
+ }
1055
+ async getSysadminUserProfile(userId) {
1056
+ return await this.request(`/accounts/sysadmin/users/${encodeURIComponent(userId)}`, {
1057
+ action: "fetch global user profile",
1058
+ });
1059
+ }
1060
+ async updateSysadminUserProfile(userId, fields) {
1061
+ return await this.request(`/accounts/sysadmin/users/${encodeURIComponent(userId)}`, {
1062
+ method: "PUT",
1063
+ json: fields,
1064
+ action: "update global user profile",
1065
+ });
1066
+ }
1034
1067
  async listProjects() {
1035
1068
  return await this.request(`/accounts/projects`, {
1036
1069
  action: "list projects",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshagent/meshagent",
3
- "version": "0.53.1",
3
+ "version": "0.53.2",
4
4
  "description": "Meshagent Client",
5
5
  "homepage": "https://github.com/meshagent/meshagent-ts",
6
6
  "scripts": {