@lobehub/chat 1.37.0 → 1.37.2
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/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/locales/en-US/common.json +2 -2
- package/package.json +1 -1
- package/src/services/file/_deprecated.test.ts +119 -0
- package/src/services/file/{pglite.ts → _deprecated.ts} +28 -32
- package/src/services/file/client.test.ts +153 -74
- package/src/services/file/client.ts +32 -28
- package/src/services/file/index.ts +2 -2
- package/src/services/import/_deprecated.ts +74 -0
- package/src/services/import/{pglite.test.ts → client.test.ts} +1 -1
- package/src/services/import/client.ts +21 -61
- package/src/services/import/index.ts +2 -2
- package/src/services/message/_deprecated.test.ts +398 -0
- package/src/services/message/_deprecated.ts +121 -0
- package/src/services/message/client.test.ts +191 -159
- package/src/services/message/client.ts +47 -50
- package/src/services/message/index.ts +2 -2
- package/src/services/plugin/_deprecated.test.ts +162 -0
- package/src/services/plugin/_deprecated.ts +42 -0
- package/src/services/plugin/client.test.ts +68 -55
- package/src/services/plugin/client.ts +20 -11
- package/src/services/plugin/index.ts +2 -2
- package/src/services/session/_deprecated.test.ts +440 -0
- package/src/services/session/_deprecated.ts +183 -0
- package/src/services/session/client.test.ts +212 -241
- package/src/services/session/client.ts +61 -60
- package/src/services/session/index.ts +2 -2
- package/src/services/topic/{client.test.ts → _deprecated.test.ts} +1 -1
- package/src/services/topic/_deprecated.ts +70 -0
- package/src/services/topic/client.ts +40 -25
- package/src/services/topic/index.ts +2 -2
- package/src/services/topic/pglite.test.ts +1 -1
- package/src/services/user/{pglite.test.ts → _deprecated.test.ts} +32 -29
- package/src/services/user/_deprecated.ts +57 -0
- package/src/services/user/client.test.ts +28 -31
- package/src/services/user/client.ts +51 -16
- package/src/services/user/index.ts +2 -2
- package/src/store/chat/slices/builtinTool/action.test.ts +1 -1
- package/src/store/user/slices/common/action.test.ts +1 -1
- package/src/services/file/pglite.test.ts +0 -198
- package/src/services/import/pglite.ts +0 -34
- package/src/services/message/pglite.test.ts +0 -430
- package/src/services/message/pglite.ts +0 -118
- package/src/services/plugin/pglite.test.ts +0 -175
- package/src/services/plugin/pglite.ts +0 -51
- package/src/services/session/pglite.test.ts +0 -411
- package/src/services/session/pglite.ts +0 -184
- package/src/services/topic/pglite.ts +0 -85
- package/src/services/user/pglite.ts +0 -92
@@ -1,21 +1,14 @@
|
|
1
|
+
import { eq } from 'drizzle-orm';
|
1
2
|
import { DeepPartial } from 'utility-types';
|
2
|
-
import {
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
4
|
|
4
|
-
import {
|
5
|
+
import { clientDB, initializeDB } from '@/database/client/db';
|
6
|
+
import { userSettings, users } from '@/database/schemas';
|
5
7
|
import { UserPreference } from '@/types/user';
|
6
8
|
import { UserSettings } from '@/types/user/settings';
|
7
9
|
|
8
10
|
import { ClientService } from './client';
|
9
11
|
|
10
|
-
vi.mock('@/database/_deprecated/models/user', () => ({
|
11
|
-
UserModel: {
|
12
|
-
getUser: vi.fn(),
|
13
|
-
updateSettings: vi.fn(),
|
14
|
-
resetSettings: vi.fn(),
|
15
|
-
updateAvatar: vi.fn(),
|
16
|
-
},
|
17
|
-
}));
|
18
|
-
|
19
12
|
const mockUser = {
|
20
13
|
avatar: 'avatar.png',
|
21
14
|
settings: { themeMode: 'light' } as unknown as UserSettings,
|
@@ -25,63 +18,67 @@ const mockUser = {
|
|
25
18
|
const mockPreference = {
|
26
19
|
useCmdEnterToSend: true,
|
27
20
|
} as UserPreference;
|
21
|
+
const clientService = new ClientService(mockUser.uuid);
|
28
22
|
|
29
|
-
|
30
|
-
|
23
|
+
beforeEach(async () => {
|
24
|
+
vi.clearAllMocks();
|
31
25
|
|
32
|
-
|
33
|
-
|
34
|
-
clientService = new ClientService();
|
35
|
-
});
|
26
|
+
await initializeDB();
|
27
|
+
await clientDB.delete(users);
|
36
28
|
|
29
|
+
await clientDB.insert(users).values({ id: mockUser.uuid, avatar: 'avatar.png' });
|
30
|
+
await clientDB
|
31
|
+
.insert(userSettings)
|
32
|
+
.values({ id: mockUser.uuid, general: { themeMode: 'light' } });
|
33
|
+
});
|
34
|
+
|
35
|
+
describe('ClientService', () => {
|
37
36
|
it('should get user state correctly', async () => {
|
38
|
-
(UserModel.getUser as Mock).mockResolvedValue(mockUser);
|
39
37
|
const spyOn = vi
|
40
38
|
.spyOn(clientService['preferenceStorage'], 'getFromLocalStorage')
|
41
39
|
.mockResolvedValue(mockPreference);
|
42
40
|
|
43
41
|
const userState = await clientService.getUserState();
|
44
42
|
|
45
|
-
expect(userState).
|
43
|
+
expect(userState).toMatchObject({
|
46
44
|
avatar: mockUser.avatar,
|
47
45
|
isOnboard: true,
|
48
46
|
canEnablePWAGuide: false,
|
49
47
|
hasConversation: false,
|
50
48
|
canEnableTrace: false,
|
51
49
|
preference: mockPreference,
|
52
|
-
settings:
|
50
|
+
settings: { general: { themeMode: 'light' } },
|
53
51
|
userId: mockUser.uuid,
|
54
52
|
});
|
55
|
-
expect(UserModel.getUser).toHaveBeenCalledTimes(1);
|
56
53
|
expect(spyOn).toHaveBeenCalledTimes(1);
|
57
54
|
});
|
58
55
|
|
59
56
|
it('should update user settings correctly', async () => {
|
60
57
|
const settingsPatch: DeepPartial<UserSettings> = { general: { themeMode: 'dark' } };
|
61
|
-
(UserModel.updateSettings as Mock).mockResolvedValue(undefined);
|
62
58
|
|
63
59
|
await clientService.updateUserSettings(settingsPatch);
|
64
60
|
|
65
|
-
|
66
|
-
|
61
|
+
const result = await clientDB.query.userSettings.findFirst({
|
62
|
+
where: eq(userSettings.id, mockUser.uuid),
|
63
|
+
});
|
64
|
+
|
65
|
+
expect(result).toMatchObject(settingsPatch);
|
67
66
|
});
|
68
67
|
|
69
68
|
it('should reset user settings correctly', async () => {
|
70
|
-
(UserModel.resetSettings as Mock).mockResolvedValue(undefined);
|
71
|
-
|
72
69
|
await clientService.resetUserSettings();
|
73
70
|
|
74
|
-
|
71
|
+
const result = await clientDB.query.userSettings.findFirst({
|
72
|
+
where: eq(userSettings.id, mockUser.uuid),
|
73
|
+
});
|
74
|
+
|
75
|
+
expect(result).toBeUndefined();
|
75
76
|
});
|
76
77
|
|
77
78
|
it('should update user avatar correctly', async () => {
|
78
79
|
const newAvatar = 'new-avatar.png';
|
79
|
-
(UserModel.updateAvatar as Mock).mockResolvedValue(undefined);
|
80
80
|
|
81
81
|
await clientService.updateAvatar(newAvatar);
|
82
|
-
|
83
|
-
expect(UserModel.updateAvatar).toHaveBeenCalledWith(newAvatar);
|
84
|
-
expect(UserModel.updateAvatar).toHaveBeenCalledTimes(1);
|
85
82
|
});
|
86
83
|
|
87
84
|
it('should update user preference correctly', async () => {
|
@@ -1,49 +1,70 @@
|
|
1
1
|
import { DeepPartial } from 'utility-types';
|
2
2
|
|
3
|
-
import {
|
4
|
-
import {
|
5
|
-
import {
|
3
|
+
import { clientDB } from '@/database/client/db';
|
4
|
+
import { users } from '@/database/schemas';
|
5
|
+
import { MessageModel } from '@/database/server/models/message';
|
6
|
+
import { SessionModel } from '@/database/server/models/session';
|
7
|
+
import { UserModel } from '@/database/server/models/user';
|
8
|
+
import { BaseClientService } from '@/services/baseClientService';
|
6
9
|
import { UserGuide, UserInitializationState, UserPreference } from '@/types/user';
|
7
10
|
import { UserSettings } from '@/types/user/settings';
|
8
11
|
import { AsyncLocalStorage } from '@/utils/localStorage';
|
9
12
|
|
10
13
|
import { IUserService } from './type';
|
11
14
|
|
12
|
-
export class ClientService implements IUserService {
|
15
|
+
export class ClientService extends BaseClientService implements IUserService {
|
13
16
|
private preferenceStorage: AsyncLocalStorage<UserPreference>;
|
14
17
|
|
15
|
-
|
18
|
+
private get userModel(): UserModel {
|
19
|
+
return new UserModel(clientDB as any, this.userId);
|
20
|
+
}
|
21
|
+
private get messageModel(): MessageModel {
|
22
|
+
return new MessageModel(clientDB as any, this.userId);
|
23
|
+
}
|
24
|
+
private get sessionModel(): SessionModel {
|
25
|
+
return new SessionModel(clientDB as any, this.userId);
|
26
|
+
}
|
27
|
+
|
28
|
+
constructor(userId?: string) {
|
29
|
+
super(userId);
|
16
30
|
this.preferenceStorage = new AsyncLocalStorage('LOBE_PREFERENCE');
|
17
31
|
}
|
18
32
|
|
19
33
|
async getUserState(): Promise<UserInitializationState> {
|
20
|
-
|
21
|
-
|
22
|
-
|
34
|
+
// if user not exist in the db, create one to make sure the user exist
|
35
|
+
await this.makeSureUserExist();
|
36
|
+
|
37
|
+
const state = await this.userModel.getUserState((encryptKeyVaultsStr) =>
|
38
|
+
encryptKeyVaultsStr ? JSON.parse(encryptKeyVaultsStr) : {},
|
39
|
+
);
|
40
|
+
|
41
|
+
const user = await UserModel.findById(clientDB as any, this.userId);
|
42
|
+
const messageCount = await this.messageModel.count();
|
43
|
+
const sessionCount = await this.sessionModel.count();
|
23
44
|
|
24
45
|
return {
|
25
|
-
|
46
|
+
...state,
|
47
|
+
avatar: user?.avatar as string,
|
26
48
|
canEnablePWAGuide: messageCount >= 4,
|
27
49
|
canEnableTrace: messageCount >= 4,
|
28
50
|
hasConversation: messageCount > 0 || sessionCount > 0,
|
29
51
|
isOnboard: true,
|
30
52
|
preference: await this.preferenceStorage.getFromLocalStorage(),
|
31
|
-
settings: user.settings as UserSettings,
|
32
|
-
userId: user.uuid,
|
33
53
|
};
|
34
54
|
}
|
35
55
|
|
36
|
-
|
37
|
-
|
38
|
-
|
56
|
+
updateUserSettings = async (value: DeepPartial<UserSettings>) => {
|
57
|
+
const { keyVaults, ...res } = value;
|
58
|
+
|
59
|
+
return this.userModel.updateSetting({ ...res, keyVaults: JSON.stringify(keyVaults) });
|
39
60
|
};
|
40
61
|
|
41
62
|
resetUserSettings = async () => {
|
42
|
-
return
|
63
|
+
return this.userModel.deleteSetting();
|
43
64
|
};
|
44
65
|
|
45
66
|
async updateAvatar(avatar: string) {
|
46
|
-
await
|
67
|
+
await this.userModel.updateUser({ avatar });
|
47
68
|
}
|
48
69
|
|
49
70
|
async updatePreference(preference: Partial<UserPreference>) {
|
@@ -54,4 +75,18 @@ export class ClientService implements IUserService {
|
|
54
75
|
async updateGuide(guide: Partial<UserGuide>) {
|
55
76
|
throw new Error('Method not implemented.');
|
56
77
|
}
|
78
|
+
|
79
|
+
async makeSureUserExist() {
|
80
|
+
const existUsers = await clientDB.query.users.findMany();
|
81
|
+
|
82
|
+
let user: { id: string };
|
83
|
+
if (existUsers.length === 0) {
|
84
|
+
const result = await clientDB.insert(users).values({ id: this.userId }).returning();
|
85
|
+
user = result[0];
|
86
|
+
} else {
|
87
|
+
user = existUsers[0];
|
88
|
+
}
|
89
|
+
|
90
|
+
return user;
|
91
|
+
}
|
57
92
|
}
|
@@ -1,5 +1,5 @@
|
|
1
|
-
import { ClientService as DeprecatedService } from './
|
2
|
-
import { ClientService } from './
|
1
|
+
import { ClientService as DeprecatedService } from './_deprecated';
|
2
|
+
import { ClientService } from './client';
|
3
3
|
import { ServerService } from './server';
|
4
4
|
|
5
5
|
const clientService =
|
@@ -2,7 +2,7 @@ import { act, renderHook } from '@testing-library/react';
|
|
2
2
|
import { describe, expect, it, vi } from 'vitest';
|
3
3
|
|
4
4
|
import { fileService } from '@/services/file';
|
5
|
-
import { ClientService } from '@/services/file/
|
5
|
+
import { ClientService } from '@/services/file/_deprecated';
|
6
6
|
import { messageService } from '@/services/message';
|
7
7
|
import { imageGenerationService } from '@/services/textToImage';
|
8
8
|
import { uploadService } from '@/services/upload';
|
@@ -5,7 +5,7 @@ import { withSWR } from '~test-utils';
|
|
5
5
|
|
6
6
|
import { DEFAULT_PREFERENCE } from '@/const/user';
|
7
7
|
import { userService } from '@/services/user';
|
8
|
-
import { ClientService } from '@/services/user/
|
8
|
+
import { ClientService } from '@/services/user/_deprecated';
|
9
9
|
import { useUserStore } from '@/store/user';
|
10
10
|
import { preferenceSelectors } from '@/store/user/selectors';
|
11
11
|
import { GlobalServerConfig } from '@/types/serverConfig';
|
@@ -1,198 +0,0 @@
|
|
1
|
-
import { eq } from 'drizzle-orm';
|
2
|
-
import { beforeEach, describe, expect, it } from 'vitest';
|
3
|
-
|
4
|
-
import { clientDB, initializeDB } from '@/database/client/db';
|
5
|
-
import { files, globalFiles, users } from '@/database/schemas';
|
6
|
-
import { clientS3Storage } from '@/services/file/ClientS3';
|
7
|
-
import { UploadFileParams } from '@/types/files';
|
8
|
-
|
9
|
-
import { ClientService } from './pglite';
|
10
|
-
|
11
|
-
const userId = 'file-user';
|
12
|
-
|
13
|
-
const fileService = new ClientService(userId);
|
14
|
-
|
15
|
-
const mockFile = {
|
16
|
-
name: 'mock.png',
|
17
|
-
fileType: 'image/png',
|
18
|
-
size: 1,
|
19
|
-
url: '',
|
20
|
-
};
|
21
|
-
|
22
|
-
beforeEach(async () => {
|
23
|
-
await initializeDB();
|
24
|
-
|
25
|
-
await clientDB.delete(users);
|
26
|
-
await clientDB.delete(globalFiles);
|
27
|
-
// 创建测试数据
|
28
|
-
await clientDB.transaction(async (tx) => {
|
29
|
-
await tx.insert(users).values({ id: userId });
|
30
|
-
});
|
31
|
-
});
|
32
|
-
|
33
|
-
describe('FileService', () => {
|
34
|
-
describe('createFile', () => {
|
35
|
-
it('createFile should save the file to the database', async () => {
|
36
|
-
const localFile: UploadFileParams = {
|
37
|
-
name: 'test',
|
38
|
-
fileType: 'image/png',
|
39
|
-
url: '',
|
40
|
-
size: 1,
|
41
|
-
hash: '123',
|
42
|
-
};
|
43
|
-
|
44
|
-
await clientS3Storage.putObject(
|
45
|
-
'123',
|
46
|
-
new File([new ArrayBuffer(1)], 'test.png', { type: 'image/png' }),
|
47
|
-
);
|
48
|
-
|
49
|
-
const result = await fileService.createFile(localFile);
|
50
|
-
|
51
|
-
expect(result).toMatchObject({ url: 'data:image/png;base64,AA==' });
|
52
|
-
});
|
53
|
-
|
54
|
-
it('should throw error when file is not found in storage during base64 conversion', async () => {
|
55
|
-
const localFile: UploadFileParams = {
|
56
|
-
name: 'test',
|
57
|
-
fileType: 'image/png',
|
58
|
-
url: '',
|
59
|
-
size: 1,
|
60
|
-
hash: 'non-existing-hash',
|
61
|
-
};
|
62
|
-
|
63
|
-
// 不调用 clientS3Storage.putObject,模拟文件不存在的情况
|
64
|
-
|
65
|
-
const promise = fileService.createFile(localFile);
|
66
|
-
|
67
|
-
await expect(promise).rejects.toThrow('file not found');
|
68
|
-
});
|
69
|
-
});
|
70
|
-
|
71
|
-
it('removeFile should delete the file from the database', async () => {
|
72
|
-
const fileId = '1';
|
73
|
-
await clientDB.insert(files).values({ id: fileId, userId, ...mockFile });
|
74
|
-
|
75
|
-
await fileService.removeFile(fileId);
|
76
|
-
|
77
|
-
const result = await clientDB.query.files.findFirst({
|
78
|
-
where: eq(files.id, fileId),
|
79
|
-
});
|
80
|
-
|
81
|
-
expect(result).toBeUndefined();
|
82
|
-
});
|
83
|
-
|
84
|
-
describe('getFile', () => {
|
85
|
-
it('should retrieve and convert local file info to FilePreview', async () => {
|
86
|
-
const fileId = 'rwlijweled';
|
87
|
-
const file = {
|
88
|
-
fileType: 'image/png',
|
89
|
-
size: 1,
|
90
|
-
name: 'test.png',
|
91
|
-
url: 'idb://12312/abc.png',
|
92
|
-
hashId: '123tttt',
|
93
|
-
};
|
94
|
-
|
95
|
-
await clientDB.insert(globalFiles).values(file);
|
96
|
-
|
97
|
-
await clientDB.insert(files).values({
|
98
|
-
id: fileId,
|
99
|
-
userId,
|
100
|
-
...file,
|
101
|
-
createdAt: new Date(1),
|
102
|
-
updatedAt: new Date(2),
|
103
|
-
fileHash: file.hashId,
|
104
|
-
});
|
105
|
-
|
106
|
-
await clientS3Storage.putObject(
|
107
|
-
file.hashId,
|
108
|
-
new File([new ArrayBuffer(1)], file.name, { type: file.fileType }),
|
109
|
-
);
|
110
|
-
|
111
|
-
const result = await fileService.getFile(fileId);
|
112
|
-
|
113
|
-
expect(result).toMatchObject({
|
114
|
-
createdAt: new Date(1),
|
115
|
-
id: 'rwlijweled',
|
116
|
-
size: 1,
|
117
|
-
type: 'image/png',
|
118
|
-
name: 'test.png',
|
119
|
-
updatedAt: new Date(2),
|
120
|
-
});
|
121
|
-
});
|
122
|
-
|
123
|
-
it('should throw an error when the file is not found', async () => {
|
124
|
-
const fileId = 'non-existent';
|
125
|
-
|
126
|
-
const getFilePromise = fileService.getFile(fileId);
|
127
|
-
|
128
|
-
await expect(getFilePromise).rejects.toThrow('file not found');
|
129
|
-
});
|
130
|
-
});
|
131
|
-
|
132
|
-
describe('removeFiles', () => {
|
133
|
-
it('should delete multiple files from the database', async () => {
|
134
|
-
const fileIds = ['1', '2', '3'];
|
135
|
-
|
136
|
-
// 插入测试文件数据
|
137
|
-
await Promise.all(
|
138
|
-
fileIds.map((id) => clientDB.insert(files).values({ id, userId, ...mockFile })),
|
139
|
-
);
|
140
|
-
|
141
|
-
await fileService.removeFiles(fileIds);
|
142
|
-
|
143
|
-
// 验证所有文件都被删除
|
144
|
-
const remainingFiles = await clientDB.query.files.findMany({
|
145
|
-
where: (fields, { inArray }) => inArray(fields.id, fileIds),
|
146
|
-
});
|
147
|
-
|
148
|
-
expect(remainingFiles).toHaveLength(0);
|
149
|
-
});
|
150
|
-
});
|
151
|
-
|
152
|
-
describe('removeAllFiles', () => {
|
153
|
-
it('should clear all files for the user', async () => {
|
154
|
-
// 插入测试文件数据
|
155
|
-
await Promise.all([
|
156
|
-
clientDB.insert(files).values({ id: '1', userId, ...mockFile }),
|
157
|
-
clientDB.insert(files).values({ id: '2', userId, ...mockFile }),
|
158
|
-
]);
|
159
|
-
|
160
|
-
await fileService.removeAllFiles();
|
161
|
-
|
162
|
-
// 验证用户的所有文件都被删除
|
163
|
-
const remainingFiles = await clientDB.query.files.findMany({
|
164
|
-
where: eq(files.userId, userId),
|
165
|
-
});
|
166
|
-
|
167
|
-
expect(remainingFiles).toHaveLength(0);
|
168
|
-
});
|
169
|
-
});
|
170
|
-
|
171
|
-
describe('checkFileHash', () => {
|
172
|
-
it('should return true if file hash exists', async () => {
|
173
|
-
const hash = 'existing-hash';
|
174
|
-
await clientDB.insert(globalFiles).values({
|
175
|
-
...mockFile,
|
176
|
-
hashId: hash,
|
177
|
-
});
|
178
|
-
await clientDB.insert(files).values({
|
179
|
-
id: '1',
|
180
|
-
userId,
|
181
|
-
...mockFile,
|
182
|
-
fileHash: hash,
|
183
|
-
});
|
184
|
-
|
185
|
-
const exists = await fileService.checkFileHash(hash);
|
186
|
-
|
187
|
-
expect(exists).toMatchObject({ isExist: true });
|
188
|
-
});
|
189
|
-
|
190
|
-
it('should return false if file hash does not exist', async () => {
|
191
|
-
const hash = 'non-existing-hash';
|
192
|
-
|
193
|
-
const exists = await fileService.checkFileHash(hash);
|
194
|
-
|
195
|
-
expect(exists).toEqual({ isExist: false });
|
196
|
-
});
|
197
|
-
});
|
198
|
-
});
|
@@ -1,34 +0,0 @@
|
|
1
|
-
import { clientDB } from '@/database/client/db';
|
2
|
-
import { DataImporterRepos } from '@/database/repositories/dataImporter';
|
3
|
-
import { BaseClientService } from '@/services/baseClientService';
|
4
|
-
import { useUserStore } from '@/store/user';
|
5
|
-
import { ImportStage, ImporterEntryData, OnImportCallbacks } from '@/types/importer';
|
6
|
-
import { UserSettings } from '@/types/user/settings';
|
7
|
-
|
8
|
-
export class ClientService extends BaseClientService {
|
9
|
-
private get dataImporter(): DataImporterRepos {
|
10
|
-
return new DataImporterRepos(clientDB as any, this.userId);
|
11
|
-
}
|
12
|
-
|
13
|
-
importSettings = async (settings: UserSettings) => {
|
14
|
-
await useUserStore.getState().importAppSettings(settings);
|
15
|
-
};
|
16
|
-
|
17
|
-
importData = async (data: ImporterEntryData, callbacks?: OnImportCallbacks) => {
|
18
|
-
callbacks?.onStageChange?.(ImportStage.Importing);
|
19
|
-
const time = Date.now();
|
20
|
-
try {
|
21
|
-
const result = await this.dataImporter.importData(data);
|
22
|
-
const duration = Date.now() - time;
|
23
|
-
|
24
|
-
callbacks?.onStageChange?.(ImportStage.Success);
|
25
|
-
callbacks?.onSuccess?.(result, duration);
|
26
|
-
} catch (e) {
|
27
|
-
console.error(e);
|
28
|
-
callbacks?.onStageChange?.(ImportStage.Error);
|
29
|
-
const error = e as Error;
|
30
|
-
|
31
|
-
callbacks?.onError?.({ code: 'ImportError', httpStatus: 0, message: error.message });
|
32
|
-
}
|
33
|
-
};
|
34
|
-
}
|