@linagora/ldap-rest-client 1.0.2 → 1.0.4

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
@@ -66,6 +66,11 @@ client.organizations.createAdmin(orgId, { username, mail })
66
66
  client.organizations.list()
67
67
  client.organizations.get(orgId)
68
68
  client.organizations.update(orgId, updates)
69
+
70
+ // Organization ownership management
71
+ client.organizations.getOwner(orgId)
72
+ client.organizations.setOwner(orgId, { username, mail })
73
+ client.organizations.transferOwnership(orgId, { newOwnerUsername })
69
74
  ```
70
75
 
71
76
  ### B2B Users (within Organizations)
@@ -75,8 +80,10 @@ client.organizations.updateUser(orgId, userId, updates)
75
80
  client.organizations.disableUser(orgId, userId)
76
81
  client.organizations.deleteUser(orgId, userId)
77
82
  client.organizations.getUser(orgId, { by, value })
78
- client.organizations.listUsers(orgId, { page, limit, status, search })
83
+ client.organizations.listUsers(orgId, { page, limit, status, search, sortBy, sortOrder })
79
84
  client.organizations.checkUserAvailability(orgId, { field, value })
85
+
86
+ // User role management ('owner', 'admin', 'moderator', 'member')
80
87
  client.organizations.changeUserRole(orgId, userId, { role })
81
88
  ```
82
89
 
@@ -91,6 +98,45 @@ client.groups.addMembers(orgId, groupId, { usernames })
91
98
  client.groups.removeMember(orgId, groupId, userId)
92
99
  ```
93
100
 
101
+ ## Configuration
102
+
103
+ ### Client Options
104
+
105
+ ```typescript
106
+ const client = new LdapRestClient({
107
+ baseUrl: 'https://ldap-rest.example.com',
108
+ auth: {
109
+ type: 'hmac',
110
+ serviceId: 'my-service',
111
+ secret: 'your-secret-key-at-least-32-chars-long',
112
+ },
113
+ timeout: 30000, // Request timeout in milliseconds (default: 30000)
114
+ logger: {
115
+ // Optional tslog configuration for custom logging
116
+ minLevel: 'info',
117
+ },
118
+ });
119
+ ```
120
+
121
+ ### Authentication Types
122
+
123
+ **HMAC (Backend Services)**
124
+ ```typescript
125
+ auth: {
126
+ type: 'hmac',
127
+ serviceId: 'registration-service',
128
+ secret: 'your-secret-key', // Minimum 32 characters recommended
129
+ }
130
+ ```
131
+
132
+ **Cookie (Browser/SSO)**
133
+ ```typescript
134
+ auth: {
135
+ type: 'cookie', // Uses cookies set by authentication service
136
+ }
137
+ // Or omit auth entirely (defaults to cookie)
138
+ ```
139
+
94
140
  ## Error Handling
95
141
 
96
142
  ```typescript
package/dist/index.d.mts CHANGED
@@ -2,16 +2,22 @@ import { ISettingsParam, Logger } from 'tslog';
2
2
 
3
3
  /**
4
4
  * HMAC authentication configuration for backend services
5
+ * Uses HMAC-SHA256 signatures as per ADR-024
5
6
  */
6
7
  interface HmacAuthConfig {
8
+ /** Authentication type */
7
9
  type: 'hmac';
10
+ /** Service identifier (e.g., 'registration-service') */
8
11
  serviceId: string;
12
+ /** Shared secret key (minimum 32 characters recommended) */
9
13
  secret: string;
10
14
  }
11
15
  /**
12
16
  * SSO Cookie authentication configuration for browser requests
17
+ * Relies on cookies set by the authentication service
13
18
  */
14
19
  interface CookieAuthConfig {
20
+ /** Authentication type */
15
21
  type: 'cookie';
16
22
  }
17
23
  /**
@@ -22,16 +28,23 @@ type AuthConfig = HmacAuthConfig | CookieAuthConfig;
22
28
  * Configuration for LDAP-REST client
23
29
  */
24
30
  interface ClientConfig {
31
+ /** Base URL of the LDAP-REST API (e.g., 'https://ldap-rest.example.com') */
25
32
  baseUrl: string;
33
+ /** Authentication configuration (defaults to cookie auth if not provided) */
26
34
  auth?: AuthConfig;
35
+ /** Request timeout in milliseconds (default: 30000) */
27
36
  timeout?: number;
37
+ /** tslog logger configuration for custom logging */
28
38
  logger?: ISettingsParam<unknown>;
29
39
  }
30
40
  /**
31
41
  * HTTP client configuration
42
+ * Subset of configuration passed to the HTTP client
32
43
  */
33
44
  interface HttpConfig {
45
+ /** Base URL of the API */
34
46
  baseUrl: string;
47
+ /** Request timeout in milliseconds */
35
48
  timeout: number;
36
49
  }
37
50
 
@@ -209,112 +222,236 @@ declare abstract class BaseResource {
209
222
  protected buildQueryString: (params: Record<string, string | number | boolean | undefined>) => string;
210
223
  }
211
224
 
225
+ /**
226
+ * Email address with optional type and label
227
+ */
212
228
  interface EmailAddress {
229
+ /** Email address */
213
230
  address: string;
231
+ /** Type of email (e.g., 'work', 'personal') */
214
232
  type?: string;
233
+ /** Custom label for the email */
215
234
  label?: string;
235
+ /** Whether this is the primary email */
216
236
  primary?: string;
217
237
  }
238
+ /**
239
+ * Instant messaging contact information
240
+ */
218
241
  interface InstantMessaging {
242
+ /** IM protocol URI (e.g., 'xmpp:user@example.com', 'skype:username') */
219
243
  uri: string;
244
+ /** Protocol name (e.g., 'xmpp', 'skype', 'slack') */
220
245
  protocol?: string;
246
+ /** Custom label for the IM account */
221
247
  label?: string;
248
+ /** Whether this is the primary IM contact */
222
249
  primary?: string;
223
250
  }
251
+ /**
252
+ * Phone number with optional type and label
253
+ */
224
254
  interface PhoneNumber {
255
+ /** Phone number (preferably in international format, e.g., '+33612345678') */
225
256
  number: string;
257
+ /** Type of phone (e.g., 'mobile', 'home', 'work', 'fax') */
226
258
  type?: string;
259
+ /** Custom label for the phone number */
227
260
  label?: string;
261
+ /** Whether this is the primary phone number */
228
262
  primary?: boolean;
229
263
  }
