@flowcore/sdk 1.4.5 → 1.5.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/CHANGELOG.md +14 -0
- package/README.md +12 -0
- package/esm/common/flowcore-client.d.ts +12 -0
- package/esm/common/flowcore-client.d.ts.map +1 -1
- package/esm/common/flowcore-client.js +44 -10
- package/package.json +1 -1
- package/script/common/flowcore-client.d.ts +12 -0
- package/script/common/flowcore-client.d.ts.map +1 -1
- package/script/common/flowcore-client.js +44 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.5.0](https://github.com/flowcore-io/flowcore-sdk/compare/v1.4.5...v1.5.0) (2024-12-19)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add retry to client ([b202c56](https://github.com/flowcore-io/flowcore-sdk/commit/b202c5660f42a02bbd45db043d48713effe658a6))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* update readme ([bf233bc](https://github.com/flowcore-io/flowcore-sdk/commit/bf233bc27b15892b5813c2121b7221d08c7b7d63))
|
|
14
|
+
* update readme ([3ffbe49](https://github.com/flowcore-io/flowcore-sdk/commit/3ffbe499e6014e64a8c420eead2763539cb5412c))
|
|
15
|
+
* use retryable status codes ([89a8919](https://github.com/flowcore-io/flowcore-sdk/commit/89a8919492c55614851779ff77ddc3f7fcde51e0))
|
|
16
|
+
|
|
3
17
|
## [1.4.5](https://github.com/flowcore-io/flowcore-sdk/compare/v1.4.4...v1.4.5) (2024-12-19)
|
|
4
18
|
|
|
5
19
|
|
package/README.md
CHANGED
|
@@ -32,6 +32,18 @@ const client = new FlowcoreClient({
|
|
|
32
32
|
apiKey: "my-api-key",
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
+
// With retry
|
|
36
|
+
// NOTE! When retry is not set it will default to 250ms delay and 3 max retries.
|
|
37
|
+
// To disable retry set retry to null.
|
|
38
|
+
const client = new FlowcoreClient({
|
|
39
|
+
apiKeyId: "my-api-key-id",
|
|
40
|
+
apiKey: "my-api-key",
|
|
41
|
+
retry: {
|
|
42
|
+
delay: 100,
|
|
43
|
+
maxRetries: 5,
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
|
|
35
47
|
// Execute a command
|
|
36
48
|
const command = new DataCoreFetchCommand({
|
|
37
49
|
dataCoreId: "my-data-core-id",
|
|
@@ -6,6 +6,10 @@ interface ClientOptionsBearer {
|
|
|
6
6
|
getBearerToken: () => Promise<string | null> | string | null;
|
|
7
7
|
apiKeyId?: never;
|
|
8
8
|
apiKey?: never;
|
|
9
|
+
retry?: {
|
|
10
|
+
delay: number;
|
|
11
|
+
maxRetries: number;
|
|
12
|
+
} | null;
|
|
9
13
|
}
|
|
10
14
|
/**
|
|
11
15
|
* The options for the api key
|
|
@@ -14,6 +18,10 @@ interface ClientOptionsApiKey {
|
|
|
14
18
|
apiKeyId: string;
|
|
15
19
|
apiKey: string;
|
|
16
20
|
getBearerToken?: never;
|
|
21
|
+
retry?: {
|
|
22
|
+
delay: number;
|
|
23
|
+
maxRetries: number;
|
|
24
|
+
} | null;
|
|
17
25
|
}
|
|
18
26
|
/**
|
|
19
27
|
* The options for the client
|
|
@@ -30,6 +38,10 @@ export declare class FlowcoreClient {
|
|
|
30
38
|
* Get the auth header
|
|
31
39
|
*/
|
|
32
40
|
private getAuthHeader;
|
|
41
|
+
/**
|
|
42
|
+
* Execute a command (inner method)
|
|
43
|
+
*/
|
|
44
|
+
private innerExecute;
|
|
33
45
|
/**
|
|
34
46
|
* Execute a command
|
|
35
47
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flowcore-client.d.ts","sourceRoot":"","sources":["../../src/common/flowcore-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"flowcore-client.d.ts","sourceRoot":"","sources":["../../src/common/flowcore-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAI3C;;GAEG;AACH,UAAU,mBAAmB;IAC3B,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAA;IAC5D,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;KACnB,GAAG,IAAI,CAAA;CACT;AAED;;GAEG;AACH,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE,KAAK,CAAA;IACtB,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;KACnB,GAAG,IAAI,CAAA;CACT;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAAG,mBAAmB,CAAA;AAErE;;GAEG;AACH,qBAAa,cAAc;IAEb,OAAO,CAAC,QAAQ,CAAC,OAAO;IADpC,OAAO,CAAC,IAAI,CAAqB;gBACJ,OAAO,EAAE,aAAa;IAiBnD;;OAEG;YACW,aAAa;IAc3B;;OAEG;YACW,YAAY;IAyD1B;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;CAGzE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ClientError } from "../exceptions/client-error.js";
|
|
2
2
|
import { CommandError } from "../exceptions/command-error.js";
|
|
3
|
+
const RETRYABLE_ERROR_CODES = [408, 429, 500, 502, 503, 504];
|
|
3
4
|
/**
|
|
4
5
|
* A base client for executing commands
|
|
5
6
|
*/
|
|
@@ -26,6 +27,12 @@ export class FlowcoreClient {
|
|
|
26
27
|
else {
|
|
27
28
|
throw new Error("Invalid client options");
|
|
28
29
|
}
|
|
30
|
+
if (this.options.retry === undefined) {
|
|
31
|
+
this.options.retry = {
|
|
32
|
+
delay: 250,
|
|
33
|
+
maxRetries: 3,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
29
36
|
}
|
|
30
37
|
/**
|
|
31
38
|
* Get the auth header
|
|
@@ -44,23 +51,44 @@ export class FlowcoreClient {
|
|
|
44
51
|
return null;
|
|
45
52
|
}
|
|
46
53
|
/**
|
|
47
|
-
* Execute a command
|
|
54
|
+
* Execute a command (inner method)
|
|
48
55
|
*/
|
|
49
|
-
async
|
|
56
|
+
async innerExecute(command, retryCount = 0) {
|
|
50
57
|
const request = await command.getRequest(this);
|
|
51
58
|
if (!request.allowedModes.includes(this.mode)) {
|
|
52
59
|
throw new CommandError(command.constructor.name, `Not allowed in "${this.mode}" mode`);
|
|
53
60
|
}
|
|
54
61
|
const authHeader = await this.getAuthHeader();
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
let response;
|
|
63
|
+
try {
|
|
64
|
+
response = await fetch(request.baseUrl + request.path, {
|
|
65
|
+
method: request.method,
|
|
66
|
+
headers: {
|
|
67
|
+
...request.headers,
|
|
68
|
+
...(authHeader ? { Authorization: authHeader } : {}),
|
|
69
|
+
},
|
|
70
|
+
body: request.body,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (this.options.retry && retryCount < this.options.retry.maxRetries) {
|
|
75
|
+
const delay = this.options.retry.delay;
|
|
76
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
77
|
+
return this.innerExecute(command, retryCount + 1);
|
|
78
|
+
}
|
|
79
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
80
|
+
throw new ClientError(`Failed to execute command: ${message}`, 0, {
|
|
81
|
+
command: command.constructor.name,
|
|
82
|
+
error: error,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
63
85
|
if (!response.ok) {
|
|
86
|
+
if (this.options.retry && RETRYABLE_ERROR_CODES.includes(response.status) &&
|
|
87
|
+
retryCount < this.options.retry.maxRetries) {
|
|
88
|
+
const delay = this.options.retry.delay;
|
|
89
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
90
|
+
return this.innerExecute(command, retryCount + 1);
|
|
91
|
+
}
|
|
64
92
|
const body = await response.json().catch(() => undefined);
|
|
65
93
|
const commandName = command.constructor.name;
|
|
66
94
|
throw new ClientError(`${commandName} failed with ${response.status}: ${response.statusText}`, response.status, body);
|
|
@@ -69,4 +97,10 @@ export class FlowcoreClient {
|
|
|
69
97
|
const parsedBody = await request.parseResponse(body, this);
|
|
70
98
|
return request.waitForResponse(this, parsedBody);
|
|
71
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Execute a command
|
|
102
|
+
*/
|
|
103
|
+
execute(command) {
|
|
104
|
+
return this.innerExecute(command, 0);
|
|
105
|
+
}
|
|
72
106
|
}
|
package/package.json
CHANGED
|
@@ -6,6 +6,10 @@ interface ClientOptionsBearer {
|
|
|
6
6
|
getBearerToken: () => Promise<string | null> | string | null;
|
|
7
7
|
apiKeyId?: never;
|
|
8
8
|
apiKey?: never;
|
|
9
|
+
retry?: {
|
|
10
|
+
delay: number;
|
|
11
|
+
maxRetries: number;
|
|
12
|
+
} | null;
|
|
9
13
|
}
|
|
10
14
|
/**
|
|
11
15
|
* The options for the api key
|
|
@@ -14,6 +18,10 @@ interface ClientOptionsApiKey {
|
|
|
14
18
|
apiKeyId: string;
|
|
15
19
|
apiKey: string;
|
|
16
20
|
getBearerToken?: never;
|
|
21
|
+
retry?: {
|
|
22
|
+
delay: number;
|
|
23
|
+
maxRetries: number;
|
|
24
|
+
} | null;
|
|
17
25
|
}
|
|
18
26
|
/**
|
|
19
27
|
* The options for the client
|
|
@@ -30,6 +38,10 @@ export declare class FlowcoreClient {
|
|
|
30
38
|
* Get the auth header
|
|
31
39
|
*/
|
|
32
40
|
private getAuthHeader;
|
|
41
|
+
/**
|
|
42
|
+
* Execute a command (inner method)
|
|
43
|
+
*/
|
|
44
|
+
private innerExecute;
|
|
33
45
|
/**
|
|
34
46
|
* Execute a command
|
|
35
47
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flowcore-client.d.ts","sourceRoot":"","sources":["../../src/common/flowcore-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"flowcore-client.d.ts","sourceRoot":"","sources":["../../src/common/flowcore-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAI3C;;GAEG;AACH,UAAU,mBAAmB;IAC3B,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAA;IAC5D,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;KACnB,GAAG,IAAI,CAAA;CACT;AAED;;GAEG;AACH,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE,KAAK,CAAA;IACtB,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;KACnB,GAAG,IAAI,CAAA;CACT;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAAG,mBAAmB,CAAA;AAErE;;GAEG;AACH,qBAAa,cAAc;IAEb,OAAO,CAAC,QAAQ,CAAC,OAAO;IADpC,OAAO,CAAC,IAAI,CAAqB;gBACJ,OAAO,EAAE,aAAa;IAiBnD;;OAEG;YACW,aAAa;IAc3B;;OAEG;YACW,YAAY;IAyD1B;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;CAGzE"}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.FlowcoreClient = void 0;
|
|
4
4
|
const client_error_js_1 = require("../exceptions/client-error.js");
|
|
5
5
|
const command_error_js_1 = require("../exceptions/command-error.js");
|
|
6
|
+
const RETRYABLE_ERROR_CODES = [408, 429, 500, 502, 503, 504];
|
|
6
7
|
/**
|
|
7
8
|
* A base client for executing commands
|
|
8
9
|
*/
|
|
@@ -29,6 +30,12 @@ class FlowcoreClient {
|
|
|
29
30
|
else {
|
|
30
31
|
throw new Error("Invalid client options");
|
|
31
32
|
}
|
|
33
|
+
if (this.options.retry === undefined) {
|
|
34
|
+
this.options.retry = {
|
|
35
|
+
delay: 250,
|
|
36
|
+
maxRetries: 3,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
32
39
|
}
|
|
33
40
|
/**
|
|
34
41
|
* Get the auth header
|
|
@@ -47,23 +54,44 @@ class FlowcoreClient {
|
|
|
47
54
|
return null;
|
|
48
55
|
}
|
|
49
56
|
/**
|
|
50
|
-
* Execute a command
|
|
57
|
+
* Execute a command (inner method)
|
|
51
58
|
*/
|
|
52
|
-
async
|
|
59
|
+
async innerExecute(command, retryCount = 0) {
|
|
53
60
|
const request = await command.getRequest(this);
|
|
54
61
|
if (!request.allowedModes.includes(this.mode)) {
|
|
55
62
|
throw new command_error_js_1.CommandError(command.constructor.name, `Not allowed in "${this.mode}" mode`);
|
|
56
63
|
}
|
|
57
64
|
const authHeader = await this.getAuthHeader();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
let response;
|
|
66
|
+
try {
|
|
67
|
+
response = await fetch(request.baseUrl + request.path, {
|
|
68
|
+
method: request.method,
|
|
69
|
+
headers: {
|
|
70
|
+
...request.headers,
|
|
71
|
+
...(authHeader ? { Authorization: authHeader } : {}),
|
|
72
|
+
},
|
|
73
|
+
body: request.body,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
if (this.options.retry && retryCount < this.options.retry.maxRetries) {
|
|
78
|
+
const delay = this.options.retry.delay;
|
|
79
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
80
|
+
return this.innerExecute(command, retryCount + 1);
|
|
81
|
+
}
|
|
82
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
83
|
+
throw new client_error_js_1.ClientError(`Failed to execute command: ${message}`, 0, {
|
|
84
|
+
command: command.constructor.name,
|
|
85
|
+
error: error,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
66
88
|
if (!response.ok) {
|
|
89
|
+
if (this.options.retry && RETRYABLE_ERROR_CODES.includes(response.status) &&
|
|
90
|
+
retryCount < this.options.retry.maxRetries) {
|
|
91
|
+
const delay = this.options.retry.delay;
|
|
92
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
93
|
+
return this.innerExecute(command, retryCount + 1);
|
|
94
|
+
}
|
|
67
95
|
const body = await response.json().catch(() => undefined);
|
|
68
96
|
const commandName = command.constructor.name;
|
|
69
97
|
throw new client_error_js_1.ClientError(`${commandName} failed with ${response.status}: ${response.statusText}`, response.status, body);
|
|
@@ -72,5 +100,11 @@ class FlowcoreClient {
|
|
|
72
100
|
const parsedBody = await request.parseResponse(body, this);
|
|
73
101
|
return request.waitForResponse(this, parsedBody);
|
|
74
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Execute a command
|
|
105
|
+
*/
|
|
106
|
+
execute(command) {
|
|
107
|
+
return this.innerExecute(command, 0);
|
|
108
|
+
}
|
|
75
109
|
}
|
|
76
110
|
exports.FlowcoreClient = FlowcoreClient;
|