@63klabs/cache-data 1.3.7 → 1.3.9
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/AGENTS.md +1107 -0
- package/CHANGELOG.md +121 -2
- package/CONTRIBUTING.md +4 -5
- package/README.md +50 -25
- package/eslint.config.js +53 -0
- package/package.json +26 -14
- package/src/lib/dao-cache.js +30 -14
- package/src/lib/tools/APIRequest.class.js +948 -91
- package/src/lib/tools/AWS.classes.js +58 -5
- package/src/lib/tools/CachedParametersSecrets.classes.js +1 -0
- package/src/lib/tools/ClientRequest.class.js +858 -31
- package/src/lib/tools/Connections.classes.js +40 -3
- package/src/lib/tools/Response.class.js +11 -0
- package/src/lib/tools/generic.response.html.js +33 -0
- package/src/lib/tools/generic.response.json.js +40 -1
- package/src/lib/tools/generic.response.rss.js +33 -0
- package/src/lib/tools/generic.response.text.js +34 -1
- package/src/lib/tools/generic.response.xml.js +39 -0
- package/src/lib/tools/index.js +211 -50
- package/src/lib/utils/ValidationExecutor.class.js +66 -0
- package/src/lib/utils/ValidationMatcher.class.js +405 -0
package/src/lib/tools/index.js
CHANGED
|
@@ -44,19 +44,31 @@ const { Connections, Connection, ConnectionRequest, ConnectionAuthentication } =
|
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* @typedef ConnectionObject
|
|
48
|
-
* @property {
|
|
49
|
-
* @property {string}
|
|
50
|
-
* @property {string}
|
|
51
|
-
* @property {string}
|
|
52
|
-
* @property {string}
|
|
53
|
-
* @property {
|
|
54
|
-
* @property {object}
|
|
55
|
-
* @property {
|
|
56
|
-
* @property {string}
|
|
57
|
-
* @property {
|
|
58
|
-
* @property {
|
|
59
|
-
* @property {
|
|
47
|
+
* @typedef {Object} ConnectionObject
|
|
48
|
+
* @property {string} method GET or POST
|
|
49
|
+
* @property {string} uri the full uri (overrides protocol, host, path, and parameters) ex https://example.com/api/v1/1004/?key=asdf&y=4
|
|
50
|
+
* @property {string} protocol https
|
|
51
|
+
* @property {string} host host/domain: example.com
|
|
52
|
+
* @property {string} path path of the request: /api/v1/1004
|
|
53
|
+
* @property {object} parameters parameters for the query string as an object in key/value pairs
|
|
54
|
+
* @property {object} headers headers for the request as an object in key/value pairs
|
|
55
|
+
* @property {string} body for POST requests, the body
|
|
56
|
+
* @property {string} note a note for logging
|
|
57
|
+
* @property {object} options https_get options
|
|
58
|
+
* @property {number} options.timeout timeout in milliseconds
|
|
59
|
+
* @property {CacheProfileObject[]} cache
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @typedef {Object} CacheProfileObject
|
|
64
|
+
* @property {string} profile The name of the cache profile
|
|
65
|
+
* @property {boolean} overrideOriginHeaderExpiration If true, the cache expiration will be overridden by the origin header expiration
|
|
66
|
+
* @property {number} defaultExpirationInSeconds The default expiration time in seconds
|
|
67
|
+
* @property {boolean} expirationIsOnInterval If true, the cache expiration will be on an interval
|
|
68
|
+
* @property {array<string>} headersToRetain
|
|
69
|
+
* @property {string} hostId The host ID to use for the cache key
|
|
70
|
+
* @property {string} pathId The path ID to use for the cache key
|
|
71
|
+
* @property {boolean} encrypt If true, the cache data will be encrypted
|
|
60
72
|
*/
|
|
61
73
|
|
|
62
74
|
/* ****************************************************************************
|
|
@@ -69,7 +81,7 @@ const { Connections, Connection, ConnectionRequest, ConnectionAuthentication } =
|
|
|
69
81
|
*************************************************************************** */
|
|
70
82
|
|
|
71
83
|
/**
|
|
72
|
-
*
|
|
84
|
+
* AppConfig needs to be extended by your own Config class definition.
|
|
73
85
|
*
|
|
74
86
|
* This super class holds common variables and methods that can be used by any
|
|
75
87
|
* application. However, each application requires it's own methods and logic
|
|
@@ -80,36 +92,177 @@ const { Connections, Connection, ConnectionRequest, ConnectionAuthentication } =
|
|
|
80
92
|
* initialized.
|
|
81
93
|
*
|
|
82
94
|
* @example
|
|
83
|
-
* class Config extends tools.
|
|
95
|
+
* class Config extends tools.AppConfig {
|
|
84
96
|
* // your custom class definition including your implementation of .init()
|
|
85
97
|
* }
|
|
86
98
|
*
|
|
87
99
|
* Config.init();
|
|
88
100
|
*/
|
|
89
|
-
class
|
|
101
|
+
class AppConfig {
|
|
90
102
|
|
|
91
103
|
static _promise = null;
|
|
104
|
+
static _promises = [];
|
|
92
105
|
static _connections = null;
|
|
93
106
|
static _settings = null;
|
|
107
|
+
static _ssmParameters = null;
|
|
94
108
|
|
|
95
109
|
/**
|
|
96
|
-
*
|
|
110
|
+
* Initialize the Config class with asynchronous parallel execution.
|
|
97
111
|
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
112
|
+
* This method returns immediately (synchronously) while initialization operations
|
|
113
|
+
* execute asynchronously in parallel. Use AppConfig.promise() to wait for all
|
|
114
|
+
* initialization to complete before accessing initialized configuration.
|
|
115
|
+
*
|
|
116
|
+
* @param {object} options Configuration options
|
|
117
|
+
* @param {object} options.settings Application settings retrieved by Config.settings()
|
|
118
|
+
* @param {ConnectionObject[]} options.connections Application connections that can then be retrieved by Config.getConn() or Config.getConnCacheProfile()
|
|
119
|
+
* @param {object} options.validations ClientRequest.init() options
|
|
120
|
+
* @param {object} options.responses Response.init() options
|
|
121
|
+
* @param {object} options.responses.settings
|
|
122
|
+
* @param {number} options.responses.settings.errorExpirationInSeconds
|
|
123
|
+
* @param {number} options.responses.settings.routeExpirationInSeconds
|
|
124
|
+
* @param {number} options.responses.settings.externalRequestHeadroomInMs
|
|
125
|
+
* @param {object} options.responses.jsonResponses
|
|
126
|
+
* @param {object} options.responses.htmlResponses
|
|
127
|
+
* @param {object} options.responses.xmlResponses
|
|
128
|
+
* @param {object} options.responses.rssResponses
|
|
129
|
+
* @param {object} options.responses.textResponses
|
|
130
|
+
* @param {object} options.ssmParameters Parameter Store
|
|
131
|
+
* @param {boolean} [options.debug=false] Enable debug logging
|
|
132
|
+
* @returns {boolean} True if initialization started successfully, false on synchronous error
|
|
133
|
+
* @example
|
|
134
|
+
* // Initialize configuration (returns immediately)
|
|
135
|
+
* const { Config } = require("./config");
|
|
136
|
+
* Config.init({
|
|
137
|
+
* settings: {
|
|
138
|
+
* dataLimit: 1000,
|
|
139
|
+
* cacheTTL: 300
|
|
140
|
+
* },
|
|
141
|
+
* connections: {
|
|
142
|
+
* myConnection: {
|
|
143
|
+
* method: "GET",
|
|
144
|
+
* host: "example.com",
|
|
145
|
+
* path: "/api/v1/data",
|
|
146
|
+
* parameters: {
|
|
147
|
+
* limit: 100
|
|
148
|
+
* }
|
|
149
|
+
* }
|
|
150
|
+
* }
|
|
151
|
+
* });
|
|
152
|
+
*
|
|
153
|
+
* // Wait for all initialization to complete
|
|
154
|
+
* await Config.promise();
|
|
155
|
+
*
|
|
156
|
+
* // Now safe to access initialized configuration
|
|
157
|
+
* const settings = Config.settings();
|
|
158
|
+
* const conn = Config.getConn('myConnection');
|
|
159
|
+
*/
|
|
160
|
+
static init(options = {}) {
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
|
|
164
|
+
const debug = (options?.debug === true);
|
|
165
|
+
if (debug) {
|
|
166
|
+
DebugAndLog.debug("Config Init in debug mode");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (options.settings) {
|
|
170
|
+
const settingsPromise = new Promise((resolve) => {
|
|
171
|
+
try {
|
|
172
|
+
AppConfig._settings = options.settings;
|
|
173
|
+
if (debug) {
|
|
174
|
+
DebugAndLog.debug("Settings initialized", AppConfig._settings);
|
|
175
|
+
}
|
|
176
|
+
resolve(true);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
DebugAndLog.error(`Settings initialization failed: ${error.message}`, error.stack);
|
|
179
|
+
resolve(false);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
AppConfig.add(settingsPromise);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (options.connections) {
|
|
186
|
+
const connectionsPromise = new Promise((resolve) => {
|
|
187
|
+
try {
|
|
188
|
+
AppConfig._connections = new Connections(options.connections);
|
|
189
|
+
if (debug) {
|
|
190
|
+
DebugAndLog.debug("Connections initialized", AppConfig._connections.info());
|
|
191
|
+
}
|
|
192
|
+
resolve(true);
|
|
193
|
+
} catch (error) {
|
|
194
|
+
DebugAndLog.error(`Connections initialization failed: ${error.message}`, error.stack);
|
|
195
|
+
resolve(false);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
AppConfig.add(connectionsPromise);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (options.validations) {
|
|
202
|
+
const validationsPromise = new Promise((resolve) => {
|
|
203
|
+
try {
|
|
204
|
+
ClientRequest.init(options.validations);
|
|
205
|
+
if (debug) {
|
|
206
|
+
DebugAndLog.debug("ClientRequest initialized", ClientRequest.info());
|
|
207
|
+
}
|
|
208
|
+
resolve(true);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
DebugAndLog.error(`ClientRequest initialization failed: ${error.message}`, error.stack);
|
|
211
|
+
resolve(false);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
AppConfig.add(validationsPromise);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (options.responses) {
|
|
218
|
+
const responsesPromise = new Promise((resolve) => {
|
|
219
|
+
try {
|
|
220
|
+
Response.init(options.responses);
|
|
221
|
+
if (debug) {
|
|
222
|
+
DebugAndLog.debug("Response initialized", Response.info());
|
|
223
|
+
}
|
|
224
|
+
resolve(true);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
DebugAndLog.error(`Response initialization failed: ${error.message}`, error.stack);
|
|
227
|
+
resolve(false);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
AppConfig.add(responsesPromise);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (options.ssmParameters) {
|
|
234
|
+
AppConfig._ssmParameters = AppConfig._initParameters(options.ssmParameters);
|
|
235
|
+
AppConfig.add(AppConfig._ssmParameters);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return true;
|
|
239
|
+
|
|
240
|
+
} catch (error) {
|
|
241
|
+
DebugAndLog.error(`Could not initialize Config ${error.message}`, error.stack);
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Add a promise to AppConfig. Use AppConfig.promise() to ensure all are resolved.
|
|
249
|
+
* @param {Promise} promise
|
|
250
|
+
*/
|
|
251
|
+
static add(promise) {
|
|
252
|
+
AppConfig._promises.push(promise);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Get the application settings object
|
|
101
257
|
*
|
|
102
258
|
* @returns {object|null} Settings object containing application configuration, or null if not initialized
|
|
103
259
|
* @example
|
|
104
|
-
* //
|
|
105
|
-
* const
|
|
106
|
-
*
|
|
107
|
-
* console.log('App version:', settings.version);
|
|
108
|
-
* console.log('Environment:', settings.environment);
|
|
109
|
-
* }
|
|
260
|
+
* // Config extends AppConfig
|
|
261
|
+
* const { Config } = require("./config");
|
|
262
|
+
* const limit = Config.settings().dataLimit;
|
|
110
263
|
*/
|
|
111
264
|
static settings() {
|
|
112
|
-
return
|
|
265
|
+
return AppConfig._settings;
|
|
113
266
|
};
|
|
114
267
|
|
|
115
268
|
/**
|
|
@@ -117,7 +270,7 @@ class _ConfigSuperClass {
|
|
|
117
270
|
* @returns {Connections}
|
|
118
271
|
*/
|
|
119
272
|
static connections() {
|
|
120
|
-
return
|
|
273
|
+
return AppConfig._connections;
|
|
121
274
|
};
|
|
122
275
|
|
|
123
276
|
/**
|
|
@@ -127,10 +280,10 @@ class _ConfigSuperClass {
|
|
|
127
280
|
* @returns {Connection|null} Connection instance or null if not found
|
|
128
281
|
*/
|
|
129
282
|
static getConnection(name) {
|
|
130
|
-
if (
|
|
283
|
+
if (AppConfig._connections === null) {
|
|
131
284
|
return null;
|
|
132
285
|
}
|
|
133
|
-
return
|
|
286
|
+
return AppConfig._connections.get(name);
|
|
134
287
|
}
|
|
135
288
|
|
|
136
289
|
/**
|
|
@@ -147,11 +300,11 @@ class _ConfigSuperClass {
|
|
|
147
300
|
* )
|
|
148
301
|
* */
|
|
149
302
|
static getConn(name) {
|
|
150
|
-
if (
|
|
303
|
+
if (AppConfig._connections === null) {
|
|
151
304
|
return null;
|
|
152
305
|
}
|
|
153
306
|
|
|
154
|
-
const connection =
|
|
307
|
+
const connection = AppConfig._connections.get(name);
|
|
155
308
|
|
|
156
309
|
if (connection === null) {
|
|
157
310
|
return null;
|
|
@@ -175,37 +328,42 @@ class _ConfigSuperClass {
|
|
|
175
328
|
*/
|
|
176
329
|
static getConnCacheProfile(connectionName, cacheProfileName) {
|
|
177
330
|
|
|
178
|
-
if (
|
|
331
|
+
if (AppConfig._connections === null) {
|
|
179
332
|
return { conn: null, cacheProfile: null };
|
|
180
333
|
}
|
|
181
334
|
|
|
182
|
-
const connection =
|
|
335
|
+
const connection = AppConfig._connections.get(connectionName);
|
|
183
336
|
|
|
184
337
|
if (connection === null) {
|
|
185
338
|
return { conn: null, cacheProfile: null };
|
|
186
339
|
}
|
|
187
340
|
|
|
188
|
-
let cacheProfile
|
|
341
|
+
let cacheProfile;
|
|
342
|
+
|
|
189
343
|
try {
|
|
190
344
|
const profile = connection.getCacheProfile(cacheProfileName);
|
|
191
345
|
cacheProfile = (profile === undefined) ? null : profile;
|
|
192
|
-
} catch
|
|
346
|
+
} catch {
|
|
193
347
|
// getCacheProfile throws if _cacheProfiles is null
|
|
194
348
|
cacheProfile = null;
|
|
195
349
|
}
|
|
196
350
|
|
|
197
351
|
return {
|
|
198
352
|
conn: connection.toObject(),
|
|
199
|
-
cacheProfile
|
|
200
|
-
};
|
|
353
|
+
cacheProfile
|
|
354
|
+
};
|
|
355
|
+
|
|
201
356
|
}
|
|
202
357
|
|
|
203
358
|
/**
|
|
204
359
|
*
|
|
205
|
-
* @returns {Promise} A promise that resolves when the Config class has finished initializing
|
|
360
|
+
* @returns {Promise<array>} A promise that resolves when the Config class has finished initializing
|
|
206
361
|
*/
|
|
207
362
|
static promise() {
|
|
208
|
-
|
|
363
|
+
if (AppConfig._promise !== null ) { // Backwards compatibility
|
|
364
|
+
AppConfig._promises.push(AppConfig._promise);
|
|
365
|
+
}
|
|
366
|
+
return Promise.all(AppConfig._promises);
|
|
209
367
|
};
|
|
210
368
|
|
|
211
369
|
|
|
@@ -246,8 +404,6 @@ class _ConfigSuperClass {
|
|
|
246
404
|
return { names: names, paths: paths};
|
|
247
405
|
};
|
|
248
406
|
|
|
249
|
-
let request = [];
|
|
250
|
-
|
|
251
407
|
let pNames = paramNames();
|
|
252
408
|
|
|
253
409
|
if (pNames.names.length > 0 || pNames.paths.length > 0 ) {
|
|
@@ -352,20 +508,20 @@ class _ConfigSuperClass {
|
|
|
352
508
|
* ]
|
|
353
509
|
* );
|
|
354
510
|
* @param {array} parameters An array of parameter locations
|
|
355
|
-
* @returns {object} Parameters from the parameter store
|
|
511
|
+
* @returns {Promise<object>} Parameters from the parameter store
|
|
356
512
|
*/
|
|
357
513
|
static async _initParameters(parameters) {
|
|
358
514
|
// make the call to get the parameters and wait before proceeding to the return
|
|
359
515
|
return await this._getParameters(parameters);
|
|
360
516
|
};
|
|
361
517
|
|
|
362
|
-
static async _initS3File(paths) {
|
|
363
|
-
|
|
364
|
-
};
|
|
518
|
+
// static async _initS3File(paths) {
|
|
519
|
+
// return {};
|
|
520
|
+
// };
|
|
365
521
|
|
|
366
|
-
static async _initDynamoDbRecord(query) {
|
|
367
|
-
|
|
368
|
-
};
|
|
522
|
+
// static async _initDynamoDbRecord(query) {
|
|
523
|
+
// return {};
|
|
524
|
+
// };
|
|
369
525
|
|
|
370
526
|
};
|
|
371
527
|
|
|
@@ -375,8 +531,11 @@ module.exports = {
|
|
|
375
531
|
nodeVerMinor,
|
|
376
532
|
nodeVerMajorMinor,
|
|
377
533
|
AWS,
|
|
534
|
+
Aws: AWS,
|
|
378
535
|
AWSXRay,
|
|
536
|
+
AwsXRay: AWSXRay, // Alias
|
|
379
537
|
APIRequest,
|
|
538
|
+
ApiRequest: APIRequest, // Alias
|
|
380
539
|
ImmutableObject,
|
|
381
540
|
Timer,
|
|
382
541
|
DebugAndLog,
|
|
@@ -388,8 +547,10 @@ module.exports = {
|
|
|
388
547
|
ClientRequest,
|
|
389
548
|
ResponseDataModel,
|
|
390
549
|
Response,
|
|
391
|
-
|
|
550
|
+
AppConfig,
|
|
551
|
+
_ConfigSuperClass: AppConfig, // Alias
|
|
392
552
|
CachedSSMParameter,
|
|
553
|
+
CachedSsmParameter: CachedSSMParameter, // Alias
|
|
393
554
|
CachedSecret,
|
|
394
555
|
CachedParameterSecret,
|
|
395
556
|
CachedParameterSecrets,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ValidationExecutor - Executes validation functions with appropriate interfaces
|
|
3
|
+
*
|
|
4
|
+
* This class provides static methods for executing validation functions with either
|
|
5
|
+
* single-parameter or multi-parameter interfaces. It handles errors gracefully and
|
|
6
|
+
* logs validation failures.
|
|
7
|
+
*
|
|
8
|
+
* @private
|
|
9
|
+
* @class ValidationExecutor
|
|
10
|
+
*/
|
|
11
|
+
class ValidationExecutor {
|
|
12
|
+
/**
|
|
13
|
+
* Execute validation function with appropriate interface.
|
|
14
|
+
*
|
|
15
|
+
* Determines whether to pass a single value or an object based on the number
|
|
16
|
+
* of parameters specified. Handles validation errors gracefully by catching
|
|
17
|
+
* exceptions and logging them.
|
|
18
|
+
*
|
|
19
|
+
* @param {Function} validateFn - Validation function to execute
|
|
20
|
+
* @param {Array<string>} paramNames - Parameter names to validate
|
|
21
|
+
* @param {Object} paramValues - All parameter values available
|
|
22
|
+
* @returns {boolean} True if validation passes, false if fails or throws
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Single parameter validation
|
|
26
|
+
* const isValid = ValidationExecutor.execute(
|
|
27
|
+
* (value) => value.length > 0,
|
|
28
|
+
* ['id'],
|
|
29
|
+
* { id: '123' }
|
|
30
|
+
* );
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // Multi-parameter validation
|
|
34
|
+
* const isValid = ValidationExecutor.execute(
|
|
35
|
+
* ({page, limit}) => page >= 1 && limit >= 1 && limit <= 100,
|
|
36
|
+
* ['page', 'limit'],
|
|
37
|
+
* { page: 1, limit: 10 }
|
|
38
|
+
* );
|
|
39
|
+
*/
|
|
40
|
+
static execute(validateFn, paramNames, paramValues) {
|
|
41
|
+
try {
|
|
42
|
+
if (paramNames.length === 1) {
|
|
43
|
+
// Single parameter: pass value directly
|
|
44
|
+
const value = paramValues[paramNames[0]];
|
|
45
|
+
return validateFn(value);
|
|
46
|
+
} else {
|
|
47
|
+
// Multiple parameters: pass object
|
|
48
|
+
const paramObj = {};
|
|
49
|
+
for (const name of paramNames) {
|
|
50
|
+
paramObj[name] = paramValues[name];
|
|
51
|
+
}
|
|
52
|
+
return validateFn(paramObj);
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
// Log error and treat as validation failure
|
|
56
|
+
const tools = require("../tools/index.js");
|
|
57
|
+
tools.DebugAndLog.error(
|
|
58
|
+
`Validation function threw error for parameters [${paramNames.join(", ")}]: ${error?.message || "Unknown error"}`,
|
|
59
|
+
error?.stack
|
|
60
|
+
);
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = ValidationExecutor;
|