@tstdl/base 0.93.123 → 0.93.125

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 (27) hide show
  1. package/document-management/server/drizzle/{0000_silly_chimera.sql → 0000_complex_black_bird.sql} +1 -1
  2. package/document-management/server/drizzle/meta/0000_snapshot.json +3 -3
  3. package/document-management/server/drizzle/meta/_journal.json +2 -2
  4. package/notification/api/notification.api.d.ts +26 -6
  5. package/notification/api/notification.api.js +15 -4
  6. package/notification/client/notification-client.d.ts +6 -0
  7. package/notification/client/notification-client.js +13 -3
  8. package/notification/models/in-app-notification.model.d.ts +9 -3
  9. package/notification/models/in-app-notification.model.js +32 -11
  10. package/notification/models/notification-log.model.js +2 -3
  11. package/notification/server/api/notification.api-controller.d.ts +1 -0
  12. package/notification/server/api/notification.api-controller.js +7 -1
  13. package/notification/server/drizzle/{0000_oval_rage.sql → 0000_wise_pyro.sql} +22 -4
  14. package/notification/server/drizzle/meta/0000_snapshot.json +249 -37
  15. package/notification/server/drizzle/meta/_journal.json +2 -2
  16. package/notification/server/module.d.ts +5 -0
  17. package/notification/server/module.js +6 -1
  18. package/notification/server/providers/in-app-channel-provider.js +1 -0
  19. package/notification/server/schemas.d.ts +3 -2
  20. package/notification/server/schemas.js +3 -2
  21. package/notification/server/services/notification.service.d.ts +11 -6
  22. package/notification/server/services/notification.service.js +138 -42
  23. package/notification/tests/notification-api.test.js +8 -1
  24. package/notification/tests/notification-flow.test.js +41 -4
  25. package/orm/server/drizzle/schema-converter.js +5 -3
  26. package/orm/tests/schema-converter.test.js +1 -0
  27. package/package.json +1 -1
@@ -384,4 +384,4 @@ CREATE INDEX "request_type_id_idx" ON "document_management"."request" USING btre
384
384
  CREATE INDEX "request_state_idx" ON "document_management"."request" USING btree ("state");--> statement-breakpoint
385
385
  CREATE INDEX "request_collection_assignment_collection_id_idx" ON "document_management"."request_collection_assignment" USING btree ("collection_id");--> statement-breakpoint
386
386
  CREATE INDEX "document_type_validation_type_id_idx" ON "document_management"."document_type_validation" USING btree ("type_id");--> statement-breakpoint
387
- CREATE UNIQUE INDEX "workflow_document_id_idx" ON "document_management"."workflow" USING btree ("document_id") WHERE "document_management"."workflow"."state" <> 'completed';
387
+ CREATE UNIQUE INDEX "workflow_document_id_partial_idx" ON "document_management"."workflow" USING btree ("document_id") WHERE "document_management"."workflow"."state" <> 'completed';
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "fee5df5b-e30c-483a-a4f2-fff78256e1c2",
2
+ "id": "ff5ec8ad-f61c-4ce5-b858-b28db663121f",
3
3
  "prevId": "00000000-0000-0000-0000-000000000000",
4
4
  "version": "7",
5
5
  "dialect": "postgresql",
@@ -2756,8 +2756,8 @@
2756
2756
  }
2757
2757
  },
