@linagora/ldap-rest-client 1.0.10 → 1.0.12

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/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # ldap-rest-client
2
2
 
3
- TypeScript client for LDAP-REST API with HMAC-SHA256 and SSO cookie authentication.
3
+ TypeScript client library for LDAP-REST API with dual authentication support (HMAC-SHA256 for backend services, SSO cookies for browsers).
4
+
5
+ ## Features
6
+
7
+ - **Dual Authentication**: HMAC-SHA256 for backend services, SSO cookies for browsers
8
+ - **Type-Safe**: Full TypeScript support with comprehensive type definitions
9
+ - **Resource-Based API**: Clean, intuitive interface for users, organizations, and groups
10
+ - **Error Handling**: Semantic error types mapped to HTTP status codes
11
+ - **Cross-Platform**: Works in Node.js (18+) and browser environments
4
12
 
5
13
  ## Installation
6
14
 
@@ -24,11 +32,31 @@ const client = new LdapRestClient({
24
32
  },
25
33
  });
26
34
 
27
- // Create user
28
- await client.users.create(userData);
35
+ // Create B2C user
36
+ await client.users.create({
37
+ username: 'johndoe',
38
+ mail: 'john@example.com',
39
+ givenName: 'John',
40
+ cn: 'John Doe',
41
+ sn: 'Doe',
42
+ userPassword: 'secure-password',
43
+ });
29
44
 
30
45
  // Create organization
31
- await client.organizations.create({ id, name, domain });
46
+ await client.organizations.create({
47
+ id: 'acme-corp',
48
+ name: 'Acme Corporation',
49
+ domain: 'acme.com',
50
+ });
51
+
52
+ // Create B2B user in organization
53
+ const user = await client.organizations.createUser('acme-corp', {
54
+ username: 'employee',
55
+ mail: 'employee@acme.com',
56
+ givenName: 'Jane',
57
+ cn: 'Jane Smith',
58
+ sn: 'Smith',
59
+ });
32
60
  ```
33
61
 
34
62
  ### Browser (SSO Cookie)
@@ -36,159 +64,116 @@ await client.organizations.create({ id, name, domain });
36
64
  ```typescript
37
65
  const client = new LdapRestClient({
38
66
  baseUrl: 'https://ldap-rest.example.com',
67
+ // auth defaults to browser cookie-based authentication
39
68
  });
40
69
 
41
- // Manage users in organization (returns User object)
42
- const user = await client.organizations.createUser(orgId, userData);
43
- console.log(user._id); // Access unique identifier
44
- console.log(user.organizationId); // Access organization ID
45
-
46
- await client.organizations.listUsers(orgId, { page: 1, limit: 20 });
70
+ // List users in organization
71
+ const result = await client.organizations.listUsers('acme-corp', {
72
+ page: 1,
73
+ limit: 20,
74
+ });
47
75
 
48
- // Manage groups (returns Group object)
49
- const group = await client.groups.create(orgId, { name: 'engineering' });
50
- await client.groups.addMembers(orgId, groupId, { usernames: ['user1'] });
76
+ // Create and manage groups
77
+ const group = await client.groups.create('acme-corp', {
78
+ name: 'engineering',
79
+ description: 'Engineering team',
80
+ });
51
81
 
