lambda-toolkit 1.1.0 → 2.0.0-dev.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.
@@ -1,2065 +1,1692 @@
1
1
  /******/ (() => { // webpackBootstrap
2
- /******/ var __webpack_modules__ = ({
2
+ /******/ "use strict";
3
+ /******/ // The require scope
4
+ /******/ var __webpack_require__ = {};
5
+ /******/
6
+ /************************************************************************/
7
+ /******/ /* webpack/runtime/define property getters */
8
+ /******/ (() => {
9
+ /******/ // define getter functions for harmony exports
10
+ /******/ __webpack_require__.d = (exports, definition) => {
11
+ /******/ for(var key in definition) {
12
+ /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
13
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
14
+ /******/ }
15
+ /******/ }
16
+ /******/ };
17
+ /******/ })();
18
+ /******/
19
+ /******/ /* webpack/runtime/hasOwnProperty shorthand */
20
+ /******/ (() => {
21
+ /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
22
+ /******/ })();
23
+ /******/
24
+ /******/ /* webpack/runtime/make namespace object */
25
+ /******/ (() => {
26
+ /******/ // define __esModule on exports
27
+ /******/ __webpack_require__.r = (exports) => {
28
+ /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
29
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
30
+ /******/ }
31
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
32
+ /******/ };
33
+ /******/ })();
34
+ /******/
35
+ /************************************************************************/
36
+ var __webpack_exports__ = {};
37
+ // ESM COMPAT FLAG
38
+ __webpack_require__.r(__webpack_exports__);
39
+
40
+ // EXPORTS
41
+ __webpack_require__.d(__webpack_exports__, {
42
+ LambdaApi: () => (/* reexport */ src_lambda_api_namespaceObject),
43
+ array: () => (/* reexport */ array_namespaceObject),
44
+ aws: () => (/* reexport */ aws_namespaceObject),
45
+ epoch: () => (/* reexport */ epoch_namespaceObject),
46
+ math: () => (/* reexport */ math_namespaceObject),
47
+ object: () => (/* reexport */ object_namespaceObject),
48
+ redis: () => (/* reexport */ redis_namespaceObject),
49
+ string: () => (/* reexport */ string_namespaceObject),
50
+ utils: () => (/* reexport */ utils_namespaceObject)
51
+ });
52
+
53
+ // NAMESPACE OBJECT: ./src/lambda_api/index.js
54
+ var src_lambda_api_namespaceObject = {};
55
+ __webpack_require__.r(src_lambda_api_namespaceObject);
56
+ __webpack_require__.d(src_lambda_api_namespaceObject, {
57
+ LambdaApi: () => (LambdaApi)
58
+ });
59
+
60
+ // NAMESPACE OBJECT: ./src/array/index.js
61
+ var array_namespaceObject = {};
62
+ __webpack_require__.r(array_namespaceObject);
63
+ __webpack_require__.d(array_namespaceObject, {
64
+ joinUnique: () => (joinUnique),
65
+ joinUniqueCustom: () => (joinUniqueCustom),
66
+ splitBatches: () => (splitBatches)
67
+ });
68
+
69
+ // NAMESPACE OBJECT: ./src/aws/index.js
70
+ var aws_namespaceObject = {};
71
+ __webpack_require__.r(aws_namespaceObject);
72
+ __webpack_require__.d(aws_namespaceObject, {
73
+ athena: () => (athena),
74
+ cwLogs: () => (cwLogs),
75
+ dynamo: () => (dynamo),
76
+ lambda: () => (lambda),
77
+ s3: () => (s3),
78
+ ses: () => (ses),
79
+ sns: () => (sns),
80
+ sqs: () => (sqs),
81
+ ssm: () => (ssm),
82
+ timestreamQuery: () => (timestreamQuery),
83
+ timestreamWrite: () => (timestreamWrite)
84
+ });
85
+
86
+ // NAMESPACE OBJECT: ./src/epoch/index.js
87
+ var epoch_namespaceObject = {};
88
+ __webpack_require__.r(epoch_namespaceObject);
89
+ __webpack_require__.d(epoch_namespaceObject, {
90
+ days: () => (days),
91
+ hours: () => (hours),
92
+ minutes: () => (minutes),
93
+ months: () => (months),
94
+ msToS: () => (msToS),
95
+ round: () => (round),
96
+ seconds: () => (seconds)
97
+ });
98
+
99
+ // NAMESPACE OBJECT: ./src/math/index.js
100
+ var math_namespaceObject = {};
101
+ __webpack_require__.r(math_namespaceObject);
102
+ __webpack_require__.d(math_namespaceObject, {
103
+ calcMean: () => (calcMean),
104
+ calcMedian: () => (calcMedian),
105
+ calcMedianAbsDev: () => (calcMedianAbsDev),
106
+ calcStdDevPopulation: () => (calcStdDevPopulation),
107
+ calcStdDevSample: () => (calcStdDevSample),
108
+ calcZScore: () => (calcZScore),
109
+ roundGaussian: () => (roundGaussian),
110
+ roundStandard: () => (roundStandard)
111
+ });
112
+
113
+ // NAMESPACE OBJECT: ./src/object/index.js
114
+ var object_namespaceObject = {};
115
+ __webpack_require__.r(object_namespaceObject);
116
+ __webpack_require__.d(object_namespaceObject, {
117
+ camelize: () => (camelize_camelize),
118
+ filterProps: () => (filterProps),
119
+ removeEmptyArrays: () => (removeEmptyArrays),
120
+ snakelize: () => (snakelize_snakelize)
121
+ });
122
+
123
+ // NAMESPACE OBJECT: ./src/redis/index.js
124
+ var redis_namespaceObject = {};
125
+ __webpack_require__.r(redis_namespaceObject);
126
+ __webpack_require__.d(redis_namespaceObject, {
127
+ createClient: () => (createClient)
128
+ });
129
+
130
+ // NAMESPACE OBJECT: ./src/string/index.js
131
+ var string_namespaceObject = {};
132
+ __webpack_require__.r(string_namespaceObject);
133
+ __webpack_require__.d(string_namespaceObject, {
134
+ camelize: () => (camelize),
135
+ capitalizeWords: () => (capitalizeWords),
136
+ snakelize: () => (snakelize)
137
+ });
138
+
139
+ // NAMESPACE OBJECT: ./src/utils/index.js
140
+ var utils_namespaceObject = {};
141
+ __webpack_require__.r(utils_namespaceObject);
142
+ __webpack_require__.d(utils_namespaceObject, {
143
+ Timer: () => (Timer),
144
+ retryOnError: () => (retryOnError),
145
+ sleep: () => (sleep_sleep),
146
+ untarJsonGz: () => (untarJsonGz)
147
+ });
148
+
149
+ ;// ./src/lambda_api/text_enum.js
150
+ const Text = {
151
+ ERROR_500: 'Internal Server Error',
152
+ ERROR_405: 'Method Not Allowed',
153
+ INVALID_ERROR_TYPE: 'Argument "errorType" must be a constructor Function',
154
+ INVALID_FN: 'Argument "fn" must be of type function',
155
+ INVALID_METHOD: 'Argument "method" must be one of the default HTTP methods',
156
+ INVALID_STATUS_CODE: 'Argument "statusCode" must be valid HTTP Status Code',
157
+ INVALID_TRANSFORM_REQUEST: 'Argument "transformRequest" must be either "camelize", "snakelize", false or null',
158
+ INVALID_TRANSFORM_RESPONSE: 'Argument "transformResponse" must be either "camelize", "snakelize", false or null',
159
+ INVALID_MATCHER_ROUTE: 'Argument "route" must be either undefined or an string with length greater than 0',
160
+ INVALID_MATCHER_ROUTE_INCLUDES: 'Argument "routeIncludes" must be either undefined or an string with length greater than 0',
161
+ INVALID_MATCHER_ROUTE_NOT_INCLUDES: 'Argument "routeNotIncludes" must be either undefined or an string with length greater than 0',
162
+ INVALID_MATCHER_ROUTE_MATCH: 'Argument "routeMatch" must be either undefined or type RegExp',
163
+ INVALID_MATCHER_PATH: 'Argument "path" must be either undefined or an string with length greater than 0',
164
+ INVALID_MATCHER_PATH_INCLUDES: 'Argument "pathIncludes" must be either undefined or an string with length greater than 0',
165
+ INVALID_MATCHER_PATH_NOT_INCLUDES: 'Argument "pathNotIncludes" must be either undefined or an string with length greater than 0',
166
+ INVALID_MATCHER_PATH_MATCH: 'Argument "pathMatch" must be either undefined or type RegExp',
167
+ INVALID_USER_RESPONSE: 'Function return must be a number, a string, an array (where p=0 is a number) or an object (where .statusCode is a number)'
168
+ };
3
169
 
4
- /***/ 44:
5
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
170
+ ;// ./src/lambda_api/lambda_api_validation_error.js
171
+ class LambdaApiValidationError extends Error {};
6
172
 
7
- const { LambdaApi } = __webpack_require__( 2705 );
8
- const array = __webpack_require__( 8278 );
9
- const aws = __webpack_require__( 4870 );
10
- const epoch = __webpack_require__( 3830 );
11
- const math = __webpack_require__( 943 );
12
- const object = __webpack_require__( 5762 );
13
- const redis = __webpack_require__( 4528 );
14
- const string = __webpack_require__( 268 );
15
- const utils = __webpack_require__( 6878 );
173
+ ;// ./src/lambda_api/validator.js
16
174
 
17
- module.exports = {
18
- array,
19
- aws,
20
- epoch,
21
- LambdaApi,
22
- math,
23
- object,
24
- redis,
25
- string,
26
- utils
27
- };
28
175
 
29
176
 
30
- /***/ }),
177
+ const evaluate = ( condition, errorMessage ) => {
178
+ if ( !condition ) { throw new LambdaApiValidationError( errorMessage ); }
179
+ };
31
180
 
32
- /***/ 115:
33
- /***/ ((module) => {
181
+ const isConstructor = v => {
182
+ try {
183
+ return !!Reflect.construct( new Proxy( v, {} ), [] );
184
+ } catch {
185
+ return false;
186
+ }
187
+ };
34
188
 
35
- module.exports = ( n, d = 2 ) => Math.round( n * ( 10 ** d ) ) / ( 10 ** d );
189
+ const Validator = {
190
+ errorType: v => evaluate( isConstructor( v ), Text.INVALID_ERROR_TYPE ),
191
+ function: v => evaluate( typeof v === 'function', Text.INVALID_FN ),
192
+ httpMethod: v => evaluate( [ 'DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT' ].includes( v ), Text.INVALID_METHOD ),
193
+ matcherPath: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_PATH ),
194
+ matcherPathIncludes: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_PATH_INCLUDES ),
195
+ matcherPathMatch: v => evaluate( v === undefined || v?.constructor?.name === RegExp.name, Text.INVALID_MATCHER_PATH_MATCH ),
196
+ matcherPathNotIncludes: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_PATH_NOT_INCLUDES ),
197
+ matcherRoute: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_ROUTE ),
198
+ matcherRouteIncludes: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_ROUTE_INCLUDES ),
199
+ matcherRouteMatch: v => evaluate( v === undefined || v?.constructor?.name === RegExp.name, Text.INVALID_MATCHER_ROUTE_MATCH ),
200
+ matcherRouteNotIncludes: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_ROUTE_NOT_INCLUDES ),
201
+ statusCode: v => evaluate( typeof v === 'number' && /^[1-5]\d\d$/.test( String( v ) ), Text.INVALID_STATUS_CODE ),
202
+ transformRequest: v => evaluate( [ 'camelcase', 'snakecase', null, false ].includes( v ), Text.INVALID_TRANSFORM_REQUEST ),
203
+ transformResponse: v => evaluate( [ 'camelcase', 'snakecase', null, false ].includes( v ), Text.INVALID_TRANSFORM_RESPONSE )
204
+ };
36
205
 
206
+ ;// ./src/object/is_serializable.js
207
+ const isSerializable = obj =>
208
+ typeof obj === 'object' &&
209
+ obj !== null &&
210
+ !( obj instanceof String ) &&
211
+ !( obj instanceof Number ) &&
212
+ !( obj instanceof Boolean ) &&
213
+ !( obj instanceof Date );
37
214
 
38
- /***/ }),
215
+ ;// ./src/string/camelize.js
216
+ // Convert a string to camelCase
217
+ const camelize = ( input, { keepAllCaps = false } = {} ) =>
218
+ // Break the string into sequences to rebuild later
219
+ !input ? input : input.split( /\s/ )
220
+ // ALL_CAPS terms are ignored
221
+ .map( term => [ term, keepAllCaps && /^[A-Z_]+$/g.test( term ) ? term : term
222
+ // Matches the penultimate letter in a sequence of upper case followed by lower case and convert it to lower case
223
+ // Effectively creating a word break eg: BDay => bDay
224
+ .replace( /[A-Z](?=[A-Z][a-z])/g, c => `${c[0].toLowerCase()}` )
225
+ .replace( /([A-Z])([A-Z]+)/g, c => `${c[0]}${c.slice( 1 ).toLowerCase()}` ) // Sequences of upper case
226
+ .replace( /([-_]\w)/g, c => c[1].toUpperCase() ) // first letter after hyphen and underline
227
+ .replace( /^([A-Z])/g, c => c[0].toLowerCase() ) // first letter
228
+ ] )
229
+ // Rebuild the string replacing the converter terms keeping the original delimiters
230
+ .reduce( ( result, [ term, repl ] ) => result.replace( term, repl ), input );
39
231
 
40
- /***/ 140:
41
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
232
+ ;// ./src/object/camelize.js
42
233
 
43
- const { encode, decode } = __webpack_require__( 5744 );
44
- const startQuery = __webpack_require__( 5723 );
45
- const getResults = __webpack_require__( 7337 );
46
234
 
47
- const getQueryExecutionId = async ( { client, nativeArgs, recursive, paginationToken } ) => {
48
- if ( !recursive && paginationToken ) {
49
- const { queryExecutionId, token } = decode( paginationToken );
50
- return { queryExecutionId, token };
51
- }
52
235
 
53
- const queryExecutionId = await startQuery( { client, ...nativeArgs } );
54
- return { queryExecutionId };
55
- };
236
+ const change = ( obj, keepAllCaps ) =>
237
+ !isSerializable( obj ) ? obj : Object.entries( obj ).reduce( ( transformed, [ key, value ] ) => {
238
+ delete transformed[key];
239
+ transformed[camelize( key, { keepAllCaps } )] = typeof value === 'object' ? change( value, keepAllCaps ) : value;
240
+ return transformed;
241
+ }, Array.isArray( obj ) ? [] : {} );
56
242
 
57
- /**
58
- * @class Result
59
- * @type {Object}
60
- * @property {Object[]} items Each query result row, parsed to a camelized js object
61
- * @property {String} paginationToken The next pagination token, if recursive = false ans there are more results for the query
62
- */
243
+ const camelize_camelize = ( obj, { keepAllCaps = false } = {} ) => change( obj, keepAllCaps );
63
244
 
64
- /**
65
- * Executes an Athena Query
66
- * @param {*} client The native client
67
- * @param {Object} nativeArgs The native args to start the Athena Query
68
- * @param {Object=} options Query configuration
69
- * @param {Boolean=} [options.recursive=false] If to recursive query all results or to return a paginationToken after each page
70
- * @param {String=} options.paginationToken The pagination token received in the previous call to resume the query (only used when recursive = false)
71
- * @param {Number=} options.maxResults The maximum number of results per page (only when using pagination token)
72
- * @returns {Result} The query result
73
- */
74
- module.exports = async ( client, nativeArgs, options ) => {
75
- const { recursive = false, paginationToken, maxResults } = options;
245
+ ;// ./src/string/snakelize.js
246
+ // convert a string to snake_case
247
+ const snakelize = ( input, { keepAllCaps = false } = {} ) =>
248
+ // Break the string into sequences to rebuild later
249
+ !input ? input : input.split( /\s/ )
250
+ // ALL_CAPS terms are ignored
251
+ .map( term => [ term, keepAllCaps && /^[A-Z_]+$/g.test( term ) ? term : term
252
+ .replace( /-/g, '_' ) // replaces hyphen
253
+ .replace( /([a-z\d])([A-Z])/g, '$1_$2' ) // add _ between lower and upper case letters
254
+ .replace( /([A-Z])([A-Z])(?=[a-z\d])/g, '$1_$2' ).toLowerCase() // add _ between uppercase char and next uppercase char follow by lowercase
255
+ ] )
256
+ // Rebuild the string replacing the converter terms keeping the original delimiters
257
+ .reduce( ( result, [ term, repl ] ) => result.replace( term, repl ), input );
76
258
 
77
- const { queryExecutionId, token } = await getQueryExecutionId( { client, nativeArgs, recursive, paginationToken } );
259
+ ;// ./src/object/snakelize.js
78
260
 
79
- const { nextToken, items } = await getResults( { client, queryExecutionId, token, recursive, maxResults } );
80
- return { paginationToken: nextToken ? encode( { queryExecutionId, token: nextToken } ) : undefined, items };
81
- };
82
261
 
83
262
 
84
- /***/ }),
263
+ const snakelize_change = ( obj, keepAllCaps ) =>
264
+ !isSerializable( obj ) ? obj : Object.entries( obj ).reduce( ( transformed, [ key, value ] ) => {
265
+ delete transformed[key];
266
+ transformed[snakelize( key, { keepAllCaps } )] = typeof value === 'object' ? snakelize_change( value, keepAllCaps ) : value;
267
+ return transformed;
268
+ }, Array.isArray( obj ) ? [] : {} );
85
269
 
86
- /***/ 228:
87
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
270
+ const snakelize_snakelize = ( obj, { keepAllCaps = false } = {} ) => snakelize_change( obj, keepAllCaps );
88
271
 
89
- const { AthenaClient } = __webpack_require__( 3744 );
90
- const clientProvider = __webpack_require__( 9039 );
91
- const query = __webpack_require__( 140 );
92
- const createInstance = __webpack_require__( 5438 );
272
+ ;// ./src/lambda_api/api_response.js
93
273
 
94
- const methods = {
95
- query
96
- };
97
274
 
98
- module.exports = createInstance( clientProvider.bind( null, AthenaClient ), methods );
275
+ const charset = 'utf-8';
99
276
 
277
+ const transformFns = {
278
+ camelcase: camelize_camelize,
279
+ snakecase: snakelize_snakelize
280
+ };
100
281
 
101
- /***/ }),
282
+ class ApiResponse {
283
+ #headers = null;
284
+ #statusCode = null;
285
+ #transformFn = false;
286
+ #isBase64Encoded = false;
287
+ #body = '';
102
288
 
103
- /***/ 268:
104
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
289
+ constructor( { headers = {}, transform } = {} ) {
290
+ this.#transformFn = transformFns[transform] ?? ( v => v );
291
+ this.#headers = Object.assign( {
292
+ 'Cache-Control': 'no-store',
293
+ 'Access-Control-Allow-Origin': '*'
294
+ }, headers );
295
+ }
105
296
 
106
- const camelize = __webpack_require__( 3914 );
107
- const capitalizeWords = __webpack_require__( 3258 );
108
- const snakelize = __webpack_require__( 3402 );
297
+ setContent( statusCode, body, headers = {}, isBase64Encoded = false ) {
298
+ this.#statusCode = statusCode;
299
+ this.#isBase64Encoded = isBase64Encoded;
300
+ if ( body?.length === 0 || [ null, undefined ].includes( body ) ) {
301
+ this.#body = '';
302
+ } else if ( typeof body === 'object' ) {
303
+ this.#body = JSON.stringify( this.#transformFn( body ) );
304
+ this.#headers['Content-Type'] = `application/json; charset=${charset}`;
305
+ } else {
306
+ this.#body = String( body );
307
+ this.#headers['Content-Type'] = `text/plain; charset=${charset}`;
308
+ }
309
+ this.#headers['Content-Length'] = this.#body.length;
310
+ Object.assign( this.#headers, headers ?? {} );
311
+ return this;
312
+ }
109
313
 
110
- module.exports = {
111
- camelize,
112
- capitalizeWords,
113
- snakelize
314
+ toJSON() {
315
+ return {
316
+ isBase64Encoded: this.#isBase64Encoded,
317
+ statusCode: this.#statusCode,
318
+ body: this.#body,
319
+ headers: this.#headers
320
+ };
321
+ }
114
322
  };
115
323
 
324
+ ;// ./src/lambda_api/event.js
116
325
 
117
- /***/ }),
118
326
 
119
- /***/ 279:
120
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
327
+ const event_transformFns = {
328
+ camelcase: camelize_camelize,
329
+ snakecase: snakelize_snakelize
330
+ };
121
331
 
122
- const { HeadObjectCommand } = __webpack_require__( 5725 );
332
+ const parseJson = content => {
333
+ try {
334
+ return JSON.parse( content );
335
+ } catch {
336
+ return content;
337
+ }
338
+ };
123
339
 
124
- module.exports = async ( client, bucket, key ) =>
125
- client.send( new HeadObjectCommand( { Bucket: bucket, Key: key } ) );
340
+ class Event {
341
+ #transformFn;
342
+ authorizer;
343
+ body;
344
+ rawBody;
345
+ headers;
346
+ method;
347
+ params;
348
+ path;
349
+ queryString;
350
+ route;
126
351
 
352
+ context = {};
127
353
 
128
- /***/ }),
354
+ constructor( { transform = false } = {} ) {
355
+ this.#transformFn = event_transformFns[transform] ?? ( v => v );
356
+ }
129
357
 
130
- /***/ 321:
131
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
358
+ parseFromAwsEvent( awsEvent ) {
359
+ this[`parseFromAwsEventV${awsEvent.version === '2.0' ? 2 : 1}`]( awsEvent );
360
+ }
132
361
 
