@scaleway/sdk-client 2.2.1 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.js +2 -0
- package/dist/bridge.js +8 -0
- package/dist/helpers/__tests__/is-browser.browser.test.js +10 -0
- package/dist/helpers/__tests__/is-browser.node.test.js +10 -0
- package/dist/helpers/__tests__/json.test.js +48 -0
- package/dist/helpers/__tests__/marshalling.test.js +177 -0
- package/dist/helpers/is-browser.js +3 -1
- package/dist/helpers/is-response.js +3 -1
- package/dist/helpers/json.js +10 -4
- package/dist/helpers/marshalling.js +7 -5
- package/dist/index.js +4 -4
- package/dist/internal/async/__tests__/interval-retrier.test.js +121 -0
- package/dist/internal/async/__tests__/sleep.test.js +19 -0
- package/dist/internal/async/interval-retrier.d.ts +1 -1
- package/dist/internal/async/interval-retrier.js +33 -3
- package/dist/internal/async/sleep.js +3 -1
- package/dist/internal/interceptors/__tests__/composer.test.js +48 -0
- package/dist/internal/interceptors/__tests__/helpers.test.js +27 -0
- package/dist/internal/interceptors/composer.js +5 -3
- package/dist/internal/interceptors/helpers.js +4 -2
- package/dist/internal/interceptors/types.js +0 -0
- package/dist/internal/logger/__tests__/index.test.js +209 -0
- package/dist/internal/logger/console-logger.js +2 -0
- package/dist/internal/logger/index.js +5 -3
- package/dist/internal/logger/level-resolver.js +4 -2
- package/dist/internal/logger/logger.js +0 -0
- package/dist/internal/validations/__tests__/string-validation.test.js +98 -0
- package/dist/internal/validations/string-validation.js +14 -9
- package/dist/internals.js +9 -8
- package/dist/package.js +2 -1
- package/dist/scw/__tests__/api.test.js +19 -0
- package/dist/scw/__tests__/auth.test.js +57 -0
- package/dist/scw/__tests__/client-ini-factory.test.js +220 -0
- package/dist/scw/__tests__/client-ini-profile.test.js +70 -0
- package/dist/scw/__tests__/client-settings.test.js +51 -0
- package/dist/scw/__tests__/client.test.js +59 -0
- package/dist/scw/__tests__/custom-marshalling.test.js +168 -0
- package/dist/scw/api.js +2 -0
- package/dist/scw/auth.js +17 -6
- package/dist/scw/client-ini-factory.js +9 -7
- package/dist/scw/client-ini-profile.js +3 -1
- package/dist/scw/client-settings.js +3 -1
- package/dist/scw/client.js +4 -2
- package/dist/scw/constants.js +6 -4
- package/dist/scw/custom-marshalling.js +17 -15
- package/dist/scw/custom-types.js +2 -0
- package/dist/scw/errors/__tests__/scw-error.test.js +41 -0
- package/dist/scw/errors/__tests__/types.test.js +16 -0
- package/dist/scw/errors/error-parser.js +3 -1
- package/dist/scw/errors/non-standard/__tests__/index.test.js +123 -0
- package/dist/scw/errors/non-standard/invalid-request-mapper.js +3 -1
- package/dist/scw/errors/non-standard/unknown-resource-mapper.js +3 -1
- package/dist/scw/errors/scw-error-from-json.js +0 -0
- package/dist/scw/errors/scw-error.js +2 -0
- package/dist/scw/errors/standard/__tests__/index.test.js +329 -0
- package/dist/scw/errors/standard/already-exists-error.js +2 -0
- package/dist/scw/errors/standard/denied-authentication-error.js +2 -0
- package/dist/scw/errors/standard/index.js +3 -1
- package/dist/scw/errors/standard/invalid-arguments-error.js +2 -0
- package/dist/scw/errors/standard/out-of-stock-error.js +2 -0
- package/dist/scw/errors/standard/permissions-denied-error.js +2 -0
- package/dist/scw/errors/standard/precondition-failed-error.js +2 -0
- package/dist/scw/errors/standard/quotas-exceeded-error.js +2 -0
- package/dist/scw/errors/standard/resource-expired-error.js +2 -0
- package/dist/scw/errors/standard/resource-locked-error.js +2 -0
- package/dist/scw/errors/standard/resource-not-found-error.js +2 -0
- package/dist/scw/errors/standard/too-many-requests-error.js +2 -0
- package/dist/scw/errors/standard/transient-state-error.js +2 -0
- package/dist/scw/errors/types.js +3 -1
- package/dist/scw/fetch/__tests__/build-fetcher.test.js +114 -0
- package/dist/scw/fetch/__tests__/http-dumper.test.js +45 -0
- package/dist/scw/fetch/__tests__/http-interceptors.test.js +60 -0
- package/dist/scw/fetch/__tests__/resource-paginator.test.js +110 -0
- package/dist/scw/fetch/__tests__/response-parser.test.js +94 -0
- package/dist/scw/fetch/build-fetcher.js +6 -4
- package/dist/scw/fetch/http-dumper.js +4 -2
- package/dist/scw/fetch/http-interceptors.js +5 -3
- package/dist/scw/fetch/resource-paginator.js +6 -4
- package/dist/scw/fetch/response-parser.js +5 -3
- package/dist/scw/fetch/types.js +0 -0
- package/dist/scw/locality.js +2 -0
- package/dist/vendor/base64/index.d.js +0 -0
- package/dist/vendor/base64/index.js +2 -0
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __exportAll = (all, no_symbols) => {
|
|
3
4
|
let target = {};
|
|
@@ -8,4 +9,5 @@ var __exportAll = (all, no_symbols) => {
|
|
|
8
9
|
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
9
10
|
return target;
|
|
10
11
|
};
|
|
12
|
+
//#endregion
|
|
11
13
|
export { __exportAll };
|
package/dist/bridge.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { isJSONObject } from "./helpers/json.js";
|
|
2
|
+
import { resolveOneOf, unmarshalArrayOfObject, unmarshalDate, unmarshalMapOfObject, urlParams, validatePathParam } from "./helpers/marshalling.js";
|
|
3
|
+
import { waitForResource } from "./internal/async/interval-retrier.js";
|
|
4
|
+
import { API } from "./scw/api.js";
|
|
5
|
+
import { Decimal } from "./scw/custom-types.js";
|
|
6
|
+
import { marshalBlobToScwFile, marshalDecimal, marshalMoney, marshalScwFile, marshalTimeSeries, unmarshalDecimal, unmarshalMoney, unmarshalScwFile, unmarshalServiceInfo, unmarshalTimeSeries, unmarshalTimeSeriesPoint } from "./scw/custom-marshalling.js";
|
|
7
|
+
import { enrichForPagination } from "./scw/fetch/resource-paginator.js";
|
|
8
|
+
export { API, Decimal, enrichForPagination, isJSONObject, marshalBlobToScwFile, marshalDecimal, marshalMoney, marshalScwFile, marshalTimeSeries, resolveOneOf, unmarshalArrayOfObject, unmarshalDate, unmarshalDecimal, unmarshalMapOfObject, unmarshalMoney, unmarshalScwFile, unmarshalServiceInfo, unmarshalTimeSeries, unmarshalTimeSeriesPoint, urlParams, validatePathParam, waitForResource };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isBrowser } from "../is-browser.js";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
//#region src/helpers/__tests__/is-browser.browser.test.ts
|
|
4
|
+
// @vitest-environment jsdom
|
|
5
|
+
describe("isBrowser", () => {
|
|
6
|
+
it("returns true by default", () => {
|
|
7
|
+
expect(isBrowser()).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
//#endregion
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isBrowser } from "../is-browser.js";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
//#region src/helpers/__tests__/is-browser.node.test.ts
|
|
4
|
+
// @vitest-environment node
|
|
5
|
+
describe("isBrowser", () => {
|
|
6
|
+
it("returns false by default", () => {
|
|
7
|
+
expect(isBrowser()).toBe(false);
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
//#endregion
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { isJSON, isJSONObject } from "../json.js";
|
|
2
|
+
import { describe, expect, test } from "vitest";
|
|
3
|
+
//#region src/helpers/__tests__/json.test.ts
|
|
4
|
+
describe("isJSON", () => {
|
|
5
|
+
test.each([
|
|
6
|
+
"str",
|
|
7
|
+
200,
|
|
8
|
+
true,
|
|
9
|
+
null,
|
|
10
|
+
[
|
|
11
|
+
true,
|
|
12
|
+
"two",
|
|
13
|
+
3
|
|
14
|
+
],
|
|
15
|
+
{ key: "value" }
|
|
16
|
+
])(`accepts %s as a valid JSON value`, (obj) => {
|
|
17
|
+
expect(isJSON(obj)).toBeTruthy();
|
|
18
|
+
});
|
|
19
|
+
test.each([
|
|
20
|
+
void 0,
|
|
21
|
+
() => {},
|
|
22
|
+
Symbol(42)
|
|
23
|
+
])(`rejects %s as a valid JSON value`, (obj) => {
|
|
24
|
+
expect(isJSON(obj)).toBeFalsy();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe("isJSONObject", () => {
|
|
28
|
+
test.each([{ key: "value" }])(`accepts %s as a valid JSONObject value`, (obj) => {
|
|
29
|
+
expect(isJSONObject(obj)).toBeTruthy();
|
|
30
|
+
});
|
|
31
|
+
test.each([
|
|
32
|
+
"str",
|
|
33
|
+
200,
|
|
34
|
+
true,
|
|
35
|
+
null,
|
|
36
|
+
[
|
|
37
|
+
true,
|
|
38
|
+
"two",
|
|
39
|
+
3
|
|
40
|
+
],
|
|
41
|
+
void 0,
|
|
42
|
+
() => {},
|
|
43
|
+
Symbol(42)
|
|
44
|
+
])(`rejects %s as a valid JSONObject value`, (obj) => {
|
|
45
|
+
expect(isJSONObject(obj)).toBeFalsy();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
//#endregion
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { isJSONObject } from "../json.js";
|
|
2
|
+
import { resolveOneOf, unmarshalArrayOfObject, unmarshalDate, unmarshalMapOfObject, urlParams, validatePathParam } from "../marshalling.js";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
//#region src/helpers/__tests__/marshalling.test.ts
|
|
5
|
+
describe("validatePathParam", () => {
|
|
6
|
+
it("returns parameter for a non-empty string", () => {
|
|
7
|
+
expect(validatePathParam("keyName", "value")).toBe("value");
|
|
8
|
+
});
|
|
9
|
+
it("returns parameter for a number", () => {
|
|
10
|
+
expect(validatePathParam("keyName", 42)).toBe("42");
|
|
11
|
+
});
|
|
12
|
+
it("throws error for an undefined value", () => {
|
|
13
|
+
expect(() => {
|
|
14
|
+
validatePathParam("keyName", void 0);
|
|
15
|
+
}).toThrow(/* @__PURE__ */ new TypeError(`param keyName cannot be empty in request`));
|
|
16
|
+
});
|
|
17
|
+
it("throws error for an empty string", () => {
|
|
18
|
+
expect(() => {
|
|
19
|
+
validatePathParam("keyName", "");
|
|
20
|
+
}).toThrow(/* @__PURE__ */ new TypeError(`param keyName cannot be empty in request`));
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe("urlParams", () => {
|
|
24
|
+
it("accepts non-empty string | number | boolean values", () => {
|
|
25
|
+
expect(urlParams(["key1", "myValue"], ["key2", 0], ["key3", false]).toString()).toStrictEqual("key1=myValue&key2=0&key3=false");
|
|
26
|
+
});
|
|
27
|
+
it("accepts Date value", () => {
|
|
28
|
+
const now = /* @__PURE__ */ new Date();
|
|
29
|
+
expect(urlParams(["key1", now]).toString()).toStrictEqual(`key1=${encodeURIComponent(now.toISOString())}`);
|
|
30
|
+
});
|
|
31
|
+
it("accepts array of string", () => {
|
|
32
|
+
expect(urlParams(["my_param", ["value-1", "value-2"]]).toString()).toStrictEqual("my_param=value-1&my_param=value-2");
|
|
33
|
+
});
|
|
34
|
+
it("accepts array of different objects", () => {
|
|
35
|
+
const now = /* @__PURE__ */ new Date();
|
|
36
|
+
expect(urlParams(["my_param", ["value-1", now]]).toString()).toStrictEqual(`my_param=value-1&my_param=${encodeURIComponent(now.toISOString())}`);
|
|
37
|
+
});
|
|
38
|
+
it("accepts array of string with a null value", () => {
|
|
39
|
+
expect(urlParams(["my_param", ["value-1", null]]).toString()).toStrictEqual("my_param=value-1");
|
|
40
|
+
});
|
|
41
|
+
it("filters null or undefined values", () => {
|
|
42
|
+
expect(urlParams(["key1", null], ["key2", void 0]).toString()).toStrictEqual("");
|
|
43
|
+
});
|
|
44
|
+
it("filters non-string keys", () => {
|
|
45
|
+
expect(urlParams([0, "valid"], [null, "valid"]).toString()).toStrictEqual("");
|
|
46
|
+
});
|
|
47
|
+
it("properly resolves input from resolveOneOf", () => {
|
|
48
|
+
const value = resolveOneOf([{
|
|
49
|
+
param: "one_of_param",
|
|
50
|
+
value: 42
|
|
51
|
+
}]);
|
|
52
|
+
expect(urlParams(["my_param", "my-value"], ...Object.entries(value)).toString()).toStrictEqual("my_param=my-value&one_of_param=42");
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe("resolveOneOf", () => {
|
|
56
|
+
it("returns the value for 1 element", () => {
|
|
57
|
+
expect(resolveOneOf([{
|
|
58
|
+
default: void 0,
|
|
59
|
+
param: "my_key",
|
|
60
|
+
value: "42"
|
|
61
|
+
}], true)).toStrictEqual({ my_key: "42" });
|
|
62
|
+
});
|
|
63
|
+
it("returns the only defined value for 2 elements", () => {
|
|
64
|
+
expect(resolveOneOf([{
|
|
65
|
+
default: void 0,
|
|
66
|
+
param: "my_key_1",
|
|
67
|
+
value: void 0
|
|
68
|
+
}, {
|
|
69
|
+
default: void 0,
|
|
70
|
+
param: "my_key_2",
|
|
71
|
+
value: "42"
|
|
72
|
+
}], true)).toStrictEqual({ my_key_2: "42" });
|
|
73
|
+
});
|
|
74
|
+
it("returns the default value with undefined values", () => {
|
|
75
|
+
expect(resolveOneOf([{
|
|
76
|
+
default: "42",
|
|
77
|
+
param: "my_key_1",
|
|
78
|
+
value: void 0
|
|
79
|
+
}, {
|
|
80
|
+
default: void 0,
|
|
81
|
+
param: "my_key_2",
|
|
82
|
+
value: void 0
|
|
83
|
+
}], true)).toStrictEqual({ my_key_1: "42" });
|
|
84
|
+
expect(resolveOneOf([{
|
|
85
|
+
default: void 0,
|
|
86
|
+
param: "my_key_2",
|
|
87
|
+
value: void 0
|
|
88
|
+
}, {
|
|
89
|
+
default: "42",
|
|
90
|
+
param: "my_key_1",
|
|
91
|
+
value: void 0
|
|
92
|
+
}], true)).toStrictEqual({ my_key_1: "42" });
|
|
93
|
+
});
|
|
94
|
+
it("throws an error when no value has been found", () => {
|
|
95
|
+
expect(() => {
|
|
96
|
+
resolveOneOf([{
|
|
97
|
+
default: void 0,
|
|
98
|
+
param: "my_key_1",
|
|
99
|
+
value: void 0
|
|
100
|
+
}, {
|
|
101
|
+
default: void 0,
|
|
102
|
+
param: "my_key_2",
|
|
103
|
+
value: void 0
|
|
104
|
+
}], true);
|
|
105
|
+
}).toThrow(/* @__PURE__ */ new TypeError(`one of my_key_1 or my_key_2 must be indicated in the request`));
|
|
106
|
+
});
|
|
107
|
+
it("returns an empty record in case the resolve is optional", () => {
|
|
108
|
+
expect(resolveOneOf([{
|
|
109
|
+
default: void 0,
|
|
110
|
+
param: "my_key_1",
|
|
111
|
+
value: void 0
|
|
112
|
+
}, {
|
|
113
|
+
default: void 0,
|
|
114
|
+
param: "my_key_2",
|
|
115
|
+
value: void 0
|
|
116
|
+
}], false)).toStrictEqual({});
|
|
117
|
+
});
|
|
118
|
+
it("handles false kind values, like boolean.false", () => {
|
|
119
|
+
expect(resolveOneOf([{
|
|
120
|
+
default: void 0,
|
|
121
|
+
param: "my_key_1",
|
|
122
|
+
value: false
|
|
123
|
+
}, {
|
|
124
|
+
default: void 0,
|
|
125
|
+
param: "my_key_2",
|
|
126
|
+
value: true
|
|
127
|
+
}], false)).toStrictEqual({ my_key_1: false });
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
describe("unmarshalDate", () => {
|
|
131
|
+
it("unmarshals valid input", () => {
|
|
132
|
+
expect(unmarshalDate("2019-08-08T15:00:00Z")).toStrictEqual(/* @__PURE__ */ new Date("2019-08-08T15:00:00Z"));
|
|
133
|
+
});
|
|
134
|
+
it(`doesn't unmarshal invalid input type`, () => {
|
|
135
|
+
expect(unmarshalDate(42)).toBeUndefined();
|
|
136
|
+
});
|
|
137
|
+
it(`doesn't unmarshal invalid string format`, () => {
|
|
138
|
+
expect(unmarshalDate("not a date")).toBeUndefined();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe("unmarshalArrayOfObject", () => {
|
|
142
|
+
const unmarshaller = (data) => {
|
|
143
|
+
if (!isJSONObject(data)) throw new Error("Should not happen");
|
|
144
|
+
return { myNumber: data.my_number };
|
|
145
|
+
};
|
|
146
|
+
it("unmarshals valid array of object", () => {
|
|
147
|
+
expect(unmarshalArrayOfObject([{ my_number: 42 }, { my_number: 94 }], unmarshaller)).toStrictEqual([{ myNumber: 42 }, { myNumber: 94 }]);
|
|
148
|
+
});
|
|
149
|
+
it(`doesn't unmarshal invalid input, with empty array as fallback`, () => {
|
|
150
|
+
expect(unmarshalArrayOfObject(null, unmarshaller)).toStrictEqual([]);
|
|
151
|
+
});
|
|
152
|
+
it(`doesn't unmarshal invalid input, with undefined as fallback`, () => {
|
|
153
|
+
expect(unmarshalArrayOfObject(null, unmarshaller, false)).toBeUndefined();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
describe("unmarshalMapOfObject", () => {
|
|
157
|
+
const unmarshaller = (data) => {
|
|
158
|
+
if (!isJSONObject(data)) throw new Error("Should not happen");
|
|
159
|
+
return { myNumber: data.my_number };
|
|
160
|
+
};
|
|
161
|
+
it("unmarshals valid array of object", () => {
|
|
162
|
+
expect(unmarshalMapOfObject({
|
|
163
|
+
"first-key": { my_number: 42 },
|
|
164
|
+
"second-key": { my_number: 94 }
|
|
165
|
+
}, unmarshaller)).toStrictEqual({
|
|
166
|
+
"first-key": { myNumber: 42 },
|
|
167
|
+
"second-key": { myNumber: 94 }
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
it(`doesn't unmarshal invalid input, with empty record as fallback`, () => {
|
|
171
|
+
expect(unmarshalMapOfObject(null, unmarshaller)).toStrictEqual({});
|
|
172
|
+
});
|
|
173
|
+
it(`doesn't unmarshal invalid input, with undefined as fallback`, () => {
|
|
174
|
+
expect(unmarshalMapOfObject(null, unmarshaller, false)).toBeUndefined();
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
//#endregion
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region src/helpers/is-response.ts
|
|
1
2
|
/**
|
|
2
3
|
* Validates an object is of type Response without using `instanceof`.
|
|
3
4
|
*
|
|
@@ -5,5 +6,6 @@
|
|
|
5
6
|
*
|
|
6
7
|
* @internal
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
+
var isResponse = (obj) => obj !== null && obj !== void 0 && typeof obj === "object" && "status" in obj && typeof obj.status === "number" && "statusText" in obj && typeof obj.statusText === "string" && "headers" in obj && typeof obj.headers === "object" && "body" in obj && typeof obj.body !== "undefined";
|
|
10
|
+
//#endregion
|
|
9
11
|
export { isResponse };
|
package/dist/helpers/json.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
//#region src/helpers/json.ts
|
|
2
|
+
var isJSON = (obj) => {
|
|
3
|
+
const objT = typeof obj;
|
|
4
|
+
return obj !== void 0 && (obj === null || objT === "string" || objT === "number" || objT === "boolean" || Array.isArray(obj) || objT === "object");
|
|
5
|
+
};
|
|
1
6
|
/**
|
|
2
7
|
* Validates an unknown object is a JSON Object.
|
|
3
8
|
*
|
|
4
9
|
* @internal
|
|
5
10
|
*/
|
|
6
|
-
|
|
11
|
+
var isJSONObject = (obj) => {
|
|
7
12
|
const objT = typeof obj;
|
|
8
13
|
return obj !== void 0 && obj !== null && objT !== "string" && objT !== "number" && objT !== "boolean" && !Array.isArray(obj) && objT === "object";
|
|
9
14
|
};
|
|
@@ -15,7 +20,7 @@ const isJSONObject = (obj) => {
|
|
|
15
20
|
*
|
|
16
21
|
* @internal
|
|
17
22
|
*/
|
|
18
|
-
|
|
23
|
+
var camelize = (str) => {
|
|
19
24
|
const strLength = str.length;
|
|
20
25
|
if (strLength <= 0) return str;
|
|
21
26
|
let out = "";
|
|
@@ -38,7 +43,7 @@ const camelize = (str) => {
|
|
|
38
43
|
*
|
|
39
44
|
* @internal
|
|
40
45
|
*/
|
|
41
|
-
|
|
46
|
+
var camelizeKeys = (obj, ignoreKeys = []) => {
|
|
42
47
|
if (Array.isArray(obj)) return obj.map((v) => camelizeKeys(v, ignoreKeys));
|
|
43
48
|
if (obj && typeof obj === "object" && !(obj instanceof Date)) {
|
|
44
49
|
const result = {};
|
|
@@ -50,4 +55,5 @@ const camelizeKeys = (obj, ignoreKeys = []) => {
|
|
|
50
55
|
}
|
|
51
56
|
return obj;
|
|
52
57
|
};
|
|
53
|
-
|
|
58
|
+
//#endregion
|
|
59
|
+
export { camelize, camelizeKeys, isJSON, isJSONObject };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region src/helpers/marshalling.ts
|
|
1
2
|
/**
|
|
2
3
|
* Returns the parameter if it's valid as path parameter
|
|
3
4
|
* (string and not empty, or number), else throws an exception.
|
|
@@ -28,7 +29,7 @@ function validatePathParam(name, param) {
|
|
|
28
29
|
*
|
|
29
30
|
* @internal
|
|
30
31
|
*/
|
|
31
|
-
|
|
32
|
+
var resolveOneOf = (list, isRequired = false) => {
|
|
32
33
|
const elt = list.find((obj) => obj.value !== void 0) ?? list.find((obj) => obj.default !== void 0);
|
|
33
34
|
const value = elt?.value ?? elt?.default;
|
|
34
35
|
if (elt && value !== void 0) return { [elt.param]: value };
|
|
@@ -51,7 +52,7 @@ var toParamString = (v) => {
|
|
|
51
52
|
if (v instanceof Date) return v.toISOString();
|
|
52
53
|
return v.toString();
|
|
53
54
|
};
|
|
54
|
-
|
|
55
|
+
var urlParams = (...paramTuples) => {
|
|
55
56
|
const params = new URLSearchParams();
|
|
56
57
|
for (const [key, value] of paramTuples) {
|
|
57
58
|
if (typeof key !== "string" || value == null) continue;
|
|
@@ -72,7 +73,7 @@ const urlParams = (...paramTuples) => {
|
|
|
72
73
|
*
|
|
73
74
|
* @internal
|
|
74
75
|
*/
|
|
75
|
-
|
|
76
|
+
var unmarshalDate = (data) => {
|
|
76
77
|
if (typeof data !== "string") return;
|
|
77
78
|
const date = new Date(data);
|
|
78
79
|
if (Number.isNaN(date.getTime())) return;
|
|
@@ -83,7 +84,7 @@ const unmarshalDate = (data) => {
|
|
|
83
84
|
*
|
|
84
85
|
* @internal
|
|
85
86
|
*/
|
|
86
|
-
|
|
87
|
+
var unmarshalArrayOfObject = (data, unmarshaller, emptyFallback = true) => {
|
|
87
88
|
if (!Array.isArray(data)) return emptyFallback ? [] : void 0;
|
|
88
89
|
return data.map((elt) => unmarshaller(elt));
|
|
89
90
|
};
|
|
@@ -92,10 +93,11 @@ const unmarshalArrayOfObject = (data, unmarshaller, emptyFallback = true) => {
|
|
|
92
93
|
*
|
|
93
94
|
* @internal
|
|
94
95
|
*/
|
|
95
|
-
|
|
96
|
+
var unmarshalMapOfObject = (data, unmarshaller, emptyFallback = true) => {
|
|
96
97
|
if (!data || typeof data !== "object" || !(data instanceof Object) || Array.isArray(data)) return emptyFallback ? {} : void 0;
|
|
97
98
|
const out = {};
|
|
98
99
|
for (const [key, value] of Object.entries(data)) out[key] = unmarshaller(value);
|
|
99
100
|
return out;
|
|
100
101
|
};
|
|
102
|
+
//#endregion
|
|
101
103
|
export { resolveOneOf, unmarshalArrayOfObject, unmarshalDate, unmarshalMapOfObject, urlParams, validatePathParam };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { enableConsoleLogger, setLogger } from "./internal/logger/index.js";
|
|
2
1
|
import { isJSONObject } from "./helpers/json.js";
|
|
3
2
|
import { resolveOneOf, unmarshalArrayOfObject, unmarshalDate, unmarshalMapOfObject, urlParams, validatePathParam } from "./helpers/marshalling.js";
|
|
4
3
|
import { createExponentialBackoffStrategy, tryAtIntervals, waitForResource } from "./internal/async/interval-retrier.js";
|
|
5
|
-
import { addAsyncHeaderInterceptor } from "./internal/interceptors/helpers.js";
|
|
6
4
|
import { API } from "./scw/api.js";
|
|
7
|
-
import { AUTH_HEADER_KEY, SESSION_HEADER_KEY } from "./scw/constants.js";
|
|
8
|
-
import { authenticateWithSessionToken } from "./scw/auth.js";
|
|
9
5
|
import { Decimal } from "./scw/custom-types.js";
|
|
10
6
|
import { marshalBlobToScwFile, marshalDecimal, marshalMoney, marshalScwFile, marshalTimeSeries, unmarshalAnyRes, unmarshalDecimal, unmarshalMoney, unmarshalScwFile, unmarshalServiceInfo, unmarshalTimeSeries, unmarshalTimeSeriesPoint } from "./scw/custom-marshalling.js";
|
|
11
7
|
import { enrichForPagination } from "./scw/fetch/resource-paginator.js";
|
|
8
|
+
import { enableConsoleLogger, setLogger } from "./internal/logger/index.js";
|
|
9
|
+
import { addAsyncHeaderInterceptor } from "./internal/interceptors/helpers.js";
|
|
10
|
+
import { AUTH_HEADER_KEY, SESSION_HEADER_KEY } from "./scw/constants.js";
|
|
11
|
+
import { authenticateWithSessionToken } from "./scw/auth.js";
|
|
12
12
|
import "./internals.js";
|
|
13
13
|
import { withAdditionalInterceptors, withDefaultPageSize, withHTTPClient, withProfile, withUserAgent, withUserAgentSuffix } from "./scw/client-ini-factory.js";
|
|
14
14
|
import { createAdvancedClient, createClient } from "./scw/client.js";
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { sleep } from "../sleep.js";
|
|
2
|
+
import { createExponentialBackoffStrategy, createFibonacciIntervalStrategy, createFixedIntervalStrategy, tryAtIntervals, waitForResource } from "../interval-retrier.js";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
//#region src/internal/async/__tests__/interval-retrier.test.ts
|
|
5
|
+
describe("createFixedIntervalStrategy", () => {
|
|
6
|
+
it("always returns the same interval", () => {
|
|
7
|
+
const fixedInterval = .5;
|
|
8
|
+
const strategy = createFixedIntervalStrategy(fixedInterval);
|
|
9
|
+
for (let i = 0; i < 100; i += 1) expect(strategy.next(0).value).toBe(fixedInterval);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
describe("createFibonacciIntervalStrategy", () => {
|
|
13
|
+
it("returns a fibonacci sequence with default base and factor", () => {
|
|
14
|
+
const strategy = createFibonacciIntervalStrategy();
|
|
15
|
+
for (const expectedNumber of [
|
|
16
|
+
1,
|
|
17
|
+
1,
|
|
18
|
+
2,
|
|
19
|
+
3,
|
|
20
|
+
5,
|
|
21
|
+
8,
|
|
22
|
+
13,
|
|
23
|
+
21,
|
|
24
|
+
34
|
|
25
|
+
]) expect(strategy.next(0).value).toBe(expectedNumber);
|
|
26
|
+
});
|
|
27
|
+
it("returns a fibonacci sequence with custom base and factor", () => {
|
|
28
|
+
const strategy = createFibonacciIntervalStrategy(500, 2);
|
|
29
|
+
for (const expectedNumber of [
|
|
30
|
+
500,
|
|
31
|
+
1e3,
|
|
32
|
+
2500,
|
|
33
|
+
6e3,
|
|
34
|
+
14500,
|
|
35
|
+
35e3
|
|
36
|
+
]) expect(strategy.next(0).value).toBe(expectedNumber);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe("createExponentialBackoffStrategy", () => {
|
|
40
|
+
it("returns a sequence where all numbers are between min and max", () => {
|
|
41
|
+
const strategy = createExponentialBackoffStrategy(1, 5);
|
|
42
|
+
for (let index = 0; index < 10; index += 1) {
|
|
43
|
+
const next = strategy.next(0).value;
|
|
44
|
+
expect(next >= 1 && next <= 100).toBe(true);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
it("uses the same number if min and max are the same", () => {
|
|
48
|
+
const strategy = createExponentialBackoffStrategy(5, 5);
|
|
49
|
+
for (let index = 0; index < 10; index += 1) {
|
|
50
|
+
const next = strategy.next(0).value;
|
|
51
|
+
expect(next).toBe(5);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
it(`throws if minDelay isn't valid`, () => {
|
|
55
|
+
try {
|
|
56
|
+
createExponentialBackoffStrategy(0, 5).next(0);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
expect(err.message).toBe(`Waiter: minDelay must be >= 1 and maxDelay must be >= minDelay`);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
it(`throws if maxDelay isn't valid`, () => {
|
|
62
|
+
try {
|
|
63
|
+
createExponentialBackoffStrategy(1, 0).next(0);
|
|
64
|
+
} catch (err) {
|
|
65
|
+
expect(err.message).toBe(`Waiter: minDelay must be >= 1 and maxDelay must be >= minDelay`);
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
createExponentialBackoffStrategy(2, 1).next(0);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
expect(err.message).toBe(`Waiter: minDelay must be >= 1 and maxDelay must be >= minDelay`);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
var mockLogic = (iterations, workingTime) => {
|
|
75
|
+
let startDate;
|
|
76
|
+
let counter = 0;
|
|
77
|
+
return async () => {
|
|
78
|
+
if (counter === 0) startDate = /* @__PURE__ */ new Date();
|
|
79
|
+
counter += 1;
|
|
80
|
+
await sleep(workingTime);
|
|
81
|
+
return {
|
|
82
|
+
done: counter >= iterations,
|
|
83
|
+
value: {
|
|
84
|
+
doneIterations: counter,
|
|
85
|
+
totalDuration: Date.now() - startDate.getTime()
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
describe("tryAtIntervals", () => {
|
|
91
|
+
const zeroIntervalStrat = createFixedIntervalStrategy(0);
|
|
92
|
+
it("does the proper number of iterations", async () => {
|
|
93
|
+
expect((await tryAtIntervals(mockLogic(3, 0), zeroIntervalStrat, .5)).doneIterations).toBe(3);
|
|
94
|
+
});
|
|
95
|
+
it("timeouts after 0s", () => expect(tryAtIntervals(mockLogic(3, 5), zeroIntervalStrat, 0)).rejects.toThrow(`Timeout after 0s`));
|
|
96
|
+
it("timeouts after 10ms", () => expect(tryAtIntervals(mockLogic(3, 5), zeroIntervalStrat, .01)).rejects.toThrow(`Timeout after 0.01s`));
|
|
97
|
+
it("uses default timeout", async () => {
|
|
98
|
+
expect((await tryAtIntervals(mockLogic(3, 0), zeroIntervalStrat)).doneIterations).toBe(3);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
describe("waitForResource", () => {
|
|
102
|
+
it("resolves with non-transient status", () => {
|
|
103
|
+
return expect(waitForResource((res) => Promise.resolve(!["transient-one", "transient-two"].includes(res.status)), () => Promise.resolve({
|
|
104
|
+
message: "All went fine.",
|
|
105
|
+
status: "final"
|
|
106
|
+
}), { resourceId: "random-uuid" }, {
|
|
107
|
+
maxDelay: 1,
|
|
108
|
+
minDelay: 1
|
|
109
|
+
})).resolves.toStrictEqual({
|
|
110
|
+
message: "All went fine.",
|
|
111
|
+
status: "final"
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
it("rejects after timeout as transient status is being returned", () => {
|
|
115
|
+
return expect(waitForResource((res) => Promise.resolve(!["transient-one", "transient-two"].includes(res.status)), () => Promise.resolve({
|
|
116
|
+
message: "Still processing.",
|
|
117
|
+
status: "transient-two"
|
|
118
|
+
}), { resourceId: "random-uuid" }, { timeout: .01 })).rejects.toThrow();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
//#endregion
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { sleep } from "../sleep.js";
|
|
2
|
+
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
|
3
|
+
//#region src/internal/async/__tests__/sleep.test.ts
|
|
4
|
+
beforeAll(() => {
|
|
5
|
+
vi.useFakeTimers();
|
|
6
|
+
vi.spyOn(global, "setTimeout");
|
|
7
|
+
});
|
|
8
|
+
afterAll(() => {
|
|
9
|
+
vi.useRealTimers();
|
|
10
|
+
});
|
|
11
|
+
describe("sleep", () => {
|
|
12
|
+
it("delays the proper amount of time", () => {
|
|
13
|
+
const delay = 50;
|
|
14
|
+
sleep(delay).catch(() => {});
|
|
15
|
+
expect(setTimeout).toHaveBeenCalledTimes(1);
|
|
16
|
+
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), delay);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
//#endregion
|
|
@@ -61,7 +61,7 @@ export declare const tryAtIntervals: <T>(retry: Retry<T>, strategy: IntervalStra
|
|
|
61
61
|
*
|
|
62
62
|
* @public
|
|
63
63
|
*/
|
|
64
|
-
export type WaitForStopCondition<T> = (obj: T) => Promise<boolean
|
|
64
|
+
export type WaitForStopCondition<T> = (obj: T) => Promise<boolean> | boolean;
|
|
65
65
|
/**
|
|
66
66
|
* The options to wait until a resource is ready.
|
|
67
67
|
*
|
|
@@ -1,8 +1,37 @@
|
|
|
1
1
|
import { sleep } from "./sleep.js";
|
|
2
|
+
//#region src/internal/async/interval-retrier.ts
|
|
2
3
|
var DEFAULT_TIMEOUT_SECONDS = 300;
|
|
3
4
|
var DEFAULT_MIN_DELAY_SECONDS = 1;
|
|
4
5
|
var DEFAULT_MAX_DELAY_SECONDS = 30;
|
|
5
6
|
/**
|
|
7
|
+
* Creates a fixed interval strategy.
|
|
8
|
+
* It returns the same interval value whatever the retry count.
|
|
9
|
+
*
|
|
10
|
+
* @param interval - The time interval (in seconds) to wait between each run
|
|
11
|
+
* @returns A fixed interval generator
|
|
12
|
+
*
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
function* createFixedIntervalStrategy(interval) {
|
|
16
|
+
while (true) yield interval;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates a fibonacci interval strategy.
|
|
20
|
+
*
|
|
21
|
+
* @param base - The base interval (in seconds) that will be multiplicated with the fibonacci number
|
|
22
|
+
* @param factor - The factor so the fibonacci suite will go slower or faster
|
|
23
|
+
* @returns A fibonnacci generator
|
|
24
|
+
*
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
function* createFibonacciIntervalStrategy(base = 1, factor = 1) {
|
|
28
|
+
let [prev, current] = [0, 1];
|
|
29
|
+
while (true) {
|
|
30
|
+
yield current * base;
|
|
31
|
+
[prev, current] = [current, prev + current * factor];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
6
35
|
* Creates an exponential backoff interval strategy.
|
|
7
36
|
*
|
|
8
37
|
* @param minDelay - The minimum delay before the next try in seconds
|
|
@@ -33,7 +62,7 @@ function* createExponentialBackoffStrategy(minDelay, maxDelay) {
|
|
|
33
62
|
*
|
|
34
63
|
* @internal
|
|
35
64
|
*/
|
|
36
|
-
|
|
65
|
+
var tryAtIntervals = async (retry, strategy, timeout = DEFAULT_TIMEOUT_SECONDS) => {
|
|
37
66
|
const timeoutTimestamp = Date.now() + timeout * 1e3;
|
|
38
67
|
let retryCount = 0;
|
|
39
68
|
while (Date.now() <= timeoutTimestamp) {
|
|
@@ -59,11 +88,12 @@ const tryAtIntervals = async (retry, strategy, timeout = DEFAULT_TIMEOUT_SECONDS
|
|
|
59
88
|
*
|
|
60
89
|
* @public
|
|
61
90
|
*/
|
|
62
|
-
|
|
91
|
+
var waitForResource = (stop, fetcher, request, options, strategy = createExponentialBackoffStrategy(options?.minDelay ?? DEFAULT_MIN_DELAY_SECONDS, options?.maxDelay ?? DEFAULT_MAX_DELAY_SECONDS)) => tryAtIntervals(async () => {
|
|
63
92
|
const value = await fetcher(request);
|
|
64
93
|
return {
|
|
65
94
|
done: await stop(value),
|
|
66
95
|
value
|
|
67
96
|
};
|
|
68
97
|
}, strategy, options?.timeout);
|
|
69
|
-
|
|
98
|
+
//#endregion
|
|
99
|
+
export { createExponentialBackoffStrategy, createFibonacciIntervalStrategy, createFixedIntervalStrategy, tryAtIntervals, waitForResource };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region src/internal/async/sleep.ts
|
|
1
2
|
/**
|
|
2
3
|
* Sleep for a specified number of time.
|
|
3
4
|
*
|
|
@@ -6,7 +7,8 @@
|
|
|
6
7
|
*
|
|
7
8
|
* @internal
|
|
8
9
|
*/
|
|
9
|
-
|
|
10
|
+
var sleep = (ms) => new Promise((resolve) => {
|
|
10
11
|
setTimeout(resolve, ms);
|
|
11
12
|
});
|
|
13
|
+
//#endregion
|
|
12
14
|
export { sleep };
|