@grantjs/server 1.0.0 → 1.1.1

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 (63) hide show
  1. package/README.md +1 -1
  2. package/dist/debug-DICR8lwQ.js +15 -0
  3. package/dist/debug-DICR8lwQ.js.map +1 -0
  4. package/dist/debug-DInHA4QB.cjs +20 -0
  5. package/dist/debug-DInHA4QB.cjs.map +1 -0
  6. package/dist/errors-BUeTn_3G.cjs +91 -0
  7. package/dist/errors-BUeTn_3G.cjs.map +1 -0
  8. package/dist/errors-CSC_Z_KP.js +62 -0
  9. package/dist/errors-CSC_Z_KP.js.map +1 -0
  10. package/dist/express/index.d.ts +3 -3
  11. package/dist/express/index.d.ts.map +1 -1
  12. package/dist/express/middleware.d.ts +2 -2
  13. package/dist/express/middleware.d.ts.map +1 -1
  14. package/dist/express.cjs +106 -95
  15. package/dist/express.cjs.map +1 -1
  16. package/dist/express.mjs +101 -99
  17. package/dist/express.mjs.map +1 -1
  18. package/dist/fastify/index.d.ts +4 -4
  19. package/dist/fastify/index.d.ts.map +1 -1
  20. package/dist/fastify/plugin.d.ts +2 -2
  21. package/dist/fastify/plugin.d.ts.map +1 -1
  22. package/dist/fastify.cjs +133 -97
  23. package/dist/fastify.cjs.map +1 -1
  24. package/dist/fastify.mjs +128 -101
  25. package/dist/fastify.mjs.map +1 -1
  26. package/dist/grant-client-f6IKMyk5.cjs +228 -0
  27. package/dist/grant-client-f6IKMyk5.cjs.map +1 -0
  28. package/dist/grant-client-t3KadxFo.js +205 -0
  29. package/dist/grant-client-t3KadxFo.js.map +1 -0
  30. package/dist/grant-client.d.ts +1 -1
  31. package/dist/grant-client.d.ts.map +1 -1
  32. package/dist/index.cjs +10 -49
  33. package/dist/index.d.ts +4 -4
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.mjs +3 -50
  36. package/dist/nest/grant.guard.d.ts +1 -1
  37. package/dist/nest/grant.guard.d.ts.map +1 -1
  38. package/dist/nest/grant.module.d.ts.map +1 -1
  39. package/dist/nest/index.d.ts +6 -6
  40. package/dist/nest/index.d.ts.map +1 -1
  41. package/dist/nest.cjs +163 -143
  42. package/dist/nest.cjs.map +1 -1
  43. package/dist/nest.mjs +150 -149
  44. package/dist/nest.mjs.map +1 -1
  45. package/dist/next/index.d.ts +4 -4
  46. package/dist/next/index.d.ts.map +1 -1
  47. package/dist/next/with-grant.d.ts +1 -1
  48. package/dist/next/with-grant.d.ts.map +1 -1
  49. package/dist/next.cjs +75 -58
  50. package/dist/next.cjs.map +1 -1
  51. package/dist/next.mjs +70 -60
  52. package/dist/next.mjs.map +1 -1
  53. package/package.json +17 -17
  54. package/dist/debug-C8ibbrE5.js +0 -9
  55. package/dist/debug-C8ibbrE5.js.map +0 -1
  56. package/dist/debug-Crb5gNDM.cjs +0 -8
  57. package/dist/debug-Crb5gNDM.cjs.map +0 -1
  58. package/dist/grant-client-D1LZI2f4.js +0 -180
  59. package/dist/grant-client-D1LZI2f4.js.map +0 -1
  60. package/dist/grant-client-DywfJN5P.cjs +0 -179
  61. package/dist/grant-client-DywfJN5P.cjs.map +0 -1
  62. package/dist/index.cjs.map +0 -1
  63. package/dist/index.mjs.map +0 -1
package/dist/nest.cjs CHANGED
@@ -1,154 +1,174 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
6
- const common = require("@nestjs/common");
7
- const debug = require("./debug-Crb5gNDM.cjs");
8
- const grantClient = require("./grant-client-DywfJN5P.cjs");
9
- const GRANT_OPTIONS_KEY = "grant:options";
2
+ const require_grant_client = require("./grant-client-f6IKMyk5.cjs");
3
+ const require_debug = require("./debug-DInHA4QB.cjs");
4
+ let _nestjs_common = require("@nestjs/common");
5
+ //#region src/nest/grant.decorator.ts
6
+ /**
7
+ * Metadata key for Grant options (resource, action) on route handlers.
8
+ * Used by GrantGuard when options are not passed in the constructor.
9
+ */
10
+ var GRANT_OPTIONS_KEY = "grant:options";
10
11
  function Grant(resourceOrOptions, action) {
11
- const options = typeof resourceOrOptions === "string" && action !== void 0 ? { resource: resourceOrOptions, action } : resourceOrOptions;
12
- return common.SetMetadata(GRANT_OPTIONS_KEY, options);
12
+ return (0, _nestjs_common.SetMetadata)(GRANT_OPTIONS_KEY, typeof resourceOrOptions === "string" && action !== void 0 ? {
13
+ resource: resourceOrOptions,
14
+ action
15
+ } : resourceOrOptions);
13
16
  }
