@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,47 @@
1
+ import { WorkspaceDto } from "./workspacesResponse"
2
+
3
+ export interface UserInfoResponse {
4
+ adminInOrganization: string[]
5
+ organizations: OrganizationDto[]
6
+ user: UserDto
7
+ }
8
+
9
+ export interface UserDto {
10
+ id: string
11
+ isDeleted: boolean
12
+ created_at: number
13
+ modified_at: number
14
+ profile: ProfileDto
15
+ settings?: UserSettings | null
16
+ }
17
+
18
+ export interface ProfileDto {
19
+ name: string
20
+ email: string
21
+ }
22
+
23
+ export interface UserSettings {
24
+ activeOrganizationId: string
25
+ activeWorkspaceId: string
26
+ }
27
+
28
+ export interface OrganizationProfileDto {
29
+ name: string
30
+ description: string
31
+ }
32
+
33
+ export interface OrganizationDto {
34
+ id: string
35
+ createdAt: number
36
+ modifiedAt: number
37
+ membersCount: number
38
+ profile: OrganizationProfileDto
39
+ }
40
+
41
+ export interface OrganizationWorkspaces extends OrganizationDto {
42
+ workspaces: WorkspaceDto[]
43
+ }
44
+
45
+ export interface MembersResponse {
46
+ members: UserDto
47
+ }
@@ -0,0 +1,49 @@
1
+ import { WorkspaceId } from "../storages/workspaces/workspaces"
2
+ import { FileId } from "../storages/files/file"
3
+
4
+ export interface WorkspaceProfileDto {
5
+ name: string
6
+ description: string
7
+ }
8
+
9
+ export interface WorkspaceDto {
10
+ id: WorkspaceId
11
+ createdAt: number
12
+ modifiedAt: number
13
+ profile: WorkspaceProfileDto
14
+ }
15
+
16
+ export interface WorkspacesResponse {
17
+ workspaces: WorkspaceDto[]
18
+ }
19
+
20
+ export interface FileUrlDto {
21
+ url: string
22
+ }
23
+
24
+ export interface FileProgressDto {
25
+ file_id: FileId
26
+ file_parts_count: number
27
+ completed_parts_count: number
28
+ success: boolean
29
+ error?: string
30
+ }
31
+
32
+ export interface FileDto {
33
+ id: string
34
+ createdAt: number
35
+ modifiedAt: number
36
+ name: string
37
+ description: string
38
+ url: string
39
+ hash: string
40
+ organizationId: string
41
+ workspaceId: string
42
+ isProcessedSuccessfully: boolean
43
+ }
44
+
45
+ export interface FileListResponse {
46
+ files: FileDto[]
47
+ totalFilesCount: number
48
+ filesPerPage: number
49
+ }
package/src/events.ts CHANGED
@@ -1,29 +1,25 @@
1
- import { type Disposable, DisposableContainer } from './disposable'
1
+ import { type Disposable, DisposableContainer } from "./disposable"
2
2
 
