@tstdl/base 0.92.142 → 0.92.144

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 (223) hide show
  1. package/ai/ai-file.service.js +1 -1
  2. package/ai/ai.service.js +3 -3
  3. package/ai/types.d.ts +1 -1
  4. package/api/client/client.d.ts +1 -1
  5. package/api/client/client.js +10 -4
  6. package/api/server/middlewares/content-type.middleware.js +8 -7
  7. package/api/types.js +1 -1
  8. package/authentication/client/authentication.service.js +3 -3
  9. package/authentication/server/authentication-ancillary.service.d.ts +11 -1
  10. package/authentication/server/authentication-ancillary.service.js +1 -1
  11. package/authentication/server/authentication-secret-requirements.validator.js +1 -1
  12. package/authentication/server/authentication.api-controller.js +22 -10
  13. package/authentication/server/authentication.service.d.ts +11 -5
  14. package/authentication/server/authentication.service.js +97 -49
  15. package/authentication/server/drizzle.config.js +2 -2
  16. package/authentication/server/module.js +1 -1
  17. package/cancellation/token.d.ts +2 -2
  18. package/cancellation/token.js +4 -4
  19. package/cookie/cookie.js +2 -2
  20. package/document-management/api/document-management.api.d.ts +122 -24
  21. package/document-management/api/document-management.api.js +17 -0
  22. package/document-management/{server/services → authorization}/document-management-authorization.service.d.ts +7 -7
  23. package/document-management/authorization/document-management-authorization.service.js +2 -0
  24. package/document-management/authorization/index.d.ts +2 -0
  25. package/document-management/authorization/index.js +2 -0
  26. package/document-management/authorization/policies.d.ts +38 -0
  27. package/document-management/authorization/policies.js +2 -0
  28. package/document-management/index.d.ts +1 -0
  29. package/document-management/index.js +1 -0
  30. package/document-management/models/document-assignment-scope.model.d.ts +1 -0
  31. package/document-management/models/document-assignment-scope.model.js +10 -3
  32. package/document-management/models/document-assignment-task.model.d.ts +1 -0
  33. package/document-management/models/document-assignment-task.model.js +8 -2
  34. package/document-management/models/document-category.model.d.ts +1 -0
  35. package/document-management/models/document-category.model.js +7 -1
  36. package/document-management/models/document-collection-assignment.model.d.ts +1 -0
  37. package/document-management/models/document-collection-assignment.model.js +12 -4
  38. package/document-management/models/document-collection.model.d.ts +2 -0
  39. package/document-management/models/document-collection.model.js +8 -2
  40. package/document-management/models/document-management-table.d.ts +3 -1
  41. package/document-management/models/document-management-table.js +2 -2
  42. package/document-management/models/document-property-value.model.d.ts +1 -0
  43. package/document-management/models/document-property-value.model.js +9 -3
  44. package/document-management/models/document-property.model.d.ts +1 -0
  45. package/document-management/models/document-property.model.js +8 -2
  46. package/document-management/models/document-request-collection-assignment.model.d.ts +1 -0
  47. package/document-management/models/document-request-collection-assignment.model.js +12 -4
  48. package/document-management/models/document-request-template.d.ts +1 -0
  49. package/document-management/models/document-request-template.js +6 -1
  50. package/document-management/models/document-request.model.d.ts +1 -0
  51. package/document-management/models/document-request.model.js +10 -1
  52. package/document-management/models/document-requests-template.d.ts +1 -0
  53. package/document-management/models/document-requests-template.js +7 -3
  54. package/document-management/models/document-tag-assignment.model.d.ts +8 -0
  55. package/document-management/models/document-tag-assignment.model.js +40 -0
  56. package/document-management/models/document-tag.model.d.ts +6 -0
  57. package/document-management/models/{document-request-submission.model.js → document-tag.model.js} +14 -18
  58. package/document-management/models/document-type-property.model.d.ts +1 -0
  59. package/document-management/models/document-type-property.model.js +7 -2
  60. package/document-management/models/document-type-validation.model.d.ts +1 -0
  61. package/document-management/models/document-type-validation.model.js +8 -2
  62. package/document-management/models/document-type.model.d.ts +1 -0
  63. package/document-management/models/document-type.model.js +7 -2
  64. package/document-management/models/document-validation-definition.model.d.ts +1 -0
  65. package/document-management/models/document-validation-definition.model.js +7 -2
  66. package/document-management/models/document-validation-execution-related-document.model.d.ts +1 -0
  67. package/document-management/models/document-validation-execution-related-document.model.js +10 -3
  68. package/document-management/models/document-validation-execution.model.d.ts +1 -0
  69. package/document-management/models/document-validation-execution.model.js +9 -3
  70. package/document-management/models/document-workflow.model.d.ts +4 -1
  71. package/document-management/models/document-workflow.model.js +16 -4
  72. package/document-management/models/document.model.d.ts +2 -2
  73. package/document-management/models/document.model.js +9 -8
  74. package/document-management/models/index.d.ts +2 -1
  75. package/document-management/models/index.js +2 -1
  76. package/document-management/server/api/document-management.api.d.ts +4 -1
  77. package/document-management/server/api/document-management.api.js +113 -22
  78. package/document-management/server/configure.d.ts +2 -2
  79. package/document-management/server/configure.js +7 -7
  80. package/document-management/server/drizzle/0000_parallel_mantis.sql +359 -0
  81. package/document-management/server/drizzle/meta/0000_snapshot.json +784 -260
  82. package/document-management/server/drizzle/meta/_journal.json +2 -2
  83. package/document-management/server/module.d.ts +2 -2
  84. package/document-management/server/module.js +2 -2
  85. package/document-management/server/schemas.d.ts +6 -5
  86. package/document-management/server/schemas.js +12 -11
  87. package/document-management/server/services/document-category-type.service.d.ts +19 -10
  88. package/document-management/server/services/document-category-type.service.js +34 -27
  89. package/document-management/server/services/document-collection.service.d.ts +13 -6
  90. package/document-management/server/services/document-collection.service.js +36 -12
  91. package/document-management/server/services/document-file.service.d.ts +8 -7
  92. package/document-management/server/services/document-file.service.js +28 -33
  93. package/document-management/server/services/document-management-ai.service.d.ts +5 -4
  94. package/document-management/server/services/document-management-ai.service.js +51 -28
  95. package/document-management/server/services/document-management-ancillary.service.d.ts +3 -21
  96. package/document-management/server/services/document-management-ancillary.service.js +0 -24
  97. package/document-management/server/services/document-management-observation.service.d.ts +15 -0
  98. package/document-management/server/services/document-management-observation.service.js +160 -0
  99. package/document-management/server/services/document-management.service.d.ts +6 -5
  100. package/document-management/server/services/document-management.service.js +112 -86
  101. package/document-management/server/services/document-property.service.d.ts +15 -7
  102. package/document-management/server/services/document-property.service.js +52 -20
  103. package/document-management/server/services/document-request.service.d.ts +13 -24
  104. package/document-management/server/services/document-request.service.js +39 -62
  105. package/document-management/server/services/document-tag.service.d.ts +10 -0
  106. package/document-management/server/services/document-tag.service.js +59 -0
  107. package/document-management/server/services/document-validation.service.d.ts +8 -8
  108. package/document-management/server/services/document-validation.service.js +41 -40
  109. package/document-management/server/services/document-workflow.service.d.ts +6 -5
  110. package/document-management/server/services/document-workflow.service.js +54 -43
  111. package/document-management/server/services/document.service.d.ts +12 -11
  112. package/document-management/server/services/document.service.js +66 -40
  113. package/document-management/server/services/index.d.ts +2 -1
  114. package/document-management/server/services/index.js +2 -1
  115. package/document-management/server/services/singleton.js +2 -2
  116. package/document-management/server/validators/ai-validation-executor.js +4 -4
  117. package/document-management/service-models/document-collection-metadata.service-model.d.ts +14 -0
  118. package/document-management/service-models/document-collection-metadata.service-model.js +1 -0
  119. package/document-management/service-models/document-folders.view-model.d.ts +1 -7
  120. package/document-management/service-models/document-folders.view-model.js +3 -15
  121. package/document-management/service-models/document-management.view-model.d.ts +20 -6
  122. package/document-management/service-models/document-management.view-model.js +62 -8
  123. package/document-management/service-models/document.service-model.d.ts +14 -11
  124. package/document-management/service-models/document.service-model.js +11 -2
  125. package/document-management/service-models/enriched/enriched-document-assignment.view.d.ts +1 -1
  126. package/document-management/service-models/enriched/enriched-document-assignment.view.js +0 -2
  127. package/document-management/service-models/enriched/enriched-document-category.view.d.ts +11 -1
  128. package/document-management/service-models/enriched/enriched-document-category.view.js +44 -1
  129. package/document-management/service-models/enriched/enriched-document-collection.view.d.ts +4 -2
  130. package/document-management/service-models/enriched/enriched-document-collection.view.js +13 -3
  131. package/document-management/service-models/enriched/enriched-document-management-data.view.d.ts +2 -0
  132. package/document-management/service-models/enriched/enriched-document-management-data.view.js +4 -2
  133. package/document-management/service-models/enriched/enriched-document-request.view.d.ts +1 -0
  134. package/document-management/service-models/enriched/enriched-document-request.view.js +2 -0
  135. package/document-management/service-models/enriched/enriched-document-type.view.d.ts +9 -1
  136. package/document-management/service-models/enriched/enriched-document-type.view.js +28 -1
  137. package/document-management/service-models/enriched/enriched-document.view.d.ts +7 -6
  138. package/document-management/service-models/enriched/enriched-document.view.js +29 -6
  139. package/document-management/service-models/{normalized-requests-template-data.model.d.ts → enriched/enriched-requests-template-data.model.d.ts} +6 -6
  140. package/document-management/service-models/{normalized-requests-template-data.model.js → enriched/enriched-requests-template-data.model.js} +1 -1
  141. package/document-management/service-models/enriched/index.d.ts +1 -0
  142. package/document-management/service-models/enriched/index.js +1 -0
  143. package/document-management/service-models/index.d.ts +2 -2
  144. package/document-management/service-models/index.js +2 -2
  145. package/examples/document-management/categories-and-types.d.ts +33 -31
  146. package/examples/document-management/categories-and-types.js +33 -0
  147. package/examples/document-management/main.d.ts +5 -4
  148. package/examples/document-management/main.js +13 -7
  149. package/function/log.js +2 -2
  150. package/http/server/node/module.d.ts +4 -1
  151. package/http/server/node/module.js +10 -1
  152. package/http/server/node/node-http-server.d.ts +3 -6
  153. package/http/server/node/node-http-server.js +68 -67
  154. package/injector/inject.js +6 -6
  155. package/injector/injector.js +3 -3
  156. package/jsx/is-component-class.js +1 -1
  157. package/key-value-store/key-value.store.d.ts +38 -7
  158. package/key-value-store/key-value.store.js +2 -1
  159. package/key-value-store/mongo/mongo-key-value.store.d.ts +1 -0
  160. package/key-value-store/mongo/mongo-key-value.store.js +14 -5
  161. package/key-value-store/postgres/drizzle/0000_shocking_slipstream.sql +12 -0
  162. package/key-value-store/postgres/drizzle/meta/0000_snapshot.json +97 -0
  163. package/key-value-store/postgres/drizzle/meta/_journal.json +13 -0
  164. package/key-value-store/postgres/drizzle.config.d.ts +2 -0
  165. package/key-value-store/postgres/drizzle.config.js +11 -0
  166. package/key-value-store/postgres/index.d.ts +2 -0
  167. package/key-value-store/postgres/index.js +2 -0
  168. package/key-value-store/postgres/key-value-store.service.d.ts +17 -0
  169. package/key-value-store/postgres/key-value-store.service.js +65 -0
  170. package/key-value-store/postgres/models/index.d.ts +2 -0
  171. package/key-value-store/postgres/models/index.js +2 -0
  172. package/key-value-store/postgres/models/key-value.model.d.ts +7 -0
  173. package/key-value-store/postgres/models/key-value.model.js +35 -0
  174. package/key-value-store/postgres/models/schemas.d.ts +3 -0
  175. package/key-value-store/postgres/models/schemas.js +4 -0
  176. package/key-value-store/postgres/module.d.ts +6 -0
  177. package/key-value-store/postgres/module.js +23 -0
  178. package/lock/web/web-lock.d.ts +0 -1
  179. package/lock/web/web-lock.js +6 -13
  180. package/orm/data-types/timestamp.js +1 -1
  181. package/orm/decorators.d.ts +37 -29
  182. package/orm/decorators.js +44 -24
  183. package/orm/entity.d.ts +1 -0
  184. package/orm/query.d.ts +10 -2
  185. package/orm/repository.types.d.ts +2 -1
  186. package/orm/schemas/json.d.ts +12 -6
  187. package/orm/schemas/json.js +12 -5
  188. package/orm/server/database.js +5 -2
  189. package/orm/server/drizzle/schema-converter.js +40 -11
  190. package/orm/server/query-converter.d.ts +2 -1
  191. package/orm/server/query-converter.js +57 -34
  192. package/orm/server/repository.d.ts +26 -43
  193. package/orm/server/repository.js +106 -39
  194. package/orm/server/transaction.d.ts +2 -1
  195. package/orm/server/transaction.js +3 -0
  196. package/orm/server/transactional.d.ts +5 -1
  197. package/orm/server/transactional.js +34 -4
  198. package/package.json +14 -11
  199. package/process/spawn.js +0 -1
  200. package/promise/deferred-promise.d.ts +4 -3
  201. package/promise/deferred-promise.js +13 -5
  202. package/queue/postgres/queue.js +8 -8
  203. package/reflection/utils.js +3 -3
  204. package/schema/decorators/class.js +0 -1
  205. package/schema/decorators/schema.js +1 -1
  206. package/schema/schemas/boolean.d.ts +1 -1
  207. package/schema/schemas/boolean.js +2 -2
  208. package/schema/schemas/number.js +3 -3
  209. package/schema/schemas/object.js +5 -6
  210. package/sse/server-sent-events-source.js +4 -1
  211. package/utils/compression.js +9 -9
  212. package/utils/date-time.d.ts +1 -0
  213. package/utils/date-time.js +18 -4
  214. package/utils/equals.d.ts +7 -0
  215. package/utils/equals.js +17 -2
  216. package/utils/function/memoize.js +10 -2
  217. package/utils/jwt.js +3 -3
  218. package/utils/object/property-name.d.ts +2 -2
  219. package/utils/timing.d.ts +2 -2
  220. package/utils/timing.js +12 -12
  221. package/document-management/models/document-request-submission.model.d.ts +0 -7
  222. package/document-management/server/drizzle/0000_moaning_luckman.sql +0 -305
  223. package/document-management/server/services/document-management-authorization.service.js +0 -28