2758
2758
  "indexes": {
2759
- "workflow_document_id_idx": {
2760
- "name": "workflow_document_id_idx",
2759
+ "workflow_document_id_partial_idx": {
2760
+ "name": "workflow_document_id_partial_idx",
2761
2761
  "columns": [
2762
2762
  {
2763
2763
  "expression": "document_id",
@@ -5,8 +5,8 @@
5
5
  {
6
6
  "idx": 0,
7
7
  "version": "7",
8
- "when": 1769464843006,
9
- "tag": "0000_silly_chimera",
8
+ "when": 1770754372969,
9
+ "tag": "0000_complex_black_bird",
10
10
  "breakpoints": true
11
11
  }
12
12
  ]
@@ -14,7 +14,7 @@ export declare const notificationApiDefinition: {
14
14
  };
15
15
  credentials: true;
16
16
  dataStream: {
17
- idProvider: (item: NotificationStreamItem) => import("../../types/tagged.js").Tagged<string, "column", import("drizzle-orm").IsPrimaryKey<import("drizzle-orm").HasDefault<import("drizzle-orm/pg-core").PgUUIDBuilderInitial<string>>>> | undefined;
17
+ idProvider: () => string;
18
18
  };
19
19
  };
20
20
  types: {
@@ -29,9 +29,19 @@ export declare const notificationApiDefinition: {
29
29
  parameters: import("../../schema/index.js").ObjectSchema<{
30
30
  offset?: number | undefined;
31
31
  limit?: number | undefined;
32
- after?: string | undefined;
32
+ after?: string | number | undefined;
33
33
  unreadOnly?: boolean | undefined;
34
- includeArchived?: boolean | undefined;
34
+ }>;
35
+ result: import("../../schema/index.js").ArraySchema<InAppNotificationView<Record<string, import("../models/notification-log.model.js").NotificationDefinition<import("../../types/types.js").ObjectLiteral, import("../../types/types.js").ObjectLiteral>>>>;
36
+ credentials: true;
37
+ };
38
+ listArchivedInApp: {
39
+ resource: string;
40
+ method: "GET";
41
+ parameters: import("../../schema/index.js").ObjectSchema<{
42
+ offset?: number | undefined;
43
+ limit?: number | undefined;
44
+ after?: string | number | undefined;
35
45
  }>;
36
46
  result: import("../../schema/index.js").ArraySchema<InAppNotificationView<Record<string, import("../models/notification-log.model.js").NotificationDefinition<import("../../types/types.js").ObjectLiteral, import("../../types/types.js").ObjectLiteral>>>>;
37
47
  credentials: true;
@@ -120,7 +130,7 @@ declare const _NotificationApiClient: import("../../api/client/index.js").ApiCli
120
130
  };
121
131
  credentials: true;
122
132
  dataStream: {
123
- idProvider: (item: NotificationStreamItem) => import("../../types/tagged.js").Tagged<string, "column", import("drizzle-orm").IsPrimaryKey<import("drizzle-orm").HasDefault<import("drizzle-orm/pg-core").PgUUIDBuilderInitial<string>>>> | undefined;
133
+ idProvider: () => string;
124
134
  };
125
135
  };
126
136
  types: {
@@ -135,9 +145,19 @@ declare const _NotificationApiClient: import("../../api/client/index.js").ApiCli
135
145
  parameters: import("../../schema/index.js").ObjectSchema<{
136
146
  offset?: number | undefined;
137
147
  limit?: number | undefined;
138
- after?: string | undefined;
148
+ after?: string | number | undefined;
139
149
  unreadOnly?: boolean | undefined;
140
- includeArchived?: boolean | undefined;
150
+ }>;
151
+ result: import("../../schema/index.js").ArraySchema<InAppNotificationView<Record<string, import("../models/notification-log.model.js").NotificationDefinition<import("../../types/types.js").ObjectLiteral, import("../../types/types.js").ObjectLiteral>>>>;
152
+ credentials: true;
153
+ };
154
+ listArchivedInApp: {
155
+ resource: string;
156
+ method: "GET";
157
+ parameters: import("../../schema/index.js").ObjectSchema<{
158
+ offset?: number | undefined;
159
+ limit?: number | undefined;
160
+ after?: string | number | undefined;
141
161
  }>;
142
162
  result: import("../../schema/index.js").ArraySchema<InAppNotificationView<Record<string, import("../models/notification-log.model.js").NotificationDefinition<import("../../types/types.js").ObjectLiteral, import("../../types/types.js").ObjectLiteral>>>>;
143
163
  credentials: true;
@@ -7,8 +7,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { compileClient } from '../../api/client/index.js';
8
8
  import { defineApi } from '../../api/types.js';
9
9
  import { ReplaceClass } from '../../injector/decorators.js';
10
- import { array, boolean, enumeration, literal, number, object, optional, record, string } from '../../schema/index.js';
10
+ import { array, boolean, enumeration, literal, number, object, optional, record, string, union } from '../../schema/index.js';
11
11
  import { DataStream } from '../../sse/data-stream.js';
12
+ import { currentTimestamp } from '../../utils/date-time.js';
12
13
  import { InAppNotificationView } from '../models/in-app-notification.model.js';
13
14
  import { NotificationChannel } from '../models/index.js';
14
15
  export const notificationApiDefinition = defineApi({
@@ -20,7 +21,7 @@ export const notificationApiDefinition = defineApi({
20
21
  result: (DataStream),
21
22
  credentials: true,
22
23
  dataStream: {
23
- idProvider: (item) => item.notification?.id,
24
+ idProvider: () => currentTimestamp().toString(),
24
25
  },
25
26
  },
26
27
  types: {
@@ -35,9 +36,19 @@ export const notificationApiDefinition = defineApi({
35
36
  parameters: object({
36
37
  limit: optional(number()),
37
38
  offset: optional(number()),
38
- after: optional(string()),
39
+ after: optional(union(number(), string())),
39
40
  unreadOnly: optional(boolean()),
40
- includeArchived: optional(boolean()),
41
+ }),
42
+ result: array(InAppNotificationView),
43
+ credentials: true,
44
+ },
45
+ listArchivedInApp: {
46
+ resource: 'in-app/archived',
47
+ method: 'GET',
48
+ parameters: object({
49
+ limit: optional(number()),
50
+ offset: optional(number()),
51
+ after: optional(union(number(), string())),
41
52
  }),
42
53
  result: array(InAppNotificationView),
43
54
  credentials: true,
@@ -1,5 +1,6 @@
1
1
  import { NotificationApiClient } from '../../notification/api/index.js';
2
2
  import type { InAppNotificationView, NotificationDefinitionMap } from '../../notification/models/index.js';
3
+ import type { NotificationStreamItem } from '../../notification/types.js';
3
4
  type NotificationState<Definitions extends NotificationDefinitionMap = NotificationDefinitionMap> = {
4
5
  notifications: InAppNotificationView<Definitions>[];
5
6
  unreadCount: number;
@@ -7,6 +8,9 @@ type NotificationState<Definitions extends NotificationDefinitionMap = Notificat
7
8
  export declare class NotificationClient<Definitions extends NotificationDefinitionMap = NotificationDefinitionMap> {
8
9
  #private;
9
10
  readonly api: NotificationApiClient;
11
+ readonly stream$: import("rxjs").Observable<NotificationStreamItem<Definitions>>;
12
+ /** Emits whenever a new notification is received via the stream. */
13
+ readonly onNewNotification$: import("rxjs").Observable<InAppNotificationView<Definitions>>;
10
14
  readonly state$: import("rxjs").Observable<NotificationState<Definitions>>;
11
15
  readonly notifications$: import("rxjs").Observable<InAppNotificationView<Definitions>[]>;
12
16
  readonly unreadCount$: import("rxjs").Observable<number>;
@@ -15,6 +19,8 @@ export declare class NotificationClient<Definitions extends NotificationDefiniti
15
19
  readonly notifications: import("../../signals/api.js").Signal<InAppNotificationView<Definitions>[]>;
16
20
  readonly unreadCount: import("../../signals/api.js").Signal<number>;
17
21
  readonly types: import("../../signals/api.js").Signal<Record<keyof Definitions, string>>;
22
+ readonly unreadNotifications: import("../../signals/api.js").Signal<InAppNotificationView<Definitions>[]>;
23
+ readonly readNotifications: import("../../signals/api.js").Signal<InAppNotificationView<Definitions>[]>;
18
24
  loadNext(count?: number): void;
19
25
  }
20
26
  export {};
@@ -4,23 +4,31 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
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
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { concatMap, defer, from, map, merge, of, scan, shareReplay, Subject, switchAll, switchMap } from 'rxjs';
7
+ import { concatMap, defer, EMPTY, filter, from, map, merge, of, scan, share, shareReplay, Subject, switchAll, switchMap } from 'rxjs';
8
8
  import { AuthenticationClientService } from '../../authentication/client/authentication.service.js';
9
9
  import { Singleton } from '../../injector/decorators.js';
10
10
  import { inject } from '../../injector/inject.js';
11
11
  import { NotificationApiClient } from '../../notification/api/index.js';
12
12
  import { forceCast } from '../../rxjs-utils/cast.js';
13
13
  import { computed, toSignal } from '../../signals/api.js';
14
- import { isDefined, isUndefined } from '../../utils/type-guards.js';
14
+ import { isDefined, isNotNull, isNull, isUndefined } from '../../utils/type-guards.js';
15
15
  let NotificationClient = class NotificationClient {
16
16
  #pagination$ = new Subject();
17
17
  #authenticationService = inject(AuthenticationClientService);
18
18
  api = inject(NotificationApiClient);
19
+ stream$ = this.#authenticationService.sessionId$.pipe(switchMap((sessionId) => {
20
+ if (isUndefined(sessionId)) {
21
+ return EMPTY;
22
+ }
23
+ return defer(() => from(this.api.stream())).pipe(switchAll(), forceCast());
24
+ }), share());
25
+ /** Emits whenever a new notification is received via the stream. */
26
+ onNewNotification$ = this.stream$.pipe(filter((item) => isDefined(item.notification)), map((item) => item.notification));
19
27
  state$ = this.#authenticationService.sessionId$.pipe(switchMap((sessionId) => {
20
28
  if (isUndefined(sessionId)) {
21
29
  return of({ notifications: [], unreadCount: 0 });
22
30
  }
23
- return merge(defer(() => from(this.api.listInApp({ limit: 20 }))).pipe(map((notifications) => ({ type: 'set-notifications', notifications: notifications }))), defer(() => from(this.api.unreadCount())).pipe(map((unreadCount) => ({ type: 'set-unread-count', unreadCount }))), defer(() => from(this.api.stream())).pipe(switchAll(), forceCast(), switchMap((item) => {
31
+ return merge(defer(() => from(this.api.listInApp({ limit: 20 }))).pipe(map((notifications) => ({ type: 'set-notifications', notifications: notifications }))), defer(() => from(this.api.unreadCount())).pipe(map((unreadCount) => ({ type: 'set-unread-count', unreadCount }))), this.stream$.pipe(switchMap((item) => {
24
32
  const actions = [];
25
33
  if (isDefined(item.unreadCount)) {
26
34
  actions.push({ type: 'set-unread-count', unreadCount: item.unreadCount });
@@ -90,6 +98,8 @@ let NotificationClient = class NotificationClient {
90
98
  notifications = computed(() => this.state().notifications);
91
99
  unreadCount = computed(() => this.state().unreadCount);
92
100
  types = toSignal(this.types$, { initialValue: {} });
101
+ unreadNotifications = computed(() => this.notifications().filter((notification) => isNull(notification.readTimestamp)));
102
+ readNotifications = computed(() => this.notifications().filter((notification) => isNotNull(notification.readTimestamp)));
93
103
  loadNext(count = 20) {
94
104
  const current = this.notifications();
95
105
  const after = current[current.length - 1]?.id;
@@ -1,14 +1,20 @@
1
1
  import { TenantBaseEntity, type Uuid } from '../../orm/index.js';
2
2
  import type { Timestamp } from '../../orm/types.js';
3
3
  import { type NotificationDefinitionMap, type NotificationLogView } from './notification-log.model.js';
4
- export declare class InAppNotification extends TenantBaseEntity {
5
- static readonly entityName = "InAppNotification";
4
+ export declare abstract class InAppNotificationBase extends TenantBaseEntity {
6
5
  userId: Uuid;
7
6
  logId: Uuid;
7
+ timestamp: Timestamp;
8
8
  readTimestamp: Timestamp | null;
9
9
  archiveTimestamp: Timestamp | null;
10
10
  }
11
- export declare class InAppNotificationView<Definitions extends NotificationDefinitionMap = NotificationDefinitionMap> extends InAppNotification {
11
+ export declare class InAppNotification extends InAppNotificationBase {
12
+ static readonly entityName = "InAppNotification";
13
+ }
14
+ export declare class InAppNotificationArchive extends InAppNotificationBase {
15
+ static readonly entityName = "InAppNotificationArchive";
16
+ }
17
+ export declare class InAppNotificationView<Definitions extends NotificationDefinitionMap = NotificationDefinitionMap> extends InAppNotificationBase {
12
18
  notification: NotificationLogView<Definitions>;
13
19
  }
14
20
  export declare function toInAppNotificationView<Definitions extends NotificationDefinitionMap = NotificationDefinitionMap>(inAppNotification: InAppNotification, notification: NotificationLogView<Definitions>): InAppNotificationView<Definitions>;
@@ -7,43 +7,64 @@ 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 { isNotNull, isNull } from 'drizzle-orm';
10
11
  import { User } from '../../authentication/index.js';
11
- import { ForeignKey, Index, TenantBaseEntity, TenantReference, TimestampProperty, UuidProperty } from '../../orm/index.js';
12
+ import { ForeignKey, Index, TenantBaseEntity, TenantReference, TimestampProperty, Unique, UuidProperty } from '../../orm/index.js';
12
13
  import { Property } from '../../schema/index.js';
13
14
  import { NotificationLogEntity } from './notification-log.model.js';
14
15
  import { NotificationTable } from './notification-table.js';
15
- let InAppNotification = class InAppNotification extends TenantBaseEntity {
16
- static entityName = 'InAppNotification';
16
+ export class InAppNotificationBase extends TenantBaseEntity {
17
17
  userId;
18
18
  logId;
19
- // TODO: anpinnen?
19
+ timestamp;
20
20
  readTimestamp;
21
21
  archiveTimestamp;
22
- };
22
+ }
23
23
  __decorate([
24
24
  UuidProperty(),
25
25
  TenantReference(() => User),
26
26
  __metadata("design:type", String)
27
- ], InAppNotification.prototype, "userId", void 0);
27
+ ], InAppNotificationBase.prototype, "userId", void 0);
28
28
  __decorate([
29
29
  UuidProperty(),
30
30
  __metadata("design:type", String)
31
- ], InAppNotification.prototype, "logId", void 0);
31
+ ], InAppNotificationBase.prototype, "logId", void 0);
32
+ __decorate([
33
+ TimestampProperty(),
34
+ __metadata("design:type", Number)
35
+ ], InAppNotificationBase.prototype, "timestamp", void 0);
32
36
  __decorate([
33
37
  TimestampProperty({ nullable: true }),
34
38
  __metadata("design:type", Object)
35
- ], InAppNotification.prototype, "readTimestamp", void 0);
39
+ ], InAppNotificationBase.prototype, "readTimestamp", void 0);
36
40
  __decorate([
37
41
  TimestampProperty({ nullable: true }),
38
42
  __metadata("design:type", Object)
39
- ], InAppNotification.prototype, "archiveTimestamp", void 0);
43
+ ], InAppNotificationBase.prototype, "archiveTimestamp", void 0);
44
+ let InAppNotification = class InAppNotification extends InAppNotificationBase {
45
+ static entityName = 'InAppNotification';
46
+ };
40
47
  InAppNotification = __decorate([
41
48
  NotificationTable({ name: 'in_app' }),
42
49
  ForeignKey(() => NotificationLogEntity, ['tenantId', 'logId', 'userId'], ['tenantId', 'id', 'userId']),
43
- Index(['tenantId', 'userId', 'logId'], { where: () => ({ archiveTimestamp: null }) })
50
+ Unique(['tenantId', 'userId', 'logId']),
51
+ Index(['tenantId', 'userId', ['timestamp', 'desc'], ['logId', 'desc']]),
52
+ Index(['tenantId', 'userId', ['timestamp', 'desc'], ['logId', 'desc']], { where: (table) => isNull(table.readTimestamp) }),
53
+ Index(['tenantId', 'userId', 'readTimestamp'], { where: (table) => isNotNull(table.readTimestamp) }) // todo: include id as soon as drizzle supports this to make it a covering index for queries that fetch read notifications
54
+ ,
55
+ Index(['timestamp'], { using: 'brin' })
44
56
  ], InAppNotification);
45
57
  export { InAppNotification };
46
- export class InAppNotificationView extends InAppNotification {
58
+ let InAppNotificationArchive = class InAppNotificationArchive extends InAppNotificationBase {
59
+ static entityName = 'InAppNotificationArchive';
60
+ };
61
+ InAppNotificationArchive = __decorate([
62
+ NotificationTable({ name: 'in_app_archive' }),
63
+ Index(['tenantId', 'userId', ['timestamp', 'desc'], ['logId', 'desc']]),
64
+ Index(['tenantId', 'userId', ['archiveTimestamp', 'desc']]) // todo: include id as soon as drizzle supports this to make it a covering index for queries that fetch archived notifications
65
+ ], InAppNotificationArchive);
66
+ export { InAppNotificationArchive };
67
+ export class InAppNotificationView extends InAppNotificationBase {
47
68
  notification;
48
69
  }
49
70
  __decorate([
@@ -9,7 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  };
10
10
  import { Subject, User } from '../../authentication/index.js';
11
11
  import { defineEnum } from '../../enumeration/index.js';
12
- import { Index, JsonProperty, Reference, TenantBaseEntity, TenantReference, TimestampProperty, Unique, UuidProperty } from '../../orm/index.js';
12
+ import { JsonProperty, Reference, TenantBaseEntity, TenantReference, TimestampProperty, Unique, UuidProperty } from '../../orm/index.js';
13
13
  import { Enumeration, Integer, StringProperty } from '../../schema/index.js';
14
14
  import { NotificationTable } from './notification-table.js';
15
15
  import { NotificationType } from './notification-type.model.js';
@@ -79,7 +79,6 @@ __decorate([
79
79
  ], NotificationLogEntity.prototype, "payload", void 0);
80
80
  NotificationLogEntity = __decorate([
81
81
  NotificationTable({ name: 'log' }),
82
- Unique(['tenantId', 'id', 'userId']),
83
- Index(['tenantId', 'userId', 'timestamp'])
82
+ Unique(['tenantId', 'userId', 'id'])
84
83
  ], NotificationLogEntity);
85
84
  export { NotificationLogEntity };
@@ -10,6 +10,7 @@ export declare class NotificationApiController implements ApiController<Notifica
10
10
  stream({ abortSignal, getToken, serverSentEvents: { lastEventId } }: ApiRequestContext<NotificationApiDefinition, 'stream'>): ApiServerResult<NotificationApiDefinition, 'stream'>;
11
11
  types(): Promise<Record<string, string>>;
12
12
  listInApp({ parameters, getToken }: ApiRequestContext<NotificationApiDefinition, 'listInApp'>): Promise<any>;
13
+ listArchivedInApp({ parameters, getToken }: ApiRequestContext<NotificationApiDefinition, 'listArchivedInApp'>): Promise<any>;
13
14
  markRead({ parameters, getToken }: ApiRequestContext<NotificationApiDefinition, 'markRead'>): Promise<'ok'>;
14
15
  markAllRead({ getToken }: ApiRequestContext<NotificationApiDefinition, 'markAllRead'>): Promise<'ok'>;
15
16
  archive({ parameters, getToken }: ApiRequestContext<NotificationApiDefinition, 'archive'>): Promise<'ok'>;
@@ -24,7 +24,9 @@ let NotificationApiController = class NotificationApiController {
24
24
  abortSignal.addEventListener('abort', () => this.sseService.unregister(token.payload.tenant, token.payload.subject, source));
25
25
  try {
26
26
  if (isDefined(lastEventId)) {
27
- const { unreadCount, missedNotifications, readIds, archiveIds } = await this.notificationService.getCatchupData(token.payload.tenant, token.payload.subject, lastEventId);
27
+ const lastEventIdNumber = Number(lastEventId);
28
+ const stateTimestamp = Number.isNaN(lastEventIdNumber) ? 0 : lastEventIdNumber;
29
+ const { unreadCount, missedNotifications, readIds, archiveIds } = await this.notificationService.getCatchupData(token.payload.tenant, token.payload.subject, stateTimestamp);
28
30
  yield { unreadCount };
29
31
  for (const readId of readIds) {
30
32
  yield { readId };
@@ -49,6 +51,10 @@ let NotificationApiController = class NotificationApiController {
49
51
  const token = await getToken();
50
52
  return await this.notificationService.listInApp(token.payload.tenant, token.payload.subject, parameters);
51
53
  }
54
+ async listArchivedInApp({ parameters, getToken }) {
55
+ const token = await getToken();
56
+ return await this.notificationService.listArchivedInApp(token.payload.tenant, token.payload.subject, parameters);
57
+ }
52
58
  async markRead({ parameters, getToken }) {
53
59
  const token = await getToken();
54
60
  await this.notificationService.markRead(token.payload.tenant, token.payload.subject, parameters.id);
@@ -6,9 +6,22 @@ CREATE TABLE "notification"."in_app" (
6
6
  "tenant_id" uuid NOT NULL,
7
7
  "user_id" uuid NOT NULL,
8
8
  "log_id" uuid NOT NULL,
9
+ "timestamp" timestamp with time zone NOT NULL,
10
+ "read_timestamp" timestamp with time zone,
11
+ "archive_timestamp" timestamp with time zone,
12
+ CONSTRAINT "in_app_tenant_id_id_pk" PRIMARY KEY("tenant_id","id"),
13
+ CONSTRAINT "in_app_tenant_id_user_id_log_id_unique" UNIQUE("tenant_id","user_id","log_id")
14
+ );
15
+ --> statement-breakpoint
16
+ CREATE TABLE "notification"."in_app_archive" (
17
+ "id" uuid DEFAULT gen_random_uuid() NOT NULL,
18
+ "tenant_id" uuid NOT NULL,
19
+ "user_id" uuid NOT NULL,
20
+ "log_id" uuid NOT NULL,
21
+ "timestamp" timestamp with time zone NOT NULL,
9
22
  "read_timestamp" timestamp with time zone,
10
23
  "archive_timestamp" timestamp with time zone,
11
- CONSTRAINT "in_app_tenant_id_id_pk" PRIMARY KEY("tenant_id","id")
24
+ CONSTRAINT "in_app_archive_tenant_id_id_pk" PRIMARY KEY("tenant_id","id")
12
25
  );
13
26
  --> statement-breakpoint
14
27
  CREATE TABLE "notification"."log" (
@@ -23,7 +36,7 @@ CREATE TABLE "notification"."log" (
23
36
  "trigger_subject_id" uuid NOT NULL,
24
37
  "payload" jsonb,
25
38
  CONSTRAINT "log_tenant_id_id_pk" PRIMARY KEY("tenant_id","id"),
26
- CONSTRAINT "log_tenant_id_id_user_id_unique" UNIQUE("tenant_id","id","user_id")
39
+ CONSTRAINT "log_tenant_id_user_id_id_unique" UNIQUE("tenant_id","user_id","id")
27
40
  );
28
41
  --> statement-breakpoint
29
42
  CREATE TABLE "notification"."preference" (
@@ -74,11 +87,16 @@ CREATE TABLE "notification"."web_push_subscription" (
74
87
  --> statement-breakpoint
75
88
  ALTER TABLE "notification"."in_app" ADD CONSTRAINT "in_app_id_user_fkey" FOREIGN KEY ("tenant_id","user_id") REFERENCES "authentication"."user"("tenant_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
76
89
  ALTER TABLE "notification"."in_app" ADD CONSTRAINT "in_app_tenantId_logId_userId_log_fkey" FOREIGN KEY ("tenant_id","log_id","user_id") REFERENCES "notification"."log"("tenant_id","id","user_id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
90
+ ALTER TABLE "notification"."in_app_archive" ADD CONSTRAINT "in_app_archive_id_user_fkey" FOREIGN KEY ("tenant_id","user_id") REFERENCES "authentication"."user"("tenant_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
77
91
  ALTER TABLE "notification"."log" ADD CONSTRAINT "log_type_type_key_fk" FOREIGN KEY ("type") REFERENCES "notification"."type"("key") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
78
92
  ALTER TABLE "notification"."log" ADD CONSTRAINT "log_id_user_fkey" FOREIGN KEY ("tenant_id","user_id") REFERENCES "authentication"."user"("tenant_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
79
93
  ALTER TABLE "notification"."log" ADD CONSTRAINT "log_id_subject_fkey" FOREIGN KEY ("tenant_id","trigger_subject_id") REFERENCES "authentication"."subject"("tenant_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
80
94
  ALTER TABLE "notification"."preference" ADD CONSTRAINT "preference_type_type_key_fk" FOREIGN KEY ("type") REFERENCES "notification"."type"("key") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
81
95
  ALTER TABLE "notification"."preference" ADD CONSTRAINT "preference_id_user_fkey" FOREIGN KEY ("tenant_id","user_id") REFERENCES "authentication"."user"("tenant_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
82
96
  ALTER TABLE "notification"."web_push_subscription" ADD CONSTRAINT "web_push_subscription_id_user_fkey" FOREIGN KEY ("tenant_id","user_id") REFERENCES "authentication"."user"("tenant_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
83
- CREATE INDEX "in_app_tenant_id_user_id_log_id_idx" ON "notification"."in_app" USING btree ("tenant_id","user_id","log_id") WHERE "notification"."in_app"."archive_timestamp" is null;--> statement-breakpoint
84
- CREATE INDEX "log_tenant_id_user_id_timestamp_idx" ON "notification"."log" USING btree ("tenant_id","user_id","timestamp");
97
+ CREATE INDEX "in_app_timestamp_idx" ON "notification"."in_app" USING brin ("timestamp");--> statement-breakpoint
98
+ CREATE INDEX "in_app_tenant_id_user_id_read_timestamp_partial_idx" ON "notification"."in_app" USING btree ("tenant_id","user_id","read_timestamp") WHERE "notification"."in_app"."read_timestamp" is not null;--> statement-breakpoint
99
+ CREATE INDEX "in_app_tenant_id_user_id_timestamp_log_id_partial_idx" ON "notification"."in_app" USING btree ("tenant_id","user_id","timestamp" DESC NULLS LAST,"log_id" DESC NULLS LAST) WHERE "notification"."in_app"."read_timestamp" is null;--> statement-breakpoint
100
+ CREATE INDEX "in_app_tenant_id_user_id_timestamp_log_id_idx" ON "notification"."in_app" USING btree ("tenant_id","user_id","timestamp" DESC NULLS LAST,"log_id" DESC NULLS LAST);--> statement-breakpoint
101
+ CREATE INDEX "in_app_archive_tenant_id_user_id_archive_timestamp_idx" ON "notification"."in_app_archive" USING btree ("tenant_id","user_id","archive_timestamp" DESC NULLS LAST);--> statement-breakpoint
102
+ CREATE INDEX "in_app_archive_tenant_id_user_id_timestamp_log_id_idx" ON "notification"."in_app_archive" USING btree ("tenant_id","user_id","timestamp" DESC NULLS LAST,"log_id" DESC NULLS LAST);