133
- const validators = __webpack_require__( 8994 );
134
- const ApiResponse = __webpack_require__( 3119 );
135
- const Event = __webpack_require__( 329 );
136
- const Handler = __webpack_require__( 3109 );
137
- const Hook = __webpack_require__( 798 );
138
- const UserResponse = __webpack_require__( 8282 );
139
- const Text = __webpack_require__( 9760 );
362
+ parseFromAwsEventV1( awsEvent ) {
363
+ const {
364
+ body,
365
+ path,
366
+ resource,
367
+ httpMethod,
368
+ requestContext,
369
+ pathParameters,
370
+ headers,
371
+ multiValueHeaders,
372
+ queryStringParameters,
373
+ multiValueQueryStringParameters: multiValueQueryString,
374
+ isBase64Encoded
375
+ } = awsEvent;
140
376
 
141
- module.exports = class LambdaApi {
142
- #apiResponse = null;
143
- #handlers = [];
144
- #errorResponses = [];
145
- #beforeHooks = [];
146
- #afterHooks = [];
147
- #transformRequest = [];
377
+ const unifiedHeaders = {
378
+ ...headers,
379
+ ...Object.fromEntries( Object.entries( multiValueHeaders ?? {} ).map( ( [ k, v ] ) => [ k, Array.isArray( v ) ? v.join( ',' ) : k ] ) )
380
+ };
148
381
 
149
- /**
150
- * Creates a new Lambda Api
151
- *
152
- * @param {Object} headers Any headers you want to be included in all responses
153
- */
154
- constructor( { headers = {}, transformRequest = false, transformResponse = false } = {} ) {
155
- validators.transformRequest( transformRequest );
156
- validators.transformResponse( transformResponse );
382
+ const unifiedQueryString = {
383
+ ...queryStringParameters,
384
+ ...Object.fromEntries( Object.entries( multiValueQueryString ?? {} ).map( ( [ k, v ] ) => [ k, Array.isArray( v ) ? v.join( ',' ) : k ] ) )
385
+ };
157
386
 
158
- this.#transformRequest = transformRequest;
159
- this.#apiResponse = new ApiResponse( { headers, transform: transformResponse } );
387
+ this.authorizer = requestContext?.authorizer;
388
+ this.rawBody = body ?? null;
389
+ this.body = body ? this.#transformFn( parseJson( body ) ) : null;
390
+ this.headers = unifiedHeaders ?? {};
391
+ this.method = httpMethod;
392
+ this.params = this.#transformFn( pathParameters ) ?? {};
393
+ this.path = path;
394
+ this.queryString = this.#transformFn( unifiedQueryString ) ?? {};
395
+ this.route = resource;
396
+ this.isBase64Encoded = isBase64Encoded ?? false;
160
397
  }
161
398
 
162
- /**
163
- * Register a function that will run before the matching route (only if matches)
164
- *
165
- * @param {Object} args
166
- * @param {function} args.fn A function
167
- */
168
- addBeforeHook( { fn } = {} ) {
169
- this.#beforeHooks.push( new Hook( { fn } ) );
170
- }
171
-
172
- /**
173
- * Register a function that will run after the matching route (only if matches)
174
- *
175
- * @param {Object} args
176
- * @param {function} args.fn A function
177
- */
178
- addAfterHook( { fn } = {} ) {
179
- this.#afterHooks.push( new Hook( { fn } ) );
180
- }
181
-
182
- /**
183
- * Register a handler for a given request method and optionally a path
184
- *
185
- * @param {Object} args
186
- * @param {string} args.method The method to match this handler
187
- * @param {function} args.fn The handler function
188
- * @param {string} [args.route] A route to match this handler
189
- * @param {string} [args.routeIncludes] A part of the route to match this handler
190
- * @param {string} [args.routeNotIncludes] A part of the route to not match this handler
191
- * @param {RegExp} [args.routeMatches] A RegExp to match the route
192
- * @param {string} [args.path] A path to match this handler
193
- * @param {string} [args.pathIncludes] A part of the path to match this handler
194
- * @param {string} [args.pathNotIncludes] A part of the path to not match this handler
195
- * @param {RegExp} [args.pathMatches] A RegExp to match the path
196
- */
197
- addHandler( { method, fn, ...matchers } = {} ) {
198
- this.#handlers.push( new Handler( { method, fn, ...matchers } ) );
199
- }
200
-
201
- /**
202
- * Register an automatic error code response for given error class (constructor name)
203
- *
204
- * @param {Object} args
205
- * @param {string} args.code The HTTP status code to return
206
- * @param {class} args.errorType The error class
207
- * @param {string} [args.message=null] Optional message to return for the status code, if not present will default to Error.message
208
- * @param {message} [args.errorType] And optional message to display
209
- */
210
- addErrorHandler( { errorType, code, message = null } = {} ) {
211
- validators.statusCode( code );
212
- validators.errorType( errorType );
213
- this.#errorResponses.push( { errorType, code, message } );
214
- }
215
-
216
- /**
217
- * Init the flow using a given AWS Lambda APIGateway event (v2 syntax)
218
- *
219
- * @param {Object} ApiGatewayPayload The raw API Gateway event
220
- * @returns {Object} The http response with status, body and headers
221
- */
222
- async process( awsEvent ) {
223
- const event = new Event( { transform: this.#transformRequest } );
224
- event.parseFromAwsEvent( awsEvent );
225
-
226
- if ( event.method === 'HEAD' ) {
227
- return this.#apiResponse.setContent( 204 ).toJSON();
228
- }
229
-
230
- const handler = this.#handlers.find( h => h.match( event ) );
231
- if ( !handler ) {
232
- return this.#apiResponse.setContent( 405, Text.ERROR_405 ).toJSON();
233
- }
234
-
235
- const chain = [
236
- ...this.#beforeHooks.map( b => b.fn ),
237
- async ev => {
238
- const result = await handler.fn( ev );
239
- const response = new UserResponse( result );
240
- this.#apiResponse.setContent( ...response.values ).toJSON();
241
- },
242
- ...this.#afterHooks.map( a => a.fn )
243
- ];
244
-
245
- try {
246
- for ( const fn of chain ) {
247
- await fn( event );
248
- }
249
- return this.#apiResponse.toJSON();
250
-
251
- } catch ( error ) {
252
- console.error( 'Lambda API Error', { error, event } );
253
-
254
- const response = this.#errorResponses.find( e => error instanceof e.errorType );
255
- if ( response ) {
256
- return this.#apiResponse.setContent( response.code, response.message ?? error.message ).toJSON();
257
- }
258
- return this.#apiResponse.setContent( 500, Text.ERROR_500 ).toJSON();
259
- }
260
- }
261
- };
262
-
263
-
264
- /***/ }),
265
-
266
- /***/ 329:
267
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
268
-
269
- const { camelize, snakelize } = __webpack_require__( 5762 );
270
-
271
- const transformFns = {
272
- camelcase: camelize,
273
- snakecase: snakelize
274
- };
275
-
276
- const parseJson = content => {
277
- try {
278
- return JSON.parse( content );
279
- } catch {
280
- return content;
281
- }
282
- };
283
-
284
- module.exports = class Event {
285
- #transformFn;
286
- authorizer;
287
- body;
288
- headers;
289
- method;
290
- params;
291
- path;
292
- queryString;
293
- route;
294
-
295
- context = {};
296
-
297
- constructor( { transform = false } = {} ) {
298
- this.#transformFn = transformFns[transform] ?? ( v => v );
299
- }
300
-
301
- parseFromAwsEvent( awsEvent ) {
302
- this[`parseFromAwsEventV${awsEvent.version === '2.0' ? 2 : 1}`]( awsEvent );
303
- }
304
-
305
- parseFromAwsEventV1( awsEvent ) {
306
- const {
307
- body,
308
- path,
309
- resource,
310
- httpMethod,
311
- requestContext,
312
- pathParameters,
313
- headers,
314
- multiValueHeaders,
315
- queryStringParameters,
316
- multiValueQueryStringParameters: multiValueQueryString,
317
- isBase64Encoded
318
- } = awsEvent;
319
-
320
- const unifiedHeaders = {
321
- ...headers,
322
- ...Object.fromEntries( Object.entries( multiValueHeaders ?? {} ).map( ( [ k, v ] ) => [ k, Array.isArray( v ) ? v.join( ',' ) : k ] ) )
323
- };
324
-
325
- const unifiedQueryString = {
326
- ...queryStringParameters,
327
- ...Object.fromEntries( Object.entries( multiValueQueryString ?? {} ).map( ( [ k, v ] ) => [ k, Array.isArray( v ) ? v.join( ',' ) : k ] ) )
328
- };
329
-
330
- this.authorizer = requestContext?.authorizer;
331
- this.body = body ? this.#transformFn( parseJson( body ) ) : null;
332
- this.headers = unifiedHeaders ?? {};
333
- this.method = httpMethod;
334
- this.params = this.#transformFn( pathParameters ) ?? {};
335
- this.path = path;
336
- this.queryString = this.#transformFn( unifiedQueryString ) ?? {};
337
- this.route = resource;
338
- this.isBase64Encoded = isBase64Encoded ?? false;
339
- }
340
-
341
- parseFromAwsEventV2( awsEvent ) {
342
- const {
343
- body,
344
- routeKey,
345
- requestContext,
346
- pathParameters,
347
- headers,
348
- queryStringParameters,
349
- isBase64Encoded
350
- } = awsEvent;
399
+ parseFromAwsEventV2( awsEvent ) {
400
+ const {
401
+ body,
402
+ routeKey,
403
+ requestContext,
404
+ pathParameters,
405
+ headers,
406
+ queryStringParameters,
407
+ isBase64Encoded
408
+ } = awsEvent;
351
409
 
352
410
  const { http: { method, path } } = requestContext;
353
411
 
354
412
  this.authorizer = requestContext?.authorizer;
413
+ this.rawBody = body ?? null;
355
414
  this.body = body ? this.#transformFn( parseJson( body ) ) : null;
356
415
  this.headers = headers ?? {};
357
416
  this.method = method;
358
- this.params = this.#transformFn( pathParameters ) ?? {};
359
- this.path = path;
360
- this.queryString = this.#transformFn( queryStringParameters ) ?? {};
361
- this.route = routeKey?.split( ' ' )[1].replace( /\/$/, '' );
362
- this.isBase64Encoded = isBase64Encoded ?? false;
363
- }
364
- };
365
-
366
-
367
- /***/ }),
368
-
369
- /***/ 345:
370
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
371
-
372
- const { GetObjectCommand } = __webpack_require__( 5725 );
373
-
374
- module.exports = async ( client, bucket, key, nativeArgs ) => {
375
- const response = await client.send( new GetObjectCommand( {
376
- ...nativeArgs,
377
- Bucket: bucket,
378
- Key: key
379
- } ) );
380
- const stream = response.Body;
381
- return Buffer.concat( await stream.toArray() ).toString( 'utf-8' );
382
- };
383
-
384
-
385
- /***/ }),
386
-
387
- /***/ 468:
388
- /***/ ((module) => {
389
-
390
- const parsePayload = payload => {
391
- try {
392
- return JSON.parse( Buffer.from( payload ).toString( 'utf-8' ) );
393
- } catch {
394
- return null;
395
- }
396
- };
397
-
398
- module.exports = class LambdaError extends Error {
399
- constructor( response ) {
400
- const { StatusCode: statusCode, Payload: rawPayload } = response;
401
- const payload = parsePayload( rawPayload );
402
- const lambdaErrorType = payload?.errorType ?? Error.name;
403
- const lambdaErrorMessage = payload?.errorMessage;
404
- if ( statusCode === 200 ) {
405
- super( `Invoked function threw "[${lambdaErrorType}]${lambdaErrorMessage ? ' ' + lambdaErrorMessage : ''}"` );
406
- } else {
407
- super( 'Error invoking the function' );
408
- }
409
- this.statusCode = statusCode;
410
- this.lambdaErrorType = lambdaErrorType;
411
- this.lambdaErrorMessage = lambdaErrorMessage;
412
- }
413
- };
414
-
415
-
416
- /***/ }),
417
-
418
- /***/ 536:
419
- /***/ ((module) => {
420
-
421
- module.exports = ( { key, items } ) => [
422
- ...items.filter( Array.isArray ).flat().reduce( ( map, v ) => {
423
- const k = key( v );
424
- if ( !map.has( k ) ) {
425
- map.set( k, v );
426
- }
427
- return map;
428
- }, new Map() ).values()
429
- ];
430
-
431
-
432
- /***/ }),
433
-
434
- /***/ 637:
435
- /***/ ((module) => {
436
-
437
- module.exports = ( n, d = 2 ) => {
438
- if ( !isFinite( n ) || typeof n !== 'number' ) { return NaN; }
439
-
440
- const m = Math.pow( 10, d );
441
- const num = +( n * m ).toFixed( 8 ); // Avoid rounding errors
442
- const i = Math.floor( num );
443
- const f = num - i;
444
- const e = 1e-8; // Allow for rounding errors in f
445
- const r = ( f > 0.5 - e && f < 0.5 + e ) ? // eslint-disable-line no-nested-ternary
446
- ( ( i % 2 === 0 ) ? i : i + 1 ) : Math.round( num );
447
- return r / m;
448
- };
449
-
450
-
451
- /***/ }),
452
-
453
- /***/ 645:
454
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
455
-
456
- const copy = __webpack_require__( 3936 );
457
- const download = __webpack_require__( 345 );
458
- const getSignedUrl = __webpack_require__( 3758 );
459
- const head = __webpack_require__( 279 );
460
- const upload = __webpack_require__( 9704 );
461
- const { S3Client } = __webpack_require__( 5725 );
462
- const clientProvider = __webpack_require__( 9039 );
463
- const createInstance = __webpack_require__( 5438 );
464
-
465
- const methods = {
466
- copy,
467
- download,
468
- getSignedUrl,
469
- head,
470
- upload
471
- };
472
-
473
- module.exports = createInstance( clientProvider.bind( null, S3Client ), methods );
474
-
475
-
476
- /***/ }),
477
-
478
- /***/ 739:
479
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
480
-
481
- const { GetQueryResultsCommand } = __webpack_require__( 7493 );
482
- const pollingDelay = __webpack_require__( 2549 );
483
- const sleep = t => new Promise( r => setTimeout( () => r(), t ) );
484
-
485
- const getResults = async ( { client, command } ) => {
486
- const { results, status } = await client.send( command );
487
-
488
- if ( [ 'Cancelled', 'Failed', 'Timeout', 'Unknown' ].includes( status ) ) {
489
- throw new Error( `Query status is "${status}"` );
490
- }
491
-
492
- if ( status === 'Complete' ) {
493
- return results;
494
- }
495
-
496
- // Running, Scheduled
497
- await sleep( pollingDelay );
498
- return getResults( { client, command } );
499
- };
500
-
501
- module.exports = async ( { client, queryId } ) => {
502
- const command = new GetQueryResultsCommand( { queryId } );
503
- return getResults( { client, command } );
504
- };
505
-
506
-
507
- /***/ }),
508
-
509
- /***/ 748:
510
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
511
-
512
- const select = __webpack_require__( 2157 );
513
-
514
- module.exports = async ( client, ...args ) => select( client, 'scan', ...args );
515
-
516
-
517
- /***/ }),
518
-
519
- /***/ 798:
520
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
521
-
522
- const validators = __webpack_require__( 8994 );
523
-
524
- module.exports = class Hook {
525
- #fn;
526
-
527
- constructor( { fn } ) {
528
- validators.function( fn );
529
- this.#fn = fn;
530
- }
531
-
532
- get fn() { return this.#fn; }
533
- };
534
-
535
-
536
- /***/ }),
537
-
538
- /***/ 809:
539
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
540
-
541
- const { DeleteSuppressedDestinationCommand } = __webpack_require__( 9556 );
542
-
543
- module.exports = ( client, address ) => client.send( new DeleteSuppressedDestinationCommand( { EmailAddress: address } ) );
544
-
545
-
546
- /***/ }),
547
-
548
- /***/ 834:
549
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
550
-
551
- const parseValue = __webpack_require__( 9129 );
552
-
553
- module.exports = resultSet => {
554
- const columns = resultSet.ResultSetMetadata.ColumnInfo
555
- .map( col => ( { name: col.Name, type: col.Type } ) );
556
-
557
- // first data row contains the table field names
558
- return resultSet.Rows.slice( 1 ).map( row => {
559
- const values = row.Data.map( d => d.VarCharValue );
560
- return columns.reduce( ( obj, p, i ) => Object.assign( obj, { [p.name]: parseValue( values[i], p.type ) } ), {} );
561
- } );
562
- };
563
-
564
-
565
- /***/ }),
566
-
567
- /***/ 943:
568
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
569
-
570
- const calcMean = __webpack_require__( 4124 );
571
- const calcMedian = __webpack_require__( 3187 );
572
- const calcMedianAbsDev = __webpack_require__( 4692 );
573
- const calcStdDevPopulation = __webpack_require__( 2736 );
574
- const calcStdDevSample = __webpack_require__( 6089 );
575
- const calcZScore = __webpack_require__( 4110 );
576
- const roundGaussian = __webpack_require__( 637 );
577
- const roundStandard = __webpack_require__( 115 );
578
-
579
- module.exports = {
580
- calcMean,
581
- calcMedian,
582
- calcMedianAbsDev,
583
- calcStdDevPopulation,
584
- calcStdDevSample,
585
- calcZScore,
586
- roundGaussian,
587
- roundStandard
588
- };
589
-
590
-
591
- /***/ }),
592
-
593
- /***/ 1417:
594
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
595
-
596
- const { GetCommand } = __webpack_require__( 3489 );
597
-
598
- const parseArgs = args => {
599
- // native args mode
600
- if ( args[0] instanceof Object ) {
601
- return args[0];
602
- }
603
- // sugar mode
604
- return {
605
- TableName: args[0],
606
- Key: args[1]
607
- };
608
- };
609
-
610
- module.exports = async ( client, ...args ) => {
611
- const response = await client.send( new GetCommand( parseArgs( args ) ) );
612
- return response.Item;
613
- };
614
-
615
-
616
- /***/ }),
617
-
618
- /***/ 1505:
619
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
620
-
621
- const documentClientProvider = __webpack_require__( 2966 );
622
- const get = __webpack_require__( 1417 );
623
- const put = __webpack_require__( 9628 );
624
- const putBatch = __webpack_require__( 5847 );
625
- const query = __webpack_require__( 5265 );
626
- const remove = __webpack_require__( 6777 );
627
- const removeBatch = __webpack_require__( 3862 );
628
- const scan = __webpack_require__( 748 );
629
- const smartUpdate = __webpack_require__( 2266 );
630
- const transactWrite = __webpack_require__( 1659 );
631
- const update = __webpack_require__( 4144 );
632
- const createInstance = __webpack_require__( 5438 );
633
-
634
- const methods = {
635
- get,
636
- put,
637
- putBatch,
638
- query,
639
- remove,
640
- removeBatch,
641
- scan,
642
- smartUpdate,
643
- transactWrite,
644
- update
645
- };
646
-
647
- module.exports = createInstance( documentClientProvider, methods );
648
-
649
-
650
- /***/ }),
651
-
652
- /***/ 1659:
653
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
654
-
655
- const { TransactWriteCommand } = __webpack_require__( 3489 );
656
-
657
- module.exports = async ( client, items ) => {
658
- const response = await client.send( new TransactWriteCommand( { TransactItems: items } ) );
659
- return response;
660
- };
661
-
662
-
663
- /***/ }),
664
-
665
- /***/ 1671:
666
- /***/ ((module) => {
667
-
668
- "use strict";
669
- module.exports = require("@aws-sdk/client-timestream-query");
670
-
671
- /***/ }),
672
-
673
- /***/ 1783:
674
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
675
-
676
- const { SendEmailCommand } = __webpack_require__( 9556 );
677
-
678
- module.exports = ( client, { to = [], from, html, subject }, args ) =>
679
- client.send( new SendEmailCommand( {
680
- Destination: {
681
- ToAddresses: to
682
- },
683
- Content: {
684
- Simple: {
685
- Body: {
686
- Html: {
687
- Data: html,
688
- Charset: 'utf-8'
689
- }
690
- },
691
- Subject: {
692
- Data: subject
693
- }
694
- }
695
- },
696
- FromEmailAddress: from,
697
- ...args
698
- } ) );
699
-
700
-
701
- /***/ }),
702
-
703
- /***/ 1976:
704
- /***/ ((module) => {
705
-
706
- "use strict";
707
- module.exports = require("@aws-sdk/client-sqs");
708
-
709
- /***/ }),
710
-
711
- /***/ 2047:
712
- /***/ ((module) => {
713
-
714
- module.exports = o => Object.fromEntries( Object.entries( o ).filter( ( [ , v ] ) => !Array.isArray( v ) || v.length > 0 ) );
715
-
716
-
717
- /***/ }),
718
-
719
- /***/ 2157:
720
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
721
-
722
- const { encode, decode } = __webpack_require__( 5744 );
723
- const { ScanCommand, QueryCommand } = __webpack_require__( 3489 );
724
-
725
- const query = async ( { client, command, args, recursive, startKey, items = [], count = 0 } ) => {
726
- const response = await client.send( new command( {
727
- ...args,
728
- ...( startKey && { ExclusiveStartKey: startKey } )
729
- } ) );
730
-
731
- const isCount = args.Select === 'COUNT';
732
- const hasLimit = Number.isFinite( args.Limit );
733
-
734
- const result = {
735
- items: isCount ? null : items.concat( response.Items ),
736
- count: count + response.Count,
737
- startKey: response.LastEvaluatedKey
738
- };
739
-
740
- if ( !recursive ) {
741
- return { items: result.items, count: result.count, ...( result.startKey && { nextToken: encode( result.startKey ) } ) };
742
- }
743
-
744
- if ( result.startKey && ( isCount || ( hasLimit && result.items.length < args.Limit ) || ( !isCount && !hasLimit ) ) ) {
745
- return query( { client, command, args, recursive, ...result } );
746
- }
747
-
748
- if ( isCount ) {
749
- return { items: null, count: result.count };
750
- }
751
- const trimmedItems = result.items.slice( 0, args.Limit );
752
- return { items: trimmedItems, count: trimmedItems.length };
753
- };
754
-
755
- module.exports = async ( client, method, args, options = { recursive: false, paginationToken: null } ) => {
756
- const command = method === 'scan' ? ScanCommand : QueryCommand;
757
-
758
- return query( { client, command, args, recursive: options.recursive, startKey: decode( options.paginationToken ) } );
759
- };
760
-
761
-
762
- /***/ }),
763
-
764
- /***/ 2266:
765
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
766
-
767
- const { UpdateCommand } = __webpack_require__( 3489 );
768
-
769
- module.exports = async ( client, tableName, key, keyValues ) => {
770
- const { updates, removals, names, values } = Object.entries( keyValues ).reduce( ( args, [ k, value ], index ) => {
771
- const isRemoval = value === undefined;
772
-
773
- const attrs = k.split( '.' ).map( ( attr, i ) => {
774
- const arrayPosition = attr.match( /\[(\d+)\]$/ )?.[1];
775
- return {
776
- key: `#${attr.replace( /\[\d+\]$|[^a-zA-Z0-9_]/g, '' )}${i}`,
777
- name: attr.replace( /\[\d+\]$/g, '' ),
778
- arrayPosition
779
- };
780
- } );
781
- const fullPath = attrs.map( attr => attr.key + ( attr.arrayPosition ? `[${attr.arrayPosition}]` : '' ) ).join( '.' );
782
- const valueId = `:v${index}`;
783
- const expAttrNames = attrs.reduce( ( obj, attr ) =>
784
- Object.assign( {}, obj, { [attr.key]: attr.name } )
785
- , {} );
786
-
787
- Object.assign( args.names, expAttrNames );
788
-
789
- if ( isRemoval ) {
790
- args.removals.push( fullPath );
791
- } else {
792
- args.updates.push( fullPath + ' = ' + valueId );
793
- Object.assign( args.values, { [valueId]: value } );
794
- }
795
-
796
- return args;
797
- }, { removals: [], updates: [], names: {}, values: {} } );
798
-
799
- const conditionalExpressions = [];
800
- for ( const k of Object.keys( key ) ) {
801
- Object.assign( names, { [`#key_${k}`]: k } );
802
- conditionalExpressions.push( `attribute_exists(#key_${k})` );
803
- }
804
-
805
- if ( updates.length + removals.length === 0 ) { return null; }
806
-
807
- const expressions = [];
808
- if ( updates.length ) {
809
- expressions.push( 'SET ' + updates.join( ', ' ) );
810
- } if ( removals.length ) {
811
- expressions.push( 'REMOVE ' + removals.join( ', ' ) );
812
- }
813
-
814
- const statement = {
815
- TableName: tableName,
816
- ReturnValues: 'ALL_NEW',
817
- Key: key,
818
- ConditionExpression: conditionalExpressions.join( ' AND ' ),
819
- UpdateExpression: expressions.join( ' ' ),
820
- ExpressionAttributeNames: names
821
- };
822
- if ( Object.keys( values ).length > 0 ) {
823
- statement.ExpressionAttributeValues = values;
824
- }
825
-
826
- try {
827
- const response = await client.send( new UpdateCommand( statement ) );
828
- return response.Attributes;
829
- } catch ( error ) {
830
- if ( error.constructor.name === 'ConditionalCheckFailedException' ) {
831
- console.info( 'Fail to update a record that was not found.' );
832
- return null;
833
- }
834
- throw error;
417
+ this.params = this.#transformFn( pathParameters ) ?? {};
418
+ this.path = path;
419
+ this.queryString = this.#transformFn( queryStringParameters ) ?? {};
420
+ this.route = routeKey?.split( ' ' )[1].replace( /\/$/, '' );
421
+ this.isBase64Encoded = isBase64Encoded ?? false;
835
422
  }
836
423
  };