@@ -68,19 +68,21 @@ import { arrayAgg } from '../../../orm/index.js';
68
68
  import { injectRepository } from '../../../orm/server/index.js';
69
69
  import { array, boolean, enumeration, integer, nullable, number, object, string } from '../../../schema/index.js';
70
70
  import { distinct } from '../../../utils/array/index.js';
71
- import { dateObjectToNumericDate, numericDateToDateObject } from '../../../utils/date-time.js';
71
+ import { numericDateToDateObject, tryDateObjectToNumericDate } from '../../../utils/date-time.js';
72
72
  import { fromEntries, objectEntries } from '../../../utils/object/object.js';
73
73
  import { assertDefined, assertDefinedPass, assertNotNull, isNotNull, isNull, isUndefined } from '../../../utils/type-guards.js';
74
74
  import { Document, DocumentProperty, DocumentRequestState, DocumentTypeProperty } from '../../models/index.js';
75
75
  import { documentCategory, documentRequest, documentRequestCollectionAssignment, documentType } from '../schemas.js';
76
76
  import { DocumentCategoryTypeService } from './document-category-type.service.js';
77
+ import { DocumentCollectionService } from './document-collection.service.js';
77
78
  import { DocumentFileService } from './document-file.service.js';
78
- import { DocumentManagementAncillaryService } from './document-management-ancillary.service.js';
79
79
  import { DocumentPropertyService } from './document-property.service.js';
