@tstdl/base 0.92.138 → 0.92.139

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 (44) hide show
  1. package/document-management/api/document-management.api.d.ts +40 -0
  2. package/document-management/api/document-management.api.js +20 -0
  3. package/document-management/server/api/document-management.api.d.ts +2 -0
  4. package/document-management/server/api/document-management.api.js +34 -32
  5. package/document-management/server/configure.d.ts +2 -0
  6. package/document-management/server/configure.js +9 -0
  7. package/document-management/server/drizzle/{0000_magical_madame_hydra.sql → 0000_moaning_luckman.sql} +4 -15
  8. package/document-management/server/drizzle/meta/0000_snapshot.json +25 -96
  9. package/document-management/server/drizzle/meta/_journal.json +2 -2
  10. package/document-management/server/index.d.ts +1 -0
  11. package/document-management/server/index.js +1 -0
  12. package/document-management/server/module.d.ts +3 -2
  13. package/document-management/server/module.js +2 -6
  14. package/document-management/server/services/document-category-type.service.d.ts +0 -1
  15. package/document-management/server/services/document-category-type.service.js +7 -7
  16. package/document-management/server/services/document-file.service.js +2 -2
  17. package/document-management/server/services/document-management-ai.service.js +5 -1
  18. package/document-management/server/services/document-management-ancillary.service.d.ts +2 -83
  19. package/document-management/server/services/document-management-ancillary.service.js +1 -23
  20. package/document-management/server/services/document-management-authorization.service.d.ts +85 -0
  21. package/document-management/server/services/document-management-authorization.service.js +28 -0
  22. package/document-management/server/services/document-management.service.d.ts +9 -2
  23. package/document-management/server/services/document-management.service.js +59 -6
  24. package/document-management/server/services/document-property.service.d.ts +7 -3
  25. package/document-management/server/services/document-property.service.js +8 -4
  26. package/document-management/server/services/document-workflow.service.js +2 -2
  27. package/document-management/server/services/enum-type-key.d.ts +1 -0
  28. package/document-management/server/services/enum-type-key.js +1 -0
  29. package/document-management/server/services/index.d.ts +1 -0
  30. package/document-management/server/services/index.js +1 -0
  31. package/document-management/service-models/enriched/enriched-document-category.view.d.ts +1 -0
  32. package/document-management/service-models/enriched/enriched-document-category.view.js +8 -0
  33. package/document-management/service-models/enriched/enriched-document.view.d.ts +3 -1
  34. package/document-management/service-models/enriched/enriched-document.view.js +2 -0
  35. package/examples/document-management/categories-and-types.d.ts +357 -312
  36. package/examples/document-management/categories-and-types.js +690 -350
  37. package/examples/document-management/main.d.ts +18 -16
  38. package/examples/document-management/main.js +27 -20
  39. package/file/mime-type.d.ts +2 -1
  40. package/file/mime-type.js +10 -18
  41. package/file/mime-types.js +1 -2
  42. package/http/server/http-server-response.js +2 -2
  43. package/package.json +3 -2
  44. package/schema/converters/openapi-converter.js +15 -12
@@ -1,20 +1,22 @@
1
1
  import '../../polyfills.js';