837
424
 
425
+ ;// ./src/lambda_api/handler.js
838
426
 
839
- /***/ }),
840
-
841
- /***/ 2445:
842
- /***/ ((module) => {
843
-
844
- module.exports = t => new Promise( r => setTimeout( r, t ) );
845
427
 
428
+ class Handler {
429
+ #method;
430
+ #fn;
431
+ #route;
432
+ #routeIncludes;
433
+ #routeNotIncludes;
434
+ #routeMatches;
435
+ #path;
436
+ #pathIncludes;
437
+ #pathNotIncludes;
438
+ #pathMatches;
846
439
 
847
- /***/ }),
440
+ constructor( { method, fn, ...matchers } ) {
441
+ Validator.httpMethod( method );
442
+ Validator.function( fn );
443
+ Validator.matcherRoute( matchers.route );
444
+ Validator.matcherRouteIncludes( matchers.routeIncludes );
445
+ Validator.matcherRouteNotIncludes( matchers.routeNotIncludes );
446
+ Validator.matcherRouteMatch( matchers.routeMatch );
447
+ Validator.matcherPath( matchers.path );
448
+ Validator.matcherPathIncludes( matchers.pathIncludes );
449
+ Validator.matcherPathNotIncludes( matchers.pathNotIncludes );
450
+ Validator.matcherPathMatch( matchers.pathMatch );
848
451
 
849
- /***/ 2538:
850
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
452
+ this.#method = method;
453
+ this.#fn = fn;
454
+ this.#route = matchers.route;
455
+ this.#routeIncludes = matchers.routeIncludes;
456
+ this.#routeNotIncludes = matchers.routeNotIncludes;
457
+ this.#routeMatches = matchers.routeMatches;
458
+ this.#path = matchers.path;
459
+ this.#pathIncludes = matchers.pathIncludes;
460
+ this.#pathNotIncludes = matchers.pathNotIncludes;
461
+ this.#pathMatches = matchers.pathMatches;
462
+ }
851
463
 
852
- const writeRecords = __webpack_require__( 8936 );
853
- const { TimestreamWriteClient } = __webpack_require__( 8248 );
854
- const { Agent } = __webpack_require__( 5692 );
855
- const clientProvider = __webpack_require__( 9039 );
856
- const createInstance = __webpack_require__( 5438 );
464
+ match( event ) {
465
+ if ( this.#method !== event.method ) {
466
+ return false;
467
+ }
468
+ if ( this.#route ) {
469
+ return this.#route === event.route;
470
+ }
471
+ if ( this.#path ) {
472
+ return this.#path === event.path;
473
+ }
474
+ if ( this.#routeIncludes && !event.route.includes( this.#routeIncludes ) ) {
475
+ return false;
476
+ }
477
+ if ( this.#routeNotIncludes && event.route.includes( this.#routeNotIncludes ) ) {
478
+ return false;
479
+ }
480
+ if ( this.#routeMatches && !this.#routeMatches.test( event.route ) ) {
481
+ return false;
482
+ }
483
+ if ( this.#pathIncludes && !event.path.includes( this.#pathIncludes ) ) {
484
+ return false;
485
+ }
486
+ if ( this.#pathNotIncludes && event.path.includes( this.#pathNotIncludes ) ) {
487
+ return false;
488
+ }
489
+ if ( this.#pathMatches && !this.#pathMatches.test( event.path ) ) {
490
+ return false;
491
+ }
492
+ return true;
493
+ }
857
494
 
858
- const methods = { writeRecords };
859
- const defaultArgs = {
860
- maxRetries: 10,
861
- httpOptions: { timeout: 60000, agent: new Agent( { maxSockets: 5000 } ) }
495
+ get fn() { return this.#fn; }
862
496
  };
863
497
 
864
- module.exports = createInstance( args => clientProvider( TimestreamWriteClient, [ Object.assign( {}, defaultArgs, args ) ] ), methods );
498
+ ;// ./src/lambda_api/hook.js
865
499
 
866
500
 
867
- /***/ }),
501
+ class Hook {
502
+ #fn;
868
503
 
869
- /***/ 2549:
870
- /***/ ((module) => {
504
+ constructor( { fn } ) {
505
+ Validator.function( fn );
506
+ this.#fn = fn;
507
+ }
871
508
 
872
- module.exports = 500;
509
+ get fn() { return this.#fn; }
510
+ };
873
511
 
512
+ ;// ./src/lambda_api/user_response.js
874
513
 
875
- /***/ }),
876
514
 
877
- /***/ 2705:
878
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
879
515
 
880
- const LambdaApi = __webpack_require__( 321 );
881
516
 
882
- module.exports = { LambdaApi };
517
+ class UserResponse {
518
+ constructor( args ) {
519
+ if ( args === undefined ) {
520
+ this.values = [ 204 ];
521
+ } else if ( typeof args === 'string' && args.length === 0 ) {
522
+ this.values = [ 204 ];
883
523
 
524
+ } else if ( typeof args === 'string' && args.length > 0 ) {
525
+ this.values = [ 200, args ];
884
526
 
885
- /***/ }),
527
+ } else if ( typeof args === 'number' ) {
528
+ Validator.statusCode( args );
529
+ this.values = [ args ];
886
530
 
887
- /***/ 2710:
888
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
531
+ } else if ( Array.isArray( args ) ) {
532
+ Validator.statusCode( args[0] );
533
+ this.values = args;
889
534
 
890
- const { CloudWatchLogsClient } = __webpack_require__( 7493 );
891
- const clientProvider = __webpack_require__( 9039 );
892
- const query = __webpack_require__( 4338 );
893
- const createInstance = __webpack_require__( 5438 );
535
+ } else if ( args.statusCode ) {
536
+ Validator.statusCode( args.statusCode );
537
+ this.values = [ args.statusCode, args.body, args.headers, args.isBase64Encoded ];
894
538
 
895
- const methods = {
896
- query
539
+ } else if ( [ undefined, null ].includes( args ) ) {
540
+ this.values = [ 200 ];
541
+ } else {
542
+ throw new LambdaApiValidationError( Text.INVALID_USER_RESPONSE );
543
+ }
544
+ }
897
545
  };
898
546
 
899
- module.exports = createInstance( clientProvider.bind( null, CloudWatchLogsClient ), methods );
900
-
901
-
902
- /***/ }),
903
-
904
- /***/ 2736:
905
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
906
-
907
- const calcMean = __webpack_require__( 4124 );
908
-
909
- module.exports = values => {
910
- const mean = calcMean( values );
911
- const squareDiffs = values.map( value => Math.pow( value - mean, 2 ) );
912
- const avgSquareDiff = calcMean( squareDiffs );
913
- return Math.sqrt( avgSquareDiff );
914
- };
547
+ ;// ./src/lambda_api/lambda_api.js
915
548
 
916
549
 
917
- /***/ }),
918
550
 
919
- /***/ 2836:
920
- /***/ ((module) => {
921
551
 
922
- module.exports = ( ...args ) => [ ...new Set( args.filter( Array.isArray ).flat() ) ];
923
552
 
924
553
 
925
- /***/ }),
926
554
 
