@dudousxd/nestjs-authz 0.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 (55) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/dist/context-accessor.d.ts +31 -0
  4. package/dist/context-accessor.d.ts.map +1 -0
  5. package/dist/context-accessor.js +2 -0
  6. package/dist/context-accessor.js.map +1 -0
  7. package/dist/decorator/can.decorator.d.ts +29 -0
  8. package/dist/decorator/can.decorator.d.ts.map +1 -0
  9. package/dist/decorator/can.decorator.js +23 -0
  10. package/dist/decorator/can.decorator.js.map +1 -0
  11. package/dist/decorator/policy.decorator.d.ts +18 -0
  12. package/dist/decorator/policy.decorator.d.ts.map +1 -0
  13. package/dist/decorator/policy.decorator.js +28 -0
  14. package/dist/decorator/policy.decorator.js.map +1 -0
  15. package/dist/errors/exceptions.d.ts +37 -0
  16. package/dist/errors/exceptions.d.ts.map +1 -0
  17. package/dist/errors/exceptions.js +53 -0
  18. package/dist/errors/exceptions.js.map +1 -0
  19. package/dist/gate.d.ts +81 -0
  20. package/dist/gate.d.ts.map +1 -0
  21. package/dist/gate.js +247 -0
  22. package/dist/gate.js.map +1 -0
  23. package/dist/guard/can.guard.d.ts +31 -0
  24. package/dist/guard/can.guard.d.ts.map +1 -0
  25. package/dist/guard/can.guard.js +92 -0
  26. package/dist/guard/can.guard.js.map +1 -0
  27. package/dist/index.d.ts +16 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +11 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/module.d.ts +20 -0
  32. package/dist/module.d.ts.map +1 -0
  33. package/dist/module.js +194 -0
  34. package/dist/module.js.map +1 -0
  35. package/dist/permission-provider.d.ts +23 -0
  36. package/dist/permission-provider.d.ts.map +1 -0
  37. package/dist/permission-provider.js +2 -0
  38. package/dist/permission-provider.js.map +1 -0
  39. package/dist/policy-registry.d.ts +23 -0
  40. package/dist/policy-registry.d.ts.map +1 -0
  41. package/dist/policy-registry.js +49 -0
  42. package/dist/policy-registry.js.map +1 -0
  43. package/dist/resource-resolver.d.ts +29 -0
  44. package/dist/resource-resolver.d.ts.map +1 -0
  45. package/dist/resource-resolver.js +24 -0
  46. package/dist/resource-resolver.js.map +1 -0
  47. package/dist/tokens.d.ts +31 -0
  48. package/dist/tokens.d.ts.map +1 -0
  49. package/dist/tokens.js +31 -0
  50. package/dist/tokens.js.map +1 -0
  51. package/dist/types.d.ts +97 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +2 -0
  54. package/dist/types.js.map +1 -0
  55. package/package.json +71 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @dudousxd/nestjs-authz
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`51d2fbc`](https://github.com/DavideCarvalho/nestjs-authz/commit/51d2fbc6b966c101a6ff0675c42843f040e02703) - Initial release: Laravel-style authorization for NestJS — gates, `@Policy`/`@Can`, the `Gate` service, a default `:id` resource resolver, `before`/`superAdmin` hooks, optional `nestjs-context` current-user with `resolveUser` hydration, and a `PERMISSION_PROVIDER` seam. The `@dudousxd/nestjs-authz-typeorm` adapter adds opt-in RBAC persistence (roles/permissions store, dialect-correct SQL, identifier allowlist, non-destructive schema auto-manage).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Davi Carvalho
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Local, structural mirror of `@dudousxd/nestjs-context`'s public accessor
3
+ * (`packages/core/src/accessor.ts`).
4
+ *
5
+ * We deliberately do NOT import nestjs-context (it is an OPTIONAL peer). Instead
6
+ * we declare the same shape here and inject it via the shared
7
+ * {@link CONTEXT_ACCESSOR} token with `@Optional()`. Any object that structurally
8
+ * satisfies this interface — including nestjs-context's real accessor — works.
9
+ *
10
+ * Kept byte-aligned with nestjs-context's `ContextAccessor`: `traceId()` /
11
+ * `tenantId()` are REQUIRED (the real accessor always provides them) and `get()`
12
+ * is included, so a future authz use of `tenantId()`/`get()` is type-safe and
13
+ * the structural match stays exact.
14
+ */
15
+ export interface UserRef {
16
+ type: string;
17
+ id: string | number;
18
+ }
19
+ /** Opaque shape of the context store. authz never reads it; mirrors the upstream surface. */
20
+ export type ContextStore = Record<string, unknown>;
21
+ export interface ContextAccessor {
22
+ /** Trace id for the current request, or `undefined` when unavailable. */
23
+ traceId(): string | undefined;
24
+ /** Current tenant id, or `undefined` when no multi-tenant context is populated. */
25
+ tenantId(): string | undefined;
26
+ /** Reference to the current user, or `undefined` when unauthenticated. */
27
+ userRef(): UserRef | undefined;
28
+ /** The raw context store for the current request, or `undefined`. */
29
+ get(): ContextStore | undefined;
30
+ }
31
+ //# sourceMappingURL=context-accessor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-accessor.d.ts","sourceRoot":"","sources":["../src/context-accessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AAED,6FAA6F;AAC7F,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,OAAO,IAAI,MAAM,GAAG,SAAS,CAAC;IAC9B,mFAAmF;IACnF,QAAQ,IAAI,MAAM,GAAG,SAAS,CAAC;IAC/B,0EAA0E;IAC1E,OAAO,IAAI,OAAO,GAAG,SAAS,CAAC;IAC/B,qEAAqE;IACrE,GAAG,IAAI,YAAY,GAAG,SAAS,CAAC;CACjC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context-accessor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-accessor.js","sourceRoot":"","sources":["../src/context-accessor.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ import 'reflect-metadata';
2
+ import { type Type } from '@nestjs/common';
3
+ export interface CanOptions {
4
+ /**
5
+ * Class-level ability (e.g. `create`): the policy method is keyed to the
6
+ * resource class but receives NO instance, so the guard skips resource loading.
7
+ */
8
+ classLevel?: boolean;
9
+ }
10
+ export interface CanMetadata {
11
+ ability: string;
12
+ /** Resource class — to load an instance, or (for class-level) to locate the policy. */
13
+ resource?: Type<unknown>;
14
+ /** When true, skip resource loading and dispatch against the resource class. */
15
+ classLevel?: boolean;
16
+ }
17
+ /**
18
+ * Guard a route with an authorization check.
19
+ *
20
+ * @example
21
+ * `@Can('update', Post)` // resolve Post by :id, run PostPolicy.update(user, post)
22
+ * `@Can('create', Post, { classLevel: true })` // run PostPolicy.create(user) — no instance loaded
23
+ * `@Can('access-admin')` // ad-hoc gate, no resource
24
+ *
25
+ * When a resource class is provided (and not `classLevel`), the guard loads an
26
+ * instance via the registered `ResourceResolver` (default: by route `:id`).
27
+ */
28
+ export declare function Can(ability: string, resource?: Type<unknown>, options?: CanOptions): MethodDecorator & ClassDecorator;
29
+ //# sourceMappingURL=can.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"can.decorator.d.ts","sourceRoot":"","sources":["../../src/decorator/can.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAe,KAAK,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAGxD,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,gFAAgF;IAChF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,GAAG,CACjB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,EACxB,OAAO,CAAC,EAAE,UAAU,GACnB,eAAe,GAAG,cAAc,CAKlC"}
@@ -0,0 +1,23 @@
1
+ import 'reflect-metadata';
2
+ import { SetMetadata } from '@nestjs/common';
3
+ import { CAN_METADATA } from '../tokens.js';
4
+ /**
5
+ * Guard a route with an authorization check.
6
+ *
7
+ * @example
8
+ * `@Can('update', Post)` // resolve Post by :id, run PostPolicy.update(user, post)
9
+ * `@Can('create', Post, { classLevel: true })` // run PostPolicy.create(user) — no instance loaded
10
+ * `@Can('access-admin')` // ad-hoc gate, no resource
11
+ *
12
+ * When a resource class is provided (and not `classLevel`), the guard loads an
13
+ * instance via the registered `ResourceResolver` (default: by route `:id`).
14
+ */
15
+ export function Can(ability, resource, options) {
16
+ const meta = { ability };
17
+ if (resource !== undefined)
18
+ meta.resource = resource;
19
+ if (options?.classLevel)
20
+ meta.classLevel = true;
21
+ return SetMetadata(CAN_METADATA, meta);
22
+ }
23
+ //# sourceMappingURL=can.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"can.decorator.js","sourceRoot":"","sources":["../../src/decorator/can.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAa,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAkB5C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,GAAG,CACjB,OAAe,EACf,QAAwB,EACxB,OAAoB;IAEpB,MAAM,IAAI,GAAgB,EAAE,OAAO,EAAE,CAAC;IACtC,IAAI,QAAQ,KAAK,SAAS;QAAE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACrD,IAAI,OAAO,EAAE,UAAU;QAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IAChD,OAAO,WAAW,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import 'reflect-metadata';
2
+ import { type Type } from '@nestjs/common';
3
+ /**
4
+ * Marks a class as the policy for `resource`. The class methods become abilities
5
+ * dispatched by name (e.g. `update(user, post)` answers `gate.authorize('update', post)`).
6
+ *
7
+ * Applying `@Policy` also makes the class an `@Injectable()` provider so it can
8
+ * be auto-discovered and resolved from the Nest container.
9
+ */
10
+ export declare function Policy(resource: Type<unknown>): ClassDecorator;
11
+ /**
12
+ * Returns the resource class a policy was declared for, or `undefined`.
13
+ *
14
+ * Uses `getMetadata` (not `getOwnMetadata`) so a subclass of a `@Policy`-decorated
15
+ * class still resolves the inherited resource via the prototype chain.
16
+ */
17
+ export declare function getPolicyResource(policy: Type<unknown> | object): Type<unknown> | undefined;
18
+ //# sourceMappingURL=policy.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.decorator.d.ts","sourceRoot":"","sources":["../../src/decorator/policy.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAIvD;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,cAAc,CAM9D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,SAAS,CAG3F"}
@@ -0,0 +1,28 @@
1
+ import 'reflect-metadata';
2
+ import { Injectable } from '@nestjs/common';
3
+ import { POLICY_RESOURCE_METADATA } from '../tokens.js';
4
+ /**
5
+ * Marks a class as the policy for `resource`. The class methods become abilities
6
+ * dispatched by name (e.g. `update(user, post)` answers `gate.authorize('update', post)`).
7
+ *
8
+ * Applying `@Policy` also makes the class an `@Injectable()` provider so it can
9
+ * be auto-discovered and resolved from the Nest container.
10
+ */
11
+ export function Policy(resource) {
12
+ return (target) => {
13
+ Reflect.defineMetadata(POLICY_RESOURCE_METADATA, resource, target);
14
+ // Make the policy a provider without forcing the app to add @Injectable().
15
+ Injectable()(target);
16
+ };
17
+ }
18
+ /**
19
+ * Returns the resource class a policy was declared for, or `undefined`.
20
+ *
21
+ * Uses `getMetadata` (not `getOwnMetadata`) so a subclass of a `@Policy`-decorated
22
+ * class still resolves the inherited resource via the prototype chain.
23
+ */
24
+ export function getPolicyResource(policy) {
25
+ const ctor = typeof policy === 'function' ? policy : policy.constructor;
26
+ return Reflect.getMetadata(POLICY_RESOURCE_METADATA, ctor);
27
+ }
28
+ //# sourceMappingURL=policy.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.decorator.js","sourceRoot":"","sources":["../../src/decorator/policy.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAa,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAGxD;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,QAAuB;IAC5C,OAAO,CAAC,MAAM,EAAE,EAAE;QAChB,OAAO,CAAC,cAAc,CAAC,wBAAwB,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QACnE,2EAA2E;QAC3E,UAAU,EAAE,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAA8B;IAC9D,MAAM,IAAI,GAAG,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,MAAyB,CAAC,WAAW,CAAC;IAC5F,OAAO,OAAO,CAAC,WAAW,CAAC,wBAAwB,EAAE,IAAI,CAA8B,CAAC;AAC1F,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { BadRequestException } from '@nestjs/common';
2
+ export declare abstract class AuthzException extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export declare class PolicyNotDecoratedException extends AuthzException {
6
+ readonly policyName: string;
7
+ constructor(policyName: string);
8
+ }
9
+ /**
10
+ * Thrown when an ability cannot be matched to any policy method or ad-hoc gate.
11
+ *
12
+ * This is a *programming* error (typically a typo'd ability name), not an
13
+ * authorization denial — so it maps to a `400 Bad Request` HttpException rather
14
+ * than surfacing as a 500. (A genuine denial throws `ForbiddenException` → 403.)
15
+ */
16
+ export declare class AbilityNotResolvedException extends BadRequestException {
17
+ readonly ability: string;
18
+ readonly name = "AbilityNotResolvedException";
19
+ constructor(ability: string);
20
+ }
21
+ /**
22
+ * Thrown when a class-level ability (`gate.allows('create')`, no resource) is
23
+ * ambiguous: more than one registered policy defines a method with that name, so
24
+ * picking one by Map-insertion order would be a silent, arbitrary choice. Pass an
25
+ * explicit resource class (`gate.allows('create', Post)`) to disambiguate.
26
+ */
27
+ export declare class AmbiguousAbilityException extends BadRequestException {
28
+ readonly ability: string;
29
+ readonly policyNames: string[];
30
+ readonly name = "AmbiguousAbilityException";
31
+ constructor(ability: string, policyNames: string[]);
32
+ }
33
+ export declare class ResourceResolverMissingException extends AuthzException {
34
+ readonly ability: string;
35
+ constructor(ability: string);
36
+ }
37
+ //# sourceMappingURL=exceptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../../src/errors/exceptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,8BAAsB,cAAe,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,2BAA4B,SAAQ,cAAc;aACjC,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAG/C;AAED;;;;;;GAMG;AACH,qBAAa,2BAA4B,SAAQ,mBAAmB;aAEtC,OAAO,EAAE,MAAM;IAD3C,SAAkB,IAAI,iCAAiC;gBAC3B,OAAO,EAAE,MAAM;CAK5C;AAED;;;;;GAKG;AACH,qBAAa,yBAA0B,SAAQ,mBAAmB;aAG9C,OAAO,EAAE,MAAM;aACf,WAAW,EAAE,MAAM,EAAE;IAHvC,SAAkB,IAAI,+BAA+B;gBAEnC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE;CAQxC;AAED,qBAAa,gCAAiC,SAAQ,cAAc;aACtC,OAAO,EAAE,MAAM;gBAAf,OAAO,EAAE,MAAM;CAK5C"}
@@ -0,0 +1,53 @@
1
+ import { BadRequestException } from '@nestjs/common';
2
+ export class AuthzException extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = new.target.name;
6
+ }
7
+ }
8
+ export class PolicyNotDecoratedException extends AuthzException {
9
+ policyName;
10
+ constructor(policyName) {
11
+ super(`${policyName} is missing @Policy(Resource). Decorate it with the resource class.`);
12
+ this.policyName = policyName;
13
+ }
14
+ }
15
+ /**
16
+ * Thrown when an ability cannot be matched to any policy method or ad-hoc gate.
17
+ *
18
+ * This is a *programming* error (typically a typo'd ability name), not an
19
+ * authorization denial — so it maps to a `400 Bad Request` HttpException rather
20
+ * than surfacing as a 500. (A genuine denial throws `ForbiddenException` → 403.)
21
+ */
22
+ export class AbilityNotResolvedException extends BadRequestException {
23
+ ability;
24
+ name = 'AbilityNotResolvedException';
25
+ constructor(ability) {
26
+ super(`Ability "${ability}" could not be resolved. No matching policy method or gate.define('${ability}', ...).`);
27
+ this.ability = ability;
28
+ }
29
+ }
30
+ /**
31
+ * Thrown when a class-level ability (`gate.allows('create')`, no resource) is
32
+ * ambiguous: more than one registered policy defines a method with that name, so
33
+ * picking one by Map-insertion order would be a silent, arbitrary choice. Pass an
34
+ * explicit resource class (`gate.allows('create', Post)`) to disambiguate.
35
+ */
36
+ export class AmbiguousAbilityException extends BadRequestException {
37
+ ability;
38
+ policyNames;
39
+ name = 'AmbiguousAbilityException';
40
+ constructor(ability, policyNames) {
41
+ super(`Ability "${ability}" is ambiguous: it is defined by multiple policies (${policyNames.join(', ')}). Pass the resource class explicitly, e.g. gate.allows('${ability}', Resource).`);
42
+ this.ability = ability;
43
+ this.policyNames = policyNames;
44
+ }
45
+ }
46
+ export class ResourceResolverMissingException extends AuthzException {
47
+ ability;
48
+ constructor(ability) {
49
+ super(`@Can('${ability}', Resource) needs an instance but no ResourceResolver is registered. Register one via AuthzModule.forRoot or pass the resource programmatically.`);
50
+ this.ability = ability;
51
+ }
52
+ }
53
+ //# sourceMappingURL=exceptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exceptions.js","sourceRoot":"","sources":["../../src/errors/exceptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,OAAgB,cAAe,SAAQ,KAAK;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,2BAA4B,SAAQ,cAAc;IACjC;IAA5B,YAA4B,UAAkB;QAC5C,KAAK,CAAC,GAAG,UAAU,qEAAqE,CAAC,CAAC;QADhE,eAAU,GAAV,UAAU,CAAQ;IAE9C,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,2BAA4B,SAAQ,mBAAmB;IAEtC;IADV,IAAI,GAAG,6BAA6B,CAAC;IACvD,YAA4B,OAAe;QACzC,KAAK,CACH,YAAY,OAAO,sEAAsE,OAAO,UAAU,CAC3G,CAAC;QAHwB,YAAO,GAAP,OAAO,CAAQ;IAI3C,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,yBAA0B,SAAQ,mBAAmB;IAG9C;IACA;IAHA,IAAI,GAAG,2BAA2B,CAAC;IACrD,YACkB,OAAe,EACf,WAAqB;QAErC,KAAK,CACH,YAAY,OAAO,uDAAuD,WAAW,CAAC,IAAI,CACxF,IAAI,CACL,4DAA4D,OAAO,eAAe,CACpF,CAAC;QAPc,YAAO,GAAP,OAAO,CAAQ;QACf,gBAAW,GAAX,WAAW,CAAU;IAOvC,CAAC;CACF;AAED,MAAM,OAAO,gCAAiC,SAAQ,cAAc;IACtC;IAA5B,YAA4B,OAAe;QACzC,KAAK,CACH,SAAS,OAAO,mJAAmJ,CACpK,CAAC;QAHwB,YAAO,GAAP,OAAO,CAAQ;IAI3C,CAAC;CACF"}
package/dist/gate.d.ts ADDED
@@ -0,0 +1,81 @@
1
+ import { ModuleRef } from '@nestjs/core';
2
+ import type { ContextAccessor } from './context-accessor.js';
3
+ import type { PermissionProvider } from './permission-provider.js';
4
+ import { PolicyRegistry } from './policy-registry.js';
5
+ import type { AuthzModuleOptions, GateFn, Resource, User } from './types.js';
6
+ declare const NO_USER: unique symbol;
7
+ type MaybeUser = User | typeof NO_USER;
8
+ /**
9
+ * Laravel-style authorization Gate.
10
+ *
11
+ * Resolves an ability against either a registered `@Policy` method (by ability
12
+ * name, matched against the resource's policy) or an ad-hoc gate defined via
13
+ * {@link define}. Applies the global `superAdmin` before-hook and the per-policy
14
+ * `before` hook with short-circuit semantics.
15
+ *
16
+ * The current user comes from the optional {@link ContextAccessor} (nestjs-context)
17
+ * when present, or is supplied explicitly via {@link forUser}.
18
+ */
19
+ export declare class Gate {
20
+ private readonly policies;
21
+ private readonly context?;
22
+ private readonly moduleRef?;
23
+ private readonly permissionProvider?;
24
+ private readonly gates;
25
+ private readonly superAdmin;
26
+ private readonly resolveUser;
27
+ constructor(policies: PolicyRegistry, options: AuthzModuleOptions | undefined, context?: ContextAccessor | undefined, moduleRef?: ModuleRef | undefined, permissionProvider?: PermissionProvider | undefined);
28
+ /**
29
+ * Locate the context accessor. Prefers the value injected into this module;
30
+ * falls back to a non-strict {@link ModuleRef} lookup so an accessor provided
31
+ * by ANY module (e.g. a global ContextModule, or the app root) is still found.
32
+ */
33
+ private resolveContext;
34
+ /**
35
+ * Locate the optional {@link PermissionProvider} (the RBAC seam). Prefers the value
36
+ * injected into this module; falls back to a non-strict {@link ModuleRef} lookup so a
37
+ * provider registered by ANY module (e.g. the RBAC adapter's global module) is found.
38
+ */
39
+ private resolvePermissionProvider;
40
+ /** Register an ad-hoc, model-less gate resolved by `ability` name. */
41
+ define(ability: string, fn: GateFn): this;
42
+ /** True when an ad-hoc gate is registered for `ability`. */
43
+ hasGate(ability: string): boolean;
44
+ /**
45
+ * Bind an explicit user, bypassing the context accessor. Use when no
46
+ * nestjs-context is wired, or to check a user other than the current one.
47
+ *
48
+ * A nullish user (`forUser(undefined)` / `forUser(null)`) is an explicit
49
+ * anonymous request: it maps to the same deny path as an unauthenticated
50
+ * context (`NO_USER`), so policies/gates are never invoked with `undefined` and
51
+ * never throw. The `resolveUser` hook is NOT applied to `forUser` — the value
52
+ * you pass is used verbatim.
53
+ */
54
+ forUser(user: User): BoundGate;
55
+ /**
56
+ * Resolve the current user from the context accessor, or `NO_USER`.
57
+ * When a `resolveUser` hook is configured, hydrate the full entity from the
58
+ * context's {@link UserRef}; a hook returning nullish maps to `NO_USER`.
59
+ */
60
+ private currentUser;
61
+ allows(ability: string, resource?: Resource): Promise<boolean>;
62
+ denies(ability: string, resource?: Resource): Promise<boolean>;
63
+ authorize(ability: string, resource?: Resource): Promise<void>;
64
+ /** @internal */
65
+ allowsForUser(user: MaybeUser, ability: string, resource?: Resource): Promise<boolean>;
66
+ private check;
67
+ private resolvePolicy;
68
+ }
69
+ /**
70
+ * A {@link Gate} bound to an explicit user. Returned by {@link Gate.forUser}.
71
+ */
72
+ export declare class BoundGate {
73
+ private readonly gate;
74
+ private readonly user;
75
+ constructor(gate: Gate, user: MaybeUser);
76
+ allows(ability: string, resource?: Resource): Promise<boolean>;
77
+ denies(ability: string, resource?: Resource): Promise<boolean>;
78
+ authorize(ability: string, resource?: Resource): Promise<void>;
79
+ }
80
+ export {};
81
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,eAAe,EAAW,MAAM,uBAAuB,CAAC;AAEtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,KAAK,EACV,kBAAkB,EAClB,MAAM,EAGN,QAAQ,EAER,IAAI,EACL,MAAM,YAAY,CAAC;AAIpB,QAAA,MAAM,OAAO,eAA0B,CAAC;AACxC,KAAK,SAAS,GAAG,IAAI,GAAG,OAAO,OAAO,CAAC;AAEvC;;;;;;;;;;GAUG;AACH,qBACa,IAAI;IAMb,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAMzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAEzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAG3B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IAhBtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoC;gBAG7C,QAAQ,EAAE,cAAc,EAGzC,OAAO,EAAE,kBAAkB,GAAG,SAAS,EAGtB,OAAO,CAAC,EAAE,eAAe,YAAA,EAEzB,SAAS,CAAC,EAAE,SAAS,YAAA,EAGrB,kBAAkB,CAAC,EAAE,kBAAkB,YAAA;IAM1D;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAUtB;;;;OAIG;IACH,OAAO,CAAC,yBAAyB;IAUjC,sEAAsE;IACtE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAKzC,4DAA4D;IAC5D,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIjC;;;;;;;;;OASG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS;IAI9B;;;;OAIG;YACW,WAAW;IAcnB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9D,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9D,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpE,gBAAgB;IAChB,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAIxE,KAAK;IAsDnB,OAAO,CAAC,aAAa;CAwBtB;AAED;;GAEG;AACH,qBAAa,SAAS;IAElB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADJ,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,SAAS;IAGlC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAIxD,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9D,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CAKrE"}
package/dist/gate.js ADDED
@@ -0,0 +1,247 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { ForbiddenException, Inject, Injectable, Optional } from '@nestjs/common';
14
+ import { ModuleRef } from '@nestjs/core';
15
+ import { AbilityNotResolvedException, AmbiguousAbilityException } from './errors/exceptions.js';
16
+ import { PolicyRegistry } from './policy-registry.js';
17
+ import { AUTHZ_MODULE_OPTIONS, CONTEXT_ACCESSOR, PERMISSION_PROVIDER } from './tokens.js';
18
+ // A sentinel marking "no user resolved" distinct from a legitimately-`undefined`
19
+ // user. `forUser(undefined)` explicitly authorizes an anonymous user.
20
+ const NO_USER = Symbol('authz:no-user');
21
+ /**
22
+ * Laravel-style authorization Gate.
23
+ *
24
+ * Resolves an ability against either a registered `@Policy` method (by ability
25
+ * name, matched against the resource's policy) or an ad-hoc gate defined via
26
+ * {@link define}. Applies the global `superAdmin` before-hook and the per-policy
27
+ * `before` hook with short-circuit semantics.
28
+ *
29
+ * The current user comes from the optional {@link ContextAccessor} (nestjs-context)
30
+ * when present, or is supplied explicitly via {@link forUser}.
31
+ */
32
+ let Gate = class Gate {
33
+ policies;
34
+ context;
35
+ moduleRef;
36
+ permissionProvider;
37
+ gates = new Map();
38
+ superAdmin;
39
+ resolveUser;
40
+ constructor(policies, options, context, moduleRef, permissionProvider) {
41
+ this.policies = policies;
42
+ this.context = context;
43
+ this.moduleRef = moduleRef;
44
+ this.permissionProvider = permissionProvider;
45
+ this.superAdmin = options?.superAdmin;
46
+ this.resolveUser = options?.resolveUser;
47
+ }
48
+ /**
49
+ * Locate the context accessor. Prefers the value injected into this module;
50
+ * falls back to a non-strict {@link ModuleRef} lookup so an accessor provided
51
+ * by ANY module (e.g. a global ContextModule, or the app root) is still found.
52
+ */
53
+ resolveContext() {
54
+ if (this.context)
55
+ return this.context;
56
+ if (!this.moduleRef)
57
+ return undefined;
58
+ try {
59
+ return this.moduleRef.get(CONTEXT_ACCESSOR, { strict: false });
60
+ }
61
+ catch {
62
+ return undefined;
63
+ }
64
+ }
65
+ /**
66
+ * Locate the optional {@link PermissionProvider} (the RBAC seam). Prefers the value
67
+ * injected into this module; falls back to a non-strict {@link ModuleRef} lookup so a
68
+ * provider registered by ANY module (e.g. the RBAC adapter's global module) is found.
69
+ */
70
+ resolvePermissionProvider() {
71
+ if (this.permissionProvider)
72
+ return this.permissionProvider;
73
+ if (!this.moduleRef)
74
+ return undefined;
75
+ try {
76
+ return this.moduleRef.get(PERMISSION_PROVIDER, { strict: false });
77
+ }
78
+ catch {
79
+ return undefined;
80
+ }
81
+ }
82
+ /** Register an ad-hoc, model-less gate resolved by `ability` name. */
83
+ define(ability, fn) {
84
+ this.gates.set(ability, fn);
85
+ return this;
86
+ }
87
+ /** True when an ad-hoc gate is registered for `ability`. */
88
+ hasGate(ability) {
89
+ return this.gates.has(ability);
90
+ }
91
+ /**
92
+ * Bind an explicit user, bypassing the context accessor. Use when no
93
+ * nestjs-context is wired, or to check a user other than the current one.
94
+ *
95
+ * A nullish user (`forUser(undefined)` / `forUser(null)`) is an explicit
96
+ * anonymous request: it maps to the same deny path as an unauthenticated
97
+ * context (`NO_USER`), so policies/gates are never invoked with `undefined` and
98
+ * never throw. The `resolveUser` hook is NOT applied to `forUser` — the value
99
+ * you pass is used verbatim.
100
+ */
101
+ forUser(user) {
102
+ return new BoundGate(this, user == null ? NO_USER : user);
103
+ }
104
+ /**
105
+ * Resolve the current user from the context accessor, or `NO_USER`.
106
+ * When a `resolveUser` hook is configured, hydrate the full entity from the
107
+ * context's {@link UserRef}; a hook returning nullish maps to `NO_USER`.
108
+ */
109
+ async currentUser() {
110
+ const context = this.resolveContext();
111
+ if (!context)
112
+ return NO_USER;
113
+ const ref = context.userRef();
114
+ if (ref === undefined)
115
+ return NO_USER;
116
+ if (this.resolveUser) {
117
+ const hydrated = await this.resolveUser(ref);
118
+ return hydrated == null ? NO_USER : hydrated;
119
+ }
120
+ return ref;
121
+ }
122
+ // --- public API (operates on the current/context user) ---
123
+ async allows(ability, resource) {
124
+ return this.check(await this.currentUser(), ability, resource);
125
+ }
126
+ async denies(ability, resource) {
127
+ return !(await this.allows(ability, resource));
128
+ }
129
+ async authorize(ability, resource) {
130
+ if (!(await this.allows(ability, resource))) {
131
+ throw new ForbiddenException(`Unauthorized: ${ability}`);
132
+ }
133
+ }
134
+ // --- internal: used by BoundGate too ---
135
+ /** @internal */
136
+ allowsForUser(user, ability, resource) {
137
+ return this.check(user, ability, resource);
138
+ }
139
+ async check(maybeUser, ability, resource) {
140
+ const user = maybeUser === NO_USER ? undefined : maybeUser;
141
+ // Global super-admin hook first.
142
+ const sa = await this.superAdmin?.(user, ability);
143
+ if (sa === true)
144
+ return true;
145
+ if (sa === false)
146
+ return false;
147
+ // RBAC seam (Laravel/spatie `Gate::before` grant): if a PermissionProvider is
148
+ // registered and the (authenticated) user holds the named permission, grant it.
149
+ // Grant-only — a `false`/`undefined` result falls through to normal resolution,
150
+ // so this never *denies* an ability a policy/gate would otherwise allow.
151
+ if (maybeUser !== NO_USER) {
152
+ const provider = this.resolvePermissionProvider();
153
+ if (provider) {
154
+ const granted = await provider.hasPermission(user, ability, resource);
155
+ if (granted === true)
156
+ return true;
157
+ }
158
+ }
159
+ const policy = this.resolvePolicy(ability, resource);
160
+ if (policy) {
161
+ const method = policy[ability];
162
+ // The `before` hook may only answer abilities the policy actually defines.
163
+ // Gate it on method existence FIRST so a policy with a `before` but no
164
+ // matching method falls through to AbilityNotResolved instead of letting
165
+ // `before` grant/deny an ability the policy never declared.
166
+ if (typeof method === 'function') {
167
+ const before = policy.before;
168
+ if (typeof before === 'function') {
169
+ const result = await before.call(policy, user, ability);
170
+ if (result === true)
171
+ return true;
172
+ if (result === false)
173
+ return false;
174
+ }
175
+ // Anonymous users are denied unless a hook granted access above.
176
+ if (maybeUser === NO_USER)
177
+ return false;
178
+ return Boolean(await method.call(policy, user, resource));
179
+ }
180
+ }
181
+ // Fall back to an ad-hoc gate.
182
+ const gate = this.gates.get(ability);
183
+ if (gate) {
184
+ if (maybeUser === NO_USER)
185
+ return false;
186
+ return Boolean(await gate(user, resource));
187
+ }
188
+ throw new AbilityNotResolvedException(ability);
189
+ }
190
+ resolvePolicy(ability, resource) {
191
+ if (resource === undefined) {
192
+ // Class-level ability with no resource: scan registered policies for the
193
+ // method. If MORE THAN ONE policy defines it, picking by Map-insertion
194
+ // order would be a silent, arbitrary (and likely wrong) choice — throw so
195
+ // the caller disambiguates by passing the resource class explicitly.
196
+ const matches = this.policies
197
+ .all()
198
+ .filter((policy) => typeof policy[ability] === 'function');
199
+ if (matches.length === 0)
200
+ return undefined;
201
+ if (matches.length > 1) {
202
+ throw new AmbiguousAbilityException(ability, matches.map((p) => p.constructor?.name ?? 'Policy'));
203
+ }
204
+ return matches[0];
205
+ }
206
+ // Resource may be an instance or a class (for class-level abilities passed as Type).
207
+ if (typeof resource === 'function') {
208
+ return this.policies.forResource(resource);
209
+ }
210
+ return this.policies.forInstance(resource);
211
+ }
212
+ };
213
+ Gate = __decorate([
214
+ Injectable(),
215
+ __param(1, Optional()),
216
+ __param(1, Inject(AUTHZ_MODULE_OPTIONS)),
217
+ __param(2, Optional()),
218
+ __param(2, Inject(CONTEXT_ACCESSOR)),
219
+ __param(3, Optional()),
220
+ __param(4, Optional()),
221
+ __param(4, Inject(PERMISSION_PROVIDER)),
222
+ __metadata("design:paramtypes", [PolicyRegistry, Object, Object, ModuleRef, Object])
223
+ ], Gate);
224
+ export { Gate };
225
+ /**
226
+ * A {@link Gate} bound to an explicit user. Returned by {@link Gate.forUser}.
227
+ */
228
+ export class BoundGate {
229
+ gate;
230
+ user;
231
+ constructor(gate, user) {
232
+ this.gate = gate;
233
+ this.user = user;
234
+ }
235
+ allows(ability, resource) {
236
+ return this.gate.allowsForUser(this.user, ability, resource);
237
+ }
238
+ async denies(ability, resource) {
239
+ return !(await this.allows(ability, resource));
240
+ }
241
+ async authorize(ability, resource) {
242
+ if (!(await this.allows(ability, resource))) {
243
+ throw new ForbiddenException(`Unauthorized: ${ability}`);
244
+ }
245
+ }
246
+ }
247
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}