@bett3r-dev/pv3-types 1.0.0
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/build/authentication.d.ts +261 -0
- package/build/authentication.d.ts.map +1 -0
- package/build/authentication.js +108 -0
- package/build/authentication.js.map +1 -0
- package/build/cache.d.ts +101 -0
- package/build/cache.d.ts.map +1 -0
- package/build/cache.js +3 -0
- package/build/cache.js.map +1 -0
- package/build/clusterAdministration.d.ts +642 -0
- package/build/clusterAdministration.d.ts.map +1 -0
- package/build/clusterAdministration.js +177 -0
- package/build/clusterAdministration.js.map +1 -0
- package/build/configuration.d.ts +66 -0
- package/build/configuration.d.ts.map +1 -0
- package/build/configuration.js +3 -0
- package/build/configuration.js.map +1 -0
- package/build/database.d.ts +120 -0
- package/build/database.d.ts.map +1 -0
- package/build/database.js +41 -0
- package/build/database.js.map +1 -0
- package/build/endpoints.d.ts +183 -0
- package/build/endpoints.d.ts.map +1 -0
- package/build/endpoints.js +78 -0
- package/build/endpoints.js.map +1 -0
- package/build/evenstore.d.ts +26 -0
- package/build/evenstore.d.ts.map +1 -0
- package/build/evenstore.js +12 -0
- package/build/evenstore.js.map +1 -0
- package/build/eventsourcing/aggregateBuilder.d.ts +10 -0
- package/build/eventsourcing/aggregateBuilder.d.ts.map +1 -0
- package/build/eventsourcing/aggregateBuilder.js +3 -0
- package/build/eventsourcing/aggregateBuilder.js.map +1 -0
- package/build/eventsourcing/commandBuilder.d.ts +58 -0
- package/build/eventsourcing/commandBuilder.d.ts.map +1 -0
- package/build/eventsourcing/commandBuilder.js +6 -0
- package/build/eventsourcing/commandBuilder.js.map +1 -0
- package/build/eventsourcing/commandHandlers.d.ts +104 -0
- package/build/eventsourcing/commandHandlers.d.ts.map +1 -0
- package/build/eventsourcing/commandHandlers.js +28 -0
- package/build/eventsourcing/commandHandlers.js.map +1 -0
- package/build/eventsourcing/eventHandlers.d.ts +102 -0
- package/build/eventsourcing/eventHandlers.d.ts.map +1 -0
- package/build/eventsourcing/eventHandlers.js +33 -0
- package/build/eventsourcing/eventHandlers.js.map +1 -0
- package/build/eventsourcing/eventHandlersBuilder.d.ts +36 -0
- package/build/eventsourcing/eventHandlersBuilder.d.ts.map +1 -0
- package/build/eventsourcing/eventHandlersBuilder.js +13 -0
- package/build/eventsourcing/eventHandlersBuilder.js.map +1 -0
- package/build/eventsourcing/externalSystemBuilder.d.ts +14 -0
- package/build/eventsourcing/externalSystemBuilder.d.ts.map +1 -0
- package/build/eventsourcing/externalSystemBuilder.js +3 -0
- package/build/eventsourcing/externalSystemBuilder.js.map +1 -0
- package/build/eventsourcing/index.d.ts +386 -0
- package/build/eventsourcing/index.d.ts.map +1 -0
- package/build/eventsourcing/index.js +47 -0
- package/build/eventsourcing/index.js.map +1 -0
- package/build/eventsourcing/invariants.d.ts +19 -0
- package/build/eventsourcing/invariants.d.ts.map +1 -0
- package/build/eventsourcing/invariants.js +3 -0
- package/build/eventsourcing/invariants.js.map +1 -0
- package/build/eventsourcing/utils.d.ts +4 -0
- package/build/eventsourcing/utils.d.ts.map +1 -0
- package/build/eventsourcing/utils.js +3 -0
- package/build/eventsourcing/utils.js.map +1 -0
- package/build/index.d.ts +16 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +32 -0
- package/build/index.js.map +1 -0
- package/build/infrastructure.d.ts +40 -0
- package/build/infrastructure.d.ts.map +1 -0
- package/build/infrastructure.js +11 -0
- package/build/infrastructure.js.map +1 -0
- package/build/logger.d.ts +32 -0
- package/build/logger.d.ts.map +1 -0
- package/build/logger.js +29 -0
- package/build/logger.js.map +1 -0
- package/build/outboxManager.d.ts +38 -0
- package/build/outboxManager.d.ts.map +1 -0
- package/build/outboxManager.js +21 -0
- package/build/outboxManager.js.map +1 -0
- package/build/ports.d.ts +39 -0
- package/build/ports.d.ts.map +1 -0
- package/build/ports.js +3 -0
- package/build/ports.js.map +1 -0
- package/build/routesAuth.d.ts +58 -0
- package/build/routesAuth.d.ts.map +1 -0
- package/build/routesAuth.js +37 -0
- package/build/routesAuth.js.map +1 -0
- package/build/typedEventEmitter.d.ts +23 -0
- package/build/typedEventEmitter.d.ts.map +1 -0
- package/build/typedEventEmitter.js +55 -0
- package/build/typedEventEmitter.js.map +1 -0
- package/build/validation.d.ts +64 -0
- package/build/validation.d.ts.map +1 -0
- package/build/validation.js +57 -0
- package/build/validation.js.map +1 -0
- package/package.json +15 -0
- package/src/authentication.ts +273 -0
- package/src/cache.ts +109 -0
- package/src/clusterAdministration.ts +216 -0
- package/src/configuration.ts +71 -0
- package/src/database.ts +157 -0
- package/src/endpoints.ts +198 -0
- package/src/evenstore.ts +27 -0
- package/src/eventsourcing/aggregateBuilder.ts +11 -0
- package/src/eventsourcing/commandBuilder.ts +64 -0
- package/src/eventsourcing/commandHandlers.ts +137 -0
- package/src/eventsourcing/eventHandlers.ts +118 -0
- package/src/eventsourcing/eventHandlersBuilder.ts +42 -0
- package/src/eventsourcing/externalSystemBuilder.ts +20 -0
- package/src/eventsourcing/index.ts +111 -0
- package/src/eventsourcing/invariants.ts +27 -0
- package/src/eventsourcing/utils.ts +4 -0
- package/src/index.ts +15 -0
- package/src/infrastructure.ts +41 -0
- package/src/logger.ts +45 -0
- package/src/outboxManager.ts +36 -0
- package/src/ports.ts +42 -0
- package/src/routesAuth.ts +58 -0
- package/src/typedEventEmitter.ts +73 -0
- package/src/validation.ts +89 -0
- package/tsconfig.json +15 -0
package/src/database.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import S from '@bett3r-dev/jsonschema-definer';
|
|
2
|
+
import { AdapterBase, PortEmitter } from './ports';
|
|
3
|
+
|
|
4
|
+
export type Document = {
|
|
5
|
+
id: string|number,
|
|
6
|
+
[key: string]: any
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type IndexOptions = {
|
|
10
|
+
isUnique: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type DatabaseOps =
|
|
14
|
+
| 'eq'
|
|
15
|
+
| 'neq'
|
|
16
|
+
| 'lt'
|
|
17
|
+
| 'gt'
|
|
18
|
+
| 'lte'
|
|
19
|
+
| 'gte'
|
|
20
|
+
| 'in'
|
|
21
|
+
| 'nin'
|
|
22
|
+
| 'contains'
|
|
23
|
+
| 'notContains'
|
|
24
|
+
| 'some'
|
|
25
|
+
| 'none'
|
|
26
|
+
| 'every'
|
|
27
|
+
| 'exists'
|
|
28
|
+
| 'notExists';
|
|
29
|
+
|
|
30
|
+
export const filterOpMap = {
|
|
31
|
+
eq: <T>( a: T, b: T ) => a === b,
|
|
32
|
+
neq: <T>( a: T, b: T ) => a !== b,
|
|
33
|
+
lt: <T>( a: T, b: T ) => a < b,
|
|
34
|
+
gt: <T>( a: T, b: T ) => a > b,
|
|
35
|
+
lte: <T>( a: T, b: T ) => a <= b,
|
|
36
|
+
gte: <T>( a: T, b: T ) => a >= b,
|
|
37
|
+
in: <T>( a: T, b: T[]) => b.includes( a ),
|
|
38
|
+
nin: <T>( a: T, b: T[]) => !b.includes( a ),
|
|
39
|
+
contains: <T>( a: T[], b: T ) => a.includes( b ),
|
|
40
|
+
notContains: <T>( a: T[], b: T ) => !a.includes( b ),
|
|
41
|
+
some: <T>( a: T[], b: T[]) => a.some( x=> b.includes( x )),
|
|
42
|
+
none: <T>( a: T[], b: T[]) => !a.some( x=> b.includes( x )),
|
|
43
|
+
every: <T>( a: T[], b: T[]) => a.every( x=> b.includes( x )),
|
|
44
|
+
exists: <T>( a:T ) => !!a,
|
|
45
|
+
notExists: <T>( a:T ) => !a
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const CollectionFilterSchema = S.shape({
|
|
49
|
+
field: S.string(),
|
|
50
|
+
op: S.enum([ 'eq', 'neq', 'lt', 'gt', 'lte', 'gte', 'in', 'nin', 'contains', 'notContains', 'some', 'every', 'exists', 'notExists' ]),
|
|
51
|
+
value: S.any()
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export type CollectionFilterOR<T extends Document = any> = {
|
|
55
|
+
OR: CollectionFilter<T>[]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type CollectionFilterAND<T extends Document = any> = {
|
|
59
|
+
AND: CollectionFilter<T>[]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type CollectionFilterInstance<Model extends Document> = {
|
|
63
|
+
field: keyof Model;
|
|
64
|
+
op: DatabaseOps;
|
|
65
|
+
value: any;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type CollectionFilter<T extends Document = any> = Partial<
|
|
69
|
+
& CollectionFilterOR<T>
|
|
70
|
+
& CollectionFilterAND<T>
|
|
71
|
+
& CollectionFilterInstance<T>
|
|
72
|
+
>
|
|
73
|
+
|
|
74
|
+
export const CollectionSortSchema = S.shape({
|
|
75
|
+
field: S.string(),
|
|
76
|
+
direction: S.enum([ 'asc', 'desc' ])
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export type CollectionSort<Model extends Document> = {
|
|
80
|
+
field: keyof Model;
|
|
81
|
+
direction?: 'asc' | 'desc';
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const CollectionQueryParamsSchema = S.shape({
|
|
85
|
+
sort: S.array().items( CollectionSortSchema ).optional(),
|
|
86
|
+
filter: S.array().items( CollectionFilterSchema ).optional(),
|
|
87
|
+
limit: S.number().optional(),
|
|
88
|
+
after: S.string().optional(),
|
|
89
|
+
select: S.array().items( S.string()).optional()
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export type CollectionQueryParams<Model extends Document> = {
|
|
93
|
+
id?: string | number;
|
|
94
|
+
limit?: number;
|
|
95
|
+
after?: string | number;
|
|
96
|
+
sort?: CollectionSort<Model>[];
|
|
97
|
+
filter?: CollectionFilter<Model>[];
|
|
98
|
+
select?: keyof Model | ( keyof Model )[]
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export type CollectionOperations<Model extends Document> = {
|
|
102
|
+
readById: ( id: string|number ) => Promise<Model|null>
|
|
103
|
+
query: ( params: CollectionQueryParams<Model> ) => Promise<Model[]>,
|
|
104
|
+
forEach: ( params: CollectionQueryParams<Model>, callback: ( record: Model, stop: () => void ) => void | Promise<void> ) => Promise<void>,
|
|
105
|
+
upsert: ( id: string | number, data: Partial<Model> ) => Promise<Model>,
|
|
106
|
+
destroyById: ( id:string | number ) => Promise<void>,
|
|
107
|
+
createMany: ( documents: Model[]) => Promise<Model[]>,
|
|
108
|
+
updateMany: ( filter: CollectionFilter<Model>[], data: Partial<Model> ) => Promise<Model[]>,
|
|
109
|
+
destroyMany: ( filter: CollectionFilter<Model>[]) => Promise<number>,
|
|
110
|
+
atomicIncrement: ( name: string, filter?: CollectionFilter<Model>, amount?: number ) => Promise<number>,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export type DatabaseChange<Model extends Document = any> = {
|
|
114
|
+
changeType: 'insert'|'update'|'delete',
|
|
115
|
+
data?: Model,
|
|
116
|
+
previous?: Model,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export type Collection<Model extends Document> = CollectionOperations<Model> & {
|
|
120
|
+
ensureIndex: ( properties: string[], options?: Partial<IndexOptions> ) => Promise<void>,
|
|
121
|
+
destroyIndex: ( properties: string[]) => Promise<void>,
|
|
122
|
+
watch: ( changeTypes: ( 'insert'|'update'|'delete' )[], onData: ( data: DatabaseChange<Model> ) => void, onError?: ( e: Error ) => void ) => Promise<{
|
|
123
|
+
close: () => void
|
|
124
|
+
}>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// export type DatabaseTransaction = {
|
|
128
|
+
// commitTransaction: <Model extends Document>( docs?: Model[]) => Promise<Model[] | void>,
|
|
129
|
+
// rollbackTransaction: ( error: Error ) => Promise<void>,
|
|
130
|
+
// getCollection: <Model extends Document>( collection:string ) => CollectionOperations<Model>
|
|
131
|
+
// _transaction: () => any
|
|
132
|
+
// }
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @category Main Types
|
|
137
|
+
*/
|
|
138
|
+
export type DatabaseTransaction = {
|
|
139
|
+
getCollection: <Model extends Document>( collection: string ) => CollectionOperations<Model>
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* @category Main Types
|
|
143
|
+
*/
|
|
144
|
+
export type DatabaseType = {
|
|
145
|
+
getCollection: <Model extends Document>( name:string ) => Collection<Model>
|
|
146
|
+
initTransaction: <Result = any>( operations: ( getCollection: <Model extends Document>( collection: string ) => CollectionOperations<Model> ) => Promise<Result | undefined>, retryBackoff?: number, options?: any ) => Promise<Result>;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* @category Main Types
|
|
150
|
+
*/
|
|
151
|
+
export type DatabasePort = PortEmitter & DatabaseType & {
|
|
152
|
+
_adapter: DatabaseAdapter
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* @category Main Types
|
|
156
|
+
*/
|
|
157
|
+
export type DatabaseAdapter<T = any> = DatabaseType & AdapterBase<T>;
|
package/src/endpoints.ts
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import S, { BaseSchema, ObjectSchema, mergeSchemas } from '@bett3r-dev/jsonschema-definer';
|
|
2
|
+
import { METHODS } from 'http';
|
|
3
|
+
import { JSONSchema7 } from 'json-schema';
|
|
4
|
+
import { AddressInfo } from 'net';
|
|
5
|
+
import { OpenAPIV3_1 } from 'openapi-types';
|
|
6
|
+
import { AdapterBase, PortEmitter } from './ports';
|
|
7
|
+
|
|
8
|
+
const CorsOptions = S.shape({
|
|
9
|
+
origin: S.string().optional(),
|
|
10
|
+
methods: S.string().enum( ...METHODS ).optional(),
|
|
11
|
+
allowedHeaders: S.anyOf( S.string(), S.array().items( S.string())).optional(),
|
|
12
|
+
exposedHeaders: S.anyOf( S.string(), S.array().items( S.string())).optional(),
|
|
13
|
+
credentials: S.boolean().optional(),
|
|
14
|
+
maxAge: S.number().optional(),
|
|
15
|
+
preflightContinue: S.boolean().optional(),
|
|
16
|
+
optionsSuccessStatus: S.number().optional(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const CompressionOptions = S.shape({
|
|
20
|
+
chunkSize: S.number().optional(),
|
|
21
|
+
level: S.number().optional(),
|
|
22
|
+
memLevel: S.number().optional(),
|
|
23
|
+
strategy: S.number().optional(),
|
|
24
|
+
threshold: S.number().optional(),
|
|
25
|
+
windowBits: S.number().optional(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const HttpConfigSchema = S.shape({
|
|
29
|
+
port: S.number().optional(),
|
|
30
|
+
cookie: S.shape({
|
|
31
|
+
enabled: S.boolean()
|
|
32
|
+
}).additionalProperties( true ).optional(),
|
|
33
|
+
listeningEnabled: S.boolean().optional(),
|
|
34
|
+
cors: mergeSchemas( CorsOptions, S.shape({
|
|
35
|
+
enabled: S.boolean()
|
|
36
|
+
})).additionalProperties( true ).optional(),
|
|
37
|
+
compression: mergeSchemas( CompressionOptions, S.shape({
|
|
38
|
+
enabled: S.boolean()
|
|
39
|
+
})).additionalProperties( true ).optional(),
|
|
40
|
+
metrics: S.shape({
|
|
41
|
+
enabled: S.boolean().optional(),
|
|
42
|
+
httpRequestDurations: S.shape({
|
|
43
|
+
enabled: S.boolean().optional(),
|
|
44
|
+
buckets: S.array().items( S.number()).optional()
|
|
45
|
+
}).optional()
|
|
46
|
+
}).optional()
|
|
47
|
+
}).optional();
|
|
48
|
+
|
|
49
|
+
export type HttpConfig = typeof HttpConfigSchema.type
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
export type EndpointsFetchInterfaceResponse<T = any> = Pick<Response, 'ok'> & {
|
|
53
|
+
json: () => Promise<T>;
|
|
54
|
+
text: () => Promise<T>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type RequestObject<RAW extends ReadableStream = any> = {
|
|
58
|
+
type: 'string',
|
|
59
|
+
raw?: RAW,
|
|
60
|
+
body: unknown,
|
|
61
|
+
query: unknown,
|
|
62
|
+
params: unknown,
|
|
63
|
+
method: string,
|
|
64
|
+
route: string,
|
|
65
|
+
filePaths: Record<string, string>,
|
|
66
|
+
headers: Record<string,string | string[]>
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type ResponseObject<RAW extends WritableStream = any> = {
|
|
70
|
+
raw?: RAW,
|
|
71
|
+
send: ( payload: unknown ) => unknown
|
|
72
|
+
header: ( key: string, value: any ) => ResponseObject
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type EndpointActionParamsContext<USER=any> = {
|
|
76
|
+
res:ResponseObject
|
|
77
|
+
req:RequestObject,
|
|
78
|
+
endpoint: Endpoint,
|
|
79
|
+
user: USER,
|
|
80
|
+
token?: string;
|
|
81
|
+
[key:string]: any
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type EndpointActionParams<BODY=any, QUERY=any, PARAMS=any, USER=any> = {
|
|
85
|
+
query: QUERY
|
|
86
|
+
params: PARAMS
|
|
87
|
+
body: BODY
|
|
88
|
+
context: Partial<EndpointActionParamsContext<USER>>
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export type EndpointSchemas<BODY, QUERY, PARAMS> = {
|
|
92
|
+
body?: BaseSchema<BODY>,
|
|
93
|
+
query?: BaseSchema<QUERY>,
|
|
94
|
+
params?: BaseSchema<PARAMS>,
|
|
95
|
+
headers?: ObjectSchema,
|
|
96
|
+
responses?: Record<number, {schema: BaseSchema , name: string}[]>,
|
|
97
|
+
errors?: Record<number, {schema: BaseSchema, name: string}[]>,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export type EndpointAction<BODY=any, RETURN=any, QUERY=any, PARAMS=any> = ( params: EndpointActionParams<BODY, QUERY, PARAMS> ) => Promise<RETURN>
|
|
101
|
+
|
|
102
|
+
export type Endpoint<BODY=any, RETURN=any, QUERY=any, PARAMS=any> = {
|
|
103
|
+
route: string;
|
|
104
|
+
action: EndpointAction<BODY, RETURN, QUERY, PARAMS>,
|
|
105
|
+
module: string;
|
|
106
|
+
name?: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
schemas?: EndpointSchemas<BODY, QUERY, PARAMS>;
|
|
109
|
+
shouldValidate?: boolean;
|
|
110
|
+
responseContentType?: string;
|
|
111
|
+
tags?: string[]
|
|
112
|
+
//REVIEW: Protocol Specific
|
|
113
|
+
method?: 'DELETE' | 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT' | 'OPTIONS';
|
|
114
|
+
//REVIEW: Protocol Specific
|
|
115
|
+
multipartProperties?: string[],
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const EndpointSchema = S.shape({
|
|
119
|
+
route: S.string().pattern( /^\/.*/ ),
|
|
120
|
+
action: S.any(),
|
|
121
|
+
module: S.string().optional(),
|
|
122
|
+
name: S.string().optional(),
|
|
123
|
+
description: S.string().optional(),
|
|
124
|
+
schemas: S.any().optional(),
|
|
125
|
+
tags: S.array().items( S.string()).optional(),
|
|
126
|
+
multipartProperties: S.array().items( S.string()).optional(),
|
|
127
|
+
method: S.string().enum( 'DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS' ).optional(),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
export type InjectHandlerContext<REQ = any, RES = any> = {
|
|
131
|
+
request: REQ,
|
|
132
|
+
response: RES,
|
|
133
|
+
callInactiveEvent: () => void
|
|
134
|
+
callStartEvent: () => void
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export type CloudFunctionsAdapter = {
|
|
138
|
+
/**
|
|
139
|
+
* Function used when working on a cloud function environment. Internal function.
|
|
140
|
+
* @param context {InjectHandlerContext}
|
|
141
|
+
* @returns {Promise<void>}
|
|
142
|
+
*/
|
|
143
|
+
injectHandler: ( context: InjectHandlerContext )=> Promise<void>,
|
|
144
|
+
/**
|
|
145
|
+
* This method is called when the server is starting a new Events Related connection. Things like SSE, WS, TCP, etc.
|
|
146
|
+
* It is used internally in cloud function environments to keep the function alive.
|
|
147
|
+
* @returns {void}
|
|
148
|
+
*/
|
|
149
|
+
callEventConnectionsActive: () => void,
|
|
150
|
+
/**
|
|
151
|
+
* This method is called when the server has no more Events Related connection. Things like SSE, WS, TCP, etc.
|
|
152
|
+
* It is used internally in cloud function environments to mark the function as idle so it can be killed.
|
|
153
|
+
* @returns {void}
|
|
154
|
+
*/
|
|
155
|
+
callEventConnectionsInactive: () => void,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export type MetricBaseType = {
|
|
159
|
+
name: string,
|
|
160
|
+
help: string,
|
|
161
|
+
labelNames: string[],
|
|
162
|
+
}
|
|
163
|
+
export type CounterMetricsType = MetricBaseType & {}
|
|
164
|
+
export type GaugeMetricsType = MetricBaseType & {}
|
|
165
|
+
|
|
166
|
+
export type EndpointsAdapter<T = any> = AdapterBase<T> & Partial<CloudFunctionsAdapter> & {
|
|
167
|
+
adapterType?: 'httpHandler',
|
|
168
|
+
getServerAddress?: () => AddressInfo;
|
|
169
|
+
registerOpenApi?: ( openapi: Record<string, any> ) => void;
|
|
170
|
+
registerOpenApiDocument?: () => void;
|
|
171
|
+
registerEndpoint: ( endpoint: Endpoint ) => Endpoint;
|
|
172
|
+
serveStaticDirectory?: ( path: string, endpoint?: string ) => void;
|
|
173
|
+
onServicesDirectorySet?: ( callback: ( serviceDirectory: Record<string, string> ) => void ) => void;
|
|
174
|
+
metrics?: {
|
|
175
|
+
addCounter: ( metric: CounterMetricsType ) => ( labels: string[]) => void
|
|
176
|
+
addGauge: ( metric: CounterMetricsType ) => ( labels: string[], value: number ) => void
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export type EndpointsType = CloudFunctionsAdapter & {
|
|
181
|
+
getEndpoints?(): Endpoint[],
|
|
182
|
+
setServiceSupportedModules: ( modules: Record<string, string[]> ) => void;
|
|
183
|
+
getOpenApiSpec: () => OpenAPIV3_1.Document,
|
|
184
|
+
generateOpenApiSpec: ( servicePath?: string ) => Promise<OpenAPIV3_1.Document>,
|
|
185
|
+
registerEndpoint<BODY, RETURN, QUERY, PARAMS>( endpoint: Endpoint<BODY, RETURN, QUERY, PARAMS> ): void;
|
|
186
|
+
registerSchema( name:string, schema: JSONSchema7, tags: string[]): void;
|
|
187
|
+
addOpenApiTag( name: string ): void;
|
|
188
|
+
call<Type, R=Type>( route: string, method?:string, params?: Partial<Pick<EndpointActionParams<Type>, 'body'|'context'>> ): Promise<R>
|
|
189
|
+
fetch( route: string, params: {method: 'get'| 'post', headers: Record<string,any>, body: string}): Promise<EndpointsFetchInterfaceResponse>
|
|
190
|
+
get<Type, R=Type>( route: string, params?: Partial<Pick<EndpointActionParams<Type>, 'body'|'context'>> ): Promise<R>
|
|
191
|
+
post<Type, R=Type>( route: string, params?: Partial<Pick<EndpointActionParams<Type>, 'body'|'context'>> ): Promise<R>,
|
|
192
|
+
start: () => Promise<void>;
|
|
193
|
+
stop: () => Promise<void>;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export type EndpointsPort = PortEmitter & EndpointsType & {
|
|
197
|
+
_adapters: () => EndpointsAdapter[]
|
|
198
|
+
}
|
package/src/evenstore.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import S from '@bett3r-dev/jsonschema-definer';
|
|
2
|
+
import { DatabaseTransaction } from './database';
|
|
3
|
+
import { CommittedEvent, EventToCommit, ReadMultipleStreamOptions, ReadStreamOptions } from './eventsourcing';
|
|
4
|
+
import { AdapterBase, PortEmitter } from './ports';
|
|
5
|
+
|
|
6
|
+
export const EventStoreConfigSchema = S.shape({
|
|
7
|
+
enabled: S.boolean().optional(),
|
|
8
|
+
collection: S.string().optional()
|
|
9
|
+
}).optional();
|
|
10
|
+
export type EventStoreConfig = typeof EventStoreConfigSchema.type;
|
|
11
|
+
|
|
12
|
+
export type EventStoreType = {
|
|
13
|
+
appendToStream: <Type>( stream:string, events: EventToCommit|EventToCommit[], expectedVersion?: number, transaction?: DatabaseTransaction ) => Promise<CommittedEvent<Type>[]>;
|
|
14
|
+
appendToMultipleStreams?: <Type>( streams: Record<string, { events: EventToCommit|EventToCommit[], expectedVersion?: number, }>, transaction?: DatabaseTransaction ) => Promise<CommittedEvent<Type>[]>;
|
|
15
|
+
readStream: <Model=any>( readOptions: ReadStreamOptions, callback: ( event: CommittedEvent, stop: () => void ) => Partial<Model> | Promise<Partial<Model>> ) => Promise<Model>
|
|
16
|
+
readMultipleStream?: <Model=any>( readOptions: ReadMultipleStreamOptions, callback: ( event: CommittedEvent, stop: () => void ) => Record<string,Partial<Model>> | Promise<Record<string,Partial<Model>>> ) => Promise<Record<string,Model>>
|
|
17
|
+
subscribe: ( onData: ( event: CommittedEvent ) => void, onError?: ( e: Error ) => void ) => Promise<{
|
|
18
|
+
close: () => void
|
|
19
|
+
}>
|
|
20
|
+
flush: () => Promise<void>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type EventStoreAdapter = AdapterBase & EventStoreType;
|
|
24
|
+
|
|
25
|
+
export type EventStorePort = PortEmitter & EventStoreType & {
|
|
26
|
+
_adapter: EventStoreAdapter
|
|
27
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command, EventFactory, EventReducers } from '.';
|
|
2
|
+
import { DatabasePort } from '..';
|
|
3
|
+
import { ExternalSystemBuilderType } from './externalSystemBuilder';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export type AggregateBuilderType<Model, EVENTS extends Record<string, EventFactory>> = Omit<ExternalSystemBuilderType<Model, EVENTS>, 'withCommandTemplate'> & {
|
|
7
|
+
withCommandTemplate: ( command: Command ) => AggregateBuilderType<Model, EVENTS>
|
|
8
|
+
notEventsourced: ( database: DatabasePort, collection: string ) => AggregateBuilderType<Model, EVENTS>
|
|
9
|
+
initialValue: ( init: () => ( Partial<Model> | null | undefined )) => Pick<AggregateBuilderType<Model, EVENTS>, 'withEventReducers' | 'withCommands'>
|
|
10
|
+
withEventReducers: ( eventReducers: EventReducers<EVENTS, Model> ) => Pick<AggregateBuilderType<Model, EVENTS>, 'withCommands'>
|
|
11
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//*******************************************
|
|
2
|
+
// Command Builder
|
|
3
|
+
//*******************************************
|
|
4
|
+
|
|
5
|
+
import { BaseSchema } from '@bett3r-dev/jsonschema-definer';
|
|
6
|
+
import { Command, CommandCommitFunction, CommandErrorHandlerFunction, CommandFormatFunction, CommandHandlerFunction, CommandLoadFunction, EventFactory, InvariantType } from '.';
|
|
7
|
+
|
|
8
|
+
export type CommandBuilderFromSchemaType<Model, EVENTS extends Record<string, EventFactory>, EVENT extends keyof EVENTS, CommandPayload> = {
|
|
9
|
+
/**
|
|
10
|
+
* Loads the streams from the aggregate. If the Command Handler is an Aggregate the fuction will be ignored.
|
|
11
|
+
* Default Implementation:
|
|
12
|
+
* ```ts
|
|
13
|
+
* loadAggregateState(state.commandHandler, (state.streams || []), options)
|
|
14
|
+
* .then(u.ensureArray)
|
|
15
|
+
* .then((aggregateState) => ({...state, aggregateState} as CommandHandlerState));
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
withLoadFunction: ( loadFunction: CommandLoadFunction<Model, CommandPayload> ) => CommandBuilderFromSchemaType<Model, EVENTS, EVENT, CommandPayload>
|
|
19
|
+
/**
|
|
20
|
+
* Commits the new event/events to the store
|
|
21
|
+
* DefaultImplementation:
|
|
22
|
+
* ```ts
|
|
23
|
+
* const defaultCommit = (state: CommandHandlerState) =>
|
|
24
|
+
* commitCommands(state);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
withCommitFunction: ( commitFunction: CommandCommitFunction<Model, CommandPayload> ) => CommandBuilderFromSchemaType<Model, EVENTS, EVENT, CommandPayload>
|
|
28
|
+
withResultFormatFunction: ( resultFormatFunction: CommandFormatFunction<Model, CommandPayload> ) => CommandBuilderFromSchemaType<Model, EVENTS, EVENT, CommandPayload>
|
|
29
|
+
withInvariant: ( invariant: InvariantType<Model, CommandPayload> | (( state: Model, data: CommandPayload ) => Promise<void> )) => CommandBuilderFromSchemaType<Model, EVENTS, EVENT, CommandPayload>,
|
|
30
|
+
produces: <EVENT extends keyof EVENTS>( events: EVENT[]) => {
|
|
31
|
+
withHandler: <USER, StateModel = Model>( handler: CommandHandlerFunction<StateModel, CommandPayload, EVENTS, EVENT, USER> ) => {
|
|
32
|
+
build: () => Command<EVENTS, EVENT, Model, CommandPayload>,
|
|
33
|
+
withErrorHandler: ( errorHandler: CommandErrorHandlerFunction<CommandPayload> ) => {
|
|
34
|
+
build: () => Command<EVENTS, EVENT, Model, CommandPayload>
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
withErrorHandler: ( errorHandler: CommandErrorHandlerFunction<CommandPayload> ) => {
|
|
38
|
+
build: () => Command<EVENTS, EVENT, Model, CommandPayload>
|
|
39
|
+
},
|
|
40
|
+
build: () => Command<EVENTS, EVENT, Model, CommandPayload>
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type CommandBuilderInstance<Model, EVENTS extends Record<string, EventFactory>, EVENT extends keyof EVENTS, CommandPayload> = {
|
|
45
|
+
withDescription: ( description: string ) => CommandBuilderInstance<Model, EVENTS, EVENT, CommandPayload>
|
|
46
|
+
/** Specify where to find the id of the aggregate when the command has no Id in the Params of the request
|
|
47
|
+
*
|
|
48
|
+
* suppose a structure of
|
|
49
|
+
* ```ts
|
|
50
|
+
* {
|
|
51
|
+
* ISC: 'QWERASDFZXCV',
|
|
52
|
+
* marketing: { promoId: '1q2w3e'}
|
|
53
|
+
* products: [{id: 1}, {id:2}]
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
* Some examples are: `ISC`, `warehouse.id`.
|
|
57
|
+
* In the case of an array use a Dollar sign `$`.
|
|
58
|
+
* `products.$.id`
|
|
59
|
+
*/
|
|
60
|
+
withDataPropertyId: ( dataPath: string ) => CommandBuilderInstance<Model, EVENTS, EVENT, CommandPayload>
|
|
61
|
+
withSchema: <CommandPayload>( schema: BaseSchema<CommandPayload> ) => CommandBuilderFromSchemaType<Model, EVENTS, EVENT, CommandPayload>,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type CommandBuilderType<Model = any, EVENTS extends Record<string, EventFactory>=any, EVENT extends keyof EVENTS=any, CommandPayload=any> = ( init?: Omit<Command<EVENTS, EVENT, CommandPayload, Model>, 'handler' | 'events' | 'schema'> ) => CommandBuilderInstance<Model, EVENTS, EVENT, CommandPayload>
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import S, { BaseSchema } from '@bett3r-dev/jsonschema-definer';
|
|
2
|
+
import { Builder, CommittedEvent, EventFactory, EventMetadata, GetMessageType, ReadStreamOptions } from '.';
|
|
3
|
+
import { AppErrorInstance, AppErrorType } from '../validation';
|
|
4
|
+
import { DatabasePort } from '../database';
|
|
5
|
+
import { EndpointActionParams, EndpointActionParamsContext } from '../endpoints';
|
|
6
|
+
|
|
7
|
+
export type CommandHandlerState<Events = Record<string, EventFactory>, Payload=any, Model = any, USER=any> = {
|
|
8
|
+
commandHandler: Aggregate | System,
|
|
9
|
+
command: Command,
|
|
10
|
+
stream: string,
|
|
11
|
+
data: Payload,
|
|
12
|
+
query: {id?: string},
|
|
13
|
+
params: Record<string, any>,
|
|
14
|
+
context: Partial<EndpointActionParamsContext<USER>>
|
|
15
|
+
events: Events[keyof Events][],
|
|
16
|
+
state: Model,
|
|
17
|
+
committedEvents?: Array<CommittedEvent>,
|
|
18
|
+
metadata?: EventMetadata
|
|
19
|
+
expectedVersion?: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type CommandExecutionResponse<Model = unknown> = {
|
|
23
|
+
state?: Model,
|
|
24
|
+
events: CommittedEvent[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type ExecuteCommandFunction = <SYSTEM extends System, COMMAND extends keyof SYSTEM['commands']>( commandHandler:SYSTEM, commandName: COMMAND ) => ( params: Partial<EndpointActionParams> ) => Promise<unknown>;
|
|
28
|
+
export type CommandLoadFunction<Model=any, Payload=any> = ( state: CommandHandlerState<Model,Payload>, options?: ReadStreamOptions, initialState?: Model ) => Promise<CommandHandlerState<Model, Payload>>
|
|
29
|
+
export type CommandCommitFunction<Model=any, Payload=any> = ( state: CommandHandlerState<Model,Payload> ) => Promise<CommandHandlerState<Model, Payload>>
|
|
30
|
+
export type CommandFormatFunction<Model=any, Payload=any> = ( handlerState: CommandHandlerState<Model, Payload> ) => Promise<CommandExecutionResponse<Model>>
|
|
31
|
+
|
|
32
|
+
export type CommandHandlerFunction<Model=any, CommandPayload=unknown, Events extends Record<string, EventFactory<EVENT>>=any, EVENT extends keyof Events=any, USER = any> = ( state: Model extends undefined ? null : Model, data: CommandPayload, aggregateState: CommandHandlerState<Events, CommandPayload, any, USER> ) => Promise<EventFactory<EVENT, GetMessageType<Events[EVENT]>>[]> | EventFactory<EVENT, GetMessageType<Events[EVENT]>>[]
|
|
33
|
+
|
|
34
|
+
export type CommandErrorHandlerFunction<CommandPayload=unknown> = ( error: AppErrorInstance, data: CommandPayload ) => Promise<any>
|
|
35
|
+
|
|
36
|
+
export type Command<EVENTS extends Record<string, EventFactory<EVENT>>=any, EVENT extends keyof EVENTS=any, SystemModel=any, CommandPayload=any> = {
|
|
37
|
+
schema: BaseSchema<CommandPayload>
|
|
38
|
+
handler: CommandHandlerFunction<SystemModel, CommandPayload, EVENTS, EVENT>
|
|
39
|
+
onErrorHandler?: CommandErrorHandlerFunction<CommandPayload>,
|
|
40
|
+
dataPropertyId?: string,
|
|
41
|
+
name?: string,
|
|
42
|
+
actors?: string[]
|
|
43
|
+
description?: string
|
|
44
|
+
multipartProperties?: string[],
|
|
45
|
+
events?: EVENT[],
|
|
46
|
+
invariants?: InvariantType[]
|
|
47
|
+
load?: CommandLoadFunction,
|
|
48
|
+
commit?: CommandCommitFunction,
|
|
49
|
+
format?: CommandFormatFunction
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type InvariantType<Model=any, Payload=any> = {
|
|
53
|
+
events?: string[],
|
|
54
|
+
rejects: AppErrorType[],
|
|
55
|
+
beforeLoad?: ( state: CommandHandlerState<any, Payload, Model> ) => Promise<CommandHandlerState<any, Payload, Model>>
|
|
56
|
+
check: ( commandHandlerState: CommandHandlerState<any, Payload, Model> ) => Promise<CommandHandlerState<any, Payload, Model> | void> | void | CommandHandlerState<any, Payload, Model>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//*******************************************
|
|
60
|
+
// Systems
|
|
61
|
+
//*******************************************
|
|
62
|
+
|
|
63
|
+
export const SystemGetQuerySchema = S.shape({
|
|
64
|
+
stream: S.string(),
|
|
65
|
+
names: S.array().items( S.string()).optional(),
|
|
66
|
+
from: S.number().optional(),
|
|
67
|
+
limit: S.number().optional(),
|
|
68
|
+
backward: S.boolean().optional(),
|
|
69
|
+
after: S.string().format( 'date-time' ).optional(),
|
|
70
|
+
before: S.string().format( 'date-time' ).optional(),
|
|
71
|
+
});
|
|
72
|
+
export type SystemGetQueryType = typeof SystemGetQuerySchema.type;
|
|
73
|
+
export const SystemEndpointParamsSchema = S.shape({
|
|
74
|
+
id: S.string().description( 'id for the aggregate' )
|
|
75
|
+
});
|
|
76
|
+
export const CommandEndpointQuerySchema = S.shape({
|
|
77
|
+
expectedVersion: S.string().optional(),
|
|
78
|
+
causationId: S.string().optional(),
|
|
79
|
+
correlationId: S.string().optional(),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export type OnValidationErrorFunctionType = Function;
|
|
83
|
+
|
|
84
|
+
export type System<Commands extends Record<string, Command | Builder<Command>>=any, EVENTS extends Record<string, EventFactory>=any> = {
|
|
85
|
+
name: string,
|
|
86
|
+
events: EVENTS,
|
|
87
|
+
isStreamable?: boolean,
|
|
88
|
+
isAggregate?: boolean,
|
|
89
|
+
isEventsourced?: boolean,
|
|
90
|
+
commands: Commands,
|
|
91
|
+
templateCommand: Command
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//*******************************************
|
|
95
|
+
// Aggregates
|
|
96
|
+
//*******************************************
|
|
97
|
+
|
|
98
|
+
export type AggregateReducedState<Model = any> = {state: Model, lastEvent?: Partial<Pick<CommittedEvent, 'id'|'version'>>}
|
|
99
|
+
|
|
100
|
+
export type EventReducers<EVENTS extends Record<string, EventFactory>=any, Model=any> = {
|
|
101
|
+
[Name in keyof EVENTS]: ( state: Model, data: GetMessageType<EVENTS[Name]>, metadata: EventMetadata ) => Partial<Model>
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export type Aggregate<Commands extends Record<string, Command | Builder<Command>>=any, EVENTS extends Record<string, EventFactory>=any, Model=any> = System<Commands, EVENTS> & {
|
|
105
|
+
schema: BaseSchema<Model>
|
|
106
|
+
outboxDatabase?: DatabasePort,
|
|
107
|
+
outboxCollection?: string,
|
|
108
|
+
initialValue: () => Partial<Model> | null | undefined,
|
|
109
|
+
eventReducers: EventReducers<EVENTS, Model>
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//*******************************************
|
|
113
|
+
// Command Handlers
|
|
114
|
+
//*******************************************
|
|
115
|
+
|
|
116
|
+
export type EventSourcingCommandHandlers = {
|
|
117
|
+
loadStream: (
|
|
118
|
+
stream: string,
|
|
119
|
+
options?: ReadStreamOptions
|
|
120
|
+
) => Promise<CommittedEvent[] | undefined>;
|
|
121
|
+
loadAggregateState: (
|
|
122
|
+
system: System,
|
|
123
|
+
stream?: string,
|
|
124
|
+
options?: ReadStreamOptions
|
|
125
|
+
) => Promise<Record<string, any> | null>;
|
|
126
|
+
executeCommand: ExecuteCommandFunction;
|
|
127
|
+
registerCommandHandlerGetEndpoints: (
|
|
128
|
+
aggregateOrSystem: Aggregate | System,
|
|
129
|
+
name?: string
|
|
130
|
+
) => string[];
|
|
131
|
+
registerCommandHandlerPostEndpoints: (
|
|
132
|
+
aggregateOrSystem: ( Aggregate | System ) & {
|
|
133
|
+
events: Record<string, EventFactory>;
|
|
134
|
+
},
|
|
135
|
+
name?: string
|
|
136
|
+
) => Record<string, string>;
|
|
137
|
+
};
|