@clairejs/server 3.15.1 → 3.16.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.
Files changed (86) hide show
  1. package/.mocharc.json +3 -0
  2. package/README.md +1 -1
  3. package/dist/common/AbstractController.js +3 -0
  4. package/dist/common/ControllerMetadata.js +1 -0
  5. package/dist/common/FileOperation.js +6 -0
  6. package/dist/common/ServerModelMetadata.js +1 -0
  7. package/dist/common/Transactionable.js +17 -0
  8. package/dist/common/auth/AbstractPrincipalResolver.js +2 -0
  9. package/dist/common/auth/IPrincipal.js +1 -0
  10. package/dist/common/constants.js +7 -0
  11. package/dist/common/decorator.d.ts +2 -2
  12. package/dist/common/decorator.js +6 -0
  13. package/dist/common/request/EndpointMetadata.js +1 -0
  14. package/dist/common/request/HttpData.js +1 -0
  15. package/dist/common/request/HttpEndpoint.js +1 -0
  16. package/dist/common/request/JobData.js +1 -0
  17. package/dist/common/request/MountedEndpointInfo.js +1 -0
  18. package/dist/common/request/RequestOptions.js +1 -0
  19. package/dist/common/request/SocketData.js +1 -0
  20. package/dist/common/request/types.d.ts +1 -1
  21. package/dist/common/request/types.js +1 -0
  22. package/dist/controllers/FileManageController.js +90 -0
  23. package/dist/controllers/FileUploadController.js +64 -0
  24. package/dist/controllers/dto/system.js +14 -0
  25. package/dist/controllers/dto/upload.js +205 -0
  26. package/dist/http/auth/AbstractHttpAuthorizer.js +2 -0
  27. package/dist/http/common/HttpRequest.js +72 -0
  28. package/dist/http/common/HttpResponse.js +62 -0
  29. package/dist/http/controller/AbstractHttpController.js +21 -0
  30. package/dist/http/controller/AbstractHttpMiddleware.js +2 -0
  31. package/dist/http/controller/AbstractHttpRequestHandler.js +69 -0
  32. package/dist/http/controller/CrudHttpController.js +302 -0
  33. package/dist/http/controller/DefaultHttpRequestHandler.js +143 -0
  34. package/dist/http/decorators.d.ts +1 -1
  35. package/dist/http/decorators.js +86 -0
  36. package/dist/http/file-upload/AbstractFileUploadHandler.js +2 -0
  37. package/dist/http/file-upload/FileUploadHandler.js +41 -0
  38. package/dist/http/file-upload/types.d.ts +1 -1
  39. package/dist/http/file-upload/types.js +1 -0
  40. package/dist/http/repository/AbstractRepository.js +26 -0
  41. package/dist/http/repository/DtoRepository.d.ts +3 -3
  42. package/dist/http/repository/DtoRepository.js +204 -0
  43. package/dist/http/repository/ICrudRepository.js +1 -0
  44. package/dist/http/repository/ModelRepository.js +696 -0
  45. package/dist/http/security/AbstractAccessCondition.js +2 -0
  46. package/dist/http/security/access-conditions/FilterModelFieldAccessCondition.js +30 -0
  47. package/dist/http/security/access-conditions/MaximumQueryLimit.js +31 -0
  48. package/dist/http/security/cors.js +1 -0
  49. package/dist/http/utils.js +32 -0
  50. package/dist/index.js +75 -1
  51. package/dist/job/AbstractJobController.js +9 -0
  52. package/dist/job/AbstractJobRepository.js +2 -0
  53. package/dist/job/AbstractJobScheduler.js +48 -0
  54. package/dist/job/AwsJobScheduler.js +405 -0
  55. package/dist/job/LocalJobScheduler.js +273 -0
  56. package/dist/job/decorators.js +57 -0
  57. package/dist/job/interfaces.js +10 -0
  58. package/dist/logging/FileLogMedium.js +44 -0
  59. package/dist/services/AbstractFileService.js +28 -0
  60. package/dist/services/AbstractMailService.js +2 -0
  61. package/dist/services/AbstractService.js +3 -0
  62. package/dist/services/AbstractSmsService.js +2 -0
  63. package/dist/services/implementations/LocalFileService.js +42 -0
  64. package/dist/services/implementations/LocalMailService.js +27 -0
  65. package/dist/services/implementations/LocalSmsService.js +17 -0
  66. package/dist/services/implementations/S3FileService.js +107 -0
  67. package/dist/services/implementations/SesMailService.js +64 -0
  68. package/dist/socket/AbstractServerSocket.js +44 -0
  69. package/dist/socket/AbstractServerSocketManager.d.ts +1 -1
  70. package/dist/socket/AbstractServerSocketManager.js +348 -0
  71. package/dist/socket/AbstractSocketConnectionHandler.js +2 -0
  72. package/dist/socket/AbstractSocketController.d.ts +3 -3
  73. package/dist/socket/AbstractSocketController.js +12 -0
  74. package/dist/socket/AwsSocketManager.d.ts +2 -2
  75. package/dist/socket/AwsSocketManager.js +160 -0
  76. package/dist/socket/IServerSocket.js +1 -0
  77. package/dist/socket/LocalSocketManager.js +292 -0
  78. package/dist/system/ClaireServer.js +78 -0
  79. package/dist/system/ExpressWrapper.js +122 -0
  80. package/dist/system/LambdaWrapper.js +151 -0
  81. package/dist/system/ServerGlobalStore.js +1 -0
  82. package/dist/system/lamba-request-mapper.js +49 -0
  83. package/dist/system/locale/LocaleEntry.js +13 -0
  84. package/dist/system/locale/LocaleTranslation.js +47 -0
  85. package/dist/system/locale/decorators.js +14 -0
  86. package/package.json +13 -20