2
- import type { DocumentCollection, DocumentWorkflowStep } from '../../document-management/index.js';
3
- import { DocumentManagementAncillaryService, type DocumentCollectionMetadata } from '../../document-management/server/index.js';
2
+ import type { DocumentCollection } from '../../document-management/index.js';
3
+ import { DocumentManagementAncillaryService, DocumentManagementAuthorizationService, type DocumentCollectionMetadata } from '../../document-management/server/index.js';
4
4
  export declare class ExampleDocumentManagementAncillaryService extends DocumentManagementAncillaryService {
5
5
  _resolveMetadata(collections: DocumentCollection[]): DocumentCollectionMetadata[];
6
- getSubject(_token?: unknown): string;
7
- canCreateDocuments(_collectionId: string, _token?: unknown): boolean;
8
- canUpdateDocuments(_collectionId: string, _token?: unknown): boolean;
9
- canDeleteDocuments(_collectionId: string, _token?: unknown): boolean;
10
- canAssignDocuments(_collectionId: string, _token?: unknown): boolean;
11
- canManageRequests(_collectionId: string, _token?: unknown): boolean;
12
- canReadCollection(_collectionId: string, _token?: unknown): boolean;
13
- canApproveDocument(_documentId: string, _token?: unknown): boolean;
14
- canRejectDocument(_documentId: string, _token?: unknown): boolean;
15
- canManageCategoriesAndTypes(_token?: unknown): boolean;
16
- canReadDocumentRequestsTemplates(_token?: unknown): boolean;
17
- canManageDocumentRequestsTemplates(_token?: unknown): boolean;
18
- canManageValidationDefinitions(_token?: unknown): boolean;
19
- canProgressDocumentWorkflow(_documentId: string, _currentWorkflowStep: DocumentWorkflowStep, _token?: unknown): boolean;
6
+ }
7
+ export declare class AllowAllDocumentManagementAuthorizationService extends DocumentManagementAuthorizationService {
8
+ getSubject(): string;
9
+ canReadCollection(): boolean;
10
+ canCreateDocuments(): boolean;
11
+ canUpdateDocuments(): boolean;
12
+ canDeleteDocuments(): boolean;
13
+ canAssignDocuments(): boolean;
14
+ canApproveDocument(): boolean;
15
+ canRejectDocument(): boolean;
16
+ canManageRequests(): boolean;
17
+ canManageCategoriesAndTypes(): boolean;
18
+ canReadDocumentRequestsTemplates(): boolean;
19
+ canManageDocumentRequestsTemplates(): boolean;
20
+ canManageValidationDefinitions(): boolean;
21
+ canProgressDocumentWorkflow(): boolean;
20
22
  }
@@ -9,8 +9,10 @@ import { configureAiService } from '../../ai/index.js';
9
9
  import { MockApiRequestTokenProvider } from '../../api/server/api-request-token.provider.js';
10
10
  import { configureApiServer } from '../../api/server/module.js';
11
11
  import { Application } from '../../application/application.js';
12
- import { DocumentCategoryTypeService, DocumentCollectionService, DocumentManagementAncillaryService, DocumentManagementApiController, DocumentRequestService } from '../../document-management/server/index.js';
13
- import { configureDocumentManagement, migrateDocumentManagementSchema } from '../../document-management/server/module.js';
12
+ import { configureTstdl } from '../../core.js';
13
+ import { configureDocumentManagement } from '../../document-management/server/configure.js';
14
+ import { DocumentCategoryTypeService, DocumentCollectionService, DocumentManagementAncillaryService, DocumentManagementApiController, DocumentManagementAuthorizationService, DocumentRequestService } from '../../document-management/server/index.js';
15
+ import { migrateDocumentManagementSchema } from '../../document-management/server/module.js';
14
16
  import { DocumentManagementService } from '../../document-management/server/services/document-management.service.js';
15
17
  import { configureNodeHttpServer } from '../../http/server/node/module.js';
16
18
  import { Injector, Singleton } from '../../injector/index.js';
@@ -21,8 +23,7 @@ import { configureS3ObjectStorage } from '../../object-storage/index.js';
21
23
  import { configureOrm } from '../../orm/server/index.js';
22
24
  import { configurePostgresQueue, migratePostgresQueueSchema } from '../../queue/postgres/index.js';
23
25
  import { boolean, positiveInteger, string } from '../../utils/config-parser.js';
