@tstdl/base 0.92.135 → 0.92.137

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 (34) hide show
  1. package/document-management/api/document-management.api.d.ts +16 -4
  2. package/document-management/api/document-management.api.js +4 -1
  3. package/document-management/models/document.model.d.ts +4 -1
  4. package/document-management/models/document.model.js +20 -7
  5. package/document-management/models/index.d.ts +0 -1
  6. package/document-management/models/index.js +0 -1
  7. package/document-management/server/api/document-management.api.js +3 -3
  8. package/document-management/server/module.d.ts +1 -0
  9. package/document-management/server/module.js +1 -0
  10. package/document-management/server/schemas.d.ts +1 -2
  11. package/document-management/server/schemas.js +1 -2
  12. package/document-management/server/services/document-file.service.d.ts +12 -8
  13. package/document-management/server/services/document-file.service.js +47 -49
  14. package/document-management/server/services/document-management-ai.service.js +9 -10
  15. package/document-management/server/services/document-management.service.js +2 -8
  16. package/document-management/server/services/document.service.js +22 -13
  17. package/document-management/service-models/document-management.view-model.d.ts +1 -2
  18. package/document-management/service-models/document-management.view-model.js +1 -6
  19. package/document-management/service-models/document.service-model.d.ts +5 -2
  20. package/document-management/service-models/document.service-model.js +2 -2
  21. package/document-management/service-models/enriched/enriched-document-management-data.view.d.ts +0 -1
  22. package/document-management/service-models/enriched/enriched-document-management-data.view.js +0 -1
  23. package/document-management/service-models/enriched/enriched-document.view.d.ts +5 -3
  24. package/document-management/service-models/enriched/enriched-document.view.js +8 -10
  25. package/document-management/service-models/enriched/index.d.ts +0 -1
  26. package/document-management/service-models/enriched/index.js +0 -1
  27. package/object-storage/object-storage.d.ts +2 -0
  28. package/orm/sqls.d.ts +2 -6
  29. package/orm/sqls.js +9 -0
  30. package/package.json +2 -2
  31. package/document-management/models/document-file.model.d.ts +0 -7
  32. package/document-management/models/document-file.model.js +0 -38
  33. package/document-management/service-models/enriched/enriched-document-file.view.d.ts +0 -12
  34. package/document-management/service-models/enriched/enriched-document-file.view.js +0 -16
