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/src/core/Route.ts
CHANGED
|
@@ -1,165 +1,165 @@
|
|
|
1
|
-
import { Api } from "./Api";
|
|
2
|
-
import { Element, IHeaders } from "./Element";
|
|
3
|
-
import { Registry } from "./Registry";
|
|
4
|
-
|
|
5
|
-
export enum RouteMethod {
|
|
6
|
-
GET = "GET",
|
|
7
|
-
POST = "POST",
|
|
8
|
-
PUT = "PUT",
|
|
9
|
-
DELETE = "DELETE",
|
|
10
|
-
PATCH = "PATCH",
|
|
11
|
-
OPTIONS = "OPTIONS"
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Represents a route
|
|
16
|
-
*/
|
|
17
|
-
export class Route extends Element {
|
|
18
|
-
public api: Api["name"] = "undefined";
|
|
19
|
-
|
|
20
|
-
public method: RouteMethod;
|
|
21
|
-
|
|
22
|
-
public arguments: Set<string> = new Set<string>();
|
|
23
|
-
|
|
24
|
-
public schema: any;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Constructor
|
|
28
|
-
*
|
|
29
|
-
* @param name - The name of the route
|
|
30
|
-
* @param url - The URL of the route
|
|
31
|
-
* @param headers - The headers to be sent with the request
|
|
32
|
-
* @param method - The HTTP method of the route
|
|
33
|
-
*/
|
|
34
|
-
private constructor (
|
|
35
|
-
name: string,
|
|
36
|
-
url: string,
|
|
37
|
-
headers: IHeaders,
|
|
38
|
-
method: RouteMethod = RouteMethod.GET
|
|
39
|
-
) {
|
|
40
|
-
super(name, url, headers);
|
|
41
|
-
this.method = method;
|
|
42
|
-
|
|
43
|
-
this.detectArguments();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Creates a new route
|
|
48
|
-
*
|
|
49
|
-
* @param name - The name of the route
|
|
50
|
-
* @param url - The URL of the route
|
|
51
|
-
* @param headers - The headers to be sent with the request
|
|
52
|
-
* @param method - The HTTP method of the route
|
|
53
|
-
* @returns The new route
|
|
54
|
-
*/
|
|
55
|
-
private static createRoute (
|
|
56
|
-
name: string,
|
|
57
|
-
url: string,
|
|
58
|
-
headers: IHeaders,
|
|
59
|
-
method: RouteMethod
|
|
60
|
-
): Route {
|
|
61
|
-
const route = new Route(name, url, headers, method);
|
|
62
|
-
Registry.i.registerRoute(route as Route);
|
|
63
|
-
return route;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Creates a new route with the GET method
|
|
68
|
-
*
|
|
69
|
-
* @param name - The name of the route
|
|
70
|
-
* @param url - The URL of the route
|
|
71
|
-
* @param headers - The headers to be sent with the request
|
|
72
|
-
* @returns The new route
|
|
73
|
-
*/
|
|
74
|
-
public static get (
|
|
75
|
-
name: string,
|
|
76
|
-
url: string,
|
|
77
|
-
headers: IHeaders = {}
|
|
78
|
-
): Route {
|
|
79
|
-
return this.createRoute(name, url, headers, RouteMethod.GET);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Creates a new route with the POST method
|
|
84
|
-
*
|
|
85
|
-
* @param name - The name of the route
|
|
86
|
-
* @param url - The URL of the route
|
|
87
|
-
* @param headers - The headers to be sent with the request
|
|
88
|
-
* @returns The new route
|
|
89
|
-
*/
|
|
90
|
-
public static post (name: string, url: string, headers: IHeaders): Route {
|
|
91
|
-
return this.createRoute(name, url, headers, RouteMethod.POST);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Creates a new route with the PUT method
|
|
96
|
-
*
|
|
97
|
-
* @param name - The name of the route
|
|
98
|
-
* @param url - The URL of the route
|
|
99
|
-
* @param headers - The headers to be sent with the request
|
|
100
|
-
* @returns The new route
|
|
101
|
-
*/
|
|
102
|
-
public static put (name: string, url: string, headers: IHeaders): Route {
|
|
103
|
-
return this.createRoute(name, url, headers, RouteMethod.PUT);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Creates a new route with the DELETE method
|
|
108
|
-
*
|
|
109
|
-
* @param name - The name of the route
|
|
110
|
-
* @param url - The URL of the route
|
|
111
|
-
* @param headers - The headers to be sent with the request
|
|
112
|
-
* @returns The new route
|
|
113
|
-
*/
|
|
114
|
-
public static delete (name: string, url: string, headers: IHeaders): Route {
|
|
115
|
-
return this.createRoute(name, url, headers, RouteMethod.DELETE);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Creates a new route with the PATCH method
|
|
120
|
-
*
|
|
121
|
-
* @param name - The name of the route
|
|
122
|
-
* @param url - The URL of the route
|
|
123
|
-
* @param headers - The headers to be sent with the request
|
|
124
|
-
* @returns The new route
|
|
125
|
-
*/
|
|
126
|
-
public static patch (name: string, url: string, headers: IHeaders): Route {
|
|
127
|
-
return this.createRoute(name, url, headers, RouteMethod.PATCH);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Creates a new route with the OPTIONS method
|
|
132
|
-
*
|
|
133
|
-
* @param name - The name of the route
|
|
134
|
-
* @param url - The URL of the route
|
|
135
|
-
* @param headers - The headers to be sent with the request
|
|
136
|
-
* @returns The new route
|
|
137
|
-
*/
|
|
138
|
-
public static options (name: string, url: string, headers: IHeaders): Route {
|
|
139
|
-
return this.createRoute(name, url, headers, RouteMethod.OPTIONS);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Detects the arguments in the URL
|
|
144
|
-
*/
|
|
145
|
-
private detectArguments (): void {
|
|
146
|
-
const matches = this.url.match(/\[([^\]]+)]/g);
|
|
147
|
-
if (matches) {
|
|
148
|
-
matches.forEach(match => {
|
|
149
|
-
const key = match.replace("[", "").replace("]", "");
|
|
150
|
-
this.arguments.add(key);
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Schema validation (Yup)
|
|
157
|
-
*
|
|
158
|
-
* @param schema - The schema to validate
|
|
159
|
-
* @returns The route
|
|
160
|
-
*/
|
|
161
|
-
public validate (schema: any): Route {
|
|
162
|
-
this.schema = schema;
|
|
163
|
-
return this;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
1
|
+
import { Api } from "./Api";
|
|
2
|
+
import { Element, IHeaders } from "./Element";
|
|
3
|
+
import { Registry } from "./Registry";
|
|
4
|
+
|
|
5
|
+
export enum RouteMethod {
|
|
6
|
+
GET = "GET",
|
|
7
|
+
POST = "POST",
|
|
8
|
+
PUT = "PUT",
|
|
9
|
+
DELETE = "DELETE",
|
|
10
|
+
PATCH = "PATCH",
|
|
11
|
+
OPTIONS = "OPTIONS"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Represents a route
|
|
16
|
+
*/
|
|
17
|
+
export class Route extends Element {
|
|
18
|
+
public api: Api["name"] = "undefined";
|
|
19
|
+
|
|
20
|
+
public method: RouteMethod;
|
|
21
|
+
|
|
22
|
+
public arguments: Set<string> = new Set<string>();
|
|
23
|
+
|
|
24
|
+
public schema: any;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Constructor
|
|
28
|
+
*
|
|
29
|
+
* @param name - The name of the route
|
|
30
|
+
* @param url - The URL of the route
|
|
31
|
+
* @param headers - The headers to be sent with the request
|
|
32
|
+
* @param method - The HTTP method of the route
|
|
33
|
+
*/
|
|
34
|
+
private constructor (
|
|
35
|
+
name: string,
|
|
36
|
+
url: string,
|
|
37
|
+
headers: IHeaders,
|
|
38
|
+
method: RouteMethod = RouteMethod.GET
|
|
39
|
+
) {
|
|
40
|
+
super(name, url, headers);
|
|
41
|
+
this.method = method;
|
|
42
|
+
|
|
43
|
+
this.detectArguments();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Creates a new route
|
|
48
|
+
*
|
|
49
|
+
* @param name - The name of the route
|
|
50
|
+
* @param url - The URL of the route
|
|
51
|
+
* @param headers - The headers to be sent with the request
|
|
52
|
+
* @param method - The HTTP method of the route
|
|
53
|
+
* @returns The new route
|
|
54
|
+
*/
|
|
55
|
+
private static createRoute (
|
|
56
|
+
name: string,
|
|
57
|
+
url: string,
|
|
58
|
+
headers: IHeaders,
|
|
59
|
+
method: RouteMethod
|
|
60
|
+
): Route {
|
|
61
|
+
const route = new Route(name, url, headers, method);
|
|
62
|
+
Registry.i.registerRoute(route as Route);
|
|
63
|
+
return route;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Creates a new route with the GET method
|
|
68
|
+
*
|
|
69
|
+
* @param name - The name of the route
|
|
70
|
+
* @param url - The URL of the route
|
|
71
|
+
* @param headers - The headers to be sent with the request
|
|
72
|
+
* @returns The new route
|
|
73
|
+
*/
|
|
74
|
+
public static get (
|
|
75
|
+
name: string,
|
|
76
|
+
url: string,
|
|
77
|
+
headers: IHeaders = {}
|
|
78
|
+
): Route {
|
|
79
|
+
return this.createRoute(name, url, headers, RouteMethod.GET);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Creates a new route with the POST method
|
|
84
|
+
*
|
|
85
|
+
* @param name - The name of the route
|
|
86
|
+
* @param url - The URL of the route
|
|
87
|
+
* @param headers - The headers to be sent with the request
|
|
88
|
+
* @returns The new route
|
|
89
|
+
*/
|
|
90
|
+
public static post (name: string, url: string, headers: IHeaders): Route {
|
|
91
|
+
return this.createRoute(name, url, headers, RouteMethod.POST);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Creates a new route with the PUT method
|
|
96
|
+
*
|
|
97
|
+
* @param name - The name of the route
|
|
98
|
+
* @param url - The URL of the route
|
|
99
|
+
* @param headers - The headers to be sent with the request
|
|
100
|
+
* @returns The new route
|
|
101
|
+
*/
|
|
102
|
+
public static put (name: string, url: string, headers: IHeaders): Route {
|
|
103
|
+
return this.createRoute(name, url, headers, RouteMethod.PUT);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Creates a new route with the DELETE method
|
|
108
|
+
*
|
|
109
|
+
* @param name - The name of the route
|
|
110
|
+
* @param url - The URL of the route
|
|
111
|
+
* @param headers - The headers to be sent with the request
|
|
112
|
+
* @returns The new route
|
|
113
|
+
*/
|
|
114
|
+
public static delete (name: string, url: string, headers: IHeaders): Route {
|
|
115
|
+
return this.createRoute(name, url, headers, RouteMethod.DELETE);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates a new route with the PATCH method
|
|
120
|
+
*
|
|
121
|
+
* @param name - The name of the route
|
|
122
|
+
* @param url - The URL of the route
|
|
123
|
+
* @param headers - The headers to be sent with the request
|
|
124
|
+
* @returns The new route
|
|
125
|
+
*/
|
|
126
|
+
public static patch (name: string, url: string, headers: IHeaders): Route {
|
|
127
|
+
return this.createRoute(name, url, headers, RouteMethod.PATCH);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Creates a new route with the OPTIONS method
|
|
132
|
+
*
|
|
133
|
+
* @param name - The name of the route
|
|
134
|
+
* @param url - The URL of the route
|
|
135
|
+
* @param headers - The headers to be sent with the request
|
|
136
|
+
* @returns The new route
|
|
137
|
+
*/
|
|
138
|
+
public static options (name: string, url: string, headers: IHeaders): Route {
|
|
139
|
+
return this.createRoute(name, url, headers, RouteMethod.OPTIONS);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Detects the arguments in the URL
|
|
144
|
+
*/
|
|
145
|
+
private detectArguments (): void {
|
|
146
|
+
const matches = this.url.match(/\[([^\]]+)]/g);
|
|
147
|
+
if (matches) {
|
|
148
|
+
matches.forEach(match => {
|
|
149
|
+
const key = match.replace("[", "").replace("]", "");
|
|
150
|
+
this.arguments.add(key);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Schema validation (Yup)
|
|
157
|
+
*
|
|
158
|
+
* @param schema - The schema to validate
|
|
159
|
+
* @returns The route
|
|
160
|
+
*/
|
|
161
|
+
public validate (schema: any): Route {
|
|
162
|
+
this.schema = schema;
|
|
163
|
+
return this;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { Cache } from "../core/Cache";
|
|
2
|
-
|
|
3
|
-
import hashStr from "./hashStr";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Fetch with cache
|
|
7
|
-
*
|
|
8
|
-
* @param input - The input
|
|
9
|
-
* @param init - The init
|
|
10
|
-
* @param ttl - The time to live
|
|
11
|
-
* @returns The response
|
|
12
|
-
*/
|
|
13
|
-
export default async function (
|
|
14
|
-
input: string | URL | globalThis.Request,
|
|
15
|
-
init?: RequestInit,
|
|
16
|
-
ttl?: number
|
|
17
|
-
): Promise<Response> {
|
|
18
|
-
const baseString = `${input.toString()}${JSON.stringify(init)}`;
|
|
19
|
-
const cacheKey = hashStr(baseString);
|
|
20
|
-
|
|
21
|
-
if (Cache.i.has(cacheKey)) {
|
|
22
|
-
return Cache.i.get(cacheKey);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const response = await fetch(input, init);
|
|
26
|
-
const data = await response.json();
|
|
27
|
-
|
|
28
|
-
Cache.i.set(cacheKey, data, ttl);
|
|
29
|
-
return data;
|
|
30
|
-
}
|
|
1
|
+
import { Cache } from "../core/Cache";
|
|
2
|
+
|
|
3
|
+
import hashStr from "./hashStr";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fetch with cache
|
|
7
|
+
*
|
|
8
|
+
* @param input - The input
|
|
9
|
+
* @param init - The init
|
|
10
|
+
* @param ttl - The time to live
|
|
11
|
+
* @returns The response
|
|
12
|
+
*/
|
|
13
|
+
export default async function (
|
|
14
|
+
input: string | URL | globalThis.Request,
|
|
15
|
+
init?: RequestInit,
|
|
16
|
+
ttl?: number
|
|
17
|
+
): Promise<Response> {
|
|
18
|
+
const baseString = `${input.toString()}${JSON.stringify(init)}`;
|
|
19
|
+
const cacheKey = hashStr(baseString);
|
|
20
|
+
|
|
21
|
+
if (Cache.i.has(cacheKey)) {
|
|
22
|
+
return Cache.i.get(cacheKey);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const response = await fetch(input, init);
|
|
26
|
+
const data = await response.json();
|
|
27
|
+
|
|
28
|
+
Cache.i.set(cacheKey, data, ttl);
|
|
29
|
+
return data;
|
|
30
|
+
}
|
package/tests/01.api.test.ts
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { Api, Klaim, Registry } from "../src/index";
|
|
3
|
-
|
|
4
|
-
describe("Api", () => {
|
|
5
|
-
it("should create an API instance with correct properties", () => {
|
|
6
|
-
const name = "testApi";
|
|
7
|
-
const url = "https://jsonplaceholder.typicode.com";
|
|
8
|
-
|
|
9
|
-
const api = Api.create(name, url, () => {});
|
|
10
|
-
|
|
11
|
-
expect(Registry.i.getApi(name)).toBe(api);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("should format the URL correctly", () => {
|
|
15
|
-
const name = "testApi";
|
|
16
|
-
const url = "https://jsonplaceholder.typicode.com/";
|
|
17
|
-
const waitingUrl = "https://jsonplaceholder.typicode.com";
|
|
18
|
-
|
|
19
|
-
const api = Api.create(name, url, () => {});
|
|
20
|
-
|
|
21
|
-
expect(api.url).toBe(waitingUrl);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("should format the name to camelCase", () => {
|
|
25
|
-
const name = "test-api";
|
|
26
|
-
const waitingName = "testApi";
|
|
27
|
-
|
|
28
|
-
const api = Api.create(
|
|
29
|
-
name,
|
|
30
|
-
"https://jsonplaceholder.typicode.com",
|
|
31
|
-
() => {},
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
expect(api.name).toBe(waitingName);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("should access the API instance from Klaim", () => {
|
|
38
|
-
const name = "testApi";
|
|
39
|
-
|
|
40
|
-
Api.create(name, "https://jsonplaceholder.typicode.com", () => {});
|
|
41
|
-
|
|
42
|
-
expect(Klaim[name]).toBeDefined();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("should set the headers correctly", () => {
|
|
46
|
-
const name = "testApi";
|
|
47
|
-
const headers = {
|
|
48
|
-
"Authorization": "Bearer token 123",
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const api = Api.create(
|
|
52
|
-
name,
|
|
53
|
-
"https://jsonplaceholder.typicode.com",
|
|
54
|
-
() => {},
|
|
55
|
-
headers,
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
expect(api.headers).toBe(headers);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { Api, Klaim, Registry } from "../src/index";
|
|
3
|
+
|
|
4
|
+
describe("Api", () => {
|
|
5
|
+
it("should create an API instance with correct properties", () => {
|
|
6
|
+
const name = "testApi";
|
|
7
|
+
const url = "https://jsonplaceholder.typicode.com";
|
|
8
|
+
|
|
9
|
+
const api = Api.create(name, url, () => {});
|
|
10
|
+
|
|
11
|
+
expect(Registry.i.getApi(name)).toBe(api);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should format the URL correctly", () => {
|
|
15
|
+
const name = "testApi";
|
|
16
|
+
const url = "https://jsonplaceholder.typicode.com/";
|
|
17
|
+
const waitingUrl = "https://jsonplaceholder.typicode.com";
|
|
18
|
+
|
|
19
|
+
const api = Api.create(name, url, () => {});
|
|
20
|
+
|
|
21
|
+
expect(api.url).toBe(waitingUrl);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should format the name to camelCase", () => {
|
|
25
|
+
const name = "test-api";
|
|
26
|
+
const waitingName = "testApi";
|
|
27
|
+
|
|
28
|
+
const api = Api.create(
|
|
29
|
+
name,
|
|
30
|
+
"https://jsonplaceholder.typicode.com",
|
|
31
|
+
() => {},
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
expect(api.name).toBe(waitingName);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should access the API instance from Klaim", () => {
|
|
38
|
+
const name = "testApi";
|
|
39
|
+
|
|
40
|
+
Api.create(name, "https://jsonplaceholder.typicode.com", () => {});
|
|
41
|
+
|
|
42
|
+
expect(Klaim[name]).toBeDefined();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should set the headers correctly", () => {
|
|
46
|
+
const name = "testApi";
|
|
47
|
+
const headers = {
|
|
48
|
+
"Authorization": "Bearer token 123",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const api = Api.create(
|
|
52
|
+
name,
|
|
53
|
+
"https://jsonplaceholder.typicode.com",
|
|
54
|
+
() => {},
|
|
55
|
+
headers,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
expect(api.headers).toBe(headers);
|
|
59
|
+
});
|
|
60
|
+
});
|