@scaleway/sdk-client 2.2.0 → 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.
Files changed (84) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +2 -0
  2. package/dist/bridge.js +8 -0
  3. package/dist/helpers/__tests__/is-browser.browser.test.js +10 -0
  4. package/dist/helpers/__tests__/is-browser.node.test.js +10 -0
  5. package/dist/helpers/__tests__/json.test.js +48 -0
  6. package/dist/helpers/__tests__/marshalling.test.js +177 -0
  7. package/dist/helpers/is-browser.js +3 -1
  8. package/dist/helpers/is-response.js +3 -1
  9. package/dist/helpers/json.js +10 -4
  10. package/dist/helpers/marshalling.js +7 -5
  11. package/dist/index.js +4 -4
  12. package/dist/internal/async/__tests__/interval-retrier.test.js +121 -0
  13. package/dist/internal/async/__tests__/sleep.test.js +19 -0
  14. package/dist/internal/async/interval-retrier.d.ts +1 -1
  15. package/dist/internal/async/interval-retrier.js +33 -3
  16. package/dist/internal/async/sleep.js +3 -1
  17. package/dist/internal/interceptors/__tests__/composer.test.js +48 -0
  18. package/dist/internal/interceptors/__tests__/helpers.test.js +27 -0
  19. package/dist/internal/interceptors/composer.js +5 -3
  20. package/dist/internal/interceptors/helpers.js +4 -2
  21. package/dist/internal/interceptors/types.js +0 -0
  22. package/dist/internal/logger/__tests__/index.test.js +209 -0
  23. package/dist/internal/logger/console-logger.js +2 -0
  24. package/dist/internal/logger/index.js +5 -3
  25. package/dist/internal/logger/level-resolver.js +4 -2
  26. package/dist/internal/logger/logger.js +0 -0
  27. package/dist/internal/validations/__tests__/string-validation.test.js +98 -0
  28. package/dist/internal/validations/string-validation.js +14 -9
  29. package/dist/internals.js +9 -8
  30. package/dist/package.js +2 -1
  31. package/dist/scw/__tests__/api.test.js +19 -0
  32. package/dist/scw/__tests__/auth.test.js +57 -0
  33. package/dist/scw/__tests__/client-ini-factory.test.js +220 -0
  34. package/dist/scw/__tests__/client-ini-profile.test.js +70 -0
  35. package/dist/scw/__tests__/client-settings.test.js +51 -0
  36. package/dist/scw/__tests__/client.test.js +59 -0
  37. package/dist/scw/__tests__/custom-marshalling.test.js +168 -0
  38. package/dist/scw/api.js +2 -0
  39. package/dist/scw/auth.js +17 -6
  40. package/dist/scw/client-ini-factory.js +9 -7
  41. package/dist/scw/client-ini-profile.js +3 -1
  42. package/dist/scw/client-settings.js +3 -1
  43. package/dist/scw/client.js +4 -2
  44. package/dist/scw/constants.js +6 -4
  45. package/dist/scw/custom-marshalling.js +17 -15
  46. package/dist/scw/custom-types.js +2 -0
  47. package/dist/scw/errors/__tests__/scw-error.test.js +41 -0
  48. package/dist/scw/errors/__tests__/types.test.js +16 -0
  49. package/dist/scw/errors/error-parser.js +3 -1
  50. package/dist/scw/errors/non-standard/__tests__/index.test.js +123 -0
  51. package/dist/scw/errors/non-standard/invalid-request-mapper.js +3 -1
  52. package/dist/scw/errors/non-standard/unknown-resource-mapper.js +3 -1
  53. package/dist/scw/errors/scw-error-from-json.js +0 -0
  54. package/dist/scw/errors/scw-error.js +2 -0
  55. package/dist/scw/errors/standard/__tests__/index.test.js +329 -0
  56. package/dist/scw/errors/standard/already-exists-error.js +2 -0
  57. package/dist/scw/errors/standard/denied-authentication-error.js +2 -0
  58. package/dist/scw/errors/standard/index.js +3 -1
  59. package/dist/scw/errors/standard/invalid-arguments-error.js +2 -0
  60. package/dist/scw/errors/standard/out-of-stock-error.js +2 -0
  61. package/dist/scw/errors/standard/permissions-denied-error.js +2 -0
  62. package/dist/scw/errors/standard/precondition-failed-error.js +2 -0
  63. package/dist/scw/errors/standard/quotas-exceeded-error.js +2 -0
  64. package/dist/scw/errors/standard/resource-expired-error.js +2 -0
  65. package/dist/scw/errors/standard/resource-locked-error.js +2 -0
  66. package/dist/scw/errors/standard/resource-not-found-error.js +2 -0
  67. package/dist/scw/errors/standard/too-many-requests-error.js +2 -0
  68. package/dist/scw/errors/standard/transient-state-error.js +2 -0
  69. package/dist/scw/errors/types.js +3 -1
  70. package/dist/scw/fetch/__tests__/build-fetcher.test.js +114 -0
  71. package/dist/scw/fetch/__tests__/http-dumper.test.js +45 -0
  72. package/dist/scw/fetch/__tests__/http-interceptors.test.js +60 -0
  73. package/dist/scw/fetch/__tests__/resource-paginator.test.js +110 -0
  74. package/dist/scw/fetch/__tests__/response-parser.test.js +94 -0
  75. package/dist/scw/fetch/build-fetcher.js +6 -4
  76. package/dist/scw/fetch/http-dumper.js +4 -2
  77. package/dist/scw/fetch/http-interceptors.js +5 -3
  78. package/dist/scw/fetch/resource-paginator.js +6 -4
  79. package/dist/scw/fetch/response-parser.js +5 -3
  80. package/dist/scw/fetch/types.js +0 -0
  81. package/dist/scw/locality.js +2 -0
  82. package/dist/vendor/base64/index.d.js +0 -0
  83. package/dist/vendor/base64/index.js +2 -0
  84. package/package.json +1 -1