264
+ /**
265
+ * Extended address details for buildings and apartments
266
+ */
230
267
  interface ExtendedAddress {
268
+ /** Locality or neighborhood name */
231
269
  locality?: string;
270
+ /** Building name or number */
232
271
  building?: string;
272
+ /** Staircase identifier */
233
273
  stairs?: string;
274
+ /** Floor number */
234
275
  floor?: string;
276
+ /** Apartment number */
235
277
  apartment?: string;
278
+ /** Entry code or access code */
236
279
  entrycode?: string;
237
280
  }
281
+ /**
282
+ * Geographic location with coordinates
283
+ */
238
284
  interface GeoLocation {
285
+ /** Geographic coordinates as [latitude, longitude] */
239
286
  geo?: [number, number];
287
+ /** Category for Cozy Cloud integration */
240
288
  cozyCategory?: string;
241
289
  }
290
+ /**
291
+ * Physical address with comprehensive location details
292
+ */
242
293
  interface Address {
294
+ /** Unique identifier for the address */
243
295
  id?: string;
296
+ /** Street name */
244
297
  street?: string;
298
+ /** Post office box number */
245
299
  pobox?: string;
300
+ /** City name */
246
301
  city?: string;
302
+ /** State, province, or region */
247
303
  region?: string;
304
+ /** Street number */
248
305
  number?: string;
306
+ /** Postal or ZIP code */
249
307
  code?: string;
308
+ /** Country name or code */
250
309
  country?: string;
310
+ /** Type of address (e.g., 'home', 'work', 'billing') */
251
311
  type?: string;
312
+ /** Custom label for the address */
252
313
  label?: string;
314
+ /** Whether this is the primary address */
253
315
  primary?: boolean;
316
+ /** Extended address details (building, floor, apartment, etc.) */
254
317
  extendedAddress?: ExtendedAddress;
318
+ /** Single-line formatted address string */
255
319
  formattedAddress?: string;
320
+ /** Geographic location with coordinates */
256
321
  geo?: GeoLocation;
257
322
  }
323
+ /**
324
+ * Structured name components for a user
325
+ */
258
326
  interface UserName {
327
+ /** Family name or last name */
259
328
  familyName?: string;
329
+ /** Given name or first name */
260
330
  givenName?: string;
331
+ /** Middle name or additional names */
261
332
  additionalName?: string;
333
+ /** Name prefix (e.g., 'Dr.', 'Mr.', 'Ms.') */
262
334
  namePrefix?: string;
335
+ /** Name suffix (e.g., 'Jr.', 'Sr.', 'III') */
263
336
  nameSuffix?: string;
337
+ /** Surname (alternative to familyName) */
264
338
  surname?: string;
265
339
  }
340
+ /**
341
+ * Complete user model with all profile fields, credentials, and encryption keys
342
+ */
266
343
  interface User {
344
+ /** Common name (username) */
267
345
  cn: string;
346
+ /** Surname or last name */
268
347
  sn: string;
348
+ /** Given name or first name */
269
349
  givenName: string;
350
+ /** Display name shown in UI */
270
351
  displayName: string;
352
+ /** Primary email address */
271
353
  mail: string;
354
+ /** Primary mobile phone number */
272
355
  mobile: string;
356
+ /** Encrypted user password */
273
357
  userPassword: string;
358
+ /** Scrypt parameter: block size */
274
359
  scryptR: number;
360
+ /** Scrypt parameter: CPU/memory cost */
275
361
  scryptN: number;
362
+ /** Scrypt parameter: parallelization */
276
363
  scryptP: number;
364
+ /** Salt for password encryption */
277
365
  scryptSalt: string;
366
+ /** Derived key length for scrypt */
278
367
  scryptDKLength: number;
368
+ /** Number of iterations for key derivation */
279
369
  iterations: number;
370
+ /** User's domain */
280
371
  domain: string;
372
+ /** User's public encryption key */
281
373
  publicKey: string;
374
+ /** User's private encryption key */
282
375
  privateKey: string;
376
+ /** Protected encryption key */
283
377
  protectedKey: string;
378
+ /** Whether two-factor authentication is enabled */
284
379
  twoFactorEnabled?: string;
380
+ /** URL of user's workspace */
285
381
  workspaceUrl?: string;
382
+ /** Recovery email for account recovery */
286
383
  recoveryEmail?: string;
384
+ /** Timestamp when password account was locked */
287
385
  pwdAccountLockedTime?: string;
386
+ /** User's role in Twake organization ('owner', 'admin', 'moderator', 'member') */
288
387
  twakeOrganizationRole?: string;
388
+ /** Full name as a single string */
289
389
  fullname?: string;
390
+ /** Structured name components */
290
391
  name?: UserName;
392
+ /** Birthday in ISO 8601 format (YYYY-MM-DD) */
291
393
  birthday?: string;
394
+ /** Gender */
292
395
  gender?: string;
396
+ /** Personal note or description */
293
397
  note?: string;
398
+ /** Array of email addresses */
294
399
  email?: EmailAddress[];
400
+ /** Array of instant messaging contacts */
295
401
  impp?: InstantMessaging[];
402
+ /** Place of birth */
296
403
  birthplace?: string;
404
+ /** Job title or position */
297
405
  jobTitle?: string;
406
+ /** Company or organization name */
298
407
  company?: string;
408
+ /** Array of phone numbers */
299
409
  phone?: PhoneNumber[];
410
+ /** Array of physical addresses */
300
411
  address?: Address[];
301
412
  }
413
+ /**
414
+ * User password credentials with scrypt encryption parameters
415
+ */
302
416
  interface UserCredentials {
417
+ /** Encrypted password */
303
418
  userPassword: string;
419
+ /** Scrypt CPU/memory cost parameter (power of 2, e.g., 16384) */
304
420
  scryptN: number;
421
+ /** Scrypt parallelization parameter (typically 1) */
305
422
  scryptP: number;
423
+ /** Scrypt block size parameter (typically 8) */
306
424
  scryptR: number;
425
+ /** Random salt for password hashing */
307
426
  scryptSalt: string;
427
+ /** Derived key length in bytes (typically 32) */
308
428
  scryptDKLength: number;
429
+ /** Number of PBKDF2 iterations */
309
430
  iterations: number;
310
431
  }
