@rhino-dev/rhino-nestjs 4.0.0 → 4.2.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.
Files changed (58) hide show
  1. package/README.md +52 -1
  2. package/dist/controllers/auth.controller.d.ts +34 -5
  3. package/dist/controllers/auth.controller.js +132 -12
  4. package/dist/controllers/auth.controller.js.map +1 -1
  5. package/dist/controllers/invitation.controller.d.ts +41 -2
  6. package/dist/controllers/invitation.controller.js +97 -12
  7. package/dist/controllers/invitation.controller.js.map +1 -1
  8. package/dist/errors/rhino-exception.d.ts +12 -1
  9. package/dist/errors/rhino-exception.js +19 -1
  10. package/dist/errors/rhino-exception.js.map +1 -1
  11. package/dist/guards/group-membership.guard.d.ts +25 -0
  12. package/dist/guards/group-membership.guard.js +70 -0
  13. package/dist/guards/group-membership.guard.js.map +1 -0
  14. package/dist/guards/jwt-auth.guard.js +23 -4
  15. package/dist/guards/jwt-auth.guard.js.map +1 -1
  16. package/dist/index.d.ts +7 -1
  17. package/dist/index.js +17 -2
  18. package/dist/index.js.map +1 -1
  19. package/dist/interfaces/rhino-config.interface.d.ts +71 -0
  20. package/dist/middleware/domain-route-resolver.d.ts +54 -0
  21. package/dist/middleware/domain-route-resolver.js +145 -0
  22. package/dist/middleware/domain-route-resolver.js.map +1 -0
  23. package/dist/middleware/route-group.middleware.d.ts +48 -4
  24. package/dist/middleware/route-group.middleware.js +274 -13
  25. package/dist/middleware/route-group.middleware.js.map +1 -1
  26. package/dist/rhino.config.d.ts +26 -1
  27. package/dist/rhino.config.js +56 -1
  28. package/dist/rhino.config.js.map +1 -1
  29. package/dist/rhino.module.d.ts +7 -0
  30. package/dist/rhino.module.js +23 -1
  31. package/dist/rhino.module.js.map +1 -1
  32. package/dist/services/auth-hooks.service.d.ts +27 -0
  33. package/dist/services/auth-hooks.service.js +85 -0
  34. package/dist/services/auth-hooks.service.js.map +1 -0
  35. package/dist/services/auth.service.d.ts +19 -0
  36. package/dist/services/auth.service.js +80 -5
  37. package/dist/services/auth.service.js.map +1 -1
  38. package/dist/services/invitation.service.d.ts +6 -0
  39. package/dist/services/invitation.service.js +45 -3
  40. package/dist/services/invitation.service.js.map +1 -1
  41. package/dist/services/membership.service.d.ts +56 -0
  42. package/dist/services/membership.service.js +113 -0
  43. package/dist/services/membership.service.js.map +1 -0
  44. package/dist/services/organization.service.js +8 -1
  45. package/dist/services/organization.service.js.map +1 -1
  46. package/dist/services/route-registration.service.d.ts +1 -0
  47. package/dist/services/route-registration.service.js +2 -0
  48. package/dist/services/route-registration.service.js.map +1 -1
  49. package/dist/tsconfig.build.tsbuildinfo +1 -1
  50. package/dist/utils/domain-pattern.d.ts +36 -0
  51. package/dist/utils/domain-pattern.js +77 -0
  52. package/dist/utils/domain-pattern.js.map +1 -0
  53. package/dist/utils/permission-matcher.js +8 -0
  54. package/dist/utils/permission-matcher.js.map +1 -1
  55. package/dist/utils/route-group-validator.d.ts +14 -0
  56. package/dist/utils/route-group-validator.js +124 -0
  57. package/dist/utils/route-group-validator.js.map +1 -0
  58. package/package.json +1 -1
@@ -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
  };
