@neuralinnovations/dataisland-sdk 0.0.1-dev2 → 0.0.1-dev4
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/.editorconfig +4 -1
- package/.eslintrc.json +1 -1
- package/README.md +91 -2
- package/jest.config.ts +3 -3
- package/jest.setup.ts +2 -2
- package/package.json +3 -2
- package/src/appBuilder.ts +6 -6
- package/src/appSdk.ts +6 -6
- package/src/commands/startCommandHandler.ts +2 -2
- package/src/context.ts +3 -3
- package/src/credentials.ts +29 -7
- package/src/disposable.ts +3 -4
- package/src/dto/accessGroupResponse.ts +35 -0
- package/src/dto/chatResponse.ts +104 -0
- package/src/dto/userInfoResponse.ts +11 -1
- package/src/dto/workspacesResponse.ts +49 -0
- package/src/events.ts +13 -13
- package/src/index.ts +24 -12
- package/src/internal/app.impl.ts +25 -28
- package/src/internal/appBuilder.impl.ts +16 -16
- package/src/internal/createApp.impl.ts +3 -3
- package/src/services/commandService.ts +3 -3
- package/src/services/credentialService.ts +3 -3
- package/src/services/middlewareService.ts +4 -4
- package/src/services/organizationService.ts +18 -116
- package/src/services/requestBuilder.ts +40 -15
- package/src/services/responseUtils.ts +32 -0
- package/src/services/rpcService.ts +28 -11
- package/src/services/service.ts +10 -8
- package/src/services/userProfileService.ts +18 -66
- package/src/storages/chat.ts +21 -0
- package/src/storages/chats.ts +17 -0
- package/src/storages/file.impl.ts +69 -0
- package/src/storages/file.ts +28 -0
- package/src/storages/files.impl.ts +213 -0
- package/src/storages/files.ts +38 -0
- package/src/storages/filesPage.ts +27 -0
- package/src/storages/groups.impl.ts +337 -0
- package/src/storages/groups.ts +43 -0
- package/src/storages/organization.impl.ts +68 -0
- package/src/storages/organization.ts +33 -0
- package/src/storages/organizations.impl.ts +191 -0
- package/src/storages/organizations.ts +8 -28
- package/src/storages/userProfile.impl.ts +56 -0
- package/src/storages/userProfile.ts +2 -2
- package/src/storages/workspace.impl.ts +109 -0
- package/src/storages/workspace.ts +49 -0
- package/src/storages/workspaces.impl.ts +212 -0
- package/src/storages/workspaces.ts +53 -0
- package/test/commands.test.ts +8 -8
- package/test/data/test_file.pdf +0 -0
- package/test/disposable.test.ts +3 -3
- package/test/events.test.ts +4 -4
- package/test/files.test.ts +52 -0
- package/test/index.test.ts +42 -83
- package/test/organization.test.ts +57 -0
- package/test/registry.test.ts +8 -8
- package/test/services.test.ts +15 -15
- package/test/setup.ts +52 -0
- package/test/unitTest.test.ts +2 -2
- package/test/workspace.test.ts +71 -0
- package/src/services/organizationImpl.ts +0 -51
- package/src/services/organizationsImpl.ts +0 -55
- package/src/types.ts +0 -86
@@ -1,62 +1,10 @@
|
|
1
|
-
import { Service } from
|
2
|
-
import { RpcService } from
|
3
|
-
import {
|
4
|
-
import { UserInfoResponse } from
|
5
|
-
import { OrganizationService } from
|
6
|
-
|
7
|
-
|
8
|
-
private content?: UserInfoResponse
|
9
|
-
|
10
|
-
get id(): string {
|
11
|
-
if (this.content) {
|
12
|
-
return this.content.user.id
|
13
|
-
}
|
14
|
-
throw new Error('The profile is not loaded.')
|
15
|
-
}
|
16
|
-
|
17
|
-
get name(): string {
|
18
|
-
if (this.content) {
|
19
|
-
return this.content.user.profile.name
|
20
|
-
}
|
21
|
-
throw new Error('The profile is not loaded.')
|
22
|
-
}
|
23
|
-
|
24
|
-
get email(): string {
|
25
|
-
if (this.content) {
|
26
|
-
return this.content.user.profile.email
|
27
|
-
}
|
28
|
-
throw new Error('The profile is not loaded.')
|
29
|
-
}
|
30
|
-
|
31
|
-
get isDeleted(): boolean {
|
32
|
-
if (this.content) {
|
33
|
-
return this.content.user.isDeleted
|
34
|
-
}
|
35
|
-
throw new Error('The profile is not loaded.')
|
36
|
-
}
|
37
|
-
|
38
|
-
get createdAt(): Date {
|
39
|
-
if (this.content) {
|
40
|
-
return new Date(this.content.user.created_at)
|
41
|
-
}
|
42
|
-
throw new Error('The profile is not loaded.')
|
43
|
-
}
|
44
|
-
|
45
|
-
get modifiedAt(): Date {
|
46
|
-
if (this.content) {
|
47
|
-
return new Date(this.content.user.modified_at)
|
48
|
-
}
|
49
|
-
throw new Error('The profile is not loaded.')
|
50
|
-
}
|
51
|
-
|
52
|
-
initFrom(content: UserInfoResponse) {
|
53
|
-
this.content = content
|
54
|
-
this.dispatch({
|
55
|
-
type: UserEvent.CHANGED,
|
56
|
-
data: this
|
57
|
-
})
|
58
|
-
}
|
59
|
-
}
|
1
|
+
import { Service } from "./service"
|
2
|
+
import { RpcService } from "./rpcService"
|
3
|
+
import { UserProfile } from "../storages/userProfile"
|
4
|
+
import { UserInfoResponse } from "../dto/userInfoResponse"
|
5
|
+
import { OrganizationService } from "./organizationService"
|
6
|
+
import { UserProfileImpl } from "../storages/userProfile.impl"
|
7
|
+
import { ResponseUtils } from "./responseUtils"
|
60
8
|
|
61
9
|
export class UserProfileService extends Service {
|
62
10
|
private readonly impl: UserProfileImpl = new UserProfileImpl()
|
@@ -65,22 +13,26 @@ export class UserProfileService extends Service {
|
|
65
13
|
return this.impl
|
66
14
|
}
|
67
15
|
|
68
|
-
async fetch(
|
16
|
+
async fetch() {
|
69
17
|
const rpc = this.resolve(RpcService) as RpcService
|
70
|
-
const response = await rpc.requestBuilder(
|
71
|
-
if (
|
72
|
-
|
18
|
+
const response = await rpc.requestBuilder("api/v1/Users/self2").sendGet()
|
19
|
+
if (ResponseUtils.isFail(response)) {
|
20
|
+
await ResponseUtils.throwError("Failed to fetch user profile", response)
|
73
21
|
}
|
74
22
|
const content = (await response.json()) as UserInfoResponse
|
23
|
+
|
24
|
+
// init user profile from the server's response
|
75
25
|
this.impl.initFrom(content)
|
76
26
|
|
77
27
|
const organizationService = this.resolve(
|
78
28
|
OrganizationService
|
79
29
|
) as OrganizationService
|
80
|
-
|
81
|
-
|
30
|
+
|
31
|
+
// init organization service from user profile
|
32
|
+
await organizationService.initFrom(
|
82
33
|
content.adminInOrganization,
|
83
|
-
content.organizations
|
34
|
+
content.organizations,
|
35
|
+
content.user.settings
|
84
36
|
)
|
85
37
|
}
|
86
38
|
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
export type ChatId = string
|
2
|
+
|
3
|
+
export enum ChatAnswer {
|
4
|
+
SHORT = "short",
|
5
|
+
LONG = "long"
|
6
|
+
}
|
7
|
+
|
8
|
+
export abstract class Chat {
|
9
|
+
/**
|
10
|
+
* Chat id.
|
11
|
+
*/
|
12
|
+
abstract get id(): ChatId
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Chat name.
|
16
|
+
*/
|
17
|
+
abstract get name(): string
|
18
|
+
|
19
|
+
abstract question(message: string, answer?: ChatAnswer): Promise<void>
|
20
|
+
}
|
21
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { EventDispatcher } from "../events"
|
2
|
+
import { Chat } from "./chat"
|
3
|
+
|
4
|
+
export enum ChatsEvent {
|
5
|
+
ADDED = "added",
|
6
|
+
REMOVED = "removed"
|
7
|
+
}
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Chats storage.
|
11
|
+
*/
|
12
|
+
export abstract class Chats extends EventDispatcher<ChatsEvent, Chat> {
|
13
|
+
/**
|
14
|
+
* Create new chat.
|
15
|
+
*/
|
16
|
+
abstract create(): Promise<Chat>
|
17
|
+
}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import { Context } from "../context"
|
2
|
+
import { Disposable } from "../disposable"
|
3
|
+
import { FileDto, FileProgressDto } from "../dto/workspacesResponse"
|
4
|
+
import { RpcService } from "../services/rpcService"
|
5
|
+
import { ResponseUtils } from "../services/responseUtils"
|
6
|
+
import { File } from "./file"
|
7
|
+
|
8
|
+
export class FileImpl extends File implements Disposable {
|
9
|
+
private _isDisposed: boolean = false
|
10
|
+
private _content?: FileDto
|
11
|
+
|
12
|
+
constructor(private readonly context: Context) {
|
13
|
+
super()
|
14
|
+
}
|
15
|
+
|
16
|
+
public initFrom(file: FileDto): File {
|
17
|
+
this._content = file
|
18
|
+
|
19
|
+
return this
|
20
|
+
}
|
21
|
+
|
22
|
+
get isDisposed(): boolean {
|
23
|
+
return this._isDisposed
|
24
|
+
}
|
25
|
+
|
26
|
+
dispose(): void {
|
27
|
+
this._isDisposed = true
|
28
|
+
}
|
29
|
+
|
30
|
+
get id(): string {
|
31
|
+
return <string>this._content?.id
|
32
|
+
}
|
33
|
+
|
34
|
+
get name(): string {
|
35
|
+
return <string>this._content?.name
|
36
|
+
}
|
37
|
+
|
38
|
+
async url(): Promise<string> {
|
39
|
+
const response = await this.context
|
40
|
+
.resolve(RpcService)
|
41
|
+
?.requestBuilder("api/v1/Files/url")
|
42
|
+
.searchParam("id", this.id)
|
43
|
+
.sendGet()
|
44
|
+
|
45
|
+
if (ResponseUtils.isFail(response)) {
|
46
|
+
await ResponseUtils.throwError(
|
47
|
+
`Failed to get file ${this.id} url`,
|
48
|
+
response
|
49
|
+
)
|
50
|
+
}
|
51
|
+
|
52
|
+
return (await response!.json()).url
|
53
|
+
}
|
54
|
+
|
55
|
+
async status(): Promise<FileProgressDto> {
|
56
|
+
const response = await this.context
|
57
|
+
.resolve(RpcService)
|
58
|
+
?.requestBuilder("api/v1/Files/fetch")
|
59
|
+
.searchParam("id", this.id)
|
60
|
+
.sendGet()
|
61
|
+
|
62
|
+
if (ResponseUtils.isFail(response)) {
|
63
|
+
await ResponseUtils.throwError(`Failed to get file ${this.id}`, response)
|
64
|
+
}
|
65
|
+
|
66
|
+
const content = await response!.json()
|
67
|
+
return content.progress as FileProgressDto
|
68
|
+
}
|
69
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { FileProgressDto } from "../dto/workspacesResponse"
|
2
|
+
|
3
|
+
export type FileId = string
|
4
|
+
|
5
|
+
/**
|
6
|
+
* File.
|
7
|
+
*/
|
8
|
+
export abstract class File {
|
9
|
+
/**
|
10
|
+
* File id.
|
11
|
+
*/
|
12
|
+
abstract get id(): FileId
|
13
|
+
|
14
|
+
/**
|
15
|
+
* File name.
|
16
|
+
*/
|
17
|
+
abstract get name(): string
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Get temporary url.
|
21
|
+
*/
|
22
|
+
abstract url(): Promise<string>
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Get file status.
|
26
|
+
*/
|
27
|
+
abstract status(): Promise<FileProgressDto>
|
28
|
+
}
|
@@ -0,0 +1,213 @@
|
|
1
|
+
import { Context } from "../context"
|
2
|
+
import { Disposable } from "../disposable"
|
3
|
+
import { FileDto, FileListResponse } from "../dto/workspacesResponse"
|
4
|
+
import { RpcService } from "../services/rpcService"
|
5
|
+
import { FileImpl } from "./file.impl"
|
6
|
+
import { Files, FilesEvent, UploadFile } from "./files"
|
7
|
+
import { WorkspaceImpl } from "./workspace.impl"
|
8
|
+
import { ResponseUtils } from "../services/responseUtils"
|
9
|
+
import { File } from "./file"
|
10
|
+
import { FilesPage } from "./filesPage"
|
11
|
+
|
12
|
+
export class FilesPageImpl extends FilesPage implements Disposable {
|
13
|
+
private _isDisposed: boolean = false
|
14
|
+
|
15
|
+
public files: File[] = []
|
16
|
+
public total: number = 0
|
17
|
+
public filesPerPage: number = 0
|
18
|
+
public page: number = 0
|
19
|
+
|
20
|
+
get pages(): number {
|
21
|
+
return Math.ceil(Math.max(this.total / this.filesPerPage, 1.0))
|
22
|
+
}
|
23
|
+
|
24
|
+
get isDisposed(): boolean {
|
25
|
+
return this._isDisposed
|
26
|
+
}
|
27
|
+
|
28
|
+
dispose(): void {
|
29
|
+
this._isDisposed = true
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
export class FilesImpl extends Files {
|
34
|
+
constructor(
|
35
|
+
private readonly workspace: WorkspaceImpl,
|
36
|
+
private readonly context: Context
|
37
|
+
) {
|
38
|
+
super()
|
39
|
+
}
|
40
|
+
|
41
|
+
// Object used as files page data, returned by "query"
|
42
|
+
public filesList?: FilesPage
|
43
|
+
|
44
|
+
async upload(file: any): Promise<File> {
|
45
|
+
return await this.internalUpload(file)
|
46
|
+
}
|
47
|
+
|
48
|
+
async delete(id: string): Promise<void> {
|
49
|
+
return await this.internalDeleteFile(id)
|
50
|
+
}
|
51
|
+
|
52
|
+
async query(query: string, page: number, limit: number): Promise<FilesPage> {
|
53
|
+
return await this.internalQuery(query, page, limit)
|
54
|
+
}
|
55
|
+
|
56
|
+
//----------------------------------------------------------------------------
|
57
|
+
// INTERNALS
|
58
|
+
//----------------------------------------------------------------------------
|
59
|
+
|
60
|
+
/**
|
61
|
+
* Delete organization.
|
62
|
+
* @param id
|
63
|
+
*/
|
64
|
+
async internalDeleteFile(id: string): Promise<void> {
|
65
|
+
if (id === undefined || id === null) {
|
66
|
+
throw new Error("File delete, id is undefined or null")
|
67
|
+
}
|
68
|
+
if (id.length === 0 || id.trim().length === 0) {
|
69
|
+
throw new Error("File delete, id is empty")
|
70
|
+
}
|
71
|
+
|
72
|
+
const response = await this.context
|
73
|
+
.resolve(RpcService)
|
74
|
+
?.requestBuilder("/api/v1/Files")
|
75
|
+
.searchParam("id", id)
|
76
|
+
.sendDelete()
|
77
|
+
if (ResponseUtils.isFail(response)) {
|
78
|
+
await ResponseUtils.throwError(`File ${id} delete, failed`, response)
|
79
|
+
}
|
80
|
+
const file = <FileImpl>this.filesList!.files.find(f => f.id === id)
|
81
|
+
const index = this.filesList!.files.indexOf(file)
|
82
|
+
if (index < 0) {
|
83
|
+
throw new Error("Organization delete, index is not found")
|
84
|
+
}
|
85
|
+
|
86
|
+
// remove file from collection
|
87
|
+
this.filesList!.files.splice(index, 1)
|
88
|
+
|
89
|
+
// dispatch event, file removed
|
90
|
+
this.dispatch({
|
91
|
+
type: FilesEvent.REMOVED,
|
92
|
+
data: file
|
93
|
+
})
|
94
|
+
|
95
|
+
// dispose file
|
96
|
+
file.dispose()
|
97
|
+
}
|
98
|
+
|
99
|
+
async internalQuery(
|
100
|
+
query: string,
|
101
|
+
page: number,
|
102
|
+
limit: number
|
103
|
+
): Promise<FilesPage> {
|
104
|
+
|
105
|
+
// check page
|
106
|
+
if (page === undefined || page === null) {
|
107
|
+
throw new Error("File fetch, page is undefined or null")
|
108
|
+
}
|
109
|
+
if (page < 0) {
|
110
|
+
throw new Error("File fetch, page is negative")
|
111
|
+
}
|
112
|
+
|
113
|
+
// check limit
|
114
|
+
if (limit === undefined || limit === null) {
|
115
|
+
throw new Error("File fetch, limit is undefined or null")
|
116
|
+
}
|
117
|
+
if (limit === 0) {
|
118
|
+
throw new Error("File fetch, limit is 0")
|
119
|
+
}
|
120
|
+
|
121
|
+
// send request to the server
|
122
|
+
const response = await this.context
|
123
|
+
.resolve(RpcService)
|
124
|
+
?.requestBuilder("api/v1/Files/list")
|
125
|
+
|
126
|
+
.searchParam("workspaceId", this.workspace.id)
|
127
|
+
.searchParam("organizationId", this.workspace.organization.id)
|
128
|
+
.searchParam("query", query)
|
129
|
+
.searchParam("page", page.toString())
|
130
|
+
.searchParam("limit", limit.toString())
|
131
|
+
.sendGet()
|
132
|
+
|
133
|
+
// check response status
|
134
|
+
if (ResponseUtils.isFail(response)) {
|
135
|
+
await ResponseUtils.throwError(
|
136
|
+
`Files fetch query:${query}, page:${page}, limit:${limit}, failed`,
|
137
|
+
response
|
138
|
+
)
|
139
|
+
}
|
140
|
+
|
141
|
+
// parse files from the server's response
|
142
|
+
const files = (await response!.json()) as FileListResponse
|
143
|
+
|
144
|
+
// create files list
|
145
|
+
const filesList = new FilesPageImpl()
|
146
|
+
filesList.total = files.totalFilesCount
|
147
|
+
filesList.filesPerPage = files.filesPerPage
|
148
|
+
filesList.page = page
|
149
|
+
|
150
|
+
// init files from the server's response
|
151
|
+
for (const fl of files.files) {
|
152
|
+
|
153
|
+
// create file implementation
|
154
|
+
const file = new FileImpl(this.context).initFrom(fl)
|
155
|
+
|
156
|
+
// add file to the collection
|
157
|
+
filesList.files.push(file)
|
158
|
+
|
159
|
+
// dispatch event, file added
|
160
|
+
this.dispatch({
|
161
|
+
type: FilesEvent.ADDED,
|
162
|
+
data: file
|
163
|
+
})
|
164
|
+
}
|
165
|
+
|
166
|
+
// set files list
|
167
|
+
this.filesList = filesList
|
168
|
+
|
169
|
+
return filesList
|
170
|
+
}
|
171
|
+
|
172
|
+
async internalUpload(file: UploadFile): Promise<File> {
|
173
|
+
// check file
|
174
|
+
if (file === undefined || file === null) {
|
175
|
+
throw new Error("File upload, file is undefined or null")
|
176
|
+
}
|
177
|
+
|
178
|
+
// form data to send
|
179
|
+
const form = new FormData()
|
180
|
+
form.append("organizationId", this.workspace.organization.id)
|
181
|
+
form.append("workspaceId", this.workspace.id)
|
182
|
+
form.append("name", file.name)
|
183
|
+
form.append("file", file, file.name)
|
184
|
+
|
185
|
+
// send request to the server
|
186
|
+
const response = await this.context
|
187
|
+
.resolve(RpcService)
|
188
|
+
?.requestBuilder("api/v1/Files")
|
189
|
+
.sendPostFormData(form)
|
190
|
+
|
191
|
+
// check response status
|
192
|
+
if (ResponseUtils.isFail(response)) {
|
193
|
+
await ResponseUtils.throwError(`File upload ${file.name}`, response)
|
194
|
+
}
|
195
|
+
|
196
|
+
// parse file from the server's response
|
197
|
+
const result = (await response!.json()).file as FileDto
|
198
|
+
|
199
|
+
// create file implementation
|
200
|
+
const fileImpl = new FileImpl(this.context).initFrom(result)
|
201
|
+
|
202
|
+
// TODO: why is this here?
|
203
|
+
this.filesList?.files.push(fileImpl)
|
204
|
+
|
205
|
+
// dispatch event, file added
|
206
|
+
this.dispatch({
|
207
|
+
type: FilesEvent.ADDED,
|
208
|
+
data: fileImpl
|
209
|
+
})
|
210
|
+
|
211
|
+
return fileImpl
|
212
|
+
}
|
213
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { EventDispatcher } from "../events"
|
2
|
+
import { File, FileId } from "./file"
|
3
|
+
import { FilesPage } from "./filesPage"
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Files event.
|
7
|
+
*/
|
8
|
+
export enum FilesEvent {
|
9
|
+
ADDED = "added",
|
10
|
+
REMOVED = "removed"
|
11
|
+
}
|
12
|
+
|
13
|
+
/**
|
14
|
+
* Upload file.
|
15
|
+
*/
|
16
|
+
export type UploadFile = globalThis.File
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Files storage.
|
20
|
+
*/
|
21
|
+
export abstract class Files extends EventDispatcher<FilesEvent, File> {
|
22
|
+
/**
|
23
|
+
* Get file by id.
|
24
|
+
*/
|
25
|
+
abstract upload(file: UploadFile): Promise<File>
|
26
|
+
|
27
|
+
/**
|
28
|
+
* Delete file.
|
29
|
+
* @param id
|
30
|
+
*/
|
31
|
+
abstract delete(id: FileId): Promise<void>
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Query files.
|
35
|
+
*/
|
36
|
+
abstract query(query: string, page: number, limit: number): Promise<FilesPage>
|
37
|
+
}
|
38
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { File } from "./file"
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Files page.
|
5
|
+
*/
|
6
|
+
export abstract class FilesPage {
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Get files.
|
10
|
+
*/
|
11
|
+
abstract get files(): File[]
|
12
|
+
|
13
|
+
/**
|
14
|
+
* Get pages count.
|
15
|
+
*/
|
16
|
+
abstract get pages(): number
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Get total count.
|
20
|
+
*/
|
21
|
+
abstract get total(): number
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Get current page.
|
25
|
+
*/
|
26
|
+
abstract get page(): number
|
27
|
+
}
|