432
+ /**
433
+ * User's cryptographic keys for end-to-end encryption
434
+ */
311
435
  interface UserKeys {
436
+ /** User's private encryption key */
312
437
  privateKey: string;
438
+ /** User's public encryption key */
313
439
  publicKey: string;
440
+ /** Password-protected version of the private key */
314
441
  protectedKey: string;
315
442
  }
443
+ /**
444
+ * User account status
445
+ */
316
446
  type UserStatus = 'active' | 'disabled';
447
+ /**
448
+ * Fields that can be used to search for users
449
+ */
317
450
  type UserSearchField = 'username' | 'phone' | 'email' | 'recoveryEmail';
451
+ /**
452
+ * Request payload for creating a new B2C user
453
+ * Includes all required fields plus optional profile information
454
+ */
318
455
  interface CreateUserRequest extends UserCredentials, UserKeys {
319
456
  cn: string;
320
457
  uid: string;
@@ -342,6 +479,10 @@ interface CreateUserRequest extends UserCredentials, UserKeys {
342
479
  phone?: PhoneNumber[];
343
480
  address?: Address[];
344
481
  }
482
+ /**
483
+ * Request payload for updating a user's profile
484
+ * All fields are optional and only provided fields will be updated
485
+ */
345
486
  interface UpdateUserRequest {
346
487
  mobile?: string;
347
488
  userPassword?: string;
@@ -420,13 +561,6 @@ interface ListUsersResponse {
420
561
  hasPreviousPage: boolean;
421
562
  };
422
563
  }
423
- /**
424
- * Response from creating a B2B user in an organization
425
- */
426
- interface CreateB2BUserResponse {
427
- /** Base DN of the created user */
428
- baseDN: string;
429
- }
430
564
 
431
565
  /**
432
566
  * Organization domain model representing a B2B organization
@@ -595,13 +729,6 @@ interface CreateGroupRequest {
595
729
  /** Optional group description */
596
730
  description?: string;
597
731
  }
598
- /**
599
- * Response from creating a group
600
- */
601
- interface CreateGroupResponse {
602
- success: true;
603
- group: Group;
604
- }
605
732
  /**
606
733
  * Request parameters for updating a group
607
734
  */