14
- var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
15
- var __decorateClass$1 = (decorators, target, key, kind) => {
16
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
17
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
18
- if (decorator = decorators[i])
19
- result = decorator(result) || result;
20
- return result;
21
- };
22
- const GRANT_CLIENT = "GrantClient";
23
- exports.GrantModule = class GrantModule {
24
- static forRoot(config) {
25
- const client = new grantClient.GrantClient(config);
26
- return {
27
- module: exports.GrantModule,
28
- providers: [
29
- { provide: grantClient.GrantClient, useValue: client },
30
- { provide: GRANT_CLIENT, useValue: client }
31
- ],
32
- exports: [grantClient.GrantClient, GRANT_CLIENT]
33
- };
34
- }
35
- };
36
- exports.GrantModule = __decorateClass$1([
37
- common.Global(),
38
- common.Module({})
39
- ], exports.GrantModule);
40
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
41
- var __decorateClass = (decorators, target, key, kind) => {
42
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
43
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
44
- if (decorator = decorators[i])
45
- result = decorator(result) || result;
46
- return result;
17
+ //#endregion
18
+ //#region \0@oxc-project+runtime@0.127.0/helpers/decorate.js
19
+ function __decorate(decorators, target, key, desc) {
20
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
21
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
22
+ 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;
23
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
24
+ }
25
+ //#endregion
26
+ //#region src/nest/grant.module.ts
27
+ var _GrantModule;
28
+ var GRANT_CLIENT = "GrantClient";
29
+ var GrantModule = _GrantModule = class GrantModule {
30
+ static forRoot(config) {
31
+ const client = new require_grant_client.GrantClient(config);
32
+ return {
33
+ module: _GrantModule,
34
+ providers: [{
35
+ provide: require_grant_client.GrantClient,
36
+ useValue: client
37
+ }, {
38
+ provide: GRANT_CLIENT,
39
+ useValue: client
40
+ }],
41
+ exports: [require_grant_client.GrantClient, GRANT_CLIENT]
42
+ };
43
+ }
47
44
  };
48
- var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
49
- const GRANT_GUARD = "GrantGuard";
45
+ GrantModule = _GrantModule = __decorate([(0, _nestjs_common.Global)(), (0, _nestjs_common.Module)({})], GrantModule);
46
+ //#endregion
47
+ //#region \0@oxc-project+runtime@0.127.0/helpers/decorateMetadata.js
48
+ function __decorateMetadata(k, v) {
49
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
50
+ }
51
+ //#endregion
52
+ //#region \0@oxc-project+runtime@0.127.0/helpers/decorateParam.js
53
+ function __decorateParam(paramIndex, decorator) {
54
+ return function(target, key) {
55
+ decorator(target, key, paramIndex);
56
+ };
57
+ }
58
+ //#endregion
59
+ //#region src/nest/grant.guard.ts
60
+ var _ref;
61
+ /** Injection token for GrantGuard. Use with @UseGuards(GRANT_GUARD) so Nest resolves the guard from the container (with GrantClient injected). */
62
+ var GRANT_GUARD = "GrantGuard";
63
+ /**
64
+ * NestJS guard that checks Grant authorization before allowing access to a route.
65
+ *
66
+ * Use in one of two ways:
67
+ *
68
+ * 1. With decorator (resource/action from metadata):
69
+ * - Import GrantModule.forRoot() in AppModule. In a feature module, add
70
+ * `{ provide: GRANT_GUARD, useClass: GrantGuard }` and use @Grant + @UseGuards(GRANT_GUARD).
71
+ * - Using the GRANT_GUARD token ensures Nest resolves the guard from the container (GrantClient injected).
72
+ *
73
+ * 2. With explicit options (supports resourceResolver):
74
+ * - @UseGuards(new GrantGuard(grantClient, { resource: 'Document', action: 'Update', resourceResolver: async ({ request }) => ... }))
75
+ *
76
+ * On success, the authorization result is attached to the request as request.authorization.
77
+ * On failure, throws UnauthorizedException (401), ForbiddenException (403), or NotFoundException (404).
78
+ */
50
79
  function isGrantGuardOptions(x) {
51
- return typeof x === "object" && x !== null && "resource" in x && "action" in x && typeof x.resource === "string" && typeof x.action === "string";
80
+ return typeof x === "object" && x !== null && "resource" in x && "action" in x && typeof x.resource === "string" && typeof x.action === "string";
52
81
  }
53
- exports.GrantGuard = class GrantGuard {
54
- constructor(client, reflectorOrOptions) {
55
- __publicField(this, "explicitOptions");
56
- __publicField(this, "reflector");
57
- this.client = client;
58
- if (reflectorOrOptions && isGrantGuardOptions(reflectorOrOptions)) {
59
- this.explicitOptions = reflectorOrOptions;
60
- } else {
61
- this.reflector = reflectorOrOptions;
62
- }
63
- }
64
- getOptionsFromContext(context) {
65
- const handler = context.getHandler();
66
- const clazz = context.getClass();
67
- if (this.reflector) {
68
- const fromHandler = this.reflector.get(GRANT_OPTIONS_KEY, handler);
69
- const fromClass = this.reflector.get(GRANT_OPTIONS_KEY, clazz);
70
- if (fromHandler) return fromHandler;
71
- if (fromClass) return fromClass;
72
- }
73
- if (typeof Reflect !== "undefined" && typeof Reflect.getMetadata === "function") {
74
- const fromHandler = Reflect.getMetadata(GRANT_OPTIONS_KEY, handler);
75
- const fromClass = Reflect.getMetadata(GRANT_OPTIONS_KEY, clazz);
76
- if (fromHandler) return fromHandler;
77
- if (fromClass) return fromClass;
78
- }
79
- return void 0;
80
- }
81
- async canActivate(context) {
82
- const request = context.switchToHttp().getRequest();
83
- const options = this.explicitOptions ?? this.getOptionsFromContext(context);
84
- if (options?.resource && options?.action) {
85
- debug.debugGrant("Nest", {
86
- resource: options.resource,
87
- action: options.action,
88
- hasReflector: !!this.reflector,
89
- handler: context.getHandler()?.name,
90
- controller: context.getClass()?.name
91
- });
92
- }
93
- if (!options || !options.resource || !options.action) {
94
- throw new common.ForbiddenException(
95
- "Grant options (resource, action) required. Use @Grant() or pass options to GrantGuard."
96
- );
97
- }
98
- if (!this.client) {
99
- throw new common.ForbiddenException(
100
- "GrantGuard: GrantClient not injected. Import GrantModule.forRoot() in AppModule and register GrantGuard as a provider."
101
- );
102
- }
103
- const token = await grantClient.extractTokenFromRequest(request, this.client.config);
104
- if (!token) {
105
- throw new common.UnauthorizedException({ error: "Unauthorized", code: "UNAUTHENTICATED" });
106
- }
107
- let resolvedResource = null;
108
- const opts = options;
109
- if (opts.resourceResolver) {
110
- resolvedResource = await opts.resourceResolver({
111
- resourceSlug: options.resource,
112
- request
113
- });
114
- if (!resolvedResource) {
115
- throw new common.NotFoundException({ error: "Resource not found", code: "NOT_FOUND" });
116
- }
117
- }
118
- const result = await this.client.isAuthorized(
119
- options.resource,
120
- options.action,
121
- {
122
- context: {
123
- resource: resolvedResource ?? void 0
124
- }
125
- },
126
- request
127
- );
128
- debug.debugGrant("Nest", {
129
- resource: options.resource,
130
- action: options.action,
131
- authorized: result.authorized,
132
- ...result.authorized ? {} : { reason: result.reason }
133
- });
134
- if (!result.authorized) {
135
- throw new common.ForbiddenException({
136
- error: "Forbidden",
137
- code: "FORBIDDEN",
138
- reason: result.reason
139
- });
140
- }
141
- request.authorization = result;
142
- return true;
143
- }
82
+ var GrantGuard = class GrantGuard {
83
+ constructor(client, reflectorOrOptions) {
84
+ require_grant_client._defineProperty(this, "explicitOptions", void 0);
85
+ require_grant_client._defineProperty(this, "reflector", void 0);
86
+ this.client = client;
87
+ if (reflectorOrOptions && isGrantGuardOptions(reflectorOrOptions)) this.explicitOptions = reflectorOrOptions;
88
+ else this.reflector = reflectorOrOptions;
89
+ }
90
+ getOptionsFromContext(context) {
91
+ const handler = context.getHandler();
92
+ const clazz = context.getClass();
93
+ if (this.reflector) {
94
+ const fromHandler = this.reflector.get(GRANT_OPTIONS_KEY, handler);
95
+ const fromClass = this.reflector.get(GRANT_OPTIONS_KEY, clazz);
96
+ if (fromHandler) return fromHandler;
97
+ if (fromClass) return fromClass;
98
+ }
99
+ if (typeof Reflect !== "undefined" && typeof Reflect.getMetadata === "function") {
100
+ const fromHandler = Reflect.getMetadata(GRANT_OPTIONS_KEY, handler);
101
+ const fromClass = Reflect.getMetadata(GRANT_OPTIONS_KEY, clazz);
102
+ if (fromHandler) return fromHandler;
103
+ if (fromClass) return fromClass;
104
+ }
105
+ }
106
+ async canActivate(context) {
107
+ const request = context.switchToHttp().getRequest();
108
+ const options = this.explicitOptions ?? this.getOptionsFromContext(context);
109
+ if (options?.resource && options?.action) require_debug.debugGrant("Nest", {
110
+ resource: options.resource,
111
+ action: options.action,
112
+ hasReflector: !!this.reflector,
113
+ handler: context.getHandler()?.name,
114
+ controller: context.getClass()?.name
115
+ });
116
+ if (!options || !options.resource || !options.action) throw new _nestjs_common.ForbiddenException("Grant options (resource, action) required. Use @Grant() or pass options to GrantGuard.");
117
+ if (!this.client) throw new _nestjs_common.ForbiddenException("GrantGuard: GrantClient not injected. Import GrantModule.forRoot() in AppModule and register GrantGuard as a provider.");
118
+ if (!await require_grant_client.extractTokenFromRequest(request, this.client.config)) throw new _nestjs_common.UnauthorizedException({
119
+ error: "Unauthorized",
120
+ code: "UNAUTHENTICATED"
121
+ });
122
+ let resolvedResource = null;
123
+ const opts = options;
124
+ if (opts.resourceResolver) {
125
+ resolvedResource = await opts.resourceResolver({
126
+ resourceSlug: options.resource,
127
+ request
128
+ });
129
+ if (!resolvedResource) throw new _nestjs_common.NotFoundException({
130
+ error: "Resource not found",
131
+ code: "NOT_FOUND"
132
+ });
133
+ }
134
+ const result = await this.client.isAuthorized(options.resource, options.action, { context: { resource: resolvedResource ?? void 0 } }, request);
135
+ require_debug.debugGrant("Nest", {
136
+ resource: options.resource,
137
+ action: options.action,
138
+ authorized: result.authorized,
139
+ ...result.authorized ? {} : { reason: result.reason }
140
+ });
141
+ if (!result.authorized) throw new _nestjs_common.ForbiddenException({
142
+ error: "Forbidden",
143
+ code: "FORBIDDEN",
144
+ reason: result.reason
145
+ });
146
+ request.authorization = result;
147
+ return true;
148
+ }
144
149
  };
145
- exports.GrantGuard = __decorateClass([
146
- common.Injectable(),
147
- __decorateParam(0, common.Inject(GRANT_CLIENT))
148
- ], exports.GrantGuard);
149
- exports.GrantClient = grantClient.GrantClient;
150
+ GrantGuard = __decorate([
151
+ (0, _nestjs_common.Injectable)(),
152
+ __decorateParam(0, (0, _nestjs_common.Inject)(GRANT_CLIENT)),
153
+ __decorateMetadata("design:paramtypes", [typeof (_ref = typeof require_grant_client.GrantClient !== "undefined" && require_grant_client.GrantClient) === "function" ? _ref : Object, Object])
154
+ ], GrantGuard);
155
+ //#endregion
150
156
  exports.GRANT_CLIENT = GRANT_CLIENT;
151
157
  exports.GRANT_GUARD = GRANT_GUARD;
152
158
  exports.GRANT_OPTIONS_KEY = GRANT_OPTIONS_KEY;
153
159
  exports.Grant = Grant;
154
- //# sourceMappingURL=nest.cjs.map
160
+ exports.GrantClient = require_grant_client.GrantClient;
161
+ Object.defineProperty(exports, "GrantGuard", {
162
+ enumerable: true,
163
+ get: function() {
164
+ return GrantGuard;
165
+ }
166
+ });
167
+ Object.defineProperty(exports, "GrantModule", {
168
+ enumerable: true,
169
+ get: function() {
170
+ return GrantModule;
171
+ }
172
+ });
173
+
174
+ //# sourceMappingURL=nest.cjs.map
package/dist/nest.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"nest.cjs","sources":["../src/nest/grant.decorator.ts","../src/nest/grant.module.ts","../src/nest/grant.guard.ts"],"sourcesContent":["import { SetMetadata } from '@nestjs/common';\n\n/**\n * Metadata key for Grant options (resource, action) on route handlers.\n * Used by GrantGuard when options are not passed in the constructor.\n */\nexport const GRANT_OPTIONS_KEY = 'grant:options';\n\n/**\n * Options for the Grant guard (resource, action; resourceResolver only via guard constructor).\n */\nexport interface GrantOptions {\n /** The resource slug to check (e.g., \"Organization\", \"Project\", \"Document\") */\n resource: string;\n /** The action to check (e.g., \"Query\", \"Create\", \"Update\", \"Delete\") */\n action: string;\n}\n\n/**\n * Decorator to require a Grant permission on a route.\n * Use with GrantGuard (injected) so the guard reads resource/action from this metadata.\n *\n * @example\n * ```ts\n * @Get()\n * @Grant('Document', 'Query')\n * @UseGuards(GrantGuard)\n * list() { ... }\n *\n * @Post()\n * @Grant('Document', 'Create')\n * @UseGuards(GrantGuard)\n * create(@Body() dto: CreateDocumentDto) { ... }\n * ```\n *\n * For dynamic resource resolution (resourceResolver), use the guard with explicit options:\n * `@UseGuards(new GrantGuard(grantClient, { resource: 'Document', action: 'Update', resourceResolver: ... }))`\n */\nexport function Grant(resource: string, action: string): ReturnType<typeof SetMetadata>;\nexport function Grant(options: GrantOptions): ReturnType<typeof SetMetadata>;\nexport function Grant(\n resourceOrOptions: string | GrantOptions,\n action?: string\n): ReturnType<typeof SetMetadata> {\n const options: GrantOptions =\n typeof resourceOrOptions === 'string' && action !== undefined\n ? { resource: resourceOrOptions, action }\n : (resourceOrOptions as GrantOptions);\n return SetMetadata(GRANT_OPTIONS_KEY, options);\n}\n","import { DynamicModule, Global, Module } from '@nestjs/common';\n\nimport { GrantClient } from '../grant-client';\n\nimport type { GrantServerConfig } from '../types';\n\nexport const GRANT_CLIENT = 'GrantClient';\n\n/**\n * NestJS module that provides GrantClient for injection.\n *\n * @example\n * ```ts\n * // app.module.ts\n * import { GrantModule } from '@grantjs/server/nest';\n *\n * @Module({\n * imports: [\n * GrantModule.forRoot({\n * apiUrl: process.env.GRANT_API_URL!,\n * getToken: (req) => req.headers?.authorization?.replace?.('Bearer ', '') ?? null,\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n *\n * Then inject GrantClient in controllers and use with GrantGuard.\n */\n@Global()\n@Module({})\nexport class GrantModule {\n static forRoot(config: GrantServerConfig): DynamicModule {\n const client = new GrantClient(config);\n return {\n module: GrantModule,\n providers: [\n { provide: GrantClient, useValue: client },\n { provide: GRANT_CLIENT, useValue: client },\n ],\n exports: [GrantClient, GRANT_CLIENT],\n };\n }\n}\n","import {\n CanActivate,\n ExecutionContext,\n ForbiddenException,\n Inject,\n Injectable,\n NotFoundException,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\n\nimport { GrantClient } from '../grant-client';\nimport { debugGrant } from '../utils/debug';\nimport { extractTokenFromRequest } from '../utils/token-extractor';\n\nimport { GRANT_OPTIONS_KEY } from './grant.decorator';\nimport { GRANT_CLIENT } from './grant.module';\n\n/** Injection token for GrantGuard. Use with @UseGuards(GRANT_GUARD) so Nest resolves the guard from the container (with GrantClient injected). */\nexport const GRANT_GUARD = 'GrantGuard';\n\nimport type { ResourceResolver, AuthorizationResult } from '../types';\nimport type { GrantOptions } from './grant.decorator';\n\n/**\n * Extended request type with Grant authorization result (for use in controllers).\n */\nexport interface AuthorizedRequest {\n authorization?: AuthorizationResult;\n}\n\n/**\n * Guard options when using explicit options (includes optional resourceResolver).\n */\nexport interface GrantGuardOptions {\n resource: string;\n action: string;\n resourceResolver?: ResourceResolver;\n}\n\n/**\n * NestJS guard that checks Grant authorization before allowing access to a route.\n *\n * Use in one of two ways:\n *\n * 1. With decorator (resource/action from metadata):\n * - Import GrantModule.forRoot() in AppModule. In a feature module, add\n * `{ provide: GRANT_GUARD, useClass: GrantGuard }` and use @Grant + @UseGuards(GRANT_GUARD).\n * - Using the GRANT_GUARD token ensures Nest resolves the guard from the container (GrantClient injected).\n *\n * 2. With explicit options (supports resourceResolver):\n * - @UseGuards(new GrantGuard(grantClient, { resource: 'Document', action: 'Update', resourceResolver: async ({ request }) => ... }))\n *\n * On success, the authorization result is attached to the request as request.authorization.\n * On failure, throws UnauthorizedException (401), ForbiddenException (403), or NotFoundException (404).\n */\nfunction isGrantGuardOptions(x: unknown): x is GrantGuardOptions {\n return (\n typeof x === 'object' &&\n x !== null &&\n 'resource' in x &&\n 'action' in x &&\n typeof (x as GrantGuardOptions).resource === 'string' &&\n typeof (x as GrantGuardOptions).action === 'string'\n );\n}\n\n@Injectable()\nexport class GrantGuard implements CanActivate {\n private readonly explicitOptions?: GrantGuardOptions;\n private readonly reflector?: Reflector;\n\n constructor(\n @Inject(GRANT_CLIENT) private readonly client: GrantClient,\n reflectorOrOptions?: Reflector | GrantGuardOptions\n ) {\n if (reflectorOrOptions && isGrantGuardOptions(reflectorOrOptions)) {\n this.explicitOptions = reflectorOrOptions;\n } else {\n this.reflector = reflectorOrOptions as Reflector | undefined;\n }\n }\n\n private getOptionsFromContext(context: ExecutionContext): GrantOptions | undefined {\n const handler = context.getHandler();\n const clazz = context.getClass();\n // Prefer Reflector when available (Nest DI)\n if (this.reflector) {\n const fromHandler = this.reflector.get<GrantOptions>(GRANT_OPTIONS_KEY, handler);\n const fromClass = this.reflector.get<GrantOptions>(GRANT_OPTIONS_KEY, clazz);\n if (fromHandler) return fromHandler;\n if (fromClass) return fromClass;\n }\n // Fallback: read metadata via Reflect (works when Reflector is not injected, e.g. ESM/CJS boundary)\n if (typeof Reflect !== 'undefined' && typeof Reflect.getMetadata === 'function') {\n const fromHandler = Reflect.getMetadata(GRANT_OPTIONS_KEY, handler) as\n | GrantOptions\n | undefined;\n const fromClass = Reflect.getMetadata(GRANT_OPTIONS_KEY, clazz) as GrantOptions | undefined;\n if (fromHandler) return fromHandler;\n if (fromClass) return fromClass;\n }\n return undefined;\n }\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest();\n\n const options = this.explicitOptions ?? this.getOptionsFromContext(context);\n\n if (options?.resource && options?.action) {\n debugGrant('Nest', {\n resource: options.resource,\n action: options.action,\n hasReflector: !!this.reflector,\n handler: context.getHandler()?.name,\n controller: context.getClass()?.name,\n });\n }\n\n if (!options || !options.resource || !options.action) {\n throw new ForbiddenException(\n 'Grant options (resource, action) required. Use @Grant() or pass options to GrantGuard.'\n );\n }\n\n if (!this.client) {\n throw new ForbiddenException(\n 'GrantGuard: GrantClient not injected. Import GrantModule.forRoot() in AppModule and register GrantGuard as a provider.'\n );\n }\n\n const token = await extractTokenFromRequest(request, this.client.config);\n if (!token) {\n throw new UnauthorizedException({ error: 'Unauthorized', code: 'UNAUTHENTICATED' });\n }\n\n let resolvedResource: Record<string, unknown> | null = null;\n\n const opts = options as GrantGuardOptions;\n if (opts.resourceResolver) {\n resolvedResource = await opts.resourceResolver({\n resourceSlug: options.resource,\n request,\n });\n if (!resolvedResource) {\n throw new NotFoundException({ error: 'Resource not found', code: 'NOT_FOUND' });\n }\n }\n\n const result = await this.client.isAuthorized(\n options.resource,\n options.action,\n {\n context: {\n resource: resolvedResource ?? undefined,\n },\n },\n request\n );\n\n debugGrant('Nest', {\n resource: options.resource,\n action: options.action,\n authorized: result.authorized,\n ...(result.authorized ? {} : { reason: result.reason }),\n });\n\n if (!result.authorized) {\n throw new ForbiddenException({\n error: 'Forbidden',\n code: 'FORBIDDEN',\n reason: result.reason,\n });\n }\n\n (request as AuthorizedRequest).authorization = result;\n return true;\n }\n}\n"],"names":["SetMetadata","GrantModule","GrantClient","__decorateClass","Global","Module","GrantGuard","debugGrant","ForbiddenException","extractTokenFromRequest","UnauthorizedException","NotFoundException","Injectable"],"mappings":"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"}
1
+ {"version":3,"file":"nest.cjs","names":[],"sources":["../src/nest/grant.decorator.ts","../src/nest/grant.module.ts","../src/nest/grant.guard.ts"],"sourcesContent":["import { SetMetadata } from '@nestjs/common';\n\n/**\n * Metadata key for Grant options (resource, action) on route handlers.\n * Used by GrantGuard when options are not passed in the constructor.\n */\nexport const GRANT_OPTIONS_KEY = 'grant:options';\n\n/**\n * Options for the Grant guard (resource, action; resourceResolver only via guard constructor).\n */\nexport interface GrantOptions {\n /** The resource slug to check (e.g., \"Organization\", \"Project\", \"Document\") */\n resource: string;\n /** The action to check (e.g., \"Query\", \"Create\", \"Update\", \"Delete\") */\n action: string;\n}\n\n/**\n * Decorator to require a Grant permission on a route.\n * Use with GrantGuard (injected) so the guard reads resource/action from this metadata.\n *\n * @example\n * ```ts\n * @Get()\n * @Grant('Document', 'Query')\n * @UseGuards(GrantGuard)\n * list() { ... }\n *\n * @Post()\n * @Grant('Document', 'Create')\n * @UseGuards(GrantGuard)\n * create(@Body() dto: CreateDocumentDto) { ... }\n * ```\n *\n * For dynamic resource resolution (resourceResolver), use the guard with explicit options:\n * `@UseGuards(new GrantGuard(grantClient, { resource: 'Document', action: 'Update', resourceResolver: ... }))`\n */\nexport function Grant(resource: string, action: string): ReturnType<typeof SetMetadata>;\nexport function Grant(options: GrantOptions): ReturnType<typeof SetMetadata>;\nexport function Grant(\n resourceOrOptions: string | GrantOptions,\n action?: string\n): ReturnType<typeof SetMetadata> {\n const options: GrantOptions =\n typeof resourceOrOptions === 'string' && action !== undefined\n ? { resource: resourceOrOptions, action }\n : (resourceOrOptions as GrantOptions);\n return SetMetadata(GRANT_OPTIONS_KEY, options);\n}\n","import { DynamicModule, Global, Module } from '@nestjs/common';\n\nimport { GrantClient } from '../grant-client';\nimport type { GrantServerConfig } from '../types';\n\nexport const GRANT_CLIENT = 'GrantClient';\n\n/**\n * NestJS module that provides GrantClient for injection.\n *\n * @example\n * ```ts\n * // app.module.ts\n * import { GrantModule } from '@grantjs/server/nest';\n *\n * @Module({\n * imports: [\n * GrantModule.forRoot({\n * apiUrl: process.env.GRANT_API_URL!,\n * getToken: (req) => req.headers?.authorization?.replace?.('Bearer ', '') ?? null,\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n *\n * Then inject GrantClient in controllers and use with GrantGuard.\n */\n@Global()\n@Module({})\nexport class GrantModule {\n static forRoot(config: GrantServerConfig): DynamicModule {\n const client = new GrantClient(config);\n return {\n module: GrantModule,\n providers: [\n { provide: GrantClient, useValue: client },\n { provide: GRANT_CLIENT, useValue: client },\n ],\n exports: [GrantClient, GRANT_CLIENT],\n };\n }\n}\n","import {\n CanActivate,\n ExecutionContext,\n ForbiddenException,\n Inject,\n Injectable,\n NotFoundException,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\n\nimport { GrantClient } from '../grant-client';\nimport { debugGrant } from '../utils/debug';\nimport { extractTokenFromRequest } from '../utils/token-extractor';\nimport { GRANT_OPTIONS_KEY } from './grant.decorator';\nimport { GRANT_CLIENT } from './grant.module';\n\n/** Injection token for GrantGuard. Use with @UseGuards(GRANT_GUARD) so Nest resolves the guard from the container (with GrantClient injected). */\nexport const GRANT_GUARD = 'GrantGuard';\n\nimport type { AuthorizationResult, ResourceResolver } from '../types';\nimport type { GrantOptions } from './grant.decorator';\n\n/**\n * Extended request type with Grant authorization result (for use in controllers).\n */\nexport interface AuthorizedRequest {\n authorization?: AuthorizationResult;\n}\n\n/**\n * Guard options when using explicit options (includes optional resourceResolver).\n */\nexport interface GrantGuardOptions {\n resource: string;\n action: string;\n resourceResolver?: ResourceResolver;\n}\n\n/**\n * NestJS guard that checks Grant authorization before allowing access to a route.\n *\n * Use in one of two ways:\n *\n * 1. With decorator (resource/action from metadata):\n * - Import GrantModule.forRoot() in AppModule. In a feature module, add\n * `{ provide: GRANT_GUARD, useClass: GrantGuard }` and use @Grant + @UseGuards(GRANT_GUARD).\n * - Using the GRANT_GUARD token ensures Nest resolves the guard from the container (GrantClient injected).\n *\n * 2. With explicit options (supports resourceResolver):\n * - @UseGuards(new GrantGuard(grantClient, { resource: 'Document', action: 'Update', resourceResolver: async ({ request }) => ... }))\n *\n * On success, the authorization result is attached to the request as request.authorization.\n * On failure, throws UnauthorizedException (401), ForbiddenException (403), or NotFoundException (404).\n */\nfunction isGrantGuardOptions(x: unknown): x is GrantGuardOptions {\n return (\n typeof x === 'object' &&\n x !== null &&\n 'resource' in x &&\n 'action' in x &&\n typeof (x as GrantGuardOptions).resource === 'string' &&\n typeof (x as GrantGuardOptions).action === 'string'\n );\n}\n\n@Injectable()\nexport class GrantGuard implements CanActivate {\n private readonly explicitOptions?: GrantGuardOptions;\n private readonly reflector?: Reflector;\n\n constructor(\n @Inject(GRANT_CLIENT) private readonly client: GrantClient,\n reflectorOrOptions?: Reflector | GrantGuardOptions\n ) {\n if (reflectorOrOptions && isGrantGuardOptions(reflectorOrOptions)) {\n this.explicitOptions = reflectorOrOptions;\n } else {\n this.reflector = reflectorOrOptions as Reflector | undefined;\n }\n }\n\n private getOptionsFromContext(context: ExecutionContext): GrantOptions | undefined {\n const handler = context.getHandler();\n const clazz = context.getClass();\n // Prefer Reflector when available (Nest DI)\n if (this.reflector) {\n const fromHandler = this.reflector.get<GrantOptions>(GRANT_OPTIONS_KEY, handler);\n const fromClass = this.reflector.get<GrantOptions>(GRANT_OPTIONS_KEY, clazz);\n if (fromHandler) return fromHandler;\n if (fromClass) return fromClass;\n }\n // Fallback: read metadata via Reflect (works when Reflector is not injected, e.g. ESM/CJS boundary)\n if (typeof Reflect !== 'undefined' && typeof Reflect.getMetadata === 'function') {\n const fromHandler = Reflect.getMetadata(GRANT_OPTIONS_KEY, handler) as\n | GrantOptions\n | undefined;\n const fromClass = Reflect.getMetadata(GRANT_OPTIONS_KEY, clazz) as GrantOptions | undefined;\n if (fromHandler) return fromHandler;\n if (fromClass) return fromClass;\n }\n return undefined;\n }\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest();\n\n const options = this.explicitOptions ?? this.getOptionsFromContext(context);\n\n if (options?.resource && options?.action) {\n debugGrant('Nest', {\n resource: options.resource,\n action: options.action,\n hasReflector: !!this.reflector,\n handler: context.getHandler()?.name,\n controller: context.getClass()?.name,\n });\n }\n\n if (!options || !options.resource || !options.action) {\n throw new ForbiddenException(\n 'Grant options (resource, action) required. Use @Grant() or pass options to GrantGuard.'\n );\n }\n\n if (!this.client) {\n throw new ForbiddenException(\n 'GrantGuard: GrantClient not injected. Import GrantModule.forRoot() in AppModule and register GrantGuard as a provider.'\n );\n }\n\n const token = await extractTokenFromRequest(request, this.client.config);\n if (!token) {\n throw new UnauthorizedException({ error: 'Unauthorized', code: 'UNAUTHENTICATED' });\n }\n\n let resolvedResource: Record<string, unknown> | null = null;\n\n const opts = options as GrantGuardOptions;\n if (opts.resourceResolver) {\n resolvedResource = await opts.resourceResolver({\n resourceSlug: options.resource,\n request,\n });\n if (!resolvedResource) {\n throw new NotFoundException({ error: 'Resource not found', code: 'NOT_FOUND' });\n }\n }\n\n const result = await this.client.isAuthorized(\n options.resource,\n options.action,\n {\n context: {\n resource: resolvedResource ?? undefined,\n },\n },\n request\n );\n\n debugGrant('Nest', {\n resource: options.resource,\n action: options.action,\n authorized: result.authorized,\n ...(result.authorized ? {} : { reason: result.reason }),\n });\n\n if (!result.authorized) {\n throw new ForbiddenException({\n error: 'Forbidden',\n code: 'FORBIDDEN',\n reason: result.reason,\n });\n }\n\n (request as AuthorizedRequest).authorization = result;\n return true;\n }\n}\n"],"mappings":"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"}