klaim 1.7.0-alpha.1 → 1.7.0-alpha.2
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/dist/klaim.es.js +473 -19
- package/eslint.config.mjs +51 -51
- package/package.json +1 -1
- package/src/core/Api.ts +40 -0
- package/src/core/Cache.ts +68 -14
- package/src/core/Element.ts +118 -4
- package/src/core/Group.ts +116 -2
- package/src/core/Hook.ts +44 -6
- package/src/core/Klaim.ts +111 -6
- package/src/core/Registry.ts +128 -0
- package/src/core/Route.ts +127 -0
- package/tests/01.api.test.ts +1 -1
- package/tests/02.route.test.ts +2 -2
- package/tests/03.hook.test.ts +2 -2
- package/tests/04.klaim.test.ts +24 -4
- package/tests/06.retry.test.ts +16 -2
- package/tests/07.validate.test.ts +12 -2
package/dist/klaim.es.js
CHANGED
|
@@ -8,87 +8,180 @@ function S(s) {
|
|
|
8
8
|
return s.trim().replace(/^\/|\/$/g, "");
|
|
9
9
|
}
|
|
10
10
|
class y {
|
|
11
|
+
/**
|
|
12
|
+
* Creates a new element with the specified properties.
|
|
13
|
+
*
|
|
14
|
+
* @param type - Element type identifier
|
|
15
|
+
* @param name - Unique name for the element
|
|
16
|
+
* @param url - Base URL or path segment
|
|
17
|
+
* @param headers - HTTP headers for the element
|
|
18
|
+
*/
|
|
11
19
|
constructor(t, e, a, r = {}) {
|
|
20
|
+
/** Element type identifier */
|
|
12
21
|
o(this, "type");
|
|
22
|
+
/** Element name (unique within its scope) */
|
|
13
23
|
o(this, "name");
|
|
24
|
+
/** Base URL or path segment */
|
|
14
25
|
o(this, "url");
|
|
26
|
+
/** HTTP headers specific to this element */
|
|
15
27
|
o(this, "headers");
|
|
28
|
+
/** Reference to parent element name */
|
|
16
29
|
o(this, "parent");
|
|
30
|
+
/** HTTP method (for routes) */
|
|
17
31
|
o(this, "method");
|
|
32
|
+
/** Set of dynamic URL parameters */
|
|
18
33
|
o(this, "arguments", /* @__PURE__ */ new Set());
|
|
34
|
+
/** Response validation schema */
|
|
19
35
|
o(this, "schema");
|
|
36
|
+
/** Middleware callbacks collection */
|
|
20
37
|
o(this, "callbacks", {
|
|
21
38
|
before: null,
|
|
22
39
|
after: null,
|
|
23
40
|
call: null
|
|
24
41
|
});
|
|
42
|
+
/** Cache duration in seconds, or false if disabled */
|
|
25
43
|
o(this, "cache", !1);
|
|
44
|
+
/** Number of retry attempts, or false if disabled */
|
|
26
45
|
o(this, "retry", !1);
|
|
27
46
|
this.type = t, this.name = P(e), this.name !== e && console.warn(`Name "${e}" has been camelCased to "${this.name}"`), this.url = S(a), this.headers = r || {};
|
|
28
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Adds a before-request middleware callback.
|
|
50
|
+
*
|
|
51
|
+
* @param callback - Function to execute before the request
|
|
52
|
+
* @returns this element instance for chaining
|
|
53
|
+
*/
|
|
29
54
|
before(t) {
|
|
30
55
|
return this.callbacks.before = t, this;
|
|
31
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Adds an after-request middleware callback.
|
|
59
|
+
*
|
|
60
|
+
* @param callback - Function to execute after the response
|
|
61
|
+
* @returns this element instance for chaining
|
|
62
|
+
*/
|
|
32
63
|
after(t) {
|
|
33
64
|
return this.callbacks.after = t, this;
|
|
34
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Adds a request lifecycle middleware callback.
|
|
68
|
+
*
|
|
69
|
+
* @param callback - Function to execute during the request
|
|
70
|
+
* @returns this element instance for chaining
|
|
71
|
+
*/
|
|
35
72
|
onCall(t) {
|
|
36
73
|
return this.callbacks.call = t, this;
|
|
37
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Enables response caching for this element.
|
|
77
|
+
*
|
|
78
|
+
* @param duration - Cache duration in seconds (default: 20)
|
|
79
|
+
* @returns this element instance for chaining
|
|
80
|
+
*/
|
|
38
81
|
withCache(t = 20) {
|
|
39
82
|
return this.cache = t, this;
|
|
40
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Enables request retries for this element.
|
|
86
|
+
*
|
|
87
|
+
* @param maxRetries - Maximum number of retry attempts (default: 2)
|
|
88
|
+
* @returns this element instance for chaining
|
|
89
|
+
*/
|
|
41
90
|
withRetry(t = 2) {
|
|
42
91
|
return this.retry = t, this;
|
|
43
92
|
}
|
|
44
93
|
}
|
|
45
94
|
const f = class f {
|
|
46
95
|
/**
|
|
47
|
-
* Private constructor to
|
|
96
|
+
* Private constructor to enforce singleton pattern.
|
|
97
|
+
* Initializes an empty cache storage.
|
|
98
|
+
*
|
|
99
|
+
* @private
|
|
48
100
|
*/
|
|
49
101
|
constructor() {
|
|
102
|
+
/**
|
|
103
|
+
* Internal storage for cached items.
|
|
104
|
+
* Maps keys to objects containing the data and expiration timestamp.
|
|
105
|
+
*
|
|
106
|
+
* @private
|
|
107
|
+
*/
|
|
50
108
|
o(this, "cache");
|
|
51
109
|
this.cache = /* @__PURE__ */ new Map();
|
|
52
110
|
}
|
|
53
111
|
/**
|
|
54
|
-
*
|
|
112
|
+
* Gets the singleton instance of the Cache.
|
|
113
|
+
* Creates the instance if it doesn't exist.
|
|
55
114
|
*
|
|
56
|
-
* @returns The singleton instance
|
|
115
|
+
* @returns The singleton Cache instance
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const cache = Cache.i;
|
|
119
|
+
* ```
|
|
57
120
|
*/
|
|
58
121
|
static get i() {
|
|
59
122
|
return f._instance || (f._instance = new f()), f._instance;
|
|
60
123
|
}
|
|
61
124
|
/**
|
|
62
|
-
*
|
|
125
|
+
* Stores a value in the cache with an optional time-to-live duration.
|
|
126
|
+
*
|
|
127
|
+
* @param key - Unique identifier for the cached item
|
|
128
|
+
* @param value - The data to cache
|
|
129
|
+
* @param ttl - Time to live in milliseconds. If 0 or not provided, the item won't expire
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* // Cache a value for 5 minutes
|
|
133
|
+
* Cache.i.set("userProfile", userData, 300000);
|
|
63
134
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
135
|
+
* // Cache without expiration
|
|
136
|
+
* Cache.i.set("appConfig", configData);
|
|
137
|
+
* ```
|
|
67
138
|
*/
|
|
68
139
|
set(t, e, a = 0) {
|
|
69
140
|
const r = Date.now() + a;
|
|
70
141
|
this.cache.set(t, { data: e, expiry: r });
|
|
71
142
|
}
|
|
72
143
|
/**
|
|
73
|
-
* Checks if the cache
|
|
144
|
+
* Checks if the cache contains a valid (non-expired) entry for the given key.
|
|
145
|
+
* Automatically removes expired entries when encountered.
|
|
74
146
|
*
|
|
75
|
-
* @param key The key to check in the cache
|
|
76
|
-
* @returns
|
|
147
|
+
* @param key - The key to check in the cache
|
|
148
|
+
* @returns true if a valid cache entry exists, false otherwise
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* if (Cache.i.has("userProfile")) {
|
|
152
|
+
* // Handle cached data exists
|
|
153
|
+
* }
|
|
154
|
+
* ```
|
|
77
155
|
*/
|
|
78
156
|
has(t) {
|
|
79
157
|
const e = this.cache.get(t);
|
|
80
158
|
return e ? Date.now() > e.expiry ? (this.cache.delete(t), !1) : !0 : !1;
|
|
81
159
|
}
|
|
82
160
|
/**
|
|
83
|
-
*
|
|
161
|
+
* Retrieves a value from the cache if it exists and hasn't expired.
|
|
162
|
+
* Returns null for non-existent or expired entries.
|
|
84
163
|
*
|
|
85
|
-
* @param key The key
|
|
86
|
-
* @returns The cached value
|
|
164
|
+
* @param key - The key of the cached item to retrieve
|
|
165
|
+
* @returns The cached value if valid, null otherwise
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* const userData = Cache.i.get("userProfile");
|
|
169
|
+
* if (userData) {
|
|
170
|
+
* // Use cached data
|
|
171
|
+
* } else {
|
|
172
|
+
* // Handle cache miss
|
|
173
|
+
* }
|
|
174
|
+
* ```
|
|
87
175
|
*/
|
|
88
176
|
get(t) {
|
|
89
177
|
return this.has(t) ? this.cache.get(t).data : null;
|
|
90
178
|
}
|
|
91
179
|
};
|
|
180
|
+
/**
|
|
181
|
+
* The singleton instance of the Cache class.
|
|
182
|
+
*
|
|
183
|
+
* @private
|
|
184
|
+
*/
|
|
92
185
|
o(f, "_instance");
|
|
93
186
|
let g = f;
|
|
94
187
|
function T(s) {
|
|
@@ -109,24 +202,46 @@ async function K(s, t, e) {
|
|
|
109
202
|
}
|
|
110
203
|
class C {
|
|
111
204
|
/**
|
|
112
|
-
*
|
|
205
|
+
* Registers a callback function for a specific route.
|
|
206
|
+
* If a callback already exists for the route, it will be replaced.
|
|
113
207
|
*
|
|
114
|
-
* @param routeName - The name of the route
|
|
115
|
-
* @param callback - The
|
|
208
|
+
* @param routeName - The fully qualified name of the route (e.g., "api.users.list")
|
|
209
|
+
* @param callback - The function to execute when the hook is triggered
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* Hook.subscribe("api.users.create", () => {
|
|
213
|
+
* analytics.trackEvent("User Created");
|
|
214
|
+
* });
|
|
215
|
+
* ```
|
|
116
216
|
*/
|
|
117
217
|
static subscribe(t, e) {
|
|
118
218
|
this._callbacks.set(t, e);
|
|
119
219
|
}
|
|
120
220
|
/**
|
|
121
|
-
*
|
|
221
|
+
* Triggers the callback function associated with a route.
|
|
222
|
+
* If no callback is registered for the route, the call is silently ignored.
|
|
122
223
|
*
|
|
123
|
-
* @param routeName - The name of the route
|
|
224
|
+
* @param routeName - The fully qualified name of the route (e.g., "api.users.list")
|
|
225
|
+
* @example
|
|
226
|
+
* ```typescript
|
|
227
|
+
* // This will trigger the callback if one is registered
|
|
228
|
+
* Hook.run("api.users.create");
|
|
229
|
+
*
|
|
230
|
+
* // This will do nothing if no callback is registered
|
|
231
|
+
* Hook.run("nonexistent.route");
|
|
232
|
+
* ```
|
|
124
233
|
*/
|
|
125
234
|
static run(t) {
|
|
126
235
|
const e = this._callbacks.get(t);
|
|
127
236
|
e && e();
|
|
128
237
|
}
|
|
129
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* Internal storage for hook callbacks.
|
|
241
|
+
* Maps route names to their corresponding callback functions.
|
|
242
|
+
*
|
|
243
|
+
* @private
|
|
244
|
+
*/
|
|
130
245
|
o(C, "_callbacks", /* @__PURE__ */ new Map());
|
|
131
246
|
const m = {};
|
|
132
247
|
async function N(s, t, e = {}, a = {}) {
|
|
@@ -200,13 +315,37 @@ function U({ route: s, api: t, response: e, data: a }) {
|
|
|
200
315
|
};
|
|
201
316
|
}
|
|
202
317
|
const l = class l {
|
|
318
|
+
/** @private */
|
|
203
319
|
constructor() {
|
|
320
|
+
/**
|
|
321
|
+
* Map storing all registered elements keyed by their full path.
|
|
322
|
+
*
|
|
323
|
+
* @private
|
|
324
|
+
*/
|
|
204
325
|
o(this, "_elements", /* @__PURE__ */ new Map());
|
|
326
|
+
/**
|
|
327
|
+
* Reference to the currently active parent element during registration.
|
|
328
|
+
*
|
|
329
|
+
* @private
|
|
330
|
+
*/
|
|
205
331
|
o(this, "_currentParent", null);
|
|
206
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* Gets the singleton instance of the Registry.
|
|
335
|
+
* Creates the instance if it doesn't exist.
|
|
336
|
+
*
|
|
337
|
+
* @returns The singleton Registry instance
|
|
338
|
+
*/
|
|
207
339
|
static get i() {
|
|
208
340
|
return l._instance || (l._instance = new l()), l._instance;
|
|
209
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* Registers an element (API, Group, or Route) in the registry.
|
|
344
|
+
* Sets up parent-child relationships and updates the Klaim object structure.
|
|
345
|
+
*
|
|
346
|
+
* @param element - The element to register
|
|
347
|
+
* @throws Error if registration fails
|
|
348
|
+
*/
|
|
210
349
|
registerElement(t) {
|
|
211
350
|
const e = this._currentParent;
|
|
212
351
|
e && (t.parent = this.getFullPath(e));
|
|
@@ -216,18 +355,42 @@ const l = class l {
|
|
|
216
355
|
e && (r = this.getOrCreateKlaimBranch(e)), r[t.name] = {};
|
|
217
356
|
}
|
|
218
357
|
}
|
|
358
|
+
/**
|
|
359
|
+
* Gets the currently active parent element.
|
|
360
|
+
* Used during element registration to establish hierarchy.
|
|
361
|
+
*
|
|
362
|
+
* @returns The current parent element or null if none is set
|
|
363
|
+
*/
|
|
219
364
|
getCurrentParent() {
|
|
220
365
|
return this._currentParent;
|
|
221
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Sets the current parent element by its full path.
|
|
369
|
+
* Used to establish context for registering child elements.
|
|
370
|
+
*
|
|
371
|
+
* @param fullPath - Full path to the parent element
|
|
372
|
+
* @throws Error if the specified element doesn't exist or isn't a valid parent type
|
|
373
|
+
*/
|
|
222
374
|
setCurrentParent(t) {
|
|
223
375
|
const e = this._elements.get(t);
|
|
224
376
|
if (!e || e.type !== "api" && e.type !== "group")
|
|
225
377
|
throw new Error(`Element ${t} not found or not a valid parent type`);
|
|
226
378
|
this._currentParent = e;
|
|
227
379
|
}
|
|
380
|
+
/**
|
|
381
|
+
* Clears the current parent reference.
|
|
382
|
+
* Called after finishing registration of child elements.
|
|
383
|
+
*/
|
|
228
384
|
clearCurrentParent() {
|
|
229
385
|
this._currentParent = null;
|
|
230
386
|
}
|
|
387
|
+
/**
|
|
388
|
+
* Registers a route element under the current parent.
|
|
389
|
+
* Sets up the route in the Klaim object hierarchy.
|
|
390
|
+
*
|
|
391
|
+
* @param element - The route element to register
|
|
392
|
+
* @throws Error if no current parent is set or if registration fails
|
|
393
|
+
*/
|
|
231
394
|
registerRoute(t) {
|
|
232
395
|
if (!this._currentParent)
|
|
233
396
|
throw new Error("No current parent set, use Route only inside Api or Group create callback");
|
|
@@ -238,6 +401,13 @@ const l = class l {
|
|
|
238
401
|
const a = this.getElementKey(t);
|
|
239
402
|
this._elements.set(a, t), this.addToKlaimRoute(t);
|
|
240
403
|
}
|
|
404
|
+
/**
|
|
405
|
+
* Gets or creates a branch in the Klaim object hierarchy.
|
|
406
|
+
*
|
|
407
|
+
* @param parent - The parent element whose branch to get/create
|
|
408
|
+
* @returns The branch object in the Klaim hierarchy
|
|
409
|
+
* @private
|
|
410
|
+
*/
|
|
241
411
|
getOrCreateKlaimBranch(t) {
|
|
242
412
|
let e = m;
|
|
243
413
|
const r = this.getFullPath(t).split(".");
|
|
@@ -245,6 +415,13 @@ const l = class l {
|
|
|
245
415
|
e[n] || (e[n] = {}), e = e[n];
|
|
246
416
|
return e;
|
|
247
417
|
}
|
|
418
|
+
/**
|
|
419
|
+
* Adds a route to the Klaim object hierarchy.
|
|
420
|
+
* Creates the necessary function wrapper for API calls.
|
|
421
|
+
*
|
|
422
|
+
* @param route - The route element to add
|
|
423
|
+
* @private
|
|
424
|
+
*/
|
|
248
425
|
addToKlaimRoute(t) {
|
|
249
426
|
if (!t.parent) return;
|
|
250
427
|
const e = t.parent.split(".");
|
|
@@ -255,9 +432,23 @@ const l = class l {
|
|
|
255
432
|
return N(t.parent, t, n, c);
|
|
256
433
|
};
|
|
257
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* Gets the registry key for an element.
|
|
437
|
+
* The key is the full path of the element in dot notation.
|
|
438
|
+
*
|
|
439
|
+
* @param element - The element to get the key for
|
|
440
|
+
* @returns The element's registry key
|
|
441
|
+
*/
|
|
258
442
|
getElementKey(t) {
|
|
259
443
|
return t ? t.parent ? `${t.parent}.${t.name}` : t.name : "";
|
|
260
444
|
}
|
|
445
|
+
/**
|
|
446
|
+
* Gets the full path for an element.
|
|
447
|
+
* Builds the path by traversing the parent hierarchy.
|
|
448
|
+
*
|
|
449
|
+
* @param element - The element to get the path for
|
|
450
|
+
* @returns The full path in dot notation
|
|
451
|
+
*/
|
|
261
452
|
getFullPath(t) {
|
|
262
453
|
if (!t) return "";
|
|
263
454
|
if (!t.parent) return t.name;
|
|
@@ -270,23 +461,56 @@ const l = class l {
|
|
|
270
461
|
}
|
|
271
462
|
return e.join(".");
|
|
272
463
|
}
|
|
464
|
+
/**
|
|
465
|
+
* Gets a route element by API and route names.
|
|
466
|
+
*
|
|
467
|
+
* @param apiName - Name of the API containing the route
|
|
468
|
+
* @param routeName - Name of the route to retrieve
|
|
469
|
+
* @returns The route element or undefined if not found
|
|
470
|
+
*/
|
|
273
471
|
getRoute(t, e) {
|
|
274
472
|
return this._elements.get(`${t}.${e}`);
|
|
275
473
|
}
|
|
474
|
+
/**
|
|
475
|
+
* Gets all child elements for a given parent path.
|
|
476
|
+
*
|
|
477
|
+
* @param elementPath - Full path of the parent element
|
|
478
|
+
* @returns Array of child elements
|
|
479
|
+
*/
|
|
276
480
|
getChildren(t) {
|
|
277
481
|
const e = [];
|
|
278
482
|
return this._elements.forEach((a) => {
|
|
279
483
|
a.parent === t && e.push(a);
|
|
280
484
|
}), e;
|
|
281
485
|
}
|
|
486
|
+
/**
|
|
487
|
+
* Updates an element in the registry.
|
|
488
|
+
*
|
|
489
|
+
* @param element - The element to update
|
|
490
|
+
* @returns The updated element or the original if not found
|
|
491
|
+
*/
|
|
282
492
|
static updateElement(t) {
|
|
283
493
|
return l.i._elements.get(l.i.getElementKey(t)) || t;
|
|
284
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
* Gets an API element by name.
|
|
497
|
+
*
|
|
498
|
+
* @param name - Name of the API to retrieve
|
|
499
|
+
* @returns The API element or undefined if not found
|
|
500
|
+
*/
|
|
285
501
|
getApi(t) {
|
|
286
502
|
const e = this._elements.get(t);
|
|
287
503
|
if (e)
|
|
288
504
|
return e.type === "api" ? e : this.findApi(e);
|
|
289
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* Finds the parent API element for a given element.
|
|
508
|
+
* Traverses up the parent hierarchy until an API element is found.
|
|
509
|
+
*
|
|
510
|
+
* @param element - The element to find the API for
|
|
511
|
+
* @returns The parent API element or undefined if not found
|
|
512
|
+
* @private
|
|
513
|
+
*/
|
|
290
514
|
findApi(t) {
|
|
291
515
|
if (!t || !t.parent) return;
|
|
292
516
|
const e = t.parent.split(".");
|
|
@@ -296,50 +520,171 @@ const l = class l {
|
|
|
296
520
|
}
|
|
297
521
|
}
|
|
298
522
|
};
|
|
523
|
+
/** Singleton instance of the Registry */
|
|
299
524
|
o(l, "_instance");
|
|
300
525
|
let i = l;
|
|
301
526
|
class b extends y {
|
|
527
|
+
/**
|
|
528
|
+
* Creates a new API instance and registers it in the global Registry.
|
|
529
|
+
*
|
|
530
|
+
* @param name - The name of the API. Will be converted to camelCase if necessary
|
|
531
|
+
* @param url - The base URL for the API
|
|
532
|
+
* @param callback - Configuration callback where routes and other settings are defined
|
|
533
|
+
* @param headers - Optional headers to be included with all requests to this API
|
|
534
|
+
* @returns The created API instance
|
|
535
|
+
* @throws Error if the API registration fails
|
|
536
|
+
* @example
|
|
537
|
+
* ```typescript
|
|
538
|
+
* Api.create("userApi", "https://api.users.com", () => {
|
|
539
|
+
* Route.get("getUser", "/users/[id]");
|
|
540
|
+
* }, { "API-Key": "secret" });
|
|
541
|
+
* ```
|
|
542
|
+
*/
|
|
302
543
|
static create(t, e, a, r = {}) {
|
|
303
544
|
const n = P(t);
|
|
304
545
|
n !== t && console.warn(`API name "${t}" has been camelCased to "${n}"`);
|
|
305
546
|
const c = new b(n, e, r);
|
|
306
547
|
return i.i.registerElement(c), i.i.setCurrentParent(n), a(), i.i.clearCurrentParent(), c;
|
|
307
548
|
}
|
|
549
|
+
/**
|
|
550
|
+
* Creates a new Api instance.
|
|
551
|
+
* Private constructor to ensure APIs are only created through the static create method.
|
|
552
|
+
*
|
|
553
|
+
* @param name - The camelCased name of the API
|
|
554
|
+
* @param url - The base URL for the API
|
|
555
|
+
* @param headers - Optional headers to be included with all requests to this API
|
|
556
|
+
*/
|
|
308
557
|
constructor(t, e, a = {}) {
|
|
309
558
|
super("api", t, e, a);
|
|
310
559
|
}
|
|
311
560
|
}
|
|
312
561
|
class E extends y {
|
|
562
|
+
/**
|
|
563
|
+
* Creates a new group and registers it in the Registry.
|
|
564
|
+
* Supports nested groups and inheritable configurations.
|
|
565
|
+
*
|
|
566
|
+
* @param name - Name of the group (will be converted to camelCase)
|
|
567
|
+
* @param callback - Configuration callback for defining routes and nested groups
|
|
568
|
+
* @returns The created group instance
|
|
569
|
+
* @throws Error if group creation fails or parent context is invalid
|
|
570
|
+
* @example
|
|
571
|
+
* ```typescript
|
|
572
|
+
* Group.create("admin", () => {
|
|
573
|
+
* Group.create("users", () => {
|
|
574
|
+
* Route.get("list", "/admin/users");
|
|
575
|
+
* });
|
|
576
|
+
* }).before(authMiddleware);
|
|
577
|
+
* ```
|
|
578
|
+
*/
|
|
313
579
|
static create(t, e) {
|
|
314
580
|
const a = P(t), r = i.i.getCurrentParent(), n = r ? i.i.getFullPath(r) : "", c = n ? `${n}.${a}` : a, u = new E(a, "");
|
|
315
581
|
a !== t && console.warn(`Group name "${t}" has been camelCased to "${a}"`), i.i.registerElement(u);
|
|
316
582
|
const h = i.i.getCurrentParent();
|
|
317
583
|
return i.i.setCurrentParent(c), e(), h ? i.i.setCurrentParent(i.i.getFullPath(h)) : i.i.clearCurrentParent(), u;
|
|
318
584
|
}
|
|
585
|
+
/**
|
|
586
|
+
* Creates a new Group instance.
|
|
587
|
+
* Private constructor to ensure groups are only created through the static create method.
|
|
588
|
+
*
|
|
589
|
+
* @param name - The camelCased name of the group
|
|
590
|
+
* @param url - Base URL for the group (usually empty)
|
|
591
|
+
* @param headers - Optional headers shared by all routes in the group
|
|
592
|
+
* @private
|
|
593
|
+
*/
|
|
319
594
|
constructor(t, e, a = {}) {
|
|
320
595
|
super("group", t, e, a);
|
|
321
596
|
}
|
|
322
|
-
|
|
597
|
+
/**
|
|
598
|
+
* Enables caching for the group and all its child routes.
|
|
599
|
+
* Child routes can override the cache duration with their own settings.
|
|
600
|
+
*
|
|
601
|
+
* @param duration - Cache duration in seconds (default: 20)
|
|
602
|
+
* @returns this group instance for chaining
|
|
603
|
+
* @example
|
|
604
|
+
* ```typescript
|
|
605
|
+
* Group.create("users", () => {
|
|
606
|
+
* Route.get("list", "/users");
|
|
607
|
+
* }).withCache(300); // Cache all routes for 5 minutes
|
|
608
|
+
* ```
|
|
609
|
+
*/
|
|
323
610
|
withCache(t = 20) {
|
|
324
611
|
return super.withCache(t), i.i.getChildren(i.i.getFullPath(this)).forEach((e) => {
|
|
325
612
|
e.cache || (e.cache = t);
|
|
326
613
|
}), this;
|
|
327
614
|
}
|
|
615
|
+
/**
|
|
616
|
+
* Enables retry mechanism for the group and all its child routes.
|
|
617
|
+
* Child routes can override the retry count with their own settings.
|
|
618
|
+
*
|
|
619
|
+
* @param maxRetries - Maximum number of retry attempts (default: 2)
|
|
620
|
+
* @returns this group instance for chaining
|
|
621
|
+
* @example
|
|
622
|
+
* ```typescript
|
|
623
|
+
* Group.create("users", () => {
|
|
624
|
+
* Route.get("list", "/users");
|
|
625
|
+
* }).withRetry(3); // Retry failed requests up to 3 times
|
|
626
|
+
* ```
|
|
627
|
+
*/
|
|
328
628
|
withRetry(t = 2) {
|
|
329
629
|
return super.withRetry(t), i.i.getChildren(i.i.getFullPath(this)).forEach((e) => {
|
|
330
630
|
e.retry || (e.retry = t);
|
|
331
631
|
}), this;
|
|
332
632
|
}
|
|
633
|
+
/**
|
|
634
|
+
* Adds a before-request middleware to the group and all its child routes.
|
|
635
|
+
* Child routes can override this middleware with their own.
|
|
636
|
+
*
|
|
637
|
+
* @param callback - Middleware function to execute before requests
|
|
638
|
+
* @returns this group instance for chaining
|
|
639
|
+
* @example
|
|
640
|
+
* ```typescript
|
|
641
|
+
* Group.create("admin", () => {
|
|
642
|
+
* Route.get("stats", "/admin/stats");
|
|
643
|
+
* }).before(({ config }) => {
|
|
644
|
+
* config.headers.Authorization = getAdminToken();
|
|
645
|
+
* });
|
|
646
|
+
* ```
|
|
647
|
+
*/
|
|
333
648
|
before(t) {
|
|
334
649
|
return super.before(t), i.i.getChildren(i.i.getFullPath(this)).forEach((e) => {
|
|
335
650
|
e.callbacks.before || (e.callbacks.before = t);
|
|
336
651
|
}), this;
|
|
337
652
|
}
|
|
653
|
+
/**
|
|
654
|
+
* Adds an after-request middleware to the group and all its child routes.
|
|
655
|
+
* Child routes can override this middleware with their own.
|
|
656
|
+
*
|
|
657
|
+
* @param callback - Middleware function to execute after requests
|
|
658
|
+
* @returns this group instance for chaining
|
|
659
|
+
* @example
|
|
660
|
+
* ```typescript
|
|
661
|
+
* Group.create("users", () => {
|
|
662
|
+
* Route.get("list", "/users");
|
|
663
|
+
* }).after(({ data }) => {
|
|
664
|
+
* console.log(`Fetched ${data.length} users`);
|
|
665
|
+
* });
|
|
666
|
+
* ```
|
|
667
|
+
*/
|
|
338
668
|
after(t) {
|
|
339
669
|
return super.after(t), i.i.getChildren(i.i.getFullPath(this)).forEach((e) => {
|
|
340
670
|
e.callbacks.after || (e.callbacks.after = t);
|
|
341
671
|
}), this;
|
|
342
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Adds a request lifecycle middleware to the group and all its child routes.
|
|
675
|
+
* Child routes can override this middleware with their own.
|
|
676
|
+
*
|
|
677
|
+
* @param callback - Middleware function to execute during requests
|
|
678
|
+
* @returns this group instance for chaining
|
|
679
|
+
* @example
|
|
680
|
+
* ```typescript
|
|
681
|
+
* Group.create("api", () => {
|
|
682
|
+
* Route.get("status", "/status");
|
|
683
|
+
* }).onCall(() => {
|
|
684
|
+
* metrics.incrementApiCalls();
|
|
685
|
+
* });
|
|
686
|
+
* ```
|
|
687
|
+
*/
|
|
343
688
|
onCall(t) {
|
|
344
689
|
return super.onCall(t), i.i.getChildren(i.i.getFullPath(this)).forEach((e) => {
|
|
345
690
|
e.callbacks.call || (e.callbacks.call = t);
|
|
@@ -347,13 +692,44 @@ class E extends y {
|
|
|
347
692
|
}
|
|
348
693
|
}
|
|
349
694
|
class $ extends y {
|
|
695
|
+
/**
|
|
696
|
+
* Creates a new Route instance.
|
|
697
|
+
*
|
|
698
|
+
* @param name - Unique name for the route
|
|
699
|
+
* @param url - URL path for the route, can include parameters in [param] format
|
|
700
|
+
* @param headers - Optional HTTP headers specific to this route
|
|
701
|
+
* @param method - HTTP method for this route
|
|
702
|
+
*/
|
|
350
703
|
constructor(t, e, a = {}, r = "GET") {
|
|
351
704
|
super("route", t, e, a), this.method = r, this.detectArguments();
|
|
352
705
|
}
|
|
706
|
+
/**
|
|
707
|
+
* Internal helper to create and register a new route.
|
|
708
|
+
*
|
|
709
|
+
* @param name - Route name
|
|
710
|
+
* @param url - Route URL path
|
|
711
|
+
* @param headers - Route-specific headers
|
|
712
|
+
* @param method - HTTP method
|
|
713
|
+
* @returns The created route element
|
|
714
|
+
* @private
|
|
715
|
+
*/
|
|
353
716
|
static createRoute(t, e, a = {}, r) {
|
|
354
717
|
const n = new $(t, e, a, r);
|
|
355
718
|
return i.i.registerRoute(n), n;
|
|
356
719
|
}
|
|
720
|
+
/**
|
|
721
|
+
* Creates a GET route.
|
|
722
|
+
*
|
|
723
|
+
* @param name - Route name
|
|
724
|
+
* @param url - Route URL path
|
|
725
|
+
* @param headers - Route-specific headers
|
|
726
|
+
* @returns The created GET route
|
|
727
|
+
* @example
|
|
728
|
+
* ```typescript
|
|
729
|
+
* Route.get("listUsers", "/users");
|
|
730
|
+
* Route.get("getUser", "/users/[id]");
|
|
731
|
+
* ```
|
|
732
|
+
*/
|
|
357
733
|
static get(t, e, a = {}) {
|
|
358
734
|
return this.createRoute(
|
|
359
735
|
t,
|
|
@@ -363,6 +739,18 @@ class $ extends y {
|
|
|
363
739
|
/* GET */
|
|
364
740
|
);
|
|
365
741
|
}
|
|
742
|
+
/**
|
|
743
|
+
* Creates a POST route.
|
|
744
|
+
*
|
|
745
|
+
* @param name - Route name
|
|
746
|
+
* @param url - Route URL path
|
|
747
|
+
* @param headers - Route-specific headers
|
|
748
|
+
* @returns The created POST route
|
|
749
|
+
* @example
|
|
750
|
+
* ```typescript
|
|
751
|
+
* Route.post("createUser", "/users");
|
|
752
|
+
* ```
|
|
753
|
+
*/
|
|
366
754
|
static post(t, e, a = {}) {
|
|
367
755
|
return this.createRoute(
|
|
368
756
|
t,
|
|
@@ -372,6 +760,18 @@ class $ extends y {
|
|
|
372
760
|
/* POST */
|
|
373
761
|
);
|
|
374
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* Creates a PUT route.
|
|
765
|
+
*
|
|
766
|
+
* @param name - Route name
|
|
767
|
+
* @param url - Route URL path
|
|
768
|
+
* @param headers - Route-specific headers
|
|
769
|
+
* @returns The created PUT route
|
|
770
|
+
* @example
|
|
771
|
+
* ```typescript
|
|
772
|
+
* Route.put("updateUser", "/users/[id]");
|
|
773
|
+
* ```
|
|
774
|
+
*/
|
|
375
775
|
static put(t, e, a = {}) {
|
|
376
776
|
return this.createRoute(
|
|
377
777
|
t,
|
|
@@ -381,6 +781,18 @@ class $ extends y {
|
|
|
381
781
|
/* PUT */
|
|
382
782
|
);
|
|
383
783
|
}
|
|
784
|
+
/**
|
|
785
|
+
* Creates a DELETE route.
|
|
786
|
+
*
|
|
787
|
+
* @param name - Route name
|
|
788
|
+
* @param url - Route URL path
|
|
789
|
+
* @param headers - Route-specific headers
|
|
790
|
+
* @returns The created DELETE route
|
|
791
|
+
* @example
|
|
792
|
+
* ```typescript
|
|
793
|
+
* Route.delete("deleteUser", "/users/[id]");
|
|
794
|
+
* ```
|
|
795
|
+
*/
|
|
384
796
|
static delete(t, e, a = {}) {
|
|
385
797
|
return this.createRoute(
|
|
386
798
|
t,
|
|
@@ -390,6 +802,18 @@ class $ extends y {
|
|
|
390
802
|
/* DELETE */
|
|
391
803
|
);
|
|
392
804
|
}
|
|
805
|
+
/**
|
|
806
|
+
* Creates a PATCH route.
|
|
807
|
+
*
|
|
808
|
+
* @param name - Route name
|
|
809
|
+
* @param url - Route URL path
|
|
810
|
+
* @param headers - Route-specific headers
|
|
811
|
+
* @returns The created PATCH route
|
|
812
|
+
* @example
|
|
813
|
+
* ```typescript
|
|
814
|
+
* Route.patch("updateUserStatus", "/users/[id]/status");
|
|
815
|
+
* ```
|
|
816
|
+
*/
|
|
393
817
|
static patch(t, e, a = {}) {
|
|
394
818
|
return this.createRoute(
|
|
395
819
|
t,
|
|
@@ -399,6 +823,18 @@ class $ extends y {
|
|
|
399
823
|
/* PATCH */
|
|
400
824
|
);
|
|
401
825
|
}
|
|
826
|
+
/**
|
|
827
|
+
* Creates an OPTIONS route.
|
|
828
|
+
*
|
|
829
|
+
* @param name - Route name
|
|
830
|
+
* @param url - Route URL path
|
|
831
|
+
* @param headers - Route-specific headers
|
|
832
|
+
* @returns The created OPTIONS route
|
|
833
|
+
* @example
|
|
834
|
+
* ```typescript
|
|
835
|
+
* Route.options("userOptions", "/users");
|
|
836
|
+
* ```
|
|
837
|
+
*/
|
|
402
838
|
static options(t, e, a = {}) {
|
|
403
839
|
return this.createRoute(
|
|
404
840
|
t,
|
|
@@ -408,6 +844,13 @@ class $ extends y {
|
|
|
408
844
|
/* OPTIONS */
|
|
409
845
|
);
|
|
410
846
|
}
|
|
847
|
+
/**
|
|
848
|
+
* Detects URL parameters in the route path.
|
|
849
|
+
* Parameters are defined using square brackets, e.g., [id] in /users/[id].
|
|
850
|
+
* Detected parameters are stored in the arguments Set.
|
|
851
|
+
*
|
|
852
|
+
* @private
|
|
853
|
+
*/
|
|
411
854
|
detectArguments() {
|
|
412
855
|
const t = this.url.match(/\[([^\]]+)]/g);
|
|
413
856
|
t && t.forEach((e) => {
|
|
@@ -415,6 +858,17 @@ class $ extends y {
|
|
|
415
858
|
this.arguments.add(a);
|
|
416
859
|
});
|
|
417
860
|
}
|
|
861
|
+
/**
|
|
862
|
+
* Sets up response validation using a schema.
|
|
863
|
+
*
|
|
864
|
+
* @param schema - Validation schema (e.g., Yup schema)
|
|
865
|
+
* @returns This route instance for chaining
|
|
866
|
+
* @example
|
|
867
|
+
* ```typescript
|
|
868
|
+
* Route.get("getUser", "/users/[id]")
|
|
869
|
+
* .validate(userSchema);
|
|
870
|
+
* ```
|
|
871
|
+
*/
|
|
418
872
|
validate(t) {
|
|
419
873
|
return this.schema = t, this;
|
|
420
874
|
}
|