@kevisual/api 0.0.47 → 0.0.49

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.
@@ -39,7 +39,7 @@ export class QueryLogin extends BaseQuery {
39
39
  this.isBrowser = opts?.isBrowser ?? true;
40
40
  this.init();
41
41
  this.onLoad = opts?.onLoad;
42
- this.storage = opts?.storage || localStorage;
42
+ this.storage = opts?.storage || globalThis?.localStorage;
43
43
  }
44
44
  setQuery(query: Query) {
45
45
  this.query = query;
@@ -67,9 +67,9 @@ export class QueryLogin extends BaseQuery {
67
67
  async login(data: QueryLoginData) {
68
68
  const res = await this.post<QueryLoginResult>({ key: 'login', ...data });
69
69
  if (res.code === 200) {
70
- const { accessToken, refreshToken } = res?.data || {};
70
+ const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
71
71
  this.storage.setItem('token', accessToken || '');
72
- await this.beforeSetLoginUser({ accessToken, refreshToken });
72
+ await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
73
73
  }
74
74
  return res;
75
75
  }
@@ -81,9 +81,9 @@ export class QueryLogin extends BaseQuery {
81
81
  async loginByCode(data: { phone: string; code: string }) {
82
82
  const res = await this.post<QueryLoginResult>({ path: 'sms', key: 'login', data });
83
83
  if (res.code === 200) {
84
- const { accessToken, refreshToken } = res?.data || {};
84
+ const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
85
85
  this.storage.setItem('token', accessToken || '');
86
- await this.beforeSetLoginUser({ accessToken, refreshToken });
86
+ await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
87
87
  }
88
88
  return res;
89
89
  }
@@ -91,17 +91,17 @@ export class QueryLogin extends BaseQuery {
91
91
  * 设置token
92
92
  * @param token
93
93
  */
94
- async setLoginToken(token: { accessToken: string; refreshToken: string }) {
95
- const { accessToken, refreshToken } = token;
94
+ async setLoginToken(token: { accessToken: string; refreshToken: string; accessTokenExpiresIn?: number }) {
95
+ const { accessToken, refreshToken, accessTokenExpiresIn } = token;
96
96
  this.storage.setItem('token', accessToken || '');
97
- await this.beforeSetLoginUser({ accessToken, refreshToken });
97
+ await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
98
98
  }
99
99
  async loginByWechat(data: { code: string }) {
100
100
  const res = await this.post<QueryLoginResult>({ path: 'wx', key: 'open-login', code: data.code });
101
101
  if (res.code === 200) {
102
- const { accessToken, refreshToken } = res?.data || {};
102
+ const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
103
103
  this.storage.setItem('token', accessToken || '');
104
- await this.beforeSetLoginUser({ accessToken, refreshToken });
104
+ await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
105
105
  }
106
106
  return res;
107
107
  }
@@ -126,7 +126,7 @@ export class QueryLogin extends BaseQuery {
126
126
  * 登陆成功,需要获取用户信息进行缓存
127
127
  * @param param0
128
128
  */
129
- async beforeSetLoginUser({ accessToken, refreshToken, check401 }: { accessToken?: string; refreshToken?: string; check401?: boolean }) {
129
+ async beforeSetLoginUser({ accessToken, refreshToken, check401, accessTokenExpiresIn }: { accessTokenExpiresIn?: number, accessToken?: string; refreshToken?: string; check401?: boolean }) {
130
130
  if (accessToken && refreshToken) {
131
131
  const resUser = await this.getMe(accessToken, check401);
132
132
  if (resUser.code === 200) {
@@ -137,6 +137,8 @@ export class QueryLogin extends BaseQuery {
137
137
  id: user.id,
138
138
  accessToken,
139
139
  refreshToken,
140
+ accessTokenExpiresIn,
141
+ createdAt: Date.now(),
140
142
  });
141
143
  } else {
142
144
  console.error('登录失败');
@@ -185,9 +187,9 @@ export class QueryLogin extends BaseQuery {
185
187
  if (hasRefreshToken) {
186
188
  const res = await that.queryRefreshToken(hasRefreshToken);
187
189
  if (res.code === 200) {
188
- const { accessToken, refreshToken } = res?.data || {};
190
+ const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
189
191
  that.storage.setItem('token', accessToken || '');
190
- await that.beforeSetLoginUser({ accessToken, refreshToken, check401: false });
192
+ await that.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn, check401: false });
191
193
  if (refetch && ctx && ctx.req && ctx.req.url && ctx.fetch) {
192
194
  await new Promise((resolve) => setTimeout(resolve, 1500));
193
195
  const url = ctx.req?.url;
@@ -336,12 +338,17 @@ export class QueryLogin extends BaseQuery {
336
338
  const user = localUserList.find((userItem) => userItem.user!.username === username);
337
339
  if (user) {
338
340
  this.storage.setItem('token', user.accessToken || '');
339
- await this.beforeSetLoginUser({ accessToken: user.accessToken, refreshToken: user.refreshToken });
341
+ await this.beforeSetLoginUser({
342
+ accessToken: user.accessToken,
343
+ refreshToken: user.refreshToken,
344
+ accessTokenExpiresIn: user.accessTokenExpiresIn
345
+ });
340
346
  return {
341
347
  code: 200,
342
348
  data: {
343
349
  accessToken: user.accessToken,
344
350
  refreshToken: user.refreshToken,
351
+ accessTokenExpiresIn: user.accessTokenExpiresIn,
345
352
  },
346
353
  success: true,
347
354
  message: '切换用户成功',
@@ -350,9 +357,9 @@ export class QueryLogin extends BaseQuery {
350
357
  const res = await this.postSwitchUser(username);
351
358
 
352
359
  if (res.code === 200) {
353
- const { accessToken, refreshToken } = res?.data || {};
360
+ const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
354
361
  this.storage.setItem('token', accessToken || '');
355
- await this.beforeSetLoginUser({ accessToken, refreshToken });
362
+ await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
356
363
  }
357
364
  return res;
358
365
  }
@@ -409,9 +416,9 @@ export class QueryLogin extends BaseQuery {
409
416
  loginToken: token,
410
417
  });
411
418
  if (res.code === 200) {
412
- const accessToken = res.data?.accessToken;
419
+ const { accessTokenExpiresIn, accessToken, refreshToken } = res.data;
413
420
  this.storage.setItem('token', accessToken || '');
414
- await this.beforeSetLoginUser({ accessToken, refreshToken: res.data?.refreshToken });
421
+ await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
415
422
  return res;
416
423
  }
417
424
  return false;
@@ -421,7 +428,7 @@ export class QueryLogin extends BaseQuery {
421
428
  *
422
429
  *
423
430
 
424
- import MD5 from 'crypto-js/md5.js';
431
+ // import MD5 from 'crypto-js/md5.js';
425
432
  import jsonwebtoken from 'jsonwebtoken';
426
433
 
427
434
  */
@@ -0,0 +1,154 @@
1
+ import { Query } from '@kevisual/query';
2
+ import type { Result, DataOpts } from '@kevisual/query/query';
3
+
4
+ export type SimpleObject = Record<string, any>;
5
+ export const markType = ['simple', 'md', 'mdx', 'wallnote', 'excalidraw', 'chat'] as const;
6
+ export type MarkType = (typeof markType)[number];
7
+ export type MarkData = {
8
+ nodes?: any[];
9
+ edges?: any[];
10
+ elements?: any[];
11
+ permission?: any;
12
+
13
+ [key: string]: any;
14
+ };
15
+ export type Mark = {
16
+ id: string;
17
+ title: string;
18
+ description: string;
19
+ markType: MarkType;
20
+ link: string;
21
+ data?: MarkData;
22
+ uid: string;
23
+ puid: string;
24
+ summary: string;
25
+ thumbnail?: string;
26
+ tags: string[];
27
+ createdAt: string;
28
+ updatedAt: string;
29
+ version: number;
30
+ };
31
+ export type ShowMarkPick = Pick<Mark, 'id' | 'title' | 'description' | 'summary' | 'link' | 'tags' | 'thumbnail' | 'updatedAt'>;
32
+
33
+ export type SearchOpts = {
34
+ page?: number;
35
+ pageSize?: number;
36
+ search?: string;
37
+ sort?: string; // DESC, ASC
38
+ markType?: MarkType; // 类型
39
+ [key: string]: any;
40
+ };
41
+
42
+ export type QueryMarkOpts<T extends SimpleObject = SimpleObject> = {
43
+ query?: Query;
44
+ isBrowser?: boolean;
45
+ onLoad?: () => void;
46
+ } & T;
47
+
48
+ export type ResultMarkList = {
49
+ list: Mark[];
50
+ pagination: {
51
+ pageSize: number;
52
+ current: number;
53
+ total: number;
54
+ };
55
+ };
56
+ export type QueryMarkData = {
57
+ id?: string;
58
+ title?: string;
59
+ description?: string;
60
+ [key: string]: any;
61
+ };
62
+ export type QueryMarkResult = {
63
+ accessToken: string;
64
+ refreshToken: string;
65
+ };
66
+
67
+ export class QueryMarkBase<T extends SimpleObject = SimpleObject> {
68
+ query: Query;
69
+ isBrowser: boolean;
70
+ load?: boolean;
71
+ storage?: Storage;
72
+ onLoad?: () => void;
73
+
74
+ constructor(opts?: QueryMarkOpts<T>) {
75
+ this.query = opts?.query || new Query();
76
+ this.isBrowser = opts?.isBrowser ?? true;
77
+ this.init();
78
+ this.onLoad = opts?.onLoad;
79
+ }
80
+ setQuery(query: Query) {
81
+ this.query = query;
82
+ }
83
+ private async init() {
84
+ this.load = true;
85
+ this.onLoad?.();
86
+ }
87
+
88
+ async post<T = Result<any>>(data: any, opts?: DataOpts): Promise<T> {
89
+ try {
90
+ return this.query.post({ path: 'mark', ...data }, opts) as Promise<T>;
91
+ } catch (error) {
92
+ console.log('error', error);
93
+ return {
94
+ code: 400,
95
+ } as any;
96
+ }
97
+ }
98
+
99
+ async getMarkList(search: SearchOpts, opts?: DataOpts) {
100
+ return this.post<Result<ResultMarkList>>({ key: 'list', ...search }, opts);
101
+ }
102
+
103
+ async getMark(id: string, opts?: DataOpts) {
104
+ return this.post<Result<Mark>>({ key: 'get', id }, opts);
105
+ }
106
+ async getVersion(id: string, opts?: DataOpts) {
107
+ return this.post<Result<{ version: number; id: string }>>({ key: 'getVersion', id }, opts);
108
+ }
109
+ /**
110
+ * 检查版本
111
+ * 当需要更新时,返回true
112
+ * @param id
113
+ * @param version
114
+ * @param opts
115
+ * @returns
116
+ */
117
+ async checkVersion(id: string, version?: number, opts?: DataOpts) {
118
+ if (!version) {
119
+ return true;
120
+ }
121
+ const res = await this.getVersion(id, opts);
122
+ if (res.code === 200) {
123
+ if (res.data!.version > version) {
124
+ return true;
125
+ }
126
+ return false;
127
+ }
128
+ return true;
129
+ }
130
+
131
+ async updateMark(data: any, opts?: DataOpts) {
132
+ return this.post<Result<Mark>>({ key: 'update', data }, opts);
133
+ }
134
+
135
+ async deleteMark(id: string, opts?: DataOpts) {
136
+ return this.post<Result<Mark>>({ key: 'delete', id }, opts);
137
+ }
138
+ }
139
+ export class QueryMark extends QueryMarkBase<SimpleObject> {
140
+ markType: string;
141
+ constructor(opts?: QueryMarkOpts & { markType?: MarkType }) {
142
+ super(opts);
143
+ this.markType = opts?.markType || 'simple';
144
+ }
145
+ async getMarkList(search?: SearchOpts, opts?: DataOpts) {
146
+ return this.post<Result<ResultMarkList>>({ key: 'list', ...search, markType: this.markType }, opts);
147
+ }
148
+ async updateMark(data: any, opts?: DataOpts) {
149
+ if (!data.id) {
150
+ data.markType = this.markType || 'simple';
151
+ }
152
+ return super.updateMark(data, opts);
153
+ }
154
+ }
@@ -1,13 +1,12 @@
1
- import MD5 from 'crypto-js/md5';
2
1
  import SparkMD5 from 'spark-md5';
3
2
 
4
3
  export const hashContent = (str: string | Blob | Buffer): Promise<string> | string => {
5
4
  if (typeof str === 'string') {
6
- return MD5(str).toString();
5
+ return SparkMD5.hash(str);
7
6
  } else if (str instanceof Blob) {
8
7
  return hashBlob(str);
9
8
  } else if (Buffer.isBuffer(str)) {
10
- return MD5(str.toString()).toString();
9
+ return SparkMD5.hash(str.toString());
11
10
  }
12
11
  console.error('hashContent error: input must be a string, Blob, or Buffer');
13
12
  return '';
@@ -0,0 +1,66 @@
1
+ 'use strict';
2
+ import { create } from 'zustand';
3
+ import { toast } from 'sonner';
4
+ import { useContextKey } from '@kevisual/context';
5
+ import { type QueryLoginBrowser } from '@/query/query-login/index.ts'
6
+ const queryLogin = useContextKey<QueryLoginBrowser>('queryLogin');
7
+
8
+ type Me = {
9
+ id?: string;
10
+ username?: string;
11
+ nickname?: string | null;
12
+ needChangePassword?: boolean;
13
+ role?: string;
14
+ description?: string | null;
15
+ type?: 'user' | 'org';
16
+ orgs?: string[];
17
+ avatar?: string;
18
+ };
19
+ export type LayoutStore = {
20
+ open: boolean;
21
+ setOpen: (open: boolean) => void;
22
+ me: Me;
23
+ setMe: (me: Me) => void;
24
+ getMe: () => Promise<void>;
25
+ openUser: boolean;
26
+ setOpenUser: (openUser: boolean) => void;
27
+ switchOrg: (username?: string, type?: 'user' | 'org') => Promise<void>;
28
+ isAdmin: boolean;
29
+ setIsAdmin: (isAdmin: boolean) => void;
30
+ checkHasOrg: () => boolean;
31
+ };
32
+ export const useLayoutStore = create<LayoutStore>((set, get) => ({
33
+ open: false,
34
+ setOpen: (open) => set({ open }),
35
+ me: {},
36
+ setMe: (me) => set({ me }),
37
+ getMe: async () => {
38
+ const res = await queryLogin.getMe();
39
+ if (res.code === 200) {
40
+ set({ me: res.data });
41
+ set({ isAdmin: res.data.orgs?.includes('admin') });
42
+ }
43
+ },
44
+ openUser: false,
45
+ setOpenUser: (openUser) => set({ openUser }),
46
+ switchOrg: async (username?: string, type?: string) => {
47
+ const res = await queryLogin.switchUser(username || '');
48
+ if (res.code === 200) {
49
+ toast.success('Switch success');
50
+ setTimeout(() => {
51
+ window.location.reload();
52
+ }, 1000);
53
+ } else {
54
+ toast.error(res.message || 'Request failed');
55
+ }
56
+ },
57
+ isAdmin: false,
58
+ setIsAdmin: (isAdmin) => set({ isAdmin }),
59
+ checkHasOrg: () => {
60
+ const user = get().me || {};
61
+ if (!user.orgs) {
62
+ return false;
63
+ }
64
+ return user?.orgs?.length > 0;
65
+ },
66
+ }));
@@ -0,0 +1,132 @@
1
+ import { create } from 'zustand';
2
+ import { type Result } from '@kevisual/query/query';
3
+ import { MarkType, Mark, QueryMark } from '@kevisual/api/query-mark';
4
+ import { uniqBy } from 'es-toolkit';
5
+ import { useContextKey } from '@kevisual/context';
6
+ import { type QueryLoginBrowser } from '@/query/query-login/index.ts'
7
+ const queryClient = useContextKey<QueryLoginBrowser>('queryLogin');
8
+
9
+ type ManagerStore = {
10
+ /** 当前选中的Mark */
11
+ currentMarkId: string;
12
+ setCurrentMarkId: (markId: string) => void;
13
+ markData?: Mark | undefined;
14
+ setMarkData: (mark?: Partial<Mark>) => void;
15
+ /** 获取Mark列表 */
16
+ getList: () => Promise<any>;
17
+ getMarkFromList: (markId: string) => Mark | undefined;
18
+ updateMark: (mark: Mark) => Promise<any>;
19
+ getMark: (markId: string) => Promise<Result<Mark>>;
20
+ deleteMark: (markId: string) => Promise<any>;
21
+ /** Mark列表 */
22
+ list: Mark[];
23
+ setList: (list: Mark[]) => void;
24
+ pagination: {
25
+ current: number;
26
+ pageSize: number;
27
+ total: number;
28
+ };
29
+ setPagination: (pagination: { current: number; pageSize: number; total: number }) => void;
30
+ /** 搜索 */
31
+ search: string;
32
+ setSearch: (search: string) => void;
33
+ /** 初始化 */
34
+ init: (markType: MarkType) => Promise<void>;
35
+ queryMark?: QueryMark;
36
+ markType?: MarkType;
37
+ open: boolean;
38
+ setOpen: (open: boolean) => void;
39
+ };
40
+ export const useMarkStore = create<ManagerStore>((set, get) => {
41
+ return {
42
+ currentMarkId: '',
43
+ setCurrentMarkId: (markId: string) => set(() => ({ currentMarkId: markId })),
44
+ open: false,
45
+ setOpen: (open: boolean) => set(() => ({ open })),
46
+ getList: async () => {
47
+ const queryMark = get().queryMark!;
48
+ const { search, pagination } = get();
49
+ const res = await queryMark.getMarkList({ page: pagination.current, pageSize: pagination.pageSize, search });
50
+ const oldList = get().list;
51
+ if (res.code === 200) {
52
+ const { pagination, list } = res.data || {};
53
+ const newList = [...oldList, ...list!];
54
+ const uniqueList = uniqBy(newList, (item) => item.id);
55
+ set(() => ({ list: uniqueList }));
56
+ set(() => ({ pagination: { current: pagination!.current, pageSize: pagination!.pageSize, total: pagination!.total } }));
57
+ }
58
+ },
59
+ getMarkFromList: (markId: string) => {
60
+ return get().list.find((item) => item.id === markId);
61
+ },
62
+ updateMark: async (mark: Mark) => {
63
+ const queryMark = get().queryMark!;
64
+ const res = await queryMark.updateMark(mark);
65
+ if (res.code === 200) {
66
+ set((state) => {
67
+ const oldList = state.list;
68
+ const resMark = res.data!;
69
+ const newList = oldList.map((item) => (item.id === mark.id ? mark : item));
70
+ if (!mark.id) {
71
+ newList.unshift(resMark);
72
+ }
73
+ return {
74
+ list: newList,
75
+ };
76
+ });
77
+ }
78
+ return res;
79
+ },
80
+ getMark: async (markId: string) => {
81
+ const queryMark = get().queryMark!;
82
+ const res = await queryMark.getMark(markId);
83
+ return res;
84
+ },
85
+ list: [],
86
+ setList: (list: any[]) => set(() => ({ list })),
87
+ init: async (markType: MarkType = 'wallnote') => {
88
+ // await get().getList();
89
+ console.log('init', set, get);
90
+ const queryMark = new QueryMark({
91
+ query: queryClient as any,
92
+ markType,
93
+ });
94
+ const url = new URL(window.location.href);
95
+ const pageSize = url.searchParams.get('pageSize') || '10';
96
+ set({ queryMark, markType, list: [], pagination: { current: 1, pageSize: parseInt(pageSize), total: 0 }, currentMarkId: '', markData: undefined });
97
+ setTimeout(async () => {
98
+ console.log('get', get);
99
+ get().getList();
100
+ }, 1000);
101
+ },
102
+ deleteMark: async (markId: string) => {
103
+ const queryMark = get().queryMark!;
104
+ const res = await queryMark.deleteMark(markId);
105
+ const currentMarkId = get().currentMarkId;
106
+ if (res.code === 200) {
107
+ // get().getList();
108
+ set((state) => ({
109
+ list: state.list.filter((item) => item.id !== markId),
110
+ }));
111
+ if (currentMarkId === markId) {
112
+ set(() => ({ currentMarkId: '', markData: undefined }));
113
+ }
114
+ }
115
+ return res;
116
+ },
117
+ queryMark: undefined,
118
+ markType: 'simple',
119
+ markData: undefined,
120
+ setMarkData: (mark?: Partial<Mark>) => set(() => ({ markData: mark as Mark })),
121
+ pagination: {
122
+ current: 1,
123
+ pageSize: 10,
124
+ total: 0,
125
+ },
126
+ setPagination: (pagination: { current: number; pageSize: number; total: number }) => set(() => ({ pagination })),
127
+ /** 搜索 */
128
+ search: '',
129
+ setSearch: (search: string) => set(() => ({ search, list: [], pagination: { current: 1, pageSize: 10, total: 0 } })),
130
+ };
131
+ });
132
+