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

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 (58) hide show
  1. package/.editorconfig +4 -1
  2. package/.eslintrc.json +1 -1
  3. package/jest.config.ts +4 -4
  4. package/jest.setup.ts +2 -0
  5. package/package.json +4 -2
  6. package/src/appBuilder.ts +24 -5
  7. package/src/appSdk.ts +31 -12
  8. package/src/commands/startCommandHandler.ts +14 -0
  9. package/src/context.ts +31 -0
  10. package/src/credentials.ts +31 -9
  11. package/src/disposable.ts +2 -2
  12. package/src/dto/accessGroupResponse.ts +35 -0
  13. package/src/dto/chatResponse.ts +104 -0
  14. package/src/dto/userInfoResponse.ts +47 -0
  15. package/src/dto/workspacesResponse.ts +49 -0
  16. package/src/events.ts +1 -5
  17. package/src/index.ts +17 -11
  18. package/src/internal/app.impl.ts +98 -30
  19. package/src/internal/appBuilder.impl.ts +39 -12
  20. package/src/internal/createApp.impl.ts +3 -3
  21. package/src/middleware.ts +1 -1
  22. package/src/services/commandService.ts +44 -0
  23. package/src/services/credentialService.ts +3 -3
  24. package/src/services/middlewareService.ts +7 -5
  25. package/src/services/organizationService.ts +28 -0
  26. package/src/services/requestBuilder.ts +102 -0
  27. package/src/services/responseUtils.ts +32 -0
  28. package/src/services/rpcService.ts +113 -53
  29. package/src/services/service.ts +3 -3
  30. package/src/services/userProfileService.ts +38 -0
  31. package/src/storages/chat.ts +37 -0
  32. package/src/storages/file.impl.ts +68 -0
  33. package/src/storages/files.impl.ts +192 -0
  34. package/src/storages/files.ts +67 -0
  35. package/src/storages/groups.impl.ts +337 -0
  36. package/src/storages/groups.ts +43 -0
  37. package/src/storages/organization.impl.ts +68 -0
  38. package/src/storages/organization.ts +33 -0
  39. package/src/storages/organizations.impl.ts +191 -0
  40. package/src/storages/organizations.ts +56 -0
  41. package/src/storages/userProfile.impl.ts +56 -0
  42. package/src/storages/userProfile.ts +42 -0
  43. package/src/storages/workspace.impl.ts +109 -0
  44. package/src/storages/workspace.ts +43 -0
  45. package/src/storages/workspaces.impl.ts +212 -0
  46. package/src/storages/workspaces.ts +53 -0
  47. package/src/unitTest.ts +42 -0
  48. package/test/commands.test.ts +24 -0
  49. package/test/disposable.test.ts +3 -3
  50. package/test/events.test.ts +4 -4
  51. package/test/index.test.ts +204 -62
  52. package/test/registry.test.ts +8 -8
  53. package/test/services.test.ts +56 -0
  54. package/test/setup.ts +2 -0
  55. package/test/unitTest.test.ts +21 -0
  56. package/test_file.pdf +0 -0
  57. package/src/internal/context.ts +0 -13
  58. package/src/types.ts +0 -110
