@my-devkit/firebase 1.0.192 → 1.0.194
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/.eslintrc.js +2 -4
- package/dist/app-factory.js +3 -3
- package/dist/app-factory.js.map +1 -1
- package/dist/bus.js +4 -1
- package/dist/bus.js.map +1 -1
- package/dist/context.js +18 -18
- package/dist/context.js.map +1 -1
- package/dist/decorators/controller/body.js.map +1 -1
- package/dist/decorators/controller/body.spec.js +1 -1
- package/dist/decorators/controller/body.spec.js.map +1 -1
- package/dist/decorators/controller/controller.spec.js.map +1 -1
- package/dist/decorators/controller/get.js +4 -1
- package/dist/decorators/controller/get.js.map +1 -1
- package/dist/decorators/controller/get.spec.js.map +1 -1
- package/dist/decorators/controller/param.js.map +1 -1
- package/dist/decorators/controller/param.spec.js +1 -1
- package/dist/decorators/controller/param.spec.js.map +1 -1
- package/dist/decorators/controller/post.js +4 -1
- package/dist/decorators/controller/post.js.map +1 -1
- package/dist/decorators/controller/post.spec.js.map +1 -1
- package/dist/decorators/controller/query.js.map +1 -1
- package/dist/decorators/controller/query.spec.js +1 -1
- package/dist/decorators/controller/query.spec.js.map +1 -1
- package/dist/decorators/handler/command-handler.js.map +1 -1
- package/dist/decorators/handler/command-handler.spec.js.map +1 -1
- package/dist/decorators/handler/event-handler.js.map +1 -1
- package/dist/decorators/handler/event-handler.spec.js.map +1 -1
- package/dist/firestore-client.js +47 -32
- package/dist/firestore-client.js.map +1 -1
- package/dist/handler-helper.js.map +1 -1
- package/dist/interfaces/type.d.ts +1 -1
- package/dist/reflect.js +0 -1
- package/dist/reflect.js.map +1 -1
- package/dist/sanity-check/controller.js.map +1 -1
- package/dist/sanity-check/module.js +1 -3
- package/dist/sanity-check/module.js.map +1 -1
- package/dist/server/middlewares/authentication-middleware.js +3 -1
- package/dist/server/middlewares/authentication-middleware.js.map +1 -1
- package/dist/server/middlewares/create-context-middleware.js.map +1 -1
- package/dist/server/middlewares/error-middleware.js.map +1 -1
- package/dist/server/middlewares/headers-middleware.js.map +1 -1
- package/dist/server/server.js.map +1 -1
- package/dist/zip-helper.js +1 -1
- package/dist/zip-helper.js.map +1 -1
- package/package.json +5 -5
- package/src/app-factory.ts +114 -59
- package/src/bus.ts +22 -5
- package/src/context.ts +2 -2
- package/src/decorators/controller/body.spec.ts +11 -5
- package/src/decorators/controller/body.ts +10 -4
- package/src/decorators/controller/controller.spec.ts +1 -3
- package/src/decorators/controller/get.spec.ts +0 -1
- package/src/decorators/controller/get.ts +5 -2
- package/src/decorators/controller/param.spec.ts +15 -5
- package/src/decorators/controller/param.ts +8 -3
- package/src/decorators/controller/post.spec.ts +0 -2
- package/src/decorators/controller/post.ts +5 -2
- package/src/decorators/controller/query.spec.ts +11 -4
- package/src/decorators/controller/query.ts +8 -3
- package/src/decorators/handler/command-handler.spec.ts +8 -13
- package/src/decorators/handler/command-handler.ts +10 -4
- package/src/decorators/handler/event-handler.spec.ts +8 -13
- package/src/decorators/handler/event-handler.ts +10 -4
- package/src/firestore-client.ts +131 -56
- package/src/handler-helper.ts +18 -5
- package/src/interfaces/app-config.ts +0 -1
- package/src/interfaces/from-array.ts +2 -1
- package/src/interfaces/newable.ts +1 -1
- package/src/interfaces/type.ts +2 -2
- package/src/reflect.ts +19 -10
- package/src/sanity-check/controller.ts +0 -1
- package/src/sanity-check/module.ts +2 -6
- package/src/server/middlewares/authentication-middleware.ts +14 -5
- package/src/server/middlewares/create-context-middleware.ts +5 -1
- package/src/server/middlewares/error-middleware.ts +5 -1
- package/src/server/middlewares/headers-middleware.ts +5 -1
- package/src/server/server.ts +32 -11
- package/src/zip-helper.ts +1 -1
- package/tsconfig.json +1 -4
package/src/firestore-client.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
_orderBy,
|
|
3
|
+
Cacheable,
|
|
4
|
+
deserialize,
|
|
5
|
+
Document,
|
|
6
|
+
Logger,
|
|
7
|
+
NotFoundError,
|
|
8
|
+
serialize
|
|
9
|
+
} from '@my-devkit/core';
|
|
2
10
|
import { getFirestore } from 'firebase-admin/firestore';
|
|
3
11
|
|
|
4
12
|
import { Injectable, TransactionalClient } from './decorators';
|
|
5
13
|
import { ITransactionalClient } from './interfaces';
|
|
6
14
|
|
|
7
|
-
|
|
8
15
|
@TransactionalClient()
|
|
9
16
|
@Injectable()
|
|
10
17
|
export class FirestoreClient implements ITransactionalClient {
|
|
@@ -45,11 +52,17 @@ export class FirestoreClient implements ITransactionalClient {
|
|
|
45
52
|
return this.queryDocument<T>(path);
|
|
46
53
|
}
|
|
47
54
|
|
|
48
|
-
public async _findWhere<T extends Document>(
|
|
55
|
+
public async _findWhere<T extends Document>(
|
|
56
|
+
collection: string,
|
|
57
|
+
whereClauses: [string, FirestoreClient.Operator, any | any[]][] = [],
|
|
58
|
+
options?: FirestoreClient.QueryOptions
|
|
59
|
+
): Promise<T> {
|
|
49
60
|
const documents = await this._getWhere<T>(collection, whereClauses, options);
|
|
50
61
|
|
|
51
62
|
if (documents.length > 1) {
|
|
52
|
-
throw new Error(
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Transactional Repository: Too many documents found (${documents.length})`
|
|
65
|
+
);
|
|
53
66
|
}
|
|
54
67
|
|
|
55
68
|
return documents[0] || null;
|
|
@@ -65,12 +78,21 @@ export class FirestoreClient implements ITransactionalClient {
|
|
|
65
78
|
return result;
|
|
66
79
|
}
|
|
67
80
|
|
|
68
|
-
public async _getAll<T extends Document>(
|
|
81
|
+
public async _getAll<T extends Document>(
|
|
82
|
+
collection: string,
|
|
83
|
+
options?: FirestoreClient.QueryOptions
|
|
84
|
+
): Promise<T[]> {
|
|
69
85
|
return this._getWhere(collection, [], options);
|
|
70
86
|
}
|
|
71
87
|
|
|
72
|
-
public async _getWhere<T extends Document>(
|
|
73
|
-
|
|
88
|
+
public async _getWhere<T extends Document>(
|
|
89
|
+
collection: string,
|
|
90
|
+
whereClauses: [string, FirestoreClient.Operator, any | any[]][] = [],
|
|
91
|
+
options?: FirestoreClient.QueryOptions
|
|
92
|
+
): Promise<T[]> {
|
|
93
|
+
Logger.info(
|
|
94
|
+
`Repository: getWhere ${collection} whereClauses: ${JSON.stringify(whereClauses)}`
|
|
95
|
+
);
|
|
74
96
|
const documentMap = await this.queryCollection<T>(collection, whereClauses, options);
|
|
75
97
|
|
|
76
98
|
for (const operation of Array.from(this.operations.values())) {
|
|
@@ -80,26 +102,36 @@ export class FirestoreClient implements ITransactionalClient {
|
|
|
80
102
|
case FirestoreClient.Action.Create:
|
|
81
103
|
if (this.doesDocumentMatchQuery(operation.document, collection, whereClauses)) {
|
|
82
104
|
documentMap.set(operation.document._path, <T>operation.document);
|
|
83
|
-
Logger.info(
|
|
105
|
+
Logger.info(
|
|
106
|
+
`Repository: Document ${operation.document._path} added to result`
|
|
107
|
+
);
|
|
84
108
|
}
|
|
85
109
|
break;
|
|
86
110
|
case FirestoreClient.Action.Update:
|
|
87
111
|
if (this.doesDocumentMatchQuery(operation.document, collection, whereClauses)) {
|
|
88
|
-
Logger.info(
|
|
112
|
+
Logger.info(
|
|
113
|
+
`Repository: Document ${operation.document._path} ${exists ? 'updated from' : 'added to'} result`
|
|
114
|
+
);
|
|
89
115
|
documentMap.set(operation.document._path, <T>operation.document);
|
|
90
116
|
} else if (exists) {
|
|
91
117
|
documentMap.delete(operation.document._path);
|
|
92
|
-
Logger.info(
|
|
118
|
+
Logger.info(
|
|
119
|
+
`Repository: Document ${operation.document._path} removed from result`
|
|
120
|
+
);
|
|
93
121
|
}
|
|
94
122
|
break;
|
|
95
123
|
case FirestoreClient.Action.Delete:
|
|
96
124
|
if (exists) {
|
|
97
125
|
documentMap.delete(operation.document._path);
|
|
98
|
-
Logger.info(
|
|
126
|
+
Logger.info(
|
|
127
|
+
`Repository: Document ${operation.document._path} removed from result`
|
|
128
|
+
);
|
|
99
129
|
}
|
|
100
130
|
break;
|
|
101
131
|
default:
|
|
102
|
-
throw new Error(
|
|
132
|
+
throw new Error(
|
|
133
|
+
`FirestoreClient: Unhandled existing operation ${operation.action} on ${operation.document._path}`
|
|
134
|
+
);
|
|
103
135
|
}
|
|
104
136
|
}
|
|
105
137
|
|
|
@@ -118,25 +150,34 @@ export class FirestoreClient implements ITransactionalClient {
|
|
|
118
150
|
return documents;
|
|
119
151
|
}
|
|
120
152
|
|
|
121
|
-
|
|
122
153
|
public createDocument<T extends Document>(document: T): void {
|
|
123
154
|
const existingOperation = this.operations.get(document._path);
|
|
124
155
|
|
|
125
156
|
if (existingOperation) {
|
|
126
157
|
switch (existingOperation.action) {
|
|
127
158
|
case FirestoreClient.Action.Create:
|
|
128
|
-
throw new Error(
|
|
159
|
+
throw new Error(
|
|
160
|
+
`FirestoreClient: can't create twice document ${document._path}`
|
|
161
|
+
);
|
|
129
162
|
case FirestoreClient.Action.Update:
|
|
130
|
-
throw new Error(
|
|
163
|
+
throw new Error(
|
|
164
|
+
`FirestoreClient: can't create already existing document ${document._path}`
|
|
165
|
+
);
|
|
131
166
|
case FirestoreClient.Action.Delete:
|
|
132
167
|
existingOperation.action = FirestoreClient.Action.Update;
|
|
133
168
|
existingOperation.document = document;
|
|
134
169
|
break;
|
|
135
170
|
default:
|
|
136
|
-
throw new Error(
|
|
171
|
+
throw new Error(
|
|
172
|
+
`FirestoreClient: Unhandled existing operation ${existingOperation.action} on ${document._path}`
|
|
173
|
+
);
|
|
137
174
|
}
|
|
138
175
|
} else {
|
|
139
|
-
this.operations.set(document._path, {
|
|
176
|
+
this.operations.set(document._path, {
|
|
177
|
+
document,
|
|
178
|
+
action: FirestoreClient.Action.Create,
|
|
179
|
+
committed: false
|
|
180
|
+
});
|
|
140
181
|
}
|
|
141
182
|
}
|
|
142
183
|
|
|
@@ -150,12 +191,20 @@ export class FirestoreClient implements ITransactionalClient {
|
|
|
150
191
|
existingOperation.document = document;
|
|
151
192
|
break;
|
|
152
193
|
case FirestoreClient.Action.Delete:
|
|
153
|
-
throw new Error(
|
|
194
|
+
throw new Error(
|
|
195
|
+
`FirestoreClient: can't update deleted document ${document._path}`
|
|
196
|
+
);
|
|
154
197
|
default:
|
|
155
|
-
throw new Error(
|
|
198
|
+
throw new Error(
|
|
199
|
+
`FirestoreClient: Unhandled existing operation ${existingOperation.action} on ${document._path}`
|
|
200
|
+
);
|
|
156
201
|
}
|
|
157
202
|
} else {
|
|
158
|
-
this.operations.set(document._path, {
|
|
203
|
+
this.operations.set(document._path, {
|
|
204
|
+
document,
|
|
205
|
+
action: FirestoreClient.Action.Update,
|
|
206
|
+
committed: false
|
|
207
|
+
});
|
|
159
208
|
}
|
|
160
209
|
}
|
|
161
210
|
|
|
@@ -172,16 +221,26 @@ export class FirestoreClient implements ITransactionalClient {
|
|
|
172
221
|
existingOperation.action = FirestoreClient.Action.Delete;
|
|
173
222
|
break;
|
|
174
223
|
case FirestoreClient.Action.Delete:
|
|
175
|
-
throw new Error(
|
|
224
|
+
throw new Error(
|
|
225
|
+
`FirestoreClient: can't delete already deleted document ${document._path}`
|
|
226
|
+
);
|
|
176
227
|
default:
|
|
177
|
-
throw new Error(
|
|
228
|
+
throw new Error(
|
|
229
|
+
`FirestoreClient: Unhandled existing operation ${existingOperation.action} on ${document._path}`
|
|
230
|
+
);
|
|
178
231
|
}
|
|
179
232
|
} else {
|
|
180
|
-
this.operations.set(document._path, {
|
|
233
|
+
this.operations.set(document._path, {
|
|
234
|
+
document,
|
|
235
|
+
action: FirestoreClient.Action.Delete,
|
|
236
|
+
committed: false
|
|
237
|
+
});
|
|
181
238
|
}
|
|
182
239
|
}
|
|
183
240
|
|
|
184
|
-
private getCollectionReference(
|
|
241
|
+
private getCollectionReference(
|
|
242
|
+
collection: string
|
|
243
|
+
): FirebaseFirestore.CollectionReference | FirebaseFirestore.Query {
|
|
185
244
|
if (collection.startsWith('**/')) {
|
|
186
245
|
return this.db.collectionGroup(collection.replace('**/', ''));
|
|
187
246
|
} else {
|
|
@@ -226,39 +285,56 @@ export class FirestoreClient implements ITransactionalClient {
|
|
|
226
285
|
return result ? deserialize<T>(result) : null;
|
|
227
286
|
}
|
|
228
287
|
|
|
229
|
-
private doesDocumentMatchQuery<T extends Document>(
|
|
288
|
+
private doesDocumentMatchQuery<T extends Document>(
|
|
289
|
+
document: T,
|
|
290
|
+
collection: string,
|
|
291
|
+
whereClauses: [string, FirestoreClient.Operator, any | any[]][]
|
|
292
|
+
): boolean {
|
|
230
293
|
const serializedDocument = serialize(document);
|
|
231
294
|
|
|
232
|
-
return
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
295
|
+
return (
|
|
296
|
+
document._path.startsWith(`${collection}/`) &&
|
|
297
|
+
whereClauses.every(wc => {
|
|
298
|
+
const documentValue = serializedDocument[wc[0]];
|
|
299
|
+
const operator = wc[1];
|
|
300
|
+
const expectedValue = wc[2];
|
|
301
|
+
|
|
302
|
+
switch (operator) {
|
|
303
|
+
case '==':
|
|
304
|
+
return documentValue === expectedValue;
|
|
305
|
+
case '!=':
|
|
306
|
+
return documentValue !== undefined && documentValue !== expectedValue;
|
|
307
|
+
case '>':
|
|
308
|
+
return documentValue > expectedValue;
|
|
309
|
+
case '>=':
|
|
310
|
+
return documentValue >= expectedValue;
|
|
311
|
+
case '<':
|
|
312
|
+
return documentValue < expectedValue;
|
|
313
|
+
case '<=':
|
|
314
|
+
return documentValue <= expectedValue;
|
|
315
|
+
case 'array-contains':
|
|
316
|
+
return (
|
|
317
|
+
Array.isArray(documentValue) && documentValue.includes(expectedValue)
|
|
318
|
+
);
|
|
319
|
+
case 'array-contains-any':
|
|
320
|
+
return (
|
|
321
|
+
Array.isArray(documentValue) &&
|
|
322
|
+
Array.isArray(expectedValue) &&
|
|
323
|
+
documentValue.some(v => expectedValue.includes(v))
|
|
324
|
+
);
|
|
325
|
+
case 'in':
|
|
326
|
+
return (
|
|
327
|
+
Array.isArray(expectedValue) && expectedValue.includes(documentValue)
|
|
328
|
+
);
|
|
329
|
+
case 'not-in':
|
|
330
|
+
return (
|
|
331
|
+
Array.isArray(expectedValue) && !expectedValue.includes(documentValue)
|
|
332
|
+
);
|
|
333
|
+
default:
|
|
334
|
+
throw new Error(`Operator ${operator} not handled!`);
|
|
335
|
+
}
|
|
336
|
+
})
|
|
337
|
+
);
|
|
262
338
|
}
|
|
263
339
|
|
|
264
340
|
private isCreateOperation(operation: FirestoreClient.Operation): boolean {
|
|
@@ -275,7 +351,6 @@ export class FirestoreClient implements ITransactionalClient {
|
|
|
275
351
|
}
|
|
276
352
|
|
|
277
353
|
export namespace FirestoreClient {
|
|
278
|
-
|
|
279
354
|
export interface Operation {
|
|
280
355
|
document: Document;
|
|
281
356
|
action: Action;
|
package/src/handler-helper.ts
CHANGED
|
@@ -6,7 +6,10 @@ import { ExecutionMode } from './execution-mode-enum';
|
|
|
6
6
|
import { FirestoreClient } from './firestore-client';
|
|
7
7
|
|
|
8
8
|
export class HandlerHelper {
|
|
9
|
-
public static async create<A extends Aggregate, R>(
|
|
9
|
+
public static async create<A extends Aggregate, R>(
|
|
10
|
+
aggregate: A,
|
|
11
|
+
callback: (a: A) => Promise<R>
|
|
12
|
+
): Promise<R> {
|
|
10
13
|
const result = await callback(aggregate);
|
|
11
14
|
|
|
12
15
|
this.client.createDocument(aggregate);
|
|
@@ -15,10 +18,15 @@ export class HandlerHelper {
|
|
|
15
18
|
return result;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
public static async update<A extends Aggregate, R>(
|
|
21
|
+
public static async update<A extends Aggregate, R>(
|
|
22
|
+
aggregateOrId: A | string,
|
|
23
|
+
callback: (a: A) => Promise<R>
|
|
24
|
+
): Promise<R> {
|
|
19
25
|
const aggregate = await this.getAggregate(aggregateOrId);
|
|
20
26
|
if (aggregate.events.length > 0) {
|
|
21
|
-
Logger.warn(
|
|
27
|
+
Logger.warn(
|
|
28
|
+
`${aggregate._type} ${aggregate.id} has ${aggregate.events.length} events!!`
|
|
29
|
+
);
|
|
22
30
|
}
|
|
23
31
|
const hashBefore = aggregate.hash;
|
|
24
32
|
|
|
@@ -28,14 +36,19 @@ export class HandlerHelper {
|
|
|
28
36
|
this.client.updateDocument(aggregate);
|
|
29
37
|
await this.publishEvents(aggregate);
|
|
30
38
|
} else {
|
|
31
|
-
Logger.debug(
|
|
39
|
+
Logger.debug(
|
|
40
|
+
`${aggregate._type} ${aggregate.id} didn't change, ${aggregate.events.length} events skipped`
|
|
41
|
+
);
|
|
32
42
|
aggregate.clearEvents();
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
return result;
|
|
36
46
|
}
|
|
37
47
|
|
|
38
|
-
public static async delete<A extends Aggregate, R>(
|
|
48
|
+
public static async delete<A extends Aggregate, R>(
|
|
49
|
+
aggregateOrId: A | string,
|
|
50
|
+
callback: (a: A) => Promise<R>
|
|
51
|
+
): Promise<R> {
|
|
39
52
|
const aggregate = await this.getAggregate(aggregateOrId);
|
|
40
53
|
|
|
41
54
|
const result = await callback(aggregate);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export type FromArray<T extends ReadonlyArray<unknown>> =
|
|
1
|
+
export type FromArray<T extends ReadonlyArray<unknown>> =
|
|
2
|
+
T extends ReadonlyArray<infer FromArray> ? FromArray : never;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type Newable<T> = new () => T;
|
|
1
|
+
export type Newable<T> = new () => T;
|
package/src/interfaces/type.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export interface Type<T = any>
|
|
2
|
-
new(...args: any[]): T;
|
|
1
|
+
export interface Type<T = any> {
|
|
2
|
+
new (...args: any[]): T;
|
|
3
3
|
}
|
package/src/reflect.ts
CHANGED
|
@@ -7,16 +7,16 @@ import { Type } from './interfaces';
|
|
|
7
7
|
import { RequestMethod } from './request-method.enum';
|
|
8
8
|
import { Server } from './server';
|
|
9
9
|
|
|
10
|
-
/* eslint-disable @typescript-eslint/ban-types */
|
|
11
10
|
class ReflectHelper<T extends ReflectTarget<any>> {
|
|
12
11
|
private readonly HANDLER_META_DATA = '__handler__';
|
|
13
12
|
private readonly CONTROLLER_META_DATA = '__controller__';
|
|
14
13
|
private readonly INJECTABLE_META_DATA = '__injectable__';
|
|
15
14
|
private readonly TRANSACTIONAL_CLIENT_META_DATA = '__transactional_client__';
|
|
16
15
|
|
|
17
|
-
constructor(
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
constructor(
|
|
17
|
+
private target: T,
|
|
18
|
+
private methodName: string | symbol
|
|
19
|
+
) {}
|
|
20
20
|
|
|
21
21
|
public getParameters(): Type[] {
|
|
22
22
|
return Reflect.getMetadata('design:paramtypes', this.target, this.methodName) || [];
|
|
@@ -27,7 +27,7 @@ class ReflectHelper<T extends ReflectTarget<any>> {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
public getInjectableId(): string {
|
|
30
|
-
return this.getMetaData<string>(this.INJECTABLE_META_DATA)
|
|
30
|
+
return this.getMetaData<string>(this.INJECTABLE_META_DATA);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
public registerTransactionalClient(): void {
|
|
@@ -35,7 +35,7 @@ class ReflectHelper<T extends ReflectTarget<any>> {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
public isTransactionalClient(): boolean {
|
|
38
|
-
return this.hasMetaData(this.TRANSACTIONAL_CLIENT_META_DATA)
|
|
38
|
+
return this.hasMetaData(this.TRANSACTIONAL_CLIENT_META_DATA);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
public getControllerConfiguration(): ControllerConfiguration {
|
|
@@ -53,12 +53,15 @@ class ReflectHelper<T extends ReflectTarget<any>> {
|
|
|
53
53
|
this.getControllerConfiguration().basePath = basePath;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
public registerControllerRoute(route: { path: string
|
|
56
|
+
public registerControllerRoute(route: { path: string; requestMethod: RequestMethod }): void {
|
|
57
57
|
this.getControllerRoute().path = route.path;
|
|
58
58
|
this.getControllerRoute().requestMethod = route.requestMethod;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
public registerControllerRouteArgumentInjector<T>(
|
|
61
|
+
public registerControllerRouteArgumentInjector<T>(
|
|
62
|
+
injector: RequestArgumentInjector<T>,
|
|
63
|
+
index: number
|
|
64
|
+
): void {
|
|
62
65
|
this.getControllerRoute().argumentInjectors[index] = injector;
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -80,7 +83,10 @@ class ReflectHelper<T extends ReflectTarget<any>> {
|
|
|
80
83
|
});
|
|
81
84
|
}
|
|
82
85
|
|
|
83
|
-
public registerEventHandler<E extends Event>(
|
|
86
|
+
public registerEventHandler<E extends Event>(
|
|
87
|
+
event: new () => E,
|
|
88
|
+
executionMode: ExecutionMode
|
|
89
|
+
): void {
|
|
84
90
|
this.getHandlerConfiguration().eventHandlers.set(this.methodName.toString(), {
|
|
85
91
|
methodName: this.methodName.toString(),
|
|
86
92
|
executionMode,
|
|
@@ -157,7 +163,10 @@ export interface HandlerConfiguration {
|
|
|
157
163
|
|
|
158
164
|
export type RequestArgumentInjector<T = any> = (req: Server.Request) => T;
|
|
159
165
|
|
|
160
|
-
export function reflect<T extends ReflectTarget<any>>(
|
|
166
|
+
export function reflect<T extends ReflectTarget<any>>(
|
|
167
|
+
target: T,
|
|
168
|
+
methodName?: string | symbol
|
|
169
|
+
): ReflectHelper<T> {
|
|
161
170
|
return new ReflectHelper(target, methodName);
|
|
162
171
|
}
|
|
163
172
|
|
|
@@ -3,10 +3,6 @@ import { Module } from '../decorators';
|
|
|
3
3
|
import { SanityCheckController } from './controller';
|
|
4
4
|
|
|
5
5
|
@Module({
|
|
6
|
-
controllers: [
|
|
7
|
-
SanityCheckController,
|
|
8
|
-
],
|
|
6
|
+
controllers: [SanityCheckController]
|
|
9
7
|
})
|
|
10
|
-
export class SanityCheckModule {
|
|
11
|
-
|
|
12
|
-
}
|
|
8
|
+
export class SanityCheckModule {}
|
|
@@ -4,10 +4,15 @@ import { Auth } from 'firebase-admin/auth';
|
|
|
4
4
|
import { Context } from '../../context';
|
|
5
5
|
import { Server } from '../server';
|
|
6
6
|
|
|
7
|
-
|
|
8
7
|
export function AuthenticationMiddleware(auth: Auth, publicPaths: string[]): Server.RequestHandler {
|
|
9
|
-
return async (
|
|
10
|
-
|
|
8
|
+
return async (
|
|
9
|
+
request: Server.Request,
|
|
10
|
+
_response: Server.Response,
|
|
11
|
+
next: Server.NextFunction
|
|
12
|
+
): Promise<void> => {
|
|
13
|
+
const authorizationHeader = request.headers.authorization
|
|
14
|
+
? request.headers.authorization.toString()
|
|
15
|
+
: null;
|
|
11
16
|
Logger.info(`${request.method} ${request.path}: Authentication check`);
|
|
12
17
|
|
|
13
18
|
if (publicPaths.includes(request.path)) {
|
|
@@ -26,7 +31,9 @@ export function AuthenticationMiddleware(auth: Auth, publicPaths: string[]): Ser
|
|
|
26
31
|
Context.user = await auth.getUser(userId);
|
|
27
32
|
next();
|
|
28
33
|
} catch (error) {
|
|
29
|
-
throw new UnauthorizedError(
|
|
34
|
+
throw new UnauthorizedError(
|
|
35
|
+
`Error while verifying token ${error.message ? error.message : null}`
|
|
36
|
+
);
|
|
30
37
|
}
|
|
31
38
|
} else if (authorizationHeader.startsWith('Basic')) {
|
|
32
39
|
const idToken = authorizationHeader.split('Basic ')[1];
|
|
@@ -38,7 +45,9 @@ export function AuthenticationMiddleware(auth: Auth, publicPaths: string[]): Ser
|
|
|
38
45
|
Context.user = await auth.getUser(userId);
|
|
39
46
|
next();
|
|
40
47
|
} catch (error) {
|
|
41
|
-
throw new UnauthorizedError(
|
|
48
|
+
throw new UnauthorizedError(
|
|
49
|
+
`Error while verifying token ${error.message ? error.message : null}`
|
|
50
|
+
);
|
|
42
51
|
}
|
|
43
52
|
} else {
|
|
44
53
|
throw new UnauthorizedError('Incorrect authorization header');
|
|
@@ -5,7 +5,11 @@ import { Context } from '../../context';
|
|
|
5
5
|
import { Server } from '../server';
|
|
6
6
|
|
|
7
7
|
export function CreateContextMiddleware(bus: Bus): Server.RequestHandler {
|
|
8
|
-
return async (
|
|
8
|
+
return async (
|
|
9
|
+
request: Server.Request,
|
|
10
|
+
_response: Server.Response,
|
|
11
|
+
next: Server.NextFunction
|
|
12
|
+
): Promise<void> => {
|
|
9
13
|
Context.create(bus);
|
|
10
14
|
Context.correlationId = request.header('X-Correlation-ID') || guid();
|
|
11
15
|
|
|
@@ -4,7 +4,11 @@ import { Context } from '../../context';
|
|
|
4
4
|
import { Server } from '../server';
|
|
5
5
|
|
|
6
6
|
export function ErrorMiddleWare(): Server.ErrorHandler {
|
|
7
|
-
return async (
|
|
7
|
+
return async (
|
|
8
|
+
error: any,
|
|
9
|
+
_request: Server.Request,
|
|
10
|
+
response: Server.Response
|
|
11
|
+
): Promise<void> => {
|
|
8
12
|
if (!(error instanceof Error)) {
|
|
9
13
|
error = new Error(error);
|
|
10
14
|
}
|
|
@@ -2,7 +2,11 @@ import { Context } from '../../context';
|
|
|
2
2
|
import { Server } from '../server';
|
|
3
3
|
|
|
4
4
|
export function HeadersMiddleWare(): Server.RequestHandler {
|
|
5
|
-
return async (
|
|
5
|
+
return async (
|
|
6
|
+
_request: Server.Request,
|
|
7
|
+
response: Server.Response,
|
|
8
|
+
next: Server.NextFunction
|
|
9
|
+
): Promise<void> => {
|
|
6
10
|
response.removeHeader('X-Powered-By'); // Remove verbose express
|
|
7
11
|
response.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); // HTTP 1.1.
|
|
8
12
|
response.setHeader('Pragma', 'no-cache'); // HTTP 1.0.
|
package/src/server/server.ts
CHANGED
|
@@ -8,7 +8,11 @@ import { RequestMethod } from '../request-method.enum';
|
|
|
8
8
|
import * as middlewares from './middlewares';
|
|
9
9
|
|
|
10
10
|
function encapsulate(handler: Server.RequestHandler): Server.RequestHandler {
|
|
11
|
-
return async (
|
|
11
|
+
return async (
|
|
12
|
+
request: Server.Request,
|
|
13
|
+
response: Server.Response,
|
|
14
|
+
next: Server.NextFunction
|
|
15
|
+
): Promise<void> => {
|
|
12
16
|
try {
|
|
13
17
|
await handler(request, response, next);
|
|
14
18
|
} catch (error) {
|
|
@@ -26,7 +30,9 @@ export class Server {
|
|
|
26
30
|
this.registerRequestHandler(cors({ origin: true }));
|
|
27
31
|
this.registerRequestHandler(middlewares.CreateContextMiddleware(options.bus));
|
|
28
32
|
this.registerRequestHandler(middlewares.HeadersMiddleWare());
|
|
29
|
-
this.registerRequestHandler(
|
|
33
|
+
this.registerRequestHandler(
|
|
34
|
+
middlewares.AuthenticationMiddleware(options.firebaseAuth, options.publicPaths)
|
|
35
|
+
);
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
public registerRequestHandler(handler: Server.RequestHandler): void {
|
|
@@ -34,13 +40,20 @@ export class Server {
|
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
public registerErrorHandler(handler: Server.ErrorHandler): void {
|
|
37
|
-
this._app.use(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
this._app.use(
|
|
44
|
+
async (
|
|
45
|
+
error: any,
|
|
46
|
+
request: Server.Request,
|
|
47
|
+
response: Server.Response,
|
|
48
|
+
next: Server.NextFunction
|
|
49
|
+
): Promise<void> => {
|
|
50
|
+
try {
|
|
51
|
+
await handler(error, request, response, next);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
next(error);
|
|
54
|
+
}
|
|
42
55
|
}
|
|
43
|
-
|
|
56
|
+
);
|
|
44
57
|
}
|
|
45
58
|
|
|
46
59
|
public registerRouter(path: string, router: express.Router): void {
|
|
@@ -56,7 +69,6 @@ export class Server {
|
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
export namespace Server {
|
|
59
|
-
|
|
60
72
|
export interface Options {
|
|
61
73
|
bus: Bus;
|
|
62
74
|
firebaseAuth: auth.Auth;
|
|
@@ -91,6 +103,15 @@ export namespace Server {
|
|
|
91
103
|
export type Request = express.Request;
|
|
92
104
|
export type Response = express.Response;
|
|
93
105
|
export type NextFunction = express.NextFunction;
|
|
94
|
-
export type RequestHandler = (
|
|
95
|
-
|
|
106
|
+
export type RequestHandler = (
|
|
107
|
+
request: Request,
|
|
108
|
+
response: Response,
|
|
109
|
+
next: NextFunction
|
|
110
|
+
) => Promise<void> | void;
|
|
111
|
+
export type ErrorHandler = (
|
|
112
|
+
error: any,
|
|
113
|
+
request: Request,
|
|
114
|
+
response: Response,
|
|
115
|
+
next: NextFunction
|
|
116
|
+
) => Promise<void> | void;
|
|
96
117
|
}
|
package/src/zip-helper.ts
CHANGED