@tstdl/base 0.91.49 → 0.91.51

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 (164) hide show
  1. package/ai/data-extracting.d.ts +1 -0
  2. package/ai/data-extracting.js +62 -0
  3. package/authentication/server/authentication.api-controller.js +4 -4
  4. package/cancellation/token.d.ts +1 -2
  5. package/cancellation/token.js +1 -1
  6. package/core.d.ts +1 -1
  7. package/core.js +1 -1
  8. package/document-management/api/document-management.api.d.ts +376 -0
  9. package/document-management/api/document-management.api.js +208 -0
  10. package/document-management/api/index.d.ts +1 -0
  11. package/document-management/api/index.js +1 -0
  12. package/document-management/drizzle/0000_wakeful_firebrand.sql +228 -0
  13. package/document-management/drizzle/meta/0000_snapshot.json +1538 -0
  14. package/document-management/drizzle/meta/_journal.json +13 -0
  15. package/document-management/drizzle.config.d.ts +2 -0
  16. package/document-management/drizzle.config.js +11 -0
  17. package/document-management/index.d.ts +2 -0
  18. package/document-management/index.js +2 -0
  19. package/document-management/localizations/english.d.ts +2 -0
  20. package/document-management/localizations/english.js +9 -0
  21. package/document-management/localizations/german.d.ts +2 -0
  22. package/document-management/localizations/german.js +9 -0
  23. package/document-management/localizations/index.d.ts +5 -0
  24. package/document-management/localizations/index.js +9 -0
  25. package/document-management/localizations/localization.d.ts +9 -0
  26. package/document-management/localizations/localization.js +2 -0
  27. package/document-management/models/document-category.model.d.ts +4 -0
  28. package/document-management/models/document-category.model.js +18 -0
  29. package/document-management/models/document-collection-document.model.d.ts +7 -0
  30. package/document-management/models/document-collection-document.model.js +33 -0
  31. package/document-management/models/document-collection.model.d.ts +3 -0
  32. package/document-management/models/document-collection.model.js +14 -0
  33. package/document-management/models/document-file.model.d.ts +7 -0
  34. package/document-management/models/document-file.model.js +33 -0
  35. package/document-management/models/document-property-value.model.d.ts +21 -0
  36. package/document-management/models/document-property-value.model.js +58 -0
  37. package/document-management/models/document-property.model.d.ts +11 -0
  38. package/document-management/models/document-property.model.js +30 -0
  39. package/document-management/models/document-request-collection.model.d.ts +6 -0
  40. package/document-management/models/document-request-collection.model.js +28 -0
  41. package/document-management/models/document-request-file.model.d.ts +11 -0
  42. package/document-management/models/document-request-file.model.js +56 -0
  43. package/document-management/models/document-request-template.d.ts +10 -0
  44. package/document-management/models/document-request-template.js +39 -0
  45. package/document-management/models/document-request.model.d.ts +9 -0
  46. package/document-management/models/document-request.model.js +37 -0
  47. package/document-management/models/document-requests-template.d.ts +5 -0
  48. package/document-management/models/document-requests-template.js +23 -0
  49. package/document-management/models/document-type-property.model.d.ts +6 -0
  50. package/document-management/models/document-type-property.model.js +28 -0
  51. package/document-management/models/document-type.model.d.ts +7 -0
  52. package/document-management/models/document-type.model.js +32 -0
  53. package/document-management/models/document.model.d.ts +9 -0
  54. package/document-management/models/document.model.js +44 -0
  55. package/document-management/models/index.d.ts +15 -0
  56. package/document-management/models/index.js +15 -0
  57. package/document-management/models/schemas.d.ts +33 -0
  58. package/document-management/models/schemas.js +34 -0
  59. package/document-management/models/service-models/categories-and-types.view-model.d.ts +6 -0
  60. package/document-management/models/service-models/categories-and-types.view-model.js +24 -0
  61. package/document-management/models/service-models/document-folders.view-model.d.ts +22 -0
  62. package/document-management/models/service-models/document-folders.view-model.js +56 -0
  63. package/document-management/models/service-models/document-requests-template.view-model.d.ts +8 -0
  64. package/document-management/models/service-models/document-requests-template.view-model.js +26 -0
  65. package/document-management/models/service-models/document.service-model.d.ts +262 -0
  66. package/document-management/models/service-models/document.service-model.js +50 -0
  67. package/document-management/models/service-models/document.view-model.d.ts +33 -0
  68. package/document-management/models/service-models/document.view-model.js +99 -0
  69. package/document-management/models/service-models/index.d.ts +8 -0
  70. package/document-management/models/service-models/index.js +8 -0
  71. package/document-management/models/service-models/normalized-document-collection-view.model.d.ts +73 -0
  72. package/document-management/models/service-models/normalized-document-collection-view.model.js +110 -0
  73. package/document-management/models/service-models/normalized-requests-template-data.model.d.ts +16 -0
  74. package/document-management/models/service-models/normalized-requests-template-data.model.js +13 -0
  75. package/document-management/models/service-models/stats.view-model.d.ts +6 -0
  76. package/document-management/models/service-models/stats.view-model.js +32 -0
  77. package/document-management/module.d.ts +11 -0
  78. package/document-management/module.js +27 -0
  79. package/document-management/services/document-management.service.d.ts +65 -0
  80. package/document-management/services/document-management.service.js +376 -0
  81. package/document-management/services/index.d.ts +1 -0
  82. package/document-management/services/index.js +1 -0
  83. package/examples/document-management/main.d.ts +1 -0
  84. package/examples/document-management/main.js +30 -0
  85. package/examples/orm/drizzle.config.js +2 -1
  86. package/examples/orm/schemas.d.ts +1 -1
  87. package/examples/orm/user.model.d.ts +1 -2
  88. package/examples/orm/user.model.js +0 -1
  89. package/http/server/node/node-http-server.js +5 -5
  90. package/injector/injector.d.ts +4 -1
  91. package/injector/injector.js +4 -1
  92. package/injector/interfaces.d.ts +3 -3
  93. package/json-path/json-path.d.ts +2 -0
  94. package/json-path/json-path.js +7 -0
  95. package/message-bus/message-bus.d.ts +4 -6
  96. package/orm/database-schema.d.ts +3 -0
  97. package/orm/database-schema.js +6 -2
  98. package/orm/database.d.ts +6 -0
  99. package/orm/database.js +14 -0
  100. package/orm/decorators.d.ts +25 -2
  101. package/orm/decorators.js +15 -0
  102. package/orm/drizzle/index.d.ts +1 -0
  103. package/orm/drizzle/index.js +1 -0
  104. package/orm/drizzle/schema-converter.d.ts +37 -8
  105. package/orm/drizzle/schema-converter.js +121 -40
  106. package/orm/entity.d.ts +15 -12
  107. package/orm/entity.js +24 -11
  108. package/orm/index.d.ts +3 -2
  109. package/orm/index.js +3 -2
  110. package/orm/module.d.ts +6 -0
  111. package/orm/module.js +15 -0
  112. package/orm/query-converter.d.ts +5 -0
  113. package/orm/query-converter.js +114 -0
  114. package/orm/query.d.ts +15 -13
  115. package/orm/repository.d.ts +90 -31
  116. package/orm/repository.js +357 -55
  117. package/orm/schemas/index.d.ts +3 -0
  118. package/orm/schemas/index.js +3 -0
  119. package/orm/schemas/json.d.ts +9 -0
  120. package/orm/schemas/json.js +19 -0
  121. package/orm/schemas/numeric-date.d.ts +8 -0
  122. package/orm/schemas/numeric-date.js +13 -0
  123. package/orm/schemas/timestamp.d.ts +10 -0
  124. package/orm/schemas/timestamp.js +20 -0
  125. package/orm/transaction.d.ts +29 -0
  126. package/orm/transaction.js +73 -0
  127. package/orm/types.d.ts +15 -8
  128. package/orm/types.js +3 -2
  129. package/package.json +22 -12
  130. package/{rxjs → rxjs-utils}/reject-error.d.ts +1 -1
  131. package/{rxjs → rxjs-utils}/retry-backoff.d.ts +2 -2
  132. package/{rxjs → rxjs-utils}/slow-array.d.ts +7 -7
  133. package/{rxjs → rxjs-utils}/slow-array.js +2 -2
  134. package/{rxjs → rxjs-utils}/start-with-provider.d.ts +1 -1
  135. package/{rxjs → rxjs-utils}/teardown.d.ts +1 -1
  136. package/{rxjs → rxjs-utils}/untrack.d.ts +1 -1
  137. package/schema/decorators/types.d.ts +2 -2
  138. package/schema/schemas/number.d.ts +1 -1
  139. package/signals/pipe.d.ts +1 -1
  140. package/signals/pipe.js +1 -2
  141. package/sse/server-sent-events.d.ts +54 -0
  142. package/sse/server-sent-events.js +54 -0
  143. package/types.d.ts +6 -2
  144. package/utils/comparison.d.ts +2 -1
  145. package/utils/comparison.js +4 -3
  146. package/utils/compression.d.ts +4 -4
  147. package/utils/compression.js +35 -43
  148. package/utils/object/dereference.d.ts +6 -4
  149. package/utils/object/dereference.js +20 -8
  150. package/utils/object/object.d.ts +2 -0
  151. package/utils/object/object.js +20 -0
  152. /package/{rxjs → rxjs-utils}/cast.d.ts +0 -0
  153. /package/{rxjs → rxjs-utils}/cast.js +0 -0
  154. /package/{rxjs → rxjs-utils}/index.d.ts +0 -0
  155. /package/{rxjs → rxjs-utils}/index.js +0 -0
  156. /package/{rxjs → rxjs-utils}/noop.d.ts +0 -0
  157. /package/{rxjs → rxjs-utils}/noop.js +0 -0
  158. /package/{rxjs → rxjs-utils}/reject-error.js +0 -0
  159. /package/{rxjs → rxjs-utils}/retry-backoff.js +0 -0
  160. /package/{rxjs → rxjs-utils}/start-with-provider.js +0 -0
  161. /package/{rxjs → rxjs-utils}/teardown.js +0 -0
  162. /package/{rxjs → rxjs-utils}/timing.d.ts +0 -0
  163. /package/{rxjs → rxjs-utils}/timing.js +0 -0
  164. /package/{rxjs → rxjs-utils}/untrack.js +0 -0