80
+ import { DocumentTagService } from './document-tag.service.js';
80
81
  import { DocumentManagementSingleton } from './singleton.js';
81
82
  const MODEL = 'gemini-2.5-flash-preview-05-20';
82
83
  let DocumentManagementAiService = DocumentManagementAiService_1 = class DocumentManagementAiService {
83
- #documentManagementAncillaryService = inject(DocumentManagementAncillaryService);
84
+ #documentCollectionService = inject(DocumentCollectionService);
85
+ #documentTagService = inject(DocumentTagService);
84
86
  #documentCategoryTypeService = inject(DocumentCategoryTypeService);
85
87
  #documentFileService = inject(DocumentFileService);
86
88
  #documentPropertyService = inject(DocumentPropertyService);
@@ -89,14 +91,14 @@ let DocumentManagementAiService = DocumentManagementAiService_1 = class Document
89
91
  #documentRepository = injectRepository(Document);
90
92
  #documentTypePropertyRepository = injectRepository(DocumentTypeProperty);
91
93
  #logger = inject(Logger, DocumentManagementAiService_1.name);
92
- async classifyDocumentType(documentId) {
94
+ async classifyDocumentType(tenantId, documentId) {
93
95
  const env_1 = { stack: [], error: void 0, hasError: false };
94
96
  try {
95
- const document = await this.#documentRepository.load(documentId);
96
- const fileContentStream = this.#documentFileService.getContentStream(document.id);
97
+ const document = await this.#documentRepository.loadByQuery({ tenantId, id: documentId });
98
+ const fileContentStream = this.#documentFileService.getContentStream(document);
97
99
  const tmpFile = __addDisposableResource(env_1, await TemporaryFile.from(fileContentStream), true);
98
100
  const filePart = await this.#aiService.processFile({ path: tmpFile.path, mimeType: document.mimeType });
99
- const categories = await this.#documentCategoryTypeService.loadCategoryViews();
101
+ const categories = await this.#documentCategoryTypeService.loadCategoryViews(tenantId);
100
102
  const typeLabelEntries = getDescriptiveTypeLabels(categories);
101
103
  const typeLabels = typeLabelEntries.map(({ label }) => label);
102
104
  this.#logger.trace(`Classifying document ${document.id}`);
@@ -136,19 +138,20 @@ let DocumentManagementAiService = DocumentManagementAiService_1 = class Document
136
138
  await result_1;
137
139
  }
138
140
  }
139
- async extractDocumentInformation(documentId) {
141
+ async extractDocumentInformation(tenantId, documentId) {
140
142
  const env_2 = { stack: [], error: void 0, hasError: false };
141
143
  try {
142
- const document = await this.#documentRepository.load(documentId);
143
- const fileContentStream = this.#documentFileService.getContentStream(document.id);
144
+ const document = await this.#documentRepository.loadByQuery({ tenantId, id: documentId });
145
+ const existingTags = await this.#documentTagService.loadTags(tenantId);
146
+ const fileContentStream = this.#documentFileService.getContentStream(document);
144
147
  const tmpFile = __addDisposableResource(env_2, await TemporaryFile.from(fileContentStream), true);
145
148
  const filePart = await this.#aiService.processFile({ path: tmpFile.path, mimeType: document.mimeType });
146
149
  if (isNull(document.typeId)) {
147
150
  throw new Error(`Document ${document.id} has no type`);
148
151
  }
149
- const typeProperties = await this.#documentTypePropertyRepository.loadManyByQuery({ typeId: document.typeId });
152
+ const typeProperties = await this.#documentTypePropertyRepository.loadManyByQuery({ tenantId: { $or: [null, tenantId] }, typeId: document.typeId });
150
153
  const propertyIds = typeProperties.map((property) => property.propertyId);
151
- const properties = (propertyIds.length > 0) ? await this.#documentPropertyRepository.loadManyByQuery({ id: { $in: propertyIds } }) : undefined;
154
+ const properties = (propertyIds.length > 0) ? await this.#documentPropertyRepository.loadManyByQuery({ tenantId: { $or: [null, tenantId] }, id: { $in: propertyIds } }) : undefined;
152
155
  const propertiesSchemaEntries = properties?.map((property) => {
153
156
  const schema = match(property.dataType)
154
157
  .with('text', () => nullable(string()))
@@ -169,6 +172,7 @@ let DocumentManagementAiService = DocumentManagementAiService_1 = class Document
169
172
  ? {}
170
173
  : { documentProperties: object(fromEntries(propertiesSchemaEntries)) }),
171
174
  });
175
+ const context = { existingTags };
172
176
  this.#logger.trace(`Extracting document ${document.id}`);
173
177
  const { json: extraction } = await this.#aiService.generate({
174
178
  model: MODEL,
@@ -186,11 +190,15 @@ let DocumentManagementAiService = DocumentManagementAiService_1 = class Document
186
190
  parts: [
187
191
  { file: filePart.file },
188
192
  {
189
- text: `Extrahiere den Inhalt des Dokuments in das angegebenen JSON Schema.
193
+ text: `<context>
194
+ ${JSON.stringify(context, null, 2)}
195
+ </context>
196
+ Extrahiere den Inhalt des Dokuments in das angegebenen JSON Schema.
190
197
 
191
198
  Vermeide es, den Titel im Untertitel zu wiederholen.
192
199
  Gib in der summary ausführlich an, welche Informationen in dem Dokument vorkommen (ohne konkrete Werte).
193
- Erstelle bis zu 7 möglichst spezifische Tags.
200
+ Erstelle bis zu 5 Tags. Verwende vorhandene Tags, wenn sie passen. Erstelle neue Tags, wenn es keine passenden gibt.
201
+ Vermeide es, den Titel oder Untertitel als Tag zu verwenden.
194
202
  Antworte auf deutsch.`,
195
203
  },
196
204
  ],
@@ -198,7 +206,7 @@ Antworte auf deutsch.`,
198
206
  ],
199
207
  });
200
208
  const filteredDocumentTags = extraction.documentTags.filter((tag) => (tag != extraction.documentTitle) && (tag != extraction.documentSubtitle));
201
- const date = isNotNull(extraction.documentDate) ? dateObjectToNumericDate(extraction.documentDate) : null;
209
+ const date = isNotNull(extraction.documentDate) ? tryAiOutputDateObjectToNumericDate(extraction.documentDate) : null;
202
210
  const parsedProperties = isUndefined(extraction.documentProperties)
203
211
  ? []
204
212
  : objectEntries(extraction.documentProperties)
@@ -208,8 +216,11 @@ Antworte auf deutsch.`,
208
216
  }
209
217
  const property = assertDefinedPass(properties?.find((property) => property.label == propertyLabel));
210
218
  const value = match(rawValue)
211
- .with({ year: P.number }, (val) => dateObjectToNumericDate(val))
212
- .otherwise((val) => val);
219
+ .with({ year: P.number }, (value) => tryAiOutputDateObjectToNumericDate(value))
220
+ .otherwise((value) => value);
221
+ if (isNull(value)) {
222
+ return null;
223
+ }
213
224
  return { propertyId: property.id, dataType: property.dataType, value };
214
225
  })
215
226
  .filter(isNotNull);
@@ -232,15 +243,18 @@ Antworte auf deutsch.`,
232
243
  await result_2;
233
244
  }
234
245
  }
235
- async findSuitableCollectionsForDocument(documentId, collectionIds) {
236
- const document = await this.#documentRepository.load(documentId);
246
+ async findSuitableCollectionsForDocument(document, collectionIds) {
237
247
  assertNotNull(document.typeId, 'Document has no type');
238
- const documentProperties = await this.#documentPropertyService.loadDocumentProperties(documentId);
239
- const collectionNamesMap = await this.#documentManagementAncillaryService.resolveMetadata(...collectionIds);
248
+ const [documentTags, documentProperties, collectionNamesMap] = await Promise.all([
249
+ this.#documentTagService.loadDocumentTags(document.tenantId, document.id),
250
+ this.#documentPropertyService.loadDocumentPropertyValues(document.tenantId, document.id),
251
+ this.#documentCollectionService.resolveMetadata(document.tenantId, collectionIds),
252
+ ]);
240
253
  const collections = collectionIds.map((collectionId, index) => ({
241
254
  id: collectionId,
242
255
  ...assertDefinedPass(collectionNamesMap[index]),
243
256
  }));
257
+ const documentTagLabels = documentTags.map((tag) => tag.label);
244
258
  const propertyEntries = documentProperties.map((property) => [property.label, property.value]);
245
259
  const context = {
246
260
  document: {
@@ -248,7 +262,7 @@ Antworte auf deutsch.`,
248
262
  subtitle: document.subtitle ?? undefined,
249
263
  date: isNotNull(document.date) ? numericDateToDateObject(document.date) : undefined,
250
264
  summary: document.summary ?? undefined,
251
- tags: ((document.tags?.length ?? 0) > 0) ? document.tags : undefined,
265
+ tags: (documentTagLabels.length > 0) ? documentTagLabels : undefined,
252
266
  properties: fromEntries(propertyEntries),
253
267
  },
254
268
  collections,
@@ -278,11 +292,11 @@ Ordne das Dokument unter "document" einer oder mehreren passenden Collection unt
278
292
  });
279
293
  return result.json.collectionIds;
280
294
  }
281
- async findSuitableRequestForDocument(documentId, collectionIds) {
295
+ async findSuitableRequestForDocument(document, collectionIds) {
282
296
  const session = this.#documentPropertyRepository.session;
283
- const document = await this.#documentRepository.load(documentId);
284
297
  assertNotNull(document.typeId, 'Document has no type');
285
- const documentProperties = await this.#documentPropertyService.loadDocumentProperties(documentId);
298
+ const documentTags = await this.#documentTagService.loadDocumentTags(document.tenantId, document.id);
299
+ const documentProperties = await this.#documentPropertyService.loadDocumentPropertyValues(document.tenantId, document.id);
286
300
  const openRequestsWithoutDocument = await session
287
301
  .select({
288
302
  id: documentRequest.id,
@@ -295,10 +309,11 @@ Ordne das Dokument unter "document" einer oder mehreren passenden Collection unt
295
309
  .innerJoin(documentRequestCollectionAssignment, eq(documentRequestCollectionAssignment.requestId, documentRequest.id))
296
310
  .innerJoin(documentType, eq(documentType.id, documentRequest.typeId))
297
311
  .innerJoin(documentCategory, eq(documentCategory.id, documentType.categoryId))
298
- .where(and(inArray(documentRequestCollectionAssignment.collectionId, collectionIds), eq(documentRequest.typeId, document.typeId), eq(documentRequest.state, DocumentRequestState.Open), drizzleIsNull(documentRequest.documentId)))
312
+ .where(and(eq(documentRequest.tenantId, document.tenantId), inArray(documentRequestCollectionAssignment.collectionId, collectionIds), eq(documentRequest.typeId, document.typeId), eq(documentRequest.state, DocumentRequestState.Open), drizzleIsNull(documentRequest.documentId)))
299
313
  .groupBy(documentRequest.id, documentCategory.label, documentType.label, documentRequest.comment);
314
+ const documentTagLabels = documentTags.map((tag) => tag.label);
300
315
  const requestsCollectionIds = distinct(openRequestsWithoutDocument.flatMap((request) => request.collectionIds));
301
- const collectionNamesMap = await this.#documentManagementAncillaryService.resolveMetadataMap(...requestsCollectionIds);
316
+ const collectionNamesMap = await this.#documentCollectionService.resolveMetadataMap(document.tenantId, requestsCollectionIds);
302
317
  const requests = openRequestsWithoutDocument.map((request) => ({
303
318
  id: request.id,
304
319
  collections: request.collectionIds.map((collectionId) => assertDefinedPass(collectionNamesMap[collectionId]).name),
@@ -311,7 +326,7 @@ Ordne das Dokument unter "document" einer oder mehreren passenden Collection unt
311
326
  subtitle: document.subtitle ?? undefined,
312
327
  date: isNotNull(document.date) ? numericDateToDateObject(document.date) : undefined,
313
328
  summary: document.summary ?? undefined,
314
- tags: ((document.tags?.length ?? 0) > 0) ? document.tags : undefined,
329
+ tags: (documentTagLabels.length > 0) ? documentTagLabels : undefined,
315
330
  properties: fromEntries(propertyEntries),
316
331
  },
317
332
  requests,
@@ -352,3 +367,11 @@ function getDescriptiveTypeLabels(categories, prefix = 'Category: ') {
352
367
  ...getDescriptiveTypeLabels(category.children, `${prefix}${category.label} -> `),
353
368
  ]);
354
369
  }
370
+ function tryAiOutputDateObjectToNumericDate(dateObject) {
371
+ const date = tryDateObjectToNumericDate(dateObject);
372
+ if (isNull(date)) {
373
+ // try to interpret the date with swapped month and day
374
+ return tryDateObjectToNumericDate({ ...dateObject, month: dateObject.day, day: dateObject.month });
375
+ }
376
+ return date;
377
+ }
@@ -1,28 +1,10 @@
1
- import { DocumentCollection } from '../../models/index.js';
2
- export type DocumentCollectionMetadata = {
3
- /**
4
- * User-friendly name of the collection
5
- * @example <name of person>
6
- * @example <address of real estate>
7
- */
8
- name: string;
9
- /**
10
- * Group of the collection, used to group multiple collections to the same "type"
11
- * @example 'Applicants'
12
- * @example 'Real estates'
13
- */
14
- group: string | null;
15
- };
1
+ import type { DocumentCollectionMetadata } from '../../../document-management/service-models/index.js';
2
+ import type { DocumentCollection } from '../../models/index.js';
16
3
  export declare abstract class DocumentManagementAncillaryService {
17
- #private;
18
- resolveMetadata<const T extends (DocumentCollection | string)[]>(...collectionsOrIds: T): Promise<{
19
- [K in keyof T]: DocumentCollectionMetadata;
20
- }>;
21
- resolveMetadataMap(...collectionsOrIds: (DocumentCollection | string)[]): Promise<Record<string, DocumentCollectionMetadata>>;
22
4
  /**
23
5
  * Resolves application-specific metadata for a list of document collections.
24
6
  * @param collections An array of DocumentCollection entities.
25
7
  * @returns A promise that resolves to an array of DocumentCollectionMetadata, corresponding to the input collections.
26
8
  */
27
- abstract _resolveMetadata(collections: DocumentCollection[]): DocumentCollectionMetadata[] | Promise<DocumentCollectionMetadata[]>;
9
+ abstract resolveMetadata(collections: DocumentCollection[]): DocumentCollectionMetadata[] | Promise<DocumentCollectionMetadata[]>;
28
10
  }
@@ -1,26 +1,2 @@
1
- import { injectRepository } from '../../../orm/server/index.js';
2
- import { fromEntries } from '../../../utils/object/index.js';
3
- import { assertDefinedPass, isString } from '../../../utils/type-guards.js';
4
- import { DocumentCollection } from '../../models/index.js';
5
1
  export class DocumentManagementAncillaryService {
6
- #documentCollectionRepository = injectRepository(DocumentCollection);
7
- async resolveMetadata(...collectionsOrIds) {
8
- if (collectionsOrIds.length == 0) {
9
- return [];
10
- }
11
- const loadIds = collectionsOrIds.filter((collection) => isString(collection));
12
- if (loadIds.length == 0) {
13
- return this._resolveMetadata(collectionsOrIds);
14
- }
15
- const loadedCollections = await this.#documentCollectionRepository.loadManyByQuery({ id: { $in: loadIds } });
16
- const collections = collectionsOrIds.map((collectionOrId) => isString(collectionOrId)
17
- ? assertDefinedPass(loadedCollections.find((collection) => collection.id == collectionOrId), `Could not load collection "${collectionOrId}".`)
18
- : collectionOrId);
19
- return this._resolveMetadata(collections);
20
- }
21
- async resolveMetadataMap(...collectionsOrIds) {
22
- const names = await this.resolveMetadata(...collectionsOrIds);
23
- const entries = collectionsOrIds.map((collectionOrId, index) => [isString(collectionOrId) ? collectionOrId : collectionOrId.id, names[index]]);
24
- return fromEntries(entries);
25
- }
26
2
  }
@@ -0,0 +1,15 @@
1
+ import { afterResolve } from '../../../injector/interfaces.js';
2
+ import { MessageBus } from '../../../message-bus/message-bus.js';
3
+ import { Database, type PgTransaction, type Transaction } from '../../../orm/server/index.js';
4
+ import type { OneOrMany } from '../../../types.js';
5
+ export declare class DocumentManagementObservationService {
6
+ #private;
7
+ readonly collectionsChangedMessageBus: MessageBus<string[]>;
8
+ [afterResolve](): void;
9
+ collectionChange(ids: OneOrMany<string>, transactionOrSession?: Transaction | Database | PgTransaction): void;
10
+ documentChange(ids: OneOrMany<string>, transactionOrSession?: Transaction | Database | PgTransaction): void;
11
+ workflowChange(ids: OneOrMany<string>, transactionOrSession?: Transaction | Database | PgTransaction): void;
12
+ requestChange(ids: OneOrMany<string>, transactionOrSession?: Transaction | Database | PgTransaction): void;
13
+ private notifyLoop;
14
+ private notify;
15
+ }
@@ -0,0 +1,160 @@
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
+ var _a;
8
+ var DocumentManagementObservationService_1;
9
+ import { eq, inArray } from 'drizzle-orm';
10
+ import { union } from 'drizzle-orm/pg-core';
11
+ import { CancellationSignal } from '../../../cancellation/token.js';
12
+ import { inject } from '../../../injector/inject.js';
13
+ import { afterResolve } from '../../../injector/interfaces.js';
14
+ import { Logger } from '../../../logger/logger.js';
15
+ import { MessageBus } from '../../../message-bus/message-bus.js';
16
+ import { Database, tryGetTstdlTransaction } from '../../../orm/server/index.js';
17
+ import { toArray } from '../../../utils/array/index.js';
18
+ import { cancelableTimeout } from '../../../utils/timing.js';
19
+ import { isDefined } from '../../../utils/type-guards.js';
20
+ import { documentAssignmentScope, documentAssignmentTask, documentCollectionAssignment, documentRequestCollectionAssignment, documentWorkflow } from '../schemas.js';
21
+ import { DocumentManagementSingleton } from './singleton.js';
22
+ let DocumentManagementObservationService = DocumentManagementObservationService_1 = class DocumentManagementObservationService {
23
+ #database = inject(Database);
24
+ #cancellationSignal = inject(CancellationSignal);
25
+ #logger = inject(Logger, DocumentManagementObservationService_1.name);
26
+ #collectionIds = new Set();
27
+ #documentIds = new Set();
28
+ #workflowIds = new Set();
29
+ #requestIds = new Set();
30
+ collectionsChangedMessageBus = inject((MessageBus), 'DocumentManagementObservation:collectionsChanged');
31
+ [afterResolve]() {
32
+ this.notifyLoop();
33
+ }
34
+ collectionChange(ids, transactionOrSession) {
35
+ const transaction = tryGetTstdlTransaction(transactionOrSession);
36
+ if (isDefined(transaction)) {
37
+ transaction.afterCommit$.subscribe(() => this.collectionChange(ids));
38
+ }
39
+ else {
40
+ for (const id of toArray(ids)) {
41
+ this.#collectionIds.add(id);
42
+ }
43
+ }
44
+ }
45
+ documentChange(ids, transactionOrSession) {
46
+ const transaction = tryGetTstdlTransaction(transactionOrSession);
47
+ if (isDefined(transaction)) {
48
+ transaction.afterCommit$.subscribe(() => this.documentChange(ids));
49
+ }
50
+ else {
51
+ for (const id of toArray(ids)) {
52
+ this.#documentIds.add(id);
53
+ }
54
+ }
55
+ }
56
+ workflowChange(ids, transactionOrSession) {
57
+ const transaction = tryGetTstdlTransaction(transactionOrSession);
58
+ if (isDefined(transaction)) {
59
+ transaction.afterCommit$.subscribe(() => this.workflowChange(ids));
60
+ }
61
+ else {
62
+ for (const id of toArray(ids)) {
63
+ this.#workflowIds.add(id);
64
+ }
65
+ }
66
+ }
67
+ requestChange(ids, transactionOrSession) {
68
+ const transaction = tryGetTstdlTransaction(transactionOrSession);
69
+ if (isDefined(transaction)) {
70
+ transaction.afterCommit$.subscribe(() => this.requestChange(ids));
71
+ }
72
+ else {
73
+ for (const id of toArray(ids)) {
74
+ this.#requestIds.add(id);
75
+ }
76
+ }
77
+ }
78
+ notifyLoop() {
79
+ void (async () => {
80
+ while (this.#cancellationSignal.isUnset) {
81
+ try {
82
+ if ((this.#collectionIds.size + this.#documentIds.size + this.#workflowIds.size + this.#requestIds.size) > 0) {
83
+ const timeoutResult = await cancelableTimeout(50, this.#cancellationSignal);
84
+ if (timeoutResult == 'canceled') {
85
+ break;
86
+ }
87
+ await this.notify();
88
+ }
89
+ }
90
+ catch (error) {
91
+ this.#logger.error(error);
92
+ await cancelableTimeout(2500, this.#cancellationSignal);
93
+ }
94
+ finally {
95
+ await cancelableTimeout(100, this.#cancellationSignal);
96
+ }
97
+ }
98
+ })();
99
+ }
100
+ async notify() {
101
+ const collectionIds = Array.from(this.#collectionIds);
102
+ const documentIds = Array.from(this.#documentIds);
103
+ const workflowIds = Array.from(this.#workflowIds);
104
+ const requestIds = Array.from(this.#requestIds);
105
+ this.#collectionIds.clear();
106
+ this.#documentIds.clear();
107
+ this.#workflowIds.clear();
108
+ this.#requestIds.clear();
109
+ try {
110
+ const documentCollectionIds = this.#database
111
+ .selectDistinct({ collectionId: documentCollectionAssignment.collectionId })
112
+ .from(documentCollectionAssignment)
113
+ .where(inArray(documentCollectionAssignment.documentId, documentIds));
114
+ const documentAssignmentTaskCollectionIds = this.#database
115
+ .selectDistinct({ collectionId: documentAssignmentScope.collectionId })
116
+ .from(documentAssignmentTask)
117
+ .innerJoin(documentAssignmentScope, eq(documentAssignmentScope.taskId, documentAssignmentTask.id))
118
+ .where(inArray(documentAssignmentTask.documentId, documentIds));
119
+ const workflowDocumentCollectionIds = this.#database
120
+ .selectDistinct({ collectionId: documentCollectionAssignment.collectionId })
121
+ .from(documentWorkflow)
122
+ .innerJoin(documentCollectionAssignment, eq(documentCollectionAssignment.documentId, documentWorkflow.documentId))
123
+ .where(inArray(documentWorkflow.id, workflowIds));
124
+ const workflowDocumentAssignmentTaskCollectionIds = this.#database
125
+ .selectDistinct({ collectionId: documentAssignmentScope.collectionId })
126
+ .from(documentWorkflow)
127
+ .innerJoin(documentAssignmentTask, eq(documentAssignmentTask.documentId, documentWorkflow.documentId))
128
+ .innerJoin(documentAssignmentScope, eq(documentAssignmentScope.taskId, documentAssignmentTask.id))
129
+ .where(inArray(documentWorkflow.id, workflowIds));
130
+ const requestCollectionIds = this.#database
131
+ .selectDistinct({ collectionId: documentRequestCollectionAssignment.collectionId })
132
+ .from(documentRequestCollectionAssignment)
133
+ .where(inArray(documentRequestCollectionAssignment.requestId, requestIds));
134
+ const result = await union(documentCollectionIds, documentAssignmentTaskCollectionIds, workflowDocumentCollectionIds, workflowDocumentAssignmentTaskCollectionIds, requestCollectionIds);
135
+ const allCollectionIds = result.map((row) => row.collectionId);
136
+ if (allCollectionIds.length > 0) {
137
+ await this.collectionsChangedMessageBus.publish(allCollectionIds);
138
+ }
139
+ }
140
+ catch (error) {
141
+ for (const collectionId of collectionIds) {
142
+ this.#collectionIds.add(collectionId);
143
+ }
144
+ for (const documentId of documentIds) {
145
+ this.#documentIds.add(documentId);
146
+ }
147
+ for (const workflowId of workflowIds) {
148
+ this.#workflowIds.add(workflowId);
149
+ }
150
+ for (const requestId of requestIds) {
151
+ this.#requestIds.add(requestId);
152
+ }
153
+ throw error;
154
+ }
155
+ }
156
+ };
157
+ DocumentManagementObservationService = DocumentManagementObservationService_1 = __decorate([
158
+ DocumentManagementSingleton()
159
+ ], DocumentManagementObservationService);
160
+ export { DocumentManagementObservationService };
@@ -1,3 +1,4 @@
1
+ import type { CancellationSignal } from '../../../cancellation/token.js';
1
2
  import { Transactional } from '../../../orm/server/index.js';
2
3
  import type { Record } from '../../../types.js';
3
4
  import { DocumentCategory, DocumentType, type DocumentProperty, type DocumentPropertyDataType } from '../../models/index.js';
@@ -9,11 +10,11 @@ export declare class DocumentManagementService extends Transactional {
9
10
  * This method is used to determine which collections a document is associated with, either directly or through requests and assignments.
10
11
  * @param documentId The ID of the document to retrieve collection IDs for.
11
12
  */
12
- getRelevantDocumentCollectionIds(documentId: string): Promise<string[]>;
13
- loadDataStream(collectionIds: string[]): ReadableStream<DocumentManagementData>;
14
- loadData(collectionIds: string[]): Promise<DocumentManagementData>;
15
- loadDocumentRequestsTemplateData(): Promise<DocumentRequestsTemplateData>;
16
- initializeCategoriesAndTypes<CategoryKey extends string, TypeKey extends string, DocumentPropertyKey extends string>(categoryLabels: Record<CategoryKey, string>, categoryParents: Record<CategoryKey, CategoryKey | null>, typeLabels: Record<TypeKey, string>, typeCategories: Record<TypeKey, CategoryKey>, propertyKeys: Record<DocumentPropertyKey, [DocumentPropertyDataType, string]>, typeProperties: Record<TypeKey, DocumentPropertyKey[]>): Promise<{
13
+ getRelevantDocumentCollectionIds(tenantId: string, documentId: string): Promise<string[]>;
14
+ loadDataStream(tenantId: string, collectionIds: string[], cancellationSignal: CancellationSignal): AsyncIterableIterator<DocumentManagementData>;
15
+ loadData(tenantId: string, collectionIds: string[]): Promise<DocumentManagementData>;
16
+ loadDocumentRequestsTemplateData(tenantId: string | null): Promise<DocumentRequestsTemplateData>;
17
+ initializeCategoriesAndTypes<CategoryKey extends string, TypeKey extends string, DocumentPropertyKey extends string>(tenantId: string | null, categoryLabels: Record<CategoryKey, string>, categoryParents: Record<CategoryKey, CategoryKey | null>, typeLabels: Record<TypeKey, string>, typeCategories: Record<TypeKey, CategoryKey>, propertyKeys: Record<DocumentPropertyKey, [DocumentPropertyDataType, string]>, typeProperties: Record<TypeKey, DocumentPropertyKey[]>): Promise<{
17
18
  categories: Record<CategoryKey, DocumentCategory>;
18
19
  types: Record<TypeKey, DocumentType>;
19
20
  properties: Record<DocumentPropertyKey, DocumentProperty>;