@mbc-cqrs-serverless/core 1.2.7-beta.0 → 1.3.1
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 +37 -0
- package/dist/app.module.js +2 -0
- package/dist/app.module.js.map +1 -1
- package/dist/auth/auth.module.d.ts +2 -0
- package/dist/auth/auth.module.js +30 -0
- package/dist/auth/auth.module.js.map +1 -0
- package/dist/auth/authz-bootstrap.service.d.ts +11 -0
- package/dist/auth/authz-bootstrap.service.js +47 -0
- package/dist/auth/authz-bootstrap.service.js.map +1 -0
- package/dist/auth/group-role-resolver.interface.d.ts +13 -0
- package/dist/auth/group-role-resolver.interface.js +3 -0
- package/dist/auth/group-role-resolver.interface.js.map +1 -0
- package/dist/auth/group-role-resolver.registry.d.ts +6 -0
- package/dist/auth/group-role-resolver.registry.js +26 -0
- package/dist/auth/group-role-resolver.registry.js.map +1 -0
- package/dist/auth/index.d.ts +4 -0
- package/dist/auth/index.js +21 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/context/invoke.d.ts +1 -0
- package/dist/context/invoke.js.map +1 -1
- package/dist/context/user.d.ts +4 -0
- package/dist/context/user.js +50 -0
- package/dist/context/user.js.map +1 -1
- package/dist/decorators/constants.d.ts +2 -0
- package/dist/decorators/constants.js +3 -1
- package/dist/decorators/constants.js.map +1 -1
- package/dist/decorators/group-role-resolver.decorator.d.ts +9 -0
- package/dist/decorators/group-role-resolver.decorator.js +17 -0
- package/dist/decorators/group-role-resolver.decorator.js.map +1 -0
- package/dist/decorators/index.d.ts +2 -0
- package/dist/decorators/index.js +2 -0
- package/dist/decorators/index.js.map +1 -1
- package/dist/decorators/notification-transport.decorator.d.ts +6 -0
- package/dist/decorators/notification-transport.decorator.js +14 -0
- package/dist/decorators/notification-transport.decorator.js.map +1 -0
- package/dist/env.validation.d.ts +19 -0
- package/dist/env.validation.js +22 -1
- package/dist/env.validation.js.map +1 -1
- package/dist/guard/roles.guard.d.ts +11 -1
- package/dist/guard/roles.guard.js +44 -8
- package/dist/guard/roles.guard.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/notification-env.validation.d.ts +8 -0
- package/dist/notification-env.validation.js +36 -0
- package/dist/notification-env.validation.js.map +1 -0
- package/dist/notifications/appsync-events.service.d.ts +44 -0
- package/dist/notifications/appsync-events.service.js +147 -0
- package/dist/notifications/appsync-events.service.js.map +1 -0
- package/dist/notifications/appsync.service.d.ts +3 -2
- package/dist/notifications/appsync.service.js +20 -12
- package/dist/notifications/appsync.service.js.map +1 -1
- package/dist/notifications/enums/index.d.ts +1 -0
- package/dist/notifications/enums/index.js +18 -0
- package/dist/notifications/enums/index.js.map +1 -0
- package/dist/notifications/enums/notification-transport.enum.d.ts +4 -0
- package/dist/notifications/enums/notification-transport.enum.js +9 -0
- package/dist/notifications/enums/notification-transport.enum.js.map +1 -0
- package/dist/notifications/event/notification.event.handler.d.ts +13 -5
- package/dist/notifications/event/notification.event.handler.js +31 -7
- package/dist/notifications/event/notification.event.handler.js.map +1 -1
- package/dist/notifications/index.d.ts +3 -0
- package/dist/notifications/index.js +3 -0
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/interfaces/index.d.ts +1 -0
- package/dist/notifications/interfaces/index.js +18 -0
- package/dist/notifications/interfaces/index.js.map +1 -0
- package/dist/notifications/interfaces/notification-transport.interface.d.ts +7 -0
- package/dist/notifications/interfaces/notification-transport.interface.js +5 -0
- package/dist/notifications/interfaces/notification-transport.interface.js.map +1 -0
- package/dist/notifications/notification.module.js +12 -2
- package/dist/notifications/notification.module.js.map +1 -1
- package/dist/services/explorer.service.d.ts +5 -0
- package/dist/services/explorer.service.js +9 -0
- package/dist/services/explorer.service.js.map +1 -1
- package/dist/services/mocks/group-role-resolver.mock.d.ts +4 -0
- package/dist/services/mocks/group-role-resolver.mock.js +20 -0
- package/dist/services/mocks/group-role-resolver.mock.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -215,6 +215,43 @@ export class TodoDataSyncHandler implements IDataSyncHandler {
|
|
|
215
215
|
}
|
|
216
216
|
```
|
|
217
217
|
|
|
218
|
+
## Group-based roles
|
|
219
|
+
|
|
220
|
+
`RolesGuard` checks direct roles from JWT `custom:roles` first, then roles from groups in `custom:groups` (tenant-scoped). Group → role mappings are **not** stored in the JWT; implement a resolver in your app.
|
|
221
|
+
|
|
222
|
+
**JWT example:**
|
|
223
|
+
|
|
224
|
+
```json
|
|
225
|
+
{
|
|
226
|
+
"custom:roles": "[{\"tenant\":\"tenant-a\",\"role\":\"admin\"}]",
|
|
227
|
+
"custom:groups": "[{\"tenant\":\"tenant-a\",\"groups\":[\"sales-team\"]}]"
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Resolver (one per app):**
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import {
|
|
235
|
+
GroupRoleResolver,
|
|
236
|
+
IGroupRoleResolver,
|
|
237
|
+
} from '@mbc-cqrs-serverless/core';
|
|
238
|
+
|
|
239
|
+
// Do not add @Injectable() — @GroupRoleResolver() already registers the provider.
|
|
240
|
+
@GroupRoleResolver()
|
|
241
|
+
export class AppGroupRoleResolver implements IGroupRoleResolver {
|
|
242
|
+
async resolveRoles({ tenantCode, groupIds, claims }) {
|
|
243
|
+
// Load roles from DynamoDB, RDS, config, etc.
|
|
244
|
+
return ['viewer', 'reporter'];
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Register the class in your NestJS module `providers`. `AuthModule` is imported automatically via core `AppModule.forRoot()` and exports `GroupRoleResolverRegistry` globally for `@Auth()` / `RolesGuard`.
|
|
250
|
+
|
|
251
|
+
### Extending authorization
|
|
252
|
+
|
|
253
|
+
`RolesGuard` evaluates `tenantRoles` from the JWT (not `getUserRole()`). The protected `getUserRole()` method is **deprecated** and not called by the default guard. Subclasses should override `verifyRole` or `resolveGroupRoles` for custom logic.
|
|
254
|
+
|
|
218
255
|
## Environment Variables
|
|
219
256
|
|
|
220
257
|
| Variable | Description | Default |
|
package/dist/app.module.js
CHANGED
|
@@ -13,6 +13,7 @@ const core_1 = require("@nestjs/core");
|
|
|
13
13
|
const app_controller_1 = require("./app.controller");
|
|
14
14
|
const app_module_definition_1 = require("./app.module-definition");
|
|
15
15
|
const app_service_1 = require("./app.service");
|
|
16
|
+
const auth_1 = require("./auth");
|
|
16
17
|
const data_sync_module_1 = require("./command-events/data-sync.module");
|
|
17
18
|
const data_store_module_1 = require("./data-store/data-store.module");
|
|
18
19
|
const env_validation_1 = require("./env.validation");
|
|
@@ -64,6 +65,7 @@ exports.AppModule = AppModule;
|
|
|
64
65
|
exports.AppModule = AppModule = __decorate([
|
|
65
66
|
(0, common_1.Module)({
|
|
66
67
|
imports: [
|
|
68
|
+
auth_1.AuthModule,
|
|
67
69
|
notification_module_1.NotificationModule,
|
|
68
70
|
data_store_module_1.DataStoreModule,
|
|
69
71
|
data_sync_module_1.DataSyncModule,
|
package/dist/app.module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAsD;AACtD,2CAA6C;AAC7C,uCAAmD;AAEnD,qDAAgD;AAChD,mEAA+E;AAC/E,+CAA0C;AAC1C,wEAAkE;AAClE,sEAAgE;AAChE,qDAAoD;AACpD,qCAAsC;AACtC,6EAAwE;AACxE,uDAAkD;AAClD,kEAA6D;AAC7D,2EAAqE;
|
|
1
|
+
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAsD;AACtD,2CAA6C;AAC7C,uCAAmD;AAEnD,qDAAgD;AAChD,mEAA+E;AAC/E,+CAA0C;AAC1C,iCAAmC;AACnC,wEAAkE;AAClE,sEAAgE;AAChE,qDAAoD;AACpD,qCAAsC;AACtC,6EAAwE;AACxE,uDAAkD;AAClD,kEAA6D;AAC7D,2EAAqE;AAc9D,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,+CAAuB;IACpD,MAAM,CAAC,OAAO,CAAC,OAA4B;QACzC,MAAM,uBAAuB,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,MAAM,CAAA;QAC5E,MAAM,OAAO,GAAW;YACtB;gBACE,IAAI,EAAE,KAAK;gBACX,MAAM,EAAE,OAAO,CAAC,UAAU;aAC3B;SACF,CAAA;QACD,iCAAiC;QACjC,IAAI,uBAAuB,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,OAAO;gBACb,MAAM,EAAE,oBAAW;aACpB,CAAC,CAAA;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QACrC,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAA;QAC3C,OAAO,CAAC,IAAI,CACV,qBAAY,CAAC,OAAO,CAAC;YACnB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,IAAI;YACX,eAAe,EAAE,IAAI;YACrB,iBAAiB,EAAE;gBACjB,YAAY,EAAE,KAAK;gBACnB,UAAU,EAAE,IAAI;aACjB;YACD,QAAQ,EAAE,IAAA,kCAAiB,EAAC,OAAO,CAAC,MAAM,CAAC;SAC5C,CAAC,CACH,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;QAChC,IAAI,uBAAuB,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,oBAAW,CAAC,CAAA;QAC3B,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,mBAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;QAE5C,OAAO;YACL,GAAG,MAAM;YACT,OAAO;SACR,CAAA;IACH,CAAC;CACF,CAAA;AA1CY,8BAAS;oBAAT,SAAS;IAZrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,iBAAU;YACV,wCAAkB;YAClB,mCAAe;YACf,iCAAc;YACd,yCAAkB;YAClB,0BAAW;SACZ;QACD,WAAW,EAAE,CAAC,8BAAa,CAAC;QAC5B,SAAS,EAAE,CAAC,wBAAU,EAAE,kCAAe,CAAC;KACzC,CAAC;GACW,SAAS,CA0CrB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.AuthModule = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const roles_guard_1 = require("../guard/roles.guard");
|
|
12
|
+
const explorer_service_1 = require("../services/explorer.service");
|
|
13
|
+
const authz_bootstrap_service_1 = require("./authz-bootstrap.service");
|
|
14
|
+
const group_role_resolver_registry_1 = require("./group-role-resolver.registry");
|
|
15
|
+
let AuthModule = class AuthModule {
|
|
16
|
+
};
|
|
17
|
+
exports.AuthModule = AuthModule;
|
|
18
|
+
exports.AuthModule = AuthModule = __decorate([
|
|
19
|
+
(0, common_1.Global)(),
|
|
20
|
+
(0, common_1.Module)({
|
|
21
|
+
providers: [
|
|
22
|
+
explorer_service_1.ExplorerService,
|
|
23
|
+
group_role_resolver_registry_1.GroupRoleResolverRegistry,
|
|
24
|
+
authz_bootstrap_service_1.AuthzBootstrapService,
|
|
25
|
+
roles_guard_1.RolesGuard,
|
|
26
|
+
],
|
|
27
|
+
exports: [group_role_resolver_registry_1.GroupRoleResolverRegistry, roles_guard_1.RolesGuard, explorer_service_1.ExplorerService],
|
|
28
|
+
})
|
|
29
|
+
], AuthModule);
|
|
30
|
+
//# sourceMappingURL=auth.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA+C;AAE/C,sDAAiD;AACjD,mEAA8D;AAC9D,uEAAiE;AACjE,iFAA0E;AAYnE,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAVtB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE;YACT,kCAAe;YACf,wDAAyB;YACzB,+CAAqB;YACrB,wBAAU;SACX;QACD,OAAO,EAAE,CAAC,wDAAyB,EAAE,wBAAU,EAAE,kCAAe,CAAC;KAClE,CAAC;GACW,UAAU,CAAG"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { OnApplicationBootstrap } from '@nestjs/common';
|
|
2
|
+
import { ModuleRef } from '@nestjs/core';
|
|
3
|
+
import { ExplorerService } from '../services/explorer.service';
|
|
4
|
+
import { GroupRoleResolverRegistry } from './group-role-resolver.registry';
|
|
5
|
+
export declare class AuthzBootstrapService implements OnApplicationBootstrap {
|
|
6
|
+
private readonly explorerService;
|
|
7
|
+
private readonly moduleRef;
|
|
8
|
+
private readonly registry;
|
|
9
|
+
constructor(explorerService: ExplorerService, moduleRef: ModuleRef, registry: GroupRoleResolverRegistry);
|
|
10
|
+
onApplicationBootstrap(): void;
|
|
11
|
+
}
|
|
@@ -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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AuthzBootstrapService = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const core_1 = require("@nestjs/core");
|
|
15
|
+
const explorer_service_1 = require("../services/explorer.service");
|
|
16
|
+
const group_role_resolver_registry_1 = require("./group-role-resolver.registry");
|
|
17
|
+
let AuthzBootstrapService = class AuthzBootstrapService {
|
|
18
|
+
constructor(explorerService, moduleRef, registry) {
|
|
19
|
+
this.explorerService = explorerService;
|
|
20
|
+
this.moduleRef = moduleRef;
|
|
21
|
+
this.registry = registry;
|
|
22
|
+
}
|
|
23
|
+
onApplicationBootstrap() {
|
|
24
|
+
const types = this.explorerService.exploreGroupRoleResolvers();
|
|
25
|
+
if (types.length > 1) {
|
|
26
|
+
throw new Error('Only one @GroupRoleResolver() is allowed per application');
|
|
27
|
+
}
|
|
28
|
+
if (types.length === 0) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const instance = this.moduleRef.get(types[0], {
|
|
32
|
+
strict: false,
|
|
33
|
+
});
|
|
34
|
+
if (!instance) {
|
|
35
|
+
throw new Error(`GroupRoleResolver ${types[0].name} was discovered but could not be resolved from DI`);
|
|
36
|
+
}
|
|
37
|
+
this.registry.set(instance);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
exports.AuthzBootstrapService = AuthzBootstrapService;
|
|
41
|
+
exports.AuthzBootstrapService = AuthzBootstrapService = __decorate([
|
|
42
|
+
(0, common_1.Injectable)(),
|
|
43
|
+
__metadata("design:paramtypes", [explorer_service_1.ExplorerService,
|
|
44
|
+
core_1.ModuleRef,
|
|
45
|
+
group_role_resolver_registry_1.GroupRoleResolverRegistry])
|
|
46
|
+
], AuthzBootstrapService);
|
|
47
|
+
//# sourceMappingURL=authz-bootstrap.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authz-bootstrap.service.js","sourceRoot":"","sources":["../../src/auth/authz-bootstrap.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAmE;AACnE,uCAAwC;AAExC,mEAA8D;AAE9D,iFAA0E;AAGnE,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAChC,YACmB,eAAgC,EAChC,SAAoB,EACpB,QAAmC;QAFnC,oBAAe,GAAf,eAAe,CAAiB;QAChC,cAAS,GAAT,SAAS,CAAW;QACpB,aAAQ,GAAR,QAAQ,CAA2B;IACnD,CAAC;IAEJ,sBAAsB;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,yBAAyB,EAAE,CAAA;QAE9D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,0DAA0D,CAC3D,CAAA;QACH,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAM;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAqB,KAAK,CAAC,CAAC,CAAC,EAAE;YAChE,MAAM,EAAE,KAAK;SACd,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,qBAAqB,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,mDAAmD,CACtF,CAAA;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC7B,CAAC;CACF,CAAA;AAhCY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,mBAAU,GAAE;qCAGyB,kCAAe;QACrB,gBAAS;QACV,wDAAyB;GAJ3C,qBAAqB,CAgCjC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { JwtClaims } from '../context/invoke';
|
|
2
|
+
export interface TenantGroupMembership {
|
|
3
|
+
tenant: string;
|
|
4
|
+
groups: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface ResolveGroupRolesInput {
|
|
7
|
+
tenantCode: string;
|
|
8
|
+
groupIds: string[];
|
|
9
|
+
claims?: JwtClaims;
|
|
10
|
+
}
|
|
11
|
+
export interface IGroupRoleResolver {
|
|
12
|
+
resolveRoles(input: ResolveGroupRolesInput): Promise<string[]>;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-role-resolver.interface.js","sourceRoot":"","sources":["../../src/auth/group-role-resolver.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.GroupRoleResolverRegistry = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
let GroupRoleResolverRegistry = class GroupRoleResolverRegistry {
|
|
12
|
+
set(resolver) {
|
|
13
|
+
if (this.resolver) {
|
|
14
|
+
throw new Error('Only one @GroupRoleResolver() is allowed per application');
|
|
15
|
+
}
|
|
16
|
+
this.resolver = resolver;
|
|
17
|
+
}
|
|
18
|
+
get() {
|
|
19
|
+
return this.resolver;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
exports.GroupRoleResolverRegistry = GroupRoleResolverRegistry;
|
|
23
|
+
exports.GroupRoleResolverRegistry = GroupRoleResolverRegistry = __decorate([
|
|
24
|
+
(0, common_1.Injectable)()
|
|
25
|
+
], GroupRoleResolverRegistry);
|
|
26
|
+
//# sourceMappingURL=group-role-resolver.registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-role-resolver.registry.js","sourceRoot":"","sources":["../../src/auth/group-role-resolver.registry.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA2C;AAKpC,IAAM,yBAAyB,GAA/B,MAAM,yBAAyB;IAGpC,GAAG,CAAC,QAA4B;QAC9B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACb,0DAA0D,CAC3D,CAAA;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,CAAC;IAED,GAAG;QACD,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;CACF,CAAA;AAfY,8DAAyB;oCAAzB,yBAAyB;IADrC,IAAA,mBAAU,GAAE;GACA,yBAAyB,CAerC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./auth.module"), exports);
|
|
18
|
+
__exportStar(require("./authz-bootstrap.service"), exports);
|
|
19
|
+
__exportStar(require("./group-role-resolver.interface"), exports);
|
|
20
|
+
__exportStar(require("./group-role-resolver.registry"), exports);
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA6B;AAC7B,4DAAyC;AACzC,kEAA+C;AAC/C,iEAA8C"}
|
package/dist/context/invoke.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../../src/context/invoke.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../../src/context/invoke.ts"],"names":[],"mappings":";;AAkFA,oDAoDC;AAED,kDAsBC;AA9JD,sEAAgE;AAChE,2CAAwE;AAExE,2CAAsC;AAEtC,wCAA8C;AA6E9C,SAAgB,oBAAoB,CAAC,GAAsB;IACzD,IAAI,2BAAiB,EAAE,CAAC;QACtB,OAAO,IAAA,qCAAgB,GAAE,CAAA;IAC3B,CAAC;IACD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,CAAA;IACX,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,UAAU,EAAW,CAAA;IACxD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAiC,CAAA;IACzD,IAAI,UAAU,GAAuB,SAAS,CAAA;IAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IAC9C,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;YACxD,MAAM,MAAM,GAAG,IAAA,sBAAS,EAAY,KAAK,CAAC,CAAA;YAC1C,UAAU,GAAG;gBACX,GAAG,EAAE;oBACH,MAAM;oBACN,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC;iBAClC;aACF,CAAA;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,8BAAqB,CAC7B,0CAA0C,CAC3C,CAAA;QACH,CAAC;IACH,CAAC;IACD,OAAO;QACL,KAAK,EAAE;YACL,QAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,EAAE;YAC7C,OAAO,EAAE,OAAO,CAAC,WAAW;YAC5B,OAAO;YACP,cAAc,EAAE;gBACd,UAAU,EAAE,OAAO,CAAC,QAAQ;gBAC5B,IAAI,EAAE;oBACJ,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,OAAO,CAAC,EAAE;oBAClD,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;iBACrC;gBACD,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;gBACtC,UAAU;aACX;SACF;QACD,OAAO,EAAE;YACP,YAAY,EACV,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;SAC9B;KACF,CAAA;AACH,CAAC;AAED,SAAgB,mBAAmB,CAAC,GAAY;IAC9C,OAAO,CACL,GAAG,EAAE,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,IAAK,EAAgB,CACzE,CAAA;IACD,IAAI;IACJ,mDAAmD;IACnD,mDAAmD;IACnD,kCAAkC;IAClC,kCAAkC;IAClC,0DAA0D;IAC1D,wCAAwC;IACxC,wDAAwD;IACxD,uBAAuB;IACvB,6BAA6B;IAC7B,sBAAsB;IACtB,6BAA6B;IAC7B,qDAAqD;IACrD,uBAAuB;IACvB,+BAA+B;IAC/B,uBAAuB;IACvB,kDAAkD;IAClD,IAAI;AACN,CAAC"}
|
package/dist/context/user.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ export declare class UserContext {
|
|
|
8
8
|
userId: string;
|
|
9
9
|
tenantRole: string;
|
|
10
10
|
tenantCode: string;
|
|
11
|
+
/** Direct roles from custom:roles for the active tenant (excludes group-derived roles). */
|
|
12
|
+
tenantRoles: string[];
|
|
13
|
+
/** Group IDs from custom:groups for the active tenant. */
|
|
14
|
+
tenantGroupIds: string[];
|
|
11
15
|
constructor(partial: Partial<UserContext>);
|
|
12
16
|
}
|
|
13
17
|
/**
|
package/dist/context/user.js
CHANGED
|
@@ -10,6 +10,52 @@ class UserContext {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
exports.UserContext = UserContext;
|
|
13
|
+
function parseTenantGroups(raw, tenantCode) {
|
|
14
|
+
if (!tenantCode) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
let parsed;
|
|
18
|
+
try {
|
|
19
|
+
parsed = JSON.parse(raw || '[]');
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
if (!Array.isArray(parsed)) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
const memberships = parsed.map((membership) => ({
|
|
28
|
+
...membership,
|
|
29
|
+
tenant: (membership.tenant || '').toLowerCase(),
|
|
30
|
+
}));
|
|
31
|
+
const match = memberships.find((membership) => membership.tenant === tenantCode);
|
|
32
|
+
const groups = match?.groups;
|
|
33
|
+
return Array.isArray(groups) ? groups : [];
|
|
34
|
+
}
|
|
35
|
+
function collectTenantRoles(roles, tenantCode) {
|
|
36
|
+
if (!tenantCode) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const seen = new Set();
|
|
40
|
+
const result = [];
|
|
41
|
+
const add = (role) => {
|
|
42
|
+
if (!seen.has(role)) {
|
|
43
|
+
seen.add(role);
|
|
44
|
+
result.push(role);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
for (const { tenant, role } of roles) {
|
|
48
|
+
if (tenant === tenantCode) {
|
|
49
|
+
add(role);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
for (const { tenant, role } of roles) {
|
|
53
|
+
if (tenant === '') {
|
|
54
|
+
add(role);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
13
59
|
/**
|
|
14
60
|
* Extract user context from JWT claims and request headers.
|
|
15
61
|
*
|
|
@@ -33,6 +79,8 @@ function getUserContext(ctx) {
|
|
|
33
79
|
// 2. Otherwise, use header value (security check delegated to RolesGuard)
|
|
34
80
|
// Note: tenantCode is normalized to lowercase for case-insensitive matching with role.tenant
|
|
35
81
|
const tenantCode = (claims['custom:tenant'] || (ctx?.event?.headers || {})[constants_1.HEADER_TENANT_CODE])?.toLowerCase();
|
|
82
|
+
const tenantGroupIds = parseTenantGroups(claims['custom:groups'], tenantCode);
|
|
83
|
+
const tenantRoles = collectTenantRoles(roles, tenantCode);
|
|
36
84
|
// Find tenantRole (case-insensitive matching - both tenantCode and role.tenant are lowercase)
|
|
37
85
|
let tenantRole = '';
|
|
38
86
|
for (const { tenant, role } of roles) {
|
|
@@ -47,6 +95,8 @@ function getUserContext(ctx) {
|
|
|
47
95
|
userId,
|
|
48
96
|
tenantRole,
|
|
49
97
|
tenantCode,
|
|
98
|
+
tenantRoles,
|
|
99
|
+
tenantGroupIds,
|
|
50
100
|
};
|
|
51
101
|
}
|
|
52
102
|
//# sourceMappingURL=user.js.map
|
package/dist/context/user.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.js","sourceRoot":"","sources":["../../src/context/user.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"user.js","sourceRoot":"","sources":["../../src/context/user.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,3 +3,5 @@ export declare const EVENT_HANDLER_METADATA = "__eventHandler__";
|
|
|
3
3
|
export declare const EVENT_FACTORY_METADATA = "__eventFactory__";
|
|
4
4
|
export declare const DATA_SYNC_HANDLER_METADATA = "__dataSyncHandler__";
|
|
5
5
|
export declare const ROLE_METADATA = "__allowedRoles__";
|
|
6
|
+
export declare const NOTIFICATION_TRANSPORT_METADATA = "__notificationTransport__";
|
|
7
|
+
export declare const GROUP_ROLE_RESOLVER_METADATA = "__groupRoleResolver__";
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ROLE_METADATA = exports.DATA_SYNC_HANDLER_METADATA = exports.EVENT_FACTORY_METADATA = exports.EVENT_HANDLER_METADATA = exports.EVENT_METADATA = void 0;
|
|
3
|
+
exports.GROUP_ROLE_RESOLVER_METADATA = exports.NOTIFICATION_TRANSPORT_METADATA = exports.ROLE_METADATA = exports.DATA_SYNC_HANDLER_METADATA = exports.EVENT_FACTORY_METADATA = exports.EVENT_HANDLER_METADATA = exports.EVENT_METADATA = void 0;
|
|
4
4
|
exports.EVENT_METADATA = '__event__';
|
|
5
5
|
exports.EVENT_HANDLER_METADATA = '__eventHandler__';
|
|
6
6
|
exports.EVENT_FACTORY_METADATA = '__eventFactory__';
|
|
7
7
|
exports.DATA_SYNC_HANDLER_METADATA = '__dataSyncHandler__';
|
|
8
8
|
exports.ROLE_METADATA = '__allowedRoles__';
|
|
9
|
+
exports.NOTIFICATION_TRANSPORT_METADATA = '__notificationTransport__';
|
|
10
|
+
exports.GROUP_ROLE_RESOLVER_METADATA = '__groupRoleResolver__';
|
|
9
11
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/decorators/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG,WAAW,CAAA;AAC5B,QAAA,sBAAsB,GAAG,kBAAkB,CAAA;AAC3C,QAAA,sBAAsB,GAAG,kBAAkB,CAAA;AAC3C,QAAA,0BAA0B,GAAG,qBAAqB,CAAA;AAClD,QAAA,aAAa,GAAG,kBAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/decorators/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG,WAAW,CAAA;AAC5B,QAAA,sBAAsB,GAAG,kBAAkB,CAAA;AAC3C,QAAA,sBAAsB,GAAG,kBAAkB,CAAA;AAC3C,QAAA,0BAA0B,GAAG,qBAAqB,CAAA;AAClD,QAAA,aAAa,GAAG,kBAAkB,CAAA;AAClC,QAAA,+BAA+B,GAAG,2BAA2B,CAAA;AAC7D,QAAA,4BAA4B,GAAG,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marks a class as the application's `IGroupRoleResolver` (exactly one per app).
|
|
3
|
+
* Discovered at bootstrap and registered in `GroupRoleResolverRegistry`.
|
|
4
|
+
*
|
|
5
|
+
* Applies `@Injectable()` with default (singleton) scope. Do **not** add `@Injectable()`
|
|
6
|
+
* on the same class — a second decorator can override scope (e.g. `REQUEST`) and break
|
|
7
|
+
* bootstrap, which resolves one instance at application startup.
|
|
8
|
+
*/
|
|
9
|
+
export declare function GroupRoleResolver(): ClassDecorator;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GroupRoleResolver = GroupRoleResolver;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const constants_1 = require("./constants");
|
|
6
|
+
/**
|
|
7
|
+
* Marks a class as the application's `IGroupRoleResolver` (exactly one per app).
|
|
8
|
+
* Discovered at bootstrap and registered in `GroupRoleResolverRegistry`.
|
|
9
|
+
*
|
|
10
|
+
* Applies `@Injectable()` with default (singleton) scope. Do **not** add `@Injectable()`
|
|
11
|
+
* on the same class — a second decorator can override scope (e.g. `REQUEST`) and break
|
|
12
|
+
* bootstrap, which resolves one instance at application startup.
|
|
13
|
+
*/
|
|
14
|
+
function GroupRoleResolver() {
|
|
15
|
+
return (0, common_1.applyDecorators)((0, common_1.SetMetadata)(constants_1.GROUP_ROLE_RESOLVER_METADATA, true), (0, common_1.Injectable)());
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=group-role-resolver.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-role-resolver.decorator.js","sourceRoot":"","sources":["../../src/decorators/group-role-resolver.decorator.ts"],"names":[],"mappings":";;AAYA,8CAKC;AAjBD,2CAAyE;AAEzE,2CAA0D;AAE1D;;;;;;;GAOG;AACH,SAAgB,iBAAiB;IAC/B,OAAO,IAAA,wBAAe,EACpB,IAAA,oBAAW,EAAC,wCAA4B,EAAE,IAAI,CAAC,EAC/C,IAAA,mBAAU,GAAE,CACK,CAAA;AACrB,CAAC"}
|
|
@@ -4,5 +4,7 @@ export * from './context.decorator';
|
|
|
4
4
|
export * from './data-sync-handler.decorator';
|
|
5
5
|
export * from './event-factory.decorator';
|
|
6
6
|
export * from './event-handler.decorator';
|
|
7
|
+
export * from './group-role-resolver.decorator';
|
|
8
|
+
export * from './notification-transport.decorator';
|
|
7
9
|
export * from './roles.decorator';
|
|
8
10
|
export * from './swagger-response.decorator';
|
package/dist/decorators/index.js
CHANGED
|
@@ -20,6 +20,8 @@ __exportStar(require("./context.decorator"), exports);
|
|
|
20
20
|
__exportStar(require("./data-sync-handler.decorator"), exports);
|
|
21
21
|
__exportStar(require("./event-factory.decorator"), exports);
|
|
22
22
|
__exportStar(require("./event-handler.decorator"), exports);
|
|
23
|
+
__exportStar(require("./group-role-resolver.decorator"), exports);
|
|
24
|
+
__exportStar(require("./notification-transport.decorator"), exports);
|
|
23
25
|
__exportStar(require("./roles.decorator"), exports);
|
|
24
26
|
__exportStar(require("./swagger-response.decorator"), exports);
|
|
25
27
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAgC;AAChC,8CAA2B;AAC3B,sDAAmC;AACnC,gEAA6C;AAC7C,4DAAyC;AACzC,4DAAyC;AACzC,oDAAiC;AACjC,+DAA4C"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAgC;AAChC,8CAA2B;AAC3B,sDAAmC;AACnC,gEAA6C;AAC7C,4DAAyC;AACzC,4DAAyC;AACzC,kEAA+C;AAC/C,qEAAkD;AAClD,oDAAiC;AACjC,+DAA4C"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decorator to register a class as a Notification Transport.
|
|
3
|
+
* Automatically marks the class as an @Injectable() provider.
|
|
4
|
+
* @param name The unique identifier for this transport (e.g., 'pusher', 'appsync-event')
|
|
5
|
+
*/
|
|
6
|
+
export declare function NotificationTransport(name: string): ClassDecorator;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NotificationTransport = NotificationTransport;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const constants_1 = require("./constants");
|
|
6
|
+
/**
|
|
7
|
+
* Decorator to register a class as a Notification Transport.
|
|
8
|
+
* Automatically marks the class as an @Injectable() provider.
|
|
9
|
+
* @param name The unique identifier for this transport (e.g., 'pusher', 'appsync-event')
|
|
10
|
+
*/
|
|
11
|
+
function NotificationTransport(name) {
|
|
12
|
+
return (0, common_1.applyDecorators)((0, common_1.SetMetadata)(constants_1.NOTIFICATION_TRANSPORT_METADATA, name), (0, common_1.Injectable)());
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=notification-transport.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-transport.decorator.js","sourceRoot":"","sources":["../../src/decorators/notification-transport.decorator.ts"],"names":[],"mappings":";;AASA,sDAKC;AAdD,2CAAyE;AAEzE,2CAA6D;AAE7D;;;;GAIG;AACH,SAAgB,qBAAqB,CAAC,IAAY;IAChD,OAAO,IAAA,wBAAe,EACpB,IAAA,oBAAW,EAAC,2CAA+B,EAAE,IAAI,CAAC,EAClD,IAAA,mBAAU,GAAE,CACK,CAAA;AACrB,CAAC"}
|
package/dist/env.validation.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ClassConstructor } from 'class-transformer';
|
|
2
|
+
export { BUILTIN_NOTIFICATION_TRANSPORT_ENV, parseNotificationTransports, validateBuiltinNotificationTransportEnv, } from './notification-env.validation';
|
|
2
3
|
export declare enum Environment {
|
|
3
4
|
Local = "local",
|
|
4
5
|
Development = "dev",
|
|
@@ -22,7 +23,25 @@ export declare class EnvironmentVariables {
|
|
|
22
23
|
SFN_COMMAND_ARN: string;
|
|
23
24
|
SNS_ENDPOINT: string;
|
|
24
25
|
SNS_REGION: string;
|
|
26
|
+
/**
|
|
27
|
+
* Comma-separated list of active notification transport names.
|
|
28
|
+
* Supported built-in values: 'appsync-graphql' | 'appsync-event'
|
|
29
|
+
* Defaults to 'appsync-graphql' when not set.
|
|
30
|
+
*
|
|
31
|
+
* Examples:
|
|
32
|
+
* NOTIFICATION_TRANSPORTS=appsync-graphql
|
|
33
|
+
* NOTIFICATION_TRANSPORTS=appsync-event
|
|
34
|
+
* NOTIFICATION_TRANSPORTS=appsync-graphql,appsync-event
|
|
35
|
+
*/
|
|
36
|
+
NOTIFICATION_TRANSPORTS: string;
|
|
25
37
|
APPSYNC_ENDPOINT: string;
|
|
38
|
+
APPSYNC_EVENTS_ENDPOINT: string;
|
|
39
|
+
/**
|
|
40
|
+
* Channel namespace name — must match the pre-created namespace in the
|
|
41
|
+
* AppSync Event API (segment 1 of every channel path).
|
|
42
|
+
* Defaults to 'default'.
|
|
43
|
+
*/
|
|
44
|
+
APPSYNC_EVENTS_NAMESPACE: string;
|
|
26
45
|
SES_ENDPOINT: string;
|
|
27
46
|
SES_REGION: string;
|
|
28
47
|
SES_FROM_EMAIL: string;
|
package/dist/env.validation.js
CHANGED
|
@@ -9,10 +9,15 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.EnvironmentVariables = exports.Environment = void 0;
|
|
12
|
+
exports.EnvironmentVariables = exports.Environment = exports.validateBuiltinNotificationTransportEnv = exports.parseNotificationTransports = exports.BUILTIN_NOTIFICATION_TRANSPORT_ENV = void 0;
|
|
13
13
|
exports.getValidateConfig = getValidateConfig;
|
|
14
14
|
const class_transformer_1 = require("class-transformer");
|
|
15
15
|
const class_validator_1 = require("class-validator");
|
|
16
|
+
const notification_env_validation_1 = require("./notification-env.validation");
|
|
17
|
+
var notification_env_validation_2 = require("./notification-env.validation");
|
|
18
|
+
Object.defineProperty(exports, "BUILTIN_NOTIFICATION_TRANSPORT_ENV", { enumerable: true, get: function () { return notification_env_validation_2.BUILTIN_NOTIFICATION_TRANSPORT_ENV; } });
|
|
19
|
+
Object.defineProperty(exports, "parseNotificationTransports", { enumerable: true, get: function () { return notification_env_validation_2.parseNotificationTransports; } });
|
|
20
|
+
Object.defineProperty(exports, "validateBuiltinNotificationTransportEnv", { enumerable: true, get: function () { return notification_env_validation_2.validateBuiltinNotificationTransportEnv; } });
|
|
16
21
|
var Environment;
|
|
17
22
|
(function (Environment) {
|
|
18
23
|
Environment["Local"] = "local";
|
|
@@ -96,11 +101,26 @@ __decorate([
|
|
|
96
101
|
(0, class_validator_1.IsOptional)(),
|
|
97
102
|
__metadata("design:type", String)
|
|
98
103
|
], EnvironmentVariables.prototype, "SNS_REGION", void 0);
|
|
104
|
+
__decorate([
|
|
105
|
+
(0, class_validator_1.IsString)(),
|
|
106
|
+
(0, class_validator_1.IsOptional)(),
|
|
107
|
+
__metadata("design:type", String)
|
|
108
|
+
], EnvironmentVariables.prototype, "NOTIFICATION_TRANSPORTS", void 0);
|
|
99
109
|
__decorate([
|
|
100
110
|
(0, class_validator_1.IsString)(),
|
|
101
111
|
(0, class_validator_1.IsOptional)(),
|
|
102
112
|
__metadata("design:type", String)
|
|
103
113
|
], EnvironmentVariables.prototype, "APPSYNC_ENDPOINT", void 0);
|
|
114
|
+
__decorate([
|
|
115
|
+
(0, class_validator_1.IsString)(),
|
|
116
|
+
(0, class_validator_1.IsOptional)(),
|
|
117
|
+
__metadata("design:type", String)
|
|
118
|
+
], EnvironmentVariables.prototype, "APPSYNC_EVENTS_ENDPOINT", void 0);
|
|
119
|
+
__decorate([
|
|
120
|
+
(0, class_validator_1.IsString)(),
|
|
121
|
+
(0, class_validator_1.IsOptional)(),
|
|
122
|
+
__metadata("design:type", String)
|
|
123
|
+
], EnvironmentVariables.prototype, "APPSYNC_EVENTS_NAMESPACE", void 0);
|
|
104
124
|
__decorate([
|
|
105
125
|
(0, class_validator_1.IsString)(),
|
|
106
126
|
(0, class_validator_1.IsOptional)(),
|
|
@@ -136,6 +156,7 @@ function getValidateConfig(cls) {
|
|
|
136
156
|
if (errors.length > 0) {
|
|
137
157
|
throw new Error(errors.toString());
|
|
138
158
|
}
|
|
159
|
+
(0, notification_env_validation_1.validateBuiltinNotificationTransportEnv)(validatedConfig);
|
|
139
160
|
return validatedConfig;
|
|
140
161
|
};
|
|
141
162
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.validation.js","sourceRoot":"","sources":["../src/env.validation.ts"],"names":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"env.validation.js","sourceRoot":"","sources":["../src/env.validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { CanActivate, ExecutionContext, Logger } from '@nestjs/common';
|
|
2
2
|
import { Reflector } from '@nestjs/core';
|
|
3
|
+
import { GroupRoleResolverRegistry } from '../auth/group-role-resolver.registry';
|
|
3
4
|
import { UserContext } from '../context';
|
|
4
5
|
export declare class RolesGuard implements CanActivate {
|
|
5
6
|
protected reflector: Reflector;
|
|
7
|
+
protected registry?: GroupRoleResolverRegistry;
|
|
6
8
|
protected readonly logger: Logger;
|
|
7
|
-
constructor(reflector: Reflector);
|
|
9
|
+
constructor(reflector: Reflector, registry?: GroupRoleResolverRegistry);
|
|
8
10
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
9
11
|
/**
|
|
10
12
|
* Verify tenant access.
|
|
@@ -59,6 +61,14 @@ export declare class RolesGuard implements CanActivate {
|
|
|
59
61
|
* This is a helper method that can be used by subclasses.
|
|
60
62
|
*/
|
|
61
63
|
protected getAuthorizerClaims(context: ExecutionContext): import("../context").JwtClaims;
|
|
64
|
+
protected hasAnyRole(requiredRoles: string[], userRoles: string[]): boolean;
|
|
65
|
+
protected resolveGroupRoles(context: ExecutionContext, groupIds: string[]): Promise<string[]>;
|
|
62
66
|
protected verifyRole(context: ExecutionContext): Promise<boolean>;
|
|
67
|
+
/**
|
|
68
|
+
* Returns the primary direct role string from JWT context.
|
|
69
|
+
*
|
|
70
|
+
* @deprecated Not invoked by `verifyRole`. For custom authorization, override
|
|
71
|
+
* `verifyRole`, `resolveGroupRoles`, or `canOverrideTenant` instead.
|
|
72
|
+
*/
|
|
63
73
|
protected getUserRole(context: ExecutionContext): Promise<string>;
|
|
64
74
|
}
|