@neuralinnovations/dataisland-sdk 0.0.1-dev1 → 0.0.1-dev10

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.
Files changed (74) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +174 -1
  3. package/dist/dataisland-sdk.d.ts +1594 -0
  4. package/dist/dataisland-sdk.js +2890 -0
  5. package/dist/dataisland-sdk.js.map +1 -0
  6. package/index.d.ts +1 -0
  7. package/index.js +1 -0
  8. package/package.json +41 -3
  9. package/src/appBuilder.ts +24 -5
  10. package/src/commands/startCommandHandler.ts +14 -0
  11. package/src/context.ts +31 -0
  12. package/src/credentials.ts +31 -9
  13. package/src/dataIslandApp.ts +59 -0
  14. package/src/disposable.ts +4 -5
  15. package/src/dto/accessGroupResponse.ts +35 -0
  16. package/src/dto/chatResponse.ts +103 -0
  17. package/src/dto/userInfoResponse.ts +47 -0
  18. package/src/dto/workspacesResponse.ts +49 -0
  19. package/src/events.ts +13 -17
  20. package/src/index.ts +44 -18
  21. package/src/internal/app.impl.ts +97 -32
  22. package/src/internal/appBuilder.impl.ts +39 -12
  23. package/src/internal/createApp.impl.ts +5 -5
  24. package/src/middleware.ts +1 -1
  25. package/src/services/commandService.ts +44 -0
  26. package/src/services/credentialService.ts +3 -3
  27. package/src/services/middlewareService.ts +8 -6
  28. package/src/services/organizationService.ts +28 -0
  29. package/src/services/requestBuilder.ts +127 -0
  30. package/src/services/responseUtils.ts +32 -0
  31. package/src/services/rpcService.ts +129 -52
  32. package/src/services/service.ts +10 -8
  33. package/src/services/userProfileService.ts +38 -0
  34. package/src/storages/chats/answer.impl.ts +163 -0
  35. package/src/storages/chats/answer.ts +42 -0
  36. package/src/storages/chats/chat.impl.ts +87 -0
  37. package/src/storages/chats/chat.ts +38 -0
  38. package/src/storages/chats/chats.impl.ts +142 -0
  39. package/src/storages/chats/chats.ts +47 -0
  40. package/src/storages/files/file.impl.ts +69 -0
  41. package/src/storages/files/file.ts +28 -0
  42. package/src/storages/files/files.impl.ts +213 -0
  43. package/src/storages/files/files.ts +38 -0
  44. package/src/storages/files/filesPage.ts +27 -0
  45. package/src/storages/groups/groups.impl.ts +326 -0
  46. package/src/storages/groups/groups.ts +101 -0
  47. package/src/storages/organizations/organization.impl.ts +95 -0
  48. package/src/storages/organizations/organization.ts +44 -0
  49. package/src/storages/organizations/organizations.impl.ts +197 -0
  50. package/src/storages/organizations/organizations.ts +56 -0
  51. package/src/storages/user/userProfile.impl.ts +56 -0
  52. package/src/storages/user/userProfile.ts +42 -0
  53. package/src/storages/workspaces/workspace.impl.ts +109 -0
  54. package/src/storages/workspaces/workspace.ts +49 -0
  55. package/src/storages/workspaces/workspaces.impl.ts +212 -0
  56. package/src/storages/workspaces/workspaces.ts +53 -0
  57. package/src/unitTest.ts +53 -0
  58. package/.browserslistrc +0 -5
  59. package/.editorconfig +0 -22
  60. package/.eslintrc.json +0 -44
  61. package/.github/workflows/publish-npm.yml +0 -28
  62. package/.prettierignore +0 -1
  63. package/.prettierrc +0 -11
  64. package/.yarnrc +0 -2
  65. package/babel.config.js +0 -6
  66. package/jest.config.ts +0 -199
  67. package/src/appSdk.ts +0 -40
  68. package/src/internal/context.ts +0 -13
  69. package/src/types.ts +0 -110
  70. package/test/disposable.test.ts +0 -39
  71. package/test/events.test.ts +0 -151
  72. package/test/index.test.ts +0 -83
  73. package/test/registry.test.ts +0 -44
  74. package/tsconfig.json +0 -31
