@yeepay/client-utils 3.0.6 → 3.1.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/README.md +34 -2
- package/dist/index.d.ts +61 -2
- package/dist/index.js +100 -20
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -41,8 +41,9 @@ const service = serviceFactory(
|
|
|
41
41
|
{
|
|
42
42
|
baseUrl: '/xxx-server',
|
|
43
43
|
headers: {},
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
mock: {
|
|
45
|
+
modules: import.meta.glob('./mock/**/*.json', { eager: true }),
|
|
46
|
+
},
|
|
46
47
|
},
|
|
47
48
|
successCallback,
|
|
48
49
|
failCallback,
|
|
@@ -81,3 +82,34 @@ export default (config: AxiosRequestConfig) => {
|
|
|
81
82
|
}, { 'new-header-hello': 'world' }]
|
|
82
83
|
}
|
|
83
84
|
```
|
|
85
|
+
|
|
86
|
+
### Debug 日志打印
|
|
87
|
+
|
|
88
|
+
开发者常常使用 console.log 日志打印来调试代码,且往往会忘记删除这些日志,导致线上环境也打印日志,影响性能与潜在安全风险。
|
|
89
|
+
|
|
90
|
+
`@yeepay/client-utils` 提供了 debug 模块来帮助开发者更好地控制日志打印。
|
|
91
|
+
|
|
92
|
+
#### 基本使用
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
import { debug } from '@yeepay/client-utils'
|
|
96
|
+
|
|
97
|
+
debug.page1('page1 is loaded')
|
|
98
|
+
|
|
99
|
+
debug.api('fetch user api is called')
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+

|
|
103
|
+
|
|
104
|
+
这些日志默认在开发环境打印,而在生产环境不打印。
|
|
105
|
+
|
|
106
|
+
如果想要在生产环境打印,可以在浏览器控制台执行:
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
debug.enableAll()
|
|
110
|
+
// 或者打印特定模块
|
|
111
|
+
debug.enable('page1')
|
|
112
|
+
|
|
113
|
+
// 恢复默认行为
|
|
114
|
+
debug.disable()
|
|
115
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,64 @@
|
|
|
1
|
+
import debug from "debug";
|
|
1
2
|
import { AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from "axios";
|
|
2
3
|
|
|
4
|
+
//#region src/debug.d.ts
|
|
5
|
+
declare const logger: Record<string, debug.Debugger> & debug.Debugger;
|
|
6
|
+
declare global {
|
|
7
|
+
interface Window {
|
|
8
|
+
debug: {
|
|
9
|
+
enableAll: () => void;
|
|
10
|
+
enable: (namespace: string) => void;
|
|
11
|
+
disable: () => void;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/request/mock.d.ts
|
|
17
|
+
/**
|
|
18
|
+
* A valid `picomatch` glob pattern, or array of patterns.
|
|
19
|
+
*/
|
|
20
|
+
type FilterPattern = ReadonlyArray<string | RegExp> | string | RegExp | null;
|
|
21
|
+
interface Mock {
|
|
22
|
+
/**
|
|
23
|
+
* Default is enable localhost domain, is disabled at other domains.
|
|
24
|
+
*
|
|
25
|
+
* @default undefined
|
|
26
|
+
*/
|
|
27
|
+
enabled?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Response delay in milliseconds.
|
|
30
|
+
*
|
|
31
|
+
* @default 200
|
|
32
|
+
*/
|
|
33
|
+
delay?: number;
|
|
34
|
+
/**
|
|
35
|
+
* The Modules that store mock data.
|
|
36
|
+
*
|
|
37
|
+
* Please use glob patterns to specify the modules.
|
|
38
|
+
*
|
|
39
|
+
* @default {}
|
|
40
|
+
*/
|
|
41
|
+
modules?: Record<string, unknown | (() => Promise<unknown>)>;
|
|
42
|
+
/**
|
|
43
|
+
* If enabled log in console.
|
|
44
|
+
*
|
|
45
|
+
* @default true
|
|
46
|
+
*/
|
|
47
|
+
log?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* The Modules to include the mock.
|
|
50
|
+
*
|
|
51
|
+
* @default ['*']
|
|
52
|
+
*/
|
|
53
|
+
includes?: FilterPattern;
|
|
54
|
+
/**
|
|
55
|
+
* The Modules to exclude the mock.
|
|
56
|
+
*
|
|
57
|
+
* @default []
|
|
58
|
+
*/
|
|
59
|
+
excludes?: FilterPattern;
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
3
62
|
//#region src/request/index.d.ts
|
|
4
63
|
interface ServiceFactoryOptions {
|
|
5
64
|
baseUrl?: string;
|
|
@@ -7,7 +66,7 @@ interface ServiceFactoryOptions {
|
|
|
7
66
|
headers?: Record<string, string>;
|
|
8
67
|
code?: string | number;
|
|
9
68
|
debug?: boolean;
|
|
10
|
-
|
|
69
|
+
mock?: Mock;
|
|
11
70
|
}
|
|
12
71
|
interface ServiceFactoryCallbacks {
|
|
13
72
|
successCallback?: (response: AxiosResponse<any>) => any;
|
|
@@ -34,4 +93,4 @@ declare function removeToken(): void;
|
|
|
34
93
|
//#region src/utils.d.ts
|
|
35
94
|
declare function getQueryObject(url?: string): Record<string, string>;
|
|
36
95
|
//#endregion
|
|
37
|
-
export { getQueryObject, getToken, removeToken, serviceFactory, setTokenFromUrl, verifySuccessCode };
|
|
96
|
+
export { logger as debug, getQueryObject, getToken, removeToken, serviceFactory, setTokenFromUrl, verifySuccessCode };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,60 @@
|
|
|
1
|
-
import
|
|
1
|
+
import debug from "debug";
|
|
2
|
+
import { interopDefault, toArray } from "@imyangyong/utils";
|
|
2
3
|
import axios from "axios";
|
|
3
4
|
import { bold, cyan, gray, green, red, yellow } from "ansis";
|
|
4
5
|
import AxiosMockAdapter from "axios-mock-adapter";
|
|
6
|
+
import picomatch from "picomatch/posix";
|
|
5
7
|
import Cookie from "js-cookie";
|
|
6
8
|
|
|
9
|
+
//#region src/debug.ts
|
|
10
|
+
function createLogger(namespace) {
|
|
11
|
+
return debug(namespace);
|
|
12
|
+
}
|
|
13
|
+
const loggers = {};
|
|
14
|
+
const logger = new Proxy(function() {}, {
|
|
15
|
+
get(_, prop) {
|
|
16
|
+
if (prop in loggers) return loggers[prop];
|
|
17
|
+
const newLogger = createLogger(`${prop}`);
|
|
18
|
+
loggers[prop] = newLogger;
|
|
19
|
+
return newLogger;
|
|
20
|
+
},
|
|
21
|
+
apply(_, thisArg, args) {
|
|
22
|
+
return (loggers.app || (loggers.app = createLogger("app"))).apply(thisArg, args);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
window.debug = {
|
|
26
|
+
enableAll: () => {
|
|
27
|
+
localStorage.setItem("debug", "*");
|
|
28
|
+
location.reload();
|
|
29
|
+
},
|
|
30
|
+
enable: (namespace) => {
|
|
31
|
+
if (!namespace) {
|
|
32
|
+
window.debug.enableAll();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const namespaces = (localStorage.getItem("debug") || "").split(",").filter(Boolean);
|
|
36
|
+
namespaces.push(`${namespace}`);
|
|
37
|
+
localStorage.setItem("debug", namespaces.join(","));
|
|
38
|
+
location.reload();
|
|
39
|
+
},
|
|
40
|
+
disable: () => {
|
|
41
|
+
try {
|
|
42
|
+
if (process?.env?.NODE_ENV === "development") localStorage.setItem("debug", "null");
|
|
43
|
+
else localStorage.removeItem("debug");
|
|
44
|
+
} finally {
|
|
45
|
+
location.reload();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
if (process.env.NODE_ENV === "development") {
|
|
51
|
+
if (!localStorage.getItem("debug")) window.debug.enableAll();
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error("Error enabling logger:", error);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
7
58
|
//#region src/request/mock.ts
|
|
8
59
|
/**
|
|
9
60
|
* 查找数组中最长相同前缀连续子序列
|
|
@@ -20,32 +71,62 @@ function longestCommonPrefix(strs) {
|
|
|
20
71
|
function isLocalhost() {
|
|
21
72
|
return window.location.hostname === "localhost";
|
|
22
73
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Simple pattern matching function that handles basic glob patterns and regex
|
|
76
|
+
*/
|
|
77
|
+
function matchesPattern(str, pattern) {
|
|
78
|
+
if (pattern instanceof RegExp) return pattern.test(str);
|
|
79
|
+
if (typeof pattern === "string") {
|
|
80
|
+
if (pattern === "*") return true;
|
|
81
|
+
return picomatch(pattern)(str);
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if a uri should be included based on includes/excludes patterns
|
|
87
|
+
*/
|
|
88
|
+
function shouldIncludeModule(uri, includes, excludes) {
|
|
89
|
+
const includePatterns = includes ? Array.isArray(includes) ? includes : [includes] : ["*"];
|
|
90
|
+
if ((excludes ? Array.isArray(excludes) ? excludes : [excludes] : []).some((pattern) => pattern && matchesPattern(uri, pattern))) return false;
|
|
91
|
+
return includePatterns.some((pattern) => pattern && matchesPattern(uri, pattern));
|
|
92
|
+
}
|
|
93
|
+
async function setupMockAdapter(axiosInstance, mock) {
|
|
94
|
+
if (!mock) return;
|
|
95
|
+
const { enabled, delay = 200, modules, includes = ["*"], excludes = [], log = true } = mock;
|
|
96
|
+
if (enabled === void 0 && !isLocalhost() || enabled === false) return;
|
|
97
|
+
if (!modules) return;
|
|
98
|
+
const mockAdapter = new AxiosMockAdapter(axiosInstance, {
|
|
99
|
+
delayResponse: delay,
|
|
100
|
+
onNoMatch: "passthrough"
|
|
101
|
+
});
|
|
102
|
+
const allPaths = Object.keys(modules);
|
|
103
|
+
const longestPrefix = longestCommonPrefix(allPaths);
|
|
104
|
+
const filteredPaths = allPaths.map((path) => {
|
|
30
105
|
const longestPrefixIndex = longestPrefix.lastIndexOf("/");
|
|
31
106
|
const dotIndex = path.lastIndexOf(".");
|
|
32
|
-
|
|
107
|
+
return {
|
|
108
|
+
uri: path.slice(longestPrefixIndex, dotIndex),
|
|
109
|
+
path
|
|
110
|
+
};
|
|
111
|
+
}).filter(({ uri }) => shouldIncludeModule(uri, includes, excludes));
|
|
112
|
+
if (filteredPaths.length === 0) return;
|
|
113
|
+
filteredPaths.forEach(({ uri, path }) => {
|
|
33
114
|
const registerMock = (mod) => {
|
|
34
|
-
const replyFunc = typeof mod
|
|
35
|
-
|
|
115
|
+
const replyFunc = typeof mod === "function" ? mod : () => [200, mod];
|
|
116
|
+
mockAdapter.onAny(new RegExp(uri)).reply((config) => {
|
|
36
117
|
const response = replyFunc(config);
|
|
37
118
|
const status = String(response[0]);
|
|
38
119
|
const statusColor = status.startsWith("2") ? green(status) : status.startsWith("3") ? yellow(status) : red(status);
|
|
39
120
|
const data = response[1] ? JSON.stringify(response[1], null, 2) : "";
|
|
40
121
|
const headers = response[2] ? JSON.stringify(response[2], null, 2) : "";
|
|
41
|
-
console.log(`${gray("Mocked:")} ${bold("URI")}: ${cyan.bold(uri)} \n${bold("Status")}: ${statusColor} \n${bold("Response")}: ${data} \n${headers ? `${bold("Headers:")} ${headers}` : ""}`);
|
|
122
|
+
if (log) console.log(`${gray("Mocked:")} ${bold("URI")}: ${cyan.bold(uri)} \n${bold("Status")}: ${statusColor} \n${bold("Response")}: ${data} \n${headers ? `${bold("Headers:")} ${headers}` : ""}`);
|
|
42
123
|
return response;
|
|
43
124
|
});
|
|
44
125
|
};
|
|
45
|
-
if (typeof
|
|
126
|
+
if (typeof modules[path] === "function") interopDefault(modules[path]()).then(registerMock).catch((error) => {
|
|
46
127
|
console.error(`@yeepay/client-utils mock trying to loading ${path} failed`, error);
|
|
47
128
|
});
|
|
48
|
-
else registerMock(
|
|
129
|
+
else registerMock(modules[path]);
|
|
49
130
|
});
|
|
50
131
|
}
|
|
51
132
|
|
|
@@ -55,8 +136,7 @@ function getQueryObject(url) {
|
|
|
55
136
|
url = !url ? window.location.href : url;
|
|
56
137
|
const search = url.substring(url.lastIndexOf("?") + 1);
|
|
57
138
|
const obj = {};
|
|
58
|
-
|
|
59
|
-
search.replace(reg, (rs, $1, $2) => {
|
|
139
|
+
search.replace(/([^?&=]+)=([^?&=]*)/g, (rs, $1, $2) => {
|
|
60
140
|
const name = decodeURIComponent($1);
|
|
61
141
|
let val = decodeURIComponent($2);
|
|
62
142
|
val = String(val);
|
|
@@ -128,7 +208,7 @@ function blobToJson(blob) {
|
|
|
128
208
|
});
|
|
129
209
|
}
|
|
130
210
|
function serviceFactory(options, ...callbacks) {
|
|
131
|
-
const { baseUrl = "/", timeout = 12e5, headers, code, debug,
|
|
211
|
+
const { baseUrl = "/", timeout = 12e5, headers, code, debug: debug$1, mock } = options;
|
|
132
212
|
const { successCallback = (_response) => ({}), failCallback = (_error) => ({}), unauthorizedCallback = (_response) => ({}), forbiddenCallback = (_response) => ({}), notfoundCallback = (_response) => ({}), requestInterceptor = (c) => c, responseInterceptor = (r) => r } = compatibleCallback(callbacks);
|
|
133
213
|
const service = axios.create({
|
|
134
214
|
baseURL: baseUrl,
|
|
@@ -149,7 +229,7 @@ function serviceFactory(options, ...callbacks) {
|
|
|
149
229
|
config.headers.Authorization = getToken();
|
|
150
230
|
const { method, url = "" } = config;
|
|
151
231
|
if (method === "get") {
|
|
152
|
-
if (!debug) if (url.includes("?")) config.url = `${url}&_t=${(/* @__PURE__ */ new Date()).getTime()}`;
|
|
232
|
+
if (!debug$1) if (url.includes("?")) config.url = `${url}&_t=${(/* @__PURE__ */ new Date()).getTime()}`;
|
|
153
233
|
else config.url = `${url}?_t=${(/* @__PURE__ */ new Date()).getTime()}`;
|
|
154
234
|
}
|
|
155
235
|
return config;
|
|
@@ -202,9 +282,9 @@ function serviceFactory(options, ...callbacks) {
|
|
|
202
282
|
service.interceptors.response.use(responseInterceptor, (error) => {
|
|
203
283
|
return Promise.reject(error);
|
|
204
284
|
});
|
|
205
|
-
if (
|
|
285
|
+
if (mock) setupMockAdapter(service, mock);
|
|
206
286
|
return service;
|
|
207
287
|
}
|
|
208
288
|
|
|
209
289
|
//#endregion
|
|
210
|
-
export { getQueryObject, getToken, removeToken, serviceFactory, setTokenFromUrl, verifySuccessCode };
|
|
290
|
+
export { logger as debug, getQueryObject, getToken, removeToken, serviceFactory, setTokenFromUrl, verifySuccessCode };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yeepay/client-utils",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.1.1",
|
|
5
5
|
"description": "shared utilities for yeepay client packages",
|
|
6
6
|
"author": "Yong Yang",
|
|
7
7
|
"homepage": "http://gitlab.yeepay.com/ued/client-utils#readme",
|
|
@@ -21,18 +21,24 @@
|
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@imyangyong/utils": "^0.8.0",
|
|
24
|
+
"@yeepay/client-utils": "link:",
|
|
24
25
|
"ansis": "^4.1.0",
|
|
25
26
|
"axios": "^1.7.0",
|
|
26
27
|
"axios-mock-adapter": "^2.1.0",
|
|
27
|
-
"
|
|
28
|
+
"debug": "^4.4.3",
|
|
29
|
+
"js-cookie": "^3.0.5",
|
|
30
|
+
"picomatch": "^4.0.3"
|
|
28
31
|
},
|
|
29
32
|
"devDependencies": {
|
|
30
33
|
"@antfu/ni": "^0.21.12",
|
|
34
|
+
"@types/debug": "^4.1.12",
|
|
31
35
|
"@types/js-cookie": "^3.0.6",
|
|
36
|
+
"@types/picomatch": "^4.0.2",
|
|
32
37
|
"@yeepay/eslint-config": "^4.17.0",
|
|
33
38
|
"bumpp": "^9.4.1",
|
|
34
39
|
"eslint": "^9.32.0",
|
|
35
40
|
"eslint-plugin-format": "^0.1.1",
|
|
41
|
+
"happy-dom": "^18.0.1",
|
|
36
42
|
"lint-staged": "^15.2.2",
|
|
37
43
|
"simple-git-hooks": "^2.11.1",
|
|
38
44
|
"tsdown": "^0.14.1",
|
|
@@ -51,6 +57,7 @@
|
|
|
51
57
|
"watch": "tsdown --watch",
|
|
52
58
|
"lint": "eslint .",
|
|
53
59
|
"release": "bumpp && pnpm publish",
|
|
54
|
-
"test": "vitest"
|
|
60
|
+
"test": "vitest",
|
|
61
|
+
"play": "npm -C playground run dev"
|
|
55
62
|
}
|
|
56
63
|
}
|