@quanticjs/notification-bff 8.3.0
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/README.md +54 -0
- package/dist/NotificationEngineClient.d.ts +20 -0
- package/dist/NotificationEngineClient.d.ts.map +1 -0
- package/dist/NotificationEngineClient.js +100 -0
- package/dist/NotificationEngineClient.js.map +1 -0
- package/dist/NotificationProxyController.d.ts +28 -0
- package/dist/NotificationProxyController.d.ts.map +1 -0
- package/dist/NotificationProxyController.js +169 -0
- package/dist/NotificationProxyController.js.map +1 -0
- package/dist/NotificationProxyModule.d.ts +20 -0
- package/dist/NotificationProxyModule.d.ts.map +1 -0
- package/dist/NotificationProxyModule.js +78 -0
- package/dist/NotificationProxyModule.js.map +1 -0
- package/dist/commands/mark-all-read.handler.d.ts +16 -0
- package/dist/commands/mark-all-read.handler.d.ts.map +1 -0
- package/dist/commands/mark-all-read.handler.js +47 -0
- package/dist/commands/mark-all-read.handler.js.map +1 -0
- package/dist/commands/mark-notification-read.handler.d.ts +18 -0
- package/dist/commands/mark-notification-read.handler.d.ts.map +1 -0
- package/dist/commands/mark-notification-read.handler.js +43 -0
- package/dist/commands/mark-notification-read.handler.js.map +1 -0
- package/dist/commands/update-notification-settings.handler.d.ts +17 -0
- package/dist/commands/update-notification-settings.handler.d.ts.map +1 -0
- package/dist/commands/update-notification-settings.handler.js +42 -0
- package/dist/commands/update-notification-settings.handler.js.map +1 -0
- package/dist/engine-result.d.ts +18 -0
- package/dist/engine-result.d.ts.map +1 -0
- package/dist/engine-result.js +61 -0
- package/dist/engine-result.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.d.ts +41 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +6 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/queries/count-unread.handler.d.ts +16 -0
- package/dist/queries/count-unread.handler.d.ts.map +1 -0
- package/dist/queries/count-unread.handler.js +47 -0
- package/dist/queries/count-unread.handler.js.map +1 -0
- package/dist/queries/get-notification-settings.handler.d.ts +17 -0
- package/dist/queries/get-notification-settings.handler.d.ts.map +1 -0
- package/dist/queries/get-notification-settings.handler.js +40 -0
- package/dist/queries/get-notification-settings.handler.js.map +1 -0
- package/dist/queries/list-notifications.handler.d.ts +21 -0
- package/dist/queries/list-notifications.handler.d.ts.map +1 -0
- package/dist/queries/list-notifications.handler.js +53 -0
- package/dist/queries/list-notifications.handler.js.map +1 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @quanticjs/notification-bff
|
|
2
|
+
|
|
3
|
+
Server-authoritative BFF proxy to the standalone notification engine. Replaces the
|
|
4
|
+
hand-rolled `NotificationController` + engine client that each app used to copy
|
|
5
|
+
(and drift on). One module, two modes.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// app.module.ts — a normal app: the bell shows only THIS app's notifications
|
|
11
|
+
import { NotificationProxyModule } from '@quanticjs/notification-bff';
|
|
12
|
+
|
|
13
|
+
@Module({
|
|
14
|
+
imports: [
|
|
15
|
+
NotificationProxyModule.forRoot({ appId: 'delivery-hub' }),
|
|
16
|
+
],
|
|
17
|
+
})
|
|
18
|
+
export class AppModule {}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// the shell/portal: the bell shows the user's notifications across ALL apps
|
|
23
|
+
NotificationProxyModule.forRoot({ appId: 'shell', unified: true })
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Mounts `GET/POST/PUT /notifications*` under the app's global prefix (e.g.
|
|
27
|
+
`/api/notifications`), proxying to the engine at
|
|
28
|
+
`NOTIFICATION_ENGINE_URL` (default `http://notification-engine:3000`).
|
|
29
|
+
|
|
30
|
+
## Scoping & security
|
|
31
|
+
|
|
32
|
+
Two independent scopes apply to every feed read/mutation:
|
|
33
|
+
|
|
34
|
+
| Scope | Source | Enforced by |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| **User** | the verified bearer token (`requireCurrentUser()`) | the **engine** — always; a caller can only ever see their own notifications |
|
|
37
|
+
| **App** | this module's config | the **BFF** — server-authoritative |
|
|
38
|
+
|
|
39
|
+
App scope:
|
|
40
|
+
|
|
41
|
+
- **Per-app** (`{ appId }`): stamps `appId=<appId>` on `list` / `unread-count` /
|
|
42
|
+
`read-all`, and **strips any client-supplied `appId`** — the browser is not a
|
|
43
|
+
security boundary and cannot widen (or be tricked into narrowing) its scope.
|
|
44
|
+
- **Shell** (`{ unified: true }`): sends **no** `appId`, so the engine returns the
|
|
45
|
+
user's notifications across every app. There is no reliance on an implicit
|
|
46
|
+
"null appId" — unified mode simply omits the app filter; the user filter still
|
|
47
|
+
applies. Provide `appId: 'shell'` alongside as an identity label.
|
|
48
|
+
|
|
49
|
+
There is **no unscoped default**: `forRoot({})` throws at boot, so an app can
|
|
50
|
+
never accidentally serve every application's notifications. The shell scope must
|
|
51
|
+
be opted into explicitly.
|
|
52
|
+
|
|
53
|
+
`config/*` and `preferences` endpoints are proxied unscoped (they are
|
|
54
|
+
app-agnostic / engine-enforced for admin).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type NotificationProxyOptions } from './interfaces';
|
|
2
|
+
export interface ProxiedResponse {
|
|
3
|
+
status: number;
|
|
4
|
+
body: unknown;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* HTTP client for the standalone notification engine's read/preference API.
|
|
8
|
+
* The browser talks to the host app's BFF; the BFF forwards the caller's bearer
|
|
9
|
+
* token so the engine resolves the same user from the shared realm. 5xx trips
|
|
10
|
+
* the circuit breaker; 4xx are passed through verbatim; an unreachable engine
|
|
11
|
+
* degrades to a 503 problem-details body (never throws into the request).
|
|
12
|
+
*/
|
|
13
|
+
export declare class NotificationEngineClient {
|
|
14
|
+
private readonly logger;
|
|
15
|
+
private readonly baseUrl;
|
|
16
|
+
private readonly breaker;
|
|
17
|
+
constructor(options: NotificationProxyOptions);
|
|
18
|
+
forward(method: 'GET' | 'POST' | 'PUT', path: string, authorization: string | undefined, body?: unknown): Promise<ProxiedResponse>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=NotificationEngineClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationEngineClient.d.ts","sourceRoot":"","sources":["../src/NotificationEngineClient.ts"],"names":[],"mappings":"AAEA,OAAO,EAA8B,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAEzF,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;;;GAMG;AACH,qBACa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;IACpE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAIrB;gBAE6C,OAAO,EAAE,wBAAwB;IAO3E,OAAO,CACX,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,EAC9B,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,IAAI,CAAC,EAAE,OAAO,GACb,OAAO,CAAC,eAAe,CAAC;CAyC5B"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var NotificationEngineClient_1;
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.NotificationEngineClient = void 0;
|
|
17
|
+
const common_1 = require("@nestjs/common");
|
|
18
|
+
const core_1 = require("@quanticjs/core");
|
|
19
|
+
const interfaces_1 = require("./interfaces");
|
|
20
|
+
/**
|
|
21
|
+
* HTTP client for the standalone notification engine's read/preference API.
|
|
22
|
+
* The browser talks to the host app's BFF; the BFF forwards the caller's bearer
|
|
23
|
+
* token so the engine resolves the same user from the shared realm. 5xx trips
|
|
24
|
+
* the circuit breaker; 4xx are passed through verbatim; an unreachable engine
|
|
25
|
+
* degrades to a 503 problem-details body (never throws into the request).
|
|
26
|
+
*/
|
|
27
|
+
let NotificationEngineClient = NotificationEngineClient_1 = class NotificationEngineClient {
|
|
28
|
+
logger = new common_1.Logger(NotificationEngineClient_1.name);
|
|
29
|
+
baseUrl;
|
|
30
|
+
breaker = (0, core_1.createCircuitBreaker)({
|
|
31
|
+
maxRetries: 2,
|
|
32
|
+
consecutiveFailures: 5,
|
|
33
|
+
halfOpenAfterMs: 30_000,
|
|
34
|
+
});
|
|
35
|
+
constructor(options) {
|
|
36
|
+
this.baseUrl =
|
|
37
|
+
options.engineBaseUrl ??
|
|
38
|
+
process.env.NOTIFICATION_ENGINE_URL ??
|
|
39
|
+
'http://notification-engine:3000';
|
|
40
|
+
}
|
|
41
|
+
async forward(method, path, authorization, body) {
|
|
42
|
+
try {
|
|
43
|
+
return await this.breaker.execute(async () => {
|
|
44
|
+
const res = await fetch(`${this.baseUrl}/api${path}`, {
|
|
45
|
+
method,
|
|
46
|
+
headers: {
|
|
47
|
+
'Content-Type': 'application/json',
|
|
48
|
+
...(authorization ? { Authorization: authorization } : {}),
|
|
49
|
+
},
|
|
50
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
51
|
+
});
|
|
52
|
+
const text = await res.text();
|
|
53
|
+
let parsed = null;
|
|
54
|
+
try {
|
|
55
|
+
parsed = text ? JSON.parse(text) : null;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
parsed = text;
|
|
59
|
+
}
|
|
60
|
+
// 4xx are passed through verbatim; only 5xx count as breaker failures.
|
|
61
|
+
if (res.status >= 500) {
|
|
62
|
+
throw new EngineUnavailableError(res.status, parsed);
|
|
63
|
+
}
|
|
64
|
+
return { status: res.status, body: parsed };
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error instanceof EngineUnavailableError) {
|
|
69
|
+
return { status: error.status, body: error.body };
|
|
70
|
+
}
|
|
71
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72
|
+
this.logger.warn(`Notification engine unreachable (${path}): ${message}`);
|
|
73
|
+
return {
|
|
74
|
+
status: 503,
|
|
75
|
+
body: {
|
|
76
|
+
type: 'https://quantic.dev/errors/SERVICE_UNAVAILABLE',
|
|
77
|
+
title: 'Service Unavailable',
|
|
78
|
+
status: 503,
|
|
79
|
+
detail: 'Notification service temporarily unavailable',
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
exports.NotificationEngineClient = NotificationEngineClient;
|
|
86
|
+
exports.NotificationEngineClient = NotificationEngineClient = NotificationEngineClient_1 = __decorate([
|
|
87
|
+
(0, common_1.Injectable)(),
|
|
88
|
+
__param(0, (0, common_1.Inject)(interfaces_1.NOTIFICATION_PROXY_OPTIONS)),
|
|
89
|
+
__metadata("design:paramtypes", [Object])
|
|
90
|
+
], NotificationEngineClient);
|
|
91
|
+
class EngineUnavailableError extends Error {
|
|
92
|
+
status;
|
|
93
|
+
body;
|
|
94
|
+
constructor(status, body) {
|
|
95
|
+
super(`Notification engine responded ${status}`);
|
|
96
|
+
this.status = status;
|
|
97
|
+
this.body = body;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=NotificationEngineClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationEngineClient.js","sourceRoot":"","sources":["../src/NotificationEngineClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { Inject, Injectable, Logger } from '@nestjs/common';\nimport { createCircuitBreaker } from '@quanticjs/core';\nimport { NOTIFICATION_PROXY_OPTIONS, type NotificationProxyOptions } from './interfaces';\n\nexport interface ProxiedResponse {\n status: number;\n body: unknown;\n}\n\n/**\n * HTTP client for the standalone notification engine's read/preference API.\n * The browser talks to the host app's BFF; the BFF forwards the caller's bearer\n * token so the engine resolves the same user from the shared realm. 5xx trips\n * the circuit breaker; 4xx are passed through verbatim; an unreachable engine\n * degrades to a 503 problem-details body (never throws into the request).\n */\n@Injectable()\nexport class NotificationEngineClient {\n private readonly logger = new Logger(NotificationEngineClient.name);\n private readonly baseUrl: string;\n\n private readonly breaker = createCircuitBreaker({\n maxRetries: 2,\n consecutiveFailures: 5,\n halfOpenAfterMs: 30_000,\n });\n\n constructor(@Inject(NOTIFICATION_PROXY_OPTIONS) options: NotificationProxyOptions) {\n this.baseUrl =\n options.engineBaseUrl ??\n process.env.NOTIFICATION_ENGINE_URL ??\n 'http://notification-engine:3000';\n }\n\n async forward(\n method: 'GET' | 'POST' | 'PUT',\n path: string,\n authorization: string | undefined,\n body?: unknown,\n ): Promise<ProxiedResponse> {\n try {\n return await this.breaker.execute(async () => {\n const res = await fetch(`${this.baseUrl}/api${path}`, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n ...(authorization ? { Authorization: authorization } : {}),\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n const text = await res.text();\n let parsed: unknown = null;\n try {\n parsed = text ? JSON.parse(text) : null;\n } catch {\n parsed = text;\n }\n // 4xx are passed through verbatim; only 5xx count as breaker failures.\n if (res.status >= 500) {\n throw new EngineUnavailableError(res.status, parsed);\n }\n return { status: res.status, body: parsed };\n });\n } catch (error: unknown) {\n if (error instanceof EngineUnavailableError) {\n return { status: error.status, body: error.body };\n }\n const message = error instanceof Error ? error.message : String(error);\n this.logger.warn(`Notification engine unreachable (${path}): ${message}`);\n return {\n status: 503,\n body: {\n type: 'https://quantic.dev/errors/SERVICE_UNAVAILABLE',\n title: 'Service Unavailable',\n status: 503,\n detail: 'Notification service temporarily unavailable',\n },\n };\n }\n }\n}\n\nclass EngineUnavailableError extends Error {\n constructor(\n readonly status: number,\n readonly body: unknown,\n ) {\n super(`Notification engine responded ${status}`);\n }\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { CommandBus, QueryBus } from '@nestjs/cqrs';
|
|
2
|
+
import type { Request } from 'express';
|
|
3
|
+
/**
|
|
4
|
+
* Thin BFF controller for the standalone notification engine. Parses the request
|
|
5
|
+
* and dispatches to the Query/Command bus — the handlers forward to the engine
|
|
6
|
+
* and return `Result`, so these endpoints get the standard pipeline behaviors
|
|
7
|
+
* (Log, AuthContext, Tracing, Performance) and `ResultInterceptor` HTTP mapping
|
|
8
|
+
* like every other controller.
|
|
9
|
+
*
|
|
10
|
+
* App scope (per-app stamp / shell unscoped) is applied in the handlers; the
|
|
11
|
+
* engine always scopes the feed to the verified token's user.
|
|
12
|
+
*/
|
|
13
|
+
export declare class NotificationProxyController {
|
|
14
|
+
private readonly queryBus;
|
|
15
|
+
private readonly commandBus;
|
|
16
|
+
constructor(queryBus: QueryBus, commandBus: CommandBus);
|
|
17
|
+
list(req: Request, query: Record<string, string>): Promise<any>;
|
|
18
|
+
unreadCount(req: Request): Promise<any>;
|
|
19
|
+
markAllRead(req: Request): Promise<any>;
|
|
20
|
+
markRead(req: Request, id: string): Promise<any>;
|
|
21
|
+
getPreferences(req: Request): Promise<any>;
|
|
22
|
+
updatePreferences(req: Request, body: unknown): Promise<any>;
|
|
23
|
+
getQuietHours(req: Request): Promise<any>;
|
|
24
|
+
updateQuietHours(req: Request, body: unknown): Promise<any>;
|
|
25
|
+
getFrequencyCap(req: Request): Promise<any>;
|
|
26
|
+
updateFrequencyCap(req: Request, body: unknown): Promise<any>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=NotificationProxyController.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationProxyController.d.ts","sourceRoot":"","sources":["../src/NotificationProxyController.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AASvC;;;;;;;;;GASG;AACH,qBAEa,2BAA2B;IAEpC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;gBADV,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,UAAU;IAMzC,IAAI,CAAQ,GAAG,EAAE,OAAO,EAAW,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAOhE,WAAW,CAAQ,GAAG,EAAE,OAAO;IAO/B,WAAW,CAAQ,GAAG,EAAE,OAAO;IAO/B,QAAQ,CAAQ,GAAG,EAAE,OAAO,EAAe,EAAE,EAAE,MAAM;IAMrD,cAAc,CAAQ,GAAG,EAAE,OAAO;IAQlC,iBAAiB,CAAQ,GAAG,EAAE,OAAO,EAAU,IAAI,EAAE,OAAO;IAQ5D,aAAa,CAAQ,GAAG,EAAE,OAAO;IAQjC,gBAAgB,CAAQ,GAAG,EAAE,OAAO,EAAU,IAAI,EAAE,OAAO;IAQ3D,eAAe,CAAQ,GAAG,EAAE,OAAO;IAQnC,kBAAkB,CAAQ,GAAG,EAAE,OAAO,EAAU,IAAI,EAAE,OAAO;CAK9D"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.NotificationProxyController = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const cqrs_1 = require("@nestjs/cqrs");
|
|
18
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
19
|
+
const list_notifications_handler_1 = require("./queries/list-notifications.handler");
|
|
20
|
+
const count_unread_handler_1 = require("./queries/count-unread.handler");
|
|
21
|
+
const get_notification_settings_handler_1 = require("./queries/get-notification-settings.handler");
|
|
22
|
+
const mark_notification_read_handler_1 = require("./commands/mark-notification-read.handler");
|
|
23
|
+
const mark_all_read_handler_1 = require("./commands/mark-all-read.handler");
|
|
24
|
+
const update_notification_settings_handler_1 = require("./commands/update-notification-settings.handler");
|
|
25
|
+
/**
|
|
26
|
+
* Thin BFF controller for the standalone notification engine. Parses the request
|
|
27
|
+
* and dispatches to the Query/Command bus — the handlers forward to the engine
|
|
28
|
+
* and return `Result`, so these endpoints get the standard pipeline behaviors
|
|
29
|
+
* (Log, AuthContext, Tracing, Performance) and `ResultInterceptor` HTTP mapping
|
|
30
|
+
* like every other controller.
|
|
31
|
+
*
|
|
32
|
+
* App scope (per-app stamp / shell unscoped) is applied in the handlers; the
|
|
33
|
+
* engine always scopes the feed to the verified token's user.
|
|
34
|
+
*/
|
|
35
|
+
let NotificationProxyController = class NotificationProxyController {
|
|
36
|
+
queryBus;
|
|
37
|
+
commandBus;
|
|
38
|
+
constructor(queryBus, commandBus) {
|
|
39
|
+
this.queryBus = queryBus;
|
|
40
|
+
this.commandBus = commandBus;
|
|
41
|
+
}
|
|
42
|
+
list(req, query) {
|
|
43
|
+
return this.queryBus.execute(new list_notifications_handler_1.ListNotificationsQuery(req.headers.authorization, query));
|
|
44
|
+
}
|
|
45
|
+
unreadCount(req) {
|
|
46
|
+
return this.queryBus.execute(new count_unread_handler_1.CountUnreadQuery(req.headers.authorization));
|
|
47
|
+
}
|
|
48
|
+
markAllRead(req) {
|
|
49
|
+
return this.commandBus.execute(new mark_all_read_handler_1.MarkAllNotificationsReadCommand(req.headers.authorization));
|
|
50
|
+
}
|
|
51
|
+
markRead(req, id) {
|
|
52
|
+
return this.commandBus.execute(new mark_notification_read_handler_1.MarkNotificationReadCommand(req.headers.authorization, id));
|
|
53
|
+
}
|
|
54
|
+
getPreferences(req) {
|
|
55
|
+
return this.queryBus.execute(new get_notification_settings_handler_1.GetNotificationSettingsQuery(req.headers.authorization, 'preferences'));
|
|
56
|
+
}
|
|
57
|
+
updatePreferences(req, body) {
|
|
58
|
+
return this.commandBus.execute(new update_notification_settings_handler_1.UpdateNotificationSettingsCommand(req.headers.authorization, 'preferences', body));
|
|
59
|
+
}
|
|
60
|
+
getQuietHours(req) {
|
|
61
|
+
return this.queryBus.execute(new get_notification_settings_handler_1.GetNotificationSettingsQuery(req.headers.authorization, 'config/quiet-hours'));
|
|
62
|
+
}
|
|
63
|
+
updateQuietHours(req, body) {
|
|
64
|
+
return this.commandBus.execute(new update_notification_settings_handler_1.UpdateNotificationSettingsCommand(req.headers.authorization, 'config/quiet-hours', body));
|
|
65
|
+
}
|
|
66
|
+
getFrequencyCap(req) {
|
|
67
|
+
return this.queryBus.execute(new get_notification_settings_handler_1.GetNotificationSettingsQuery(req.headers.authorization, 'config/frequency-cap'));
|
|
68
|
+
}
|
|
69
|
+
updateFrequencyCap(req, body) {
|
|
70
|
+
return this.commandBus.execute(new update_notification_settings_handler_1.UpdateNotificationSettingsCommand(req.headers.authorization, 'config/frequency-cap', body));
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
exports.NotificationProxyController = NotificationProxyController;
|
|
74
|
+
__decorate([
|
|
75
|
+
(0, common_1.Get)(),
|
|
76
|
+
(0, swagger_1.ApiOperation)({ summary: 'List notifications for the current user (proxied)' }),
|
|
77
|
+
(0, swagger_1.ApiResponse)({ status: 200, description: 'Paginated list of notifications' }),
|
|
78
|
+
__param(0, (0, common_1.Req)()),
|
|
79
|
+
__param(1, (0, common_1.Query)()),
|
|
80
|
+
__metadata("design:type", Function),
|
|
81
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
82
|
+
__metadata("design:returntype", void 0)
|
|
83
|
+
], NotificationProxyController.prototype, "list", null);
|
|
84
|
+
__decorate([
|
|
85
|
+
(0, common_1.Get)('unread-count'),
|
|
86
|
+
(0, swagger_1.ApiOperation)({ summary: 'Get unread notification count (proxied)' }),
|
|
87
|
+
(0, swagger_1.ApiResponse)({ status: 200, description: 'Unread count' }),
|
|
88
|
+
__param(0, (0, common_1.Req)()),
|
|
89
|
+
__metadata("design:type", Function),
|
|
90
|
+
__metadata("design:paramtypes", [Object]),
|
|
91
|
+
__metadata("design:returntype", void 0)
|
|
92
|
+
], NotificationProxyController.prototype, "unreadCount", null);
|
|
93
|
+
__decorate([
|
|
94
|
+
(0, common_1.Post)('read-all'),
|
|
95
|
+
(0, swagger_1.ApiOperation)({ summary: 'Mark all notifications as read (proxied)' }),
|
|
96
|
+
(0, swagger_1.ApiResponse)({ status: 200, description: 'All notifications marked as read' }),
|
|
97
|
+
__param(0, (0, common_1.Req)()),
|
|
98
|
+
__metadata("design:type", Function),
|
|
99
|
+
__metadata("design:paramtypes", [Object]),
|
|
100
|
+
__metadata("design:returntype", void 0)
|
|
101
|
+
], NotificationProxyController.prototype, "markAllRead", null);
|
|
102
|
+
__decorate([
|
|
103
|
+
(0, common_1.Post)(':id/read'),
|
|
104
|
+
(0, swagger_1.ApiOperation)({ summary: 'Mark a notification as read (proxied)' }),
|
|
105
|
+
(0, swagger_1.ApiResponse)({ status: 200, description: 'Notification marked as read' }),
|
|
106
|
+
__param(0, (0, common_1.Req)()),
|
|
107
|
+
__param(1, (0, common_1.Param)('id')),
|
|
108
|
+
__metadata("design:type", Function),
|
|
109
|
+
__metadata("design:paramtypes", [Object, String]),
|
|
110
|
+
__metadata("design:returntype", void 0)
|
|
111
|
+
], NotificationProxyController.prototype, "markRead", null);
|
|
112
|
+
__decorate([
|
|
113
|
+
(0, common_1.Get)('preferences'),
|
|
114
|
+
(0, swagger_1.ApiOperation)({ summary: 'Get effective notification preferences (proxied)' }),
|
|
115
|
+
__param(0, (0, common_1.Req)()),
|
|
116
|
+
__metadata("design:type", Function),
|
|
117
|
+
__metadata("design:paramtypes", [Object]),
|
|
118
|
+
__metadata("design:returntype", void 0)
|
|
119
|
+
], NotificationProxyController.prototype, "getPreferences", null);
|
|
120
|
+
__decorate([
|
|
121
|
+
(0, common_1.Put)('preferences'),
|
|
122
|
+
(0, swagger_1.ApiOperation)({ summary: 'Upsert notification preference overrides (proxied)' }),
|
|
123
|
+
__param(0, (0, common_1.Req)()),
|
|
124
|
+
__param(1, (0, common_1.Body)()),
|
|
125
|
+
__metadata("design:type", Function),
|
|
126
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
127
|
+
__metadata("design:returntype", void 0)
|
|
128
|
+
], NotificationProxyController.prototype, "updatePreferences", null);
|
|
129
|
+
__decorate([
|
|
130
|
+
(0, common_1.Get)('config/quiet-hours'),
|
|
131
|
+
(0, swagger_1.ApiOperation)({ summary: 'Get quiet-hours config (proxied)' }),
|
|
132
|
+
__param(0, (0, common_1.Req)()),
|
|
133
|
+
__metadata("design:type", Function),
|
|
134
|
+
__metadata("design:paramtypes", [Object]),
|
|
135
|
+
__metadata("design:returntype", void 0)
|
|
136
|
+
], NotificationProxyController.prototype, "getQuietHours", null);
|
|
137
|
+
__decorate([
|
|
138
|
+
(0, common_1.Put)('config/quiet-hours'),
|
|
139
|
+
(0, swagger_1.ApiOperation)({ summary: 'Update quiet-hours config (proxied; engine enforces admin)' }),
|
|
140
|
+
__param(0, (0, common_1.Req)()),
|
|
141
|
+
__param(1, (0, common_1.Body)()),
|
|
142
|
+
__metadata("design:type", Function),
|
|
143
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
144
|
+
__metadata("design:returntype", void 0)
|
|
145
|
+
], NotificationProxyController.prototype, "updateQuietHours", null);
|
|
146
|
+
__decorate([
|
|
147
|
+
(0, common_1.Get)('config/frequency-cap'),
|
|
148
|
+
(0, swagger_1.ApiOperation)({ summary: 'Get per-channel frequency caps (proxied)' }),
|
|
149
|
+
__param(0, (0, common_1.Req)()),
|
|
150
|
+
__metadata("design:type", Function),
|
|
151
|
+
__metadata("design:paramtypes", [Object]),
|
|
152
|
+
__metadata("design:returntype", void 0)
|
|
153
|
+
], NotificationProxyController.prototype, "getFrequencyCap", null);
|
|
154
|
+
__decorate([
|
|
155
|
+
(0, common_1.Put)('config/frequency-cap'),
|
|
156
|
+
(0, swagger_1.ApiOperation)({ summary: 'Update per-channel frequency caps (proxied; engine enforces admin)' }),
|
|
157
|
+
__param(0, (0, common_1.Req)()),
|
|
158
|
+
__param(1, (0, common_1.Body)()),
|
|
159
|
+
__metadata("design:type", Function),
|
|
160
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
161
|
+
__metadata("design:returntype", void 0)
|
|
162
|
+
], NotificationProxyController.prototype, "updateFrequencyCap", null);
|
|
163
|
+
exports.NotificationProxyController = NotificationProxyController = __decorate([
|
|
164
|
+
(0, swagger_1.ApiTags)('notifications'),
|
|
165
|
+
(0, common_1.Controller)('notifications'),
|
|
166
|
+
__metadata("design:paramtypes", [cqrs_1.QueryBus,
|
|
167
|
+
cqrs_1.CommandBus])
|
|
168
|
+
], NotificationProxyController);
|
|
169
|
+
//# sourceMappingURL=NotificationProxyController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationProxyController.js","sourceRoot":"","sources":["../src/NotificationProxyController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Body, Controller, Get, Param, Post, Put, Query, Req } from '@nestjs/common';\nimport { CommandBus, QueryBus } from '@nestjs/cqrs';\nimport type { Request } from 'express';\nimport { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';\nimport { ListNotificationsQuery } from './queries/list-notifications.handler';\nimport { CountUnreadQuery } from './queries/count-unread.handler';\nimport { GetNotificationSettingsQuery } from './queries/get-notification-settings.handler';\nimport { MarkNotificationReadCommand } from './commands/mark-notification-read.handler';\nimport { MarkAllNotificationsReadCommand } from './commands/mark-all-read.handler';\nimport { UpdateNotificationSettingsCommand } from './commands/update-notification-settings.handler';\n\n/**\n * Thin BFF controller for the standalone notification engine. Parses the request\n * and dispatches to the Query/Command bus — the handlers forward to the engine\n * and return `Result`, so these endpoints get the standard pipeline behaviors\n * (Log, AuthContext, Tracing, Performance) and `ResultInterceptor` HTTP mapping\n * like every other controller.\n *\n * App scope (per-app stamp / shell unscoped) is applied in the handlers; the\n * engine always scopes the feed to the verified token's user.\n */\n@ApiTags('notifications')\n@Controller('notifications')\nexport class NotificationProxyController {\n constructor(\n private readonly queryBus: QueryBus,\n private readonly commandBus: CommandBus,\n ) {}\n\n @Get()\n @ApiOperation({ summary: 'List notifications for the current user (proxied)' })\n @ApiResponse({ status: 200, description: 'Paginated list of notifications' })\n list(@Req() req: Request, @Query() query: Record<string, string>) {\n return this.queryBus.execute(new ListNotificationsQuery(req.headers.authorization, query));\n }\n\n @Get('unread-count')\n @ApiOperation({ summary: 'Get unread notification count (proxied)' })\n @ApiResponse({ status: 200, description: 'Unread count' })\n unreadCount(@Req() req: Request) {\n return this.queryBus.execute(new CountUnreadQuery(req.headers.authorization));\n }\n\n @Post('read-all')\n @ApiOperation({ summary: 'Mark all notifications as read (proxied)' })\n @ApiResponse({ status: 200, description: 'All notifications marked as read' })\n markAllRead(@Req() req: Request) {\n return this.commandBus.execute(new MarkAllNotificationsReadCommand(req.headers.authorization));\n }\n\n @Post(':id/read')\n @ApiOperation({ summary: 'Mark a notification as read (proxied)' })\n @ApiResponse({ status: 200, description: 'Notification marked as read' })\n markRead(@Req() req: Request, @Param('id') id: string) {\n return this.commandBus.execute(new MarkNotificationReadCommand(req.headers.authorization, id));\n }\n\n @Get('preferences')\n @ApiOperation({ summary: 'Get effective notification preferences (proxied)' })\n getPreferences(@Req() req: Request) {\n return this.queryBus.execute(\n new GetNotificationSettingsQuery(req.headers.authorization, 'preferences'),\n );\n }\n\n @Put('preferences')\n @ApiOperation({ summary: 'Upsert notification preference overrides (proxied)' })\n updatePreferences(@Req() req: Request, @Body() body: unknown) {\n return this.commandBus.execute(\n new UpdateNotificationSettingsCommand(req.headers.authorization, 'preferences', body),\n );\n }\n\n @Get('config/quiet-hours')\n @ApiOperation({ summary: 'Get quiet-hours config (proxied)' })\n getQuietHours(@Req() req: Request) {\n return this.queryBus.execute(\n new GetNotificationSettingsQuery(req.headers.authorization, 'config/quiet-hours'),\n );\n }\n\n @Put('config/quiet-hours')\n @ApiOperation({ summary: 'Update quiet-hours config (proxied; engine enforces admin)' })\n updateQuietHours(@Req() req: Request, @Body() body: unknown) {\n return this.commandBus.execute(\n new UpdateNotificationSettingsCommand(req.headers.authorization, 'config/quiet-hours', body),\n );\n }\n\n @Get('config/frequency-cap')\n @ApiOperation({ summary: 'Get per-channel frequency caps (proxied)' })\n getFrequencyCap(@Req() req: Request) {\n return this.queryBus.execute(\n new GetNotificationSettingsQuery(req.headers.authorization, 'config/frequency-cap'),\n );\n }\n\n @Put('config/frequency-cap')\n @ApiOperation({ summary: 'Update per-channel frequency caps (proxied; engine enforces admin)' })\n updateFrequencyCap(@Req() req: Request, @Body() body: unknown) {\n return this.commandBus.execute(\n new UpdateNotificationSettingsCommand(req.headers.authorization, 'config/frequency-cap', body),\n );\n }\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DynamicModule } from '@nestjs/common';
|
|
2
|
+
import { type NotificationProxyOptions } from './interfaces';
|
|
3
|
+
/**
|
|
4
|
+
* BFF proxy to the standalone notification engine, mounted at `/notifications`
|
|
5
|
+
* (under the app's global prefix). Thin controller → Query/Command bus →
|
|
6
|
+
* handlers that forward to the engine. The handlers self-register with the
|
|
7
|
+
* global CqrsModule (provided by `QuanticCoreModule`); do NOT import CqrsModule
|
|
8
|
+
* here. Import this module ONCE per app:
|
|
9
|
+
*
|
|
10
|
+
* NotificationProxyModule.forRoot({ appId: 'delivery-hub' }) // per-app bell
|
|
11
|
+
* NotificationProxyModule.forRoot({ appId: 'shell', unified: true }) // shell
|
|
12
|
+
*
|
|
13
|
+
* `forRoot({})` throws at boot — there is no unscoped default, so an app can
|
|
14
|
+
* never accidentally serve every app's notifications. In every mode the engine
|
|
15
|
+
* scopes the feed to the verified token's user (callers see only their own).
|
|
16
|
+
*/
|
|
17
|
+
export declare class NotificationProxyModule {
|
|
18
|
+
static forRoot(options: NotificationProxyOptions): DynamicModule;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=NotificationProxyModule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationProxyModule.d.ts","sourceRoot":"","sources":["../src/NotificationProxyModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAyB,MAAM,gBAAgB,CAAC;AAGtE,OAAO,EAA8B,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAiBzF;;;;;;;;;;;;;GAaG;AACH,qBACa,uBAAuB;IAClC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,wBAAwB,GAAG,aAAa;CAgBjE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var NotificationProxyModule_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.NotificationProxyModule = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const NotificationEngineClient_1 = require("./NotificationEngineClient");
|
|
13
|
+
const NotificationProxyController_1 = require("./NotificationProxyController");
|
|
14
|
+
const interfaces_1 = require("./interfaces");
|
|
15
|
+
const list_notifications_handler_1 = require("./queries/list-notifications.handler");
|
|
16
|
+
const count_unread_handler_1 = require("./queries/count-unread.handler");
|
|
17
|
+
const get_notification_settings_handler_1 = require("./queries/get-notification-settings.handler");
|
|
18
|
+
const mark_notification_read_handler_1 = require("./commands/mark-notification-read.handler");
|
|
19
|
+
const mark_all_read_handler_1 = require("./commands/mark-all-read.handler");
|
|
20
|
+
const update_notification_settings_handler_1 = require("./commands/update-notification-settings.handler");
|
|
21
|
+
const HANDLERS = [
|
|
22
|
+
list_notifications_handler_1.ListNotificationsHandler,
|
|
23
|
+
count_unread_handler_1.CountUnreadHandler,
|
|
24
|
+
get_notification_settings_handler_1.GetNotificationSettingsHandler,
|
|
25
|
+
mark_notification_read_handler_1.MarkNotificationReadHandler,
|
|
26
|
+
mark_all_read_handler_1.MarkAllNotificationsReadHandler,
|
|
27
|
+
update_notification_settings_handler_1.UpdateNotificationSettingsHandler,
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* BFF proxy to the standalone notification engine, mounted at `/notifications`
|
|
31
|
+
* (under the app's global prefix). Thin controller → Query/Command bus →
|
|
32
|
+
* handlers that forward to the engine. The handlers self-register with the
|
|
33
|
+
* global CqrsModule (provided by `QuanticCoreModule`); do NOT import CqrsModule
|
|
34
|
+
* here. Import this module ONCE per app:
|
|
35
|
+
*
|
|
36
|
+
* NotificationProxyModule.forRoot({ appId: 'delivery-hub' }) // per-app bell
|
|
37
|
+
* NotificationProxyModule.forRoot({ appId: 'shell', unified: true }) // shell
|
|
38
|
+
*
|
|
39
|
+
* `forRoot({})` throws at boot — there is no unscoped default, so an app can
|
|
40
|
+
* never accidentally serve every app's notifications. In every mode the engine
|
|
41
|
+
* scopes the feed to the verified token's user (callers see only their own).
|
|
42
|
+
*/
|
|
43
|
+
let NotificationProxyModule = NotificationProxyModule_1 = class NotificationProxyModule {
|
|
44
|
+
static forRoot(options) {
|
|
45
|
+
validateOptions(options);
|
|
46
|
+
const providers = [
|
|
47
|
+
{ provide: interfaces_1.NOTIFICATION_PROXY_OPTIONS, useValue: options },
|
|
48
|
+
NotificationEngineClient_1.NotificationEngineClient,
|
|
49
|
+
...HANDLERS,
|
|
50
|
+
];
|
|
51
|
+
return {
|
|
52
|
+
module: NotificationProxyModule_1,
|
|
53
|
+
controllers: [NotificationProxyController_1.NotificationProxyController],
|
|
54
|
+
providers,
|
|
55
|
+
exports: [NotificationEngineClient_1.NotificationEngineClient],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
exports.NotificationProxyModule = NotificationProxyModule;
|
|
60
|
+
exports.NotificationProxyModule = NotificationProxyModule = NotificationProxyModule_1 = __decorate([
|
|
61
|
+
(0, common_1.Module)({})
|
|
62
|
+
], NotificationProxyModule);
|
|
63
|
+
function validateOptions(options) {
|
|
64
|
+
if (!options || typeof options !== 'object') {
|
|
65
|
+
throw new Error('NotificationProxyModule.forRoot requires options: { appId } for a per-app bell, ' +
|
|
66
|
+
'or { unified: true } for a shell/portal.');
|
|
67
|
+
}
|
|
68
|
+
if (!options.unified && !options.appId) {
|
|
69
|
+
throw new Error('NotificationProxyModule.forRoot must specify either { appId } (per-app scope) or ' +
|
|
70
|
+
'{ unified: true } (shell scope). Refusing to start unscoped — an unscoped per-app ' +
|
|
71
|
+
'bell would expose every application’s notifications.');
|
|
72
|
+
}
|
|
73
|
+
if (options.appId !== undefined && !/^[a-z][a-z0-9-]{1,63}$/.test(options.appId)) {
|
|
74
|
+
throw new Error(`NotificationProxyModule.forRoot: invalid appId "${options.appId}" — must be a lowercase ` +
|
|
75
|
+
'application slug (matching the engine application registry).');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=NotificationProxyModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationProxyModule.js","sourceRoot":"","sources":["../src/NotificationProxyModule.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAsE;AACtE,yEAAsE;AACtE,+EAA4E;AAC5E,6CAAyF;AACzF,qFAAgF;AAChF,yEAAoE;AACpE,mGAA6F;AAC7F,8FAAwF;AACxF,4EAAmF;AACnF,0GAAoG;AAEpG,MAAM,QAAQ,GAAG;IACf,qDAAwB;IACxB,yCAAkB;IAClB,kEAA8B;IAC9B,4DAA2B;IAC3B,uDAA+B;IAC/B,wEAAiC;CAClC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AAEI,IAAM,uBAAuB,+BAA7B,MAAM,uBAAuB;IAClC,MAAM,CAAC,OAAO,CAAC,OAAiC;QAC9C,eAAe,CAAC,OAAO,CAAC,CAAC;QAEzB,MAAM,SAAS,GAAe;YAC5B,EAAE,OAAO,EAAE,uCAA0B,EAAE,QAAQ,EAAE,OAAO,EAAE;YAC1D,mDAAwB;YACxB,GAAG,QAAQ;SACZ,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,yBAAuB;YAC/B,WAAW,EAAE,CAAC,yDAA2B,CAAC;YAC1C,SAAS;YACT,OAAO,EAAE,CAAC,mDAAwB,CAAC;SACpC,CAAC;IACJ,CAAC;CACF,CAAA;AAjBY,0DAAuB;kCAAvB,uBAAuB;IADnC,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,uBAAuB,CAiBnC;AAED,SAAS,eAAe,CAAC,OAAiC;IACxD,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,kFAAkF;YAChF,0CAA0C,CAC7C,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,mFAAmF;YACjF,oFAAoF;YACpF,sDAAsD,CACzD,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CACb,mDAAmD,OAAO,CAAC,KAAK,0BAA0B;YACxF,8DAA8D,CACjE,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { DynamicModule, Module, type Provider } from '@nestjs/common';\nimport { NotificationEngineClient } from './NotificationEngineClient';\nimport { NotificationProxyController } from './NotificationProxyController';\nimport { NOTIFICATION_PROXY_OPTIONS, type NotificationProxyOptions } from './interfaces';\nimport { ListNotificationsHandler } from './queries/list-notifications.handler';\nimport { CountUnreadHandler } from './queries/count-unread.handler';\nimport { GetNotificationSettingsHandler } from './queries/get-notification-settings.handler';\nimport { MarkNotificationReadHandler } from './commands/mark-notification-read.handler';\nimport { MarkAllNotificationsReadHandler } from './commands/mark-all-read.handler';\nimport { UpdateNotificationSettingsHandler } from './commands/update-notification-settings.handler';\n\nconst HANDLERS = [\n ListNotificationsHandler,\n CountUnreadHandler,\n GetNotificationSettingsHandler,\n MarkNotificationReadHandler,\n MarkAllNotificationsReadHandler,\n UpdateNotificationSettingsHandler,\n];\n\n/**\n * BFF proxy to the standalone notification engine, mounted at `/notifications`\n * (under the app's global prefix). Thin controller → Query/Command bus →\n * handlers that forward to the engine. The handlers self-register with the\n * global CqrsModule (provided by `QuanticCoreModule`); do NOT import CqrsModule\n * here. Import this module ONCE per app:\n *\n * NotificationProxyModule.forRoot({ appId: 'delivery-hub' }) // per-app bell\n * NotificationProxyModule.forRoot({ appId: 'shell', unified: true }) // shell\n *\n * `forRoot({})` throws at boot — there is no unscoped default, so an app can\n * never accidentally serve every app's notifications. In every mode the engine\n * scopes the feed to the verified token's user (callers see only their own).\n */\n@Module({})\nexport class NotificationProxyModule {\n static forRoot(options: NotificationProxyOptions): DynamicModule {\n validateOptions(options);\n\n const providers: Provider[] = [\n { provide: NOTIFICATION_PROXY_OPTIONS, useValue: options },\n NotificationEngineClient,\n ...HANDLERS,\n ];\n\n return {\n module: NotificationProxyModule,\n controllers: [NotificationProxyController],\n providers,\n exports: [NotificationEngineClient],\n };\n }\n}\n\nfunction validateOptions(options: NotificationProxyOptions): void {\n if (!options || typeof options !== 'object') {\n throw new Error(\n 'NotificationProxyModule.forRoot requires options: { appId } for a per-app bell, ' +\n 'or { unified: true } for a shell/portal.',\n );\n }\n if (!options.unified && !options.appId) {\n throw new Error(\n 'NotificationProxyModule.forRoot must specify either { appId } (per-app scope) or ' +\n '{ unified: true } (shell scope). Refusing to start unscoped — an unscoped per-app ' +\n 'bell would expose every application’s notifications.',\n );\n }\n if (options.appId !== undefined && !/^[a-z][a-z0-9-]{1,63}$/.test(options.appId)) {\n throw new Error(\n `NotificationProxyModule.forRoot: invalid appId \"${options.appId}\" — must be a lowercase ` +\n 'application slug (matching the engine application registry).',\n );\n }\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ICommandHandler } from '@nestjs/cqrs';
|
|
2
|
+
import { Result } from '@quanticjs/core';
|
|
3
|
+
import { NotificationEngineClient } from '../NotificationEngineClient';
|
|
4
|
+
import { type NotificationProxyOptions } from '../interfaces';
|
|
5
|
+
/** Mark all of the caller's notifications read — scoped to this app (or all apps in shell mode). */
|
|
6
|
+
export declare class MarkAllNotificationsReadCommand {
|
|
7
|
+
readonly authorization: string | undefined;
|
|
8
|
+
constructor(authorization: string | undefined);
|
|
9
|
+
}
|
|
10
|
+
export declare class MarkAllNotificationsReadHandler implements ICommandHandler<MarkAllNotificationsReadCommand> {
|
|
11
|
+
private readonly engine;
|
|
12
|
+
private readonly options;
|
|
13
|
+
constructor(engine: NotificationEngineClient, options: NotificationProxyOptions);
|
|
14
|
+
execute(command: MarkAllNotificationsReadCommand): Promise<Result<unknown>>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=mark-all-read.handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mark-all-read.handler.d.ts","sourceRoot":"","sources":["../../src/commands/mark-all-read.handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAA8B,KAAK,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAG1F,oGAAoG;AACpG,qBAAa,+BAA+B;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS;gBAAjC,aAAa,EAAE,MAAM,GAAG,SAAS;CACvD;AAED,qBACa,+BACX,YAAW,eAAe,CAAC,+BAA+B,CAAC;IAGzD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACa,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAD3C,MAAM,EAAE,wBAAwB,EACI,OAAO,EAAE,wBAAwB;IAGlF,OAAO,CAAC,OAAO,EAAE,+BAA+B,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;CAIlF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.MarkAllNotificationsReadHandler = exports.MarkAllNotificationsReadCommand = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const cqrs_1 = require("@nestjs/cqrs");
|
|
18
|
+
const NotificationEngineClient_1 = require("../NotificationEngineClient");
|
|
19
|
+
const interfaces_1 = require("../interfaces");
|
|
20
|
+
const engine_result_1 = require("../engine-result");
|
|
21
|
+
/** Mark all of the caller's notifications read — scoped to this app (or all apps in shell mode). */
|
|
22
|
+
class MarkAllNotificationsReadCommand {
|
|
23
|
+
authorization;
|
|
24
|
+
constructor(authorization) {
|
|
25
|
+
this.authorization = authorization;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.MarkAllNotificationsReadCommand = MarkAllNotificationsReadCommand;
|
|
29
|
+
let MarkAllNotificationsReadHandler = class MarkAllNotificationsReadHandler {
|
|
30
|
+
engine;
|
|
31
|
+
options;
|
|
32
|
+
constructor(engine, options) {
|
|
33
|
+
this.engine = engine;
|
|
34
|
+
this.options = options;
|
|
35
|
+
}
|
|
36
|
+
async execute(command) {
|
|
37
|
+
const path = (0, engine_result_1.scopedFeedPath)(this.options, '/notifications/read-all');
|
|
38
|
+
return (0, engine_result_1.toResult)(await this.engine.forward('POST', path, command.authorization));
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
exports.MarkAllNotificationsReadHandler = MarkAllNotificationsReadHandler;
|
|
42
|
+
exports.MarkAllNotificationsReadHandler = MarkAllNotificationsReadHandler = __decorate([
|
|
43
|
+
(0, cqrs_1.CommandHandler)(MarkAllNotificationsReadCommand),
|
|
44
|
+
__param(1, (0, common_1.Inject)(interfaces_1.NOTIFICATION_PROXY_OPTIONS)),
|
|
45
|
+
__metadata("design:paramtypes", [NotificationEngineClient_1.NotificationEngineClient, Object])
|
|
46
|
+
], MarkAllNotificationsReadHandler);
|
|
47
|
+
//# sourceMappingURL=mark-all-read.handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mark-all-read.handler.js","sourceRoot":"","sources":["../../src/commands/mark-all-read.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAwC;AACxC,uCAA+D;AAE/D,0EAAuE;AACvE,8CAA0F;AAC1F,oDAA4D;AAE5D,oGAAoG;AACpG,MAAa,+BAA+B;IACrB;IAArB,YAAqB,aAAiC;QAAjC,kBAAa,GAAb,aAAa,CAAoB;IAAG,CAAC;CAC3D;AAFD,0EAEC;AAGM,IAAM,+BAA+B,GAArC,MAAM,+BAA+B;IAIvB;IACoC;IAFvD,YACmB,MAAgC,EACI,OAAiC;QADrE,WAAM,GAAN,MAAM,CAA0B;QACI,YAAO,GAAP,OAAO,CAA0B;IACrF,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,OAAwC;QACpD,MAAM,IAAI,GAAG,IAAA,8BAAc,EAAC,IAAI,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;QACrE,OAAO,IAAA,wBAAQ,EAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;IAClF,CAAC;CACF,CAAA;AAZY,0EAA+B;0CAA/B,+BAA+B;IAD3C,IAAA,qBAAc,EAAC,+BAA+B,CAAC;IAM3C,WAAA,IAAA,eAAM,EAAC,uCAA0B,CAAC,CAAA;qCADV,mDAAwB;GAJxC,+BAA+B,CAY3C","sourcesContent":["import { Inject } from '@nestjs/common';\nimport { CommandHandler, ICommandHandler } from '@nestjs/cqrs';\nimport { Result } from '@quanticjs/core';\nimport { NotificationEngineClient } from '../NotificationEngineClient';\nimport { NOTIFICATION_PROXY_OPTIONS, type NotificationProxyOptions } from '../interfaces';\nimport { scopedFeedPath, toResult } from '../engine-result';\n\n/** Mark all of the caller's notifications read — scoped to this app (or all apps in shell mode). */\nexport class MarkAllNotificationsReadCommand {\n constructor(readonly authorization: string | undefined) {}\n}\n\n@CommandHandler(MarkAllNotificationsReadCommand)\nexport class MarkAllNotificationsReadHandler\n implements ICommandHandler<MarkAllNotificationsReadCommand>\n{\n constructor(\n private readonly engine: NotificationEngineClient,\n @Inject(NOTIFICATION_PROXY_OPTIONS) private readonly options: NotificationProxyOptions,\n ) {}\n\n async execute(command: MarkAllNotificationsReadCommand): Promise<Result<unknown>> {\n const path = scopedFeedPath(this.options, '/notifications/read-all');\n return toResult(await this.engine.forward('POST', path, command.authorization));\n }\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ICommandHandler } from '@nestjs/cqrs';
|
|
2
|
+
import { Result } from '@quanticjs/core';
|
|
3
|
+
import { NotificationEngineClient } from '../NotificationEngineClient';
|
|
4
|
+
/**
|
|
5
|
+
* Mark a single notification read (proxied). Addressed by id and user-scoped by
|
|
6
|
+
* the engine (another user's / another app's id 404s), so no app scope applied.
|
|
7
|
+
*/
|
|
8
|
+
export declare class MarkNotificationReadCommand {
|
|
9
|
+
readonly authorization: string | undefined;
|
|
10
|
+
readonly id: string;
|
|
11
|
+
constructor(authorization: string | undefined, id: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class MarkNotificationReadHandler implements ICommandHandler<MarkNotificationReadCommand> {
|
|
14
|
+
private readonly engine;
|
|
15
|
+
constructor(engine: NotificationEngineClient);
|
|
16
|
+
execute(command: MarkNotificationReadCommand): Promise<Result<unknown>>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=mark-notification-read.handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mark-notification-read.handler.d.ts","sourceRoot":"","sources":["../../src/commands/mark-notification-read.handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAGvE;;;GAGG;AACH,qBAAa,2BAA2B;IAEpC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS;IAC1C,QAAQ,CAAC,EAAE,EAAE,MAAM;gBADV,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,EAAE,EAAE,MAAM;CAEtB;AAED,qBACa,2BACX,YAAW,eAAe,CAAC,2BAA2B,CAAC;IAE3C,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,wBAAwB;IAEvD,OAAO,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;CAS9E"}
|