@@ -0,0 +1,376 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { getEntityMap } from '../../database/index.js';
8
+ import { Enumerable } from '../../enumerable/index.js';
9
+ import { BadRequestError } from '../../errors/index.js';
10
+ import { getMimeType, getMimeTypeExtensions } from '../../file/index.js';
11
+ import { Singleton, inject, injectArgument, provide } from '../../injector/index.js';
12
+ import { ObjectStorage } from '../../object-storage/index.js';
13
+ import { DATABASE_CONFIG, EntityRepositoryConfig, injectRepository } from '../../orm/index.js';
14
+ import { toArray } from '../../utils/array/index.js';
15
+ import { assertDefinedPass, compareByValueSelectionToOrder, currentTimestamp, digest, isBoolean, isDefined, isNotNull, isNull, isNumber, isString, isUint8Array, millisecondsPerMinute } from '../../utils/index.js';
16
+ import { groupToMap } from '../../utils/iterable-helpers/index.js';
17
+ import { readBinaryStream } from '../../utils/stream/index.js';
18
+ import { Document, DocumentCategory, DocumentCollection, DocumentCollectionDocument, DocumentFile, DocumentProperty, DocumentPropertyBooleanValue, DocumentPropertyDataType, DocumentPropertyDecimalValue, DocumentPropertyIntegerValue, DocumentPropertyTextValue, DocumentRequest, DocumentRequestCollection, DocumentRequestFile, DocumentRequestTemplate, DocumentRequestsTemplate, DocumentType, DocumentTypeProperty } from '../models/index.js';
19
+ import { DocumentManagementConfig } from '../module.js';
20
+ let DocumentManagementService = class DocumentManagementService {
21
+ documentService = injectRepository(Document);
22
+ documentFileService = injectRepository(DocumentFile);
23
+ documentCollectionService = injectRepository(DocumentCollection);
24
+ documentCategoryService = injectRepository(DocumentCategory);
25
+ documentTypeService = injectRepository(DocumentType);
26
+ documentRequestService = injectRepository(DocumentRequest);
27
+ documentRequestsTemplateService = injectRepository(DocumentRequestsTemplate);
28
+ documentRequestTemplateService = injectRepository(DocumentRequestTemplate);
29
+ documentRequestCollectionService = injectRepository(DocumentRequestCollection);
30
+ documentRequestFileService = injectRepository(DocumentRequestFile);
31
+ documentPropertyService = injectRepository(DocumentProperty);
32
+ documentTypePropertyService = injectRepository(DocumentTypeProperty);
33
+ documentPropertyTextValueService = injectRepository(DocumentPropertyTextValue);
34
+ documentPropertyIntegerValueService = injectRepository(DocumentPropertyIntegerValue);
35
+ documentPropertyDecimalValueService = injectRepository(DocumentPropertyDecimalValue);
36
+ documentPropertyBooleanValueService = injectRepository(DocumentPropertyBooleanValue);
37
+ documentCollectionDocumentService = injectRepository(DocumentCollectionDocument);
38
+ fileObjectStorage = inject(ObjectStorage, (injectArgument(this, { optional: true }) ?? inject(DocumentManagementConfig)).fileObjectStorageModule);
39
+ async loadData(collectionIds, collectionsMetadata) {
40
+ return this.documentCollectionService.transaction(async (_, transaction) => {
41
+ const [collections, collectionDocuments, requestCollections, categories, types] = await Promise.all([
42
+ this.documentCollectionService.withTransaction(transaction).loadMany(collectionIds),
43
+ this.documentCollectionDocumentService.withTransaction(transaction).loadManyByQuery({ collectionId: { $in: collectionIds } }),
44
+ this.documentRequestCollectionService.withTransaction(transaction).loadManyByQuery({ collectionId: { $in: collectionIds } }),
45
+ this.documentCategoryService.withTransaction(transaction).loadManyByQuery({}, { order: { label: 1 } }),
46
+ this.documentTypeService.withTransaction(transaction).loadManyByQuery({}, { order: { label: 1 } })
47
+ ]);
48
+ const documentIds = collectionDocuments.map((document) => document.documentId);
49
+ const requestIds = requestCollections.map((requestCollection) => requestCollection.requestId);
50
+ const [documents, requests, requestFiles, textValues, integerValues, decimalValues, booleanValues] = await Promise.all([
51
+ this.documentService.withTransaction(transaction).loadManyByQuery({ id: { $in: documentIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
52
+ this.documentRequestService.withTransaction(transaction).loadManyByQuery({ id: { $in: requestIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
53
+ this.documentRequestFileService.withTransaction(transaction).loadManyByQuery({ requestId: { $in: requestIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
54
+ this.documentPropertyTextValueService.withTransaction(transaction).loadManyByQuery({ documentId: { $in: documentIds } }),
55
+ this.documentPropertyIntegerValueService.withTransaction(transaction).loadManyByQuery({ documentId: { $in: documentIds } }),
56
+ this.documentPropertyDecimalValueService.withTransaction(transaction).loadManyByQuery({ documentId: { $in: documentIds } }),
57
+ this.documentPropertyBooleanValueService.withTransaction(transaction).loadManyByQuery({ documentId: { $in: documentIds } })
58
+ ]);
59
+ const documentFileIds = documents.map((document) => document.fileId);
60
+ const requestFileIds = requestFiles.map((requestFile) => requestFile.fileId);
61
+ const files = await this.documentFileService.withTransaction(transaction).loadManyByQuery({ id: { $in: [...documentFileIds, ...requestFileIds] } }, { order: { 'metadata.createTimestamp': 'desc' } });
62
+ const requestsFilesMap = groupToMap(requestFiles, (requestFile) => requestFile.requestId);
63
+ const valuesMap = Enumerable.from(textValues).concat(integerValues).concat(decimalValues).concat(booleanValues).groupToMap((value) => value.documentId);
64
+ const collectionViews = collections.toSorted(compareByValueSelectionToOrder(collectionIds, (collection) => collection.id)).map((collection) => ({
65
+ ...collection,
66
+ name: collectionsMetadata?.[collection.id]?.name ?? null,
67
+ group: collectionsMetadata?.[collection.id]?.group ?? null
68
+ }));
69
+ const documentViews = documents.map((document) => ({
70
+ ...document,
71
+ collectionAssignments: collectionDocuments.filter((collectionDocument) => collectionDocument.documentId == document.id).map(({ collectionId, archiveTimestamp }) => ({ collectionId, archiveTimestamp })),
72
+ properties: valuesMap.get(document.id) ?? []
73
+ }));
74
+ const requestViews = requests.map((request) => ({
75
+ ...request,
76
+ collectionIds: requestCollections.filter((requestCollection) => requestCollection.requestId == request.id).map((requestCollection) => requestCollection.collectionId),
77
+ requestFiles: requestsFilesMap.get(request.id) ?? []
78
+ }));
79
+ return {
80
+ collections: collectionViews,
81
+ documents: documentViews,
82
+ requests: requestViews,
83
+ files,
84
+ categories,
85
+ types
86
+ };
87
+ });
88
+ }
89
+ async loadDocumentRequestsTemplateData() {
90
+ const [requestsTemplates, requestTemplates] = await Promise.all([
91
+ this.documentRequestsTemplateService.loadManyByQuery({}, { order: { label: 'asc' } }),
92
+ this.documentRequestTemplateService.loadManyByQuery({})
93
+ ]);
94
+ const templates = requestsTemplates.map((requestsTemplate) => ({
95
+ ...requestsTemplate,
96
+ requestTemplates: requestTemplates.filter((requestTemplate) => requestTemplate.requestsTemplateId == requestsTemplate.id)
97
+ }));
98
+ return { templates };
99
+ }
100
+ async loadCategoriesAndTypes() {
101
+ const [categories, types] = await Promise.all([
102
+ this.documentCategoryService.loadManyByQuery({}, { order: { label: 1 } }),
103
+ this.documentTypeService.loadManyByQuery({}, { order: { label: 1 } })
104
+ ]);
105
+ return { categories, types };
106
+ }
107
+ async loadDocument(id) {
108
+ return this.documentService.load(id);
109
+ }
110
+ async loadDocumentFile(id) {
111
+ return this.documentFileService.load(id);
112
+ }
113
+ async loadType(id) {
114
+ return this.documentTypeService.load(id);
115
+ }
116
+ async getFileContentUrl(fileId, title, download = false) {
117
+ const file = await this.documentFileService.load(fileId);
118
+ return this.getDocumentFileContentObjectUrl(title ?? fileId, file, download);
119
+ }
120
+ async createCategory(parameters) {
121
+ return this.documentCategoryService.insert(parameters);
122
+ }
123
+ async createType(parameters) {
124
+ return this.documentTypeService.insert(parameters);
125
+ }
126
+ async createCollection(parameters) {
127
+ return this.documentCollectionService.insert(parameters ?? {});
128
+ }
129
+ async collectionHasDocumentByFilter(collectionId, filter) {
130
+ const collectionDocuments = await this.documentCollectionDocumentService.loadManyByQuery({ collectionId });
131
+ const documentIds = collectionDocuments.map((cd) => cd.documentId);
132
+ return this.documentService.hasByQuery({ $and: [{ id: { $in: documentIds } }, filter] });
133
+ }
134
+ async getRequestFilesStats(collectionIds) {
135
+ const collectionRequests = await this.documentRequestCollectionService.loadManyByQuery({ collectionId: { $in: toArray(collectionIds) } });
136
+ const requestIds = collectionRequests.map((collectionRequest) => collectionRequest.requestId);
137
+ const filteredRequests = await this.documentRequestService.loadManyByQuery({ id: { $in: requestIds }, completed: false });
138
+ const filteredRequestIds = filteredRequests.map((request) => request.id);
139
+ const requiredFilesCount = filteredRequests.reduce((sum, request) => sum + request.requiredFilesCount, 0);
140
+ const [pendingFilesCount, approvedFilesCount] = await Promise.all([
141
+ this.documentRequestFileService.countByQuery({ requestId: { $in: filteredRequestIds }, approval: null }),
142
+ this.documentRequestFileService.countByQuery({ requestId: { $in: filteredRequestIds }, approval: true })
143
+ ]);
144
+ return { requiredFilesCount, requiredFilesLeft: Math.max(0, requiredFilesCount - approvedFilesCount), pendingFilesCount, approvedFilesCount };
145
+ }
146
+ async createDocumentRequestsTemplate(parameters) {
147
+ return this.documentRequestsTemplateService.insert(parameters);
148
+ }
149
+ async updateDocumentRequestsTemplate({ id, label, metadata }) {
150
+ return this.documentRequestsTemplateService.update(id, { label, metadata });
151
+ }
152
+ async applyDocumentRequestsTemplate({ id, collectionIds, metadata }) {
153
+ const requestTemplates = await this.documentRequestTemplateService.loadManyByQuery({ requestsTemplateId: id });
154
+ await this.documentRequestService.transaction(async (_, transaction) => {
155
+ for (const { typeId, requiredFilesCount, comment } of requestTemplates) {
156
+ await this.createDocumentRequest({ typeId, requiredFilesCount, comment, collectionIds, metadata }, transaction);
157
+ }
158
+ });
159
+ }
160
+ async deleteDocumentRequestsTemplate(parameters) {
161
+ return this.documentRequestsTemplateService.delete(parameters.id);
162
+ }
163
+ async createDocumentRequestTemplate(parameters) {
164
+ return this.documentRequestTemplateService.insert(parameters);
165
+ }
166
+ async updateDocumentRequestTemplate({ id, typeId, requiredFilesCount, comment, metadata }) {
167
+ return this.documentRequestTemplateService.update(id, { typeId, requiredFilesCount, comment, metadata });
168
+ }
169
+ async deleteDocumentRequestTemplate(parameters) {
170
+ return this.documentRequestTemplateService.delete(parameters.id);
171
+ }
172
+ async createDocument({ typeId, addition, date, expiration, originalFileName, collectionIds, properties, metadata }, content) {
173
+ return this.documentService.transaction(async (_, transaction) => {
174
+ const documentFile = await this.createDocumentFile(content, originalFileName, transaction);
175
+ const document = await this.documentService.withTransaction(transaction).insert({ fileId: documentFile.id, typeId, addition, date, expiration, metadata });
176
+ if (isDefined(collectionIds)) {
177
+ for (const collectionId of toArray(collectionIds)) {
178
+ await this.documentCollectionDocumentService.withTransaction(transaction).insert({ collectionId, documentId: document.id, archiveTimestamp: null });
179
+ }
180
+ }
181
+ if (isDefined(properties)) {
182
+ const mappedProperties = properties.map((property) => ({ ...property, documentId: document.id }));
183
+ await this.setDocumentProperties(mappedProperties, transaction);
184
+ }
185
+ return document;
186
+ });
187
+ }
188
+ async approveDocumentRequestFile({ id, approvalComment, documentMetadata, requestFileMetadata }) {
189
+ return this.documentRequestFileService.transaction(async (_, transaction) => {
190
+ const requestFile = await this.documentRequestFileService.withTransaction(transaction).load(id);
191
+ const requestCollections = await this.documentRequestCollectionService.withTransaction(transaction).loadManyByQuery({ requestId: requestFile.requestId });
192
+ if (requestFile.approval == true) {
193
+ throw new BadRequestError('Document request file already accepted.');
194
+ }
195
+ const request = await this.documentRequestService.withTransaction(transaction).load(requestFile.requestId);
196
+ const document = await this.documentService.withTransaction(transaction).insert({
197
+ fileId: requestFile.fileId,
198
+ typeId: request.typeId,
199
+ addition: requestFile.addition,
200
+ date: null,
201
+ expiration: null,
202
+ metadata: documentMetadata
203
+ });
204
+ for (const { collectionId } of requestCollections) {
205
+ await this.addDocumentToCollection({ collectionId, documentId: document.id }, transaction);
206
+ }
207
+ await this.documentRequestFileService.withTransaction(transaction).update(id, { approval: true, approvalComment, approvalTimestamp: currentTimestamp(), createdDocumentId: document.id, metadata: requestFileMetadata });
208
+ return document;
209
+ });
210
+ }
211
+ async rejectDocumentRequestFile({ id, approvalComment, metadata }) {
212
+ return this.documentRequestFileService.transaction(async (_, transaction) => {
213
+ const requestFile = await this.documentRequestFileService.withTransaction(transaction).load(id);
214
+ if (requestFile.approval == true) {
215
+ throw new BadRequestError('Document request file already accepted.');
216
+ }
217
+ await this.documentRequestFileService.withTransaction(transaction).update(id, { approval: false, approvalComment, approvalTimestamp: currentTimestamp(), metadata });
218
+ });
219
+ }
220
+ async updateDocumentRequestFile({ id, addition, approvalComment, metadata }) {
221
+ return this.documentRequestFileService.update(id, { addition, approvalComment, metadata });
222
+ }
223
+ async deleteDocumentRequestFile({ id, metadata }) {
224
+ const requestFile = await this.documentRequestFileService.load(id);
225
+ if (isNotNull(requestFile.approval)) {
226
+ throw new BadRequestError('Only pending request files can be deleted.');
227
+ }
228
+ await this.documentRequestFileService.delete(id, metadata);
229
+ }
230
+ async createDocumentFile(content, originalFileName, dbTransaction) {
231
+ return this.documentFileService.useTransaction(dbTransaction, async (_, transaction) => {
232
+ const contentAsUint8Array = isUint8Array(content) ? content : await readBinaryStream(content);
233
+ const hash = await digest('SHA-256', contentAsUint8Array).toHex();
234
+ const mimeType = await getMimeType(contentAsUint8Array);
235
+ const documentFile = await this.documentFileService.withTransaction(transaction).insert({
236
+ originalFileName,
237
+ mimeType,
238
+ hash,
239
+ size: contentAsUint8Array.length
240
+ });
241
+ const key = getDocumentFileKey(documentFile.id);
242
+ await this.fileObjectStorage.uploadObject(key, contentAsUint8Array);
243
+ return documentFile;
244
+ });
245
+ }
246
+ async createDocumentRequestFile({ requestId, addition, originalFileName, metadata }, content) {
247
+ return this.documentRequestFileService.transaction(async (_, transaction) => {
248
+ const [request, existingRequestFiles] = await Promise.all([
249
+ this.documentRequestService.withTransaction(transaction).load(requestId),
250
+ this.documentRequestFileService.withTransaction(transaction).loadManyByQuery({ requestId })
251
+ ]);
252
+ const filesCountLeft = (request.completed ? 0 : request.requiredFilesCount) - existingRequestFiles.reduce((sum, requestFile) => sum + ((requestFile.approval != false) ? 1 : 0), 0);
253
+ if (filesCountLeft <= 0) {
254
+ throw new BadRequestError('Maximum amount of allowed files reached.');
255
+ }
256
+ const file = await this.createDocumentFile(content, originalFileName, transaction);
257
+ return this.documentRequestFileService.withTransaction(transaction).insert({ requestId, fileId: file.id, addition, createdDocumentId: null, approval: null, approvalComment: null, approvalTimestamp: null, metadata });
258
+ });
259
+ }
260
+ async createDocumentRequest(parameters, transaction) {
261
+ if (parameters.collectionIds.length == 0) {
262
+ throw new BadRequestError('No target collectionId specified.');
263
+ }
264
+ return this.documentRequestService.useTransaction(transaction, async (_, tx) => {
265
+ const request = await this.documentRequestService.withTransaction(tx).insert({ ...parameters, completed: false });
266
+ const newDocumentRequestCollections = parameters.collectionIds.map((collectionId) => ({ requestId: request.id, collectionId }));
267
+ await this.documentRequestCollectionService.withTransaction(tx).insertMany(newDocumentRequestCollections);
268
+ return request;
269
+ });
270
+ }
271
+ async updateDocument(parameters, transaction) {
272
+ const { id: documentId, properties: propertyUpdates, ...update } = parameters;
273
+ await this.documentService.useTransaction(transaction, async (repository, tx) => {
274
+ await repository.update(documentId, update);
275
+ if (isDefined(propertyUpdates)) {
276
+ const mappedPropertyUpdates = propertyUpdates.map((property) => ({ documentId, ...property }));
277
+ await this.setDocumentProperties(mappedPropertyUpdates, tx);
278
+ }
279
+ });
280
+ }
281
+ async updateDocumentRequest(parameters, transaction) {
282
+ const { id: documentRequestId, ...update } = parameters;
283
+ const requestFiles = await this.documentRequestFileService.withOptionalTransaction(transaction).loadManyByQuery({ requestId: parameters.id });
284
+ if (parameters.completed == true) {
285
+ const hasCreatedDocument = requestFiles.some((requestFile) => isNotNull(requestFile.createdDocumentId));
286
+ if (!hasCreatedDocument) {
287
+ throw new BadRequestError('Cannot complete requests which has no approved files.');
288
+ }
289
+ }
290
+ await this.documentRequestService.withOptionalTransaction(transaction).update(documentRequestId, update);
291
+ }
292
+ async deleteDocumentRequest({ id, metadata }, transaction) {
293
+ const requestFiles = await this.documentRequestFileService.loadManyByQuery({ requestId: id });
294
+ const hasCreatedDocument = requestFiles.some((requestFile) => isNotNull(requestFile.createdDocumentId));
295
+ if (hasCreatedDocument) {
296
+ throw new BadRequestError('Cannot delete requests which has approved files.');
297
+ }
298
+ await this.documentRequestService.withOptionalTransaction(transaction).delete(id, metadata);
299
+ }
300
+ async setDocumentProperties(setDocumentPropertyItems, transaction) {
301
+ if ((setDocumentPropertyItems.length == 0)) {
302
+ return;
303
+ }
304
+ await this.documentPropertyService.useTransaction(transaction, async (_, tx) => {
305
+ const propertyIds = setDocumentPropertyItems.map((property) => property.propertyId);
306
+ const properties = await this.documentPropertyService.withTransaction(tx).loadManyByQuery({ id: { $in: propertyIds } });
307
+ const propertiesMap = getEntityMap(properties);
308
+ for (const { documentId, propertyId, value, metadata } of setDocumentPropertyItems) {
309
+ const property = assertDefinedPass(propertiesMap.get(propertyId));
310
+ validatePropertyValue(propertyId, property.dataType, value);
311
+ const propertyValueService = this.getDocumentPropertyValueService(property.dataType);
312
+ await propertyValueService.withTransaction(tx).upsert(['documentId', 'propertyId'], { documentId, propertyId, value: value, metadata }, undefined);
313
+ }
314
+ });
315
+ }
316
+ async addDocumentToCollection(parameters, transaction) {
317
+ await this.documentCollectionDocumentService.withOptionalTransaction(transaction).upsert(['collectionId', 'documentId'], { ...parameters, archiveTimestamp: null });
318
+ }
319
+ async archiveDocument({ collectionId, documentId, metadata }) {
320
+ await this.documentCollectionDocumentService.updateByQuery({ collectionId, documentId }, { archiveTimestamp: currentTimestamp(), metadata });
321
+ }
322
+ async createProperty(parameters) {
323
+ return this.documentPropertyService.insert(parameters);
324
+ }
325
+ async assignPropertyToType(parameters) {
326
+ await this.documentTypePropertyService.insert(parameters);
327
+ }
328
+ getDocumentPropertyValueService(dataType) {
329
+ switch (dataType) {
330
+ case DocumentPropertyDataType.Text:
331
+ return this.documentPropertyTextValueService;
332
+ case DocumentPropertyDataType.Integer:
333
+ return this.documentPropertyIntegerValueService;
334
+ case DocumentPropertyDataType.Decimal:
335
+ return this.documentPropertyDecimalValueService;
336
+ case DocumentPropertyDataType.Boolean:
337
+ return this.documentPropertyBooleanValueService;
338
+ default:
339
+ throw new BadRequestError('Unknown property data type.');
340
+ }
341
+ }
342
+ async getDocumentFileContentObjectUrl(title, file, download) {
343
+ const key = getDocumentFileKey(file.id);
344
+ const fileExtension = getMimeTypeExtensions(file.mimeType)[0] ?? 'bin';
345
+ const disposition = download ? 'attachment' : 'inline';
346
+ const filename = `${title}.${fileExtension}`;
347
+ return this.fileObjectStorage.getDownloadUrl(key, currentTimestamp() + (5 * millisecondsPerMinute), {
348
+ 'Response-Content-Type': file.mimeType,
349
+ 'Response-Content-Disposition': `${disposition}; filename="${encodeURIComponent(filename)}"`
350
+ });
351
+ }
352
+ };
353
+ DocumentManagementService = __decorate([
354
+ Singleton({
355
+ providers: [
356
+ provide(EntityRepositoryConfig, { useValue: { schema: 'document_management' } }),
357
+ { provide: DATABASE_CONFIG, useFactory: (_, context) => context.resolve(DocumentManagementConfig).database }
358
+ ]
359
+ })
360
+ ], DocumentManagementService);
361
+ export { DocumentManagementService };
362
+ function getDocumentFileKey(id) {
363
+ return `${id.slice(0, 2)}/${id.slice(0, 4)}/${id}`;
364
+ }
365
+ const validators = {
366
+ [DocumentPropertyDataType.Text]: (value) => isString(value) || isNull(value),
367
+ [DocumentPropertyDataType.Integer]: (value) => isNumber(value) || isNull(value),
368
+ [DocumentPropertyDataType.Decimal]: (value) => isNumber(value) || isNull(value),
369
+ [DocumentPropertyDataType.Boolean]: (value) => isBoolean(value) || isNull(value)
370
+ };
371
+ function validatePropertyValue(propertyId, dataType, value) {
372
+ const valid = validators[dataType](value);
373
+ if (!valid) {
374
+ throw new BadRequestError(`Invalid value for data type ${DocumentPropertyDataType[dataType]} for property ${propertyId}.`);
375
+ }
376
+ }
@@ -0,0 +1 @@
1
+ export * from './document-management.service.js';
@@ -0,0 +1 @@
1
+ export * from './document-management.service.js';
@@ -0,0 +1 @@
1
+ import '../../polyfills.js';
@@ -0,0 +1,30 @@
1
+ import '../../polyfills.js';
2
+ import { Application } from '../../application/application.js';
3
+ import { configureDocumentManagement, migrateDocumentManagementSchema } from '../../document-management/module.js';
4
+ import { DocumentManagementService } from '../../document-management/services/document-management.service.js';
5
+ import { injectAsync } from '../../injector/inject.js';
6
+ import { configureS3ObjectStorage } from '../../object-storage/index.js';
7
+ async function bootstrap() {
8
+ configureDocumentManagement({
9
+ database: {
10
+ connection: {
11
+ database: 'xxx',
12
+ user: 'xxx',
13
+ password: 'xxx'
14
+ }
15
+ },
16
+ fileObjectStorageModule: 'documents'
17
+ });
18
+ configureS3ObjectStorage({ endpoint: 'http://localhost:10000', accessKey: 'tstdl-dev', secretKey: 'tstdl-dev', bucketPerModule: true });
19
+ await migrateDocumentManagementSchema();
20
+ }
21
+ async function main() {
22
+ const documentManagementService = await injectAsync(DocumentManagementService);
23
+ const collection = await documentManagementService.createCollection();
24
+ const category = await documentManagementService.createCategory({ label: 'Testkategorie' });
25
+ const type = await documentManagementService.createType({ categoryId: category.id, group: null, label: 'Testtyp' });
26
+ const request = await documentManagementService.createDocumentRequest({ typeId: type.id, requiredFilesCount: 1, comment: null, collectionIds: [collection.id] });
27
+ const data = await documentManagementService.loadData([collection.id]);
28
+ console.log(data);
29
+ }
30
+ Application.run({ bootstrap }, main);
@@ -1,5 +1,6 @@
1
+ import { resolve } from 'node:path';
1
2
  import { defineConfig } from 'drizzle-kit';
2
3
  export default defineConfig({
3
4
  dialect: 'postgresql',
4
- schema: './schemas.js'
5
+ schema: resolve(__dirname, './schemas.js')
5
6
  });
@@ -1,3 +1,3 @@
1
1
  import { User } from './user.model.js';
2
2
  export declare const mySchema: import("../../orm/database-schema.js").DatabaseSchema<"my_application">;
3
- export declare const user: import("../../orm/index.js").PgTableFromType<"my_application", typeof User>;
3
+ export declare const user: import("../../orm/drizzle/schema-converter.js").PgTableFromType<"my_application", typeof User>;
@@ -1,4 +1,4 @@
1
- import { Entity, Enum, Integer } from '../../orm/index.js';
1
+ import { Entity, Integer } from '../../orm/index.js';
2
2
  export declare enum Foo {
3
3
  Bar = 0,
4
4
  Baz = 1
@@ -10,5 +10,4 @@ export declare class User extends Entity {
10
10
  age: Integer | null;
11
11
  hasAge: boolean;
12
12
  mail: string;
13
- foo: Enum<typeof Foo>;
14
13
  }
@@ -21,7 +21,6 @@ export class User extends Entity {
21
21
  age;
22
22
  hasAge;
23
23
  mail;
24
- foo;
25
24
  }
26
25
  __decorate([
27
26
  StringProperty(),
@@ -11,6 +11,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
13
  import * as Http from 'node:http';
14
+ import { Writable } from 'node:stream';
15
+ import { bindNodeCallback, share } from 'rxjs';
14
16
  import { CancellationToken } from '../../../cancellation/index.js';
15
17
  import { disposeAsync } from '../../../disposable/index.js';
16
18
  import { HttpHeaders } from '../../../http/http-headers.js';
@@ -19,11 +21,9 @@ import { ResolveArg, Singleton } from '../../../injector/index.js';
19
21
  import { Logger } from '../../../logger/index.js';
20
22
  import { encodeUtf8 } from '../../../utils/encoding.js';
21
23
  import { FeedableAsyncIterable } from '../../../utils/feedable-async-iterable.js';
22
- import { getReadableStreamIterable } from '../../../utils/stream/readable-stream-adapter.js';
23
24
  import { Timer } from '../../../utils/timer.js';
24
25
  import { cancelableTimeout } from '../../../utils/timing.js';
25
26
  import { isDefined, isNullOrUndefined, isString } from '../../../utils/type-guards.js';
26
- import { bindNodeCallback, share } from 'rxjs';
27
27
  import { HttpServerRequest } from '../http-server-request.js';
28
28
  import { HttpServer } from '../http-server.js';
29
29
  let NodeHttpServer = class NodeHttpServer extends HttpServer {
@@ -167,12 +167,12 @@ async function writeResponseBody(response, httpResponse) {
167
167
  if (!httpResponse.hasHeader('Content-Length')) {
168
168
  httpResponse.setHeader('Content-Length', bytes.byteLength);
169
169
  }
170
+ null.getWriter().closed;
170
171
  await write(httpResponse, bytes);
171
172
  }
172
173
  else if (isDefined(streamData)) {
173
- for await (const chunk of getReadableStreamIterable(streamData)) {
174
- await write(httpResponse, chunk);
175
- }
174
+ const responseStream = Writable.toWeb(httpResponse);
175
+ await streamData.pipeTo(responseStream);
176
176
  }
177
177
  return new Promise((resolve) => {
178
178
  httpResponse.end(resolve);
@@ -49,7 +49,7 @@ export declare class Injector implements AsyncDisposable {
49
49
  * @param provider provider used to resolve the token
50
50
  * @param options registration options
51
51
  */
52
- static registerSingleton<T, A = any, C extends Record = Record>(token: InjectionToken<T, A>, providers: OneOrMany<Provider<T, A, C>>, options?: TypedOmit<RegistrationOptions<T, A, C>, 'lifecycle'>): void;
52
+ static registerSingleton<T, A = ResolveArgument<T, any>, C extends Record = Record>(token: InjectionToken<T, A>, providers: OneOrMany<Provider<T, A, C>>, options?: TypedOmit<RegistrationOptions<T, A, C>, 'lifecycle'>): void;
53
53
  dispose(): Promise<void>;
54
54
  [Symbol.asyncDispose](): Promise<void>;
55
55
  fork(name: string): Injector;
@@ -108,3 +108,6 @@ export declare class Injector implements AsyncDisposable {
108
108
  private getInjectionContext;
109
109
  private assertNotDisposed;
110
110
  }
111
+ export declare function provide<T = any, A = any, D extends Record = Record>(token: InjectionToken<T, A>, provider: Provider<T, A, D> & {
112
+ multi?: boolean;
113
+ }): ProvidersItem<T, A, D>;
@@ -260,7 +260,7 @@ export class Injector {
260
260
  const { token, providers } = registration;
261
261
  const injector = (providers.length > 0) ? this.fork('LocalProvidersInjector') : this;
262
262
  for (const nestedProvider of providers) {
263
- injector.register(nestedProvider.provide, nestedProvider, { multi: nestedProvider.multi });
263
+ injector.registerSingleton(nestedProvider.provide, nestedProvider, { multi: nestedProvider.multi });
264
264
  }
265
265
  const injectionContext = injector.getInjectionContext(context, argument, chain);
266
266
  const previousInjectionContext = setCurrentInjectionContext(injectionContext);
@@ -442,6 +442,9 @@ export class Injector {
442
442
  }
443
443
  }
444
444
  }
445
+ export function provide(token, provider) {
446
+ return { provide: token, ...provider };
447
+ }
445
448
  function addRegistration(registrations, registration) {
446
449
  if (isClassProvider(registration.provider)) {
447
450
  const injectable = reflectionRegistry.getMetadata(registration.provider.useClass)?.data.has(injectableMetadataSymbol) ?? false;
@@ -4,13 +4,13 @@ import type { AfterResolveContext } from './types.js';
4
4
  export declare const resolveArgumentType: unique symbol;
5
5
  export declare const afterResolve: unique symbol;
6
6
  export type ResolveArgumentType = typeof resolveArgumentType;
7
- export type ResolveArgument<T, Fallback = undefined> = undefined | (T extends Resolvable<infer U> ? U : T extends Type<Resolvable<infer U>> ? U : T extends (ArgumentedInjectionToken<any, any> | ReifyingInjectionToken) ? InjectionTokenArgument<T> : Fallback);
7
+ export type ResolveArgument<T, Fallback = undefined> = undefined | (T extends Resolvable<infer U> ? (U | undefined) : T extends Type<Resolvable<infer U>> ? (U | undefined) : T extends (ArgumentedInjectionToken<any, any> | ReifyingInjectionToken) ? InjectionTokenArgument<T> : Fallback);
8
8
  export interface Resolvable<A = unknown, D extends Record = Record> extends Partial<AfterResolve<A, D>> {
9
9
  /**
10
- * type of resolve argument
10
+ * Type of resolve argument
11
11
  * @deprecated only used for type inference
12
12
  */
13
- readonly [resolveArgumentType]: A;
13
+ readonly [resolveArgumentType]?: A;
14
14
  }
15
15
  export interface AfterResolve<A = unknown, D extends Record = Record> {
16
16
  [afterResolve](argument: A, context: AfterResolveContext<D>): void | Promise<void>;
@@ -14,12 +14,14 @@ export declare class JsonPath<T = any> implements Iterable<JsonPathNode> {
14
14
  static from(options?: JsonPathOptions): JsonPath;
15
15
  static from(path: JsonPathInput, options?: JsonPathOptions): JsonPath;
16
16
  static isJsonPath(path: string): boolean;
17
+ toString(): string;
17
18
  /**
18
19
  * Add a property or index to current path
19
20
  * @param key
20
21
  * @returns new JsonPath instance
21
22
  */
22
23
  add<K extends keyof T>(key: K): JsonPath<T[K]>;
24
+ slice(start: number, end?: number): JsonPath;
23
25
  /**
24
26
  * Updates options
25
27
  * @param options
@@ -40,6 +40,7 @@ export class JsonPath {
40
40
  }
41
41
  else {
42
42
  this._options = pathOrNodesOrOptions;
43
+ this._nodes = [];
43
44
  }
44
45
  }
45
46
  static from(pathOrNodesOrOptions = [], options = {}) {
@@ -48,6 +49,9 @@ export class JsonPath {
48
49
  static isJsonPath(path) {
49
50
  return isJsonPath(path);
50
51
  }
52
+ toString() {
53
+ return this.path;
54
+ }
51
55
  /**
52
56
  * Add a property or index to current path
53
57
  * @param key
@@ -56,6 +60,9 @@ export class JsonPath {
56
60
  add(key) {
57
61
  return new JsonPath([...this.nodes, key], this._options);
58
62
  }
63
+ slice(start, end) {
64
+ return new JsonPath(this.nodes.slice(start, end), this._options);
65
+ }
59
66
  /**
60
67
  * Updates options
61
68
  * @param options
@@ -1,14 +1,12 @@
1
1
  import type { Observable } from 'rxjs';
2
- import type { Resolvable } from '../injector/interfaces.js';
3
- import { resolveArgumentType } from '../injector/interfaces.js';
4
- import type { AsyncDisposable } from '../disposable/disposable.js';
5
- import { disposeAsync } from '../disposable/disposable.js';
2
+ import { type Resolvable, resolveArgumentType } from '../injector/interfaces.js';
3
+ import { type AsyncDisposable, disposeAsync } from '../disposable/disposable.js';
6
4
  export type MessageBusArgument = string;
7
5
  export declare abstract class MessageBus<T> implements AsyncDisposable, Resolvable<MessageBusArgument> {
8
6
  readonly [resolveArgumentType]: string;
9
- /** messages from other instances */
7
+ /** Messages from other instances */
10
8
  abstract readonly messages$: Observable<T>;
11
- /** messages from other instances and itself */
9
+ /** Messages from other instances and itself */
12
10
  abstract readonly allMessages$: Observable<T>;
13
11
  dispose(): Promise<void>;
14
12
  abstract publish(message: T): Promise<void>;
@@ -1,8 +1,11 @@
1
+ import type { PgEnum } from 'drizzle-orm/pg-core';
2
+ import type { Enumeration, EnumerationValue, UnionToTuple } from '../types.js';
1
3
  import { type PgTableFromType } from './drizzle/schema-converter.js';
2
4
  import type { EntityType } from './entity.js';
3
5
  export declare class DatabaseSchema<Name extends string> {
4
6
  readonly name: Name;
5
7
  constructor(name: Name);
6
8
  getTable<T extends EntityType>(type: T): PgTableFromType<Name, T>;
9
+ getEnum<T extends Enumeration>(enumeration: T, name: string): PgEnum<UnionToTuple<`${EnumerationValue<T>}`> extends [string, ...string[]] ? UnionToTuple<`${EnumerationValue<T>}`> : never>;
7
10
  }
8
11
  export declare function databaseSchema<Name extends string>(name: Name): DatabaseSchema<Name>;
@@ -1,11 +1,15 @@
1
- import { getDrizzleTableFromType } from './drizzle/schema-converter.js';
1
+ import { getDrizzleTableFromType, getPgEnum, registerEnum } from './drizzle/schema-converter.js';
2
2
  export class DatabaseSchema {
3
3
  name;
4
4
  constructor(name) {
5
5
  this.name = name;
6
6
  }
7
7
  getTable(type) {
8
- return getDrizzleTableFromType(this.name, type);
8
+ return getDrizzleTableFromType(type, this.name);
9
+ }
10
+ getEnum(enumeration, name) {
11
+ registerEnum(enumeration, name);
12
+ return getPgEnum(this.name, enumeration); // eslint-disable-line @typescript-eslint/no-unsafe-return
9
13
  }
10
14
  }
11
15
  export function databaseSchema(name) {