52
- // Get user's organizations
53
- const orgs = await client.users.getUserOrganizations(userId, 'admin');
82
+ await client.groups.addMembers('acme-corp', group._id, {
83
+ usernames: ['user1', 'user2'],
84
+ });
54
85
  ```
55
86
 
56
- ## API Reference
87
+ ## API Overview
57
88
 
58
- ### Users (B2C)
59
- ```typescript
60
- client.users.create(userData)
61
- client.users.update(username, updates)
62
- client.users.disable(username)
63
- client.users.delete(username)
64
- client.users.checkAvailability({ field, value })
65
- client.users.fetch({ by, value, fields })
66
- client.users.getUserOrganizations(userId, role?) // Get user's organizations by role
67
-
68
- // Technical/service accounts
69
- client.users.create({ ...userData, isTechnical: true }) // Create technical account
70
- client.users.update(username, { isTechnical: true }) // Mark user as technical
71
- ```
89
+ The client provides three main resource interfaces:
72
90
 
73
- ### Organizations
74
- ```typescript
75
- client.organizations.create({ id, name, domain })
76
- client.organizations.createAdmin(orgId, { username, mail })
77
- client.organizations.list()
78
- client.organizations.get(orgId)
79
- client.organizations.update(orgId, updates)
80
-
81
- // Organization ownership management
82
- client.organizations.getOwner(orgId)
83
- client.organizations.setOwner(orgId, { username, mail })
84
- client.organizations.transferOwnership(orgId, { newOwnerUsername })
85
- ```
91
+ - **`client.users`** - B2C user management (top-level users)
92
+ - **`client.organizations`** - Organization and B2B user management
93
+ - **`client.groups`** - Group management within organizations
86
94
 
87
- ### B2B Users (within Organizations)
88
- ```typescript
89
- // Returns full User object with _id and organizationId
90
- const user = await client.organizations.createUser(orgId, userData)
91
- console.log(user._id, user.organizationId)
92
-
93
- // Returns updated User object or { success: true }
94
- const updatedUser = await client.organizations.updateUser(orgId, userId, updates)
95
-
96
- client.organizations.disableUser(orgId, userId)
97
- client.organizations.deleteUser(orgId, userId)
98
- client.organizations.getUser(orgId, { by, value })
99
- client.organizations.listUsers(orgId, { page, limit, status, search, sortBy, sortOrder, isTechnical })
100
- client.organizations.checkUserAvailability(orgId, { field, value })
101
-
102
- // User role management ('owner', 'admin', 'moderator', 'member')
103
- // Returns { role, previousRole }
104
- const result = await client.organizations.changeUserRole(orgId, userId, { role })
105
- console.log(`Changed from ${result.previousRole} to ${result.role}`)
106
-
107
- // Technical/service accounts in organizations
108
- const techUser = await client.organizations.createUser(orgId, { ...userData, isTechnical: true })
109
- await client.organizations.updateUser(orgId, userId, { isTechnical: true })
110
- // List only technical users
111
- await client.organizations.listUsers(orgId, { isTechnical: true })
112
- ```
95
+ For complete API documentation, see **[API.md](./API.md)**.
113
96
 
114
- ### Groups
115
- ```typescript
116
- // Returns Group object directly
117
- const group = await client.groups.create(orgId, { name, description })
118
-
119
- client.groups.list(orgId, { page, limit })
120
- client.groups.get(orgId, groupId)
121
- client.groups.update(orgId, groupId, updates)
122
- client.groups.delete(orgId, groupId)
123
- client.groups.addMembers(orgId, groupId, { usernames })
124
- client.groups.removeMember(orgId, groupId, userId)
125
- ```
97
+ ### Key Concepts
126
98
 
127
- ## Configuration
99
+ **Authentication:**
100
+ - **HMAC-SHA256**: For server-to-server communication
101
+ - **Cookie/SSO**: For browser-based applications
128
102
 
129
- ### Client Options
103
+ ## Configuration
130
104
 
131
105
  ```typescript
132
106
  const client = new LdapRestClient({
133
- baseUrl: 'https://ldap-rest.example.com',
107
+ baseUrl: 'https://ldap-rest.example.com', // Required
134
108
  auth: {
135
- type: 'hmac',
109
+ type: 'hmac', // or 'cookie'
136
110
  serviceId: 'my-service',
137
111
  secret: 'your-secret-key-at-least-32-chars-long',
138
112
  },
139
- timeout: 30000, // Request timeout in milliseconds (default: 30000)
113
+ timeout: 30000, // Optional, default: 30000ms
140
114
  logger: {
141
- // Optional tslog configuration for custom logging
142
- minLevel: 'info',
115
+ minLevel: 'info', // Optional, tslog configuration
143
116
  },
144
117
  });
