@scaleway/sdk-client 1.1.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.
Files changed (149) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +36 -0
  3. package/dist/bridge.d.ts +12 -0
  4. package/dist/helpers/is-browser.cjs +4 -0
  5. package/dist/helpers/is-browser.d.ts +1 -0
  6. package/dist/helpers/is-browser.js +4 -0
  7. package/dist/helpers/is-response.cjs +4 -0
  8. package/dist/helpers/is-response.d.ts +8 -0
  9. package/dist/helpers/is-response.js +4 -0
  10. package/dist/helpers/json.cjs +7 -0
  11. package/dist/helpers/json.d.ts +13 -0
  12. package/dist/helpers/json.js +7 -0
  13. package/dist/helpers/marshalling.cjs +76 -0
  14. package/dist/helpers/marshalling.d.ts +60 -0
  15. package/dist/helpers/marshalling.js +76 -0
  16. package/dist/index.cjs +52 -0
  17. package/dist/index.d.ts +15 -0
  18. package/dist/index.js +52 -0
  19. package/dist/internal/async/interval-retrier.cjs +53 -0
  20. package/dist/internal/async/interval-retrier.d.ts +111 -0
  21. package/dist/internal/async/interval-retrier.js +53 -0
  22. package/dist/internal/async/sleep.cjs +6 -0
  23. package/dist/internal/async/sleep.d.ts +9 -0
  24. package/dist/internal/async/sleep.js +6 -0
  25. package/dist/internal/interceptors/composer.cjs +25 -0
  26. package/dist/internal/interceptors/composer.d.ts +25 -0
  27. package/dist/internal/interceptors/composer.js +25 -0
  28. package/dist/internal/interceptors/helpers.cjs +12 -0
  29. package/dist/internal/interceptors/helpers.d.ts +21 -0
  30. package/dist/internal/interceptors/helpers.js +12 -0
  31. package/dist/internal/interceptors/types.d.ts +89 -0
  32. package/dist/internal/logger/console-logger.cjs +24 -0
  33. package/dist/internal/logger/console-logger.d.ts +23 -0
  34. package/dist/internal/logger/console-logger.js +24 -0
  35. package/dist/internal/logger/index.cjs +12 -0
  36. package/dist/internal/logger/index.d.ts +25 -0
  37. package/dist/internal/logger/index.js +12 -0
  38. package/dist/internal/logger/level-resolver.cjs +13 -0
  39. package/dist/internal/logger/level-resolver.d.ts +9 -0
  40. package/dist/internal/logger/level-resolver.js +13 -0
  41. package/dist/internal/logger/logger.d.ts +13 -0
  42. package/dist/internal/validations/string-validation.cjs +30 -0
  43. package/dist/internal/validations/string-validation.d.ts +18 -0
  44. package/dist/internal/validations/string-validation.js +30 -0
  45. package/dist/internals.d.ts +10 -0
  46. package/dist/package.json.cjs +67 -0
  47. package/dist/package.json.js +67 -0
  48. package/dist/scw/api.cjs +8 -0
  49. package/dist/scw/api.d.ts +10 -0
  50. package/dist/scw/api.js +8 -0
  51. package/dist/scw/auth.cjs +26 -0
  52. package/dist/scw/auth.d.ts +57 -0
  53. package/dist/scw/auth.js +26 -0
  54. package/dist/scw/client-ini-factory.cjs +66 -0
  55. package/dist/scw/client-ini-factory.d.ts +111 -0
  56. package/dist/scw/client-ini-factory.js +66 -0
  57. package/dist/scw/client-ini-profile.cjs +23 -0
  58. package/dist/scw/client-ini-profile.d.ts +82 -0
  59. package/dist/scw/client-ini-profile.js +23 -0
  60. package/dist/scw/client-settings.cjs +51 -0
  61. package/dist/scw/client-settings.d.ts +59 -0
  62. package/dist/scw/client-settings.js +51 -0
  63. package/dist/scw/client.cjs +31 -0
  64. package/dist/scw/client.d.ts +71 -0
  65. package/dist/scw/client.js +31 -0
  66. package/dist/scw/constants.cjs +7 -0
  67. package/dist/scw/constants.d.ts +2 -0
  68. package/dist/scw/constants.js +7 -0
  69. package/dist/scw/custom-marshalling.cjs +126 -0
  70. package/dist/scw/custom-marshalling.d.ts +80 -0
  71. package/dist/scw/custom-marshalling.js +126 -0
  72. package/dist/scw/custom-types.cjs +11 -0
  73. package/dist/scw/custom-types.d.ts +74 -0
  74. package/dist/scw/custom-types.js +11 -0
  75. package/dist/scw/errors/error-parser.cjs +76 -0
  76. package/dist/scw/errors/error-parser.d.ts +12 -0
  77. package/dist/scw/errors/error-parser.js +76 -0
  78. package/dist/scw/errors/non-standard/invalid-request-mapper.cjs +36 -0
  79. package/dist/scw/errors/non-standard/invalid-request-mapper.d.ts +12 -0
  80. package/dist/scw/errors/non-standard/invalid-request-mapper.js +36 -0
  81. package/dist/scw/errors/non-standard/unknown-resource-mapper.cjs +23 -0
  82. package/dist/scw/errors/non-standard/unknown-resource-mapper.d.ts +11 -0
  83. package/dist/scw/errors/non-standard/unknown-resource-mapper.js +23 -0
  84. package/dist/scw/errors/scw-error-from-json.d.ts +10 -0
  85. package/dist/scw/errors/scw-error.cjs +43 -0
  86. package/dist/scw/errors/scw-error.d.ts +25 -0
  87. package/dist/scw/errors/scw-error.js +43 -0
  88. package/dist/scw/errors/standard/already-exists-error.cjs +31 -0
  89. package/dist/scw/errors/standard/already-exists-error.d.ts +16 -0
  90. package/dist/scw/errors/standard/already-exists-error.js +31 -0
  91. package/dist/scw/errors/standard/denied-authentication-error.cjs +37 -0
  92. package/dist/scw/errors/standard/denied-authentication-error.d.ts +15 -0
  93. package/dist/scw/errors/standard/denied-authentication-error.js +37 -0
  94. package/dist/scw/errors/standard/index.cjs +28 -0
  95. package/dist/scw/errors/standard/index.d.ts +17 -0
  96. package/dist/scw/errors/standard/index.js +28 -0
  97. package/dist/scw/errors/standard/invalid-arguments-error.cjs +54 -0
  98. package/dist/scw/errors/standard/invalid-arguments-error.d.ts +24 -0
  99. package/dist/scw/errors/standard/invalid-arguments-error.js +54 -0
  100. package/dist/scw/errors/standard/out-of-stock-error.cjs +17 -0
  101. package/dist/scw/errors/standard/out-of-stock-error.d.ts +14 -0
  102. package/dist/scw/errors/standard/out-of-stock-error.js +17 -0
  103. package/dist/scw/errors/standard/permissions-denied-error.cjs +29 -0
  104. package/dist/scw/errors/standard/permissions-denied-error.d.ts +23 -0
  105. package/dist/scw/errors/standard/permissions-denied-error.js +29 -0
  106. package/dist/scw/errors/standard/precondition-failed-error.cjs +32 -0
  107. package/dist/scw/errors/standard/precondition-failed-error.d.ts +15 -0
  108. package/dist/scw/errors/standard/precondition-failed-error.js +32 -0
  109. package/dist/scw/errors/standard/quotas-exceeded-error.cjs +43 -0
  110. package/dist/scw/errors/standard/quotas-exceeded-error.d.ts +34 -0
  111. package/dist/scw/errors/standard/quotas-exceeded-error.js +43 -0
  112. package/dist/scw/errors/standard/resource-expired-error.cjs +31 -0
  113. package/dist/scw/errors/standard/resource-expired-error.d.ts +16 -0
  114. package/dist/scw/errors/standard/resource-expired-error.js +31 -0
  115. package/dist/scw/errors/standard/resource-locked-error.cjs +20 -0
  116. package/dist/scw/errors/standard/resource-locked-error.d.ts +15 -0
  117. package/dist/scw/errors/standard/resource-locked-error.js +20 -0
  118. package/dist/scw/errors/standard/resource-not-found-error.cjs +24 -0
  119. package/dist/scw/errors/standard/resource-not-found-error.d.ts +15 -0
  120. package/dist/scw/errors/standard/resource-not-found-error.js +24 -0
  121. package/dist/scw/errors/standard/too-many-requests-error.cjs +58 -0
  122. package/dist/scw/errors/standard/too-many-requests-error.d.ts +32 -0
  123. package/dist/scw/errors/standard/too-many-requests-error.js +58 -0
  124. package/dist/scw/errors/standard/transient-state-error.cjs +31 -0
  125. package/dist/scw/errors/standard/transient-state-error.d.ts +16 -0
  126. package/dist/scw/errors/standard/transient-state-error.js +31 -0
  127. package/dist/scw/errors/types.cjs +15 -0
  128. package/dist/scw/errors/types.d.ts +9 -0
  129. package/dist/scw/errors/types.js +15 -0
  130. package/dist/scw/fetch/build-fetcher.cjs +60 -0
  131. package/dist/scw/fetch/build-fetcher.d.ts +23 -0
  132. package/dist/scw/fetch/build-fetcher.js +60 -0
  133. package/dist/scw/fetch/http-dumper.cjs +20 -0
  134. package/dist/scw/fetch/http-dumper.d.ts +18 -0
  135. package/dist/scw/fetch/http-dumper.js +20 -0
  136. package/dist/scw/fetch/http-interceptors.cjs +43 -0
  137. package/dist/scw/fetch/http-interceptors.d.ts +38 -0
  138. package/dist/scw/fetch/http-interceptors.js +43 -0
  139. package/dist/scw/fetch/resource-paginator.cjs +36 -0
  140. package/dist/scw/fetch/resource-paginator.d.ts +47 -0
  141. package/dist/scw/fetch/resource-paginator.js +36 -0
  142. package/dist/scw/fetch/response-parser.cjs +55 -0
  143. package/dist/scw/fetch/response-parser.d.ts +25 -0
  144. package/dist/scw/fetch/response-parser.js +55 -0
  145. package/dist/scw/fetch/types.d.ts +16 -0
  146. package/dist/scw/locality.d.ts +2 -0
  147. package/dist/vendor/base64/index.cjs +42 -0
  148. package/dist/vendor/base64/index.js +42 -0
  149. package/package.json +37 -0
