@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.
@@ -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 = JSON.parse(JSON.stringify(ClientRequest.#unauthenticatedAuthorizations));
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 {Array<string>} options.validations.referrers An array of accepted referrers. String matching goes from right to left, so ['example.com'] will allow example.com and subdomain.example.com
87
- * @param {object} options.validations.parameters An object containing functions for validating request parameters (path, querystring, headers, cookies, etc).
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
- * Utility function for getPathArray and getResourceArray
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 JSON.parse(JSON.stringify(ClientRequest.#unauthenticatedAuthorizations));
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) ? JSON.parse(JSON.stringify(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) ? JSON.parse(JSON.stringify(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
- return JSON.parse(JSON.stringify(this._cacheProfiles.find(isProfile)));
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
- if ( this._authentication !== null ) { obj.authentication = this._authentication.toObject(); }
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
- * new ConnectionAuthentication(
292
- * {
293
- * headers: { x-key: "bsomeKeyForAHeaderField", x-user: "myUserID" },
294
- * parameters: { apikey: "myExampleApiKeyForResource1234" },
295
- * body: { key: "myExampleApiKeyForResource1283" },
296
- * basic: { username: "myUsername", password: "myPassword" }
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 JSON.parse(JSON.stringify(obj));
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