@aligent/microservice-util-lib 0.2.2 → 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 (71) hide show
  1. package/README.md +2 -2
  2. package/docs/classes/S3Dao.md +102 -107
  3. package/docs/functions/apiKeyAuthMiddleware.md +37 -0
  4. package/docs/functions/basicAuthMiddleware.md +37 -0
  5. package/docs/functions/chunkBy.md +43 -0
  6. package/docs/functions/fetchSsmParams.md +61 -0
  7. package/docs/functions/getAwsIdFromArn.md +37 -0
  8. package/docs/functions/hasDefinedProperties.md +57 -0
  9. package/docs/functions/oAuth10aAuthMiddleware.md +43 -0
  10. package/docs/functions/oAuth20AuthMiddleware.md +37 -0
  11. package/docs/functions/remap.md +71 -0
  12. package/docs/functions/retryWrapper.md +46 -0
  13. package/docs/interfaces/ApiKey.md +44 -0
  14. package/docs/interfaces/Basic.md +32 -0
  15. package/docs/interfaces/OAuth10a.md +93 -0
  16. package/docs/interfaces/OAuth20.md +44 -0
  17. package/docs/interfaces/RetryConfig.md +53 -42
  18. package/docs/modules.md +21 -267
  19. package/docs/type-aliases/ObjectMap.md +13 -0
  20. package/docs/type-aliases/Remap.md +21 -0
  21. package/package.json +15 -40
  22. package/{dist/chunkBy/chunkBy.js → src/chunk-by/chunk-by.js} +3 -4
  23. package/{dist/fetchSsmParams/fetchSsmParams.d.ts → src/fetch-ssm-params/fetch-ssm-params.d.ts} +2 -2
  24. package/src/fetch-ssm-params/fetch-ssm-params.js +28 -0
  25. package/src/get-aws-id-from-arn/get-aws-id-from-arn.d.ts +12 -0
  26. package/src/get-aws-id-from-arn/get-aws-id-from-arn.js +20 -0
  27. package/{dist/hasPropertiesDefined/hasPropertiesDefined.js → src/has-properties-defined/has-properties-defined.js} +2 -8
  28. package/src/index.d.ts +10 -0
  29. package/src/index.js +24 -0
  30. package/src/openapi-fetch-middlewares/authentications.d.ts +66 -0
  31. package/src/openapi-fetch-middlewares/authentications.js +96 -0
  32. package/src/openapi-fetch-middlewares/oauth10a/oauth10a.d.ts +12 -0
  33. package/src/openapi-fetch-middlewares/oauth10a/oauth10a.js +209 -0
  34. package/src/openapi-fetch-middlewares/types/authentications.d.ts +71 -0
  35. package/src/openapi-fetch-middlewares/types/authentications.js +2 -0
  36. package/{dist → src}/remap/remap.d.ts +6 -6
  37. package/src/remap/remap.js +97 -0
  38. package/{dist/retryWrapper/retryWrapper.d.ts → src/retry-wrapper/retry-wrapper.d.ts} +1 -1
  39. package/src/retry-wrapper/retry-wrapper.js +56 -0
  40. package/{dist → src}/s3/s3.d.ts +3 -6
  41. package/src/s3/s3.js +86 -0
  42. package/dist/chunkBy/chunkBy.js.map +0 -1
  43. package/dist/chunkBy/chunkBy.test.d.ts +0 -1
  44. package/dist/chunkBy/chunkBy.test.js +0 -17
  45. package/dist/chunkBy/chunkBy.test.js.map +0 -1
  46. package/dist/fetchSsmParams/fetchSsmParams.js +0 -80
  47. package/dist/fetchSsmParams/fetchSsmParams.js.map +0 -1
  48. package/dist/fetchSsmParams/fetchSsmParams.test.d.ts +0 -1
  49. package/dist/fetchSsmParams/fetchSsmParams.test.js +0 -110
  50. package/dist/fetchSsmParams/fetchSsmParams.test.js.map +0 -1
  51. package/dist/hasPropertiesDefined/hasPropertiesDefined.js.map +0 -1
  52. package/dist/hasPropertiesDefined/hasPropertiesDefined.test.d.ts +0 -1
  53. package/dist/hasPropertiesDefined/hasPropertiesDefined.test.js +0 -37
  54. package/dist/hasPropertiesDefined/hasPropertiesDefined.test.js.map +0 -1
  55. package/dist/index.d.ts +0 -7
  56. package/dist/index.js +0 -19
  57. package/dist/index.js.map +0 -1
  58. package/dist/remap/remap.js +0 -50
  59. package/dist/remap/remap.js.map +0 -1
  60. package/dist/remap/remap.test.d.ts +0 -1
  61. package/dist/remap/remap.test.js +0 -65
  62. package/dist/remap/remap.test.js.map +0 -1
  63. package/dist/retryWrapper/retryWrapper.js +0 -121
  64. package/dist/retryWrapper/retryWrapper.js.map +0 -1
  65. package/dist/retryWrapper/retryWrapper.test.d.ts +0 -1
  66. package/dist/retryWrapper/retryWrapper.test.js +0 -234
  67. package/dist/retryWrapper/retryWrapper.test.js.map +0 -1
  68. package/dist/s3/s3.js +0 -192
  69. package/dist/s3/s3.js.map +0 -1
  70. /package/{dist/chunkBy/chunkBy.d.ts → src/chunk-by/chunk-by.d.ts} +0 -0
  71. /package/{dist/hasPropertiesDefined/hasPropertiesDefined.d.ts → src/has-properties-defined/has-properties-defined.d.ts} +0 -0
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.apiKeyAuthMiddleware = apiKeyAuthMiddleware;
4
+ exports.basicAuthMiddleware = basicAuthMiddleware;
5
+ exports.oAuth10aAuthMiddleware = oAuth10aAuthMiddleware;
6
+ exports.oAuth20AuthMiddleware = oAuth20AuthMiddleware;
7
+ const oauth10a_1 = require("./oauth10a/oauth10a");
8
+ /**
9
+ * Creates an openapi-fetch middleware for API key authentication.
10
+ * This middleware sets the API key in the specified header for each request.
11
+ *
12
+ * @param {ApiKey} config - The configuration for API key authentication.
13
+ * @returns {Middleware} The middleware for API key authentication.
14
+ *
15
+ * @example
16
+ * const middleware = apiKeyAuthMiddleware({
17
+ * header: 'x-api-key',
18
+ * value: async () => 'your-api-key',
19
+ * });
20
+ */
21
+ function apiKeyAuthMiddleware(config) {
22
+ return {
23
+ onRequest: async ({ request }) => {
24
+ request.headers.set(config.header, await config.value());
25
+ },
26
+ };
27
+ }
28
+ /**
29
+ * Creates an openapi-fetch middleware for Basic authentication.
30
+ * This middleware sets the `Authorization` header with the Basic authentication credentials
31
+ * (username and password) for each request.
32
+ *
33
+ * @param {Basic} config - The configuration for Basic authentication.
34
+ * @returns {Middleware} The middleware for Basic authentication.
35
+ *
36
+ * @example
37
+ * const middleware = basicAuthMiddleware({
38
+ * credentials: async () => ({ username: 'user', password: 'pass' }),
39
+ * });
40
+ */
41
+ function basicAuthMiddleware(config) {
42
+ return {
43
+ onRequest: async ({ request }) => {
44
+ const { username, password } = await config.credentials();
45
+ request.headers.set('Authorization', `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`);
46
+ },
47
+ };
48
+ }
49
+ /**
50
+ * Creates an openapi-fetch middleware for OAuth 1.0a authentication.
51
+ * This middleware generates OAuth 1.0a parameters and sets the `Authorization` header
52
+ * for each request.
53
+ *
54
+ * @param {OAuth10a} config - The configuration for OAuth 1.0a authentication.
55
+ * @returns {Middleware} The middleware for OAuth 1.0a authentication.
56
+ *
57
+ * @example
58
+ * const middleware = oAuth10aAuthMiddleware({
59
+ * algorithm: 'HMAC-SHA256',
60
+ * credentials: async () => ({
61
+ * consumerKey: 'key',
62
+ * consumerSecret: 'secret',
63
+ * token: 'token',
64
+ * tokenSecret: 'tokenSecret',
65
+ * }),
66
+ * });
67
+ */
68
+ function oAuth10aAuthMiddleware(config) {
69
+ return {
70
+ onRequest: async ({ request, options, params }) => {
71
+ const oauthParams = await (0, oauth10a_1.generateOauthParams)(request, options, params, config);
72
+ request.headers.set('Authorization', `OAuth ${oauthParams}`);
73
+ },
74
+ };
75
+ }
76
+ /**
77
+ * Creates an openapi-fetch middleware for OAuth 2.0 authentication.
78
+ * This middleware sets the `Authorization` header with the OAuth 2.0 token for each request.
79
+ *
80
+ * @param {OAuth20} options - The configuration for OAuth 2.0 authentication.
81
+ * @returns {Middleware} The middleware for OAuth 2.0 authentication.
82
+ *
83
+ * @example
84
+ * const middleware = oAuth20AuthMiddleware({
85
+ * token: async () => 'your-access-token',
86
+ * tokenType: 'Bearer',
87
+ * });
88
+ */
89
+ function oAuth20AuthMiddleware(options) {
90
+ return {
91
+ onRequest: async ({ request }) => {
92
+ const { tokenType = 'Bearer' } = options;
93
+ request.headers.set('Authorization', `${tokenType} ${await options.token()}`);
94
+ },
95
+ };
96
+ }
@@ -0,0 +1,12 @@
1
+ import { MiddlewareCallbackParams } from 'openapi-fetch';
2
+ import { OAuth10a } from '../authentications';
3
+ /**
4
+ * Generates OAuth 1.0a parameters for signing a request.
5
+ *
6
+ * @param {MiddlewareCallbackParams['request']} request - The request object.
7
+ * @param {MiddlewareCallbackParams['options']} options - The options object.
8
+ * @param {MiddlewareCallbackParams['params']} params - The parameters object.
9
+ * @param {OAuth10a} config - The OAuth 1.0a configuration.
10
+ * @returns {Promise<string>} The generated OAuth 1.0a Authorization header.
11
+ */
12
+ export declare function generateOauthParams(request: MiddlewareCallbackParams['request'], options: MiddlewareCallbackParams['options'], params: MiddlewareCallbackParams['params'], config: OAuth10a): Promise<string>;
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateOauthParams = generateOauthParams;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const oauth_sign_1 = require("oauth-sign");
9
+ /**
10
+ * Determines whether a given URL is absolute.
11
+ *
12
+ * A URL is considered absolute if it begins with a scheme (e.g., "http://", "https://")
13
+ * or is protocol-relative (e.g., "//example.com").
14
+ * RFC 3986 defines scheme name as a sequence of characters beginning with a letter
15
+ * and followed by any combination of letters, digits, plus, period, or hyphen.
16
+ *
17
+ * @param {string} url - The URL to check.
18
+ * @returns {boolean} `true` if the URL is absolute, otherwise `false`.
19
+ *
20
+ * @example
21
+ * isAbsoluteURL('https://example.com'); // true
22
+ * isAbsoluteURL('//example.com'); // true
23
+ * isAbsoluteURL('/relative/path'); // false
24
+ */
25
+ function isAbsoluteURL(url) {
26
+ return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url);
27
+ }
28
+ /**
29
+ * Combines a base URL and a relative URL into a single URL.
30
+ *
31
+ * @param {string} baseURL - The base URL.
32
+ * @param {string} relativeURL - The relative URL to combine with the base URL.
33
+ * @returns {string} The combined URL.
34
+ *
35
+ * @example
36
+ * combineURLs('https://example.com', '/path'); // 'https://example.com/path'
37
+ */
38
+ function combineURLs(baseURL, relativeURL) {
39
+ return relativeURL
40
+ ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
41
+ : baseURL;
42
+ }
43
+ /**
44
+ * Replaces placeholders in a URL with corresponding values from the path parameters.
45
+ *
46
+ * @param {string} url - The URL containing placeholders (e.g., `{id}`).
47
+ * @param {Record<string, unknown>} [pathParams] - The path parameters to replace in the URL.
48
+ * @returns {string} The URL with placeholders replaced by actual values.
49
+ *
50
+ * @example
51
+ * combineUrlAndPathParams('/users/{id}', { id: 123 }); // '/users/123'
52
+ */
53
+ function combineUrlAndPathParams(url, pathParams) {
54
+ if (!pathParams) {
55
+ return url;
56
+ }
57
+ for (const [key, value] of Object.entries(pathParams)) {
58
+ url = url.replace(`{${key}}`, String(value));
59
+ }
60
+ return url;
61
+ }
62
+ /**
63
+ * Processes a URL for OAuth 1.0a by removing unnecessary parts and preparing it for signing.
64
+ *
65
+ * @param {string} baseURL - The base URL.
66
+ * @param {string} url - The URL to process.
67
+ * @returns {{ baseUri: string, searchParams: URLSearchParams | null }} The processed URL and its search parameters.
68
+ */
69
+ function handleOAuthUrl(baseURL, url) {
70
+ const oauthUrl = new URL(!baseURL || isAbsoluteURL(url) ? url : combineURLs(baseURL, url));
71
+ let searchParams = null;
72
+ // Query parameters are hashed as part of params rather than as part of the URL
73
+ if (oauthUrl.search) {
74
+ searchParams = new URLSearchParams(oauthUrl.search);
75
+ oauthUrl.search = '';
76
+ }
77
+ // Do not include hash in signature
78
+ oauthUrl.hash = '';
79
+ // Remove port if it is the default for that protocol
80
+ if ((oauthUrl.protocol === 'https:' && oauthUrl.port === '443') ||
81
+ (oauthUrl.protocol === 'http:' && oauthUrl.port === '80')) {
82
+ oauthUrl.port = '';
83
+ }
84
+ return {
85
+ baseUri: oauthUrl.toString(),
86
+ searchParams,
87
+ };
88
+ }
89
+ /**
90
+ * Adds a parameter to the list of parameters to sign.
91
+ *
92
+ * @param {Record<string, string | string[]>} paramsToSign - The parameters to sign.
93
+ * @param {string} key - The key of the parameter.
94
+ * @param {string} value - The value of the parameter.
95
+ */
96
+ function addParamToSign(paramsToSign, key, value) {
97
+ const existingValue = paramsToSign[key];
98
+ if (typeof existingValue === 'string') {
99
+ paramsToSign[key] = [existingValue, value];
100
+ }
101
+ else if (Array.isArray(existingValue)) {
102
+ existingValue.push(value);
103
+ }
104
+ else {
105
+ paramsToSign[key] = value;
106
+ }
107
+ }
108
+ /**
109
+ * Adds multiple parameters to the list of parameters to sign.
110
+ *
111
+ * @param {Record<string, string | string[]>} paramsToSign - The parameters to sign.
112
+ * @param {URLSearchParams | Record<string, unknown> | string} params - The parameters to add.
113
+ */
114
+ function addParamsToSign(paramsToSign, params) {
115
+ // Ensure `params` is compatible with `URLSearchParams`
116
+ const normalizedParams = typeof params === 'string' || params instanceof URLSearchParams
117
+ ? params
118
+ : Object.entries(params).reduce((acc, [key, value]) => {
119
+ acc[key] = Array.isArray(value) ? value.map(String) : String(value);
120
+ return acc;
121
+ }, {});
122
+ new URLSearchParams(normalizedParams).forEach((value, key) => {
123
+ addParamToSign(paramsToSign, key, value);
124
+ });
125
+ }
126
+ /**
127
+ * Determines whether a body hash should be generated for the request.
128
+ *
129
+ * @param {string} body - The request body.
130
+ * @param {string} method - The HTTP method.
131
+ * @param {OAuth10a['includeBodyHash']} includeBodyHash - The body hash inclusion setting.
132
+ * @returns {boolean} `true` if a body hash should be generated, otherwise `false`.
133
+ */
134
+ function shouldGenerateBodyHash(body, method, includeBodyHash) {
135
+ if (includeBodyHash === 'auto' && ['POST', 'PUT'].includes(method) && body) {
136
+ return true;
137
+ }
138
+ return includeBodyHash === true;
139
+ }
140
+ /**
141
+ * Generates OAuth 1.0a parameters for signing a request.
142
+ *
143
+ * @param {MiddlewareCallbackParams['request']} request - The request object.
144
+ * @param {MiddlewareCallbackParams['options']} options - The options object.
145
+ * @param {MiddlewareCallbackParams['params']} params - The parameters object.
146
+ * @param {OAuth10a} config - The OAuth 1.0a configuration.
147
+ * @returns {Promise<string>} The generated OAuth 1.0a Authorization header.
148
+ */
149
+ async function generateOauthParams(request, options, params, config) {
150
+ const { algorithm, includeBodyHash = 'auto', realm, callback, verifier } = config;
151
+ const { consumerKey, consumerSecret, token, tokenSecret } = await config.credentials();
152
+ const method = (request.method || 'GET').toUpperCase();
153
+ const url = combineUrlAndPathParams(request.url, params.path);
154
+ const oauthParams = {
155
+ oauth_consumer_key: consumerKey,
156
+ oauth_nonce: crypto_1.default.randomUUID(),
157
+ oauth_signature_method: algorithm,
158
+ oauth_timestamp: String(Math.floor(Date.now() * 0.001)),
159
+ oauth_version: '1.0',
160
+ };
161
+ // if provided, oauth_token can be included in the oauth parameters
162
+ // more information: https://datatracker.ietf.org/doc/html/rfc5849#section-3.1
163
+ if (token) {
164
+ oauthParams.oauth_token = token;
165
+ }
166
+ if (callback) {
167
+ oauthParams.oauth_callback = callback;
168
+ }
169
+ if (verifier) {
170
+ oauthParams.oauth_verifier = verifier;
171
+ }
172
+ const paramsToSign = {};
173
+ addParamsToSign(paramsToSign, oauthParams);
174
+ if (params.query) {
175
+ addParamsToSign(paramsToSign, params.query);
176
+ }
177
+ const { baseUri, searchParams } = handleOAuthUrl(options.baseUrl, url);
178
+ if (searchParams) {
179
+ addParamsToSign(paramsToSign, searchParams);
180
+ }
181
+ const body = await request.text();
182
+ // If user submit a form, then include form parameters in the
183
+ // signature as parameters rather than the body hash
184
+ if (request.headers.get('Content-Type') === 'application/x-www-form-urlencoded') {
185
+ addParamsToSign(paramsToSign, new URLSearchParams(body));
186
+ console.log(JSON.stringify(paramsToSign));
187
+ }
188
+ else {
189
+ if (shouldGenerateBodyHash(body, method, includeBodyHash)) {
190
+ const bodyHash = crypto_1.default
191
+ .createHash(algorithm === 'HMAC-SHA1' ? 'sha1' : 'sha256')
192
+ .update(Buffer.from(body))
193
+ .digest('base64');
194
+ oauthParams.oauth_body_hash = bodyHash;
195
+ addParamToSign(paramsToSign, 'oauth_body_hash', bodyHash);
196
+ }
197
+ }
198
+ oauthParams.oauth_signature = (0, oauth_sign_1.sign)(algorithm, method, baseUri, paramsToSign, consumerSecret, tokenSecret);
199
+ // realm should not be included in the signature calculation
200
+ // but is optional in the OAuth 1.0 Authorization header
201
+ // so we need to add it after signing the request
202
+ // more information: https://datatracker.ietf.org/doc/html/rfc5849#section-3.4.1.3.1
203
+ if (realm) {
204
+ oauthParams.realm = realm;
205
+ }
206
+ return Object.entries(oauthParams)
207
+ .map(e => [e[0], '="', (0, oauth_sign_1.rfc3986)(e[1]), '"'].join(''))
208
+ .join(',');
209
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Represents an API key authentication method.
3
+ *
4
+ * This interface is used for API key-based authentication, where the key is sent
5
+ * in a specific header. The value of the API key is retrieved asynchronously.
6
+ *
7
+ * @interface ApiKey
8
+ * @property {string} header - The header name where the API key will be set.
9
+ * @property {() => Promise<string>} value - A function that returns a promise resolving to the API key value.
10
+ */
11
+ export interface ApiKey {
12
+ header: string;
13
+ value: () => Promise<string>;
14
+ }
15
+ /**
16
+ * Represents basic authentication credentials.
17
+ *
18
+ * This interface is used for basic authentication, where the username and password
19
+ * are retrieved asynchronously.
20
+ *
21
+ * @interface Basic
22
+ * @property {() => Promise<{ username: string; password: string }>} credentials - A function that returns a promise resolving to the username and password.
23
+ */
24
+ export interface Basic {
25
+ credentials: () => Promise<{
26
+ username: string;
27
+ password: string;
28
+ }>;
29
+ }
30
+ /**
31
+ * Represents OAuth 1.0a authentication credentials.
32
+ *
33
+ * This interface is used for OAuth 1.0a authentication, where the consumer key, consumer secret,
34
+ * token, and token secret are retrieved asynchronously. It also supports optional parameters
35
+ * like body hash inclusion, realm, callback, and verifier.
36
+ *
37
+ * @interface OAuth10a
38
+ * @property {'HMAC-SHA1' | 'HMAC-SHA256'} algorithm - The signing algorithm to use.
39
+ * @property {() => Promise<{ consumerKey: string; consumerSecret: string; token?: string; tokenSecret: string }>} credentials - A function that returns a promise resolving to the OAuth 1.0a credentials.
40
+ * @property {boolean | 'auto'} [includeBodyHash] - Whether to include a body hash in the signature. Defaults to 'auto'.
41
+ * @property {string} [realm] - The realm parameter for the Authorization header.
42
+ * @property {string} [callback] - The callback URL for OAuth 1.0a.
43
+ * @property {string} [verifier] - The verifier for OAuth 1.0a.
44
+ */
45
+ export interface OAuth10a {
46
+ algorithm: 'HMAC-SHA1' | 'HMAC-SHA256';
47
+ credentials: () => Promise<{
48
+ consumerKey: string;
49
+ consumerSecret: string;
50
+ token?: string;
51
+ tokenSecret: string;
52
+ }>;
53
+ includeBodyHash?: boolean | 'auto';
54
+ realm?: string;
55
+ callback?: string;
56
+ verifier?: string;
57
+ }
58
+ /**
59
+ * Represents OAuth 2.0 authentication credentials.
60
+ *
61
+ * This interface is used for OAuth 2.0 authentication, where an access token is retrieved
62
+ * asynchronously. It also supports an optional token type (e.g., 'Bearer').
63
+ *
64
+ * @interface OAuth20
65
+ * @property {() => Promise<string>} token - A function that returns a promise resolving to the access token.
66
+ * @property {string} [tokenType] - The type of the token (e.g., 'Bearer'). Defaults to 'Bearer' if not specified.
67
+ */
68
+ export interface OAuth20 {
69
+ token: () => Promise<string>;
70
+ tokenType?: string;
71
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -3,7 +3,7 @@ export type SimplifyIntersection<A> = A extends object ? {
3
3
  [K in keyof A]: A[K] extends object ? SimplifyIntersection<A[K]> : A[K];
4
4
  } : A;
5
5
  /** A list of keys to keys, with an optional transformer function */
6
- type ObjectMap = readonly ((readonly [string, string, ((...args: any[]) => any)?]))[];
6
+ type ObjectMap = ReadonlyArray<readonly [string, string, ((...args: any[]) => any)?]>;
7
7
  /**
8
8
  * Given a Key, a base Object and an ObjectMap, this will return the
9
9
  * type of the property referencable by the Key on the base Object, or in
@@ -28,11 +28,11 @@ type ObjectMap = readonly ((readonly [string, string, ((...args: any[]) => any)?
28
28
  */
29
29
  type GetKeyType<Key extends string, O extends {
30
30
  [key: string]: any;
31
- }, M extends ObjectMap[number]> = M extends readonly [string, string, ((...args: any[]) => (infer U))] ? unknown extends U ? Key extends `${infer K}.${infer Rest}` ? GetKeyType<Rest, O[K], M> : O[Key] : U : Key extends `${infer K}.${infer Rest}` ? GetKeyType<Rest, O[K], M> : O[Key];
31
+ }, M extends ObjectMap[number]> = M extends readonly [string, string, (...args: any[]) => infer U] ? unknown extends U ? Key extends `${infer K}.${infer Rest}` ? GetKeyType<Rest, O[K], M> : O[Key] : U : Key extends `${infer K}.${infer Rest}` ? GetKeyType<Rest, O[K], M> : O[Key];
32
32
  /**
33
- * Given an ObjectMap, return a new ObjectMap with the first index of each
34
- * tuple replaced with the value of the second index
35
- */
33
+ * Given an ObjectMap, return a new ObjectMap with the first index of each
34
+ * tuple replaced with the value of the second index
35
+ */
36
36
  type OverrideIndex<M extends ObjectMap[number], V extends string> = readonly [M[0], V, M[2]];
37
37
  /**
38
38
  * Given a key and a base object, return the type of the property referencable
@@ -143,5 +143,5 @@ type Remap<MapArray extends ObjectMap, Original extends {
143
143
  declare function remap<Original extends {
144
144
  [key: string]: any;
145
145
  }, MapArray extends ObjectMap>(object: Original, map: MapArray): Remap<MapArray, Original>;
146
- export { Remap, ObjectMap };
146
+ export type { ObjectMap, Remap };
147
147
  export default remap;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ /**
5
+ * Get a value from an object using a dot-notation path
6
+ * @param obj The object to get the value from
7
+ * @param path The dot-notation path (e.g., 'foo.bar.baz')
8
+ * @returns The value at the path, or undefined if not found
9
+ */
10
+ function getValue(obj, path) {
11
+ let current = obj;
12
+ for (const key of path.split('.')) {
13
+ if (current == null)
14
+ return undefined;
15
+ current = current[key];
16
+ }
17
+ return current;
18
+ }
19
+ /**
20
+ * Check if a key looks like an array index (numeric string)
21
+ */
22
+ function isArrayIndex(key) {
23
+ return /^\d+$/.test(key);
24
+ }
25
+ /**
26
+ * Set a value in an object using a dot-notation path
27
+ * @param obj The object to set the value in
28
+ * @param path The dot-notation path (e.g., 'foo.bar.baz')
29
+ * @param value The value to set
30
+ */
31
+ function setValue(obj, path, value) {
32
+ const keys = path.split('.').filter(key => !!key); // Skip empty keys, e.g. in 'foo..bar'
33
+ const lastKey = keys.pop();
34
+ if (!lastKey) {
35
+ // Somehow we've been given a path with no keys, so we can't set anything
36
+ return;
37
+ }
38
+ // Navigate to the parent object, creating nested structures as needed
39
+ let current = obj;
40
+ for (let i = 0; i < keys.length; i++) {
41
+ const key = keys[i]; // We've already filtered out empty keys, so this is safe
42
+ // If this key already has a valid object to put the next key on, continue
43
+ if (key in current && typeof current[key] === 'object' && current[key] !== null) {
44
+ current = current[key];
45
+ continue;
46
+ }
47
+ // Otherwise, set the current key as an object or array based on what the next key is
48
+ const nextKey = keys.at(i + 1) ?? lastKey;
49
+ current[key] = isArrayIndex(nextKey) ? [] : {};
50
+ current = current[key];
51
+ }
52
+ // Set the final value
53
+ current[lastKey] = value;
54
+ }
55
+ /**
56
+ * Map one object's values to another structure
57
+ * @param object the object to map from
58
+ * @param map the keys for the mapping
59
+ * @returns the remapped object
60
+ *
61
+ * @example without a transformer function
62
+ * ```ts
63
+ * const map = [
64
+ * ['foo', 'baz'],
65
+ * ['bar', 'qux.0']
66
+ * ] as const;
67
+ * const obj = { foo: 'hi', bar: 7 }
68
+ * remap(obj, map); // { baz: 'hi', qux: [7] }
69
+ * ```
70
+ * @example with a transformer function
71
+ * ```ts
72
+ * const map = [
73
+ * ['foo', 'baz'],
74
+ * ['bar', 'qux.0', (x: number) => x + 1]
75
+ * ] as const;
76
+ * const obj = { foo: 'hi', bar: 7 }
77
+ * remap(obj, map); // { baz: 'hi', qux: [8] }
78
+ * ```
79
+ * @example with an empty initial key
80
+ * ```ts
81
+ * const map = [
82
+ * ['', 'baz', (x: { foo: number, bar: number }) => x.foo + x.bar]
83
+ * ]
84
+ * const obj = { foo: 3, bar: 7 }
85
+ * remap(obj, map); // { baz: 10 }
86
+ * ```
87
+ */
88
+ function remap(object, map) {
89
+ const out = {};
90
+ map.forEach(item => {
91
+ const parser = item[2] ? item[2] : (val) => val;
92
+ const value = item[0] ? getValue(object, item[0]) : object;
93
+ setValue(out, item[1], parser(value));
94
+ });
95
+ return out;
96
+ }
97
+ exports.default = remap;
@@ -36,5 +36,5 @@ interface RetryConfig {
36
36
  * ```
37
37
  */
38
38
  declare function retryWrapper<T>(fn: () => Promise<T>, config: RetryConfig): Promise<T>;
39
- export { RetryConfig };
39
+ export type { RetryConfig };
40
40
  export default retryWrapper;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Retry an async function if it fails
5
+ * @param fn the function to be retried
6
+ * @param config the configuration for retries
7
+ * @param retryCount the number of retries so far
8
+ * @param error the error from teh last retry
9
+ */
10
+ async function retryWrapperInternal(fn, config, retryCount, error) {
11
+ if (config.retries < 0) {
12
+ throw error;
13
+ }
14
+ if (error) {
15
+ if (config.onRetry) {
16
+ config.onRetry(retryCount, error, config);
17
+ }
18
+ }
19
+ try {
20
+ const result = await fn();
21
+ return result;
22
+ }
23
+ catch (err) {
24
+ await (() => new Promise(res => setTimeout(res, config.delay)))();
25
+ return await retryWrapperInternal(fn, {
26
+ ...config,
27
+ retries: config.retries - 1,
28
+ delay: config.delay + config.backoffAmount,
29
+ }, retryCount + 1, err);
30
+ }
31
+ }
32
+ /**
33
+ * Retry an async function if it fails
34
+ * @param fn the function to be retried
35
+ * @param config the configuration for retries
36
+ * @example
37
+ * ```ts
38
+ * retryWrapper(someAsyncFunction, {
39
+ * retries: 3,
40
+ * onRetry: (_, error) => console.error(error)
41
+ * });
42
+ * ```
43
+ */
44
+ async function retryWrapper(fn, config) {
45
+ const defaultConfig = {
46
+ retries: 1,
47
+ delay: 0,
48
+ backoffAmount: 0,
49
+ onRetry: () => null,
50
+ };
51
+ return await retryWrapperInternal(fn, {
52
+ ...defaultConfig,
53
+ ...config,
54
+ }, 0);
55
+ }
56
+ exports.default = retryWrapper;
@@ -20,7 +20,7 @@ declare class S3Dao {
20
20
  * @param chunkSize the number of entries that should be in each chunk
21
21
  * @returns an array of objects which can be used to fetch the chunks
22
22
  */
23
- storeChunked<T extends any[]>(data: T, chunkSize: number): Promise<GetObjectCommandInput[]>;
23
+ storeChunked<T extends unknown[]>(data: T, chunkSize: number): Promise<GetObjectCommandInput[]>;
24
24
  /**
25
25
  * Fetch an object from the S3 bucket
26
26
  * @param objectDetails the object which describes the location of the object
@@ -33,11 +33,8 @@ declare class S3Dao {
33
33
  */
34
34
  fetchChunks<T>(chunks: GetObjectCommandInput[]): AsyncGenerator<{
35
35
  chunk: T;
36
- s3Object: GetObjectCommandInput;
37
- }, {
38
- chunk: T;
39
- s3Object: GetObjectCommandInput;
40
- }, unknown>;
36
+ s3Object: GetObjectCommandInput | undefined;
37
+ }, Awaited<T>, unknown>;
41
38
  /**
42
39
  * Delete an object from the S3 bucket
43
40
  * @param objectDetails the object to delete