24
- import { TstdlCategoryParents, TstdlDocumentCategoryLabels, TstdlDocumentTypeCategories, TstdlDocumentTypeLabels } from './categories-and-types.js';
25
- import { configureTstdl } from '../../core.js';
26
+ import { TstdlCategoryParents, TstdlDocumentCategoryLabels, TstdlDocumentPropertyConfiguration, TstdlDocumentTypeCategories, TstdlDocumentTypeLabels, TstdlDocumentTypeProperties } from './categories-and-types.js';
26
27
  const config = {
27
28
  database: {
28
29
  host: string('DATABASE_HOST', '127.0.0.1'),
@@ -48,30 +49,35 @@ const config = {
48
49
  bucketPerModule: boolean('S3_BUCKET_PER_MODULE', true),
49
50
  },
50
51
  };
51
- const userId = crypto.randomUUID();
52
52
  let ExampleDocumentManagementAncillaryService = class ExampleDocumentManagementAncillaryService extends DocumentManagementAncillaryService {
53
53
  _resolveMetadata(collections) {
54
54
  return collections.map((collection) => ({ name: collection.id.split('-')[0], group: null }));
55
55
  }
56
- getSubject(_token) { return userId; }
57
- canCreateDocuments(_collectionId, _token) { return true; }
58
- canUpdateDocuments(_collectionId, _token) { return true; }
59
- canDeleteDocuments(_collectionId, _token) { return true; }
60
- canAssignDocuments(_collectionId, _token) { return true; }
61
- canManageRequests(_collectionId, _token) { return true; }
62
- canReadCollection(_collectionId, _token) { return true; }
63
- canApproveDocument(_documentId, _token) { return true; }
64
- canRejectDocument(_documentId, _token) { return true; }
65
- canManageCategoriesAndTypes(_token) { return true; }
66
- canReadDocumentRequestsTemplates(_token) { return true; }
67
- canManageDocumentRequestsTemplates(_token) { return true; }
68
- canManageValidationDefinitions(_token) { return true; }
69
- canProgressDocumentWorkflow(_documentId, _currentWorkflowStep, _token) { return true; }
70
56
  };
71
57
  ExampleDocumentManagementAncillaryService = __decorate([
72
58
  Singleton()
73
59
  ], ExampleDocumentManagementAncillaryService);
74
60
  export { ExampleDocumentManagementAncillaryService };
61
+ let AllowAllDocumentManagementAuthorizationService = class AllowAllDocumentManagementAuthorizationService extends DocumentManagementAuthorizationService {
62
+ getSubject() { return '00000000-0000-0000-0000-000000000000'; }
63
+ canReadCollection() { return true; }
64
+ canCreateDocuments() { return true; }
65
+ canUpdateDocuments() { return true; }
66
+ canDeleteDocuments() { return true; }
67
+ canAssignDocuments() { return true; }
68
+ canApproveDocument() { return true; }
69
+ canRejectDocument() { return true; }
70
+ canManageRequests() { return true; }
71
+ canManageCategoriesAndTypes() { return true; }
72
+ canReadDocumentRequestsTemplates() { return true; }
73
+ canManageDocumentRequestsTemplates() { return true; }
74
+ canManageValidationDefinitions() { return true; }
75
+ canProgressDocumentWorkflow() { return true; }
76
+ };
77
+ AllowAllDocumentManagementAuthorizationService = __decorate([
78
+ Singleton()
79
+ ], AllowAllDocumentManagementAuthorizationService);
80
+ export { AllowAllDocumentManagementAuthorizationService };
75
81
  async function bootstrap() {
76
82
  const injector = inject(Injector);
77
83
  configureTstdl();
@@ -89,6 +95,7 @@ async function bootstrap() {
89
95
  });
90
96
  configureDocumentManagement({
91
97
  ancillaryService: ExampleDocumentManagementAncillaryService,
98
+ authorizationService: AllowAllDocumentManagementAuthorizationService,
92
99
  fileObjectStorageModule: 'documents',
93
100
  fileUploadObjectStorageModule: 'document-uploads',
94
101
  filePreviewObjectStorageModule: 'document-previews',
@@ -122,7 +129,7 @@ async function bootstrap() {
122
129
  }
123
130
  async function main() {
124
131
  const [documentManagementService, documentCollectionService] = await injectManyAsync(DocumentManagementService, DocumentCollectionService, DocumentCategoryTypeService, DocumentRequestService);
125
- const { categories, types } = await documentManagementService.initializeCategoriesAndTypes(TstdlDocumentCategoryLabels, TstdlCategoryParents, TstdlDocumentTypeLabels, TstdlDocumentTypeCategories);
132
+ const { categories, types } = await documentManagementService.initializeCategoriesAndTypes(TstdlDocumentCategoryLabels, TstdlCategoryParents, TstdlDocumentTypeLabels, TstdlDocumentTypeCategories, TstdlDocumentPropertyConfiguration, TstdlDocumentTypeProperties);
126
133
  const collectionCount = await documentCollectionService.repository.count();
127
134
  for (let i = 0; i < (3 - collectionCount); i++) {
128
135
  await documentCollectionService.createCollection(null);
@@ -1,2 +1,3 @@
1
- export declare function getMimeType(file: string | Uint8Array | ReadableStream<Uint8Array>): Promise<string>;
1
+ export declare function getMimeType(file: string | Uint8Array | ReadableStream<Uint8Array>): Promise<string | undefined>;
2
+ export declare function getMimeType<F>(file: string | Uint8Array | ReadableStream<Uint8Array>, fallback: F): Promise<string | F>;
2
3
  export declare function getMimeTypeExtensions(mimeType: string): string[];
package/file/mime-type.js CHANGED
@@ -1,23 +1,15 @@
1
- import { spawnCommand } from '../process/spawn.js';
2
- import { isDefined, isString } from '../utils/type-guards.js';
1
+ import { fileTypeFromBuffer, fileTypeFromFile, fileTypeFromStream } from 'file-type';
2
+ import { isReadableStream, isString, isUint8Array } from '../utils/type-guards.js';
3
+ import { match } from 'ts-pattern';
3
4
  import { mimeTypesMap } from './mime-types.js';
4
- export async function getMimeType(file) {
5
- const path = isString(file) ? file : '-';
6
- const data = isString(file) ? undefined : file;
7
- return spawnFileCommand(['--brief', '--mime-type', path], data);
5
+ export async function getMimeType(file, fallback) {
6
+ const result = await match(file)
7
+ .when(isString, async (f) => await fileTypeFromFile(f))
8
+ .when(isUint8Array, async (f) => await fileTypeFromBuffer(f))
9
+ .when((isReadableStream), async (f) => await fileTypeFromStream(f))
10
+ .exhaustive();
11
+ return result?.mime ?? fallback;
8
12
  }
9
13
  export function getMimeTypeExtensions(mimeType) {
10
14
  return mimeTypesMap.get(mimeType) ?? [];
11
15
  }
12
- async function spawnFileCommand(args, file) {
13
- const process = await spawnCommand('file', args);
14
- if (isDefined(file)) {
15
- process.autoWrite(file);
16
- }
17
- await process.wait({ throwOnNonZeroExitCode: true });
18
- const output = await process.readOutput();
19
- if (output.includes('file or directory')) {
20
- throw new Error(output.trim());
21
- }
22
- return output.trim();
23
- }
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/naming-convention */
2
1
  import { objectEntries } from '../utils/object/object.js';
3
2
  export const mimeTypes = {
4
3
  'application/andrew-inset': ['ez'],
@@ -767,6 +766,6 @@ export const mimeTypes = {
767
766
  'video/x-msvideo': ['avi'],
768
767
  'video/x-sgi-movie': ['movie'],
769
768
  'video/x-smv': ['smv'],
770
- 'x-conference/x-cooltalk': ['ice']
769
+ 'x-conference/x-cooltalk': ['ice'],
771
770
  };
772
771
  export const mimeTypesMap = new Map(objectEntries(mimeTypes));
@@ -19,8 +19,8 @@ export class HttpServerResponse {
19
19
  ...options,
20
20
  headers: {
21
21
  Location: url,
22
- ...options?.headers
23
- }
22
+ ...options?.headers,
23
+ },
24
24
  });
25
25
  }
26
26
  update(options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tstdl/base",
3
- "version": "0.92.138",
3
+ "version": "0.92.139",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -152,6 +152,7 @@
152
152
  "@zxcvbn-ts/language-en": "^3.0",
153
153
  "chroma-js": "^2.6",
154
154
  "drizzle-orm": "^0.43",
155
+ "file-type": "^21.0",
155
156
  "handlebars": "^4.7",
156
157
  "minio": "^8.0",
157
158
  "mjml": "^4.15",
@@ -183,7 +184,7 @@
183
184
  "concurrently": "9.1",
184
185
  "drizzle-kit": "0.31",
185
186
  "eslint": "9.27",
186
- "globals": "16.1",
187
+ "globals": "16.2",
187
188
  "tsc-alias": "1.8",
188
189
  "typedoc-plugin-missing-exports": "4.0",
189
190
  "typescript": "5.8",
@@ -20,7 +20,7 @@ export function convertToOpenApiSchema(testable) {
20
20
  ...openApiSchema,
21
21
  ...(hasOwnProperty(openApiSchema, 'nullable') ? undefined : { nullable: false }),
22
22
  ...(isNotNull(schema.description) ? { description: schema.description } : undefined),
23
- ...(isDefined(schema.example) ? { example: schema.example } : undefined)
23
+ ...(isDefined(schema.example) ? { example: schema.example } : undefined),
24
24
  };
25
25
  }
26
26
  function convertToOpenApiSchemaBase(schema) {
@@ -32,36 +32,36 @@ function convertToOpenApiSchemaBase(schema) {
32
32
  properties: fromEntries(convertedEntries),
33
33
  required: entries
34
34
  .filter(([, propertySchema]) => !(propertySchema instanceof OptionalSchema) && !((propertySchema instanceof NullableSchema) && (propertySchema.schema instanceof OptionalSchema)))
35
- .map(([property]) => property)
35
+ .map(([property]) => property),
36
36
  };
37
37
  }
38
38
  if (schema instanceof StringSchema) {
39
39
  return {
40
- type: 'string'
40
+ type: 'string',
41
41
  };
42
42
  }
43
43
  if (schema instanceof DateSchema) {
44
44
  return {
45
45
  type: 'string',
46
- format: 'date-time'
46
+ format: 'date-time',
47
47
  };
48
48
  }
49
49
  if (schema instanceof NumberSchema) {
50
50
  return {
51
51
  type: schema.integer ? 'integer' : 'number',
52
52
  ...(isNumber(schema.minimum) ? { minimum: schema.minimum } : undefined),
53
- ...(isNumber(schema.maximum) ? { maximum: schema.maximum } : undefined)
53
+ ...(isNumber(schema.maximum) ? { maximum: schema.maximum } : undefined),
54
54
  };
55
55
  }
56
56
  if (schema instanceof BooleanSchema) {
57
57
  return {
58
- type: 'boolean'
58
+ type: 'boolean',
59
59
  };
60
60
  }
61
61
  if (schema instanceof LiteralSchema) {
62
62
  return {
63
63
  type: typeof schema.value,
64
- enum: [schema.value]
64
+ enum: [schema.value],
65
65
  };
66
66
  }
67
67
  if (schema instanceof ArraySchema) {
@@ -69,19 +69,22 @@ function convertToOpenApiSchemaBase(schema) {
69
69
  type: 'array',
70
70
  items: convertToOpenApiSchema(schema.itemSchema),
71
71
  ...(isNumber(schema.minimum) ? { minItems: schema.minimum } : undefined),
72
- ...(isNumber(schema.maximum) ? { maxItems: schema.maximum } : undefined)
72
+ ...(isNumber(schema.maximum) ? { maxItems: schema.maximum } : undefined),
73
73
  };
74
74
  }
75
75
  if (schema instanceof EnumerationSchema) {
76
76
  const hasString = schema.allowedValues.some(isString);
77
77
  const hasNumber = schema.allowedValues.some(isNumber);
78
+ if (schema.allowedValues.length === 0) {
79
+ throw new NotSupportedError('Enum must have at least one value.');
80
+ }
78
81
  if (!hasString && !hasNumber) {
79
82
  throw new NotSupportedError('Enum must be either string or number but not both.');
80
83
  }
81
84
  return {
82
85
  type: hasString ? 'string' : 'number',
83
86
  format: 'enum',
84
- enum: schema.allowedValues
87
+ enum: schema.allowedValues,
85
88
  };
86
89
  }
87
90
  if (schema instanceof NullableSchema) {
@@ -89,17 +92,17 @@ function convertToOpenApiSchemaBase(schema) {
89
92
  const enumSchema = convertToOpenApiSchema(schema.schema);
90
93
  return {
91
94
  ...enumSchema,
92
- nullable: true
95
+ nullable: true,
93
96
  };
94
97
  }
95
98
  return {
96
99
  ...convertToOpenApiSchema(schema.schema),
97
- nullable: true
100
+ nullable: true,
98
101
  };
99
102
  }
100
103
  if (schema instanceof UnionSchema) {
101
104
  return {
102
- oneOf: schema.schemas.map((innerSchema) => convertToOpenApiSchema(innerSchema))
105
+ oneOf: schema.schemas.map((innerSchema) => convertToOpenApiSchema(innerSchema)),
103
106
  };
104
107
  }
105
108
  throw new NotSupportedError(`Schema "${schema.name}" not supported.`);