@neuralinnovations/dataisland-sdk 0.0.1-dev3 → 0.0.1-dev5

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/README.md CHANGED
@@ -1,7 +1,96 @@
1
1
  # DataIsland Client SDK
2
2
 
3
- ```typescript
3
+ The DataIsland Client SDK is a TypeScript library designed to seamlessly integrate DataIsland web services into websites.
4
4
 
5
+ ## Table of contents
5
6
 
7
+ 1. [Connect](#connect)
8
+ 2. [Create app](#create-app)
9
+ 3. [Use organizations](#use-organizations)
10
+ 4. [Use chat](#use-chat)
11
+ 5. [Use workspaces](#use-workspaces)
12
+ 6. [Use files](#use-files)
13
+ 7. [Use access groups](#use-access-groups)
14
+ 8. [Use invites](#use-invites)
6
15
 
7
- ```
16
+ ### Connect
17
+
18
+ For connecting this library to your website project simply install it using npm package manager.
19
+
20
+ `npm i @neuralinnovations/dataisland-sdk`
21
+
22
+ ### Create app
23
+
24
+ You can initialize default app sdk instance using this code example.
25
+
26
+ ```
27
+ const app = await dataIslandApp("your-app-name", async (builder: AppBuilder) => {
28
+ builder.useHost(HOST)
29
+ builder.useCredential(new BearerCredential(TOKEN))
30
+ })
31
+ ```
32
+
33
+ It is immpossible to create more than one app sdk intance with same name.
34
+
35
+ **HOST** is a DataIsland API url which can be passed using environment file.
36
+
37
+ Second required parameter for builder is Credentials. It is recomended to use Bearer credentials instance and pass your user Auth0 **TOKEN** in order to get access to API.
38
+
39
+ You can also add requests middlewares with builder options.
40
+
41
+ ```
42
+ const app = await dataIslandApp("your-app-name", async (builder: AppBuilder) => {
43
+ builder.useHost(YOUR_HOST)
44
+ builder.useAutomaticDataCollectionEnabled(false)
45
+ builder.useCredential(new BasicCredential("email", "password"))
46
+ builder.registerMiddleware(async (req, next) => {
47
+ req.headers.set("Your-header-name", "value")
48
+ return await next(req)
49
+ })
50
+ })
51
+ ```
52
+
53
+ ### Use organizations
54
+
55
+ Organization is a top data structure object, which represents a company or some group of people using our services.
56
+ It contains of users ( admin or regular ), workspaces with files ( folders with access control features ) and chats.
57
+
58
+ By default all user organizations are fetched with user profile during app sdk start. But if there are no organizations linked to the user, you should run Create organization flow. This flow requires organization name and description data, and also first workspace name and description data provided by user.
59
+
60
+ **NOTE** There are two types of DataIsland web api servers, public and private. On public servers users can create their own organization after first registration, on private servers you must register using invite links.
61
+
62
+ Default organization creation code example:
63
+
64
+ ```
65
+ // create organization
66
+ const org = await app.organizations.create(
67
+ "your-organization-name",
68
+ "your-organization-description"
69
+ )
70
+ ```
71
+
72
+ ### Use workspaces
73
+
74
+ Workspaces are folder-like objects used to store files and controll access to it using acces groups. During creation you must pass organization Id, name and description of new workspace and regulation options. You can pass existing group ID or ask to create new group for this workspace in regulation section.
75
+
76
+ Default workspace creation example:
77
+
78
+ ```
79
+ const workspace = await org.workspaces.create(
80
+ "your-workspace-name",
81
+ "your-workspace-description",
82
+ regulation: {
83
+ isCreateNewGroup: boolean - "Bool option for new group creation"
84
+ newGroupName: string - "New group name"
85
+ groupIds: string[] - "Array of selected accessed groups IDs"
86
+ }
87
+ )
88
+ ```
89
+
90
+ ### Use files
91
+
92
+ ### Use chat
93
+
94
+ ### Use access groups
95
+
96
+ ### Use Invites
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neuralinnovations/dataisland-sdk",
3
- "version": "0.0.1-dev3",
3
+ "version": "0.0.1-dev5",
4
4
  "description": "SDK for DataIsland project",