3
- export interface Events<TE, TD> {
4
- get events(): EventDispatcher<TE, TD>
3
+ export interface Input<EventType, DataType> {
4
+ type?: EventType
5
+ data: DataType
5
6
  }
6
7
 
7
- export interface Input<ET, DT> {
8
- type?: ET
9
- data: DT
10
- }
11
-
12
- export interface Event<ET, DT> extends Input<ET, DT> {
8
+ export interface Event<EventType, DataType> extends Input<EventType, DataType> {
13
9
  unsubscribe: () => void
14
10
  }
15
11
 
16
- export interface EventSubscriber<ET, DT> {
17
- 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
18
14
  }
19
15
 
20
- export class EventDispatcher<ET, DT> implements EventSubscriber<ET, DT> {
16
+ export class EventDispatcher<EventType, DataType> implements EventSubscriber<EventType, DataType> {
21
17
  private _listeners: Array<{
22
- callback: (value: Event<ET, DT>) => void
18
+ callback: (value: Event<EventType, DataType>) => void
23
19
  disposable: Disposable
24
20
  }> = []
25
21
 
26
- dispatch(input: Input<ET, DT>): void {
22
+ dispatch(input: Input<EventType, DataType>): void {
27
23
  this._listeners.slice().forEach(it => {
28
24
  const value = {
29
25
  type: input.type,
@@ -31,16 +27,16 @@ export class EventDispatcher<ET, DT> implements EventSubscriber<ET, DT> {
31
27
  unsubscribe: () => {
32
28
  it.disposable.dispose()
33
29
  }
34
- } satisfies Event<ET, DT>
30
+ } satisfies Event<EventType, DataType>
35
31
  it.callback(value)
36
32
  })
37
33
  }
38
34
 
39
- subscribe(callback: (event: Event<ET, DT>) => void, type?: ET): Disposable {
35
+ subscribe(callback: (event: Event<EventType, DataType>) => void, type?: EventType): Disposable {
40
36
  const container = new DisposableContainer()
41
37
  if (type !== undefined) {
42
38
  const cb = callback
43
- const listener = (evt: Event<ET, DT>): void => {
39
+ const listener = (evt: Event<EventType, DataType>): void => {
44
40
  if (evt.type === type) {
45
41
  cb(evt)
46
42
  }
package/src/index.ts CHANGED
@@ -1,16 +1,29 @@
1
- import { version } from '../package.json'
2
- import { _createApp } from './internal/createApp.impl'
3
- import { type AppBuilder } from './appBuilder'
4
- import { type AppSdk } from './appSdk'
1
+ import { version } from "../package.json"
2
+ import { _createApp } from "./internal/createApp.impl"
3
+ import { type AppBuilder } from "./appBuilder"
4
+ import { type DataIslandApp } from "./dataIslandApp"
5
5
 
6
- export * from './events'
7
- export * from './types'
8
- export * from './disposable'
9
- export * from './types'
10
- export * from './credentials'
6
+ export * from "./events"
7
+ export * from "./disposable"
8
+ export * from "./credentials"
9
+ export * from "./dataIslandApp"
10
+ export * from "./appBuilder"
11
+ export * from "./context"
12
+ export * from "./middleware"
13
+ export * from "./storages/organizations/organizations"
14
+ export * from "./storages/organizations/organization"
15
+ export * from "./storages/workspaces/workspaces"
16
+ export * from "./storages/workspaces/workspace"
17
+ export * from "./storages/groups/groups"
18
+ export * from "./storages/user/userProfile"
19
+ export * from "./storages/files/files"
20
+ export * from "./storages/files/file"
21
+ export * from "./storages/files/filesPage"
22
+ export * from "./storages/chats/chats"
23
+ export * from "./storages/chats/chat"
11
24
 
12
- const _appsNotReady = new Map<string, Promise<AppSdk>>()
13
- const _appsReady = new Map<string, AppSdk>()
25
+ const _appsNotReady = new Map<string, Promise<DataIslandApp>>()
26
+ const _appsReady = new Map<string, DataIslandApp>()
14
27
 
15
28
  /**
16
29
  * Current SDK version.
@@ -20,14 +33,17 @@ export const SDK_VERSION = version
20
33
  /**
21
34
  * Default DataIsland App name.
22
35
  */
23
- export const DEFAULT_NAME = '[DEFAULT]'
36
+ export const DEFAULT_NAME = "[DEFAULT]"
24
37
 
25
38
  /**
26
39
  * Default DataIsland App host.
27
40
  */
28
- export const DEFAULT_HOST = 'https://dataisland.com.ua'
41
+ export const DEFAULT_HOST = "https://api.dataisland.com.ua"
29
42
 
30
- export function sdks(): AppSdk[] {
43
+ /**
44
+ * Returns a list of DataIsland App instances.
45
+ */
46
+ export function dataIslandInstances(): DataIslandApp[] {
31
47
  return Array.from(_appsReady.values())
32
48
  }
33
49
 
@@ -38,19 +54,19 @@ export function sdks(): AppSdk[] {
38
54
  * @returns A DataIsland App instance.
39
55
  * @example
40
56
  * ```js
41
- * import { appSdk } from 'data-island'
57
+ * import { dataIslandApp, DEFAULT_NAME } from '@neuralinnovations/dataisland-sdk'
42
58
  *
43
- * const app = await appSdk("my-app", builder => {
59
+ * const app = await dataIslandApp(DEFAULT_NAME, builder => {
44
60
  * builder.useHost("https://dataisland.com.ua")
45
61
  * builder.useAutomaticDataCollectionEnabled(true)
46
62
  * builder.useCredential(new BasicCredential("email", "password"))
47
63
  * })
48
64
  * ```
49
65
  */
50
- export async function appSdk(
66
+ export async function dataIslandApp(
51
67
  name?: string,
52
68
  setup?: (builder: AppBuilder) => Promise<void>
53
- ): Promise<AppSdk> {
69
+ ): Promise<DataIslandApp> {
54
70
  name = name ?? DEFAULT_NAME
55
71
 
56
72
  let appPromise = _appsNotReady.get(name)
@@ -62,8 +78,18 @@ export async function appSdk(
62
78
  })
63
79
  .catch(reason => {
64
80
  console.error(`Error: ${reason}`)
81
+ _appsNotReady.delete(name ?? DEFAULT_NAME)
65
82
  })
66
83
  _appsNotReady.set(name, appPromise)
84
+ } else {
85
+ if (setup !== undefined) {
86
+ throw new Error(
87
+ `DataIsland ${name} is initializing. You can't setup the same again.`
88
+ )
89
+ }
67
90
  }
68
91
  return await appPromise
69
92
  }
93
+
94
+ export { File } from "./storages/files/file"
95
+ export { FilesPage } from "./storages/files/filesPage"
@@ -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 { DataIslandApp } from "../dataIslandApp"
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/organizations"
21
+ import { UserProfile } from "../storages/user/userProfile"
22
+ import { isUnitTest, UnitTest } from "../unitTest"
23
+
24
+ export class DataIslandAppImpl extends DataIslandApp {
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,45 @@ 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
+
57
107
  // call customer setup
58
108
  if (setup !== undefined) {
59
109
  await setup(builder)
@@ -66,17 +116,6 @@ export class AppImplementation implements AppSdk {
66
116
  this._automaticDataCollectionEnabled =
67
117
  builder.automaticDataCollectionEnabled
68
118
 
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
119
  // register services
81
120
  const services: Array<[ServiceContext, Service]> = []
82
121
  builder.services.forEach(serviceFactory => {
@@ -89,31 +128,57 @@ export class AppImplementation implements AppSdk {
89
128
  }, serviceContext)
90
129
  const serviceInstance = serviceFactory[1](serviceContext)
91
130
  services.push([serviceContext, serviceInstance])
92
- this._registry.set(serviceFactory[0], {
93
- provide: () => serviceInstance
94
- })
131
+ this._registry.map(serviceFactory[0]).asValue(serviceInstance)
95
132
  })
96
133
 
97
134
  builder.middlewares.forEach(middleware => {
98
135
  this.resolve(MiddlewareService)?.useMiddleware(middleware)
99
136
  })
100
137
 
138
+ builder.commands.forEach(command => {
139
+ this.resolve(CommandService)?.register(command[0], command[1])
140
+ })
141
+
142
+ this.credential = builder.credential
143
+
144
+ //-------------------------------------------------------------------------
145
+ // register services
146
+ //-------------------------------------------------------------------------
101
147
  const waitList: Array<Promise<void>> = []
102
148
  // call onRegister service's callback
103
149
  services.forEach(([serviceContext]) => {
104
- waitList.push(serviceContext.onRegister())
150
+ if (typeof serviceContext.onRegister === "function") {
151
+ waitList.push(serviceContext.onRegister())
152
+ }
105
153
  })
106
154
 
155
+ // wait for all services to register
107
156
  await Promise.all(waitList)
157
+ //-------------------------------------------------------------------------
108
158
 
159
+ //-------------------------------------------------------------------------
160
+ // start services
161
+ //-------------------------------------------------------------------------
109
162
  waitList.length = 0
110
163
  // call onStart service's callback
111
164
  services.forEach(([serviceContext]) => {
112
- waitList.push(serviceContext.onStart())
165
+ if (typeof serviceContext.onStart === "function") {
166
+ waitList.push(serviceContext.onStart())
167
+ }
113
168
  })
114
169
 
170
+ // wait for all services to start
115
171
  await Promise.all(waitList)
172
+ //-------------------------------------------------------------------------
173
+
174
+ // start app, execute start command
175
+ if (!isUnitTest(UnitTest.DO_NOT_START)) {
176
+ await this.context.execute(new StartCommand())
177
+ }
116
178
 
117
- await Promise.resolve()
179
+ // log app initialized
180
+ if (!isUnitTest(UnitTest.DO_NOT_PRINT_INITIALIZED_LOG)) {
181
+ console.log(`DataIsland ${this.name} initialized`)
182
+ }
118
183
  }
119
184
  }
@@ -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,12 +1,12 @@
1
- import { AppImplementation } from './app.impl'
2
- import { type AppBuilder } from '../appBuilder'
3
- import { AppSdk } from '../appSdk'
1
+ import { DataIslandAppImpl } from "./app.impl"
2
+ import { type AppBuilder } from "../appBuilder"
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
  }
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,9 +1,9 @@
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
- _middlewares: Middleware[] = []
6
+ private _middlewares: Middleware[] = []
7
7
 
8
8
  public useMiddleware(middleware: Middleware): Disposable {
9
9
  this._middlewares.push(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
  }