@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/dist/tokens.js ADDED
@@ -0,0 +1,31 @@
1
+ /** Injection token holding the resolved {@link AuthzModuleOptions}. */
2
+ export const AUTHZ_MODULE_OPTIONS = Symbol.for('@dudousxd/nestjs-authz:options');
3
+ /** Injection token for the optional {@link ResourceResolver} registered by the app. */
4
+ export const RESOURCE_RESOLVER = Symbol.for('@dudousxd/nestjs-authz:resource-resolver');
5
+ /** Metadata key for `@Policy(Resource)` — stores the resource class on the policy. */
6
+ export const POLICY_RESOURCE_METADATA = 'nestjs-authz:policy-resource';
7
+ /** Metadata key for `@Can(ability, Resource?)` — stores the ability descriptor on a route. */
8
+ export const CAN_METADATA = 'nestjs-authz:can';
9
+ /**
10
+ * Cross-lib injection token for an optional {@link PermissionProvider} — the seam the
11
+ * RBAC adapter (`@dudousxd/nestjs-authz-typeorm`) registers so that a model-less,
12
+ * named ability (`gate.allows('posts.publish')`) is granted when the current user
13
+ * holds that persisted permission. This is the Laravel/spatie `Gate::before` grant.
14
+ *
15
+ * `Symbol.for(key)` uses the global symbol registry so an RBAC package registering
16
+ * this same key resolves to the SAME symbol instance without importing core internals.
17
+ * The token is consulted with `@Optional()` — when absent, the Gate behaves exactly
18
+ * as before (backward-compatible: unknown abilities still throw).
19
+ */
20
+ export const PERMISSION_PROVIDER = Symbol.for('@dudousxd/nestjs-authz:permission-provider');
21
+ /**
22
+ * Cross-lib injection token for the current-request context accessor, owned by
23
+ * `@dudousxd/nestjs-context`. We do NOT import nestjs-context — instead we share
24
+ * its well-known token by value so DI resolves the same provider when present.
25
+ *
26
+ * `Symbol.for(key)` uses the global symbol registry, so this resolves to the
27
+ * SAME symbol instance as nestjs-context's `tokens.ts` without any import.
28
+ * The key MUST stay byte-identical with nestjs-context's export.
29
+ */
30
+ export const CONTEXT_ACCESSOR = Symbol.for('@dudousxd/nestjs-context:accessor');
31
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;AAEjF,uFAAuF;AACvF,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AAExF,sFAAsF;AACtF,MAAM,CAAC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC;AAEvE,8FAA8F;AAC9F,MAAM,CAAC,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;AAE5F;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC"}
@@ -0,0 +1,97 @@
1
+ import type { Type } from '@nestjs/common';
2
+ import type { UserRef } from './context-accessor.js';
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
+ */
8
+ export type Resource = object;
9
+ /**
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).
12
+ */
13
+ export type User = unknown;
14
+ /**
15
+ * A policy method: decides a single ability for a `(user, resource?)` pair.
16
+ * Class-level abilities (e.g. `create`) omit the resource. May be async.
17
+ */
18
+ export type PolicyMethod = (user: User, resource?: Resource) => boolean | Promise<boolean>;
19
+ /**
20
+ * Optional per-policy `before` hook. Runs before the ability method.
21
+ * - return `true` → allow (short-circuit)
22
+ * - return `false` → deny (short-circuit)
23
+ * - return `void`/`undefined` → fall through to the ability method
24
+ */
25
+ export type PolicyBeforeHook = (user: User, ability: string) => boolean | undefined | Promise<boolean | undefined>;
26
+ /** A policy instance is an arbitrary object whose methods are abilities. */
27
+ export type PolicyInstance = Record<string, unknown> & {
28
+ before?: PolicyBeforeHook;
29
+ };
30
+ /**
31
+ * An ad-hoc gate: a model-less ability resolved by name via `gate.define`.
32
+ */
33
+ export type GateFn = (user: User, resource?: Resource) => boolean | Promise<boolean>;
34
+ /**
35
+ * Global super-admin before-hook. Runs before any policy/gate; truthy → allow.
36
+ * `void`/`undefined`/`false` falls through to normal resolution.
37
+ */
38
+ export type SuperAdminHook = (user: User, ability: string) => boolean | undefined | Promise<boolean | undefined>;
39
+ export interface AuthzModuleOptions {
40
+ /**
41
+ * Policy classes to register explicitly. Each must be decorated with
42
+ * `@Policy(Resource)`. Auto-discovery of `@Policy` providers also works, so
43
+ * this is optional.
44
+ */
45
+ policies?: Array<Type<PolicyInstance>>;
46
+ /**
47
+ * Global super-admin before-hook applied to every authorization check. Return
48
+ * `true` to grant (e.g. super-admins). Returning `void`/`false` falls through.
49
+ *
50
+ * ⚠️ IMPORTANT — what `user` is: on the **context path** (no `forUser`), the
51
+ * `user` passed here is the raw {@link UserRef} from nestjs-context — just
52
+ * `{ type, id }`, NOT your hydrated user entity. So `superAdmin: u => u.isAdmin`
53
+ * will NOT fire from a route/`gate.allows(...)` unless you also configure
54
+ * {@link AuthzModuleOptions.resolveUser} to hydrate the full entity. On the
55
+ * explicit `gate.forUser(entity)` path you receive exactly what you passed.
56
+ */
57
+ superAdmin?: SuperAdminHook;
58
+ /**
59
+ * Optional hook to hydrate the full user entity from the context's
60
+ * {@link UserRef} (`{ type, id }`) before policies / `before` / `superAdmin`
61
+ * run. WITHOUT this hook, the context path passes only `{ type, id }` to those
62
+ * functions (it does not load your `User` row), so property checks such as
63
+ * `superAdmin: u => u.isAdmin` or `post.authorId === user.id` against a real
64
+ * column will not see hydrated fields. Provide `resolveUser` to load the entity
65
+ * (e.g. from your ORM) keyed by the ref. Returning `undefined` is treated as
66
+ * "no user" (deny path), identical to an anonymous request.
67
+ *
68
+ * Only affects the context path; `gate.forUser(entity)` always uses the value
69
+ * you pass directly and never invokes this hook.
70
+ */
71
+ resolveUser?: (ref: UserRef) => User | undefined | Promise<User | undefined>;
72
+ /**
73
+ * Override the default {@link ResourceResolver} used to load an instance for
74
+ * `@Can(ability, Resource)` routes. Defaults to {@link IdParamResourceResolver}
75
+ * (reads the route `:id` param), registered automatically by `forRoot`. Apps
76
+ * needing real ORM entities provide their own here (or bind the
77
+ * `RESOURCE_RESOLVER` token directly).
78
+ */
79
+ resourceResolver?: ResourceResolver;
80
+ /**
81
+ * Route param name the default {@link IdParamResourceResolver} reads to build
82
+ * the resource shim. Defaults to `'id'`. Ignored when {@link resourceResolver}
83
+ * is supplied.
84
+ */
85
+ idParam?: string;
86
+ }
87
+ export interface AuthzModuleOptionsFactory {
88
+ createAuthzOptions(): Promise<AuthzModuleOptions> | AuthzModuleOptions;
89
+ }
90
+ export interface AuthzModuleAsyncOptions {
91
+ imports?: unknown[];
92
+ useExisting?: Type<AuthzModuleOptionsFactory>;
93
+ useClass?: Type<AuthzModuleOptionsFactory>;
94
+ useFactory?: (...args: unknown[]) => Promise<AuthzModuleOptions> | AuthzModuleOptions;
95
+ inject?: unknown[];
96
+ }
97
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B;;;GAGG;AACH,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,QAAQ,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAE3F;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,KACZ,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;AAExD,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACrD,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,QAAQ,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAErF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,KACZ,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;AAExD,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IACvC;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IAC7E;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACxC,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC,GAAG,kBAAkB,CAAC;CACxE;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,kBAAkB,CAAC,GAAG,kBAAkB,CAAC;IACtF,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@dudousxd/nestjs-authz",
3
+ "version": "0.2.0",
4
+ "description": "NestJS authorization — Laravel-style Gates & Policies, @Can guard, resource resolver (zero DB).",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/DavideCarvalho/nestjs-authz.git",
9
+ "directory": "packages/core"
10
+ },
11
+ "author": "Davi Carvalho <davi@goflip.ai>",
12
+ "type": "module",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js",
19
+ "default": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist/",
24
+ "README.md",
25
+ "CHANGELOG.md"
26
+ ],
27
+ "peerDependencies": {
28
+ "@dudousxd/nestjs-context": ">=0.1.0",
29
+ "@nestjs/common": ">=10.0.0",
30
+ "@nestjs/core": ">=10.0.0",
31
+ "reflect-metadata": ">=0.1.13"
32
+ },
33
+ "peerDependenciesMeta": {
34
+ "@dudousxd/nestjs-context": {
35
+ "optional": true
36
+ }
37
+ },
38
+ "devDependencies": {
39
+ "@nestjs/common": "^11.0.0",
40
+ "@nestjs/core": "^11.0.0",
41
+ "@nestjs/platform-express": "^11.0.0",
42
+ "@nestjs/testing": "^11.0.0",
43
+ "@types/express": "^4.17.21",
44
+ "@types/node": "^20.0.0",
45
+ "@types/supertest": "^6.0.2",
46
+ "express": "^4.19.2",
47
+ "reflect-metadata": "^0.2.2",
48
+ "rxjs": "^7.8.1",
49
+ "supertest": "^7.0.0",
50
+ "typescript": "^5.4.0",
51
+ "vitest": "^3.0.0"
52
+ },
53
+ "engines": {
54
+ "node": ">=20"
55
+ },
56
+ "keywords": [
57
+ "nestjs",
58
+ "authorization",
59
+ "authz",
60
+ "gate",
61
+ "policy",
62
+ "acl",
63
+ "rbac"
64
+ ],
65
+ "scripts": {
66
+ "build": "tsc -p tsconfig.json",
67
+ "test": "vitest run --passWithNoTests",
68
+ "test:watch": "vitest",
69
+ "typecheck": "tsc -p tsconfig.json --noEmit"
70
+ }
71
+ }