@tstdl/base 0.92.123 → 0.92.125

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 (221) hide show
  1. package/ai/ai-file.service.js +23 -18
  2. package/ai/ai.service.d.ts +4 -12
  3. package/ai/ai.service.js +79 -147
  4. package/ai/functions.d.ts +1 -1
  5. package/ai/types.d.ts +3 -1
  6. package/api/server/gateway.js +6 -6
  7. package/authentication/authentication.api.js +24 -24
  8. package/authentication/server/authentication.service.js +20 -20
  9. package/browser/page-controller.js +1 -1
  10. package/context/context.js +5 -5
  11. package/document-management/api/document-management.api.d.ts +60 -215
  12. package/document-management/api/document-management.api.js +32 -68
  13. package/document-management/models/document-assignment-scope.model.d.ts +11 -0
  14. package/document-management/models/{document-request-assignment-task-collection.model.js → document-assignment-scope.model.js} +14 -10
  15. package/document-management/models/document-assignment-task.model.d.ts +13 -0
  16. package/document-management/models/document-assignment-task.model.js +38 -0
  17. package/document-management/models/document-category.model.d.ts +2 -0
  18. package/document-management/models/document-category.model.js +7 -1
  19. package/document-management/models/{document-collection-document.model.d.ts → document-collection-assignment.model.d.ts} +1 -1
  20. package/document-management/models/{document-collection-document.model.js → document-collection-assignment.model.js} +7 -7
  21. package/document-management/models/document-collection.model.d.ts +2 -0
  22. package/document-management/models/document-collection.model.js +10 -0
  23. package/document-management/models/document-property-value.model.d.ts +3 -11
  24. package/document-management/models/document-property-value.model.js +15 -46
  25. package/document-management/models/document-property.model.d.ts +2 -1
  26. package/document-management/models/document-property.model.js +2 -2
  27. package/document-management/models/document-request-submission.model.d.ts +7 -0
  28. package/document-management/models/document-request-submission.model.js +34 -0
  29. package/document-management/models/document-request-template.d.ts +2 -4
  30. package/document-management/models/document-request-template.js +3 -8
  31. package/document-management/models/document-request.model.d.ts +14 -6
  32. package/document-management/models/document-request.model.js +22 -12
  33. package/document-management/models/document-type-validation.model.d.ts +6 -0
  34. package/document-management/models/document-type-validation.model.js +34 -0
  35. package/document-management/models/document-type.model.d.ts +0 -1
  36. package/document-management/models/document-type.model.js +0 -5
  37. package/document-management/models/document-validation-definition.model.d.ts +10 -0
  38. package/document-management/models/document-validation-definition.model.js +39 -0
  39. package/document-management/models/document-validation-execution-related-document.model.d.ts +7 -0
  40. package/document-management/models/document-validation-execution-related-document.model.js +34 -0
  41. package/document-management/models/document-validation-execution.model.d.ts +26 -0
  42. package/document-management/models/document-validation-execution.model.js +72 -0
  43. package/document-management/models/document-workflow.model.d.ts +35 -0
  44. package/document-management/models/document-workflow.model.js +70 -0
  45. package/document-management/models/document.model.d.ts +12 -1
  46. package/document-management/models/document.model.js +21 -5
  47. package/document-management/models/index.d.ts +10 -5
  48. package/document-management/models/index.js +10 -5
  49. package/document-management/models/service-models/categories-and-types.view-model.d.ts +3 -3
  50. package/document-management/models/service-models/categories-and-types.view-model.js +2 -21
  51. package/document-management/models/service-models/document-folders.view-model.d.ts +7 -14
  52. package/document-management/models/service-models/document-folders.view-model.js +20 -44
  53. package/document-management/models/service-models/document-management.view-model.d.ts +41 -0
  54. package/document-management/models/service-models/{document.view-model.js → document-management.view-model.js} +43 -26
  55. package/document-management/models/service-models/document.service-model.d.ts +51 -81
  56. package/document-management/models/service-models/document.service-model.js +30 -28
  57. package/document-management/models/service-models/enriched/enriched-document-assignment.view.d.ts +11 -0
  58. package/document-management/models/service-models/enriched/enriched-document-assignment.view.js +12 -0
  59. package/document-management/models/service-models/enriched/enriched-document-category.view.d.ts +13 -0
  60. package/document-management/models/service-models/enriched/enriched-document-category.view.js +47 -0
  61. package/document-management/models/service-models/enriched/enriched-document-collection.view.d.ts +22 -0
  62. package/document-management/models/service-models/enriched/enriched-document-collection.view.js +89 -0
  63. package/document-management/models/service-models/enriched/enriched-document-file.view.d.ts +12 -0
  64. package/document-management/models/service-models/enriched/enriched-document-file.view.js +16 -0
  65. package/document-management/models/service-models/enriched/enriched-document-management-data.view.d.ts +41 -0
  66. package/document-management/models/service-models/enriched/enriched-document-management-data.view.js +130 -0
  67. package/document-management/models/service-models/enriched/enriched-document-request.view.d.ts +17 -0
  68. package/document-management/models/service-models/enriched/enriched-document-request.view.js +52 -0
  69. package/document-management/models/service-models/enriched/enriched-document-type.view.d.ts +9 -0
  70. package/document-management/models/service-models/enriched/enriched-document-type.view.js +10 -0
  71. package/document-management/models/service-models/enriched/enriched-document.view.d.ts +28 -0
  72. package/document-management/models/service-models/enriched/enriched-document.view.js +77 -0
  73. package/document-management/models/service-models/enriched/enriched.d.ts +18 -0
  74. package/document-management/models/service-models/enriched/enriched.js +39 -0
  75. package/document-management/models/service-models/enriched/index.d.ts +9 -0
  76. package/document-management/models/service-models/enriched/index.js +9 -0
  77. package/document-management/models/service-models/index.d.ts +2 -2
  78. package/document-management/models/service-models/index.js +2 -2
  79. package/document-management/models/service-models/normalized-requests-template-data.model.d.ts +12 -10
  80. package/document-management/models/service-models/normalized-requests-template-data.model.js +5 -4
  81. package/document-management/models/service-models/stats.view-model.d.ts +7 -5
  82. package/document-management/models/service-models/stats.view-model.js +19 -9
  83. package/document-management/server/module.d.ts +2 -2
  84. package/document-management/server/module.js +3 -7
  85. package/document-management/server/schemas.d.ts +18 -23
  86. package/document-management/server/schemas.js +18 -23
  87. package/document-management/server/services/document-category-type.service.d.ts +25 -0
  88. package/document-management/server/services/document-category-type.service.js +66 -0
  89. package/document-management/server/services/document-collection.service.d.ts +13 -0
  90. package/document-management/server/services/document-collection.service.js +41 -0
  91. package/document-management/server/services/document-file.service.d.ts +17 -0
  92. package/document-management/server/services/document-file.service.js +204 -0
  93. package/document-management/server/services/document-management-ai.service.d.ts +22 -0
  94. package/document-management/server/services/document-management-ai.service.js +340 -0
  95. package/document-management/server/services/document-management-ancillary.service.d.ts +127 -3
  96. package/document-management/server/services/document-management-ancillary.service.js +24 -0
  97. package/document-management/server/services/document-management.service.d.ts +10 -122
  98. package/document-management/server/services/document-management.service.js +106 -888
  99. package/document-management/server/services/document-property.service.d.ts +84 -0
  100. package/document-management/server/services/document-property.service.js +87 -0
  101. package/document-management/server/services/document-request.service.d.ts +30 -0
  102. package/document-management/server/services/document-request.service.js +138 -0
  103. package/document-management/server/services/document-validation.service.d.ts +20 -0
  104. package/document-management/server/services/document-validation.service.js +145 -0
  105. package/document-management/server/services/document-workflow.service.d.ts +20 -0
  106. package/document-management/server/services/document-workflow.service.js +132 -0
  107. package/document-management/server/services/document.service.d.ts +16 -0
  108. package/document-management/server/services/document.service.js +81 -0
  109. package/document-management/server/services/index.d.ts +9 -0
  110. package/document-management/server/services/index.js +9 -0
  111. package/document-management/server/validators/ai-validation-executor.d.ts +19 -0
  112. package/document-management/server/validators/ai-validation-executor.js +51 -0
  113. package/document-management/server/validators/index.d.ts +2 -0
  114. package/document-management/server/validators/index.js +2 -0
  115. package/document-management/server/validators/single-document-validation-executor.d.ts +16 -0
  116. package/document-management/server/validators/single-document-validation-executor.js +20 -0
  117. package/document-management/server/validators/validator.d.ts +21 -0
  118. package/document-management/server/validators/validator.js +2 -0
  119. package/eslint.config.js +31 -17
  120. package/examples/document-management/main.d.ts +18 -3
  121. package/examples/document-management/main.js +28 -12
  122. package/file/mime-type.js +2 -9
  123. package/formats.d.ts +5 -2
  124. package/formats.js +32 -23
  125. package/http/client/http-client.js +1 -1
  126. package/injector/injector.js +2 -2
  127. package/object-storage/s3/s3.object-storage.js +1 -1
  128. package/orm/data-types/bytea.d.ts +8 -0
  129. package/orm/data-types/bytea.js +8 -0
  130. package/orm/data-types/index.d.ts +4 -0
  131. package/orm/data-types/index.js +4 -0
  132. package/orm/data-types/numeric-date.d.ts +9 -0
  133. package/orm/data-types/numeric-date.js +9 -0
  134. package/orm/data-types/timestamp.d.ts +9 -0
  135. package/orm/data-types/timestamp.js +9 -0
  136. package/orm/decorators.d.ts +139 -5
  137. package/orm/decorators.js +50 -0
  138. package/orm/entity.d.ts +19 -0
  139. package/orm/entity.js +19 -0
  140. package/orm/index.d.ts +5 -0
  141. package/orm/index.js +5 -0
  142. package/orm/query.d.ts +51 -0
  143. package/orm/query.js +6 -0
  144. package/orm/repository.types.d.ts +54 -2
  145. package/orm/server/database-schema.d.ts +34 -0
  146. package/orm/server/database-schema.js +29 -0
  147. package/orm/server/database.d.ts +19 -1
  148. package/orm/server/database.js +17 -3
  149. package/orm/server/drizzle/schema-converter.d.ts +2 -1
  150. package/orm/server/drizzle/schema-converter.js +12 -1
  151. package/orm/server/encryption.d.ts +16 -0
  152. package/orm/server/encryption.js +29 -4
  153. package/orm/server/index.d.ts +7 -0
  154. package/orm/server/index.js +7 -0
  155. package/orm/server/module.d.ts +20 -0
  156. package/orm/server/module.js +9 -0
  157. package/orm/server/query-converter.d.ts +17 -0
  158. package/orm/server/query-converter.js +66 -11
  159. package/orm/server/repository.d.ts +324 -18
  160. package/orm/server/repository.js +344 -73
  161. package/orm/server/transaction.d.ts +5 -5
  162. package/orm/server/transaction.js +5 -5
  163. package/orm/server/transactional.d.ts +75 -0
  164. package/orm/server/transactional.js +134 -0
  165. package/orm/server/types.d.ts +1 -0
  166. package/orm/sqls.d.ts +55 -0
  167. package/orm/sqls.js +60 -0
  168. package/orm/types.d.ts +67 -4
  169. package/orm/utils.d.ts +19 -3
  170. package/orm/utils.js +12 -0
  171. package/package.json +32 -31
  172. package/password/password-check-result.model.d.ts +9 -7
  173. package/password/password-check-result.model.js +8 -8
  174. package/password/password-check.js +5 -7
  175. package/password/password-check.localization.js +12 -12
  176. package/pdf/pdf.service.js +1 -1
  177. package/pdf/utils.d.ts +9 -0
  178. package/pdf/utils.js +19 -2
  179. package/process/spawn.d.ts +11 -4
  180. package/process/spawn.js +42 -5
  181. package/queue/postgres/queue.js +5 -5
  182. package/queue/queue.d.ts +6 -4
  183. package/queue/queue.js +6 -6
  184. package/schema/schemas/one-or-many.d.ts +2 -1
  185. package/schema/schemas/one-or-many.js +1 -1
  186. package/search-index/elastic/model/index-mapping.d.ts +1 -1
  187. package/search-index/elastic/model/index-mapping.js +0 -1
  188. package/search-index/elastic/search-index.d.ts +1 -2
  189. package/search-index/elastic/search-index.js +3 -3
  190. package/types.d.ts +1 -0
  191. package/utils/async-hook/async-hook.d.ts +9 -0
  192. package/utils/async-hook/async-hook.js +21 -0
  193. package/utils/async-hook/index.d.ts +1 -0
  194. package/utils/async-hook/index.js +1 -0
  195. package/utils/compression.js +1 -1
  196. package/utils/function/class.d.ts +6 -0
  197. package/utils/function/class.js +9 -0
  198. package/utils/function/index.d.ts +1 -0
  199. package/utils/function/index.js +1 -0
  200. package/utils/function/memoize.d.ts +18 -0
  201. package/utils/function/memoize.js +41 -2
  202. package/utils/jwt.d.ts +1 -1
  203. package/utils/jwt.js +5 -5
  204. package/utils/object/forward-ref.d.ts +3 -2
  205. package/utils/object/forward-ref.js +12 -12
  206. package/utils/object/lazy-property.js +2 -2
  207. package/utils/proxy.js +1 -1
  208. package/utils/stream/{readable-stream-from-promise.d.ts → from-promise.d.ts} +1 -0
  209. package/utils/stream/from-promise.js +27 -0
  210. package/utils/stream/index.d.ts +1 -1
  211. package/utils/stream/index.js +1 -1
  212. package/utils/stream/stream-reader.js +71 -31
  213. package/document-management/models/document-request-assignment-task-collection.model.d.ts +0 -7
  214. package/document-management/models/document-request-assignment-task.model.d.ts +0 -14
  215. package/document-management/models/document-request-assignment-task.model.js +0 -77
  216. package/document-management/models/document-request-file.model.d.ts +0 -16
  217. package/document-management/models/document-request-file.model.js +0 -86
  218. package/document-management/models/service-models/document.view-model.d.ts +0 -41
  219. package/document-management/models/service-models/normalized-document-collection-view.model.d.ts +0 -73
  220. package/document-management/models/service-models/normalized-document-collection-view.model.js +0 -110
  221. package/utils/stream/readable-stream-from-promise.js +0 -8