927
- /***/ 2847:
928
- /***/ ((module) => {
929
555
 
930
- const parseInteger = value => {
931
- const number = parseInt( value, 10 );
932
- return number <= Number.MAX_SAFE_INTEGER && number >= Number.MIN_SAFE_INTEGER ? number : value;
933
- };
556
+ class LambdaApi {
557
+ #apiResponse = null;
558
+ #handlers = [];
559
+ #errorResponses = [];
560
+ #beforeHooks = [];
561
+ #afterHooks = [];
562
+ #transformRequest = [];
934
563
 
935
- const parseFloatingPoint = value => {
936
- if ( value.replace( /[^\d]/g, '' ).length > 16 ) {
937
- return value;
938
- }
939
- const number = parseFloat( value, 10 );
940
- return number <= Number.MAX_SAFE_INTEGER && number >= Number.MIN_SAFE_INTEGER ? number : value;
941
- };
564
+ /**
565
+ * Creates a new Lambda Api
566
+ *
567
+ * @param {Object} headers Any headers you want to be included in all responses
568
+ */
569
+ constructor( { headers = {}, transformRequest = false, transformResponse = false } = {} ) {
570
+ Validator.transformRequest( transformRequest );
571
+ Validator.transformResponse( transformResponse );
942
572
 
943
- /* eslint-disable consistent-return */
944
- module.exports = value => {
945
- if ( [ null, undefined ].includes( value ) ) {
946
- return undefined;
573
+ this.#transformRequest = transformRequest;
574
+ this.#apiResponse = new ApiResponse( { headers, transform: transformResponse } );
947
575
  }
948
576
 
949
- if ( /^\d{4}-\d\d-\d\d((T| )\d\d:\d\d:\d\d(.\d{3})?(Z|\+\d\d:?\d\d)?)?$/.test( value ) ) {
950
- return new Date( value );
577
+ /**
578
+ * Register a function that will run before the matching route (only if matches)
579
+ *
580
+ * @param {Object} args
581
+ * @param {function} args.fn A function
582
+ */
583
+ addBeforeHook( { fn } = {} ) {
584
+ this.#beforeHooks.push( new Hook( { fn } ) );
951
585
  }
952
586
 
953
- // integer
954
- if ( /^-?\d+$/.test( value ) ) {
955
- return parseInteger( value );
587
+ /**
588
+ * Register a function that will run after the matching route (only if matches)
589
+ *
590
+ * @param {Object} args
591
+ * @param {function} args.fn A function
592
+ */
593
+ addAfterHook( { fn } = {} ) {
594
+ this.#afterHooks.push( new Hook( { fn } ) );
956
595
  }
957
596
 
958
- // float
959
- if ( /^-?(\d+\.|\.\d+|\d+\.\d+)$/.test( value ) ) {
960
- return parseFloatingPoint( value );
597
+ /**
598
+ * Register a handler for a given request method and optionally a path
599
+ *
600
+ * @param {Object} args
601
+ * @param {string} args.method The method to match this handler
602
+ * @param {function} args.fn The handler function
603
+ * @param {string} [args.route] A route to match this handler
604
+ * @param {string} [args.routeIncludes] A part of the route to match this handler
605
+ * @param {string} [args.routeNotIncludes] A part of the route to not match this handler
606
+ * @param {RegExp} [args.routeMatches] A RegExp to match the route
607
+ * @param {string} [args.path] A path to match this handler
608
+ * @param {string} [args.pathIncludes] A part of the path to match this handler
609
+ * @param {string} [args.pathNotIncludes] A part of the path to not match this handler
610
+ * @param {RegExp} [args.pathMatches] A RegExp to match the path
611
+ */
612
+ addHandler( { method, fn, ...matchers } = {} ) {
613
+ this.#handlers.push( new Handler( { method, fn, ...matchers } ) );
961
614
  }
962
615
 
963
- // boolean
964
- if ( /^true$/.test( value ) ) {
965
- return true;
616
+ /**
617
+ * Register an automatic error code response for given error class (constructor name)
618
+ *
619
+ * @param {Object} args
620
+ * @param {string} args.code The HTTP status code to return
621
+ * @param {class} args.errorType The error class
622
+ * @param {string} [args.message=null] Optional message to return for the status code, if not present will default to Error.message
623
+ * @param {message} [args.errorType] And optional message to display
624
+ */
625
+ addErrorHandler( { errorType, code, message = null } = {} ) {
626
+ Validator.statusCode( code );
627
+ Validator.errorType( errorType );
628
+ this.#errorResponses.push( { errorType, code, message } );
966
629
  }
967
630
 
968
- if ( /^false$/.test( value ) ) {
969
- return false;
970
- }
631
+ /**
632
+ * Init the flow using a given AWS Lambda APIGateway event (v2 syntax)
633
+ *
634
+ * @param {Object} ApiGatewayPayload The raw API Gateway event
635
+ * @returns {Object} The http response with status, body and headers
636
+ */
637
+ async process( awsEvent ) {
638
+ const event = new Event( { transform: this.#transformRequest } );
639
+ event.parseFromAwsEvent( awsEvent );
971
640
 
972
- return value;
973
- };
641
+ if ( event.method === 'HEAD' ) {
642
+ return this.#apiResponse.setContent( 204 ).toJSON();
643
+ }
974
644
 
645
+ const handler = this.#handlers.find( h => h.match( event ) );
646
+ if ( !handler ) {
647
+ return this.#apiResponse.setContent( 405, Text.ERROR_405 ).toJSON();
648
+ }
975
649
 
976
- /***/ }),
650
+ const chain = [
651
+ ...this.#beforeHooks.map( b => b.fn ),
652
+ async ev => {
653
+ const result = await handler.fn( ev );
654
+ const response = new UserResponse( result );
655
+ this.#apiResponse.setContent( ...response.values ).toJSON();
656
+ },
657
+ ...this.#afterHooks.map( a => a.fn )
658
+ ];
977
659
 
978
- /***/ 2966:
979
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
660
+ try {
661
+ for ( const fn of chain ) {
662
+ await fn( event );
663
+ }
664
+ return this.#apiResponse.toJSON();
980
665
 
981
- const { DynamoDBClient } = __webpack_require__( 4671 );
982
- const { DynamoDBDocumentClient } = __webpack_require__( 3489 );
983
- const cache = __webpack_require__( 4164 );
666
+ } catch ( error ) {
667
+ console.error( 'Lambda API Error', { error, event } );
984
668
 
985
- module.exports = nativeArgs => {
986
- const translateConfig = {
987
- // Yes I copied those from the docs, read more here:
988
- // https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_lib_dynamodb.html#dynamodbdocumentclientresolvedconfig-1
989
- marshallOptions: {
990
- // Whether to automatically convert empty strings, blobs, and sets to `null`.
991
- convertEmptyValues: true, // false, by default.
992
- // Whether to remove undefined values while marshalling.
993
- removeUndefinedValues: true, // false, by default.
994
- // Whether to convert typeof object to map attribute.
995
- convertClassInstanceToMap: true // false, by default.
996
- },
997
- unmarshallOptions: {
998
- // Whether to return numbers as a string instead of converting them to native JavaScript numbers.
999
- wrapNumbers: false // false, by default.
669
+ const response = this.#errorResponses.find( e => error instanceof e.errorType );
670
+ if ( response ) {
671
+ return this.#apiResponse.setContent( response.code, response.message ?? error.message ).toJSON();
672
+ }
673
+ return this.#apiResponse.setContent( 500, Text.ERROR_500 ).toJSON();
1000
674
  }
1001
- };
675
+ }
676
+ };
1002
677
 
1003
- const key = `Dynamodb(${JSON.stringify( nativeArgs )}).DocumentClient`;
1004
- return cache.get( key ) ?? ( () => {
1005
- const client = new DynamoDBClient( nativeArgs );
1006
- const docClient = DynamoDBDocumentClient.from( client, translateConfig );
678
+ ;// ./src/lambda_api/index.js
1007
679
 
1008
- cache.set( key, docClient );
1009
- return docClient;
1010
- } )();
1011
- };
1012
680
 
1013
681
 
1014
- /***/ }),
1015
682
 
1016
- /***/ 3099:
1017
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
683
+ ;// ./src/array/join_unique.js
684
+ const joinUnique = ( ...args ) => [ ...new Set( args.filter( Array.isArray ).flat() ) ];
685
+
686
+ ;// ./src/array/join_unique_custom.js
687
+ const joinUniqueCustom = ( { key, items } ) => [
688
+ ...items.filter( Array.isArray ).flat().reduce( ( map, v ) => {
689
+ const k = key( v );
690
+ if ( !map.has( k ) ) {
691
+ map.set( k, v );
692
+ }
693
+ return map;
694
+ }, new Map() ).values()
695
+ ];
1018
696
 
1019
- const publish = __webpack_require__( 8080 );
1020
- const publishBatch = __webpack_require__( 3531 );
1021
- const { SNSClient } = __webpack_require__( 7651 );
1022
- const clientProvider = __webpack_require__( 9039 );
1023
- const createInstance = __webpack_require__( 5438 );
697
+ ;// ./src/array/split_batches.js
698
+ const splitBatches = ( items, size ) => items.reduce( ( arrs, item ) =>
699
+ ( arrs[0] && arrs[0].length < size ) ?
700
+ [ [ ...arrs[0], item ] ].concat( arrs.slice( 1 ) ) :
701
+ [ [ item ] ].concat( arrs )
702
+ , [] ).reverse();
1024
703
 
1025
- const methods = {
1026
- publish,
1027
- publishBatch
1028
- };
704
+ ;// ./src/array/index.js
1029
705
 
1030
- module.exports = createInstance( clientProvider.bind( null, SNSClient ), methods );
1031
706
 
1032
707
 
1033
- /***/ }),
1034
708
 
1035
- /***/ 3106:
1036
- /***/ ((module) => {
1037
709
 
1038
- "use strict";
1039
- module.exports = require("zlib");
1040
710
 
1041
- /***/ }),
711
+ ;// external "@aws-sdk/client-athena"
712
+ const client_athena_namespaceObject = require("@aws-sdk/client-athena");
713
+ ;// external "node:crypto"
714
+ const external_node_crypto_namespaceObject = require("node:crypto");
715
+ ;// ./src/aws/core/cache_storage.js
1042
716
 
1043
- /***/ 3109:
1044
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1045
717
 
1046
- const validators = __webpack_require__( 8994 );
718
+ const cacheSym = Symbol.for( 'cache' );
1047
719
 
1048
- module.exports = class Handler {
1049
- #method;
1050
- #fn;
1051
- #route;
1052
- #routeIncludes;
1053
- #routeNotIncludes;
1054
- #routeMatches;
1055
- #path;
1056
- #pathIncludes;
1057
- #pathNotIncludes;
1058
- #pathMatches;
720
+ const hash = text => (0,external_node_crypto_namespaceObject.createHash)( 'md5' ).update( text ).digest( 'hex' );
1059
721
 
1060
- constructor( { method, fn, ...matchers } ) {
1061
- validators.httpMethod( method );
1062
- validators.function( fn );
1063
- validators.matcherRoute( matchers.route );
1064
- validators.matcherRouteIncludes( matchers.routeIncludes );
1065
- validators.matcherRouteNotIncludes( matchers.routeNotIncludes );
1066
- validators.matcherRouteMatch( matchers.routeMatch );
1067
- validators.matcherPath( matchers.path );
1068
- validators.matcherPathIncludes( matchers.pathIncludes );
1069
- validators.matcherPathNotIncludes( matchers.pathNotIncludes );
1070
- validators.matcherPathMatch( matchers.pathMatch );
722
+ const propOpts = {
723
+ enumerable: false,
724
+ configurable: false,
725
+ writable: false
726
+ };
1071
727
 
1072
- this.#method = method;
1073
- this.#fn = fn;
1074
- this.#route = matchers.route;
1075
- this.#routeIncludes = matchers.routeIncludes;
1076
- this.#routeNotIncludes = matchers.routeNotIncludes;
1077
- this.#routeMatches = matchers.routeMatches;
1078
- this.#path = matchers.path;
1079
- this.#pathIncludes = matchers.pathIncludes;
1080
- this.#pathNotIncludes = matchers.pathNotIncludes;
1081
- this.#pathMatches = matchers.pathMatches;
1082
- }
728
+ const CacheStorage = {
729
+ set: ( key, value ) => {
730
+ const keySym = Symbol.for( hash( key ) );
1083
731
 
1084
- match( event ) {
1085
- if ( this.#method !== event.method ) {
1086
- return false;
1087
- }
1088
- if ( this.#route ) {
1089
- return this.#route === event.route;
1090
- }
1091
- if ( this.#path ) {
1092
- return this.#path === event.path;
1093
- }
1094
- if ( this.#routeIncludes && !event.route.includes( this.#routeIncludes ) ) {
1095
- return false;
1096
- }
1097
- if ( this.#routeNotIncludes && event.route.includes( this.#routeNotIncludes ) ) {
1098
- return false;
1099
- }
1100
- if ( this.#routeMatches && !this.#routeMatches.test( event.route ) ) {
1101
- return false;
1102
- }
1103
- if ( this.#pathIncludes && !event.path.includes( this.#pathIncludes ) ) {
1104
- return false;
1105
- }
1106
- if ( this.#pathNotIncludes && event.path.includes( this.#pathNotIncludes ) ) {
1107
- return false;
1108
- }
1109
- if ( this.#pathMatches && !this.#pathMatches.test( event.path ) ) {
1110
- return false;
732
+ if ( !global[cacheSym] ) {
733
+ Object.defineProperty( global, cacheSym, { ...propOpts, value: {} } );
1111
734
  }
1112
- return true;
1113
- }
1114
735
 
1115
- get fn() { return this.#fn; }
736
+ Object.defineProperty( global[cacheSym], keySym, { ...propOpts, value } );
737
+ },
738
+ get: key => {
739
+ return global[cacheSym]?.[Symbol.for( hash( key ) )];
740
+ }
1116
741
  };
1117
742
 
743
+ ;// ./src/aws/core/generic_client_provider.js
1118
744
 
1119
- /***/ }),
1120
-
1121
- /***/ 3119:
1122
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1123
-
1124
- const { snakelize, camelize } = __webpack_require__( 5762 );
1125
- const charset = 'utf-8';
1126
745
 
1127
- const transformFns = {
1128
- camelcase: camelize,
1129
- snakecase: snakelize
746
+ const genericClientProvider = ( constructor, args = [] ) => {
747
+ const cacheKey = `${constructor.name}(${args.map( arg => JSON.stringify( arg ) ).join( ',' )})`;
748
+ return CacheStorage.get( cacheKey ) ?? ( () => {
749
+ const client = Reflect.construct( constructor, args );
750
+ CacheStorage.set( cacheKey, client );
751
+ return client;
752
+ } )();
1130
753
  };
1131
754
 
1132
- module.exports = class ApiResponse {
1133
- #headers = null;
1134
- #statusCode = null;
1135
- #transformFn = false;
1136
- #isBase64Encoded = false;
1137
- #body = '';
755
+ ;// ./src/aws/core/encoder.js
756
+ const Encoder = {
757
+ encode: k => {
758
+ if ( k === null || k === undefined ) { return k; }
1138
759
 
1139
- constructor( { headers = {}, transform } = {} ) {
1140
- this.#transformFn = transformFns[transform] ?? ( v => v );
1141
- this.#headers = Object.assign( {
1142
- 'Cache-Control': 'no-store',
1143
- 'Access-Control-Allow-Origin': '*'
1144
- }, headers );
1145
- }
760
+ return Buffer.from( JSON.stringify( k ) ).toString( 'base64' );
761
+ },
762
+ decode: k => {
763
+ if ( k === null || k === undefined ) { return k; }
1146
764
 
1147
- setContent( statusCode, body, headers = {}, isBase64Encoded = false ) {
1148
- this.#statusCode = statusCode;
1149
- this.#isBase64Encoded = isBase64Encoded;
1150
- if ( body?.length === 0 || [ null, undefined ].includes( body ) ) {
1151
- this.#body = '';
1152
- } else if ( typeof body === 'object' ) {
1153
- this.#body = JSON.stringify( this.#transformFn( body ) );
1154
- this.#headers['Content-Type'] = `application/json; charset=${charset}`;
1155
- } else {
1156
- this.#body = String( body );
1157
- this.#headers['Content-Type'] = `text/plain; charset=${charset}`;
765
+ const result = Buffer.from( k, 'base64' ).toString( 'utf8' );
766
+ try {
767
+ return JSON.parse( result );
768
+ } catch {
769
+ return result;
1158
770
  }
1159
- this.#headers['Content-Length'] = this.#body.length;
1160
- Object.assign( this.#headers, headers ?? {} );
1161
- return this;
1162
- }
1163
-
1164
- toJSON() {
1165
- return {
1166
- isBase64Encoded: this.#isBase64Encoded,
1167
- statusCode: this.#statusCode,
1168
- body: this.#body,
1169
- headers: this.#headers
1170
- };
1171
771
  }
1172
772
  };
1173
773
 
774
+ ;// ./src/aws/athena/lib/start_query.js
1174
775
 
1175
- /***/ }),
1176
776
 
1177
- /***/ 3131:
1178
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1179
777
 
1180
- const { SendMessageBatchCommand } = __webpack_require__( 1976 );
1181
- const sanitizeSqs = __webpack_require__( 8175 );
778
+ /**
779
+ * args : https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/athena/command/StartQueryExecutionCommand/
780
+ * A ClientRequestToken is created automatically
781
+ */
782
+ const startQuery = async ( { client, ...args } ) => {
783
+ const cmd = new client_athena_namespaceObject.StartQueryExecutionCommand( {
784
+ ClientRequestToken: (0,external_node_crypto_namespaceObject.randomBytes)( 16 ).toString( 'hex' ),
785
+ ...args
786
+ } );
787
+ const { QueryExecutionId: queryId } = await client.send( cmd );
788
+ return queryId;
789
+ };
790
+
791
+ ;// ./src/aws/athena/lib/parse_value.js
792
+ /* eslint consistent-return: 0 */
793
+ const removeNullValues = ( o, isArray = Array.isArray( o ) ) =>
794
+ Object.entries( o ).reduce( ( newObj, [ k, v ] ) => {
795
+ if ( v === null && !isArray ) { return newObj; }
796
+ return Object.assign( newObj, { [k]: v?.constructor === Object ? removeNullValues( v ) : v } );
797
+ }, isArray ? [] : {} );
1182
798
 
1183
- module.exports = async ( client, queue, messages ) => {
1184
- if ( messages.length > 10 ) {
1185
- throw new Error( 'SQS.sendMessageBatch only accepts up to 10 messages.' );
799
+ const parseValue = ( v, type ) => {
800
+ if ( [ null, undefined ].includes( v ) ) {
801
+ return undefined;
1186
802
  }
1187
- const response = await client.send( new SendMessageBatchCommand( {
1188
- QueueUrl: queue,
1189
- Entries: messages.map( ( { body, id = null, nativeArgs }, index ) => ( {
1190
- Id: id ?? `message_${index}`,
1191
- MessageBody: sanitizeSqs( typeof body === 'string' ? body : JSON.stringify( body ) ),
1192
- ...nativeArgs
1193
- } ) )
1194
- } ) );
803
+ if ( v === '' && type !== 'varchar' ) {
804
+ return undefined;
805
+ }
806
+ if ( type === 'boolean' ) {
807
+ return v === 'true';
808
+ }
809
+ if ( [ 'float', 'decimal', 'double' ].includes( type ) ) {
810
+ return parseFloat( v );
811
+ }
812
+ if ( [ 'tinyint', 'smallint', 'int', 'bigint' ].includes( type ) ) {
813
+ return parseInt( v );
814
+ }
815
+ if ( 'timestamp' === type ) {
816
+ return new Date( v ).getTime();
817
+ }
818
+ if ( [ 'row', 'array' ].includes( type ) ) {
819
+ const obj = v.replace( /(?<=(?:{|,\s)[\w-_]+)=/g, '@@DELIMITER@@' ) // replaces delimiter = with @@DELIMITER@@
820
+ .replace( /(?<={|,\s)([\w_-]+)(?=@@DELIMITER@@)/g, '"$1"' ) // wrap object keys
821
+ .replace( /(?<=@@DELIMITER@@)((?:(?!,\s|}|\[|{).)+)/g, '"$1"' ) // wrap object values
822
+ .replace( /(?<=\[|,\s)((?:(?!,\s|{|\]|").)+)/g, '"$1"' ) // wrap array values
823
+ .replace( /"null"/g, 'null' ) // convert "null" to null
824
+ .replace( /@@DELIMITER@@/g, ':' ); // replaces @@DELIMITER@@ for :
1195
825
 
1196
- if ( response.Failed?.length > 0 ) {
1197
- const error = new Error( 'SQS.sendMessageBatch Failed. See error details' );
1198
- error.details = response.Failed;
1199
- throw error;
826
+ return removeNullValues( JSON.parse( obj ) );
1200
827
  }
1201
- return response;
828
+ if ( 'json' === type ) {
829
+ return JSON.parse( v );
830
+ }
831
+ return v;
1202
832
  };
1203
833
 
834
+ ;// ./src/aws/athena/lib/parse_results.js
1204
835
 
1205
- /***/ }),
1206
836
 
1207
- /***/ 3187:
1208
- /***/ ((module) => {
837
+ const parseResults = resultSet => {
838
+ const columns = resultSet.ResultSetMetadata.ColumnInfo
839
+ .map( col => ( { name: col.Name, type: col.Type } ) );
1209
840
 
1210
- module.exports = values => {
1211
- //Sort bug: https://www.tutorialrepublic.com/faq/how-to-sort-an-array-of-integers-correctly-in-javascript.php
1212
- const sorted = values.slice().sort( ( a, b ) => a - b );
1213
- const evenArray = values.length % 2 === 0;
1214
- const midIndex = Math.floor( values.length / 2 );
1215
- return evenArray ? ( sorted[midIndex - 1] + sorted[midIndex] ) / 2 : sorted[midIndex];
841
+ // first data row contains the table field names
842
+ return resultSet.Rows.slice( 1 ).map( row => {
843
+ const values = row.Data.map( d => d.VarCharValue );
844
+ return columns.reduce( ( obj, p, i ) => Object.assign( obj, { [p.name]: parseValue( values[i], p.type ) } ), {} );
845
+ } );
1216
846
  };
1217
847
 
848
+ ;// ./src/aws/athena/lib/polling_delay.js
849
+ const pollingDelay = 500;
1218
850
 
1219
- /***/ }),
851
+ ;// ./src/aws/athena/lib/get_results.js
1220
852
 
1221
- /***/ 3258:
1222
- /***/ ((module) => {
1223
853
 
1224
- module.exports = input =>
1225
- // Break the string into sequences to rebuild later
1226
- !input ? input : input.split( /\s/ )
1227
- // ALL_CAPS terms are ignored
1228
- .map( term => [ term, term.charAt( 0 ).toUpperCase() + term.slice( 1 ).toLowerCase() ] )
1229
- // Rebuild the string replacing the converter terms keeping the original delimiters
1230
- .reduce( ( result, [ term, repl ] ) => result.replace( term, repl ), input );
1231
854
 
1232
855
 
1233
- /***/ }),
856
+ const sleep = t => new Promise( r => setTimeout( () => r(), t ) );
1234
857
 
1235
- /***/ 3340:
1236
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
858
+ const getQueryResults = async ( { client, queryExecutionId, maxResults, token } ) => {
859
+ const { NextToken: nextToken, ResultSet } = await client.send( new client_athena_namespaceObject.GetQueryResultsCommand( {
860
+ ...{ QueryExecutionId: queryExecutionId },
861
+ ...( maxResults ? { MaxResults: maxResults } : {} ),
862
+ ...( token ? { NextToken: token } : {} )
863
+ } ) );
1237
864
 
1238
- const deleteMessage = __webpack_require__( 5637 );
1239
- const sendMessage = __webpack_require__( 6720 );
1240
- const sendMessageBatch = __webpack_require__( 3131 );
1241
- const { SQSClient } = __webpack_require__( 1976 );
1242
- const clientProvider = __webpack_require__( 9039 );
1243
- const createInstance = __webpack_require__( 5438 );
865
+ return { nextToken, items: parseResults( ResultSet ) };
866
+ };
867
+ const getQueryResultsRecursive = async ( { client, queryExecutionId, token } ) => {
868
+ const { nextToken, items } = await getQueryResults( { client, queryExecutionId, token } );
1244
869
 
1245
- const methods = {
1246
- deleteMessage,
1247
- sendMessage,
1248
- sendMessageBatch
870
+ if ( nextToken ) {
871
+ return { items: items.concat( ( await getQueryResultsRecursive( { client, queryExecutionId, token: nextToken } ) ).items ) };
872
+ }
873
+ return { items };
1249
874
  };
1250
875
 
1251
- module.exports = createInstance( clientProvider.bind( null, SQSClient ), methods );
876
+ /**
877
+ * https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/athena/command/GetQueryResultsCommand/
878
+ * { client, recursive, queryExecutionId, maxResults, paginationToken }
879
+ */
880
+ const getResults = async ( { client, recursive, queryExecutionId, token, maxResults } ) => {
881
+ const { QueryExecution: { Status: status } } = await client.send( new client_athena_namespaceObject.GetQueryExecutionCommand( { QueryExecutionId: queryExecutionId } ) );
1252
882
 
883
+ if ( status.State === 'FAILED' ) {
884
+ throw new Error( status.AthenaError?.ErrorMessage ?? status.StateChangeReason );
885
+ }
1253
886
 
1254
- /***/ }),
887
+ if ( status.State === 'SUCCEEDED' ) {
888
+ const fn = recursive ? getQueryResultsRecursive : getQueryResults;
889
+ return fn( { client, recursive, queryExecutionId, token, maxResults } );
890
+ }
1255
891
 
1256
- /***/ 3402:
1257
- /***/ ((module) => {
892
+ // sleep an try again
893
+ await sleep( pollingDelay );
894
+ return getResults( { client, recursive, queryExecutionId, token, maxResults } );
895
+ };
1258
896
 
1259
- // convert a string to snake_case
1260
- module.exports = ( input, { keepAllCaps = false } = {} ) =>
1261
- // Break the string into sequences to rebuild later
1262
- !input ? input : input.split( /\s/ )
1263
- // ALL_CAPS terms are ignored
1264
- .map( term => [ term, keepAllCaps && /^[A-Z_]+$/g.test( term ) ? term : term
1265
- .replace( /-/g, '_' ) // replaces hyphen
1266
- .replace( /([a-z\d])([A-Z])/g, '$1_$2' ) // add _ between lower and upper case letters
1267
- .replace( /([A-Z])([A-Z])(?=[a-z\d])/g, '$1_$2' ).toLowerCase() // add _ between uppercase char and next uppercase char follow by lowercase
1268
- ] )
1269
- // Rebuild the string replacing the converter terms keeping the original delimiters
1270
- .reduce( ( result, [ term, repl ] ) => result.replace( term, repl ), input );
897
+ ;// ./src/aws/athena/query.js
1271
898
 
1272
899
 
1273
- /***/ }),
1274
900
 
1275
- /***/ 3446:
1276
- /***/ ((module) => {
1277
901
 
1278
- module.exports = class LambdaApiValidationError extends Error {};
902
+ const getQueryExecutionId = async ( { client, nativeArgs, recursive, paginationToken } ) => {
903
+ if ( !recursive && paginationToken ) {
904
+ const { queryExecutionId, token } = Encoder.decode( paginationToken );
905
+ return { queryExecutionId, token };
906
+ }
1279
907
 
908
+ const queryExecutionId = await startQuery( { client, ...nativeArgs } );
909
+ return { queryExecutionId };
910
+ };
1280
911
 
1281
- /***/ }),
912
+ /**
913
+ * @class Result
914
+ * @type {Object}
915
+ * @property {Object[]} items Each query result row, parsed to a camelized js object
916
+ * @property {String} paginationToken The next pagination token, if recursive = false ans there are more results for the query
917
+ */
1282
918
 
1283
- /***/ 3489:
1284
- /***/ ((module) => {
919
+ /**
920
+ * Executes an Athena Query
921
+ * @param {*} client The native client
922
+ * @param {Object} nativeArgs The native args to start the Athena Query
923
+ * @param {Object=} options Query configuration
924
+ * @param {Boolean=} [options.recursive=false] If to recursive query all results or to return a paginationToken after each page
925
+ * @param {String=} options.paginationToken The pagination token received in the previous call to resume the query (only used when recursive = false)
926
+ * @param {Number=} options.maxResults The maximum number of results per page (only when using pagination token)
927
+ * @returns {Result} The query result
928
+ */
929
+ const query = async ( client, nativeArgs, options ) => {
930
+ const { recursive = false, paginationToken, maxResults } = options;
1285
931
 
1286
- "use strict";
1287
- module.exports = require("@aws-sdk/lib-dynamodb");
932
+ const { queryExecutionId, token } = await getQueryExecutionId( { client, nativeArgs, recursive, paginationToken } );
1288
933
 
1289
- /***/ }),
934
+ const { nextToken, items } = await getResults( { client, queryExecutionId, token, recursive, maxResults } );
935
+ return { paginationToken: nextToken ? Encoder.encode( { queryExecutionId, token: nextToken } ) : undefined, items };
936
+ };
1290
937
 
1291
- /***/ 3531:
1292
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
938
+ ;// ./src/aws/core/create_instance.js
939
+ /**
940
+ * This is base object each AWS abstraction will provide
941
+ */
942
+ const createInstance = ( providerFn, methods ) => {
943
+ // This creates the "instance",
944
+ // so calling the method as a function returns a copy of its client instantiated with the given args
945
+ // every method called from it will use this instance
946
+ const factory = args => {
947
+ const client = providerFn( args );
948
+ // return self, so it is possible use the native client
949
+ methods.getClient = () => client;
950
+ return Object.entries( methods ).reduce( ( o, [ k, v ] ) => Object.assign( o, { [k]: v.bind( null, client ) } ), { } );
951
+ };
1293
952
 
1294
- const { PublishBatchCommand } = __webpack_require__( 7651 );
953
+ // This is the singleton part;
954
+ // First add the static method to the factory;
955
+ Object.entries( methods ).forEach( ( [ key, value ] ) => factory[key] = value );
1295
956
 
1296
- module.exports = async ( client, topic, messages ) => {
1297
- if ( messages.length > 10 ) {
1298
- throw new Error( 'SNS.publishBatch only accepts up to 10 messages.' );
1299
- }
1300
- const response = await client.send( new PublishBatchCommand( {
1301
- TopicArn: topic,
1302
- PublishBatchRequestEntries: messages.map( ( { body, id = null, nativeArgs }, index ) => ( {
1303
- Id: id ?? `message_${index}`,
1304
- Message: typeof body === 'string' ? body : JSON.stringify( body ),
1305
- ...nativeArgs
1306
- } ) )
1307
- } ) );
957
+ // Then add the special method "getClient", so it is possible use the native client
958
+ factory.getClient = client => client;
1308
959
 
1309
- if ( response.Failed?.length > 0 ) {
1310
- const error = new Error( 'SNS.publishBatch Failed. See error details' );
1311
- error.details = response.Failed;
1312
- throw error;
1313
- }
1314
- return response;
960
+ // Finally makes the proxy which will allow each singleton method to use the client provider of the AWS service+
961
+ return new Proxy( factory, {
962
+ get( target, key ) {
963
+ const t = target[key];
964
+ return ( typeof t === 'function' ) ? t.bind( null, providerFn() ) : t;
965
+ }
966
+ } );
1315
967
  };
1316
968
 
969
+ ;// ./src/aws/athena/index.js
970
+
1317
971
 
1318
- /***/ }),
1319
972
 
1320
- /***/ 3544:
1321
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1322
973
 
1323
- const invoke = __webpack_require__( 5894 );
1324
- const { LambdaClient } = __webpack_require__( 5892 );
1325
- const clientProvider = __webpack_require__( 9039 );
1326
- const createInstance = __webpack_require__( 5438 );
1327
974
 
1328
975
  const methods = {
1329
- invoke
976
+ query: query
1330
977
  };
1331
978
 
1332
- module.exports = createInstance( clientProvider.bind( null, LambdaClient ), methods );
1333
-
979
+ const athena = createInstance( genericClientProvider.bind( null, client_athena_namespaceObject.AthenaClient ), methods );
1334
980
 
1335
- /***/ }),
981
+ ;// external "@aws-sdk/client-cloudwatch-logs"
982
+ const client_cloudwatch_logs_namespaceObject = require("@aws-sdk/client-cloudwatch-logs");
983
+ ;// ./src/aws/cw_logs/query/start_query.js
1336
984
 
1337
- /***/ 3649:
1338
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1339
985
 
1340
- const { StartQueryCommand } = __webpack_require__( 7493 );
1341
-
1342
- module.exports = async ( { client, nativeArgs, range } ) => {
986
+ const start_query_startQuery = async ( { client, nativeArgs, range } ) => {
1343
987
  const startTime = range?.from ? Math.trunc( range.from / 1000 ) : nativeArgs.startTime;
1344
988
  const endTime = range?.to ? Math.trunc( range.to / 1000 ) : nativeArgs.endTime;
1345
989
 
1346
- const { queryId } = await client.send( new StartQueryCommand( { ...nativeArgs, startTime, endTime } ) );
990
+ const { queryId } = await client.send( new client_cloudwatch_logs_namespaceObject.StartQueryCommand( { ...nativeArgs, startTime, endTime } ) );
1347
991
  return queryId;
1348
992
  };
1349
993
 
994
+ ;// ./src/aws/cw_logs/query/polling_delay.js
995
+ const polling_delay_pollingDelay = 500;
1350
996
 
1351
- /***/ }),
997
+ ;// ./src/utils/sleep.js
998
+ const sleep_sleep = t => new Promise( r => setTimeout( r, t ) );
1352
999
 
1353
- /***/ 3744:
1354
- /***/ ((module) => {
1000
+ ;// ./src/aws/cw_logs/query/get_results.js
1355
1001
 
1356
- "use strict";
1357
- module.exports = require("@aws-sdk/client-athena");
1358
1002
 
1359
- /***/ }),
1360
1003
 
1361
- /***/ 3758:
1362
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1363
1004
 
1364
- const { getSignedUrl } = __webpack_require__( 4991 );
1365
- const { GetObjectCommand } = __webpack_require__( 5725 );
1005
+ const getResultsRecursive = async ( { client, command } ) => {
1006
+ const { results, status } = await client.send( command );
1366
1007
 
1367
- module.exports = async ( client, bucket, key, expiration ) => {
1368
- const getObjectCmd = new GetObjectCommand( { Bucket: bucket, Key: key } );
1369
- const url = await getSignedUrl( client, getObjectCmd, { expiresIn: expiration } );
1370
- return url;
1371
- };
1008
+ if ( [ 'Cancelled', 'Failed', 'Timeout', 'Unknown' ].includes( status ) ) {
1009
+ throw new Error( `Query status is "${status}"` );
1010
+ }
1372
1011
 
1012
+ if ( status === 'Complete' ) {
1013
+ return results;
1014
+ }
1373
1015
 
1374
- /***/ }),
1016
+ // Running, Scheduled
1017
+ await sleep_sleep( polling_delay_pollingDelay );
1018
+ return getResultsRecursive( { client, command } );
1019
+ };
1375
1020
 
1376
- /***/ 3830:
1377
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1021
+ const get_results_getResults = async ( { client, queryId } ) => {
1022
+ const command = new client_cloudwatch_logs_namespaceObject.GetQueryResultsCommand( { queryId } );
1023
+ return getResultsRecursive( { client, command } );
1024
+ };
1378
1025
 
1379
- const days = __webpack_require__( 5263 );
1380
- const hours = __webpack_require__( 6961 );
1381
- const minutes = __webpack_require__( 6635 );
1382
- const months = __webpack_require__( 8119 );
1383
- const msToS = __webpack_require__( 7416 );
1384
- const round = __webpack_require__( 3990 );
1385
- const seconds = __webpack_require__( 7051 );
1026
+ ;// ./src/aws/cw_logs/query/parse_value.js
1027
+ const parseInteger = value => {
1028
+ const number = parseInt( value, 10 );
1029
+ return number <= Number.MAX_SAFE_INTEGER && number >= Number.MIN_SAFE_INTEGER ? number : value;
1030
+ };
1386
1031
 
1387
- module.exports = {
1388
- days,
1389
- hours,
1390
- minutes,
1391
- months,
1392
- msToS,
1393
- round,
1394
- seconds
1032
+ const parseFloatingPoint = value => {
1033
+ if ( value.replace( /[^\d]/g, '' ).length > 16 ) {
1034
+ return value;
1035
+ }
1036
+ const number = parseFloat( value, 10 );
1037
+ return number <= Number.MAX_SAFE_INTEGER && number >= Number.MIN_SAFE_INTEGER ? number : value;
1395
1038
  };
1396
1039
 
1040
+ /* eslint-disable consistent-return */
1041
+ const parse_value_parseValue = value => {
1042
+ if ( [ null, undefined ].includes( value ) ) {
1043
+ return undefined;
1044
+ }
1045
+
1046
+ if ( /^\d{4}-\d\d-\d\d((T| )\d\d:\d\d:\d\d(.\d{3})?(Z|\+\d\d:?\d\d)?)?$/.test( value ) ) {
1047
+ return new Date( value );
1048
+ }
1397
1049
 
1398
- /***/ }),
1050
+ // integer
1051
+ if ( /^-?\d+$/.test( value ) ) {
1052
+ return parseInteger( value );
1053
+ }
1399
1054
 
1400
- /***/ 3862:
1401
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1055
+ // float
1056
+ if ( /^-?(\d+\.|\.\d+|\d+\.\d+)$/.test( value ) ) {
1057
+ return parseFloatingPoint( value );
1058
+ }
1402
1059
 
1403
- const batchWrite = __webpack_require__( 8593 );
1060
+ // boolean
1061
+ if ( /^true$/.test( value ) ) {
1062
+ return true;
1063
+ }
1404
1064
 
1405
- module.exports = async ( client, ...args ) => batchWrite( client, 'remove', ...args );
1065
+ if ( /^false$/.test( value ) ) {
1066
+ return false;
1067
+ }
1406
1068
 
1069
+ return value;
1070
+ };
1407
1071
 
1408
- /***/ }),
1072
+ ;// ./src/aws/cw_logs/query/parse_item.js
1409
1073
 
1410
- /***/ 3914:
1411
- /***/ ((module) => {
1412
1074
 
1413
- // Convert a string to camelCase
1414
- module.exports = ( input, { keepAllCaps = false } = {} ) =>
1415
- // Break the string into sequences to rebuild later
1416
- !input ? input : input.split( /\s/ )
1417
- // ALL_CAPS terms are ignored
1418
- .map( term => [ term, keepAllCaps && /^[A-Z_]+$/g.test( term ) ? term : term
1419
- // Matches the penultimate letter in a sequence of upper case followed by lower case and convert it to lower case
1420
- // Effectively creating a word break eg: BDay => bDay
1421
- .replace( /[A-Z](?=[A-Z][a-z])/g, c => `${c[0].toLowerCase()}` )
1422
- .replace( /([A-Z])([A-Z]+)/g, c => `${c[0]}${c.slice( 1 ).toLowerCase()}` ) // Sequences of upper case
1423
- .replace( /([-_]\w)/g, c => c[1].toUpperCase() ) // first letter after hyphen and underline
1424
- .replace( /^([A-Z])/g, c => c[0].toLowerCase() ) // first letter
1425
- ] )
1426
- // Rebuild the string replacing the converter terms keeping the original delimiters
1427
- .reduce( ( result, [ term, repl ] ) => result.replace( term, repl ), input );
1075
+ const parseItem = item =>
1076
+ item.reduce( ( row, { field, value } ) =>
1077
+ Object.assign( row, {
1078
+ [field]: parse_value_parseValue( value )
1079
+ } ), {} );
1428
1080
 
1081
+ ;// ./src/aws/cw_logs/query/parse_results.js
1429
1082
 
1430
- /***/ }),
1431
1083
 
1432
- /***/ 3936:
1433
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1084
+ const parse_results_parseResults = results => results.map( item => parseItem( item ) );
1434
1085
 
1435
- const { CopyObjectCommand } = __webpack_require__( 5725 );
1086
+ ;// ./src/aws/cw_logs/query/index.js
1436
1087
 
1437
- module.exports = async ( client, bucket, key, source, nativeArgs ) => {
1438
- const response = await client.send( new CopyObjectCommand( {
1439
- ...nativeArgs,
1440
- Bucket: bucket,
1441
- Key: key,
1442
- CopySource: source
1443
- } ) );
1444
- return response;
1445
- };
1446
1088
 
1447
1089
 
1448
- /***/ }),
1449
1090
 
1450
- /***/ 3990:
1451
- /***/ ((module) => {
1091
+ /**
1092
+ * @class Result
1093
+ * @type {Object}
1094
+ * @property {Object[]} items Each query result row, parsed to a camelized js object
1095
+ * @property {Number} count Total number of results
1096
+ */
1452
1097
 
1453
- module.exports = ( time, interval ) => time - ( time % interval );
1098
+ /**
1099
+ * Executes an Athena Query
1100
+ * @param {*} client The native client
1101
+ * @param {Object} nativeArgs The native args to start the Cloudwatch Query
1102
+ * @param {Object=} options Extra options for this command
1103
+ * @param {Object=} options.range Since the nativeArgs "startTime" and "endTime" are second based epochs, the "range" argument accepts milliseconds based epochs for convenience, thus overwriting the "nativeArgs"
1104
+ * @param {Number} options.range.from The beginning of the time range to query, overwrites "startTime"
1105
+ * @param {Number} options.range.to The end of the time range to query, overwrites "endTime"
1106
+ * @returns {Result} The query result
1107
+ */
1108
+ const query_query = async ( client, nativeArgs, { range = {} } = {} ) => {
1109
+ const queryId = await start_query_startQuery( { client, nativeArgs, range } );
1110
+ const results = await get_results_getResults( { client, queryId } );
1111
+ const items = parse_results_parseResults( results );
1112
+ return { items, count: items.length };
1113
+ };
1454
1114
 
1115
+ ;// ./src/aws/cw_logs/index.js
1455
1116
 
1456
- /***/ }),
1457
1117
 
1458
- /***/ 4110:
1459
- /***/ ((module) => {
1460
1118
 
1461
- module.exports = ( sample, mean, stdDev ) => stdDev === 0 ? NaN : ( sample - mean ) / stdDev;
1462
1119
 
1463
1120
 
1464
- /***/ }),
1121
+ const cw_logs_methods = {
1122
+ query: query_query
1123
+ };
1465
1124
 
1466
- /***/ 4124:
1467
- /***/ ((module) => {
1125
+ const cwLogs = createInstance( genericClientProvider.bind( null, client_cloudwatch_logs_namespaceObject.CloudWatchLogsClient ), cw_logs_methods );
1468
1126
 
1469
- module.exports = values => values.reduce( ( sum, value ) => sum + value, 0 ) / values.length;
1127
+ ;// external "@aws-sdk/client-dynamodb"
1128
+ const client_dynamodb_namespaceObject = require("@aws-sdk/client-dynamodb");
1129
+ ;// external "@aws-sdk/lib-dynamodb"
1130
+ const lib_dynamodb_namespaceObject = require("@aws-sdk/lib-dynamodb");
1131
+ ;// ./src/aws/dynamo/document_client_provider.js
1470
1132
 
1471
1133
 
1472
- /***/ }),
1473
1134
 
1474
- /***/ 4127:
1475
- /***/ ((module) => {
1476
1135
 
1477
- module.exports = 500;
1136
+ const documentClientProvider = nativeArgs => {
1137
+ const translateConfig = {
1138
+ // Yes I copied those from the docs, read more here:
1139
+ // https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_lib_dynamodb.html#dynamodbdocumentclientresolvedconfig-1
1140
+ marshallOptions: {
1141
+ // Whether to automatically convert empty strings, blobs, and sets to `null`.
1142
+ convertEmptyValues: true, // false, by default.
1143
+ // Whether to remove undefined values while marshalling.
1144
+ removeUndefinedValues: true, // false, by default.
1145
+ // Whether to convert typeof object to map attribute.
1146
+ convertClassInstanceToMap: true // false, by default.
1147
+ },
1148
+ unmarshallOptions: {
1149
+ // Whether to return numbers as a string instead of converting them to native JavaScript numbers.
1150
+ wrapNumbers: false // false, by default.
1151
+ }
1152
+ };
1478
1153
 
1154
+ const key = `Dynamodb(${JSON.stringify( nativeArgs )}).DocumentClient`;
1155
+ return CacheStorage.get( key ) ?? ( () => {
1156
+ const client = new client_dynamodb_namespaceObject.DynamoDBClient( nativeArgs );
1157
+ const docClient = lib_dynamodb_namespaceObject.DynamoDBDocumentClient.from( client, translateConfig );
1479
1158
 
1480
- /***/ }),
1159
+ CacheStorage.set( key, docClient );
1160
+ return docClient;
1161
+ } )();
1162
+ };
1481
1163
 
1482
- /***/ 4144:
1483
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1164
+ ;// ./src/aws/dynamo/get.js
1484
1165
 
1485
- const { UpdateCommand } = __webpack_require__( 3489 );
1486
1166
 
1487
- module.exports = async ( client, nativeArgs ) => {
1488
- const args = Object.assign( { ReturnValues: 'ALL_NEW' }, nativeArgs );
1489
- const response = await client.send( new UpdateCommand( args ) );
1490
- return response.Attributes;
1167
+ const parseArgs = args => {
1168
+ // native args mode
1169
+ if ( args[0] instanceof Object ) {
1170
+ return args[0];
1171
+ }
1172
+ // sugar mode
1173
+ return {
1174
+ TableName: args[0],
1175
+ Key: args[1]
1176
+ };
1491
1177
  };
1492
1178
 
1179
+ const get = async ( client, ...args ) => {
1180
+ const response = await client.send( new lib_dynamodb_namespaceObject.GetCommand( parseArgs( args ) ) );
1181
+ return response.Item;
1182
+ };
1493
1183
 
1494
- /***/ }),
1495
-
1496
- /***/ 4164:
1497
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1184
+ ;// ./src/aws/dynamo/put.js
1498
1185
 
1499
- const cacheSym = Symbol.for( 'cache' );
1500
- const crypto = __webpack_require__( 6982 );
1501
1186
 
1502
- const hash = text => crypto.createHash( 'md5' ).update( text ).digest( 'hex' );
1187
+ const put_parseArgs = args => {
1188
+ // native args mode
1189
+ if ( args[0] instanceof Object ) {
1190
+ return args[0];
1191
+ }
1192
+ // sugar mode
1193
+ return {
1194
+ TableName: args[0],
1195
+ Item: args[1],
1196
+ ReturnValues: 'NONE',
1197
+ ReturnConsumedCapacity: 'NONE'
1198
+ };
1199
+ };
1503
1200
 
1504
- const propOpts = {
1505
- enumerable: false,
1506
- configurable: false,
1507
- writable: false
1201
+ /**
1202
+ *
1203
+ * @param {*} client
1204
+ * @param {...any} args The args. either one object with the native args or two string args, tableName and item.
1205
+ * @returns
1206
+ */
1207
+ const put = async ( client, ...args ) => {
1208
+ const nativeArgs = put_parseArgs( args );
1209
+ const response = await client.send( new lib_dynamodb_namespaceObject.PutCommand( nativeArgs ) );
1210
+ return response.Attributes ?? nativeArgs.Item;
1508
1211
  };
1509
1212
 
1510
- module.exports = {
1511
- set: ( key, value ) => {
1512
- const keySym = Symbol.for( hash( key ) );
1213
+ ;// ./src/aws/dynamo/batch_write.js
1513
1214
 
1514
- if ( !global[cacheSym] ) {
1515
- Object.defineProperty( global, cacheSym, { ...propOpts, value: {} } );
1516
- }
1517
1215
 
1518
- Object.defineProperty( global[cacheSym], keySym, { ...propOpts, value } );
1519
- },
1520
- get: key => {
1521
- return global[cacheSym]?.[Symbol.for( hash( key ) )];
1522
- }
1523
- };
1524
1216
 
1217
+ const batchSize = 25;
1525
1218
 
1526
- /***/ }),
1219
+ const getMapper = method => method === 'put' ? v => ( { PutRequest: { Item: v } } ) : v => ( { DeleteRequest: { Key: v } } );
1527
1220
 
1528
- /***/ 4225:
1529
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1221
+ const process = async ( { client, method, table, batches } ) => {
1222
+ if ( batches.length === 0 ) { return true; }
1530
1223
 
1531
- const query = __webpack_require__( 6030 );
1532
- const { TimestreamQueryClient } = __webpack_require__( 1671 );
1533
- const { Agent } = __webpack_require__( 5692 );
1534
- const clientProvider = __webpack_require__( 9039 );
1535
- const createInstance = __webpack_require__( 5438 );
1224
+ const response = await client.send( new lib_dynamodb_namespaceObject.BatchWriteCommand( { RequestItems: { [table]: batches[0] } } ) );
1536
1225
 
1537
- const methods = { query };
1538
- const defaultArgs = {
1539
- maxRetries: 10,
1540
- httpOptions: { timeout: 60000, agent: new Agent( { maxSockets: 5000 } ) }
1226
+ const unprocessed = response.UnprocessedItems?.[table];
1227
+ return process( {
1228
+ client, method, table,
1229
+ batches: unprocessed ? splitBatches( batches.slice( 1 ).flat().concat( unprocessed ), batchSize ) : batches.slice( 1 )
1230
+ } );
1541
1231
  };
1542
1232
 
1543
- module.exports = createInstance( args => clientProvider( TimestreamQueryClient, [ Object.assign( {}, defaultArgs, args ) ] ), methods );
1233
+ const batchWrite = async ( client, method, table, items ) =>
1234
+ process( { client, method, table, batches: splitBatches( items.map( getMapper( method ) ), batchSize ) } );
1544
1235
 
1236
+ ;// ./src/aws/dynamo/put_batch.js
1545
1237
 
1546
- /***/ }),
1547
1238
 
1548
- /***/ 4243:
1549
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1239
+ const putBatch = async ( client, ...args ) => batchWrite( client, 'put', ...args );
1550
1240
 
1551
- const sleep = __webpack_require__( 2445 );
1241
+ ;// ./src/aws/dynamo/select.js
1552
1242
 
1553
- const execWithRetry = async ( closure, { limit, delay, retryHook, execCount = 0 } ) => {
1554
- if ( !( closure instanceof Function ) ) {
1555
- throw new Error( 'Closure is not a function' );
1556
- }
1557
1243
 
1558
- try {
1559
- return await closure();
1560
- } catch ( error ) {
1561
- // exhausted
1562
- if ( execCount === limit ) { throw error; }
1563
1244
 
1564
- // async retry hook to check if it should retry or give up and throw
1565
- if ( retryHook instanceof Function ) {
1566
- try {
1567
- const retry = await retryHook( error, execCount );
1568
- if ( retry === false ) { return false; }
1245
+ const select_query = async ( { client, command, args, recursive, startKey, items = [], count = 0 } ) => {
1246
+ const response = await client.send( new command( {
1247
+ ...args,
1248
+ ...( startKey && { ExclusiveStartKey: startKey } )
1249
+ } ) );
1250
+
1251
+ const isCount = args.Select === 'COUNT';
1252
+ const hasLimit = Number.isFinite( args.Limit );
1253
+
1254
+ const result = {
1255
+ items: isCount ? null : items.concat( response.Items ),
1256
+ count: count + response.Count,
1257
+ startKey: response.LastEvaluatedKey
1258
+ };
1569
1259
 
1570
- // Hook errors break the flow
1571
- } catch ( hookError ) {
1572
- console.debug( hookError );
1573
- throw hookError;
1574
- }
1575
- }
1260
+ if ( !recursive ) {
1261
+ return { items: result.items, count: result.count, ...( result.startKey && { nextToken: Encoder.encode( result.startKey ) } ) };
1262
+ }
1576
1263
 
1577
- // if there is no hook back-off and retry
1578
- if ( delay > 0 ) {
1579
- await sleep( delay ** ( 1 + execCount ) );
1580
- }
1581
- return execWithRetry( closure, { limit, delay, retryHook, execCount: execCount + 1 } );
1264
+ if ( result.startKey && ( isCount || ( hasLimit && result.items.length < args.Limit ) || ( !isCount && !hasLimit ) ) ) {
1265
+ return select_query( { client, command, args, recursive, ...result } );
1266
+ }
1267
+
1268
+ if ( isCount ) {
1269
+ return { items: null, count: result.count };
1582
1270
  }
1271
+ const trimmedItems = result.items.slice( 0, args.Limit );
1272
+ return { items: trimmedItems, count: trimmedItems.length };
1583
1273
  };
1584
1274
 
1585
- /**
1586
- *
1587
- * @param {Function} closure A self contained function that will be invoked
1588
- * @param {Object} config
1589
- * @param {Number} limit The max number of retries
1590
- * @param {Number} delay The delay between each retry (it will be multiplied by the number of retries, so, it is linear back-off)
1591
- * @param {Function} retryHook A function to be called every-time a retry is needed.
1592
- * If this functions returns false, the retry error is raised
1593
- * If this functions throws error, the thrown error is raised
1594
- * @returns {Any} The closure result
1595
- */
1596
- module.exports = async ( closure, { limit = 0, delay = 0, retryHook = null } = {} ) =>
1597
- execWithRetry( closure, { limit, delay, retryHook } );
1275
+ const select_select = async ( client, method, args, options = { recursive: false, paginationToken: null } ) => {
1276
+ const command = method === 'scan' ? lib_dynamodb_namespaceObject.ScanCommand : lib_dynamodb_namespaceObject.QueryCommand;
1598
1277
 
1278
+ return select_query( { client, command, args, recursive: options.recursive, startKey: Encoder.decode( options.paginationToken ) } );
1279
+ };
1599
1280
 
1600
- /***/ }),
1281
+ ;// ./src/aws/dynamo/query.js
1601
1282
 
1602
- /***/ 4338:
1603
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1604
1283
 
1605
- const startQuery = __webpack_require__( 3649 );
1606
- const getResults = __webpack_require__( 739 );
1607
- const parseResults = __webpack_require__( 9552 );
1284
+ const dynamo_query_query = async ( client, ...args ) => select_select( client, 'query', ...args );
1608
1285
 
1609
- /**
1610
- * @class Result
1611
- * @type {Object}
1612
- * @property {Object[]} items Each query result row, parsed to a camelized js object
1613
- * @property {Number} count Total number of results
1614
- */
1286
+ ;// ./src/aws/dynamo/remove.js
1615
1287
 
1616
- /**
1617
- * Executes an Athena Query
1618
- * @param {*} client The native client
1619
- * @param {Object} nativeArgs The native args to start the Cloudwatch Query
1620
- * @param {Object=} options Extra options for this command
1621
- * @param {Object=} options.range Since the nativeArgs "startTime" and "endTime" are second based epochs, the "range" argument accepts milliseconds based epochs for convenience, thus overwriting the "nativeArgs"
1622
- * @param {Number} options.range.from The beginning of the time range to query, overwrites "startTime"
1623
- * @param {Number} options.range.to The end of the time range to query, overwrites "endTime"
1624
- * @returns {Result} The query result
1625
- */
1626
- module.exports = async ( client, nativeArgs, { range = {} } = {} ) => {
1627
- const queryId = await startQuery( { client, nativeArgs, range } );
1628
- const results = await getResults( { client, queryId } );
1629
- const items = parseResults( results );
1630
- return { items, count: items.length };
1631
- };
1632
1288
 
1289
+ const remove = async ( client, tableName, key ) => {
1290
+ const { Attributes: item } = await client.send( new lib_dynamodb_namespaceObject.DeleteCommand( {
1291
+ ReturnValues: 'ALL_OLD',
1292
+ TableName: tableName,
1293
+ Key: key
1294
+ } ) );
1295
+ return item;
1296
+ };
1633
1297
 
1634
- /***/ }),
1298
+ ;// ./src/aws/dynamo/remove_batch.js
1635
1299
 
