@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
package/dist/gate.d.ts CHANGED
@@ -1,262 +1,136 @@
1
+ import { type Ability, AuthorizationService } from '@nestjs/authorization';
1
2
  import { type Type } from '@nestjs/common';
2
- import { ModuleRef } from '@nestjs/core';
3
- import type { ContextAccessor } from './context-accessor.js';
4
- import type { DecisionProvider } from './decision-provider.js';
5
- import { type AuthzDecisionReason } from './diagnostics.js';
6
- import type { PermissionProvider } from './permission-provider.js';
7
- import { PolicyRegistry } from './policy-registry.js';
8
- import { type RoleProvider } from './role-provider.js';
3
+ import { PolicyIndex } from './policy-index.js';
4
+ import { AuthzRbac } from './rbac.js';
9
5
  import { type ScopeConstraint } from './scope.js';
10
6
  import type { AuthzModuleOptions, GateFn, Resource, User } from './types.js';
11
- declare const NO_USER: unique symbol;
12
- type MaybeUser = User | typeof NO_USER;
13
- /** A single item in a {@link Gate.allowsMany} batch. */
7
+ /** The arguments after the user of ability `A` on policy `P`. */
8
+ export type AbilityArgsOf<P, A extends keyof P> = P[A] extends (user: never, ...args: infer R) => unknown ? R : never;
9
+ /** A string ability, optionally on a resource (instance, or class for class-level abilities). */
14
10
  export interface BatchAbility {
15
11
  ability: string;
16
12
  resource?: Resource;
17
13
  }