@@ -0,0 +1,132 @@
1
+ var _a;
2
+ import { match } from 'ts-pattern';
3
+ import { DocumentAssignmentScope } from '../../../document-management/models/document-assignment-scope.model.js';
4
+ import { DocumentAssignmentTask } from '../../../document-management/models/document-assignment-task.model.js';
5
+ import { DocumentWorkflow, DocumentWorkflowFailReason, DocumentWorkflowState, DocumentWorkflowStep } from '../../../document-management/models/document-workflow.model.js';
6
+ import { DocumentApproval } from '../../../document-management/models/document.model.js';
7
+ import { BadRequestError } from '../../../errors/bad-request.error.js';
8
+ import { NotImplementedError } from '../../../errors/not-implemented.error.js';
9
+ import { inject } from '../../../injector/inject.js';
10
+ import { afterResolve } from '../../../injector/interfaces.js';
11
+ import { Logger } from '../../../logger/index.js';
12
+ import { injectRepository } from '../../../orm/server/repository.js';
13
+ import { Transactional } from '../../../orm/server/transactional.js';
14
+ import { Queue } from '../../../queue/queue.js';
15
+ import { _throw } from '../../../utils/throw.js';
16
+ import { isNotNull, isNull } from '../../../utils/type-guards.js';
17
+ import { DocumentCollectionService } from './document-collection.service.js';
18
+ import { DocumentManagementAiService } from './document-management-ai.service.js';
19
+ import { DocumentRequestService } from './document-request.service.js';
20
+ import { DocumentService } from './document.service.js';
21
+ export class DocumentWorkflowService extends Transactional {
22
+ #documentManagementAiService = inject(DocumentManagementAiService);
23
+ #documentService = inject(DocumentService);
24
+ #documentCollectionService = inject(DocumentCollectionService);
25
+ #documentRequestService = inject(DocumentRequestService);
26
+ #documentAssignmentTaskRepository = injectRepository(DocumentAssignmentTask);
27
+ #documentAssignmentScopeRepository = injectRepository(DocumentAssignmentScope);
28
+ #queue = inject((Queue), { name: 'DocumentWorkflow', processTimeout: 5 * 60 * 1000, maxTries: 3 });
29
+ #logger = inject(Logger, _a.name);
30
+ repository = injectRepository(DocumentWorkflow).withSession(this.session);
31
+ [afterResolve](_, { cancellationSignal }) {
32
+ if (this.isInTransaction) {
33
+ return;
34
+ }
35
+ this.#queue.process({ concurrency: 5, cancellationSignal }, async (job) => this.processWorkflowJob(job), this.#logger);
36
+ }
37
+ async loadLatestWorkflow(documentId) {
38
+ return this.repository.loadByQuery({ documentId }, { order: { 'metadata.createTimestamp': 'desc' } });
39
+ }
40
+ async tryLoadLatestWorkflow(documentId) {
41
+ return this.repository.tryLoadByQuery({ documentId }, { order: { 'metadata.createTimestamp': 'desc' } });
42
+ }
43
+ async loadLatestWorkflows(documentIds) {
44
+ return this.repository.loadManyByQuery({ documentId: { $in: documentIds } }, { distinct: ['documentId'], order: { 'metadata.createTimestamp': 'desc' } });
45
+ }
46
+ async proceedWorkflow(documentId, userId) {
47
+ return this.transaction(async (tx) => {
48
+ const workflow = await this.withTransaction(tx).loadLatestWorkflow(documentId);
49
+ if (workflow.state != DocumentWorkflowState.Completed) {
50
+ throw new BadRequestError('Current workflow is not completed');
51
+ }
52
+ if (isNotNull(workflow.completeUserId)) {
53
+ throw new BadRequestError('Latest workflow is already completed');
54
+ }
55
+ await this.repository.withTransaction(tx).update(workflow.id, { completeUserId: userId });
56
+ await match(workflow.step)
57
+ .with(DocumentWorkflowStep.Classification, () => _throw(new BadRequestError('Proceeding from classification occurs automatically.')))
58
+ .with(DocumentWorkflowStep.Extraction, async () => this.withTransaction(tx).initiateWorkflow(documentId, DocumentWorkflowStep.Assignment))
59
+ .with(DocumentWorkflowStep.Assignment, async () => this.withTransaction(tx).initiateWorkflow(documentId, DocumentWorkflowStep.Validation))
60
+ .with(DocumentWorkflowStep.Validation, () => { })
61
+ .exhaustive();
62
+ });
63
+ }
64
+ async initiateWorkflow(documentId, step) {
65
+ const workflow = await this.repository.insert({ documentId, step, state: 'pending', failReason: null, completeUserId: null });
66
+ await this.#queue.enqueue({ workflowId: workflow.id });
67
+ return workflow;
68
+ }
69
+ async setWorkflowState(id, state, failReason = null) {
70
+ await this.repository.update(id, { state, failReason });
71
+ }
72
+ async processWorkflowJob(job) {
73
+ this.#logger.verbose(`Processing workflow job for workflow "${job.data.workflowId}"`);
74
+ const workflow = await this.repository.load(job.data.workflowId);
75
+ try {
76
+ await this.setWorkflowState(workflow.id, DocumentWorkflowState.Running);
77
+ await match(workflow.step)
78
+ .with(DocumentWorkflowStep.Classification, async () => this.processClassificationWorkflow(workflow))
79
+ .with(DocumentWorkflowStep.Extraction, async () => this.processExtractionWorkflow(workflow))
80
+ .with(DocumentWorkflowStep.Assignment, async () => this.processAssignmentWorkflow(workflow))
81
+ .with(DocumentWorkflowStep.Validation, async () => this.processValidationWorkflow(workflow))
82
+ .exhaustive();
83
+ await this.setWorkflowState(workflow.id, DocumentWorkflowState.Completed);
84
+ if (workflow.step == DocumentWorkflowStep.Classification) {
85
+ // automatically start extraction after classification
86
+ await this.initiateWorkflow(workflow.documentId, DocumentWorkflowStep.Extraction);
87
+ }
88
+ }
89
+ catch (error) {
90
+ this.#logger.error(error);
91
+ const isLastTry = job.tries == this.#queue.maxTries;
92
+ if (isLastTry) {
93
+ await this.repository.update(workflow.id, { state: DocumentWorkflowState.Error });
94
+ }
95
+ }
96
+ }
97
+ async processClassificationWorkflow(workflow) {
98
+ const typeId = await this.#documentManagementAiService.classifyDocumentType(workflow.documentId);
99
+ await this.#documentService.repository.update(workflow.documentId, { typeId, approval: DocumentApproval.Pending });
100
+ }
101
+ async processExtractionWorkflow(workflow) {
102
+ const extraction = await this.#documentManagementAiService.extractDocumentInformation(workflow.documentId);
103
+ await this.#documentService.updateDocument(workflow.documentId, extraction);
104
+ }
105
+ async processAssignmentWorkflow(workflow) {
106
+ const assignmentTask = await this.#documentAssignmentTaskRepository.loadByQuery({ documentId: workflow.documentId });
107
+ const assignmentScopes = await this.#documentAssignmentScopeRepository.loadManyByQuery({ taskId: assignmentTask.id });
108
+ const collectionIds = assignmentScopes.map((scope) => scope.collectionId);
109
+ await match(assignmentTask.target)
110
+ .with('collection', async () => {
111
+ const suitableCollectionIds = await this.#documentManagementAiService.findSuitableCollectionsForDocument(workflow.documentId, collectionIds);
112
+ if (suitableCollectionIds.length == 0) {
113
+ await this.setWorkflowState(workflow.id, DocumentWorkflowState.Failed, DocumentWorkflowFailReason.NoSuitableCollection);
114
+ return;
115
+ }
116
+ await this.#documentCollectionService.assignDocument(workflow.documentId, suitableCollectionIds);
117
+ })
118
+ .with('request', async () => {
119
+ const suitableRequestId = await this.#documentManagementAiService.findSuitableRequestForDocument(workflow.documentId, collectionIds);
120
+ if (isNull(suitableRequestId)) {
121
+ await this.setWorkflowState(workflow.id, DocumentWorkflowState.Failed, DocumentWorkflowFailReason.NoSuitableRequest);
122
+ return;
123
+ }
124
+ await this.#documentRequestService.assignDocument(suitableRequestId, workflow.documentId);
125
+ })
126
+ .exhaustive();
127
+ }
128
+ async processValidationWorkflow(_workflow) {
129
+ throw new NotImplementedError();
130
+ }
131
+ }
132
+ _a = DocumentWorkflowService;
@@ -0,0 +1,16 @@
1
+ import { type UpdatableDocumentProperties } from '../../../document-management/models/index.js';
2
+ import type { CreateDocumentParameters, SetDocumentPropertyParameters } from '../../../document-management/models/service-models/index.js';
3
+ import { Transactional } from '../../../orm/server/index.js';
4
+ import { Document } from '../../models/index.js';
5
+ export declare class DocumentService extends Transactional {
6
+ #private;
7
+ readonly repository: import("../../../orm/server/repository.js").EntityRepository<Document>;
8
+ createDocument({ typeId, title, subtitle, date, summary, tags, approval, comment, createUserId, originalFileName, assignment, properties, metadata }: CreateDocumentParameters, content: Uint8Array | ReadableStream<Uint8Array>): Promise<Document>;
9
+ updateDocument(id: string, update: Partial<Pick<Document, UpdatableDocumentProperties>> & {
10
+ properties?: SetDocumentPropertyParameters[];
11
+ }): Promise<void>;
12
+ /**
13
+ * @returns collectionIds from either direct assignment or automatic assignment scope
14
+ */
15
+ private createAssignment;
16
+ }
@@ -0,0 +1,81 @@
1
+ var _a;
2
+ import { match, P } from 'ts-pattern';
3
+ import { DocumentApproval, DocumentAssignmentScope, DocumentAssignmentTask, DocumentWorkflowStep } from '../../../document-management/models/index.js';
4
+ import { BadRequestError } from '../../../errors/bad-request.error.js';
5
+ import { inject } from '../../../injector/inject.js';
6
+ import { Logger } from '../../../logger/logger.js';
7
+ import { Transactional } from '../../../orm/server/index.js';
8
+ import { injectRepository } from '../../../orm/server/repository.js';
9
+ import { getPdfPageCount } from '../../../pdf/utils.js';
10
+ import { toArray } from '../../../utils/array/index.js';
11
+ import { objectKeys } from '../../../utils/object/object.js';
12
+ import { tryIgnoreLogAsync } from '../../../utils/try-ignore.js';
13
+ import { isDefined, isUndefined } from '../../../utils/type-guards.js';
14
+ import { Document } from '../../models/index.js';
15
+ import { DocumentCollectionService } from './document-collection.service.js';
16
+ import { DocumentFileService } from './document-file.service.js';
17
+ import { DocumentPropertyService } from './document-property.service.js';
18
+ import { DocumentRequestService } from './document-request.service.js';
19
+ import { DocumentWorkflowService } from './document-workflow.service.js';
20
+ export class DocumentService extends Transactional {
21
+ #documentFileService = inject(DocumentFileService);
22
+ #requestService = inject(DocumentRequestService);
23
+ #workflowService = inject(DocumentWorkflowService, undefined, { forwardRef: true });
24
+ #documentPropertyService = inject(DocumentPropertyService);
25
+ #documentCollectionService = inject(DocumentCollectionService);
26
+ #documentAssignmentTaskRepository = injectRepository(DocumentAssignmentTask);
27
+ #documentAssignmentScopeRepository = injectRepository(DocumentAssignmentScope);
28
+ #logger = inject(Logger, _a.name);
29
+ repository = injectRepository(Document).withSession(this.session);
30
+ async createDocument({ typeId, title, subtitle, date, summary, tags, approval, comment, createUserId, originalFileName, assignment, properties, metadata }, content) {
31
+ const document = await this.transaction(async (tx) => {
32
+ const documentFile = await this.#documentFileService.withTransaction(tx).create(content, originalFileName);
33
+ const pages = documentFile.mimeType.includes('pdf') ? await tryIgnoreLogAsync(this.#logger, async () => getPdfPageCount(content), null) : null;
34
+ const document = await this.repository.withTransaction(tx).insert({ fileId: documentFile.id, typeId, title, subtitle, pages, date, summary, tags, metadata, approval, comment, createUserId });
35
+ if (isDefined(properties)) {
36
+ await this.#documentPropertyService.withTransaction(tx).setPropertyValues(document.id, properties);
37
+ }
38
+ await this.withTransaction(tx).createAssignment(document.id, assignment, tx);
39
+ await this.#workflowService.withTransaction(tx).initiateWorkflow(document.id, DocumentWorkflowStep.Classification);
40
+ return document;
41
+ });
42
+ return document;
43
+ }
44
+ async updateDocument(id, update) {
45
+ await this.transaction(async (tx) => {
46
+ const document = await this.repository.withTransaction(tx).load(id);
47
+ if (document.approval == DocumentApproval.Approved) {
48
+ throw new BadRequestError('Cannot update approved documents.');
49
+ }
50
+ const updateKeyLength = objectKeys(update).length;
51
+ if ((updateKeyLength > 1) || (isUndefined(update.properties) && (updateKeyLength > 0))) {
52
+ await this.repository.withTransaction(tx).update(id, update);
53
+ }
54
+ if (isDefined(update.properties)) {
55
+ await this.#documentPropertyService.withTransaction(tx).setPropertyValues(id, update.properties);
56
+ }
57
+ });
58
+ }
59
+ /**
60
+ * @returns collectionIds from either direct assignment or automatic assignment scope
61
+ */
62
+ async createAssignment(documentId, assignment, transaction) {
63
+ return match(assignment)
64
+ .with({ collections: P.select() }, async (collectionIds) => {
65
+ const collectionIdsArray = toArray(collectionIds);
66
+ await this.#documentCollectionService.withTransaction(transaction).assignDocument(documentId, collectionIdsArray);
67
+ })
68
+ .with({ request: P.select() }, async (requestId) => {
69
+ await this.#requestService.withTransaction(transaction).assignDocument(requestId, documentId);
70
+ })
71
+ .with({ automatic: P.select() }, async ({ target, scope }) => {
72
+ const collectionIdsArray = toArray(scope);
73
+ const assignmentTask = await this.#documentAssignmentTaskRepository.withTransaction(transaction).insert({ documentId: documentId, target });
74
+ for (const collectionId of collectionIdsArray) {
75
+ await this.#documentAssignmentScopeRepository.withTransaction(transaction).insert({ taskId: assignmentTask.id, collectionId });
76
+ }
77
+ })
78
+ .exhaustive();
79
+ }
80
+ }
81
+ _a = DocumentService;
@@ -1,2 +1,11 @@
1
+ export * from './document-category-type.service.js';
2
+ export * from './document-collection.service.js';
3
+ export * from './document-file.service.js';
4
+ export * from './document-management-ai.service.js';
1
5
  export * from './document-management-ancillary.service.js';
2
6
  export * from './document-management.service.js';
7
+ export * from './document-property.service.js';
8
+ export * from './document-request.service.js';
9
+ export * from './document-validation.service.js';
10
+ export * from './document-workflow.service.js';
11
+ export * from './document.service.js';
@@ -1,2 +1,11 @@
1
+ export * from './document-category-type.service.js';
2
+ export * from './document-collection.service.js';
3
+ export * from './document-file.service.js';
4
+ export * from './document-management-ai.service.js';
1
5
  export * from './document-management-ancillary.service.js';
2
6
  export * from './document-management.service.js';
7
+ export * from './document-property.service.js';
8
+ export * from './document-request.service.js';
9
+ export * from './document-validation.service.js';
10
+ export * from './document-workflow.service.js';
11
+ export * from './document.service.js';
@@ -0,0 +1,19 @@
1
+ import { AiService } from '../../../ai/index.js';
2
+ import { type EnumType } from '../../../enumeration/enumeration.js';
3
+ import type { SchemaTestable } from '../../../schema/schema.js';
4
+ import { DocumentValidationExecutor, type DocumentValidationExecutorContext, type DocumentValidationExecutorResult } from './validator.js';
5
+ export declare const AiValidationDifficulty: {
6
+ readonly Easy: "easy";
7
+ readonly MediumLow: "medium-low";
8
+ readonly MediumHigh: "medium-high";
9
+ readonly Hard: "hard";
10
+ };
11
+ export type AiValidationDifficulty = EnumType<typeof AiValidationDifficulty>;
12
+ export declare abstract class AiValidationExecutor<R> extends DocumentValidationExecutor {
13
+ protected readonly aiService: AiService;
14
+ abstract readonly schema: SchemaTestable<R>;
15
+ abstract readonly difficulty: AiValidationDifficulty;
16
+ execute(context: DocumentValidationExecutorContext): Promise<DocumentValidationExecutorResult>;
17
+ abstract getPrompt(context: DocumentValidationExecutorContext): string | Promise<string>;
18
+ abstract getResult(output: R): DocumentValidationExecutorResult | Promise<DocumentValidationExecutorResult>;
19
+ }
@@ -0,0 +1,51 @@
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 { AiService } from '../../../ai/index.js';
8
+ import { defineEnum } from '../../../enumeration/enumeration.js';
9
+ import { Singleton } from '../../../injector/decorators.js';
10
+ import { inject } from '../../../injector/inject.js';
11
+ import { match } from 'ts-pattern';
12
+ import { DocumentValidationExecutor } from './validator.js';
13
+ export const AiValidationDifficulty = defineEnum('AiValidationDifficulty', {
14
+ Easy: 'easy',
15
+ MediumLow: 'medium-low',
16
+ MediumHigh: 'medium-high',
17
+ Hard: 'hard',
18
+ });
19
+ let AiValidationExecutor = class AiValidationExecutor extends DocumentValidationExecutor {
20
+ aiService = inject(AiService);
21
+ async execute(context) {
22
+ const validationPrompt = await this.getPrompt(context);
23
+ const model = match(this.difficulty)
24
+ .with('easy', () => 'gemini-2.0-flash-lite')
25
+ .with('medium-low', () => 'gemini-2.5-flash-exp-04-17')
26
+ .with('medium-high', () => 'gemini-2.5-flash-exp-04-17')
27
+ .with('hard', () => 'gemini-2.5-pro-exp-03-25')
28
+ .exhaustive();
29
+ const prompt = `Deine Aufgabe ist es ein Dokument zu validieren.
30
+
31
+ Validierungsaufgabe:
32
+ ${validationPrompt}`;
33
+ const generation = await this.aiService.generate({
34
+ model,
35
+ generationOptions: {
36
+ temperature: 0.2,
37
+ topK: 20,
38
+ },
39
+ generationSchema: this.schema,
40
+ contents: [{
41
+ role: 'user',
42
+ parts: [{ text: prompt }],
43
+ }],
44
+ });
45
+ return await this.getResult(generation.json);
46
+ }
47
+ };
48
+ AiValidationExecutor = __decorate([
49
+ Singleton()
50
+ ], AiValidationExecutor);
51
+ export { AiValidationExecutor };
@@ -0,0 +1,2 @@
1
+ export * from './ai-validation-executor.js';
2
+ export * from './validator.js';
@@ -0,0 +1,2 @@
1
+ export * from './ai-validation-executor.js';
2
+ export * from './validator.js';
@@ -0,0 +1,16 @@
1
+ import { type SchemaOutput } from '../../../schema/index.js';
2
+ import { AiValidationExecutor } from './ai-validation-executor.js';
3
+ import type { DocumentValidationExecutorResult } from './validator.js';
4
+ export declare class SingleDocumentValidationExecutor extends AiValidationExecutor<{
5
+ hasMultipleDocuments: boolean;
6
+ reason?: string;
7
+ }> {
8
+ readonly identifier = "single-document";
9
+ readonly difficulty: "medium-low";
10
+ schema: import("../../../schema/index.js").ObjectSchema<{
11
+ hasMultipleDocuments: boolean;
12
+ reason?: string | undefined;
13
+ }>;
14
+ getPrompt(): string;
15
+ getResult(output: SchemaOutput<typeof this['schema']>): DocumentValidationExecutorResult;
16
+ }
@@ -0,0 +1,20 @@
1
+ import { DocumentValidationResultStatus } from '../../../document-management/models/document-validation-execution.model.js';
2
+ import { boolean, object, optional, string } from '../../../schema/index.js';
3
+ import { AiValidationDifficulty, AiValidationExecutor } from './ai-validation-executor.js';
4
+ export class SingleDocumentValidationExecutor extends AiValidationExecutor {
5
+ identifier = 'single-document';
6
+ difficulty = AiValidationDifficulty.MediumLow;
7
+ schema = object({
8
+ hasMultipleDocuments: boolean(),
9
+ reason: optional(string()),
10
+ });
11
+ getPrompt() {
12
+ return 'Überprüfe ob das Dokument aus mehreren Dokumenten zusammengesetzt ist. Falls ja, begründe in wenigen Worten. Antworte auf deutsch.';
13
+ }
14
+ getResult(output) {
15
+ if (output.hasMultipleDocuments) {
16
+ return { status: DocumentValidationResultStatus.Warning, message: output.reason ?? null };
17
+ }
18
+ return { status: DocumentValidationResultStatus.Passed };
19
+ }
20
+ }
@@ -0,0 +1,21 @@
1
+ import type { Document, DocumentCategory, DocumentCollection, DocumentProperty, DocumentPropertyValue, DocumentType, DocumentValidationDefinition, DocumentValidationExecution, DocumentValidationResultStatus } from '../../../document-management/models/index.js';
2
+ export type DocumentValidationExecutorContextDocumentData = {
3
+ document: Document;
4
+ collections: DocumentCollection[];
5
+ category: DocumentCategory;
6
+ type: DocumentType;
7
+ properties: DocumentProperty[];
8
+ propertyValues: DocumentPropertyValue[];
9
+ };
10
+ export type DocumentValidationExecutorContext = {
11
+ execution: DocumentValidationExecution;
12
+ definition: DocumentValidationDefinition;
13
+ } & DocumentValidationExecutorContextDocumentData;
14
+ export type DocumentValidationExecutorResult = {
15
+ status: DocumentValidationResultStatus;
16
+ message?: string | null;
17
+ };
18
+ export declare abstract class DocumentValidationExecutor {
19
+ abstract readonly identifier: string;
20
+ abstract execute(execution: DocumentValidationExecutorContext): Promise<DocumentValidationExecutorResult>;
21
+ }
@@ -0,0 +1,2 @@
1
+ export class DocumentValidationExecutor {
2
+ }
package/eslint.config.js CHANGED
@@ -12,25 +12,24 @@ export default [
12
12
  parser: tsParser,
13
13
  parserOptions: {
14
14
  projectService: {
15
- allowDefaultProject: ['*.js']
16
- }
15
+ allowDefaultProject: ['*.js'],
16
+ },
17
17
  },
18
- globals: { ...globals.browser, ...globals.node }
19
- }
18
+ globals: { ...globals.browser, ...globals.node },
19
+ },
20
20
  },
