@tstdl/base 0.93.93 → 0.93.95
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.
- package/api/response.js +1 -1
- package/authentication/client/authentication.service.js +1 -1
- package/{utils/format-error.js → errors/format.js} +32 -26
- package/errors/index.d.ts +1 -0
- package/errors/index.js +1 -0
- package/errors/tests/format.test.d.ts +1 -0
- package/errors/tests/format.test.js +84 -0
- package/http/http.error.d.ts +1 -1
- package/logger/formatters/json.js +2 -2
- package/logger/formatters/pretty-print.js +16 -4
- package/logger/formatters/pretty-print.test.d.ts +1 -0
- package/logger/formatters/pretty-print.test.js +60 -0
- package/mail/mail.service.js +1 -1
- package/orm/decorators.d.ts +5 -5
- package/package.json +1 -1
- package/rpc/rpc.error.js +1 -1
- package/schema/schema.error.d.ts +1 -1
- package/task-queue/postgres/task-queue.js +1 -1
- package/task-queue/task-context.d.ts +4 -0
- package/task-queue/task-context.js +12 -0
- package/test-column-builder.d.ts +22 -0
- package/test-column-builder.js +1 -0
- package/test4.d.ts +0 -22
- package/test4.js +8 -122
- package/test5.js +8 -6
- package/utils/index.d.ts +0 -1
- package/utils/index.js +0 -1
- /package/{utils/format-error.d.ts → errors/format.d.ts} +0 -0
package/api/response.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SecretRequirementsError } from '../authentication/errors/secret-requirements.error.js';
|
|
2
2
|
import { SchemaError } from '../schema/schema.error.js';
|
|
3
|
-
import { formatError } from '../
|
|
3
|
+
import { formatError } from '../errors/index.js';
|
|
4
4
|
import { ApiError, BadRequestError, ForbiddenError, InvalidCredentialsError, InvalidTokenError, MaxBytesExceededError, MethodNotAllowedError, NotFoundError, NotImplementedError, NotSupportedError, UnauthorizedError, UnsupportedMediaTypeError } from '../errors/index.js';
|
|
5
5
|
import { assertString, isDefined, isFunction, isObject, isString } from '../utils/type-guards.js';
|
|
6
6
|
import { deserializeSchemaError, serializeSchemaError } from './default-error-handlers.js';
|
|
@@ -21,7 +21,7 @@ import { Logger } from '../../logger/index.js';
|
|
|
21
21
|
import { MessageBus } from '../../message-bus/index.js';
|
|
22
22
|
import { computed, signal, toObservable } from '../../signals/api.js';
|
|
23
23
|
import { currentTimestampSeconds } from '../../utils/date-time.js';
|
|
24
|
-
import { formatError } from '../../
|
|
24
|
+
import { formatError } from '../../errors/index.js';
|
|
25
25
|
import { timeout } from '../../utils/timing.js';
|
|
26
26
|
import { assertDefinedPass, isDefined, isNotFunction, isNullOrUndefined, isUndefined } from '../../utils/type-guards.js';
|
|
27
27
|
import { millisecondsPerMinute, millisecondsPerSecond } from '../../utils/units.js';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { isArray, isDefined, isFunction, isObject, isString, isUndefined } from './type-guards.js';
|
|
1
|
+
import { decycle, objectKeys } from '../utils/object/index.js';
|
|
2
|
+
import { tryChain } from '../utils/try-chain.js';
|
|
3
|
+
import { isArray, isDefined, isFunction, isObject, isString, isUndefined } from '../utils/type-guards.js';
|
|
4
|
+
import { unwrapError } from './utils.js';
|
|
6
5
|
export function serializeError(error, options = {}) {
|
|
7
6
|
const { includeName = true, includeRest = 'if-no-extra-info', includeExtraInfo = true, includeStack = true, depth = 5, } = options;
|
|
8
7
|
if (depth <= 0) {
|
|
@@ -97,39 +96,46 @@ function formatSerializedError(serialized, options) {
|
|
|
97
96
|
const { includeName = true, includeStack = true, depth = 5 } = options;
|
|
98
97
|
// 1. Header (Name: Message)
|
|
99
98
|
const prefix = includeName && name ? `${name}: ` : '';
|
|
100
|
-
const
|
|
99
|
+
const messageString = String(message);
|
|
100
|
+
const header = `${prefix}${messageString}`;
|
|
101
|
+
const alignedHeader = (prefix.length > 0 && messageString.includes('\n'))
|
|
102
|
+
? `${prefix}${messageString.replace(/\n/g, `\n${' '.repeat(prefix.length)}`)}`
|
|
103
|
+
: header;
|
|
104
|
+
let formatted = alignedHeader;
|
|
101
105
|
// 2. Body (Rest / Extra Info)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
body += `\n${JSON.stringify(rest, null, 2)}`;
|
|
106
|
+
if (isDefined(rest)) {
|
|
107
|
+
formatted += `\n${indent(JSON.stringify(rest, null, 2), 4)}`;
|
|
105
108
|
}
|
|
106
|
-
if (extraInfo) {
|
|
107
|
-
|
|
109
|
+
if (isDefined(extraInfo)) {
|
|
110
|
+
formatted += `\n${indent(JSON.stringify(extraInfo, null, 2), 4)}`;
|
|
108
111
|
}
|
|
109
112
|
// 3. Stack Trace
|
|
110
|
-
|
|
111
|
-
if (includeStack && stack) {
|
|
113
|
+
if (includeStack && isDefined(stack)) {
|
|
112
114
|
// Deduplicate header if stack already starts with it (standard Node.js behavior)
|
|
113
115
|
if (stack.startsWith(header)) {
|
|
114
|
-
|
|
116
|
+
formatted += stack.slice(header.length);
|
|
115
117
|
}
|
|
116
118
|
else {
|
|
117
|
-
|
|
119
|
+
formatted += `\n${stack}`;
|
|
118
120
|
}
|
|
119
121
|
}
|
|
120
122
|
// 4. Recursion (Causes and Aggregate Errors)
|
|
121
123
|
const nextOptions = { ...options, depth: depth - 1 };
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return
|
|
124
|
+
if (includeStack && isDefined(cause)) {
|
|
125
|
+
formatted += formatNestedError('Caused by:', cause, nextOptions);
|
|
126
|
+
}
|
|
127
|
+
if (isArray(aggregateErrors)) {
|
|
128
|
+
for (const [index, err] of aggregateErrors.entries()) {
|
|
129
|
+
formatted += formatNestedError(`Sub-error #${index + 1}:`, err, nextOptions);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return formatted;
|
|
131
133
|
}
|
|
132
134
|
function formatNestedError(prefix, serializedError, options) {
|
|
133
|
-
const formatted = formatSerializedError(serializedError, options)
|
|
134
|
-
return `\n
|
|
135
|
+
const formatted = formatSerializedError(serializedError, options);
|
|
136
|
+
return `\n${prefix}\n${indent(formatted, 2)}`;
|
|
137
|
+
}
|
|
138
|
+
function indent(text, spaces) {
|
|
139
|
+
const indentation = ' '.repeat(spaces);
|
|
140
|
+
return text.split('\n').map((line) => (line.length > 0 ? `${indentation}${line}` : line)).join('\n');
|
|
135
141
|
}
|
package/errors/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from './custom.error.js';
|
|
|
10
10
|
export * from './details.error.js';
|
|
11
11
|
export * from './errors.localization.js';
|
|
12
12
|
export * from './forbidden.error.js';
|
|
13
|
+
export * from './format.js';
|
|
13
14
|
export * from './invalid-credentials.error.js';
|
|
14
15
|
export * from './invalid-token.error.js';
|
|
15
16
|
export * from './max-bytes-exceeded.error.js';
|
package/errors/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export * from './custom.error.js';
|
|
|
10
10
|
export * from './details.error.js';
|
|
11
11
|
export * from './errors.localization.js';
|
|
12
12
|
export * from './forbidden.error.js';
|
|
13
|
+
export * from './format.js';
|
|
13
14
|
export * from './invalid-credentials.error.js';
|
|
14
15
|
export * from './invalid-token.error.js';
|
|
15
16
|
export * from './max-bytes-exceeded.error.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { formatError } from '../format.js';
|
|
3
|
+
describe('formatError', () => {
|
|
4
|
+
it('should format a simple error', () => {
|
|
5
|
+
const error = new Error('test message');
|
|
6
|
+
const formatted = formatError(error, { includeStack: false });
|
|
7
|
+
expect(formatted).toBe('Error: test message');
|
|
8
|
+
});
|
|
9
|
+
it('should align multi-line messages', () => {
|
|
10
|
+
const error = new Error('line 1\nline 2');
|
|
11
|
+
const formatted = formatError(error, { includeStack: false });
|
|
12
|
+
expect(formatted).toBe('Error: line 1\n line 2');
|
|
13
|
+
});
|
|
14
|
+
it('should format nested errors with causes', () => {
|
|
15
|
+
const cause = new Error('cause message');
|
|
16
|
+
const error = new Error('top message', { cause });
|
|
17
|
+
const formatted = formatError(error, { includeStack: true });
|
|
18
|
+
expect(formatted).toContain('Error: top message');
|
|
19
|
+
expect(formatted).toContain('Caused by:');
|
|
20
|
+
expect(formatted).toContain('Error: cause message');
|
|
21
|
+
});
|
|
22
|
+
it('should deduplicate stack header', () => {
|
|
23
|
+
const error = new Error('test message');
|
|
24
|
+
const formatted = formatError(error, { includeStack: true });
|
|
25
|
+
const lines = formatted.split('\n');
|
|
26
|
+
expect(lines[0]).toBe('Error: test message');
|
|
27
|
+
expect(lines[1].trim()).toMatch(/^at /);
|
|
28
|
+
});
|
|
29
|
+
it('should handle multi-line message alignment with stack deduplication', () => {
|
|
30
|
+
const error = new Error('multi\nline');
|
|
31
|
+
const formatted = formatError(error, { includeStack: true });
|
|
32
|
+
expect(formatted).toContain('Error: multi\n line');
|
|
33
|
+
const lines = formatted.split('\n');
|
|
34
|
+
expect(lines[0]).toBe('Error: multi');
|
|
35
|
+
expect(lines[1]).toBe(' line');
|
|
36
|
+
expect(lines[2].trim()).toMatch(/^at /);
|
|
37
|
+
});
|
|
38
|
+
it('should format rest properties', () => {
|
|
39
|
+
const error = new Error('message');
|
|
40
|
+
error.code = 'ERR_CODE';
|
|
41
|
+
error.details = { foo: 'bar' };
|
|
42
|
+
const formatted = formatError(error, { includeStack: false, includeRest: true });
|
|
43
|
+
expect(formatted).toContain('Error: message');
|
|
44
|
+
expect(formatted).toContain('"code": "ERR_CODE"');
|
|
45
|
+
expect(formatted).toContain('"foo": "bar"');
|
|
46
|
+
});
|
|
47
|
+
it('should format AggregateError', () => {
|
|
48
|
+
const error1 = new Error('sub error 1');
|
|
49
|
+
const error2 = new Error('sub error 2');
|
|
50
|
+
const aggregateError = new AggregateError([error1, error2], 'aggregate message');
|
|
51
|
+
const formatted = formatError(aggregateError, { includeStack: false });
|
|
52
|
+
expect(formatted).toContain('AggregateError: aggregate message');
|
|
53
|
+
expect(formatted).toContain('Sub-error #1:');
|
|
54
|
+
expect(formatted).toContain('Error: sub error 1');
|
|
55
|
+
expect(formatted).toContain('Sub-error #2:');
|
|
56
|
+
expect(formatted).toContain('Error: sub error 2');
|
|
57
|
+
});
|
|
58
|
+
it('should handle deep cause chains', () => {
|
|
59
|
+
const cause2 = new Error('bottom');
|
|
60
|
+
const cause1 = new Error('middle', { cause: cause2 });
|
|
61
|
+
const error = new Error('top', { cause: cause1 });
|
|
62
|
+
const formatted = formatError(error, { includeStack: true });
|
|
63
|
+
expect(formatted).toContain('Error: top');
|
|
64
|
+
expect(formatted).toContain('Caused by:\n Error: middle');
|
|
65
|
+
expect(formatted).toContain('\n Caused by:\n Error: bottom');
|
|
66
|
+
});
|
|
67
|
+
it('should handle non-error objects', () => {
|
|
68
|
+
const obj = { foo: 'bar', baz: 123 };
|
|
69
|
+
const formatted = formatError(obj);
|
|
70
|
+
expect(formatted).toContain('"foo": "bar"');
|
|
71
|
+
expect(formatted).toContain('"baz": 123');
|
|
72
|
+
});
|
|
73
|
+
it('should handle errors with empty messages', () => {
|
|
74
|
+
const error = new Error('');
|
|
75
|
+
error.name = 'CustomError';
|
|
76
|
+
const formatted = formatError(error, { includeStack: false });
|
|
77
|
+
expect(formatted).toBe('CustomError: ');
|
|
78
|
+
});
|
|
79
|
+
it('should handle null or undefined', () => {
|
|
80
|
+
// Current behavior defaults name to 'Error' for non-raw-object fallback
|
|
81
|
+
expect(formatError(null)).toBe('Error: null');
|
|
82
|
+
expect(formatError(undefined)).toBe('Error: undefined');
|
|
83
|
+
});
|
|
84
|
+
});
|
package/http/http.error.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type EnumType } from '../enumeration/enumeration.js';
|
|
2
2
|
import type { TypedOmit, UndefinableJson } from '../types/index.js';
|
|
3
|
-
import type { ErrorExtraInfo } from '../
|
|
3
|
+
import type { ErrorExtraInfo } from '../errors/index.js';
|
|
4
4
|
import { CustomError } from '../errors/custom.error.js';
|
|
5
5
|
import type { HttpClientRequest, HttpClientRequestObject, HttpClientResponse, HttpClientResponseObject } from './client/index.js';
|
|
6
6
|
export declare const HttpErrorReason: {
|
|
@@ -6,7 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { Singleton } from '../../injector/decorators.js';
|
|
8
8
|
import { enumValueName } from '../../utils/enum.js';
|
|
9
|
-
import { formatError } from '../../
|
|
9
|
+
import { formatError } from '../../errors/index.js';
|
|
10
10
|
import { isNotNullOrUndefined } from '../../utils/type-guards.js';
|
|
11
11
|
import { LogFormatter } from '../formatter.js';
|
|
12
12
|
import { LogLevel } from '../level.js';
|
|
@@ -22,7 +22,7 @@ let JsonLogFormatter = class JsonLogFormatter extends LogFormatter {
|
|
|
22
22
|
};
|
|
23
23
|
// Special handling for error objects to make them serializable
|
|
24
24
|
if (isNotNullOrUndefined(payload.error)) {
|
|
25
|
-
logObject['error'] = formatError(payload.error
|
|
25
|
+
logObject['error'] = formatError(payload.error);
|
|
26
26
|
}
|
|
27
27
|
return JSON.stringify(logObject);
|
|
28
28
|
}
|
|
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { Singleton } from '../../injector/decorators.js';
|
|
8
8
|
import { supportsColoredStdout } from '../../supports.js';
|
|
9
9
|
import { enumValueName } from '../../utils/enum.js';
|
|
10
|
-
import { formatError } from '../../
|
|
10
|
+
import { formatError } from '../../errors/index.js';
|
|
11
11
|
import { objectKeys } from '../../utils/object/object.js';
|
|
12
12
|
import { isNotNullOrUndefined } from '../../utils/type-guards.js';
|
|
13
13
|
import { LogFormatter } from '../formatter.js';
|
|
@@ -41,9 +41,21 @@ let PrettyPrintLogFormatter = class PrettyPrintLogFormatter extends LogFormatter
|
|
|
41
41
|
if (objectKeys(displayMeta).length > 0) {
|
|
42
42
|
metadataString = ` ${dimColor}${JSON.stringify(displayMeta)}${resetColor}`;
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
}
|
|
45
|
+
if (isNotNullOrUndefined(payload.error)) {
|
|
46
|
+
const formattedError = formatError(payload.error);
|
|
47
|
+
errorString += `\n${formattedError
|
|
48
|
+
.split('\n')
|
|
49
|
+
.map((line) => {
|
|
50
|
+
if (line.trim().startsWith('at ')) {
|
|
51
|
+
return `${dimColor}${line}${resetColor}`;
|
|
52
|
+
}
|
|
53
|
+
if (line.startsWith('Caused by:') || line.startsWith('Sub-error #')) {
|
|
54
|
+
return `${color}${line}${resetColor}`;
|
|
55
|
+
}
|
|
56
|
+
return line;
|
|
57
|
+
})
|
|
58
|
+
.join('\n')}`;
|
|
47
59
|
}
|
|
48
60
|
return `${dimColor}${payload.timestamp.toISOString()}${resetColor} ${color}${levelString}${resetColor} ${moduleString}${moduleString.length > 0 ? ' ' : ''}${payload.message}${metadataString}${errorString}`;
|
|
49
61
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
// Mock supports before importing PrettyPrintLogFormatter
|
|
3
|
+
vi.mock('#/supports.js', () => ({
|
|
4
|
+
supportsColoredStdout: true,
|
|
5
|
+
supportsColoredStderr: true,
|
|
6
|
+
}));
|
|
7
|
+
import { LogLevel } from '../level.js';
|
|
8
|
+
import { PrettyPrintLogFormatter } from './pretty-print.js';
|
|
9
|
+
describe('PrettyPrintLogFormatter', () => {
|
|
10
|
+
const formatter = new PrettyPrintLogFormatter();
|
|
11
|
+
it('should format a log entry with an error and no context', () => {
|
|
12
|
+
const error = new Error('test error');
|
|
13
|
+
const payload = {
|
|
14
|
+
timestamp: new Date('2026-01-22T13:00:00.000Z'),
|
|
15
|
+
level: LogLevel.Error,
|
|
16
|
+
module: ['Test'],
|
|
17
|
+
message: 'something failed',
|
|
18
|
+
interpolationKeys: [],
|
|
19
|
+
context: {},
|
|
20
|
+
error,
|
|
21
|
+
};
|
|
22
|
+
const formatted = formatter.format(payload);
|
|
23
|
+
expect(formatted).toContain('ERROR:');
|
|
24
|
+
expect(formatted).toContain('[Test]');
|
|
25
|
+
expect(formatted).toContain('something failed');
|
|
26
|
+
expect(formatted).toContain('Error: test error');
|
|
27
|
+
expect(formatted).toContain('at '); // Should include stack trace
|
|
28
|
+
});
|
|
29
|
+
it('should dim stack trace lines', () => {
|
|
30
|
+
const error = new Error('test error');
|
|
31
|
+
const payload = {
|
|
32
|
+
timestamp: new Date('2026-01-22T13:00:00.000Z'),
|
|
33
|
+
level: LogLevel.Error,
|
|
34
|
+
module: ['Test'],
|
|
35
|
+
message: 'something failed',
|
|
36
|
+
interpolationKeys: [],
|
|
37
|
+
context: {},
|
|
38
|
+
error,
|
|
39
|
+
};
|
|
40
|
+
const formatted = formatter.format(payload);
|
|
41
|
+
// Check for dim color escape code \x1b[2m before "at " (including indentation)
|
|
42
|
+
expect(formatted).toContain('\x1b[2m at ');
|
|
43
|
+
});
|
|
44
|
+
it('should highlight "Caused by:" with level color', () => {
|
|
45
|
+
const cause = new Error('the cause');
|
|
46
|
+
const error = new Error('the error', { cause });
|
|
47
|
+
const payload = {
|
|
48
|
+
timestamp: new Date('2026-01-22T13:00:00.000Z'),
|
|
49
|
+
level: LogLevel.Error,
|
|
50
|
+
module: ['Test'],
|
|
51
|
+
message: 'failed',
|
|
52
|
+
interpolationKeys: [],
|
|
53
|
+
context: {},
|
|
54
|
+
error,
|
|
55
|
+
};
|
|
56
|
+
const formatted = formatter.format(payload);
|
|
57
|
+
// LogLevel.Error color is \x1b[31m
|
|
58
|
+
expect(formatted).toContain('\x1b[31mCaused by:');
|
|
59
|
+
});
|
|
60
|
+
});
|
package/mail/mail.service.js
CHANGED
|
@@ -9,7 +9,7 @@ import { Logger } from '../logger/index.js';
|
|
|
9
9
|
import { DatabaseConfig, injectRepository } from '../orm/server/index.js';
|
|
10
10
|
import { TemplateService } from '../templates/template.service.js';
|
|
11
11
|
import { currentTimestamp } from '../utils/date-time.js';
|
|
12
|
-
import { formatError } from '../
|
|
12
|
+
import { formatError } from '../errors/index.js';
|
|
13
13
|
import { assertDefined } from '../utils/type-guards.js';
|
|
14
14
|
import { MailClient, MailClientConfig } from './mail.client.js';
|
|
15
15
|
import { MailLog } from './models/index.js';
|
package/orm/decorators.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { LiteralUnion, SetRequired } from 'type-fest';
|
|
|
8
8
|
import { type SpecificCreateDecoratorOptions } from '../reflection/index.js';
|
|
9
9
|
import type { AbstractConstructor, Record, TypedOmit } from '../types/index.js';
|
|
10
10
|
import type { ValueOrProvider } from '../utils/value-or-provider.js';
|
|
11
|
-
import type { AnyEntity, BaseEntity,
|
|
11
|
+
import type { AnyEntity, BaseEntity, EntityType } from './entity.js';
|
|
12
12
|
import type { Query } from './query/index.js';
|
|
13
13
|
import type { TargetColumn, TargetColumnPath } from './repository.types.js';
|
|
14
14
|
import type { ExtraConfigColumnsFromType } from './server/types.js';
|
|
@@ -46,7 +46,7 @@ export type OrmTableReflectionData<T extends BaseEntity = BaseEntity> = {
|
|
|
46
46
|
index?: IndexReflectionData[];
|
|
47
47
|
paradeIndex?: ParadeIndexReflectionData<T>;
|
|
48
48
|
propertyOverrides?: Record<string, OrmColumnReflectionData>;
|
|
49
|
-
checks?: CheckReflectionData[];
|
|
49
|
+
checks?: CheckReflectionData<T>[];
|
|
50
50
|
foreignKeys?: ForeignKeyReflectionData[];
|
|
51
51
|
inheritance?: InheritanceMetadata<T>;
|
|
52
52
|
childEntity?: ChildEntityMetadata;
|
|
@@ -108,9 +108,9 @@ export type IndexReflectionData<T extends BaseEntity = any> = {
|
|
|
108
108
|
order?: 'asc' | 'desc';
|
|
109
109
|
options?: IndexOptions<T>;
|
|
110
110
|
};
|
|
111
|
-
type CheckReflectionData = {
|
|
111
|
+
export type CheckReflectionData<T extends BaseEntity = any> = {
|
|
112
112
|
name: string;
|
|
113
|
-
builder: CheckBuilder
|
|
113
|
+
builder: CheckBuilder<T>;
|
|
114
114
|
options?: {
|
|
115
115
|
naming?: NamingStrategy;
|
|
116
116
|
};
|
|
@@ -266,7 +266,7 @@ export declare function TenantReference<T extends AnyEntity>(target: () => Entit
|
|
|
266
266
|
* @param name The name of the check constraint.
|
|
267
267
|
* @param builder A function to build the SQL check expression.
|
|
268
268
|
*/
|
|
269
|
-
export declare function Check<T extends
|
|
269
|
+
export declare function Check<T extends BaseEntity>(name: string, builder: CheckBuilder<T>): ClassDecorator;
|
|
270
270
|
/**
|
|
271
271
|
* Mark a column for encryption.
|
|
272
272
|
* The underlying database type will typically be `bytea`.
|
package/package.json
CHANGED
package/rpc/rpc.error.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CustomError } from '../errors/custom.error.js';
|
|
2
|
-
import { formatError } from '../
|
|
2
|
+
import { formatError } from '../errors/index.js';
|
|
3
3
|
import { isDefined, isObject } from '../utils/type-guards.js';
|
|
4
4
|
export class RpcError extends CustomError {
|
|
5
5
|
static errorName = 'RpcError';
|
package/schema/schema.error.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CustomError, type CustomErrorOptions } from '../errors/custom.error.js';
|
|
2
2
|
import type { JsonPath } from '../json-path/index.js';
|
|
3
3
|
import type { AbstractConstructor, OneOrMany, TypedOmit, UndefinableJson } from '../types/index.js';
|
|
4
|
-
import type { ErrorExtraInfo } from '../
|
|
4
|
+
import type { ErrorExtraInfo } from '../errors/index.js';
|
|
5
5
|
export type SchemaErrorOptions = Pick<CustomErrorOptions, 'fast'> & {
|
|
6
6
|
path: string | JsonPath;
|
|
7
7
|
details?: UndefinableJson;
|
|
@@ -69,7 +69,7 @@ import { RateLimiter } from '../../rate-limit/index.js';
|
|
|
69
69
|
import { createArray, distinct, toArray } from '../../utils/array/array.js';
|
|
70
70
|
import { digest } from '../../utils/cryptography.js';
|
|
71
71
|
import { currentTimestamp } from '../../utils/date-time.js';
|
|
72
|
-
import { serializeError } from '../../
|
|
72
|
+
import { serializeError } from '../../errors/index.js';
|
|
73
73
|
import { cancelableTimeout } from '../../utils/timing.js';
|
|
74
74
|
import { isDefined, isNotNull, isNull, isString, isUndefined } from '../../utils/type-guards.js';
|
|
75
75
|
import { millisecondsPerSecond } from '../../utils/units.js';
|
|
@@ -8,6 +8,10 @@ export declare class TaskContext<Definitions extends TaskDefinitionMap, Type ext
|
|
|
8
8
|
constructor(queue: TaskQueue<Definitions>, task: TaskOfType<Definitions, Type>, signal: CancellationToken, logger: Logger);
|
|
9
9
|
get id(): string;
|
|
10
10
|
get type(): Type;
|
|
11
|
+
get parentId(): string | null;
|
|
12
|
+
get tags(): string[];
|
|
13
|
+
get completeAfterTags(): string[];
|
|
14
|
+
get scheduleAfterTags(): string[];
|
|
11
15
|
get data(): TaskData<Definitions, Type>;
|
|
12
16
|
get state(): TaskState<Definitions, Type> | null;
|
|
13
17
|
get attempt(): number;
|
|
@@ -18,6 +18,18 @@ export class TaskContext {
|
|
|
18
18
|
get type() {
|
|
19
19
|
return this.#task.type;
|
|
20
20
|
}
|
|
21
|
+
get parentId() {
|
|
22
|
+
return this.#task.parentId;
|
|
23
|
+
}
|
|
24
|
+
get tags() {
|
|
25
|
+
return this.#task.tags;
|
|
26
|
+
}
|
|
27
|
+
get completeAfterTags() {
|
|
28
|
+
return this.#task.completeAfterTags;
|
|
29
|
+
}
|
|
30
|
+
get scheduleAfterTags() {
|
|
31
|
+
return this.#task.scheduleAfterTags;
|
|
32
|
+
}
|
|
21
33
|
get data() {
|
|
22
34
|
return this.#task.data;
|
|
23
35
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ColumnBuilder } from './orm/types.js';
|
|
2
|
+
import type { Uuid, Timestamp, Json, IsPrimaryKey, HasDefault } from './orm/types.js';
|
|
3
|
+
type T1 = ColumnBuilder<string>;
|
|
4
|
+
type T2 = ColumnBuilder<Uuid>;
|
|
5
|
+
type T3 = ColumnBuilder<Timestamp>;
|
|
6
|
+
type T4 = ColumnBuilder<Json<{
|
|
7
|
+
a: number;
|
|
8
|
+
}>>;
|
|
9
|
+
type T5 = ColumnBuilder<IsPrimaryKey<HasDefault<Uuid>>>;
|
|
10
|
+
type IsNever<T> = [T] extends [never] ? true : false;
|
|
11
|
+
export type Results = {
|
|
12
|
+
string: T1;
|
|
13
|
+
uuid: T2;
|
|
14
|
+
timestamp: T3;
|
|
15
|
+
json: T4;
|
|
16
|
+
pk_uuid: T5;
|
|
17
|
+
uuid_is_never: IsNever<T2>;
|
|
18
|
+
timestamp_is_never: IsNever<T3>;
|
|
19
|
+
json_is_never: IsNever<T4>;
|
|
20
|
+
pk_uuid_is_never: IsNever<T5>;
|
|
21
|
+
};
|
|
22
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/test4.d.ts
CHANGED
|
@@ -1,23 +1 @@
|
|
|
1
1
|
import './polyfills.js';
|
|
2
|
-
import { DocumentManagementAuthorizationService, type DocumentCollection, type DocumentCollectionMetadata } from './document-management/index.js';
|
|
3
|
-
import { DocumentManagementAncillaryService } from './document-management/server/index.js';
|
|
4
|
-
export declare class TestDocumentManagementAncillaryService extends DocumentManagementAncillaryService {
|
|
5
|
-
resolveMetadata(_tenantId: string, collections: DocumentCollection[]): DocumentCollectionMetadata[];
|
|
6
|
-
}
|
|
7
|
-
export declare class AllowAllDocumentManagementAuthorizationService extends DocumentManagementAuthorizationService {
|
|
8
|
-
getTenantId(): string;
|
|
9
|
-
getSubject(): string;
|
|
10
|
-
canReadCollection(): boolean;
|
|
11
|
-
canCreateDocuments(): boolean;
|
|
12
|
-
canUpdateDocument(): boolean;
|
|
13
|
-
canDeleteDocuments(): boolean;
|
|
14
|
-
canAssignDocuments(): boolean;
|
|
15
|
-
canApproveDocument(): boolean;
|
|
16
|
-
canRejectDocument(): boolean;
|
|
17
|
-
canManageRequests(): boolean;
|
|
18
|
-
canManageCategoriesAndTypes(): boolean;
|
|
19
|
-
canReadDocumentRequestsTemplates(): boolean;
|
|
20
|
-
canManageDocumentRequestsTemplates(): boolean;
|
|
21
|
-
canManageValidationDefinitions(): boolean;
|
|
22
|
-
canProgressDocumentWorkflow(): boolean;
|
|
23
|
-
}
|
package/test4.js
CHANGED
|
@@ -1,25 +1,10 @@
|
|
|
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
1
|
import './polyfills.js';
|
|
8
|
-
import { configureAiService } from './ai/index.js';
|
|
9
2
|
import { Application } from './application/application.js';
|
|
10
|
-
import { provideModule, provideSignalHandler } from './application/index.js';
|
|
11
|
-
import { DocumentManagementAuthorizationService } from './document-management/index.js';
|
|
12
|
-
import { configureDocumentManagement } from './document-management/server/configure.js';
|
|
13
|
-
import { DocumentManagementAncillaryService, DocumentManagementService } from './document-management/server/index.js';
|
|
14
|
-
import { migrateDocumentManagementSchema } from './document-management/server/module.js';
|
|
15
|
-
import { Singleton } from './injector/decorators.js';
|
|
3
|
+
import { provideInitializer, provideModule, provideSignalHandler } from './application/index.js';
|
|
16
4
|
import { injectAsync } from './injector/inject.js';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { configureOrm } from './orm/server/index.js';
|
|
20
|
-
import { configurePostgresTaskQueue } from './task-queue/postgres/module.js';
|
|
5
|
+
import { PrettyPrintLogFormatter, provideConsoleLogTransport } from './logger/index.js';
|
|
6
|
+
import { configureOrm, Database } from './orm/server/index.js';
|
|
21
7
|
import { boolean, positiveInteger, string } from './utils/config-parser.js';
|
|
22
|
-
import { cancelableTimeout } from './utils/timing.js';
|
|
23
8
|
const config = {
|
|
24
9
|
database: {
|
|
25
10
|
host: string('DATABASE_HOST', '127.0.0.1'),
|
|
@@ -45,36 +30,6 @@ const config = {
|
|
|
45
30
|
bucketPerModule: boolean('S3_BUCKET_PER_MODULE', true),
|
|
46
31
|
},
|
|
47
32
|
};
|
|
48
|
-
let TestDocumentManagementAncillaryService = class TestDocumentManagementAncillaryService extends DocumentManagementAncillaryService {
|
|
49
|
-
resolveMetadata(_tenantId, collections) {
|
|
50
|
-
return collections.map((collection) => ({ name: collection.id, group: null }));
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
TestDocumentManagementAncillaryService = __decorate([
|
|
54
|
-
Singleton()
|
|
55
|
-
], TestDocumentManagementAncillaryService);
|
|
56
|
-
export { TestDocumentManagementAncillaryService };
|
|
57
|
-
let AllowAllDocumentManagementAuthorizationService = class AllowAllDocumentManagementAuthorizationService extends DocumentManagementAuthorizationService {
|
|
58
|
-
getTenantId() { return '00000000-0000-0000-0000-000000000000'; }
|
|
59
|
-
getSubject() { return '00000000-0000-0000-0000-000000000000'; }
|
|
60
|
-
canReadCollection() { return true; }
|
|
61
|
-
canCreateDocuments() { return true; }
|
|
62
|
-
canUpdateDocument() { return true; }
|
|
63
|
-
canDeleteDocuments() { return true; }
|
|
64
|
-
canAssignDocuments() { return true; }
|
|
65
|
-
canApproveDocument() { return true; }
|
|
66
|
-
canRejectDocument() { return true; }
|
|
67
|
-
canManageRequests() { return true; }
|
|
68
|
-
canManageCategoriesAndTypes() { return true; }
|
|
69
|
-
canReadDocumentRequestsTemplates() { return true; }
|
|
70
|
-
canManageDocumentRequestsTemplates() { return true; }
|
|
71
|
-
canManageValidationDefinitions() { return true; }
|
|
72
|
-
canProgressDocumentWorkflow() { return true; }
|
|
73
|
-
};
|
|
74
|
-
AllowAllDocumentManagementAuthorizationService = __decorate([
|
|
75
|
-
Singleton()
|
|
76
|
-
], AllowAllDocumentManagementAuthorizationService);
|
|
77
|
-
export { AllowAllDocumentManagementAuthorizationService };
|
|
78
33
|
async function bootstrap() {
|
|
79
34
|
configureOrm({
|
|
80
35
|
connection: {
|
|
@@ -86,83 +41,14 @@ async function bootstrap() {
|
|
|
86
41
|
},
|
|
87
42
|
repositoryConfig: { schema: 'vitrass' },
|
|
88
43
|
});
|
|
89
|
-
configureS3ObjectStorage({
|
|
90
|
-
endpoint: config.s3.endpoint,
|
|
91
|
-
bucket: config.s3.bucket,
|
|
92
|
-
bucketPerModule: config.s3.bucketPerModule,
|
|
93
|
-
accessKey: config.s3.accessKey,
|
|
94
|
-
secretKey: config.s3.secretKey,
|
|
95
|
-
});
|
|
96
|
-
configureDocumentManagement({
|
|
97
|
-
ancillaryService: TestDocumentManagementAncillaryService,
|
|
98
|
-
authorizationService: AllowAllDocumentManagementAuthorizationService,
|
|
99
|
-
fileObjectStorageModule: 'documents',
|
|
100
|
-
fileUploadObjectStorageModule: 'document-uploads',
|
|
101
|
-
filePreviewObjectStorageModule: 'document-previews',
|
|
102
|
-
});
|
|
103
|
-
configurePostgresTaskQueue();
|
|
104
|
-
configureLocalMessageBus();
|
|
105
|
-
console.log('Configuring AI service');
|
|
106
|
-
configureAiService({
|
|
107
|
-
apiKey: config.ai.apiKey,
|
|
108
|
-
keyFile: config.ai.keyFile,
|
|
109
|
-
});
|
|
110
|
-
await migrateDocumentManagementSchema();
|
|
111
44
|
}
|
|
112
|
-
async function main(
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
console.log(await documentManagementService.createCollection({ metadata: { attributes: { name: 'Patrick Hein' } } }));
|
|
116
|
-
console.log(await documentManagementService.createCollection({ metadata: { attributes: { name: 'Merit Klenk' } } }));
|
|
117
|
-
console.log(await documentManagementService.createCollection({ metadata: { attributes: { name: 'Haus' } } }));
|
|
118
|
-
*/
|
|
119
|
-
const patrickHein = '4396c175-0551-4e70-aed8-13f51d307f4f';
|
|
120
|
-
const meritKlenk = '28cec615-b327-43b0-aae6-f049cef9aa26';
|
|
121
|
-
const haus = '32d9895f-476d-41f1-b79e-359c548957d3';
|
|
122
|
-
const personalausweisType = '2c5c2b21-33ba-4262-ab96-24eaf05864a6';
|
|
123
|
-
const lohnabrechnungType = '735d09c1-1ce9-4a29-ad23-3149b6be56ba';
|
|
124
|
-
const bauplanType = '1b813c5d-1e75-4f59-853a-4272bb9d9c20';
|
|
125
|
-
/*
|
|
126
|
-
const personalausweisProperties = await Promise.all([
|
|
127
|
-
await documentManagementService.createProperty({ label: 'Vorname', dataType: DocumentPropertyDataType.Text }),
|
|
128
|
-
await documentManagementService.createProperty({ label: 'Nachname', dataType: DocumentPropertyDataType.Text }),
|
|
129
|
-
await documentManagementService.createProperty({ label: 'Ausweisnummer', dataType: DocumentPropertyDataType.Text }),
|
|
130
|
-
await documentManagementService.createProperty({ label: 'Geburtsdatum', dataType: DocumentPropertyDataType.Date }),
|
|
131
|
-
await documentManagementService.createProperty({ label: 'Geburtsort', dataType: DocumentPropertyDataType.Text }),
|
|
132
|
-
await documentManagementService.createProperty({ label: 'Staatsangehörigkeit', dataType: DocumentPropertyDataType.Text }),
|
|
133
|
-
await documentManagementService.createProperty({ label: 'Gültig bis', dataType: DocumentPropertyDataType.Date }),
|
|
134
|
-
await documentManagementService.createProperty({ label: 'Ausstellende Behörde', dataType: DocumentPropertyDataType.Text }),
|
|
135
|
-
await documentManagementService.createProperty({ label: 'Anschrift Straße', dataType: DocumentPropertyDataType.Text }),
|
|
136
|
-
await documentManagementService.createProperty({ label: 'Anschrift Hausnummer', dataType: DocumentPropertyDataType.Text }),
|
|
137
|
-
await documentManagementService.createProperty({ label: 'Anschrift Postleitzahl', dataType: DocumentPropertyDataType.Text }),
|
|
138
|
-
await documentManagementService.createProperty({ label: 'Anschrift Stadt', dataType: DocumentPropertyDataType.Text })
|
|
139
|
-
]);
|
|
140
|
-
|
|
141
|
-
const propertyIds = personalausweisProperties.map((p) => p.id);
|
|
142
|
-
|
|
143
|
-
for (const id of propertyIds) {
|
|
144
|
-
await documentManagementService.assignPropertyToType({ propertyId: id, typeId: personalausweisType });
|
|
145
|
-
}
|
|
146
|
-
*/
|
|
147
|
-
/*
|
|
148
|
-
await documentManagementService.createDocumentRequest({ collectionIds: [patrickHein], typeId: lohnabrechnungType, requiredFilesCount: 1, comment: 'Abrechnung Feb 2025' });
|
|
149
|
-
await documentManagementService.createDocumentRequest({ collectionIds: [patrickHein], typeId: lohnabrechnungType, requiredFilesCount: 1, comment: 'Abrechnung Jan 2025' });
|
|
150
|
-
await documentManagementService.createDocumentRequest({ collectionIds: [patrickHein], typeId: lohnabrechnungType, requiredFilesCount: 1, comment: 'Abrechnung Dez 2024' });
|
|
151
|
-
await documentManagementService.createDocumentRequest({ collectionIds: [meritKlenk], typeId: personalausweisType, requiredFilesCount: 1, comment: null });
|
|
152
|
-
await documentManagementService.createDocumentRequest({ collectionIds: [patrickHein], typeId: personalausweisType, requiredFilesCount: 1, comment: null });
|
|
153
|
-
await documentManagementService.createDocumentRequest({ collectionIds: [haus], typeId: bauplanType, requiredFilesCount: 1, comment: null });
|
|
154
|
-
*/
|
|
155
|
-
/*
|
|
156
|
-
const file = await openAsBlob('/home/patrick/Downloads/Brutto-Netto-Abrechnung 2025 01 Januar.pdf');
|
|
157
|
-
|
|
158
|
-
const task = await documentManagementService.createDocumentRequestAssignmentTask(
|
|
159
|
-
{ originalFileName: 'Brutto-Netto-Abrechnung 2025 01 Januar.pdf', collectionIds: [patrickHein, meritKlenk, haus] },
|
|
160
|
-
file.stream()
|
|
161
|
-
);
|
|
162
|
-
*/
|
|
163
|
-
await cancelableTimeout(60000, cancellationSignal);
|
|
45
|
+
async function main(_cancellationSignal) {
|
|
46
|
+
const database = await injectAsync(Database);
|
|
47
|
+
await database.execute('FOO BAR BAZ');
|
|
164
48
|
}
|
|
165
49
|
Application.run('Test', [
|
|
50
|
+
provideInitializer(bootstrap),
|
|
166
51
|
provideModule(main),
|
|
167
52
|
provideSignalHandler(),
|
|
53
|
+
provideConsoleLogTransport(PrettyPrintLogFormatter),
|
|
168
54
|
]);
|
package/test5.js
CHANGED
|
@@ -7,12 +7,14 @@ import { Logger } from './logger/logger.js';
|
|
|
7
7
|
import { provideConsoleLogTransport } from './logger/transports/console.js';
|
|
8
8
|
async function main(_cancellationSignal) {
|
|
9
9
|
const logger = inject(Logger, 'Test');
|
|
10
|
-
logger.error('Hello World!', { sessionId: '
|
|
11
|
-
logger.
|
|
12
|
-
logger.
|
|
13
|
-
logger.
|
|
14
|
-
logger.
|
|
15
|
-
logger.
|
|
10
|
+
logger.error('Hello World!', { sessionId: 'abc' });
|
|
11
|
+
logger.error('Hello World!', new Error('FOO!!'), { sessionId: 'def' });
|
|
12
|
+
logger.error(new Error('BAR!!'), { sessionId: 'ghi' });
|
|
13
|
+
// logger.warn('Hello World!');
|
|
14
|
+
// logger.info('Hello World!');
|
|
15
|
+
// logger.verbose('Hello World!');
|
|
16
|
+
// logger.debug('Hello World!');
|
|
17
|
+
// logger.trace('Hello World!');
|
|
16
18
|
}
|
|
17
19
|
Application.run('Test', [
|
|
18
20
|
provideConsoleLogTransport(PrettyPrintLogFormatter),
|
package/utils/index.d.ts
CHANGED
|
@@ -19,7 +19,6 @@ export * from './equals.js';
|
|
|
19
19
|
export * from './factory-map.js';
|
|
20
20
|
export * from './feedable-async-iterable.js';
|
|
21
21
|
export * from './file-reader.js';
|
|
22
|
-
export * from './format-error.js';
|
|
23
22
|
export * from './format.js';
|
|
24
23
|
export * from './helpers.js';
|
|
25
24
|
export * from './html-link-utils.js';
|
package/utils/index.js
CHANGED
|
@@ -19,7 +19,6 @@ export * from './equals.js';
|
|
|
19
19
|
export * from './factory-map.js';
|
|
20
20
|
export * from './feedable-async-iterable.js';
|
|
21
21
|
export * from './file-reader.js';
|
|
22
|
-
export * from './format-error.js';
|
|
23
22
|
export * from './format.js';
|
|
24
23
|
export * from './helpers.js';
|
|
25
24
|
export * from './html-link-utils.js';
|
|
File without changes
|