1636
- /***/ 4348:
1637
- /***/ ((module) => {
1638
1300
 
1639
- "use strict";
1640
- module.exports = require("@aws-sdk/client-ssm");
1301
+ const removeBatch = async ( client, ...args ) => batchWrite( client, 'remove', ...args );
1641
1302
 
1642
- /***/ }),
1303
+ ;// ./src/aws/dynamo/scan.js
1643
1304
 
1644
- /***/ 4528:
1645
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1646
1305
 
1647
- const createClient = __webpack_require__( 5422 );
1306
+ const scan = async ( client, ...args ) => select_select( client, 'scan', ...args );
1648
1307
 
1649
- module.exports = {
1650
- createClient
1651
- };
1308
+ ;// ./src/aws/dynamo/smart_update.js
1652
1309
 
1653
1310
 
1654
- /***/ }),
1311
+ const smartUpdate = async ( client, tableName, key, keyValues ) => {
1312
+ const { updates, removals, names, values } = Object.entries( keyValues ).reduce( ( args, [ k, value ], index ) => {
1313
+ const isRemoval = value === undefined;
1655
1314
 
1656
- /***/ 4671:
1657
- /***/ ((module) => {
1315
+ const attrs = k.split( '.' ).map( ( attr, i ) => {
1316
+ const arrayPosition = attr.match( /\[(\d+)\]$/ )?.[1];
1317
+ return {
1318
+ key: `#${attr.replace( /\[\d+\]$|[^a-zA-Z0-9_]/g, '' )}${i}`,
1319
+ name: attr.replace( /\[\d+\]$/g, '' ),
1320
+ arrayPosition
1321
+ };
1322
+ } );
1323
+ const fullPath = attrs.map( attr => attr.key + ( attr.arrayPosition ? `[${attr.arrayPosition}]` : '' ) ).join( '.' );
1324
+ const valueId = `:v${index}`;
1325
+ const expAttrNames = attrs.reduce( ( obj, attr ) =>
1326
+ Object.assign( {}, obj, { [attr.key]: attr.name } )
1327
+ , {} );
1658
1328
 
1659
- "use strict";
1660
- module.exports = require("@aws-sdk/client-dynamodb");
1329
+ Object.assign( args.names, expAttrNames );
1661
1330
 
1662
- /***/ }),
1331
+ if ( isRemoval ) {
1332
+ args.removals.push( fullPath );
1333
+ } else {
1334
+ args.updates.push( fullPath + ' = ' + valueId );
1335
+ Object.assign( args.values, { [valueId]: value } );
1336
+ }
1663
1337
 
1664
- /***/ 4692:
1665
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1338
+ return args;
1339
+ }, { removals: [], updates: [], names: {}, values: {} } );
1666
1340
 
1667
- const calcMedian = __webpack_require__( 3187 );
1341
+ const conditionalExpressions = [];
1342
+ for ( const k of Object.keys( key ) ) {
1343
+ Object.assign( names, { [`#key_${k}`]: k } );
1344
+ conditionalExpressions.push( `attribute_exists(#key_${k})` );
1345
+ }
1668
1346
 
1669
- module.exports = pop => {
1670
- const center = calcMedian( pop );
1671
- return calcMedian( pop.map( v => Math.abs( v - center ) ) );
1672
- };
1347
+ if ( updates.length + removals.length === 0 ) { return null; }
1673
1348
 
1349
+ const expressions = [];
1350
+ if ( updates.length ) {
1351
+ expressions.push( 'SET ' + updates.join( ', ' ) );
1352
+ } if ( removals.length ) {
1353
+ expressions.push( 'REMOVE ' + removals.join( ', ' ) );
1354
+ }
1674
1355
 
1675
- /***/ }),
1356
+ const statement = {
1357
+ TableName: tableName,
1358
+ ReturnValues: 'ALL_NEW',
1359
+ Key: key,
1360
+ ConditionExpression: conditionalExpressions.join( ' AND ' ),
1361
+ UpdateExpression: expressions.join( ' ' ),
1362
+ ExpressionAttributeNames: names
1363
+ };
1364
+ if ( Object.keys( values ).length > 0 ) {
1365
+ statement.ExpressionAttributeValues = values;
1366
+ }
1676
1367
 
1677
- /***/ 4821:
1678
- /***/ ((module) => {
1368
+ try {
1369
+ const response = await client.send( new lib_dynamodb_namespaceObject.UpdateCommand( statement ) );
1370
+ return response.Attributes;
1371
+ } catch ( error ) {
1372
+ if ( error.constructor.name === 'ConditionalCheckFailedException' ) {
1373
+ console.info( 'Fail to update a record that was not found.' );
1374
+ return null;
1375
+ }
1376
+ throw error;
1377
+ }
1378
+ };
1679
1379
 
1680
- module.exports = ( items, size ) => items.reduce( ( arrs, item ) =>
1681
- ( arrs[0] && arrs[0].length < size ) ?
1682
- [ [ ...arrs[0], item ] ].concat( arrs.slice( 1 ) ) :
1683
- [ [ item ] ].concat( arrs )
1684
- , [] ).reverse();
1380
+ ;// ./src/aws/dynamo/transact_write.js
1685
1381
 
1686
1382
 
1687
- /***/ }),
1383
+ const transactWrite = async ( client, items ) => {
1384
+ const response = await client.send( new lib_dynamodb_namespaceObject.TransactWriteCommand( { TransactItems: items } ) );
1385
+ return response;
1386
+ };
1688
1387
 
1689
- /***/ 4870:
1690
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1388
+ ;// ./src/aws/dynamo/update.js
1691
1389
 
1692
- const athena = __webpack_require__( 228 );
1693
- const cwLogs = __webpack_require__( 2710 );
1694
- const dynamo = __webpack_require__( 1505 );
1695
- const lambda = __webpack_require__( 3544 );
1696
- const s3 = __webpack_require__( 645 );
1697
- const ses = __webpack_require__( 5624 );
1698
- const sns = __webpack_require__( 3099 );
1699
- const sqs = __webpack_require__( 3340 );
1700
- const ssm = __webpack_require__( 5888 );
1701
- const timestreamQuery = __webpack_require__( 4225 );
1702
- const timestreamWrite = __webpack_require__( 2538 );
1703
1390
 
1704
- module.exports = {
1705
- athena,
1706
- cwLogs,
1707
- dynamo,
1708
- lambda,
1709
- s3,
1710
- ses,
1711
- sns,
1712
- sqs,
1713
- ssm,
1714
- timestreamQuery,
1715
- timestreamWrite
1391
+ const update = async ( client, nativeArgs ) => {
1392
+ const args = Object.assign( { ReturnValues: 'ALL_NEW' }, nativeArgs );
1393
+ const response = await client.send( new lib_dynamodb_namespaceObject.UpdateCommand( args ) );
1394
+ return response.Attributes;
1716
1395
  };
1717
1396
 
1397
+ ;// ./src/aws/dynamo/index.js
1718
1398
 
1719
- /***/ }),
1720
1399
 
1721
- /***/ 4991:
1722
- /***/ ((module) => {
1723
1400
 
1724
- "use strict";
1725
- module.exports = require("@aws-sdk/s3-request-presigner");
1726
1401
 
1727
- /***/ }),
1728
1402
 
1729
- /***/ 5263:
1730
- /***/ ((module) => {
1731
1403
 
1732
- module.exports = t => t * 24 * 60 * 60 * 1000;
1733
1404
 
1734
1405
 
1735
- /***/ }),
1736
1406
 
1737
- /***/ 5265:
1738
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1739
1407
 
