@dudousxd/nestjs-authz 0.8.0 → 0.9.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 (132) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +279 -0
  3. package/dist/authz.guard.d.ts +48 -0
  4. package/dist/authz.guard.d.ts.map +1 -0
  5. package/dist/authz.guard.js +144 -0
  6. package/dist/authz.guard.js.map +1 -0
  7. package/dist/can-endpoint.controller.d.ts +0 -19
  8. package/dist/can-endpoint.controller.d.ts.map +1 -1
  9. package/dist/can-endpoint.controller.js +18 -9
  10. package/dist/can-endpoint.controller.js.map +1 -1
  11. package/dist/decision-provider.d.ts +25 -16
  12. package/dist/decision-provider.d.ts.map +1 -1
  13. package/dist/decision-provider.js +11 -1
  14. package/dist/decision-provider.js.map +1 -1
  15. package/dist/decisions.d.ts +24 -0
  16. package/dist/decisions.d.ts.map +1 -0
  17. package/dist/decisions.js +87 -0
  18. package/dist/decisions.js.map +1 -0
  19. package/dist/decorator/roles.decorator.d.ts +6 -12
  20. package/dist/decorator/roles.decorator.d.ts.map +1 -1
  21. package/dist/decorator/roles.decorator.js +13 -15
  22. package/dist/decorator/roles.decorator.js.map +1 -1
  23. package/dist/diagnostics.d.ts +15 -5
  24. package/dist/diagnostics.d.ts.map +1 -1
  25. package/dist/diagnostics.js +3 -1
  26. package/dist/diagnostics.js.map +1 -1
  27. package/dist/errors/exceptions.d.ts +0 -8
  28. package/dist/errors/exceptions.d.ts.map +1 -1
  29. package/dist/errors/exceptions.js +0 -14
  30. package/dist/errors/exceptions.js.map +1 -1
  31. package/dist/gate.d.ts +83 -209
  32. package/dist/gate.d.ts.map +1 -1
  33. package/dist/gate.js +209 -577
  34. package/dist/gate.js.map +1 -1
  35. package/dist/helpers.d.ts +46 -0
  36. package/dist/helpers.d.ts.map +1 -0
  37. package/dist/helpers.js +89 -0
  38. package/dist/helpers.js.map +1 -0
  39. package/dist/index.d.ts +28 -21
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +30 -13
  42. package/dist/index.js.map +1 -1
  43. package/dist/links.d.ts +39 -0
  44. package/dist/links.d.ts.map +1 -0
  45. package/dist/links.js +57 -0
  46. package/dist/links.js.map +1 -0
  47. package/dist/module.d.ts +23 -22
  48. package/dist/module.d.ts.map +1 -1
  49. package/dist/module.js +129 -158
  50. package/dist/module.js.map +1 -1
  51. package/dist/official.d.ts +39 -0
  52. package/dist/official.d.ts.map +1 -0
  53. package/dist/official.js +44 -0
  54. package/dist/official.js.map +1 -0
  55. package/dist/permission-cache.d.ts +18 -9
  56. package/dist/permission-cache.d.ts.map +1 -1
  57. package/dist/permission-cache.js +87 -24
  58. package/dist/permission-cache.js.map +1 -1
  59. package/dist/permission-matcher.d.ts +13 -0
  60. package/dist/permission-matcher.d.ts.map +1 -1
  61. package/dist/permission-matcher.js +38 -2
  62. package/dist/permission-matcher.js.map +1 -1
  63. package/dist/permission-provider.d.ts +11 -0
  64. package/dist/permission-provider.d.ts.map +1 -1
  65. package/dist/policies/authz-policy.d.ts +42 -0
  66. package/dist/policies/authz-policy.d.ts.map +1 -0
  67. package/dist/policies/authz-policy.js +80 -0
  68. package/dist/policies/authz-policy.js.map +1 -0
  69. package/dist/policies/gate.policy.d.ts +18 -0
  70. package/dist/policies/gate.policy.d.ts.map +1 -0
  71. package/dist/policies/gate.policy.js +37 -0
  72. package/dist/policies/gate.policy.js.map +1 -0
  73. package/dist/policies/index.d.ts +5 -0
  74. package/dist/policies/index.d.ts.map +1 -0
  75. package/dist/policies/index.js +5 -0
  76. package/dist/policies/index.js.map +1 -0
  77. package/dist/policies/permission.policy.d.ts +27 -0
  78. package/dist/policies/permission.policy.d.ts.map +1 -0
  79. package/dist/policies/permission.policy.js +61 -0
  80. package/dist/policies/permission.policy.js.map +1 -0
  81. package/dist/policies/role.policy.d.ts +27 -0
  82. package/dist/policies/role.policy.d.ts.map +1 -0
  83. package/dist/policies/role.policy.js +51 -0
  84. package/dist/policies/role.policy.js.map +1 -0
  85. package/dist/policy-index.d.ts +51 -0
  86. package/dist/policy-index.d.ts.map +1 -0
  87. package/dist/policy-index.js +135 -0
  88. package/dist/policy-index.js.map +1 -0
  89. package/dist/rbac.d.ts +92 -0
  90. package/dist/rbac.d.ts.map +1 -0
  91. package/dist/rbac.js +293 -0
  92. package/dist/rbac.js.map +1 -0
  93. package/dist/resource-resolver.d.ts +15 -17
  94. package/dist/resource-resolver.d.ts.map +1 -1
  95. package/dist/resource-resolver.js +8 -8
  96. package/dist/resource-resolver.js.map +1 -1
  97. package/dist/runtime.d.ts +31 -0
  98. package/dist/runtime.d.ts.map +1 -0
  99. package/dist/runtime.js +40 -0
  100. package/dist/runtime.js.map +1 -0
  101. package/dist/tokens.d.ts +4 -8
  102. package/dist/tokens.d.ts.map +1 -1
  103. package/dist/tokens.js +4 -8
  104. package/dist/tokens.js.map +1 -1
  105. package/dist/types.d.ts +52 -169
  106. package/dist/types.d.ts.map +1 -1
  107. package/package.json +19 -10
  108. package/skills/authz-enforcement/SKILL.md +67 -131
  109. package/skills/authz-policies/SKILL.md +43 -117
  110. package/skills/authz-query-scopes/SKILL.md +16 -9
  111. package/skills/authz-rbac-seams/SKILL.md +39 -12
  112. package/skills/authz-setup/SKILL.md +45 -106
  113. package/dist/decorator/can.decorator.d.ts +0 -29
  114. package/dist/decorator/can.decorator.d.ts.map +0 -1
  115. package/dist/decorator/can.decorator.js +0 -23
  116. package/dist/decorator/can.decorator.js.map +0 -1
  117. package/dist/decorator/policy.decorator.d.ts +0 -18
  118. package/dist/decorator/policy.decorator.d.ts.map +0 -1
  119. package/dist/decorator/policy.decorator.js +0 -28
  120. package/dist/decorator/policy.decorator.js.map +0 -1
  121. package/dist/guard/can.guard.d.ts +0 -31
  122. package/dist/guard/can.guard.d.ts.map +0 -1
  123. package/dist/guard/can.guard.js +0 -92
  124. package/dist/guard/can.guard.js.map +0 -1
  125. package/dist/guard/roles.guard.d.ts +0 -21
  126. package/dist/guard/roles.guard.d.ts.map +0 -1
  127. package/dist/guard/roles.guard.js +0 -50
  128. package/dist/guard/roles.guard.js.map +0 -1
  129. package/dist/policy-registry.d.ts +0 -46
  130. package/dist/policy-registry.d.ts.map +0 -1
  131. package/dist/policy-registry.js +0 -101
  132. package/dist/policy-registry.js.map +0 -1
