@tstdl/base 0.93.99 → 0.93.101
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/authentication/client/authentication.service.d.ts +1 -1
- package/authentication/client/authentication.service.js +23 -11
- package/file/mime-type.d.ts +2 -2
- package/file/mime-type.js +2 -3
- package/file/server/index.d.ts +1 -0
- package/file/server/index.js +1 -0
- package/file/server/mime-type.d.ts +2 -0
- package/file/server/mime-type.js +5 -0
- package/notification/api/index.d.ts +1 -0
- package/notification/api/index.js +1 -0
- package/notification/api/notification.api.d.ts +8 -16
- package/notification/api/notification.api.js +13 -26
- package/notification/index.d.ts +1 -1
- package/notification/index.js +1 -1
- package/notification/models/in-app-notification.model.d.ts +9 -4
- package/notification/models/in-app-notification.model.js +25 -10
- package/notification/models/index.d.ts +1 -1
- package/notification/models/index.js +1 -1
- package/notification/models/notification-log.model.d.ts +42 -5
- package/notification/models/notification-log.model.js +34 -20
- package/notification/models/notification-preference.model.d.ts +2 -2
- package/notification/models/notification-preference.model.js +9 -9
- package/notification/models/notification-type.model.d.ts +17 -0
- package/notification/models/{notification-category.model.js → notification-type.model.js} +12 -13
- package/notification/models/web-push-subscription.model.d.ts +2 -2
- package/notification/models/web-push-subscription.model.js +8 -7
- package/notification/server/api/notification.api-controller.d.ts +2 -2
- package/notification/server/api/notification.api-controller.js +4 -3
- package/notification/server/drizzle/{0000_glorious_randall.sql → 0000_shiny_the_anarchist.sql} +27 -32
- package/notification/server/drizzle/meta/0000_snapshot.json +179 -179
- package/notification/server/drizzle/meta/_journal.json +2 -2
- package/notification/server/module.d.ts +2 -0
- package/notification/server/module.js +1 -0
- package/notification/server/providers/channel-provider.d.ts +4 -3
- package/notification/server/providers/channel-provider.js +2 -1
- package/notification/server/providers/email-channel-provider.d.ts +3 -3
- package/notification/server/providers/email-channel-provider.js +7 -9
- package/notification/server/providers/in-app-channel-provider.d.ts +5 -5
- package/notification/server/providers/in-app-channel-provider.js +15 -16
- package/notification/server/providers/index.d.ts +1 -1
- package/notification/server/providers/index.js +1 -1
- package/notification/server/providers/web-push-channel-provider.d.ts +5 -4
- package/notification/server/providers/web-push-channel-provider.js +8 -7
- package/notification/server/schemas.d.ts +3 -3
- package/notification/server/schemas.js +3 -4
- package/notification/server/services/index.d.ts +2 -4
- package/notification/server/services/index.js +2 -4
- package/notification/server/services/notification-delivery.worker.d.ts +7 -1
- package/notification/server/services/notification-delivery.worker.js +49 -37
- package/notification/server/services/notification-sse.service.d.ts +4 -7
- package/notification/server/services/notification-sse.service.js +4 -11
- package/notification/server/services/notification-template.d.ts +2 -2
- package/notification/server/services/notification-template.js +3 -1
- package/notification/server/services/notification-template.service.d.ts +1 -1
- package/notification/server/services/notification-template.service.js +7 -3
- package/notification/server/services/notification-type.service.d.ts +11 -0
- package/notification/server/services/notification-type.service.js +41 -0
- package/notification/server/services/notification.service.d.ts +4 -5
- package/notification/server/services/notification.service.js +44 -27
- package/notification/tests/notification-api.test.js +95 -0
- package/notification/tests/notification-flow.test.js +174 -28
- package/notification/tests/notification-type.service.test.d.ts +1 -0
- package/notification/tests/notification-type.service.test.js +35 -0
- package/package.json +2 -2
- package/rate-limit/postgres/postgres-rate-limiter.d.ts +9 -4
- package/rate-limit/postgres/postgres-rate-limiter.js +17 -10
- package/rate-limit/rate-limiter.d.ts +6 -6
- package/rate-limit/tests/postgres-rate-limiter.test.js +1 -1
- package/task-queue/postgres/task-queue.js +1 -1
- package/task-queue/task-queue.d.ts +3 -3
- package/task-queue/tests/extensive-dependencies.test.d.ts +1 -0
- package/task-queue/tests/extensive-dependencies.test.js +234 -0
- package/notification/enums.d.ts +0 -22
- package/notification/enums.js +0 -19
- package/notification/models/notification-category.model.d.ts +0 -17
- package/notification/server/services/notification-category.service.d.ts +0 -11
- package/notification/server/services/notification-category.service.js +0 -41
- package/notification/server/services/notification-delivery.task.d.ts +0 -9
- package/notification/server/services/notification-delivery.task.js +0 -1
- package/notification/server/services/singleton.d.ts +0 -3
- package/notification/server/services/singleton.js +0 -10
- package/notification/tests/notification-category.service.test.js +0 -36
- package/notification/tests/test-notification.model.d.ts +0 -4
- package/notification/tests/test-notification.model.js +0 -25
- /package/notification/tests/{notification-category.service.test.d.ts → notification-api.test.d.ts} +0 -0
|
@@ -25,7 +25,7 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
|
|
|
25
25
|
private readonly forceRefreshToken;
|
|
26
26
|
private readonly lock;
|
|
27
27
|
private readonly logger;
|
|
28
|
-
private readonly
|
|
28
|
+
private readonly disposeSignal;
|
|
29
29
|
private clockOffset;
|
|
30
30
|
private refreshLoopPromise;
|
|
31
31
|
/**
|
|
@@ -7,23 +7,24 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
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
|
-
import { Subject, filter, firstValueFrom, race, timer } from 'rxjs';
|
|
10
|
+
import { Subject, filter, firstValueFrom, map, race, timer } from 'rxjs';
|
|
11
11
|
import { CancellationSignal, CancellationToken } from '../../cancellation/token.js';
|
|
12
12
|
import { BadRequestError } from '../../errors/bad-request.error.js';
|
|
13
13
|
import { ForbiddenError } from '../../errors/forbidden.error.js';
|
|
14
|
+
import { formatError } from '../../errors/index.js';
|
|
14
15
|
import { InvalidTokenError } from '../../errors/invalid-token.error.js';
|
|
15
16
|
import { NotFoundError } from '../../errors/not-found.error.js';
|
|
16
17
|
import { NotSupportedError } from '../../errors/not-supported.error.js';
|
|
17
18
|
import { UnauthorizedError } from '../../errors/unauthorized.error.js';
|
|
19
|
+
import { HttpError } from '../../http/index.js';
|
|
18
20
|
import { Singleton, afterResolve, inject } from '../../injector/index.js';
|
|
19
21
|
import { Lock } from '../../lock/index.js';
|
|
20
22
|
import { Logger } from '../../logger/index.js';
|
|
21
23
|
import { MessageBus } from '../../message-bus/index.js';
|
|
22
24
|
import { computed, signal, toObservable } from '../../signals/api.js';
|
|
23
25
|
import { currentTimestampSeconds } from '../../utils/date-time.js';
|
|
24
|
-
import { formatError } from '../../errors/index.js';
|
|
25
26
|
import { timeout } from '../../utils/timing.js';
|
|
26
|
-
import { assertDefinedPass, isDefined, isNotFunction, isNullOrUndefined, isUndefined } from '../../utils/type-guards.js';
|
|
27
|
+
import { assertDefinedPass, isDefined, isInstanceOf, isNotFunction, isNullOrUndefined, isUndefined } from '../../utils/type-guards.js';
|
|
27
28
|
import { millisecondsPerMinute, millisecondsPerSecond } from '../../utils/units.js';
|
|
28
29
|
import { AUTHENTICATION_API_CLIENT, INITIAL_AUTHENTICATION_DATA } from './tokens.js';
|
|
29
30
|
const tokenStorageKey = 'AuthenticationService:token';
|
|
@@ -69,7 +70,7 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
69
70
|
forceRefreshToken = new CancellationToken();
|
|
70
71
|
lock = inject(Lock, refreshLockResource);
|
|
71
72
|
logger = inject(Logger, 'AuthenticationService');
|
|
72
|
-
|
|
73
|
+
disposeSignal = inject(CancellationSignal).createChild();
|
|
73
74
|
clockOffset = 0;
|
|
74
75
|
refreshLoopPromise;
|
|
75
76
|
/**
|
|
@@ -188,7 +189,7 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
188
189
|
* Stops refresh loop and completes subjects.
|
|
189
190
|
*/
|
|
190
191
|
async dispose() {
|
|
191
|
-
this.
|
|
192
|
+
this.disposeSignal.set();
|
|
192
193
|
await this.refreshLoopPromise;
|
|
193
194
|
this.errorSubject.complete();
|
|
194
195
|
await this.loggedOutBus.dispose();
|
|
@@ -375,13 +376,13 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
375
376
|
if (this.isLoggedIn()) {
|
|
376
377
|
await this.syncClock();
|
|
377
378
|
}
|
|
378
|
-
while (this.
|
|
379
|
+
while (this.disposeSignal.isUnset) {
|
|
379
380
|
try {
|
|
380
381
|
const token = this.token();
|
|
381
382
|
if (isUndefined(token)) {
|
|
382
383
|
// Wait for login or dispose.
|
|
383
384
|
// We ignore forceRefreshToken here because we can't refresh without a token.
|
|
384
|
-
await firstValueFrom(race([this.definedToken$, this.
|
|
385
|
+
await firstValueFrom(race([this.definedToken$, this.disposeSignal]), { defaultValue: undefined });
|
|
385
386
|
continue;
|
|
386
387
|
}
|
|
387
388
|
const now = this.estimatedServerTimestampSeconds();
|
|
@@ -402,13 +403,20 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
402
403
|
if (!lockAcquired) {
|
|
403
404
|
// Lock held by another instance, wait 5 seconds or until state/token changes.
|
|
404
405
|
// We ignore forceRefreshToken here to avoid a busy loop if it is already set.
|
|
405
|
-
await firstValueFrom(race([
|
|
406
|
+
const changeReason = await firstValueFrom(race([
|
|
407
|
+
timer(5000).pipe(map(() => 'timer')),
|
|
408
|
+
this.token$.pipe(filter((t) => t !== token), map(() => 'token')),
|
|
409
|
+
this.disposeSignal,
|
|
410
|
+
]), { defaultValue: undefined });
|
|
411
|
+
if (changeReason == 'token') {
|
|
412
|
+
this.forceRefreshToken.unset();
|
|
413
|
+
}
|
|
406
414
|
continue;
|
|
407
415
|
}
|
|
408
416
|
}
|
|
409
417
|
const delay = Math.min(maxRefreshDelay, ((this.token()?.exp ?? 0) - this.estimatedServerTimestampSeconds() - refreshBufferSeconds) * millisecondsPerSecond);
|
|
410
418
|
const wakeUpSignals = [
|
|
411
|
-
this.
|
|
419
|
+
this.disposeSignal,
|
|
412
420
|
this.token$.pipe(filter((t) => t != token)),
|
|
413
421
|
];
|
|
414
422
|
if (!forceRefresh) {
|
|
@@ -423,14 +431,18 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
423
431
|
}
|
|
424
432
|
catch (error) {
|
|
425
433
|
this.logger.error(error);
|
|
426
|
-
|
|
434
|
+
const initialToken = this.token();
|
|
435
|
+
await firstValueFrom(race([timer(5000), this.disposeSignal, this.token$.pipe(filter((t) => t != initialToken))]), { defaultValue: undefined });
|
|
436
|
+
await timeout(2500);
|
|
427
437
|
}
|
|
428
438
|
}
|
|
429
439
|
}
|
|
430
440
|
async handleRefreshError(error) {
|
|
431
441
|
this.logger.error(error);
|
|
432
442
|
this.errorSubject.next(error);
|
|
433
|
-
|
|
443
|
+
const isUnrecoverable = unrecoverableErrors.some((errorType) => isInstanceOf(error, errorType))
|
|
444
|
+
|| (error instanceof HttpError && ((error.response?.statusCode == 401) || (error.response?.statusCode == 404)));
|
|
445
|
+
if (isUnrecoverable) {
|
|
434
446
|
await this.logout();
|
|
435
447
|
}
|
|
436
448
|
}
|
package/file/mime-type.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare function getMimeType(file:
|
|
2
|
-
export declare function getMimeType<F>(file:
|
|
1
|
+
export declare function getMimeType(file: Uint8Array | ReadableStream<Uint8Array>): Promise<string | undefined>;
|
|
2
|
+
export declare function getMimeType<F>(file: Uint8Array | ReadableStream<Uint8Array>, fallback: F): Promise<string | F>;
|
|
3
3
|
export declare function getMimeTypeExtensions(mimeType: string): string[];
|
package/file/mime-type.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { fileTypeFromBuffer,
|
|
2
|
-
import { isReadableStream, isString, isUint8Array } from '../utils/type-guards.js';
|
|
1
|
+
import { fileTypeFromBuffer, fileTypeFromStream } from 'file-type';
|
|
3
2
|
import { match } from 'ts-pattern';
|
|
3
|
+
import { isReadableStream, isUint8Array } from '../utils/type-guards.js';
|
|
4
4
|
import { mimeTypesMap } from './mime-types.js';
|
|
5
5
|
export async function getMimeType(file, fallback) {
|
|
6
6
|
const result = await match(file)
|
|
7
|
-
.when(isString, async (f) => await fileTypeFromFile(f))
|
|
8
7
|
.when(isUint8Array, async (f) => await fileTypeFromBuffer(f))
|
|
9
8
|
.when((isReadableStream), async (f) => await fileTypeFromStream(f))
|
|
10
9
|
.exhaustive();
|
package/file/server/index.d.ts
CHANGED
package/file/server/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './notification.api.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './notification.api.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ServerSentEvents } from '../../sse/server-sent-events.js';
|
|
2
|
+
import { InAppNotificationView } from '../models/in-app-notification.model.js';
|
|
2
3
|
export declare const notificationApiDefinition: {
|
|
3
4
|
resource: string;
|
|
4
5
|
endpoints: {
|
|
@@ -15,16 +16,7 @@ export declare const notificationApiDefinition: {
|
|
|
15
16
|
limit?: number | undefined;
|
|
16
17
|
includeArchived?: boolean | undefined;
|
|
17
18
|
}>;
|
|
18
|
-
result: import("../../schema/index.js").ArraySchema<
|
|
19
|
-
type: string;
|
|
20
|
-
id: string;
|
|
21
|
-
createdAt: number;
|
|
22
|
-
priority: string;
|
|
23
|
-
logId: string;
|
|
24
|
-
payload?: {} | undefined;
|
|
25
|
-
readAt?: number | undefined;
|
|
26
|
-
archivedAt?: number | undefined;
|
|
27
|
-
}>;
|
|
19
|
+
result: import("../../schema/index.js").ArraySchema<InAppNotificationView>;
|
|
28
20
|
};
|
|
29
21
|
markRead: {
|
|
30
22
|
resource: string;
|
|
@@ -46,17 +38,17 @@ export declare const notificationApiDefinition: {
|
|
|
46
38
|
resource: string;
|
|
47
39
|
method: "GET";
|
|
48
40
|
result: import("../../schema/index.js").ArraySchema<{
|
|
41
|
+
type: string;
|
|
49
42
|
enabled: boolean;
|
|
50
|
-
channel:
|
|
51
|
-
categoryId: string;
|
|
43
|
+
channel: "email" | "in-app" | "web-push";
|
|
52
44
|
}>;
|
|
53
45
|
};
|
|
54
46
|
updatePreference: {
|
|
55
47
|
resource: string;
|
|
56
48
|
method: "POST";
|
|
57
49
|
parameters: import("../../schema/index.js").ObjectSchema<{
|
|
58
|
-
readonly
|
|
59
|
-
readonly channel:
|
|
50
|
+
readonly type: string;
|
|
51
|
+
readonly channel: "email" | "in-app" | "web-push";
|
|
60
52
|
readonly enabled: boolean;
|
|
61
53
|
}>;
|
|
62
54
|
result: import("../../schema/index.js").LiteralSchema<"ok">;
|
|
@@ -67,8 +59,8 @@ export declare const notificationApiDefinition: {
|
|
|
67
59
|
parameters: import("../../schema/index.js").ObjectSchema<{
|
|
68
60
|
readonly endpoint: string;
|
|
69
61
|
readonly keys: {
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
p256dhBase64: string;
|
|
63
|
+
authBase64: string;
|
|
72
64
|
};
|
|
73
65
|
}>;
|
|
74
66
|
result: import("../../schema/index.js").LiteralSchema<"ok">;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { defineApi } from '../../api/types.js';
|
|
2
|
-
import { boolean, explicitObject, literal, number, object, optional, string
|
|
3
|
-
import { NotificationChannel } from '../enums.js';
|
|
2
|
+
import { array, boolean, enumeration, explicitObject, literal, number, object, optional, string } from '../../schema/index.js';
|
|
4
3
|
import { ServerSentEvents } from '../../sse/server-sent-events.js';
|
|
4
|
+
import { InAppNotificationView } from '../models/in-app-notification.model.js';
|
|
5
|
+
import { NotificationChannel } from '../models/index.js';
|
|
5
6
|
export const notificationApiDefinition = defineApi({
|
|
6
|
-
resource: '
|
|
7
|
+
resource: 'notifications',
|
|
7
8
|
endpoints: {
|
|
8
9
|
stream: {
|
|
9
10
|
resource: 'stream',
|
|
@@ -18,40 +19,26 @@ export const notificationApiDefinition = defineApi({
|
|
|
18
19
|
offset: optional(number()),
|
|
19
20
|
includeArchived: optional(boolean()),
|
|
20
21
|
}),
|
|
21
|
-
result: array(
|
|
22
|
-
id: string(),
|
|
23
|
-
logId: string(),
|
|
24
|
-
readAt: optional(number()),
|
|
25
|
-
archivedAt: optional(number()),
|
|
26
|
-
// Add more joined fields from Log if needed, or return polymorphic payload
|
|
27
|
-
type: string(),
|
|
28
|
-
priority: string(),
|
|
29
|
-
createdAt: number(),
|
|
30
|
-
payload: optional(object({})),
|
|
31
|
-
})),
|
|
22
|
+
result: array(InAppNotificationView),
|
|
32
23
|
},
|
|
33
24
|
markRead: {
|
|
34
25
|
resource: 'in-app/:id/read',
|
|
35
26
|
method: 'POST',
|
|
36
|
-
parameters: object({
|
|
37
|
-
id: string(),
|
|
38
|
-
}),
|
|
27
|
+
parameters: object({ id: string() }),
|
|
39
28
|
result: literal('ok'),
|
|
40
29
|
},
|
|
41
30
|
archive: {
|
|
42
31
|
resource: 'in-app/:id/archive',
|
|
43
32
|
method: 'POST',
|
|
44
|
-
parameters: object({
|
|
45
|
-
id: string(),
|
|
46
|
-
}),
|
|
33
|
+
parameters: object({ id: string() }),
|
|
47
34
|
result: literal('ok'),
|
|
48
35
|
},
|
|
49
36
|
getPreferences: {
|
|
50
37
|
resource: 'preferences',
|
|
51
38
|
method: 'GET',
|
|
52
39
|
result: array(object({
|
|
53
|
-
|
|
54
|
-
channel:
|
|
40
|
+
type: string(),
|
|
41
|
+
channel: enumeration(NotificationChannel),
|
|
55
42
|
enabled: boolean(),
|
|
56
43
|
})),
|
|
57
44
|
},
|
|
@@ -59,8 +46,8 @@ export const notificationApiDefinition = defineApi({
|
|
|
59
46
|
resource: 'preferences',
|
|
60
47
|
method: 'POST',
|
|
61
48
|
parameters: explicitObject({
|
|
62
|
-
|
|
63
|
-
channel:
|
|
49
|
+
type: string(),
|
|
50
|
+
channel: enumeration(NotificationChannel),
|
|
64
51
|
enabled: boolean(),
|
|
65
52
|
}),
|
|
66
53
|
result: literal('ok'),
|
|
@@ -71,8 +58,8 @@ export const notificationApiDefinition = defineApi({
|
|
|
71
58
|
parameters: explicitObject({
|
|
72
59
|
endpoint: string(),
|
|
73
60
|
keys: object({
|
|
74
|
-
|
|
75
|
-
|
|
61
|
+
p256dhBase64: string(),
|
|
62
|
+
authBase64: string(),
|
|
76
63
|
}),
|
|
77
64
|
}),
|
|
78
65
|
result: literal('ok'),
|
package/notification/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './api/index.js';
|
|
2
2
|
export * from './models/index.js';
|
package/notification/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './api/index.js';
|
|
2
2
|
export * from './models/index.js';
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TenantBaseEntity, type Uuid } from '../../orm/index.js';
|
|
2
2
|
import type { Timestamp } from '../../orm/types.js';
|
|
3
|
-
|
|
3
|
+
import { type NotificationLog } from './notification-log.model.js';
|
|
4
|
+
export declare class InAppNotification extends TenantBaseEntity {
|
|
4
5
|
static readonly entityName = "InAppNotification";
|
|
5
6
|
userId: Uuid;
|
|
6
7
|
logId: Uuid;
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
readTimestamp: Timestamp | null;
|
|
9
|
+
archiveTimestamp: Timestamp | null;
|
|
9
10
|
}
|
|
11
|
+
export declare class InAppNotificationView extends InAppNotification {
|
|
12
|
+
notification: NotificationLog;
|
|
13
|
+
}
|
|
14
|
+
export declare function toInAppNotificationView(inAppNotification: InAppNotification, notification: NotificationLog): InAppNotificationView;
|
|
@@ -7,16 +7,17 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
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
|
-
import { User } from '../../authentication/
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { User } from '../../authentication/index.js';
|
|
11
|
+
import { ForeignKey, Index, TenantBaseEntity, TenantReference, TimestampProperty, UuidProperty } from '../../orm/index.js';
|
|
12
|
+
import { Property } from '../../schema/index.js';
|
|
13
|
+
import { NotificationLogEntity } from './notification-log.model.js';
|
|
13
14
|
import { NotificationTable } from './notification-table.js';
|
|
14
|
-
let InAppNotification = class InAppNotification extends
|
|
15
|
+
let InAppNotification = class InAppNotification extends TenantBaseEntity {
|
|
15
16
|
static entityName = 'InAppNotification';
|
|
16
17
|
userId;
|
|
17
18
|
logId;
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
readTimestamp;
|
|
20
|
+
archiveTimestamp;
|
|
20
21
|
};
|
|
21
22
|
__decorate([
|
|
22
23
|
UuidProperty(),
|
|
@@ -25,18 +26,32 @@ __decorate([
|
|
|
25
26
|
], InAppNotification.prototype, "userId", void 0);
|
|
26
27
|
__decorate([
|
|
27
28
|
UuidProperty(),
|
|
28
|
-
TenantReference(() => NotificationLog),
|
|
29
29
|
__metadata("design:type", String)
|
|
30
30
|
], InAppNotification.prototype, "logId", void 0);
|
|
31
31
|
__decorate([
|
|
32
32
|
TimestampProperty({ nullable: true }),
|
|
33
33
|
__metadata("design:type", Object)
|
|
34
|
-
], InAppNotification.prototype, "
|
|
34
|
+
], InAppNotification.prototype, "readTimestamp", void 0);
|
|
35
35
|
__decorate([
|
|
36
36
|
TimestampProperty({ nullable: true }),
|
|
37
37
|
__metadata("design:type", Object)
|
|
38
|
-
], InAppNotification.prototype, "
|
|
38
|
+
], InAppNotification.prototype, "archiveTimestamp", void 0);
|
|
39
39
|
InAppNotification = __decorate([
|
|
40
|
-
NotificationTable({ name: 'in_app' })
|
|
40
|
+
NotificationTable({ name: 'in_app' }),
|
|
41
|
+
ForeignKey(() => NotificationLogEntity, ['tenantId', 'logId', 'userId'], ['tenantId', 'id', 'userId']),
|
|
42
|
+
Index(['tenantId', 'userId', 'readTimestamp', 'archiveTimestamp'])
|
|
41
43
|
], InAppNotification);
|
|
42
44
|
export { InAppNotification };
|
|
45
|
+
export class InAppNotificationView extends InAppNotification {
|
|
46
|
+
notification;
|
|
47
|
+
}
|
|
48
|
+
__decorate([
|
|
49
|
+
Property(NotificationLogEntity),
|
|
50
|
+
__metadata("design:type", Object)
|
|
51
|
+
], InAppNotificationView.prototype, "notification", void 0);
|
|
52
|
+
export function toInAppNotificationView(inAppNotification, notification) {
|
|
53
|
+
return {
|
|
54
|
+
...inAppNotification,
|
|
55
|
+
notification,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from './in-app-notification.model.js';
|
|
2
|
-
export * from './notification-category.model.js';
|
|
3
2
|
export * from './notification-log.model.js';
|
|
4
3
|
export * from './notification-preference.model.js';
|
|
5
4
|
export * from './notification-table.js';
|
|
5
|
+
export * from './notification-type.model.js';
|
|
6
6
|
export * from './web-push-subscription.model.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from './in-app-notification.model.js';
|
|
2
|
-
export * from './notification-category.model.js';
|
|
3
2
|
export * from './notification-log.model.js';
|
|
4
3
|
export * from './notification-preference.model.js';
|
|
5
4
|
export * from './notification-table.js';
|
|
5
|
+
export * from './notification-type.model.js';
|
|
6
6
|
export * from './web-push-subscription.model.js';
|
|
@@ -1,13 +1,50 @@
|
|
|
1
|
+
import { type EnumType } from '../../enumeration/index.js';
|
|
1
2
|
import { type Json, TenantEntity, type Uuid } from '../../orm/index.js';
|
|
2
3
|
import type { ObjectLiteral } from '../../types/types.js';
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
export declare const NotificationChannel: {
|
|
5
|
+
readonly InApp: "in-app";
|
|
6
|
+
readonly Email: "email";
|
|
7
|
+
readonly WebPush: "web-push";
|
|
8
|
+
};
|
|
9
|
+
export type NotificationChannel = EnumType<typeof NotificationChannel>;
|
|
10
|
+
export declare const NotificationPriority: {
|
|
11
|
+
readonly Low: "low";
|
|
12
|
+
readonly Medium: "medium";
|
|
13
|
+
readonly High: "high";
|
|
14
|
+
readonly Urgent: "urgent";
|
|
15
|
+
};
|
|
16
|
+
export type NotificationPriority = EnumType<typeof NotificationPriority>;
|
|
17
|
+
export declare const NotificationStatus: {
|
|
18
|
+
readonly Pending: "pending";
|
|
19
|
+
readonly Sent: "sent";
|
|
20
|
+
readonly Delivered: "delivered";
|
|
21
|
+
readonly Read: "read";
|
|
22
|
+
readonly Failed: "failed";
|
|
23
|
+
};
|
|
24
|
+
export type NotificationStatus = EnumType<typeof NotificationStatus>;
|
|
25
|
+
export type NotificationDefinition<Payload extends ObjectLiteral = ObjectLiteral> = {
|
|
26
|
+
payload: Payload;
|
|
27
|
+
};
|
|
28
|
+
export type NotificationDefinitionMap<Definition extends Record<string, NotificationDefinition> = Record<string, NotificationDefinition>> = Definition;
|
|
29
|
+
export type NotificationTypes<Definitions extends NotificationDefinitionMap> = Extract<keyof Definitions, string>;
|
|
30
|
+
export type NotificationPayload<Definitions extends NotificationDefinitionMap, Type extends NotificationTypes<Definitions>> = Definitions[Type]['payload'];
|
|
31
|
+
export type NotificationOfType<Definitions extends NotificationDefinitionMap, Type extends NotificationTypes<Definitions>> = string extends NotificationTypes<Definitions> ? NotificationLog<Definitions> & {
|
|
32
|
+
type: Type;
|
|
33
|
+
} : Extract<NotificationLog<Definitions>, {
|
|
34
|
+
type: Type;
|
|
35
|
+
}>;
|
|
36
|
+
export type NotificationLog<Definitions extends NotificationDefinitionMap = NotificationDefinitionMap> = {
|
|
37
|
+
[Type in NotificationTypes<Definitions>]: Omit<NotificationLogEntity<Definitions, Type>, 'type' | 'payload'> & {
|
|
38
|
+
type: Type;
|
|
39
|
+
payload: Json<NotificationPayload<Definitions, Type>> | null;
|
|
40
|
+
};
|
|
41
|
+
}[NotificationTypes<Definitions>];
|
|
42
|
+
export declare class NotificationLogEntity<Definitions extends NotificationDefinitionMap = NotificationDefinitionMap, Type extends NotificationTypes<Definitions> = NotificationTypes<Definitions>> extends TenantEntity {
|
|
5
43
|
static readonly entityName = "NotificationLog";
|
|
6
44
|
userId: Uuid;
|
|
7
|
-
|
|
8
|
-
type: string;
|
|
45
|
+
type: Type;
|
|
9
46
|
priority: NotificationPriority;
|
|
10
47
|
status: NotificationStatus;
|
|
11
48
|
currentStep: number;
|
|
12
|
-
payload: Json<
|
|
49
|
+
payload: Json<NotificationPayload<Definitions, Type>> | null;
|
|
13
50
|
}
|
|
@@ -8,15 +8,32 @@ 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 { User } from '../../authentication/models/user.model.js';
|
|
11
|
-
import {
|
|
11
|
+
import { defineEnum } from '../../enumeration/index.js';
|
|
12
|
+
import { JsonProperty, Reference, TenantEntity, TenantReference, Unique, UuidProperty } from '../../orm/index.js';
|
|
12
13
|
import { Enumeration, Integer, StringProperty } from '../../schema/index.js';
|
|
13
|
-
import { NotificationPriority, NotificationStatus } from '../enums.js';
|
|
14
|
-
import { NotificationCategory } from './notification-category.model.js';
|
|
15
14
|
import { NotificationTable } from './notification-table.js';
|
|
16
|
-
|
|
15
|
+
import { NotificationType } from './notification-type.model.js';
|
|
16
|
+
export const NotificationChannel = defineEnum('NotificationChannel', {
|
|
17
|
+
InApp: 'in-app',
|
|
18
|
+
Email: 'email',
|
|
19
|
+
WebPush: 'web-push',
|
|
20
|
+
});
|
|
21
|
+
export const NotificationPriority = defineEnum('NotificationPriority', {
|
|
22
|
+
Low: 'low',
|
|
23
|
+
Medium: 'medium',
|
|
24
|
+
High: 'high',
|
|
25
|
+
Urgent: 'urgent',
|
|
26
|
+
});
|
|
27
|
+
export const NotificationStatus = defineEnum('NotificationStatus', {
|
|
28
|
+
Pending: 'pending',
|
|
29
|
+
Sent: 'sent',
|
|
30
|
+
Delivered: 'delivered',
|
|
31
|
+
Read: 'read',
|
|
32
|
+
Failed: 'failed',
|
|
33
|
+
});
|
|
34
|
+
let NotificationLogEntity = class NotificationLogEntity extends TenantEntity {
|
|
17
35
|
static entityName = 'NotificationLog';
|
|
18
36
|
userId;
|
|
19
|
-
categoryId;
|
|
20
37
|
type;
|
|
21
38
|
priority;
|
|
22
39
|
status;
|
|
@@ -27,33 +44,30 @@ __decorate([
|
|
|
27
44
|
UuidProperty(),
|
|
28
45
|
TenantReference(() => User),
|
|
29
46
|
__metadata("design:type", String)
|
|
30
|
-
],
|
|
31
|
-
__decorate([
|
|
32
|
-
UuidProperty(),
|
|
33
|
-
TenantReference(() => NotificationCategory),
|
|
34
|
-
__metadata("design:type", String)
|
|
35
|
-
], NotificationLog.prototype, "categoryId", void 0);
|
|
47
|
+
], NotificationLogEntity.prototype, "userId", void 0);
|
|
36
48
|
__decorate([
|
|
49
|
+
Reference(() => NotificationType, 'key'),
|
|
37
50
|
StringProperty(),
|
|
38
51
|
__metadata("design:type", String)
|
|
39
|
-
],
|
|
52
|
+
], NotificationLogEntity.prototype, "type", void 0);
|
|
40
53
|
__decorate([
|
|
41
54
|
Enumeration(NotificationPriority),
|
|
42
55
|
__metadata("design:type", String)
|
|
43
|
-
],
|
|
56
|
+
], NotificationLogEntity.prototype, "priority", void 0);
|
|
44
57
|
__decorate([
|
|
45
58
|
Enumeration(NotificationStatus),
|
|
46
59
|
__metadata("design:type", String)
|
|
47
|
-
],
|
|
60
|
+
], NotificationLogEntity.prototype, "status", void 0);
|
|
48
61
|
__decorate([
|
|
49
62
|
Integer(),
|
|
50
63
|
__metadata("design:type", Number)
|
|
51
|
-
],
|
|
64
|
+
], NotificationLogEntity.prototype, "currentStep", void 0);
|
|
52
65
|
__decorate([
|
|
53
66
|
JsonProperty({ nullable: true }),
|
|
54
67
|
__metadata("design:type", Object)
|
|
55
|
-
],
|
|
56
|
-
|
|
57
|
-
NotificationTable({ name: 'log' })
|
|
58
|
-
|
|
59
|
-
|
|
68
|
+
], NotificationLogEntity.prototype, "payload", void 0);
|
|
69
|
+
NotificationLogEntity = __decorate([
|
|
70
|
+
NotificationTable({ name: 'log' }),
|
|
71
|
+
Unique(['tenantId', 'id', 'userId'])
|
|
72
|
+
], NotificationLogEntity);
|
|
73
|
+
export { NotificationLogEntity };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { TenantEntity, type Uuid } from '../../orm/index.js';
|
|
2
|
-
import { NotificationChannel } from '
|
|
2
|
+
import { NotificationChannel } from './notification-log.model.js';
|
|
3
3
|
export declare class NotificationPreference extends TenantEntity {
|
|
4
4
|
static readonly entityName = "NotificationPreference";
|
|
5
5
|
userId: Uuid;
|
|
6
|
-
|
|
6
|
+
type: string;
|
|
7
7
|
channel: NotificationChannel;
|
|
8
8
|
enabled: boolean;
|
|
9
9
|
}
|
|
@@ -8,15 +8,15 @@ 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 { User } from '../../authentication/models/user.model.js';
|
|
11
|
-
import { TenantEntity, TenantReference, Unique, UuidProperty } from '../../orm/index.js';
|
|
12
|
-
import { BooleanProperty, Enumeration } from '../../schema/index.js';
|
|
13
|
-
import { NotificationChannel } from '
|
|
14
|
-
import { NotificationCategory } from './notification-category.model.js';
|
|
11
|
+
import { Reference, TenantEntity, TenantReference, Unique, UuidProperty } from '../../orm/index.js';
|
|
12
|
+
import { BooleanProperty, Enumeration, StringProperty } from '../../schema/index.js';
|
|
13
|
+
import { NotificationChannel } from './notification-log.model.js';
|
|
15
14
|
import { NotificationTable } from './notification-table.js';
|
|
15
|
+
import { NotificationType } from './notification-type.model.js';
|
|
16
16
|
let NotificationPreference = class NotificationPreference extends TenantEntity {
|
|
17
17
|
static entityName = 'NotificationPreference';
|
|
18
18
|
userId;
|
|
19
|
-
|
|
19
|
+
type;
|
|
20
20
|
channel;
|
|
21
21
|
enabled;
|
|
22
22
|
};
|
|
@@ -26,10 +26,10 @@ __decorate([
|
|
|
26
26
|
__metadata("design:type", String)
|
|
27
27
|
], NotificationPreference.prototype, "userId", void 0);
|
|
28
28
|
__decorate([
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
Reference(() => NotificationType, 'key'),
|
|
30
|
+
StringProperty(),
|
|
31
31
|
__metadata("design:type", String)
|
|
32
|
-
], NotificationPreference.prototype, "
|
|
32
|
+
], NotificationPreference.prototype, "type", void 0);
|
|
33
33
|
__decorate([
|
|
34
34
|
Enumeration(NotificationChannel),
|
|
35
35
|
__metadata("design:type", String)
|
|
@@ -40,6 +40,6 @@ __decorate([
|
|
|
40
40
|
], NotificationPreference.prototype, "enabled", void 0);
|
|
41
41
|
NotificationPreference = __decorate([
|
|
42
42
|
NotificationTable({ name: 'preference' }),
|
|
43
|
-
Unique(['tenantId', 'userId', '
|
|
43
|
+
Unique(['tenantId', 'userId', 'type', 'channel'])
|
|
44
44
|
], NotificationPreference);
|
|
45
45
|
export { NotificationPreference };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Entity } from '../../orm/index.js';
|
|
2
|
+
import type { NotificationChannel } from './notification-log.model.js';
|
|
3
|
+
export type ThrottlingConfig = {
|
|
4
|
+
limit: number;
|
|
5
|
+
interval: number;
|
|
6
|
+
};
|
|
7
|
+
export type EscalationRule = {
|
|
8
|
+
delay: number;
|
|
9
|
+
channel: NotificationChannel;
|
|
10
|
+
};
|
|
11
|
+
export declare class NotificationType extends Entity {
|
|
12
|
+
static readonly entityName = "NotificationType";
|
|
13
|
+
label: string;
|
|
14
|
+
key: string;
|
|
15
|
+
throttling: ThrottlingConfig | null;
|
|
16
|
+
escalations: EscalationRule[] | null;
|
|
17
|
+
}
|