21
21
  stylistic.configs.customize({
22
22
  semi: true,
23
23
  arrowParens: true,
24
- commaDangle: 'never'
25
24
  }),
26
25
  {
27
26
  rules: {
28
- 'prefer-named-capture-group': ['warn']
29
- }
27
+ 'prefer-named-capture-group': ['warn'],
28
+ },
30
29
  },
31
30
  {
32
31
  plugins: {
33
- '@typescript-eslint': tseslint
32
+ '@typescript-eslint': tseslint,
34
33
  },
35
34
  rules: {
36
35
  ...tseslint.configs['strict-type-checked'].rules,
@@ -48,24 +47,39 @@ export default [
48
47
  '@typescript-eslint/no-unsafe-assignment': 'off',
49
48
  '@typescript-eslint/no-unused-vars': ['warn', { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }],
50
49
  '@typescript-eslint/promise-function-async': 'error',
51
- '@typescript-eslint/restrict-template-expressions': ['warn', { allowNumber: true, allowBoolean: true, allowNullish: true }]
52
- }
50
+ '@typescript-eslint/restrict-template-expressions': ['warn', { allowNumber: true, allowBoolean: true, allowNullish: true }],
51
+ },
53
52
  },
54
53
  {
55
54
  rules: {
56
55
  '@stylistic/member-delimiter-style': ['warn', {
57
- multiline: { delimiter: 'comma', requireLast: false },
56
+ multiline: { delimiter: 'comma', requireLast: true },
58
57
  singleline: { delimiter: 'comma', requireLast: false },
59
58
  overrides: {
60
59
  interface: {
61
60
  multiline: { delimiter: 'semi', requireLast: true },
62
- singleline: { delimiter: 'semi', requireLast: true }
63
- }
64
- }
61
+ singleline: { delimiter: 'semi', requireLast: true },
62
+ },
63
+ },
65
64
  }],
