@63klabs/cache-data 1.3.4 → 1.3.6
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/AI_CONTEXT.md +863 -0
- package/CHANGELOG.md +44 -1
- package/CONTRIBUTING.md +161 -0
- package/README.md +139 -27
- package/package.json +9 -5
- package/scripts/README.md +175 -0
- package/scripts/audit-documentation.mjs +856 -0
- package/scripts/review-documentation-files.mjs +406 -0
- package/scripts/setup-dev-environment.sh +59 -0
- package/scripts/verify-example-files.mjs +194 -0
- package/src/lib/dao-cache.js +1286 -288
- package/src/lib/dao-endpoint.js +181 -42
- package/src/lib/tools/AWS.classes.js +82 -0
- package/src/lib/tools/CachedParametersSecrets.classes.js +98 -7
- package/src/lib/tools/ClientRequest.class.js +43 -10
- package/src/lib/tools/Connections.classes.js +148 -13
- package/src/lib/tools/DebugAndLog.class.js +244 -75
- package/src/lib/tools/ImmutableObject.class.js +44 -2
- package/src/lib/tools/RequestInfo.class.js +38 -0
- package/src/lib/tools/Response.class.js +245 -81
- package/src/lib/tools/ResponseDataModel.class.js +123 -47
- package/src/lib/tools/Timer.class.js +138 -26
- package/src/lib/tools/index.js +89 -2
- package/src/lib/tools/utils.js +40 -4
- package/src/lib/utils/InMemoryCache.js +221 -0
|
@@ -1,11 +1,48 @@
|
|
|
1
1
|
const RequestInfo = require('./RequestInfo.class');
|
|
2
2
|
const Timer = require('./Timer.class');
|
|
3
3
|
const DebugAndLog = require('./DebugAndLog.class');
|
|
4
|
+
const { safeClone } = require('./utils');
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Extends RequestInfo
|
|
8
9
|
* Can be used to create a custom ClientRequest object
|
|
10
|
+
* @example
|
|
11
|
+
* // Initialize ClientRequest with validations
|
|
12
|
+
* ClientRequest.init({
|
|
13
|
+
* validations: {
|
|
14
|
+
* referrers: ['example.com', 'myapp.com'],
|
|
15
|
+
* parameters: {
|
|
16
|
+
* queryStringParameters: {
|
|
17
|
+
* limit: (value) => !isNaN(value) && value > 0 && value <= 100,
|
|
18
|
+
* page: (value) => !isNaN(value) && value > 0
|
|
19
|
+
* },
|
|
20
|
+
* pathParameters: {
|
|
21
|
+
* id: (value) => /^[a-zA-Z0-9-]+$/.test(value)
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Use in Lambda handler
|
|
29
|
+
* exports.handler = async (event, context) => {
|
|
30
|
+
* const clientRequest = new ClientRequest(event, context);
|
|
31
|
+
*
|
|
32
|
+
* if (!clientRequest.isValid()) {
|
|
33
|
+
* return { statusCode: 400, body: 'Invalid request' };
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* const userId = clientRequest.getPathAt(1);
|
|
37
|
+
* const queryParams = clientRequest.getQueryStringParameters();
|
|
38
|
+
*
|
|
39
|
+
* // Add logging for monitoring
|
|
40
|
+
* clientRequest.addPathLog(`users/${userId}`);
|
|
41
|
+
* clientRequest.addQueryLog(`limit=${queryParams.limit}`);
|
|
42
|
+
*
|
|
43
|
+
* // Process request...
|
|
44
|
+
* return { statusCode: 200, body: 'Success' };
|
|
45
|
+
* };
|
|
9
46
|
*/
|
|
10
47
|
class ClientRequest extends RequestInfo {
|
|
11
48
|
|
|
@@ -22,7 +59,7 @@ class ClientRequest extends RequestInfo {
|
|
|
22
59
|
/* What and who of the request */
|
|
23
60
|
#event = null;
|
|
24
61
|
#context = null;
|
|
25
|
-
#authorizations =
|
|
62
|
+
#authorizations = safeClone(ClientRequest.#unauthenticatedAuthorizations);
|
|
26
63
|
#roles = [];
|
|
27
64
|
|
|
28
65
|
/* The request data */
|
|
@@ -83,8 +120,8 @@ class ClientRequest extends RequestInfo {
|
|
|
83
120
|
* This is used to initialize the ClientRequest class for all requests.
|
|
84
121
|
* Add ClientRequest.init(options) to the Config.init process or at the
|
|
85
122
|
* top of the main index.js file outside of the handler.
|
|
86
|
-
* @param {
|
|
87
|
-
* @
|
|
123
|
+
* @param {object} options - Configuration options with validations property containing referrers and parameters
|
|
124
|
+
* @throws {Error} If options is not an object
|
|
88
125
|
*/
|
|
89
126
|
static init(options) {
|
|
90
127
|
if (typeof options === 'object') {
|
|
@@ -193,12 +230,8 @@ class ClientRequest extends RequestInfo {
|
|
|
193
230
|
}
|
|
194
231
|
|
|
195
232
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
* @param {array<string>} arr array to slice
|
|
199
|
-
* @param {number} n number of elements to return
|
|
200
|
-
* @returns {array<string>} array of elements
|
|
201
|
-
*/
|
|
233
|
+
// Utility function for getPathArray and getResourceArray
|
|
234
|
+
// Returns array slice based on n parameter
|
|
202
235
|
#getArray(arr, n = 0) {
|
|
203
236
|
if (n === 0 || arr.length <= n || (n < 0 && arr.length <= (n*-1))) {
|
|
204
237
|
return arr;
|
|
@@ -352,7 +385,7 @@ class ClientRequest extends RequestInfo {
|
|
|
352
385
|
if (this.isAuthenticated()) {
|
|
353
386
|
return this.#authorizations;
|
|
354
387
|
} else {
|
|
355
|
-
return
|
|
388
|
+
return safeClone(ClientRequest.#unauthenticatedAuthorizations);
|
|
356
389
|
}
|
|
357
390
|
};
|
|
358
391
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const DebugAndLog = require('./DebugAndLog.class');
|
|
2
|
+
const { safeClone } = require('./utils');
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
/* ****************************************************************************
|
|
@@ -9,6 +10,30 @@ const DebugAndLog = require('./DebugAndLog.class');
|
|
|
9
10
|
*
|
|
10
11
|
*************************************************************************** */
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* @class Connections
|
|
15
|
+
* @property {object} _connections An object containing Connection objects
|
|
16
|
+
* @example
|
|
17
|
+
* // Create a Connections container with multiple connections
|
|
18
|
+
* const connections = new Connections([
|
|
19
|
+
* { name: 'api', host: 'api.example.com', path: '/v1/users' },
|
|
20
|
+
* { name: 'auth', host: 'auth.example.com', path: '/oauth/token' }
|
|
21
|
+
* ]);
|
|
22
|
+
*
|
|
23
|
+
* // Get a specific connection
|
|
24
|
+
* const apiConnection = connections.get('api');
|
|
25
|
+
* const connectionObj = apiConnection.get();
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Add connections dynamically
|
|
29
|
+
* const connections = new Connections();
|
|
30
|
+
* connections.add({ name: 'database', host: 'db.example.com', path: '/query' });
|
|
31
|
+
* connections.add({ name: 'cache', host: 'cache.example.com', path: '/get' });
|
|
32
|
+
*
|
|
33
|
+
* // Use with endpoint requests
|
|
34
|
+
* const dbConn = connections.get('database');
|
|
35
|
+
* const result = await endpoint.get(dbConn);
|
|
36
|
+
*/
|
|
12
37
|
class Connections {
|
|
13
38
|
|
|
14
39
|
_connections = {};
|
|
@@ -84,6 +109,41 @@ class Connections {
|
|
|
84
109
|
* that can then be used to generate and submit a request to a DAO class or
|
|
85
110
|
* APIRequest object.
|
|
86
111
|
* You can store and manage multiple connections using the Connections object.
|
|
112
|
+
* @example
|
|
113
|
+
* // Create a simple connection
|
|
114
|
+
* const apiConnection = new Connection({
|
|
115
|
+
* name: 'userAPI',
|
|
116
|
+
* host: 'api.example.com',
|
|
117
|
+
* path: '/v1/users',
|
|
118
|
+
* method: 'GET'
|
|
119
|
+
* });
|
|
120
|
+
*
|
|
121
|
+
* // Get connection object for use with endpoint
|
|
122
|
+
* const connObj = apiConnection.get();
|
|
123
|
+
* const users = await endpoint.get(connObj);
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* // Create connection with authentication
|
|
127
|
+
* const authConn = new Connection({
|
|
128
|
+
* name: 'secureAPI',
|
|
129
|
+
* host: 'secure.example.com',
|
|
130
|
+
* path: '/api/data',
|
|
131
|
+
* authentication: {
|
|
132
|
+
* headers: { 'x-api-key': 'your-api-key' }
|
|
133
|
+
* }
|
|
134
|
+
* });
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* // Create connection with cache configuration
|
|
138
|
+
* const cachedConn = new Connection({
|
|
139
|
+
* name: 'cachedAPI',
|
|
140
|
+
* host: 'api.example.com',
|
|
141
|
+
* path: '/data',
|
|
142
|
+
* cache: {
|
|
143
|
+
* profile: 'default',
|
|
144
|
+
* expirationInSeconds: 300
|
|
145
|
+
* }
|
|
146
|
+
* });
|
|
87
147
|
*/
|
|
88
148
|
class Connection {
|
|
89
149
|
|
|
@@ -150,7 +210,7 @@ class Connection {
|
|
|
150
210
|
* @returns {Object}
|
|
151
211
|
*/
|
|
152
212
|
getParameters() {
|
|
153
|
-
let params = (this._parameters !== null) ?
|
|
213
|
+
let params = (this._parameters !== null) ? safeClone(this._parameters) : null;
|
|
154
214
|
|
|
155
215
|
if ("parameters" in this._getAuthenticationObject()) {
|
|
156
216
|
if (params === null) { params = {}; }
|
|
@@ -166,7 +226,7 @@ class Connection {
|
|
|
166
226
|
* @returns {Object}
|
|
167
227
|
*/
|
|
168
228
|
getHeaders() {
|
|
169
|
-
let headers = (this._headers !== null) ?
|
|
229
|
+
let headers = (this._headers !== null) ? safeClone(this._headers) : null;
|
|
170
230
|
|
|
171
231
|
if ("headers" in this._getAuthenticationObject()) {
|
|
172
232
|
if (headers === null) { headers = {}; }
|
|
@@ -204,11 +264,16 @@ class Connection {
|
|
|
204
264
|
*/
|
|
205
265
|
getCacheProfile( profileName ) {
|
|
206
266
|
|
|
267
|
+
if (this._cacheProfiles === null) {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
207
271
|
function isProfile(item) {
|
|
208
272
|
return item.profile === profileName;
|
|
209
273
|
};
|
|
210
274
|
|
|
211
|
-
|
|
275
|
+
const profile = this._cacheProfiles.find(isProfile);
|
|
276
|
+
return profile ? safeClone(profile) : undefined;
|
|
212
277
|
};
|
|
213
278
|
|
|
214
279
|
_setAuthentication(authentication) {
|
|
@@ -248,7 +313,10 @@ class Connection {
|
|
|
248
313
|
if ( parameters !== null ) { obj.parameters = parameters; }
|
|
249
314
|
if ( body !== null ) { obj.body = body; }
|
|
250
315
|
|
|
251
|
-
|
|
316
|
+
const authObj = this._getAuthenticationObject();
|
|
317
|
+
if ( Object.keys(authObj).length > 0 ) { obj.authentication = authObj; }
|
|
318
|
+
|
|
319
|
+
if ( this._cacheProfiles !== null ) { obj.cache = this._cacheProfiles; }
|
|
252
320
|
|
|
253
321
|
return obj;
|
|
254
322
|
};
|
|
@@ -288,14 +356,43 @@ class Connection {
|
|
|
288
356
|
* Header, parameter, and/or Basic auth key/value pairs can be passed in.
|
|
289
357
|
* Additional methods could be added in the future.
|
|
290
358
|
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
* );
|
|
359
|
+
* @example
|
|
360
|
+
* // Create authentication with API key in header
|
|
361
|
+
* const auth = new ConnectionAuthentication({
|
|
362
|
+
* headers: {
|
|
363
|
+
* 'x-api-key': 'your-api-key-here',
|
|
364
|
+
* 'x-user-id': 'user123'
|
|
365
|
+
* }
|
|
366
|
+
* });
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* // Create authentication with query parameters
|
|
370
|
+
* const auth = new ConnectionAuthentication({
|
|
371
|
+
* parameters: {
|
|
372
|
+
* apikey: 'your-api-key',
|
|
373
|
+
* token: 'auth-token'
|
|
374
|
+
* }
|
|
375
|
+
* });
|
|
376
|
+
*
|
|
377
|
+
* @example
|
|
378
|
+
* // Create authentication with Basic auth
|
|
379
|
+
* const auth = new ConnectionAuthentication({
|
|
380
|
+
* basic: {
|
|
381
|
+
* username: 'myUsername',
|
|
382
|
+
* password: 'myPassword'
|
|
383
|
+
* }
|
|
384
|
+
* });
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* // Use with Connection
|
|
388
|
+
* const connection = new Connection({
|
|
389
|
+
* name: 'secureAPI',
|
|
390
|
+
* host: 'api.example.com',
|
|
391
|
+
* path: '/secure/data',
|
|
392
|
+
* authentication: new ConnectionAuthentication({
|
|
393
|
+
* headers: { 'Authorization': 'Bearer token123' }
|
|
394
|
+
* })
|
|
395
|
+
* });
|
|
299
396
|
*/
|
|
300
397
|
class ConnectionAuthentication {
|
|
301
398
|
|
|
@@ -414,7 +511,7 @@ class ConnectionAuthentication {
|
|
|
414
511
|
let body = this._getBody();
|
|
415
512
|
if ( Object.keys(body).length ) { obj.body = body; }
|
|
416
513
|
|
|
417
|
-
return
|
|
514
|
+
return safeClone(obj);
|
|
418
515
|
};
|
|
419
516
|
|
|
420
517
|
// Static methods that could perform authentication could go here
|
|
@@ -428,6 +525,44 @@ class ConnectionAuthentication {
|
|
|
428
525
|
* Connection by adding request specific parameters. While a Connection
|
|
429
526
|
* cannot be modified after creation (it is a config), a ClientRequest can be
|
|
430
527
|
* modified as the application or DAO assembles the request.
|
|
528
|
+
* @example
|
|
529
|
+
* // Create a connection request from a base connection
|
|
530
|
+
* const baseConnection = new Connection({
|
|
531
|
+
* name: 'api',
|
|
532
|
+
* host: 'api.example.com',
|
|
533
|
+
* path: '/users'
|
|
534
|
+
* });
|
|
535
|
+
*
|
|
536
|
+
* const request = new ConnectionRequest(baseConnection.get());
|
|
537
|
+
*
|
|
538
|
+
* // Add dynamic headers
|
|
539
|
+
* request.addHeader('Authorization', `Bearer ${token}`);
|
|
540
|
+
* request.addHeader('X-Request-ID', requestId);
|
|
541
|
+
*
|
|
542
|
+
* // Add query parameters
|
|
543
|
+
* request.addParameter('limit', 10);
|
|
544
|
+
* request.addParameter('page', 1);
|
|
545
|
+
*
|
|
546
|
+
* // Make the request
|
|
547
|
+
* const result = await endpoint.get(request);
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* // Build a request dynamically in a DAO
|
|
551
|
+
* class UsersDAO {
|
|
552
|
+
* static async getUser(userId, authToken) {
|
|
553
|
+
* const request = new ConnectionRequest({
|
|
554
|
+
* host: 'api.example.com',
|
|
555
|
+
* path: `/users/${userId}`
|
|
556
|
+
* });
|
|
557
|
+
*
|
|
558
|
+
* request.addHeaders({
|
|
559
|
+
* 'Authorization': `Bearer ${authToken}`,
|
|
560
|
+
* 'Content-Type': 'application/json'
|
|
561
|
+
* });
|
|
562
|
+
*
|
|
563
|
+
* return await endpoint.get(request);
|
|
564
|
+
* }
|
|
565
|
+
* }
|
|
431
566
|
*/
|
|
432
567
|
class ConnectionRequest extends Connection {
|
|
433
568
|
|