@@ -0,0 +1,48 @@
1
+ import { composeRequestInterceptors, composeResponseErrorInterceptors } from "../composer.js";
2
+ import { describe, expect, it } from "vitest";
3
+ //#region src/internal/interceptors/__tests__/composer.test.ts
4
+ describe("composeRequestInterceptors", () => {
5
+ it("modifies the request header", async () => {
6
+ return expect(composeRequestInterceptors([({ request }) => {
7
+ const clone = request.clone();
8
+ clone.headers.set("new-header", "42");
9
+ return clone;
10
+ }])(new Request("https://api.scaleway.com")).then((obj) => obj.headers.get("new-header"))).resolves.toBe("42");
11
+ });
12
+ });
13
+ describe("composeResponseErrorInterceptors", () => {
14
+ it("passes the error to all interceptors if they all throw", () => {
15
+ class NumberError extends Error {
16
+ counter;
17
+ constructor(obj) {
18
+ super();
19
+ this.counter = obj;
20
+ Object.setPrototypeOf(this, NumberError.prototype);
21
+ }
22
+ }
23
+ return expect(composeResponseErrorInterceptors([({ error }) => {
24
+ throw error instanceof NumberError ? new NumberError(error.counter + 1) : error;
25
+ }, ({ error }) => {
26
+ throw error instanceof NumberError ? new NumberError(error.counter + 2) : error;
27
+ }])(new Request("https://api.scaleway.com"), new NumberError(42))).rejects.toThrow(new NumberError(45));
28
+ });
29
+ it("stops at the second interceptor (amongst three) if it resolves", () => {
30
+ return expect(composeResponseErrorInterceptors([
31
+ ({ error }) => {
32
+ throw error;
33
+ },
34
+ () => Promise.resolve(42),
35
+ ({ error }) => {
36
+ throw error;
37
+ }
38
+ ])(new Request("https://api.scaleway.com"), /* @__PURE__ */ new TypeError(""))).resolves.toBe(42);
39
+ });
40
+ it("throws the last processed error", () => {
41
+ return expect(composeResponseErrorInterceptors([({ error }) => {
42
+ throw error;
43
+ }, () => {
44
+ throw new TypeError("second error");
45
+ }])(new Request("https://api.scaleway.com"), /* @__PURE__ */ new TypeError("first error"))).rejects.toThrow(/* @__PURE__ */ new TypeError("second error"));
46
+ });
47
+ });
48
+ //#endregion
@@ -0,0 +1,27 @@
1
+ import { addAsyncHeaderInterceptor, addHeaderInterceptor } from "../helpers.js";
2
+ import { describe, expect, it } from "vitest";
3
+ //#region src/internal/interceptors/__tests__/helpers.test.ts
4
+ describe("addHeaderInterceptor", () => {
5
+ it("insertsnothing if value is undefined", async () => {
6
+ const request = new Request("https://api.scaleway.com/my/path");
7
+ expect((await addHeaderInterceptor("my-key", void 0)({ request })).headers.has("my-key")).toBe(false);
8
+ });
9
+ it("inserts 1 key/value in the request", async () => {
10
+ const request = new Request("https://api.scaleway.com/my/path");
11
+ expect((await addHeaderInterceptor("my-key", "my-value")({ request })).headers.get("my-key")).toBe("my-value");
12
+ });
13
+ it(`doesn't modify the input request`, async () => {
14
+ const request = new Request("https://api.scaleway.com/my/path");
15
+ const originalHeaders = request.headers;
16
+ const updatedReq = await addHeaderInterceptor("my-key", "my-value")({ request });
17
+ expect(request.headers).toBe(originalHeaders);
18
+ expect(updatedReq.headers.get("my-key")).toBe("my-value");
19
+ });
20
+ });
21
+ describe("addAsyncHeaderInterceptor", () => {
22
+ it("inserts 1 key/value in the request", async () => {
23
+ const request = new Request("https://api.scaleway.com/my/path");
24
+ expect((await addAsyncHeaderInterceptor("my-key", async () => Promise.resolve("my-value"))({ request })).headers.get("my-key")).toBe("my-value");
25
+ });
26
+ });
27
+ //#endregion
@@ -1,3 +1,4 @@
1
+ //#region src/internal/interceptors/composer.ts
1
2
  /**
2
3
  * Composes request interceptors.
3
4
  *
@@ -6,7 +7,7 @@
6
7
  *
7
8
  * @internal
8
9
  */