@@ -0,0 +1,60 @@
1
+ import { isBrowser } from "../../helpers/is-browser.js";
2
+ import { composeRequestInterceptors, composeResponseInterceptors, composeResponseErrorInterceptors } from "../../internal/interceptors/composer.js";
3
+ import { obfuscateAuthHeadersEntry } from "../auth.js";
4
+ import { logRequest, logResponse, obfuscateInterceptor } from "./http-interceptors.js";
5
+ import { responseParser } from "./response-parser.js";
6
+ const buildRequest = (request, settings) => {
7
+ let { path } = request;
8
+ if (request.urlParams instanceof URLSearchParams) {
9
+ path = path.concat(`?${request.urlParams.toString()}`);
10
+ }
11
+ return new Request(`${settings.apiURL}${path}`, {
12
+ body: request.body,
13
+ headers: {
14
+ Accept: "application/json",
15
+ .../* istanbul ignore next */
16
+ !isBrowser() ? { "User-Agent": settings.userAgent } : {},
17
+ ...request.headers
18
+ },
19
+ method: request.method
20
+ });
21
+ };
22
+ const asIs = (response) => response;
23
+ const buildFetcher = (settings, httpClient) => {
24
+ let requestNumber = 0;
25
+ const prepareRequest = (requestId) => composeRequestInterceptors([
26
+ ...settings.interceptors.map((obj) => obj.request).filter((obj) => obj),
27
+ logRequest(requestId, obfuscateInterceptor(obfuscateAuthHeadersEntry))
28
+ ]);
29
+ const prepareResponse = (requestId) => composeResponseInterceptors([
30
+ ...settings.interceptors.map((obj) => obj.response).filter((obj) => obj),
31
+ logResponse(requestId)
32
+ ]);
33
+ const prepareResponseErrors = () => composeResponseErrorInterceptors(
34
+ settings.interceptors.map((obj) => obj.responseError).filter((obj) => obj)
35
+ );
36
+ return async (request, unwrapper = asIs) => {
37
+ const requestId = `${requestNumber += 1}`;
38
+ const reqInterceptors = prepareRequest(requestId);
39
+ const finalRequest = await reqInterceptors(buildRequest(request, settings));
40
+ try {
41
+ const response = await httpClient(finalRequest);
42
+ const resInterceptors = prepareResponse(requestId);
43
+ const finalResponse = await resInterceptors(response);
44
+ const resUnmarshaller = responseParser(
45
+ unwrapper,
46
+ request.responseType ?? "json"
47
+ );
48
+ const unmarshaledResponse = await resUnmarshaller(finalResponse);
49
+ return unmarshaledResponse;
50
+ } catch (err) {
51
+ const resErrorInterceptors = prepareResponseErrors();
52
+ const handledError = await resErrorInterceptors(finalRequest, err);
53
+ return unwrapper(handledError);
54
+ }
55
+ };
56
+ };
57
+ export {
58
+ buildFetcher,
59
+ buildRequest
60
+ };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const toPascalCase = (str) => str.replace(
4
+ /\w+/g,
5
+ (word) => `${word[0].toUpperCase()}${word.slice(1).toLowerCase()}`
6
+ );
7
+ const serializeHeadersEntry = ([name, value]) => `${toPascalCase(name)}: ${value}`;
8
+ const serializeHeaders = (headers) => Array.from(headers.entries(), serializeHeadersEntry);
9
+ const dumpRequest = async (request) => [
10
+ `${request.method.toUpperCase()}: ${request.url}`,
11
+ ...serializeHeaders(request.headers),
12
+ await request.clone().text()
13
+ ].join("\r\n");
14
+ const dumpResponse = async (response) => [
15
+ `HTTP ${response.status} ${response.ok ? "OK" : "NOK"}`,
16
+ ...serializeHeaders(response.headers),
17
+ await response.clone().text()
18
+ ].join("\r\n");
19
+ exports.dumpRequest = dumpRequest;
20
+ exports.dumpResponse = dumpResponse;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Dumps a Request into a readable string.
3
+ *
4
+ * @param request - The request
5
+ * @returns The readable string
6
+ *
7
+ * @internal
8
+ */
9
+ export declare const dumpRequest: (request: Readonly<Request>) => Promise<string>;
10
+ /**
11
+ * Dumps a Response into a readable string.
12
+ *
13
+ * @param response - The response
14
+ * @returns The readable string
15
+ *
16
+ * @internal
17
+ */
18
+ export declare const dumpResponse: (response: Readonly<Response>) => Promise<string>;
@@ -0,0 +1,20 @@
1
+ const toPascalCase = (str) => str.replace(
2
+ /\w+/g,
3
+ (word) => `${word[0].toUpperCase()}${word.slice(1).toLowerCase()}`
4
+ );
5
+ const serializeHeadersEntry = ([name, value]) => `${toPascalCase(name)}: ${value}`;
6
+ const serializeHeaders = (headers) => Array.from(headers.entries(), serializeHeadersEntry);
7
+ const dumpRequest = async (request) => [
8
+ `${request.method.toUpperCase()}: ${request.url}`,
9
+ ...serializeHeaders(request.headers),
10
+ await request.clone().text()
11
+ ].join("\r\n");
12
+ const dumpResponse = async (response) => [
13
+ `HTTP ${response.status} ${response.ok ? "OK" : "NOK"}`,
14
+ ...serializeHeaders(response.headers),
15
+ await response.clone().text()
16
+ ].join("\r\n");
17
+ export {
18
+ dumpRequest,
19
+ dumpResponse
20
+ };
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const index = require("../../internal/logger/index.cjs");
4
+ const levelResolver = require("../../internal/logger/level-resolver.cjs");
5
+ const httpDumper = require("./http-dumper.cjs");
6
+ class ObfuscatedRequest extends Request {
7
+ constructor(request, obfuscate) {
8
+ super(request);
9
+ this.request = request;
10
+ this.obfuscate = obfuscate;
11
+ }
12
+ get headers() {
13
+ return new Headers(Array.from(this.request.headers, this.obfuscate));
14
+ }
15
+ clone() {
16
+ return new ObfuscatedRequest(this.request, this.obfuscate);
17
+ }
18
+ }
19
+ const obfuscateInterceptor = (obfuscate) => ({ request }) => new ObfuscatedRequest(request, obfuscate);
20
+ const identity = ({ request }) => request;
21
+ const logRequest = (identifier, obfuscate = identity) => async ({ request }) => {
22
+ if (levelResolver.shouldLog(levelResolver.LevelResolver[index.getLogger().logLevel], "debug")) {
23
+ index.getLogger().debug(
24
+ `--------------- Scaleway SDK REQUEST ${identifier} ---------------
25
+ ${await httpDumper.dumpRequest(await obfuscate({ request }))}
26
+ ---------------------------------------------------------`
27
+ );
28
+ }
29
+ return request;
30
+ };
31
+ const logResponse = (identifier) => async ({ response }) => {
32
+ if (levelResolver.shouldLog(levelResolver.LevelResolver[index.getLogger().logLevel], "debug")) {
33
+ index.getLogger().debug(
34
+ `--------------- Scaleway SDK RESPONSE ${identifier} ---------------
35
+ ${await httpDumper.dumpResponse(response)}
36
+ ---------------------------------------------------------`
37
+ );
38
+ }
39
+ return response;
40
+ };
41
+ exports.logRequest = logRequest;
42
+ exports.logResponse = logResponse;
43
+ exports.obfuscateInterceptor = obfuscateInterceptor;
@@ -0,0 +1,38 @@
1
+ import type { RequestInterceptor, ResponseInterceptor } from '../../internal/interceptors/types';
2
+ /**
3
+ * Mapper of an header entry.
4
+ *
5
+ * @internal
6
+ */
7
+ interface HeaderEntryMapper {
8
+ (entry: [string, string]): [string, string];
9
+ }
10
+ /**
11
+ * Creates an interceptor to obfuscate the requests.
12
+ *
13
+ * @param obfuscate - The Header entries obfuscator mapper
14
+ * @returns The obfuscated Request
15
+ *
16
+ * @internal
17
+ */
18
+ export declare const obfuscateInterceptor: (obfuscate: HeaderEntryMapper) => RequestInterceptor;
19
+ /**
20
+ * Creates an interceptor to log the requests.
21
+ *
22
+ * @param identifier - The request identifier
23
+ * @param obfuscate - The obfuscation interceptor
24
+ * @returns The interceptor
25
+ *
26
+ * @internal
27
+ */
28
+ export declare const logRequest: (identifier: string, obfuscate?: RequestInterceptor) => RequestInterceptor;
29
+ /**
30
+ * Creates an interceptor to log the responses.
31
+ *
32
+ * @param identifier - The request identifier
33
+ * @returns The interceptor
34
+ *
35
+ * @internal
36
+ */
37
+ export declare const logResponse: (identifier: string) => ResponseInterceptor;
38
+ export {};
@@ -0,0 +1,43 @@
1
+ import { getLogger } from "../../internal/logger/index.js";
2
+ import { shouldLog, LevelResolver } from "../../internal/logger/level-resolver.js";
3
+ import { dumpRequest, dumpResponse } from "./http-dumper.js";
4
+ class ObfuscatedRequest extends Request {
5
+ constructor(request, obfuscate) {
6
+ super(request);
7
+ this.request = request;
8
+ this.obfuscate = obfuscate;
9
+ }
10
+ get headers() {
11
+ return new Headers(Array.from(this.request.headers, this.obfuscate));
12
+ }
13
+ clone() {
14
+ return new ObfuscatedRequest(this.request, this.obfuscate);
15
+ }
16
+ }
17
+ const obfuscateInterceptor = (obfuscate) => ({ request }) => new ObfuscatedRequest(request, obfuscate);
18
+ const identity = ({ request }) => request;
19
+ const logRequest = (identifier, obfuscate = identity) => async ({ request }) => {
20
+ if (shouldLog(LevelResolver[getLogger().logLevel], "debug")) {
21
+ getLogger().debug(
22
+ `--------------- Scaleway SDK REQUEST ${identifier} ---------------
23
+ ${await dumpRequest(await obfuscate({ request }))}
24
+ ---------------------------------------------------------`
25
+ );
26
+ }
27
+ return request;
28
+ };
29
+ const logResponse = (identifier) => async ({ response }) => {
30
+ if (shouldLog(LevelResolver[getLogger().logLevel], "debug")) {
31
+ getLogger().debug(
32
+ `--------------- Scaleway SDK RESPONSE ${identifier} ---------------
33
+ ${await dumpResponse(response)}
34
+ ---------------------------------------------------------`
35
+ );
36
+ }
37
+ return response;
38
+ };
39
+ export {
40
+ logRequest,
41
+ logResponse,
42
+ obfuscateInterceptor
43
+ };
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const extract = (key) => (result) => result[key];
4
+ function* pages(key, fetcher, request, firstPage) {
5
+ if (!Array.isArray(firstPage[key])) {
6
+ throw new Error(`Property ${key} is not a list in paginated result`);
7
+ }
8
+ const getList = extract(key);
9
+ let page = request.page || 1;
10
+ if (page === 1) {
11
+ yield Promise.resolve(getList(firstPage));
12
+ page += 1;
13
+ }
14
+ const { length } = firstPage[key];
15
+ if (!length) return;
16
+ const { totalCount } = firstPage;
17
+ while (page <= Math.floor((totalCount + length - 1) / length)) {
18
+ yield fetcher({ ...request, page }).then(getList);
19
+ page += 1;
20
+ }
21
+ }
22
+ async function* fetchPaginated(key, fetcher, request, initial = fetcher(request)) {
23
+ yield* pages(key, fetcher, request, await initial);
24
+ }
25
+ const fetchAll = async (key, fetcher, request, initial = fetcher(request)) => (await Promise.all(Array.from(pages(key, fetcher, request, await initial)))).flat();
26
+ const enrichForPagination = (key, fetcher, request) => {
27
+ const firstPage = fetcher(request);
28
+ return Object.assign(firstPage, {
29
+ all: () => fetchAll(key, fetcher, request, firstPage),
30
+ [Symbol.asyncIterator]: () => fetchPaginated(key, fetcher, request, firstPage)
31
+ });
32
+ };
33
+ exports.enrichForPagination = enrichForPagination;
34
+ exports.extract = extract;
35
+ exports.fetchAll = fetchAll;
36
+ exports.fetchPaginated = fetchPaginated;
@@ -0,0 +1,47 @@
1
+ interface PaginationOptions {
2
+ page?: number;
3
+ pageSize?: number;
4
+ }
5
+ interface PaginatedResponse {
6
+ totalCount: number;
7
+ }
8
+ export type PaginatedFetcher<T, R extends PaginationOptions = PaginationOptions> = (request: R) => Promise<T>;
9
+ export type PaginatedContent<K extends string, T = unknown> = PaginatedResponse & {
10
+ [key in K]: T[];
11
+ };
12
+ export declare const extract: <K extends string>(key: K) => <T extends PaginatedContent<K>>(result: T) => T[K];
13
+ /**
14
+ * Fetches a paginated resource.
15
+ *
16
+ * @param key - The resource key of values list
17
+ * @param fetcher - The method to retrieve paginated resources
18
+ * @param request - A request with pagination options
19
+ * @param initial - The first page
20
+ * @returns An async generator of resources arrays
21
+ */
22
+ export declare function fetchPaginated<K extends string, T extends PaginatedContent<K>, R extends PaginationOptions>(key: K, fetcher: PaginatedFetcher<T, R>, request: R, initial?: Promise<T>): AsyncGenerator<T[K], void, void>;
23
+ /**
24
+ * Fetches all paginated resource.
25
+ *
26
+ * @param key - The resource key of values list
27
+ * @param fetcher - The method to retrieve paginated resources
28
+ * @param request - A request with pagination options
29
+ * @param initial - The first page
30
+ * @returns A resources array Promise
31
+ */
32
+ export declare const fetchAll: <K extends string, T extends PaginatedContent<K>, R extends PaginationOptions>(key: K, fetcher: PaginatedFetcher<T, R>, request: R, initial?: Promise<T>) => Promise<(Awaited<T[K]> extends infer T_1 ? T_1 extends Awaited<T[K]> ? T_1 extends readonly (infer InnerArr)[] ? InnerArr : T_1 : never : never)[]>;
33
+ /**
34
+ * Enriches a listing method with helpers.
35
+ *
36
+ * @param key - The resource key of values list
37
+ * @param fetcher - The method to retrieve paginated resources
38
+ * @param request - A request with pagination options
39
+ * @returns A resource Promise with the pagination helpers
40
+ *
41
+ * @internal
42
+ */
43
+ export declare const enrichForPagination: <K extends string, T extends PaginatedContent<K>, R extends PaginationOptions>(key: K, fetcher: PaginatedFetcher<T, R>, request: R) => Promise<T> & {
44
+ all: () => Promise<(Awaited<T[K]> extends infer T_1 ? T_1 extends Awaited<T[K]> ? T_1 extends readonly (infer InnerArr)[] ? InnerArr : T_1 : never : never)[]>;
45
+ [Symbol.asyncIterator]: () => AsyncGenerator<T[K], void, void>;
46
+ };
47
+ export {};
@@ -0,0 +1,36 @@
1
+ const extract = (key) => (result) => result[key];
2
+ function* pages(key, fetcher, request, firstPage) {
3
+ if (!Array.isArray(firstPage[key])) {
4
+ throw new Error(`Property ${key} is not a list in paginated result`);
5
+ }
6
+ const getList = extract(key);
7
+ let page = request.page || 1;
8
+ if (page === 1) {
9
+ yield Promise.resolve(getList(firstPage));
10
+ page += 1;
11
+ }
12
+ const { length } = firstPage[key];
13
+ if (!length) return;
14
+ const { totalCount } = firstPage;
15
+ while (page <= Math.floor((totalCount + length - 1) / length)) {
16
+ yield fetcher({ ...request, page }).then(getList);
17
+ page += 1;
18
+ }
19
+ }
20
+ async function* fetchPaginated(key, fetcher, request, initial = fetcher(request)) {
21
+ yield* pages(key, fetcher, request, await initial);
22
+ }
23
+ const fetchAll = async (key, fetcher, request, initial = fetcher(request)) => (await Promise.all(Array.from(pages(key, fetcher, request, await initial)))).flat();
24
+ const enrichForPagination = (key, fetcher, request) => {
25
+ const firstPage = fetcher(request);
26
+ return Object.assign(firstPage, {
27
+ all: () => fetchAll(key, fetcher, request, firstPage),
28
+ [Symbol.asyncIterator]: () => fetchPaginated(key, fetcher, request, firstPage)
29
+ });
30
+ };
31
+ export {
32
+ enrichForPagination,
33
+ extract,
34
+ fetchAll,
35
+ fetchPaginated
36
+ };
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const isResponse = require("../../helpers/is-response.cjs");
4
+ const json = require("../../helpers/json.cjs");
5
+ const errorParser = require("../errors/error-parser.cjs");
6
+ const scwError = require("../errors/scw-error.cjs");
7
+ const X_TOTAL_COUNT_HEADER_KEY = "x-total-count";
8
+ const TOTAL_COUNT_RES_KEY = "total_count";
9
+ const fixLegacyTotalCount = (obj, headers) => {
10
+ const headerVal = headers.get(X_TOTAL_COUNT_HEADER_KEY);
11
+ if (!headerVal) {
12
+ return obj;
13
+ }
14
+ const totalCount = parseInt(headerVal, 10);
15
+ if (Number.isNaN(totalCount)) {
16
+ return obj;
17
+ }
18
+ if (json.isJSONObject(obj) && !(TOTAL_COUNT_RES_KEY in obj)) {
19
+ return Object.assign(obj, { [TOTAL_COUNT_RES_KEY]: totalCount });
20
+ }
21
+ return obj;
22
+ };
23
+ const responseParser = (unmarshaller, responseType) => async (response) => {
24
+ if (!isResponse.isResponse(response)) {
25
+ throw new TypeError("Invalid response object");
26
+ }
27
+ if (response.ok) {
28
+ if (response.status === 204) return unmarshaller(void 0);
29
+ const contentType = response.headers.get("Content-Type");
30
+ try {
31
+ if (responseType === "json" && contentType === "application/json") {
32
+ return unmarshaller(
33
+ fixLegacyTotalCount(await response.json(), response.headers)
34
+ );
35
+ }
36
+ if (responseType === "blob") {
37
+ return unmarshaller(await response.blob());
38
+ }
39
+ return unmarshaller(await response.text());
40
+ } catch (err) {
41
+ throw new scwError.ScalewayError(
42
+ response.status,
43
+ `could not parse '${contentType ?? ""}' response${err instanceof Error ? `: ${err.message}` : ""}`
44
+ );
45
+ }
46
+ }
47
+ const error = await response.clone().json().catch(() => response.text());
48
+ if (json.isJSONObject(error)) throw errorParser.parseScalewayError(response.status, error);
49
+ throw new scwError.ScalewayError(
50
+ response.status,
51
+ typeof error === "string" ? error : "cannot read error response body"
52
+ );
53
+ };
54
+ exports.fixLegacyTotalCount = fixLegacyTotalCount;
55
+ exports.responseParser = responseParser;
@@ -0,0 +1,25 @@
1
+ import type { ResponseUnmarshaller } from './types';
2
+ /**
3
+ * Fixes the totalCount property for old APIs.
4
+ *
5
+ * @internal
6
+ */
7
+ export declare const fixLegacyTotalCount: <T>(obj: T, headers: Headers) => T;
8
+ /**
9
+ * Makes response parser.
10
+ *
11
+ * @param unmarshaller - The response payload unmarshaller
12
+ * @returns An async converter of HTTP Response to desired result
13
+ *
14
+ * @throws {@link ScalewayError}
15
+ * Thrown by the API if the request couldn't be completed.
16
+ *
17
+ * @throws TypeError
18
+ * Thrown if the response parameter isn't of the expected type.
19
+ *
20
+ * @throws Error
21
+ * JSON parsing could trigger an error.
22
+ *
23
+ * @internal
24
+ */
25
+ export declare const responseParser: <T>(unmarshaller: ResponseUnmarshaller<T>, responseType: "json" | "text" | "blob") => (response: Response) => Promise<T>;
@@ -0,0 +1,55 @@
1
+ import { isResponse } from "../../helpers/is-response.js";
2
+ import { isJSONObject } from "../../helpers/json.js";
3
+ import { parseScalewayError } from "../errors/error-parser.js";
4
+ import { ScalewayError } from "../errors/scw-error.js";
5
+ const X_TOTAL_COUNT_HEADER_KEY = "x-total-count";
6
+ const TOTAL_COUNT_RES_KEY = "total_count";
7
+ const fixLegacyTotalCount = (obj, headers) => {
8
+ const headerVal = headers.get(X_TOTAL_COUNT_HEADER_KEY);
9
+ if (!headerVal) {
10
+ return obj;
11
+ }
12
+ const totalCount = parseInt(headerVal, 10);
13
+ if (Number.isNaN(totalCount)) {
14
+ return obj;
15
+ }
16
+ if (isJSONObject(obj) && !(TOTAL_COUNT_RES_KEY in obj)) {
17
+ return Object.assign(obj, { [TOTAL_COUNT_RES_KEY]: totalCount });
18
+ }
19
+ return obj;
20
+ };
21
+ const responseParser = (unmarshaller, responseType) => async (response) => {
22
+ if (!isResponse(response)) {
23
+ throw new TypeError("Invalid response object");
24
+ }
25
+ if (response.ok) {
26
+ if (response.status === 204) return unmarshaller(void 0);
27
+ const contentType = response.headers.get("Content-Type");
28
+ try {
29
+ if (responseType === "json" && contentType === "application/json") {
30
+ return unmarshaller(
31
+ fixLegacyTotalCount(await response.json(), response.headers)
32
+ );
33
+ }
34
+ if (responseType === "blob") {
35
+ return unmarshaller(await response.blob());
36
+ }
37
+ return unmarshaller(await response.text());
38
+ } catch (err) {
39
+ throw new ScalewayError(
40
+ response.status,
41
+ `could not parse '${contentType ?? ""}' response${err instanceof Error ? `: ${err.message}` : ""}`
42
+ );
43
+ }
44
+ }
45
+ const error = await response.clone().json().catch(() => response.text());
46
+ if (isJSONObject(error)) throw parseScalewayError(response.status, error);
47
+ throw new ScalewayError(
48
+ response.status,
49
+ typeof error === "string" ? error : "cannot read error response body"
50
+ );
51
+ };
52
+ export {
53
+ fixLegacyTotalCount,
54
+ responseParser
55
+ };
@@ -0,0 +1,16 @@
1
+ /** Scaleway Request. */
2
+ export interface ScwRequest {
3
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
4
+ path: string;
5
+ headers?: Record<string, string>;
6
+ body?: string;
7
+ urlParams?: URLSearchParams;
8
+ responseType?: 'json' | 'text' | 'blob';
9
+ }
10
+ /**
11
+ * A factory to unmarshal a response.
12
+ *
13
+ * @param obj - The input object.
14
+ * @returns The output object
15
+ */
16
+ export type ResponseUnmarshaller<T> = (obj: unknown) => T;
@@ -0,0 +1,2 @@
1
+ export type Region = 'fr-par' | 'nl-ams' | 'pl-waw' | (string & {});
2
+ export type Zone = 'fr-par-1' | 'fr-par-2' | 'fr-par-3' | 'nl-ams-1' | 'nl-ams-2' | 'nl-ams-3' | 'pl-waw-1' | 'pl-waw-2' | (string & {});
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ var lookup = [];
4
+ var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5
+ for (var i = 0, len = code.length; i < len; ++i) {
6
+ lookup[i] = code[i];
7
+ }
8
+ function tripletToBase64(num) {
9
+ return lookup[num >> 18 & 63] + lookup[num >> 12 & 63] + lookup[num >> 6 & 63] + lookup[num & 63];
10
+ }
11
+ function encodeChunk(uint8, start, end) {
12
+ var tmp;
13
+ var output = [];
14
+ for (var i = start; i < end; i += 3) {
15
+ tmp = (uint8[i] << 16 & 16711680) + (uint8[i + 1] << 8 & 65280) + (uint8[i + 2] & 255);
16
+ output.push(tripletToBase64(tmp));
17
+ }
18
+ return output.join("");
19
+ }
20
+ function fromByteArray(uint8) {
21
+ var tmp;
22
+ var len = uint8.length;
23
+ var extraBytes = len % 3;
24
+ var parts = [];
25
+ var maxChunkLength = 16383;
26
+ for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
27
+ parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));
28
+ }
29
+ if (extraBytes === 1) {
30
+ tmp = uint8[len - 1];
31
+ parts.push(
32
+ lookup[tmp >> 2] + lookup[tmp << 4 & 63] + "=="
33
+ );
34
+ } else if (extraBytes === 2) {
35
+ tmp = (uint8[len - 2] << 8) + uint8[len - 1];
36
+ parts.push(
37
+ lookup[tmp >> 10] + lookup[tmp >> 4 & 63] + lookup[tmp << 2 & 63] + "="
38
+ );
39
+ }
40
+ return parts.join("");
41
+ }
42
+ exports.fromByteArray = fromByteArray;
@@ -0,0 +1,42 @@
1
+ var lookup = [];
2
+ var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3
+ for (var i = 0, len = code.length; i < len; ++i) {
4
+ lookup[i] = code[i];
5
+ }
6
+ function tripletToBase64(num) {
7
+ return lookup[num >> 18 & 63] + lookup[num >> 12 & 63] + lookup[num >> 6 & 63] + lookup[num & 63];
8
+ }
9
+ function encodeChunk(uint8, start, end) {
10
+ var tmp;
11
+ var output = [];
12
+ for (var i = start; i < end; i += 3) {
13
+ tmp = (uint8[i] << 16 & 16711680) + (uint8[i + 1] << 8 & 65280) + (uint8[i + 2] & 255);
14
+ output.push(tripletToBase64(tmp));
15
+ }
16
+ return output.join("");
17
+ }
18
+ function fromByteArray(uint8) {
19
+ var tmp;
20
+ var len = uint8.length;
21
+ var extraBytes = len % 3;
22
+ var parts = [];
23
+ var maxChunkLength = 16383;
24
+ for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
25
+ parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));
26
+ }
27
+ if (extraBytes === 1) {
28
+ tmp = uint8[len - 1];
29
+ parts.push(
30
+ lookup[tmp >> 2] + lookup[tmp << 4 & 63] + "=="
31
+ );
32
+ } else if (extraBytes === 2) {
33
+ tmp = (uint8[len - 2] << 8) + uint8[len - 1];
34
+ parts.push(
35
+ lookup[tmp >> 10] + lookup[tmp >> 4 & 63] + lookup[tmp << 2 & 63] + "="
36
+ );
37
+ }
38
+ return parts.join("");
39
+ }
40
+ export {
41
+ fromByteArray
42
+ };
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@scaleway/sdk-client",
3
+ "version": "1.1.0",
4
+ "license": "Apache-2.0",
5
+ "description": "Scaleway SDK Client",
6
+ "keywords": [
7
+ "scaleway",
8
+ "cloud",
9
+ "sdk",
10
+ "client"
11
+ ],
12
+ "main": "dist/index.cjs",
13
+ "module": "dist/index.js",
14
+ "types": "dist/index.d.ts",
15
+ "scripts": {
16
+ "typecheck": "tsc --noEmit",
17
+ "type:generate": "tsc --declaration -p tsconfig.build.json",
18
+ "build": "vite build --config ../../vite.config.ts && pnpm run type:generate && tsc-alias -p tsconfig.build.json",
19
+ "build:profile": "npx vite-bundle-visualizer -c ../../vite.config.ts"
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/scaleway/scaleway-sdk-js",
30
+ "directory": "packages/client"
31
+ },
32
+ "engines": {
33
+ "node": ">=18.0"
34
+ },
35
+ "type": "module",
36
+ "gitHead": "3436da6ff6b394f1000688c996f96c2471b2598a"
37
+ }