@intellegens/cornerstone-client 0.0.9999-alpha-9 → 0.0.9999-alpha-10
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/demo/index.ts +29 -0
- package/demo/public_html/favicon.ico +0 -0
- package/demo/public_html/index.html +106 -0
- package/demo/public_html/websettings.json +3 -0
- package/jest.config.js +29 -0
- package/package.json +1 -1
- package/src/adapters/CollectionViewAdapter/index.ts +390 -0
- package/src/adapters/index.ts +1 -0
- package/src/data/api/dto/PropertyPathDto.ts +4 -0
- package/src/data/api/dto/ReadOptionsDto.ts +8 -0
- package/src/data/api/dto/ReadResultDto.ts +13 -0
- package/src/data/api/dto/ReadResultMetadataDto.ts +8 -0
- package/src/data/api/dto/crud/CrudMetadataDto.ts +4 -0
- package/src/data/api/dto/crud/index.ts +1 -0
- package/src/data/api/dto/index.ts +4 -0
- package/src/data/api/dto/read/ReadMetadataDto.ts +8 -0
- package/src/data/api/dto/read/ReadSelectedDefinitionDto.ts +21 -0
- package/src/data/api/dto/read/ReadSelectedNestedCollectionCriteriaDto.ts +25 -0
- package/src/data/api/dto/read/ReadSelectedNestedCriteriaDto.ts +20 -0
- package/src/data/api/dto/read/ReadSelectedOrderingDefinitionDto.ts +8 -0
- package/src/data/api/dto/read/ReadSelectedOrderingPropertyDefinitionDto.ts +16 -0
- package/src/data/api/dto/read/ReadSelectedPaginationDefinitionDto.ts +13 -0
- package/src/data/api/dto/read/ReadSelectedSearchDefinitionDto.ts +43 -0
- package/src/data/api/dto/read/ReadSelectedSearchPropertyDefinitionDto.ts +186 -0
- package/src/data/api/dto/read/index.ts +9 -0
- package/src/data/api/dto/response/ApiErrorDto.ts +21 -0
- package/src/data/api/dto/response/ApiErrorResponseDto.ts +13 -0
- package/src/data/api/dto/response/ApiResponseDto.ts +7 -0
- package/src/data/api/dto/response/ApiSuccessResponseDto.ts +13 -0
- package/src/data/api/dto/response/MetadataDto.ts +24 -0
- package/src/data/api/dto/response/index.ts +5 -0
- package/src/data/api/enum/index.ts +2 -0
- package/src/data/api/enum/read/ReadSelectedCollectionOperator.ts +17 -0
- package/src/data/api/enum/read/ReadSelectedComparisonOperator.ts +96 -0
- package/src/data/api/enum/read/ReadSelectedLogicalOperator.ts +16 -0
- package/src/data/api/enum/read/ReadSelectedOrderingDirection.ts +13 -0
- package/src/data/api/enum/read/ReadSelectedPropertyType.ts +86 -0
- package/src/data/api/enum/read/index.ts +5 -0
- package/src/data/api/enum/response/ErrorCode.ts +13 -0
- package/src/data/api/enum/response/index.ts +1 -0
- package/src/data/api/index.ts +3 -0
- package/src/data/api/interface/IConcurrencySafe.ts +9 -0
- package/src/data/api/interface/IIdentifiable.ts +12 -0
- package/src/data/api/interface/IIdentifiableSecondary.ts +9 -0
- package/src/data/api/interface/index.ts +3 -0
- package/src/data/auth/dto/ClaimDto.ts +4 -0
- package/src/data/auth/dto/RegisterRequestDto.ts +4 -0
- package/src/data/auth/dto/RoleDto.ts +6 -0
- package/src/data/auth/dto/SignInRequestDto.ts +4 -0
- package/src/data/auth/dto/TokensDto.ts +4 -0
- package/src/data/auth/dto/UserDto.ts +18 -0
- package/src/data/auth/dto/UserInfoDto.ts +15 -0
- package/src/data/auth/dto/index.ts +4 -0
- package/src/data/auth/index.ts +2 -0
- package/src/data/auth/policy.ts +63 -0
- package/src/data/index.ts +2 -0
- package/src/index.ts +4 -0
- package/src/services/api/ApiCrudControllerClient/index.ts +129 -0
- package/src/services/api/ApiInitializationService/index.ts +254 -0
- package/src/services/api/ApiReadControllerClient/index.ts +137 -0
- package/src/services/api/HttpService/FetchHttpService.ts +34 -0
- package/src/services/api/HttpService/HttpRequestConfig.ts +10 -0
- package/src/services/api/HttpService/HttpResponse.ts +14 -0
- package/src/services/api/HttpService/IHttpService.ts +17 -0
- package/src/services/api/HttpService/README.md +106 -0
- package/src/services/api/HttpService/index.ts +12 -0
- package/src/services/api/UserManagementControllerClient/index.ts +160 -0
- package/src/services/api/index.ts +5 -0
- package/src/services/auth/client/AuthService/index.ts +187 -0
- package/src/services/auth/client/AuthorizationManagementControllerClient/index.ts +165 -0
- package/src/services/auth/client/index.ts +2 -0
- package/src/services/auth/index.ts +1 -0
- package/src/services/index.ts +2 -0
- package/src/utils/authorization/index.ts +47 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/result/index.ts +25 -0
- package/src/utils/search/index.ts +150 -0
- package/tests/ApiClients.test.ts +284 -0
- package/tests/CollectionViewAdapter.test.ts +392 -0
- package/tests/HttpService.test.ts +303 -0
- package/tests/setup.ts +76 -0
- package/tsconfig.json +19 -0
- package/LICENSE.md +0 -7
- /package/{adapters → dist/adapters}/CollectionViewAdapter/index.d.ts +0 -0
- /package/{adapters → dist/adapters}/CollectionViewAdapter/index.js +0 -0
- /package/{adapters → dist/adapters}/index.d.ts +0 -0
- /package/{adapters → dist/adapters}/index.js +0 -0
- /package/{data → dist/data}/api/dto/PropertyPathDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/PropertyPathDto.js +0 -0
- /package/{data → dist/data}/api/dto/ReadOptionsDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/ReadOptionsDto.js +0 -0
- /package/{data → dist/data}/api/dto/ReadResultDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/ReadResultDto.js +0 -0
- /package/{data → dist/data}/api/dto/ReadResultMetadataDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/ReadResultMetadataDto.js +0 -0
- /package/{data → dist/data}/api/dto/crud/CrudMetadataDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/crud/CrudMetadataDto.js +0 -0
- /package/{data → dist/data}/api/dto/crud/index.d.ts +0 -0
- /package/{data → dist/data}/api/dto/crud/index.js +0 -0
- /package/{data → dist/data}/api/dto/index.d.ts +0 -0
- /package/{data → dist/data}/api/dto/index.js +0 -0
- /package/{data → dist/data}/api/dto/read/ReadMetadataDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/read/ReadMetadataDto.js +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedDefinitionDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedDefinitionDto.js +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedNestedCollectionCriteriaDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedNestedCollectionCriteriaDto.js +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedNestedCriteriaDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedNestedCriteriaDto.js +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedOrderingDefinitionDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedOrderingDefinitionDto.js +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedOrderingPropertyDefinitionDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedOrderingPropertyDefinitionDto.js +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedPaginationDefinitionDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedPaginationDefinitionDto.js +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedSearchDefinitionDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedSearchDefinitionDto.js +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedSearchPropertyDefinitionDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/read/ReadSelectedSearchPropertyDefinitionDto.js +0 -0
- /package/{data → dist/data}/api/dto/read/index.d.ts +0 -0
- /package/{data → dist/data}/api/dto/read/index.js +0 -0
- /package/{data → dist/data}/api/dto/response/ApiErrorDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/response/ApiErrorDto.js +0 -0
- /package/{data → dist/data}/api/dto/response/ApiErrorResponseDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/response/ApiErrorResponseDto.js +0 -0
- /package/{data → dist/data}/api/dto/response/ApiResponseDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/response/ApiResponseDto.js +0 -0
- /package/{data → dist/data}/api/dto/response/ApiSuccessResponseDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/response/ApiSuccessResponseDto.js +0 -0
- /package/{data → dist/data}/api/dto/response/EmptyMetadataDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/response/EmptyMetadataDto.js +0 -0
- /package/{data → dist/data}/api/dto/response/MetadataDto.d.ts +0 -0
- /package/{data → dist/data}/api/dto/response/MetadataDto.js +0 -0
- /package/{data → dist/data}/api/dto/response/index.d.ts +0 -0
- /package/{data → dist/data}/api/dto/response/index.js +0 -0
- /package/{data → dist/data}/api/enum/index.d.ts +0 -0
- /package/{data → dist/data}/api/enum/index.js +0 -0
- /package/{data → dist/data}/api/enum/read/ReadSelectedCollectionOperator.d.ts +0 -0
- /package/{data → dist/data}/api/enum/read/ReadSelectedCollectionOperator.js +0 -0
- /package/{data → dist/data}/api/enum/read/ReadSelectedComparisonOperator.d.ts +0 -0
- /package/{data → dist/data}/api/enum/read/ReadSelectedComparisonOperator.js +0 -0
- /package/{data → dist/data}/api/enum/read/ReadSelectedLogicalOperator.d.ts +0 -0
- /package/{data → dist/data}/api/enum/read/ReadSelectedLogicalOperator.js +0 -0
- /package/{data → dist/data}/api/enum/read/ReadSelectedOrderingDirection.d.ts +0 -0
- /package/{data → dist/data}/api/enum/read/ReadSelectedOrderingDirection.js +0 -0
- /package/{data → dist/data}/api/enum/read/ReadSelectedPropertyType.d.ts +0 -0
- /package/{data → dist/data}/api/enum/read/ReadSelectedPropertyType.js +0 -0
- /package/{data → dist/data}/api/enum/read/index.d.ts +0 -0
- /package/{data → dist/data}/api/enum/read/index.js +0 -0
- /package/{data → dist/data}/api/enum/response/ApiErrorCodes.d.ts +0 -0
- /package/{data → dist/data}/api/enum/response/ApiErrorCodes.js +0 -0
- /package/{data → dist/data}/api/enum/response/ErrorCode.d.ts +0 -0
- /package/{data → dist/data}/api/enum/response/ErrorCode.js +0 -0
- /package/{data → dist/data}/api/enum/response/index.d.ts +0 -0
- /package/{data → dist/data}/api/enum/response/index.js +0 -0
- /package/{data → dist/data}/api/index.d.ts +0 -0
- /package/{data → dist/data}/api/index.js +0 -0
- /package/{data → dist/data}/api/interface/IConcurrencySafe.d.ts +0 -0
- /package/{data → dist/data}/api/interface/IConcurrencySafe.js +0 -0
- /package/{data → dist/data}/api/interface/IIdentifiable.d.ts +0 -0
- /package/{data → dist/data}/api/interface/IIdentifiable.js +0 -0
- /package/{data → dist/data}/api/interface/IIdentifiableSecondary.d.ts +0 -0
- /package/{data → dist/data}/api/interface/IIdentifiableSecondary.js +0 -0
- /package/{data → dist/data}/api/interface/index.d.ts +0 -0
- /package/{data → dist/data}/api/interface/index.js +0 -0
- /package/{data → dist/data}/auth/dto/ClaimDto.d.ts +0 -0
- /package/{data → dist/data}/auth/dto/ClaimDto.js +0 -0
- /package/{data → dist/data}/auth/dto/RegisterRequestDto.d.ts +0 -0
- /package/{data → dist/data}/auth/dto/RegisterRequestDto.js +0 -0
- /package/{data → dist/data}/auth/dto/RoleDto.d.ts +0 -0
- /package/{data → dist/data}/auth/dto/RoleDto.js +0 -0
- /package/{data → dist/data}/auth/dto/SignInRequestDto.d.ts +0 -0
- /package/{data → dist/data}/auth/dto/SignInRequestDto.js +0 -0
- /package/{data → dist/data}/auth/dto/TokensDto.d.ts +0 -0
- /package/{data → dist/data}/auth/dto/TokensDto.js +0 -0
- /package/{data → dist/data}/auth/dto/UserDto.d.ts +0 -0
- /package/{data → dist/data}/auth/dto/UserDto.js +0 -0
- /package/{data → dist/data}/auth/dto/UserInfoDto.d.ts +0 -0
- /package/{data → dist/data}/auth/dto/UserInfoDto.js +0 -0
- /package/{data → dist/data}/auth/dto/index.d.ts +0 -0
- /package/{data → dist/data}/auth/dto/index.js +0 -0
- /package/{data → dist/data}/auth/index.d.ts +0 -0
- /package/{data → dist/data}/auth/index.js +0 -0
- /package/{data → dist/data}/auth/policy.d.ts +0 -0
- /package/{data → dist/data}/auth/policy.js +0 -0
- /package/{data → dist/data}/index.d.ts +0 -0
- /package/{data → dist/data}/index.js +0 -0
- /package/{index.d.ts → dist/index.d.ts} +0 -0
- /package/{index.js → dist/index.js} +0 -0
- /package/{services → dist/services}/api/ApiCrudControllerClient/index.d.ts +0 -0
- /package/{services → dist/services}/api/ApiCrudControllerClient/index.js +0 -0
- /package/{services → dist/services}/api/ApiInitializationService/index.d.ts +0 -0
- /package/{services → dist/services}/api/ApiInitializationService/index.js +0 -0
- /package/{services → dist/services}/api/ApiReadControllerClient/index.d.ts +0 -0
- /package/{services → dist/services}/api/ApiReadControllerClient/index.js +0 -0
- /package/{services → dist/services}/api/HttpService/FetchHttpService.d.ts +0 -0
- /package/{services → dist/services}/api/HttpService/FetchHttpService.js +0 -0
- /package/{services → dist/services}/api/HttpService/HttpRequestConfig.d.ts +0 -0
- /package/{services → dist/services}/api/HttpService/HttpRequestConfig.js +0 -0
- /package/{services → dist/services}/api/HttpService/HttpResponse.d.ts +0 -0
- /package/{services → dist/services}/api/HttpService/HttpResponse.js +0 -0
- /package/{services → dist/services}/api/HttpService/IHttpService.d.ts +0 -0
- /package/{services → dist/services}/api/HttpService/IHttpService.js +0 -0
- /package/{services → dist/services}/api/HttpService/index.d.ts +0 -0
- /package/{services → dist/services}/api/HttpService/index.js +0 -0
- /package/{services → dist/services}/api/UserManagementControllerClient/index.d.ts +0 -0
- /package/{services → dist/services}/api/UserManagementControllerClient/index.js +0 -0
- /package/{services → dist/services}/api/index.d.ts +0 -0
- /package/{services → dist/services}/api/index.js +0 -0
- /package/{services → dist/services}/auth/client/AuthService/index.d.ts +0 -0
- /package/{services → dist/services}/auth/client/AuthService/index.js +0 -0
- /package/{services → dist/services}/auth/client/AuthorizationManagementControllerClient/index.d.ts +0 -0
- /package/{services → dist/services}/auth/client/AuthorizationManagementControllerClient/index.js +0 -0
- /package/{services → dist/services}/auth/client/index.d.ts +0 -0
- /package/{services → dist/services}/auth/client/index.js +0 -0
- /package/{services → dist/services}/auth/index.d.ts +0 -0
- /package/{services → dist/services}/auth/index.js +0 -0
- /package/{services → dist/services}/index.d.ts +0 -0
- /package/{services → dist/services}/index.js +0 -0
- /package/{utils → dist/utils}/authorization/index.d.ts +0 -0
- /package/{utils → dist/utils}/authorization/index.js +0 -0
- /package/{utils → dist/utils}/index.d.ts +0 -0
- /package/{utils → dist/utils}/index.js +0 -0
- /package/{utils → dist/utils}/result/index.d.ts +0 -0
- /package/{utils → dist/utils}/result/index.js +0 -0
- /package/{utils → dist/utils}/search/index.d.ts +0 -0
- /package/{utils → dist/utils}/search/index.js +0 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IConcurrencySafe } from './IConcurrencySafe';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Interface for entities that have a Id property.
|
|
5
|
+
* Will be used as a primary key in the database.
|
|
6
|
+
*/
|
|
7
|
+
export interface IIdentifiable<TKey> extends IConcurrencySafe {
|
|
8
|
+
/**
|
|
9
|
+
* Gets or sets the Id of the entity.
|
|
10
|
+
*/
|
|
11
|
+
id: TKey;
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ClaimDto } from '@data';
|
|
2
|
+
import { IIdentifiable } from '@data';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents a user with an identifier and email address.
|
|
6
|
+
*
|
|
7
|
+
* @template TKey The type of the user identifier.
|
|
8
|
+
*
|
|
9
|
+
* @param {TKey} id The unique identifier for the user.
|
|
10
|
+
* @param {string} email The email address associated with the user.
|
|
11
|
+
* @param {string[]} roles The roles associated with the user.
|
|
12
|
+
* @param {ClaimDto[]} claims The claims associated with the user.
|
|
13
|
+
*/
|
|
14
|
+
export type UserDto<TKey> = IIdentifiable<TKey> & {
|
|
15
|
+
email: string;
|
|
16
|
+
roles: string[];
|
|
17
|
+
claims: ClaimDto[];
|
|
18
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { UserDto } from '@data';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents user information along with access token expiry.
|
|
5
|
+
*
|
|
6
|
+
* @template TKey The type of the user identifier.
|
|
7
|
+
* @template TUser The type of the user object, defaulting to `UserDto<TKey>`.
|
|
8
|
+
*
|
|
9
|
+
* @param {TUser} user The user object containing user details.
|
|
10
|
+
* @param {Date} accessTokenExpiry The date and time when the access token will expire.
|
|
11
|
+
*/
|
|
12
|
+
export type UserInfoDto<TKey, TUser = UserDto<TKey>> = {
|
|
13
|
+
user: TUser;
|
|
14
|
+
accessTokenExpiry: Date;
|
|
15
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for policies that can be checked.
|
|
3
|
+
*
|
|
4
|
+
* @interface IPolicy<TParams extends unknown[]>
|
|
5
|
+
* @template TParams - The type of the parameters that will be passed to the policy check function.
|
|
6
|
+
*/
|
|
7
|
+
export interface IPolicy<TParams extends unknown[]> {
|
|
8
|
+
/**
|
|
9
|
+
* Checks if the policy is valid for the given parameters.
|
|
10
|
+
*
|
|
11
|
+
* @param params - Parameters to pass to the policy check function.
|
|
12
|
+
* @return A promise that resolves if the policy is valid, rejects otherwise.
|
|
13
|
+
*/
|
|
14
|
+
check(...params: TParams): Promise<boolean>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Base class for policies. It implements the IPolicy interface.
|
|
19
|
+
*
|
|
20
|
+
* @class PolicyBase
|
|
21
|
+
* @template TParams - The type of the parameters that will be passed to the policy check function.
|
|
22
|
+
*/
|
|
23
|
+
export class PolicyBase<TParams extends unknown[]> implements IPolicy<TParams> {
|
|
24
|
+
/**
|
|
25
|
+
* Checks if the policy is valid for the given parameters.
|
|
26
|
+
*
|
|
27
|
+
* @return A promise that resolves if the policy is valid, rejects otherwise.
|
|
28
|
+
* @throws {Error} Error if not implemented.
|
|
29
|
+
*/
|
|
30
|
+
public async check(): Promise<boolean> {
|
|
31
|
+
throw new Error('Not implemented');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Class for policies that can be checked.
|
|
37
|
+
*
|
|
38
|
+
* @class Policy
|
|
39
|
+
* @template TParams - The type of the parameters that will be passed to the policy check function.
|
|
40
|
+
*/
|
|
41
|
+
export class Policy<TParams extends unknown[]> extends PolicyBase<TParams> {
|
|
42
|
+
private readonly _verificationFn: (...params: TParams) => Promise<boolean>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Creates a new policy.
|
|
46
|
+
*
|
|
47
|
+
* @param verificationFn - The function that will be used to verify the policy.
|
|
48
|
+
*/
|
|
49
|
+
constructor(verificationFn: (...params: TParams) => Promise<boolean>) {
|
|
50
|
+
super();
|
|
51
|
+
this._verificationFn = verificationFn;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Checks if the policy is valid for the given parameters.
|
|
56
|
+
*
|
|
57
|
+
* @param params - Parameters to pass to the policy check function.
|
|
58
|
+
* @return A promise that resolves if the policy is valid, rejects otherwise.
|
|
59
|
+
*/
|
|
60
|
+
public async check(...params: TParams): Promise<boolean> {
|
|
61
|
+
return this._verificationFn(...params);
|
|
62
|
+
}
|
|
63
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { apiInitializationService } from '../ApiInitializationService';
|
|
2
|
+
import { ApiErrorResponseDto, ApiResponseDto, ApiSuccessResponseDto, EmptyMetadataDto } from '../../../data/api/dto';
|
|
3
|
+
import { IIdentifiable } from '../../../data/api/interface';
|
|
4
|
+
import { IHttpService } from '../HttpService';
|
|
5
|
+
import { ApiReadControllerClient } from '../ApiReadControllerClient';
|
|
6
|
+
import { ErrorCode } from '@data';
|
|
7
|
+
import { fail, ok } from '@utils/result';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generic API client for consuming any Cornerstone CrudController
|
|
11
|
+
*
|
|
12
|
+
* @export
|
|
13
|
+
* @class ApiCrudControllerClient
|
|
14
|
+
* @template TKey - Type of the entity key (e.g., number, string, GUID, etc.)
|
|
15
|
+
* @template TDto - Data Transfer Object representing the entity
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export class ApiCrudControllerClient<TKey, TDto extends IIdentifiable<TKey>> extends ApiReadControllerClient<TKey, TDto> {
|
|
19
|
+
/**
|
|
20
|
+
* Constructor
|
|
21
|
+
* @param baseControllerPath Base path to API controller
|
|
22
|
+
* @param httpService HTTP service implementation to use for requests
|
|
23
|
+
*/
|
|
24
|
+
constructor(baseControllerPath: string, httpService?: IHttpService) {
|
|
25
|
+
super(baseControllerPath, httpService);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a new entity.
|
|
30
|
+
* @param dto - Insert request DTO
|
|
31
|
+
* @param {AbortSignal} [signal] - Optional cancellation signal
|
|
32
|
+
* @returns The created entity DTO
|
|
33
|
+
*/
|
|
34
|
+
public async create(dto: TDto, signal?: AbortSignal): Promise<ApiResponseDto<TDto, EmptyMetadataDto>> {
|
|
35
|
+
try {
|
|
36
|
+
const url = await apiInitializationService.getApiUrl(this.baseControllerPath, `/Create`);
|
|
37
|
+
const res = await this.httpService.request(url, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { 'Content-Type': 'application/json' },
|
|
40
|
+
body: JSON.stringify(dto),
|
|
41
|
+
credentials: 'include',
|
|
42
|
+
signal,
|
|
43
|
+
});
|
|
44
|
+
if (!res.ok) {
|
|
45
|
+
return fail<ApiSuccessResponseDto<TDto, EmptyMetadataDto>, ApiErrorResponseDto>(await res.json());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return ok<ApiSuccessResponseDto<TDto, EmptyMetadataDto>, ApiErrorResponseDto>(await res.json());
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.error(err);
|
|
51
|
+
|
|
52
|
+
return fail<ApiSuccessResponseDto<TDto, EmptyMetadataDto>, ApiErrorResponseDto>({
|
|
53
|
+
error: {
|
|
54
|
+
code: ErrorCode.UnknownError,
|
|
55
|
+
message: 'Unknown error occurred while creating the record.',
|
|
56
|
+
metadata: {} as EmptyMetadataDto,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Updates an existing entity.
|
|
64
|
+
* @param id - The ID of the entity to update
|
|
65
|
+
* @param dto - Update request DTO
|
|
66
|
+
* @param {AbortSignal} [signal] - Optional cancellation signal
|
|
67
|
+
* @returns The updated entity DTO
|
|
68
|
+
*/
|
|
69
|
+
public async update(id: TKey, dto: TDto, signal?: AbortSignal): Promise<ApiResponseDto<TDto, EmptyMetadataDto>> {
|
|
70
|
+
try {
|
|
71
|
+
const url = await apiInitializationService.getApiUrl(this.baseControllerPath, `/Update?id=${encodeURIComponent(String(id))}`);
|
|
72
|
+
const res = await this.httpService.request(url, {
|
|
73
|
+
method: 'PUT',
|
|
74
|
+
headers: { 'Content-Type': 'application/json' },
|
|
75
|
+
body: JSON.stringify(dto),
|
|
76
|
+
credentials: 'include',
|
|
77
|
+
signal,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (!res.ok) {
|
|
81
|
+
return fail<ApiSuccessResponseDto<TDto, EmptyMetadataDto>, ApiErrorResponseDto>(await res.json());
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return ok<ApiSuccessResponseDto<TDto, EmptyMetadataDto>, ApiErrorResponseDto>(await res.json());
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.error(err);
|
|
87
|
+
|
|
88
|
+
return fail<ApiSuccessResponseDto<TDto, EmptyMetadataDto>, ApiErrorResponseDto>({
|
|
89
|
+
error: {
|
|
90
|
+
code: ErrorCode.UnknownError,
|
|
91
|
+
message: `Unknown error occurred while updating the record with id ${id}`,
|
|
92
|
+
metadata: {} as EmptyMetadataDto,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Deletes an entity by ID.
|
|
100
|
+
* @param id - The ID of the entity to delete
|
|
101
|
+
* @param {AbortSignal} [signal] - Optional cancellation signal
|
|
102
|
+
*/
|
|
103
|
+
public async delete(id: TKey, signal?: AbortSignal): Promise<ApiResponseDto<undefined, EmptyMetadataDto>> {
|
|
104
|
+
try {
|
|
105
|
+
const url = await apiInitializationService.getApiUrl(this.baseControllerPath, `/Delete?id=${encodeURIComponent(String(id))}`);
|
|
106
|
+
const res = await this.httpService.request(url, {
|
|
107
|
+
method: 'DELETE',
|
|
108
|
+
credentials: 'include',
|
|
109
|
+
signal,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
if (!res.ok) {
|
|
113
|
+
return fail<ApiSuccessResponseDto<undefined, EmptyMetadataDto>, ApiErrorResponseDto>(await res.json());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return ok<ApiSuccessResponseDto<undefined, EmptyMetadataDto>, ApiErrorResponseDto>(await res.json());
|
|
117
|
+
} catch (err) {
|
|
118
|
+
console.error(err);
|
|
119
|
+
|
|
120
|
+
return fail<ApiSuccessResponseDto<undefined, EmptyMetadataDto>, ApiErrorResponseDto>({
|
|
121
|
+
error: {
|
|
122
|
+
code: ErrorCode.UnknownError,
|
|
123
|
+
message: `Unknown error occurred while deleting the record with id ${id}`,
|
|
124
|
+
metadata: {} as EmptyMetadataDto,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// websettings.json configuration file contents type
|
|
2
|
+
import { fail, ok } from '@utils';
|
|
3
|
+
|
|
4
|
+
type WebSettings = {
|
|
5
|
+
api: string | undefined;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generic shared settings interface - can represent any user-configured settings structure
|
|
10
|
+
* The actual properties depend on what users configure in their appsettings.json or environment variables
|
|
11
|
+
*/
|
|
12
|
+
type ISharedSettings = {
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Initialization info DTO that matches the server-side structure
|
|
18
|
+
*/
|
|
19
|
+
type IInitializationInfoDto<TSharedSettings = ISharedSettings> = {
|
|
20
|
+
settings: TSharedSettings;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
import { ApiErrorResponseDto, ApiSuccessResponseDto, EmptyMetadataDto } from '@/data';
|
|
24
|
+
import { defaultHttpService, IHttpService } from '../HttpService';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Central API configuration service, fetches and exposes Cornerstone API configuration
|
|
28
|
+
*
|
|
29
|
+
* @export
|
|
30
|
+
* @class ApiInitializationService
|
|
31
|
+
*/
|
|
32
|
+
export class ApiInitializationService {
|
|
33
|
+
/**
|
|
34
|
+
* If API base URL detection was completed
|
|
35
|
+
* IMPORTANT: This property is not meant to be used in normal cases - when ever possible use the .getApiUrl(relativeEndpointPath: string) method instead.
|
|
36
|
+
*/
|
|
37
|
+
public _apiBaseUrlDetected = false;
|
|
38
|
+
|
|
39
|
+
// #region HTTP service
|
|
40
|
+
/**
|
|
41
|
+
* If API base URL detection was completed, this property will hold the method by which detection was performed
|
|
42
|
+
* IMPORTANT: This property is not meant to be used in normal cases - when ever possible use the .getApiUrl(relativeEndpointPath: string) method instead.
|
|
43
|
+
*/
|
|
44
|
+
public _apiBaseUrlDetectionMethod: string | undefined = undefined;
|
|
45
|
+
/**
|
|
46
|
+
* If API base URL detection was completed, this property will hold the detected API base URL
|
|
47
|
+
* IMPORTANT: This property is not meant to be used in normal cases - when ever possible use the .getApiUrl(relativeEndpointPath: string) method instead.
|
|
48
|
+
*/
|
|
49
|
+
public _apiBaseUrl: string | undefined = undefined;
|
|
50
|
+
|
|
51
|
+
// #endregion
|
|
52
|
+
|
|
53
|
+
// #region API Base URL detection
|
|
54
|
+
/**
|
|
55
|
+
* If API base URL detection has failed, this property will hold the error with which it has failed
|
|
56
|
+
* IMPORTANT: This property is not meant to be used in normal cases - when ever possible use the .getApiUrl(relativeEndpointPath: string) method instead.
|
|
57
|
+
*/
|
|
58
|
+
public _apiBaseError: Error | undefined = undefined;
|
|
59
|
+
// #region config App
|
|
60
|
+
public appConfig?: ISharedSettings | undefined;
|
|
61
|
+
private _httpService: IHttpService = defaultHttpService;
|
|
62
|
+
private _apiBaseUrlPromise: Promise<string | undefined> | undefined = undefined;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Initializes the API configuration
|
|
66
|
+
*
|
|
67
|
+
* This method calls all methods that need to be called during the API configuration phase:
|
|
68
|
+
* - Starts detection of API base URL.
|
|
69
|
+
* - Fetches shared settings from the server.
|
|
70
|
+
*
|
|
71
|
+
* @async
|
|
72
|
+
* @param httpService - HTTP service implementation to use for requests
|
|
73
|
+
* @param {AbortSignal} [signal] - Optional cancellation signal
|
|
74
|
+
* @return {Promise<void>} Resolves when initialization is complete.
|
|
75
|
+
*/
|
|
76
|
+
public async initialize({
|
|
77
|
+
httpService,
|
|
78
|
+
signal,
|
|
79
|
+
}: {
|
|
80
|
+
httpService?: IHttpService;
|
|
81
|
+
signal?: AbortSignal;
|
|
82
|
+
} = {}): Promise<void> {
|
|
83
|
+
// Store configuration
|
|
84
|
+
if (httpService !== undefined) this._httpService = httpService;
|
|
85
|
+
// (Pre)detect API base URL
|
|
86
|
+
await this._getApiBaseUrl(signal);
|
|
87
|
+
// Initialize app config
|
|
88
|
+
await this._getAppConfig();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Gets configured HTTP service
|
|
93
|
+
* @returns
|
|
94
|
+
*/
|
|
95
|
+
public _getHttpService(): IHttpService {
|
|
96
|
+
return this._httpService;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Tries detecting API base URL by multiple methods
|
|
101
|
+
*
|
|
102
|
+
* - Checks the response headers of the current URL for the `CORNERSTONE-API-BASEURL` header.
|
|
103
|
+
* - Attempts to load the `websettings.json` file and looks for an `api` field.
|
|
104
|
+
* - Defaults to `undefined`.
|
|
105
|
+
*
|
|
106
|
+
* IMPORTANT: This method is not meant to be used in normal cases - when ever possible use the .getApiUrl(relativeEndpointPath: string) method instead.
|
|
107
|
+
*
|
|
108
|
+
* @async
|
|
109
|
+
* @param {AbortSignal} [signal] - Optional cancellation signal
|
|
110
|
+
* @return {Promise<string | undefined>} Returns detected API base URL
|
|
111
|
+
* @throws {Error} Throws error if either of the detection methods fails
|
|
112
|
+
*/
|
|
113
|
+
public async _getApiBaseUrl(signal?: AbortSignal): Promise<string | undefined> {
|
|
114
|
+
// Check if API already detected; don't reattempt detection
|
|
115
|
+
if (this._apiBaseUrlDetected) return this._apiBaseUrl;
|
|
116
|
+
|
|
117
|
+
// Check if detection already in progress; don't allow multiple detections in parallel
|
|
118
|
+
if (this._apiBaseUrlPromise) return this._apiBaseUrlPromise;
|
|
119
|
+
|
|
120
|
+
// Detect API base URL
|
|
121
|
+
return (this._apiBaseUrlPromise = new Promise<string | undefined>((resolve, reject) =>
|
|
122
|
+
(async () => {
|
|
123
|
+
// Reset
|
|
124
|
+
this._apiBaseUrlDetected = false;
|
|
125
|
+
this._apiBaseUrlDetectionMethod = undefined;
|
|
126
|
+
this._apiBaseUrl = undefined;
|
|
127
|
+
this._apiBaseError = undefined;
|
|
128
|
+
|
|
129
|
+
// Check CORNERSTONE-API-BASEURL header for API base URL
|
|
130
|
+
try {
|
|
131
|
+
const currentUrlResponse = await this._httpService.request(window.location.href, {
|
|
132
|
+
method: 'GET',
|
|
133
|
+
signal,
|
|
134
|
+
});
|
|
135
|
+
const apiHeader: string | null =
|
|
136
|
+
currentUrlResponse.headers['CORNERSTONE-API-BASEURL'] || currentUrlResponse.headers['cornerstone-api-baseurl'] || null;
|
|
137
|
+
if (apiHeader) {
|
|
138
|
+
this._apiBaseUrlDetected = true;
|
|
139
|
+
this._apiBaseUrlDetectionMethod = 'GET / Header:CORNERSTONE-API-BASEURL';
|
|
140
|
+
this._apiBaseUrl = apiHeader;
|
|
141
|
+
this._apiBaseError = undefined;
|
|
142
|
+
this._apiBaseUrlPromise = undefined;
|
|
143
|
+
return resolve(this._apiBaseUrl);
|
|
144
|
+
}
|
|
145
|
+
} catch (err) {
|
|
146
|
+
this._apiBaseError = err instanceof Error ? err : new Error('Failed loading API base URL from response header!');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Check ./websettings.json header for API base URL
|
|
150
|
+
try {
|
|
151
|
+
const webSettingsResponse = await this._httpService.request('./websettings.json', {
|
|
152
|
+
method: 'GET',
|
|
153
|
+
signal,
|
|
154
|
+
});
|
|
155
|
+
if (webSettingsResponse.status === 404) return (this._apiBaseUrl = undefined);
|
|
156
|
+
const webSettings: WebSettings = await webSettingsResponse.json();
|
|
157
|
+
if (webSettings?.api) {
|
|
158
|
+
this._apiBaseUrlDetected = true;
|
|
159
|
+
this._apiBaseUrlDetectionMethod = 'GET websettings.json';
|
|
160
|
+
this._apiBaseUrl = webSettings.api;
|
|
161
|
+
this._apiBaseError = undefined;
|
|
162
|
+
this._apiBaseUrlPromise = undefined;
|
|
163
|
+
return resolve(this._apiBaseUrl);
|
|
164
|
+
}
|
|
165
|
+
} catch (err) {
|
|
166
|
+
this._apiBaseError = err instanceof Error ? err : new Error('Failed loading API base URL from settings file!');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Check if error caught during any of the detection methods
|
|
170
|
+
if (this._apiBaseError !== undefined) {
|
|
171
|
+
this._apiBaseUrlDetected = false;
|
|
172
|
+
this._apiBaseUrlDetectionMethod = undefined;
|
|
173
|
+
this._apiBaseUrl = undefined;
|
|
174
|
+
this._apiBaseUrlPromise = undefined;
|
|
175
|
+
return reject(this._apiBaseError);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Default to no API found
|
|
179
|
+
this._apiBaseUrlDetected = true;
|
|
180
|
+
this._apiBaseUrlDetectionMethod = undefined;
|
|
181
|
+
this._apiBaseUrl = undefined;
|
|
182
|
+
this._apiBaseError = undefined;
|
|
183
|
+
this._apiBaseUrlPromise = undefined;
|
|
184
|
+
return resolve(this._apiBaseUrl);
|
|
185
|
+
})(),
|
|
186
|
+
));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Composes a full API URL for a provided endpoint path.
|
|
191
|
+
*
|
|
192
|
+
* @async
|
|
193
|
+
* @param relativeEndpointPathSections Relative endpoint path sections
|
|
194
|
+
* @return {Promise<string | undefined>} Returns the API endpoint's URL
|
|
195
|
+
* @throws {Error} Throws error if API base URL detection fails
|
|
196
|
+
*/
|
|
197
|
+
public async getApiUrl(...relativeEndpointPathSections: string[]): Promise<string> {
|
|
198
|
+
const apiBaseUrl = await this._getApiBaseUrl();
|
|
199
|
+
const domain = !apiBaseUrl ? '/' : `${this.removeEndsWithSlashChar(apiBaseUrl)}/`;
|
|
200
|
+
const path = relativeEndpointPathSections.map(section => this.removeStartsWithSlashChar(this.removeEndsWithSlashChar(section))).join('/');
|
|
201
|
+
return `${domain}${path}`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Removes starting '/' character
|
|
206
|
+
* @param str String to remove the starting '/' character from
|
|
207
|
+
* @returns String with starting '/' character removed
|
|
208
|
+
*/
|
|
209
|
+
private removeStartsWithSlashChar(str: string): string {
|
|
210
|
+
return !str.startsWith('/') ? str : str.substring(1);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// #endregion
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Removes ending '/' character
|
|
217
|
+
* @param str String to remove the ending '/' character from
|
|
218
|
+
* @returns String with ending '/' character removed
|
|
219
|
+
*/
|
|
220
|
+
private removeEndsWithSlashChar(str: string): string {
|
|
221
|
+
return !str.endsWith('/') ? str : str.substring(0, str.length - 1);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Fetches initialization info (shared settings) from the server
|
|
226
|
+
* @returns Promise that resolves to shared settings or undefined if the request fails
|
|
227
|
+
*/
|
|
228
|
+
private async _getAppConfig(): Promise<void> {
|
|
229
|
+
try {
|
|
230
|
+
const response = await fetch(`${this._apiBaseUrl}/system/init`, { credentials: 'include' });
|
|
231
|
+
if (!response.ok) {
|
|
232
|
+
throw fail(await response.json()) as ApiErrorResponseDto;
|
|
233
|
+
}
|
|
234
|
+
const apiResponse = ok<ApiSuccessResponseDto<IInitializationInfoDto, EmptyMetadataDto>, ApiErrorResponseDto>(await response.json());
|
|
235
|
+
|
|
236
|
+
if (!apiResponse.ok) {
|
|
237
|
+
throw apiResponse.error;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Return the settings from the nested structure
|
|
241
|
+
this.appConfig = apiResponse.result.settings;
|
|
242
|
+
} catch (error) {
|
|
243
|
+
console.error('Failed to get app config', error);
|
|
244
|
+
this.appConfig = undefined;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// #endregion
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Singleton instance of ApiInitializationService
|
|
253
|
+
*/
|
|
254
|
+
export const apiInitializationService = new ApiInitializationService();
|