@tstdl/base 0.92.138 → 0.92.140

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 (52) hide show
  1. package/ai/ai.service.js +1 -1
  2. package/css/css-variables.d.ts +14 -0
  3. package/css/css-variables.js +55 -0
  4. package/css/index.d.ts +1 -0
  5. package/css/index.js +1 -0
  6. package/document-management/api/document-management.api.d.ts +59 -0
  7. package/document-management/api/document-management.api.js +28 -0
  8. package/document-management/server/api/document-management.api.d.ts +4 -1
  9. package/document-management/server/api/document-management.api.js +61 -28
  10. package/document-management/server/configure.d.ts +2 -0
  11. package/document-management/server/configure.js +9 -0
  12. package/document-management/server/drizzle/{0000_magical_madame_hydra.sql → 0000_moaning_luckman.sql} +4 -15
  13. package/document-management/server/drizzle/meta/0000_snapshot.json +25 -96
  14. package/document-management/server/drizzle/meta/_journal.json +2 -2
  15. package/document-management/server/index.d.ts +1 -0
  16. package/document-management/server/index.js +1 -0
  17. package/document-management/server/module.d.ts +3 -2
  18. package/document-management/server/module.js +2 -6
  19. package/document-management/server/services/document-category-type.service.d.ts +0 -1
  20. package/document-management/server/services/document-category-type.service.js +7 -7
  21. package/document-management/server/services/document-file.service.js +2 -2
  22. package/document-management/server/services/document-management-ai.service.js +5 -1
  23. package/document-management/server/services/document-management-ancillary.service.d.ts +2 -83
  24. package/document-management/server/services/document-management-ancillary.service.js +1 -23
  25. package/document-management/server/services/document-management-authorization.service.d.ts +85 -0
  26. package/document-management/server/services/document-management-authorization.service.js +28 -0
  27. package/document-management/server/services/document-management.service.d.ts +10 -2
  28. package/document-management/server/services/document-management.service.js +69 -6
  29. package/document-management/server/services/document-property.service.d.ts +7 -3
  30. package/document-management/server/services/document-property.service.js +8 -4
  31. package/document-management/server/services/document-workflow.service.js +2 -2
  32. package/document-management/server/services/enum-type-key.d.ts +1 -0
  33. package/document-management/server/services/enum-type-key.js +1 -0
  34. package/document-management/server/services/index.d.ts +1 -0
  35. package/document-management/server/services/index.js +1 -0
  36. package/document-management/service-models/enriched/enriched-document-category.view.d.ts +1 -0
  37. package/document-management/service-models/enriched/enriched-document-category.view.js +8 -0
  38. package/document-management/service-models/enriched/enriched-document.view.d.ts +3 -1
  39. package/document-management/service-models/enriched/enriched-document.view.js +2 -0
  40. package/examples/api/streaming.js +8 -8
  41. package/examples/document-management/categories-and-types.d.ts +357 -312
  42. package/examples/document-management/categories-and-types.js +690 -350
  43. package/examples/document-management/main.d.ts +18 -16
  44. package/examples/document-management/main.js +29 -20
  45. package/file/mime-type.d.ts +2 -1
  46. package/file/mime-type.js +10 -18
  47. package/file/mime-types.js +1 -2
  48. package/http/server/http-server-response.js +2 -2
  49. package/package.json +5 -3
  50. package/schema/converters/openapi-converter.js +15 -12
  51. package/sse/server-sent-events-source.js +2 -2
  52. package/utils/object/object.js +1 -1
@@ -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';
@@ -20,9 +22,9 @@ import { WebServerModule } from '../../module/index.js';
20
22
  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';
25
+ import { configureDefaultSignalsImplementation } from '../../signals/implementation/configure.js';
23
26
  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';