@@ -0,0 +1,26 @@
1
+ import { getObjectMetadata } from "@clairejs/core";
2
+ export class AbstractRepository {
3
+ model;
4
+ modelMetadata;
5
+ constructor(model) {
6
+ this.model = model;
7
+ this.modelMetadata = getObjectMetadata(this.model);
8
+ }
9
+ async beforeCreating(principal, records) {
10
+ //-- check for fields that has URI with mapper property
11
+ for (const record of records) {
12
+ for (const field of this.modelMetadata.fields) {
13
+ if (field.userResolver && principal) {
14
+ //-- resolve user from principal
15
+ record[field.name] = field.userResolver(principal);
16
+ }
17
+ }
18
+ }
19
+ }
20
+ project(records, projection) {
21
+ if (!projection) {
22
+ return records;
23
+ }
24
+ return records.map((re) => projection.reduce((collector, fieldName) => Object.assign(collector, { [fieldName]: re[fieldName] }), {}));
25
+ }
26
+ }
@@ -3,7 +3,7 @@ import { IQueryProvider, ITransaction, QueryCondition } from "@clairejs/orm";
3
3
  import { IPrincipal } from "../../common/auth/IPrincipal";
4
4
  import { AbstractRepository } from "./AbstractRepository";
5
5
  import { ICrudRepository } from "./ICrudRepository";
6
- export declare type DtoDissolver<R extends Identifiable, K extends Identifiable> = (t: DeepPartial<K>) => MappingMetadata<R, any>[];
6
+ export type DtoDissolver<R extends Identifiable, K extends Identifiable> = (t: DeepPartial<K>) => MappingMetadata<R, any>[];
7
7
  export interface MappingMetadata<R extends Identifiable, K extends AbstractModel> {
8
8
  multiple: boolean;
9
9
  modelClass: Constructor<K>;
@@ -12,7 +12,7 @@ export interface MappingMetadata<R extends Identifiable, K extends AbstractModel
12
12
  rootMapping: (ks?: DeepPartial<K>[]) => DeepPartial<R>;
13
13
  nestedMapping?: DtoDissolver<R, K>;
14
14
  }