9
- const composeRequestInterceptors = (interceptors) => async (request) => interceptors.reduce(async (asyncResult, interceptor) => interceptor({ request: await asyncResult }), Promise.resolve(request));
10
+ var composeRequestInterceptors = (interceptors) => async (request) => interceptors.reduce(async (asyncResult, interceptor) => interceptor({ request: await asyncResult }), Promise.resolve(request));
10
11
  /**
11
12
  * Composes response interceptors.
12
13
  *
@@ -15,13 +16,13 @@ const composeRequestInterceptors = (interceptors) => async (request) => intercep
15
16
  *
16
17
  * @internal
17
18
  */
18
- const composeResponseInterceptors = (interceptors) => async (response) => interceptors.reduce(async (asyncResult, interceptor) => interceptor({ response: await asyncResult }), Promise.resolve(response));
19
+ var composeResponseInterceptors = (interceptors) => async (response) => interceptors.reduce(async (asyncResult, interceptor) => interceptor({ response: await asyncResult }), Promise.resolve(response));
19
20
  /**
20
21
  * Compose response error interceptors.
21
22
  *
22
23
  * @internal
23
24
  */
24
- const composeResponseErrorInterceptors = (interceptors) => async (request, error) => {
25
+ var composeResponseErrorInterceptors = (interceptors) => async (request, error) => {
25
26
  let prevError = error;
26
27
  for (const interceptor of interceptors) try {
27
28
  return await interceptor({
@@ -33,4 +34,5 @@ const composeResponseErrorInterceptors = (interceptors) => async (request, error
33
34
  }
34
35
  throw prevError;
35
36
  };
37
+ //#endregion
36
38
  export { composeRequestInterceptors, composeResponseErrorInterceptors, composeResponseInterceptors };
@@ -1,3 +1,4 @@
1
+ //#region src/internal/interceptors/helpers.ts
1
2
  /**
2
3
  * Adds an header to a request through an interceptor.
3
4
  *
@@ -7,7 +8,7 @@
7
8
  *
8
9
  * @internal
9
10
  */
10
- const addHeaderInterceptor = (key, value) => ({ request }) => {
11
+ var addHeaderInterceptor = (key, value) => ({ request }) => {
11
12
  const clone = request.clone();
12
13
  if (value !== void 0) clone.headers.append(key, value);
13
14
  return clone;
@@ -21,5 +22,6 @@ const addHeaderInterceptor = (key, value) => ({ request }) => {
21
22
  *
22
23
  * @internal
23
24
  */
24
- const addAsyncHeaderInterceptor = (key, getter) => async (request) => addHeaderInterceptor(key, await getter())(request);
25
+ var addAsyncHeaderInterceptor = (key, getter) => async (request) => addHeaderInterceptor(key, await getter())(request);
26
+ //#endregion
25
27
  export { addAsyncHeaderInterceptor, addHeaderInterceptor };
File without changes
@@ -0,0 +1,209 @@
1
+ import { ConsoleLogger } from "../console-logger.js";
2
+ import { enableConsoleLogger, getLogger, setLogger } from "../index.js";
3
+ import { describe, expect, it, vi } from "vitest";
4
+ //#region src/internal/logger/__tests__/index.test.ts
5
+ var makeCallbackConsole = (onMessage) => ({
6
+ ...console,
7
+ debug: onMessage,
8
+ error: onMessage,
9
+ info: onMessage,
10
+ warn: onMessage
11
+ });
12
+ var allLogLevels = [
13
+ "debug",
14
+ "info",
15
+ "warn",
16
+ "error"
17
+ ];
18
+ var IS_LEVEL_ENOUGH_CASES = [
19
+ {
20
+ base: "debug",
21
+ tests: [
22
+ {
23
+ expected: true,
24
+ target: "debug"
25
+ },
26
+ {
27
+ expected: true,
28
+ target: "info"
29
+ },
30
+ {
31
+ expected: true,
32
+ target: "warn"
33
+ },
34
+ {
35
+ expected: true,
36
+ target: "error"
37
+ }
38
+ ]
39
+ },
40
+ {
41
+ base: "info",
42
+ tests: [
43
+ {
44
+ expected: false,
45
+ target: "debug"
46
+ },
47
+ {
48
+ expected: true,
49
+ target: "info"
50
+ },
51
+ {
52
+ expected: true,
53
+ target: "warn"
54
+ },
55
+ {
56
+ expected: true,
57
+ target: "error"
58
+ }
59
+ ]
60
+ },
61
+ {
62
+ base: "warn",
63
+ tests: [
64
+ {
65
+ expected: false,
66
+ target: "debug"
67
+ },
68
+ {
69
+ expected: false,
70
+ target: "info"
71
+ },
72
+ {
73
+ expected: true,
74
+ target: "warn"
75
+ },
76
+ {
77
+ expected: true,
78
+ target: "error"
79
+ }
80
+ ]
81
+ },
82
+ {
83
+ base: "error",
84
+ tests: [
85
+ {
86
+ expected: false,
87
+ target: "debug"
88
+ },
89
+ {
90
+ expected: false,
91
+ target: "info"
92
+ },
93
+ {
94
+ expected: false,
95
+ target: "warn"
96
+ },
97
+ {
98
+ expected: true,
99
+ target: "error"
100
+ }
101
+ ]
102
+ },
103
+ {
104
+ base: "unknown",
105
+ tests: [
106
+ {
107
+ expected: false,
108
+ target: "debug"
109
+ },
110
+ {
111
+ expected: false,
112
+ target: "info"
113
+ },
114
+ {
115
+ expected: false,
116
+ target: "warn"
117
+ },
118
+ {
119
+ expected: false,
120
+ target: "error"
121
+ }
122
+ ]
123
+ }
124
+ ];
125
+ describe("ConsoleLogger", () => {
126
+ it("initializes with the asked level", () => {
127
+ expect(new ConsoleLogger("info").logLevel).toBe("info");
128
+ });
129
+ it("returns the proper level boolean", () => {
130
+ const log = vi.fn().mockImplementation(() => {});
131
+ const out = makeCallbackConsole(log);
132
+ for (const test of IS_LEVEL_ENOUGH_CASES) {
133
+ const logger = new ConsoleLogger(test.base, "", out);
134
+ setLogger(logger);
135
+ for (const elt of test.tests) {
136
+ log.mockReset();
137
+ logger[elt.target](elt.target);
138
+ if (elt.expected) expect(log).toHaveBeenCalledWith(elt.target);
139
+ else expect(log).not.toHaveBeenCalledWith(elt.target);
140
+ }
141
+ }
142
+ });
143
+ it("prints the indicated output", () => {
144
+ const prefix = "test:";
145
+ let latestMessage = "";
146
+ const logger = new ConsoleLogger("debug", prefix, makeCallbackConsole((message) => {
147
+ latestMessage = message;
148
+ }));
149
+ for (const method of allLogLevels) {
150
+ const randomStr = (Math.random() + 1).toString(36).substring(7);
151
+ logger[method](randomStr);
152
+ expect(latestMessage).toBe(`${prefix} ${randomStr}`);
153
+ }
154
+ });
155
+ it("prints no output (as loglevel is silent)", () => {
156
+ let latestMessage = "";
157
+ const logger = new ConsoleLogger("silent", "test:", makeCallbackConsole((message) => {
158
+ latestMessage = message;
159
+ }));
160
+ for (const method of allLogLevels) {
161
+ const randomStr = (Math.random() + 1).toString(36).substring(7);
162
+ logger[method](randomStr);
163
+ expect(latestMessage).toBe("");
164
+ }
165
+ });
166
+ });
167
+ describe("setLogger", () => {
168
+ it(`changes the logger object when called'`, () => {
169
+ const initialLogger = getLogger();
170
+ setLogger(new ConsoleLogger("info"));
171
+ expect(initialLogger).not.toBe(getLogger());
172
+ });
173
+ it(`changes the logLevel when updated`, () => {
174
+ setLogger(new ConsoleLogger("warn"));
175
+ const { logLevel } = getLogger();
176
+ setLogger(new ConsoleLogger("debug"));
177
+ expect(getLogger().logLevel).not.toBe(logLevel);
178
+ expect(getLogger().logLevel).toBe("debug");
179
+ });
180
+ });
181
+ describe("enableConsoleLogger", () => {
182
+ it(`initializes console logger with warn level by default`, () => {
183
+ setLogger(new ConsoleLogger("silent"));
184
+ expect(getLogger().logLevel).toBe("silent");
185
+ enableConsoleLogger();
186
+ expect(getLogger().logLevel).toBe("warn");
187
+ });
188
+ it(`initializes console logger with given level`, () => {
189
+ enableConsoleLogger("silent");
190
+ expect(getLogger().logLevel).toBe("silent");
191
+ enableConsoleLogger("debug");
192
+ expect(getLogger().logLevel).toBe("debug");
193
+ enableConsoleLogger("info");
194
+ expect(getLogger().logLevel).toBe("info");
195
+ enableConsoleLogger("warn");
196
+ expect(getLogger().logLevel).toBe("warn");
197
+ enableConsoleLogger("error");
198
+ expect(getLogger().logLevel).toBe("error");
199
+ });
200
+ it(`replaces custom logger with new console logger`, () => {
201
+ const customLogger = new ConsoleLogger("error");
202
+ setLogger(customLogger);
203
+ expect(getLogger().logLevel).toBe(customLogger.logLevel);
204
+ enableConsoleLogger("warn");
205
+ expect(getLogger().logLevel).toBe("warn");
206
+ expect(getLogger()).not.toBe(customLogger);
207
+ });
208
+ });
209
+ //#endregion
@@ -1,4 +1,5 @@
1
1
  import { LevelResolver, shouldLog } from "./level-resolver.js";
2
+ //#region src/internal/logger/console-logger.ts
2
3
  /**
3
4
  * A Logger using console output.
4
5
  *
@@ -26,4 +27,5 @@ var ConsoleLogger = class {
26
27
  info = this.makeMethod("info");
27
28
  warn = this.makeMethod("warn");
28
29
  };
30
+ //#endregion
29
31
  export { ConsoleLogger };
@@ -1,4 +1,5 @@
1
1
  import { ConsoleLogger } from "./console-logger.js";
2
+ //#region src/internal/logger/index.ts
2
3
  var sdkLogger = new ConsoleLogger("silent");
3
4
  /**
4
5
  * Sets a logger to be used within the SDK.
@@ -7,7 +8,7 @@ var sdkLogger = new ConsoleLogger("silent");
7
8
  *
8
9
  * @public
9
10
  */
10
- const setLogger = (logger) => {
11
+ var setLogger = (logger) => {
11
12
  sdkLogger = logger;
12
13
  };
13
14
  /**
@@ -18,11 +19,12 @@ const setLogger = (logger) => {
18
19
  *
19
20
  * @public
20
21
  */
21
- const enableConsoleLogger = (logLevel = "warn", prefix = "scaleway-sdk-js:") => setLogger(new ConsoleLogger(logLevel, prefix));
22
+ var enableConsoleLogger = (logLevel = "warn", prefix = "scaleway-sdk-js:") => setLogger(new ConsoleLogger(logLevel, prefix));
22
23
  /**
23
24
  * Returns the active SDK logger.
24
25
  *
25
26
  * @internal
26
27
  */
27
- const getLogger = () => sdkLogger;
28
+ var getLogger = () => sdkLogger;
29
+ //#endregion
28
30
  export { enableConsoleLogger, getLogger, setLogger };
@@ -1,4 +1,5 @@
1
- let LevelResolver = /* @__PURE__ */ function(LevelResolver) {
1
+ //#region src/internal/logger/level-resolver.ts
2
+ var LevelResolver = /* @__PURE__ */ function(LevelResolver) {
2
3
  LevelResolver[LevelResolver["silent"] = 0] = "silent";
3
4
  LevelResolver[LevelResolver["error"] = 1] = "error";
4
5
  LevelResolver[LevelResolver["warn"] = 2] = "warn";
@@ -6,5 +7,6 @@ let LevelResolver = /* @__PURE__ */ function(LevelResolver) {
6
7
  LevelResolver[LevelResolver["debug"] = 4] = "debug";
7
8
  return LevelResolver;
8
9
  }({});
9
- const shouldLog = (currentLevel, level) => LevelResolver[level] <= currentLevel;
10
+ var shouldLog = (currentLevel, level) => LevelResolver[level] <= currentLevel;
11
+ //#endregion
10
12
  export { LevelResolver, shouldLog };
File without changes
@@ -0,0 +1,98 @@
1
+ import { isAccessKey, isEmail, isOrganizationId, isProjectId, isRegion, isSecretKey, isURL, isUUID, isZone } from "../string-validation.js";
2
+ import { describe, expect, it } from "vitest";
3
+ //#region src/internal/validations/__tests__/string-validation.test.ts
4
+ var validUUIDs = ["00000000-0000-0000-0000-000000000000", "123e4567-e89b-12d3-a456-426614174000"];
5
+ var invalidUUIDs = [
6
+ "",
7
+ "1",
8
+ "23e4567-e89b-12d3-a456-426614174000"
9
+ ];
10
+ var validators = [
11
+ {
12
+ invalids: invalidUUIDs,
13
+ name: "UUID",
14
+ validator: isUUID,
15
+ valids: validUUIDs
16
+ },
17
+ {
18
+ invalids: [
19
+ "",
20
+ "SCW012345678",
21
+ "WCS01234567890123456"
22
+ ],
23
+ name: "AccessKey",
24
+ validator: isAccessKey,
25
+ valids: ["SCW01234567890123456"]
26
+ },
27
+ {
28
+ invalids: invalidUUIDs,
29
+ name: "SecretKey",
30
+ validator: isSecretKey,
31
+ valids: validUUIDs
32
+ },
33
+ {
34
+ invalids: invalidUUIDs,
35
+ name: "Organization",
36
+ validator: isOrganizationId,
37
+ valids: validUUIDs
38
+ },
39
+ {
40
+ invalids: invalidUUIDs,
41
+ name: "Project",
42
+ validator: isProjectId,
43
+ valids: validUUIDs
44
+ },
45
+ {
46
+ invalids: [
47
+ "",
48
+ "f-par",
49
+ "fr",
50
+ "-par",
51
+ "fr-pa"
52
+ ],
53
+ name: "Region",
54
+ validator: isRegion,
55
+ valids: [
56
+ "fr-par",
57
+ "nl-ams",
58
+ "pl-waw"
59
+ ]
60
+ },
61
+ {
62
+ invalids: [
63
+ "",
64
+ "fr-par",
65
+ "fr"
66
+ ],
67
+ name: "Zone",
68
+ validator: isZone,
69
+ valids: [
70
+ "fr-par-1",
71
+ "fr-par-2",
72
+ "nl-ams-1",
73
+ "pl-waw-1",
74
+ "pl-waw-9"
75
+ ]
76
+ },
77
+ {
78
+ invalids: ["", "api.scaleway.com"],
79
+ name: "URL",
80
+ validator: isURL,
81
+ valids: ["https://api.scaleway.com"]
82
+ },
83
+ {
84
+ invalids: ["", "@example.com"],
85
+ name: "Email",
86
+ validator: isEmail,
87
+ valids: ["john@example.com"]
88
+ }
89
+ ];
90
+ for (const component of validators) describe(component.validator.name, () => {
91
+ it(`validates correct ${component.name} format`, () => {
92
+ for (const str of component.valids) expect(component.validator(str)).toStrictEqual(true);
93
+ });
94
+ it(`doesn't validate incorrect ${component.name} format`, () => {
95
+ for (const str of component.invalids) expect(component.validator(str)).toStrictEqual(false);
96
+ });
97
+ });
98
+ //#endregion
@@ -1,23 +1,25 @@
1
+ //#region src/internal/validations/string-validation.ts
1
2
  var isAccessKeyRegex = /^SCW[A-Z0-9]{17}$/i;
3
+ var isEmailRegex = /^.+@.+$/i;
2
4
  var isRegionRegex = /^[a-z]{2}-[a-z]{3}$/i;
3
5
  var isUUIDRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/i;
4
6
  var isZoneRegex = /^[a-z]{2}-[a-z]{3}-[1-9]$/i;
5
7
  /** Returns true if the given string has a valid UUID format. */
6
- const isUUID = (str) => isUUIDRegex.test(str);
8
+ var isUUID = (str) => isUUIDRegex.test(str);
7
9
  /** Returns true if the given string has a valid Scaleway access key format. */
8
- const isAccessKey = (str) => isAccessKeyRegex.test(str);
10
+ var isAccessKey = (str) => isAccessKeyRegex.test(str);
9
11
  /** Returns true if the given string has a valid Scaleway secret key format. */
10
- const isSecretKey = (str) => isUUID(str);
12
+ var isSecretKey = (str) => isUUID(str);
11
13
  /** Returns true if the given string has a valid Scaleway organization ID format. */
12
- const isOrganizationId = (str) => isUUID(str);
14
+ var isOrganizationId = (str) => isUUID(str);
13
15
  /** Returns true if the given string has a valid Scaleway project ID format. */
14
- const isProjectId = (str) => isUUID(str);
16
+ var isProjectId = (str) => isUUID(str);
15
17
  /** Returns true if the given string has a valid region format. */
16
- const isRegion = (str) => isRegionRegex.test(str);
18
+ var isRegion = (str) => isRegionRegex.test(str);
17
19
  /** Returns true if the given string has a valid zone format. */
18
- const isZone = (str) => isZoneRegex.test(str);
20
+ var isZone = (str) => isZoneRegex.test(str);
19
21
  /** Returns true if the given string has a valid URL format and starts by `http(s):`. */
20
- const isURL = (str) => {
22
+ var isURL = (str) => {
21
23
  let url;
22
24
  try {
23
25
  url = new URL(str);
@@ -26,4 +28,7 @@ const isURL = (str) => {
26
28
  }
27
29
  return url.protocol === "http:" || url.protocol === "https:";
28
30
  };
29
- export { isAccessKey, isOrganizationId, isProjectId, isRegion, isSecretKey, isURL, isUUID, isZone };
31
+ /** Returns true if the given string has an email format. */
32
+ var isEmail = (str) => isEmailRegex.test(str);
33
+ //#endregion
34
+ export { isAccessKey, isEmail, isOrganizationId, isProjectId, isRegion, isSecretKey, isURL, isUUID, isZone };
package/dist/internals.js CHANGED
@@ -1,8 +1,9 @@
1
- import "./helpers/json.js";
2
- import "./helpers/marshalling.js";
3
- import "./internal/async/interval-retrier.js";
4
- import "./internal/interceptors/helpers.js";
5
- import "./scw/api.js";
6
- import "./scw/auth.js";
7
- import "./scw/custom-marshalling.js";
8
- import "./scw/fetch/resource-paginator.js";
1
+ import { isJSONObject } from "./helpers/json.js";
2
+ import { resolveOneOf, unmarshalArrayOfObject, unmarshalDate, unmarshalMapOfObject, urlParams, validatePathParam } from "./helpers/marshalling.js";
3
+ import { createExponentialBackoffStrategy, tryAtIntervals, waitForResource } from "./internal/async/interval-retrier.js";
4
+ import { API } from "./scw/api.js";
5
+ import { marshalBlobToScwFile, marshalDecimal, marshalMoney, marshalScwFile, marshalTimeSeries, unmarshalAnyRes, unmarshalDecimal, unmarshalMoney, unmarshalScwFile, unmarshalServiceInfo, unmarshalTimeSeries, unmarshalTimeSeriesPoint } from "./scw/custom-marshalling.js";
6
+ import { enrichForPagination } from "./scw/fetch/resource-paginator.js";
7
+ import { addAsyncHeaderInterceptor } from "./internal/interceptors/helpers.js";
8
+ import { authenticateWithSessionToken } from "./scw/auth.js";
9
+ export { API, addAsyncHeaderInterceptor, authenticateWithSessionToken, createExponentialBackoffStrategy, enrichForPagination, isJSONObject, marshalBlobToScwFile, marshalDecimal, marshalMoney, marshalScwFile, marshalTimeSeries, resolveOneOf, tryAtIntervals, unmarshalAnyRes, unmarshalArrayOfObject, unmarshalDate, unmarshalDecimal, unmarshalMapOfObject, unmarshalMoney, unmarshalScwFile, unmarshalServiceInfo, unmarshalTimeSeries, unmarshalTimeSeriesPoint, urlParams, validatePathParam, waitForResource };
package/dist/package.js CHANGED
@@ -1,6 +1,6 @@
1
1
  var package_default = {
2
2
  name: "@scaleway/sdk-client",
3
- version: "2.1.0",
3
+ version: "2.2.2",
4
4
  license: "Apache-2.0",
5
5
  description: "Scaleway SDK Client",
6
6
  keywords: [
@@ -29,4 +29,5 @@ var package_default = {
29
29
  "default": "./dist/index.js"
30
30
  } }
31
31
  };
32
+ //#endregion
32
33
  export { package_default as default };
@@ -0,0 +1,19 @@
1
+ import { API } from "../api.js";
2
+ import { createClient } from "../client.js";
3
+ import { describe, expect, it } from "vitest";
4
+ //#region src/scw/__tests__/api.test.ts
5
+ var CustomAPI = class extends API {
6
+ getBaseURL = () => {
7
+ if (!this.client.settings.apiURL) throw new Error("API URL is missing");
8
+ return this.client.settings.apiURL;
9
+ };
10
+ };
11
+ describe("API", () => {
12
+ it("binds methods properly", () => {
13
+ const unboundMethod = new CustomAPI(createClient()).getBaseURL;
14
+ expect(() => {
15
+ unboundMethod();
16
+ }).not.toThrow();
17
+ });
18
+ });
19
+ //#endregion
@@ -0,0 +1,57 @@
1
+ import { authenticateWithSecrets, authenticateWithSessionToken, obfuscateAuthHeadersEntry, obfuscateToken, obfuscateUUID } from "../auth.js";
2
+ import { describe, expect, it } from "vitest";
3
+ //#region src/scw/__tests__/auth.test.ts
4
+ describe("obfuscateToken", () => {
5
+ it("hides anything after 5 characters", () => {
6
+ expect(obfuscateToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c")).toBe("eyJhbxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
7
+ expect(obfuscateToken("")).toBe("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
8
+ });
9
+ });
10
+ describe("obfuscateUUID", () => {
11
+ it("hides anything after 8 characters", () => {
12
+ expect(obfuscateUUID("db31db7b-473d-488e-bd2e-1b77ee426910")).toBe("db31db7b-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
13
+ expect(obfuscateUUID("")).toBe("-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
14
+ });
15
+ });
16
+ describe("obfuscateAuthHeadersEntry", () => {
17
+ it("obfuscates an auth token", () => {
18
+ expect(obfuscateAuthHeadersEntry(["x-auth-token", "db31db7b-473d-488e-bd2e-1b77ee426910"])).toStrictEqual(["x-auth-token", "db31db7b-xxxx-xxxx-xxxx-xxxxxxxxxxxx"]);
19
+ });
20
+ it("obfuscates a session token", () => {
21
+ expect(obfuscateAuthHeadersEntry(["x-session-token", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"])).toStrictEqual(["x-session-token", "eyJhbxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]);
22
+ });
23
+ it(`doesn't obfuscate unknown key`, () => {
24
+ expect(obfuscateAuthHeadersEntry(["x-unknown-key", "random-value"])).toStrictEqual(["x-unknown-key", "random-value"]);
25
+ });
26
+ });
27
+ describe("authenticateWithSessionToken", () => {
28
+ it("retrieves the token and updates the request header", async () => {
29
+ const dummyToken = "dummy";
30
+ const sourceReq = new Request("https://api.scaleway.com/my/path");
31
+ const updatedReq = await authenticateWithSessionToken(() => Promise.resolve(dummyToken))({ request: sourceReq });
32
+ const expectedReq = sourceReq.clone();
33
+ expectedReq.headers.append("x-session-token", "dummy");
34
+ expect(updatedReq).toMatchObject(expectedReq);
35
+ });
36
+ });
37
+ describe("authenticateWithSecrets", () => {
38
+ const sourceReq = new Request("https://api.scaleway.com/my/path");
39
+ it("updates the request header with the valid secrets", async () => {
40
+ const validSecrets = {
41
+ accessKey: "SCW01234567890123456",
42
+ secretKey: "e4b83996-4c60-449a-98d2-38f5de7b4e6b"
43
+ };
44
+ const updatedReq = await authenticateWithSecrets(validSecrets)({ request: sourceReq });
45
+ const expectedReq = sourceReq.clone();
46
+ expectedReq.headers.append("x-auth-token", validSecrets.secretKey);
47
+ expect(updatedReq).toMatchObject(expectedReq);
48
+ });
49
+ it("throws an exception for invalid secrets", () => {
50
+ const invalidSecrets = {
51
+ accessKey: "",
52
+ secretKey: ""
53
+ };
54
+ expect(() => authenticateWithSecrets(invalidSecrets)({ request: sourceReq })).toThrow();
55
+ });
56
+ });
57
+ //#endregion