@linagora/ldap-rest-client 1.0.0 → 1.0.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/dist/index.d.mts CHANGED
@@ -68,7 +68,7 @@ interface Auth {
68
68
  */
69
69
  interface RequestOptions {
70
70
  /** HTTP method */
71
- method: 'GET' | 'POST' | 'PATCH' | 'DELETE';
71
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
72
72
  /** Request path (relative to base URL) */
73
73
  path: string;
74
74
  /** Request body (will be JSON stringified) */
@@ -81,6 +81,7 @@ interface RequestOptions {
81
81
  *
82
82
  * Handles all HTTP communication with the LDAP-REST API including:
83
83
  * - Optional HMAC authentication or cookie-based SSO
84
+ * - Automatic redirect following for SSO flows
84
85
  * - Error mapping and handling
85
86
  * - Request timeouts
86
87
  *
@@ -143,6 +144,16 @@ declare class HttpClient {
143
144
  * @returns {Promise<T>} Parsed response body
144
145
  */
145
146
  post: <T>(path: string, body?: unknown, headers?: Record<string, string>) => Promise<T>;
147
+ /**
148
+ * Performs a PUT request
149
+ *
150
+ * @template T - Response type
151
+ * @param {string} path - Request path
152
+ * @param {unknown} [body] - Request body
153
+ * @param {Record<string, string>} [headers] - Additional headers
154
+ * @returns {Promise<T>} Parsed response body
155
+ */
156
+ put: <T>(path: string, body?: unknown, headers?: Record<string, string>) => Promise<T>;
146
157
  /**
147
158
  * Performs a PATCH request
148
159
  *
@@ -499,7 +510,7 @@ interface UpdateOrganizationRequest {
499
510
  /**
500
511
  * User role within an organization
501
512
  */
502
- type OrganizationRole = 'admin' | 'moderator' | 'member';
513
+ type OrganizationRole = 'owner' | 'admin' | 'moderator' | 'member';
503
514
  /**
504
515
  * Request parameters for changing a user's role in an organization
505
516
  */
@@ -507,6 +518,51 @@ interface ChangeUserRoleRequest {
507
518
  /** New role for the user */
508
519
  role: OrganizationRole;
509
520
  }
521
+ /**
522
+ * Organization owner information
523
+ */
524
+ interface OrganizationOwner {
525
+ /** Owner username */
526
+ username: string;
527
+ /** Owner email address */
528
+ mail?: string;
529
+ /** Owner display name */
530
+ displayName?: string;
531
+ }
532
+ /**
533
+ * Response from getting organization owner
534
+ */
535
+ interface GetOwnerResponse {
536
+ /** Current owner (null if no owner set) */
537
+ owner: OrganizationOwner | null;
538
+ }
539
+ /**
540
+ * Request parameters for setting organization owner
541
+ */
542
+ interface SetOwnerRequest {
543
+ /** Username of the user to set as owner */
544
+ username: string;
545
+ /** Email address of the user */
546
+ mail: string;
547
+ }
548
+ /**
549
+ * Request parameters for transferring organization ownership
550
+ */
551
+ interface TransferOwnershipRequest {
552
+ /** Username of the new owner */
553
+ newOwnerUsername: string;
554
+ }
555
+ /**
556
+ * Fields that can be used to search for organizations
557
+ */
558
+ type OrganizationSearchField = 'id' | 'domain';
559
+ /**
560
+ * Parameters for checking availability of organization id or domain
561
+ */
562
+ interface CheckOrganizationAvailabilityParams extends Record<string, string> {
563
+ field: OrganizationSearchField;
564
+ value: string;
565
+ }
510
566
 
511
567
  /**
512
568
  * Group domain model representing a group within a B2B organization
@@ -738,7 +794,7 @@ declare class OrganizationsResource extends BaseResource {
738
794
  /**
739
795
  * Checks if an organization identifier is available
740
796
  *
741
- * @param {CheckAvailabilityParams} params - Field and value to check
797
+ * @param {CheckOrganizationAvailabilityParams} params - Field and value to check
742
798
  * @returns {Promise<CheckAvailabilityResponse>} Availability status
743
799
  * @throws {ApiError} On API errors
744
800
  *
@@ -750,7 +806,7 @@ declare class OrganizationsResource extends BaseResource {
750
806
  * });
751
807
  * ```
752
808
  */
753
- checkAvailability: (params: CheckAvailabilityParams) => Promise<CheckAvailabilityResponse>;
809
+ checkAvailability: (params: CheckOrganizationAvailabilityParams) => Promise<CheckAvailabilityResponse>;
754
810
  /**
755
811
  * Links a user as the first admin of an organization
756
812
  *
@@ -829,6 +885,96 @@ declare class OrganizationsResource extends BaseResource {
829
885
  update: (organizationId: string, data: UpdateOrganizationRequest) => Promise<{
830
886
  success: true;
831
887
  }>;
888
+ /**
889
+ * Gets the current owner of an organization
890
+ *
891
+ * Returns the owner information including username, email, and display name.
892
+ * Returns null if no owner is set.
893
+ *
894
+ * @param {string} organizationId - Organization identifier
895
+ * @returns {Promise<GetOwnerResponse>} Owner information or null
896
+ * @throws {NotFoundError} When organization is not found
897
+ * @throws {ApiError} On other API errors
898
+ *
899
+ * @example
900
+ * ```typescript
901
+ * const response = await client.organizations.getOwner('org_abc123');
902
+ * if (response.owner) {
903
+ * console.log(`Owner: ${response.owner.username}`);
904
+ * }
905
+ * ```
906
+ */
907
+ getOwner: (organizationId: string) => Promise<GetOwnerResponse>;
908
+ /**
909
+ * Sets the initial owner of an organization
910
+ *
911
+ * Can only be used when the organization has no owner. To transfer ownership
912
+ * from an existing owner, use transferOwnership instead.
913
+ * Typically used by SaaS tools during organization setup.
914
+ *
915
+ * @param {string} organizationId - Organization identifier
916
+ * @param {SetOwnerRequest} data - Owner details (username and email)
917
+ * @returns {Promise<{ success: true }>} Success response
918
+ * @throws {NotFoundError} When organization or user is not found
919
+ * @throws {ConflictError} When organization already has an owner
920
+ * @throws {ApiError} On other API errors
921
+ *
922
+ * @example
923
+ * ```typescript
924
+ * await client.organizations.setOwner('org_abc123', {
925
+ * username: 'john.doe',
926
+ * mail: 'john.doe@acme.example.com'
927
+ * });
928
+ * ```
929
+ */
930
+ setOwner: (organizationId: string, data: SetOwnerRequest) => Promise<{
931
+ success: true;
932
+ }>;
933
+ /**
934
+ * Transfers organization ownership to another user
935
+ *
936
+ * Must be called by the current owner or by SaaS tools (with HMAC auth).
937
+ * The current owner will be demoted to admin role.
938
+ * The new owner must be an existing user.
939
+ *
940
+ * @param {string} organizationId - Organization identifier
941
+ * @param {TransferOwnershipRequest} data - New owner username
942
+ * @returns {Promise<{ success: true }>} Success response
943
+ * @throws {NotFoundError} When organization or new owner user is not found
944
+ * @throws {ForbiddenError} When caller is not the current owner or SaaS tool
945
+ * @throws {ConflictError} When ownership changed by another request (race condition)
946
+ * @throws {ApiError} On other API errors
947
+ *
948
+ * @example
949
+ * ```typescript
950
+ * await client.organizations.transferOwnership('org_abc123', {
951
+ * newOwnerUsername: 'jane.doe'
952
+ * });
953
+ * ```
954
+ */
955
+ transferOwnership: (organizationId: string, data: TransferOwnershipRequest) => Promise<{
956
+ success: true;
957
+ }>;
958
+ /**
959
+ * Deletes an organization
960
+ *
961
+ * Permanently removes the organization and all its data.
962
+ * Can only be called by the organization owner or SaaS tools (with HMAC auth).
963
+ *
964
+ * @param {string} organizationId - Organization identifier
965
+ * @returns {Promise<{ success: true }>} Success response
966
+ * @throws {NotFoundError} When organization is not found
967
+ * @throws {ForbiddenError} When caller is not the organization owner
968
+ * @throws {ApiError} On other API errors
969
+ *
970
+ * @example
971
+ * ```typescript
972
+ * await client.organizations.delete('org_abc123');
973
+ * ```
974
+ */
975
+ delete: (organizationId: string) => Promise<{
976
+ success: true;
977
+ }>;
832
978
  /**
833
979
  * Creates a new user in an organization's LDAP branch
834
980
  *
@@ -1396,4 +1542,4 @@ declare class NetworkError extends LdapRestError {
1396
1542
  constructor(message: string, cause?: Error);
1397
1543
  }
1398
1544
 
1399
- export { type AddGroupMembersRequest, type Address, ApiError, AuthenticationError, AuthorizationError, type ChangeUserRoleRequest, type CheckAvailabilityParams, type CheckAvailabilityResponse, 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 Group, GroupsResource, type InstantMessaging, LdapRestClient, LdapRestError, type ListGroupsParams, type ListGroupsResponse, type ListUsersParams, type ListUsersResponse, NetworkError, NotFoundError, type Organization, type OrganizationMetadata, type OrganizationRole, type OrganizationStatus, OrganizationsResource, type PhoneNumber, RateLimitError, type UpdateGroupRequest, type UpdateOrganizationRequest, type UpdateUserRequest, type User, type UserCredentials, type UserKeys, type UserName, type UserSearchField, type UserStatus, UsersResource, ValidationError };
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 };
package/dist/index.d.ts CHANGED
@@ -68,7 +68,7 @@ interface Auth {
68
68
  */
69
69
  interface RequestOptions {
70
70
  /** HTTP method */
71
- method: 'GET' | 'POST' | 'PATCH' | 'DELETE';
71
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
72
72
  /** Request path (relative to base URL) */
73
73
  path: string;
74
74
  /** Request body (will be JSON stringified) */
@@ -81,6 +81,7 @@ interface RequestOptions {
81
81
  *
82
82
  * Handles all HTTP communication with the LDAP-REST API including:
83
83
  * - Optional HMAC authentication or cookie-based SSO
84
+ * - Automatic redirect following for SSO flows
84
85
  * - Error mapping and handling
85
86
  * - Request timeouts
86
87
  *
@@ -143,6 +144,16 @@ declare class HttpClient {
143
144
  * @returns {Promise<T>} Parsed response body
144
145
  */
145
146
  post: <T>(path: string, body?: unknown, headers?: Record<string, string>) => Promise<T>;
147
+ /**
148
+ * Performs a PUT request
149
+ *
150
+ * @template T - Response type
151
+ * @param {string} path - Request path
152
+ * @param {unknown} [body] - Request body
153
+ * @param {Record<string, string>} [headers] - Additional headers
154
+ * @returns {Promise<T>} Parsed response body
155
+ */
156
+ put: <T>(path: string, body?: unknown, headers?: Record<string, string>) => Promise<T>;
146
157
  /**
147
158
  * Performs a PATCH request
148
159
  *
@@ -499,7 +510,7 @@ interface UpdateOrganizationRequest {
499
510
  /**
500
511
  * User role within an organization
501
512
  */
502
- type OrganizationRole = 'admin' | 'moderator' | 'member';
513
+ type OrganizationRole = 'owner' | 'admin' | 'moderator' | 'member';
503
514
  /**
504
515
  * Request parameters for changing a user's role in an organization
505
516
  */
@@ -507,6 +518,51 @@ interface ChangeUserRoleRequest {
507
518
  /** New role for the user */
508
519
  role: OrganizationRole;
509
520
  }
521
+ /**
522
+ * Organization owner information
523
+ */
524
+ interface OrganizationOwner {
525
+ /** Owner username */
526
+ username: string;
527
+ /** Owner email address */
528
+ mail?: string;
529
+ /** Owner display name */
530
+ displayName?: string;
531
+ }
532
+ /**
533
+ * Response from getting organization owner
534
+ */
535
+ interface GetOwnerResponse {
536
+ /** Current owner (null if no owner set) */
537
+ owner: OrganizationOwner | null;
538
+ }
539
+ /**
540
+ * Request parameters for setting organization owner
541
+ */
542
+ interface SetOwnerRequest {
543
+ /** Username of the user to set as owner */
544
+ username: string;
545
+ /** Email address of the user */
546
+ mail: string;
547
+ }
548
+ /**
549
+ * Request parameters for transferring organization ownership
550
+ */
551
+ interface TransferOwnershipRequest {
552
+ /** Username of the new owner */
553
+ newOwnerUsername: string;
554
+ }
555
+ /**
556
+ * Fields that can be used to search for organizations
557
+ */
558
+ type OrganizationSearchField = 'id' | 'domain';
559
+ /**
560
+ * Parameters for checking availability of organization id or domain
561
+ */
562
+ interface CheckOrganizationAvailabilityParams extends Record<string, string> {
563
+ field: OrganizationSearchField;
564
+ value: string;
565
+ }
510
566
 
511
567
  /**
512
568
  * Group domain model representing a group within a B2B organization
@@ -738,7 +794,7 @@ declare class OrganizationsResource extends BaseResource {
738
794
  /**
739
795
  * Checks if an organization identifier is available
740
796
  *
741
- * @param {CheckAvailabilityParams} params - Field and value to check
797
+ * @param {CheckOrganizationAvailabilityParams} params - Field and value to check
742
798
  * @returns {Promise<CheckAvailabilityResponse>} Availability status
743
799
  * @throws {ApiError} On API errors
744
800
  *
@@ -750,7 +806,7 @@ declare class OrganizationsResource extends BaseResource {
750
806
  * });
751
807
  * ```
752
808
  */
753
- checkAvailability: (params: CheckAvailabilityParams) => Promise<CheckAvailabilityResponse>;
809
+ checkAvailability: (params: CheckOrganizationAvailabilityParams) => Promise<CheckAvailabilityResponse>;
754
810
  /**
755
811
  * Links a user as the first admin of an organization
756
812
  *
@@ -829,6 +885,96 @@ declare class OrganizationsResource extends BaseResource {
829
885
  update: (organizationId: string, data: UpdateOrganizationRequest) => Promise<{
830
886
  success: true;
831
887
  }>;
888
+ /**
889
+ * Gets the current owner of an organization
890
+ *
891
+ * Returns the owner information including username, email, and display name.
892
+ * Returns null if no owner is set.
893
+ *
894
+ * @param {string} organizationId - Organization identifier
895
+ * @returns {Promise<GetOwnerResponse>} Owner information or null
896
+ * @throws {NotFoundError} When organization is not found
897
+ * @throws {ApiError} On other API errors
898
+ *
899
+ * @example
900
+ * ```typescript
901
+ * const response = await client.organizations.getOwner('org_abc123');
902
+ * if (response.owner) {
903
+ * console.log(`Owner: ${response.owner.username}`);
904
+ * }
905
+ * ```
906
+ */
907
+ getOwner: (organizationId: string) => Promise<GetOwnerResponse>;
908
+ /**
909
+ * Sets the initial owner of an organization
910
+ *
911
+ * Can only be used when the organization has no owner. To transfer ownership
912
+ * from an existing owner, use transferOwnership instead.
913
+ * Typically used by SaaS tools during organization setup.
914
+ *
915
+ * @param {string} organizationId - Organization identifier
916
+ * @param {SetOwnerRequest} data - Owner details (username and email)
917
+ * @returns {Promise<{ success: true }>} Success response
918
+ * @throws {NotFoundError} When organization or user is not found
919
+ * @throws {ConflictError} When organization already has an owner
920
+ * @throws {ApiError} On other API errors
921
+ *
922
+ * @example
923
+ * ```typescript
924
+ * await client.organizations.setOwner('org_abc123', {
925
+ * username: 'john.doe',
926
+ * mail: 'john.doe@acme.example.com'
927
+ * });
928
+ * ```
929
+ */
930
+ setOwner: (organizationId: string, data: SetOwnerRequest) => Promise<{
931
+ success: true;
932
+ }>;
933
+ /**
934
+ * Transfers organization ownership to another user
935
+ *
936
+ * Must be called by the current owner or by SaaS tools (with HMAC auth).
937
+ * The current owner will be demoted to admin role.
938
+ * The new owner must be an existing user.
939
+ *
940
+ * @param {string} organizationId - Organization identifier
941
+ * @param {TransferOwnershipRequest} data - New owner username
942
+ * @returns {Promise<{ success: true }>} Success response
943
+ * @throws {NotFoundError} When organization or new owner user is not found
944
+ * @throws {ForbiddenError} When caller is not the current owner or SaaS tool
945
+ * @throws {ConflictError} When ownership changed by another request (race condition)
946
+ * @throws {ApiError} On other API errors
947
+ *
948
+ * @example
949
+ * ```typescript
950
+ * await client.organizations.transferOwnership('org_abc123', {
951
+ * newOwnerUsername: 'jane.doe'
952
+ * });
953
+ * ```
954
+ */
955
+ transferOwnership: (organizationId: string, data: TransferOwnershipRequest) => Promise<{
956
+ success: true;
957
+ }>;
958
+ /**
959
+ * Deletes an organization
960
+ *
961
+ * Permanently removes the organization and all its data.
962
+ * Can only be called by the organization owner or SaaS tools (with HMAC auth).
963
+ *
964
+ * @param {string} organizationId - Organization identifier
965
+ * @returns {Promise<{ success: true }>} Success response
966
+ * @throws {NotFoundError} When organization is not found
967
+ * @throws {ForbiddenError} When caller is not the organization owner
968
+ * @throws {ApiError} On other API errors
969
+ *
970
+ * @example
971
+ * ```typescript
972
+ * await client.organizations.delete('org_abc123');
973
+ * ```
974
+ */
975
+ delete: (organizationId: string) => Promise<{
976
+ success: true;
977
+ }>;
832
978
  /**
833
979
  * Creates a new user in an organization's LDAP branch
834
980
  *
@@ -1396,4 +1542,4 @@ declare class NetworkError extends LdapRestError {
1396
1542
  constructor(message: string, cause?: Error);
1397
1543
  }
1398
1544
 
1399
- export { type AddGroupMembersRequest, type Address, ApiError, AuthenticationError, AuthorizationError, type ChangeUserRoleRequest, type CheckAvailabilityParams, type CheckAvailabilityResponse, 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 Group, GroupsResource, type InstantMessaging, LdapRestClient, LdapRestError, type ListGroupsParams, type ListGroupsResponse, type ListUsersParams, type ListUsersResponse, NetworkError, NotFoundError, type Organization, type OrganizationMetadata, type OrganizationRole, type OrganizationStatus, OrganizationsResource, type PhoneNumber, RateLimitError, type UpdateGroupRequest, type UpdateOrganizationRequest, type UpdateUserRequest, type User, type UserCredentials, type UserKeys, type UserName, type UserSearchField, type UserStatus, UsersResource, ValidationError };
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 };
package/dist/index.js CHANGED
@@ -318,6 +318,7 @@ var HttpClient = class {
318
318
  });
319
319
  const headers = {
320
320
  "Content-Type": "application/json",
321
+ Accept: "application/json",
321
322
  ...options.headers
322
323
  };
323
324
  if (authHeader) {
@@ -331,7 +332,8 @@ var HttpClient = class {
331
332
  headers,
332
333
  body: bodyString,
333
334
  signal: controller.signal,
334
- credentials: authHeader ? void 0 : "include"
335
+ credentials: authHeader ? void 0 : "include",
336
+ redirect: "follow"
335
337
  });
336
338
  clearTimeout(timeoutId);
337
339
  this.logger.info("Request completed", {
@@ -439,6 +441,18 @@ var HttpClient = class {
439
441
  post = (path, body, headers) => {
440
442
  return this.request({ method: "POST", path, body, headers });
441
443
  };
444
+ /**
445
+ * Performs a PUT request
446
+ *
447
+ * @template T - Response type
448
+ * @param {string} path - Request path
449
+ * @param {unknown} [body] - Request body
450
+ * @param {Record<string, string>} [headers] - Additional headers
451
+ * @returns {Promise<T>} Parsed response body
452
+ */
453
+ put = (path, body, headers) => {
454
+ return this.request({ method: "PUT", path, body, headers });
455
+ };
442
456
  /**
443
457
  * Performs a PATCH request
444
458
  *
@@ -621,7 +635,7 @@ var OrganizationsResource = class extends BaseResource {
621
635
  /**
622
636
  * Checks if an organization identifier is available
623
637
  *
624
- * @param {CheckAvailabilityParams} params - Field and value to check
638
+ * @param {CheckOrganizationAvailabilityParams} params - Field and value to check
625
639
  * @returns {Promise<CheckAvailabilityResponse>} Availability status
626
640
  * @throws {ApiError} On API errors
627
641
  *
@@ -722,6 +736,101 @@ var OrganizationsResource = class extends BaseResource {
722
736
  update = async (organizationId, data) => {
723
737
  return this.http.patch(`/api/v1/organizations/${encodeURIComponent(organizationId)}`, data);
724
738
  };
739
+ /**
740
+ * Gets the current owner of an organization
741
+ *
742
+ * Returns the owner information including username, email, and display name.
743
+ * Returns null if no owner is set.
744
+ *
745
+ * @param {string} organizationId - Organization identifier
746
+ * @returns {Promise<GetOwnerResponse>} Owner information or null
747
+ * @throws {NotFoundError} When organization is not found
748
+ * @throws {ApiError} On other API errors
749
+ *
750
+ * @example
751
+ * ```typescript
752
+ * const response = await client.organizations.getOwner('org_abc123');
753
+ * if (response.owner) {
754
+ * console.log(`Owner: ${response.owner.username}`);
755
+ * }
756
+ * ```
757
+ */
758
+ getOwner = async (organizationId) => {
759
+ return this.http.get(`/api/v1/organizations/${encodeURIComponent(organizationId)}/owner`);
760
+ };
761
+ /**
762
+ * Sets the initial owner of an organization
763
+ *
764
+ * Can only be used when the organization has no owner. To transfer ownership
765
+ * from an existing owner, use transferOwnership instead.
766
+ * Typically used by SaaS tools during organization setup.
767
+ *
768
+ * @param {string} organizationId - Organization identifier
769
+ * @param {SetOwnerRequest} data - Owner details (username and email)
770
+ * @returns {Promise<{ success: true }>} Success response
771
+ * @throws {NotFoundError} When organization or user is not found
772
+ * @throws {ConflictError} When organization already has an owner
773
+ * @throws {ApiError} On other API errors
774
+ *
775
+ * @example
776
+ * ```typescript
777
+ * await client.organizations.setOwner('org_abc123', {
778
+ * username: 'john.doe',
779
+ * mail: 'john.doe@acme.example.com'
780
+ * });
781
+ * ```
782
+ */
783
+ setOwner = async (organizationId, data) => {
784
+ return this.http.post(
785
+ `/api/v1/organizations/${encodeURIComponent(organizationId)}/owner`,
786
+ data
787
+ );
788
+ };
789
+ /**
790
+ * Transfers organization ownership to another user
791
+ *
792
+ * Must be called by the current owner or by SaaS tools (with HMAC auth).
793
+ * The current owner will be demoted to admin role.
794
+ * The new owner must be an existing user.
795
+ *
796
+ * @param {string} organizationId - Organization identifier
797
+ * @param {TransferOwnershipRequest} data - New owner username
798
+ * @returns {Promise<{ success: true }>} Success response
799
+ * @throws {NotFoundError} When organization or new owner user is not found
800
+ * @throws {ForbiddenError} When caller is not the current owner or SaaS tool
801
+ * @throws {ConflictError} When ownership changed by another request (race condition)
802
+ * @throws {ApiError} On other API errors
803
+ *
804
+ * @example
805
+ * ```typescript
806
+ * await client.organizations.transferOwnership('org_abc123', {
807
+ * newOwnerUsername: 'jane.doe'
808
+ * });
809
+ * ```
810
+ */
811
+ transferOwnership = async (organizationId, data) => {
812
+ return this.http.put(`/api/v1/organizations/${encodeURIComponent(organizationId)}/owner`, data);
813
+ };
814
+ /**
815
+ * Deletes an organization
816
+ *
817
+ * Permanently removes the organization and all its data.
818
+ * Can only be called by the organization owner or SaaS tools (with HMAC auth).
819
+ *
820
+ * @param {string} organizationId - Organization identifier
821
+ * @returns {Promise<{ success: true }>} Success response
822
+ * @throws {NotFoundError} When organization is not found
823
+ * @throws {ForbiddenError} When caller is not the organization owner
824
+ * @throws {ApiError} On other API errors
825
+ *
826
+ * @example
827
+ * ```typescript
828
+ * await client.organizations.delete('org_abc123');
829
+ * ```
830
+ */
831
+ delete = async (organizationId) => {
832
+ return this.http.delete(`/api/v1/organizations/${encodeURIComponent(organizationId)}`);
833
+ };
725
834
  // ===== B2B User Management Methods =====
726
835
  /**
727
836
  * Creates a new user in an organization's LDAP branch
package/dist/index.mjs CHANGED
@@ -280,6 +280,7 @@ var HttpClient = class {
280
280
  });
281
281
  const headers = {
282
282
  "Content-Type": "application/json",
283
+ Accept: "application/json",
283
284
  ...options.headers
284
285
  };
285
286
  if (authHeader) {
@@ -293,7 +294,8 @@ var HttpClient = class {
293
294
  headers,
294
295
  body: bodyString,
295
296
  signal: controller.signal,
296
- credentials: authHeader ? void 0 : "include"
297
+ credentials: authHeader ? void 0 : "include",
298
+ redirect: "follow"
297
299
  });
298
300
  clearTimeout(timeoutId);
299
301
  this.logger.info("Request completed", {
@@ -401,6 +403,18 @@ var HttpClient = class {
401
403
  post = (path, body, headers) => {
402
404
  return this.request({ method: "POST", path, body, headers });
403
405
  };
406
+ /**
407
+ * Performs a PUT request
408
+ *
409
+ * @template T - Response type
410
+ * @param {string} path - Request path
411
+ * @param {unknown} [body] - Request body
412
+ * @param {Record<string, string>} [headers] - Additional headers
413
+ * @returns {Promise<T>} Parsed response body
414
+ */
415
+ put = (path, body, headers) => {
416
+ return this.request({ method: "PUT", path, body, headers });
417
+ };
404
418
  /**
405
419
  * Performs a PATCH request
406
420
  *
@@ -583,7 +597,7 @@ var OrganizationsResource = class extends BaseResource {
583
597
  /**
584
598
  * Checks if an organization identifier is available
585
599
  *
586
- * @param {CheckAvailabilityParams} params - Field and value to check
600
+ * @param {CheckOrganizationAvailabilityParams} params - Field and value to check
587
601
  * @returns {Promise<CheckAvailabilityResponse>} Availability status
588
602
  * @throws {ApiError} On API errors
589
603
  *
@@ -684,6 +698,101 @@ var OrganizationsResource = class extends BaseResource {
684
698
  update = async (organizationId, data) => {
685
699
  return this.http.patch(`/api/v1/organizations/${encodeURIComponent(organizationId)}`, data);
686
700
  };
701
+ /**
702
+ * Gets the current owner of an organization
703
+ *
704
+ * Returns the owner information including username, email, and display name.
705
+ * Returns null if no owner is set.
706
+ *
707
+ * @param {string} organizationId - Organization identifier
708
+ * @returns {Promise<GetOwnerResponse>} Owner information or null
709
+ * @throws {NotFoundError} When organization is not found
710
+ * @throws {ApiError} On other API errors
711
+ *
712
+ * @example
713
+ * ```typescript
714
+ * const response = await client.organizations.getOwner('org_abc123');
715
+ * if (response.owner) {
716
+ * console.log(`Owner: ${response.owner.username}`);
717
+ * }
718
+ * ```
719
+ */
720
+ getOwner = async (organizationId) => {
721
+ return this.http.get(`/api/v1/organizations/${encodeURIComponent(organizationId)}/owner`);
722
+ };
723
+ /**
724
+ * Sets the initial owner of an organization
725
+ *
726
+ * Can only be used when the organization has no owner. To transfer ownership
727
+ * from an existing owner, use transferOwnership instead.
728
+ * Typically used by SaaS tools during organization setup.
729
+ *
730
+ * @param {string} organizationId - Organization identifier
731
+ * @param {SetOwnerRequest} data - Owner details (username and email)
732
+ * @returns {Promise<{ success: true }>} Success response
733
+ * @throws {NotFoundError} When organization or user is not found
734
+ * @throws {ConflictError} When organization already has an owner
735
+ * @throws {ApiError} On other API errors
736
+ *
737
+ * @example
738
+ * ```typescript
739
+ * await client.organizations.setOwner('org_abc123', {
740
+ * username: 'john.doe',
741
+ * mail: 'john.doe@acme.example.com'
742
+ * });
743
+ * ```
744
+ */
745
+ setOwner = async (organizationId, data) => {
746
+ return this.http.post(
747
+ `/api/v1/organizations/${encodeURIComponent(organizationId)}/owner`,
748
+ data
749
+ );
750
+ };
751
+ /**
752
+ * Transfers organization ownership to another user
753
+ *
754
+ * Must be called by the current owner or by SaaS tools (with HMAC auth).
755
+ * The current owner will be demoted to admin role.
756
+ * The new owner must be an existing user.
757
+ *
758
+ * @param {string} organizationId - Organization identifier
759
+ * @param {TransferOwnershipRequest} data - New owner username
760
+ * @returns {Promise<{ success: true }>} Success response
761
+ * @throws {NotFoundError} When organization or new owner user is not found
762
+ * @throws {ForbiddenError} When caller is not the current owner or SaaS tool
763
+ * @throws {ConflictError} When ownership changed by another request (race condition)
764
+ * @throws {ApiError} On other API errors
765
+ *
766
+ * @example
767
+ * ```typescript
768
+ * await client.organizations.transferOwnership('org_abc123', {
769
+ * newOwnerUsername: 'jane.doe'
770
+ * });
771
+ * ```
772
+ */
773
+ transferOwnership = async (organizationId, data) => {
774
+ return this.http.put(`/api/v1/organizations/${encodeURIComponent(organizationId)}/owner`, data);
775
+ };
776
+ /**
777
+ * Deletes an organization
778
+ *
779
+ * Permanently removes the organization and all its data.
780
+ * Can only be called by the organization owner or SaaS tools (with HMAC auth).
781
+ *
782
+ * @param {string} organizationId - Organization identifier
783
+ * @returns {Promise<{ success: true }>} Success response
784
+ * @throws {NotFoundError} When organization is not found
785
+ * @throws {ForbiddenError} When caller is not the organization owner
786
+ * @throws {ApiError} On other API errors
787
+ *
788
+ * @example
789
+ * ```typescript
790
+ * await client.organizations.delete('org_abc123');
791
+ * ```
792
+ */
793
+ delete = async (organizationId) => {
794
+ return this.http.delete(`/api/v1/organizations/${encodeURIComponent(organizationId)}`);
795
+ };
687
796
  // ===== B2B User Management Methods =====
688
797
  /**
689
798
  * Creates a new user in an organization's LDAP branch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linagora/ldap-rest-client",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "TypeScript API client for LDAP-REST",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -44,8 +44,7 @@
44
44
  "license": "MIT",
45
45
  "repository": {
46
46
  "type": "git",
47
- "url": "https://github.com/linagora/twake-workplace-private.git",
48
- "directory": "ldap-rest-client"
47
+ "url": "https://github.com/linagora/ldap-rest-client.git"
49
48
  },
50
49
  "devDependencies": {
51
50
  "@types/jest": "^29.5.11",