5
5
  "licenses": [
6
6
  {
@@ -8,7 +8,7 @@ import { UserProfile } from "./storages/userProfile"
8
8
  /**
9
9
  * DataIsland App instance.
10
10
  */
11
- export abstract class AppSdk {
11
+ export abstract class DataIslandApp {
12
12
  /**
13
13
  * The name of this app.
14
14
  */
package/src/disposable.ts CHANGED
@@ -9,7 +9,8 @@ export interface Disposable {
9
9
  * Represents a lifetime.
10
10
  */
11
11
  export class Lifetime {
12
- constructor(private readonly container: DisposableContainer) {}
12
+ constructor(private readonly container: DisposableContainer) {
13
+ }
13
14
 
14
15
  /**
15
16
  * Define a new nested disposable to this lifetime.
@@ -147,5 +148,3 @@ export function disposable(action: () => void, target: unknown): Disposable {
147
148
  action.call(target)
148
149
  })
149
150
  }
150
-
151
- export const eternalLifetime = new DisposableContainer().lifetime
@@ -1,5 +1,5 @@
1
1
  import { WorkspaceId } from "../storages/workspaces"
2
- import { FileId } from "../storages/files"
2
+ import { FileId } from "../storages/file"
3
3
 
4
4
  export interface WorkspaceProfileDto {
5
5
  name: string
@@ -26,7 +26,7 @@ export interface FileProgressDto {
26
26
  file_parts_count: number
27
27
  completed_parts_count: number
28
28
  success: boolean
29
- error: string
29
+ error?: string
30
30
  }
31
31
 
32
32
  export interface FileDto {
package/src/events.ts CHANGED
@@ -1,25 +1,25 @@
1
1
  import { type Disposable, DisposableContainer } from "./disposable"
2
2
 
3
- export interface Input<ET, DT> {
4
- type?: ET
5
- data: DT
3
+ export interface Input<EventType, DataType> {
4
+ type?: EventType
5
+ data: DataType
6
6
  }
7
7
 
8
- export interface Event<ET, DT> extends Input<ET, DT> {
8
+ export interface Event<EventType, DataType> extends Input<EventType, DataType> {
9
9
  unsubscribe: () => void
10
10
  }
11
11
 
12
- export interface EventSubscriber<ET, DT> {
13
- subscribe: (callback: (event: Event<ET, DT>) => void, type?: ET) => Disposable
12
+ export interface EventSubscriber<EventType, DataType> {
13
+ subscribe: (callback: (event: Event<EventType, DataType>) => void, type?: EventType) => Disposable
14
14
  }
15
15
 
16
- export class EventDispatcher<ET, DT> implements EventSubscriber<ET, DT> {
16
+ export class EventDispatcher<EventType, DataType> implements EventSubscriber<EventType, DataType> {
17
17
  private _listeners: Array<{
18
- callback: (value: Event<ET, DT>) => void
18
+ callback: (value: Event<EventType, DataType>) => void
19
19
  disposable: Disposable
20
20
  }> = []
21
21
 
22
- dispatch(input: Input<ET, DT>): void {
22
+ dispatch(input: Input<EventType, DataType>): void {
23
23
  this._listeners.slice().forEach(it => {
24
24
  const value = {
25
25
  type: input.type,
@@ -27,16 +27,16 @@ export class EventDispatcher<ET, DT> implements EventSubscriber<ET, DT> {
27
27
  unsubscribe: () => {
28
28
  it.disposable.dispose()
29
29
  }
30
- } satisfies Event<ET, DT>
30
+ } satisfies Event<EventType, DataType>
31
31
  it.callback(value)
32
32
  })
33
33
  }
34
34
 
35
- subscribe(callback: (event: Event<ET, DT>) => void, type?: ET): Disposable {
35
+ subscribe(callback: (event: Event<EventType, DataType>) => void, type?: EventType): Disposable {
36
36
  const container = new DisposableContainer()
37
37
  if (type !== undefined) {
38
38
  const cb = callback
39
- const listener = (evt: Event<ET, DT>): void => {
39
+ const listener = (evt: Event<EventType, DataType>): void => {
40
40
  if (evt.type === type) {
41
41
  cb(evt)
42
42
  }
package/src/index.ts CHANGED
@@ -1,15 +1,26 @@
1
1
  import { version } from "../package.json"
2
2
  import { _createApp } from "./internal/createApp.impl"
3
3
  import { type AppBuilder } from "./appBuilder"
4
- import { type AppSdk } from "./appSdk"
4
+ import { type DataIslandApp } from "./dataIslandApp"
5
5
 
6
6
  export * from "./events"
7
7
  export * from "./disposable"
8
8
  export * from "./credentials"
9
- export * from "./appSdk"
9
+ export * from "./dataIslandApp"
10
+ export * from "./storages/organizations"
11
+ export * from "./storages/organization"
12
+ export * from "./storages/workspaces"
13
+ export * from "./storages/workspace"
14
+ export * from "./storages/groups"
15
+ export * from "./storages/userProfile"
16
+ export * from "./storages/files"
17
+ export * from "./storages/file"
18
+ export * from "./storages/filesPage"
19
+ export * from "./storages/chats"
20
+ export * from "./storages/chat"
10
21
 
11
- const _appsNotReady = new Map<string, Promise<AppSdk>>()
12
- const _appsReady = new Map<string, AppSdk>()
22
+ const _appsNotReady = new Map<string, Promise<DataIslandApp>>()
23
+ const _appsReady = new Map<string, DataIslandApp>()
13
24
 
14
25
  /**
15
26
  * Current SDK version.
@@ -26,7 +37,10 @@ export const DEFAULT_NAME = "[DEFAULT]"
26
37
  */
27
38
  export const DEFAULT_HOST = "https://api.dataisland.com.ua"
28
39
 
29
- export function sdks(): AppSdk[] {
40
+ /**
41
+ * Returns a list of DataIsland App instances.
42
+ */
43
+ export function dataIslandInstances(): DataIslandApp[] {
30
44
  return Array.from(_appsReady.values())
31
45
  }
32
46
 
@@ -37,19 +51,19 @@ export function sdks(): AppSdk[] {
37
51
  * @returns A DataIsland App instance.
38
52
  * @example
39
53
  * ```js
40
- * import { appSdk } from 'data-island'
54
+ * import { dataIslandApp, DEFAULT_NAME } from '@neuralinnovations/dataisland-sdk'
41
55
  *
42
- * const app = await appSdk("my-app", builder => {
56
+ * const app = await dataIslandApp(DEFAULT_NAME, builder => {
43
57
  * builder.useHost("https://dataisland.com.ua")
44
58
  * builder.useAutomaticDataCollectionEnabled(true)
45
59
  * builder.useCredential(new BasicCredential("email", "password"))
46
60
  * })
47
61
  * ```
48
62
  */
49
- export async function appSdk(
63
+ export async function dataIslandApp(
50
64
  name?: string,
51
65
  setup?: (builder: AppBuilder) => Promise<void>
52
- ): Promise<AppSdk> {
66
+ ): Promise<DataIslandApp> {
53
67
  name = name ?? DEFAULT_NAME
54
68
 
55
69
  let appPromise = _appsNotReady.get(name)
@@ -67,9 +81,12 @@ export async function appSdk(
67
81
  } else {
68
82
  if (setup !== undefined) {
69
83
  throw new Error(
70
- `App ${name} is initializing. You can't setup the same again.`
84
+ `DataIsland ${name} is initializing. You can't setup the same again.`
71
85
  )
72
86
  }
73
87
  }
74
88
  return await appPromise
75
89
  }
90
+
91
+ export { File } from "./storages/file"
92
+ export { FilesPage } from "./storages/filesPage"
@@ -8,7 +8,7 @@ import { type Service, ServiceContext } from "../services/service"
8
8
  import { CredentialService } from "../services/credentialService"
9
9
  import { MiddlewareService } from "../services/middlewareService"
10
10
  import { type CredentialBase } from "../credentials"
11
- import { AppSdk } from "../appSdk"
11
+ import { DataIslandApp } from "../dataIslandApp"
12
12
  import { RpcService } from "../services/rpcService"
13
13
  import { CommandService } from "../services/commandService"
14
14
  import {
@@ -21,7 +21,7 @@ import { Organizations } from "../storages/organizations"
21
21
  import { UserProfile } from "../storages/userProfile"
22
22
  import { isUnitTest, UnitTest } from "../unitTest"
23
23
 
24
- export class AppImplementation extends AppSdk {
24
+ export class DataIslandAppImpl extends DataIslandApp {
25
25
  readonly name: string
26
26
  private _host: string = DEFAULT_HOST
27
27
  private _automaticDataCollectionEnabled: boolean = true
@@ -104,13 +104,6 @@ export class AppImplementation extends AppSdk {
104
104
  return new OrganizationService(context)
105
105
  })
106
106
 
107
- // register middlewares
108
- builder.registerMiddleware(async (req, next) => {
109
- req.headers.set("accept", "text/plain")
110
- req.headers.set("content-type", "application/json")
111
- return await next(req)
112
- })
113
-
114
107
  // call customer setup
115
108
  if (setup !== undefined) {
116
109
  await setup(builder)
@@ -154,7 +147,9 @@ export class AppImplementation extends AppSdk {
154
147
  const waitList: Array<Promise<void>> = []
155
148
  // call onRegister service's callback
156
149
  services.forEach(([serviceContext]) => {
157
- waitList.push(serviceContext.onRegister())
150
+ if (typeof serviceContext.onRegister === "function") {
151
+ waitList.push(serviceContext.onRegister())
152
+ }
158
153
  })
159
154
 
160
155
  // wait for all services to register
@@ -167,7 +162,9 @@ export class AppImplementation extends AppSdk {
167
162
  waitList.length = 0
168
163
  // call onStart service's callback
169
164
  services.forEach(([serviceContext]) => {
170
- waitList.push(serviceContext.onStart())
165
+ if (typeof serviceContext.onStart === "function") {
166
+ waitList.push(serviceContext.onStart())
167
+ }
171
168
  })
172
169
 
173
170
  // wait for all services to start
@@ -181,7 +178,7 @@ export class AppImplementation extends AppSdk {
181
178
 
182
179
  // log app initialized
183
180
  if (!isUnitTest(UnitTest.DO_NOT_PRINT_INITIALIZED_LOG)) {
184
- console.log(`AppSDK ${this.name} initialized`)
181
+ console.log(`DataIsland ${this.name} initialized`)
185
182
  }
186
183
  }
187
184
  }
@@ -1,12 +1,12 @@
1
- import { AppImplementation } from "./app.impl"
1
+ import { DataIslandAppImpl } from "./app.impl"
2
2
  import { type AppBuilder } from "../appBuilder"
3
- import { AppSdk } from "../appSdk"
3
+ import { DataIslandApp } from "../dataIslandApp"
4
4
 
5
5
  export async function _createApp(
6
6
  name: string,
7
7
  setup?: (builder: AppBuilder) => Promise<void>
8
- ): Promise<AppSdk> {
9
- const app = new AppImplementation(name)
8
+ ): Promise<DataIslandApp> {
9
+ const app = new DataIslandAppImpl(name)
10
10
  await app.initialize(setup)
11
11
  return app
12
12
  }
@@ -3,7 +3,7 @@ import { type Middleware } from "../middleware"
3
3
  import { type Disposable } from "../disposable"
4
4
 
5
5
  export class MiddlewareService extends Service {
6
- _middlewares: Middleware[] = []
6
+ private _middlewares: Middleware[] = []
7
7
 
8
8
  public useMiddleware(middleware: Middleware): Disposable {
9
9
  this._middlewares.push(middleware)
@@ -48,18 +48,42 @@ export class RequestBuilder {
48
48
  return this
49
49
  }
50
50
 
51
- public async sendPost(body?: BodyInit | null | object): Promise<Response> {
51
+ public async sendPostFormData(body: FormData): Promise<Response> {
52
52
  const url = this._url
53
+
54
+ // set search params
53
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
54
77
  if (body !== undefined && body !== null && typeof body === "object") {
55
- body = JSON.stringify(body)
78
+ json = JSON.stringify(body)
56
79
  }
80
+ const request = new Request(url, {
81
+ method: "POST",
82
+ headers: this._headers,
83
+ body: json
84
+ })
57
85
  return await this._request(
58
- new Request(url, {
59
- method: "POST",
60
- headers: this._headers,
61
- body
62
- })
86
+ request
63
87
  )
64
88
  }
65
89
 
@@ -85,17 +109,18 @@ export class RequestBuilder {
85
109
  )
86
110
  }
87
111
 
88
- public async sendPut(body?: BodyInit | null | object): Promise<Response> {
112
+ public async sendPutJson(body: object | null | undefined): Promise<Response> {
89
113
  const url = this._url
90
114
  url.search = this._searchParams.toString()
115
+ let json: string | null | undefined = null
91
116
  if (body !== undefined && body !== null && typeof body === "object") {
92
- body = JSON.stringify(body)
117
+ json = JSON.stringify(body)
93
118
  }
94
119
  return await this._request(
95
120
  new Request(url, {
96
121
  method: "PUT",
97
122
  headers: this._headers,
98
- body
123
+ body: json
99
124
  })
100
125
  )
101
126
  }
@@ -14,6 +14,7 @@ export interface RequestOptions {
14
14
  * RPC service.
15
15
  */
16
16
  export class RpcService extends Service {
17
+
17
18
  constructor(
18
19
  serviceContext: ServiceContext,
19
20
  /**
@@ -32,6 +33,22 @@ export class RpcService extends Service {
32
33
  }
33
34
  ) {
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
+ }
42
+
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)
50
+ })
51
+ }
35
52
  }
36
53
 
37
54
  /**
@@ -87,35 +104,35 @@ export class RpcService extends Service {
87
104
  /**
88
105
  * Send a POST request.
89
106
  * @param path
90
- * @param body
107
+ * @param body JSON object
91
108
  * @param options
92
109
  */
93
110
  async post(
94
111
  path: string,
95
- body?: BodyInit | null,
112
+ body: object | null | undefined,
96
113
  options?: RequestOptions
97
114
  ): Promise<Response> {
98
115
  return this.requestBuilder(path)
99
116
  .searchParams(options?.searchParams)
100
117
  .headers(options?.headers)
101
- .sendPost(body)
118
+ .sendPostJson(body)
102
119
  }
103
120
 
104
121
  /**
105
122
  * Send a PUT request.
106
123
  * @param path
107
- * @param body
124
+ * @param body JSON object
108
125
  * @param options
109
126
  */
110
127
  async put(
111
128
  path: string,
112
- body?: BodyInit | null,
129
+ body: object | null | undefined,
113
130
  options?: RequestOptions
114
131
  ): Promise<Response> {
115
132
  return this.requestBuilder(path)
116
133
  .searchParams(options?.searchParams)
117
134
  .headers(options?.headers)
118
- .sendPut(body)
135
+ .sendPutJson(body)
119
136
  }
120
137
 
121
138
  /**
@@ -6,7 +6,8 @@ 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
  }
@@ -1,12 +1,5 @@
1
- import { EventDispatcher } from "../events"
2
-
3
1
  export type ChatId = string
4
2
 
5
- export enum ChatsEvent {
6
- ADDED = "added",
7
- REMOVED = "removed"
8
- }
9
-
10
3
  export enum ChatAnswer {
11
4
  SHORT = "short",
12
5
  LONG = "long"
@@ -26,12 +19,3 @@ export abstract class Chat {
26
19
  abstract question(message: string, answer?: ChatAnswer): Promise<void>
27
20
  }
28
21
 
29
- /**
30
- * Chats storage.
31
- */
32
- export abstract class Chats extends EventDispatcher<ChatsEvent, Chat> {
33
- /**
34
- * Create new chat.
35
- */
36
- abstract create(): Promise<Chat>
37
- }
@@ -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
+ }
@@ -2,8 +2,8 @@ import { Context } from "../context"
2
2
  import { Disposable } from "../disposable"
3
3
  import { FileDto, FileProgressDto } from "../dto/workspacesResponse"
4
4
  import { RpcService } from "../services/rpcService"
5
- import { File } from "./files"
6
5
  import { ResponseUtils } from "../services/responseUtils"
6
+ import { File } from "./file"
7
7
 
8
8
  export class FileImpl extends File implements Disposable {
9
9
  private _isDisposed: boolean = false
@@ -32,7 +32,7 @@ export class FileImpl extends File implements Disposable {
32
32
  }
33
33
 
34
34
  get name(): string {
35
- return <string>this._content?.id
35
+ return <string>this._content?.name
36
36
  }
37
37
 
38
38
  async url(): Promise<string> {
@@ -55,7 +55,7 @@ export class FileImpl extends File implements Disposable {
55
55
  async status(): Promise<FileProgressDto> {
56
56
  const response = await this.context
57
57
  .resolve(RpcService)
58
- ?.requestBuilder("api/v1/Files/url")
58
+ ?.requestBuilder("api/v1/Files/fetch")
59
59
  .searchParam("id", this.id)
60
60
  .sendGet()
61
61
 
@@ -63,6 +63,7 @@ export class FileImpl extends File implements Disposable {
63
63
  await ResponseUtils.throwError(`Failed to get file ${this.id}`, response)
64
64
  }
65
65
 
66
- return (await response!.json()).progress as FileProgressDto
66
+ const content = await response!.json()
67
+ return content.progress as FileProgressDto
67
68
  }
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
+ }