1740
- const select = __webpack_require__( 2157 );
1741
1408
 
1742
- module.exports = async ( client, ...args ) => select( client, 'query', ...args );
1743
1409
 
1744
1410
 
1745
- /***/ }),
1411
+ const dynamo_methods = {
1412
+ get: get,
1413
+ put: put,
1414
+ putBatch: putBatch,
1415
+ query: dynamo_query_query,
1416
+ remove: remove,
1417
+ removeBatch: removeBatch,
1418
+ scan: scan,
1419
+ smartUpdate: smartUpdate,
1420
+ transactWrite: transactWrite,
1421
+ update: update
1422
+ };
1746
1423
 
1747
- /***/ 5422:
1748
- /***/ ((module) => {
1424
+ const dynamo = createInstance( documentClientProvider, dynamo_methods );
1749
1425
 
1750
- global.__redisInstances = {};
1426
+ ;// external "@aws-sdk/client-lambda"
1427
+ const client_lambda_namespaceObject = require("@aws-sdk/client-lambda");
1428
+ ;// ./src/aws/lambda/lambda_error.js
1429
+ const parsePayload = payload => {
1430
+ try {
1431
+ return JSON.parse( Buffer.from( payload ).toString( 'utf-8' ) );
1432
+ } catch {
1433
+ return null;
1434
+ }
1435
+ };
1751
1436
 
1752
- /**
1753
- * Create a redis client instance
1754
- * @param {Object} redis Redis npm dependency
1755
- * @param {String} address Redis DB address (either RW or RO)
1756
- * @returns redisClient A new redis client instance connected to the database
1757
- */
1758
- module.exports = async ( { redis, address, protocol = 'rediss', port = 6379 } ) => {
1759
- if ( global.__redisInstances[address] ) {
1760
- try {
1761
- const r = await global.__redisInstances[address].ping();
1762
- if ( r === 'PONG' ) {
1763
- return global.__redisInstances[address];
1764
- } else {
1765
- delete global.__redisInstances[address];
1766
- }
1767
- } catch {
1768
- delete global.__redisInstances[address];
1437
+ class LambdaError extends Error {
1438
+ constructor( response ) {
1439
+ const { StatusCode: statusCode, Payload: rawPayload } = response;
1440
+ const payload = parsePayload( rawPayload );
1441
+ const lambdaErrorType = payload?.errorType ?? Error.name;
1442
+ const lambdaErrorMessage = payload?.errorMessage;
1443
+ if ( statusCode === 200 ) {
1444
+ super( `Invoked function threw "[${lambdaErrorType}]${lambdaErrorMessage ? ' ' + lambdaErrorMessage : ''}"` );
1445
+ } else {
1446
+ super( 'Error invoking the function' );
1769
1447
  }
1448
+ this.statusCode = statusCode;
1449
+ this.lambdaErrorType = lambdaErrorType;
1450
+ this.lambdaErrorMessage = lambdaErrorMessage;
1770
1451
  }
1771
-
1772
- const client = redis.createClient( { url: `${protocol}://${address}:${port}`, socket: { keepAlive: 15000 } } );
1773
-
1774
- await client.connect();
1775
-
1776
- global.__redisInstances[address] = client;
1777
- return client;
1778
1452
  };
1779
1453
 
1454
+ ;// ./src/aws/lambda/invoke.js
1780
1455
 
1781
- /***/ }),
1782
1456
 
1783
- /***/ 5438:
1784
- /***/ ((module) => {
1785
1457
 
1786
- /**
1787
- * This is base object each AWS abstraction will provide
1788
- */
1789
- module.exports = ( providerFn, methods ) => {
1790
- // This creates the "instance",
1791
- // so calling the method as a function returns a copy of its client instantiated with the given args
1792
- // every method called from it will use this instance
1793
- const factory = args => {
1794
- const client = providerFn( args );
1795
- // return self, so it is possible use the native client
1796
- methods.getClient = () => client;
1797
- return Object.entries( methods ).reduce( ( o, [ k, v ] ) => Object.assign( o, { [k]: v.bind( null, client ) } ), { } );
1798
- };
1458
+ const invoke = async ( client, name, payload = {}, type = 'RequestResponse' ) => {
1459
+ const response = await client.send( new client_lambda_namespaceObject.InvokeCommand( {
1460
+ FunctionName: name,
1461
+ InvocationType: type,
1462
+ Payload: Buffer.from( JSON.stringify( payload ) )
1463
+ } ) );
1799
1464
 
1800
- // This is the singleton part;
1801
- // First add the static method to the factory;
1802
- Object.entries( methods ).forEach( ( [ key, value ] ) => factory[key] = value );
1465
+ if ( response.FunctionError ) {
1466
+ throw new LambdaError( response );
1467
+ }
1803
1468
 
1804
- // Then add the special method "getClient", so it is possible use the native client
1805
- factory.getClient = client => client;
1469
+ if ( type !== 'RequestResponse' ) { return true; }
1806
1470
 
1807
- // Finally makes the proxy which will allow each singleton method to use the client provider of the AWS service+
1808
- return new Proxy( factory, {
1809
- get( target, key ) {
1810
- const t = target[key];
1811
- return ( typeof t === 'function' ) ? t.bind( null, providerFn() ) : t;
1812
- }
1813
- } );
1471
+ try {
1472
+ return JSON.parse( Buffer.from( response.Payload ).toString() );
1473
+ } catch {
1474
+ return response.Payload;
1475
+ }
1814
1476
  };
1815
1477
 
1478
+ ;// ./src/aws/lambda/index.js
1816
1479
 
1817
- /***/ }),
1818
1480
 
1819
- /***/ 5624:
1820
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1821
1481
 
1822
- const deleteSuppressedDestination = __webpack_require__( 809 );
1823
- const sendEmail = __webpack_require__( 1783 );
1824
- const { SESv2Client } = __webpack_require__( 9556 );
1825
- const clientProvider = __webpack_require__( 9039 );
1826
- const createInstance = __webpack_require__( 5438 );
1827
-
1828
- const methods = {
1829
- deleteSuppressedDestination,
1830
- sendEmail
1831
- };
1832
1482
 
1833
- module.exports = createInstance( clientProvider.bind( null, SESv2Client ), methods );
1834
1483
 
1484
+ const lambda_methods = {
1485
+ invoke: invoke
1486
+ };
1835
1487
 
1836
- /***/ }),
1488
+ const lambda = createInstance( genericClientProvider.bind( null, client_lambda_namespaceObject.LambdaClient ), lambda_methods );
1837
1489
 
1838
- /***/ 5637:
1839
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1490
+ ;// external "@aws-sdk/client-s3"
1491
+ const client_s3_namespaceObject = require("@aws-sdk/client-s3");
1492
+ ;// ./src/aws/s3/copy.js
1840
1493
 
1841
- const { DeleteMessageCommand } = __webpack_require__( 1976 );
1842
1494
 
1843
- module.exports = async ( client, queue, receiptHandle ) =>
1844
- client.send( new DeleteMessageCommand( {
1845
- QueueUrl: queue,
1846
- ReceiptHandle: receiptHandle
1495
+ const copy = async ( client, bucket, key, source, nativeArgs ) => {
1496
+ const response = await client.send( new client_s3_namespaceObject.CopyObjectCommand( {
1497
+ ...nativeArgs,
1498
+ Bucket: bucket,
1499
+ Key: key,
1500
+ CopySource: source
1847
1501
  } ) );
1502
+ return response;
1503
+ };
1848
1504
 
1505
+ ;// ./src/aws/s3/download.js
1849
1506
 
1850
- /***/ }),
1851
-
1852
- /***/ 5692:
1853
- /***/ ((module) => {
1854
1507
 
1855
- "use strict";
1856
- module.exports = require("https");
1508
+ const download = async ( client, bucket, key, nativeArgs ) => {
1509
+ const response = await client.send( new client_s3_namespaceObject.GetObjectCommand( {
1510
+ ...nativeArgs,
1511
+ Bucket: bucket,
1512
+ Key: key
1513
+ } ) );
1514
+ const stream = response.Body;
1515
+ return Buffer.concat( await stream.toArray() ).toString( 'utf-8' );
1516
+ };
1857
1517
 
1858
- /***/ }),
1518
+ ;// external "@aws-sdk/s3-request-presigner"
1519
+ const s3_request_presigner_namespaceObject = require("@aws-sdk/s3-request-presigner");
1520
+ ;// ./src/aws/s3/get_signed_url.js
1859
1521
 
1860
- /***/ 5723:
1861
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1862
1522
 
1863
- const { randomBytes } = __webpack_require__( 6982 );
1864
- const { StartQueryExecutionCommand } = __webpack_require__( 3744 );
1865
1523
 
1866
- /**
1867
- * args : https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/athena/command/StartQueryExecutionCommand/
1868
- * A ClientRequestToken is created automatically
1869
- */
1870
- module.exports = async ( { client, ...args } ) => {
1871
- const cmd = new StartQueryExecutionCommand( {
1872
- ClientRequestToken: randomBytes( 16 ).toString( 'hex' ),
1873
- ...args
1874
- } );
1875
- const { QueryExecutionId: queryId } = await client.send( cmd );
1876
- return queryId;
1524
+ const getSignedUrl = async ( client, bucket, key, expiration ) => {
1525
+ const getObjectCmd = new client_s3_namespaceObject.GetObjectCommand( { Bucket: bucket, Key: key } );
1526
+ const url = await (0,s3_request_presigner_namespaceObject.getSignedUrl)( client, getObjectCmd, { expiresIn: expiration } );
1527
+ return url;
1877
1528
  };
1878
1529
 
1530
+ ;// ./src/aws/s3/head.js
1879
1531
 
1880
- /***/ }),
1881
1532
 
1882
- /***/ 5725:
1883
- /***/ ((module) => {
1533
+ const head = async ( client, bucket, key ) =>
1534
+ client.send( new client_s3_namespaceObject.HeadObjectCommand( { Bucket: bucket, Key: key } ) );
1884
1535
 
1885
- "use strict";
1886
- module.exports = require("@aws-sdk/client-s3");
1536
+ ;// ./src/aws/s3/upload.js
1887
1537
 
1888
- /***/ }),
1889
1538
 
1890
- /***/ 5744:
1891
- /***/ ((module) => {
1539
+ const upload = ( client, bucket, key, body, nativeArgs ) =>
1540
+ client.send( new client_s3_namespaceObject.PutObjectCommand( {
1541
+ ...nativeArgs,
1542
+ Bucket: bucket,
1543
+ Key: key,
1544
+ Body: typeof body === 'string' || Buffer.isBuffer( body ) ? body : JSON.stringify( body )
1545
+ } ) );
1546
+
1547
+ ;// ./src/aws/s3/index.js
1892
1548
 
1893
- module.exports = {
1894
- encode: k => {
1895
- if ( k === null || k === undefined ) { return k; }
1896
1549
 
1897
- return Buffer.from( JSON.stringify( k ) ).toString( 'base64' );
1898
- },
1899
- decode: k => {
1900
- if ( k === null || k === undefined ) { return k; }
1901
1550
 
1902
- const result = Buffer.from( k, 'base64' ).toString( 'utf8' );
1903
- try {
1904
- return JSON.parse( result );
1905
- } catch {
1906
- return result;
1907
- }
1908
- }
1909
- };
1910
1551
 
1911
1552
 
1912
- /***/ }),
1913
1553
 
1914
- /***/ 5762:
1915
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1916
1554
 
1917
- const camelize = __webpack_require__( 8256 );
1918
- const filterProps = __webpack_require__( 6451 );
1919
- const removeEmptyArrays = __webpack_require__( 2047 );
1920
- const snakelize = __webpack_require__( 7572 );
1921
1555
 
1922
- module.exports = {
1923
- camelize,
1924
- filterProps,
1925
- removeEmptyArrays,
1926
- snakelize
1927
- };
1928
1556
 
1557
+ const s3_methods = {
1558
+ copy: copy,
1559
+ download: download,
1560
+ getSignedUrl: getSignedUrl,
1561
+ head: head,
1562
+ upload: upload
1563
+ };
1929
1564
 
1930
- /***/ }),
1565
+ const s3 = createInstance( genericClientProvider.bind( null, client_s3_namespaceObject.S3Client ), s3_methods );
1931
1566
 
1932
- /***/ 5847:
1933
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1567
+ ;// external "@aws-sdk/client-sesv2"
1568
+ const client_sesv2_namespaceObject = require("@aws-sdk/client-sesv2");
1569
+ ;// ./src/aws/ses/delete_suppressed_destination.js
1934
1570
 
1935
- const batchWrite = __webpack_require__( 8593 );
1936
1571
 
1937
- module.exports = async ( client, ...args ) => batchWrite( client, 'put', ...args );
1572
+ const deleteSuppressedDestination = ( client, address ) => client.send( new client_sesv2_namespaceObject.DeleteSuppressedDestinationCommand( { EmailAddress: address } ) );
1938
1573
 
1574
+ ;// ./src/aws/ses/send_email.js
1939
1575
 
1940
- /***/ }),
1941
1576
 
1942
- /***/ 5888:
1943
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1577
+ const sendEmail = ( client, { to = [], from, html, subject }, args ) =>
1578
+ client.send( new client_sesv2_namespaceObject.SendEmailCommand( {
1579
+ Destination: {
1580
+ ToAddresses: to
1581
+ },
1582
+ Content: {
1583
+ Simple: {
1584
+ Body: {
1585
+ Html: {
1586
+ Data: html,
1587
+ Charset: 'utf-8'
1588
+ }
1589
+ },
1590
+ Subject: {
1591
+ Data: subject
1592
+ }
1593
+ }
1594
+ },
1595
+ FromEmailAddress: from,
1596
+ ...args
1597
+ } ) );
1944
1598
 
1945
- const get = __webpack_require__( 8660 );
1946
- const { SSMClient } = __webpack_require__( 4348 );
1947
- const clientProvider = __webpack_require__( 9039 );
1948
- const createInstance = __webpack_require__( 5438 );
1599
+ ;// ./src/aws/ses/index.js
1949
1600
 
1950
- const methods = { get };
1951
1601
 
1952
- module.exports = createInstance( clientProvider.bind( null, SSMClient ), methods );
1953
1602
 
1954
1603
 
1955
- /***/ }),
1956
1604
 
1957
- /***/ 5892:
1958
- /***/ ((module) => {
1959
1605
 
1960
- "use strict";
1961
- module.exports = require("@aws-sdk/client-lambda");
1606
+ const ses_methods = {
1607
+ deleteSuppressedDestination: deleteSuppressedDestination,
1608
+ sendEmail: sendEmail
1609
+ };
1962
1610
 
1963
- /***/ }),
1611
+ const ses = createInstance( genericClientProvider.bind( null, client_sesv2_namespaceObject.SESv2Client ), ses_methods );
1964
1612
 
1965
- /***/ 5894:
1966
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1613
+ ;// external "@aws-sdk/client-sns"
1614
+ const client_sns_namespaceObject = require("@aws-sdk/client-sns");
1615
+ ;// ./src/aws/sns/publish.js
1967
1616
 
1968
- const { InvokeCommand } = __webpack_require__( 5892 );
1969
- const AWSLambdaError = __webpack_require__( 468 );
1970
1617
 