@@ -0,0 +1,28 @@
1
+ import { Service } from "./service"
2
+ import { Organizations } from "../storages/organizations/organizations"
3
+ import { OrganizationDto, UserSettings } from "../dto/userInfoResponse"
4
+ import { OrganizationsImpl } from "../storages/organizations/organizations.impl"
5
+
6
+ export class OrganizationService extends Service {
7
+ private _impl?: OrganizationsImpl
8
+
9
+ private get impl(): OrganizationsImpl {
10
+ return this._impl ?? (this._impl = new OrganizationsImpl(this.context))
11
+ }
12
+
13
+ get organizations(): Organizations {
14
+ return this.impl
15
+ }
16
+
17
+ async initFrom(
18
+ adminInOrganization: string[],
19
+ organizations: OrganizationDto[],
20
+ settings?: UserSettings | null
21
+ ): Promise<void> {
22
+ await this.impl.internalInitFrom(
23
+ adminInOrganization,
24
+ organizations,
25
+ settings
26
+ )
27
+ }
28
+ }
@@ -0,0 +1,127 @@
1
+ export class RequestBuilder {
2
+ private readonly _headers: Headers
3
+ private readonly _searchParams: URLSearchParams
4
+
5
+ constructor(
6
+ private readonly _url: URL,
7
+ private readonly _request: (req: Request) => Promise<Response>
8
+ ) {
9
+ this._headers = new Headers()
10
+ this._searchParams = new URLSearchParams()
11
+ }
12
+
13
+ public header(name: string, value: string): RequestBuilder {
14
+ this._headers.set(name, value)
15
+ return this
16
+ }
17
+
18
+ public headers(
19
+ headers?: [string, string][] | Record<string, string> | Headers
20
+ ): RequestBuilder {
21
+ if (headers === undefined) {
22
+ return this
23
+ }
24
+ if (headers instanceof Headers) {
25
+ headers.forEach((value, name) => {
26
+ this._headers.set(name, value)
27
+ })
28
+ } else {
29
+ Object.entries(headers).forEach(([name, value]) => {
30
+ this._headers.set(name, value)
31
+ })
32
+ }
33
+ return this
34
+ }
35
+
36
+ public searchParam(name: string, value: string): RequestBuilder {
37
+ this._searchParams.set(name, value)
38
+ return this
39
+ }
40
+
41
+ public searchParams(searchParams?: Map<string, string>): RequestBuilder {
42
+ if (searchParams === undefined) {
43
+ return this
44
+ }
45
+ searchParams.forEach((value, name) => {
46
+ this._searchParams.set(name, value)
47
+ })
48
+ return this
49
+ }
50
+
51
+ public async sendPostFormData(body: FormData): Promise<Response> {
52
+ const url = this._url
53
+
54
+ // set search params
55
+ url.search = this._searchParams.toString()
56
+
57
+ // create request
58
+ const req = new Request(url, {
59
+ method: "POST",
60
+ headers: this._headers,
61
+ body
62
+ })
63
+
64
+ // discard content type
65
+ const reqAny = req as any
66
+ reqAny.discardContentType = true
67
+
68
+ return await this._request(
69
+ req
70
+ )
71
+ }
72
+
73
+ public async sendPostJson(body: object | null | undefined): Promise<Response> {
74
+ const url = this._url
75
+ url.search = this._searchParams.toString()
76
+ let json: string | null | undefined = null
77
+ if (body !== undefined && body !== null && typeof body === "object") {
78
+ json = JSON.stringify(body)
79
+ }
80
+ const request = new Request(url, {
81
+ method: "POST",
82
+ headers: this._headers,
83
+ body: json
84
+ })
85
+ return await this._request(
86
+ request
87
+ )
88
+ }
89
+
90
+ public async sendGet(): Promise<Response> {
91
+ const url = this._url
92
+ url.search = this._searchParams.toString()
93
+ return await this._request(
94
+ new Request(url, {
95
+ method: "GET",
96
+ headers: this._headers
97
+ })
98
+ )
99
+ }
100
+
101
+ public async sendDelete(): Promise<Response> {
102
+ const url = this._url
103
+ url.search = this._searchParams.toString()
104
+ return await this._request(
105
+ new Request(url, {
106
+ method: "DELETE",
107
+ headers: this._headers
108
+ })
109
+ )
110
+ }
111
+
112
+ public async sendPutJson(body: object | null | undefined): Promise<Response> {
113
+ const url = this._url
114
+ url.search = this._searchParams.toString()
115
+ let json: string | null | undefined = null
116
+ if (body !== undefined && body !== null && typeof body === "object") {
117
+ json = JSON.stringify(body)
118
+ }
119
+ return await this._request(
120
+ new Request(url, {
121
+ method: "PUT",
122
+ headers: this._headers,
123
+ body: json
124
+ })
125
+ )
126
+ }
127
+ }
@@ -0,0 +1,32 @@
1
+ export class ResponseUtils {
2
+ public static isOk(response?: Response | null): boolean {
3
+ return response !== undefined && response !== null && response.ok
4
+ }
5
+
6
+ public static isFail(response?: Response | null): boolean {
7
+ return !ResponseUtils.isOk(response)
8
+ }
9
+
10
+ public static async throwError(
11
+ message: string,
12
+ response: Response | undefined | null
13
+ ): Promise<void> {
14
+ if (response === undefined) {
15
+ throw new Error(`${message}. Response is undefined`)
16
+ }
17
+ if (response === null) {
18
+ throw new Error(`${message}. Response is null`)
19
+ }
20
+ let errorBody: string = ""
21
+ if (response) {
22
+ try {
23
+ errorBody = (await response.text()) ?? ""
24
+ } catch (e) {
25
+ console.error(e)
26
+ }
27
+ }
28
+ throw new Error(
29
+ `${message}. Response fail. Status: ${response?.status},${response?.statusText}, body: ${errorBody}`
30
+ )
31
+ }
32
+ }
@@ -1,72 +1,149 @@
1
- import { Service, type ServiceContext } from './service'
2
- import { MiddlewareService } from './middlewareService'
1
+ import { Service, type ServiceContext } from "./service"
2
+ import { MiddlewareService } from "./middlewareService"
3
+ import { RequestBuilder } from "./requestBuilder"
3
4
 