145
118
  ```
146
119
 
147
- ### Authentication Types
148
-
149
- **HMAC (Backend Services)**
150
- ```typescript
151
- auth: {
152
- type: 'hmac',
153
- serviceId: 'registration-service',
154
- secret: 'your-secret-key', // Minimum 32 characters recommended
155
- }
156
- ```
157
-
158
- **Cookie (Browser/SSO)**
159
- ```typescript
160
- auth: {
161
- type: 'cookie', // Uses cookies set by authentication service
162
- }
163
- // Or omit auth entirely (defaults to cookie)
164
- ```
120
+ See **[API.md - Configuration](./API.md#configuration)** for detailed options.
165
121
 
166
122
  ## Error Handling
167
123
 
124
+ All errors extend `LdapRestError` and map to specific HTTP status codes:
125
+
168
126
  ```typescript
169
- import { ConflictError, NotFoundError } from '@linagora/ldap-rest-client';
127
+ import {
128
+ ValidationError,
129
+ NotFoundError,
130
+ ConflictError,
131
+ } from '@linagora/ldap-rest-client';
170
132
 
171
133
  try {
172
134
  await client.users.create(userData);
173
135
  } catch (error) {
174
136
  if (error instanceof ConflictError) {
175
- // Handle conflict (409)
176
- } else if (error instanceof NotFoundError) {
177
- // Handle not found (404)
137
+ console.error('User already exists');
138
+ } else if (error instanceof ValidationError) {
139
+ console.error('Invalid data:', error.message);
178
140
  }
179
141
  }
180
142
  ```
181
143
 
182
- Available errors: `ValidationError`, `AuthenticationError`, `AuthorizationError`, `NotFoundError`, `ConflictError`, `RateLimitError`, `NetworkError`, `ApiError`
144
+ **Available error types:** `ValidationError` (400), `AuthenticationError` (401), `AuthorizationError` (403), `NotFoundError` (404), `ConflictError` (409), `RateLimitError` (429), `NetworkError`, `ApiError`.
145
+
146
+ See **[API.md - Error Handling](./API.md#error-handling)** for complete documentation.
147
+
148
+ ## Documentation
149
+
150
+ - **[API Reference](./API.md)** - Complete API documentation
183
151
 
184
152
  ## Development
185
153
 
186
154
  ```bash
155
+ # Install dependencies
187
156
  npm install
157
+
158
+ # Run tests
188
159
  npm test
160
+
161
+ # Build library
189
162
  npm run build