1971
- module.exports = async ( client, name, payload = {}, type = 'RequestResponse' ) => {
1972
- const response = await client.send( new InvokeCommand( {
1973
- FunctionName: name,
1974
- InvocationType: type,
1975
- Payload: Buffer.from( JSON.stringify( payload ) )
1618
+ const publish = async ( client, topic, message, args = {} ) => {
1619
+ const response = await client.send( new client_sns_namespaceObject.PublishCommand( {
1620
+ ...args,
1621
+ TopicArn: topic,
1622
+ Message: typeof message === 'string' ? message : JSON.stringify( message )
1976
1623
  } ) );
1977
-
1978
- if ( response.FunctionError ) {
1979
- throw new AWSLambdaError( response );
1980
- }
1981
-
1982
- if ( type !== 'RequestResponse' ) { return true; }
1983
-
1984
- try {
1985
- return JSON.parse( Buffer.from( response.Payload ).toString() );
1986
- } catch {
1987
- return response.Payload;
1988
- }
1624
+ return response.MessageId;
1989
1625
  };
1990
1626
 
1627
+ ;// ./src/aws/sns/publish_batch.js
1991
1628
 
1992
- /***/ }),
1993
-
1994
- /***/ 6030:
1995
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1996
1629
 
1997
- const { QueryCommand } = __webpack_require__( 1671 );
1998
- const { camelize } = __webpack_require__( 5762 );
1999
- const parseItems = __webpack_require__( 7261 );
2000
-
2001
- const query = async ( client, queryString, { prevItems = [], recursive, paginationToken, maxRows, rawResponse } ) => {
2002
- const response = await client.send( new QueryCommand( { QueryString: queryString, NextToken: paginationToken, MaxRows: maxRows } ) );
2003
- if ( !recursive && rawResponse ) {
2004
- return response;
1630
+ const publishBatch = async ( client, topic, messages ) => {
1631
+ if ( messages.length > 10 ) {
1632
+ throw new Error( 'SNS.publishBatch only accepts up to 10 messages.' );
2005
1633
  }
1634
+ const response = await client.send( new client_sns_namespaceObject.PublishBatchCommand( {
1635
+ TopicArn: topic,
1636
+ PublishBatchRequestEntries: messages.map( ( { body, id = null, nativeArgs }, index ) => ( {
1637
+ Id: id ?? `message_${index}`,
1638
+ Message: typeof body === 'string' ? body : JSON.stringify( body ),
1639
+ ...nativeArgs
1640
+ } ) )
1641
+ } ) );
2006
1642
 
2007
- const nextToken = response.NextToken;
2008
- if ( nextToken && recursive ) {
2009
- return query( client, queryString, { prevItems: parseItems( response ), recursive, paginationToken: nextToken, maxRows } );
1643
+ if ( response.Failed?.length > 0 ) {
1644
+ const error = new Error( 'SNS.publishBatch Failed. See error details' );
1645
+ error.details = response.Failed;
1646
+ throw error;
2010
1647
  }
2011
-
2012
- const items = prevItems.concat( parseItems( response ) );
2013
- return { nextToken, count: items.length, items, queryStatus: camelize( response.QueryStatus ) };
1648
+ return response;
2014
1649
  };
2015
1650
 
2016
- module.exports = async ( client, queryString, { recursive = false, paginationToken = undefined, maxRows = undefined, rawResponse = false } = {} ) =>
2017
- query( client, queryString, { recursive, paginationToken, maxRows, rawResponse } );
1651
+ ;// ./src/aws/sns/index.js
2018
1652
 
2019
1653
 
2020
- /***/ }),
2021
1654
 
2022
- /***/ 6089:
2023
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2024
1655
 
2025
- const calcMean = __webpack_require__( 4124 );
2026
1656
 
2027
- module.exports = values => {
2028
- if ( values.length < 2 ) { return NaN; }
2029
1657
 
2030
- const mean = calcMean( values );
2031
- const squareDiffs = values.map( value => Math.pow( value - mean, 2 ) );
2032
- const avgSquareDiff = squareDiffs.reduce( ( sum, v ) => sum + v, 0 ) / ( values.length - 1 );
2033
- return Math.sqrt( avgSquareDiff );
1658
+ const sns_methods = {
1659
+ publish: publish,
1660
+ publishBatch: publishBatch
2034
1661
  };
2035
1662
 
1663
+ const sns = createInstance( genericClientProvider.bind( null, client_sns_namespaceObject.SNSClient ), sns_methods );
2036
1664
 
2037
- /***/ }),
2038
-
2039
- /***/ 6451:
2040
- /***/ ((module) => {
2041
-
2042
- module.exports = ( obj, props ) => Object.fromEntries( Object.entries( obj ).filter( ( [ k ] ) => props.includes( k ) ) );
1665
+ ;// external "@aws-sdk/client-sqs"
1666
+ const client_sqs_namespaceObject = require("@aws-sdk/client-sqs");
1667
+ ;// ./src/aws/sqs/delete_message.js
2043
1668
 
2044
1669
 
2045
- /***/ }),
2046
-
2047
- /***/ 6635:
2048
- /***/ ((module) => {
2049
-
2050
- module.exports = t => t * 60 * 1000;
1670
+ const deleteMessage = async ( client, queue, receiptHandle ) =>
1671
+ client.send( new client_sqs_namespaceObject.DeleteMessageCommand( {
1672
+ QueueUrl: queue,
1673
+ ReceiptHandle: receiptHandle
1674
+ } ) );
2051
1675
 
1676
+ ;// ./src/aws/sqs/sanitize_sqs.js
1677
+ /*
1678
+ References:
1679
+ - https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html
1680
+ - https://stackoverflow.com/questions/58809098/remove-invalid-characters-from-message-sent-to-aws-amazon-sqs
1681
+ */
1682
+ const sanitizeSqs = v => v?.replace( /[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/ug, '' ) // eslint-disable-line
2052
1683
 
2053
- /***/ }),
1684
+ ;// ./src/aws/sqs/send_message.js
2054
1685
 
2055
- /***/ 6720:
2056
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2057
1686
 
2058
- const { SendMessageCommand } = __webpack_require__( 1976 );
2059
- const sanitizeSqs = __webpack_require__( 8175 );
2060
1687
 
2061
- module.exports = async ( client, queue, body, args ) => {
2062
- const response = await client.send( new SendMessageCommand( {
1688
+ const sendMessage = async ( client, queue, body, args ) => {
1689
+ const response = await client.send( new client_sqs_namespaceObject.SendMessageCommand( {
2063
1690
  ...args,
2064
1691
  MessageBody: sanitizeSqs( typeof body === 'string' ? body : JSON.stringify( body ) ),
2065
1692
  QueueUrl: queue
@@ -2067,75 +1694,88 @@ module.exports = async ( client, queue, body, args ) => {
2067
1694
  return response.MessageId;
2068
1695
  };
2069
1696
 
1697
+ ;// ./src/aws/sqs/send_message_batch.js
2070
1698
 
2071
- /***/ }),
2072
1699
 
2073
- /***/ 6777:
2074
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2075
1700
 
2076
- const { DeleteCommand } = __webpack_require__( 3489 );
2077
-
2078
- module.exports = async ( client, tableName, key ) => {
2079
- const { Attributes: item } = await client.send( new DeleteCommand( {
2080
- ReturnValues: 'ALL_OLD',
2081
- TableName: tableName,
2082
- Key: key
1701
+ const sendMessageBatch = async ( client, queue, messages ) => {
1702
+ if ( messages.length > 10 ) {
1703
+ throw new Error( 'SQS.sendMessageBatch only accepts up to 10 messages.' );
1704
+ }
1705
+ const response = await client.send( new client_sqs_namespaceObject.SendMessageBatchCommand( {
1706
+ QueueUrl: queue,
1707
+ Entries: messages.map( ( { body, id = null, nativeArgs }, index ) => ( {
1708
+ Id: id ?? `message_${index}`,
1709
+ MessageBody: sanitizeSqs( typeof body === 'string' ? body : JSON.stringify( body ) ),
1710
+ ...nativeArgs
1711
+ } ) )
2083
1712
  } ) );
2084
- return item;
1713
+
1714
+ if ( response.Failed?.length > 0 ) {
1715
+ const error = new Error( 'SQS.sendMessageBatch Failed. See error details' );
1716
+ error.details = response.Failed;
1717
+ throw error;
1718
+ }
1719
+ return response;
2085
1720
  };
2086
1721
 
1722
+ ;// ./src/aws/sqs/index.js
2087
1723
 
2088
- /***/ }),
2089
1724
 
2090
- /***/ 6878:
2091
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2092
1725
 
2093
- const retryOnError = __webpack_require__( 4243 );
2094
- const sleep = __webpack_require__( 2445 );
2095
- const Timer = __webpack_require__( 9651 );
2096
- const untarJsonGz = __webpack_require__( 8233 );
2097
1726
 
2098
- module.exports = {
2099
- retryOnError,
2100
- sleep,
2101
- Timer,
2102
- untarJsonGz
2103
- };
2104
1727
 
2105
1728
 
2106
- /***/ }),
2107
1729
 
2108
- /***/ 6961:
2109
- /***/ ((module) => {
1730
+ const sqs_methods = {
1731
+ deleteMessage: deleteMessage,
1732
+ sendMessage: sendMessage,
1733
+ sendMessageBatch: sendMessageBatch
1734
+ };
1735
+
1736
+ const sqs = createInstance( genericClientProvider.bind( null, client_sqs_namespaceObject.SQSClient ), sqs_methods );
2110
1737
 
2111
- module.exports = t => t * 60 * 60 * 1000;
1738
+ ;// external "@aws-sdk/client-ssm"
1739
+ const client_ssm_namespaceObject = require("@aws-sdk/client-ssm");
1740
+ ;// ./src/aws/ssm/get.js
2112
1741
 
2113
1742
 
2114
- /***/ }),
2115
1743
 
2116
- /***/ 6982:
2117
- /***/ ((module) => {
1744
+ const get_get = async ( client, name ) => {
1745
+ const key = `SSM_${name}`;
1746
+ const cacheValue = CacheStorage.get( key );
1747
+ if ( cacheValue ) { return cacheValue; }
1748
+
1749
+ try {
1750
+ const response = await client.send( new client_ssm_namespaceObject.GetParameterCommand( { Name: name, WithDecryption: true } ) );
1751
+ const value = response?.Parameter?.Value;
1752
+ CacheStorage.set( key, value );
1753
+ return value;
1754
+ } catch ( error ) {
1755
+ if ( error.constructor.name === 'ParameterNotFound' ) {
1756
+ return null;
1757
+ }
1758
+ throw error;
1759
+ }
1760
+ };
2118
1761
 
2119
- "use strict";
2120
- module.exports = require("crypto");
1762
+ ;// ./src/aws/ssm/index.js
2121
1763
 
2122
- /***/ }),
2123
1764
 
2124
- /***/ 7051:
2125
- /***/ ((module) => {
2126
1765
 
2127
- module.exports = t => t * 1000;
2128
1766
 
2129
1767
 
2130
- /***/ }),
1768
+ const ssm_methods = { get: get_get };
2131
1769
 
2132
- /***/ 7261:
2133
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1770
+ const ssm = createInstance( genericClientProvider.bind( null, client_ssm_namespaceObject.SSMClient ), ssm_methods );
2134
1771
 
1772
+ ;// external "@aws-sdk/client-timestream-query"
1773
+ const client_timestream_query_namespaceObject = require("@aws-sdk/client-timestream-query");
1774
+ ;// ./src/aws/timestream_query/parse_items.js
2135
1775
  // https://docs.aws.amazon.com/timestream/latest/developerguide/API_query_Type.html
2136
1776
  // https://docs.aws.amazon.com/timestream/latest/developerguide/supported-data-types.html
2137
1777
 
2138
- const { ScalarType } = __webpack_require__( 1671 );
1778
+
2139
1779
 
2140
1780
  const parseBigInt = value => {
2141
1781
  const asInt = parseInt( value, 10 );
@@ -2144,29 +1784,29 @@ const parseBigInt = value => {
2144
1784
 
2145
1785
  const parseScalarValue = ( type, value ) => {
2146
1786
  switch ( type ) {
2147
- case ScalarType.BOOLEAN:
2148
- return value === 'true';
2149
- case ScalarType.DOUBLE:
2150
- return parseFloat( value );
2151
- case ScalarType.TIMESTAMP:
2152
- return new Date( `${value.replace( ' ', 'T' )}Z` );
2153
- case ScalarType.INTEGER:
2154
- return parseInt( value, 10 );
2155
- case ScalarType.UNKNOWN: // is NULL
2156
- return null;
2157
- case ScalarType.BIGINT:
2158
- return parseBigInt( value );
2159
- case ScalarType.VARCHAR:
2160
- case ScalarType.DATE:
2161
- case ScalarType.TIME:
2162
- case ScalarType.INTERVAL_DAY_TO_SECOND:
2163
- case ScalarType.INTERVAL_YEAR_TO_MONTH:
2164
- default:
2165
- return value;
1787
+ case client_timestream_query_namespaceObject.ScalarType.BOOLEAN:
1788
+ return value === 'true';
1789
+ case client_timestream_query_namespaceObject.ScalarType.DOUBLE:
1790
+ return parseFloat( value );
1791
+ case client_timestream_query_namespaceObject.ScalarType.TIMESTAMP:
1792
+ return new Date( `${value.replace( ' ', 'T' )}Z` );
1793
+ case client_timestream_query_namespaceObject.ScalarType.INTEGER:
1794
+ return parseInt( value, 10 );
1795
+ case client_timestream_query_namespaceObject.ScalarType.UNKNOWN: // is NULL
1796
+ return null;
1797
+ case client_timestream_query_namespaceObject.ScalarType.BIGINT:
1798
+ return parseBigInt( value );
1799
+ case client_timestream_query_namespaceObject.ScalarType.VARCHAR:
1800
+ case client_timestream_query_namespaceObject.ScalarType.DATE:
1801
+ case client_timestream_query_namespaceObject.ScalarType.TIME:
1802
+ case client_timestream_query_namespaceObject.ScalarType.INTERVAL_DAY_TO_SECOND:
1803
+ case client_timestream_query_namespaceObject.ScalarType.INTERVAL_YEAR_TO_MONTH:
1804
+ default:
1805
+ return value;
2166
1806
  }
2167
1807
  };
2168
1808
 
2169
- const parseValue = ( typeInfo, datum ) => {
1809
+ const parse_items_parseValue = ( typeInfo, datum ) => {
2170
1810
  // value might be null
2171
1811
  if ( datum['NullValue'] === true ) {
2172
1812
  return null;
@@ -2176,13 +1816,13 @@ const parseValue = ( typeInfo, datum ) => {
2176
1816
  if ( Object.hasOwn( typeInfo, 'TimeSeriesMeasureValueColumnInfo' ) ) {
2177
1817
  return datum.TimeSeriesValue.map( v => ( {
2178
1818
  time: new Date( v.Time ),
2179
- value: parseValue( typeInfo.TimeSeriesMeasureValueColumnInfo.Type, v.Value )
1819
+ value: parse_items_parseValue( typeInfo.TimeSeriesMeasureValueColumnInfo.Type, v.Value )
2180
1820
  } ) );
2181
1821
  }
2182
1822
 
2183
1823
  // maybe an array
2184
1824
  if ( Object.hasOwn( typeInfo, 'ArrayColumnInfo' ) ) {
2185
- return datum.ArrayValue.map( v => parseValue( typeInfo.ArrayColumnInfo.Type, v ) );
1825
+ return datum.ArrayValue.map( v => parse_items_parseValue( typeInfo.ArrayColumnInfo.Type, v ) );
2186
1826
  }
2187
1827
 
2188
1828
  // or even a row
@@ -2190,7 +1830,7 @@ const parseValue = ( typeInfo, datum ) => {
2190
1830
  const rowColumnInfo = typeInfo.RowColumnInfo;
2191
1831
  return datum.RowValue.Data.reduce( ( object, value, index ) => {
2192
1832
  const { Name: name, Type: typeInfo } = rowColumnInfo[index];
2193
- return Object.assign( object, { [name]: parseValue( typeInfo, value ) } );
1833
+ return Object.assign( object, { [name]: parse_items_parseValue( typeInfo, value ) } );
2194
1834
  }, {} );
2195
1835
  }
2196
1836
 
@@ -2198,532 +1838,338 @@ const parseValue = ( typeInfo, datum ) => {
2198
1838
  return parseScalarValue( typeInfo.ScalarType, datum['ScalarValue'] );
2199
1839
  };
2200
1840
 
2201
- module.exports = response => {
1841
+ const parseItems = response => {
2202
1842
  const { ColumnInfo: colInfo, Rows: rows } = response;
2203
1843
  return rows.map( row =>
2204
1844
  row.Data.reduce( ( entry, value, index ) => {
2205
1845
  const { Name: name, Type: typeInfo } = colInfo[index];
2206
- return Object.assign( entry, { [name]: parseValue( typeInfo, value ) } );
1846
+ return Object.assign( entry, { [name]: parse_items_parseValue( typeInfo, value ) } );
2207
1847
  }, { } )
2208
1848
  );
2209
1849
  };
2210
1850
 
1851
+ ;// ./src/aws/timestream_query/query.js
2211
1852
 
2212
- /***/ }),
2213
-
2214
- /***/ 7337:
2215
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2216
1853
 
2217
- const { GetQueryExecutionCommand, GetQueryResultsCommand } = __webpack_require__( 3744 );
2218
- const parseResults = __webpack_require__( 834 );
2219
- const pollingDelay = __webpack_require__( 4127 );
2220
-
2221
- const sleep = t => new Promise( r => setTimeout( () => r(), t ) );
2222
-
2223
- const getQueryResults = async ( { client, queryExecutionId, maxResults, token } ) => {
2224
- const { NextToken: nextToken, ResultSet } = await client.send( new GetQueryResultsCommand( {
2225
- ...{ QueryExecutionId: queryExecutionId },
2226
- ...( maxResults ? { MaxResults: maxResults } : {} ),
2227
- ...( token ? { NextToken: token } : {} )
2228
- } ) );
2229
-
2230
- return { nextToken, items: parseResults( ResultSet ) };
2231
- };
2232
- const getQueryResultsRecursive = async ( { client, queryExecutionId, token } ) => {
2233
- const { nextToken, items } = await getQueryResults( { client, queryExecutionId, token } );
2234
-
2235
- if ( nextToken ) {
2236
- return { items: items.concat( ( await getQueryResultsRecursive( { client, queryExecutionId, token: nextToken } ) ).items ) };
2237
- }
2238
- return { items };
2239
- };
2240
1854
 
2241
- /**
2242
- * https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/athena/command/GetQueryResultsCommand/
2243
- * { client, recursive, queryExecutionId, maxResults, paginationToken }
2244
- */
2245
- const getResults = async ( { client, recursive, queryExecutionId, token, maxResults } ) => {
2246
- const { QueryExecution: { Status: status } } = await client.send( new GetQueryExecutionCommand( { QueryExecutionId: queryExecutionId } ) );
2247
1855
 
2248
- if ( status.State === 'FAILED' ) {
2249
- throw new Error( status.AthenaError?.ErrorMessage ?? status.StateChangeReason );
1856
+ const sendQuery = async ( client, queryString, { prevItems = [], recursive, paginationToken, maxRows, rawResponse } ) => {
1857
+ const response = await client.send( new client_timestream_query_namespaceObject.QueryCommand( { QueryString: queryString, NextToken: paginationToken, MaxRows: maxRows } ) );
1858
+ if ( !recursive && rawResponse ) {
1859
+ return response;
2250
1860
  }
2251
1861
 
2252
- if ( status.State === 'SUCCEEDED' ) {
2253
- const fn = recursive ? getQueryResultsRecursive : getQueryResults;
2254
- return fn( { client, recursive, queryExecutionId, token, maxResults } );
1862
+ const nextToken = response.NextToken;
1863
+ if ( nextToken && recursive ) {
1864
+ return sendQuery( client, queryString, { prevItems: parseItems( response ), recursive, paginationToken: nextToken, maxRows } );
2255
1865
  }
2256
1866
 
2257
- // sleep an try again
2258
- await sleep( pollingDelay );
2259
- return getResults( { client, recursive, queryExecutionId, token, maxResults } );
1867
+ const items = prevItems.concat( parseItems( response ) );
1868
+ return { nextToken, count: items.length, items, queryStatus: camelize_camelize( response.QueryStatus ) };
2260
1869
  };
2261
1870
 
2262
- module.exports = getResults;
2263
-
2264
-
2265
- /***/ }),
2266
-
2267
- /***/ 7416:
2268
- /***/ ((module) => {
1871
+ const timestream_query_query_query =
1872
+ async ( client, queryString, { recursive = false, paginationToken = undefined, maxRows = undefined, rawResponse = false } = {} ) =>
1873
+ sendQuery( client, queryString, { recursive, paginationToken, maxRows, rawResponse } );
2269
1874
 
2270
- module.exports = v => Math.ceil( v / 1000 );
1875
+ ;// external "https"
1876
+ const external_https_namespaceObject = require("https");
1877
+ ;// ./src/aws/timestream_query/index.js
2271
1878
 
2272
1879
 
2273
- /***/ }),
2274
1880
 
2275
- /***/ 7493:
2276
- /***/ ((module) => {
2277
1881
 
2278
- "use strict";
2279
- module.exports = require("@aws-sdk/client-cloudwatch-logs");
2280
1882
 
2281
- /***/ }),
2282
1883
 
2283
- /***/ 7572:
2284
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1884
+ const timestream_query_methods = { query: timestream_query_query_query };
1885
+ const defaultArgs = {
1886
+ maxRetries: 10,
1887
+ httpOptions: { timeout: 60000, agent: new external_https_namespaceObject.Agent( { maxSockets: 5000 } ) }
1888
+ };
2285
1889
 
2286
- const isSerializable = __webpack_require__( 8864 );
2287
- const snakelize = __webpack_require__( 3402 );
1890
+ const timestreamQuery =
1891
+ createInstance( args => genericClientProvider( client_timestream_query_namespaceObject.TimestreamQueryClient, [ Object.assign( {}, defaultArgs, args ) ] ), timestream_query_methods );
2288
1892
 
2289
- const change = ( obj, keepAllCaps ) =>
2290
- !isSerializable( obj ) ? obj : Object.entries( obj ).reduce( ( transformed, [ key, value ] ) => {
2291
- delete transformed[key];
2292
- transformed[snakelize( key, { keepAllCaps } )] = typeof value === 'object' ? change( value, keepAllCaps ) : value;
2293
- return transformed;
2294
- }, Array.isArray( obj ) ? [] : {} );
1893
+ ;// external "@aws-sdk/client-timestream-write"
1894
+ const client_timestream_write_namespaceObject = require("@aws-sdk/client-timestream-write");
1895
+ ;// ./src/aws/timestream_write/write_records.js
2295
1896
 
2296
- module.exports = ( obj, { keepAllCaps = false } = {} ) => change( obj, keepAllCaps );
2297
1897
 
1898
+ const writeRecords = async ( client, { database, table, records, ignoreRejections = false } ) => {
1899
+ try {
1900
+ const response = await client.send( new client_timestream_write_namespaceObject.WriteRecordsCommand( {
1901
+ DatabaseName: database,
1902
+ TableName: table,
1903
+ Records: records
1904
+ } ) );
1905
+ return { recordsIngested: response.RecordsIngested };
1906
+ } catch ( error ) {
1907
+ if ( ignoreRejections && error.name === 'RejectedRecordsException' ) {
1908
+ return { rejectedRecords: error.RejectedRecords };
1909
+ }
1910
+ throw error;
1911
+ }
1912
+ };
2298
1913
 
2299
- /***/ }),
1914
+ ;// ./src/aws/timestream_write/index.js
2300
1915
 
2301
- /***/ 7651:
2302
- /***/ ((module) => {
2303
1916
 
2304
- "use strict";
2305
- module.exports = require("@aws-sdk/client-sns");
2306
1917
 
2307
- /***/ }),
2308
1918
 
2309
- /***/ 8080:
2310
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2311
1919
 
2312
- const { PublishCommand } = __webpack_require__( 7651 );
2313
1920
 
2314
- module.exports = async ( client, topic, message, args = {} ) => {
2315
- const response = await client.send( new PublishCommand( {
2316
- ...args,
2317
- TopicArn: topic,
2318
- Message: typeof message === 'string' ? message : JSON.stringify( message )
2319
- } ) );
2320
- return response.MessageId;
1921
+ const timestream_write_methods = { writeRecords: writeRecords };
1922
+ const timestream_write_defaultArgs = {
1923
+ maxRetries: 10,
1924
+ httpOptions: { timeout: 60000, agent: new external_https_namespaceObject.Agent( { maxSockets: 5000 } ) }
2321
1925
  };
2322
1926
 
1927
+ const timestreamWrite =
1928
+ createInstance( args => genericClientProvider( client_timestream_write_namespaceObject.TimestreamWriteClient, [ Object.assign( {}, timestream_write_defaultArgs, args ) ] ), timestream_write_methods );
2323
1929
 
2324
- /***/ }),
2325
-
2326
- /***/ 8119:
2327
- /***/ ((module) => {
1930
+ ;// ./src/aws/index.js
2328
1931
 
2329
- module.exports = t => t * 30 * 24 * 60 * 60 * 1000;
2330
1932
 
2331
1933
 
2332
- /***/ }),
2333
-
2334
- /***/ 8175:
2335
- /***/ ((module) => {
2336
-
2337
- /*
2338
- References:
2339
- - https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html
2340
- - https://stackoverflow.com/questions/58809098/remove-invalid-characters-from-message-sent-to-aws-amazon-sqs
2341
- */
2342
- module.exports = v => v?.replace( /[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/ug, '' ) // eslint-disable-line
2343
-
2344
1934
 
2345
- /***/ }),
2346
1935
 
2347
- /***/ 8233:
2348
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2349
1936
 
2350
- const { unzipSync } = __webpack_require__( 3106 );
2351
1937
 
2352
- const firstIndexOf = ( c, ...vars ) => Math.min( ...vars.map( v => c.indexOf( v ) ).filter( n => n > -1 ) );
2353
- const lastIndexOf = ( c, ...vars ) => Math.max( ...vars.map( v => c.lastIndexOf( v ) ) );
2354
1938
 
2355
- /**
2356
- * Decompress JSON
2357
- *
2358
- * Reads a gzipped tarball (.tar.gz)
2359
- * 1. Unzip it
2360
- * 2. Convert all to utf-8
2361
- * 3. Split files using the \0star separator
2362
- * 4. Trim files until JSON markup start/end ({})
2363
- * 5. JSON parse
2364
- *
2365
- * Enjoy this 100% native tarball decompression!
2366
- */
2367
- module.exports = raw =>
2368
- unzipSync( raw )
2369
- .toString( 'utf-8' )
2370
- .split( '\0ustar' )
2371
- .slice( 1 )
2372
- .map( c =>
2373
- JSON.parse( c.substring( firstIndexOf( c, '{', '[' ), lastIndexOf( c, '}', ']' ) + 1 ) )
2374
- );
2375
1939
 
2376
1940
 
2377
- /***/ }),
2378
1941
 
2379
- /***/ 8248:
2380
- /***/ ((module) => {
2381
1942
 
2382
- "use strict";
2383
- module.exports = require("@aws-sdk/client-timestream-write");
2384
1943
 
2385
- /***/ }),
2386
1944
 
2387
- /***/ 8256:
2388
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1945
+ ;// ./src/epoch/days.js
1946
+ const days = t => t * 24 * 60 * 60 * 1000;
2389
1947
 
2390
- const isSerializable = __webpack_require__( 8864 );
2391
- const camelize = __webpack_require__( 3914 );
1948
+ ;// ./src/epoch/hours.js
1949
+ const hours = t => t * 60 * 60 * 1000;
2392
1950
 
2393
- const change = ( obj, keepAllCaps ) =>
2394
- !isSerializable( obj ) ? obj : Object.entries( obj ).reduce( ( transformed, [ key, value ] ) => {
2395
- delete transformed[key];
2396
- transformed[camelize( key, { keepAllCaps } )] = typeof value === 'object' ? change( value, keepAllCaps ) : value;
2397
- return transformed;
2398
- }, Array.isArray( obj ) ? [] : {} );
1951
+ ;// ./src/epoch/minutes.js
1952
+ const minutes = t => t * 60 * 1000;
2399
1953
 
2400
- module.exports = ( obj, { keepAllCaps = false } = {} ) => change( obj, keepAllCaps );
1954
+ ;// ./src/epoch/months.js
1955
+ const months = t => t * 30 * 24 * 60 * 60 * 1000;
2401
1956
 
1957
+ ;// ./src/epoch/ms_to_s.js
1958
+ const msToS = v => Math.ceil( v / 1000 );
2402
1959
 
2403
- /***/ }),
1960
+ ;// ./src/epoch/round.js
1961
+ const round = ( time, interval ) => time - ( time % interval );
2404
1962
 
2405
- /***/ 8278:
2406
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1963
+ ;// ./src/epoch/seconds.js
1964
+ const seconds = t => t * 1000;
2407
1965
 
2408
- const joinUnique = __webpack_require__( 2836 );
2409
- const joinUniqueCustom = __webpack_require__( 536 );
2410
- const splitBatches = __webpack_require__( 4821 );
1966
+ ;// ./src/epoch/index.js
2411
1967
 
2412
- module.exports = {
2413
- joinUnique,
2414
- joinUniqueCustom,
2415
- splitBatches
2416
- };
2417
1968
 
2418
1969
 
2419
- /***/ }),
2420
1970
 
2421
- /***/ 8282:
2422
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2423
1971
 
2424
- const validators = __webpack_require__( 8994 );
2425
- const LambdaApiValidationError = __webpack_require__( 3446 );
2426
- const Text = __webpack_require__( 9760 );
2427
1972
 
2428
- module.exports = class UserResponse {
2429
- constructor( args ) {
2430
- if ( args === undefined ) {
2431
- this.values = [ 204 ];
2432
- } else if ( typeof args === 'string' && args.length === 0 ) {
2433
- this.values = [ 204 ];
2434
1973
 
2435
- } else if ( typeof args === 'string' && args.length > 0 ) {
2436
- this.values = [ 200, args ];
2437
1974
 
2438
- } else if ( typeof args === 'number' ) {
2439
- validators.statusCode( args );
2440
- this.values = [ args ];
2441
1975
 
2442
- } else if ( Array.isArray( args ) ) {
2443
- validators.statusCode( args[0] );
2444
- this.values = args;
2445
1976
 
2446
- } else if ( args.statusCode ) {
2447
- validators.statusCode( args.statusCode );
2448
- this.values = [ args.statusCode, args.body, args.headers, args.isBase64Encoded ];
1977
+ ;// ./src/math/calc_mean.js
1978
+ const calcMean = values => values.reduce( ( sum, value ) => sum + value, 0 ) / values.length;
2449
1979
 
2450
- } else if ( [ undefined, null ].includes( args ) ) {
2451
- this.values = [ 200 ];
2452
- } else {
2453
- throw new LambdaApiValidationError( Text.INVALID_USER_RESPONSE );
2454
- }
2455
- }
1980
+ ;// ./src/math/calc_median.js
1981
+ const calcMedian = values => {
1982
+ //Sort bug: https://www.tutorialrepublic.com/faq/how-to-sort-an-array-of-integers-correctly-in-javascript.php
1983
+ const sorted = values.slice().sort( ( a, b ) => a - b );
1984
+ const evenArray = values.length % 2 === 0;
1985
+ const midIndex = Math.floor( values.length / 2 );
1986
+ return evenArray ? ( sorted[midIndex - 1] + sorted[midIndex] ) / 2 : sorted[midIndex];
2456
1987
  };
2457
1988
 
1989
+ ;// ./src/math/calc_median_abs_dev.js
2458
1990
 
2459
- /***/ }),
2460
-
2461
- /***/ 8593:
2462
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2463
1991
 
2464
- const { BatchWriteCommand } = __webpack_require__( 3489 );
2465
- const splitBatches = __webpack_require__( 4821 );
2466
-
2467
- const batchSize = 25;
2468
-
2469
- const getMapper = method => method === 'put' ? v => ( { PutRequest: { Item: v } } ) : v => ( { DeleteRequest: { Key: v } } );
1992
+ const calcMedianAbsDev = pop => {
1993
+ const center = calcMedian( pop );
1994
+ return calcMedian( pop.map( v => Math.abs( v - center ) ) );
1995
+ };
2470
1996
 
2471
- const process = async ( { client, method, table, batches } ) => {
2472
- if ( batches.length === 0 ) { return true; }
1997
+ ;// ./src/math/calc_std_dev_population.js
2473
1998
 
2474
- const response = await client.send( new BatchWriteCommand( { RequestItems: { [table]: batches[0] } } ) );
2475
1999
 
2476
- const unprocessed = response.UnprocessedItems?.[table];
2477
- return process( {
2478
- client, method, table,
2479
- batches: unprocessed ? splitBatches( batches.slice( 1 ).flat().concat( unprocessed ), batchSize ) : batches.slice( 1 )
2480
- } );
2000
+ const calcStdDevPopulation = values => {
2001
+ const mean = calcMean( values );
2002
+ const squareDiffs = values.map( value => Math.pow( value - mean, 2 ) );
2003
+ const avgSquareDiff = calcMean( squareDiffs );
2004
+ return Math.sqrt( avgSquareDiff );
2481
2005
  };
2482
2006
 
2483
- module.exports = async ( client, method, table, items ) =>
2484
- process( { client, method, table, batches: splitBatches( items.map( getMapper( method ) ), batchSize ) } );
2007
+ ;// ./src/math/calc_std_dev_sample.js
2485
2008
 
2486
2009
 
2487
- /***/ }),
2010
+ const calcStdDevSample = values => {
2011
+ if ( values.length < 2 ) { return NaN; }
2488
2012
 
2489
- /***/ 8660:
2490
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2013
+ const mean = calcMean( values );
2014
+ const squareDiffs = values.map( value => Math.pow( value - mean, 2 ) );
2015
+ const avgSquareDiff = squareDiffs.reduce( ( sum, v ) => sum + v, 0 ) / ( values.length - 1 );
2016
+ return Math.sqrt( avgSquareDiff );
2017
+ };
2491
2018
 
2492
- const cacheStorage = __webpack_require__( 4164 );
2493
- const { GetParameterCommand } = __webpack_require__( 4348 );
2019
+ ;// ./src/math/calc_z_score.js
2020
+ const calcZScore = ( sample, mean, stdDev ) => stdDev === 0 ? NaN : ( sample - mean ) / stdDev;
2494
2021
 
2495
- module.exports = async ( client, name ) => {
2496
- const key = `SSM_${name}`;
2497
- const cacheValue = cacheStorage.get( key );
2498
- if ( cacheValue ) { return cacheValue; }
2022
+ ;// ./src/math/round_gaussian.js
2023
+ const roundGaussian = ( n, d = 2 ) => {
2024
+ if ( !isFinite( n ) || typeof n !== 'number' ) { return NaN; }
2499
2025
 
2500
- try {
2501
- const response = await client.send( new GetParameterCommand( { Name: name, WithDecryption: true } ) );
2502
- const value = response?.Parameter?.Value;
2503
- cacheStorage.set( key, value );
2504
- return value;
2505
- } catch ( error ) {
2506
- if ( error.constructor.name === 'ParameterNotFound' ) {
2507
- return null;
2508
- }
2509
- throw error;
2510
- }
2026
+ const m = Math.pow( 10, d );
2027
+ const num = +( n * m ).toFixed( 8 ); // Avoid rounding errors
2028
+ const i = Math.floor( num );
2029
+ const f = num - i;
2030
+ const e = 1e-8; // Allow for rounding errors in f
2031
+ const r = ( f > 0.5 - e && f < 0.5 + e ) ? // eslint-disable-line no-nested-ternary
2032
+ ( ( i % 2 === 0 ) ? i : i + 1 ) : Math.round( num );
2033
+ return r / m;
2511
2034
  };
2512
2035
 
2036
+ ;// ./src/math/round_standard.js
2037
+ const roundStandard = ( n, d = 2 ) => Math.round( n * ( 10 ** d ) ) / ( 10 ** d );
2513
2038
 
2514
- /***/ }),
2515
-
2516
- /***/ 8864:
2517
- /***/ ((module) => {
2039
+ ;// ./src/math/index.js
2518
2040
 
2519
- module.exports = obj =>
2520
- typeof obj === 'object' &&
2521
- obj !== null &&
2522
- !( obj instanceof String ) &&
2523
- !( obj instanceof Number ) &&
2524
- !( obj instanceof Boolean ) &&
2525
- !( obj instanceof Date );
2526
2041
 
2527
2042
 
2528
- /***/ }),
2529
2043
 
2530
- /***/ 8936:
2531
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2532
2044
 
2533
- const { WriteRecordsCommand } = __webpack_require__( 8248 );
2534
2045
 
2535
- module.exports = async ( client, { database, table, records, ignoreRejections = false } ) => {
2536
- try {
2537
- const response = await client.send( new WriteRecordsCommand( {
2538
- DatabaseName: database,
2539
- TableName: table,
2540
- Records: records
2541
- } ) );
2542
- return { recordsIngested: response.RecordsIngested };
2543
- } catch ( error ) {
2544
- if ( ignoreRejections && error.name === 'RejectedRecordsException' ) {
2545
- return { rejectedRecords: error.RejectedRecords };
2546
- }
2547
- throw error;
2548
- }
2549
- };
2550
2046
 
2551
2047
 
2552
- /***/ }),
2553
2048
 
2554
- /***/ 8994:
2555
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2556
2049
 
2557
- const Text = __webpack_require__( 9760 );
2558
- const LambdaApiValidationError = __webpack_require__( 3446 );
2559
2050
 
2560
- const evaluate = ( condition, errorMessage ) => {
2561
- if ( !condition ) { throw new LambdaApiValidationError( errorMessage ); }
2562
- };
2051
+ ;// ./src/object/filter_props.js
2052
+ const filterProps = ( obj, props ) => Object.fromEntries( Object.entries( obj ).filter( ( [ k ] ) => props.includes( k ) ) );
2563
2053
 
2564
- const isConstructor = v => {
2565
- try {
2566
- return !!Reflect.construct( new Proxy( v, {} ), [] );
2567
- } catch {
2568
- return false;
2569
- }
2570
- };
2054
+ ;// ./src/object/remove_empty_arrays.js
2055
+ const removeEmptyArrays = o => Object.fromEntries( Object.entries( o ).filter( ( [ , v ] ) => !Array.isArray( v ) || v.length > 0 ) );
2571
2056
 
2572
- module.exports = {
2573
- errorType: v => evaluate( isConstructor( v ), Text.INVALID_ERROR_TYPE ),
2574
- function: v => evaluate( typeof v === 'function', Text.INVALID_FN ),
2575
- httpMethod: v => evaluate( [ 'DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT' ].includes( v ), Text.INVALID_METHOD ),
2576
- matcherPath: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_PATH ),
2577
- matcherPathIncludes: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_PATH_INCLUDES ),
2578
- matcherPathMatch: v => evaluate( v === undefined || v?.constructor?.name === RegExp.name, Text.INVALID_MATCHER_PATH_MATCH ),
2579
- matcherPathNotIncludes: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_PATH_NOT_INCLUDES ),
2580
- matcherRoute: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_ROUTE ),
2581
- matcherRouteIncludes: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_ROUTE_INCLUDES ),
2582
- matcherRouteMatch: v => evaluate( v === undefined || v?.constructor?.name === RegExp.name, Text.INVALID_MATCHER_ROUTE_MATCH ),
2583
- matcherRouteNotIncludes: v => evaluate( v === undefined || ( typeof v === 'string' && v.length > 0 ), Text.INVALID_MATCHER_ROUTE_NOT_INCLUDES ),
2584
- statusCode: v => evaluate( typeof v === 'number' && /^[1-5]\d\d$/.test( String( v ) ), Text.INVALID_STATUS_CODE ),
2585
- transformRequest: v => evaluate( [ 'camelcase', 'snakecase', null, false ].includes( v ), Text.INVALID_TRANSFORM_REQUEST ),
2586
- transformResponse: v => evaluate( [ 'camelcase', 'snakecase', null, false ].includes( v ), Text.INVALID_TRANSFORM_RESPONSE )
2587
- };
2057
+ ;// ./src/object/index.js
2588
2058
 