5
+ /**
6
+ * Options for the RpcService.
7
+ */
8
+ export interface RequestOptions {
9
+ searchParams?: Map<string, string>
10
+ headers?: [string, string][] | Record<string, string> | Headers
11
+ }
12
+
13
+ /**
14
+ * RPC service.
15
+ */
4
16
  export class RpcService extends Service {
5
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
- async request(req: Request): Promise<Response> {
7
- throw new Error('Not implemented')
8
- }
9
17
 
10
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
11
- buildUrl(path: string): string {
12
- throw new Error('Not implemented')
13
- }
18
+ constructor(
19
+ serviceContext: ServiceContext,
20
+ /**
21
+ * Host of the RPC service.
22
+ * It is not used if you use the `urlBuilder` option.
23
+ */
24
+ public readonly host: string,
25
+ /**
26
+ * Options for the RpcService.
27
+ */
28
+ private readonly options?: {
29
+ // make it possible to override the url builder
30
+ urlBuilder?: (path: string) => URL
31
+ // make it possible to override the fetch method
32
+ fetchMethod?: (uri: Request) => Promise<Response>
33
+ }
34
+ ) {
35
+ super(serviceContext)
36
+
37
+ serviceContext.onRegister = async () => {
38
+ serviceContext.resolve(MiddlewareService)?.useMiddleware((req, next) => {
39
+ if (!req.headers.has("accept")) {
40
+ req.headers.set("accept", "text/plain")
41
+ }
14
42
 
15
- async get(path: string): Promise<Response> {
16
- return await this.request(
17
- new Request(this.buildUrl(path), {
18
- method: 'GET'
43
+ if ((req as any).discardContentType) {
44
+ delete (req as any).discardContentType
45
+ } else {
46
+ req.headers.set("content-type", "application/json")
47
+ }
48
+
49
+ return next(req)
19
50
  })
20
- )
51
+ }
21
52
  }
22
53
 
23
- async post(path: string, body?: BodyInit | null): Promise<Response> {
24
- return await this.request(
25
- new Request(this.buildUrl(path), {
26
- method: 'POST',
27
- body
54
+ /**
55
+ * Request method.
56
+ */
57
+ async request(req: Request): Promise<Response> {
58
+ const middlewareService = this.resolve(MiddlewareService)
59
+ if (middlewareService !== undefined) {
60
+ return await middlewareService.process(req, async req => {
61
+ return (await this.options?.fetchMethod?.(req)) ?? (await fetch(req))
28
62
  })
29
- )
63
+ }
64
+ return (await this.options?.fetchMethod?.(req)) ?? (await fetch(req))
30
65
  }
31
66
 
32
- async put(path: string, body?: BodyInit | null): Promise<Response> {
33
- return await this.request(
34
- new Request(this.buildUrl(path), {
35
- method: 'PUT',
36
- body
37
- })
38
- )
67
+ /**
68
+ * Build URL.
69
+ * @param path
70
+ */
71
+ buildUrl(path: string): URL {
72
+ if (this.options !== undefined && this.options.urlBuilder !== undefined) {
73
+ return this.options.urlBuilder(path)
74
+ }
75
+ if (this.host.endsWith("/") && path.startsWith("/")) {
76
+ return new URL(`${this.host}${path.slice(1)}`)
77
+ }
78
+ if (!this.host.endsWith("/") && !path.startsWith("/")) {
79
+ return new URL(`${this.host}/${path}`)
80
+ }
81
+ return new URL(`${this.host}${path}`)
39
82
  }
40
83
 
41
- async delete(path: string): Promise<Response> {
42
- return await this.request(
43
- new Request(this.buildUrl(path), {
44
- method: 'DELETE'
45
- })
46
- )
84
+ /**
85
+ * Create a request builder.
86
+ * @param path
87
+ */
88
+ requestBuilder(path: string): RequestBuilder {
89
+ return new RequestBuilder(this.buildUrl(path), this.request.bind(this))
47
90
  }
48
- }
49
91
 
50
- export class RpcServiceImpl extends RpcService {
51
- constructor(serviceContext: ServiceContext, public readonly host: string) {
52
- super(serviceContext)
92
+ /**
93
+ * Send a GET request.
94
+ * @param path
95
+ * @param options
96
+ */
97
+ async get(path: string, options?: RequestOptions): Promise<Response> {
98
+ return this.requestBuilder(path)
99
+ .searchParams(options?.searchParams)
100
+ .headers(options?.headers)
101
+ .sendGet()
53
102
  }
54
103
 
55
- override async request(req: Request): Promise<Response> {
56
- const middlewareService = this.resolve(MiddlewareService)
57
- if (middlewareService !== undefined) {
58
- return await middlewareService.process(req, async req => {
59
- return await fetch(req)
60
- })
61
- } else {
62
- return await fetch(req)
63
- }
104
+ /**
105
+ * Send a POST request.
106
+ * @param path
107
+ * @param body JSON object
108
+ * @param options
109
+ */
110
+ async post(
111
+ path: string,
112
+ body: object | null | undefined,
113
+ options?: RequestOptions
114
+ ): Promise<Response> {
115
+ return this.requestBuilder(path)
116
+ .searchParams(options?.searchParams)
117
+ .headers(options?.headers)
118
+ .sendPostJson(body)
64
119
  }
65
120
 
66
- override buildUrl(path: string): string {
67
- if (this.host.endsWith('/') && path.startsWith('/')) {
68
- return `${this.host}${path.slice(1)}`
69
- }
70
- return `${this.host}${path}`
121
+ /**
122
+ * Send a PUT request.
123
+ * @param path
124
+ * @param body JSON object
125
+ * @param options
126
+ */
127
+ async put(
128
+ path: string,
129
+ body: object | null | undefined,
130
+ options?: RequestOptions
131
+ ): Promise<Response> {
132
+ return this.requestBuilder(path)
133
+ .searchParams(options?.searchParams)
134
+ .headers(options?.headers)
135
+ .sendPutJson(body)
136
+ }
137
+
138
+ /**
139
+ * Send a DELETE request.
140
+ * @param path
141
+ * @param options
142
+ */
143
+ async delete(path: string, options?: RequestOptions): Promise<Response> {
144
+ return this.requestBuilder(path)
145
+ .searchParams(options?.searchParams)
146
+ .headers(options?.headers)
147
+ .sendDelete()
71
148
  }
72
149
  }
@@ -1,12 +1,13 @@
1
- import { type Context } from '../internal/context'
2
- import { type Constructor } from '../internal/registry'
3
- import { type DisposableContainer, type Lifetime } from '../disposable'
1
+ import { type Context } from "../context"
2
+ import { type Constructor } from "../internal/registry"
3
+ import { type DisposableContainer, type Lifetime } from "../disposable"
4
4
 
5
5
  export class ServiceContext {
6
6
  constructor(
7
7
  public readonly context: Context,
8
8
  private readonly disposableContainer: DisposableContainer
9
- ) {}
9
+ ) {
10
+ }
10
11
 
11
12
  public get lifetime(): Lifetime {
12
13
  return this.disposableContainer.lifetime
@@ -16,15 +17,15 @@ export class ServiceContext {
16
17
  return this.context.resolve(type)
17
18
  }
18
19
 
19
- public async onRegister(): Promise<void> {
20
+ public onRegister: () => Promise<void> = async (): Promise<void> => {
20
21
  await Promise.resolve()
21
22
  }
22
23
 
23
- public async onStart(): Promise<void> {
24
+ public onStart: () => Promise<void> = async (): Promise<void> => {
24
25
  await Promise.resolve()
25
26
  }
26
27
 
27
- public onUnregister(): void {
28
+ public onUnregister: () => void = (): void => {
28
29
  // do nothing
29
30
  }
30
31
  }
@@ -42,5 +43,6 @@ export abstract class Service {
42
43
  return this.serviceContext.context
43
44
  }
44
45
 
45
- public constructor(private readonly serviceContext: ServiceContext) {}
46
+ public constructor(private readonly serviceContext: ServiceContext) {
47
+ }
46
48
  }
@@ -0,0 +1,38 @@
1
+ import { Service } from "./service"
2
+ import { RpcService } from "./rpcService"
3
+ import { UserProfile } from "../storages/user/userProfile"
4
+ import { UserInfoResponse } from "../dto/userInfoResponse"
5
+ import { OrganizationService } from "./organizationService"
6
+ import { UserProfileImpl } from "../storages/user/userProfile.impl"
7
+ import { ResponseUtils } from "./responseUtils"
8
+
9
+ export class UserProfileService extends Service {
10
+ private readonly impl: UserProfileImpl = new UserProfileImpl()
11
+
12
+ get userProfile(): UserProfile {
13
+ return this.impl
14
+ }
15
+
16
+ async fetch() {
17
+ const rpc = this.resolve(RpcService) as RpcService
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)
21
+ }
22
+ const content = (await response.json()) as UserInfoResponse
23
+
24
+ // init user profile from the server's response
25
+ this.impl.initFrom(content)
26
+
27
+ const organizationService = this.resolve(
28
+ OrganizationService
29
+ ) as OrganizationService
30
+
31
+ // init organization service from user profile
32
+ await organizationService.initFrom(
33
+ content.adminInOrganization,
34
+ content.organizations,
35
+ content.user.settings
36
+ )
37
+ }
38
+ }
@@ -0,0 +1,163 @@
1
+ import { Context } from "../../context"
2
+ import {
3
+ AnswerDto,
4
+ AnswerStatus,
5
+ AnswerStepDto,
6
+ FetchAnswerResponse,
7
+ FetchTokensResponse,
8
+ SourceDto,
9
+ StepType
10
+ } from "../../dto/chatResponse"
11
+ import { ResponseUtils } from "../../services/responseUtils"
12
+ import { RpcService } from "../../services/rpcService"
13
+ import { Answer, AnswerId } from "./answer"
14
+ import { Chat } from "./chat"
15
+
16
+ export class AnswerImpl extends Answer {
17
+ private _content?: AnswerDto
18
+
19
+ private _steps?: AnswerStepDto[]
20
+ private _status?: AnswerStatus
21
+ private _id?: AnswerId
22
+
23
+ constructor(
24
+ private readonly chat: Chat,
25
+ private readonly context: Context) {
26
+ super()
27
+ }
28
+
29
+ async initFromData(answer: AnswerDto): Promise<AnswerImpl> {
30
+ this._content = answer
31
+ this._id = answer.id
32
+
33
+ // fetch answer
34
+ await this.fetch()
35
+
36
+ return this
37
+ }
38
+
39
+ async initFromId(id: AnswerId): Promise<AnswerImpl> {
40
+ this._id = id
41
+
42
+ // fetch answer
43
+ await this.fetch()
44
+
45
+ return this
46
+ }
47
+
48
+ get id(): string {
49
+ return <string>this._id
50
+ }
51
+
52
+ get status(): AnswerStatus {
53
+ return <AnswerStatus>this._status
54
+ }
55
+
56
+ private getStep(type: StepType): AnswerStepDto | undefined {
57
+ return this._steps?.find(step => step.type === type)
58
+ }
59
+
60
+ async sources(type: StepType): Promise<SourceDto[]> {
61
+ // fetch answer
62
+ await this.fetch()
63
+ // get step
64
+ const step = this.getStep(type)
65
+
66
+ // check step
67
+ if (!step) {
68
+ throw new Error(`Step with type ${type.toString()} is not found, answer: ${this.id}, organization: ${this.chat.organization.id}`)
69
+ }
70
+
71
+ // get sources
72
+ const response = await this.context
73
+ .resolve(RpcService)
74
+ ?.requestBuilder("api/v1/Chats/answer/sources")
75
+ .searchParam("chat_uid", this.chat.id)
76
+ .searchParam("uid", this.id)
77
+ .searchParam("step_id", step.id)
78
+ .sendGet()
79
+
80
+ // check response status
81
+ if (ResponseUtils.isFail(response)) {
82
+ await ResponseUtils.throwError(`Failed to get sources for ${type.toString()}, answer: ${this.id}, organization: ${this.chat.organization.id}`, response)
83
+ }
84
+
85
+ // parse sources from the server's response
86
+ const sources = (await response!.json()).sources as SourceDto[]
87
+
88
+ return sources
89
+ }
90
+
91
+ async fetch(): Promise<void> {
92
+ // fetch answer from position 0
93
+ const position = 0
94
+ // fetch answer
95
+ const response = await this.context
96
+ .resolve(RpcService)
97
+ ?.requestBuilder("api/v1/Chats/answer/fetch")
98
+ .searchParam("chatId", this.chat.id)
99
+ .searchParam("questionId", this.id)
100
+ .searchParam("position", position.toString())
101
+ .sendGet()
102
+
103
+ // check response status
104
+ if (ResponseUtils.isFail(response)) {
105
+ await ResponseUtils.throwError(`Failed to fetch answer ${this.id}`, response)
106
+ }
107
+
108
+ // parse answer from the server's response
109
+ const answer = (await response!.json()) as FetchAnswerResponse
110
+
111
+ // update answer
112
+ this._status = <AnswerStatus>answer.status
113
+ this._steps = <AnswerStepDto[]>answer.steps
114
+ }
115
+
116
+ async fetchTokens(type: StepType, token_start_at: number): Promise<FetchTokensResponse> {
117
+ // fetch answer
118
+ await this.fetch()
119
+ // get step
120
+ const step = this.getStep(type)
121
+
122
+ // check step
123
+ if (!step) {
124
+ throw new Error(`Step with type ${type.toString()} is not found`)
125
+ }
126
+
127
+ // get tokens
128
+ const response = await this.context
129
+ .resolve(RpcService)
130
+ ?.requestBuilder("api/v1/Chats/answer/fetch/tokens")
131
+ .searchParam("chat_uid", this.chat.id)
132
+ .searchParam("uid", this.id)
133
+ .searchParam("step_id", step.id)
134
+ .searchParam("token_start_at", token_start_at.toString())
135
+ .sendGet()
136
+
137
+ // check response status
138
+ if (ResponseUtils.isFail(response)) {
139
+ await ResponseUtils.throwError(`Failed to get sources for ${type.toString()}`, response)
140
+ }
141
+
142
+ // parse tokens from the server's response
143
+ const tokens = (await response!.json()) as FetchTokensResponse
144
+
145
+ return tokens
146
+ }
147
+
148
+ async cancel(): Promise<void> {
149
+ // send request to the server
150
+ const response = await this.context
151
+ .resolve(RpcService)
152
+ ?.requestBuilder("api/v1/Chats/answer/cancel")
153
+ .sendPutJson({
154
+ chat_id: this.chat.id,
155
+ uid: this.id
156
+ })
157
+
158
+ // check response status
159
+ if (ResponseUtils.isFail(response)) {
160
+ await ResponseUtils.throwError("Failed to cancel a question", response)
161
+ }
162
+ }
163
+ }
@@ -0,0 +1,42 @@
1
+ import {
2
+ AnswerStatus,
3
+ FetchTokensResponse,
4
+ SourceDto,
5
+ StepType
6
+ } from "../../dto/chatResponse"
7
+
8
+ export type AnswerId = string
9
+ export type StepId = string
10
+
11
+ export abstract class Answer {
12
+
13
+ /**
14
+ * Answer id.
15
+ */
16
+ abstract get id(): AnswerId
17
+
18
+ /**
19
+ * Answer status.
20
+ */
21
+ abstract get status(): AnswerStatus
22
+
23
+ /**
24
+ * Answer sources.
25
+ */
26
+ abstract sources(type: StepType): Promise<SourceDto[]>
27
+
28
+ /**
29
+ * Fetch answer.
30
+ */
31
+ abstract fetch(): Promise<void>
32
+
33
+ /**
34
+ * Fetch answer.
35
+ */
36
+ abstract fetchTokens(type: StepType, tokenStartAt: number): Promise<FetchTokensResponse>
37
+
38
+ /**
39
+ * Cancel answer
40
+ */
41
+ abstract cancel(): Promise<void>
42
+ }