@dsanchos/api 1.0.0 → 1.0.1
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/api.d.ts +3 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +75 -0
- package/dist/api.js.map +1 -0
- package/dist/api.types.d.ts +45 -0
- package/dist/api.types.d.ts.map +1 -0
- package/dist/api.types.js +2 -0
- package/dist/api.types.js.map +1 -0
- package/dist/core.d.ts +5 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +29 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/{source/index.ts → dist/index.js} +4 -3
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +5 -0
- package/dist/logger.js.map +1 -0
- package/dist/polling.d.ts +3 -0
- package/dist/polling.d.ts.map +1 -0
- package/dist/polling.js +20 -0
- package/dist/polling.js.map +1 -0
- package/package.json +5 -1
- package/source/api.ts +0 -101
- package/source/api.types.ts +0 -60
- package/source/core.ts +0 -37
- package/source/logger.ts +0 -9
- package/source/polling.ts +0 -22
- package/tsconfig.json +0 -26
- /package/{readme.md → README.md} +0 -0
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../source/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAc,MAAM,gBAAgB,CAAC;AAMnE,wBAAsB,GAAG,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CA6F1D"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import fetch from "node-fetch";
|
|
2
|
+
import { getConfig } from "./core.js";
|
|
3
|
+
import { Logger } from "./logger.js";
|
|
4
|
+
const cache = new Map();
|
|
5
|
+
export async function api(props) {
|
|
6
|
+
const { baseUrl, baseKeepUnusedDataFor = 60, baseHeader, interceptors, logger, } = getConfig();
|
|
7
|
+
const finalProps = interceptors?.request
|
|
8
|
+
? await Promise.resolve(interceptors.request(props))
|
|
9
|
+
: props;
|
|
10
|
+
const { method, url, headers, body, keepUnusedDataFor = baseKeepUnusedDataFor, provideCache = "", invalidateCache = "", } = finalProps;
|
|
11
|
+
let data = null;
|
|
12
|
+
let isLoading = true;
|
|
13
|
+
let isFetching = true;
|
|
14
|
+
let isError = false;
|
|
15
|
+
let error = null;
|
|
16
|
+
const TTL = keepUnusedDataFor * 1000;
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
if (provideCache) {
|
|
19
|
+
const cached = cache.get(provideCache);
|
|
20
|
+
if (cached && now - cached.timestamp < TTL) {
|
|
21
|
+
return {
|
|
22
|
+
data: cached.data,
|
|
23
|
+
isLoading: false,
|
|
24
|
+
isFetching: false,
|
|
25
|
+
isError: false,
|
|
26
|
+
error: null,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
isFetching = true;
|
|
32
|
+
if (!data)
|
|
33
|
+
isLoading = true;
|
|
34
|
+
const start = performance.now();
|
|
35
|
+
const response = await fetch(`${baseUrl}${url}`, {
|
|
36
|
+
method,
|
|
37
|
+
headers: headers ?? baseHeader,
|
|
38
|
+
body: body ? JSON.stringify(body) : null,
|
|
39
|
+
});
|
|
40
|
+
const ms = Math.round(performance.now() - start);
|
|
41
|
+
if (logger) {
|
|
42
|
+
Logger(method, url, response.status, ms);
|
|
43
|
+
}
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
46
|
+
}
|
|
47
|
+
data = await response.json();
|
|
48
|
+
isLoading = false;
|
|
49
|
+
if (invalidateCache) {
|
|
50
|
+
for (const key of invalidateCache) {
|
|
51
|
+
cache.delete(key);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
if (provideCache) {
|
|
56
|
+
cache.set(provideCache, { data, timestamp: now });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
error = err instanceof Error ? err.message : String(err);
|
|
62
|
+
isError = true;
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
isFetching = false;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
data,
|
|
69
|
+
isLoading,
|
|
70
|
+
isFetching,
|
|
71
|
+
isError,
|
|
72
|
+
error,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../source/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type METHODS = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
2
|
+
export type CacheEntry = {
|
|
3
|
+
data: any;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
};
|
|
6
|
+
export type headersMap = {
|
|
7
|
+
"Content-Type": "application/json" | "application/x-www-form-urlencoded" | "multipart/form-data" | "text/html" | "text/plain";
|
|
8
|
+
Accept: "application/json" | "text/html" | "*/*";
|
|
9
|
+
Authorization: `Bearer ${string}` | `Basic ${string}` | `ApiKey ${string}`;
|
|
10
|
+
"Cache-Control": "no-cache" | "no-store" | "max-age=3600";
|
|
11
|
+
"Accept-Encoding": "gzip" | "deflate" | "gzip, deflate";
|
|
12
|
+
};
|
|
13
|
+
export type Headers = {
|
|
14
|
+
[K in keyof headersMap]?: headersMap[K];
|
|
15
|
+
};
|
|
16
|
+
export interface API {
|
|
17
|
+
method: METHODS;
|
|
18
|
+
url: string;
|
|
19
|
+
headers?: Headers;
|
|
20
|
+
body?: any;
|
|
21
|
+
keepUnusedDataFor?: number;
|
|
22
|
+
pollingInterval?: number;
|
|
23
|
+
stopAfter?: number;
|
|
24
|
+
provideCache?: string;
|
|
25
|
+
invalidateCache?: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface APIResponse {
|
|
28
|
+
data: any;
|
|
29
|
+
isLoading: boolean;
|
|
30
|
+
isFetching: boolean;
|
|
31
|
+
isError: boolean;
|
|
32
|
+
error: string | null;
|
|
33
|
+
}
|
|
34
|
+
export type OnData = (res: any, stop: () => void) => void;
|
|
35
|
+
export interface CORE {
|
|
36
|
+
baseUrl: string;
|
|
37
|
+
baseKeepUnusedDataFor: number;
|
|
38
|
+
baseHeader: Headers;
|
|
39
|
+
interceptors?: {
|
|
40
|
+
request?: (props: API) => API | Promise<API>;
|
|
41
|
+
response?: (res: APIResponse) => APIResponse | Promise<APIResponse>;
|
|
42
|
+
};
|
|
43
|
+
logger?: boolean;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=api.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.types.d.ts","sourceRoot":"","sources":["../source/api.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAElE,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,GAAG,CAAC;IACV,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,cAAc,EACV,kBAAkB,GAClB,mCAAmC,GACnC,qBAAqB,GACrB,WAAW,GACX,YAAY,CAAC;IAEjB,MAAM,EAAE,kBAAkB,GAAG,WAAW,GAAG,KAAK,CAAC;IAEjD,aAAa,EAAE,UAAU,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,GAAG,UAAU,MAAM,EAAE,CAAC;IAE3E,eAAe,EAAE,UAAU,GAAG,UAAU,GAAG,cAAc,CAAC;IAE1D,iBAAiB,EAAE,MAAM,GAAG,SAAS,GAAG,eAAe,CAAC;CACzD,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;KACnB,CAAC,IAAI,MAAM,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,GAAG,CAAC;IACV,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AAE1D,MAAM,WAAW,IAAI;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE;QACb,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7C,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;KACrE,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.types.js","sourceRoot":"","sources":["../source/api.types.ts"],"names":[],"mappings":""}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../source/core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAUhD,wBAAgB,OAAO,CAAC,KAAK,EAAE,IAAI,QAalC;AAED,wBAAgB,SAAS,SAExB;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,KAEhE"}
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const config = {
|
|
2
|
+
baseUrl: "",
|
|
3
|
+
baseKeepUnusedDataFor: 60,
|
|
4
|
+
baseHeader: {},
|
|
5
|
+
interceptors: {},
|
|
6
|
+
logger: true,
|
|
7
|
+
};
|
|
8
|
+
export function ApiCore(props) {
|
|
9
|
+
config.baseUrl = props.baseUrl;
|
|
10
|
+
config.baseKeepUnusedDataFor = props.baseKeepUnusedDataFor;
|
|
11
|
+
config.baseHeader = props.baseHeader;
|
|
12
|
+
if (props.logger) {
|
|
13
|
+
config.logger = props.logger;
|
|
14
|
+
}
|
|
15
|
+
if (props.interceptors) {
|
|
16
|
+
config.interceptors = props.interceptors;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function getConfig() {
|
|
20
|
+
return config;
|
|
21
|
+
}
|
|
22
|
+
export function defineApi(props) {
|
|
23
|
+
return props;
|
|
24
|
+
}
|
|
25
|
+
// Планы на будущее!
|
|
26
|
+
// retry.ts — повтор запроса при ошибке (retryCount, retryDelay)
|
|
27
|
+
// queue.ts — очередь запросов (не слать 100 запросов одновременно)
|
|
28
|
+
// abort.ts — отмена запроса через AbortController
|
|
29
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../source/core.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAS;IACnB,OAAO,EAAE,EAAE;IACX,qBAAqB,EAAE,EAAE;IACzB,UAAU,EAAE,EAAE;IACd,YAAY,EAAE,EAAE;IAChB,MAAM,EAAE,IAAI;CACb,CAAC;AAEF,MAAM,UAAU,OAAO,CAAC,KAAW;IACjC,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/B,MAAM,CAAC,qBAAqB,GAAG,KAAK,CAAC,qBAAqB,CAAC;IAE3D,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IAErC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACvB,MAAM,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,SAAS,CAAgC,KAAQ;IAC/D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,oBAAoB;AACpB,uEAAuE;AACvE,0EAA0E;AAC1E,yDAAyD"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { api } from "./api.js";
|
|
2
|
-
export { ApiCore, defineApi } from "./core.js";
|
|
3
|
-
export { polling } from "./polling.js";
|
|
1
|
+
export { api } from "./api.js";
|
|
2
|
+
export { ApiCore, defineApi } from "./core.js";
|
|
3
|
+
export { polling } from "./polling.js";
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../source/logger.ts"],"names":[],"mappings":"AAAA,wBAAgB,MAAM,CACpB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,QAIX"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../source/logger.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM,CACpB,MAAc,EACd,GAAW,EACX,MAAc,EACd,EAAU;IAEV,MAAM,SAAS,GAAG,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK,MAAM,KAAK,GAAG,OAAO,MAAM,KAAK,EAAE,KAAK,CAAC,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.d.ts","sourceRoot":"","sources":["../source/polling.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAElD,wBAAgB,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAkBxD"}
|
package/dist/polling.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { api } from "./api.js";
|
|
2
|
+
export function polling(props, onData) {
|
|
3
|
+
const { pollingInterval = 3000, stopAfter } = props;
|
|
4
|
+
let isActive = true;
|
|
5
|
+
const stop = () => {
|
|
6
|
+
isActive = false;
|
|
7
|
+
};
|
|
8
|
+
async function poll() {
|
|
9
|
+
if (!isActive)
|
|
10
|
+
return;
|
|
11
|
+
const res = await api(props);
|
|
12
|
+
onData(res, stop);
|
|
13
|
+
if (isActive)
|
|
14
|
+
setTimeout(poll, pollingInterval);
|
|
15
|
+
}
|
|
16
|
+
poll();
|
|
17
|
+
if (stopAfter)
|
|
18
|
+
setTimeout(stop, stopAfter);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=polling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.js","sourceRoot":"","sources":["../source/polling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAG/B,MAAM,UAAU,OAAO,CAAC,KAAU,EAAE,MAAc;IAChD,MAAM,EAAE,eAAe,GAAG,IAAI,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACpD,IAAI,QAAQ,GAAG,IAAI,CAAC;IAEpB,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,QAAQ,GAAG,KAAK,CAAC;IACnB,CAAC,CAAC;IAEF,KAAK,UAAU,IAAI;QACjB,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClB,IAAI,QAAQ;YAAE,UAAU,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,EAAE,CAAC;IAEP,IAAI,SAAS;QAAE,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AAC7C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsanchos/api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
7
11
|
"exports": {
|
|
8
12
|
".": {
|
|
9
13
|
"import": "./dist/index.js",
|
package/source/api.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import fetch from "node-fetch";
|
|
2
|
-
import type { API, APIResponse, CacheEntry } from "./api.types.js";
|
|
3
|
-
import { getConfig } from "./core.js";
|
|
4
|
-
import { Logger } from "./logger.js";
|
|
5
|
-
|
|
6
|
-
const cache = new Map<string, CacheEntry>();
|
|
7
|
-
|
|
8
|
-
export async function api(props: API): Promise<APIResponse> {
|
|
9
|
-
const {
|
|
10
|
-
baseUrl,
|
|
11
|
-
baseKeepUnusedDataFor = 60,
|
|
12
|
-
baseHeader,
|
|
13
|
-
interceptors,
|
|
14
|
-
logger,
|
|
15
|
-
} = getConfig();
|
|
16
|
-
|
|
17
|
-
const finalProps = interceptors?.request
|
|
18
|
-
? await Promise.resolve(interceptors.request(props))
|
|
19
|
-
: props;
|
|
20
|
-
|
|
21
|
-
const {
|
|
22
|
-
method,
|
|
23
|
-
url,
|
|
24
|
-
headers,
|
|
25
|
-
body,
|
|
26
|
-
keepUnusedDataFor = baseKeepUnusedDataFor,
|
|
27
|
-
provideCache = "",
|
|
28
|
-
invalidateCache = "",
|
|
29
|
-
} = finalProps;
|
|
30
|
-
|
|
31
|
-
let data = null;
|
|
32
|
-
let isLoading = true;
|
|
33
|
-
let isFetching = true;
|
|
34
|
-
let isError = false;
|
|
35
|
-
let error = null;
|
|
36
|
-
|
|
37
|
-
const TTL = keepUnusedDataFor * 1000;
|
|
38
|
-
const now = Date.now();
|
|
39
|
-
|
|
40
|
-
if (provideCache) {
|
|
41
|
-
const cached = cache.get(provideCache);
|
|
42
|
-
|
|
43
|
-
if (cached && now - cached.timestamp < TTL) {
|
|
44
|
-
return {
|
|
45
|
-
data: cached.data,
|
|
46
|
-
isLoading: false,
|
|
47
|
-
isFetching: false,
|
|
48
|
-
isError: false,
|
|
49
|
-
error: null,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
isFetching = true;
|
|
56
|
-
if (!data) isLoading = true;
|
|
57
|
-
|
|
58
|
-
const start = performance.now();
|
|
59
|
-
const response = await fetch(`${baseUrl}${url}`, {
|
|
60
|
-
method,
|
|
61
|
-
headers: headers ?? baseHeader,
|
|
62
|
-
body: body ? JSON.stringify(body) : null,
|
|
63
|
-
});
|
|
64
|
-
const ms = Math.round(performance.now() - start);
|
|
65
|
-
|
|
66
|
-
if (logger) {
|
|
67
|
-
Logger(method, url, response.status, ms);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (!response.ok) {
|
|
71
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
data = await response.json();
|
|
75
|
-
|
|
76
|
-
isLoading = false;
|
|
77
|
-
|
|
78
|
-
if (invalidateCache) {
|
|
79
|
-
for (const key of invalidateCache) {
|
|
80
|
-
cache.delete(key);
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
if (provideCache) {
|
|
84
|
-
cache.set(provideCache, { data, timestamp: now });
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
} catch (err) {
|
|
88
|
-
error = err instanceof Error ? err.message : String(err);
|
|
89
|
-
isError = true;
|
|
90
|
-
} finally {
|
|
91
|
-
isFetching = false;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
data,
|
|
96
|
-
isLoading,
|
|
97
|
-
isFetching,
|
|
98
|
-
isError,
|
|
99
|
-
error,
|
|
100
|
-
};
|
|
101
|
-
}
|
package/source/api.types.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
export type METHODS = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
2
|
-
|
|
3
|
-
export type CacheEntry = {
|
|
4
|
-
data: any;
|
|
5
|
-
timestamp: number;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export type headersMap = {
|
|
9
|
-
"Content-Type":
|
|
10
|
-
| "application/json"
|
|
11
|
-
| "application/x-www-form-urlencoded"
|
|
12
|
-
| "multipart/form-data"
|
|
13
|
-
| "text/html"
|
|
14
|
-
| "text/plain";
|
|
15
|
-
|
|
16
|
-
Accept: "application/json" | "text/html" | "*/*";
|
|
17
|
-
|
|
18
|
-
Authorization: `Bearer ${string}` | `Basic ${string}` | `ApiKey ${string}`;
|
|
19
|
-
|
|
20
|
-
"Cache-Control": "no-cache" | "no-store" | "max-age=3600";
|
|
21
|
-
|
|
22
|
-
"Accept-Encoding": "gzip" | "deflate" | "gzip, deflate";
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export type Headers = {
|
|
26
|
-
[K in keyof headersMap]?: headersMap[K];
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export interface API {
|
|
30
|
-
method: METHODS;
|
|
31
|
-
url: string;
|
|
32
|
-
headers?: Headers;
|
|
33
|
-
body?: any;
|
|
34
|
-
keepUnusedDataFor?: number;
|
|
35
|
-
pollingInterval?: number;
|
|
36
|
-
stopAfter?: number;
|
|
37
|
-
provideCache?: string;
|
|
38
|
-
invalidateCache?: string[];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface APIResponse {
|
|
42
|
-
data: any;
|
|
43
|
-
isLoading: boolean;
|
|
44
|
-
isFetching: boolean;
|
|
45
|
-
isError: boolean;
|
|
46
|
-
error: string | null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export type OnData = (res: any, stop: () => void) => void;
|
|
50
|
-
|
|
51
|
-
export interface CORE {
|
|
52
|
-
baseUrl: string;
|
|
53
|
-
baseKeepUnusedDataFor: number;
|
|
54
|
-
baseHeader: Headers;
|
|
55
|
-
interceptors?: {
|
|
56
|
-
request?: (props: API) => API | Promise<API>;
|
|
57
|
-
response?: (res: APIResponse) => APIResponse | Promise<APIResponse>;
|
|
58
|
-
};
|
|
59
|
-
logger?: boolean;
|
|
60
|
-
}
|
package/source/core.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { API, CORE } from "./api.types.js";
|
|
2
|
-
|
|
3
|
-
const config: CORE = {
|
|
4
|
-
baseUrl: "",
|
|
5
|
-
baseKeepUnusedDataFor: 60,
|
|
6
|
-
baseHeader: {},
|
|
7
|
-
interceptors: {},
|
|
8
|
-
logger: true,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export function ApiCore(props: CORE) {
|
|
12
|
-
config.baseUrl = props.baseUrl;
|
|
13
|
-
config.baseKeepUnusedDataFor = props.baseKeepUnusedDataFor;
|
|
14
|
-
|
|
15
|
-
config.baseHeader = props.baseHeader;
|
|
16
|
-
|
|
17
|
-
if (props.logger) {
|
|
18
|
-
config.logger = props.logger;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (props.interceptors) {
|
|
22
|
-
config.interceptors = props.interceptors;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function getConfig() {
|
|
27
|
-
return config;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function defineApi<T extends Record<string, API>>(props: T) {
|
|
31
|
-
return props;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Планы на будущее!
|
|
35
|
-
// retry.ts — повтор запроса при ошибке (retryCount, retryDelay)
|
|
36
|
-
// queue.ts — очередь запросов (не слать 100 запросов одновременно)
|
|
37
|
-
// abort.ts — отмена запроса через AbortController
|
package/source/logger.ts
DELETED
package/source/polling.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { api } from "./api.js";
|
|
2
|
-
import type { API, OnData } from "./api.types.js";
|
|
3
|
-
|
|
4
|
-
export function polling(props: API, onData: OnData): void {
|
|
5
|
-
const { pollingInterval = 3000, stopAfter } = props;
|
|
6
|
-
let isActive = true;
|
|
7
|
-
|
|
8
|
-
const stop = () => {
|
|
9
|
-
isActive = false;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
async function poll() {
|
|
13
|
-
if (!isActive) return;
|
|
14
|
-
const res = await api(props);
|
|
15
|
-
onData(res, stop);
|
|
16
|
-
if (isActive) setTimeout(poll, pollingInterval);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
poll();
|
|
20
|
-
|
|
21
|
-
if (stopAfter) setTimeout(stop, stopAfter);
|
|
22
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"rootDir": "./source",
|
|
4
|
-
"outDir": "./dist",
|
|
5
|
-
|
|
6
|
-
"module": "nodenext",
|
|
7
|
-
"moduleResolution": "nodenext",
|
|
8
|
-
"target": "esnext",
|
|
9
|
-
"types": ["node"],
|
|
10
|
-
|
|
11
|
-
"sourceMap": true,
|
|
12
|
-
"declaration": true,
|
|
13
|
-
"declarationMap": true,
|
|
14
|
-
// "noEmit": true,
|
|
15
|
-
// "allowImportingTsExtensions":
|
|
16
|
-
|
|
17
|
-
"noUncheckedIndexedAccess": true,
|
|
18
|
-
"exactOptionalPropertyTypes": true,
|
|
19
|
-
"strict": true,
|
|
20
|
-
"verbatimModuleSyntax": true,
|
|
21
|
-
"isolatedModules": true,
|
|
22
|
-
"noUncheckedSideEffectImports": true,
|
|
23
|
-
"moduleDetection": "force",
|
|
24
|
-
"skipLibCheck": true
|
|
25
|
-
}
|
|
26
|
-
}
|
/package/{readme.md → README.md}
RENAMED
|
File without changes
|