27
+ import { TstdlCategoryParents, TstdlDocumentCategoryLabels, TstdlDocumentPropertyConfiguration, TstdlDocumentTypeCategories, TstdlDocumentTypeLabels, TstdlDocumentTypeProperties } from './categories-and-types.js';
26
28
  const config = {
27
29
  database: {
28
30
  host: string('DATABASE_HOST', '127.0.0.1'),
@@ -48,36 +50,42 @@ const config = {
48
50
  bucketPerModule: boolean('S3_BUCKET_PER_MODULE', true),
49
51
  },
50
52
  };
51
- const userId = crypto.randomUUID();
52
53
  let ExampleDocumentManagementAncillaryService = class ExampleDocumentManagementAncillaryService extends DocumentManagementAncillaryService {
53
54
  _resolveMetadata(collections) {
54
55
  return collections.map((collection) => ({ name: collection.id.split('-')[0], group: null }));
55
56
  }
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
57
  };
71
58
  ExampleDocumentManagementAncillaryService = __decorate([
72
59
  Singleton()
73
60
  ], ExampleDocumentManagementAncillaryService);
74
61
  export { ExampleDocumentManagementAncillaryService };
62
+ let AllowAllDocumentManagementAuthorizationService = class AllowAllDocumentManagementAuthorizationService extends DocumentManagementAuthorizationService {
63
+ getSubject() { return '00000000-0000-0000-0000-000000000000'; }
64
+ canReadCollection() { return true; }
65
+ canCreateDocuments() { return true; }
66
+ canUpdateDocuments() { return true; }
67
+ canDeleteDocuments() { return true; }
68
+ canAssignDocuments() { return true; }
69
+ canApproveDocument() { return true; }
70
+ canRejectDocument() { return true; }
71
+ canManageRequests() { return true; }
72
+ canManageCategoriesAndTypes() { return true; }
73
+ canReadDocumentRequestsTemplates() { return true; }
74
+ canManageDocumentRequestsTemplates() { return true; }
75
+ canManageValidationDefinitions() { return true; }
76
+ canProgressDocumentWorkflow() { return true; }
77
+ };
78
+ AllowAllDocumentManagementAuthorizationService = __decorate([
79
+ Singleton()
80
+ ], AllowAllDocumentManagementAuthorizationService);
81
+ export { AllowAllDocumentManagementAuthorizationService };
75
82
  async function bootstrap() {
76
83
  const injector = inject(Injector);
77
84
  configureTstdl();
78
85
  configureNodeHttpServer();
79
86
  configurePostgresQueue();
80
87
  configureLocalMessageBus();
88
+ configureDefaultSignalsImplementation();
81
89
  configureOrm({
82
90
  connection: {
83
91
  host: config.database.host,
@@ -89,6 +97,7 @@ async function bootstrap() {
89
97
  });
90
98
  configureDocumentManagement({
91
99
  ancillaryService: ExampleDocumentManagementAncillaryService,
100
+ authorizationService: AllowAllDocumentManagementAuthorizationService,
92
101
  fileObjectStorageModule: 'documents',
93
102
  fileUploadObjectStorageModule: 'document-uploads',
94
103
  filePreviewObjectStorageModule: 'document-previews',
@@ -122,7 +131,7 @@ async function bootstrap() {
122
131
  }
123
132
  async function main() {
124
133
  const [documentManagementService, documentCollectionService] = await injectManyAsync(DocumentManagementService, DocumentCollectionService, DocumentCategoryTypeService, DocumentRequestService);
125
- const { categories, types } = await documentManagementService.initializeCategoriesAndTypes(TstdlDocumentCategoryLabels, TstdlCategoryParents, TstdlDocumentTypeLabels, TstdlDocumentTypeCategories);
134
+ const { categories, types } = await documentManagementService.initializeCategoriesAndTypes(TstdlDocumentCategoryLabels, TstdlCategoryParents, TstdlDocumentTypeLabels, TstdlDocumentTypeCategories, TstdlDocumentPropertyConfiguration, TstdlDocumentTypeProperties);
126
135
  const collectionCount = await documentCollectionService.repository.count();
127
136
  for (let i = 0; i < (3 - collectionCount); i++) {
128
137
  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/node';
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.140",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -51,6 +51,7 @@
51
51
  "./browser": "./browser/index.js",
52
52
  "./cancellation": "./cancellation/index.js",
53
53
  "./cookie": "./cookie/index.js",
54
+ "./css": "./css/index.js",
54
55
  "./data-structures": "./data-structures/index.js",
55
56
  "./database": "./database/index.js",
56
57
  "./database/mongo": "./database/mongo/index.js",
@@ -144,7 +145,7 @@
144
145
  "peerDependencies": {
145
146
  "@elastic/elasticsearch": "^9.0",
146
147
  "@google-cloud/storage": "7.16",
147
- "@google/genai": "^1.0",
148
+ "@google/genai": "^1.1",
148
149
  "@tstdl/angular": "^0.92",
149
150
  "@zxcvbn-ts/core": "^3.0",
150
151
  "@zxcvbn-ts/language-common": "^3.0",
@@ -152,6 +153,7 @@
152
153
  "@zxcvbn-ts/language-en": "^3.0",
153
154
  "chroma-js": "^2.6",
154
155
  "drizzle-orm": "^0.43",
156
+ "file-type": "^21.0",
155
157
  "handlebars": "^4.7",
156
158
  "minio": "^8.0",
157
159
  "mjml": "^4.15",
@@ -183,7 +185,7 @@
183
185
  "concurrently": "9.1",
184
186
  "drizzle-kit": "0.31",
185
187
  "eslint": "9.27",
186
- "globals": "16.1",
188
+ "globals": "16.2",
187
189
  "tsc-alias": "1.8",
188
190
  "typedoc-plugin-missing-exports": "4.0",
189
191
  "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.`);
@@ -42,11 +42,11 @@ export class ServerSentEventsSource {
42
42
  await this.#writer.write(message);
43
43
  }
44
44
  async sendJson({ name, data, id, retry }) {
45
- return this.sendText({
45
+ await this.sendText({
46
46
  name,
47
47
  data: JSON.stringify(data),
48
48
  id,
49
- retry
49
+ retry,
50
50
  });
51
51
  }
52
52
  }
@@ -49,7 +49,7 @@ export function filterObject(object, predicate) {
49
49
  }
50
50
  export async function filterObjectAsync(object, predicate) {
51
51
  const entries = objectEntries(object);
52
- const mappedEntries = await toArrayAsync(filterAsync(entries, async ([key, value]) => predicate(value, key)));
52
+ const mappedEntries = await toArrayAsync(filterAsync(entries, async ([key, value]) => await predicate(value, key)));
53
53
  return Object.fromEntries(mappedEntries);
54
54
  }
55
55
  export function filterUndefinedFromRecord(record) {