klaim 1.6.0 → 1.6.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/Makefile +39 -14
- package/README.md +262 -262
- package/deno.json +38 -38
- package/package.json +10 -10
- package/src/core/Cache.ts +72 -72
- package/src/core/Element.ts +150 -150
- package/src/core/Klaim.ts +222 -222
- package/src/core/Route.ts +165 -165
- package/src/tools/fetchWithCache.ts +30 -30
- package/tests/01.api.test.ts +60 -60
- package/tests/02.route.test.ts +186 -186
- package/tests/03.hook.test.ts +34 -34
- package/tests/04.klaim.test.ts +96 -96
- package/tests/05.cache.test.ts +46 -46
- package/tests/06.retry.test.ts +54 -54
- package/tests/07.validate.test.ts +61 -61
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "klaim",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
4
4
|
"author": "antharuu",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,22 +9,22 @@
|
|
|
9
9
|
"main": "dist/klaim.cjs.js",
|
|
10
10
|
"module": "dist/klaim.es.js",
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@eslint/js": "^9.
|
|
12
|
+
"@eslint/js": "^9.7.0",
|
|
13
13
|
"@stylistic/eslint-plugin": "^2.3.0",
|
|
14
14
|
"@types/bun": "latest",
|
|
15
15
|
"@types/eslint__js": "^8.42.3",
|
|
16
|
-
"@types/node": "^20.14.
|
|
17
|
-
"@vitest/coverage-v8": "^
|
|
18
|
-
"@vitest/ui": "^
|
|
16
|
+
"@types/node": "^20.14.10",
|
|
17
|
+
"@vitest/coverage-v8": "^2.0.2",
|
|
18
|
+
"@vitest/ui": "^2.0.2",
|
|
19
19
|
"dotenv-cli": "^7.4.2",
|
|
20
|
-
"eslint": "^9.
|
|
21
|
-
"eslint-plugin-jsdoc": "^48.
|
|
20
|
+
"eslint": "^9.7.0",
|
|
21
|
+
"eslint-plugin-jsdoc": "^48.7.0",
|
|
22
22
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
23
23
|
"jsdom": "^24.1.0",
|
|
24
|
-
"release-it": "^17.
|
|
25
|
-
"typescript-eslint": "^7.
|
|
24
|
+
"release-it": "^17.5.0",
|
|
25
|
+
"typescript-eslint": "^7.16.0",
|
|
26
26
|
"vite": "^5.3.3",
|
|
27
|
-
"vitest": "^
|
|
27
|
+
"vitest": "^2.0.2",
|
|
28
28
|
"yup": "^1.4.0"
|
|
29
29
|
},
|
|
30
30
|
"bugs": {
|
package/src/core/Cache.ts
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A simple cache implementation that stores key-value pairs with a time-to-live (TTL) in milliseconds.
|
|
3
|
-
*/
|
|
4
|
-
export class Cache {
|
|
5
|
-
private static _instance: Cache;
|
|
6
|
-
|
|
7
|
-
private cache: Map<string, { data: any; expiry: number }>;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Private constructor to prevent instantiation from outside the class.
|
|
11
|
-
*/
|
|
12
|
-
private constructor () {
|
|
13
|
-
this.cache = new Map();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Provides access to the singleton instance of the class.
|
|
18
|
-
*
|
|
19
|
-
* @returns The singleton instance of Cache.
|
|
20
|
-
*/
|
|
21
|
-
public static get i (): Cache {
|
|
22
|
-
if (!Cache._instance) {
|
|
23
|
-
Cache._instance = new Cache();
|
|
24
|
-
}
|
|
25
|
-
return Cache._instance;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Sets the cache for a specific key.
|
|
30
|
-
*
|
|
31
|
-
* @param key The key to cache the value under.
|
|
32
|
-
* @param value The value to be cached.
|
|
33
|
-
* @param ttl Time to live in milliseconds.
|
|
34
|
-
*/
|
|
35
|
-
public set (key: string, value: any, ttl: number = 0): void {
|
|
36
|
-
const expiry = Date.now() + ttl;
|
|
37
|
-
this.cache.set(key, { data: value, expiry });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Checks if the cache has a valid entry for the given key.
|
|
42
|
-
*
|
|
43
|
-
* @param key The key to check in the cache.
|
|
44
|
-
* @returns True if a valid cache entry exists, otherwise false.
|
|
45
|
-
*/
|
|
46
|
-
public has (key: string): boolean {
|
|
47
|
-
const cacheEntry = this.cache.get(key);
|
|
48
|
-
if (!cacheEntry) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (Date.now() > cacheEntry.expiry) {
|
|
53
|
-
this.cache.delete(key);
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Gets the cached value for the given key.
|
|
62
|
-
*
|
|
63
|
-
* @param key The key to retrieve from the cache.
|
|
64
|
-
* @returns The cached value or null if not found or expired.
|
|
65
|
-
*/
|
|
66
|
-
public get (key: string): any | null {
|
|
67
|
-
if (this.has(key)) {
|
|
68
|
-
return this.cache.get(key)!.data;
|
|
69
|
-
}
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* A simple cache implementation that stores key-value pairs with a time-to-live (TTL) in milliseconds.
|
|
3
|
+
*/
|
|
4
|
+
export class Cache {
|
|
5
|
+
private static _instance: Cache;
|
|
6
|
+
|
|
7
|
+
private cache: Map<string, { data: any; expiry: number }>;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Private constructor to prevent instantiation from outside the class.
|
|
11
|
+
*/
|
|
12
|
+
private constructor () {
|
|
13
|
+
this.cache = new Map();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Provides access to the singleton instance of the class.
|
|
18
|
+
*
|
|
19
|
+
* @returns The singleton instance of Cache.
|
|
20
|
+
*/
|
|
21
|
+
public static get i (): Cache {
|
|
22
|
+
if (!Cache._instance) {
|
|
23
|
+
Cache._instance = new Cache();
|
|
24
|
+
}
|
|
25
|
+
return Cache._instance;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Sets the cache for a specific key.
|
|
30
|
+
*
|
|
31
|
+
* @param key The key to cache the value under.
|
|
32
|
+
* @param value The value to be cached.
|
|
33
|
+
* @param ttl Time to live in milliseconds.
|
|
34
|
+
*/
|
|
35
|
+
public set (key: string, value: any, ttl: number = 0): void {
|
|
36
|
+
const expiry = Date.now() + ttl;
|
|
37
|
+
this.cache.set(key, { data: value, expiry });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Checks if the cache has a valid entry for the given key.
|
|
42
|
+
*
|
|
43
|
+
* @param key The key to check in the cache.
|
|
44
|
+
* @returns True if a valid cache entry exists, otherwise false.
|
|
45
|
+
*/
|
|
46
|
+
public has (key: string): boolean {
|
|
47
|
+
const cacheEntry = this.cache.get(key);
|
|
48
|
+
if (!cacheEntry) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (Date.now() > cacheEntry.expiry) {
|
|
53
|
+
this.cache.delete(key);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Gets the cached value for the given key.
|
|
62
|
+
*
|
|
63
|
+
* @param key The key to retrieve from the cache.
|
|
64
|
+
* @returns The cached value or null if not found or expired.
|
|
65
|
+
*/
|
|
66
|
+
public get (key: string): any | null {
|
|
67
|
+
if (this.has(key)) {
|
|
68
|
+
return this.cache.get(key)!.data;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/core/Element.ts
CHANGED
|
@@ -1,150 +1,150 @@
|
|
|
1
|
-
import cleanUrl from "../tools/cleanUrl";
|
|
2
|
-
import toCamelCase from "../tools/toCamelCase";
|
|
3
|
-
|
|
4
|
-
import { Api } from "./Api";
|
|
5
|
-
import { Route } from "./Route";
|
|
6
|
-
|
|
7
|
-
export type IHeaders = Record<string, string>;
|
|
8
|
-
|
|
9
|
-
export interface ICallbackBeforeArgs {
|
|
10
|
-
route: Route;
|
|
11
|
-
api: Api;
|
|
12
|
-
url: string;
|
|
13
|
-
config: Record<string, unknown>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface ICallbackAfterArgs {
|
|
17
|
-
route: Route;
|
|
18
|
-
api: Api;
|
|
19
|
-
response: Response;
|
|
20
|
-
data: any;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface ICallbackCallArgs {
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export type ICallback<ArgsType> = (args: ArgsType) => Partial<ArgsType> | void;
|
|
27
|
-
|
|
28
|
-
interface IElementCallbacks {
|
|
29
|
-
before: (ICallback<ICallbackBeforeArgs>) | null;
|
|
30
|
-
after: (ICallback<ICallbackAfterArgs>) | null;
|
|
31
|
-
call: (ICallback<ICallbackCallArgs>) | null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface IElement {
|
|
35
|
-
name: string;
|
|
36
|
-
url: string;
|
|
37
|
-
headers: IHeaders;
|
|
38
|
-
callbacks: IElementCallbacks;
|
|
39
|
-
cache: false | number;
|
|
40
|
-
retry: false | number;
|
|
41
|
-
|
|
42
|
-
before: (callback: ICallback<ICallbackBeforeArgs>) => this;
|
|
43
|
-
after: (callback: ICallback<ICallbackAfterArgs>) => this;
|
|
44
|
-
onCall: (callback: ICallback<ICallbackCallArgs>) => this;
|
|
45
|
-
|
|
46
|
-
withCache: (duration?: number) => this;
|
|
47
|
-
withRetry: (maxRetries?: number) => this;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Represents an element (API or Route)
|
|
52
|
-
*/
|
|
53
|
-
export abstract class Element implements IElement {
|
|
54
|
-
public name: string;
|
|
55
|
-
|
|
56
|
-
public url: string;
|
|
57
|
-
|
|
58
|
-
public headers: IHeaders;
|
|
59
|
-
|
|
60
|
-
public callbacks: IElementCallbacks = {
|
|
61
|
-
/**
|
|
62
|
-
* Called before the request is sent
|
|
63
|
-
*/
|
|
64
|
-
before: null,
|
|
65
|
-
/**
|
|
66
|
-
* Called after the request is sent and before the data is returned
|
|
67
|
-
*/
|
|
68
|
-
after: null,
|
|
69
|
-
/**
|
|
70
|
-
* Called when the route is called (call also includes retries)
|
|
71
|
-
*/
|
|
72
|
-
call: null
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
public cache: false | number = false;
|
|
76
|
-
|
|
77
|
-
public retry: false | number = false;
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Constructor
|
|
81
|
-
*
|
|
82
|
-
* @param name - The name of the element
|
|
83
|
-
* @param url - The base URL of the element
|
|
84
|
-
* @param headers - The headers to be sent with each request
|
|
85
|
-
*/
|
|
86
|
-
protected constructor (name: string, url: string, headers: IHeaders = {}) {
|
|
87
|
-
this.name = toCamelCase(name);
|
|
88
|
-
if (this.name !== name) {
|
|
89
|
-
console.warn(`Name "${name}" has been camelCased to "${this.name}"`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
this.url = cleanUrl(url);
|
|
93
|
-
this.headers = headers || {};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Sets the before callback
|
|
98
|
-
*
|
|
99
|
-
* @param callback - The callback
|
|
100
|
-
* @returns The route
|
|
101
|
-
*/
|
|
102
|
-
public before (callback: ICallback<ICallbackBeforeArgs> | null): this {
|
|
103
|
-
this.callbacks.before = callback;
|
|
104
|
-
return this;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Sets the after callback
|
|
109
|
-
*
|
|
110
|
-
* @param callback - The callback
|
|
111
|
-
* @returns The route
|
|
112
|
-
*/
|
|
113
|
-
public after (callback: ICallback<ICallbackAfterArgs>): this {
|
|
114
|
-
this.callbacks.after = callback;
|
|
115
|
-
return this;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Sets the onCall callback
|
|
120
|
-
*
|
|
121
|
-
* @param callback - The callback
|
|
122
|
-
* @returns The route
|
|
123
|
-
*/
|
|
124
|
-
public onCall (callback: ICallback<ICallbackCallArgs>): this {
|
|
125
|
-
this.callbacks.call = callback;
|
|
126
|
-
return this;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Enables caching for the Route
|
|
131
|
-
*
|
|
132
|
-
* @param duration - The duration to cache the response for seconds (default: 20)
|
|
133
|
-
* @returns The Route
|
|
134
|
-
*/
|
|
135
|
-
public withCache (duration = 20): this {
|
|
136
|
-
this.cache = duration;
|
|
137
|
-
return this;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Enables retry for the Route
|
|
142
|
-
*
|
|
143
|
-
* @param maxRetries - The maximum number of retries (default: 3)
|
|
144
|
-
* @returns The Route
|
|
145
|
-
*/
|
|
146
|
-
public withRetry (maxRetries = 2): this {
|
|
147
|
-
this.retry = maxRetries;
|
|
148
|
-
return this;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
1
|
+
import cleanUrl from "../tools/cleanUrl";
|
|
2
|
+
import toCamelCase from "../tools/toCamelCase";
|
|
3
|
+
|
|
4
|
+
import { Api } from "./Api";
|
|
5
|
+
import { Route } from "./Route";
|
|
6
|
+
|
|
7
|
+
export type IHeaders = Record<string, string>;
|
|
8
|
+
|
|
9
|
+
export interface ICallbackBeforeArgs {
|
|
10
|
+
route: Route;
|
|
11
|
+
api: Api;
|
|
12
|
+
url: string;
|
|
13
|
+
config: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ICallbackAfterArgs {
|
|
17
|
+
route: Route;
|
|
18
|
+
api: Api;
|
|
19
|
+
response: Response;
|
|
20
|
+
data: any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ICallbackCallArgs {
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type ICallback<ArgsType> = (args: ArgsType) => Partial<ArgsType> | void;
|
|
27
|
+
|
|
28
|
+
interface IElementCallbacks {
|
|
29
|
+
before: (ICallback<ICallbackBeforeArgs>) | null;
|
|
30
|
+
after: (ICallback<ICallbackAfterArgs>) | null;
|
|
31
|
+
call: (ICallback<ICallbackCallArgs>) | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface IElement {
|
|
35
|
+
name: string;
|
|
36
|
+
url: string;
|
|
37
|
+
headers: IHeaders;
|
|
38
|
+
callbacks: IElementCallbacks;
|
|
39
|
+
cache: false | number;
|
|
40
|
+
retry: false | number;
|
|
41
|
+
|
|
42
|
+
before: (callback: ICallback<ICallbackBeforeArgs>) => this;
|
|
43
|
+
after: (callback: ICallback<ICallbackAfterArgs>) => this;
|
|
44
|
+
onCall: (callback: ICallback<ICallbackCallArgs>) => this;
|
|
45
|
+
|
|
46
|
+
withCache: (duration?: number) => this;
|
|
47
|
+
withRetry: (maxRetries?: number) => this;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Represents an element (API or Route)
|
|
52
|
+
*/
|
|
53
|
+
export abstract class Element implements IElement {
|
|
54
|
+
public name: string;
|
|
55
|
+
|
|
56
|
+
public url: string;
|
|
57
|
+
|
|
58
|
+
public headers: IHeaders;
|
|
59
|
+
|
|
60
|
+
public callbacks: IElementCallbacks = {
|
|
61
|
+
/**
|
|
62
|
+
* Called before the request is sent
|
|
63
|
+
*/
|
|
64
|
+
before: null,
|
|
65
|
+
/**
|
|
66
|
+
* Called after the request is sent and before the data is returned
|
|
67
|
+
*/
|
|
68
|
+
after: null,
|
|
69
|
+
/**
|
|
70
|
+
* Called when the route is called (call also includes retries)
|
|
71
|
+
*/
|
|
72
|
+
call: null
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
public cache: false | number = false;
|
|
76
|
+
|
|
77
|
+
public retry: false | number = false;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Constructor
|
|
81
|
+
*
|
|
82
|
+
* @param name - The name of the element
|
|
83
|
+
* @param url - The base URL of the element
|
|
84
|
+
* @param headers - The headers to be sent with each request
|
|
85
|
+
*/
|
|
86
|
+
protected constructor (name: string, url: string, headers: IHeaders = {}) {
|
|
87
|
+
this.name = toCamelCase(name);
|
|
88
|
+
if (this.name !== name) {
|
|
89
|
+
console.warn(`Name "${name}" has been camelCased to "${this.name}"`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.url = cleanUrl(url);
|
|
93
|
+
this.headers = headers || {};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Sets the before callback
|
|
98
|
+
*
|
|
99
|
+
* @param callback - The callback
|
|
100
|
+
* @returns The route
|
|
101
|
+
*/
|
|
102
|
+
public before (callback: ICallback<ICallbackBeforeArgs> | null): this {
|
|
103
|
+
this.callbacks.before = callback;
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Sets the after callback
|
|
109
|
+
*
|
|
110
|
+
* @param callback - The callback
|
|
111
|
+
* @returns The route
|
|
112
|
+
*/
|
|
113
|
+
public after (callback: ICallback<ICallbackAfterArgs>): this {
|
|
114
|
+
this.callbacks.after = callback;
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Sets the onCall callback
|
|
120
|
+
*
|
|
121
|
+
* @param callback - The callback
|
|
122
|
+
* @returns The route
|
|
123
|
+
*/
|
|
124
|
+
public onCall (callback: ICallback<ICallbackCallArgs>): this {
|
|
125
|
+
this.callbacks.call = callback;
|
|
126
|
+
return this;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Enables caching for the Route
|
|
131
|
+
*
|
|
132
|
+
* @param duration - The duration to cache the response for seconds (default: 20)
|
|
133
|
+
* @returns The Route
|
|
134
|
+
*/
|
|
135
|
+
public withCache (duration = 20): this {
|
|
136
|
+
this.cache = duration;
|
|
137
|
+
return this;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Enables retry for the Route
|
|
142
|
+
*
|
|
143
|
+
* @param maxRetries - The maximum number of retries (default: 3)
|
|
144
|
+
* @returns The Route
|
|
145
|
+
*/
|
|
146
|
+
public withRetry (maxRetries = 2): this {
|
|
147
|
+
this.retry = maxRetries;
|
|
148
|
+
return this;
|
|
149
|
+
}
|
|
150
|
+
}
|