66
65
  '@stylistic/yield-star-spacing': ['warn', 'after'],
67
66
  '@stylistic/generator-star-spacing': ['warn', 'before'],
68
- '@stylistic/indent': 'off'
69
- }
70
- }
67
+ '@stylistic/indent': 'off',
68
+ '@stylistic/comma-dangle': [
69
+ 'error',
70
+ {
71
+ arrays: 'always-multiline',
72
+ objects: 'always-multiline',
73
+ imports: 'always-multiline',
74
+ exports: 'always-multiline',
75
+ functions: 'only-multiline',
76
+ importAttributes: 'always-multiline',
77
+ dynamicImports: 'always-multiline',
78
+ enums: 'always-multiline',
79
+ generics: 'always-multiline',
80
+ tuples: 'always-multiline',
81
+ },
82
+ ],
83
+ },
84
+ },
71
85
  ];
@@ -1,6 +1,21 @@
1
1
  import '../../polyfills.js';
2
- import type { DocumentCollection } from '../../document-management/index.js';
3
- import { DocumentManagementAncillaryService } from '../../document-management/server/index.js';
2
+ import type { DocumentCollection, DocumentWorkflowStep } from '../../document-management/index.js';
3
+ import { DocumentManagementAncillaryService, type DocumentCollectionMetadata } from '../../document-management/server/index.js';
4
4
  export declare class TestDocumentManagementAncillaryService extends DocumentManagementAncillaryService {
5
- resolveNames(collections: DocumentCollection[]): Promise<string[]>;
5
+ _resolveMetadata(collections: DocumentCollection[]): DocumentCollectionMetadata[];
6
+ canReadCollection(_collectionId: string, _token?: unknown): boolean;
7
+ canWriteCollection(_collectionId: string, _token?: unknown): boolean;
8
+ canApproveDocument(_documentId: string, _token?: unknown): boolean;
9
+ canRejectDocument(_documentId: string, _token?: unknown): boolean;
10
+ canReadDocumentRequest(_requestId: string, _token?: unknown): boolean;
11
+ canAssignDocumentToRequest(_requestId: string, _documentId: string, _token?: unknown): boolean;
12
+ canManageCategoriesAndTypes(_token?: unknown): boolean;
13
+ canReadDocumentRequestsTemplates(_token?: unknown): boolean;
14
+ canManageDocumentRequestsTemplates(_token?: unknown): boolean;
15
+ canCreateUnassignedDocument(_token?: unknown): boolean;
16
+ canCreateRequestAssignedDocument(_token?: unknown): boolean;
17
+ canDeleteDocument(_documentId: string, _token?: unknown): boolean;
18
+ canManageDocumentRequest(_token?: unknown): boolean;
19
+ canManageValidationDefinitions(_token?: unknown): boolean;
20
+ canProgressDocumentWorkflow(_documentId: string, _currentWorkflowStep: DocumentWorkflowStep, _token?: unknown): boolean;
6
21
  }