15
- export declare const SingleMap: <R extends Identifiable<string | number>, K extends AbstractModel>(modelClass: Constructor<K>, forwardOps: (ops?: QueryCondition<R>[] | undefined) => QueryCondition<K>[] | undefined, forwardMapping: (t: DeepPartial<K>) => DeepPartial<K> | undefined, rootMapping: (k?: DeepPartial<K> | undefined) => DeepPartial<R>, nestedMapping?: DtoDissolver<R, K> | undefined) => {
15
+ export declare const SingleMap: <R extends Identifiable, K extends AbstractModel>(modelClass: Constructor<K>, forwardOps: (ops?: QueryCondition<R>[] | undefined) => QueryCondition<K>[] | undefined, forwardMapping: (t: DeepPartial<K>) => DeepPartial<K> | undefined, rootMapping: (k?: DeepPartial<K> | undefined) => DeepPartial<R>, nestedMapping?: DtoDissolver<R, K> | undefined) => {
16
16
  multiple: boolean;
17
17
  modelClass: Constructor<K>;
18
18
  forwardOps: (ops?: QueryCondition<R>[] | undefined) => QueryCondition<K>[] | undefined;
@@ -20,7 +20,7 @@ export declare const SingleMap: <R extends Identifiable<string | number>, K exte
20
20
  rootMapping: (ks?: DeepPartial<K>[] | undefined) => DeepPartial<R>;
21
21
  nestedMapping: DtoDissolver<R, K> | undefined;
22
22
  };
23
- export declare const MultipleMap: <R extends Identifiable<string | number>, K extends AbstractModel>(modelClass: Constructor<K>, forwardOps: (ops?: QueryCondition<R>[] | undefined) => QueryCondition<K>[] | undefined, forwardMapping: (t: DeepPartial<K>[]) => DeepPartial<K>[] | undefined, rootMapping: (ks?: DeepPartial<K>[] | undefined) => DeepPartial<R>, nestedMapping?: DtoDissolver<R, K> | undefined) => {
23
+ export declare const MultipleMap: <R extends Identifiable, K extends AbstractModel>(modelClass: Constructor<K>, forwardOps: (ops?: QueryCondition<R>[] | undefined) => QueryCondition<K>[] | undefined, forwardMapping: (t: DeepPartial<K>[]) => DeepPartial<K>[] | undefined, rootMapping: (ks?: DeepPartial<K>[] | undefined) => DeepPartial<R>, nestedMapping?: DtoDissolver<R, K> | undefined) => {
24
24
  multiple: boolean;
25
25
  modelClass: Constructor<K>;
26
26
  forwardOps: (ops?: QueryCondition<R>[] | undefined) => QueryCondition<K>[] | undefined;
@@ -0,0 +1,204 @@
1
+ import { deepMerge, Errors, } from "@clairejs/core";
2
+ import { AbstractRepository } from "./AbstractRepository";
3
+ import { ModelRepository } from "./ModelRepository";
4
+ export const SingleMap = (modelClass, forwardOps, forwardMapping, rootMapping, nestedMapping) => ({
5
+ multiple: false,
6
+ modelClass,
7
+ forwardOps,
8
+ forwardMapping: (t) => {
9
+ const v = forwardMapping(t[0] || {});
10
+ return v && [v];
11
+ },
12
+ rootMapping: (ks) => {
13
+ const k = ks && ks[0];
14
+ return rootMapping(k);
15
+ },
16
+ nestedMapping,
17
+ });
18
+ export const MultipleMap = (modelClass, forwardOps, forwardMapping, rootMapping, nestedMapping) => ({
19
+ multiple: true,
20
+ modelClass,
21
+ forwardOps,
22
+ forwardMapping,
23
+ rootMapping,
24
+ nestedMapping,
25
+ });
26
+ export class DtoRepository extends AbstractRepository {
27
+ model;
28
+ dissolver;
29
+ constructor(model, dissolver) {
30
+ super(model);
31
+ this.model = model;
32
+ this.dissolver = dissolver;
33
+ }
34
+ async getMapValue(root, currentInstancesResolver, mappers, preOperator, postOperator) {
35
+ for (const mapper of mappers) {
36
+ const currentInstances = await currentInstancesResolver(mapper);
37
+ let instances = preOperator
38
+ ? await preOperator(mapper, mapper.forwardMapping(currentInstances), currentInstances)
39
+ : mapper.forwardMapping(currentInstances);
40
+ if (mapper.nestedMapping && instances) {
41
+ //-- resolve nested
42
+ for (const instance of instances) {
43
+ await this.getMapValue(root, currentInstancesResolver, mapper.nestedMapping(instance), preOperator, postOperator);
44
+ }
45
+ }
46
+ if (postOperator) {
47
+ instances = await postOperator(mapper, mapper.forwardMapping(currentInstances), currentInstances);
48
+ }
49
+ //-- backward assign
50
+ const partial = mapper.rootMapping(instances);
51
+ deepMerge(root, partial);
52
+ }
53
+ }
54
+ async createMany({ principal, body, tx, }) {
55
+ const result = [];
56
+ await this.beforeCreating(principal, body.records);
57
+ for (const record of body.records) {
58
+ await this.getMapValue(record, async (mapper) => {
59
+ const repo = new ModelRepository(mapper.modelClass);
60
+ const currentInstances = await repo.getMany({
61
+ ops: mapper.forwardOps(),
62
+ queryProvider: tx,
63
+ });
64
+ return currentInstances.records;
65
+ }, this.dissolver(record), async (mapper, ks, currentInstances) => {
66
+ if (!ks) {
67
+ return [];
68
+ }
69
+ const repo = new ModelRepository(mapper.modelClass);
70
+ const ops = mapper.forwardOps();
71
+ if (mapper.multiple) {
72
+ //-- if ks contain an array of instances, we need to remove old instances and create new ones
73
+ await repo.deleteMany({ ops, tx });
74
+ //-- try creating new
75
+ const createManyResult = await repo.createMany({ principal, body: { records: ks }, tx });
76
+ return createManyResult.records;
77
+ }
78
+ else {
79
+ //-- single mapping, we need to update record if found
80
+ const k = ks[0];
81
+ if (!k) {
82
+ return [];
83
+ }
84
+ if (currentInstances.length === 0) {
85
+ //-- record not found, create new
86
+ const instances = await repo.createMany({
87
+ principal,
88
+ body: { records: ks },
89
+ tx,
90
+ });
91
+ return instances.records;
92
+ }
93
+ else if (currentInstances.length === 1) {
94
+ const result = await repo.updateMany({ principal, ops, body: { update: k }, tx });
95
+ return [{ ...currentInstances[0], ...k, ...result.modified[0] }];
96
+ }
97
+ else {
98
+ throw Errors.VALIDATION_ERROR(`Found multiple record when creating ${mapper.modelClass.name}`);
99
+ }
100
+ }
101
+ });
102
+ result.push(record);
103
+ }
104
+ return { records: result };
105
+ }
106
+ async updateMany({ principal, queries, ops, body, tx, }) {
107
+ //-- check queries for id field
108
+ if (!queries?.fields?.id || queries.fields.id.length !== 1) {
109
+ throw Errors.VALIDATION_ERROR("Missing required id field in query");
110
+ }
111
+ const result = { ...body.update, id: queries.fields.id[0] };
112
+ await this.beforeCreating(principal, [result]);
113
+ await this.getMapValue(result, async (mapper) => {
114
+ const repo = new ModelRepository(mapper.modelClass);
115
+ const currentInstances = await repo.getMany({
116
+ ops: mapper.forwardOps(ops),
117
+ queryProvider: tx,
118
+ });
119
+ return currentInstances.records;
120
+ }, this.dissolver(result), async (mapper, ks, currentInstances) => {
121
+ if (!ks) {
122
+ return [];
123
+ }
124
+ const repo = new ModelRepository(mapper.modelClass);
125
+ const opsx = mapper.forwardOps(ops);
126
+ if (mapper.multiple) {
127
+ //-- if ks contain an array of instances, we need to remove old instances and create new ones
128
+ await repo.deleteMany({ ops: opsx, tx });
129
+ //-- try creating new
130
+ const createManyResult = await repo.createMany({ principal, body: { records: ks }, tx });
131
+ return createManyResult.records;
132
+ }
133
+ else {
134
+ //-- if ks contain only one instance, we only need to update that instance
135
+ const k = ks[0];
136
+ if (!k) {
137
+ return [];
138
+ }
139
+ if (currentInstances.length == 0) {
140
+ //-- record not found, return empty array
141
+ return [];
142
+ }
143
+ if (currentInstances.length > 1) {
144
+ //-- remove all instances
145
+ await repo.deleteMany({ ops: opsx, tx });
146
+ //-- try creating new
147
+ await repo.createMany({ principal, body: { records: [k] }, tx });
148
+ }
149
+ else {
150
+ //-- update current instance
151
+ await repo.updateMany({ principal, ops: opsx, body: { update: k }, tx });
152
+ }
153
+ return currentInstances.map((re) => ({ ...re, ...k }));
154
+ }
155
+ });
156
+ let projection = ["id"];
157
+ if (queries.returning) {
158
+ //-- return result
159
+ projection = [
160
+ ...projection,
161
+ ...Object.keys(body.update).filter((key) => body.update[key] !== undefined),
162
+ ];
163
+ }
164
+ return { modified: result.id ? this.project([result], projection) : [] };
165
+ }
166
+ async getMany({ queries, ops, queryProvider, }) {
167
+ //-- check queries for id field
168
+ if (!queries?.fields?.id || queries.fields.id.length !== 1) {
169
+ throw Errors.VALIDATION_ERROR("Missing required id field in query");
170
+ }
171
+ const result = { id: queries.fields.id[0] };
172
+ await this.getMapValue(result, async () => [], this.dissolver(result), async (mapper) => {
173
+ const repo = new ModelRepository(mapper.modelClass);
174
+ //-- forward get
175
+ const instances = await repo.getMany({
176
+ ops: mapper.forwardOps(ops),
177
+ queryProvider,
178
+ });
179
+ return instances.records;
180
+ });
181
+ return result.id
182
+ ? { records: this.project([result], queries.projection), total: 1 }
183
+ : { records: [], total: 0 };
184
+ }
185
+ async deleteMany({ queries, ops, tx, }) {
186
+ //-- check queries for id field
187
+ if (!queries?.fields?.id || queries.fields.id.length !== 1) {
188
+ throw Errors.VALIDATION_ERROR("Missing required id field in query");
189
+ }
190
+ const result = { id: queries.fields.id[0] };
191
+ await this.getMapValue(result, async () => [], this.dissolver(result), undefined, async (mapper) => {
192
+ const repo = new ModelRepository(mapper.modelClass);
193
+ //const nestedQueries = mapper.forwardQuery();
194
+ const nestedOps = mapper.forwardOps(ops);
195
+ const result = await repo.deleteMany({
196
+ queries: { returning: queries?.returning },
197
+ ops: nestedOps,
198
+ tx,
199
+ });
200
+ return result.modified;
201
+ });
202
+ return { modified: result.id ? [result] : [] };
203
+ }
204
+ }
@@ -0,0 +1 @@
1
+ export {};