163
+
164
+ # Type checking
165
+ npm run typecheck
166
+
167
+ # Linting and formatting
168
+ npm run lint
169
+ npm run format
190
170
  ```
191
171
 
172
+ ## Requirements
173
+
174
+ - Node.js 18+
175
+ - TypeScript 5+
176
+
192
177
  ## License
193
178
 
194
179
  MIT
package/dist/index.d.mts CHANGED
@@ -415,6 +415,8 @@ interface User {
415
415
  address?: Address[];
416
416
  /** Whether this is a technical/service account */
417
417
  isTechnical?: boolean;
418
+ /** Whether this B2B user is pending invitation (only for B2B users) */
419
+ invited?: boolean;
418
420
  }
419
421
  /**
420
422
  * User password credentials with scrypt encryption parameters
@@ -485,6 +487,7 @@ interface CreateUserRequest extends UserCredentials, UserKeys {
485
487
  phone?: PhoneNumber[];
486
488
  address?: Address[];
487
489
  isTechnical?: boolean;
490
+ invited?: boolean;
488
491
  }
489
492
  /**
490
493
  * Request payload for updating a user's profile
@@ -512,6 +515,7 @@ interface UpdateUserRequest {
512
515
  phone?: PhoneNumber[];
513
516
  address?: Address[];
514
517
  isTechnical?: boolean;
518
+ invited?: boolean;
515
519
  [key: string]: string | number | boolean | null | undefined | UserName | EmailAddress[] | InstantMessaging[] | PhoneNumber[] | Address[];
516
520
  }
517
521
  /**
@@ -576,6 +580,18 @@ interface ListUsersResponse {
576
580
  * Returns the full user object with all fields populated
577
581
  */
578
582
  type CreateB2BUserResponse = User;
583
+ /**
584
+ * Parameters for searching users across all branches
585
+ */
586
+ interface SearchUsersParams {
587
+ /** Search field (username, email, phone, recoveryEmail) */
588
+ by: UserSearchField | 'recoveryEmail';
589
+ /** Search value */
590
+ value: string;
591
+ /** Optional comma-separated list of fields to return */
592
+ fields?: string;
593
+ [key: string]: string | undefined;
594
+ }
579
595
 
580
596
  /**
581
597
  * Organization domain model representing a B2B organization
@@ -606,11 +622,16 @@ interface Organization {
606
622
  * - suspended: Organization is temporarily disabled
607
623
  */
608
624
  type OrganizationStatus = 'active' | 'suspended';
625
+ /**
626
+ * Supported primitive types for metadata values
627
+ */
628
+ type MetadataValue = string | number | boolean | null;
609
629
  /**
610
630
  * Optional metadata for organization customization
611
631
  *
612
632
  * Allows storing custom properties like industry, company size,
613
633
  * contact information, or any other organization-specific data.
634
+ * Supports strings, numbers, booleans, and null values.
614
635
  */
615
636
  interface OrganizationMetadata {
616
637
  /** Industry/sector (e.g., 'Technology', 'Healthcare') */
@@ -620,7 +641,7 @@ interface OrganizationMetadata {
620
641
  /** Primary contact information */
621
642
  contact?: string;
622
643
  /** Additional custom fields as key-value pairs */
623
- [key: string]: string | undefined;
644
+ [key: string]: MetadataValue | undefined;
624
645
  }
625
646
  /**
626
647
  * Request parameters for creating an organization
@@ -905,6 +926,34 @@ declare class UsersResource extends BaseResource {
905
926
  * ```
906
927
  */
907
928
  fetch: (params: FetchUserRequest) => Promise<User>;
929
+ /**
930
+ * Search users across all branches (B2C and B2B)
931
+ *
932
+ * Returns array of all users matching the search criteria from both
933
+ * B2C and B2B branches. Email searches return immediately if found
934
+ * in B2C since email is unique.
935
+ *
936
+ * @param {SearchUsersParams} params - Search parameters (by, value, fields)
937
+ * @returns {Promise<User[]>} Array of matching users
938
+ * @throws {ApiError} On API errors
939
+ *
940
+ * @example
941
+ * ```typescript
942
+ * // Search by username across all branches
943
+ * const users = await client.users.search({
944
+ * by: 'username',
945
+ * value: 'johndoe'
946
+ * });
947
+ *
948
+ * // Search by email with field filtering
949
+ * const users = await client.users.search({
950
+ * by: 'email',
951
+ * value: 'john@example.com',
952
+ * fields: 'cn,mail,organizationId'
953
+ * });
954
+ * ```
955
+ */
956
+ search: (params: SearchUsersParams) => Promise<User[]>;
908
957
  /**
909
958
  * Gets organizations where a user has a role
910
959
  *
@@ -1721,4 +1770,4 @@ declare class NetworkError extends LdapRestError {
1721
1770
  constructor(message: string, cause?: Error);
1722
1771
  }
1723
1772
 
1724
- export { type AddGroupMembersRequest, type Address, ApiError, AuthenticationError, AuthorizationError, type ChangeUserRoleRequest, type ChangeUserRoleResponse, type CheckAvailabilityParams, type CheckAvailabilityResponse, type CheckOrganizationAvailabilityParams, type ClientConfig, ConflictError, type CreateAdminRequest, type CreateB2BUserResponse, type CreateGroupRequest, type CreateOrganizationRequest, type CreateOrganizationResponse, type CreateUserRequest, type EmailAddress, type ExtendedAddress, type FetchUserRequest, type GeoLocation, type GetOwnerResponse, type Group, GroupsResource, type InstantMessaging, LdapRestClient, LdapRestError, type ListGroupsParams, type ListGroupsResponse, type ListUsersParams, type ListUsersResponse, NetworkError, NotFoundError, type Organization, type OrganizationMetadata, type OrganizationOwner, type OrganizationRole, type OrganizationSearchField, type OrganizationStatus, OrganizationsResource, type PhoneNumber, RateLimitError, type SetOwnerRequest, type TransferOwnershipRequest, type UpdateGroupRequest, type UpdateOrganizationRequest, type UpdateUserRequest, type User, type UserCredentials, type UserKeys, type UserName, type UserSearchField, type UserStatus, UsersResource, ValidationError };
1773
+ export { type AddGroupMembersRequest, type Address, ApiError, AuthenticationError, AuthorizationError, type ChangeUserRoleRequest, type ChangeUserRoleResponse, type CheckAvailabilityParams, type CheckAvailabilityResponse, type CheckOrganizationAvailabilityParams, type ClientConfig, ConflictError, type CreateAdminRequest, type CreateB2BUserResponse, type CreateGroupRequest, type CreateOrganizationRequest, type CreateOrganizationResponse, type CreateUserRequest, type EmailAddress, type ExtendedAddress, type FetchUserRequest, type GeoLocation, type GetOwnerResponse, type Group, GroupsResource, type InstantMessaging, LdapRestClient, LdapRestError, type ListGroupsParams, type ListGroupsResponse, type ListUsersParams, type ListUsersResponse, type MetadataValue, NetworkError, NotFoundError, type Organization, type OrganizationMetadata, type OrganizationOwner, type OrganizationRole, type OrganizationSearchField, type OrganizationStatus, OrganizationsResource, type PhoneNumber, RateLimitError, type SearchUsersParams, type SetOwnerRequest, type TransferOwnershipRequest, type UpdateGroupRequest, type UpdateOrganizationRequest, type UpdateUserRequest, type User, type UserCredentials, type UserKeys, type UserName, type UserSearchField, type UserStatus, UsersResource, ValidationError };
package/dist/index.d.ts CHANGED
@@ -415,6 +415,8 @@ interface User {
415
415
  address?: Address[];
416
416
  /** Whether this is a technical/service account */