@@ -6,16 +6,31 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import '../../polyfills.js';
8
8
  import { Application } from '../../application/application.js';
9
- import { DocumentManagementAncillaryService } from '../../document-management/server/index.js';
9
+ import { DocumentCategoryTypeService, DocumentCollectionService, DocumentManagementAncillaryService, DocumentRequestService } from '../../document-management/server/index.js';
10
10
  import { configureDocumentManagement, migrateDocumentManagementSchema } from '../../document-management/server/module.js';
11
11
  import { DocumentManagementService } from '../../document-management/server/services/document-management.service.js';
12
12
  import { Singleton } from '../../injector/index.js';
13
- import { injectAsync } from '../../injector/inject.js';
13
+ import { injectManyAsync } from '../../injector/inject.js';
14
14
  import { configureS3ObjectStorage } from '../../object-storage/index.js';
15
15
  let TestDocumentManagementAncillaryService = class TestDocumentManagementAncillaryService extends DocumentManagementAncillaryService {
16
- async resolveNames(collections) {
17
- return collections.map((collection) => collection.metadata.attributes['name']);
16
+ _resolveMetadata(collections) {
17
+ return collections.map((collection) => ({ name: collection.metadata.attributes['name'], group: null }));
18
18
  }
19
+ canReadCollection(_collectionId, _token) { return true; }
20
+ canWriteCollection(_collectionId, _token) { return true; }
21
+ canApproveDocument(_documentId, _token) { return true; }
22
+ canRejectDocument(_documentId, _token) { return true; }
23
+ canReadDocumentRequest(_requestId, _token) { return true; }
24
+ canAssignDocumentToRequest(_requestId, _documentId, _token) { return true; }
25
+ canManageCategoriesAndTypes(_token) { return true; }
26
+ canReadDocumentRequestsTemplates(_token) { return true; }
27
+ canManageDocumentRequestsTemplates(_token) { return true; }
28
+ canCreateUnassignedDocument(_token) { return true; }
29
+ canCreateRequestAssignedDocument(_token) { return true; }
30
+ canDeleteDocument(_documentId, _token) { return true; }
31
+ canManageDocumentRequest(_token) { return true; }
32
+ canManageValidationDefinitions(_token) { return true; }
33
+ canProgressDocumentWorkflow(_documentId, _currentWorkflowStep, _token) { return true; }
19
34
  };
20
35
  TestDocumentManagementAncillaryService = __decorate([
21
36
  Singleton()
@@ -25,23 +40,24 @@ async function bootstrap() {
25
40
  configureDocumentManagement({
26
41
  ancillaryService: TestDocumentManagementAncillaryService,
27
42
  fileObjectStorageModule: 'documents',
43
+ filePreviewObjectStorageModule: 'document-previews',
28
44
  database: {
29
45
  connection: {
30
46
  database: 'xxx',
31
47
  user: 'xxx',
32
- password: 'xxx'
33
- }
34
- }
48
+ password: 'xxx',
49
+ },
50
+ },
35
51
  });
36
52
  configureS3ObjectStorage({ endpoint: 'http://localhost:10000', accessKey: 'tstdl-dev', secretKey: 'tstdl-dev', bucketPerModule: true });
37
53
  await migrateDocumentManagementSchema();
38
54
  }
39
55
  async function main() {
40
- const documentManagementService = await injectAsync(DocumentManagementService);
41
- const collection = await documentManagementService.createCollection();
42
- const category = await documentManagementService.createCategory({ label: 'Testkategorie' });
43
- const type = await documentManagementService.createType({ categoryId: category.id, group: null, label: 'Testtyp' });
44
- const request = await documentManagementService.createDocumentRequest({ typeId: type.id, requiredFilesCount: 1, comment: null, collectionIds: [collection.id] });
56
+ const [documentManagementService, documentCollectionService, documentCategoryTypeService, documentRequestService] = await injectManyAsync(DocumentManagementService, DocumentCollectionService, DocumentCategoryTypeService, DocumentRequestService);
57
+ const collection = await documentCollectionService.createCollection(null);
58
+ const category = await documentCategoryTypeService.createCategory('Testkategorie', null);
59
+ const type = await documentCategoryTypeService.createType('Testtyp', category.id);
60
+ const request = await documentRequestService.createRequest(type.id, [collection.id], null);
45
61
  const data = await documentManagementService.loadData([collection.id]);
46
62
  console.log(data);
47
63
  }
package/file/mime-type.js CHANGED
@@ -12,16 +12,9 @@ export function getMimeTypeExtensions(mimeType) {
12
12
  async function spawnFileCommand(args, file) {
13
13
  const process = await spawnCommand('file', args);
14
14
  if (isDefined(file)) {
15
- try {
16
- await process.write(file);
17
- }
18
- catch { /* ignore as file command closes stdin early */ }
19
- }
20
- const { code } = await process.wait();
21
- if (code != 0) {
22
- const errorOutput = await process.readError();
23
- throw new Error(errorOutput.trim());
15
+ process.autoWrite(file);
24
16
  }
17
+ await process.wait({ throwOnNonZeroExitCode: true });
25
18
  const output = await process.readOutput();
26
19
  if (output.includes('file or directory')) {
27
20
  throw new Error(output.trim());
package/formats.d.ts CHANGED
@@ -13,8 +13,8 @@ export declare const dateShort: Intl.DateTimeFormatOptions;
13
13
  export declare const dateMedium: Intl.DateTimeFormatOptions;
14
14
  export declare const dateLong: Intl.DateTimeFormatOptions;
15
15
  export declare const timeShort: Intl.DateTimeFormatOptions;
16
- export declare const euroFormat: Intl.NumberFormatOptions;
17
- export declare const euroFormatWithoutCents: Intl.NumberFormatOptions;
16
+ export declare const currencyFormat: Intl.NumberFormatOptions;
17
+ export declare const currencyFormatWithoutCents: Intl.NumberFormatOptions;
18
18
  export declare const percentFormat: Intl.NumberFormatOptions;
19
19
  export declare function formatNumber(value: number, format?: Intl.NumberFormatOptions): string;
20
20
  export declare function formatInteger(value: number): string;
@@ -24,7 +24,10 @@ export declare function formatTimeShort(value: number): string;
24
24
  export declare function formatDateShort(value: Date | number): string;
25
25
  export declare function formatDate(dateOrTimestamp: number | Date): string;
26
26
  export declare function formatNumericDate(numericDate: number): string;
27
+ export declare function formatCurrency(value: number, currency: string): string;
28
+ export declare function formatCurrencyWithoutCents(value: number, currency: string): string;
27
29
  export declare function formatEuro(value: number): string;
30
+ export declare function formatEuroWithoutCents(value: number): string;
28
31
  export declare function formatPercent(value: number): string;
29
32
  export type FormatPersonNameOptions<F = unknown> = {
30
33
  lastNameFirst?: boolean;