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