2589
2059
 
2590
- /***/ }),
2591
2060
 
2592
- /***/ 9039:
2593
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2594
2061
 
2595
- const cache = __webpack_require__( 4164 );
2596
2062
 
2597
- module.exports = ( constructor, args = [] ) => {
2598
- const cacheKey = `${constructor.name}(${args.map( arg => JSON.stringify( arg ) ).join( ',' )})`;
2599
- return cache.get( cacheKey ) ?? ( () => {
2600
- const client = Reflect.construct( constructor, args );
2601
- cache.set( cacheKey, client );
2602
- return client;
2603
- } )();
2604
- };
2605
2063
 
2606
2064
 
2607
- /***/ }),
2065
+ ;// ./src/redis/create_client.js
2066
+ global.__redisInstances = {};
2608
2067
 
2609
- /***/ 9129:
2610
- /***/ ((module) => {
2068
+ /**
2069
+ * Create a redis client instance
2070
+ *
2071
+ * @param {Object} args
2072
+ * @param {Object} args.redis Redis npm dependency
2073
+ * @param {String} args.address Redis DB address (either RW or RO)
2074
+ * @param {String} [args.protocol=rediss] Redis connection protocol
2075
+ * @param {String} [args.port=6379] Redis DB connection port
2076
+ * @returns redisClient A new redis client instance connected to the database
2077
+ */
2078
+ const createClient = async ( { redis, address, protocol = 'rediss', port = 6379 } ) => {
2079
+ if ( global.__redisInstances[address] ) {
2080
+ try {
2081
+ const r = await global.__redisInstances[address].ping();
2082
+ if ( r === 'PONG' ) {
2083
+ return global.__redisInstances[address];
2084
+ } else {
2085
+ delete global.__redisInstances[address];
2086
+ }
2087
+ } catch {
2088
+ delete global.__redisInstances[address];
2089
+ }
2090
+ }
2611
2091
 
2612
- /* eslint consistent-return: 0 */
2613
- const removeNullValues = ( o, isArray = Array.isArray( o ) ) =>
2614
- Object.entries( o ).reduce( ( newObj, [ k, v ] ) => {
2615
- if ( v === null && !isArray ) { return newObj; }
2616
- return Object.assign( newObj, { [k]: v?.constructor === Object ? removeNullValues( v ) : v } );
2617
- }, isArray ? [] : {} );
2092
+ const client = redis.createClient( { url: `${protocol}://${address}:${port}`, socket: { keepAlive: 15000 } } );
2618
2093
 
2619
- module.exports = ( v, type ) => {
2620
- if ( [ null, undefined ].includes( v ) ) {
2621
- return undefined;
2622
- }
2623
- if ( v === '' && type !== 'varchar' ) {
2624
- return undefined;
2625
- }
2626
- if ( type === 'boolean' ) {
2627
- return v === 'true';
2628
- }
2629
- if ( [ 'float', 'decimal', 'double' ].includes( type ) ) {
2630
- return parseFloat( v );
2631
- }
2632
- if ( [ 'tinyint', 'smallint', 'int', 'bigint' ].includes( type ) ) {
2633
- return parseInt( v );
2634
- }
2635
- if ( 'timestamp' === type ) {
2636
- return new Date( v ).getTime();
2637
- }
2638
- if ( [ 'row', 'array' ].includes( type ) ) {
2639
- const obj = v.replace( /(?<=(?:{|,\s)[\w-_]+)=/g, '@@DELIMITER@@' ) // replaces delimiter = with @@DELIMITER@@
2640
- .replace( /(?<={|,\s)([\w_-]+)(?=@@DELIMITER@@)/g, '"$1"' ) // wrap object keys
2641
- .replace( /(?<=@@DELIMITER@@)((?:(?!,\s|}|\[|{).)+)/g, '"$1"' ) // wrap object values
2642
- .replace( /(?<=\[|,\s)((?:(?!,\s|{|\]|").)+)/g, '"$1"' ) // wrap array values
2643
- .replace( /"null"/g, 'null' ) // convert "null" to null
2644
- .replace( /@@DELIMITER@@/g, ':' ); // replaces @@DELIMITER@@ for :
2094
+ await client.connect();
2645
2095
 
2646
- return removeNullValues( JSON.parse( obj ) );
2647
- }
2648
- if ( 'json' === type ) {
2649
- return JSON.parse( v );
2650
- }
2651
- return v;
2096
+ global.__redisInstances[address] = client;
2097
+ return client;
2652
2098
  };
2653
2099
 
2100
+ ;// ./src/redis/index.js
2654
2101
 
2655
- /***/ }),
2656
2102
 
2657
- /***/ 9179:
2658
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2659
2103
 
2660
- const parseValue = __webpack_require__( 2847 );
2661
2104
 
2662
- module.exports = item =>
2663
- item.reduce( ( row, { field, value } ) =>
2664
- Object.assign( row, {
2665
- [field]: parseValue( value )
2666
- } ), {} );
2105
+ ;// ./src/string/capitalize_words.js
2106
+ const capitalizeWords = input =>
2107
+ // Break the string into sequences to rebuild later
2108
+ !input ? input : input.split( /\s/ )
2109
+ // ALL_CAPS terms are ignored
2110
+ .map( term => [ term, term.charAt( 0 ).toUpperCase() + term.slice( 1 ).toLowerCase() ] )
2111
+ // Rebuild the string replacing the converter terms keeping the original delimiters
2112
+ .reduce( ( result, [ term, repl ] ) => result.replace( term, repl ), input );
2667
2113
 
2114
+ ;// ./src/string/index.js
2668
2115
 
2669
- /***/ }),
2670
2116
 
2671
- /***/ 9552:
2672
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2673
2117
 
2674
- const parseItem = __webpack_require__( 9179 );
2675
2118
 
2676
- module.exports = results => results.map( item => parseItem( item ) );
2677
2119
 
2678
2120
 
2679
- /***/ }),
2121
+ ;// ./src/utils/retry_on_error.js
2680
2122
 
2681
- /***/ 9556:
2682
- /***/ ((module) => {
2683
2123
 
2684
- "use strict";
2685
- module.exports = require("@aws-sdk/client-sesv2");
2124
+ const execWithRetry = async ( closure, { limit, delay, retryHook, execCount = 0 } ) => {
2125
+ if ( !( closure instanceof Function ) ) {
2126
+ throw new Error( 'Closure is not a function' );
2127
+ }
2686
2128
 
2687
- /***/ }),
2129
+ try {
2130
+ return await closure();
2131
+ } catch ( error ) {
2132
+ // exhausted
2133
+ if ( execCount === limit ) { throw error; }
2688
2134
 
2689
- /***/ 9628:
2690
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2135
+ // async retry hook to check if it should retry or give up and throw
2136
+ if ( retryHook instanceof Function ) {
2137
+ try {
2138
+ const retry = await retryHook( error, execCount );
2139
+ if ( retry === false ) { return false; }
2691
2140
 
2692
- const { PutCommand } = __webpack_require__( 3489 );
2141
+ // Hook errors break the flow
2142
+ } catch ( hookError ) {
2143
+ console.debug( hookError );
2144
+ throw hookError;
2145
+ }
2146
+ }
2693
2147
 
2694
- const parseArgs = args => {
2695
- // native args mode
2696
- if ( args[0] instanceof Object ) {
2697
- return args[0];
2148
+ // if there is no hook back-off and retry
2149
+ if ( delay > 0 ) {
2150
+ await sleep_sleep( delay ** ( 1 + execCount ) );
2151
+ }
2152
+ return execWithRetry( closure, { limit, delay, retryHook, execCount: execCount + 1 } );
2698
2153
  }
2699
- // sugar mode
2700
- return {
2701
- TableName: args[0],
2702
- Item: args[1],
2703
- ReturnValues: 'NONE',
2704
- ReturnConsumedCapacity: 'NONE'
2705
- };
2706
2154
  };
2707
2155
 
2708
2156
  /**
2709
2157
  *
2710
- * @param {*} client
2711
- * @param {...any} args The args. either one object with the native args or two string args, tableName and item.
2712
- * @returns
2158
+ * @param {Function} closure A self contained function that will be invoked
2159
+ * @param {Object} config
2160
+ * @param {Number} config.limit The max number of retries
2161
+ * @param {Number} config.delay The delay between each retry (it will be raised to the power of the number of retries, so it is exponential back-off)
2162
+ * @param {Function} config.retryHook A function to be called every time a retry is needed.
2163
+ * If this functions returns true, the retry flow continues until limit
2164
+ * If this functions returns false, the retry flow is aborted, returning false
2165
+ * If this functions throws an error, the retry flow is aborted with that error
2166
+ * @returns {Any} The closure result
2713
2167
  */
2714
- module.exports = async ( client, ...args ) => {
2715
- const nativeArgs = parseArgs( args );
2716
- const response = await client.send( new PutCommand( nativeArgs ) );
2717
- return response.Attributes ?? nativeArgs.Item;
2718
- };
2719
-
2720
-
2721
- /***/ }),
2722
-
2723
- /***/ 9651:
2724
- /***/ ((module) => {
2168
+ const retryOnError = async ( closure, { limit = 0, delay = 0, retryHook = null } = {} ) =>
2169
+ execWithRetry( closure, { limit, delay, retryHook } );
2725
2170
 
2726
- module.exports = class Timer {
2171
+ ;// ./src/utils/timer.js
2172
+ class Timer {
2727
2173
  #startedAt;
2728
2174
  #stoppedAt = null;
2729
2175
  #running = false;
@@ -2765,84 +2211,54 @@ module.exports = class Timer {
2765
2211
  }
2766
2212
  };
2767
2213
 
2214
+ ;// external "node:zlib"
2215
+ const external_node_zlib_namespaceObject = require("node:zlib");
2216
+ ;// ./src/utils/untar_json_gz.js
2768
2217
 
2769
- /***/ }),
2770
2218
 
2771
- /***/ 9704:
2772
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2219
+ const firstIndexOf = ( c, ...vars ) => Math.min( ...vars.map( v => c.indexOf( v ) ).filter( n => n > -1 ) );
2220
+ const lastIndexOf = ( c, ...vars ) => Math.max( ...vars.map( v => c.lastIndexOf( v ) ) );
2773
2221
 
2774
- const { PutObjectCommand } = __webpack_require__( 5725 );
2222
+ /**
2223
+ * Decompress JSON
2224
+ *
2225
+ * Reads a gzipped tarball (.tar.gz)
2226
+ * 1. Unzip it
2227
+ * 2. Convert all to utf-8
2228
+ * 3. Split files using the \0star separator
2229
+ * 4. Trim files until JSON markup start/end ({})
2230
+ * 5. JSON parse
2231
+ *
2232
+ * Enjoy this 100% native tarball decompression!
2233
+ */
2234
+ const untarJsonGz = raw =>
2235
+ (0,external_node_zlib_namespaceObject.unzipSync)( raw )
2236
+ .toString( 'utf-8' )
2237
+ .split( '\0ustar' )
2238
+ .slice( 1 )
2239
+ .map( c =>
2240
+ JSON.parse( c.substring( firstIndexOf( c, '{', '[' ), lastIndexOf( c, '}', ']' ) + 1 ) )
2241
+ );
2775
2242
 
2776
- module.exports = ( client, bucket, key, body, nativeArgs ) =>
2777
- client.send( new PutObjectCommand( {
2778
- ...nativeArgs,
2779
- Bucket: bucket,
2780
- Key: key,
2781
- Body: typeof body === 'string' || Buffer.isBuffer( body ) ? body : JSON.stringify( body )
2782
- } ) );
2243
+ ;// ./src/utils/index.js
2783
2244
 
2784
2245
 
2785
- /***/ }),
2786
2246
 
2787
- /***/ 9760:
2788
- /***/ ((module) => {
2789
2247
 
2790
- module.exports = {
2791
- ERROR_500: 'Internal Server Error',
2792
- ERROR_405: 'Method Not Allowed',
2793
- INVALID_ERROR_TYPE: 'Argument "errorType" must be a constructor Function',
2794
- INVALID_FN: 'Argument "fn" must be of type function',
2795
- INVALID_METHOD: 'Argument "method" must be one of the default HTTP methods',
2796
- INVALID_STATUS_CODE: 'Argument "statusCode" must be valid HTTP Status Code',
2797
- INVALID_TRANSFORM_REQUEST: 'Argument "transformRequest" must be either "camelize", "snakelize", false or null',
2798
- INVALID_TRANSFORM_RESPONSE: 'Argument "transformResponse" must be either "camelize", "snakelize", false or null',
2799
- INVALID_MATCHER_ROUTE: 'Argument "route" must be either undefined or an string with length greater than 0',
2800
- INVALID_MATCHER_ROUTE_INCLUDES: 'Argument "routeIncludes" must be either undefined or an string with length greater than 0',
2801
- INVALID_MATCHER_ROUTE_NOT_INCLUDES: 'Argument "routeNotIncludes" must be either undefined or an string with length greater than 0',
2802
- INVALID_MATCHER_ROUTE_MATCH: 'Argument "routeMatch" must be either undefined or type RegExp',
2803
- INVALID_MATCHER_PATH: 'Argument "path" must be either undefined or an string with length greater than 0',
2804
- INVALID_MATCHER_PATH_INCLUDES: 'Argument "pathIncludes" must be either undefined or an string with length greater than 0',
2805
- INVALID_MATCHER_PATH_NOT_INCLUDES: 'Argument "pathNotIncludes" must be either undefined or an string with length greater than 0',
2806
- INVALID_MATCHER_PATH_MATCH: 'Argument "pathMatch" must be either undefined or type RegExp',
2807
- INVALID_USER_RESPONSE: 'Function return must be a number, a string, an array (where p=0 is a number) or an object (where .statusCode is a number)'
2808
- };
2809
2248
 
2810
2249
 
2811
- /***/ })
2812
2250
 
2813
- /******/ });
2814
- /************************************************************************/
2815
- /******/ // The module cache
2816
- /******/ var __webpack_module_cache__ = {};
2817
- /******/
2818
- /******/ // The require function
2819
- /******/ function __webpack_require__(moduleId) {
2820
- /******/ // Check if module is in cache
2821
- /******/ var cachedModule = __webpack_module_cache__[moduleId];
2822
- /******/ if (cachedModule !== undefined) {
2823
- /******/ return cachedModule.exports;
2824
- /******/ }
2825
- /******/ // Create a new module (and put it into the cache)
2826
- /******/ var module = __webpack_module_cache__[moduleId] = {
2827
- /******/ // no module.id needed
2828
- /******/ // no module.loaded needed
2829
- /******/ exports: {}
2830
- /******/ };
2831
- /******/
2832
- /******/ // Execute the module function
2833
- /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
2834
- /******/
2835
- /******/ // Return the exports of the module
2836
- /******/ return module.exports;
2837
- /******/ }
2838
- /******/
2839
- /************************************************************************/
2840
- /******/
2841
- /******/ // startup
2842
- /******/ // Load entry module and return exports
2843
- /******/ // This entry module is referenced by other modules so it can't be inlined
2844
- /******/ var __webpack_exports__ = __webpack_require__(44);
2845
- /******/ module.exports = __webpack_exports__;
2846
- /******/
2251
+ ;// ./src/index.mjs
2252
+
2253
+
2254
+
2255
+
2256
+
2257
+
2258
+
2259
+
2260
+
2261
+
2262
+ module.exports = __webpack_exports__;
2847
2263
  /******/ })()
2848
2264
  ;