@kontent-ai/core-sdk 11.0.0-7 → 11.0.0
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/.npmignore +14 -14
- package/LICENSE.md +9 -9
- package/README.md +3 -1
- package/dist/devkit/devkit.models.d.ts +2 -1
- package/dist/devkit_api.d.ts +1 -1
- package/dist/devkit_api.js +1 -0
- package/dist/devkit_api.js.map +1 -1
- package/dist/http/http.adapter.js +1 -1
- package/dist/http/http.models.d.ts +15 -4
- package/dist/http/http.service.js +40 -29
- package/dist/http/http.service.js.map +1 -1
- package/dist/models/core.models.d.ts +9 -7
- package/dist/models/error.models.d.ts +19 -18
- package/dist/public_api.d.ts +2 -1
- package/dist/public_api.js +1 -0
- package/dist/public_api.js.map +1 -1
- package/dist/sdk-info.js +1 -1
- package/dist/utils/error.utils.d.ts +3 -1
- package/dist/utils/error.utils.js +12 -9
- package/dist/utils/error.utils.js.map +1 -1
- package/dist/utils/header.utils.js +5 -1
- package/dist/utils/header.utils.js.map +1 -1
- package/dist/utils/retry.utils.d.ts +1 -1
- package/dist/utils/retry.utils.js +27 -30
- package/dist/utils/retry.utils.js.map +1 -1
- package/lib/devkit/devkit.models.ts +2 -1
- package/lib/devkit_api.ts +1 -1
- package/lib/http/http.adapter.ts +1 -1
- package/lib/http/http.models.ts +21 -11
- package/lib/http/http.service.ts +45 -30
- package/lib/models/core.models.ts +9 -7
- package/lib/models/error.models.ts +41 -35
- package/lib/public_api.ts +3 -1
- package/lib/utils/error.utils.ts +15 -10
- package/lib/utils/header.utils.ts +7 -1
- package/lib/utils/retry.utils.ts +28 -31
- package/package.json +3 -10
package/.npmignore
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
# Ignore everything
|
|
2
|
-
*
|
|
3
|
-
|
|
4
|
-
# But descend into directories
|
|
5
|
-
|
|
6
|
-
# Recursively allow files under subtree
|
|
7
|
-
!/lib/**
|
|
8
|
-
!/dist/**
|
|
9
|
-
!package.json
|
|
10
|
-
!.npmignore
|
|
11
|
-
!README.md
|
|
12
|
-
!LICENSE.md
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
# Ignore everything
|
|
2
|
+
*
|
|
3
|
+
|
|
4
|
+
# But descend into directories
|
|
5
|
+
|
|
6
|
+
# Recursively allow files under subtree
|
|
7
|
+
!/lib/**
|
|
8
|
+
!/dist/**
|
|
9
|
+
!package.json
|
|
10
|
+
!.npmignore
|
|
11
|
+
!README.md
|
|
12
|
+
!LICENSE.md
|
|
13
|
+
|
|
14
|
+
|
package/LICENSE.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
# MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Kontent s.r.o.
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
-
|
|
7
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
-
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Kontent s.r.o.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
[](https://www.npmjs.com/package/@kontent-ai/core-sdk)
|
|
2
|
-
[](https://github.com/kontent-ai/core-sdk-js/actions/workflows/build.yml)
|
|
3
|
+
[](https://github.com/kontent-ai/core-sdk-js/actions/workflows/unit-tests.yml)
|
|
4
|
+
[](https://github.com/kontent-ai/core-sdk-js/actions/workflows/integration-tests.yml)
|
|
3
5
|
[](https://www.npmjs.com/package/@kontent-ai/core-sdk)
|
|
4
6
|
[](https://snyk.io/test/github/kontent-ai/core-sdk-js)
|
|
5
7
|
[](https://github.com/kontent-ai/core-sdk-js)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { HttpServiceStatus
|
|
1
|
+
import type { HttpServiceStatus } from "../http/http.models.js";
|
|
2
|
+
import type { JsonValue } from "../models/json.models.js";
|
|
2
3
|
export type FetchResponse = {
|
|
3
4
|
readonly statusCode: HttpServiceStatus;
|
|
4
5
|
readonly json: JsonValue;
|
package/dist/devkit_api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { deleteFolderRecursive } from "./devkit/script.utils.js";
|
|
2
2
|
export { replaceSdkVersionPlaceholder } from "./utils/sdk-version.utils.js";
|
|
3
3
|
export type { FetchResponse } from "./devkit/devkit.models.js";
|
|
4
|
-
export
|
|
4
|
+
export { getFakeBlob, getFetchBlobMock, getFetchJsonMock } from "./devkit/test.utils.js";
|
package/dist/devkit_api.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// biome-ignore lint/performance/noBarrelFile: One barrel for the Devkit API is fine
|
|
2
2
|
export { deleteFolderRecursive } from "./devkit/script.utils.js";
|
|
3
3
|
export { replaceSdkVersionPlaceholder } from "./utils/sdk-version.utils.js";
|
|
4
|
+
export { getFakeBlob, getFetchBlobMock, getFetchJsonMock } from "./devkit/test.utils.js";
|
|
4
5
|
//# sourceMappingURL=devkit_api.js.map
|
package/dist/devkit_api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devkit_api.js","sourceRoot":"","sources":["../lib/devkit_api.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"devkit_api.js","sourceRoot":"","sources":["../lib/devkit_api.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAE5E,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -19,7 +19,7 @@ export function getDefaultHttpAdapter() {
|
|
|
19
19
|
.find((m) => m.name.toLowerCase() === "Content-Type".toLowerCase())
|
|
20
20
|
?.value.toLowerCase();
|
|
21
21
|
if (contentTypeResponseHeader?.includes("application/json")) {
|
|
22
|
-
// Includes instead of
|
|
22
|
+
// Includes instead of equal due to the fact that the header value can be 'application/json; charset=utf-8' or similar
|
|
23
23
|
return (await response.json());
|
|
24
24
|
}
|
|
25
25
|
return null;
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import type { Header, HttpMethod, LiteralUnionNumber, RetryStrategyOptions } from "../models/core.models.js";
|
|
2
2
|
import type { CoreSdkError } from "../models/error.models.js";
|
|
3
3
|
import type { JsonValue } from "../models/json.models.js";
|
|
4
|
-
|
|
4
|
+
type Success<TData> = {
|
|
5
|
+
readonly success: true;
|
|
6
|
+
readonly response: TData;
|
|
7
|
+
readonly error?: never;
|
|
8
|
+
};
|
|
9
|
+
type Failure = {
|
|
10
|
+
readonly success: false;
|
|
11
|
+
readonly response?: never;
|
|
12
|
+
readonly error: CoreSdkError;
|
|
13
|
+
};
|
|
14
|
+
export type HttpResult<TData> = Success<TData> | Failure;
|
|
5
15
|
/**
|
|
6
16
|
* Helper status codes for the HTTP service.
|
|
7
17
|
* It can be any valid number status code as this type only serves as a helper.
|
|
@@ -21,13 +31,13 @@ export type DefaultHttpServiceConfig = {
|
|
|
21
31
|
*/
|
|
22
32
|
readonly adapter?: HttpAdapter;
|
|
23
33
|
};
|
|
24
|
-
export type HttpResponse<TResponseData extends JsonValue | Blob, TBodyData extends JsonValue | Blob> =
|
|
25
|
-
readonly
|
|
34
|
+
export type HttpResponse<TResponseData extends JsonValue | Blob, TBodyData extends JsonValue | Blob> = HttpResult<{
|
|
35
|
+
readonly data: TResponseData;
|
|
26
36
|
readonly body: TBodyData;
|
|
27
37
|
readonly method: HttpMethod;
|
|
28
38
|
readonly requestHeaders: readonly Header[];
|
|
29
39
|
readonly adapterResponse: Omit<AdapterResponse, "toJsonAsync" | "toBlobAsync">;
|
|
30
|
-
}
|
|
40
|
+
}>;
|
|
31
41
|
export type ExecuteRequestOptions<TBodyData extends JsonValue | Blob> = {
|
|
32
42
|
readonly url: string;
|
|
33
43
|
readonly method: HttpMethod;
|
|
@@ -90,3 +100,4 @@ export type AdapterRequestOptions = {
|
|
|
90
100
|
export type HttpAdapter = {
|
|
91
101
|
readonly requestAsync: (options: AdapterRequestOptions) => Promise<AdapterResponse>;
|
|
92
102
|
};
|
|
103
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { sdkInfo } from "../sdk-info.js";
|
|
2
2
|
import { isNotUndefined } from "../utils/core.utils.js";
|
|
3
|
-
import {
|
|
3
|
+
import { getErrorMessage } from "../utils/error.utils.js";
|
|
4
4
|
import { getSdkIdHeader } from "../utils/header.utils.js";
|
|
5
5
|
import { runWithRetryAsync, toRequiredRetryStrategyOptions } from "../utils/retry.utils.js";
|
|
6
6
|
import { tryCatch } from "../utils/try.utils.js";
|
|
@@ -31,10 +31,8 @@ export function getDefaultHttpService(config) {
|
|
|
31
31
|
error: {
|
|
32
32
|
message: "Failed to stringify body of request.",
|
|
33
33
|
url: options.url,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
error: error,
|
|
37
|
-
},
|
|
34
|
+
reason: "invalidBody",
|
|
35
|
+
error: error,
|
|
38
36
|
},
|
|
39
37
|
};
|
|
40
38
|
}
|
|
@@ -51,10 +49,8 @@ export function getDefaultHttpService(config) {
|
|
|
51
49
|
error: {
|
|
52
50
|
message: `Failed to parse url '${options.url}'.`,
|
|
53
51
|
url: options.url,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
error,
|
|
57
|
-
},
|
|
52
|
+
reason: "invalidUrl",
|
|
53
|
+
error,
|
|
58
54
|
},
|
|
59
55
|
};
|
|
60
56
|
}
|
|
@@ -99,34 +95,49 @@ export function getDefaultHttpService(config) {
|
|
|
99
95
|
body: requestBody,
|
|
100
96
|
});
|
|
101
97
|
};
|
|
98
|
+
const getErrorForInvalidResponseAsync = async (response) => {
|
|
99
|
+
const sharedErrorData = {
|
|
100
|
+
message: getErrorMessage({
|
|
101
|
+
url: options.url,
|
|
102
|
+
adapterResponse: response,
|
|
103
|
+
method: options.method,
|
|
104
|
+
}),
|
|
105
|
+
url: options.url,
|
|
106
|
+
};
|
|
107
|
+
if (response.status === 404) {
|
|
108
|
+
const error = {
|
|
109
|
+
...sharedErrorData,
|
|
110
|
+
reason: "notFound",
|
|
111
|
+
isValidResponse: response.isValidResponse,
|
|
112
|
+
responseHeaders: response.responseHeaders,
|
|
113
|
+
status: 404,
|
|
114
|
+
statusText: response.statusText,
|
|
115
|
+
kontentErrorResponse: await getKontentErrorDataAsync(response),
|
|
116
|
+
};
|
|
117
|
+
return error;
|
|
118
|
+
}
|
|
119
|
+
const error = {
|
|
120
|
+
...sharedErrorData,
|
|
121
|
+
reason: "invalidResponse",
|
|
122
|
+
isValidResponse: response.isValidResponse,
|
|
123
|
+
responseHeaders: response.responseHeaders,
|
|
124
|
+
status: response.status,
|
|
125
|
+
statusText: response.statusText,
|
|
126
|
+
kontentErrorResponse: await getKontentErrorDataAsync(response),
|
|
127
|
+
};
|
|
128
|
+
return error;
|
|
129
|
+
};
|
|
102
130
|
const resolveResponseAsync = async (response) => {
|
|
103
131
|
if (!response.isValidResponse) {
|
|
104
|
-
const kontentErrorResponse = await getKontentErrorDataAsync(response);
|
|
105
132
|
return {
|
|
106
133
|
success: false,
|
|
107
|
-
error:
|
|
108
|
-
details: {
|
|
109
|
-
type: "invalidResponse",
|
|
110
|
-
isValidResponse: response.isValidResponse,
|
|
111
|
-
responseHeaders: response.responseHeaders,
|
|
112
|
-
status: response.status,
|
|
113
|
-
statusText: response.statusText,
|
|
114
|
-
kontentErrorResponse,
|
|
115
|
-
},
|
|
116
|
-
message: getDefaultErrorMessage({
|
|
117
|
-
url: options.url,
|
|
118
|
-
adapterResponse: response,
|
|
119
|
-
kontentErrorResponse,
|
|
120
|
-
method: options.method,
|
|
121
|
-
}),
|
|
122
|
-
url: options.url,
|
|
123
|
-
},
|
|
134
|
+
error: await getErrorForInvalidResponseAsync(response),
|
|
124
135
|
};
|
|
125
136
|
}
|
|
126
137
|
return {
|
|
127
138
|
success: true,
|
|
128
|
-
|
|
129
|
-
|
|
139
|
+
response: {
|
|
140
|
+
data: await resolveDataAsync(response),
|
|
130
141
|
body: options.body,
|
|
131
142
|
method: options.method,
|
|
132
143
|
adapterResponse: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.service.js","sourceRoot":"","sources":["../../lib/http/http.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"http.service.js","sourceRoot":"","sources":["../../lib/http/http.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,24 +36,26 @@ export type KontentErrorResponseData = {
|
|
|
36
36
|
};
|
|
37
37
|
export type RetryStrategyOptions = {
|
|
38
38
|
/**
|
|
39
|
-
* Maximum number of
|
|
39
|
+
* Maximum number of retry attempts.
|
|
40
|
+
*
|
|
40
41
|
* If not provided, the default implementation will be used.
|
|
41
42
|
*/
|
|
42
|
-
readonly
|
|
43
|
+
readonly maxRetries?: number;
|
|
43
44
|
/**
|
|
44
45
|
* Function to determine if the error should be retried.
|
|
46
|
+
*
|
|
45
47
|
* If not provided, the default implementation will be used.
|
|
46
48
|
*/
|
|
47
49
|
readonly canRetryError?: (error: CoreSdkError) => boolean;
|
|
48
50
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* indicate the time to wait before retrying the request.
|
|
51
|
+
* Function to determine the delay between requests in milliseconds.
|
|
52
|
+
*
|
|
53
|
+
* If not provided, the default implementation will be used.
|
|
53
54
|
*/
|
|
54
|
-
readonly
|
|
55
|
+
readonly getDelayBetweenRetriesMs?: (error: CoreSdkError) => number;
|
|
55
56
|
/**
|
|
56
57
|
* Whether to log the retry attempt.
|
|
58
|
+
*
|
|
57
59
|
* If false, the retry attempt will not be logged.
|
|
58
60
|
* If undefined, the default implementation will be used.
|
|
59
61
|
* Otherwise, the function will be called with the retry attempt and url.
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import type { AdapterResponse, HttpServiceStatus } from "../http/http.models.js";
|
|
2
2
|
import type { KontentErrorResponseData, RetryStrategyOptions } from "./core.models.js";
|
|
3
|
-
export type
|
|
4
|
-
export type
|
|
3
|
+
export type ErrorReason = "invalidResponse" | "invalidUrl" | "unknown" | "invalidBody" | "notFound";
|
|
4
|
+
export type CoreSdkErrorDetails<TReason extends ErrorReason = ErrorReason> = (Details<"invalidResponse", {
|
|
5
|
+
readonly kontentErrorResponse: KontentErrorResponseData | undefined;
|
|
6
|
+
} & Pick<AdapterResponse<HttpServiceStatus>, "isValidResponse" | "responseHeaders" | "status" | "statusText">> | Details<"notFound", {
|
|
7
|
+
readonly kontentErrorResponse: KontentErrorResponseData | undefined;
|
|
8
|
+
} & Pick<AdapterResponse<404>, "isValidResponse" | "responseHeaders" | "status" | "statusText">> | Details<"invalidBody", {
|
|
9
|
+
readonly error: unknown;
|
|
10
|
+
}> | Details<"invalidUrl", {
|
|
11
|
+
readonly error: unknown;
|
|
12
|
+
}> | Details<"unknown", {
|
|
13
|
+
readonly error: unknown;
|
|
14
|
+
}>) & {
|
|
15
|
+
readonly reason: TReason;
|
|
16
|
+
};
|
|
17
|
+
export type CoreSdkError<TReason extends ErrorReason = ErrorReason> = {
|
|
5
18
|
/**
|
|
6
19
|
* The message of the error
|
|
7
20
|
*/
|
|
@@ -11,27 +24,15 @@ export type CoreSdkError = {
|
|
|
11
24
|
*/
|
|
12
25
|
readonly url: string;
|
|
13
26
|
/**
|
|
14
|
-
*
|
|
27
|
+
* Used retry strategy.
|
|
15
28
|
*/
|
|
16
29
|
readonly retryStrategyOptions?: Required<RetryStrategyOptions>;
|
|
17
30
|
/**
|
|
18
31
|
* The number of times the request has been retried.
|
|
19
32
|
*/
|
|
20
33
|
readonly retryAttempt?: number;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
readonly details: SdkErrorDetails<"invalidResponse", {
|
|
25
|
-
readonly kontentErrorResponse: KontentErrorResponseData | undefined;
|
|
26
|
-
} & Pick<AdapterResponse<HttpServiceStatus>, "isValidResponse" | "responseHeaders" | "status" | "statusText">> | SdkErrorDetails<"invalidBody", {
|
|
27
|
-
readonly error: unknown;
|
|
28
|
-
}> | SdkErrorDetails<"invalidUrl", {
|
|
29
|
-
readonly error: unknown;
|
|
30
|
-
}> | SdkErrorDetails<"unknown", {
|
|
31
|
-
readonly error: unknown;
|
|
32
|
-
}>;
|
|
33
|
-
};
|
|
34
|
-
type SdkErrorDetails<TType extends ErrorType, TDetails> = {
|
|
35
|
-
readonly type: TType;
|
|
34
|
+
} & CoreSdkErrorDetails<TReason>;
|
|
35
|
+
type Details<TReason extends ErrorReason, TDetails> = {
|
|
36
|
+
readonly reason: TReason;
|
|
36
37
|
} & TDetails;
|
|
37
38
|
export {};
|
package/dist/public_api.d.ts
CHANGED
|
@@ -3,8 +3,9 @@ export { getDefaultHttpService } from "./http/http.service.js";
|
|
|
3
3
|
export { getSdkIdHeader } from "./utils/header.utils.js";
|
|
4
4
|
export { toRequiredRetryStrategyOptions } from "./utils/retry.utils.js";
|
|
5
5
|
export { tryCatch, tryCatchAsync } from "./utils/try.utils.js";
|
|
6
|
+
export { isKontent404Error } from "./utils/error.utils.js";
|
|
6
7
|
export type { AdapterRequestOptions, AdapterResponse, DefaultHttpServiceConfig, DownloadFileRequestOptions, ExecuteRequestOptions, HttpAdapter, HttpResponse, HttpService, HttpServiceStatus, UploadFileRequestOptions, } from "./http/http.models.js";
|
|
7
8
|
export type { Header, HttpMethod, RetryStrategyOptions, SDKInfo, } from "./models/core.models.js";
|
|
8
|
-
export type { CoreSdkError,
|
|
9
|
+
export type { CoreSdkError, ErrorReason, CoreSdkErrorDetails, } from "./models/error.models.js";
|
|
9
10
|
export type { JsonArray, JsonObject, JsonValue } from "./models/json.models.js";
|
|
10
11
|
export type { EmptyObject, Override, Prettify } from "./models/utility.models.js";
|
package/dist/public_api.js
CHANGED
|
@@ -4,4 +4,5 @@ export { getDefaultHttpService } from "./http/http.service.js";
|
|
|
4
4
|
export { getSdkIdHeader } from "./utils/header.utils.js";
|
|
5
5
|
export { toRequiredRetryStrategyOptions } from "./utils/retry.utils.js";
|
|
6
6
|
export { tryCatch, tryCatchAsync } from "./utils/try.utils.js";
|
|
7
|
+
export { isKontent404Error } from "./utils/error.utils.js";
|
|
7
8
|
//# sourceMappingURL=public_api.js.map
|
package/dist/public_api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public_api.js","sourceRoot":"","sources":["../lib/public_api.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"public_api.js","sourceRoot":"","sources":["../lib/public_api.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/sdk-info.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { AdapterResponse } from "../http/http.models.js";
|
|
2
2
|
import type { HttpMethod, KontentErrorResponseData } from "../models/core.models.js";
|
|
3
|
-
|
|
3
|
+
import type { CoreSdkError } from "../models/error.models.js";
|
|
4
|
+
export declare function isKontent404Error(error: CoreSdkError): error is CoreSdkError<"invalidResponse">;
|
|
5
|
+
export declare function getErrorMessage({ method, url, adapterResponse, kontentErrorResponse, }: {
|
|
4
6
|
readonly url: string;
|
|
5
7
|
readonly method: HttpMethod;
|
|
6
8
|
readonly adapterResponse: AdapterResponse;
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { isNotUndefined } from "./core.utils.js";
|
|
2
|
-
export function
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
export function isKontent404Error(error) {
|
|
3
|
+
return isErrorOfType("invalidResponse", error) && error.status === 404;
|
|
4
|
+
}
|
|
5
|
+
export function getErrorMessage({ method, url, adapterResponse, kontentErrorResponse, }) {
|
|
6
|
+
const details = kontentErrorResponse ? getKontentErrorResponseMessage(adapterResponse, kontentErrorResponse) : undefined;
|
|
7
|
+
return `Failed to execute '${method}' request '${url}'.${details ? ` ${details}` : ""}`;
|
|
8
|
+
}
|
|
9
|
+
function isErrorOfType(reason, error) {
|
|
10
|
+
return error.reason === reason;
|
|
5
11
|
}
|
|
6
12
|
function getValidationErrorMessage(validationErrors) {
|
|
7
13
|
if (!validationErrors?.length) {
|
|
@@ -18,11 +24,8 @@ function getValidationErrorMessage(validationErrors) {
|
|
|
18
24
|
})
|
|
19
25
|
.join(", ");
|
|
20
26
|
}
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return `Response failed with status '${adapterResponse.status}' and status text '${adapterResponse.statusText}'.${kontentErrorResponse.message}${validationErrorMessage ? ` ${validationErrorMessage}` : ""}`;
|
|
25
|
-
}
|
|
26
|
-
return undefined;
|
|
27
|
+
function getKontentErrorResponseMessage(adapterResponse, kontentErrorResponse) {
|
|
28
|
+
const validationErrorMessage = getValidationErrorMessage(kontentErrorResponse.validation_errors);
|
|
29
|
+
return `Response failed with status '${adapterResponse.status}' and status text '${adapterResponse.statusText}'.${kontentErrorResponse.message}${validationErrorMessage ? ` ${validationErrorMessage}` : ""}`;
|
|
27
30
|
}
|
|
28
31
|
//# sourceMappingURL=error.utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.utils.js","sourceRoot":"","sources":["../../lib/utils/error.utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"error.utils.js","sourceRoot":"","sources":["../../lib/utils/error.utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,UAAU,iBAAiB,CAAC,KAAmB;IACpD,OAAO,aAAa,CAAC,iBAAiB,EAAE,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,EAC/B,MAAM,EACN,GAAG,EACH,eAAe,EACf,oBAAoB,GAMpB;IACA,MAAM,OAAO,GAAG,oBAAoB,CAAC,CAAC,CAAC,8BAA8B,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzH,OAAO,sBAAsB,MAAM,cAAc,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACzF,CAAC;AAED,SAAS,aAAa,CAA8B,MAAe,EAAE,KAAmB;IACvF,OAAO,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC;AAChC,CAAC;AAED,SAAS,yBAAyB,CAAC,gBAAoD;IACtF,IAAI,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC/B,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,gBAAgB;SACrB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACV,MAAM,OAAO,GAAsB;YAClC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS;YACtC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS;YACtC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS;SAClD,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QACzB,OAAO,GAAG,CAAC,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC1E,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AACd,CAAC;AAED,SAAS,8BAA8B,CAAC,eAAgC,EAAE,oBAA8C;IACvH,MAAM,sBAAsB,GAAG,yBAAyB,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;IACjG,OAAO,gCAAgC,eAAe,CAAC,MAAM,sBAAsB,eAAe,CAAC,UAAU,KAAK,oBAAoB,CAAC,OAAO,GAAG,sBAAsB,CAAC,CAAC,CAAC,IAAI,sBAAsB,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC/M,CAAC"}
|
|
@@ -9,7 +9,11 @@ export function getRetryAfterHeaderValue(headers) {
|
|
|
9
9
|
if (!retryAfterHeader) {
|
|
10
10
|
return undefined;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
const numberValue = +retryAfterHeader.value;
|
|
13
|
+
if (!Number.isSafeInteger(numberValue)) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
return numberValue;
|
|
13
17
|
}
|
|
14
18
|
export function toSdkHeaders(headers) {
|
|
15
19
|
return Array.from(headers.entries()).map(([key, value]) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"header.utils.js","sourceRoot":"","sources":["../../lib/utils/header.utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,cAAc,CAAC,IAAa;IAC3C,OAAO;QACN,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE;KAClD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,OAA0B;IAClE,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC;IAE7G,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"header.utils.js","sourceRoot":"","sources":["../../lib/utils/header.utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,cAAc,CAAC,IAAa;IAC3C,OAAO;QACN,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE;KAClD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,OAA0B;IAClE,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC;IAE7G,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,MAAM,WAAW,GAAG,CAAC,gBAAgB,CAAC,KAAK,CAAC;IAE5C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;QACxC,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,OAAO,WAAW,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC5C,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,KAAK;KACZ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAA0B;IACxD,OAAO,OAAO,CAAC,MAAM,CAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAClD,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,OAAO,CAAC;IAChB,CAAC,EAAE,IAAI,OAAO,EAAE,CAAC,CAAC;AACnB,CAAC"}
|
|
@@ -10,4 +10,4 @@ export declare function runWithRetryAsync<TResponse extends JsonValue | Blob, TB
|
|
|
10
10
|
readonly method: HttpMethod;
|
|
11
11
|
}): Promise<HttpResponse<TResponse, TBodyData>>;
|
|
12
12
|
export declare function toRequiredRetryStrategyOptions(options?: RetryStrategyOptions): Required<RetryStrategyOptions>;
|
|
13
|
-
export declare function getDefaultRetryAttemptLogMessage(retryAttempt: number,
|
|
13
|
+
export declare function getDefaultRetryAttemptLogMessage(retryAttempt: number, maxRetries: number, url: string): string;
|
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import { getRetryAfterHeaderValue } from "./header.utils.js";
|
|
2
|
-
const
|
|
3
|
-
const
|
|
2
|
+
const defaultMaxRetries = 3;
|
|
3
|
+
const getDefaultDelayBetweenRetriesMs = (error) => {
|
|
4
|
+
if (error.reason === "notFound" || error.reason === "invalidResponse") {
|
|
5
|
+
return getRetryFromHeaderMs({ error });
|
|
6
|
+
}
|
|
7
|
+
return 0;
|
|
8
|
+
};
|
|
4
9
|
const defaultCanRetryError = (error) => {
|
|
5
|
-
if (error.
|
|
6
|
-
if (error.
|
|
10
|
+
if (error.reason === "invalidResponse") {
|
|
11
|
+
if (error.kontentErrorResponse) {
|
|
7
12
|
// The request is clearly invalid as we got an error response from the API
|
|
8
13
|
return false;
|
|
9
14
|
}
|
|
10
|
-
return error.
|
|
15
|
+
return error.status >= 500 || error.status === 429;
|
|
11
16
|
}
|
|
12
17
|
return true;
|
|
13
18
|
};
|
|
14
19
|
export async function runWithRetryAsync(data) {
|
|
15
|
-
const { success,
|
|
20
|
+
const { success, response, error } = await data.funcAsync();
|
|
16
21
|
if (success) {
|
|
17
22
|
return {
|
|
18
23
|
success: true,
|
|
19
|
-
|
|
24
|
+
response,
|
|
20
25
|
};
|
|
21
26
|
}
|
|
22
27
|
const newRetryAttempt = data.retryAttempt + 1;
|
|
@@ -47,11 +52,11 @@ export async function runWithRetryAsync(data) {
|
|
|
47
52
|
});
|
|
48
53
|
}
|
|
49
54
|
export function toRequiredRetryStrategyOptions(options) {
|
|
50
|
-
const
|
|
55
|
+
const maxRetries = options?.maxRetries ?? defaultMaxRetries;
|
|
51
56
|
return {
|
|
52
|
-
|
|
57
|
+
maxRetries: maxRetries,
|
|
53
58
|
canRetryError: options?.canRetryError ?? defaultCanRetryError,
|
|
54
|
-
|
|
59
|
+
getDelayBetweenRetriesMs: options?.getDelayBetweenRetriesMs ?? getDefaultDelayBetweenRetriesMs,
|
|
55
60
|
logRetryAttempt: options?.logRetryAttempt === false
|
|
56
61
|
? false
|
|
57
62
|
: (attempt, url) => {
|
|
@@ -59,13 +64,13 @@ export function toRequiredRetryStrategyOptions(options) {
|
|
|
59
64
|
options.logRetryAttempt(attempt, url);
|
|
60
65
|
}
|
|
61
66
|
else {
|
|
62
|
-
console.warn(getDefaultRetryAttemptLogMessage(attempt,
|
|
67
|
+
console.warn(getDefaultRetryAttemptLogMessage(attempt, maxRetries, url));
|
|
63
68
|
}
|
|
64
69
|
},
|
|
65
70
|
};
|
|
66
71
|
}
|
|
67
|
-
export function getDefaultRetryAttemptLogMessage(retryAttempt,
|
|
68
|
-
return `Retry attempt '${retryAttempt}' from a maximum of '${
|
|
72
|
+
export function getDefaultRetryAttemptLogMessage(retryAttempt, maxRetries, url) {
|
|
73
|
+
return `Retry attempt '${retryAttempt}' from a maximum of '${maxRetries}' retries. Requested url: '${url}'`;
|
|
69
74
|
}
|
|
70
75
|
function logRetryAttempt(opts, retryAttempt, url) {
|
|
71
76
|
if (opts.logRetryAttempt) {
|
|
@@ -76,7 +81,7 @@ function waitAsync(ms) {
|
|
|
76
81
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
77
82
|
}
|
|
78
83
|
function getRetryResult({ retryAttempt, error, options, }) {
|
|
79
|
-
if (retryAttempt >= options.
|
|
84
|
+
if (retryAttempt >= options.maxRetries) {
|
|
80
85
|
return {
|
|
81
86
|
canRetry: false,
|
|
82
87
|
};
|
|
@@ -86,24 +91,16 @@ function getRetryResult({ retryAttempt, error, options, }) {
|
|
|
86
91
|
canRetry: false,
|
|
87
92
|
};
|
|
88
93
|
}
|
|
89
|
-
return getRetryFromHeader({ options, error });
|
|
90
|
-
}
|
|
91
|
-
function getRetryFromHeader({ options, error }) {
|
|
92
|
-
if (error.details.type !== "invalidResponse") {
|
|
93
|
-
return {
|
|
94
|
-
canRetry: false,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
const retryAfterHeaderValue = getRetryAfterHeaderValue(error.details.responseHeaders);
|
|
98
|
-
if (retryAfterHeaderValue) {
|
|
99
|
-
return {
|
|
100
|
-
canRetry: true,
|
|
101
|
-
retryInMs: retryAfterHeaderValue * 1000,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
94
|
return {
|
|
105
95
|
canRetry: true,
|
|
106
|
-
retryInMs: options.
|
|
96
|
+
retryInMs: options.getDelayBetweenRetriesMs(error),
|
|
107
97
|
};
|
|
108
98
|
}
|
|
99
|
+
function getRetryFromHeaderMs({ error }) {
|
|
100
|
+
const retryAfterHeaderValue = getRetryAfterHeaderValue(error.responseHeaders);
|
|
101
|
+
if (retryAfterHeaderValue) {
|
|
102
|
+
return retryAfterHeaderValue * 1000;
|
|
103
|
+
}
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
109
106
|
//# sourceMappingURL=retry.utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.utils.js","sourceRoot":"","sources":["../../lib/utils/retry.utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAW7D,MAAM,
|
|
1
|
+
{"version":3,"file":"retry.utils.js","sourceRoot":"","sources":["../../lib/utils/retry.utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { HttpServiceStatus
|
|
1
|
+
import type { HttpServiceStatus } from "../http/http.models.js";
|
|
2
|
+
import type { JsonValue } from "../models/json.models.js";
|
|
2
3
|
|
|
3
4
|
export type FetchResponse = {
|
|
4
5
|
readonly statusCode: HttpServiceStatus;
|
package/lib/devkit_api.ts
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
export { deleteFolderRecursive } from "./devkit/script.utils.js";
|
|
3
3
|
export { replaceSdkVersionPlaceholder } from "./utils/sdk-version.utils.js";
|
|
4
4
|
export type { FetchResponse } from "./devkit/devkit.models.js";
|
|
5
|
-
export
|
|
5
|
+
export { getFakeBlob, getFetchBlobMock, getFetchJsonMock } from "./devkit/test.utils.js";
|
package/lib/http/http.adapter.ts
CHANGED
|
@@ -26,7 +26,7 @@ export function getDefaultHttpAdapter(): HttpAdapter {
|
|
|
26
26
|
?.value.toLowerCase();
|
|
27
27
|
|
|
28
28
|
if (contentTypeResponseHeader?.includes("application/json")) {
|
|
29
|
-
// Includes instead of
|
|
29
|
+
// Includes instead of equal due to the fact that the header value can be 'application/json; charset=utf-8' or similar
|
|
30
30
|
return (await response.json()) as JsonValue;
|
|
31
31
|
}
|
|
32
32
|
|
package/lib/http/http.models.ts
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import type { Header, HttpMethod, LiteralUnionNumber, RetryStrategyOptions } from "../models/core.models.js";
|
|
2
2
|
import type { CoreSdkError } from "../models/error.models.js";
|
|
3
3
|
import type { JsonValue } from "../models/json.models.js";
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
type Success<TData> = {
|
|
6
|
+
readonly success: true;
|
|
7
|
+
readonly response: TData;
|
|
8
|
+
readonly error?: never;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type Failure = {
|
|
12
|
+
readonly success: false;
|
|
13
|
+
readonly response?: never;
|
|
14
|
+
readonly error: CoreSdkError;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type HttpResult<TData> = Success<TData> | Failure;
|
|
5
18
|
|
|
6
19
|
/**
|
|
7
20
|
* Helper status codes for the HTTP service.
|
|
@@ -26,16 +39,13 @@ export type DefaultHttpServiceConfig = {
|
|
|
26
39
|
readonly adapter?: HttpAdapter;
|
|
27
40
|
};
|
|
28
41
|
|
|
29
|
-
export type HttpResponse<TResponseData extends JsonValue | Blob, TBodyData extends JsonValue | Blob> =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
},
|
|
37
|
-
CoreSdkError
|
|
38
|
-
>;
|
|
42
|
+
export type HttpResponse<TResponseData extends JsonValue | Blob, TBodyData extends JsonValue | Blob> = HttpResult<{
|
|
43
|
+
readonly data: TResponseData;
|
|
44
|
+
readonly body: TBodyData;
|
|
45
|
+
readonly method: HttpMethod;
|
|
46
|
+
readonly requestHeaders: readonly Header[];
|
|
47
|
+
readonly adapterResponse: Omit<AdapterResponse, "toJsonAsync" | "toBlobAsync">;
|
|
48
|
+
}>;
|
|
39
49
|
|
|
40
50
|
export type ExecuteRequestOptions<TBodyData extends JsonValue | Blob> = {
|
|
41
51
|
readonly url: string;
|
package/lib/http/http.service.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { CoreSdkError } from "../models/error.models.js";
|
|
|
3
3
|
import type { JsonValue } from "../models/json.models.js";
|
|
4
4
|
import { sdkInfo } from "../sdk-info.js";
|
|
5
5
|
import { isNotUndefined } from "../utils/core.utils.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getErrorMessage } from "../utils/error.utils.js";
|
|
7
7
|
import { getSdkIdHeader } from "../utils/header.utils.js";
|
|
8
8
|
import { runWithRetryAsync, toRequiredRetryStrategyOptions } from "../utils/retry.utils.js";
|
|
9
9
|
import { type Result, tryCatch } from "../utils/try.utils.js";
|
|
@@ -55,10 +55,8 @@ export function getDefaultHttpService(config?: DefaultHttpServiceConfig): HttpSe
|
|
|
55
55
|
error: {
|
|
56
56
|
message: "Failed to stringify body of request.",
|
|
57
57
|
url: options.url,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
error: error,
|
|
61
|
-
},
|
|
58
|
+
reason: "invalidBody",
|
|
59
|
+
error: error,
|
|
62
60
|
},
|
|
63
61
|
};
|
|
64
62
|
}
|
|
@@ -78,10 +76,8 @@ export function getDefaultHttpService(config?: DefaultHttpServiceConfig): HttpSe
|
|
|
78
76
|
error: {
|
|
79
77
|
message: `Failed to parse url '${options.url}'.`,
|
|
80
78
|
url: options.url,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
error,
|
|
84
|
-
},
|
|
79
|
+
reason: "invalidUrl",
|
|
80
|
+
error,
|
|
85
81
|
},
|
|
86
82
|
};
|
|
87
83
|
}
|
|
@@ -135,36 +131,55 @@ export function getDefaultHttpService(config?: DefaultHttpServiceConfig): HttpSe
|
|
|
135
131
|
});
|
|
136
132
|
};
|
|
137
133
|
|
|
134
|
+
const getErrorForInvalidResponseAsync = async (response: AdapterResponse): Promise<CoreSdkError> => {
|
|
135
|
+
const sharedErrorData: Pick<CoreSdkError, "message" | "url"> = {
|
|
136
|
+
message: getErrorMessage({
|
|
137
|
+
url: options.url,
|
|
138
|
+
adapterResponse: response,
|
|
139
|
+
method: options.method,
|
|
140
|
+
}),
|
|
141
|
+
url: options.url,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
if (response.status === 404) {
|
|
145
|
+
const error: CoreSdkError<"notFound"> = {
|
|
146
|
+
...sharedErrorData,
|
|
147
|
+
reason: "notFound",
|
|
148
|
+
isValidResponse: response.isValidResponse,
|
|
149
|
+
responseHeaders: response.responseHeaders,
|
|
150
|
+
status: 404,
|
|
151
|
+
statusText: response.statusText,
|
|
152
|
+
kontentErrorResponse: await getKontentErrorDataAsync(response),
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
return error;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const error: CoreSdkError<"invalidResponse"> = {
|
|
159
|
+
...sharedErrorData,
|
|
160
|
+
reason: "invalidResponse",
|
|
161
|
+
isValidResponse: response.isValidResponse,
|
|
162
|
+
responseHeaders: response.responseHeaders,
|
|
163
|
+
status: response.status,
|
|
164
|
+
statusText: response.statusText,
|
|
165
|
+
kontentErrorResponse: await getKontentErrorDataAsync(response),
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
return error;
|
|
169
|
+
};
|
|
170
|
+
|
|
138
171
|
const resolveResponseAsync = async (response: AdapterResponse): Promise<HttpResponse<TResponseData, TBodyData>> => {
|
|
139
172
|
if (!response.isValidResponse) {
|
|
140
|
-
const kontentErrorResponse = await getKontentErrorDataAsync(response);
|
|
141
|
-
|
|
142
173
|
return {
|
|
143
174
|
success: false,
|
|
144
|
-
error:
|
|
145
|
-
details: {
|
|
146
|
-
type: "invalidResponse",
|
|
147
|
-
isValidResponse: response.isValidResponse,
|
|
148
|
-
responseHeaders: response.responseHeaders,
|
|
149
|
-
status: response.status,
|
|
150
|
-
statusText: response.statusText,
|
|
151
|
-
kontentErrorResponse,
|
|
152
|
-
},
|
|
153
|
-
message: getDefaultErrorMessage({
|
|
154
|
-
url: options.url,
|
|
155
|
-
adapterResponse: response,
|
|
156
|
-
kontentErrorResponse,
|
|
157
|
-
method: options.method,
|
|
158
|
-
}),
|
|
159
|
-
url: options.url,
|
|
160
|
-
},
|
|
175
|
+
error: await getErrorForInvalidResponseAsync(response),
|
|
161
176
|
};
|
|
162
177
|
}
|
|
163
178
|
|
|
164
179
|
return {
|
|
165
180
|
success: true,
|
|
166
|
-
|
|
167
|
-
|
|
181
|
+
response: {
|
|
182
|
+
data: await resolveDataAsync(response),
|
|
168
183
|
body: options.body,
|
|
169
184
|
method: options.method,
|
|
170
185
|
adapterResponse: {
|
|
@@ -45,27 +45,29 @@ export type KontentErrorResponseData = {
|
|
|
45
45
|
|
|
46
46
|
export type RetryStrategyOptions = {
|
|
47
47
|
/**
|
|
48
|
-
* Maximum number of
|
|
48
|
+
* Maximum number of retry attempts.
|
|
49
|
+
*
|
|
49
50
|
* If not provided, the default implementation will be used.
|
|
50
51
|
*/
|
|
51
|
-
readonly
|
|
52
|
+
readonly maxRetries?: number;
|
|
52
53
|
|
|
53
54
|
/**
|
|
54
55
|
* Function to determine if the error should be retried.
|
|
56
|
+
*
|
|
55
57
|
* If not provided, the default implementation will be used.
|
|
56
58
|
*/
|
|
57
59
|
readonly canRetryError?: (error: CoreSdkError) => boolean;
|
|
58
60
|
|
|
59
61
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* indicate the time to wait before retrying the request.
|
|
62
|
+
* Function to determine the delay between requests in milliseconds.
|
|
63
|
+
*
|
|
64
|
+
* If not provided, the default implementation will be used.
|
|
64
65
|
*/
|
|
65
|
-
readonly
|
|
66
|
+
readonly getDelayBetweenRetriesMs?: (error: CoreSdkError) => number;
|
|
66
67
|
|
|
67
68
|
/**
|
|
68
69
|
* Whether to log the retry attempt.
|
|
70
|
+
*
|
|
69
71
|
* If false, the retry attempt will not be logged.
|
|
70
72
|
* If undefined, the default implementation will be used.
|
|
71
73
|
* Otherwise, the function will be called with the retry attempt and url.
|
|
@@ -1,9 +1,44 @@
|
|
|
1
1
|
import type { AdapterResponse, HttpServiceStatus } from "../http/http.models.js";
|
|
2
2
|
import type { KontentErrorResponseData, RetryStrategyOptions } from "./core.models.js";
|
|
3
3
|
|
|
4
|
-
export type
|
|
4
|
+
export type ErrorReason = "invalidResponse" | "invalidUrl" | "unknown" | "invalidBody" | "notFound";
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type CoreSdkErrorDetails<TReason extends ErrorReason = ErrorReason> = (
|
|
7
|
+
| Details<
|
|
8
|
+
"invalidResponse",
|
|
9
|
+
{
|
|
10
|
+
readonly kontentErrorResponse: KontentErrorResponseData | undefined;
|
|
11
|
+
} & Pick<AdapterResponse<HttpServiceStatus>, "isValidResponse" | "responseHeaders" | "status" | "statusText">
|
|
12
|
+
>
|
|
13
|
+
| Details<
|
|
14
|
+
"notFound",
|
|
15
|
+
{
|
|
16
|
+
readonly kontentErrorResponse: KontentErrorResponseData | undefined;
|
|
17
|
+
} & Pick<AdapterResponse<404>, "isValidResponse" | "responseHeaders" | "status" | "statusText">
|
|
18
|
+
>
|
|
19
|
+
| Details<
|
|
20
|
+
"invalidBody",
|
|
21
|
+
{
|
|
22
|
+
readonly error: unknown;
|
|
23
|
+
}
|
|
24
|
+
>
|
|
25
|
+
| Details<
|
|
26
|
+
"invalidUrl",
|
|
27
|
+
{
|
|
28
|
+
readonly error: unknown;
|
|
29
|
+
}
|
|
30
|
+
>
|
|
31
|
+
| Details<
|
|
32
|
+
"unknown",
|
|
33
|
+
{
|
|
34
|
+
readonly error: unknown;
|
|
35
|
+
}
|
|
36
|
+
>
|
|
37
|
+
) & {
|
|
38
|
+
readonly reason: TReason;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type CoreSdkError<TReason extends ErrorReason = ErrorReason> = {
|
|
7
42
|
/**
|
|
8
43
|
* The message of the error
|
|
9
44
|
*/
|
|
@@ -15,7 +50,7 @@ export type CoreSdkError = {
|
|
|
15
50
|
readonly url: string;
|
|
16
51
|
|
|
17
52
|
/**
|
|
18
|
-
*
|
|
53
|
+
* Used retry strategy.
|
|
19
54
|
*/
|
|
20
55
|
readonly retryStrategyOptions?: Required<RetryStrategyOptions>;
|
|
21
56
|
|
|
@@ -23,37 +58,8 @@ export type CoreSdkError = {
|
|
|
23
58
|
* The number of times the request has been retried.
|
|
24
59
|
*/
|
|
25
60
|
readonly retryAttempt?: number;
|
|
61
|
+
} & CoreSdkErrorDetails<TReason>;
|
|
26
62
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*/
|
|
30
|
-
readonly details:
|
|
31
|
-
| SdkErrorDetails<
|
|
32
|
-
"invalidResponse",
|
|
33
|
-
{
|
|
34
|
-
readonly kontentErrorResponse: KontentErrorResponseData | undefined;
|
|
35
|
-
} & Pick<AdapterResponse<HttpServiceStatus>, "isValidResponse" | "responseHeaders" | "status" | "statusText">
|
|
36
|
-
>
|
|
37
|
-
| SdkErrorDetails<
|
|
38
|
-
"invalidBody",
|
|
39
|
-
{
|
|
40
|
-
readonly error: unknown;
|
|
41
|
-
}
|
|
42
|
-
>
|
|
43
|
-
| SdkErrorDetails<
|
|
44
|
-
"invalidUrl",
|
|
45
|
-
{
|
|
46
|
-
readonly error: unknown;
|
|
47
|
-
}
|
|
48
|
-
>
|
|
49
|
-
| SdkErrorDetails<
|
|
50
|
-
"unknown",
|
|
51
|
-
{
|
|
52
|
-
readonly error: unknown;
|
|
53
|
-
}
|
|
54
|
-
>;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
type SdkErrorDetails<TType extends ErrorType, TDetails> = {
|
|
58
|
-
readonly type: TType;
|
|
63
|
+
type Details<TReason extends ErrorReason, TDetails> = {
|
|
64
|
+
readonly reason: TReason;
|
|
59
65
|
} & TDetails;
|
package/lib/public_api.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { getDefaultHttpService } from "./http/http.service.js";
|
|
|
4
4
|
export { getSdkIdHeader } from "./utils/header.utils.js";
|
|
5
5
|
export { toRequiredRetryStrategyOptions } from "./utils/retry.utils.js";
|
|
6
6
|
export { tryCatch, tryCatchAsync } from "./utils/try.utils.js";
|
|
7
|
+
export { isKontent404Error } from "./utils/error.utils.js";
|
|
7
8
|
|
|
8
9
|
// Types
|
|
9
10
|
export type {
|
|
@@ -26,7 +27,8 @@ export type {
|
|
|
26
27
|
} from "./models/core.models.js";
|
|
27
28
|
export type {
|
|
28
29
|
CoreSdkError,
|
|
29
|
-
|
|
30
|
+
ErrorReason,
|
|
31
|
+
CoreSdkErrorDetails,
|
|
30
32
|
} from "./models/error.models.js";
|
|
31
33
|
export type { JsonArray, JsonObject, JsonValue } from "./models/json.models.js";
|
|
32
34
|
export type { EmptyObject, Override, Prettify } from "./models/utility.models.js";
|
package/lib/utils/error.utils.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { AdapterResponse } from "../http/http.models.js";
|
|
2
2
|
import type { HttpMethod, KontentErrorResponseData, KontentValidationError } from "../models/core.models.js";
|
|
3
|
+
import type { CoreSdkError, ErrorReason } from "../models/error.models.js";
|
|
3
4
|
import { isNotUndefined } from "./core.utils.js";
|
|
4
5
|
|
|
5
|
-
export function
|
|
6
|
+
export function isKontent404Error(error: CoreSdkError): error is CoreSdkError<"invalidResponse"> {
|
|
7
|
+
return isErrorOfType("invalidResponse", error) && error.status === 404;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getErrorMessage({
|
|
6
11
|
method,
|
|
7
12
|
url,
|
|
8
13
|
adapterResponse,
|
|
@@ -13,8 +18,12 @@ export function getDefaultErrorMessage({
|
|
|
13
18
|
readonly adapterResponse: AdapterResponse;
|
|
14
19
|
readonly kontentErrorResponse?: KontentErrorResponseData;
|
|
15
20
|
}): string {
|
|
16
|
-
const
|
|
17
|
-
return `Failed to execute '${method}' request '${url}'.${
|
|
21
|
+
const details = kontentErrorResponse ? getKontentErrorResponseMessage(adapterResponse, kontentErrorResponse) : undefined;
|
|
22
|
+
return `Failed to execute '${method}' request '${url}'.${details ? ` ${details}` : ""}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isErrorOfType<TReason extends ErrorReason>(reason: TReason, error: CoreSdkError): error is CoreSdkError<TReason> {
|
|
26
|
+
return error.reason === reason;
|
|
18
27
|
}
|
|
19
28
|
|
|
20
29
|
function getValidationErrorMessage(validationErrors?: readonly KontentValidationError[]): string | undefined {
|
|
@@ -33,11 +42,7 @@ function getValidationErrorMessage(validationErrors?: readonly KontentValidation
|
|
|
33
42
|
.join(", ");
|
|
34
43
|
}
|
|
35
44
|
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return `Response failed with status '${adapterResponse.status}' and status text '${adapterResponse.statusText}'.${kontentErrorResponse.message}${validationErrorMessage ? ` ${validationErrorMessage}` : ""}`;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return undefined;
|
|
45
|
+
function getKontentErrorResponseMessage(adapterResponse: AdapterResponse, kontentErrorResponse: KontentErrorResponseData): string {
|
|
46
|
+
const validationErrorMessage = getValidationErrorMessage(kontentErrorResponse.validation_errors);
|
|
47
|
+
return `Response failed with status '${adapterResponse.status}' and status text '${adapterResponse.statusText}'.${kontentErrorResponse.message}${validationErrorMessage ? ` ${validationErrorMessage}` : ""}`;
|
|
43
48
|
}
|
|
@@ -14,7 +14,13 @@ export function getRetryAfterHeaderValue(headers: readonly Header[]): number | u
|
|
|
14
14
|
return undefined;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const numberValue = +retryAfterHeader.value;
|
|
18
|
+
|
|
19
|
+
if (!Number.isSafeInteger(numberValue)) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return numberValue;
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
export function toSdkHeaders(headers: Headers): readonly Header[] {
|
package/lib/utils/retry.utils.ts
CHANGED
|
@@ -13,16 +13,22 @@ type RetryResult =
|
|
|
13
13
|
readonly retryInMs: number;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
const
|
|
17
|
-
const
|
|
16
|
+
const defaultMaxRetries: NonNullable<RetryStrategyOptions["maxRetries"]> = 3;
|
|
17
|
+
const getDefaultDelayBetweenRetriesMs: NonNullable<RetryStrategyOptions["getDelayBetweenRetriesMs"]> = (error) => {
|
|
18
|
+
if (error.reason === "notFound" || error.reason === "invalidResponse") {
|
|
19
|
+
return getRetryFromHeaderMs({ error });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return 0;
|
|
23
|
+
};
|
|
18
24
|
const defaultCanRetryError: NonNullable<RetryStrategyOptions["canRetryError"]> = (error) => {
|
|
19
|
-
if (error.
|
|
20
|
-
if (error.
|
|
25
|
+
if (error.reason === "invalidResponse") {
|
|
26
|
+
if (error.kontentErrorResponse) {
|
|
21
27
|
// The request is clearly invalid as we got an error response from the API
|
|
22
28
|
return false;
|
|
23
29
|
}
|
|
24
30
|
|
|
25
|
-
return error.
|
|
31
|
+
return error.status >= 500 || error.status === 429;
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
return true;
|
|
@@ -36,12 +42,12 @@ export async function runWithRetryAsync<TResponse extends JsonValue | Blob, TBod
|
|
|
36
42
|
readonly requestHeaders: readonly Header[];
|
|
37
43
|
readonly method: HttpMethod;
|
|
38
44
|
}): Promise<HttpResponse<TResponse, TBodyData>> {
|
|
39
|
-
const { success,
|
|
45
|
+
const { success, response, error } = await data.funcAsync();
|
|
40
46
|
|
|
41
47
|
if (success) {
|
|
42
48
|
return {
|
|
43
49
|
success: true,
|
|
44
|
-
|
|
50
|
+
response,
|
|
45
51
|
};
|
|
46
52
|
}
|
|
47
53
|
|
|
@@ -79,12 +85,12 @@ export async function runWithRetryAsync<TResponse extends JsonValue | Blob, TBod
|
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
export function toRequiredRetryStrategyOptions(options?: RetryStrategyOptions): Required<RetryStrategyOptions> {
|
|
82
|
-
const
|
|
88
|
+
const maxRetries: number = options?.maxRetries ?? defaultMaxRetries;
|
|
83
89
|
|
|
84
90
|
return {
|
|
85
|
-
|
|
91
|
+
maxRetries: maxRetries,
|
|
86
92
|
canRetryError: options?.canRetryError ?? defaultCanRetryError,
|
|
87
|
-
|
|
93
|
+
getDelayBetweenRetriesMs: options?.getDelayBetweenRetriesMs ?? getDefaultDelayBetweenRetriesMs,
|
|
88
94
|
logRetryAttempt:
|
|
89
95
|
options?.logRetryAttempt === false
|
|
90
96
|
? false
|
|
@@ -92,14 +98,14 @@ export function toRequiredRetryStrategyOptions(options?: RetryStrategyOptions):
|
|
|
92
98
|
if (options?.logRetryAttempt) {
|
|
93
99
|
options.logRetryAttempt(attempt, url);
|
|
94
100
|
} else {
|
|
95
|
-
console.warn(getDefaultRetryAttemptLogMessage(attempt,
|
|
101
|
+
console.warn(getDefaultRetryAttemptLogMessage(attempt, maxRetries, url));
|
|
96
102
|
}
|
|
97
103
|
},
|
|
98
104
|
};
|
|
99
105
|
}
|
|
100
106
|
|
|
101
|
-
export function getDefaultRetryAttemptLogMessage(retryAttempt: number,
|
|
102
|
-
return `Retry attempt '${retryAttempt}' from a maximum of '${
|
|
107
|
+
export function getDefaultRetryAttemptLogMessage(retryAttempt: number, maxRetries: number, url: string): string {
|
|
108
|
+
return `Retry attempt '${retryAttempt}' from a maximum of '${maxRetries}' retries. Requested url: '${url}'`;
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
function logRetryAttempt(opts: Pick<RetryStrategyOptions, "logRetryAttempt">, retryAttempt: number, url: string): void {
|
|
@@ -121,7 +127,7 @@ function getRetryResult({
|
|
|
121
127
|
readonly error: CoreSdkError;
|
|
122
128
|
readonly options: Required<RetryStrategyOptions>;
|
|
123
129
|
}): RetryResult {
|
|
124
|
-
if (retryAttempt >= options.
|
|
130
|
+
if (retryAttempt >= options.maxRetries) {
|
|
125
131
|
return {
|
|
126
132
|
canRetry: false,
|
|
127
133
|
};
|
|
@@ -133,27 +139,18 @@ function getRetryResult({
|
|
|
133
139
|
};
|
|
134
140
|
}
|
|
135
141
|
|
|
136
|
-
return
|
|
142
|
+
return {
|
|
143
|
+
canRetry: true,
|
|
144
|
+
retryInMs: options.getDelayBetweenRetriesMs(error),
|
|
145
|
+
};
|
|
137
146
|
}
|
|
138
147
|
|
|
139
|
-
function
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
canRetry: false,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const retryAfterHeaderValue = getRetryAfterHeaderValue(error.details.responseHeaders);
|
|
148
|
+
function getRetryFromHeaderMs({ error }: { readonly error: CoreSdkError<"invalidResponse" | "notFound"> }): number {
|
|
149
|
+
const retryAfterHeaderValue = getRetryAfterHeaderValue(error.responseHeaders);
|
|
147
150
|
|
|
148
151
|
if (retryAfterHeaderValue) {
|
|
149
|
-
return
|
|
150
|
-
canRetry: true,
|
|
151
|
-
retryInMs: retryAfterHeaderValue * 1000,
|
|
152
|
-
};
|
|
152
|
+
return retryAfterHeaderValue * 1000;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
return
|
|
156
|
-
canRetry: true,
|
|
157
|
-
retryInMs: options.defaultDelayBetweenRequestsMs,
|
|
158
|
-
};
|
|
155
|
+
return 0;
|
|
159
156
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kontent-ai/core-sdk",
|
|
3
|
-
"version": "11.0.0
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/kontent-ai/kontent-core-js"
|
|
@@ -25,13 +25,8 @@
|
|
|
25
25
|
},
|
|
26
26
|
"type": "module",
|
|
27
27
|
"scripts": {
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"release:beta": "standard-version --prerelease",
|
|
31
|
-
"release:beta:major": "standard-version --prerelease --release-as major",
|
|
32
|
-
"prepublishOnly": "npm run build && npm run push:tags",
|
|
33
|
-
"publish:beta": "npm publish --tag=next",
|
|
34
|
-
"build": "npm run biome:check && npm run eslint && npm run clean && tsc --p tsconfig.build.json && npm run update:version",
|
|
28
|
+
"prepublishOnly": "npm run build",
|
|
29
|
+
"build": "npm run biome:check && npm run eslint && npm run clean && tsc --p tsconfig.build.json && npm run update:version",
|
|
35
30
|
"test": "npm run test:unit && npm run test:integration",
|
|
36
31
|
"test:unit": "vitest run --config=vitest-unit.config.ts",
|
|
37
32
|
"test:integration": "vitest run --config=vitest-integration.config.ts",
|
|
@@ -40,7 +35,6 @@
|
|
|
40
35
|
"biome:fix": "biome check --write",
|
|
41
36
|
"biome:fix:unsafe": "biome check --write --unsafe",
|
|
42
37
|
"clean": "tsx scripts/clean.ts",
|
|
43
|
-
"push:tags": "git push --tags",
|
|
44
38
|
"update:version": "tsx ./scripts/update-version.ts"
|
|
45
39
|
},
|
|
46
40
|
"devDependencies": {
|
|
@@ -51,7 +45,6 @@
|
|
|
51
45
|
"@biomejs/biome": "1.9.4",
|
|
52
46
|
"@types/node": "22.15.29",
|
|
53
47
|
"chalk": "5.4.1",
|
|
54
|
-
"standard-version": "9.5.0",
|
|
55
48
|
"typescript": "5.8.3",
|
|
56
49
|
"vitest": "3.2.1",
|
|
57
50
|
"dotenv-cli": "8.0.0",
|