@yeepay/client-utils 3.1.0 → 4.0.0
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 +33 -5
- package/dist/index.js +110 -55
- package/package.json +8 -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,7 +1,36 @@
|
|
|
1
|
-
import
|
|
1
|
+
import debug from "debug";
|
|
2
|
+
import { AxiosError, 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/is.d.ts
|
|
17
|
+
declare function isTouchDevice(): boolean;
|
|
18
|
+
declare const BREAKPOINTS: {
|
|
19
|
+
MOBILE_MAX: number;
|
|
20
|
+
TABLET_MIN: number;
|
|
21
|
+
TABLET_MAX: number;
|
|
22
|
+
DESKTOP_MIN: number;
|
|
23
|
+
};
|
|
24
|
+
declare const MEDIA_QUERIES: {
|
|
25
|
+
MOBILE: string;
|
|
26
|
+
TABLET: string;
|
|
27
|
+
DESKTOP: string;
|
|
28
|
+
};
|
|
29
|
+
declare function isMobile(): boolean;
|
|
30
|
+
declare function isTablet(): boolean;
|
|
31
|
+
declare function isDesktop(): boolean;
|
|
32
|
+
//#endregion
|
|
3
33
|
//#region src/request/mock.d.ts
|
|
4
|
-
|
|
5
34
|
/**
|
|
6
35
|
* A valid `picomatch` glob pattern, or array of patterns.
|
|
7
36
|
*/
|
|
@@ -64,11 +93,10 @@ interface ServiceFactoryCallbacks {
|
|
|
64
93
|
notfoundCallback?: (response: AxiosResponse<any> | any) => any;
|
|
65
94
|
requestInterceptor?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig;
|
|
66
95
|
responseInterceptor?: (response: AxiosResponse<any>) => AxiosResponse<any>;
|
|
96
|
+
responseInterceptorFailCallback?: (error: AxiosError) => any;
|
|
67
97
|
}
|
|
68
|
-
type ServiceFactoryCallbacksCompatible = [ServiceFactoryCallbacks['successCallback']?, ServiceFactoryCallbacks['failCallback']?, ServiceFactoryCallbacks['unauthorizedCallback']?, ServiceFactoryCallbacks['forbiddenCallback']?, ServiceFactoryCallbacks['notfoundCallback']?, ServiceFactoryCallbacks['requestInterceptor']?, ServiceFactoryCallbacks['responseInterceptor']?];
|
|
69
98
|
declare function verifySuccessCode<T extends string | number>(code: T, customCode?: T): boolean;
|
|
70
99
|
declare function serviceFactory(options: ServiceFactoryOptions, callbacks: ServiceFactoryCallbacks): AxiosInstance;
|
|
71
|
-
declare function serviceFactory(options: ServiceFactoryOptions, ...callbacks: ServiceFactoryCallbacksCompatible): AxiosInstance;
|
|
72
100
|
//#endregion
|
|
73
101
|
//#region src/request/token.d.ts
|
|
74
102
|
declare function getToken(): string | undefined;
|
|
@@ -81,4 +109,4 @@ declare function removeToken(): void;
|
|
|
81
109
|
//#region src/utils.d.ts
|
|
82
110
|
declare function getQueryObject(url?: string): Record<string, string>;
|
|
83
111
|
//#endregion
|
|
84
|
-
export { getQueryObject, getToken, removeToken, serviceFactory, setTokenFromUrl, verifySuccessCode };
|
|
112
|
+
export { BREAKPOINTS, MEDIA_QUERIES, logger as debug, getQueryObject, getToken, isDesktop, isMobile, isTablet, isTouchDevice, removeToken, serviceFactory, setTokenFromUrl, verifySuccessCode };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import debug from "debug";
|
|
1
2
|
import { interopDefault, toArray } from "@imyangyong/utils";
|
|
2
3
|
import axios from "axios";
|
|
3
4
|
import { bold, cyan, gray, green, red, yellow } from "ansis";
|
|
@@ -5,6 +6,90 @@ import AxiosMockAdapter from "axios-mock-adapter";
|
|
|
5
6
|
import picomatch from "picomatch/posix";
|
|
6
7
|
import Cookie from "js-cookie";
|
|
7
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
|
|
58
|
+
//#region src/is.ts
|
|
59
|
+
function isTouchDevice() {
|
|
60
|
+
if (typeof navigator === "undefined" || typeof window === "undefined") return false;
|
|
61
|
+
if ("maxTouchPoints" in navigator) return navigator.maxTouchPoints > 0;
|
|
62
|
+
if (typeof window.matchMedia === "function") return window.matchMedia("(pointer: coarse)").matches;
|
|
63
|
+
const ua = navigator.userAgent || "";
|
|
64
|
+
return /android|iphone|ipad|ipod|windows phone|blackberry|mobile/i.test(ua);
|
|
65
|
+
}
|
|
66
|
+
const BREAKPOINTS = {
|
|
67
|
+
MOBILE_MAX: 767,
|
|
68
|
+
TABLET_MIN: 768,
|
|
69
|
+
TABLET_MAX: 1023,
|
|
70
|
+
DESKTOP_MIN: 1024
|
|
71
|
+
};
|
|
72
|
+
const MEDIA_QUERIES = {
|
|
73
|
+
MOBILE: `(max-width: ${BREAKPOINTS.MOBILE_MAX}px)`,
|
|
74
|
+
TABLET: `(min-width: ${BREAKPOINTS.TABLET_MIN}px) and (max-width: ${BREAKPOINTS.TABLET_MAX}px)`,
|
|
75
|
+
DESKTOP: `(min-width: ${BREAKPOINTS.DESKTOP_MIN}px)`
|
|
76
|
+
};
|
|
77
|
+
function isMobile() {
|
|
78
|
+
if (!isTouchDevice()) return false;
|
|
79
|
+
if (typeof window.matchMedia === "function") return window.matchMedia(MEDIA_QUERIES.MOBILE).matches;
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
function isTablet() {
|
|
83
|
+
if (!isTouchDevice()) return false;
|
|
84
|
+
if (typeof window.matchMedia === "function") return window.matchMedia(MEDIA_QUERIES.TABLET).matches;
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
function isDesktop() {
|
|
88
|
+
if (typeof navigator === "undefined" || typeof window === "undefined") return false;
|
|
89
|
+
return window.matchMedia(MEDIA_QUERIES.DESKTOP).matches;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//#endregion
|
|
8
93
|
//#region src/request/mock.ts
|
|
9
94
|
/**
|
|
10
95
|
* 查找数组中最长相同前缀连续子序列
|
|
@@ -28,8 +113,7 @@ function matchesPattern(str, pattern) {
|
|
|
28
113
|
if (pattern instanceof RegExp) return pattern.test(str);
|
|
29
114
|
if (typeof pattern === "string") {
|
|
30
115
|
if (pattern === "*") return true;
|
|
31
|
-
|
|
32
|
-
return isMatch(str);
|
|
116
|
+
return picomatch(pattern)(str);
|
|
33
117
|
}
|
|
34
118
|
return false;
|
|
35
119
|
}
|
|
@@ -38,11 +122,8 @@ function matchesPattern(str, pattern) {
|
|
|
38
122
|
*/
|
|
39
123
|
function shouldIncludeModule(uri, includes, excludes) {
|
|
40
124
|
const includePatterns = includes ? Array.isArray(includes) ? includes : [includes] : ["*"];
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (isExcluded) return false;
|
|
44
|
-
const isIncluded = includePatterns.some((pattern) => pattern && matchesPattern(uri, pattern));
|
|
45
|
-
return isIncluded;
|
|
125
|
+
if ((excludes ? Array.isArray(excludes) ? excludes : [excludes] : []).some((pattern) => pattern && matchesPattern(uri, pattern))) return false;
|
|
126
|
+
return includePatterns.some((pattern) => pattern && matchesPattern(uri, pattern));
|
|
46
127
|
}
|
|
47
128
|
async function setupMockAdapter(axiosInstance, mock) {
|
|
48
129
|
if (!mock) return;
|
|
@@ -55,16 +136,14 @@ async function setupMockAdapter(axiosInstance, mock) {
|
|
|
55
136
|
});
|
|
56
137
|
const allPaths = Object.keys(modules);
|
|
57
138
|
const longestPrefix = longestCommonPrefix(allPaths);
|
|
58
|
-
const
|
|
139
|
+
const filteredPaths = allPaths.map((path) => {
|
|
59
140
|
const longestPrefixIndex = longestPrefix.lastIndexOf("/");
|
|
60
141
|
const dotIndex = path.lastIndexOf(".");
|
|
61
|
-
const uri = path.slice(longestPrefixIndex, dotIndex);
|
|
62
142
|
return {
|
|
63
|
-
uri,
|
|
143
|
+
uri: path.slice(longestPrefixIndex, dotIndex),
|
|
64
144
|
path
|
|
65
145
|
};
|
|
66
|
-
});
|
|
67
|
-
const filteredPaths = paths.filter(({ uri }) => shouldIncludeModule(uri, includes, excludes));
|
|
146
|
+
}).filter(({ uri }) => shouldIncludeModule(uri, includes, excludes));
|
|
68
147
|
if (filteredPaths.length === 0) return;
|
|
69
148
|
filteredPaths.forEach(({ uri, path }) => {
|
|
70
149
|
const registerMock = (mod) => {
|
|
@@ -92,8 +171,7 @@ function getQueryObject(url) {
|
|
|
92
171
|
url = !url ? window.location.href : url;
|
|
93
172
|
const search = url.substring(url.lastIndexOf("?") + 1);
|
|
94
173
|
const obj = {};
|
|
95
|
-
|
|
96
|
-
search.replace(reg, (rs, $1, $2) => {
|
|
174
|
+
search.replace(/([^?&=]+)=([^?&=]*)/g, (rs, $1, $2) => {
|
|
97
175
|
const name = decodeURIComponent($1);
|
|
98
176
|
let val = decodeURIComponent($2);
|
|
99
177
|
val = String(val);
|
|
@@ -134,26 +212,13 @@ function verifySuccessCode(code, customCode) {
|
|
|
134
212
|
if (customCode) return toArray(customCode).includes(code) || !code;
|
|
135
213
|
return code === 0 || code === "0" || code === "000000" || code === 200 || !code;
|
|
136
214
|
}
|
|
137
|
-
function compatibleCallback(compatibleCallbacks = []) {
|
|
138
|
-
if (Array.isArray(compatibleCallbacks) && compatibleCallbacks.length && typeof compatibleCallbacks[0] === "function") return {
|
|
139
|
-
successCallback: compatibleCallbacks[0] || (() => ({})),
|
|
140
|
-
failCallback: compatibleCallbacks[1] || (() => ({})),
|
|
141
|
-
unauthorizedCallback: compatibleCallbacks[2] || (() => ({})),
|
|
142
|
-
forbiddenCallback: compatibleCallbacks[3] || (() => ({})),
|
|
143
|
-
notfoundCallback: compatibleCallbacks[4] || (() => ({})),
|
|
144
|
-
requestInterceptor: compatibleCallbacks[5] || ((c) => c),
|
|
145
|
-
responseInterceptor: compatibleCallbacks[6] || ((r) => r)
|
|
146
|
-
};
|
|
147
|
-
else return compatibleCallbacks[0];
|
|
148
|
-
}
|
|
149
215
|
function blobToJson(blob) {
|
|
150
216
|
return new Promise((resolve, reject) => {
|
|
151
217
|
const reader = new FileReader();
|
|
152
218
|
reader.onload = (event) => {
|
|
153
219
|
try {
|
|
154
220
|
const jsonString = event.target?.result;
|
|
155
|
-
|
|
156
|
-
resolve(jsonObject);
|
|
221
|
+
resolve(JSON.parse(jsonString));
|
|
157
222
|
} catch (error) {
|
|
158
223
|
reject(error);
|
|
159
224
|
}
|
|
@@ -164,16 +229,13 @@ function blobToJson(blob) {
|
|
|
164
229
|
reader.readAsText(blob);
|
|
165
230
|
});
|
|
166
231
|
}
|
|
167
|
-
function serviceFactory(options,
|
|
168
|
-
const { baseUrl = "/", timeout = 12e5, headers, code, debug, mock } = options;
|
|
169
|
-
const { successCallback = (_response) => ({}), failCallback = (_error) => ({}), unauthorizedCallback = (_response) => ({}), forbiddenCallback = (_response) => ({}), notfoundCallback = (_response) => ({}), requestInterceptor = (c) => c, responseInterceptor = (r) => r } =
|
|
232
|
+
function serviceFactory(options, callbacks) {
|
|
233
|
+
const { baseUrl = "/", timeout = 12e5, headers, code, debug: debug$1, mock } = options;
|
|
234
|
+
const { successCallback = (_response) => ({}), failCallback = (_error) => ({}), unauthorizedCallback = (_response) => ({}), forbiddenCallback = (_response) => ({}), notfoundCallback = (_response) => ({}), requestInterceptor = (c) => c, responseInterceptor = (r) => r, responseInterceptorFailCallback = (error) => Promise.reject(error) } = callbacks;
|
|
170
235
|
const service = axios.create({
|
|
171
236
|
baseURL: baseUrl,
|
|
172
237
|
timeout,
|
|
173
|
-
headers
|
|
174
|
-
validateStatus(status) {
|
|
175
|
-
return status >= 200 && status < 300 || status === 401 || status === 403 || status === 400 || status === 500;
|
|
176
|
-
}
|
|
238
|
+
headers
|
|
177
239
|
});
|
|
178
240
|
/**
|
|
179
241
|
* request拦截器, 先入栈后执行
|
|
@@ -186,7 +248,7 @@ function serviceFactory(options, ...callbacks) {
|
|
|
186
248
|
config.headers.Authorization = getToken();
|
|
187
249
|
const { method, url = "" } = config;
|
|
188
250
|
if (method === "get") {
|
|
189
|
-
if (!debug) if (url.includes("?")) config.url = `${url}&_t=${(/* @__PURE__ */ new Date()).getTime()}`;
|
|
251
|
+
if (!debug$1) if (url.includes("?")) config.url = `${url}&_t=${(/* @__PURE__ */ new Date()).getTime()}`;
|
|
190
252
|
else config.url = `${url}?_t=${(/* @__PURE__ */ new Date()).getTime()}`;
|
|
191
253
|
}
|
|
192
254
|
return config;
|
|
@@ -205,16 +267,12 @@ function serviceFactory(options, ...callbacks) {
|
|
|
205
267
|
}
|
|
206
268
|
return response;
|
|
207
269
|
}, async (error) => {
|
|
208
|
-
|
|
270
|
+
try {
|
|
271
|
+
if (error.response.data instanceof Blob && error.response.headers["content-type"]?.split(";")[0]?.trim() === "application/json") error.response.data = await blobToJson(error.response.data);
|
|
272
|
+
} catch (error$1) {}
|
|
209
273
|
return Promise.reject(error);
|
|
210
274
|
});
|
|
211
275
|
service.interceptors.response.use((response) => {
|
|
212
|
-
if (response.status && response.status === 401) return unauthorizedCallback(response);
|
|
213
|
-
if (response.status && response.status === 403) return forbiddenCallback(response);
|
|
214
|
-
if (response.status && (response.status === 400 || response.status === 500)) {
|
|
215
|
-
failCallback(response);
|
|
216
|
-
return Promise.reject(response);
|
|
217
|
-
}
|
|
218
276
|
if (verifySuccessCode(response.data.code, code)) {
|
|
219
277
|
successCallback(response);
|
|
220
278
|
return response;
|
|
@@ -224,24 +282,21 @@ function serviceFactory(options, ...callbacks) {
|
|
|
224
282
|
}
|
|
225
283
|
}, (error) => {
|
|
226
284
|
if (axios.isCancel(error)) return Promise.reject(error);
|
|
227
|
-
let status = 0;
|
|
228
285
|
try {
|
|
229
|
-
status = error.response.status || error.response.data.status;
|
|
230
|
-
|
|
231
|
-
if (
|
|
286
|
+
const status = error.response.status || error.response.data.status;
|
|
287
|
+
if (status === 401) unauthorizedCallback(error);
|
|
288
|
+
else if (status === 403) forbiddenCallback(error);
|
|
289
|
+
else if (status === 404) notfoundCallback(error);
|
|
290
|
+
else failCallback(error);
|
|
291
|
+
} catch (_) {
|
|
292
|
+
failCallback(error);
|
|
232
293
|
}
|
|
233
|
-
if (status) if (status === 403) forbiddenCallback(error);
|
|
234
|
-
else if (status === 404) notfoundCallback(error);
|
|
235
|
-
else failCallback(error);
|
|
236
|
-
else failCallback(error);
|
|
237
|
-
return Promise.reject(error);
|
|
238
|
-
});
|
|
239
|
-
service.interceptors.response.use(responseInterceptor, (error) => {
|
|
240
294
|
return Promise.reject(error);
|
|
241
295
|
});
|
|
296
|
+
service.interceptors.response.use(responseInterceptor, responseInterceptorFailCallback);
|
|
242
297
|
if (mock) setupMockAdapter(service, mock);
|
|
243
298
|
return service;
|
|
244
299
|
}
|
|
245
300
|
|
|
246
301
|
//#endregion
|
|
247
|
-
export { getQueryObject, getToken, removeToken, serviceFactory, setTokenFromUrl, verifySuccessCode };
|
|
302
|
+
export { BREAKPOINTS, MEDIA_QUERIES, logger as debug, getQueryObject, getToken, isDesktop, isMobile, isTablet, isTouchDevice, 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": "
|
|
4
|
+
"version": "4.0.0",
|
|
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,20 +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
|
-
"axios": "^1.
|
|
26
|
+
"axios": "^1.13.2",
|
|
26
27
|
"axios-mock-adapter": "^2.1.0",
|
|
28
|
+
"debug": "^4.4.3",
|
|
27
29
|
"js-cookie": "^3.0.5",
|
|
28
30
|
"picomatch": "^4.0.3"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
31
33
|
"@antfu/ni": "^0.21.12",
|
|
34
|
+
"@types/debug": "^4.1.12",
|
|
32
35
|
"@types/js-cookie": "^3.0.6",
|
|
33
36
|
"@types/picomatch": "^4.0.2",
|
|
34
37
|
"@yeepay/eslint-config": "^4.17.0",
|
|
35
38
|
"bumpp": "^9.4.1",
|
|
36
39
|
"eslint": "^9.32.0",
|
|
37
40
|
"eslint-plugin-format": "^0.1.1",
|
|
41
|
+
"happy-dom": "^18.0.1",
|
|
38
42
|
"lint-staged": "^15.2.2",
|
|
39
43
|
"simple-git-hooks": "^2.11.1",
|
|
40
44
|
"tsdown": "^0.14.1",
|
|
@@ -53,6 +57,7 @@
|
|
|
53
57
|
"watch": "tsdown --watch",
|
|
54
58
|
"lint": "eslint .",
|
|
55
59
|
"release": "bumpp && pnpm publish",
|
|
56
|
-
"test": "vitest"
|
|
60
|
+
"test": "vitest",
|
|
61
|
+
"play": "npm -C playground run dev"
|
|
57
62
|
}
|
|
58
63
|
}
|