417
417
  isTechnical?: boolean;
418
+ /** Whether this B2B user is pending invitation (only for B2B users) */
419
+ invited?: boolean;
418
420
  }
419
421
  /**
420
422
  * User password credentials with scrypt encryption parameters
@@ -485,6 +487,7 @@ interface CreateUserRequest extends UserCredentials, UserKeys {
485
487
  phone?: PhoneNumber[];
486
488
  address?: Address[];
487
489
  isTechnical?: boolean;
490
+ invited?: boolean;
488
491
  }
489
492
  /**
490
493
  * Request payload for updating a user's profile
@@ -512,6 +515,7 @@ interface UpdateUserRequest {
512
515
  phone?: PhoneNumber[];
513
516
  address?: Address[];
514
517
  isTechnical?: boolean;
518
+ invited?: boolean;
515
519
  [key: string]: string | number | boolean | null | undefined | UserName | EmailAddress[] | InstantMessaging[] | PhoneNumber[] | Address[];
516
520
  }
517
521
  /**
@@ -576,6 +580,18 @@ interface ListUsersResponse {
576
580
  * Returns the full user object with all fields populated
577
581
  */
578
582
  type CreateB2BUserResponse = User;
583
+ /**
584
+ * Parameters for searching users across all branches
585
+ */
586
+ interface SearchUsersParams {
587
+ /** Search field (username, email, phone, recoveryEmail) */
588
+ by: UserSearchField | 'recoveryEmail';
589
+ /** Search value */
590
+ value: string;
591
+ /** Optional comma-separated list of fields to return */
592
+ fields?: string;
593
+ [key: string]: string | undefined;
594
+ }
579
595
 
580
596
  /**
581
597
  * Organization domain model representing a B2B organization
@@ -606,11 +622,16 @@ interface Organization {
606
622
  * - suspended: Organization is temporarily disabled
607
623
  */
608
624
  type OrganizationStatus = 'active' | 'suspended';