@@ -74,6 +74,9 @@ export declare const documentManagementApiDefinition: {
74
74
  initiateDocumentUpload: {
75
75
  resource: string;
76
76
  method: "POST";
77
+ parameters: import("../../schema/index.js").ObjectSchema<{
78
+ contentLength: number;
79
+ }>;
77
80
  result: import("../../schema/index.js").ObjectSchema<{
78
81
  uploadId: string;
79
82
  uploadUrl: string;
@@ -92,7 +95,7 @@ export declare const documentManagementApiDefinition: {
92
95
  tags?: string[] | null | undefined;
93
96
  comment?: string | null | undefined;
94
97
  approval?: import("../models/document.model.js").DocumentApproval | undefined;
95
- originalFileName: string | null;
98
+ originalFileName?: string | null | undefined;
96
99
  assignment: {
97
100
  collections: string | string[];
98
101
  } | {
@@ -282,15 +285,18 @@ export declare const documentManagementApiDefinition: {
282
285
  parameters: import("../../schema/index.js").ObjectSchema<{
283
286
  id: import("../../orm/types.js").IsPrimaryKey<import("../../orm/types.js").HasDefault<import("../../orm/schemas/uuid.js").Uuid>>;
284
287
  date?: import("../../orm/types.js").NumericDate | null | undefined;
288
+ size?: number | undefined;
289
+ hash?: string | undefined;
285
290
  summary?: string | null | undefined;
286
291
  title?: string | null | undefined;
292
+ mimeType?: string | undefined;
287
293
  typeId?: import("../../orm/types.js").Uuid | null | undefined;
288
294
  subtitle?: string | null | undefined;
289
295
  tags?: string[] | null | undefined;
290
296
  comment?: string | null | undefined;
291
- fileId?: import("../../orm/types.js").Uuid | undefined;
292
297
  pages?: number | null | undefined;
293
298
  approval?: import("../models/document.model.js").DocumentApproval | undefined;
299
+ originalFileName?: string | null | undefined;
294
300
  createUserId?: import("../../orm/types.js").Uuid | null | undefined;
295
301
  properties?: {
296
302
  propertyId: import("../../orm/schemas/uuid.js").Uuid;
@@ -381,6 +387,9 @@ declare const _DocumentManagementApi: import("../../api/client/index.js").ApiCli
381
387
  initiateDocumentUpload: {
382
388
  resource: string;
383
389
  method: "POST";
390
+ parameters: import("../../schema/index.js").ObjectSchema<{
391
+ contentLength: number;
392
+ }>;
384
393
  result: import("../../schema/index.js").ObjectSchema<{
385
394
  uploadId: string;
386
395
  uploadUrl: string;
@@ -399,7 +408,7 @@ declare const _DocumentManagementApi: import("../../api/client/index.js").ApiCli
399
408
  tags?: string[] | null | undefined;
400
409
  comment?: string | null | undefined;
401
410
  approval?: import("../models/document.model.js").DocumentApproval | undefined;
402
- originalFileName: string | null;
411
+ originalFileName?: string | null | undefined;
403
412
  assignment: {
404
413
  collections: string | string[];
405
414
  } | {
@@ -589,15 +598,18 @@ declare const _DocumentManagementApi: import("../../api/client/index.js").ApiCli
589
598
  parameters: import("../../schema/index.js").ObjectSchema<{
590
599
  id: import("../../orm/types.js").IsPrimaryKey<import("../../orm/types.js").HasDefault<import("../../orm/schemas/uuid.js").Uuid>>;
591
600
  date?: import("../../orm/types.js").NumericDate | null | undefined;
601
+ size?: number | undefined;
602
+ hash?: string | undefined;
592
603
  summary?: string | null | undefined;
593
604
  title?: string | null | undefined;
605
+ mimeType?: string | undefined;
594
606
  typeId?: import("../../orm/types.js").Uuid | null | undefined;
595
607
  subtitle?: string | null | undefined;
596
608
  tags?: string[] | null | undefined;
597
609
  comment?: string | null | undefined;
598
- fileId?: import("../../orm/types.js").Uuid | undefined;
599
610
  pages?: number | null | undefined;
600
611
  approval?: import("../models/document.model.js").DocumentApproval | undefined;
612
+ originalFileName?: string | null | undefined;
601
613
  createUserId?: import("../../orm/types.js").Uuid | null | undefined;
602
614
  properties?: {
603
615
  propertyId: import("../../orm/schemas/uuid.js").Uuid;
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { compileClient } from '../../api/client/index.js';
8
8
  import { defineApi } from '../../api/index.js';
9
9
  import { ReplaceClass } from '../../injector/decorators.js';
10
- import { array, boolean, literal, object, optional, string } from '../../schema/index.js';
10
+ import { array, boolean, literal, number, object, optional, string } from '../../schema/index.js';
11
11
  import { Document, DocumentCategory, DocumentRequest, DocumentRequestsTemplate, DocumentRequestTemplate, DocumentType } from '../models/index.js';
12
12
  import { addOrArchiveDocumentToOrFromCollectionParametersSchema, applyDocumentRequestsTemplateParametersSchema, createDocumentCategoryParametersSchema, createDocumentParametersSchema, createDocumentRequestParametersSchema, createDocumentRequestsTemplateParametersSchema, createDocumentRequestTemplateParametersSchema, createDocumentTypeParametersSchema, deleteDocumentRequestParametersSchema, deleteDocumentRequestsTemplateParametersSchema, deleteDocumentRequestTemplateParametersSchema, DocumentCategoryView, DocumentManagementData, DocumentRequestsTemplateData, loadDataParametersSchema, updateDocumentParametersSchema, updateDocumentRequestParametersSchema, updateDocumentRequestsTemplateParametersSchema, updateDocumentRequestTemplateParametersSchema } from '../service-models/index.js';
13
13
  export const documentManagementApiDefinition = defineApi({
@@ -69,6 +69,9 @@ export const documentManagementApiDefinition = defineApi({
69
69
  initiateDocumentUpload: {
70
70
  resource: 'document-uploads',
71
71
  method: 'POST',
72
+ parameters: object({
73
+ contentLength: number(),
74
+ }),
72
75
  result: object({
73
76
  uploadId: string(),
74
77
  uploadUrl: string(),
@@ -10,7 +10,6 @@ export type DocumentApproval = EnumType<typeof DocumentApproval>;
10
10
  export type UpdatableDocumentProperties = keyof Pick<Document, 'typeId' | 'title' | 'subtitle' | 'date' | 'summary' | 'tags' | 'comment'>;
11
11
  export declare class Document extends Entity {
12
12
  static readonly entityName: 'Document';
13
- fileId: Uuid;
14
13
  typeId: Uuid | null;
15
14
  title: string | null;
16
15
  subtitle: string | null;
@@ -20,5 +19,9 @@ export declare class Document extends Entity {
20
19
  tags: string[] | null;
21
20
  approval: DocumentApproval;
22
21
  comment: string | null;
22
+ originalFileName: string | null;
23
+ mimeType: string;
24
+ hash: string;
25
+ size: number;
23
26
  createUserId: Uuid | null;
24
27
  }
@@ -12,7 +12,6 @@ import { References } from '../../orm/decorators.js';
12
12
  import { Entity } from '../../orm/entity.js';
13
13
  import { NumericDate, Uuid } from '../../orm/types.js';
14
14
  import { Array, Enumeration, Integer, string, StringProperty } from '../../schema/index.js';
15
- import { DocumentFile } from './document-file.model.js';
16
15
  import { DocumentManagementTable } from './document-management-table.js';
17
16
  import { DocumentType } from './document-type.model.js';
18
17
  export const DocumentApproval = defineEnum('DocumentApproval', {
@@ -21,7 +20,6 @@ export const DocumentApproval = defineEnum('DocumentApproval', {
21
20
  Rejected: 'rejected',
22
21
  });
23
22
  let Document = class Document extends Entity {
24
- fileId;
25
23
  typeId;
26
24
  title;
27
25
  subtitle;
@@ -31,13 +29,12 @@ let Document = class Document extends Entity {
31
29
  tags;
32
30
  approval;
33
31
  comment;
32
+ originalFileName;
33
+ mimeType;
34
+ hash;
35
+ size;
34
36
  createUserId;
35
37
  };
36
- __decorate([
37
- Uuid(),
38
- References(() => DocumentFile),
39
- __metadata("design:type", String)
40
- ], Document.prototype, "fileId", void 0);
41
38
  __decorate([
42
39
  Uuid({ nullable: true }),
43
40
  References(() => DocumentType),
@@ -75,6 +72,22 @@ __decorate([
75
72
  StringProperty({ nullable: true }),
76
73
  __metadata("design:type", Object)
77
74
  ], Document.prototype, "comment", void 0);
75
+ __decorate([
76
+ StringProperty({ nullable: true }),
77
+ __metadata("design:type", Object)
78
+ ], Document.prototype, "originalFileName", void 0);
79
+ __decorate([
80
+ StringProperty(),
81
+ __metadata("design:type", String)
82
+ ], Document.prototype, "mimeType", void 0);
83
+ __decorate([
84
+ StringProperty(),
85
+ __metadata("design:type", String)
86
+ ], Document.prototype, "hash", void 0);
87
+ __decorate([
88
+ Integer(),
89
+ __metadata("design:type", Number)
90
+ ], Document.prototype, "size", void 0);
78
91
  __decorate([
79
92
  Uuid({ nullable: true }),
80
93
  __metadata("design:type", Object)
@@ -3,7 +3,6 @@ export * from './document-assignment-task.model.js';
3
3
  export * from './document-category.model.js';
4
4
  export * from './document-collection-assignment.model.js';
5
5
  export * from './document-collection.model.js';
6
- export * from './document-file.model.js';
7
6
  export * from './document-management-table.js';
8
7
  export * from './document-property-value.model.js';
9
8
  export * from './document-property.model.js';
@@ -3,7 +3,6 @@ export * from './document-assignment-task.model.js';
3
3
  export * from './document-category.model.js';
4
4
  export * from './document-collection-assignment.model.js';
5
5
  export * from './document-collection.model.js';
6
- export * from './document-file.model.js';
7
6
  export * from './document-management-table.js';
8
7
  export * from './document-property-value.model.js';
9
8
  export * from './document-property.model.js';
@@ -58,7 +58,7 @@ let DocumentManagementApiController = DocumentManagementApiController_1 = class
58
58
  const token = await context.getToken();
59
59
  const allowed = await this.#documentManagementAncillaryService.canReadDocument(context.parameters.id, token);
60
60
  if (!allowed) {
61
- throw new ForbiddenError(`You are not allowed to load content for file ${context.parameters.id}.`);
61
+ throw new ForbiddenError(`You are not allowed to load content for document ${context.parameters.id}.`);
62
62
  }
63
63
  const url = await this.#documentService.getContentUrl(context.parameters.id, context.parameters.download);
64
64
  return HttpServerResponse.fromObject({
@@ -72,7 +72,7 @@ let DocumentManagementApiController = DocumentManagementApiController_1 = class
72
72
  const token = await context.getToken();
73
73
  const allowed = await this.#documentManagementAncillaryService.canReadDocument(context.parameters.id, token);
74
74
  if (!allowed) {
75
- throw new ForbiddenError(`You are not allowed to get content URL for file ${context.parameters.id}.`);
75
+ throw new ForbiddenError(`You are not allowed to get content URL for document ${context.parameters.id}.`);
76
76
  }
77
77
  return await this.#documentService.getContentUrl(context.parameters.id, context.parameters.download);
78
78
  }
@@ -95,7 +95,7 @@ let DocumentManagementApiController = DocumentManagementApiController_1 = class
95
95
  async initiateDocumentUpload(context) {
96
96
  const token = await context.getToken();
97
97
  const subject = await this.#ancillaryService.getSubject(token);
98
- return await this.#documentFileService.initiateUpload({ key: subject });
98
+ return await this.#documentFileService.initiateUpload({ key: subject, contentLength: context.parameters.contentLength });
99
99
  }
100
100
  async createDocument(context) {
101
101
  const token = await context.getToken();
@@ -8,6 +8,7 @@ export declare class DocumentManagementConfig {
8
8
  fileUploadObjectStorageModule: string;
9
9
  filePreviewObjectStorageModule: string;
10
10
  database?: DatabaseConfig;
11
+ maxFileSize?: number;
11
12
  }
12
13
  export declare function configureDocumentManagement(config: DocumentManagementConfig): void;
13
14
  export declare function migrateDocumentManagementSchema(): Promise<void>;
@@ -8,6 +8,7 @@ export class DocumentManagementConfig {
8
8
  fileUploadObjectStorageModule;
9
9
  filePreviewObjectStorageModule;
10
10
  database;
11
+ maxFileSize;
11
12
  }
12
13
  ;
13
14
  export function configureDocumentManagement(config) {
@@ -1,4 +1,4 @@
1
- import { Document, DocumentAssignmentScope, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentFile, DocumentProperty, DocumentPropertyValue, DocumentRequest, DocumentRequestCollectionAssignment, DocumentRequestsTemplate, DocumentRequestSubmission, DocumentRequestTemplate, DocumentType, DocumentTypeProperty, DocumentTypeValidation, DocumentValidationDefinition, DocumentValidationExecution, DocumentValidationExecutionRelatedDocument, DocumentWorkflow } from '../models/index.js';
1
+ import { Document, DocumentAssignmentScope, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentProperty, DocumentPropertyValue, DocumentRequest, DocumentRequestCollectionAssignment, DocumentRequestsTemplate, DocumentRequestSubmission, DocumentRequestTemplate, DocumentType, DocumentTypeProperty, DocumentTypeValidation, DocumentValidationDefinition, DocumentValidationExecution, DocumentValidationExecutionRelatedDocument, DocumentWorkflow } from '../models/index.js';
2
2
  export declare const documentManagementSchema: import("../../orm/server/database-schema.js").DatabaseSchema<"document_management">;
3
3
  export declare const aocumentApproval: import("drizzle-orm/pg-core").PgEnum<["pending", "approved", "rejected"]>;
4
4
  export declare const documentAssignmentCollectionTarget: import("drizzle-orm/pg-core").PgEnum<["request", "collection"]>;
@@ -15,7 +15,6 @@ export declare const documentAssignmentTask: import("../../orm/server/types.js")
15
15
  export declare const documentCategory: import("../../orm/server/types.js").PgTableFromType<typeof DocumentCategory, "document_management">;
16
16
  export declare const documentCollection: import("../../orm/server/types.js").PgTableFromType<typeof DocumentCollection, "document_management">;
17
17
  export declare const documentCollectionAssignment: import("../../orm/server/types.js").PgTableFromType<typeof DocumentCollectionAssignment, "document_management">;
18
- export declare const documentFile: import("../../orm/server/types.js").PgTableFromType<typeof DocumentFile, "document_management">;
19
18
  export declare const documentProperty: import("../../orm/server/types.js").PgTableFromType<typeof DocumentProperty, "document_management">;
20
19
  export declare const documentPropertyValue: import("../../orm/server/types.js").PgTableFromType<typeof DocumentPropertyValue, "document_management">;
21
20
  export declare const documentRequest: import("../../orm/server/types.js").PgTableFromType<typeof DocumentRequest, "document_management">;
@@ -1,5 +1,5 @@
1
1
  import { databaseSchema } from '../../orm/server/database-schema.js';
2
- import { Document, DocumentApproval, DocumentAssignmentScope, DocumentAssignmentTarget, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentFile, DocumentProperty, DocumentPropertyDataType, DocumentPropertyValue, DocumentRequest, DocumentRequestCollectionAssignment, DocumentRequestState, DocumentRequestsTemplate, DocumentRequestSubmission, DocumentRequestTemplate, DocumentType, DocumentTypeProperty, DocumentTypeValidation, DocumentValidationDefinition, DocumentValidationExecution, DocumentValidationExecutionRelatedDocument, DocumentValidationExecutionState, DocumentValidationResultStatus, DocumentWorkflow, DocumentWorkflowFailReason, DocumentWorkflowState, DocumentWorkflowStep } from '../models/index.js';
2
+ import { Document, DocumentApproval, DocumentAssignmentScope, DocumentAssignmentTarget, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentProperty, DocumentPropertyDataType, DocumentPropertyValue, DocumentRequest, DocumentRequestCollectionAssignment, DocumentRequestState, DocumentRequestsTemplate, DocumentRequestSubmission, DocumentRequestTemplate, DocumentType, DocumentTypeProperty, DocumentTypeValidation, DocumentValidationDefinition, DocumentValidationExecution, DocumentValidationExecutionRelatedDocument, DocumentValidationExecutionState, DocumentValidationResultStatus, DocumentWorkflow, DocumentWorkflowFailReason, DocumentWorkflowState, DocumentWorkflowStep } from '../models/index.js';
3
3
  export const documentManagementSchema = databaseSchema('document_management');
4
4
  export const aocumentApproval = documentManagementSchema.getEnum(DocumentApproval);
5
5
  export const documentAssignmentCollectionTarget = documentManagementSchema.getEnum(DocumentAssignmentTarget);
@@ -16,7 +16,6 @@ export const documentAssignmentTask = documentManagementSchema.getTable(Document
16
16
  export const documentCategory = documentManagementSchema.getTable(DocumentCategory);
17
17
  export const documentCollection = documentManagementSchema.getTable(DocumentCollection);
18
18
  export const documentCollectionAssignment = documentManagementSchema.getTable(DocumentCollectionAssignment);
19
- export const documentFile = documentManagementSchema.getTable(DocumentFile);
20
19
  export const documentProperty = documentManagementSchema.getTable(DocumentProperty);
21
20
  export const documentPropertyValue = documentManagementSchema.getTable(DocumentPropertyValue);
22
21
  export const documentRequest = documentManagementSchema.getTable(DocumentRequest);
@@ -1,29 +1,33 @@
1
1
  import type { FileContentPart } from '../../../ai/types.js';
2
2
  import { Transactional } from '../../../orm/server/index.js';
3
- import { DocumentFile } from '../../models/index.js';
3
+ export type DocumentFileMetadata = {
4
+ mimeType: string;
5
+ size: number;
6
+ hash: string;
7
+ };
4
8
  export declare class DocumentFileService extends Transactional {
5
9
  #private;
6
- load(id: string): Promise<DocumentFile>;
7
10
  /**
8
11
  * Initiates a file upload
9
- * @param key - key which can be used to authorize the creation of the file. Same key must be provided to {@link create} method, or it will throw an error.
12
+ * @param key - key which can be used to authorize the creation of the file. Same key must be provided to {@link store} method, or it will throw an error.
10
13
  * The key could be the user id from the request token. This ensures that the file can only be created by the user who initiated the upload.
11
14
  * @returns upload information
12
15
  */
13
- initiateUpload({ key }: {
16
+ initiateUpload({ key, contentLength }: {
14
17
  key: string;
18
+ contentLength: number;
15
19
  }): Promise<{
16
20
  uploadId: string;
17
21
  uploadUrl: string;
18
22
  }>;
19
- create(content: Uint8Array | ReadableStream<Uint8Array>, originalFileName: string | null): Promise<DocumentFile>;
20
- create(content: {
23
+ store(documentId: string, content: Uint8Array | ReadableStream<Uint8Array>): Promise<DocumentFileMetadata>;
24
+ store(documentId: string, content: {
21
25
  uploadId: string;
22
26
  uploadKey: string;
23
- }, originalFileName: string | null): Promise<[DocumentFile, Uint8Array]>;
27
+ }): Promise<[DocumentFileMetadata, Uint8Array]>;
24
28
  getContent(fileId: string): Promise<Uint8Array>;
25
29
  getContentStream(fileId: string): ReadableStream<Uint8Array>;
26
- getContentUrl(fileId: string, title: string | null, download?: boolean): Promise<string>;
30
+ getContentUrl(documentId: string, title: string | null, download?: boolean): Promise<string>;
27
31
  getPreview(fileId: string, page?: number): Promise<Uint8Array>;
28
32
  getPreviewStream(fileId: string, page?: number): ReadableStream<Uint8Array>;
29
33
  getPreviewUrl(fileId: string, page?: number): Promise<string>;
@@ -78,12 +78,11 @@ import { getRandomString } from '../../../utils/random.js';
78
78
  import { readableStreamFromPromise, readBinaryStream } from '../../../utils/stream/index.js';
79
79
  import { isDefined, isNotReadableStream, isNotUint8Array, isUint8Array } from '../../../utils/type-guards.js';
80
80
  import { millisecondsPerMinute, secondsPerMinute } from '../../../utils/units.js';
81
- import { Document, DocumentFile } from '../../models/index.js';
81
+ import { Document } from '../../models/index.js';
82
82
  import { DocumentManagementConfig } from '../module.js';
83
83
  import { DocumentManagementSingleton } from './singleton.js';
84
84
  let DocumentFileService = DocumentFileService_1 = class DocumentFileService extends Transactional {
85
85
  #config = inject(DocumentManagementConfig);
86
- #documentFileRepository = injectRepository(DocumentFile);
87
86
  #documentRepository = injectRepository(Document);
88
87
  #aiService = inject(AiService);
89
88
  #fileObjectStorage = inject(ObjectStorage, this.#config.fileObjectStorageModule);
@@ -91,78 +90,78 @@ let DocumentFileService = DocumentFileService_1 = class DocumentFileService exte
91
90
  #fileUploadObjectStorage = inject(ObjectStorage, { module: this.#config.fileUploadObjectStorageModule, configuration: { lifecycle: { expiration: { after: 5 * secondsPerMinute } } } });
92
91
  #logger = inject(Logger, DocumentFileService_1.name);
93
92
  #aiFilePartCache = new Map();
94
- async load(id) {
95
- return await this.#documentFileRepository.load(id);
96
- }
97
93
  /**
98
94
  * Initiates a file upload
99
- * @param key - key which can be used to authorize the creation of the file. Same key must be provided to {@link create} method, or it will throw an error.
95
+ * @param key - key which can be used to authorize the creation of the file. Same key must be provided to {@link store} method, or it will throw an error.
100
96
  * The key could be the user id from the request token. This ensures that the file can only be created by the user who initiated the upload.
101
97
  * @returns upload information
102
98
  */
103
- async initiateUpload({ key }) {
99
+ async initiateUpload({ key, contentLength }) {
100
+ if (contentLength > (this.#config.maxFileSize ?? Number.POSITIVE_INFINITY)) {
101
+ throw new ForbiddenError(`Content length exceeds the maximum limit of ${this.#config.maxFileSize} bytes.`);
102
+ }
104
103
  const id = getRandomString(64, Alphabet.LowerUpperCaseNumbers);
105
- const url = await this.#fileUploadObjectStorage.getUploadUrl(id, currentTimestamp() + (5 * millisecondsPerMinute), { metadata: { 'upload-key': key } });
104
+ const url = await this.#fileUploadObjectStorage.getUploadUrl(id, currentTimestamp() + (5 * millisecondsPerMinute), { contentLength, metadata: { 'upload-key': key } });
106
105
  return { uploadId: id, uploadUrl: url };
107
106
  }
108
- async create(content, originalFileName) {
107
+ async store(documentId, content) {
109
108
  const isUpload = isNotUint8Array(content) && isNotReadableStream(content);
110
109
  if (isUpload) {
111
110
  const object = await this.#fileUploadObjectStorage.getObject(content.uploadId);
112
111
  const objectMetadata = await object.getMetadata();
112
+ const objectContentLength = await object.getContentLength();
113
113
  if (content.uploadKey != objectMetadata['upload-key']) {
114
114
  throw new ForbiddenError(`Invalid upload key`);
115
115
  }
116
+ if (objectContentLength > (this.#config.maxFileSize ?? Number.POSITIVE_INFINITY)) {
117
+ await this.#fileUploadObjectStorage.deleteObject(object.key);
118
+ throw new ForbiddenError(`Content length exceeds the maximum limit of ${this.#config.maxFileSize} bytes.`);
119
+ }
116
120
  }
117
121
  const contentAsUint8Array = isUpload
118
122
  ? await this.#fileUploadObjectStorage.getContent(content.uploadId)
119
123
  : (isUint8Array(content) ? content : await readBinaryStream(content));
120
124
  const hash = await digest('SHA-256', contentAsUint8Array).toHex();
121
125
  const mimeType = await getMimeType(contentAsUint8Array);
122
- return await this.transaction(async (tx) => {
123
- const documentFile = await this.#documentFileRepository
124
- .withTransaction(tx)
125
- .insert({
126
- originalFileName,
127
- mimeType,
128
- hash,
129
- size: contentAsUint8Array.length,
130
- });
131
- const objectKey = getDocumentFileKey(documentFile.id);
132
- if (isUpload) {
133
- await this.#fileUploadObjectStorage.moveObject(content.uploadId, [this.#fileObjectStorage, objectKey]);
134
- return [documentFile, contentAsUint8Array];
135
- }
136
- await this.#fileObjectStorage.uploadObject(objectKey, contentAsUint8Array, { contentLength: contentAsUint8Array.length, contentType: mimeType });
137
- return documentFile;
138
- });
126
+ const metadata = {
127
+ mimeType,
128
+ size: contentAsUint8Array.length,
129
+ hash,
130
+ };
131
+ const objectKey = getObjectKey(documentId);
132
+ if (isUpload) {
133
+ await this.#fileUploadObjectStorage.moveObject(content.uploadId, [this.#fileObjectStorage, objectKey]);
134
+ return [metadata, contentAsUint8Array];
135
+ }
136
+ await this.#fileObjectStorage.uploadObject(objectKey, contentAsUint8Array, { contentLength: contentAsUint8Array.length, contentType: mimeType });
137
+ return metadata;
139
138
  }
140
139
  async getContent(fileId) {
141
- const objectKey = getDocumentFileKey(fileId);
140
+ const objectKey = getObjectKey(fileId);
142
141
  return await this.#fileObjectStorage.getContent(objectKey);
143
142
  }
144
143
  getContentStream(fileId) {
145
- const objectKey = getDocumentFileKey(fileId);
144
+ const objectKey = getObjectKey(fileId);
146
145
  return this.#fileObjectStorage.getContentStream(objectKey);
147
146
  }
148
- async getContentUrl(fileId, title, download = false) {
149
- const file = await this.#documentFileRepository.load(fileId);
150
- return await this.getDocumentFileContentObjectUrl(title ?? fileId, file, download);
147
+ async getContentUrl(documentId, title, download = false) {
148
+ const document = await this.#documentRepository.load(documentId);
149
+ return await this.getDocumentFileContentObjectUrl(document, title ?? documentId, download);
151
150
  }
152
151
  async getPreview(fileId, page = 1) {
153
- const objectKey = getDocumentFileKey(fileId);
152
+ const objectKey = getObjectKey(fileId);
154
153
  await this.createPreviewIfNotExists(fileId, page);
155
154
  return await this.#filePreviewObjectStorage.getContent(objectKey);
156
155
  }
157
156
  getPreviewStream(fileId, page = 1) {
158
157
  return readableStreamFromPromise(async () => {
159
- const objectKey = getDocumentFileKey(fileId);
158
+ const objectKey = getObjectKey(fileId);
160
159
  await this.createPreviewIfNotExists(fileId, page);
161
160
  return this.#filePreviewObjectStorage.getContentStream(objectKey);
162
161
  });
163
162
  }
164
163
  async getPreviewUrl(fileId, page = 1) {
165
- const objectKey = getDocumentFileKey(fileId);
164
+ const objectKey = getObjectKey(fileId);
166
165
  await this.createPreviewIfNotExists(fileId, page);
167
166
  return await this.#filePreviewObjectStorage.getDownloadUrl(objectKey, currentTimestamp() + (5 * millisecondsPerMinute), {
168
167
  'Response-Content-Type': 'image/jpeg',
@@ -172,18 +171,17 @@ let DocumentFileService = DocumentFileService_1 = class DocumentFileService exte
172
171
  const env_1 = { stack: [], error: void 0, hasError: false };
173
172
  try {
174
173
  const document = await this.#documentRepository.load(documentId);
175
- const cachedAiFilePart = this.#aiFilePartCache.get(document.fileId);
174
+ const cachedAiFilePart = this.#aiFilePartCache.get(document.id);
176
175
  if (isDefined(cachedAiFilePart)) {
177
176
  if (cachedAiFilePart.timestamp > (currentTimestamp() - (5 * millisecondsPerMinute))) {
178
177
  return cachedAiFilePart.part;
179
178
  }
180
- this.#aiFilePartCache.delete(documentId);
179
+ this.#aiFilePartCache.delete(document.id);
181
180
  }
182
- const file = await this.load(document.fileId);
183
181
  const fileContentStream = this.getContentStream(document.id);
184
182
  const tmpFile = __addDisposableResource(env_1, await TemporaryFile.from(fileContentStream), true);
185
- const filePart = await this.#aiService.processFile({ path: tmpFile.path, mimeType: file.mimeType });
186
- this.#aiFilePartCache.set(document.fileId, { part: filePart, timestamp: currentTimestamp() });
183
+ const filePart = await this.#aiService.processFile({ path: tmpFile.path, mimeType: document.mimeType });
184
+ this.#aiFilePartCache.set(document.id, { part: filePart, timestamp: currentTimestamp() });
187
185
  return filePart;
188
186
  }
189
187
  catch (e_1) {
@@ -196,13 +194,13 @@ let DocumentFileService = DocumentFileService_1 = class DocumentFileService exte
196
194
  await result_1;
197
195
  }
198
196
  }
199
- async createPreviewIfNotExists(fileId, page = 1) {
200
- const key = getDocumentFileKey(fileId);
197
+ async createPreviewIfNotExists(documentId, page = 1) {
198
+ const key = getObjectKey(documentId);
201
199
  const hasPreview = await this.#filePreviewObjectStorage.exists(key);
202
200
  if (!hasPreview) {
203
- const file = await this.#documentFileRepository.load(fileId);
201
+ const document = await this.#documentRepository.load(documentId);
204
202
  const content = await this.#fileObjectStorage.getContent(key);
205
- const image = await match(file.mimeType)
203
+ const image = await match(document.mimeType)
206
204
  .with('application/pdf', async () => {
207
205
  const imageBytes = await pdfToImage(content, page, 768, 'jpeg');
208
206
  return await imageToPreview(imageBytes);
@@ -212,13 +210,13 @@ let DocumentFileService = DocumentFileService_1 = class DocumentFileService exte
212
210
  await this.#filePreviewObjectStorage.uploadObject(key, image, { contentLength: image.length, contentType: 'image/jpeg' });
213
211
  }
214
212
  }
215
- async getDocumentFileContentObjectUrl(title, file, download) {
216
- const key = getDocumentFileKey(file.id);
217
- const fileExtension = getMimeTypeExtensions(file.mimeType)[0] ?? 'bin';
213
+ async getDocumentFileContentObjectUrl(document, title, download) {
214
+ const key = getObjectKey(document.id);
215
+ const fileExtension = getMimeTypeExtensions(document.mimeType)[0] ?? 'bin';
218
216
  const disposition = download ? 'attachment' : 'inline';
219
217
  const filename = `${title}.${fileExtension}`;
220
218
  return await this.#fileObjectStorage.getDownloadUrl(key, currentTimestamp() + (5 * millisecondsPerMinute), {
221
- 'Response-Content-Type': file.mimeType,
219
+ 'Response-Content-Type': document.mimeType,
222
220
  'Response-Content-Disposition': `${disposition}; filename = "${encodeURIComponent(filename)}"`,
223
221
  });
224
222
  }
@@ -227,8 +225,8 @@ DocumentFileService = DocumentFileService_1 = __decorate([
227
225
  DocumentManagementSingleton()
228
226
  ], DocumentFileService);
229
227
  export { DocumentFileService };
230
- function getDocumentFileKey(id) {
231
- return `${id.slice(0, 2)}/${id.slice(0, 4)}/${id}`;
228
+ function getObjectKey(documentId) {
229
+ return `${documentId.slice(0, 2)}/${documentId.slice(0, 4)}/${documentId}`;
232
230
  }
233
231
  async function imageToPreview(input) {
234
232
  return await sharp(input)
@@ -78,6 +78,7 @@ import { DocumentFileService } from './document-file.service.js';
78
78
  import { DocumentManagementAncillaryService } from './document-management-ancillary.service.js';
79
79
  import { DocumentPropertyService } from './document-property.service.js';
80
80
  import { DocumentManagementSingleton } from './singleton.js';
81
+ const MODEL = 'gemini-2.5-flash-preview-05-20';
81
82
  let DocumentManagementAiService = DocumentManagementAiService_1 = class DocumentManagementAiService {
82
83
  #documentManagementAncillaryService = inject(DocumentManagementAncillaryService);
83
84
  #documentCategoryTypeService = inject(DocumentCategoryTypeService);
@@ -92,16 +93,15 @@ let DocumentManagementAiService = DocumentManagementAiService_1 = class Document
92
93
  const env_1 = { stack: [], error: void 0, hasError: false };
93
94
  try {
94
95
  const document = await this.#documentRepository.load(documentId);
95
- const file = await this.#documentFileService.load(document.fileId);
96
- const fileContentStream = this.#documentFileService.getContentStream(document.fileId);
96
+ const fileContentStream = this.#documentFileService.getContentStream(document.id);
97
97
  const tmpFile = __addDisposableResource(env_1, await TemporaryFile.from(fileContentStream), true);
98
- const filePart = await this.#aiService.processFile({ path: tmpFile.path, mimeType: file.mimeType });
98
+ const filePart = await this.#aiService.processFile({ path: tmpFile.path, mimeType: document.mimeType });
99
99
  const categories = await this.#documentCategoryTypeService.loadCategoryViews();
100
100
  const typeLabelEntries = getDescriptiveTypeLabels(categories);
101
101
  const typeLabels = typeLabelEntries.map(({ label }) => label);
102
102
  this.#logger.trace(`Classifying document ${document.id}`);
103
103
  const documentTypeGeneration = await this.#aiService.generate({
104
- model: 'gemini-2.5-flash-preview-04-17',
104
+ model: MODEL,
105
105
  generationOptions: {
106
106
  maxOutputTokens: 128,
107
107
  temperature: 0.1,
@@ -140,10 +140,9 @@ let DocumentManagementAiService = DocumentManagementAiService_1 = class Document
140
140
  const env_2 = { stack: [], error: void 0, hasError: false };
141
141
  try {
142
142
  const document = await this.#documentRepository.load(documentId);
143
- const file = await this.#documentFileService.load(document.fileId);
144
- const fileContentStream = this.#documentFileService.getContentStream(document.fileId);
143
+ const fileContentStream = this.#documentFileService.getContentStream(document.id);
145
144
  const tmpFile = __addDisposableResource(env_2, await TemporaryFile.from(fileContentStream), true);
146
- const filePart = await this.#aiService.processFile({ path: tmpFile.path, mimeType: file.mimeType });
145
+ const filePart = await this.#aiService.processFile({ path: tmpFile.path, mimeType: document.mimeType });
147
146
  if (isNull(document.typeId)) {
148
147
  throw new Error(`Document ${document.id} has no type`);
149
148
  }
@@ -172,7 +171,7 @@ let DocumentManagementAiService = DocumentManagementAiService_1 = class Document
172
171
  });
173
172
  this.#logger.trace(`Extracting document ${document.id}`);
174
173
  const { json: extraction } = await this.#aiService.generate({
175
- model: 'gemini-2.5-flash-preview-04-17',
174
+ model: MODEL,
176
175
  generationOptions: {
177
176
  maxOutputTokens: 2048,
178
177
  temperature: 0.2,
@@ -254,7 +253,7 @@ Antworte auf deutsch.`,
254
253
  collections,
255
254
  };
256
255
  const result = await this.#aiService.generate({
257
- model: 'gemini-2.5-flash-preview-04-17',
256
+ model: MODEL,
258
257
  generationOptions: {
259
258
  maxOutputTokens: 100,
260
259
  temperature: 0,
@@ -317,7 +316,7 @@ Ordne das Dokument unter "document" einer oder mehreren passenden Collection unt
317
316
  requests,
318
317
  };
319
318
  const result = await this.#aiService.generate({
320
- model: 'gemini-2.5-flash-preview-04-17',
319
+ model: MODEL,
321
320
  generationOptions: {
322
321
  maxOutputTokens: 100,
323
322
  temperature: 0,
@@ -12,7 +12,7 @@ import { compareByValueSelectionToOrder } from '../../../utils/comparison.js';
12
12
  import { groupToMap, groupToSingleMap } from '../../../utils/iterable-helpers/index.js';
13
13
  import { fromEntries, objectEntries } from '../../../utils/object/index.js';
14
14
  import { assertDefinedPass, isDefined, isNotNull, isNotNullOrUndefined, isNull, isUndefined } from '../../../utils/type-guards.js';
15
- import { DocumentApproval, DocumentAssignmentScope, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentFile, DocumentRequest, DocumentRequestCollectionAssignment, DocumentRequestTemplate, DocumentRequestsTemplate, DocumentType, DocumentValidationExecution, DocumentWorkflowStep } from '../../models/index.js';
15
+ import { DocumentApproval, DocumentAssignmentScope, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentRequest, DocumentRequestCollectionAssignment, DocumentRequestTemplate, DocumentRequestsTemplate, DocumentType, DocumentValidationExecution, DocumentWorkflowStep } from '../../models/index.js';
16
16
  import { DocumentCategoryTypeService, enumTypeKey } from './document-category-type.service.js';
17
17
  import { DocumentManagementAncillaryService } from './document-management-ancillary.service.js';
18
18
  import { DocumentPropertyService } from './document-property.service.js';
@@ -25,7 +25,6 @@ let DocumentManagementService = class DocumentManagementService extends Transact
25
25
  #documentCollectionRepository = injectRepository(DocumentCollection);
26
26
  #documentCategoryRepository = injectRepository(DocumentCategory);
27
27
  #documentCollectionAssignmentRepository = injectRepository(DocumentCollectionAssignment);
28
- #documentFileRepository = injectRepository(DocumentFile);
29
28
  #documentService = inject(DocumentService);
30
29
  #documentPropertyService = inject(DocumentPropertyService);
31
30
  #documentRequestCollectionAssignmentRepository = injectRepository(DocumentRequestCollectionAssignment);
@@ -62,12 +61,8 @@ let DocumentManagementService = class DocumentManagementService extends Transact
62
61
  this.#documentService.withTransaction(tx).repository.loadManyByQuery({ id: { $in: documentIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
63
62
  this.#documentPropertyService.withTransaction(tx).loadDocumentProperties(documentIds),
64
63
  ]);
65
- const documentFileIds = documents.map((document) => document.fileId);
66
64
  const workflowRelevantDocumentIds = documents.map((document) => (document.approval == DocumentApproval.Pending) ? document.id : null).filter(isNotNull);
67
- const [files, currentWorkflows] = await Promise.all([
68
- this.#documentFileRepository.withTransaction(tx).loadManyByQuery({ id: { $in: documentFileIds } }, { order: { 'metadata.createTimestamp': 'desc' } }),
69
- this.#documentWorkflowService.loadLatestWorkflows(workflowRelevantDocumentIds),
70
- ]);
65
+ const currentWorkflows = await this.#documentWorkflowService.loadLatestWorkflows(workflowRelevantDocumentIds);
71
66
  const documentWorkflowMap = groupToSingleMap(currentWorkflows, (workflow) => workflow.documentId);
72
67
  const valuesMap = Enumerable.from(propertyValues).groupToMap((value) => value.documentId);
73
68
  const validationWorkflowIds = currentWorkflows.map((workflow) => (workflow.step == DocumentWorkflowStep.Validation) ? workflow.id : null).filter(isNotNull);
@@ -107,7 +102,6 @@ let DocumentManagementService = class DocumentManagementService extends Transact
107
102
  collections: collectionViews,
108
103
  documents: documentViews,
109
104
  requests: requestViews,
110
- files,
111
105
  categories,
112
106
  types,
113
107
  };
@@ -39,24 +39,33 @@ let DocumentService = DocumentService_1 = class DocumentService extends Transact
39
39
  async create({ typeId, title, subtitle, date, summary, tags, approval, comment, originalFileName, assignment, properties, metadata }, contentSource, { createUserId }) {
40
40
  const document = await this.transaction(async (tx) => {
41
41
  const isUpload = isNotUint8Array(contentSource) && isNotReadableStream(contentSource);
42
- const [documentFile, content] = isUpload
43
- ? await this.#documentFileService.withTransaction(tx).create(contentSource, originalFileName)
44
- : [await this.#documentFileService.withTransaction(tx).create(contentSource, originalFileName), contentSource];
45
- const pages = documentFile.mimeType.includes('pdf') ? await tryIgnoreLogAsync(this.#logger, async () => await getPdfPageCount(content), null) : null;
46
42
  const document = await this.repository.withTransaction(tx).insert({
47
- fileId: documentFile.id,
48
43
  typeId: typeId ?? null,
49
44
  title: title ?? null,
50
45
  subtitle: subtitle ?? null,
51
- pages,
46
+ pages: -1,
52
47
  date: date ?? null,
53
48
  summary: summary ?? null,
54
49
  tags: tags ?? null,
55
50
  approval: approval ?? DocumentApproval.Pending,
56
51
  comment: comment ?? null,
57
52
  createUserId: createUserId ?? null,
53
+ originalFileName: originalFileName ?? null,
54
+ mimeType: 'pending',
55
+ hash: 'pending',
56
+ size: -1,
58
57
  metadata,
59
58
  });
59
+ const [documentMetadata, content] = isUpload
60
+ ? await this.#documentFileService.withTransaction(tx).store(document.id, contentSource)
61
+ : [await this.#documentFileService.withTransaction(tx).store(document.id, contentSource), contentSource];
62
+ const pages = documentMetadata.mimeType.includes('pdf') ? await tryIgnoreLogAsync(this.#logger, async () => await getPdfPageCount(content), null) : null;
63
+ await this.repository.withTransaction(tx).update(document.id, {
64
+ mimeType: documentMetadata.mimeType,
65
+ hash: documentMetadata.hash,
66
+ size: documentMetadata.size,
67
+ pages,
68
+ });
60
69
  if (isDefined(properties)) {
61
70
  await this.#documentPropertyService.withTransaction(tx).setPropertyValues(document.id, properties);
62
71
  }
@@ -83,37 +92,37 @@ let DocumentService = DocumentService_1 = class DocumentService extends Transact
83
92
  }
84
93
  async getContent(documentOrId) {
85
94
  const document = isString(documentOrId) ? await this.repository.load(documentOrId) : documentOrId;
86
- return await this.#documentFileService.getContent(document.fileId);
95
+ return await this.#documentFileService.getContent(document.id);
87
96
  }
88
97
  getContentStream(documentOrId) {
89
98
  return readableStreamFromPromise(async () => {
90
99
  const document = isString(documentOrId) ? await this.repository.load(documentOrId) : documentOrId;
91
- return this.#documentFileService.getContentStream(document.fileId);
100
+ return this.#documentFileService.getContentStream(document.id);
92
101
  });
93
102
  }
94
103
  async getContentUrl(documentOrId, download = false) {
95
104
  const document = isString(documentOrId) ? await this.repository.load(documentOrId) : documentOrId;
96
- return await this.#documentFileService.getContentUrl(document.fileId, document.title, download);
105
+ return await this.#documentFileService.getContentUrl(document.id, document.title, download);
97
106
  }
98
107
  async getPreview(documentOrId, page = 1) {
99
108
  const document = isString(documentOrId) ? await this.repository.load(documentOrId) : documentOrId;
100
- return await this.#documentFileService.getPreview(document.fileId, page);
109
+ return await this.#documentFileService.getPreview(document.id, page);
101
110
  }
102
111
  getPreviewStream(documentOrId, page = 1) {
103
112
  return readableStreamFromPromise(async () => {
104
113
  const document = isString(documentOrId) ? await this.repository.load(documentOrId) : documentOrId;
105
- return this.#documentFileService.getPreviewStream(document.fileId, page);
114
+ return this.#documentFileService.getPreviewStream(document.id, page);
106
115
  });
107
116
  }
108
117
  async getPreviewUrl(documentOrId, page = 1) {
109
118
  const document = isString(documentOrId) ? await this.repository.load(documentOrId) : documentOrId;
110
- return await this.#documentFileService.getPreviewUrl(document.fileId, page);
119
+ return await this.#documentFileService.getPreviewUrl(document.id, page);
111
120
  }
112
121
  /**
113
122
  * @returns collectionIds from either direct assignment or automatic assignment scope
114
123
  */
115
124
  async createAssignment(documentId, assignment, transaction) {
116
- return await match(assignment)
125
+ await match(assignment)
117
126
  .with({ collections: P.select() }, async (collectionIds) => {
118
127
  const collectionIdsArray = toArray(collectionIds);
119
128
  await this.#documentCollectionService.withTransaction(transaction).assignDocument(documentId, collectionIdsArray);
@@ -1,5 +1,5 @@
1
1
  import type { TypedOmit } from '../../types.js';
2
- import { Document, DocumentAssignmentTarget, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentFile, DocumentPropertyDataType, DocumentRequest, DocumentType, DocumentValidationExecution, DocumentWorkflow } from '../models/index.js';
2
+ import { Document, DocumentAssignmentTarget, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentPropertyDataType, DocumentRequest, DocumentType, DocumentValidationExecution, DocumentWorkflow } from '../models/index.js';
3
3
  export declare class DocumentCollectionView extends DocumentCollection {
4
4
  name: string;
5
5
  group: string | null;
@@ -37,7 +37,6 @@ export declare class DocumentManagementData {
37
37
  collections: DocumentCollectionView[];
38
38
  documents: DocumentView[];
39
39
  requests: DocumentRequestView[];
40
- files: DocumentFile[];
41
40
  categories: DocumentCategory[];
42
41
  types: DocumentType[];
43
42
  }
@@ -8,7 +8,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
10
  import { Array, Enumeration, Property, string, StringProperty, Union } from '../../schema/index.js';
11
- import { Document, DocumentAssignmentTarget, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentFile, DocumentPropertyDataType, DocumentRequest, DocumentType, DocumentValidationExecution, DocumentWorkflow } from '../models/index.js';
11
+ import { Document, DocumentAssignmentTarget, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentPropertyDataType, DocumentRequest, DocumentType, DocumentValidationExecution, DocumentWorkflow } from '../models/index.js';
12
12
  export class DocumentCollectionView extends DocumentCollection {
13
13
  name;
14
14
  group;
@@ -118,7 +118,6 @@ export class DocumentManagementData {
118
118
  collections;
119
119
  documents;
120
120
  requests;
121
- files;
122
121
  categories;
123
122
  types;
124
123
  }
@@ -134,10 +133,6 @@ __decorate([
134
133
  Array(DocumentRequestView),
135
134
  __metadata("design:type", Array)
136
135
  ], DocumentManagementData.prototype, "requests", void 0);
137
- __decorate([
138
- Array(DocumentFile),
139
- __metadata("design:type", Array)
140
- ], DocumentManagementData.prototype, "files", void 0);
141
136
  __decorate([
142
137
  Array(DocumentCategory),
143
138
  __metadata("design:type", Array)
@@ -23,7 +23,7 @@ export declare const createDocumentParametersSchema: import("../../schema/index.
23
23
  tags?: string[] | null | undefined;
24
24
  comment?: string | null | undefined;
25
25
  approval?: import("../models/document.model.js").DocumentApproval | undefined;
26
- originalFileName: string | null;
26
+ originalFileName?: string | null | undefined;
27
27
  assignment: {
28
28
  collections: string | string[];
29
29
  } | {
@@ -49,15 +49,18 @@ export declare const createDocumentParametersSchema: import("../../schema/index.
49
49
  export declare const updateDocumentParametersSchema: import("../../schema/index.js").ObjectSchema<{
50
50
  id: import("../../orm/types.js").IsPrimaryKey<import("../../orm/types.js").HasDefault<import("../../orm/schemas/uuid.js").Uuid>>;
51
51
  date?: import("../../orm/types.js").NumericDate | null | undefined;
52
+ size?: number | undefined;
53
+ hash?: string | undefined;
52
54
  summary?: string | null | undefined;
53
55
  title?: string | null | undefined;
56
+ mimeType?: string | undefined;
54
57
  typeId?: import("../../orm/types.js").Uuid | null | undefined;
55
58
  subtitle?: string | null | undefined;
56
59
  tags?: string[] | null | undefined;
57
60
  comment?: string | null | undefined;
58
- fileId?: import("../../orm/types.js").Uuid | undefined;
59
61
  pages?: number | null | undefined;
60
62
  approval?: import("../models/document.model.js").DocumentApproval | undefined;
63
+ originalFileName?: string | null | undefined;
61
64
  createUserId?: import("../../orm/types.js").Uuid | null | undefined;
62
65
  properties?: {
63
66
  propertyId: import("../../orm/schemas/uuid.js").Uuid;
@@ -1,10 +1,10 @@
1
1
  import { EntityMetadata } from '../../orm/entity.js';
2
2
  import { array, assign, boolean, enumeration, never, nullable, number, object, omit, oneOrMany, optional, partial, pick, string, union } from '../../schema/index.js';
3
- import { Document, DocumentAssignmentTarget, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentFile, DocumentProperty, DocumentPropertyValue, DocumentRequest, DocumentRequestsTemplate, DocumentRequestTemplate, DocumentType, DocumentTypeProperty } from '../models/index.js';
3
+ import { Document, DocumentAssignmentTarget, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentProperty, DocumentPropertyValue, DocumentRequest, DocumentRequestsTemplate, DocumentRequestTemplate, DocumentType, DocumentTypeProperty } from '../models/index.js';
4
4
  export const metadataParameterSchema = optional(partial(pick(EntityMetadata, 'attributes')));
5
5
  export const metadataParameterObjectSchema = object({ metadata: metadataParameterSchema });
6
6
  export const setDocumentPropertyParametersSchema = assign(pick(DocumentPropertyValue, ['propertyId']), object({ value: union(string(), number(), boolean(), nullable(never())) }), metadataParameterObjectSchema);
7
- export const createDocumentParametersSchema = assign(partial(pick(Document, ['typeId', 'title', 'subtitle', 'date', 'summary', 'tags', 'approval', 'comment'])), pick(DocumentFile, ['originalFileName']), object({
7
+ export const createDocumentParametersSchema = assign(partial(pick(Document, ['typeId', 'title', 'subtitle', 'date', 'summary', 'tags', 'approval', 'comment', 'originalFileName'])), object({
8
8
  uploadId: string(),
9
9
  assignment: union(object({ collections: oneOrMany(string(), { minimum: 1 }) }), object({ request: string() }), object({
10
10
  automatic: object({
@@ -17,7 +17,6 @@ export declare class EnrichedDocumentManagementData {
17
17
  collections: Map<string, import("../document-management.view-model.js").DocumentCollectionView>;
18
18
  documents: Map<string, import("../document-management.view-model.js").DocumentView>;
19
19
  requests: Map<string, import("../document-management.view-model.js").DocumentRequestView>;
20
- files: Map<string, import("../../index.js").DocumentFile>;
21
20
  categories: Map<string, import("../../index.js").DocumentCategory>;
22
21
  types: Map<string, import("../../index.js").DocumentType>;
23
22
  };
@@ -40,7 +40,6 @@ export class EnrichedDocumentManagementData {
40
40
  collections: () => getEntityMap(this.rawData.collections),
41
41
  documents: () => getEntityMap(this.rawData.documents),
42
42
  requests: () => getEntityMap(this.rawData.requests),
43
- files: () => getEntityMap(this.rawData.files),
44
43
  categories: () => getEntityMap(this.rawData.categories),
45
44
  types: () => getEntityMap(this.rawData.types),
46
45
  });
@@ -2,10 +2,9 @@ import type { TypedOmit } from '../../../types.js';
2
2
  import type { DocumentApproval, DocumentValidationExecution, DocumentWorkflow } from '../../models/index.js';
3
3
  import type { DocumentPropertyValueView, DocumentView } from '../document-management.view-model.js';
4
4
  import { EnrichedDocumentAssignment } from './enriched-document-assignment.view.js';
5
- import { EnrichedDocumentFile } from './enriched-document-file.view.js';
6
5
  import type { EnrichedDocumentManagementData } from './enriched-document-management-data.view.js';
7
6
  import type { EnrichedDocumentType } from './enriched-document-type.view.js';
8
- export declare class EnrichedDocument implements TypedOmit<DocumentView, 'typeId' | 'fileId' | 'assignment' | 'createUserId' | 'metadata'> {
7
+ export declare class EnrichedDocument implements TypedOmit<DocumentView, 'typeId' | 'assignment' | 'createUserId' | 'metadata'> {
9
8
  #private;
10
9
  readonly id: string;
11
10
  readonly title: string | null;
@@ -16,11 +15,14 @@ export declare class EnrichedDocument implements TypedOmit<DocumentView, 'typeId
16
15
  readonly tags: string[] | null;
17
16
  readonly approval: DocumentApproval;
18
17
  readonly comment: string | null;
18
+ readonly originalFileName: string | null;
19
+ readonly mimeType: string;
20
+ readonly hash: string;
21
+ readonly size: number;
19
22
  readonly properties: DocumentPropertyValueView[];
20
23
  readonly currentWorkflow: DocumentWorkflow | null;
21
24
  readonly validations: DocumentValidationExecution[] | null;
22
25
  get type(): EnrichedDocumentType | null;
23
- get file(): EnrichedDocumentFile;
24
26
  get assignments(): EnrichedDocumentAssignment;
25
27
  constructor(data: EnrichedDocumentManagementData, document: DocumentView);
26
28
  }
@@ -10,7 +10,6 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  import { Memoize } from '../../../utils/function/memoize.js';
11
11
  import { assertDefinedPass, isNull } from '../../../utils/type-guards.js';
12
12
  import { EnrichedDocumentAssignment } from './enriched-document-assignment.view.js';
13
- import { EnrichedDocumentFile } from './enriched-document-file.view.js';
14
13
  export class EnrichedDocument {
15
14
  #data;
16
15
  #documentView;
@@ -23,6 +22,10 @@ export class EnrichedDocument {
23
22
  tags;
24
23
  approval;
25
24
  comment;
25
+ originalFileName;
26
+ mimeType;
27
+ hash;
28
+ size;
26
29
  properties;
27
30
  currentWorkflow;
28
31
  validations;
@@ -32,10 +35,6 @@ export class EnrichedDocument {
32
35
  }
33
36
  return assertDefinedPass(this.#data.maps.types.get(this.#documentView.typeId));
34
37
  }
35
- get file() {
36
- const file = assertDefinedPass(this.#data.rawDataMaps.files.get(this.#documentView.fileId));
37
- return new EnrichedDocumentFile(file, this);
38
- }
39
38
  get assignments() {
40
39
  return new EnrichedDocumentAssignment(this.#data, this, this.#documentView.assignment);
41
40
  }
@@ -51,6 +50,10 @@ export class EnrichedDocument {
51
50
  this.tags = document.tags;
52
51
  this.approval = document.approval;
53
52
  this.comment = document.comment;
53
+ this.originalFileName = document.originalFileName;
54
+ this.mimeType = document.mimeType;
55
+ this.hash = document.hash;
56
+ this.size = document.size;
54
57
  this.properties = document.properties;
55
58
  this.currentWorkflow = document.currentWorkflow;
56
59
  this.validations = document.validations;
@@ -61,11 +64,6 @@ __decorate([
61
64
  __metadata("design:type", Object),
62
65
  __metadata("design:paramtypes", [])
63
66
  ], EnrichedDocument.prototype, "type", null);
64
- __decorate([
65
- Memoize(),
66
- __metadata("design:type", EnrichedDocumentFile),
67
- __metadata("design:paramtypes", [])
68
- ], EnrichedDocument.prototype, "file", null);
69
67
  __decorate([
70
68
  Memoize(),
71
69
  __metadata("design:type", EnrichedDocumentAssignment),
@@ -1,7 +1,6 @@
1
1
  export * from './enriched-document-assignment.view.js';
2
2
  export * from './enriched-document-category.view.js';
3
3
  export * from './enriched-document-collection.view.js';
4
- export * from './enriched-document-file.view.js';
5
4
  export * from './enriched-document-management-data.view.js';
6
5
  export * from './enriched-document-request.view.js';
7
6
  export * from './enriched-document-type.view.js';
@@ -1,7 +1,6 @@
1
1
  export * from './enriched-document-assignment.view.js';
2
2
  export * from './enriched-document-category.view.js';
3
3
  export * from './enriched-document-collection.view.js';
4
- export * from './enriched-document-file.view.js';
5
4
  export * from './enriched-document-management-data.view.js';
6
5
  export * from './enriched-document-request.view.js';
7
6
  export * from './enriched-document-type.view.js';
@@ -6,6 +6,8 @@ export type UploadObjectOptions = {
6
6
  metadata?: ObjectMetadata;
7
7
  };
8
8
  export type UploadUrlOptions = {
9
+ contentLength?: number;
10
+ contentType?: string;
9
11
  metadata?: ObjectMetadata;
10
12
  };
11
13
  export type CopyObjectOptions = {
package/orm/sqls.d.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * @module
3
- * Provides utility SQL functions and constants for use with Drizzle ORM,
4
- * simplifying common SQL operations like generating UUIDs, working with intervals,
5
- * and aggregating data.
6
- */
7
1
  import { type AnyColumn, type Column, type SQL } from 'drizzle-orm';
8
2
  import type { GetSelectTableSelection, SelectResultField, TableLike } from 'drizzle-orm/query-builders/select.types';
9
3
  import type { Uuid } from './types.js';
@@ -72,3 +66,5 @@ export declare function numNulls(...columns: Column[]): SQL<number>;
72
66
  * @returns A Drizzle SQL object representing the count of non-nulls.
73
67
  */
74
68
  export declare function numNonNulls(...columns: Column[]): SQL<number>;
69
+ export declare function least<T extends (Column | SQL | number)>(...values: T[]): SQL<SelectResultField<T>>;
70
+ export declare function greatest<T extends (Column | SQL | number)>(...values: T[]): SQL<SelectResultField<T>>;
package/orm/sqls.js CHANGED
@@ -4,6 +4,7 @@
4
4
  * simplifying common SQL operations like generating UUIDs, working with intervals,
5
5
  * and aggregating data.
6
6
  */
7
+ import { isNumber } from '../utils/type-guards.js';
7
8
  import { sql, Table } from 'drizzle-orm';
8
9
  /** Drizzle SQL helper for getting the current transaction's timestamp. Returns a Date object. */
9
10
  export const TRANSACTION_TIMESTAMP = sql `transaction_timestamp()`;
@@ -86,3 +87,11 @@ export function numNulls(...columns) {
86
87
  export function numNonNulls(...columns) {
87
88
  return sql `num_nonnulls(${sql.join(columns, sql.raw(', '))})`;
88
89
  }
90
+ export function least(...values) {
91
+ const sqlValues = values.map((value) => isNumber(value) ? sql.raw(String(value)) : value);
92
+ return sql `least(${sql.join(sqlValues, sql.raw(', '))})`;
93
+ }
94
+ export function greatest(...values) {
95
+ const sqlValues = values.map((value) => isNumber(value) ? sql.raw(String(value)) : value);
96
+ return sql `greatest(${sql.join(sqlValues, sql.raw(', '))})`;
97
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tstdl/base",
3
- "version": "0.92.135",
3
+ "version": "0.92.137",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -171,7 +171,7 @@
171
171
  }
172
172
  },
173
173
  "devDependencies": {
174
- "@stylistic/eslint-plugin": "4.2",
174
+ "@stylistic/eslint-plugin": "4.4",
175
175
  "@types/chroma-js": "2.4",
176
176
  "@types/koa__router": "12.0",
177
177
  "@types/luxon": "3.6",
@@ -1,7 +0,0 @@
1
- import { Entity } from '../../orm/entity.js';
2
- export declare class DocumentFile extends Entity {
3
- originalFileName: string | null;
4
- mimeType: string;
5
- hash: string;
6
- size: number;
7
- }
@@ -1,38 +0,0 @@
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 __metadata = (this && this.__metadata) || function (k, v) {
8
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
- };
10
- import { Entity } from '../../orm/entity.js';
11
- import { Integer, StringProperty } from '../../schema/index.js';
12
- import { DocumentManagementTable } from './document-management-table.js';
13
- let DocumentFile = class DocumentFile extends Entity {
14
- originalFileName;
15
- mimeType;
16
- hash;
17
- size;
18
- };
19
- __decorate([
20
- StringProperty({ nullable: true }),
21
- __metadata("design:type", Object)
22
- ], DocumentFile.prototype, "originalFileName", void 0);
23
- __decorate([
24
- StringProperty(),
25
- __metadata("design:type", String)
26
- ], DocumentFile.prototype, "mimeType", void 0);
27
- __decorate([
28
- StringProperty(),
29
- __metadata("design:type", String)
30
- ], DocumentFile.prototype, "hash", void 0);
31
- __decorate([
32
- Integer(),
33
- __metadata("design:type", Number)
34
- ], DocumentFile.prototype, "size", void 0);
35
- DocumentFile = __decorate([
36
- DocumentManagementTable()
37
- ], DocumentFile);
38
- export { DocumentFile };
@@ -1,12 +0,0 @@
1
- import type { TypedOmit } from '../../../types.js';
2
- import type { DocumentFile } from '../../models/index.js';
3
- import type { EnrichedDocument } from './enriched-document.view.js';
4
- export declare class EnrichedDocumentFile implements TypedOmit<DocumentFile, 'metadata'> {
5
- readonly id: string;
6
- readonly originalFileName: string | null;
7
- readonly mimeType: string;
8
- readonly hash: string;
9
- readonly size: number;
10
- readonly document: EnrichedDocument;
11
- constructor(file: DocumentFile, document: EnrichedDocument);
12
- }
@@ -1,16 +0,0 @@
1
- export class EnrichedDocumentFile {
2
- id;
3
- originalFileName;
4
- mimeType;
5
- hash;
6
- size;
7
- document;
8
- constructor(file, document) {
9
- this.id = file.id;
10
- this.originalFileName = file.originalFileName;
11
- this.mimeType = file.mimeType;
12
- this.hash = file.hash;
13
- this.size = file.size;
14
- this.document = document;
15
- }
16
- }