@@ -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;AAiBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGI,IAAM,WAAW,mBAAjB,MAAM,WAAW;IAEmB;IACQ;IAFjD,YACyC,MAAmB,EACX,OAA2B;QADnC,WAAM,GAAN,MAAM,CAAa;QACX,YAAO,GAAP,OAAO,CAAoB;IACzE,CAAC;IAEJ,SAAS,CAAC,QAA4B;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QACxB,IAAI,CAAC,GAAG;YAAE,OAAO;QAEjB,IAAI,IAAI,CAAC,wBAAwB,KAAK,KAAK,EAAE,CAAC;YAC5C,QAAQ,CAAC,KAAK,CAAC,6CAAoB,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACtD,CAAC;QAED,IAAI,IAAI,CAAC,mBAAmB,KAAK,KAAK,EAAE,CAAC;YACvC,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC3D,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAgB,CAAC;gBACrD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtB,QAAQ,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,SAAS,CACjC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,sBAAa,CAAC,GAAG,EAAE,EACzC,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,MAAM,EAAE,sBAAa,CAAC,GAAG,EAAE,CACjD,CAAC;gBACJ,CAAC;gBACD,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,EAAE,CAAC;oBAC1E,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,CAAgB,CAAC;oBAC3C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;wBAAE,SAAS;oBAChC,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,sBAAa,CAAC,GAAG,CAAC;oBAC7D,QAAQ,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;gBAChF,CAAC;YACH,CAAC;QACH,CAAC;QAED,IACE,IAAI,CAAC,oBAAoB,KAAK,KAAK;YACnC,CAAC,GAAG,CAAC,WAAW,EAAE,4BAA4B,IAAI,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,EAC3E,CAAC;YACD,QAAQ,CAAC,KAAK,CAAC,+DAA6B,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAAO,CACZ,MAAmB,EACnB,UAA8B,EAAE;QAEhC,MAAM,UAAU,GAAG,IAAA,8BAAe,EAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,oBAAoB,GAAG,aAAW,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC;QAC5E,OAAO,aAAW,CAAC,KAAK,CAAC;YACvB,eAAe,EAAE;gBACf,EAAE,OAAO,EAAE,qBAAY,EAAE,QAAQ,EAAE,UAAU,EAAE;gBAC/C;oBACE,OAAO,EAAE,4BAAmB;oBAC5B,QAAQ,EAAE,UAAU,CAAC,YAAY,IAAI,IAAI;iBAC1C;aACF;YACD,OAAO,EAAE,EAAE;YACX,OAAO;YACP,iBAAiB,EAAE,oBAAoB;SACxC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,YAAY,CACjB,OAAqD;QAErD,MAAM,cAAc,GAAa;YAC/B,OAAO,EAAE,qBAAY;YACrB,UAAU,EAAE,KAAK,EAAE,GAAG,IAAW,EAAE,EAAE,CAAC,IAAA,8BAAe,EAAC,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;YACxF,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;SAC7B,CAAC;QACF,MAAM,cAAc,GAAa;YAC/B,OAAO,EAAE,4BAAmB;YAC5B,UAAU,EAAE,CAAC,GAAgB,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI;YAC1D,MAAM,EAAE,CAAC,qBAAY,CAAC;SACvB,CAAC;QACF,OAAO,aAAW,CAAC,KAAK,CAAC;YACvB,eAAe,EAAE,CAAC,cAAc,EAAE,cAAc,CAAC;YACjD,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;YAC9B,OAAO;YACP,iBAAiB,EAAE,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAgB;SAC7D,CAAC,CAAC;IACL,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,IAKpB;QACC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC;QAC1B,MAAM,cAAc,GAAe,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,aAAa;YAAE,cAAc,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,gBAAS,EAAE,QAAQ,EAAE,6BAAY,EAAE,CAAC,CAAC;QAC5F,IAAI,IAAI,CAAC,eAAe;YAAE,cAAc,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,gBAAS,EAAE,QAAQ,EAAE,2CAAmB,EAAE,CAAC,CAAC;QAErG,OAAO;YACL,MAAM,EAAE,aAAW;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,WAAW,EAAE,IAAI,CAAC,mBAAmB,KAAK,KAAK;gBAC7C,CAAC,CAAC,CAAC,oCAAgB,EAAE,gCAAc,EAAE,4CAAoB,EAAE,oCAAgB,CAAC;gBAC5E,CAAC,CAAC,EAAE;YACN,SAAS,EAAE;gBACT,GAAG,IAAI,CAAC,eAAe;gBACvB,EAAE,OAAO,EAAE,6BAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE;gBACjD,GAAG,aAAW,CAAC,aAAa,EAAE;gBAC9B,6BAAY;gBACZ,2CAAmB;gBACnB,6CAAoB;gBACpB,+DAA6B;gBAC7B,GAAG,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC;gBACtC,GAAG,cAAc;aAClB;YACD,OAAO,EAAE,aAAW,CAAC,WAAW,EAAE;SACnC,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,sBAAsB,CAAC,MAAmB;QACvD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAa,CAAC;QACjC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;YACrD,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAgB;gBAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC5D,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,EAAE,CAAgB;oBAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAEO,MAAM,CAAC,aAAa;QAC1B,OAAO;YACL,iCAAkB;YAClB,8BAAa;YACb,kCAAe;YACf,2CAAmB;YACnB,sCAAiB;YACjB,sCAAiB;YACjB,0CAAmB;YACnB,4BAAY;YACZ,8BAAa;YACb,4BAAY;YACZ,0BAAW;YACX,sCAAiB;SAClB,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,WAAW;QACxB,OAAO;YACL,wEAAwE;YACxE,qBAAY;YACZ,4BAAmB;YACnB,6BAAoB;YACpB,iCAAkB;YAClB,8BAAa;YACb,kCAAe;YACf,2CAAmB;YACnB,sCAAiB;YACjB,sCAAiB;YACjB,0CAAmB;YACnB,4BAAY;YACZ,8BAAa;YACb,4BAAY;YACZ,0BAAW;YACX,sCAAiB;YACjB,6BAAY;YACZ,2CAAmB;SACpB,CAAC;IACJ,CAAC;CACF,CAAA;AA7KY,kCAAW;sBAAX,WAAW;IAFvB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;IAGN,WAAA,IAAA,eAAM,EAAC,qBAAY,CAAC,CAAA;IACpB,WAAA,IAAA,eAAM,EAAC,6BAAoB,CAAC,CAAA;;GAHpB,WAAW,CA6KvB;AAED,SAAS,WAAW,CAAC,IAAiB;IACpC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAO,CAAC;IAC5B,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACjB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACZ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"rhino.module.js","sourceRoot":"","sources":["../src/rhino.module.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { ModuleRef } from '@nestjs/core';
2
+ import { RhinoConfigService } from '../rhino.config';
3
+ import type { AuthHookContext, AuthLifecycleHooks } from '../interfaces/rhino-config.interface';
4
+ export type AuthHookEvent = 'afterLogin' | 'afterLogout' | 'afterRegister' | 'afterPasswordRecover' | 'afterPasswordReset';
5
+ /**
6
+ * Resolves a group's optional lifecycle-hooks class/object and runs a single
7
+ * event (design §7). A hook may reject by throwing — the caller (auth
8
+ * controller) decides whether to revoke a token. When a group has no `hooks`
9
+ * config, every event is a silent no-op.
10
+ *
11
+ * `ModuleRef` is optional so the service works in lightweight unit tests that
12
+ * construct it without a Nest container; in that case a `Type` hooks value is
13
+ * instantiated directly via `new`.
14
+ */
15
+ export declare class AuthHooksService {
16
+ private readonly config;
17
+ private readonly moduleRef?;
18
+ constructor(config: RhinoConfigService, moduleRef?: ModuleRef);
19
+ /** Resolve the hooks instance for a group, or `null` when none is configured. */
20
+ resolve(routeGroup: string | null | undefined): AuthLifecycleHooks | null;
21
+ /**
22
+ * Run a single lifecycle event for the resolved group. Returns silently when
23
+ * the group has no hooks or the specific method is absent. A rejection
24
+ * propagates to the caller verbatim.
25
+ */
26
+ run(event: AuthHookEvent, routeGroup: string | null | undefined, ctx: AuthHookContext): Promise<void>;
27
+ }
@@ -0,0 +1,85 @@
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.AuthHooksService = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const core_1 = require("@nestjs/core");
18
+ const rhino_config_1 = require("../rhino.config");
19
+ /**
20
+ * Resolves a group's optional lifecycle-hooks class/object and runs a single
21
+ * event (design §7). A hook may reject by throwing — the caller (auth
22
+ * controller) decides whether to revoke a token. When a group has no `hooks`
23
+ * config, every event is a silent no-op.
24
+ *
25
+ * `ModuleRef` is optional so the service works in lightweight unit tests that
26
+ * construct it without a Nest container; in that case a `Type` hooks value is
27
+ * instantiated directly via `new`.
28
+ */
29
+ let AuthHooksService = class AuthHooksService {
30
+ config;
31
+ moduleRef;
32
+ constructor(config, moduleRef) {
33
+ this.config = config;
34
+ this.moduleRef = moduleRef;
35
+ }
36
+ /** Resolve the hooks instance for a group, or `null` when none is configured. */
37
+ resolve(routeGroup) {
38
+ const hooks = this.config.routeGroupHooks(routeGroup);
39
+ if (!hooks)
40
+ return null;
41
+ // Plain object implementing the contract.
42
+ if (typeof hooks !== 'function')
43
+ return hooks;
44
+ // A class/Type: prefer the DI container, fall back to direct construction.
45
+ const Cls = hooks;
46
+ if (this.moduleRef) {
47
+ try {
48
+ const instance = this.moduleRef.get(Cls, { strict: false });
49
+ if (instance)
50
+ return instance;
51
+ }
52
+ catch {
53
+ /* not registered as a provider — construct directly below */
54
+ }
55
+ }
56
+ try {
57
+ return new Cls();
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ }
63
+ /**
64
+ * Run a single lifecycle event for the resolved group. Returns silently when
65
+ * the group has no hooks or the specific method is absent. A rejection
66
+ * propagates to the caller verbatim.
67
+ */
68
+ async run(event, routeGroup, ctx) {
69
+ const instance = this.resolve(routeGroup);
70
+ if (!instance)
71
+ return;
72
+ const fn = instance[event];
73
+ if (typeof fn !== 'function')
74
+ return;
75
+ await fn.call(instance, ctx);
76
+ }
77
+ };
78
+ exports.AuthHooksService = AuthHooksService;
79
+ exports.AuthHooksService = AuthHooksService = __decorate([
80
+ (0, common_1.Injectable)(),
81
+ __param(1, (0, common_1.Optional)()),
82
+ __metadata("design:paramtypes", [rhino_config_1.RhinoConfigService,
83
+ core_1.ModuleRef])
84
+ ], AuthHooksService);
85
+ //# sourceMappingURL=auth-hooks.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-hooks.service.js","sourceRoot":"","sources":["../../src/services/auth-hooks.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAsD;AACtD,uCAAyC;AACzC,kDAAqD;AAarD;;;;;;;;;GASG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAER;IACY;IAF/B,YACmB,MAA0B,EACd,SAAqB;QADjC,WAAM,GAAN,MAAM,CAAoB;QACd,cAAS,GAAT,SAAS,CAAY;IACjD,CAAC;IAEJ,iFAAiF;IACjF,OAAO,CAAC,UAAqC;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QACtD,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,0CAA0C;QAC1C,IAAI,OAAO,KAAK,KAAK,UAAU;YAAE,OAAO,KAA2B,CAAC;QACpE,2EAA2E;QAC3E,MAAM,GAAG,GAAG,KAAmD,CAAC;QAChE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC5D,IAAI,QAAQ;oBAAE,OAAO,QAAQ,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,6DAA6D;YAC/D,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,OAAO,IAAI,GAAG,EAAE,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,GAAG,CACP,KAAoB,EACpB,UAAqC,EACrC,GAAoB;QAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,OAAO,EAAE,KAAK,UAAU;YAAE,OAAO;QACrC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC/B,CAAC;CACF,CAAA;AA7CY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;IAIR,WAAA,IAAA,iBAAQ,GAAE,CAAA;qCADc,iCAAkB;QACF,gBAAS;GAHzC,gBAAgB,CA6C5B"}
@@ -26,8 +26,27 @@ export declare class AuthService {
26
26
  verifyToken(token: string): TokenPayload;
27
27
  login(email: string, password: string): Promise<LoginResult>;
28
28
  logout(_user: any): Promise<void>;
29
+ /**
30
+ * Revoke a just-issued token. JWTs are stateless, so "revoking" means
31
+ * recording the token in a denylist (when the consumer provides a
32
+ * `RevokedToken` model) so the JwtAuthGuard can reject it on the next
33
+ * request. Used when a lifecycle hook rejects a login/register: the token is
34
+ * never returned AND — IF a denylist model exists — can no longer be used
35
+ * even if it leaked.
36
+ *
37
+ * Bounded guarantee: the caller (AuthController) ALWAYS drops the token from
38
+ * the response on rejection, so an attacker never receives it. Persisting it
39
+ * to a denylist is the *additional* protection against a leaked token. When
40
+ * no `RevokedToken` model is configured we log a clear WARNING so operators
41
+ * know revoke is advisory-only — pair it with short-TTL JWTs (see README /
42
+ * CLAUDE.md "Group-auth hooks & token revocation").
43
+ */
44
+ revokeToken(token: string): Promise<void>;
45
+ /** Whether a token has been revoked via {@link revokeToken}. */
46
+ isTokenRevoked(token: string): Promise<boolean>;
29
47
  requestPasswordRecovery(email: string): Promise<{
30
48
  token: string;
49
+ user: any;
31
50
  } | null>;
32
51
  resetPassword(email: string, token: string, newPassword: string): Promise<void>;
33
52
  }
@@ -90,10 +90,27 @@ let AuthService = AuthService_1 = class AuthService {
90
90
  }
91
91
  async login(email, password) {
92
92
  const auth = this.config.authConfig();
93
- const user = await this.userDelegate().findFirst({
94
- where: { [auth.emailField]: email },
95
- include: { userRoles: { include: { organization: true, role: true } } },
96
- }).catch(() => null);
93
+ // Only eager-load the org membership graph when multi-tenancy is configured.
94
+ // Single-tenant / org-less apps have no `userRoles` relation on their User
95
+ // model, so an unconditional include would throw inside Prisma and the
96
+ // `.catch(() => null)` below would surface as "Invalid credentials" — i.e.
97
+ // an org-less app could never log a valid user in. Gating the include on
98
+ // `multiTenantEnabled()` keeps multi-tenant behavior byte-for-byte while
99
+ // letting org-less apps authenticate. (We still degrade gracefully if the
100
+ // include fails for any other reason: retry the plain lookup.)
101
+ const wantsOrg = this.config.multiTenantEnabled();
102
+ let user = null;
103
+ if (wantsOrg) {
104
+ user = await this.userDelegate().findFirst({
105
+ where: { [auth.emailField]: email },
106
+ include: { userRoles: { include: { organization: true, role: true } } },
107
+ }).catch(() => null);
108
+ }
109
+ if (!user) {
110
+ user = await this.userDelegate().findFirst({
111
+ where: { [auth.emailField]: email },
112
+ }).catch(() => null);
113
+ }
97
114
  if (!user)
98
115
  throw rhino_exception_1.RhinoException.unauthorized('Invalid credentials');
99
116
  const hashed = user[auth.passwordField];
@@ -107,6 +124,64 @@ let AuthService = AuthService_1 = class AuthService {
107
124
  async logout(_user) {
108
125
  // JWT stateless; consumer can add blacklist logic via hooks.
109
126
  }
127
+ /**
128
+ * Revoke a just-issued token. JWTs are stateless, so "revoking" means
129
+ * recording the token in a denylist (when the consumer provides a
130
+ * `RevokedToken` model) so the JwtAuthGuard can reject it on the next
131
+ * request. Used when a lifecycle hook rejects a login/register: the token is
132
+ * never returned AND — IF a denylist model exists — can no longer be used
133
+ * even if it leaked.
134
+ *
135
+ * Bounded guarantee: the caller (AuthController) ALWAYS drops the token from
136
+ * the response on rejection, so an attacker never receives it. Persisting it
137
+ * to a denylist is the *additional* protection against a leaked token. When
138
+ * no `RevokedToken` model is configured we log a clear WARNING so operators
139
+ * know revoke is advisory-only — pair it with short-TTL JWTs (see README /
140
+ * CLAUDE.md "Group-auth hooks & token revocation").
141
+ */
142
+ async revokeToken(token) {
143
+ if (!token)
144
+ return;
145
+ let delegate;
146
+ try {
147
+ delegate = this.prisma.model('revokedToken');
148
+ }
149
+ catch {
150
+ this.logger.warn('AuthService.revokeToken: no `RevokedToken` model is configured, so token ' +
151
+ 'revocation is advisory only — the token is dropped from the response but ' +
152
+ 'cannot be denylisted if it has already leaked. Add a `RevokedToken` model ' +
153
+ '(token, createdAt) to your Prisma schema and use short-TTL JWTs.');
154
+ return;
155
+ }
156
+ try {
157
+ await delegate.create({ data: { token, createdAt: new Date() } });
158
+ }
159
+ catch (err) {
160
+ // The model exists but the write failed — surface it so a misconfigured
161
+ // denylist is not silently a no-op.
162
+ this.logger.warn(`AuthService.revokeToken: failed to persist revoked token (${err.message}).`);
163
+ }
164
+ }
165
+ /** Whether a token has been revoked via {@link revokeToken}. */
166
+ async isTokenRevoked(token) {
167
+ if (!token)
168
+ return false;
169
+ let delegate;
170
+ try {
171
+ delegate = this.prisma.model('revokedToken');
172
+ }
173
+ catch {
174
+ // No denylist model — nothing can be revoked, so nothing is revoked.
175
+ return false;
176
+ }
177
+ try {
178
+ const row = await delegate.findFirst({ where: { token } });
179
+ return Boolean(row);
180
+ }
181
+ catch {
182
+ return false;
183
+ }
184
+ }
110
185
  async requestPasswordRecovery(email) {
111
186
  const user = await this.userDelegate().findFirst({ where: { email } }).catch(() => null);
112
187
  if (!user)
@@ -123,7 +198,7 @@ let AuthService = AuthService_1 = class AuthService {
123
198
  this.logger.warn(`AuthService: could not persist password reset token (${err.message}). ` +
124
199
  'Add a `PasswordResetToken` model to your Prisma schema to enable this feature.');
125
200
  }
126
- return { token };
201
+ return { token, user };
127
202
  }
128
203
  async resetPassword(email, token, newPassword) {
129
204
  let reset = null;
@@ -1 +1 @@
1
- {"version":3,"file":"auth.service.js","sourceRoot":"","sources":["../../src/services/auth.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.service.js","sourceRoot":"","sources":["../../src/services/auth.service.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,8 @@ export interface CreateInvitationInput {
5
5
  roleId: number;
6
6
  organization: any;
7
7
  invitedBy: any;
8
+ /** The group the invitee will join (design §8). NULL = wildcard membership. */
9
+ routeGroup?: string | null;
8
10
  }
9
11
  /**
10
12
  * Invitation lifecycle: create/resend/cancel/accept with token-based acceptance.
@@ -16,6 +18,8 @@ export declare class InvitationService {
16
18
  constructor(prisma: PrismaService, config: RhinoConfigService);
17
19
  private delegate;
18
20
  private generateToken;
21
+ /** Whether the inviter holds a membership row for `routeGroup` (wildcard ok). */
22
+ private inviterIsMember;
19
23
  private expiresAt;
20
24
  list(organizationId: number, status?: string): Promise<any>;
21
25
  create(input: CreateInvitationInput): Promise<any>;
@@ -26,10 +30,12 @@ export declare class InvitationService {
26
30
  organization: any;
27
31
  role: any;
28
32
  email: any;
33
+ routeGroup: any;
29
34
  accepted?: undefined;
30
35
  } | {
31
36
  accepted: boolean;
32
37
  organization: any;
38
+ routeGroup: any;
33
39
  requiresRegistration?: undefined;
34
40
  role?: undefined;
35
41
  email?: undefined;
@@ -14,6 +14,7 @@ const common_1 = require("@nestjs/common");
14
14
  const crypto_1 = require("crypto");
15
15
  const prisma_service_1 = require("../prisma/prisma.service");
16
16
  const rhino_config_1 = require("../rhino.config");
17
+ const rhino_exception_1 = require("../errors/rhino-exception");
17
18
  /**
18
19
  * Invitation lifecycle: create/resend/cancel/accept with token-based acceptance.
19
20
  * Mirrors Laravel's InvitationController + OrganizationInvitation model.
@@ -31,6 +32,21 @@ let InvitationService = class InvitationService {
31
32
  generateToken() {
32
33
  return (0, crypto_1.randomBytes)(32).toString('hex'); // 64 hex chars
33
34
  }
35
+ /** Whether the inviter holds a membership row for `routeGroup` (wildcard ok). */
36
+ inviterIsMember(inviter, routeGroup, org) {
37
+ const rows = inviter?.userRoles ?? inviter?.user_roles ?? [];
38
+ const orgId = org?.id ?? null;
39
+ for (const ur of rows) {
40
+ const rg = ur.routeGroup ?? ur.route_group ?? null;
41
+ if (rg !== null && String(rg) !== routeGroup)
42
+ continue;
43
+ const rowOrg = ur.organizationId ?? ur.organization_id ?? null;
44
+ if (orgId != null && rowOrg != null && rowOrg !== orgId)
45
+ continue;
46
+ return true;
47
+ }
48
+ return false;
49
+ }
34
50
  expiresAt() {
35
51
  const days = this.config.invitationsConfig().expiresDays;
36
52
  const d = new Date();
@@ -51,12 +67,35 @@ let InvitationService = class InvitationService {
51
67
  throw new common_1.BadRequestException('Role not allowed for invitations');
52
68
  }
53
69
  }
70
+ const routeGroup = input.routeGroup ?? null;
71
+ // The `public` group has no auth, so it cannot be invited into (design §8).
72
+ if (routeGroup === 'public') {
73
+ throw new common_1.BadRequestException('Cannot invite into the public group');
74
+ }
75
+ // When enforcement is on, the inviter must themselves be a member of the
76
+ // group they are inviting into (design §8). NULL (wildcard) skips this — a
77
+ // wildcard inviter can invite into any group.
78
+ if (this.config.enforceGroupMembership() && routeGroup != null) {
79
+ if (!this.inviterIsMember(input.invitedBy, routeGroup, input.organization)) {
80
+ // Coarse membership denial → 403 for parity with Laravel/Rails
81
+ // (Decision 9.C), matching the controller's gate.
82
+ throw rhino_exception_1.RhinoException.membershipDenied('You are not a member of that group');
83
+ }
84
+ }
85
+ // Tenant groups carry an org; non-tenant groups store a NULL org. Default
86
+ // to using the org (legacy behavior) — only drop it when enforcement is on
87
+ // AND the group is positively non-tenant, keeping flag-off paths unchanged.
88
+ const dropOrg = this.config.enforceGroupMembership() &&
89
+ routeGroup != null &&
90
+ !this.config.isTenantGroup(routeGroup);
91
+ const organizationId = dropOrg ? null : input.organization?.id ?? null;
54
92
  const token = this.generateToken();
55
93
  const invitation = await this.delegate().create({
56
94
  data: {
57
- organizationId: input.organization.id,
95
+ organizationId,
58
96
  email: input.email,
59
97
  roleId: input.roleId,
98
+ routeGroup,
60
99
  token,
61
100
  status: 'pending',
62
101
  invitedById: input.invitedBy.id,
@@ -110,6 +149,7 @@ let InvitationService = class InvitationService {
110
149
  await this.delegate().update({ where: { id: inv.id }, data: { status: 'expired' } });
111
150
  throw new common_1.BadRequestException('Invitation expired');
112
151
  }
152
+ const routeGroup = inv.routeGroup ?? inv.route_group ?? null;
113
153
  if (!userId) {
114
154
  // User is unauthenticated — return org/role so client can register
115
155
  return {
@@ -117,13 +157,15 @@ let InvitationService = class InvitationService {
117
157
  organization: inv.organization,
118
158
  role: inv.role,
119
159
  email: inv.email,
160
+ routeGroup,
120
161
  };
121
162
  }
122
163
  await this.prisma.model('userRole').create({
123
164
  data: {
124
165
  userId,
125
- organizationId: inv.organizationId,
166
+ organizationId: inv.organizationId ?? null,
126
167
  roleId: inv.roleId,
168
+ routeGroup,
127
169
  permissions: [],
128
170
  },
129
171
  });
@@ -131,7 +173,7 @@ let InvitationService = class InvitationService {
131
173
  where: { id: inv.id },
132
174
  data: { status: 'accepted', acceptedAt: new Date() },
133
175
  });
134
- return { accepted: true, organization: inv.organization };
176
+ return { accepted: true, organization: inv.organization, routeGroup };
135
177
  }
136
178
  };
137
179
  exports.InvitationService = InvitationService;
@@ -1 +1 @@
1
- {"version":3,"file":"invitation.service.js","sourceRoot":"","sources":["../../src/services/invitation.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"invitation.service.js","sourceRoot":"","sources":["../../src/services/invitation.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import { RhinoConfigService } from '../rhino.config';
2
+ /**
3
+ * A single `user_roles` membership row, normalized across snake_case /
4
+ * camelCase shapes (Prisma vs raw SQL). `routeGroup === null` is a WILDCARD
5
+ * (Decision 9.B) — the row is a member of every group.
6
+ */
7
+ export interface MembershipRow {
8
+ routeGroup: string | null;
9
+ organizationId: number | string | null;
10
+ permissions: unknown;
11
+ role?: any;
12
+ }
13
+ /**
14
+ * Membership enforcement & permission resolution (design §6).
15
+ *
16
+ * Gated entirely by `auth.enforceGroupMembership`:
17
+ * - OFF (default): {@link enabled} is `false`; callers skip every check and
18
+ * fall back to the legacy org-presence heuristic. Behavior is unchanged.
19
+ * - ON: a user must hold a `user_roles` row whose `route_group` matches the
20
+ * request's group (a NULL row is a wildcard) and — for tenant groups — whose
21
+ * organization matches the resolved org. Permissions then resolve from that
22
+ * matched row only.
23
+ *
24
+ * Membership is a COARSE gate (may you enter the group); the ResourcePolicy
25
+ * remains the FINE check. They run in sequence and are never merged.
26
+ */
27
+ export declare class MembershipService {
28
+ private readonly config;
29
+ constructor(config: RhinoConfigService);
30
+ /** Whether membership enforcement is active at all. */
31
+ enabled(): boolean;
32
+ private userRoles;
33
+ /**
34
+ * Find the membership rows that admit `user` into `routeGroup` for the given
35
+ * organization. A row matches when:
36
+ * - its `route_group` is NULL (wildcard) OR equals `routeGroup`, AND
37
+ * - for tenant groups, its organization equals the resolved org's id
38
+ * (NULL-org wildcard rows still match); for non-tenant groups the org is
39
+ * ignored entirely.
40
+ */
41
+ matchingRows(user: any, routeGroup: string | null | undefined, organization: {
42
+ id: number | string;
43
+ } | null | undefined, isTenant: boolean): MembershipRow[];
44
+ /**
45
+ * Whether `user` is a member of `routeGroup` (for the resolved org, when the
46
+ * group is a tenant group). Only meaningful when {@link enabled}.
47
+ */
48
+ isMember(user: any, routeGroup: string | null | undefined, organization: {
49
+ id: number | string;
50
+ } | null | undefined, isTenant: boolean): boolean;
51
+ /**
52
+ * Permissions granted to the user from the matched membership rows only
53
+ * (design §6: "permissions then resolve from that matching membership row").
54
+ */
55
+ permissionsFromRows(rows: MembershipRow[]): string[];
56
+ }