@@ -754,6 +881,27 @@ declare class UsersResource extends BaseResource {
754
881
  * ```
755
882
  */
756
883
  fetch: (params: FetchUserRequest) => Promise<User>;
884
+ /**
885
+ * Gets organizations where a user has a role
886
+ *
887
+ * Returns organizations where the user is an admin or owner.
888
+ * Optionally filter by specific role.
889
+ *
890
+ * @param {string} userId - User identifier (username)
891
+ * @param {string} [role] - Optional role filter ('owner', 'admin', 'moderator', 'member')
892
+ * @returns {Promise<Organization[]>} Array of organizations
893
+ * @throws {ApiError} On API errors
894
+ *
895
+ * @example
896
+ * ```typescript
897
+ * // Get all organizations where user has any role
898
+ * const orgs = await client.users.getUserOrganizations('johndoe');
899
+ *
900
+ * // Get only organizations where user is owner
901
+ * const ownedOrgs = await client.users.getUserOrganizations('johndoe', 'owner');
902
+ * ```
903
+ */
904
+ getUserOrganizations: (userId: string, role?: string) => Promise<Organization[]>;
757
905
  }
758
906
 
759
907
  /**
@@ -982,7 +1130,7 @@ declare class OrganizationsResource extends BaseResource {
982
1130
  *
983
1131
  * @param {string} organizationId - Organization identifier
984
1132
  * @param {CreateUserRequest} data - User data including credentials and profile
985
- * @returns {Promise<CreateB2BUserResponse>} Response with user's baseDN
1133
+ * @returns {Promise<User>} The created user object
986
1134
  * @throws {ForbiddenError} When user lacks admin privileges
987
1135
  * @throws {NotFoundError} When organization is not found
988
1136
  * @throws {ConflictError} When username/email/phone already exists
@@ -990,14 +1138,14 @@ declare class OrganizationsResource extends BaseResource {
990
1138
  *
991
1139
  * @example
992
1140
  * ```typescript
993
- * const result = await client.organizations.createUser('org_abc123', {
1141
+ * const user = await client.organizations.createUser('org_abc123', {
994
1142
  * cn: 'john.doe',
995
1143
  * uid: 'john.doe',
996
1144
  * // ... other user fields
997
1145
  * });
998
1146
  * ```
999
1147
  */
1000
- createUser: (organizationId: string, data: CreateUserRequest) => Promise<CreateB2BUserResponse>;
1148
+ createUser: (organizationId: string, data: CreateUserRequest) => Promise<User>;
1001
1149
  /**
1002
1150
  * Updates a user in an organization
1003
1151
  *
@@ -1006,19 +1154,19 @@ declare class OrganizationsResource extends BaseResource {
1006
1154
  * @param {string} organizationId - Organization identifier
1007
1155
  * @param {string} userId - User identifier (username)
1008
1156
  * @param {UpdateUserRequest} data - Fields to update
1009
- * @returns {Promise<{ success: true }>} Success response
1157
+ * @returns {Promise<User | { success: true }>} Updated user object or success response
1010
1158
  * @throws {NotFoundError} When user or organization is not found
1011
1159
  * @throws {ForbiddenError} When user lacks admin privileges
1012
1160
  * @throws {ApiError} On other API errors
1013
1161
  *
1014
1162
  * @example
1015
1163
  * ```typescript
1016
- * await client.organizations.updateUser('org_abc123', 'john.doe', {
1164
+ * const result = await client.organizations.updateUser('org_abc123', 'john.doe', {
1017
1165
  * mobile: '+33687654321'
1018
1166
  * });
1019
1167
  * ```
1020
1168
  */
1021
- updateUser: (organizationId: string, userId: string, data: UpdateUserRequest) => Promise<{
1169
+ updateUser: (organizationId: string, userId: string, data: UpdateUserRequest) => Promise<User | {
1022
1170
  success: true;
1023
1171
  }>;
1024
1172
  /**
@@ -1189,7 +1337,7 @@ declare class GroupsResource extends BaseResource {
1189
1337
  *
1190
1338
  * @param {string} organizationId - Organization identifier
1191
1339
  * @param {CreateGroupRequest} data - Group data (name and optional description)
1192
- * @returns {Promise<CreateGroupResponse>} Created group details
1340
+ * @returns {Promise<Group>} Created group object
1193
1341
  * @throws {ForbiddenError} When user lacks admin privileges
1194
1342
  * @throws {NotFoundError} When organization is not found
1195
1343
  * @throws {ConflictError} When group name already exists
@@ -1197,13 +1345,13 @@ declare class GroupsResource extends BaseResource {
1197
1345
  *
1198
1346
  * @examples
1199
1347
  * ```typescript
1200
- * const result = await client.groups.create('org_abc123', {
1348
+ * const group = await client.groups.create('org_abc123', {
1201
1349
  * name: 'engineering',
1202
1350
  * description: 'Engineering team'
1203
1351
  * });
1204
1352
  * ```
1205
1353
  */
1206
- create: (organizationId: string, data: CreateGroupRequest) => Promise<CreateGroupResponse>;
1354
+ create: (organizationId: string, data: CreateGroupRequest) => Promise<Group>;
1207
1355
  /**
1208
1356
  * Lists all groups in an organization with pagination
1209
1357
  *
@@ -1542,4 +1690,4 @@ declare class NetworkError extends LdapRestError {
1542
1690
  constructor(message: string, cause?: Error);
1543
1691
  }
1544
1692
 
1545
- export { type AddGroupMembersRequest, type Address, ApiError, AuthenticationError, AuthorizationError, type ChangeUserRoleRequest, type CheckAvailabilityParams, type CheckAvailabilityResponse, type CheckOrganizationAvailabilityParams, type ClientConfig, ConflictError, type CreateAdminRequest, type CreateB2BUserResponse, type CreateGroupRequest, type CreateGroupResponse, 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 };
1693
+ export { type AddGroupMembersRequest, type Address, ApiError, AuthenticationError, AuthorizationError, type ChangeUserRoleRequest, type CheckAvailabilityParams, type CheckAvailabilityResponse, type CheckOrganizationAvailabilityParams, type ClientConfig, ConflictError, type CreateAdminRequest, 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 };
package/dist/index.d.ts CHANGED
@@ -2,16 +2,22 @@ import { ISettingsParam, Logger } from 'tslog';
2
2
 
3
3
  /**
4
4
  * HMAC authentication configuration for backend services
5
+ * Uses HMAC-SHA256 signatures as per ADR-024
5
6
  */
6
7
  interface HmacAuthConfig {
8
+ /** Authentication type */
7
9
  type: 'hmac';
10
+ /** Service identifier (e.g., 'registration-service') */
8
11
  serviceId: string;
12
+ /** Shared secret key (minimum 32 characters recommended) */
9
13
  secret: string;
10
14
  }
11
15
  /**
12
16
  * SSO Cookie authentication configuration for browser requests
17
+ * Relies on cookies set by the authentication service
13
18
  */
14
19
  interface CookieAuthConfig {
20
+ /** Authentication type */
15
21
  type: 'cookie';
16
22
  }
17
23
  /**
@@ -22,16 +28,23 @@ type AuthConfig = HmacAuthConfig | CookieAuthConfig;
22
28
  * Configuration for LDAP-REST client
23
29
  */
24
30
  interface ClientConfig {
31
+ /** Base URL of the LDAP-REST API (e.g., 'https://ldap-rest.example.com') */
25
32
  baseUrl: string;
33
+ /** Authentication configuration (defaults to cookie auth if not provided) */
26
34
  auth?: AuthConfig;
35
+ /** Request timeout in milliseconds (default: 30000) */
27
36
  timeout?: number;
37
+ /** tslog logger configuration for custom logging */
28
38
  logger?: ISettingsParam<unknown>;
29
39
  }
30
40
  /**
31
41
  * HTTP client configuration
42
+ * Subset of configuration passed to the HTTP client
32
43
  */
33
44
  interface HttpConfig {
45
+ /** Base URL of the API */
34
46
  baseUrl: string;
47
+ /** Request timeout in milliseconds */
35
48
  timeout: number;
36
49
  }
37
50
 
@@ -209,112 +222,236 @@ declare abstract class BaseResource {
209
222
  protected buildQueryString: (params: Record<string, string | number | boolean | undefined>) => string;
210
223
  }
211
224
 
225
+ /**
226
+ * Email address with optional type and label
227
+ */
212
228
  interface EmailAddress {
229
+ /** Email address */
213
230
  address: string;
231
+ /** Type of email (e.g., 'work', 'personal') */
214
232
  type?: string;
233
+ /** Custom label for the email */
215
234
  label?: string;
235
+ /** Whether this is the primary email */
216
236
  primary?: string;
217
237
  }
238
+ /**
239
+ * Instant messaging contact information
240
+ */
218
241
  interface InstantMessaging {
242
+ /** IM protocol URI (e.g., 'xmpp:user@example.com', 'skype:username') */
219
243
  uri: string;
244
+ /** Protocol name (e.g., 'xmpp', 'skype', 'slack') */
220
245
  protocol?: string;
246
+ /** Custom label for the IM account */
221
247
  label?: string;
248
+ /** Whether this is the primary IM contact */
222
249
  primary?: string;
223
250
  }
251
+ /**
252
+ * Phone number with optional type and label
253
+ */
224
254
  interface PhoneNumber {
255
+ /** Phone number (preferably in international format, e.g., '+33612345678') */
225
256
  number: string;
257
+ /** Type of phone (e.g., 'mobile', 'home', 'work', 'fax') */
226
258
  type?: string;
259
+ /** Custom label for the phone number */
227
260
  label?: string;
261
+ /** Whether this is the primary phone number */
228
262
  primary?: boolean;
229
263
  }
264
+ /**
265
+ * Extended address details for buildings and apartments
266
+ */
230
267
  interface ExtendedAddress {
268
+ /** Locality or neighborhood name */
231
269
  locality?: string;
270
+ /** Building name or number */
232
271
  building?: string;
272
+ /** Staircase identifier */
233
273
  stairs?: string;
274
+ /** Floor number */
234
275
  floor?: string;
276
+ /** Apartment number */
235
277
  apartment?: string;
278
+ /** Entry code or access code */
236
279
  entrycode?: string;
237
280
  }
281
+ /**
282
+ * Geographic location with coordinates
283
+ */
238
284
  interface GeoLocation {
285
+ /** Geographic coordinates as [latitude, longitude] */
239
286
  geo?: [number, number];
287
+ /** Category for Cozy Cloud integration */
240
288
  cozyCategory?: string;
241
289
  }
290
+ /**
291
+ * Physical address with comprehensive location details
292
+ */
242
293
  interface Address {
294
+ /** Unique identifier for the address */
243
295
  id?: string;
296
+ /** Street name */
244
297
  street?: string;
298
+ /** Post office box number */
245
299
  pobox?: string;
300
+ /** City name */
246
301
  city?: string;
302
+ /** State, province, or region */
247
303
  region?: string;
304
+ /** Street number */
248
305
  number?: string;
306
+ /** Postal or ZIP code */
249
307
  code?: string;
308
+ /** Country name or code */
250
309
  country?: string;
310
+ /** Type of address (e.g., 'home', 'work', 'billing') */
251
311
  type?: string;
312
+ /** Custom label for the address */
252
313
  label?: string;
314
+ /** Whether this is the primary address */
253
315
  primary?: boolean;
316
+ /** Extended address details (building, floor, apartment, etc.) */
254
317
  extendedAddress?: ExtendedAddress;
318
+ /** Single-line formatted address string */
255
319
  formattedAddress?: string;
320
+ /** Geographic location with coordinates */
256
321
  geo?: GeoLocation;
257
322
  }
323
+ /**
324
+ * Structured name components for a user
325
+ */
258
326
  interface UserName {
327
+ /** Family name or last name */
259
328
  familyName?: string;
329
+ /** Given name or first name */
260
330
  givenName?: string;
331
+ /** Middle name or additional names */
261
332
  additionalName?: string;
333
+ /** Name prefix (e.g., 'Dr.', 'Mr.', 'Ms.') */
262
334
  namePrefix?: string;
335
+ /** Name suffix (e.g., 'Jr.', 'Sr.', 'III') */
263
336
  nameSuffix?: string;
337
+ /** Surname (alternative to familyName) */
264
338
  surname?: string;
265
339
  }
340
+ /**
341
+ * Complete user model with all profile fields, credentials, and encryption keys
342
+ */
266
343
  interface User {
344
+ /** Common name (username) */
267
345
  cn: string;
346
+ /** Surname or last name */
268
347
  sn: string;
348
+ /** Given name or first name */
269
349
  givenName: string;
350
+ /** Display name shown in UI */
270
351
  displayName: string;
352
+ /** Primary email address */
271
353
  mail: string;
354
+ /** Primary mobile phone number */
272
355
  mobile: string;
356
+ /** Encrypted user password */
273
357
  userPassword: string;
358
+ /** Scrypt parameter: block size */
274
359
  scryptR: number;
360
+ /** Scrypt parameter: CPU/memory cost */
275
361
  scryptN: number;
362
+ /** Scrypt parameter: parallelization */
276
363
  scryptP: number;
364
+ /** Salt for password encryption */
277
365
  scryptSalt: string;
366
+ /** Derived key length for scrypt */
278
367
  scryptDKLength: number;
368
+ /** Number of iterations for key derivation */
279
369
  iterations: number;
370
+ /** User's domain */
280
371
  domain: string;
372
+ /** User's public encryption key */
281
373
  publicKey: string;
374
+ /** User's private encryption key */
282
375
  privateKey: string;
376
+ /** Protected encryption key */
283
377
  protectedKey: string;
378
+ /** Whether two-factor authentication is enabled */
284
379
  twoFactorEnabled?: string;
380
+ /** URL of user's workspace */
285
381
  workspaceUrl?: string;
382
+ /** Recovery email for account recovery */
286
383
  recoveryEmail?: string;
384
+ /** Timestamp when password account was locked */
287
385
  pwdAccountLockedTime?: string;
386
+ /** User's role in Twake organization ('owner', 'admin', 'moderator', 'member') */
288
387
  twakeOrganizationRole?: string;
388
+ /** Full name as a single string */
289
389
  fullname?: string;
390
+ /** Structured name components */
290
391
  name?: UserName;
392
+ /** Birthday in ISO 8601 format (YYYY-MM-DD) */
291
393
  birthday?: string;
394
+ /** Gender */
292
395
  gender?: string;
396
+ /** Personal note or description */
293
397
  note?: string;
398
+ /** Array of email addresses */
294
399
  email?: EmailAddress[];
400
+ /** Array of instant messaging contacts */
295
401
  impp?: InstantMessaging[];
402
+ /** Place of birth */
296
403
  birthplace?: string;
404
+ /** Job title or position */
297
405
  jobTitle?: string;
406
+ /** Company or organization name */
298
407
  company?: string;
408
+ /** Array of phone numbers */
299
409
  phone?: PhoneNumber[];
410
+ /** Array of physical addresses */
300
411
  address?: Address[];
301
412
  }
413
+ /**
414
+ * User password credentials with scrypt encryption parameters
415
+ */
302
416
  interface UserCredentials {
417
+ /** Encrypted password */
303
418
  userPassword: string;
419
+ /** Scrypt CPU/memory cost parameter (power of 2, e.g., 16384) */
304
420
  scryptN: number;
421
+ /** Scrypt parallelization parameter (typically 1) */
305
422
  scryptP: number;
423
+ /** Scrypt block size parameter (typically 8) */
306
424
  scryptR: number;
425
+ /** Random salt for password hashing */
307
426
  scryptSalt: string;
427
+ /** Derived key length in bytes (typically 32) */
308
428
  scryptDKLength: number;
429
+ /** Number of PBKDF2 iterations */
309
430
  iterations: number;
310
431
  }
432
+ /**
433
+ * User's cryptographic keys for end-to-end encryption
434
+ */
311
435
  interface UserKeys {
436
+ /** User's private encryption key */
312
437
  privateKey: string;
438
+ /** User's public encryption key */
313
439
  publicKey: string;
440
+ /** Password-protected version of the private key */
314
441
  protectedKey: string;
315
442
  }
443
+ /**
444
+ * User account status
445
+ */
316
446
  type UserStatus = 'active' | 'disabled';
447
+ /**
448
+ * Fields that can be used to search for users
449
+ */
317
450
  type UserSearchField = 'username' | 'phone' | 'email' | 'recoveryEmail';
451
+ /**
452
+ * Request payload for creating a new B2C user
453
+ * Includes all required fields plus optional profile information
454
+ */
318
455
  interface CreateUserRequest extends UserCredentials, UserKeys {
319
456
  cn: string;
320
457
  uid: string;
@@ -342,6 +479,10 @@ interface CreateUserRequest extends UserCredentials, UserKeys {
342
479
  phone?: PhoneNumber[];
343
480
  address?: Address[];
344
481
  }
482
+ /**
483
+ * Request payload for updating a user's profile
484
+ * All fields are optional and only provided fields will be updated
485
+ */
345
486
  interface UpdateUserRequest {
346
487
  mobile?: string;
347
488
  userPassword?: string;
@@ -420,13 +561,6 @@ interface ListUsersResponse {
420
561
  hasPreviousPage: boolean;
421
562
  };
422
563
  }
423
- /**
424
- * Response from creating a B2B user in an organization
425
- */
426
- interface CreateB2BUserResponse {
427
- /** Base DN of the created user */
428
- baseDN: string;
429
- }
430
564
 
431
565
  /**
432
566
  * Organization domain model representing a B2B organization
@@ -595,13 +729,6 @@ interface CreateGroupRequest {
595
729
  /** Optional group description */
596
730
  description?: string;
597
731
  }
598
- /**
599
- * Response from creating a group
600
- */
601
- interface CreateGroupResponse {
602
- success: true;
603
- group: Group;
604
- }
605
732
  /**
606
733
  * Request parameters for updating a group
607
734
  */
@@ -754,6 +881,27 @@ declare class UsersResource extends BaseResource {
754
881
  * ```
755
882
  */
756
883
  fetch: (params: FetchUserRequest) => Promise<User>;
884
+ /**
885
+ * Gets organizations where a user has a role
886
+ *
887
+ * Returns organizations where the user is an admin or owner.
888
+ * Optionally filter by specific role.
889
+ *
890
+ * @param {string} userId - User identifier (username)
891
+ * @param {string} [role] - Optional role filter ('owner', 'admin', 'moderator', 'member')
892
+ * @returns {Promise<Organization[]>} Array of organizations
893
+ * @throws {ApiError} On API errors
894
+ *
895
+ * @example
896
+ * ```typescript
897
+ * // Get all organizations where user has any role
898
+ * const orgs = await client.users.getUserOrganizations('johndoe');
899
+ *
900
+ * // Get only organizations where user is owner
901
+ * const ownedOrgs = await client.users.getUserOrganizations('johndoe', 'owner');
902
+ * ```
903
+ */
904
+ getUserOrganizations: (userId: string, role?: string) => Promise<Organization[]>;
757
905
  }
758
906
 
759
907
  /**
@@ -982,7 +1130,7 @@ declare class OrganizationsResource extends BaseResource {
982
1130
  *
983
1131
  * @param {string} organizationId - Organization identifier
984
1132
  * @param {CreateUserRequest} data - User data including credentials and profile
985
- * @returns {Promise<CreateB2BUserResponse>} Response with user's baseDN
1133
+ * @returns {Promise<User>} The created user object
986
1134
  * @throws {ForbiddenError} When user lacks admin privileges
987
1135
  * @throws {NotFoundError} When organization is not found
988
1136
  * @throws {ConflictError} When username/email/phone already exists
@@ -990,14 +1138,14 @@ declare class OrganizationsResource extends BaseResource {
990
1138
  *
991
1139
  * @example
992
1140
  * ```typescript
993
- * const result = await client.organizations.createUser('org_abc123', {
1141
+ * const user = await client.organizations.createUser('org_abc123', {
994
1142
  * cn: 'john.doe',
995
1143
  * uid: 'john.doe',
996
1144
  * // ... other user fields
997
1145
  * });
998
1146
  * ```
999
1147
  */
1000
- createUser: (organizationId: string, data: CreateUserRequest) => Promise<CreateB2BUserResponse>;
1148
+ createUser: (organizationId: string, data: CreateUserRequest) => Promise<User>;
1001
1149
  /**
1002
1150
  * Updates a user in an organization
1003
1151
  *
@@ -1006,19 +1154,19 @@ declare class OrganizationsResource extends BaseResource {
1006
1154
  * @param {string} organizationId - Organization identifier
1007
1155
  * @param {string} userId - User identifier (username)
1008
1156
  * @param {UpdateUserRequest} data - Fields to update
1009
- * @returns {Promise<{ success: true }>} Success response
1157
+ * @returns {Promise<User | { success: true }>} Updated user object or success response
1010
1158
  * @throws {NotFoundError} When user or organization is not found
1011
1159
  * @throws {ForbiddenError} When user lacks admin privileges
1012
1160
  * @throws {ApiError} On other API errors
1013
1161
  *
1014
1162
  * @example
1015
1163
  * ```typescript
1016
- * await client.organizations.updateUser('org_abc123', 'john.doe', {
1164
+ * const result = await client.organizations.updateUser('org_abc123', 'john.doe', {
1017
1165
  * mobile: '+33687654321'
1018
1166
  * });
1019
1167
  * ```
1020
1168
  */
1021
- updateUser: (organizationId: string, userId: string, data: UpdateUserRequest) => Promise<{
1169
+ updateUser: (organizationId: string, userId: string, data: UpdateUserRequest) => Promise<User | {
1022
1170
  success: true;
1023
1171
  }>;
1024
1172
  /**
@@ -1189,7 +1337,7 @@ declare class GroupsResource extends BaseResource {
1189
1337
  *
1190
1338
  * @param {string} organizationId - Organization identifier
1191
1339
  * @param {CreateGroupRequest} data - Group data (name and optional description)
1192
- * @returns {Promise<CreateGroupResponse>} Created group details
1340
+ * @returns {Promise<Group>} Created group object
1193
1341
  * @throws {ForbiddenError} When user lacks admin privileges
1194
1342
  * @throws {NotFoundError} When organization is not found
1195
1343
  * @throws {ConflictError} When group name already exists
@@ -1197,13 +1345,13 @@ declare class GroupsResource extends BaseResource {
1197
1345
  *
1198
1346
  * @examples
1199
1347
  * ```typescript
1200
- * const result = await client.groups.create('org_abc123', {
1348
+ * const group = await client.groups.create('org_abc123', {
1201
1349
  * name: 'engineering',
1202
1350
  * description: 'Engineering team'
1203
1351
  * });
1204
1352
  * ```
1205
1353
  */
1206
- create: (organizationId: string, data: CreateGroupRequest) => Promise<CreateGroupResponse>;
1354
+ create: (organizationId: string, data: CreateGroupRequest) => Promise<Group>;
1207
1355
  /**
1208
1356
  * Lists all groups in an organization with pagination
1209
1357
  *
@@ -1542,4 +1690,4 @@ declare class NetworkError extends LdapRestError {
1542
1690
  constructor(message: string, cause?: Error);
1543
1691
  }
1544
1692
 
1545
- export { type AddGroupMembersRequest, type Address, ApiError, AuthenticationError, AuthorizationError, type ChangeUserRoleRequest, type CheckAvailabilityParams, type CheckAvailabilityResponse, type CheckOrganizationAvailabilityParams, type ClientConfig, ConflictError, type CreateAdminRequest, type CreateB2BUserResponse, type CreateGroupRequest, type CreateGroupResponse, 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 };
1693
+ export { type AddGroupMembersRequest, type Address, ApiError, AuthenticationError, AuthorizationError, type ChangeUserRoleRequest, type CheckAvailabilityParams, type CheckAvailabilityResponse, type CheckOrganizationAvailabilityParams, type ClientConfig, ConflictError, type CreateAdminRequest, 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 };
package/dist/index.js CHANGED
@@ -38,6 +38,11 @@ module.exports = __toCommonJS(index_exports);
38
38
 
39
39
  // src/config/ClientConfig.ts
40
40
  var ConfigValidator = class {
41
+ /**
42
+ * Validates the client configuration
43
+ * @param {ClientConfig} config - Configuration to validate
44
+ * @throws {Error} If configuration is invalid
45
+ */
41
46
  static validate(config) {
42
47
  if (!config.baseUrl || config.baseUrl.trim().length === 0) {
43
48
  throw new Error("baseUrl is required");
@@ -64,6 +69,11 @@ var ConfigValidator = class {
64
69
  throw new Error("timeout must be a positive number");
65
70
  }
66
71
  }
72
+ /**
73
+ * Normalizes the client configuration by applying defaults
74
+ * @param {ClientConfig} config - Configuration to normalize
75
+ * @returns {NormalizedClientConfig} Normalized configuration with defaults applied
76
+ */
67
77
  static normalize(config) {
68
78
  return {
69
79
  baseUrl: config.baseUrl.replace(/\/$/, ""),
@@ -72,6 +82,11 @@ var ConfigValidator = class {
72
82
  logger: config.logger
73
83
  };
74
84
  }
85
+ /**
86
+ * Extracts HTTP-specific configuration from normalized config
87
+ * @param {NormalizedClientConfig} config - Normalized configuration
88
+ * @returns {HttpConfig} HTTP client configuration
89
+ */
75
90
  static toHttpConfig(config) {
76
91
  return {
77
92
  baseUrl: config.baseUrl,
@@ -617,6 +632,30 @@ var UsersResource = class extends BaseResource {
617
632
  const query = this.buildQueryString(params);
618
633
  return this.http.get(`/api/v1/users${query}`);
619
634
  };
635
+ /**
636
+ * Gets organizations where a user has a role
637
+ *
638
+ * Returns organizations where the user is an admin or owner.
639
+ * Optionally filter by specific role.
640
+ *
641
+ * @param {string} userId - User identifier (username)
642
+ * @param {string} [role] - Optional role filter ('owner', 'admin', 'moderator', 'member')
643
+ * @returns {Promise<Organization[]>} Array of organizations
644
+ * @throws {ApiError} On API errors
645
+ *
646
+ * @example
647
+ * ```typescript
648
+ * // Get all organizations where user has any role
649
+ * const orgs = await client.users.getUserOrganizations('johndoe');
650
+ *
651
+ * // Get only organizations where user is owner
652
+ * const ownedOrgs = await client.users.getUserOrganizations('johndoe', 'owner');
653
+ * ```
654
+ */
655
+ getUserOrganizations = async (userId, role) => {
656
+ const query = role ? this.buildQueryString({ role }) : "";
657
+ return this.http.get(`/api/v1/users/${encodeURIComponent(userId)}/organizations${query}`);
658
+ };
620
659
  };
621
660
 
622
661
  // src/resources/OrganizationsResource.ts
@@ -839,7 +878,7 @@ var OrganizationsResource = class extends BaseResource {
839
878
  *
840
879
  * @param {string} organizationId - Organization identifier
841
880
  * @param {CreateUserRequest} data - User data including credentials and profile
842
- * @returns {Promise<CreateB2BUserResponse>} Response with user's baseDN
881
+ * @returns {Promise<User>} The created user object
843
882
  * @throws {ForbiddenError} When user lacks admin privileges
844
883
  * @throws {NotFoundError} When organization is not found
845
884
  * @throws {ConflictError} When username/email/phone already exists
@@ -847,7 +886,7 @@ var OrganizationsResource = class extends BaseResource {
847
886
  *
848
887
  * @example
849
888
  * ```typescript
850
- * const result = await client.organizations.createUser('org_abc123', {
889
+ * const user = await client.organizations.createUser('org_abc123', {
851
890
  * cn: 'john.doe',
852
891
  * uid: 'john.doe',
853
892
  * // ... other user fields
@@ -868,14 +907,14 @@ var OrganizationsResource = class extends BaseResource {
868
907
  * @param {string} organizationId - Organization identifier
869
908
  * @param {string} userId - User identifier (username)
870
909
  * @param {UpdateUserRequest} data - Fields to update
871
- * @returns {Promise<{ success: true }>} Success response
910
+ * @returns {Promise<User | { success: true }>} Updated user object or success response
872
911
  * @throws {NotFoundError} When user or organization is not found
873
912
  * @throws {ForbiddenError} When user lacks admin privileges
874
913
  * @throws {ApiError} On other API errors
875
914
  *
876
915
  * @example
877
916
  * ```typescript
878
- * await client.organizations.updateUser('org_abc123', 'john.doe', {
917
+ * const result = await client.organizations.updateUser('org_abc123', 'john.doe', {
879
918
  * mobile: '+33687654321'
880
919
  * });
881
920
  * ```
@@ -1054,7 +1093,7 @@ var GroupsResource = class extends BaseResource {
1054
1093
  *
1055
1094
  * @param {string} organizationId - Organization identifier
1056
1095
  * @param {CreateGroupRequest} data - Group data (name and optional description)
1057
- * @returns {Promise<CreateGroupResponse>} Created group details
1096
+ * @returns {Promise<Group>} Created group object
1058
1097
  * @throws {ForbiddenError} When user lacks admin privileges
1059
1098
  * @throws {NotFoundError} When organization is not found
1060
1099
  * @throws {ConflictError} When group name already exists
@@ -1062,7 +1101,7 @@ var GroupsResource = class extends BaseResource {
1062
1101
  *
1063
1102
  * @examples
1064
1103
  * ```typescript
1065
- * const result = await client.groups.create('org_abc123', {
1104
+ * const group = await client.groups.create('org_abc123', {
1066
1105
  * name: 'engineering',
1067
1106
  * description: 'Engineering team'
1068
1107
  * });
package/dist/index.mjs CHANGED
@@ -1,5 +1,10 @@
1
1
  // src/config/ClientConfig.ts
2
2
  var ConfigValidator = class {
3
+ /**
4
+ * Validates the client configuration
5
+ * @param {ClientConfig} config - Configuration to validate
6
+ * @throws {Error} If configuration is invalid
7
+ */
3
8
  static validate(config) {
4
9
  if (!config.baseUrl || config.baseUrl.trim().length === 0) {
5
10
  throw new Error("baseUrl is required");
@@ -26,6 +31,11 @@ var ConfigValidator = class {
26
31
  throw new Error("timeout must be a positive number");
27
32
  }
28
33
  }
34
+ /**
35
+ * Normalizes the client configuration by applying defaults
36
+ * @param {ClientConfig} config - Configuration to normalize
37
+ * @returns {NormalizedClientConfig} Normalized configuration with defaults applied
38
+ */
29
39
  static normalize(config) {
30
40
  return {
31
41
  baseUrl: config.baseUrl.replace(/\/$/, ""),
@@ -34,6 +44,11 @@ var ConfigValidator = class {
34
44
  logger: config.logger
35
45
  };
36
46
  }
47
+ /**
48
+ * Extracts HTTP-specific configuration from normalized config
49
+ * @param {NormalizedClientConfig} config - Normalized configuration
50
+ * @returns {HttpConfig} HTTP client configuration
51
+ */
37
52
  static toHttpConfig(config) {
38
53
  return {
39
54
  baseUrl: config.baseUrl,
@@ -579,6 +594,30 @@ var UsersResource = class extends BaseResource {
579
594
  const query = this.buildQueryString(params);
580
595
  return this.http.get(`/api/v1/users${query}`);
581
596
  };
597
+ /**
598
+ * Gets organizations where a user has a role
599
+ *
600
+ * Returns organizations where the user is an admin or owner.
601
+ * Optionally filter by specific role.
602
+ *
603
+ * @param {string} userId - User identifier (username)
604
+ * @param {string} [role] - Optional role filter ('owner', 'admin', 'moderator', 'member')
605
+ * @returns {Promise<Organization[]>} Array of organizations
606
+ * @throws {ApiError} On API errors
607
+ *
608
+ * @example
609
+ * ```typescript
610
+ * // Get all organizations where user has any role
611
+ * const orgs = await client.users.getUserOrganizations('johndoe');
612
+ *
613
+ * // Get only organizations where user is owner
614
+ * const ownedOrgs = await client.users.getUserOrganizations('johndoe', 'owner');
615
+ * ```
616
+ */
617
+ getUserOrganizations = async (userId, role) => {
618
+ const query = role ? this.buildQueryString({ role }) : "";
619
+ return this.http.get(`/api/v1/users/${encodeURIComponent(userId)}/organizations${query}`);
620
+ };
582
621
  };
583
622
 
584
623
  // src/resources/OrganizationsResource.ts
@@ -801,7 +840,7 @@ var OrganizationsResource = class extends BaseResource {
801
840
  *
802
841
  * @param {string} organizationId - Organization identifier
803
842
  * @param {CreateUserRequest} data - User data including credentials and profile
804
- * @returns {Promise<CreateB2BUserResponse>} Response with user's baseDN
843
+ * @returns {Promise<User>} The created user object
805
844
  * @throws {ForbiddenError} When user lacks admin privileges
806
845
  * @throws {NotFoundError} When organization is not found
807
846
  * @throws {ConflictError} When username/email/phone already exists
@@ -809,7 +848,7 @@ var OrganizationsResource = class extends BaseResource {
809
848
  *
810
849
  * @example
811
850
  * ```typescript
812
- * const result = await client.organizations.createUser('org_abc123', {
851
+ * const user = await client.organizations.createUser('org_abc123', {
813
852
  * cn: 'john.doe',
814
853
  * uid: 'john.doe',
815
854
  * // ... other user fields
@@ -830,14 +869,14 @@ var OrganizationsResource = class extends BaseResource {
830
869
  * @param {string} organizationId - Organization identifier
831
870
  * @param {string} userId - User identifier (username)
832
871
  * @param {UpdateUserRequest} data - Fields to update
833
- * @returns {Promise<{ success: true }>} Success response
872
+ * @returns {Promise<User | { success: true }>} Updated user object or success response
834
873
  * @throws {NotFoundError} When user or organization is not found
835
874
  * @throws {ForbiddenError} When user lacks admin privileges
836
875
  * @throws {ApiError} On other API errors
837
876
  *
838
877
  * @example
839
878
  * ```typescript
840
- * await client.organizations.updateUser('org_abc123', 'john.doe', {
879
+ * const result = await client.organizations.updateUser('org_abc123', 'john.doe', {
841
880
  * mobile: '+33687654321'
842
881
  * });
843
882
  * ```
@@ -1016,7 +1055,7 @@ var GroupsResource = class extends BaseResource {
1016
1055
  *
1017
1056
  * @param {string} organizationId - Organization identifier
1018
1057
  * @param {CreateGroupRequest} data - Group data (name and optional description)
1019
- * @returns {Promise<CreateGroupResponse>} Created group details
1058
+ * @returns {Promise<Group>} Created group object
1020
1059
  * @throws {ForbiddenError} When user lacks admin privileges
1021
1060
  * @throws {NotFoundError} When organization is not found
1022
1061
  * @throws {ConflictError} When group name already exists
@@ -1024,7 +1063,7 @@ var GroupsResource = class extends BaseResource {
1024
1063
  *
1025
1064
  * @examples
1026
1065
  * ```typescript
1027
- * const result = await client.groups.create('org_abc123', {
1066
+ * const group = await client.groups.create('org_abc123', {
1028
1067
  * name: 'engineering',
1029
1068
  * description: 'Engineering team'
1030
1069
  * });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linagora/ldap-rest-client",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "TypeScript API client for LDAP-REST",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",