625
+ /**
626
+ * Supported primitive types for metadata values
627
+ */
628
+ type MetadataValue = string | number | boolean | null;
609
629
  /**
610
630
  * Optional metadata for organization customization
611
631
  *
612
632
  * Allows storing custom properties like industry, company size,
613
633
  * contact information, or any other organization-specific data.
634
+ * Supports strings, numbers, booleans, and null values.
614
635
  */
615
636
  interface OrganizationMetadata {
616
637
  /** Industry/sector (e.g., 'Technology', 'Healthcare') */
@@ -620,7 +641,7 @@ interface OrganizationMetadata {
620
641
  /** Primary contact information */
621
642
  contact?: string;
622
643
  /** Additional custom fields as key-value pairs */
623
- [key: string]: string | undefined;
644
+ [key: string]: MetadataValue | undefined;
624
645
  }
625
646
  /**
626
647
  * Request parameters for creating an organization
@@ -905,6 +926,34 @@ declare class UsersResource extends BaseResource {
905
926
  * ```
906
927
  */
907
928
  fetch: (params: FetchUserRequest) => Promise<User>;
929
+ /**
930
+ * Search users across all branches (B2C and B2B)
931
+ *
932
+ * Returns array of all users matching the search criteria from both
933
+ * B2C and B2B branches. Email searches return immediately if found
934
+ * in B2C since email is unique.
935
+ *
936
+ * @param {SearchUsersParams} params - Search parameters (by, value, fields)
937
+ * @returns {Promise<User[]>} Array of matching users
938
+ * @throws {ApiError} On API errors
939
+ *
940
+ * @example
941
+ * ```typescript
942
+ * // Search by username across all branches
943
+ * const users = await client.users.search({
944
+ * by: 'username',
945
+ * value: 'johndoe'
946
+ * });
947
+ *
948
+ * // Search by email with field filtering
949
+ * const users = await client.users.search({
950
+ * by: 'email',
951
+ * value: 'john@example.com',
952
+ * fields: 'cn,mail,organizationId'
953
+ * });
954
+ * ```
955
+ */
956
+ search: (params: SearchUsersParams) => Promise<User[]>;
908
957
  /**
909
958
  * Gets organizations where a user has a role
910
959
  *
@@ -1721,4 +1770,4 @@ declare class NetworkError extends LdapRestError {
1721
1770
  constructor(message: string, cause?: Error);
1722
1771
  }
1723
1772
 
1724
- export { type AddGroupMembersRequest, type Address, ApiError, AuthenticationError, AuthorizationError, type ChangeUserRoleRequest, type ChangeUserRoleResponse, type CheckAvailabilityParams, type CheckAvailabilityResponse, type CheckOrganizationAvailabilityParams, type ClientConfig, ConflictError, type CreateAdminRequest, type CreateB2BUserResponse, type CreateGroupRequest, type CreateOrganizationRequest, type CreateOrganizationResponse, type CreateUserRequest, type EmailAddress, type ExtendedAddress, type FetchUserRequest, type GeoLocation, type GetOwnerResponse, type Group, GroupsResource, type InstantMessaging, LdapRestClient, LdapRestError, type ListGroupsParams, type ListGroupsResponse, type ListUsersParams, type ListUsersResponse, NetworkError, NotFoundError, type Organization, type OrganizationMetadata, type OrganizationOwner, type OrganizationRole, type OrganizationSearchField, type OrganizationStatus, OrganizationsResource, type PhoneNumber, RateLimitError, type SetOwnerRequest, type TransferOwnershipRequest, type UpdateGroupRequest, type UpdateOrganizationRequest, type UpdateUserRequest, type User, type UserCredentials, type UserKeys, type UserName, type UserSearchField, type UserStatus, UsersResource, ValidationError };
1773
+ export { type AddGroupMembersRequest, type Address, ApiError, AuthenticationError, AuthorizationError, type ChangeUserRoleRequest, type ChangeUserRoleResponse, type CheckAvailabilityParams, type CheckAvailabilityResponse, type CheckOrganizationAvailabilityParams, type ClientConfig, ConflictError, type CreateAdminRequest, type CreateB2BUserResponse, type CreateGroupRequest, type CreateOrganizationRequest, type CreateOrganizationResponse, type CreateUserRequest, type EmailAddress, type ExtendedAddress, type FetchUserRequest, type GeoLocation, type GetOwnerResponse, type Group, GroupsResource, type InstantMessaging, LdapRestClient, LdapRestError, type ListGroupsParams, type ListGroupsResponse, type ListUsersParams, type ListUsersResponse, type MetadataValue, NetworkError, NotFoundError, type Organization, type OrganizationMetadata, type OrganizationOwner, type OrganizationRole, type OrganizationSearchField, type OrganizationStatus, OrganizationsResource, type PhoneNumber, RateLimitError, type SearchUsersParams, type SetOwnerRequest, type TransferOwnershipRequest, type UpdateGroupRequest, type UpdateOrganizationRequest, type UpdateUserRequest, type User, type UserCredentials, type UserKeys, type UserName, type UserSearchField, type UserStatus, UsersResource, ValidationError };
package/dist/index.js CHANGED
@@ -632,6 +632,37 @@ var UsersResource = class extends BaseResource {
632
632
  const query = this.buildQueryString(params);
633
633
  return this.http.get(`/api/v1/users${query}`);
634
634
  };
635
+ /**
636
+ * Search users across all branches (B2C and B2B)
637
+ *
638
+ * Returns array of all users matching the search criteria from both
639
+ * B2C and B2B branches. Email searches return immediately if found
640
+ * in B2C since email is unique.
641
+ *
642
+ * @param {SearchUsersParams} params - Search parameters (by, value, fields)
643
+ * @returns {Promise<User[]>} Array of matching users
644
+ * @throws {ApiError} On API errors
645
+ *
646
+ * @example
647
+ * ```typescript
648
+ * // Search by username across all branches
649
+ * const users = await client.users.search({
650
+ * by: 'username',
651
+ * value: 'johndoe'
652
+ * });
653
+ *
654
+ * // Search by email with field filtering
655
+ * const users = await client.users.search({
656
+ * by: 'email',
657
+ * value: 'john@example.com',
658
+ * fields: 'cn,mail,organizationId'
659
+ * });
660
+ * ```
661
+ */
662
+ search = async (params) => {
663
+ const query = this.buildQueryString(params);
664
+ return this.http.get(`/api/v1/users/search${query}`);
665
+ };
635
666
  /**
636
667
  * Gets organizations where a user has a role
637
668
  *
package/dist/index.mjs CHANGED
@@ -594,6 +594,37 @@ var UsersResource = class extends BaseResource {
594
594
  const query = this.buildQueryString(params);
595
595
  return this.http.get(`/api/v1/users${query}`);
596
596
  };
597
+ /**
598
+ * Search users across all branches (B2C and B2B)
599
+ *
600
+ * Returns array of all users matching the search criteria from both
601
+ * B2C and B2B branches. Email searches return immediately if found
602
+ * in B2C since email is unique.
603
+ *
604
+ * @param {SearchUsersParams} params - Search parameters (by, value, fields)
605
+ * @returns {Promise<User[]>} Array of matching users
606
+ * @throws {ApiError} On API errors
607
+ *
608
+ * @example
609
+ * ```typescript
610
+ * // Search by username across all branches
611
+ * const users = await client.users.search({
612
+ * by: 'username',
613
+ * value: 'johndoe'
614
+ * });
615
+ *
616
+ * // Search by email with field filtering
617
+ * const users = await client.users.search({
618
+ * by: 'email',
619
+ * value: 'john@example.com',
620
+ * fields: 'cn,mail,organizationId'
621
+ * });
622
+ * ```
623
+ */
624
+ search = async (params) => {
625
+ const query = this.buildQueryString(params);
626
+ return this.http.get(`/api/v1/users/search${query}`);
627
+ };
597
628
  /**
598
629
  * Gets organizations where a user has a role
599
630
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linagora/ldap-rest-client",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "TypeScript API client for LDAP-REST",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",