@@ -1,29 +1,27 @@
1
1
  import type { ExecutionContext, Type } from '@nestjs/common';
2
+ /** Per-call hints `byId(Resource, { param })` passes to the resolver. */
3
+ export interface ResourceResolveHints {
4
+ /** The route param holding the id, when `byId` named one. */
5
+ param?: string;
6
+ }
2
7
  /**
3
- * Resolves a resource instance for a `@Can(ability, Resource)` route so the guard
4
- * can pass it to the policy method. Apps register an implementation (typically
5
- * ORM-backed) via `AuthzModule.forRoot({ ... })` or as a provider bound to the
6
- * {@link RESOURCE_RESOLVER} token.
7
- *
8
- * Class-level abilities (no resource class on `@Can`) never call the resolver.
8
+ * Loads the resource a `byId(Resource)` argument resolver hands to the policy
9
+ * (`@Can(PostPolicy, 'update', byId(Post))`). Register one, typically ORM-backed, with
10
+ * `AuthzModule.forRoot({ resourceResolver })`. Return `undefined` for "not found":
11
+ * `byId` then refuses the call with a 403 before the policy runs.
9
12
  */
10
13
  export interface ResourceResolver {
11
- /**
12
- * Load the resource instance for `resource` in the given request context.
13
- * Return `undefined` to signal "not found" — the guard treats a missing
14
- * resource as a denial.
15
- */
16
- resolve(resource: Type<unknown>, ctx: ExecutionContext): Promise<object | undefined> | object | undefined;
14
+ resolve(resource: Type<unknown>, ctx: ExecutionContext, hints?: ResourceResolveHints): Promise<object | undefined> | object | undefined;
17
15
  }
18
16
  /**
19
- * Default resolver: reads the route `:id` param and produces a lightweight
20
- * `{ id }` shim of the requested resource class. This keeps the guard usable
21
- * out-of-the-box (e.g. ownership checks on `resource.id`) without an ORM, while
22
- * apps that need real entities register their own {@link ResourceResolver}.
17
+ * Default resolver: reads the route `:id` param and produces a lightweight `{ id }`
18
+ * object whose prototype is the resource class's, enough for ownership checks on
19
+ * `resource.id` without an ORM. Register your own {@link ResourceResolver} to load
20
+ * real entities.
23
21
  */
24
22
  export declare class IdParamResourceResolver implements ResourceResolver {
25
23
  private readonly param;
26
24
  constructor(param?: string);
27
- resolve(resource: Type<unknown>, ctx: ExecutionContext): object | undefined;
25
+ resolve(resource: Type<unknown>, ctx: ExecutionContext, hints?: ResourceResolveHints): object | undefined;
28
26
  }
29
27
  //# sourceMappingURL=resource-resolver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resource-resolver.d.ts","sourceRoot":"","sources":["../src/resource-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAE7D;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,OAAO,CACL,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,EACvB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;CACrD;AAED;;;;;GAKG;AACH,qBAAa,uBAAwB,YAAW,gBAAgB;IAClD,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,GAAE,MAAa;IAEjD,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS;CAU5E"}