@@ -1,17 +1,27 @@
1
- import { DEFAULT_HOST } from '../index'
2
- import { type AppBuilder } from '../appBuilder'
3
- import { AppBuilderImplementation } from './appBuilder.impl'
4
- import { type Constructor, Registry } from './registry'
5
- import { Context } from './context'
6
- import { DisposableContainer, type Lifetime } from '../disposable'
7
- import { type Service, ServiceContext } from '../services/service'
8
- import { CredentialService } from '../services/credentialService'
9
- import { MiddlewareService } from '../services/middlewareService'
10
- import { type CredentialBase } from '../credentials'
11
- import { type AppSdk } from '../appSdk'
12
- import { RpcService, RpcServiceImpl } from '../services/rpcService'
13
-
14
- export class AppImplementation implements AppSdk {
1
+ import { DEFAULT_HOST } from "../index"
2
+ import { type AppBuilder } from "../appBuilder"
3
+ import { AppBuilderImplementation } from "./appBuilder.impl"
4
+ import { type Constructor, Registry } from "./registry"
5
+ import { Context } from "../context"
6
+ import { DisposableContainer, type Lifetime } from "../disposable"
7
+ import { type Service, ServiceContext } from "../services/service"
8
+ import { CredentialService } from "../services/credentialService"
9
+ import { MiddlewareService } from "../services/middlewareService"
10
+ import { type CredentialBase } from "../credentials"
11
+ import { AppSdk } from "../appSdk"
12
+ import { RpcService } from "../services/rpcService"
13
+ import { CommandService } from "../services/commandService"
14
+ import {
15
+ StartCommandHandler,
16
+ StartCommand
17
+ } from "../commands/startCommandHandler"
18
+ import { UserProfileService } from "../services/userProfileService"
19
+ import { OrganizationService } from "../services/organizationService"
20
+ import { Organizations } from "../storages/organizations"
21
+ import { UserProfile } from "../storages/userProfile"
22
+ import { isUnitTest, UnitTest } from "../unitTest"
23
+
24
+ export class AppImplementation extends AppSdk {
15
25
  readonly name: string
16
26
  private _host: string = DEFAULT_HOST
17
27
  private _automaticDataCollectionEnabled: boolean = true
@@ -20,10 +30,17 @@ export class AppImplementation implements AppSdk {
20
30
  private readonly _disposable: DisposableContainer
21
31
 
22
32
  constructor(name: string) {
33
+ super()
23
34
  this.name = name
24
35
  this._registry = new Registry()
25
36
  this._disposable = new DisposableContainer()
26
- this._context = new Context(this._registry, this._disposable.lifetime)
37
+ this._context = new Context(this._registry, this._disposable.lifetime, name)
38
+
39
+ this._registry.map(Context).asValue(this._context)
40
+ }
41
+
42
+ get context(): Context {
43
+ return this._context
27
44
  }
28
45
 
29
46
  get credential(): CredentialBase | undefined {
@@ -48,12 +65,52 @@ export class AppImplementation implements AppSdk {
48
65
  return this._host
49
66
  }
50
67
 
68
+ get organizations(): Organizations {
69
+ return this.resolve(OrganizationService)?.organizations as Organizations
70
+ }
71
+
72
+ get userProfile(): UserProfile {
73
+ return this.resolve(UserProfileService)?.userProfile as UserProfile
74
+ }
75
+
51
76
  async initialize(
52
77
  setup: ((builder: AppBuilder) => Promise<void>) | undefined
53
78
  ): Promise<void> {
54
79
  // create app builder
55
80
  const builder = new AppBuilderImplementation()
56
81
 
82
+ // register commands
83
+ builder.registerCommand(StartCommand, (context: Context) => {
84
+ return new StartCommandHandler(context)
85
+ })
86
+
87
+ // register services
88
+ builder.registerService(CredentialService, (context: ServiceContext) => {
89
+ return new CredentialService(context)
90
+ })
91
+ builder.registerService(MiddlewareService, (context: ServiceContext) => {
92
+ return new MiddlewareService(context)
93
+ })
94
+ builder.registerService(RpcService, (context: ServiceContext) => {
95
+ return new RpcService(context, builder.host)
96
+ })
97
+ builder.registerService(CommandService, (context: ServiceContext) => {
98
+ return new CommandService(context)
99
+ })
100
+ builder.registerService(UserProfileService, (context: ServiceContext) => {
101
+ return new UserProfileService(context)
102
+ })
103
+ builder.registerService(OrganizationService, (context: ServiceContext) => {
104
+ return new OrganizationService(context)
105
+ })
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
+
57
114
  // call customer setup
58
115
  if (setup !== undefined) {
59
116
  await setup(builder)
@@ -66,17 +123,6 @@ export class AppImplementation implements AppSdk {
66
123
  this._automaticDataCollectionEnabled =
67
124
  builder.automaticDataCollectionEnabled
68
125
 
69
- // register services
70
- builder.registerService(CredentialService, (context: ServiceContext) => {
71
- return new CredentialService(context)
72
- })
73
- builder.registerService(MiddlewareService, (context: ServiceContext) => {
74
- return new MiddlewareService(context)
75
- })
76
- builder.registerService(RpcService, (context: ServiceContext) => {
77
- return new RpcServiceImpl(context, builder.host) as RpcService
78
- })
79
-
80
126
  // register services
81
127
  const services: Array<[ServiceContext, Service]> = []
82
128
  builder.services.forEach(serviceFactory => {
@@ -89,31 +135,53 @@ export class AppImplementation implements AppSdk {
89
135
  }, serviceContext)
90
136
  const serviceInstance = serviceFactory[1](serviceContext)
91
137
  services.push([serviceContext, serviceInstance])
92
- this._registry.set(serviceFactory[0], {
93
- provide: () => serviceInstance
94
- })
138
+ this._registry.map(serviceFactory[0]).asValue(serviceInstance)
95
139
  })
96
140
 
97
141
  builder.middlewares.forEach(middleware => {
98
142
  this.resolve(MiddlewareService)?.useMiddleware(middleware)
99
143
  })
100
144
 
145
+ builder.commands.forEach(command => {
146
+ this.resolve(CommandService)?.register(command[0], command[1])
147
+ })
148
+
149
+ this.credential = builder.credential
150
+
151
+ //-------------------------------------------------------------------------
152
+ // register services
153
+ //-------------------------------------------------------------------------
101
154
  const waitList: Array<Promise<void>> = []
102
155
  // call onRegister service's callback
103
156
  services.forEach(([serviceContext]) => {
104
157
  waitList.push(serviceContext.onRegister())
105
158
  })
106
159
 
160
+ // wait for all services to register
107
161
  await Promise.all(waitList)
162
+ //-------------------------------------------------------------------------
108
163
 
164
+ //-------------------------------------------------------------------------
165
+ // start services
166
+ //-------------------------------------------------------------------------
109
167
  waitList.length = 0
110
168
  // call onStart service's callback
111
169
  services.forEach(([serviceContext]) => {
112
170
  waitList.push(serviceContext.onStart())
113
171
  })
114
172
 
173
+ // wait for all services to start
115
174
  await Promise.all(waitList)
175
+ //-------------------------------------------------------------------------
116
176
 
117
- await Promise.resolve()
177
+ // start app, execute start command
178
+ if (!isUnitTest(UnitTest.DO_NOT_START)) {
179
+ await this.context.execute(new StartCommand())
180
+ }
181
+
182
+ // log app initialized
183
+ if (!isUnitTest(UnitTest.DO_NOT_PRINT_INITIALIZED_LOG)) {
184
+ console.log(`AppSDK ${this.name} initialized`)
185
+ }
118
186
  }
119
187
  }
@@ -1,16 +1,29 @@
1
- import { AppBuilder } from '../appBuilder'
2
- import { DEFAULT_HOST } from '../index'
3
- import { type CredentialBase, DefaultCredential } from '../credentials'
4
- import type { Middleware } from '../middleware'
5
- import { type Service, type ServiceContext } from '../services/service'
6
- import { type Constructor } from './registry'
1
+ import { AppBuilder } from "../appBuilder"
2
+ import { DEFAULT_HOST } from "../index"
3
+ import { type CredentialBase, DefaultCredential } from "../credentials"
4
+ import type { Middleware } from "../middleware"
5
+ import { type Service, type ServiceContext } from "../services/service"
6
+ import { type Constructor } from "./registry"
7
+ import { Command, CommandHandler } from "../services/commandService"
8
+ import { Context } from "../context"
9
+ import { UnitTest } from "../unitTest"
7
10
 
8
11
  export class AppBuilderImplementation extends AppBuilder {
12
+ envData: Record<string, any> = {
13
+ unitTest: UnitTest.DO_NOTHING
14
+ }
9
15
  host: string = DEFAULT_HOST
10
16
  automaticDataCollectionEnabled: boolean = true
11
17
  credential: CredentialBase = new DefaultCredential()
12
18
  middlewares: Middleware[] = []
13
19
  services: Array<[Constructor<any>, (context: ServiceContext) => Service]> = []
20
+ commands: Array<
21
+ [Constructor<any>, (context: Context) => CommandHandler<any>]
22
+ > = []
23
+
24
+ get env(): Record<string, any> {
25
+ return this.envData
26
+ }
14
27
 
15
28
  useHost(host: string): AppBuilder {
16
29
  this.host = host ?? DEFAULT_HOST
@@ -20,7 +33,7 @@ export class AppBuilderImplementation extends AppBuilder {
20
33
  useAutomaticDataCollectionEnabled(value: boolean): AppBuilder {
21
34
  if (value === undefined || value === null) {
22
35
  throw new Error(
23
- 'useAutomaticDataCollectionEnabled, value is undefined|null'
36
+ "useAutomaticDataCollectionEnabled, value is undefined|null"
24
37
  )
25
38
  }
26
39
  this.automaticDataCollectionEnabled = value
@@ -29,15 +42,15 @@ export class AppBuilderImplementation extends AppBuilder {
29
42
 
30
43
  useCredential(credential: CredentialBase): AppBuilder {
31
44
  if (credential === undefined || credential === null) {
32
- throw new Error('useCredential, credential is undefined|null')
45
+ throw new Error("useCredential, credential is undefined|null")
33
46
  }
34
47
  this.credential = credential
35
48
  return this
36
49
  }
37
50
 
38
- addMiddleware(middleware: Middleware): AppBuilder {
51
+ registerMiddleware(middleware: Middleware): AppBuilder {
39
52
  if (middleware === undefined || middleware === null) {
40
- throw new Error('addMiddleware, middleware is undefined|null')
53
+ throw new Error("addMiddleware, middleware is undefined|null")
41
54
  }
42
55
  this.middlewares.push(middleware)
43
56
  return this
@@ -48,12 +61,26 @@ export class AppBuilderImplementation extends AppBuilder {
48
61
  factory: (context: ServiceContext) => T
49
62
  ): AppBuilder {
50
63
  if (type === undefined || type === null) {
51
- throw new Error('registerService, type is undefined|null')
64
+ throw new Error("registerService, type is undefined|null")
52
65
  }
53
66
  if (factory === undefined || factory === null) {
54
- throw new Error('registerService, factory is undefined|null')
67
+ throw new Error("registerService, factory is undefined|null")
55
68
  }
56
69
  this.services.push([type, factory])
57
70
  return this
58
71
  }
72
+
73
+ registerCommand<T extends Command>(
74
+ messageType: Constructor<T>,
75
+ commandFactory: (context: Context) => CommandHandler<T>
76
+ ): AppBuilder {
77
+ if (messageType === undefined || messageType === null) {
78
+ throw new Error("registerCommand, messageType is undefined|null")
79
+ }
80
+ if (commandFactory === undefined || commandFactory === null) {
81
+ throw new Error("registerCommand, commandFactory is undefined|null")
82
+ }
83
+ this.commands.push([messageType, commandFactory])
84
+ return this
85
+ }
59
86
  }
@@ -1,6 +1,6 @@
1
- import { AppImplementation } from './app.impl'
2
- import { type AppBuilder } from '../appBuilder'
3
- import { AppSdk } from '../appSdk'
1
+ import { AppImplementation } from "./app.impl"
2
+ import { type AppBuilder } from "../appBuilder"
3
+ import { AppSdk } from "../appSdk"
4
4
 
5
5
  export async function _createApp(
6
6
  name: string,
package/src/middleware.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  export type Middleware = (
5
5
  req: Request,
6
6
  next: (req: Request) => Promise<Response>
7
- ) => Promise<void>
7
+ ) => Promise<Response>
@@ -0,0 +1,44 @@
1
+ import { Service } from "./service"
2
+ import { Context } from "../context"
3
+ import { Constructor } from "../internal/registry"
4
+
5
+ export abstract class CommandHandler<T> {
6
+ constructor(protected readonly context: Context) {}
7
+
8
+ resolve<T>(type: Constructor<T>): T | undefined {
9
+ return this.context.resolve<T>(type)
10
+ }
11
+
12
+ abstract execute(message: T): Promise<void>
13
+ }
14
+
15
+ export abstract class Command {}
16
+
17
+ export class CommandService extends Service {
18
+ private readonly _registry: Map<
19
+ Constructor<any>,
20
+ (context: Context) => CommandHandler<any>
21
+ > = new Map()
22
+ private _lastPromise: Promise<void> = Promise.resolve()
23
+
24
+ register<T extends Command>(
25
+ messageType: Constructor<T>,
26
+ commandFactory: (context: Context) => CommandHandler<T>
27
+ ): void {
28
+ this._registry.set(messageType, commandFactory)
29
+ }
30
+
31
+ async execute<T extends Command>(message: T): Promise<void> {
32
+ const commandFactory = this._registry.get((message as any).constructor)
33
+ if (commandFactory) {
34
+ const command = commandFactory(this.context)
35
+ await this._lastPromise
36
+ this._lastPromise = command.execute(message)
37
+ await this._lastPromise
38
+ } else {
39
+ throw new Error(
40
+ `Command not found for message type ${message.constructor.name}`
41
+ )
42
+ }
43
+ }
44
+ }
@@ -1,6 +1,6 @@
1
- import { type CredentialBase } from '../credentials'
2
- import { Service } from './service'
3
- import { type DisposableContainer } from '../disposable'
1
+ import { type CredentialBase } from "../credentials"
2
+ import { Service } from "./service"
3
+ import { type DisposableContainer } from "../disposable"
4
4
 
5
5
  export class CredentialService extends Service {
6
6
  private _credentialDispose?: DisposableContainer = undefined
@@ -1,6 +1,6 @@
1
- import { Service } from './service'
2
- import { type Middleware } from '../middleware'
3
- import { type Disposable } from '../disposable'
1
+ import { Service } from "./service"
2
+ import { type Middleware } from "../middleware"
3
+ import { type Disposable } from "../disposable"
4
4
 
5
5
  export class MiddlewareService extends Service {
6
6
  _middlewares: Middleware[] = []
@@ -24,10 +24,12 @@ export class MiddlewareService extends Service {
24
24
  const processNext = async (request: Request): Promise<Response> => {
25
25
  index++
26
26
  if (index < middlewares.length) {
27
- await middlewares[index](request, processNext)
27
+ return await middlewares[index](request, processNext)
28
+ } else {
29
+ return await next(request)
28
30
  }
29
- return await next(request)
30
31
  }
32
+
31
33
  return await processNext(req)
32
34
  }
33
35
  }
@@ -0,0 +1,28 @@
1
+ import { Service } from "./service"
2
+ import { Organizations } from "../storages/organizations"
3
+ import { OrganizationDto, UserSettings } from "../dto/userInfoResponse"
4
+ import { OrganizationsImpl } from "../storages/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,102 @@
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 sendPost(body?: BodyInit | null | object): Promise<Response> {
52
+ const url = this._url
53
+ url.search = this._searchParams.toString()
54
+ if (body !== undefined && body !== null && typeof body === "object") {
55
+ body = JSON.stringify(body)
56
+ }
57
+ return await this._request(
58
+ new Request(url, {
59
+ method: "POST",
60
+ headers: this._headers,
61
+ body
62
+ })
63
+ )
64
+ }
65
+
66
+ public async sendGet(): Promise<Response> {
67
+ const url = this._url
68
+ url.search = this._searchParams.toString()
69
+ return await this._request(
70
+ new Request(url, {
71
+ method: "GET",
72
+ headers: this._headers
73
+ })
74
+ )
75
+ }
76
+
77
+ public async sendDelete(): Promise<Response> {
78
+ const url = this._url
79
+ url.search = this._searchParams.toString()
80
+ return await this._request(
81
+ new Request(url, {
82
+ method: "DELETE",
83
+ headers: this._headers
84
+ })
85
+ )
86
+ }
87
+
88
+ public async sendPut(body?: BodyInit | null | object): Promise<Response> {
89
+ const url = this._url
90
+ url.search = this._searchParams.toString()
91
+ if (body !== undefined && body !== null && typeof body === "object") {
92
+ body = JSON.stringify(body)
93
+ }
94
+ return await this._request(
95
+ new Request(url, {
96
+ method: "PUT",
97
+ headers: this._headers,
98
+ body
99
+ })
100
+ )
101
+ }
102
+ }
@@ -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
+ }