@kevisual/api 0.0.59 → 0.0.61
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/query-login-node.js +39 -48
- package/dist/query-login.js +39 -48
- package/package.json +1 -1
- package/query/query-login/browser-cache/cache-store.ts +123 -0
- package/query/query-login/browser-cache/cache.ts +29 -0
- package/query/query-login/login-cache.ts +57 -56
- package/query/query-login/query-login-browser.ts +1 -1
- package/query/query-login/query-login.ts +25 -6
- package/query/query-login/test/expire.ts +10 -0
- package/query/query-proxy/proxy.ts +23 -5
- package/query/query-proxy/router-api-proxy.ts +4 -0
package/dist/query-login-node.js
CHANGED
|
@@ -312,6 +312,16 @@ class BaseQuery {
|
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
// query/query-login/login-cache.ts
|
|
315
|
+
var defaultCacheData = {
|
|
316
|
+
loginUsers: [],
|
|
317
|
+
user: undefined,
|
|
318
|
+
id: undefined,
|
|
319
|
+
accessToken: undefined,
|
|
320
|
+
refreshToken: undefined,
|
|
321
|
+
accessTokenExpiresIn: undefined,
|
|
322
|
+
createdAt: undefined
|
|
323
|
+
};
|
|
324
|
+
|
|
315
325
|
class LoginCacheStore {
|
|
316
326
|
cache;
|
|
317
327
|
name;
|
|
@@ -321,13 +331,7 @@ class LoginCacheStore {
|
|
|
321
331
|
throw new Error("cache is required");
|
|
322
332
|
}
|
|
323
333
|
this.cache = opts.cache;
|
|
324
|
-
this.cacheData = {
|
|
325
|
-
loginUsers: [],
|
|
326
|
-
user: undefined,
|
|
327
|
-
id: undefined,
|
|
328
|
-
accessToken: undefined,
|
|
329
|
-
refreshToken: undefined
|
|
330
|
-
};
|
|
334
|
+
this.cacheData = { ...defaultCacheData };
|
|
331
335
|
this.name = opts.name;
|
|
332
336
|
}
|
|
333
337
|
async setValue(value) {
|
|
@@ -337,27 +341,13 @@ class LoginCacheStore {
|
|
|
337
341
|
}
|
|
338
342
|
async delValue() {
|
|
339
343
|
await this.cache.del();
|
|
340
|
-
this.cacheData = {
|
|
341
|
-
loginUsers: [],
|
|
342
|
-
user: undefined,
|
|
343
|
-
id: undefined,
|
|
344
|
-
accessToken: undefined,
|
|
345
|
-
refreshToken: undefined
|
|
346
|
-
};
|
|
344
|
+
this.cacheData = { ...defaultCacheData };
|
|
347
345
|
}
|
|
348
346
|
getValue() {
|
|
349
347
|
return this.cache.get(this.name);
|
|
350
348
|
}
|
|
351
349
|
async init() {
|
|
352
|
-
const defaultData = {
|
|
353
|
-
loginUsers: [],
|
|
354
|
-
user: undefined,
|
|
355
|
-
id: undefined,
|
|
356
|
-
accessToken: undefined,
|
|
357
|
-
refreshToken: undefined,
|
|
358
|
-
accessTokenExpiresIn: undefined,
|
|
359
|
-
createdAt: undefined
|
|
360
|
-
};
|
|
350
|
+
const defaultData = { ...this.cacheData };
|
|
361
351
|
if (this.cache.init) {
|
|
362
352
|
try {
|
|
363
353
|
const cacheData = await this.cache.init();
|
|
@@ -370,18 +360,18 @@ class LoginCacheStore {
|
|
|
370
360
|
}
|
|
371
361
|
return this.cacheData;
|
|
372
362
|
}
|
|
373
|
-
async setLoginUser(
|
|
374
|
-
const has = this.cacheData.loginUsers.find((u) => u.id ===
|
|
363
|
+
async setLoginUser(loginUser) {
|
|
364
|
+
const has = this.cacheData.loginUsers.find((u) => u.id === loginUser.id);
|
|
375
365
|
if (has) {
|
|
376
|
-
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !==
|
|
377
|
-
}
|
|
378
|
-
this.cacheData.loginUsers.push(
|
|
379
|
-
this.cacheData.user =
|
|
380
|
-
this.cacheData.id =
|
|
381
|
-
this.cacheData.accessToken =
|
|
382
|
-
this.cacheData.refreshToken =
|
|
383
|
-
this.cacheData.accessTokenExpiresIn =
|
|
384
|
-
this.cacheData.createdAt =
|
|
366
|
+
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== loginUser.id);
|
|
367
|
+
}
|
|
368
|
+
this.cacheData.loginUsers.push(loginUser);
|
|
369
|
+
this.cacheData.user = loginUser.user;
|
|
370
|
+
this.cacheData.id = loginUser.id;
|
|
371
|
+
this.cacheData.accessToken = loginUser.accessToken;
|
|
372
|
+
this.cacheData.refreshToken = loginUser.refreshToken;
|
|
373
|
+
this.cacheData.accessTokenExpiresIn = loginUser.accessTokenExpiresIn;
|
|
374
|
+
this.cacheData.createdAt = loginUser.createdAt;
|
|
385
375
|
await this.setValue(this.cacheData);
|
|
386
376
|
}
|
|
387
377
|
getCurrentUser() {
|
|
@@ -417,22 +407,22 @@ class LoginCacheStore {
|
|
|
417
407
|
if (has) {
|
|
418
408
|
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== user.id);
|
|
419
409
|
}
|
|
420
|
-
this.cacheData.
|
|
421
|
-
this.cacheData.
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
410
|
+
const hasOther = this.cacheData.loginUsers.length > 0;
|
|
411
|
+
const current = this.cacheData.loginUsers[this.cacheData.loginUsers.length - 1];
|
|
412
|
+
if (hasOther && current) {
|
|
413
|
+
this.cacheData.user = current.user;
|
|
414
|
+
this.cacheData.id = current.id;
|
|
415
|
+
this.cacheData.accessToken = current.accessToken;
|
|
416
|
+
this.cacheData.refreshToken = current.refreshToken;
|
|
417
|
+
this.cacheData.accessTokenExpiresIn = current.accessTokenExpiresIn;
|
|
418
|
+
this.cacheData.createdAt = current.createdAt;
|
|
419
|
+
} else {
|
|
420
|
+
this.cacheData = { ...defaultCacheData };
|
|
421
|
+
}
|
|
426
422
|
await this.setValue(this.cacheData);
|
|
427
423
|
}
|
|
428
424
|
async clearAll() {
|
|
429
|
-
this.cacheData
|
|
430
|
-
this.cacheData.user = undefined;
|
|
431
|
-
this.cacheData.id = undefined;
|
|
432
|
-
this.cacheData.accessToken = undefined;
|
|
433
|
-
this.cacheData.refreshToken = undefined;
|
|
434
|
-
this.cacheData.accessTokenExpiresIn = undefined;
|
|
435
|
-
this.cacheData.createdAt = undefined;
|
|
425
|
+
this.cacheData = { ...defaultCacheData };
|
|
436
426
|
await this.setValue(this.cacheData);
|
|
437
427
|
}
|
|
438
428
|
}
|
|
@@ -1023,7 +1013,7 @@ class QueryLogin extends BaseQuery {
|
|
|
1023
1013
|
async queryRefreshToken(opts) {
|
|
1024
1014
|
const refreshToken = opts?.refreshToken;
|
|
1025
1015
|
let accessToken = opts?.accessToken;
|
|
1026
|
-
const _refreshToken = refreshToken
|
|
1016
|
+
const _refreshToken = refreshToken ?? await this.cacheStore.getRefreshToken();
|
|
1027
1017
|
let data = {};
|
|
1028
1018
|
if (accessToken) {
|
|
1029
1019
|
data.accessToken = accessToken;
|
|
@@ -1134,6 +1124,7 @@ class QueryLogin extends BaseQuery {
|
|
|
1134
1124
|
}
|
|
1135
1125
|
const isExpired = await this.cacheStore.getIsExpired();
|
|
1136
1126
|
if (isExpired) {
|
|
1127
|
+
console.log("token过期,正在刷新token", this.cacheStore.cacheData);
|
|
1137
1128
|
const res = await this.refreshLoginUser();
|
|
1138
1129
|
if (res.code === 200) {
|
|
1139
1130
|
return res.data?.accessToken || null;
|
package/dist/query-login.js
CHANGED
|
@@ -312,6 +312,16 @@ class BaseQuery {
|
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
// query/query-login/login-cache.ts
|
|
315
|
+
var defaultCacheData = {
|
|
316
|
+
loginUsers: [],
|
|
317
|
+
user: undefined,
|
|
318
|
+
id: undefined,
|
|
319
|
+
accessToken: undefined,
|
|
320
|
+
refreshToken: undefined,
|
|
321
|
+
accessTokenExpiresIn: undefined,
|
|
322
|
+
createdAt: undefined
|
|
323
|
+
};
|
|
324
|
+
|
|
315
325
|
class LoginCacheStore {
|
|
316
326
|
cache;
|
|
317
327
|
name;
|
|
@@ -321,13 +331,7 @@ class LoginCacheStore {
|
|
|
321
331
|
throw new Error("cache is required");
|
|
322
332
|
}
|
|
323
333
|
this.cache = opts.cache;
|
|
324
|
-
this.cacheData = {
|
|
325
|
-
loginUsers: [],
|
|
326
|
-
user: undefined,
|
|
327
|
-
id: undefined,
|
|
328
|
-
accessToken: undefined,
|
|
329
|
-
refreshToken: undefined
|
|
330
|
-
};
|
|
334
|
+
this.cacheData = { ...defaultCacheData };
|
|
331
335
|
this.name = opts.name;
|
|
332
336
|
}
|
|
333
337
|
async setValue(value) {
|
|
@@ -337,27 +341,13 @@ class LoginCacheStore {
|
|
|
337
341
|
}
|
|
338
342
|
async delValue() {
|
|
339
343
|
await this.cache.del();
|
|
340
|
-
this.cacheData = {
|
|
341
|
-
loginUsers: [],
|
|
342
|
-
user: undefined,
|
|
343
|
-
id: undefined,
|
|
344
|
-
accessToken: undefined,
|
|
345
|
-
refreshToken: undefined
|
|
346
|
-
};
|
|
344
|
+
this.cacheData = { ...defaultCacheData };
|
|
347
345
|
}
|
|
348
346
|
getValue() {
|
|
349
347
|
return this.cache.get(this.name);
|
|
350
348
|
}
|
|
351
349
|
async init() {
|
|
352
|
-
const defaultData = {
|
|
353
|
-
loginUsers: [],
|
|
354
|
-
user: undefined,
|
|
355
|
-
id: undefined,
|
|
356
|
-
accessToken: undefined,
|
|
357
|
-
refreshToken: undefined,
|
|
358
|
-
accessTokenExpiresIn: undefined,
|
|
359
|
-
createdAt: undefined
|
|
360
|
-
};
|
|
350
|
+
const defaultData = { ...this.cacheData };
|
|
361
351
|
if (this.cache.init) {
|
|
362
352
|
try {
|
|
363
353
|
const cacheData = await this.cache.init();
|
|
@@ -370,18 +360,18 @@ class LoginCacheStore {
|
|
|
370
360
|
}
|
|
371
361
|
return this.cacheData;
|
|
372
362
|
}
|
|
373
|
-
async setLoginUser(
|
|
374
|
-
const has = this.cacheData.loginUsers.find((u) => u.id ===
|
|
363
|
+
async setLoginUser(loginUser) {
|
|
364
|
+
const has = this.cacheData.loginUsers.find((u) => u.id === loginUser.id);
|
|
375
365
|
if (has) {
|
|
376
|
-
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !==
|
|
377
|
-
}
|
|
378
|
-
this.cacheData.loginUsers.push(
|
|
379
|
-
this.cacheData.user =
|
|
380
|
-
this.cacheData.id =
|
|
381
|
-
this.cacheData.accessToken =
|
|
382
|
-
this.cacheData.refreshToken =
|
|
383
|
-
this.cacheData.accessTokenExpiresIn =
|
|
384
|
-
this.cacheData.createdAt =
|
|
366
|
+
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== loginUser.id);
|
|
367
|
+
}
|
|
368
|
+
this.cacheData.loginUsers.push(loginUser);
|
|
369
|
+
this.cacheData.user = loginUser.user;
|
|
370
|
+
this.cacheData.id = loginUser.id;
|
|
371
|
+
this.cacheData.accessToken = loginUser.accessToken;
|
|
372
|
+
this.cacheData.refreshToken = loginUser.refreshToken;
|
|
373
|
+
this.cacheData.accessTokenExpiresIn = loginUser.accessTokenExpiresIn;
|
|
374
|
+
this.cacheData.createdAt = loginUser.createdAt;
|
|
385
375
|
await this.setValue(this.cacheData);
|
|
386
376
|
}
|
|
387
377
|
getCurrentUser() {
|
|
@@ -417,22 +407,22 @@ class LoginCacheStore {
|
|
|
417
407
|
if (has) {
|
|
418
408
|
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== user.id);
|
|
419
409
|
}
|
|
420
|
-
this.cacheData.
|
|
421
|
-
this.cacheData.
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
410
|
+
const hasOther = this.cacheData.loginUsers.length > 0;
|
|
411
|
+
const current = this.cacheData.loginUsers[this.cacheData.loginUsers.length - 1];
|
|
412
|
+
if (hasOther && current) {
|
|
413
|
+
this.cacheData.user = current.user;
|
|
414
|
+
this.cacheData.id = current.id;
|
|
415
|
+
this.cacheData.accessToken = current.accessToken;
|
|
416
|
+
this.cacheData.refreshToken = current.refreshToken;
|
|
417
|
+
this.cacheData.accessTokenExpiresIn = current.accessTokenExpiresIn;
|
|
418
|
+
this.cacheData.createdAt = current.createdAt;
|
|
419
|
+
} else {
|
|
420
|
+
this.cacheData = { ...defaultCacheData };
|
|
421
|
+
}
|
|
426
422
|
await this.setValue(this.cacheData);
|
|
427
423
|
}
|
|
428
424
|
async clearAll() {
|
|
429
|
-
this.cacheData
|
|
430
|
-
this.cacheData.user = undefined;
|
|
431
|
-
this.cacheData.id = undefined;
|
|
432
|
-
this.cacheData.accessToken = undefined;
|
|
433
|
-
this.cacheData.refreshToken = undefined;
|
|
434
|
-
this.cacheData.accessTokenExpiresIn = undefined;
|
|
435
|
-
this.cacheData.createdAt = undefined;
|
|
425
|
+
this.cacheData = { ...defaultCacheData };
|
|
436
426
|
await this.setValue(this.cacheData);
|
|
437
427
|
}
|
|
438
428
|
}
|
|
@@ -1023,7 +1013,7 @@ class QueryLogin extends BaseQuery {
|
|
|
1023
1013
|
async queryRefreshToken(opts) {
|
|
1024
1014
|
const refreshToken = opts?.refreshToken;
|
|
1025
1015
|
let accessToken = opts?.accessToken;
|
|
1026
|
-
const _refreshToken = refreshToken
|
|
1016
|
+
const _refreshToken = refreshToken ?? await this.cacheStore.getRefreshToken();
|
|
1027
1017
|
let data = {};
|
|
1028
1018
|
if (accessToken) {
|
|
1029
1019
|
data.accessToken = accessToken;
|
|
@@ -1134,6 +1124,7 @@ class QueryLogin extends BaseQuery {
|
|
|
1134
1124
|
}
|
|
1135
1125
|
const isExpired = await this.cacheStore.getIsExpired();
|
|
1136
1126
|
if (isExpired) {
|
|
1127
|
+
console.log("token过期,正在刷新token", this.cacheStore.cacheData);
|
|
1137
1128
|
const res = await this.refreshLoginUser();
|
|
1138
1129
|
if (res.code === 200) {
|
|
1139
1130
|
return res.data?.accessToken || null;
|
package/package.json
CHANGED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { createStore, UseStore, get, set, del, clear, keys, values, entries, update, setMany, getMany, delMany } from 'idb-keyval';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 缓存存储选项
|
|
5
|
+
*/
|
|
6
|
+
export type CacheStoreOpts = {
|
|
7
|
+
/**
|
|
8
|
+
* 数据库名称
|
|
9
|
+
*/
|
|
10
|
+
dbName?: string;
|
|
11
|
+
/**
|
|
12
|
+
* 存储空间名称
|
|
13
|
+
*/
|
|
14
|
+
storeName?: string;
|
|
15
|
+
};
|
|
16
|
+
export class BaseCacheStore {
|
|
17
|
+
store: UseStore;
|
|
18
|
+
constructor(opts?: CacheStoreOpts) {
|
|
19
|
+
this.store = createStore(opts?.dbName || 'default-db', opts?.storeName || 'cache-store');
|
|
20
|
+
}
|
|
21
|
+
async get(key: string) {
|
|
22
|
+
return get(key, this.store);
|
|
23
|
+
}
|
|
24
|
+
async set(key: string, value: any) {
|
|
25
|
+
return set(key, value, this.store);
|
|
26
|
+
}
|
|
27
|
+
async del(key: string) {
|
|
28
|
+
return del(key, this.store);
|
|
29
|
+
}
|
|
30
|
+
async clear() {
|
|
31
|
+
return clear(this.store);
|
|
32
|
+
}
|
|
33
|
+
async keys() {
|
|
34
|
+
return keys(this.store);
|
|
35
|
+
}
|
|
36
|
+
async values() {
|
|
37
|
+
return values(this.store);
|
|
38
|
+
}
|
|
39
|
+
async entries() {
|
|
40
|
+
return entries(this.store);
|
|
41
|
+
}
|
|
42
|
+
async update(key: string, updater: (value: any) => any) {
|
|
43
|
+
return update(key, updater, this.store);
|
|
44
|
+
}
|
|
45
|
+
async setMany(entries: [string, any][]) {
|
|
46
|
+
return setMany(entries, this.store);
|
|
47
|
+
}
|
|
48
|
+
async getMany(keys: string[]) {
|
|
49
|
+
return getMany(keys, this.store);
|
|
50
|
+
}
|
|
51
|
+
async delMany(keys: string[]) {
|
|
52
|
+
return delMany(keys, this.store);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 缓存存储
|
|
58
|
+
*/
|
|
59
|
+
export class CacheStore extends BaseCacheStore {
|
|
60
|
+
constructor(opts?: CacheStoreOpts) {
|
|
61
|
+
super(opts);
|
|
62
|
+
}
|
|
63
|
+
async getData<T = any>(key: string) {
|
|
64
|
+
const data = await this.get(key);
|
|
65
|
+
return data.data as T;
|
|
66
|
+
}
|
|
67
|
+
async setData(key: string, data: any) {
|
|
68
|
+
return this.set(key, data);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 获取缓存数据,并检查是否过期
|
|
72
|
+
* @param key 缓存键
|
|
73
|
+
* @returns 缓存数据
|
|
74
|
+
*/
|
|
75
|
+
async getCheckData<T = any>(key: string) {
|
|
76
|
+
const data = await this.get(key);
|
|
77
|
+
if (data.expireTime && data.expireTime < Date.now()) {
|
|
78
|
+
await super.del(key);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return data.data as T;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 设置缓存数据,并检查是否过期
|
|
85
|
+
* @param key 缓存键
|
|
86
|
+
* @param data 缓存数据
|
|
87
|
+
* @param opts 缓存选项
|
|
88
|
+
* @returns 缓存数据
|
|
89
|
+
*/
|
|
90
|
+
async setCheckData(key: string, data: any, opts?: { expireTime?: number; updatedAt?: number }) {
|
|
91
|
+
const now = Date.now();
|
|
92
|
+
const expireTime = now + (opts?.expireTime || 1000 * 60 * 60 * 24 * 10);
|
|
93
|
+
const newData = {
|
|
94
|
+
data,
|
|
95
|
+
updatedAt: opts?.updatedAt || Date.now(),
|
|
96
|
+
expireTime,
|
|
97
|
+
};
|
|
98
|
+
await this.set(key, newData);
|
|
99
|
+
return data;
|
|
100
|
+
}
|
|
101
|
+
async checkNew(key: string, data: any): Promise<boolean> {
|
|
102
|
+
const existing = await this.get(key);
|
|
103
|
+
if (!existing) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
if (!data?.updatedAt) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
const updatedAt = new Date(data.updatedAt).getTime();
|
|
110
|
+
if (isNaN(updatedAt)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
return updatedAt > existing.updatedAt;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 删除缓存数据
|
|
117
|
+
* @param key 缓存键
|
|
118
|
+
* @returns 缓存数据
|
|
119
|
+
*/
|
|
120
|
+
async delCheckData(key: string) {
|
|
121
|
+
return this.del(key);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export { CacheStore, BaseCacheStore } from './cache-store.ts'
|
|
2
|
+
import { CacheStore } from './cache-store.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 一个简单的缓存类,用于存储字符串。
|
|
6
|
+
* 对数据进行添加对比内容。
|
|
7
|
+
*/
|
|
8
|
+
export class MyCache<T = any> extends CacheStore {
|
|
9
|
+
key: string;
|
|
10
|
+
constructor(opts?: { key?: string }) {
|
|
11
|
+
const { key, ...rest } = opts || {};
|
|
12
|
+
super(rest);
|
|
13
|
+
this.key = key || 'my-cache';
|
|
14
|
+
}
|
|
15
|
+
async getData<U = T>(key: string = this.key): Promise<U> {
|
|
16
|
+
return super.getCheckData<U>(key) as any;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 设置缓存数据,默认过期时间为10天
|
|
20
|
+
* @param data
|
|
21
|
+
* @param opts
|
|
22
|
+
*/
|
|
23
|
+
async setData<U = T>(data: U, opts?: { expireTime?: number, updatedAt?: number }) {
|
|
24
|
+
super.setCheckData(this.key, data, opts);
|
|
25
|
+
}
|
|
26
|
+
async del(): Promise<void> {
|
|
27
|
+
await super.del(this.key);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -90,6 +90,15 @@ export type LoginCacheStoreOpts<T extends Cache = Cache> = {
|
|
|
90
90
|
name: string;
|
|
91
91
|
cache: T;
|
|
92
92
|
};
|
|
93
|
+
const defaultCacheData: CacheLogin = {
|
|
94
|
+
loginUsers: [],
|
|
95
|
+
user: undefined,
|
|
96
|
+
id: undefined,
|
|
97
|
+
accessToken: undefined,
|
|
98
|
+
refreshToken: undefined,
|
|
99
|
+
accessTokenExpiresIn: undefined,
|
|
100
|
+
createdAt: undefined,
|
|
101
|
+
}
|
|
93
102
|
export class LoginCacheStore<T extends Cache = Cache> implements CacheStore<T> {
|
|
94
103
|
cache: T;
|
|
95
104
|
name: string;
|
|
@@ -100,12 +109,16 @@ export class LoginCacheStore<T extends Cache = Cache> implements CacheStore<T> {
|
|
|
100
109
|
}
|
|
101
110
|
// @ts-ignore
|
|
102
111
|
this.cache = opts.cache;
|
|
103
|
-
this.cacheData = {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
112
|
+
this.cacheData = { ...defaultCacheData };
|
|
113
|
+
this.name = opts.name;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 设置缓存
|
|
117
|
+
* @param key
|
|
118
|
+
* @param value
|
|
119
|
+
* @returns
|
|
120
|
+
accessTokenExpiresIn: undefined,
|
|
121
|
+
createdAt: undefined,
|
|
109
122
|
};
|
|
110
123
|
this.name = opts.name;
|
|
111
124
|
}
|
|
@@ -125,13 +138,7 @@ export class LoginCacheStore<T extends Cache = Cache> implements CacheStore<T> {
|
|
|
125
138
|
*/
|
|
126
139
|
async delValue() {
|
|
127
140
|
await this.cache.del();
|
|
128
|
-
this.cacheData = {
|
|
129
|
-
loginUsers: [],
|
|
130
|
-
user: undefined,
|
|
131
|
-
id: undefined,
|
|
132
|
-
accessToken: undefined,
|
|
133
|
-
refreshToken: undefined,
|
|
134
|
-
};
|
|
141
|
+
this.cacheData = { ...defaultCacheData };
|
|
135
142
|
}
|
|
136
143
|
getValue(): Promise<CacheLogin> {
|
|
137
144
|
return this.cache.get(this.name);
|
|
@@ -139,44 +146,38 @@ export class LoginCacheStore<T extends Cache = Cache> implements CacheStore<T> {
|
|
|
139
146
|
/**
|
|
140
147
|
* 初始化,设置默认值
|
|
141
148
|
*/
|
|
142
|
-
async init() {
|
|
143
|
-
const defaultData: CacheLogin = {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const cacheData = await this.cache.init();
|
|
155
|
-
this.cacheData = cacheData || defaultData;
|
|
156
|
-
} catch (error) {
|
|
157
|
-
console.log('cacheInit error', error);
|
|
149
|
+
async init(): Promise<CacheLogin> {
|
|
150
|
+
const defaultData: CacheLogin = { ...this.cacheData };
|
|
151
|
+
return new Promise(async (resolve) => {
|
|
152
|
+
if (this.cache.init) {
|
|
153
|
+
try {
|
|
154
|
+
const cacheData = await this.cache.init();
|
|
155
|
+
this.cacheData = cacheData || defaultData;
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.log('cacheInit error', error);
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
this.cacheData = (await this.getValue()) || defaultData;
|
|
158
161
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
return this.cacheData;
|
|
162
|
+
resolve(this.cacheData);
|
|
163
|
+
});
|
|
163
164
|
}
|
|
164
165
|
/**
|
|
165
166
|
* 设置当前用户
|
|
166
167
|
* @param user
|
|
167
168
|
*/
|
|
168
|
-
async setLoginUser(
|
|
169
|
-
const has = this.cacheData.loginUsers.find((u) => u.id ===
|
|
169
|
+
async setLoginUser(loginUser: CacheLoginUser) {
|
|
170
|
+
const has = this.cacheData.loginUsers.find((u) => u.id === loginUser.id);
|
|
170
171
|
if (has) {
|
|
171
|
-
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !==
|
|
172
|
+
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== loginUser.id);
|
|
172
173
|
}
|
|
173
|
-
this.cacheData.loginUsers.push(
|
|
174
|
-
this.cacheData.user =
|
|
175
|
-
this.cacheData.id =
|
|
176
|
-
this.cacheData.accessToken =
|
|
177
|
-
this.cacheData.refreshToken =
|
|
178
|
-
this.cacheData.accessTokenExpiresIn =
|
|
179
|
-
this.cacheData.createdAt =
|
|
174
|
+
this.cacheData.loginUsers.push(loginUser);
|
|
175
|
+
this.cacheData.user = loginUser.user;
|
|
176
|
+
this.cacheData.id = loginUser.id;
|
|
177
|
+
this.cacheData.accessToken = loginUser.accessToken;
|
|
178
|
+
this.cacheData.refreshToken = loginUser.refreshToken;
|
|
179
|
+
this.cacheData.accessTokenExpiresIn = loginUser.accessTokenExpiresIn;
|
|
180
|
+
this.cacheData.createdAt = loginUser.createdAt;
|
|
180
181
|
await this.setValue(this.cacheData);
|
|
181
182
|
}
|
|
182
183
|
|
|
@@ -214,22 +215,22 @@ export class LoginCacheStore<T extends Cache = Cache> implements CacheStore<T> {
|
|
|
214
215
|
if (has) {
|
|
215
216
|
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== user.id);
|
|
216
217
|
}
|
|
217
|
-
this.cacheData.
|
|
218
|
-
this.cacheData.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
218
|
+
const hasOther = this.cacheData.loginUsers.length > 0;
|
|
219
|
+
const current = this.cacheData.loginUsers[this.cacheData.loginUsers.length - 1];
|
|
220
|
+
if (hasOther && current) {
|
|
221
|
+
this.cacheData.user = current.user;
|
|
222
|
+
this.cacheData.id = current.id;
|
|
223
|
+
this.cacheData.accessToken = current.accessToken;
|
|
224
|
+
this.cacheData.refreshToken = current.refreshToken;
|
|
225
|
+
this.cacheData.accessTokenExpiresIn = current.accessTokenExpiresIn;
|
|
226
|
+
this.cacheData.createdAt = current.createdAt;
|
|
227
|
+
} else {
|
|
228
|
+
this.cacheData = { ...defaultCacheData };
|
|
229
|
+
}
|
|
223
230
|
await this.setValue(this.cacheData);
|
|
224
231
|
}
|
|
225
232
|
async clearAll() {
|
|
226
|
-
this.cacheData
|
|
227
|
-
this.cacheData.user = undefined;
|
|
228
|
-
this.cacheData.id = undefined;
|
|
229
|
-
this.cacheData.accessToken = undefined;
|
|
230
|
-
this.cacheData.refreshToken = undefined;
|
|
231
|
-
this.cacheData.accessTokenExpiresIn = undefined;
|
|
232
|
-
this.cacheData.createdAt = undefined;
|
|
233
|
+
this.cacheData = { ...defaultCacheData };
|
|
233
234
|
await this.setValue(this.cacheData);
|
|
234
235
|
}
|
|
235
236
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { QueryLogin, QueryLoginOpts } from './query-login.ts';
|
|
2
|
-
import { MyCache } from '
|
|
2
|
+
import { MyCache } from './browser-cache/cache.ts';
|
|
3
3
|
type QueryLoginNodeOptsWithoutCache = Omit<QueryLoginOpts, 'cache'>;
|
|
4
4
|
|
|
5
5
|
export class QueryLoginBrowser extends QueryLogin {
|
|
@@ -3,6 +3,7 @@ import type { Result, DataOpts } from '@kevisual/query/query';
|
|
|
3
3
|
import { LoginCacheStore, CacheStore, User } from './login-cache.ts';
|
|
4
4
|
import { Cache } from './login-cache.ts';
|
|
5
5
|
import { BaseLoad } from '@kevisual/load';
|
|
6
|
+
import { EventEmitter } from 'eventemitter3'
|
|
6
7
|
export type QueryLoginOpts<T extends Cache = Cache> = {
|
|
7
8
|
query?: Query;
|
|
8
9
|
isBrowser?: boolean;
|
|
@@ -26,9 +27,11 @@ export class QueryLogin<T extends Cache = Cache> extends BaseQuery {
|
|
|
26
27
|
*/
|
|
27
28
|
cacheStore: CacheStore<T>;
|
|
28
29
|
isBrowser: boolean;
|
|
29
|
-
load?: boolean;
|
|
30
30
|
storage: Storage;
|
|
31
|
+
load: boolean = false;
|
|
32
|
+
status: 'init' | 'logining' | 'loginSuccess' | 'loginError' = 'init';
|
|
31
33
|
onLoad?: () => void;
|
|
34
|
+
emitter = new EventEmitter();
|
|
32
35
|
|
|
33
36
|
constructor(opts?: QueryLoginOpts<T>) {
|
|
34
37
|
super({
|
|
@@ -42,14 +45,29 @@ export class QueryLogin<T extends Cache = Cache> extends BaseQuery {
|
|
|
42
45
|
if (!this.storage) {
|
|
43
46
|
throw new Error('storage is required');
|
|
44
47
|
}
|
|
48
|
+
this.cacheStore.init().then(() => {
|
|
49
|
+
this.onLoad?.();
|
|
50
|
+
this.load = true;
|
|
51
|
+
this.emitter.emit('load');
|
|
52
|
+
});
|
|
45
53
|
}
|
|
46
54
|
setQuery(query: Query) {
|
|
47
55
|
this.query = query;
|
|
48
56
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
async init() {
|
|
58
|
+
if (this.load) {
|
|
59
|
+
return this.cacheStore.cacheData;
|
|
60
|
+
}
|
|
61
|
+
return new Promise(async (resolve) => {
|
|
62
|
+
const timer = setTimeout(() => {
|
|
63
|
+
resolve(this.cacheStore.cacheData);
|
|
64
|
+
}, 1000 * 20); // 20秒超时,避免一直等待
|
|
65
|
+
const listener = () => {
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
resolve(this.cacheStore.cacheData);
|
|
68
|
+
}
|
|
69
|
+
this.emitter.once('load', listener);
|
|
70
|
+
});
|
|
53
71
|
}
|
|
54
72
|
async post<T = any>(data: any, opts?: DataOpts) {
|
|
55
73
|
try {
|
|
@@ -196,7 +214,7 @@ export class QueryLogin<T extends Cache = Cache> extends BaseQuery {
|
|
|
196
214
|
async queryRefreshToken(opts?: { refreshToken?: string, accessToken?: string }) {
|
|
197
215
|
const refreshToken = opts?.refreshToken;
|
|
198
216
|
let accessToken = opts?.accessToken;
|
|
199
|
-
const _refreshToken = refreshToken
|
|
217
|
+
const _refreshToken = refreshToken ?? (await this.cacheStore.getRefreshToken());
|
|
200
218
|
let data: any = {};
|
|
201
219
|
if (accessToken) {
|
|
202
220
|
data.accessToken = accessToken;
|
|
@@ -360,6 +378,7 @@ export class QueryLogin<T extends Cache = Cache> extends BaseQuery {
|
|
|
360
378
|
}
|
|
361
379
|
const isExpired = await this.cacheStore.getIsExpired();
|
|
362
380
|
if (isExpired) {
|
|
381
|
+
console.log('token过期,正在刷新token', this.cacheStore.cacheData);
|
|
363
382
|
const res = await this.refreshLoginUser()
|
|
364
383
|
if (res.code === 200) {
|
|
365
384
|
// 刷新成功,返回新的token
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const cacheData = {
|
|
2
|
+
accessTokenExpiresIn: 604800,
|
|
3
|
+
createdAt: 1771926793545
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
const expiresIn = cacheData.createdAt + cacheData.accessTokenExpiresIn * 1000;
|
|
7
|
+
console.log('expiresIn', expiresIn);
|
|
8
|
+
const now = Date.now();
|
|
9
|
+
console.log('now', now);
|
|
10
|
+
console.log('isExpired', now >= expiresIn);
|
|
@@ -4,6 +4,7 @@ import { filter } from '@kevisual/js-filter'
|
|
|
4
4
|
import { EventEmitter } from 'eventemitter3';
|
|
5
5
|
import { initApi } from './router-api-proxy.ts';
|
|
6
6
|
import Fuse from 'fuse.js';
|
|
7
|
+
import { cloneDeep } from 'es-toolkit';
|
|
7
8
|
|
|
8
9
|
export const RouteTypeList = ['api', 'context', 'worker', 'page'] as const;
|
|
9
10
|
export type RouterViewItemInfo = RouterViewApi | RouterViewContext | RouterViewWorker | RouteViewPage;
|
|
@@ -26,6 +27,10 @@ type RouteViewBase = {
|
|
|
26
27
|
* 默认动作配置
|
|
27
28
|
*/
|
|
28
29
|
action?: { path?: string; key?: string; id?: string; payload?: any;[key: string]: any };
|
|
30
|
+
/**
|
|
31
|
+
* 本地状态,loading、active、error等
|
|
32
|
+
*/
|
|
33
|
+
routerStatus?: 'loading' | 'active' | 'inactive' | 'error';
|
|
29
34
|
}
|
|
30
35
|
export type RouterViewApi = {
|
|
31
36
|
type: 'api',
|
|
@@ -67,7 +72,7 @@ export type RouterViewWorker = {
|
|
|
67
72
|
* @returns
|
|
68
73
|
*/
|
|
69
74
|
export const pickRouterViewData = (item: RouterViewItem) => {
|
|
70
|
-
const { action, response, _id, ...rest } = item;
|
|
75
|
+
const { action, response, _id, ...rest } = cloneDeep(item);
|
|
71
76
|
if (rest.type === 'api') {
|
|
72
77
|
if (rest.api) {
|
|
73
78
|
delete rest.api.query;
|
|
@@ -83,6 +88,7 @@ export const pickRouterViewData = (item: RouterViewItem) => {
|
|
|
83
88
|
delete rest.context.router;
|
|
84
89
|
}
|
|
85
90
|
}
|
|
91
|
+
delete rest.routerStatus;
|
|
86
92
|
return rest
|
|
87
93
|
}
|
|
88
94
|
/**
|
|
@@ -98,7 +104,7 @@ export type RouteViewPage = {
|
|
|
98
104
|
export type RouterViewQuery = {
|
|
99
105
|
id: string,
|
|
100
106
|
query: string,
|
|
101
|
-
title: string
|
|
107
|
+
title: string,
|
|
102
108
|
}
|
|
103
109
|
/**
|
|
104
110
|
* 后端存储结构
|
|
@@ -143,6 +149,7 @@ export class QueryProxy {
|
|
|
143
149
|
}
|
|
144
150
|
|
|
145
151
|
private initRouterView(item: RouterViewItem) {
|
|
152
|
+
item.routerStatus = 'loading';
|
|
146
153
|
if (item.type === 'api' && item.api?.url) {
|
|
147
154
|
const url = item.api.url;
|
|
148
155
|
if (item?.api?.query) return item;
|
|
@@ -245,10 +252,14 @@ export class QueryProxy {
|
|
|
245
252
|
// @ts-ignore
|
|
246
253
|
const context = globalThis['context'] || {}
|
|
247
254
|
const router = item?.context?.router || context[item?.context?.key] as QueryRouterServer;
|
|
255
|
+
if (item) {
|
|
256
|
+
item.routerStatus = router ? 'active' : 'error';
|
|
257
|
+
}
|
|
248
258
|
if (!router) {
|
|
249
259
|
console.warn(`未发现Context router ${item?.context?.key}`);
|
|
250
260
|
return
|
|
251
261
|
}
|
|
262
|
+
|
|
252
263
|
const routes = router.getList();
|
|
253
264
|
// TODO: args
|
|
254
265
|
// const args = fromJSONSchema(r);
|
|
@@ -308,6 +319,9 @@ export class QueryProxy {
|
|
|
308
319
|
}
|
|
309
320
|
const viewItem = item.worker;
|
|
310
321
|
const worker = viewItem?.worker;
|
|
322
|
+
if (item) {
|
|
323
|
+
item.routerStatus = worker ? 'active' : 'error';
|
|
324
|
+
}
|
|
311
325
|
if (!worker) {
|
|
312
326
|
console.warn('Worker not initialized');
|
|
313
327
|
return;
|
|
@@ -377,11 +391,15 @@ export class QueryProxy {
|
|
|
377
391
|
const url = item.page.url;
|
|
378
392
|
try {
|
|
379
393
|
if (typeof window !== 'undefined') {
|
|
380
|
-
await import(url)
|
|
381
|
-
|
|
382
|
-
|
|
394
|
+
await import(url)
|
|
395
|
+
if (item) {
|
|
396
|
+
item.routerStatus = 'active';
|
|
397
|
+
}
|
|
383
398
|
}
|
|
384
399
|
} catch (e) {
|
|
400
|
+
if (item) {
|
|
401
|
+
item.routerStatus = 'error';
|
|
402
|
+
}
|
|
385
403
|
console.warn('引入Page脚本失败:', url, e);
|
|
386
404
|
return;
|
|
387
405
|
}
|
|
@@ -17,12 +17,16 @@ export const initApi = async (opts: {
|
|
|
17
17
|
const token = opts?.token;
|
|
18
18
|
const query = item?.api?.query || new Query({ url: item?.api?.url || '/api/router' })
|
|
19
19
|
const res = await query.post<{ list: RouterItem[] }>({ path: "router", key: 'list', token: token });
|
|
20
|
+
if (item) {
|
|
21
|
+
item.routerStatus = res?.code === 200 ? 'active' : 'error';
|
|
22
|
+
}
|
|
20
23
|
if (res.code !== 200) {
|
|
21
24
|
return {
|
|
22
25
|
code: res.code,
|
|
23
26
|
message: `初始化路由失败: ${res.message}, url: ${query.url}`
|
|
24
27
|
}
|
|
25
28
|
}
|
|
29
|
+
|
|
26
30
|
let _list = res.data?.list || []
|
|
27
31
|
if (opts?.exclude) {
|
|
28
32
|
if (opts?.exclude) {
|