@rhino-dev/rhino-nestjs 4.0.0 → 4.2.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 +52 -1
- package/dist/blueprint/blueprint-runner.js +32 -1
- package/dist/blueprint/blueprint-runner.js.map +1 -1
- package/dist/blueprint/blueprint-sorter.d.ts +54 -0
- package/dist/blueprint/blueprint-sorter.js +107 -0
- package/dist/blueprint/blueprint-sorter.js.map +1 -0
- package/dist/controllers/auth.controller.d.ts +34 -5
- package/dist/controllers/auth.controller.js +132 -12
- package/dist/controllers/auth.controller.js.map +1 -1
- package/dist/controllers/invitation.controller.d.ts +41 -2
- package/dist/controllers/invitation.controller.js +97 -12
- package/dist/controllers/invitation.controller.js.map +1 -1
- package/dist/errors/rhino-exception.d.ts +12 -1
- package/dist/errors/rhino-exception.js +19 -1
- package/dist/errors/rhino-exception.js.map +1 -1
- package/dist/guards/group-membership.guard.d.ts +25 -0
- package/dist/guards/group-membership.guard.js +70 -0
- package/dist/guards/group-membership.guard.js.map +1 -0
- package/dist/guards/jwt-auth.guard.js +23 -4
- package/dist/guards/jwt-auth.guard.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +17 -2
- package/dist/index.js.map +1 -1
- package/dist/interfaces/rhino-config.interface.d.ts +71 -0
- package/dist/middleware/domain-route-resolver.d.ts +54 -0
- package/dist/middleware/domain-route-resolver.js +145 -0
- package/dist/middleware/domain-route-resolver.js.map +1 -0
- package/dist/middleware/route-group.middleware.d.ts +48 -4
- package/dist/middleware/route-group.middleware.js +274 -13
- package/dist/middleware/route-group.middleware.js.map +1 -1
- package/dist/rhino.config.d.ts +26 -1
- package/dist/rhino.config.js +56 -1
- package/dist/rhino.config.js.map +1 -1
- package/dist/rhino.module.d.ts +7 -0
- package/dist/rhino.module.js +23 -1
- package/dist/rhino.module.js.map +1 -1
- package/dist/services/auth-hooks.service.d.ts +27 -0
- package/dist/services/auth-hooks.service.js +85 -0
- package/dist/services/auth-hooks.service.js.map +1 -0
- package/dist/services/auth.service.d.ts +19 -0
- package/dist/services/auth.service.js +80 -5
- package/dist/services/auth.service.js.map +1 -1
- package/dist/services/invitation.service.d.ts +6 -0
- package/dist/services/invitation.service.js +45 -3
- package/dist/services/invitation.service.js.map +1 -1
- package/dist/services/membership.service.d.ts +56 -0
- package/dist/services/membership.service.js +113 -0
- package/dist/services/membership.service.js.map +1 -0
- package/dist/services/organization.service.js +8 -1
- package/dist/services/organization.service.js.map +1 -1
- package/dist/services/route-registration.service.d.ts +1 -0
- package/dist/services/route-registration.service.js +2 -0
- package/dist/services/route-registration.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/domain-pattern.d.ts +36 -0
- package/dist/utils/domain-pattern.js +77 -0
- package/dist/utils/domain-pattern.js.map +1 -0
- package/dist/utils/permission-matcher.js +8 -0
- package/dist/utils/permission-matcher.js.map +1 -1
- package/dist/utils/route-group-validator.d.ts +14 -0
- package/dist/utils/route-group-validator.js +124 -0
- package/dist/utils/route-group-validator.js.map +1 -0
- package/package.json +1 -1
|
@@ -12,45 +12,306 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.RouteGroupMiddleware = void 0;
|
|
13
13
|
const common_1 = require("@nestjs/common");
|
|
14
14
|
const rhino_config_1 = require("../rhino.config");
|
|
15
|
+
const domain_pattern_1 = require("../utils/domain-pattern");
|
|
15
16
|
/**
|
|
16
|
-
* Detects which Rhino route group the current request belongs to
|
|
17
|
-
* (based on URL prefix) and attaches:
|
|
17
|
+
* Detects which Rhino route group the current request belongs to and attaches:
|
|
18
18
|
* - `req.__routeGroup` — the group name
|
|
19
19
|
* - `req.__skipAuth` — true when the group has `skipAuth: true`
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* Group selection considers BOTH:
|
|
22
|
+
*
|
|
23
|
+
* 1. **Host** — when a group declares a `domain`, it is only eligible for
|
|
24
|
+
* requests whose `req.hostname` matches that domain. A literal domain
|
|
25
|
+
* (`admin.example.com`) must match exactly; a parameterized domain
|
|
26
|
+
* (`{organization}.example.com`) captures the subdomain and exposes it as
|
|
27
|
+
* `req.params.organization` so ResolveOrganizationMiddleware can resolve
|
|
28
|
+
* the tenant from the host — mirroring Laravel's `Route::domain(...)`.
|
|
29
|
+
*
|
|
30
|
+
* 2. **URL prefix** — the existing path-prefix matching, unchanged for groups
|
|
31
|
+
* without a `domain`.
|
|
32
|
+
*
|
|
33
|
+
* Host-scoped groups take precedence over plain prefix groups when both could
|
|
34
|
+
* match, so two groups can share the same prefix and be selected by host.
|
|
35
|
+
*
|
|
36
|
+
* Enforcement: if the request path targets a model that is ONLY served by
|
|
37
|
+
* domain-scoped group(s) and the host matches none of them, the request is
|
|
38
|
+
* rejected with 404 — a wrong-host request must not be served as that group.
|
|
39
|
+
*
|
|
40
|
+
* Install this middleware globally BEFORE `JwtAuthGuard` so the guard can read
|
|
41
|
+
* `req.__skipAuth`, and BEFORE `ResolveOrganizationMiddleware` so a captured
|
|
42
|
+
* subdomain param is available for org resolution.
|
|
23
43
|
*/
|
|
24
44
|
let RouteGroupMiddleware = class RouteGroupMiddleware {
|
|
25
45
|
config;
|
|
46
|
+
/** Cache compiled domain patterns keyed by group name. */
|
|
47
|
+
compiledCache = new Map();
|
|
26
48
|
constructor(config) {
|
|
27
49
|
this.config = config;
|
|
28
50
|
}
|
|
51
|
+
compileFor(name, domain) {
|
|
52
|
+
if (this.compiledCache.has(name))
|
|
53
|
+
return this.compiledCache.get(name) ?? null;
|
|
54
|
+
const compiled = (0, domain_pattern_1.compileDomain)(domain);
|
|
55
|
+
this.compiledCache.set(name, compiled);
|
|
56
|
+
return compiled;
|
|
57
|
+
}
|
|
29
58
|
use(req, _res, next) {
|
|
30
59
|
// BP-006: `req.url` is stripped to the middleware's mount-point when
|
|
31
60
|
// registered via NestModule.configure(consumer).forRoutes('*'), so it
|
|
32
61
|
// collapses to `/` for every request. `req.originalUrl` carries the full
|
|
33
62
|
// request URL verbatim — use that for prefix matching.
|
|
34
63
|
const url = String(req.originalUrl ?? req.url ?? '').split('?')[0];
|
|
64
|
+
const host = this.resolveHost(req);
|
|
35
65
|
const groups = this.config.routeGroups();
|
|
36
|
-
|
|
66
|
+
// FIX 11.1 (auth-path resolution): an auth entry path (login/logout/
|
|
67
|
+
// register/password recover|reset) must resolve to the auth-enabled group
|
|
68
|
+
// that matches this host/prefix, falling back to the empty-prefix/default
|
|
69
|
+
// group, and must ALWAYS keep `__skipAuth` so the JWT guard never blocks
|
|
70
|
+
// login/register/recover. A host-claiming empty-prefix DOMAIN group (which
|
|
71
|
+
// matches every path) must NOT win the auth path away from the group it
|
|
72
|
+
// belongs to. This branch is a no-op for apps with no auth-enabled group.
|
|
73
|
+
if (this.isAuthEntryPath(url) && this.config.authEnabledGroups().length > 0) {
|
|
74
|
+
this.resolveAuthEntry(req, url, host, groups);
|
|
75
|
+
return next();
|
|
76
|
+
}
|
|
77
|
+
// NOTE: never mutate `req.__skipAuth` inside this loop. Candidate matches
|
|
78
|
+
// record their group's `skipAuth` flag and the winning match applies it
|
|
79
|
+
// exactly once below, so a losing prefix group can't leak skipAuth onto a
|
|
80
|
+
// domain group that wins precedence (BLOCKER 1).
|
|
81
|
+
let prefixMatch = null;
|
|
82
|
+
let domainMatch = null;
|
|
83
|
+
// The empty-prefix, non-domain "default" group (e.g. `default`), if any. It
|
|
84
|
+
// serves every path that no more-specific prefix/domain group claims, so it
|
|
85
|
+
// is the fallback `__routeGroup` — making enforcement uniform: even the
|
|
86
|
+
// default group tags its routes with the group name (parity with
|
|
87
|
+
// Laravel/Rails). Without this, a null request-group matched ANY membership
|
|
88
|
+
// row (the route_group dimension was ignored). See FIX 3.
|
|
89
|
+
let defaultMatch = null;
|
|
90
|
+
// Tracks whether the URL path targeted a domain-scoped group whose host did
|
|
91
|
+
// NOT match — used for wrong-host 404 enforcement.
|
|
92
|
+
let blockedByHost = false;
|
|
93
|
+
// Tracks whether ANY non-domain group is eligible to serve this request
|
|
94
|
+
// (matched its prefix, or is a catch-all empty-prefix group). An
|
|
95
|
+
// empty-prefix domain group matches every path, so it must not 404 a
|
|
96
|
+
// request that such a non-domain group could serve (BLOCKER 2).
|
|
97
|
+
let nonDomainEligible = false;
|
|
37
98
|
for (const [name, group] of Object.entries(groups)) {
|
|
38
99
|
const prefix = group.prefix ?? '';
|
|
39
|
-
|
|
100
|
+
const compiled = this.compileFor(name, group.domain);
|
|
101
|
+
if (compiled) {
|
|
102
|
+
// Domain-scoped group: only eligible when the host matches.
|
|
103
|
+
const hostResult = (0, domain_pattern_1.matchDomain)(compiled, host);
|
|
104
|
+
const pathMatches = this.prefixMatches(url, prefix);
|
|
105
|
+
if (!hostResult) {
|
|
106
|
+
// Host doesn't match this domain group. If the path would otherwise
|
|
107
|
+
// target this group, remember it for wrong-host enforcement (only
|
|
108
|
+
// honored below when no other group can serve the request).
|
|
109
|
+
if (pathMatches)
|
|
110
|
+
blockedByHost = true;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
// Host matches. Require the prefix to match too (empty prefix => match).
|
|
114
|
+
if (!pathMatches)
|
|
115
|
+
continue;
|
|
116
|
+
if (!domainMatch) {
|
|
117
|
+
domainMatch = {
|
|
118
|
+
name,
|
|
119
|
+
prefix,
|
|
120
|
+
params: hostResult.params,
|
|
121
|
+
skipAuth: group.skipAuth,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
40
124
|
continue;
|
|
125
|
+
}
|
|
126
|
+
// Plain prefix group (no domain) — original behavior.
|
|
41
127
|
if (prefix.startsWith(':'))
|
|
42
128
|
continue; // dynamic tenant prefix — handled by ResolveOrganizationMiddleware
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
129
|
+
if (!prefix) {
|
|
130
|
+
// Catch-all (empty-prefix) non-domain group: eligible for any path, so
|
|
131
|
+
// a wrong-host domain group must not block requests it could serve. It
|
|
132
|
+
// becomes the `__routeGroup` only as a FALLBACK (below) — a concrete
|
|
133
|
+
// prefix or domain group always wins. Recording it lets the default
|
|
134
|
+
// group tag its routes with the group name so membership enforcement
|
|
135
|
+
// is uniform across all groups (FIX 3).
|
|
136
|
+
nonDomainEligible = true;
|
|
137
|
+
if (!defaultMatch) {
|
|
138
|
+
defaultMatch = { name, prefix, skipAuth: group.skipAuth };
|
|
139
|
+
}
|
|
140
|
+
continue;
|
|
48
141
|
}
|
|
142
|
+
if (this.prefixMatches(url, prefix)) {
|
|
143
|
+
nonDomainEligible = true;
|
|
144
|
+
if (!prefixMatch) {
|
|
145
|
+
prefixMatch = { name, prefix, skipAuth: group.skipAuth };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Host-scoped match takes precedence over a plain prefix match. Apply
|
|
150
|
+
// `__skipAuth` exactly once, from the winning group only.
|
|
151
|
+
if (domainMatch) {
|
|
152
|
+
req.__routeGroup = domainMatch.name;
|
|
153
|
+
if (domainMatch.skipAuth)
|
|
154
|
+
req.__skipAuth = true;
|
|
155
|
+
// Expose captured subdomain params (e.g. {organization}) so that
|
|
156
|
+
// ResolveOrganizationMiddleware can resolve the tenant from the host.
|
|
157
|
+
this.exposeDomainParams(req, domainMatch.params);
|
|
158
|
+
return next();
|
|
159
|
+
}
|
|
160
|
+
if (prefixMatch) {
|
|
161
|
+
req.__routeGroup = prefixMatch.name;
|
|
162
|
+
if (prefixMatch.skipAuth)
|
|
163
|
+
req.__skipAuth = true;
|
|
164
|
+
return next();
|
|
165
|
+
}
|
|
166
|
+
// Fallback: an empty-prefix, non-domain "default" group serves whatever no
|
|
167
|
+
// concrete prefix/domain group claimed. Tag the request with its name so
|
|
168
|
+
// the default group is a first-class membership dimension (FIX 3). A
|
|
169
|
+
// wrong-host domain group must not pre-empt a request this group can serve,
|
|
170
|
+
// so this also resolves the blockedByHost case below.
|
|
171
|
+
if (defaultMatch) {
|
|
172
|
+
req.__routeGroup = defaultMatch.name;
|
|
173
|
+
if (defaultMatch.skipAuth)
|
|
174
|
+
req.__skipAuth = true;
|
|
175
|
+
return next();
|
|
176
|
+
}
|
|
177
|
+
// No group matched. If a domain-scoped group targeted by the path had a
|
|
178
|
+
// non-matching host AND no non-domain group is eligible to serve the
|
|
179
|
+
// request, reject: a wrong-host request must not be served as that group.
|
|
180
|
+
// (An empty-prefix domain group that would block every path is overridden
|
|
181
|
+
// here by any eligible non-domain group — BLOCKER 2.)
|
|
182
|
+
if (blockedByHost && !nonDomainEligible) {
|
|
183
|
+
return next(new common_1.NotFoundException('Not found'));
|
|
49
184
|
}
|
|
50
|
-
if (match)
|
|
51
|
-
req.__routeGroup = match.name;
|
|
52
185
|
next();
|
|
53
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Whether `url` targets one of the auth entry endpoints. These are the
|
|
189
|
+
* routes that must never be blocked by the JWT guard (login/register/recover)
|
|
190
|
+
* and that must resolve to the group they belong to. Matches the auth
|
|
191
|
+
* controller's `@Controller('auth')` action paths under any prefix.
|
|
192
|
+
*/
|
|
193
|
+
isAuthEntryPath(url) {
|
|
194
|
+
return (/(^|\/)auth\/login(\/|$)/.test(url) ||
|
|
195
|
+
/(^|\/)auth\/logout(\/|$)/.test(url) ||
|
|
196
|
+
/(^|\/)auth\/register(\/|$)/.test(url) ||
|
|
197
|
+
/(^|\/)auth\/password\/[^/]+(\/|$)/.test(url));
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Resolve the route group for an auth entry path (FIX 11.1). Precedence:
|
|
201
|
+
* 1. an auth-enabled DOMAIN group whose host matches (and prefix matches);
|
|
202
|
+
* 2. an auth-enabled PREFIX group whose prefix matches;
|
|
203
|
+
* 3. the empty-prefix / default group (auth-enabled preferred, else any);
|
|
204
|
+
* 4. otherwise leave `__routeGroup` unset (legacy/global auth path).
|
|
205
|
+
*
|
|
206
|
+
* `__skipAuth` is ALWAYS set on an auth entry path so the JWT guard never
|
|
207
|
+
* blocks login/register/recover, regardless of which group wins — even a
|
|
208
|
+
* host-claiming empty-prefix domain group cannot strip it.
|
|
209
|
+
*/
|
|
210
|
+
resolveAuthEntry(req, url, host, groups) {
|
|
211
|
+
let authDomain = null;
|
|
212
|
+
let authPrefix = null;
|
|
213
|
+
let authDefault = null;
|
|
214
|
+
let plainDefault = null;
|
|
215
|
+
for (const [name, group] of Object.entries(groups)) {
|
|
216
|
+
const prefix = group.prefix ?? '';
|
|
217
|
+
if (prefix.startsWith(':'))
|
|
218
|
+
continue; // dynamic tenant prefix
|
|
219
|
+
const authEnabled = group.auth === true && name !== 'public';
|
|
220
|
+
const compiled = this.compileFor(name, group.domain);
|
|
221
|
+
if (compiled) {
|
|
222
|
+
if (!authEnabled)
|
|
223
|
+
continue;
|
|
224
|
+
const hostResult = (0, domain_pattern_1.matchDomain)(compiled, host);
|
|
225
|
+
if (!hostResult)
|
|
226
|
+
continue;
|
|
227
|
+
if (!this.prefixMatches(url, prefix))
|
|
228
|
+
continue;
|
|
229
|
+
if (!authDomain)
|
|
230
|
+
authDomain = { name, params: hostResult.params };
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
// Plain (non-domain) group.
|
|
234
|
+
if (!prefix) {
|
|
235
|
+
// Empty-prefix / default group: the auth-path fallback.
|
|
236
|
+
if (authEnabled) {
|
|
237
|
+
if (authDefault == null)
|
|
238
|
+
authDefault = name;
|
|
239
|
+
}
|
|
240
|
+
else if (plainDefault == null) {
|
|
241
|
+
plainDefault = name;
|
|
242
|
+
}
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (authEnabled && this.prefixMatches(url, prefix)) {
|
|
246
|
+
// Prefer the most specific (longest) matching prefix.
|
|
247
|
+
if (!authPrefix || prefix.length > authPrefix.prefixLen) {
|
|
248
|
+
authPrefix = { name, prefixLen: prefix.length };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// Auth entry paths are always exempt from the JWT guard.
|
|
253
|
+
req.__skipAuth = true;
|
|
254
|
+
if (authDomain) {
|
|
255
|
+
req.__routeGroup = authDomain.name;
|
|
256
|
+
this.exposeDomainParams(req, authDomain.params);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (authPrefix) {
|
|
260
|
+
req.__routeGroup = authPrefix.name;
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
// Fall back to the default group: an auth-enabled empty-prefix group is the
|
|
264
|
+
// legacy/global auth path itself (design §11.1), so it adopts the auth
|
|
265
|
+
// route. If none is auth-enabled, use any empty-prefix default group so the
|
|
266
|
+
// request still carries a first-class group (parity with FIX 3).
|
|
267
|
+
const fallback = authDefault ?? plainDefault;
|
|
268
|
+
if (fallback)
|
|
269
|
+
req.__routeGroup = fallback;
|
|
270
|
+
// else: no group claims it → legacy/global auth path (null group).
|
|
271
|
+
}
|
|
272
|
+
resolveHost(req) {
|
|
273
|
+
// Express populates `req.hostname` (port-stripped). Fall back to the Host
|
|
274
|
+
// header for environments/tests that only set headers.
|
|
275
|
+
const fromExpress = req.hostname;
|
|
276
|
+
if (fromExpress)
|
|
277
|
+
return String(fromExpress);
|
|
278
|
+
const header = req.headers?.host ?? req.host;
|
|
279
|
+
return header ? String(header).split(':')[0] : undefined;
|
|
280
|
+
}
|
|
281
|
+
prefixMatches(url, prefix) {
|
|
282
|
+
if (!prefix)
|
|
283
|
+
return true; // empty prefix => any path under the group
|
|
284
|
+
if (prefix.startsWith(':'))
|
|
285
|
+
return false;
|
|
286
|
+
return url.includes(`/${prefix}/`) || url.endsWith(`/${prefix}`);
|
|
287
|
+
}
|
|
288
|
+
exposeDomainParams(req, params) {
|
|
289
|
+
if (!params || Object.keys(params).length === 0)
|
|
290
|
+
return;
|
|
291
|
+
// DNS hostnames are case-insensitive but the regex capture preserves the
|
|
292
|
+
// host's casing verbatim. Lowercase the captured subdomain params so org
|
|
293
|
+
// resolution (and the resolver's cache key) is consistent — `ACME` and
|
|
294
|
+
// `acme` must resolve the same lowercase-slugged org.
|
|
295
|
+
const normalized = {};
|
|
296
|
+
for (const [key, value] of Object.entries(params)) {
|
|
297
|
+
normalized[key] = typeof value === 'string' ? value.toLowerCase() : value;
|
|
298
|
+
}
|
|
299
|
+
req.params = req.params ?? {};
|
|
300
|
+
for (const [key, value] of Object.entries(normalized)) {
|
|
301
|
+
// Don't clobber an explicit path param of the same name.
|
|
302
|
+
if (req.params[key] == null)
|
|
303
|
+
req.params[key] = value;
|
|
304
|
+
}
|
|
305
|
+
// Convention: a `{organization}` (or `{org}`) domain param feeds org
|
|
306
|
+
// resolution exactly like the `:organization` path param does. Surface it
|
|
307
|
+
// under `organization` so ResolveOrganizationMiddleware reads it uniformly.
|
|
308
|
+
const orgParam = normalized.organization ?? normalized.org;
|
|
309
|
+
if (orgParam != null && req.params.organization == null) {
|
|
310
|
+
req.params.organization = orgParam;
|
|
311
|
+
}
|
|
312
|
+
// Also record the (normalized) captured subdomain for downstream/debug use.
|
|
313
|
+
req.__domainParams = normalized;
|
|
314
|
+
}
|
|
54
315
|
};
|
|
55
316
|
exports.RouteGroupMiddleware = RouteGroupMiddleware;
|
|
56
317
|
exports.RouteGroupMiddleware = RouteGroupMiddleware = __decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-group.middleware.js","sourceRoot":"","sources":["../../src/middleware/route-group.middleware.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"route-group.middleware.js","sourceRoot":"","sources":["../../src/middleware/route-group.middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/rhino.config.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { RhinoConfig, ModelRegistration, RouteGroupConfig } from './interfaces/rhino-config.interface';
|
|
1
|
+
import type { RhinoConfig, ModelRegistration, RouteGroupConfig, AuthLifecycleHooks } from './interfaces/rhino-config.interface';
|
|
2
|
+
import type { Type } from '@nestjs/common';
|
|
2
3
|
/**
|
|
3
4
|
* Injectable accessor for the consuming app's Rhino configuration.
|
|
4
5
|
* Wraps the raw config object with convenience lookup methods.
|
|
@@ -17,6 +18,29 @@ export declare class RhinoConfigService {
|
|
|
17
18
|
* `'*'` expands to every registered model.
|
|
18
19
|
*/
|
|
19
20
|
modelsInRouteGroup(name: string): string[];
|
|
21
|
+
/**
|
|
22
|
+
* Master flag for group-membership enforcement (Decision 9.A/B/C). Default
|
|
23
|
+
* `false` → behavior unchanged.
|
|
24
|
+
*/
|
|
25
|
+
enforceGroupMembership(): boolean;
|
|
26
|
+
/** Whether a group has opted into per-group auth routes (Decision 9.A). */
|
|
27
|
+
routeGroupAuthEnabled(name: string | null | undefined): boolean;
|
|
28
|
+
/** The configured lifecycle-hooks provider/object for a group, if any. */
|
|
29
|
+
routeGroupHooks(name: string | null | undefined): Type<AuthLifecycleHooks> | AuthLifecycleHooks | undefined;
|
|
30
|
+
/** Names of all groups with `auth: true` (excludes the `public` group). */
|
|
31
|
+
authEnabledGroups(): string[];
|
|
32
|
+
/**
|
|
33
|
+
* Whether a route group is a tenant (org-scoped) group. A group is a tenant
|
|
34
|
+
* group when multi-tenancy is enabled AND the group does not opt out via
|
|
35
|
+
* `belongsToOrganization: false`-style config; here we treat a group as a
|
|
36
|
+
* tenant group when its declared models include any org-scoped model, or when
|
|
37
|
+
* the group carries a tenant `domain`/`prefix` param. Conservatively: a group
|
|
38
|
+
* is non-tenant only when explicitly marked. For membership purposes the org
|
|
39
|
+
* is only required when the request actually resolved an organization, so the
|
|
40
|
+
* effective rule is "tenant group ⇒ org must match". We expose the simpler
|
|
41
|
+
* predicate: multi-tenant enabled and not the public group.
|
|
42
|
+
*/
|
|
43
|
+
isTenantGroup(name: string | null | undefined): boolean;
|
|
20
44
|
multiTenantEnabled(): boolean;
|
|
21
45
|
organizationIdentifierColumn(): string;
|
|
22
46
|
nestedConfig(): {
|
|
@@ -35,6 +59,7 @@ export declare class RhinoConfigService {
|
|
|
35
59
|
userModel: string;
|
|
36
60
|
emailField: string;
|
|
37
61
|
passwordField: string;
|
|
62
|
+
enforceGroupMembership: boolean;
|
|
38
63
|
};
|
|
39
64
|
}
|
|
40
65
|
/**
|
package/dist/rhino.config.js
CHANGED
|
@@ -16,6 +16,7 @@ exports.RhinoConfigService = void 0;
|
|
|
16
16
|
exports.normalizeConfig = normalizeConfig;
|
|
17
17
|
const common_1 = require("@nestjs/common");
|
|
18
18
|
const tokens_1 = require("./constants/tokens");
|
|
19
|
+
const route_group_validator_1 = require("./utils/route-group-validator");
|
|
19
20
|
/**
|
|
20
21
|
* Injectable accessor for the consuming app's Rhino configuration.
|
|
21
22
|
* Wraps the raw config object with convenience lookup methods.
|
|
@@ -55,6 +56,54 @@ let RhinoConfigService = class RhinoConfigService {
|
|
|
55
56
|
return Object.keys(this.models());
|
|
56
57
|
return group.models;
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Master flag for group-membership enforcement (Decision 9.A/B/C). Default
|
|
61
|
+
* `false` → behavior unchanged.
|
|
62
|
+
*/
|
|
63
|
+
enforceGroupMembership() {
|
|
64
|
+
return this.config.auth?.enforceGroupMembership === true;
|
|
65
|
+
}
|
|
66
|
+
/** Whether a group has opted into per-group auth routes (Decision 9.A). */
|
|
67
|
+
routeGroupAuthEnabled(name) {
|
|
68
|
+
if (!name)
|
|
69
|
+
return false;
|
|
70
|
+
return this.routeGroup(name)?.auth === true;
|
|
71
|
+
}
|
|
72
|
+
/** The configured lifecycle-hooks provider/object for a group, if any. */
|
|
73
|
+
routeGroupHooks(name) {
|
|
74
|
+
if (!name)
|
|
75
|
+
return undefined;
|
|
76
|
+
return this.routeGroup(name)?.hooks;
|
|
77
|
+
}
|
|
78
|
+
/** Names of all groups with `auth: true` (excludes the `public` group). */
|
|
79
|
+
authEnabledGroups() {
|
|
80
|
+
return Object.entries(this.routeGroups())
|
|
81
|
+
.filter(([name, g]) => g.auth === true && name !== 'public')
|
|
82
|
+
.map(([name]) => name);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Whether a route group is a tenant (org-scoped) group. A group is a tenant
|
|
86
|
+
* group when multi-tenancy is enabled AND the group does not opt out via
|
|
87
|
+
* `belongsToOrganization: false`-style config; here we treat a group as a
|
|
88
|
+
* tenant group when its declared models include any org-scoped model, or when
|
|
89
|
+
* the group carries a tenant `domain`/`prefix` param. Conservatively: a group
|
|
90
|
+
* is non-tenant only when explicitly marked. For membership purposes the org
|
|
91
|
+
* is only required when the request actually resolved an organization, so the
|
|
92
|
+
* effective rule is "tenant group ⇒ org must match". We expose the simpler
|
|
93
|
+
* predicate: multi-tenant enabled and not the public group.
|
|
94
|
+
*/
|
|
95
|
+
isTenantGroup(name) {
|
|
96
|
+
if (name === 'public')
|
|
97
|
+
return false;
|
|
98
|
+
if (name) {
|
|
99
|
+
const group = this.routeGroup(name);
|
|
100
|
+
// Explicit per-group override wins.
|
|
101
|
+
if (group && typeof group.tenant === 'boolean')
|
|
102
|
+
return group.tenant;
|
|
103
|
+
}
|
|
104
|
+
// Default: a group is org-scoped iff multi-tenancy is enabled.
|
|
105
|
+
return this.multiTenantEnabled();
|
|
106
|
+
}
|
|
58
107
|
multiTenantEnabled() {
|
|
59
108
|
const mt = this.config.multiTenant;
|
|
60
109
|
if (!mt)
|
|
@@ -89,6 +138,7 @@ let RhinoConfigService = class RhinoConfigService {
|
|
|
89
138
|
userModel: this.config.auth?.userModel ?? 'user',
|
|
90
139
|
emailField: this.config.auth?.emailField ?? 'email',
|
|
91
140
|
passwordField: this.config.auth?.passwordField ?? 'password',
|
|
141
|
+
enforceGroupMembership: this.config.auth?.enforceGroupMembership === true,
|
|
92
142
|
};
|
|
93
143
|
}
|
|
94
144
|
};
|
|
@@ -102,7 +152,7 @@ exports.RhinoConfigService = RhinoConfigService = __decorate([
|
|
|
102
152
|
* Normalize a raw config value (defaults applied) — used by the module in forRoot.
|
|
103
153
|
*/
|
|
104
154
|
function normalizeConfig(config) {
|
|
105
|
-
|
|
155
|
+
const normalized = {
|
|
106
156
|
...config,
|
|
107
157
|
models: config.models ?? {},
|
|
108
158
|
routeGroups: config.routeGroups ?? {},
|
|
@@ -123,8 +173,13 @@ function normalizeConfig(config) {
|
|
|
123
173
|
userModel: 'user',
|
|
124
174
|
emailField: 'email',
|
|
125
175
|
passwordField: 'password',
|
|
176
|
+
enforceGroupMembership: false,
|
|
126
177
|
...(config.auth ?? {}),
|
|
127
178
|
},
|
|
128
179
|
};
|
|
180
|
+
// Fail fast on route groups that would silently shadow each other (same
|
|
181
|
+
// prefix + intersecting host-set + overlapping models).
|
|
182
|
+
(0, route_group_validator_1.validateRouteGroups)(normalized);
|
|
183
|
+
return normalized;
|
|
129
184
|
}
|
|
130
185
|
//# sourceMappingURL=rhino.config.js.map
|
package/dist/rhino.config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rhino.config.js","sourceRoot":"","sources":["../src/rhino.config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"rhino.config.js","sourceRoot":"","sources":["../src/rhino.config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAsJA,0CAgCC;AAtLD,2CAAoD;AACpD,+CAAkD;AAQlD,yEAAoE;AAEpE;;;GAGG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IACsB;IAAnD,YAAmD,MAAmB;QAAnB,WAAM,GAAN,MAAM,CAAa;IAAG,CAAC;IAE1E,GAAG;QACD,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,IAAY;QAChB,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,QAAQ,CAAC,IAAY;QACnB,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC;IACvC,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED;;;OAGG;IACH,kBAAkB,CAAC,IAAY;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QACtB,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5D,OAAO,KAAK,CAAC,MAAM,CAAC;IACtB,CAAC;IAED;;;OAGG;IACH,sBAAsB;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAC3D,CAAC;IAED,2EAA2E;IAC3E,qBAAqB,CAAC,IAA+B;QACnD,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QACxB,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9C,CAAC;IAED,0EAA0E;IAC1E,eAAe,CACb,IAA+B;QAE/B,IAAI,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC;QAC5B,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC;IACtC,CAAC;IAED,2EAA2E;IAC3E,iBAAiB;QACf,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;aACtC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,QAAQ,CAAC;aAC3D,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED;;;;;;;;;;OAUG;IACH,aAAa,CAAC,IAA+B;QAC3C,IAAI,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QACpC,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACpC,oCAAoC;YACpC,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC,MAAM,CAAC;QACtE,CAAC;QACD,+DAA+D;QAC/D,OAAO,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACnC,CAAC;IAED,kBAAkB;QAChB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACnC,IAAI,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC;QACtB,IAAI,EAAE,CAAC,OAAO,KAAK,KAAK;YAAE,OAAO,KAAK,CAAC;QACvC,OAAO,OAAO,CAAC,EAAE,CAAC,4BAA4B,CAAC,IAAI,EAAE,CAAC,OAAO,KAAK,IAAI,CAAC;IACzE,CAAC;IAED,4BAA4B;QAC1B,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,4BAA4B,IAAI,IAAI,CAAC;IACvE,CAAC;IAED,YAAY;QACV,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,QAAQ;YAC1C,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,IAAI,EAAE;YACtD,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,IAAI,IAAI;SACzD,CAAC;IACJ,CAAC;IAED,iBAAiB;QACf,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,WAAW,IAAI,CAAC;YACtD,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,IAAI,IAAI;YAC3D,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,mBAAmB;SAClE,CAAC;IACJ,CAAC;IAED,UAAU;QACR,OAAO;YACL,SAAS,EACP,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS;gBAC3B,OAAO,CAAC,GAAG,CAAC,UAAU;gBACtB,yBAAyB;YAC3B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,IAAI,IAAI;YACpD,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,IAAI,MAAM;YAChD,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,IAAI,OAAO;YACnD,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,IAAI,UAAU;YAC5D,sBAAsB,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,sBAAsB,KAAK,IAAI;SAC1E,CAAC;IACJ,CAAC;CACF,CAAA;AAjIY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,mBAAU,GAAE;IAEE,WAAA,IAAA,eAAM,EAAC,qBAAY,CAAC,CAAA;;GADtB,kBAAkB,CAiI9B;AAED;;GAEG;AACH,SAAgB,eAAe,CAAC,MAAmB;IACjD,MAAM,UAAU,GAAgB;QAC9B,GAAG,MAAM;QACT,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE;QACrC,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE;QACrD,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,aAAa,EAAE,EAAE;YACjB,aAAa,EAAE,IAAI;YACnB,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;SACzB;QACD,WAAW,EAAE;YACX,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,IAAI;YAClB,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC;SAC9B;QACD,IAAI,EAAE;YACJ,YAAY,EAAE,IAAI;YAClB,SAAS,EAAE,MAAM;YACjB,UAAU,EAAE,OAAO;YACnB,aAAa,EAAE,UAAU;YACzB,sBAAsB,EAAE,KAAK;YAC7B,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;SACvB;KACF,CAAC;IAEF,wEAAwE;IACxE,wDAAwD;IACxD,IAAA,2CAAmB,EAAC,UAAU,CAAC,CAAC;IAEhC,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
package/dist/rhino.module.d.ts
CHANGED
|
@@ -13,6 +13,12 @@ export interface RhinoModuleOptions {
|
|
|
13
13
|
autoModelMiddleware?: boolean;
|
|
14
14
|
/** Wire ResolveOrganizationMiddleware for all routes when multiTenant enabled. Default true. */
|
|
15
15
|
autoTenantMiddleware?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Install GroupMembershipGuard globally as APP_GUARD. Default false (opt-in).
|
|
18
|
+
* The guard is a no-op unless `auth.enforceGroupMembership` is on, so this is
|
|
19
|
+
* safe to enable alongside `autoAuthGuard` when using group membership.
|
|
20
|
+
*/
|
|
21
|
+
autoMembershipGuard?: boolean;
|
|
16
22
|
}
|
|
17
23
|
/**
|
|
18
24
|
* Rhino NestJS dynamic module.
|
|
@@ -57,5 +63,6 @@ export declare class RhinoModule implements NestModule {
|
|
|
57
63
|
private static build;
|
|
58
64
|
private static collectModelMiddleware;
|
|
59
65
|
private static coreProviders;
|
|
66
|
+
private static collectHookClasses;
|
|
60
67
|
private static coreExports;
|
|
61
68
|
}
|
package/dist/rhino.module.js
CHANGED
|
@@ -29,8 +29,11 @@ const nested_service_1 = require("./services/nested.service");
|
|
|
29
29
|
const scope_service_1 = require("./services/scope.service");
|
|
30
30
|
const auth_service_1 = require("./services/auth.service");
|
|
31
31
|
const invitation_service_1 = require("./services/invitation.service");
|
|
32
|
+
const auth_hooks_service_1 = require("./services/auth-hooks.service");
|
|
33
|
+
const membership_service_1 = require("./services/membership.service");
|
|
32
34
|
const jwt_auth_guard_1 = require("./guards/jwt-auth.guard");
|
|
33
35
|
const resource_policy_guard_1 = require("./guards/resource-policy.guard");
|
|
36
|
+
const group_membership_guard_1 = require("./guards/group-membership.guard");
|
|
34
37
|
const global_controller_1 = require("./controllers/global.controller");
|
|
35
38
|
const auth_controller_1 = require("./controllers/auth.controller");
|
|
36
39
|
const invitation_controller_1 = require("./controllers/invitation.controller");
|
|
@@ -132,6 +135,7 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
132
135
|
static forRoot(config, options = {}) {
|
|
133
136
|
const normalized = (0, rhino_config_1.normalizeConfig)(config);
|
|
134
137
|
const middlewareFromConfig = RhinoModule_1.collectModelMiddleware(normalized);
|
|
138
|
+
const hookClasses = RhinoModule_1.collectHookClasses(normalized);
|
|
135
139
|
return RhinoModule_1.build({
|
|
136
140
|
configProviders: [
|
|
137
141
|
{ provide: tokens_1.RHINO_CONFIG, useValue: normalized },
|
|
@@ -143,6 +147,7 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
143
147
|
imports: [],
|
|
144
148
|
options,
|
|
145
149
|
middlewareClasses: middlewareFromConfig,
|
|
150
|
+
hookClasses,
|
|
146
151
|
});
|
|
147
152
|
}
|
|
148
153
|
/**
|
|
@@ -173,6 +178,8 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
173
178
|
const guardProviders = [];
|
|
174
179
|
if (opts.autoAuthGuard)
|
|
175
180
|
guardProviders.push({ provide: core_1.APP_GUARD, useClass: jwt_auth_guard_1.JwtAuthGuard });
|
|
181
|
+
if (opts.autoMembershipGuard)
|
|
182
|
+
guardProviders.push({ provide: core_1.APP_GUARD, useClass: group_membership_guard_1.GroupMembershipGuard });
|
|
176
183
|
if (opts.autoPolicyGuard)
|
|
177
184
|
guardProviders.push({ provide: core_1.APP_GUARD, useClass: resource_policy_guard_1.ResourcePolicyGuard });
|
|
178
185
|
return {
|
|
@@ -187,9 +194,10 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
187
194
|
...RhinoModule_1.coreProviders(),
|
|
188
195
|
jwt_auth_guard_1.JwtAuthGuard,
|
|
189
196
|
resource_policy_guard_1.ResourcePolicyGuard,
|
|
197
|
+
group_membership_guard_1.GroupMembershipGuard,
|
|
190
198
|
route_group_middleware_1.RouteGroupMiddleware,
|
|
191
199
|
resolve_organization_middleware_1.ResolveOrganizationMiddleware,
|
|
192
|
-
...dedupeTypes(args.middlewareClasses),
|
|
200
|
+
...dedupeTypes([...args.middlewareClasses, ...(args.hookClasses ?? [])]),
|
|
193
201
|
...guardProviders,
|
|
194
202
|
],
|
|
195
203
|
exports: RhinoModule_1.coreExports(),
|
|
@@ -221,8 +229,19 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
221
229
|
scope_service_1.ScopeService,
|
|
222
230
|
auth_service_1.AuthService,
|
|
223
231
|
invitation_service_1.InvitationService,
|
|
232
|
+
auth_hooks_service_1.AuthHooksService,
|
|
233
|
+
membership_service_1.MembershipService,
|
|
224
234
|
];
|
|
225
235
|
}
|
|
236
|
+
static collectHookClasses(config) {
|
|
237
|
+
const set = new Set();
|
|
238
|
+
for (const group of Object.values(config.routeGroups ?? {})) {
|
|
239
|
+
const hooks = group.hooks;
|
|
240
|
+
if (hooks && typeof hooks === 'function')
|
|
241
|
+
set.add(hooks);
|
|
242
|
+
}
|
|
243
|
+
return Array.from(set);
|
|
244
|
+
}
|
|
226
245
|
static coreExports() {
|
|
227
246
|
return [
|
|
228
247
|
// Injection tokens (BP-010 — surfaced for consumer middleware/services)
|
|
@@ -241,8 +260,11 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
241
260
|
scope_service_1.ScopeService,
|
|
242
261
|
auth_service_1.AuthService,
|
|
243
262
|
invitation_service_1.InvitationService,
|
|
263
|
+
auth_hooks_service_1.AuthHooksService,
|
|
264
|
+
membership_service_1.MembershipService,
|
|
244
265
|
jwt_auth_guard_1.JwtAuthGuard,
|
|
245
266
|
resource_policy_guard_1.ResourcePolicyGuard,
|
|
267
|
+
group_membership_guard_1.GroupMembershipGuard,
|
|
246
268
|
];
|
|
247
269
|
}
|
|
248
270
|
};
|
package/dist/rhino.module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rhino.module.js","sourceRoot":"","sources":["../src/rhino.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAUwB;AACxB,uCAAyC;AACzC,iDAAqE;AACrE,+CAI4B;AAK5B,4DAAwD;AACxD,kEAA8D;AAC9D,4EAAuE;AACvE,sEAAkE;AAClE,sEAAkE;AAClE,0EAAsE;AACtE,4DAAwD;AACxD,8DAA0D;AAC1D,4DAAwD;AACxD,0DAAsD;AACtD,sEAAkE;AAClE,4DAAuD;AACvD,0EAAqE;AACrE,uEAAmE;AACnE,mEAA+D;AAC/D,+EAA2E;AAC3E,uEAAmE;AACnE,gFAA2E;AAC3E,kGAA6F;AAE7F,MAAM,gBAAgB,GAAkC;IACtD,KAAK,EAAE,sBAAa,CAAC,GAAG;IACxB,IAAI,EAAE,sBAAa,CAAC,GAAG;IACvB,KAAK,EAAE,sBAAa,CAAC,IAAI;IACzB,MAAM,EAAE,sBAAa,CAAC,GAAG;IACzB,OAAO,EAAE,sBAAa,CAAC,MAAM;IAC7B,OAAO,EAAE,sBAAa,CAAC,GAAG;IAC1B,OAAO,EAAE,sBAAa,CAAC,IAAI;IAC3B,WAAW,EAAE,sBAAa,CAAC,MAAM;CAClC,CAAC;AAEF,SAAS,UAAU,CAAC,IAAY,EAAE,MAAc;IAC9C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO,CAAC;QACb,KAAK,OAAO;YACV,OAAO,IAAI,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,GAAG,IAAI,UAAU,CAAC;QAC3B,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,GAAG,IAAI,MAAM,CAAC;QACvB,KAAK,SAAS;YACZ,OAAO,GAAG,IAAI,cAAc,CAAC;QAC/B,KAAK,aAAa;YAChB,OAAO,GAAG,IAAI,mBAAmB,CAAC;QACpC;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;
|
|
1
|
+
{"version":3,"file":"rhino.module.js","sourceRoot":"","sources":["../src/rhino.module.ts"],"names":[],"mappings":"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"}
|