1
+ {"version":3,"file":"resource-resolver.d.ts","sourceRoot":"","sources":["../src/resource-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAE7D,yEAAyE;AACzE,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CACL,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,EACvB,GAAG,EAAE,gBAAgB,EACrB,KAAK,CAAC,EAAE,oBAAoB,GAC3B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;CACrD;AAED;;;;;GAKG;AACH,qBAAa,uBAAwB,YAAW,gBAAgB;IAClD,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,GAAE,MAAa;IAEjD,OAAO,CACL,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,EACvB,GAAG,EAAE,gBAAgB,EACrB,KAAK,CAAC,EAAE,oBAAoB,GAC3B,MAAM,GAAG,SAAS;CAStB"}
@@ -1,21 +1,21 @@
1
1
  /**
2
- * Default resolver: reads the route `:id` param and produces a lightweight
3
- * `{ id }` shim of the requested resource class. This keeps the guard usable
4
- * out-of-the-box (e.g. ownership checks on `resource.id`) without an ORM, while
5
- * apps that need real entities register their own {@link ResourceResolver}.
2
+ * Default resolver: reads the route `:id` param and produces a lightweight `{ id }`
3
+ * object whose prototype is the resource class's, enough for ownership checks on
4
+ * `resource.id` without an ORM. Register your own {@link ResourceResolver} to load
5
+ * real entities.
6
6
  */
7
7
  export class IdParamResourceResolver {
8
8
  param;
9
9
  constructor(param = 'id') {
10
10
  this.param = param;
11
11
  }
12
- resolve(resource, ctx) {
12
+ resolve(resource, ctx, hints) {
13
+ if (ctx.getType() !== 'http')
14
+ return undefined;
13
15
  const req = ctx.switchToHttp().getRequest();
14
- const id = req?.params?.[this.param];
16
+ const id = req?.params?.[hints?.param ?? this.param];
15
17
  if (id === undefined)
16
18
  return undefined;
17
- // Construct a shaped instance so `instance.constructor === resource`, which
18
- // is how PolicyRegistry maps an instance back to its policy.
19
19
  const instance = Object.create(resource.prototype);
20
20
  instance.id = id;
21
21
  return instance;
@@ -1 +1 @@
1
- {"version":3,"file":"resource-resolver.js","sourceRoot":"","sources":["../src/resource-resolver.ts"],"names":[],"mappings":"AAsBA;;;;;GAKG;AACH,MAAM,OAAO,uBAAuB;IACL;IAA7B,YAA6B,QAAgB,IAAI;QAApB,UAAK,GAAL,KAAK,CAAe;IAAG,CAAC;IAErD,OAAO,CAAC,QAAuB,EAAE,GAAqB;QACpD,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,UAAU,EAAwC,CAAC;QAClF,MAAM,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACvC,4EAA4E;QAC5E,6DAA6D;QAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA4B,CAAC;QAC9E,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
1
+ {"version":3,"file":"resource-resolver.js","sourceRoot":"","sources":["../src/resource-resolver.ts"],"names":[],"mappings":"AAsBA;;;;;GAKG;AACH,MAAM,OAAO,uBAAuB;IACL;IAA7B,YAA6B,QAAgB,IAAI;QAApB,UAAK,GAAL,KAAK,CAAe;IAAG,CAAC;IAErD,OAAO,CACL,QAAuB,EACvB,GAAqB,EACrB,KAA4B;QAE5B,IAAI,GAAG,CAAC,OAAO,EAAE,KAAK,MAAM;YAAE,OAAO,SAAS,CAAC;QAC/C,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,UAAU,EAAwC,CAAC;QAClF,MAAM,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;QACrD,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA4B,CAAC;QAC9E,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,31 @@
1
+ import type { ExecutionContext } from '@nestjs/common';
2
+ import type { DecisionProvider } from './decision-provider.js';
3
+ import { type ResourceResolver } from './resource-resolver.js';
4
+ import type { SuperAdminHook } from './types.js';
5
+ /**
6
+ * What `@Can()` argument resolvers and policy base classes need from the app but
7
+ * cannot inject: the official resolvers run with only the `ExecutionContext`, and a
8
+ * policy base class cannot add constructor parameters to its subclasses. `AuthzModule`
9
+ * fills this in when it boots. One application per process is the expected case; with
10
+ * several, the last one to boot wins.
11
+ */
12
+ interface AuthzRuntime {
13
+ resourceResolver: ResourceResolver;
14
+ superAdmin: SuperAdminHook | undefined;
15
+ /** The external decision point, looked up lazily (an adapter may register it late). */
16
+ decisionProvider: () => DecisionProvider | undefined;
17
+ getUser: (context: ExecutionContext) => unknown;
18
+ }
19
+ /** @internal Called by `AuthzModule` at boot, and by the testing helpers. */
20
+ export declare function configureAuthzRuntime(patch: Partial<AuthzRuntime>): void;
21
+ /** @internal Restore the defaults (tests). */
22
+ export declare function resetAuthzRuntime(): void;
23
+ /** @internal */
24
+ export declare function authzRuntime(): Readonly<AuthzRuntime>;
25
+ /**
26
+ * The user the official guard sees for this call: the `getUser` given to
27
+ * `AuthorizationModule.forRoot()`, else the official `defaultGetUser`. `null` for a guest.
28
+ */
29
+ export declare function currentUserOf(context: ExecutionContext): Promise<unknown>;
30
+ export {};
31
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAA2B,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;GAMG;AACH,UAAU,YAAY;IACpB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,UAAU,EAAE,cAAc,GAAG,SAAS,CAAC;IACvC,uFAAuF;IACvF,gBAAgB,EAAE,MAAM,gBAAgB,GAAG,SAAS,CAAC;IACrD,OAAO,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC;CACjD;AAWD,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAKxE;AAED,8CAA8C;AAC9C,wBAAgB,iBAAiB,IAAI,IAAI,CAKxC;AAED,gBAAgB;AAChB,wBAAgB,YAAY,IAAI,QAAQ,CAAC,YAAY,CAAC,CAErD;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAG/E"}
@@ -0,0 +1,40 @@
1
+ import { defaultGetUser } from '@nestjs/authorization';
2
+ import { IdParamResourceResolver } from './resource-resolver.js';
3
+ const noDecisionProvider = () => undefined;
4
+ const runtime = {
5
+ resourceResolver: new IdParamResourceResolver(),
6
+ superAdmin: undefined,
7
+ decisionProvider: noDecisionProvider,
8
+ getUser: defaultGetUser,
9
+ };
10
+ /** @internal Called by `AuthzModule` at boot, and by the testing helpers. */
11
+ export function configureAuthzRuntime(patch) {
12
+ if (patch.resourceResolver)
13
+ runtime.resourceResolver = patch.resourceResolver;
14
+ if ('superAdmin' in patch)
15
+ runtime.superAdmin = patch.superAdmin;
16
+ if (patch.decisionProvider)
17
+ runtime.decisionProvider = patch.decisionProvider;
18
+ if (patch.getUser)
19
+ runtime.getUser = patch.getUser;
20
+ }
21
+ /** @internal Restore the defaults (tests). */
22
+ export function resetAuthzRuntime() {
23
+ runtime.resourceResolver = new IdParamResourceResolver();
24
+ runtime.superAdmin = undefined;
25
+ runtime.decisionProvider = noDecisionProvider;
26
+ runtime.getUser = defaultGetUser;
27
+ }
28
+ /** @internal */
29
+ export function authzRuntime() {
30
+ return runtime;
31
+ }
32
+ /**
33
+ * The user the official guard sees for this call: the `getUser` given to
34
+ * `AuthorizationModule.forRoot()`, else the official `defaultGetUser`. `null` for a guest.
35
+ */
36
+ export async function currentUserOf(context) {
37
+ const user = await runtime.getUser(context);
38
+ return user === undefined || user === false ? null : user;
39
+ }
40
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,EAAE,uBAAuB,EAAyB,MAAM,wBAAwB,CAAC;AAkBxF,MAAM,kBAAkB,GAAG,GAAiC,EAAE,CAAC,SAAS,CAAC;AAEzE,MAAM,OAAO,GAAiB;IAC5B,gBAAgB,EAAE,IAAI,uBAAuB,EAAE;IAC/C,UAAU,EAAE,SAAS;IACrB,gBAAgB,EAAE,kBAAkB;IACpC,OAAO,EAAE,cAAc;CACxB,CAAC;AAEF,6EAA6E;AAC7E,MAAM,UAAU,qBAAqB,CAAC,KAA4B;IAChE,IAAI,KAAK,CAAC,gBAAgB;QAAE,OAAO,CAAC,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC;IAC9E,IAAI,YAAY,IAAI,KAAK;QAAE,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACjE,IAAI,KAAK,CAAC,gBAAgB;QAAE,OAAO,CAAC,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC;IAC9E,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;AACrD,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CAAC,gBAAgB,GAAG,IAAI,uBAAuB,EAAE,CAAC;IACzD,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAC/B,OAAO,CAAC,gBAAgB,GAAG,kBAAkB,CAAC;IAC9C,OAAO,CAAC,OAAO,GAAG,cAAc,CAAC;AACnC,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAyB;IAC3D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5D,CAAC"}
package/dist/tokens.d.ts CHANGED
@@ -17,12 +17,8 @@ export declare const RESOURCE_RESOLVER: symbol;
17
17
  * or empty, the endpoint behaves exactly as before (class-level / ad-hoc only).
18
18
  */
19
19
  export declare const RESOURCE_HYDRATOR: symbol;
20
- /** Metadata key for `@Policy(Resource)` — stores the resource class on the policy. */
21
- export declare const POLICY_RESOURCE_METADATA = "nestjs-authz:policy-resource";
22
- /** Metadata key for `@Can(ability, Resource?)` — stores the ability descriptor on a route. */
23
- export declare const CAN_METADATA = "nestjs-authz:can";
24
- /** Metadata key for `@Roles(...roles)` — stores the allowed role names on a route. */
25
- export declare const ROLES_METADATA = "nestjs-authz:roles";
20
+ /** Metadata key of the `@PolicyFor(Resource)` link on a policy class. */
21
+ export { POLICY_RESOURCE_METADATA } from './links.js';
26
22
  /**
27
23
  * Cross-lib injection token for an optional {@link PermissionProvider} — the seam the
28
24
  * RBAC adapter (`@dudousxd/nestjs-authz-typeorm`) registers so that a model-less,
@@ -31,8 +27,8 @@ export declare const ROLES_METADATA = "nestjs-authz:roles";
31
27
  *
32
28
  * `Symbol.for(key)` uses the global symbol registry so an RBAC package registering
33
29
  * this same key resolves to the SAME symbol instance without importing core internals.
34
- * The token is consulted with `@Optional()` — when absent, the Gate behaves exactly
35
- * as before (backward-compatible: unknown abilities still throw).
30
+ * The token is consulted with `@Optional()` — when absent, an unknown string ability
31
+ * still throws.
36
32
  */
37
33
  export declare const PERMISSION_PROVIDER: symbol;
38
34
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAEA,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,QAAiC,CAAC;AAEnE,uFAAuF;AACvF,eAAO,MAAM,iBAAiB,QAA2C,CAAC;AAE1E;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,QAA2C,CAAC;AAE1E,sFAAsF;AACtF,eAAO,MAAM,wBAAwB,iCAAiC,CAAC;AAEvE,8FAA8F;AAC9F,eAAO,MAAM,YAAY,qBAAqB,CAAC;AAE/C,sFAAsF;AACtF,eAAO,MAAM,cAAc,uBAAuB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,QAA6C,CAAC;AAE9E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,QAAuC,CAAC;AAElE;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,QAA2C,CAAC;AAE1E;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,QAAoC,CAAC"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAEA,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,QAAiC,CAAC;AAEnE,uFAAuF;AACvF,eAAO,MAAM,iBAAiB,QAA2C,CAAC;AAE1E;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,QAA2C,CAAC;AAE1E,yEAAyE;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,QAA6C,CAAC;AAE9E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,QAAuC,CAAC;AAElE;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,QAA2C,CAAC;AAE1E;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,QAAoC,CAAC"}
package/dist/tokens.js CHANGED
@@ -18,12 +18,8 @@ export const RESOURCE_RESOLVER = capability('authz', 'resource-resolver');
18
18
  * or empty, the endpoint behaves exactly as before (class-level / ad-hoc only).
19
19
  */
20
20
  export const RESOURCE_HYDRATOR = capability('authz', 'resource-hydrator');
21
- /** Metadata key for `@Policy(Resource)` — stores the resource class on the policy. */
22
- export const POLICY_RESOURCE_METADATA = 'nestjs-authz:policy-resource';
23
- /** Metadata key for `@Can(ability, Resource?)` — stores the ability descriptor on a route. */
24
- export const CAN_METADATA = 'nestjs-authz:can';
25
- /** Metadata key for `@Roles(...roles)` — stores the allowed role names on a route. */
26
- export const ROLES_METADATA = 'nestjs-authz:roles';
21
+ /** Metadata key of the `@PolicyFor(Resource)` link on a policy class. */
22
+ export { POLICY_RESOURCE_METADATA } from './links.js';
27
23
  /**
28
24
  * Cross-lib injection token for an optional {@link PermissionProvider} — the seam the
29
25
  * RBAC adapter (`@dudousxd/nestjs-authz-typeorm`) registers so that a model-less,
@@ -32,8 +28,8 @@ export const ROLES_METADATA = 'nestjs-authz:roles';
32
28
  *
33
29
  * `Symbol.for(key)` uses the global symbol registry so an RBAC package registering
34
30
  * this same key resolves to the SAME symbol instance without importing core internals.
35
- * The token is consulted with `@Optional()` — when absent, the Gate behaves exactly
36
- * as before (backward-compatible: unknown abilities still throw).
31
+ * The token is consulted with `@Optional()` — when absent, an unknown string ability
32
+ * still throws.
37
33
  */
38
34
  export const PERMISSION_PROVIDER = capability('authz', 'permission-provider');
39
35
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE1D,uEAAuE;AACvE,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAEnE,uFAAuF;AACvF,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;AAE1E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;AAE1E,sFAAsF;AACtF,MAAM,CAAC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC;AAEvE,8FAA8F;AAC9F,MAAM,CAAC,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAE/C,sFAAsF;AACtF,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;AAE9E;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;AAE1E;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC"}
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE1D,uEAAuE;AACvE,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAEnE,uFAAuF;AACvF,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;AAE1E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;AAE1E,yEAAyE;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;AAE9E;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;AAE1E;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,217 +1,100 @@
1
1
  import type { Type } from '@nestjs/common';
2
2
  import type { UserRef } from './context-accessor.js';
3
3
  import type { ResourceResolver } from './resource-resolver.js';
4
- /**
5
- * A resource instance passed to policy methods. `unknown` because authz never
6
- * inspects the resource itself — the policy method does.
7
- */
4
+ /** A resource passed to a policy ability. authz never inspects it; the policy does. */
8
5
  export type Resource = object;
9
6
  /**
10
- * The current user as seen by a policy/gate. authz does not model the user; it
11
- * is whatever the app's auth layer produced (or `undefined` when unauthenticated).
7
+ * The user a policy or gate sees: whatever authentication produced, `null` for a
8
+ * guest. authz does not model it.
12
9
  */
13
10
  export type User = unknown;
14
11
  /**
15
- * The richer result a policy method / ad-hoc gate may return instead of a bare
16
- * boolean: a verdict plus an optional human-readable `message` explaining a denial.
17
- * The message is surfaced on the thrown `ForbiddenException` (so a 403 is debuggable)
18
- * and published on the diagnostics decision. Returning a bare boolean is unchanged.
19
- *
20
- * Mirrors Laravel's `Response::allow()/deny('message')`.
12
+ * A verdict with an optional reason. What a {@link DecisionProvider} may answer instead of
13
+ * a bare boolean. Only `allowed` is used: `@nestjs/authorization` has no deny-with-reason, so a
14
+ * route denial is the official 403 and the `message` is dropped (README, "Migrating from 0.8").
21
15
  */
22
16
  export interface PolicyResponse {
23
17
  allowed: boolean;
24
18
  message?: string;
25
19
  }
26
- /**
27
- * What a policy method / gate / hook may return: a bare boolean (unchanged) or the
28
- * richer {@link PolicyResponse}. Hooks additionally allow `void`/`undefined` to mean
29
- * "no opinion — fall through".
30
- */
20
+ /** A bare boolean or a {@link PolicyResponse}. */
31
21
  export type PolicyResult = boolean | PolicyResponse;
22
+ /** An ad-hoc, model-less gate registered with `gate.define(name, fn)`. */
23
+ export type GateFn = (user: User, resource?: Resource) => boolean | Promise<boolean>;
32
24
  /**
33
- * A policy method: decides a single ability for a `(user, resource?)` pair.
34
- * Class-level abilities (e.g. `create`) omit the resource. May be async. May return
35
- * a bare boolean (unchanged) or a richer {@link PolicyResponse} with a deny message.
25
+ * The global super-admin hook. `true` grants any check; anything else falls through.
26
+ * Policies honor it when they extend `AuthzPolicy` (or call `superAdminBefore` from
27
+ * their `before()`); `RolePolicy` and `PermissionPolicy` do. The `Gate`'s string
28
+ * abilities and `gate.scope()` ask it first.
36
29
  */
37
- export type PolicyMethod = (user: User, resource?: Resource) => PolicyResult | Promise<PolicyResult>;
38
- /**
39
- * Optional per-policy `before` hook. Runs before the ability method.
40
- * - return `true` → allow (short-circuit)
41
- * - return `false` → deny (short-circuit)
42
- * - return `void`/`undefined` → fall through to the ability method
43
- */
44
- export type PolicyBeforeHook = (user: User, ability: string) => PolicyResult | undefined | Promise<PolicyResult | undefined>;
45
- /** A policy instance is an arbitrary object whose methods are abilities. */
46
- export type PolicyInstance = Record<string, unknown> & {
47
- before?: PolicyBeforeHook;
48
- };
49
- /**
50
- * An ad-hoc gate: a model-less ability resolved by name via `gate.define`.
51
- * May return a bare boolean (unchanged) or a richer {@link PolicyResponse}.
52
- */
53
- export type GateFn = (user: User, resource?: Resource) => PolicyResult | Promise<PolicyResult>;
54
- /**
55
- * Global `after` hook. Mirrors Laravel's `Gate::after()`: runs AFTER policy/gate
56
- * resolution and may observe or override the decision.
57
- *
58
- * `result` is the verdict produced by the policy/gate (`true`/`false`), or
59
- * `undefined` when the policy/gate returned a nullish value (it had "no opinion").
60
- *
61
- * Override semantics (Laravel-idiomatic): the hook's return value REPLACES the
62
- * decision ONLY when the policy/gate produced no explicit verdict (`result` is
63
- * `undefined`). When the policy/gate DID decide (returned a boolean), `after` is
64
- * purely an observer and its return value is ignored — so it can never silently
65
- * overturn an explicit allow/deny. Returning `void`/`undefined` always leaves the
66
- * decision untouched. Like a policy, it may return a {@link PolicyResponse} to
67
- * attach a deny message.
68
- */
69
- export type AfterHook = (user: User, ability: string, result: boolean | undefined, resource?: Resource) => PolicyResult | undefined | Promise<PolicyResult | undefined>;
30
+ export type SuperAdminHook = (user: User, ability: string,
70
31
  /**
71
- * A resource loader: turns an `id` into the REAL entity instance for a resource
72
- * `type`. Used by the opt-in `POST /authz/can` endpoint to rehydrate the client's
73
- * `{ type, id }` shim before authorizing, so an instance-bound `@Policy` matches by
74
- * constructor. Returning nullish signals "not found" (the endpoint denies). May be async.
32
+ * What the check targets: the resource of a single check (the policy's first
33
+ * argument), or the entity class for `gate.scope(...)`. `undefined` for a model-less
34
+ * ability. Lets the hook scope the bypass (e.g. to one tenant's resources).
75
35
  */
36
+ resource?: Resource) => boolean | null | undefined | Promise<boolean | null | undefined>;
37
+ /** Loads the real entity for a client `{ type, id }` reference (the `POST /authz/can` endpoint). */
76
38
  export type ResourceLoader = (id: string | number) => unknown | Promise<unknown>;
77
- /**
78
- * Resource loaders keyed by the resource `type` name as emitted by the client/codegen
79
- * (e.g. `'Post'`). See {@link AuthzModuleOptions.resourceLoaders}.
80
- */
39
+ /** Resource loaders keyed by the resource `type` name the client sends (e.g. `'Post'`). */
81
40
  export type ResourceLoaderMap = Record<string, ResourceLoader>;
82
41
  /**
83
- * Global super-admin before-hook. Runs before any policy/gate; truthy → allow.
84
- * `void`/`undefined`/`false` falls through to normal resolution.
42
+ * What happens to a route that declares no `@Can()` (nor `Can.Anyone()` / `@Public()`):
43
+ * - `'deny'` (default): nothing special; the official `AuthorizationGuard` denies it.
44
+ * - `'allow'`: the migration mode. `AuthzModule` registers its own global {@link AuthzGuard},
45
+ * which enforces the official requirements exactly as the official guard does and lets
46
+ * unannotated routes through. Needs `AuthorizationModule.forRoot({ globalGuard: false })`.
85
47
  */
86
- export type SuperAdminHook = (user: User, ability: string,
87
- /**
88
- * The dispatch target: the resource instance/class of a single check, or the scoped entity
89
- * class for `gate.scope(...)`. `undefined` for a model-less ability.
90
- */
91
- resource?: Resource) => PolicyResult | undefined | Promise<PolicyResult | undefined>;
92
- export interface AuthzModuleOptions {
48
+ export type UnannotatedRoutes = 'allow' | 'deny';
49
+ /** Options that decide what the module registers, so they are static (read before any factory runs). */
50
+ export interface AuthzModuleStaticOptions {
93
51
  /**
94
- * Policy classes to register explicitly. Each must be decorated with
95
- * `@Policy(Resource)`. Auto-discovery of `@Policy` providers also works, so
96
- * this is optional.
52
+ * Opt-in `POST /authz/can` endpoint for client checks that are not hydrated. `true`
53
+ * mounts it at `authz/can`; a string at that path. Off by default.
97
54
  */
98
- policies?: Array<Type<PolicyInstance>>;
55
+ canEndpoint?: boolean | string;
99
56
  /**
100
- * Global super-admin before-hook applied to every authorization check. Return
101
- * `true` to grant (e.g. super-admins). Returning `void`/`false` falls through.
102
- *
103
- * ⚠️ IMPORTANT — what `user` is: on the **context path** (no `forUser`), the
104
- * `user` passed here is the raw {@link UserRef} from nestjs-context — just
105
- * `{ type, id }`, NOT your hydrated user entity. So `superAdmin: u => u.isAdmin`
106
- * will NOT fire from a route/`gate.allows(...)` unless you also configure
107
- * {@link AuthzModuleOptions.resolveUser} to hydrate the full entity. On the
108
- * explicit `gate.forUser(entity)` path you receive exactly what you passed.
57
+ * Class decorators applied to every controller this module mounts (the `POST /authz/can`
58
+ * endpoint), after its own: `[UseGuards(JwtAuthGuard), ApiTags('authz')]`. The controllers
59
+ * are open to the official guard by default (`Can.Anyone()`); a `@Can()` here restricts them.
109
60
  */
61
+ decorators?: ClassDecorator[];
62
+ /** See {@link UnannotatedRoutes}. Default `'deny'`. */
63
+ unannotated?: UnannotatedRoutes;
64
+ }
65
+ export interface AuthzModuleOptions extends AuthzModuleStaticOptions {
66
+ /** The global super-admin hook. See {@link SuperAdminHook}. */
110
67
  superAdmin?: SuperAdminHook;
111
68
  /**
112
- * Global `after` hook (Laravel's `Gate::after()`). Runs AFTER policy/gate
113
- * resolution and may observe or override the decision. It can only OVERRIDE the
114
- * verdict when the policy/gate produced no explicit result (returned nullish);
115
- * when the policy/gate decided explicitly, `after` is observe-only and its return
116
- * value is ignored. Returning `void`/`undefined` always leaves the decision
117
- * untouched. See {@link AfterHook}.
118
- *
119
- * Receives the same (possibly un-hydrated) `user` as {@link superAdmin} on the
120
- * context path — apply {@link resolveUser} if you need the full entity.
121
- */
122
- after?: AfterHook;
123
- /**
124
- * Optional hook to hydrate the full user entity from the context's
125
- * {@link UserRef} (`{ type, id }`) before policies / `before` / `superAdmin`
126
- * run. WITHOUT this hook, the context path passes only `{ type, id }` to those
127
- * functions (it does not load your `User` row), so property checks such as
128
- * `superAdmin: u => u.isAdmin` or `post.authorId === user.id` against a real
129
- * column will not see hydrated fields. Provide `resolveUser` to load the entity
130
- * (e.g. from your ORM) keyed by the ref. Returning `undefined` is treated as
131
- * "no user" (deny path), identical to an anonymous request.
132
- *
133
- * Only affects the context path; `gate.forUser(entity)` always uses the value
134
- * you pass directly and never invokes this hook.
69
+ * Hydrates the full user from nestjs-context's `{ type, id }` ref for `Gate` calls
70
+ * made without a user (`gate.allows(...)` rather than `gate.forUser(user)`), when
71
+ * `@nestjs/authentication`'s `AuthenticationContext` has no user to offer. Runs once
72
+ * per `type:id` per request (nestjs-context store). Routes never use it: the official
73
+ * guard reads the user with its own `getUser`.
135
74
  */
136
75
  resolveUser?: (ref: UserRef) => User | undefined | Promise<User | undefined>;
137
76
  /**
138
- * Override the default {@link RoleResolver} used by coarse role-checks
139
- * (`gate.hasRole('teacher')`, `@Roles('admin')`). The default reads `user.roles`
140
- * (`string[]`) OR `user.role` (`string | string[]`) off the user object, so
141
- * role-checks work with ZERO RBAC tables. Provide this to derive roles from a
142
- * different shape. When the optional `ROLE_PROVIDER` seam is ALSO registered, the
143
- * Gate unions both sources' roles.
144
- *
145
- * On the context path the resolver receives whatever the context produced (the
146
- * raw {@link UserRef} unless `resolveUser` hydrated the entity); on the explicit
147
- * `gate.forUser(entity)` path it receives exactly what you passed.
77
+ * Derives roles from the user object. Default: `user.roles` (`string[]`) or
78
+ * `user.role` (`string | string[]`). Unioned with the RBAC adapter's role store.
148
79
  */
149
80
  resolveRoles?: (user: User) => string[] | undefined | Promise<string[] | undefined>;
150
- /**
151
- * Override the default {@link ResourceResolver} used to load an instance for
152
- * `@Can(ability, Resource)` routes. Defaults to {@link IdParamResourceResolver}
153
- * (reads the route `:id` param), registered automatically by `forRoot`. Apps
154
- * needing real ORM entities provide their own here (or bind the
155
- * `RESOURCE_RESOLVER` token directly).
156
- */
81
+ /** Loads the resource for `byId(Resource)`. Default: {@link IdParamResourceResolver}. */
157
82
  resourceResolver?: ResourceResolver;
158
- /**
159
- * Route param name the default {@link IdParamResourceResolver} reads to build
160
- * the resource shim. Defaults to `'id'`. Ignored when {@link resourceResolver}
161
- * is supplied.
162
- */
83
+ /** Route param the default resolver reads. Default `'id'`. */
163
84
  idParam?: string;
164
- /**
165
- * Opt-in `POST /authz/can` fallback endpoint. **Off by default.** When enabled,
166
- * registers a controller that runs `gate.allows(ability, resource?)` for the
167
- * current (context) user and returns `{ allowed: boolean }`. This is the
168
- * last-resort path the codegen-emitted `can()` helper targets.
169
- *
170
- * - `true` → mount at the default path `authz/can`.
171
- * - `string` → mount at that path (e.g. `'api/authz/can'`).
172
- * - `false`/omitted → no endpoint is registered.
173
- *
174
- * Prefer the no-request paths (shared Inertia props, per-resource `can` maps)
175
- * — this endpoint exists only for abilities not already hydrated on the client.
176
- */
177
- canEndpoint?: boolean | string;
178
- /**
179
- * Resource loaders keyed by the resource `type` name the client/codegen emits
180
- * (e.g. `'Post'`). They close the per-instance gap in the {@link canEndpoint}
181
- * fallback: when the endpoint receives `{ ability, resource: { type, id } }` and a
182
- * loader is registered for `type`, it `await`s `loader(id)` and authorizes the REAL
183
- * entity — so an instance-bound `@Policy` matches by constructor and its method runs
184
- * with the loaded resource. A loader returning nullish is treated as "not found"
185
- * (the endpoint denies). Types WITHOUT a loader keep the prior behavior (class-level
186
- * / ad-hoc only; a resource-bound ability still denies). Opt-in: unset → unchanged.
187
- *
188
- * ```ts
189
- * resourceLoaders: { Post: (id) => postRepo.findOneBy({ id: Number(id) }) }
190
- * ```
191
- */
85
+ /** Loaders that turn the endpoint's `{ type, id }` into the real entity, keyed by type. */
192
86
  resourceLoaders?: ResourceLoaderMap;
193
87
  }
194
88
  export interface AuthzModuleOptionsFactory {
195
89
  createAuthzOptions(): Promise<AuthzModuleOptions> | AuthzModuleOptions;
196
90
  }
197
- export interface AuthzModuleAsyncOptions {
91
+ export interface AuthzModuleAsyncOptions extends AuthzModuleStaticOptions {
198
92
  imports?: unknown[];
199
93
  useExisting?: Type<AuthzModuleOptionsFactory>;
200
94
  useClass?: Type<AuthzModuleOptionsFactory>;
201
95
  useFactory?: (...args: unknown[]) => Promise<AuthzModuleOptions> | AuthzModuleOptions;
202
96
  inject?: unknown[];
203
- /**
204
- * Opt-in `POST /authz/can` fallback endpoint (see {@link AuthzModuleOptions.canEndpoint}).
205
- * Declared statically here because controllers are registered at module-definition
206
- * time, before the async options factory resolves. Off by default.
207
- */
208
- canEndpoint?: boolean | string;
209
- /**
210
- * Resource loaders for the {@link canEndpoint} fallback
211
- * (see {@link AuthzModuleOptions.resourceLoaders}). May also be returned from the
212
- * async options factory; either way the endpoint reads them from the resolved
213
- * options, so this declaration is for the rarer case of supplying them statically.
214
- */
97
+ /** See {@link AuthzModuleOptions.resourceLoaders}. */
215
98
  resourceLoaders?: ResourceLoaderMap;
216
99
  }
217
100
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-authz",
3
- "version": "0.8.0",
4
- "description": "NestJS authorization — Laravel-style Gates & Policies, @Can guard, resource resolver (zero DB).",
3
+ "version": "0.9.0",
4
+ "description": "Extras on top of @nestjs/authorization: persisted RBAC policies, @Can helpers (byId, roles, permission), a Gate with batch checks and ad-hoc gates, super-admin, query scoping.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -21,7 +21,8 @@
21
21
  "acl",
22
22
  "rbac",
23
23
  "tanstack-intent",
24
- "cerbos"
24
+ "cerbos",
25
+ "nestjs-authorization"
25
26
  ],
26
27
  "author": "Davi Carvalho <davi@goflip.ai>",
27
28
  "type": "module",
@@ -55,24 +56,32 @@
55
56
  },
56
57
  "peerDependencies": {
57
58
  "@dudousxd/nestjs-context": ">=0.1.0",
58
- "@nestjs/common": ">=10.0.0",
59
- "@nestjs/core": ">=10.0.0",
60
- "reflect-metadata": ">=0.1.13"
59
+ "@nestjs/authentication": "^0.1.5",
60
+ "@nestjs/authorization": "^0.1.3",
61
+ "@nestjs/common": "^12.0.0",
62
+ "@nestjs/core": "^12.0.0",
63
+ "reflect-metadata": ">=0.1.13",
64
+ "rxjs": "^7.1.0"
61
65
  },
62
66
  "peerDependenciesMeta": {
63
67
  "@dudousxd/nestjs-context": {
64
68
  "optional": true
69
+ },
70
+ "@nestjs/authentication": {
71
+ "optional": true
65
72
  }
66
73
  },
67
74
  "devDependencies": {
68
75
  "@cerbos/http": "0.29.0",
76
+ "@nestjs/authentication": "0.1.5",
77
+ "@nestjs/authorization": "0.1.3",
69
78
  "@nestjs/common": "12.0.1",
70
79
  "@nestjs/core": "12.0.1",
71
80
  "@nestjs/platform-express": "12.0.1",
72
81
  "@nestjs/testing": "12.0.1",
73
82
  "@tanstack/intent": "0.4.0",
74
83
  "@types/express": "4.17.25",
75
- "@types/node": "20.19.43",
84
+ "@types/node": "22.20.5",
76
85
  "@types/supertest": "6.0.3",
77
86
  "express": "4.22.2",
78
87
  "reflect-metadata": "0.2.2",
@@ -82,12 +91,12 @@
82
91
  "vitest": "3.2.7"
83
92
  },
84
93
  "engines": {
85
- "node": ">=20"
94
+ "node": ">=22"
86
95
  },
87
96
  "scripts": {
88
- "build": "tsc -p tsconfig.json",
97
+ "build": "tsc -p tsconfig.json --incremental false",
89
98
  "test": "vitest run --passWithNoTests",
90
99
  "test:watch": "vitest",
91
- "typecheck": "tsc -p tsconfig.json --noEmit"
100
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json"
92
101
  }
93
102
  }