18
- /** A single result from a {@link Gate.allowsMany} batch: the input plus its verdict. */
19
- export interface BatchResult {
14
+ /** An official policy check: `policy[ability](user, ...args)`. */
15
+ export interface BatchPolicyCheck {
16
+ policy: Type<unknown>;
20
17
  ability: string;
21
- resource?: Resource;
22
- allowed: boolean;
18
+ args?: readonly unknown[];
23
19
  }
20
+ /** One item of a {@link Gate.allowsMany} batch. */
21
+ export type BatchItem = BatchAbility | BatchPolicyCheck;
22
+ /** One result of a {@link Gate.allowsMany} batch: the item plus its verdict. */
23
+ export type BatchResult = BatchItem & {
24
+ allowed: boolean;
25
+ };
24
26
  /**
25
- * Laravel-style authorization Gate.
27
+ * A façade over the official `AuthorizationService` for service-layer checks, with what
28
+ * the official service does not have:
26
29
  *
27
- * Resolves an ability against either a registered `@Policy` method (by ability
28
- * name, matched against the resource's policy) or an ad-hoc gate defined via
29
- * {@link define}. Applies the global `superAdmin` before-hook and the per-policy
30
- * `before` hook with short-circuit semantics.
30
+ * - **string abilities**, Laravel-style: `gate.allows('update', post)` finds the policy
31
+ * linked to `Post` with `@PolicyFor(Post)`; `gate.allows('access-admin')` runs an
32
+ * ad-hoc gate from {@link define}; `gate.allows('posts.publish')` asks the persisted
33
+ * permissions. Asks `superAdmin` first, then the external decision point
34
+ * (`DECISION_PROVIDER`), then the policy — which has the final word: a persisted
35
+ * permission named like the ability does not bypass it — then the persisted
36
+ * permissions, then the ad-hoc gate.
37
+ * - **official policy checks**: `gate.allows(PostPolicy, 'update', post)`, exactly
38
+ * `AuthorizationService.can()`.
39
+ * - **batches** ({@link allowsMany}) sharing one permission fetch, **query scopes**
40
+ * ({@link scope}), **roles** ({@link hasRole}), an allow+deny decision event, and an
41
+ * ambient user when none is passed ({@link forUser} passes one): `@nestjs/authentication`'s
42
+ * `AuthenticationContext.user` when that package is installed, else nestjs-context's.
31
43
  *
32
- * The current user comes from the optional {@link ContextAccessor} (nestjs-context)
33
- * when present, or is supplied explicitly via {@link forUser}.
44
+ * Every policy decision is the official service's: the policy's own `before()`, then
45
+ * the ability, allowed only on a literal `true`.
34
46
  */
35
47
  export declare class Gate {
36
- private readonly policies;
37
- private readonly context?;
38
- private readonly moduleRef?;
39
- private readonly permissionProvider?;
40
- private readonly roleProvider?;
41
- private readonly decisionProvider?;
48
+ private readonly index;
49
+ private readonly rbac;
42
50
  private readonly gates;
43
51
  private readonly superAdmin;
44
- private readonly after;
45
- private readonly resolveUser;
46
- private readonly roleResolver;
47
- private contextResolved;
48
- private contextCached;
49
- private permissionProviderResolved;
50
- private permissionProviderCached;
51
- private roleProviderResolved;
52
- private roleProviderCached;
53
- private decisionProviderResolved;
54
- private decisionProviderCached;
55
- constructor(policies: PolicyRegistry, options: AuthzModuleOptions | undefined, context?: ContextAccessor | undefined, moduleRef?: ModuleRef | undefined, permissionProvider?: PermissionProvider | undefined, roleProvider?: RoleProvider | undefined, decisionProvider?: DecisionProvider | undefined);
56
- /**
57
- * Locate the context accessor. Prefers the value injected into this module;
58
- * falls back to a non-strict {@link ModuleRef} lookup so an accessor provided
59
- * by ANY module (e.g. a global ContextModule, or the app root) is still found.
60
- */
61
- private resolveContext;
62
- /**
63
- * Locate the optional {@link PermissionProvider} (the RBAC seam). Prefers the value
64
- * injected into this module; falls back to a non-strict {@link ModuleRef} lookup so a
65
- * provider registered by ANY module (e.g. the RBAC adapter's global module) is found.
66
- */
67
- private resolvePermissionProvider;
68
- /**
69
- * Locate the optional {@link RoleProvider} (the coarse role seam). Prefers the value
70
- * injected into this module; falls back to a non-strict {@link ModuleRef} lookup so a
71
- * provider registered by ANY module (e.g. the RBAC adapter's global module) is found.
72
- */
73
- private resolveRoleProvider;
74
- /**
75
- * Locate the optional {@link DecisionProvider} (the external-PDP seam). Same lookup strategy as
76
- * {@link resolvePermissionProvider}: injected value first, then a memoized non-strict scan.
77
- */
78
- private resolveDecisionProvider;
79
- /**
80
- * The per-request {@link PermissionCache}, stashed on the nestjs-context store so
81
- * every check within one HTTP request shares a single `getPermissions` fetch
82
- * (kills the N+1 a list page would otherwise cause). Returns `undefined` when no
83
- * context store is available (standalone use), in which case callers fall back to
84
- * a transient cache (e.g. one per `allowsMany` batch) or no memoization.
85
- */
86
- private resolveRequestCache;
52
+ private readonly authz;
53
+ constructor(authz: AuthorizationService | undefined, index: PolicyIndex, rbac: AuthzRbac, options?: AuthzModuleOptions);
87
54
  /** Register an ad-hoc, model-less gate resolved by `ability` name. */
88
55
  define(ability: string, fn: GateFn): this;
89
56
  /** True when an ad-hoc gate is registered for `ability`. */
90
57
  hasGate(ability: string): boolean;
91
- /**
92
- * Names of every ad-hoc gate registered via {@link define}. Used by integrations
93
- * (e.g. `@dudousxd/nestjs-authz-inertia`) that enumerate the user's class-level
94
- * abilities to share them as Inertia props — no network round-trip needed.
95
- */
58
+ /** Names of every ad-hoc gate registered with {@link define}. */
96
59
  gateNames(): string[];
97
60
  /**
98
- * Bind an explicit user, bypassing the context accessor. Use when no
99
- * nestjs-context is wired, or to check a user other than the current one.
100
- *
101
- * A nullish user (`forUser(undefined)` / `forUser(null)`) is an explicit
102
- * anonymous request: it maps to the same deny path as an unauthenticated
103
- * context (`NO_USER`), so policies/gates are never invoked with `undefined` and
104
- * never throw. The `resolveUser` hook is NOT applied to `forUser` — the value
105
- * you pass is used verbatim.
61
+ * Bind an explicit user. `null`/`undefined` is a guest. The usual way to check in a
62
+ * service: pass the user your handler received.
106
63
  */
107
64
  forUser(user: User): BoundGate;
108
65
  /**
109
- * Resolve the current user from the context accessor, or `NO_USER`.
110
- * When a `resolveUser` hook is configured, hydrate the full entity from the
111
- * context's {@link UserRef}; a hook returning nullish maps to `NO_USER`.
66
+ * The ambient user, for calls without {@link forUser}: `@nestjs/authentication`'s
67
+ * `AuthenticationContext.user` when that optional peer is installed and has one, else
68
+ * nestjs-context's user ref (hydrated by `resolveUser` when configured, once per
69
+ * request). `null` without either.
112
70
  */
113
71
  private currentUser;
72
+ allows<P, const A extends Ability<P>>(policy: Type<P>, ability: A, ...args: AbilityArgsOf<P, A>): Promise<boolean>;
114
73
  allows(ability: string, resource?: Resource): Promise<boolean>;
74
+ denies<P, const A extends Ability<P>>(policy: Type<P>, ability: A, ...args: AbilityArgsOf<P, A>): Promise<boolean>;
115
75
  denies(ability: string, resource?: Resource): Promise<boolean>;
116
- authorize(ability: string, resource?: Resource): Promise<void>;
117
76
  /**
118
- * Authorize MANY abilities for the current (context) user in a single pass. The
119
- * user is resolved ONCE and a single {@link PermissionCache} is shared across all
120
- * items, so a list page (N cards) costs one user resolution + at most one
121
- * permission fetch instead of N of each. Order is preserved; each result echoes
122
- * its input `ability`/`resource` plus the `allowed` verdict.
123
- *
124
- * Fault-isolating: an item whose ability is unresolved/ambiguous denies just
125
- * THAT item (it does not throw and abort the batch) — a batch is a best-effort
126
- * verdict list, not an enforcement gate.
77
+ * Like {@link allows}, but throws the official `AuthorizationError` on a denial, which
78
+ * the official module turns into a 401/403 (or the transport's error) when it leaves
79
+ * a handler.
127
80
  */
128
- allowsMany(items: BatchAbility[]): Promise<BatchResult[]>;
81
+ authorize<P, const A extends Ability<P>>(policy: Type<P>, ability: A, ...args: AbilityArgsOf<P, A>): Promise<void>;
82
+ authorize(ability: string, resource?: Resource): Promise<void>;
83
+ /** Check many abilities at once (one user, one permission fetch). A failing item denies. */
84
+ allowsMany(items: readonly BatchItem[]): Promise<BatchResult[]>;
129
85
  /**
130
- * Resolve the QUERY SCOPE constraint for the current (context) user against
131
- * `entity` — the `accessibleBy` / Pundit `policy_scope` concept. Returns an
132
- * ORM-neutral {@link ScopeConstraint} an adapter (e.g. the TypeORM `applyScope`
133
- * helper) turns into a parameterized `WHERE`.
134
- *
135
- * Consistent with the Gate's single-resource semantics:
136
- * - super-admin / before-grant / permission-provider grant → `allow-all`,
137
- * - anonymous, or no policy/scope → `deny-all` (default-deny),
138
- * - otherwise the policy's `scope` (or `viewAny`-style) constraint.
139
- *
140
- * `ability` (default `'viewAny'`) names the permission-provider check used for
141
- * the allow-all grant and the policy fallback method.
86
+ * The query scope of `entity` (a resource class linked with `@PolicyFor`, or the
87
+ * policy class itself) for the current user, from the policy's `scope(user, entity)`
88
+ * method (else the `ability` method, `viewAny` by default). See {@link ScopeConstraint}.
142
89
  */
143
90
  scope(entity: Type<unknown>, ability?: string): Promise<ScopeConstraint>;
144
- /** True when the current user holds `role`. */
91
+ /** True when the current user holds `role` (a fact: `superAdmin` does not apply). */
145
92
  hasRole(role: string): Promise<boolean>;
146
- /** True when the current user holds ANY of `roles`. */
93
+ /** True when the current user holds any of `roles`. */
147
94
  hasAnyRole(roles: string[]): Promise<boolean>;
148
95
  /** @internal */
149
- allowsForUser(user: MaybeUser, ability: string, resource?: Resource): Promise<boolean>;
150
- /** @internal — batch check for an explicit/bound user (see {@link allowsMany}). */
151
- allowsManyForUser(user: MaybeUser, items: BatchAbility[]): Promise<BatchResult[]>;
152
- /**
153
- * Run a batch of checks against one already-resolved user, sharing a single
154
- * {@link PermissionCache} so the provider's `getPermissions` runs at most once.
155
- * Prefers the per-request cache (so the batch also coalesces with other checks in
156
- * the same request); falls back to a transient per-batch cache when standalone.
157
- */
158
- private checkMany;
96
+ allowsFor(user: User, first: string | Type<unknown>, rest: unknown[]): Promise<boolean>;
97
+ /** @internal */
98
+ authorizeFor(user: User, first: string | Type<unknown>, rest: unknown[]): Promise<void>;
99
+ /** @internal */
100
+ allowsManyFor(user: User, items: readonly BatchItem[]): Promise<BatchResult[]>;
159
101
  /**
160
- * One {@link DecisionProvider.decideMany} round-trip for a whole batch, when the provider
161
- * supports it. Returns `undefined` (→ per-item `decide`) otherwise. A batch-call failure makes
162
- * every item fall back to its own `decide` call rather than failing the batch.
102
+ * One `decideMany` round-trip to the external decision point for the string abilities
103
+ * of a batch, when it supports batching. Empty otherwise, and when the batch call fails
104
+ * (each item then asks `decide` on its own).
163
105
  */
164
106
  private prefetchDecisions;
165
- /** @internal — used by {@link BoundGate.authorize} to surface the deny reason/message. */
166
- decideForUser(user: MaybeUser, ability: string, resource?: Resource): Promise<{
167
- allowed: boolean;
168
- reason: AuthzDecisionReason;
169
- message?: string;
170
- }>;
171
107
  /** @internal */
172
- hasAnyRoleForUser(user: MaybeUser, roles: string[]): Promise<boolean>;
173
- /** @internal — used by {@link BoundGate.scope}. */
174
- scopeForUser(user: MaybeUser, entity: Type<unknown>, ability?: string): Promise<ScopeConstraint>;
175
- /**
176
- * Resolve a query-scope constraint for `entity`, mirroring {@link resolveBase}'s
177
- * grant order so scoping stays consistent with single-resource decisions:
178
- *
179
- * 1. super-admin hook grants → `allow-all`;
180
- * 1b. decision provider `planScope` → its constraint (unless it abstains);
181
- * 2. (authenticated) permission-provider grant for `ability` → `allow-all`;
182
- * 3. the policy's `scope` (or `viewAny`-style) method → its constraint;
183
- * 4. otherwise (anonymous, no policy, no scope method) → `deny-all`.
184
- *
185
- * The policy `before` hook is also honored as an allow/deny grant before the
186
- * scope method runs, so a policy that broadly allows/denies in `before` scopes
187
- * the same way it decides.
188
- */
189
- private resolveScope;
190
- /**
191
- * Pick the policy's scope method: the conventional `scope`, else the `ability`
192
- * method (e.g. `viewAny`) when it is scope-shaped. Returns `undefined` when the
193
- * policy declares neither.
194
- */
195
- private resolveScopeMethod;
196
- /**
197
- * Whether the registered {@link PermissionProvider} grants `ability` for an authenticated `user` —
198
- * the RBAC "before" grant shared by the single-resource ({@link resolveBase}) and scope
199
- * ({@link resolveScope}) paths, single-sourced here so the grant order can't drift between them.
200
- *
201
- * Grant-only: a `false`/nullish result is "no grant", never a deny. When the provider lists the
202
- * user's granted permissions, segment-based wildcard matching runs in the core (a granted
203
- * `posts.*` satisfies `posts.update`, `*` satisfies anything) regardless of adapter; a nullish
204
- * list defers to the exact-match `hasPermission`. The granted set is fetched through `cache` when
205
- * one is supplied, else via a direct fetch.
206
- */
207
- private permissionProviderGrants;
208
- /**
209
- * Resolve the user's effective roles and test membership against `roles`. Returns
210
- * `false` for an anonymous (NO_USER) caller and whenever no source yields a role
211
- * (deny-by-default). Roles come from the UNION of the default/overridden
212
- * {@link RoleResolver} (reads the user object) and the optional {@link RoleProvider}
213
- * seam (a persisted store) — so an app needs neither to opt in.
214
- */
215
- private checkRoles;
216
- /** The current user's effective role names (resolver ∪ provider). */
217
- private rolesOf;
218
- private check;
219
- /**
220
- * Resolve a decision AND publish it for observers. Returns the full decision
221
- * (verdict + reason + optional deny message) so {@link authorize} can surface the
222
- * `reason`/`message` on the thrown `ForbiddenException`. {@link check} discards
223
- * everything but the verdict.
224
- */
108
+ hasAnyRoleFor(user: User, roles: string[]): Promise<boolean>;
109
+ /** @internal */
110
+ scopeFor(user: User, entity: Type<unknown>, ability: string): Promise<ScopeConstraint>;
111
+ /** Decide, publish the decision, and (in `authorize` mode) let the official service emit its denial. */
225
112
  private decide;
226
- /**
227
- * Resolve an ability to a final verdict, the path that decided it, and an optional
228
- * deny message. Runs the global `after` hook over the base decision (see
229
- * {@link AfterHook} for override semantics). Throws
230
- * {@link AbilityNotResolvedException}/{@link AmbiguousAbilityException} when no
231
- * decision can be reached (those paths emit no decision and skip `after`).
232
- */
233
- private resolve;
234
- /**
235
- * The pre-`after` resolution. `allowed` is `undefined` when the deciding path
236
- * (policy method / ad-hoc gate) returned a nullish value — "no opinion" — which
237
- * lets the {@link AfterHook} supply a verdict before the default-deny finalize.
238
- */
239
- private resolveBase;
240
- private resolvePolicy;
113
+ private decidePolicy;
114
+ private decideString;
115
+ /** The linked policy defining `ability` for `resource` (or for no resource, unambiguously). */
116
+ private policyFor;
241
117
  }
242
- /**
243
- * A {@link Gate} bound to an explicit user. Returned by {@link Gate.forUser}.
244
- */
118
+ /** A {@link Gate} bound to an explicit user. Returned by {@link Gate.forUser}. */
245
119
  export declare class BoundGate {
246
120
  private readonly gate;
247
121
  private readonly user;
248
- constructor(gate: Gate, user: MaybeUser);
122
+ constructor(gate: Gate, user: User);
123
+ allows<P, const A extends Ability<P>>(policy: Type<P>, ability: A, ...args: AbilityArgsOf<P, A>): Promise<boolean>;
249
124
  allows(ability: string, resource?: Resource): Promise<boolean>;
125
+ denies<P, const A extends Ability<P>>(policy: Type<P>, ability: A, ...args: AbilityArgsOf<P, A>): Promise<boolean>;
250
126
  denies(ability: string, resource?: Resource): Promise<boolean>;
251
- /** Batch-authorize many abilities for the bound user in one pass (see {@link Gate.allowsMany}). */
252
- allowsMany(items: BatchAbility[]): Promise<BatchResult[]>;
253
- /** Resolve the query-scope constraint for the bound user (see {@link Gate.scope}). */
254
- scope(entity: Type<unknown>, ability?: string): Promise<ScopeConstraint>;
127
+ authorize<P, const A extends Ability<P>>(policy: Type<P>, ability: A, ...args: AbilityArgsOf<P, A>): Promise<void>;
255
128
  authorize(ability: string, resource?: Resource): Promise<void>;
256
- /** True when the bound user holds `role`. */
129
+ /** Batch-check for the bound user (see {@link Gate.allowsMany}). */
130
+ allowsMany(items: readonly BatchItem[]): Promise<BatchResult[]>;
131
+ /** The query scope for the bound user (see {@link Gate.scope}). */
132
+ scope(entity: Type<unknown>, ability?: string): Promise<ScopeConstraint>;
257
133
  hasRole(role: string): Promise<boolean>;
258
- /** True when the bound user holds ANY of `roles`. */
259
134
  hasAnyRole(roles: string[]): Promise<boolean>;
260
135
  }
261
- export {};
262
136
  //# sourceMappingURL=gate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}