@grantjs/server 1.18.2 → 1.18.3
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.
- package/dist/{debug-F-NPwfWM.cjs → debug-Bd3mwO_G.cjs} +2 -3
- package/dist/{debug-F-NPwfWM.cjs.map → debug-Bd3mwO_G.cjs.map} +1 -1
- package/dist/{debug-BcdveYlv.js → debug-DfEEZ0z2.js} +2 -3
- package/dist/{debug-BcdveYlv.js.map → debug-DfEEZ0z2.js.map} +1 -1
- package/dist/{errors-Cln6JSBJ.js → errors-CfqUl3ZG.js} +3 -4
- package/dist/{errors-Cln6JSBJ.js.map → errors-CfqUl3ZG.js.map} +1 -1
- package/dist/{errors-BB6c22Du.cjs → errors-M--U1x5o.cjs} +3 -4
- package/dist/{errors-BB6c22Du.cjs.map → errors-M--U1x5o.cjs.map} +1 -1
- package/dist/express.cjs +4 -5
- package/dist/express.mjs +4 -5
- package/dist/fastify.cjs +4 -5
- package/dist/fastify.mjs +4 -5
- package/dist/{grant-client-CWj6832E.js → grant-client-1Cd2jhvZ.js} +7 -13
- package/dist/{grant-client-CWj6832E.js.map → grant-client-1Cd2jhvZ.js.map} +1 -1
- package/dist/{grant-client-BtXpNZ6b.cjs → grant-client-DEaSxech.cjs} +7 -13
- package/dist/{grant-client-BtXpNZ6b.cjs.map → grant-client-DEaSxech.cjs.map} +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/nest.cjs +8 -14
- package/dist/nest.cjs.map +1 -1
- package/dist/nest.mjs +8 -14
- package/dist/nest.mjs.map +1 -1
- package/dist/next.cjs +4 -5
- package/dist/next.mjs +4 -5
- package/package.json +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/utils/debug.ts
|
|
2
2
|
var DEBUG_GRANT_ENV = "DEBUG_GRANT";
|
|
3
3
|
/** Whether Grant debug logging is enabled (set DEBUG_GRANT=1 in development). */
|
|
4
4
|
function isDebugGrant() {
|
|
@@ -13,7 +13,6 @@ function debugGrant(integration, data) {
|
|
|
13
13
|
if (!isDebugGrant()) return;
|
|
14
14
|
console.debug(`[Grant ${integration}]`, data);
|
|
15
15
|
}
|
|
16
|
-
//#endregion
|
|
17
16
|
Object.defineProperty(exports, "debugGrant", {
|
|
18
17
|
enumerable: true,
|
|
19
18
|
get: function() {
|
|
@@ -21,4 +20,4 @@ Object.defineProperty(exports, "debugGrant", {
|
|
|
21
20
|
}
|
|
22
21
|
});
|
|
23
22
|
|
|
24
|
-
//# sourceMappingURL=debug-
|
|
23
|
+
//# sourceMappingURL=debug-Bd3mwO_G.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug-
|
|
1
|
+
{"version":3,"file":"debug-Bd3mwO_G.cjs","names":[],"sources":["../src/utils/debug.ts"],"sourcesContent":["const DEBUG_GRANT_ENV = 'DEBUG_GRANT';\n\n/** Whether Grant debug logging is enabled (set DEBUG_GRANT=1 in development). */\nfunction isDebugGrant(): boolean {\n return process.env[DEBUG_GRANT_ENV] === '1';\n}\n\n/**\n * Log Grant integration debug info when DEBUG_GRANT=1.\n * Used by Express middleware, Fastify grant hook, Next withGrant, and Nest GrantGuard.\n * Set DEBUG_GRANT=1 in .env or the environment to see resource, action, and outcome in development.\n */\nexport function debugGrant(integration: string, data: Record<string, unknown>): void {\n if (!isDebugGrant()) return;\n console.debug(`[Grant ${integration}]`, data);\n}\n"],"mappings":";AAAA,IAAM,kBAAkB;;AAGxB,SAAS,eAAwB;CAC/B,OAAO,QAAQ,IAAI,qBAAqB;AAC1C;;;;;;AAOA,SAAgB,WAAW,aAAqB,MAAqC;CACnF,IAAI,CAAC,aAAa,GAAG;CACrB,QAAQ,MAAM,UAAU,YAAY,IAAI,IAAI;AAC9C"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/utils/debug.ts
|
|
2
2
|
var DEBUG_GRANT_ENV = "DEBUG_GRANT";
|
|
3
3
|
/** Whether Grant debug logging is enabled (set DEBUG_GRANT=1 in development). */
|
|
4
4
|
function isDebugGrant() {
|
|
@@ -13,7 +13,6 @@ function debugGrant(integration, data) {
|
|
|
13
13
|
if (!isDebugGrant()) return;
|
|
14
14
|
console.debug(`[Grant ${integration}]`, data);
|
|
15
15
|
}
|
|
16
|
-
//#endregion
|
|
17
16
|
export { debugGrant as t };
|
|
18
17
|
|
|
19
|
-
//# sourceMappingURL=debug-
|
|
18
|
+
//# sourceMappingURL=debug-DfEEZ0z2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug-
|
|
1
|
+
{"version":3,"file":"debug-DfEEZ0z2.js","names":[],"sources":["../src/utils/debug.ts"],"sourcesContent":["const DEBUG_GRANT_ENV = 'DEBUG_GRANT';\n\n/** Whether Grant debug logging is enabled (set DEBUG_GRANT=1 in development). */\nfunction isDebugGrant(): boolean {\n return process.env[DEBUG_GRANT_ENV] === '1';\n}\n\n/**\n * Log Grant integration debug info when DEBUG_GRANT=1.\n * Used by Express middleware, Fastify grant hook, Next withGrant, and Nest GrantGuard.\n * Set DEBUG_GRANT=1 in .env or the environment to see resource, action, and outcome in development.\n */\nexport function debugGrant(integration: string, data: Record<string, unknown>): void {\n if (!isDebugGrant()) return;\n console.debug(`[Grant ${integration}]`, data);\n}\n"],"mappings":";AAAA,IAAM,kBAAkB;;AAGxB,SAAS,eAAwB;CAC/B,OAAO,QAAQ,IAAI,qBAAqB;AAC1C;;;;;;AAOA,SAAgB,WAAW,aAAqB,MAAqC;CACnF,IAAI,CAAC,aAAa,GAAG;CACrB,QAAQ,MAAM,UAAU,YAAY,IAAI,IAAI;AAC9C"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as _defineProperty } from "./grant-client-
|
|
2
|
-
|
|
1
|
+
import { n as _defineProperty } from "./grant-client-1Cd2jhvZ.js";
|
|
2
|
+
// src/errors.ts
|
|
3
3
|
/**
|
|
4
4
|
* Base error class for Grant server errors
|
|
5
5
|
*/
|
|
@@ -60,7 +60,6 @@ var NotFoundError = class NotFoundError extends GrantServerError {
|
|
|
60
60
|
Object.setPrototypeOf(this, NotFoundError.prototype);
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
|
-
//#endregion
|
|
64
63
|
export { NotFoundError as a, GrantServerError as i, AuthorizationError as n, BadRequestError as r, AuthenticationError as t };
|
|
65
64
|
|
|
66
|
-
//# sourceMappingURL=errors-
|
|
65
|
+
//# sourceMappingURL=errors-CfqUl3ZG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors-
|
|
1
|
+
{"version":3,"file":"errors-CfqUl3ZG.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Base error class for Grant server errors\n */\nexport class GrantServerError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly statusCode: number = 500\n ) {\n super(message);\n this.name = 'GrantServerError';\n Object.setPrototypeOf(this, GrantServerError.prototype);\n }\n}\n\n/**\n * Authentication error (401)\n * Thrown when user is not authenticated\n */\nexport class AuthenticationError extends GrantServerError {\n constructor(message: string = 'Unauthorized', code: string = 'UNAUTHENTICATED') {\n super(message, code, 401);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Authorization error (403)\n * Thrown when user is authenticated but lacks required permission\n */\nexport class AuthorizationError extends GrantServerError {\n constructor(\n message: string = 'Forbidden',\n code: string = 'FORBIDDEN',\n public readonly reason?: string\n ) {\n super(message, code, 403);\n this.name = 'AuthorizationError';\n Object.setPrototypeOf(this, AuthorizationError.prototype);\n }\n}\n\n/**\n * Bad request error (400)\n * Thrown when request is malformed or missing required data\n */\nexport class BadRequestError extends GrantServerError {\n constructor(message: string = 'Bad Request', code: string = 'BAD_REQUEST') {\n super(message, code, 400);\n this.name = 'BadRequestError';\n Object.setPrototypeOf(this, BadRequestError.prototype);\n }\n}\n\n/**\n * Not found error (404)\n * Thrown when resource is not found\n */\nexport class NotFoundError extends GrantServerError {\n constructor(message: string = 'Not Found', code: string = 'NOT_FOUND') {\n super(message, code, 404);\n this.name = 'NotFoundError';\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n"],"mappings":";;;;;AAGA,IAAa,mBAAb,MAAa,yBAAyB,MAAM;CAC1C,YACE,SACA,MACA,aAAqC,KACrC;EACA,MAAM,OAAO;EAHG,gBAAA,MAAA,QAAA,KAAA,CAAA;EACA,gBAAA,MAAA,cAAA,KAAA,CAAA;EADA,KAAA,OAAA;EACA,KAAA,aAAA;EAGhB,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,iBAAiB,SAAS;CACxD;AACF;;;;;AAMA,IAAa,sBAAb,MAAa,4BAA4B,iBAAiB;CACxD,YAAY,UAAkB,gBAAgB,OAAe,mBAAmB;EAC9E,MAAM,SAAS,MAAM,GAAG;EACxB,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,oBAAoB,SAAS;CAC3D;AACF;;;;;AAMA,IAAa,qBAAb,MAAa,2BAA2B,iBAAiB;CACvD,YACE,UAAkB,aAClB,OAAe,aACf,QACA;EACA,MAAM,SAAS,MAAM,GAAG;EAFR,gBAAA,MAAA,UAAA,KAAA,CAAA;EAAA,KAAA,SAAA;EAGhB,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,mBAAmB,SAAS;CAC1D;AACF;;;;;AAMA,IAAa,kBAAb,MAAa,wBAAwB,iBAAiB;CACpD,YAAY,UAAkB,eAAe,OAAe,eAAe;EACzE,MAAM,SAAS,MAAM,GAAG;EACxB,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,gBAAgB,SAAS;CACvD;AACF;;;;;AAMA,IAAa,gBAAb,MAAa,sBAAsB,iBAAiB;CAClD,YAAY,UAAkB,aAAa,OAAe,aAAa;EACrE,MAAM,SAAS,MAAM,GAAG;EACxB,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,cAAc,SAAS;CACrD;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const require_grant_client = require("./grant-client-
|
|
2
|
-
|
|
1
|
+
const require_grant_client = require("./grant-client-DEaSxech.cjs");
|
|
2
|
+
// src/errors.ts
|
|
3
3
|
/**
|
|
4
4
|
* Base error class for Grant server errors
|
|
5
5
|
*/
|
|
@@ -60,7 +60,6 @@ var NotFoundError = class NotFoundError extends GrantServerError {
|
|
|
60
60
|
Object.setPrototypeOf(this, NotFoundError.prototype);
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
|
-
//#endregion
|
|
64
63
|
Object.defineProperty(exports, "AuthenticationError", {
|
|
65
64
|
enumerable: true,
|
|
66
65
|
get: function() {
|
|
@@ -92,4 +91,4 @@ Object.defineProperty(exports, "NotFoundError", {
|
|
|
92
91
|
}
|
|
93
92
|
});
|
|
94
93
|
|
|
95
|
-
//# sourceMappingURL=errors-
|
|
94
|
+
//# sourceMappingURL=errors-M--U1x5o.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors-
|
|
1
|
+
{"version":3,"file":"errors-M--U1x5o.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Base error class for Grant server errors\n */\nexport class GrantServerError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly statusCode: number = 500\n ) {\n super(message);\n this.name = 'GrantServerError';\n Object.setPrototypeOf(this, GrantServerError.prototype);\n }\n}\n\n/**\n * Authentication error (401)\n * Thrown when user is not authenticated\n */\nexport class AuthenticationError extends GrantServerError {\n constructor(message: string = 'Unauthorized', code: string = 'UNAUTHENTICATED') {\n super(message, code, 401);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Authorization error (403)\n * Thrown when user is authenticated but lacks required permission\n */\nexport class AuthorizationError extends GrantServerError {\n constructor(\n message: string = 'Forbidden',\n code: string = 'FORBIDDEN',\n public readonly reason?: string\n ) {\n super(message, code, 403);\n this.name = 'AuthorizationError';\n Object.setPrototypeOf(this, AuthorizationError.prototype);\n }\n}\n\n/**\n * Bad request error (400)\n * Thrown when request is malformed or missing required data\n */\nexport class BadRequestError extends GrantServerError {\n constructor(message: string = 'Bad Request', code: string = 'BAD_REQUEST') {\n super(message, code, 400);\n this.name = 'BadRequestError';\n Object.setPrototypeOf(this, BadRequestError.prototype);\n }\n}\n\n/**\n * Not found error (404)\n * Thrown when resource is not found\n */\nexport class NotFoundError extends GrantServerError {\n constructor(message: string = 'Not Found', code: string = 'NOT_FOUND') {\n super(message, code, 404);\n this.name = 'NotFoundError';\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n"],"mappings":";;;;;AAGA,IAAa,mBAAb,MAAa,yBAAyB,MAAM;CAC1C,YACE,SACA,MACA,aAAqC,KACrC;EACA,MAAM,OAAO;EAHG,qBAAA,gBAAA,MAAA,QAAA,KAAA,CAAA;EACA,qBAAA,gBAAA,MAAA,cAAA,KAAA,CAAA;EADA,KAAA,OAAA;EACA,KAAA,aAAA;EAGhB,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,iBAAiB,SAAS;CACxD;AACF;;;;;AAMA,IAAa,sBAAb,MAAa,4BAA4B,iBAAiB;CACxD,YAAY,UAAkB,gBAAgB,OAAe,mBAAmB;EAC9E,MAAM,SAAS,MAAM,GAAG;EACxB,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,oBAAoB,SAAS;CAC3D;AACF;;;;;AAMA,IAAa,qBAAb,MAAa,2BAA2B,iBAAiB;CACvD,YACE,UAAkB,aAClB,OAAe,aACf,QACA;EACA,MAAM,SAAS,MAAM,GAAG;EAFR,qBAAA,gBAAA,MAAA,UAAA,KAAA,CAAA;EAAA,KAAA,SAAA;EAGhB,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,mBAAmB,SAAS;CAC1D;AACF;;;;;AAMA,IAAa,kBAAb,MAAa,wBAAwB,iBAAiB;CACpD,YAAY,UAAkB,eAAe,OAAe,eAAe;EACzE,MAAM,SAAS,MAAM,GAAG;EACxB,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,gBAAgB,SAAS;CACvD;AACF;;;;;AAMA,IAAa,gBAAb,MAAa,sBAAsB,iBAAiB;CAClD,YAAY,UAAkB,aAAa,OAAe,aAAa;EACrE,MAAM,SAAS,MAAM,GAAG;EACxB,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,cAAc,SAAS;CACrD;AACF"}
|
package/dist/express.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_grant_client = require("./grant-client-
|
|
3
|
-
const require_errors = require("./errors-
|
|
4
|
-
const require_debug = require("./debug-
|
|
5
|
-
|
|
2
|
+
const require_grant_client = require("./grant-client-DEaSxech.cjs");
|
|
3
|
+
const require_errors = require("./errors-M--U1x5o.cjs");
|
|
4
|
+
const require_debug = require("./debug-Bd3mwO_G.cjs");
|
|
5
|
+
// src/express/middleware.ts
|
|
6
6
|
/**
|
|
7
7
|
* Create Express middleware to check if user is granted permission
|
|
8
8
|
*
|
|
@@ -98,7 +98,6 @@ function grant(client, options) {
|
|
|
98
98
|
}
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
|
-
//#endregion
|
|
102
101
|
exports.AuthenticationError = require_errors.AuthenticationError;
|
|
103
102
|
exports.AuthorizationError = require_errors.AuthorizationError;
|
|
104
103
|
exports.BadRequestError = require_errors.BadRequestError;
|
package/dist/express.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { i as extractTokenFromRequest, t as GrantClient } from "./grant-client-
|
|
2
|
-
import { a as NotFoundError, i as GrantServerError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-
|
|
3
|
-
import { t as debugGrant } from "./debug-
|
|
4
|
-
|
|
1
|
+
import { i as extractTokenFromRequest, t as GrantClient } from "./grant-client-1Cd2jhvZ.js";
|
|
2
|
+
import { a as NotFoundError, i as GrantServerError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-CfqUl3ZG.js";
|
|
3
|
+
import { t as debugGrant } from "./debug-DfEEZ0z2.js";
|
|
4
|
+
// src/express/middleware.ts
|
|
5
5
|
/**
|
|
6
6
|
* Create Express middleware to check if user is granted permission
|
|
7
7
|
*
|
|
@@ -97,7 +97,6 @@ function grant(client, options) {
|
|
|
97
97
|
}
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
|
-
//#endregion
|
|
101
100
|
export { AuthenticationError, AuthorizationError, BadRequestError, GrantClient, GrantServerError, NotFoundError, grant };
|
|
102
101
|
|
|
103
102
|
//# sourceMappingURL=express.mjs.map
|
package/dist/fastify.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_grant_client = require("./grant-client-
|
|
3
|
-
const require_errors = require("./errors-
|
|
4
|
-
const require_debug = require("./debug-
|
|
5
|
-
|
|
2
|
+
const require_grant_client = require("./grant-client-DEaSxech.cjs");
|
|
3
|
+
const require_errors = require("./errors-M--U1x5o.cjs");
|
|
4
|
+
const require_debug = require("./debug-Bd3mwO_G.cjs");
|
|
5
|
+
// src/fastify/plugin.ts
|
|
6
6
|
/**
|
|
7
7
|
* Create a Fastify preHandler hook to check if user is granted permission
|
|
8
8
|
*
|
|
@@ -126,7 +126,6 @@ var grantPlugin = async (fastify, options) => {
|
|
|
126
126
|
const grant = new require_grant_client.GrantClient(options);
|
|
127
127
|
fastify.decorate("grant", grant);
|
|
128
128
|
};
|
|
129
|
-
//#endregion
|
|
130
129
|
exports.AuthenticationError = require_errors.AuthenticationError;
|
|
131
130
|
exports.AuthorizationError = require_errors.AuthorizationError;
|
|
132
131
|
exports.BadRequestError = require_errors.BadRequestError;
|
package/dist/fastify.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { i as extractTokenFromRequest, t as GrantClient } from "./grant-client-
|
|
2
|
-
import { a as NotFoundError, i as GrantServerError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-
|
|
3
|
-
import { t as debugGrant } from "./debug-
|
|
4
|
-
|
|
1
|
+
import { i as extractTokenFromRequest, t as GrantClient } from "./grant-client-1Cd2jhvZ.js";
|
|
2
|
+
import { a as NotFoundError, i as GrantServerError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-CfqUl3ZG.js";
|
|
3
|
+
import { t as debugGrant } from "./debug-DfEEZ0z2.js";
|
|
4
|
+
// src/fastify/plugin.ts
|
|
5
5
|
/**
|
|
6
6
|
* Create a Fastify preHandler hook to check if user is granted permission
|
|
7
7
|
*
|
|
@@ -125,7 +125,6 @@ var grantPlugin = async (fastify, options) => {
|
|
|
125
125
|
const grant = new GrantClient(options);
|
|
126
126
|
fastify.decorate("grant", grant);
|
|
127
127
|
};
|
|
128
|
-
//#endregion
|
|
129
128
|
export { AuthenticationError, AuthorizationError, BadRequestError, GrantClient, GrantServerError, NotFoundError, grant, grantPlugin };
|
|
130
129
|
|
|
131
130
|
//# sourceMappingURL=fastify.mjs.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/utils/token-extractor.ts
|
|
2
2
|
/**
|
|
3
3
|
* Extract Bearer token from Authorization header
|
|
4
4
|
*/
|
|
@@ -61,8 +61,7 @@ async function extractTokenFromRequest(request, config) {
|
|
|
61
61
|
}
|
|
62
62
|
return null;
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/typeof.js
|
|
64
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/typeof.js
|
|
66
65
|
function _typeof(o) {
|
|
67
66
|
"@babel/helpers - typeof";
|
|
68
67
|
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
@@ -71,8 +70,7 @@ function _typeof(o) {
|
|
|
71
70
|
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
72
71
|
}, _typeof(o);
|
|
73
72
|
}
|
|
74
|
-
|
|
75
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/toPrimitive.js
|
|
73
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/toPrimitive.js
|
|
76
74
|
function toPrimitive(t, r) {
|
|
77
75
|
if ("object" != _typeof(t) || !t) return t;
|
|
78
76
|
var e = t[Symbol.toPrimitive];
|
|
@@ -83,14 +81,12 @@ function toPrimitive(t, r) {
|
|
|
83
81
|
}
|
|
84
82
|
return ("string" === r ? String : Number)(t);
|
|
85
83
|
}
|
|
86
|
-
|
|
87
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/toPropertyKey.js
|
|
84
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/toPropertyKey.js
|
|
88
85
|
function toPropertyKey(t) {
|
|
89
86
|
var i = toPrimitive(t, "string");
|
|
90
87
|
return "symbol" == _typeof(i) ? i : i + "";
|
|
91
88
|
}
|
|
92
|
-
|
|
93
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/defineProperty.js
|
|
89
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/defineProperty.js
|
|
94
90
|
function _defineProperty(e, r, t) {
|
|
95
91
|
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
96
92
|
value: t,
|
|
@@ -99,8 +95,7 @@ function _defineProperty(e, r, t) {
|
|
|
99
95
|
writable: !0
|
|
100
96
|
}) : e[r] = t, e;
|
|
101
97
|
}
|
|
102
|
-
|
|
103
|
-
//#region src/grant-client.ts
|
|
98
|
+
// src/grant-client.ts
|
|
104
99
|
/**
|
|
105
100
|
* Grant Client for server-side applications
|
|
106
101
|
*
|
|
@@ -199,7 +194,6 @@ var GrantClient = class {
|
|
|
199
194
|
});
|
|
200
195
|
}
|
|
201
196
|
};
|
|
202
|
-
//#endregion
|
|
203
197
|
export { extractTokenFromRequest as i, _defineProperty as n, extractBearerToken as r, GrantClient as t };
|
|
204
198
|
|
|
205
|
-
//# sourceMappingURL=grant-client-
|
|
199
|
+
//# sourceMappingURL=grant-client-1Cd2jhvZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grant-client-CWj6832E.js","names":[],"sources":["../src/utils/token-extractor.ts","../src/grant-client.ts"],"sourcesContent":["import type { GrantServerConfig } from '../types';\n\n/**\n * Extract Bearer token from Authorization header\n */\nexport function extractBearerToken(authHeader: string | undefined): string | null {\n if (!authHeader) return null;\n\n const parts = authHeader.trim().split(/\\s+/);\n if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {\n return null;\n }\n\n return parts[1];\n}\n\n/**\n * Parse cookie header string into key-value pairs\n */\nfunction parseCookieHeader(cookieHeader: string): Record<string, string> {\n const cookies: Record<string, string> = {};\n\n cookieHeader.split(';').forEach((cookie) => {\n const [name, ...rest] = cookie.trim().split('=');\n if (name && rest.length > 0) {\n cookies[name.trim()] = rest.join('=').trim();\n }\n });\n\n return cookies;\n}\n\n/**\n * Extract token from cookies\n */\nexport function extractTokenFromCookies(\n cookieHeader: string | undefined,\n cookieName: string\n): string | null {\n if (!cookieHeader) return null;\n\n const cookies = parseCookieHeader(cookieHeader);\n return cookies[cookieName] || null;\n}\n\n/**\n * Extract token from Express request\n */\nexport async function extractTokenFromRequest(\n request: unknown,\n config: GrantServerConfig\n): Promise<string | null> {\n // Use custom token resolver if provided\n if (config.getToken) {\n const token = await config.getToken(request);\n if (token) return token;\n }\n\n // Try to extract from request (Express-style or Web API / NextRequest)\n const req = request as {\n headers?:\n { authorization?: string; cookie?: string } | { get: (name: string) => string | null };\n cookies?: Record<string, string>;\n };\n\n if (!req?.headers) return null;\n\n // Web API Headers (NextRequest, Request): headers.get(name)\n const headersGet = (req.headers as { get?: (name: string) => string | null }).get;\n if (typeof headersGet === 'function') {\n const authHeader = headersGet.call(req.headers, 'authorization');\n const bearerToken = extractBearerToken(authHeader ?? undefined);\n if (bearerToken) return bearerToken;\n const cookieName = config.cookieName || 'grant-access-token';\n const cookieHeader = headersGet.call(req.headers, 'cookie');\n if (cookieHeader) {\n const cookieToken = extractTokenFromCookies(cookieHeader, cookieName);\n if (cookieToken) return cookieToken;\n }\n return null;\n }\n\n // Express-style: headers.authorization, headers.cookie\n const plainHeaders = req.headers as { authorization?: string; cookie?: string };\n const authHeader = plainHeaders.authorization;\n const bearerToken = extractBearerToken(authHeader);\n if (bearerToken) return bearerToken;\n\n const cookieName = config.cookieName || 'grant-access-token';\n\n if (req.cookies?.[cookieName]) {\n return req.cookies[cookieName];\n }\n\n const cookieHeader = plainHeaders.cookie;\n if (cookieHeader) {\n const cookieToken = extractTokenFromCookies(cookieHeader, cookieName);\n if (cookieToken) return cookieToken;\n }\n\n return null;\n}\n","import type { AuthorizationResult, GrantServerConfig, PermissionCheckOptions } from './types';\nimport { extractTokenFromRequest } from './utils/token-extractor';\n\n/**\n * Grant Client for server-side applications\n *\n * Makes HTTP requests to the Grant API to check permissions.\n * Uses API-key exchanged tokens (scope in JWT claims); token-based and cookie-based extraction supported.\n * No caching - server-side caching is handled by grant-api.\n */\nexport class GrantClient {\n public readonly config: Required<Pick<GrantServerConfig, 'apiUrl'>> & GrantServerConfig;\n\n constructor(config: GrantServerConfig) {\n this.config = config;\n }\n\n // ============================================================================\n // Public API - Permission Checks\n // ============================================================================\n\n /**\n * Check if the current user has a specific permission\n *\n * @example\n * ```ts\n * const canEdit = await grant.isGranted('document', 'update', { scope });\n * if (canEdit) {\n * // Proceed with operation\n * }\n * ```\n */\n async isGranted(\n resource: string,\n action: string,\n options?: PermissionCheckOptions,\n request?: unknown\n ): Promise<boolean> {\n const result = await this.isAuthorized(resource, action, options, request);\n return result.authorized;\n }\n\n /**\n * Check authorization with full result details\n *\n * @example\n * ```ts\n * const result = await grant.isAuthorized('document', 'update', { scope }, request);\n * if (!result.authorized) {\n * console.log('Denied:', result.reason);\n * }\n * ```\n */\n async isAuthorized(\n resource: string,\n action: string,\n options?: PermissionCheckOptions,\n request?: unknown\n ): Promise<AuthorizationResult> {\n try {\n // API expects: { permission: { resource, action }, context: { resource?: any }, scope?: { tenant, id } }\n const response = await this.fetchWithAuth(\n '/api/auth/is-authorized',\n {\n method: 'POST',\n body: JSON.stringify({\n permission: {\n resource,\n action,\n },\n context: {\n resource: options?.context?.resource || null,\n },\n }),\n },\n request\n );\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n return {\n authorized: false,\n reason: error.message || `API error: ${response.status}`,\n };\n }\n\n const json = await response.json();\n // API returns { success: true, data: { authorized, ... } }\n const result: AuthorizationResult = json.data ?? json;\n return result;\n } catch (error) {\n return {\n authorized: false,\n reason: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n /**\n * Extract token from a request object\n * Useful for middleware that needs to extract token before making authorization calls\n */\n async getTokenFromRequest(request: unknown): Promise<string | null> {\n return extractTokenFromRequest(request, this.config);\n }\n\n // ============================================================================\n // Private - HTTP & Authentication\n // ============================================================================\n\n /**\n * Make an authenticated fetch request (token from request; no refresh).\n */\n private async fetchWithAuth(\n url: string,\n init?: RequestInit,\n request?: unknown\n ): Promise<Response> {\n return this.doFetch(url, init, request);\n }\n\n /**\n * Perform the actual fetch request\n */\n private async doFetch(url: string, init?: RequestInit, request?: unknown): Promise<Response> {\n const fetchFn = this.config.fetch ?? globalThis.fetch;\n const fullUrl = url.startsWith('http') ? url : `${this.config.apiUrl}${url}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(init?.headers as Record<string, string>),\n };\n\n // Add authorization header if token is available\n if (request) {\n const token = await extractTokenFromRequest(request, this.config);\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n // Forward cookies if using cookie-based auth\n const req = request as { headers?: { cookie?: string } };\n if (req.headers?.cookie) {\n headers['Cookie'] = req.headers.cookie;\n }\n }\n\n return fetchFn(fullUrl, {\n ...init,\n headers,\n // Include cookies for same-origin requests (supports cookie-based auth)\n credentials: this.config.credentials ?? 'include',\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"grant-client-1Cd2jhvZ.js","names":[],"sources":["../src/utils/token-extractor.ts","../src/grant-client.ts"],"sourcesContent":["import type { GrantServerConfig } from '../types';\n\n/**\n * Extract Bearer token from Authorization header\n */\nexport function extractBearerToken(authHeader: string | undefined): string | null {\n if (!authHeader) return null;\n\n const parts = authHeader.trim().split(/\\s+/);\n if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {\n return null;\n }\n\n return parts[1];\n}\n\n/**\n * Parse cookie header string into key-value pairs\n */\nfunction parseCookieHeader(cookieHeader: string): Record<string, string> {\n const cookies: Record<string, string> = {};\n\n cookieHeader.split(';').forEach((cookie) => {\n const [name, ...rest] = cookie.trim().split('=');\n if (name && rest.length > 0) {\n cookies[name.trim()] = rest.join('=').trim();\n }\n });\n\n return cookies;\n}\n\n/**\n * Extract token from cookies\n */\nexport function extractTokenFromCookies(\n cookieHeader: string | undefined,\n cookieName: string\n): string | null {\n if (!cookieHeader) return null;\n\n const cookies = parseCookieHeader(cookieHeader);\n return cookies[cookieName] || null;\n}\n\n/**\n * Extract token from Express request\n */\nexport async function extractTokenFromRequest(\n request: unknown,\n config: GrantServerConfig\n): Promise<string | null> {\n // Use custom token resolver if provided\n if (config.getToken) {\n const token = await config.getToken(request);\n if (token) return token;\n }\n\n // Try to extract from request (Express-style or Web API / NextRequest)\n const req = request as {\n headers?:\n { authorization?: string; cookie?: string } | { get: (name: string) => string | null };\n cookies?: Record<string, string>;\n };\n\n if (!req?.headers) return null;\n\n // Web API Headers (NextRequest, Request): headers.get(name)\n const headersGet = (req.headers as { get?: (name: string) => string | null }).get;\n if (typeof headersGet === 'function') {\n const authHeader = headersGet.call(req.headers, 'authorization');\n const bearerToken = extractBearerToken(authHeader ?? undefined);\n if (bearerToken) return bearerToken;\n const cookieName = config.cookieName || 'grant-access-token';\n const cookieHeader = headersGet.call(req.headers, 'cookie');\n if (cookieHeader) {\n const cookieToken = extractTokenFromCookies(cookieHeader, cookieName);\n if (cookieToken) return cookieToken;\n }\n return null;\n }\n\n // Express-style: headers.authorization, headers.cookie\n const plainHeaders = req.headers as { authorization?: string; cookie?: string };\n const authHeader = plainHeaders.authorization;\n const bearerToken = extractBearerToken(authHeader);\n if (bearerToken) return bearerToken;\n\n const cookieName = config.cookieName || 'grant-access-token';\n\n if (req.cookies?.[cookieName]) {\n return req.cookies[cookieName];\n }\n\n const cookieHeader = plainHeaders.cookie;\n if (cookieHeader) {\n const cookieToken = extractTokenFromCookies(cookieHeader, cookieName);\n if (cookieToken) return cookieToken;\n }\n\n return null;\n}\n","import type { AuthorizationResult, GrantServerConfig, PermissionCheckOptions } from './types';\nimport { extractTokenFromRequest } from './utils/token-extractor';\n\n/**\n * Grant Client for server-side applications\n *\n * Makes HTTP requests to the Grant API to check permissions.\n * Uses API-key exchanged tokens (scope in JWT claims); token-based and cookie-based extraction supported.\n * No caching - server-side caching is handled by grant-api.\n */\nexport class GrantClient {\n public readonly config: Required<Pick<GrantServerConfig, 'apiUrl'>> & GrantServerConfig;\n\n constructor(config: GrantServerConfig) {\n this.config = config;\n }\n\n // ============================================================================\n // Public API - Permission Checks\n // ============================================================================\n\n /**\n * Check if the current user has a specific permission\n *\n * @example\n * ```ts\n * const canEdit = await grant.isGranted('document', 'update', { scope });\n * if (canEdit) {\n * // Proceed with operation\n * }\n * ```\n */\n async isGranted(\n resource: string,\n action: string,\n options?: PermissionCheckOptions,\n request?: unknown\n ): Promise<boolean> {\n const result = await this.isAuthorized(resource, action, options, request);\n return result.authorized;\n }\n\n /**\n * Check authorization with full result details\n *\n * @example\n * ```ts\n * const result = await grant.isAuthorized('document', 'update', { scope }, request);\n * if (!result.authorized) {\n * console.log('Denied:', result.reason);\n * }\n * ```\n */\n async isAuthorized(\n resource: string,\n action: string,\n options?: PermissionCheckOptions,\n request?: unknown\n ): Promise<AuthorizationResult> {\n try {\n // API expects: { permission: { resource, action }, context: { resource?: any }, scope?: { tenant, id } }\n const response = await this.fetchWithAuth(\n '/api/auth/is-authorized',\n {\n method: 'POST',\n body: JSON.stringify({\n permission: {\n resource,\n action,\n },\n context: {\n resource: options?.context?.resource || null,\n },\n }),\n },\n request\n );\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n return {\n authorized: false,\n reason: error.message || `API error: ${response.status}`,\n };\n }\n\n const json = await response.json();\n // API returns { success: true, data: { authorized, ... } }\n const result: AuthorizationResult = json.data ?? json;\n return result;\n } catch (error) {\n return {\n authorized: false,\n reason: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n /**\n * Extract token from a request object\n * Useful for middleware that needs to extract token before making authorization calls\n */\n async getTokenFromRequest(request: unknown): Promise<string | null> {\n return extractTokenFromRequest(request, this.config);\n }\n\n // ============================================================================\n // Private - HTTP & Authentication\n // ============================================================================\n\n /**\n * Make an authenticated fetch request (token from request; no refresh).\n */\n private async fetchWithAuth(\n url: string,\n init?: RequestInit,\n request?: unknown\n ): Promise<Response> {\n return this.doFetch(url, init, request);\n }\n\n /**\n * Perform the actual fetch request\n */\n private async doFetch(url: string, init?: RequestInit, request?: unknown): Promise<Response> {\n const fetchFn = this.config.fetch ?? globalThis.fetch;\n const fullUrl = url.startsWith('http') ? url : `${this.config.apiUrl}${url}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(init?.headers as Record<string, string>),\n };\n\n // Add authorization header if token is available\n if (request) {\n const token = await extractTokenFromRequest(request, this.config);\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n // Forward cookies if using cookie-based auth\n const req = request as { headers?: { cookie?: string } };\n if (req.headers?.cookie) {\n headers['Cookie'] = req.headers.cookie;\n }\n }\n\n return fetchFn(fullUrl, {\n ...init,\n headers,\n // Include cookies for same-origin requests (supports cookie-based auth)\n credentials: this.config.credentials ?? 'include',\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/utils/token-extractor.ts
|
|
2
2
|
/**
|
|
3
3
|
* Extract Bearer token from Authorization header
|
|
4
4
|
*/
|
|
@@ -61,8 +61,7 @@ async function extractTokenFromRequest(request, config) {
|
|
|
61
61
|
}
|
|
62
62
|
return null;
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/typeof.js
|
|
64
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/typeof.js
|
|
66
65
|
function _typeof(o) {
|
|
67
66
|
"@babel/helpers - typeof";
|
|
68
67
|
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
@@ -71,8 +70,7 @@ function _typeof(o) {
|
|
|
71
70
|
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
72
71
|
}, _typeof(o);
|
|
73
72
|
}
|
|
74
|
-
|
|
75
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/toPrimitive.js
|
|
73
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/toPrimitive.js
|
|
76
74
|
function toPrimitive(t, r) {
|
|
77
75
|
if ("object" != _typeof(t) || !t) return t;
|
|
78
76
|
var e = t[Symbol.toPrimitive];
|
|
@@ -83,14 +81,12 @@ function toPrimitive(t, r) {
|
|
|
83
81
|
}
|
|
84
82
|
return ("string" === r ? String : Number)(t);
|
|
85
83
|
}
|
|
86
|
-
|
|
87
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/toPropertyKey.js
|
|
84
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/toPropertyKey.js
|
|
88
85
|
function toPropertyKey(t) {
|
|
89
86
|
var i = toPrimitive(t, "string");
|
|
90
87
|
return "symbol" == _typeof(i) ? i : i + "";
|
|
91
88
|
}
|
|
92
|
-
|
|
93
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/defineProperty.js
|
|
89
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/defineProperty.js
|
|
94
90
|
function _defineProperty(e, r, t) {
|
|
95
91
|
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
96
92
|
value: t,
|
|
@@ -99,8 +95,7 @@ function _defineProperty(e, r, t) {
|
|
|
99
95
|
writable: !0
|
|
100
96
|
}) : e[r] = t, e;
|
|
101
97
|
}
|
|
102
|
-
|
|
103
|
-
//#region src/grant-client.ts
|
|
98
|
+
// src/grant-client.ts
|
|
104
99
|
/**
|
|
105
100
|
* Grant Client for server-side applications
|
|
106
101
|
*
|
|
@@ -199,7 +194,6 @@ var GrantClient = class {
|
|
|
199
194
|
});
|
|
200
195
|
}
|
|
201
196
|
};
|
|
202
|
-
//#endregion
|
|
203
197
|
Object.defineProperty(exports, "GrantClient", {
|
|
204
198
|
enumerable: true,
|
|
205
199
|
get: function() {
|
|
@@ -225,4 +219,4 @@ Object.defineProperty(exports, "extractTokenFromRequest", {
|
|
|
225
219
|
}
|
|
226
220
|
});
|
|
227
221
|
|
|
228
|
-
//# sourceMappingURL=grant-client-
|
|
222
|
+
//# sourceMappingURL=grant-client-DEaSxech.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grant-client-BtXpNZ6b.cjs","names":[],"sources":["../src/utils/token-extractor.ts","../src/grant-client.ts"],"sourcesContent":["import type { GrantServerConfig } from '../types';\n\n/**\n * Extract Bearer token from Authorization header\n */\nexport function extractBearerToken(authHeader: string | undefined): string | null {\n if (!authHeader) return null;\n\n const parts = authHeader.trim().split(/\\s+/);\n if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {\n return null;\n }\n\n return parts[1];\n}\n\n/**\n * Parse cookie header string into key-value pairs\n */\nfunction parseCookieHeader(cookieHeader: string): Record<string, string> {\n const cookies: Record<string, string> = {};\n\n cookieHeader.split(';').forEach((cookie) => {\n const [name, ...rest] = cookie.trim().split('=');\n if (name && rest.length > 0) {\n cookies[name.trim()] = rest.join('=').trim();\n }\n });\n\n return cookies;\n}\n\n/**\n * Extract token from cookies\n */\nexport function extractTokenFromCookies(\n cookieHeader: string | undefined,\n cookieName: string\n): string | null {\n if (!cookieHeader) return null;\n\n const cookies = parseCookieHeader(cookieHeader);\n return cookies[cookieName] || null;\n}\n\n/**\n * Extract token from Express request\n */\nexport async function extractTokenFromRequest(\n request: unknown,\n config: GrantServerConfig\n): Promise<string | null> {\n // Use custom token resolver if provided\n if (config.getToken) {\n const token = await config.getToken(request);\n if (token) return token;\n }\n\n // Try to extract from request (Express-style or Web API / NextRequest)\n const req = request as {\n headers?:\n { authorization?: string; cookie?: string } | { get: (name: string) => string | null };\n cookies?: Record<string, string>;\n };\n\n if (!req?.headers) return null;\n\n // Web API Headers (NextRequest, Request): headers.get(name)\n const headersGet = (req.headers as { get?: (name: string) => string | null }).get;\n if (typeof headersGet === 'function') {\n const authHeader = headersGet.call(req.headers, 'authorization');\n const bearerToken = extractBearerToken(authHeader ?? undefined);\n if (bearerToken) return bearerToken;\n const cookieName = config.cookieName || 'grant-access-token';\n const cookieHeader = headersGet.call(req.headers, 'cookie');\n if (cookieHeader) {\n const cookieToken = extractTokenFromCookies(cookieHeader, cookieName);\n if (cookieToken) return cookieToken;\n }\n return null;\n }\n\n // Express-style: headers.authorization, headers.cookie\n const plainHeaders = req.headers as { authorization?: string; cookie?: string };\n const authHeader = plainHeaders.authorization;\n const bearerToken = extractBearerToken(authHeader);\n if (bearerToken) return bearerToken;\n\n const cookieName = config.cookieName || 'grant-access-token';\n\n if (req.cookies?.[cookieName]) {\n return req.cookies[cookieName];\n }\n\n const cookieHeader = plainHeaders.cookie;\n if (cookieHeader) {\n const cookieToken = extractTokenFromCookies(cookieHeader, cookieName);\n if (cookieToken) return cookieToken;\n }\n\n return null;\n}\n","import type { AuthorizationResult, GrantServerConfig, PermissionCheckOptions } from './types';\nimport { extractTokenFromRequest } from './utils/token-extractor';\n\n/**\n * Grant Client for server-side applications\n *\n * Makes HTTP requests to the Grant API to check permissions.\n * Uses API-key exchanged tokens (scope in JWT claims); token-based and cookie-based extraction supported.\n * No caching - server-side caching is handled by grant-api.\n */\nexport class GrantClient {\n public readonly config: Required<Pick<GrantServerConfig, 'apiUrl'>> & GrantServerConfig;\n\n constructor(config: GrantServerConfig) {\n this.config = config;\n }\n\n // ============================================================================\n // Public API - Permission Checks\n // ============================================================================\n\n /**\n * Check if the current user has a specific permission\n *\n * @example\n * ```ts\n * const canEdit = await grant.isGranted('document', 'update', { scope });\n * if (canEdit) {\n * // Proceed with operation\n * }\n * ```\n */\n async isGranted(\n resource: string,\n action: string,\n options?: PermissionCheckOptions,\n request?: unknown\n ): Promise<boolean> {\n const result = await this.isAuthorized(resource, action, options, request);\n return result.authorized;\n }\n\n /**\n * Check authorization with full result details\n *\n * @example\n * ```ts\n * const result = await grant.isAuthorized('document', 'update', { scope }, request);\n * if (!result.authorized) {\n * console.log('Denied:', result.reason);\n * }\n * ```\n */\n async isAuthorized(\n resource: string,\n action: string,\n options?: PermissionCheckOptions,\n request?: unknown\n ): Promise<AuthorizationResult> {\n try {\n // API expects: { permission: { resource, action }, context: { resource?: any }, scope?: { tenant, id } }\n const response = await this.fetchWithAuth(\n '/api/auth/is-authorized',\n {\n method: 'POST',\n body: JSON.stringify({\n permission: {\n resource,\n action,\n },\n context: {\n resource: options?.context?.resource || null,\n },\n }),\n },\n request\n );\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n return {\n authorized: false,\n reason: error.message || `API error: ${response.status}`,\n };\n }\n\n const json = await response.json();\n // API returns { success: true, data: { authorized, ... } }\n const result: AuthorizationResult = json.data ?? json;\n return result;\n } catch (error) {\n return {\n authorized: false,\n reason: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n /**\n * Extract token from a request object\n * Useful for middleware that needs to extract token before making authorization calls\n */\n async getTokenFromRequest(request: unknown): Promise<string | null> {\n return extractTokenFromRequest(request, this.config);\n }\n\n // ============================================================================\n // Private - HTTP & Authentication\n // ============================================================================\n\n /**\n * Make an authenticated fetch request (token from request; no refresh).\n */\n private async fetchWithAuth(\n url: string,\n init?: RequestInit,\n request?: unknown\n ): Promise<Response> {\n return this.doFetch(url, init, request);\n }\n\n /**\n * Perform the actual fetch request\n */\n private async doFetch(url: string, init?: RequestInit, request?: unknown): Promise<Response> {\n const fetchFn = this.config.fetch ?? globalThis.fetch;\n const fullUrl = url.startsWith('http') ? url : `${this.config.apiUrl}${url}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(init?.headers as Record<string, string>),\n };\n\n // Add authorization header if token is available\n if (request) {\n const token = await extractTokenFromRequest(request, this.config);\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n // Forward cookies if using cookie-based auth\n const req = request as { headers?: { cookie?: string } };\n if (req.headers?.cookie) {\n headers['Cookie'] = req.headers.cookie;\n }\n }\n\n return fetchFn(fullUrl, {\n ...init,\n headers,\n // Include cookies for same-origin requests (supports cookie-based auth)\n credentials: this.config.credentials ?? 'include',\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"grant-client-DEaSxech.cjs","names":[],"sources":["../src/utils/token-extractor.ts","../src/grant-client.ts"],"sourcesContent":["import type { GrantServerConfig } from '../types';\n\n/**\n * Extract Bearer token from Authorization header\n */\nexport function extractBearerToken(authHeader: string | undefined): string | null {\n if (!authHeader) return null;\n\n const parts = authHeader.trim().split(/\\s+/);\n if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {\n return null;\n }\n\n return parts[1];\n}\n\n/**\n * Parse cookie header string into key-value pairs\n */\nfunction parseCookieHeader(cookieHeader: string): Record<string, string> {\n const cookies: Record<string, string> = {};\n\n cookieHeader.split(';').forEach((cookie) => {\n const [name, ...rest] = cookie.trim().split('=');\n if (name && rest.length > 0) {\n cookies[name.trim()] = rest.join('=').trim();\n }\n });\n\n return cookies;\n}\n\n/**\n * Extract token from cookies\n */\nexport function extractTokenFromCookies(\n cookieHeader: string | undefined,\n cookieName: string\n): string | null {\n if (!cookieHeader) return null;\n\n const cookies = parseCookieHeader(cookieHeader);\n return cookies[cookieName] || null;\n}\n\n/**\n * Extract token from Express request\n */\nexport async function extractTokenFromRequest(\n request: unknown,\n config: GrantServerConfig\n): Promise<string | null> {\n // Use custom token resolver if provided\n if (config.getToken) {\n const token = await config.getToken(request);\n if (token) return token;\n }\n\n // Try to extract from request (Express-style or Web API / NextRequest)\n const req = request as {\n headers?:\n { authorization?: string; cookie?: string } | { get: (name: string) => string | null };\n cookies?: Record<string, string>;\n };\n\n if (!req?.headers) return null;\n\n // Web API Headers (NextRequest, Request): headers.get(name)\n const headersGet = (req.headers as { get?: (name: string) => string | null }).get;\n if (typeof headersGet === 'function') {\n const authHeader = headersGet.call(req.headers, 'authorization');\n const bearerToken = extractBearerToken(authHeader ?? undefined);\n if (bearerToken) return bearerToken;\n const cookieName = config.cookieName || 'grant-access-token';\n const cookieHeader = headersGet.call(req.headers, 'cookie');\n if (cookieHeader) {\n const cookieToken = extractTokenFromCookies(cookieHeader, cookieName);\n if (cookieToken) return cookieToken;\n }\n return null;\n }\n\n // Express-style: headers.authorization, headers.cookie\n const plainHeaders = req.headers as { authorization?: string; cookie?: string };\n const authHeader = plainHeaders.authorization;\n const bearerToken = extractBearerToken(authHeader);\n if (bearerToken) return bearerToken;\n\n const cookieName = config.cookieName || 'grant-access-token';\n\n if (req.cookies?.[cookieName]) {\n return req.cookies[cookieName];\n }\n\n const cookieHeader = plainHeaders.cookie;\n if (cookieHeader) {\n const cookieToken = extractTokenFromCookies(cookieHeader, cookieName);\n if (cookieToken) return cookieToken;\n }\n\n return null;\n}\n","import type { AuthorizationResult, GrantServerConfig, PermissionCheckOptions } from './types';\nimport { extractTokenFromRequest } from './utils/token-extractor';\n\n/**\n * Grant Client for server-side applications\n *\n * Makes HTTP requests to the Grant API to check permissions.\n * Uses API-key exchanged tokens (scope in JWT claims); token-based and cookie-based extraction supported.\n * No caching - server-side caching is handled by grant-api.\n */\nexport class GrantClient {\n public readonly config: Required<Pick<GrantServerConfig, 'apiUrl'>> & GrantServerConfig;\n\n constructor(config: GrantServerConfig) {\n this.config = config;\n }\n\n // ============================================================================\n // Public API - Permission Checks\n // ============================================================================\n\n /**\n * Check if the current user has a specific permission\n *\n * @example\n * ```ts\n * const canEdit = await grant.isGranted('document', 'update', { scope });\n * if (canEdit) {\n * // Proceed with operation\n * }\n * ```\n */\n async isGranted(\n resource: string,\n action: string,\n options?: PermissionCheckOptions,\n request?: unknown\n ): Promise<boolean> {\n const result = await this.isAuthorized(resource, action, options, request);\n return result.authorized;\n }\n\n /**\n * Check authorization with full result details\n *\n * @example\n * ```ts\n * const result = await grant.isAuthorized('document', 'update', { scope }, request);\n * if (!result.authorized) {\n * console.log('Denied:', result.reason);\n * }\n * ```\n */\n async isAuthorized(\n resource: string,\n action: string,\n options?: PermissionCheckOptions,\n request?: unknown\n ): Promise<AuthorizationResult> {\n try {\n // API expects: { permission: { resource, action }, context: { resource?: any }, scope?: { tenant, id } }\n const response = await this.fetchWithAuth(\n '/api/auth/is-authorized',\n {\n method: 'POST',\n body: JSON.stringify({\n permission: {\n resource,\n action,\n },\n context: {\n resource: options?.context?.resource || null,\n },\n }),\n },\n request\n );\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n return {\n authorized: false,\n reason: error.message || `API error: ${response.status}`,\n };\n }\n\n const json = await response.json();\n // API returns { success: true, data: { authorized, ... } }\n const result: AuthorizationResult = json.data ?? json;\n return result;\n } catch (error) {\n return {\n authorized: false,\n reason: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n /**\n * Extract token from a request object\n * Useful for middleware that needs to extract token before making authorization calls\n */\n async getTokenFromRequest(request: unknown): Promise<string | null> {\n return extractTokenFromRequest(request, this.config);\n }\n\n // ============================================================================\n // Private - HTTP & Authentication\n // ============================================================================\n\n /**\n * Make an authenticated fetch request (token from request; no refresh).\n */\n private async fetchWithAuth(\n url: string,\n init?: RequestInit,\n request?: unknown\n ): Promise<Response> {\n return this.doFetch(url, init, request);\n }\n\n /**\n * Perform the actual fetch request\n */\n private async doFetch(url: string, init?: RequestInit, request?: unknown): Promise<Response> {\n const fetchFn = this.config.fetch ?? globalThis.fetch;\n const fullUrl = url.startsWith('http') ? url : `${this.config.apiUrl}${url}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(init?.headers as Record<string, string>),\n };\n\n // Add authorization header if token is available\n if (request) {\n const token = await extractTokenFromRequest(request, this.config);\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n // Forward cookies if using cookie-based auth\n const req = request as { headers?: { cookie?: string } };\n if (req.headers?.cookie) {\n headers['Cookie'] = req.headers.cookie;\n }\n }\n\n return fetchFn(fullUrl, {\n ...init,\n headers,\n // Include cookies for same-origin requests (supports cookie-based auth)\n credentials: this.config.credentials ?? 'include',\n });\n }\n}\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_grant_client = require("./grant-client-
|
|
3
|
-
const require_errors = require("./errors-
|
|
2
|
+
const require_grant_client = require("./grant-client-DEaSxech.cjs");
|
|
3
|
+
const require_errors = require("./errors-M--U1x5o.cjs");
|
|
4
4
|
exports.AuthenticationError = require_errors.AuthenticationError;
|
|
5
5
|
exports.AuthorizationError = require_errors.AuthorizationError;
|
|
6
6
|
exports.BadRequestError = require_errors.BadRequestError;
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as extractTokenFromRequest, r as extractBearerToken, t as GrantClient } from "./grant-client-
|
|
2
|
-
import { a as NotFoundError, i as GrantServerError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-
|
|
1
|
+
import { i as extractTokenFromRequest, r as extractBearerToken, t as GrantClient } from "./grant-client-1Cd2jhvZ.js";
|
|
2
|
+
import { a as NotFoundError, i as GrantServerError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-CfqUl3ZG.js";
|
|
3
3
|
export { AuthenticationError, AuthorizationError, BadRequestError, GrantClient, GrantServerError, NotFoundError, extractBearerToken, extractTokenFromRequest };
|
package/dist/nest.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_grant_client = require("./grant-client-
|
|
3
|
-
const require_debug = require("./debug-
|
|
2
|
+
const require_grant_client = require("./grant-client-DEaSxech.cjs");
|
|
3
|
+
const require_debug = require("./debug-Bd3mwO_G.cjs");
|
|
4
4
|
let _nestjs_common = require("@nestjs/common");
|
|
5
|
-
|
|
5
|
+
// src/nest/grant.decorator.ts
|
|
6
6
|
/**
|
|
7
7
|
* Metadata key for Grant options (resource, action) on route handlers.
|
|
8
8
|
* Used by GrantGuard when options are not passed in the constructor.
|
|
@@ -14,16 +14,14 @@ function Grant(resourceOrOptions, action) {
|
|
|
14
14
|
action
|
|
15
15
|
} : resourceOrOptions);
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorate.js
|
|
17
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/decorate.js
|
|
19
18
|
function __decorate(decorators, target, key, desc) {
|
|
20
19
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
21
20
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
22
21
|
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
22
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
24
23
|
}
|
|
25
|
-
|
|
26
|
-
//#region src/nest/grant.module.ts
|
|
24
|
+
// src/nest/grant.module.ts
|
|
27
25
|
var _GrantModule;
|
|
28
26
|
var GRANT_CLIENT = "GrantClient";
|
|
29
27
|
var GrantModule = _GrantModule = class GrantModule {
|
|
@@ -43,20 +41,17 @@ var GrantModule = _GrantModule = class GrantModule {
|
|
|
43
41
|
}
|
|
44
42
|
};
|
|
45
43
|
GrantModule = _GrantModule = __decorate([(0, _nestjs_common.Global)(), (0, _nestjs_common.Module)({})], GrantModule);
|
|
46
|
-
|
|
47
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorateMetadata.js
|
|
44
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/decorateMetadata.js
|
|
48
45
|
function __decorateMetadata(k, v) {
|
|
49
46
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
50
47
|
}
|
|
51
|
-
|
|
52
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorateParam.js
|
|
48
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/decorateParam.js
|
|
53
49
|
function __decorateParam(paramIndex, decorator) {
|
|
54
50
|
return function(target, key) {
|
|
55
51
|
decorator(target, key, paramIndex);
|
|
56
52
|
};
|
|
57
53
|
}
|
|
58
|
-
|
|
59
|
-
//#region src/nest/grant.guard.ts
|
|
54
|
+
// src/nest/grant.guard.ts
|
|
60
55
|
/** Injection token for GrantGuard. Use with @UseGuards(GRANT_GUARD) so Nest resolves the guard from the container (with GrantClient injected). */
|
|
61
56
|
var GRANT_GUARD = "GrantGuard";
|
|
62
57
|
/**
|
|
@@ -152,7 +147,6 @@ GrantGuard = __decorate([
|
|
|
152
147
|
__decorateParam(0, (0, _nestjs_common.Inject)(GRANT_CLIENT)),
|
|
153
148
|
__decorateMetadata("design:paramtypes", [typeof require_grant_client.GrantClient === "undefined" ? Object : require_grant_client.GrantClient, Object])
|
|
154
149
|
], GrantGuard);
|
|
155
|
-
//#endregion
|
|
156
150
|
exports.GRANT_CLIENT = GRANT_CLIENT;
|
|
157
151
|
exports.GRANT_GUARD = GRANT_GUARD;
|
|
158
152
|
exports.GRANT_OPTIONS_KEY = GRANT_OPTIONS_KEY;
|
package/dist/nest.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nest.cjs","names":["SetMetadata","GrantClient","_decorate","Global","Module","ForbiddenException","extractTokenFromRequest","UnauthorizedException","NotFoundException","_decorate","Injectable","_decorateParam","Inject","_decorateMetadata","GrantClient"],"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 | 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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"}
|
|
1
|
+
{"version":3,"file":"nest.cjs","names":["SetMetadata","GrantClient","_decorate","Global","Module","ForbiddenException","extractTokenFromRequest","UnauthorizedException","NotFoundException","_decorate","Injectable","_decorateParam","Inject","_decorateMetadata","GrantClient"],"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 | 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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"}
|
package/dist/nest.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { i as extractTokenFromRequest, n as _defineProperty, t as GrantClient } from "./grant-client-
|
|
2
|
-
import { t as debugGrant } from "./debug-
|
|
1
|
+
import { i as extractTokenFromRequest, n as _defineProperty, t as GrantClient } from "./grant-client-1Cd2jhvZ.js";
|
|
2
|
+
import { t as debugGrant } from "./debug-DfEEZ0z2.js";
|
|
3
3
|
import { ForbiddenException, Global, Inject, Injectable, Module, NotFoundException, SetMetadata, UnauthorizedException } from "@nestjs/common";
|
|
4
|
-
|
|
4
|
+
// src/nest/grant.decorator.ts
|
|
5
5
|
/**
|
|
6
6
|
* Metadata key for Grant options (resource, action) on route handlers.
|
|
7
7
|
* Used by GrantGuard when options are not passed in the constructor.
|
|
@@ -13,16 +13,14 @@ function Grant(resourceOrOptions, action) {
|
|
|
13
13
|
action
|
|
14
14
|
} : resourceOrOptions);
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorate.js
|
|
16
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/decorate.js
|
|
18
17
|
function __decorate(decorators, target, key, desc) {
|
|
19
18
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
19
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
20
|
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;
|
|
22
21
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
22
|
}
|
|
24
|
-
|
|
25
|
-
//#region src/nest/grant.module.ts
|
|
23
|
+
// src/nest/grant.module.ts
|
|
26
24
|
var _GrantModule;
|
|
27
25
|
var GRANT_CLIENT = "GrantClient";
|
|
28
26
|
var GrantModule = _GrantModule = class GrantModule {
|
|
@@ -42,20 +40,17 @@ var GrantModule = _GrantModule = class GrantModule {
|
|
|
42
40
|
}
|
|
43
41
|
};
|
|
44
42
|
GrantModule = _GrantModule = __decorate([Global(), Module({})], GrantModule);
|
|
45
|
-
|
|
46
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorateMetadata.js
|
|
43
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/decorateMetadata.js
|
|
47
44
|
function __decorateMetadata(k, v) {
|
|
48
45
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
49
46
|
}
|
|
50
|
-
|
|
51
|
-
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorateParam.js
|
|
47
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/decorateParam.js
|
|
52
48
|
function __decorateParam(paramIndex, decorator) {
|
|
53
49
|
return function(target, key) {
|
|
54
50
|
decorator(target, key, paramIndex);
|
|
55
51
|
};
|
|
56
52
|
}
|
|
57
|
-
|
|
58
|
-
//#region src/nest/grant.guard.ts
|
|
53
|
+
// src/nest/grant.guard.ts
|
|
59
54
|
/** Injection token for GrantGuard. Use with @UseGuards(GRANT_GUARD) so Nest resolves the guard from the container (with GrantClient injected). */
|
|
60
55
|
var GRANT_GUARD = "GrantGuard";
|
|
61
56
|
/**
|
|
@@ -151,7 +146,6 @@ GrantGuard = __decorate([
|
|
|
151
146
|
__decorateParam(0, Inject(GRANT_CLIENT)),
|
|
152
147
|
__decorateMetadata("design:paramtypes", [typeof GrantClient === "undefined" ? Object : GrantClient, Object])
|
|
153
148
|
], GrantGuard);
|
|
154
|
-
//#endregion
|
|
155
149
|
export { GRANT_CLIENT, GRANT_GUARD, GRANT_OPTIONS_KEY, Grant, GrantClient, GrantGuard, GrantModule };
|
|
156
150
|
|
|
157
151
|
//# sourceMappingURL=nest.mjs.map
|
package/dist/nest.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nest.mjs","names":["_decorate","_decorate","_decorateParam","_decorateMetadata"],"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 | 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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"}
|
|
1
|
+
{"version":3,"file":"nest.mjs","names":["_decorate","_decorate","_decorateParam","_decorateMetadata"],"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 | 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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"}
|
package/dist/next.cjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_grant_client = require("./grant-client-
|
|
3
|
-
const require_errors = require("./errors-
|
|
4
|
-
const require_debug = require("./debug-
|
|
2
|
+
const require_grant_client = require("./grant-client-DEaSxech.cjs");
|
|
3
|
+
const require_errors = require("./errors-M--U1x5o.cjs");
|
|
4
|
+
const require_debug = require("./debug-Bd3mwO_G.cjs");
|
|
5
5
|
let next_server = require("next/server");
|
|
6
|
-
|
|
6
|
+
// src/next/with-grant.ts
|
|
7
7
|
/**
|
|
8
8
|
* Wrap a Next.js App Router route handler with Grant authorization.
|
|
9
9
|
* Use for GET, POST, PUT, PATCH, DELETE in app/api/.../route.ts.
|
|
@@ -68,7 +68,6 @@ function withGrant(client, options, handler) {
|
|
|
68
68
|
return handler(request, { authorization: result });
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
-
//#endregion
|
|
72
71
|
exports.AuthenticationError = require_errors.AuthenticationError;
|
|
73
72
|
exports.AuthorizationError = require_errors.AuthorizationError;
|
|
74
73
|
exports.BadRequestError = require_errors.BadRequestError;
|
package/dist/next.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { i as extractTokenFromRequest, t as GrantClient } from "./grant-client-
|
|
2
|
-
import { a as NotFoundError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-
|
|
3
|
-
import { t as debugGrant } from "./debug-
|
|
1
|
+
import { i as extractTokenFromRequest, t as GrantClient } from "./grant-client-1Cd2jhvZ.js";
|
|
2
|
+
import { a as NotFoundError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-CfqUl3ZG.js";
|
|
3
|
+
import { t as debugGrant } from "./debug-DfEEZ0z2.js";
|
|
4
4
|
import { NextResponse } from "next/server";
|
|
5
|
-
|
|
5
|
+
// src/next/with-grant.ts
|
|
6
6
|
/**
|
|
7
7
|
* Wrap a Next.js App Router route handler with Grant authorization.
|
|
8
8
|
* Use for GET, POST, PUT, PATCH, DELETE in app/api/.../route.ts.
|
|
@@ -67,7 +67,6 @@ function withGrant(client, options, handler) {
|
|
|
67
67
|
return handler(request, { authorization: result });
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
-
//#endregion
|
|
71
70
|
export { AuthenticationError, AuthorizationError, BadRequestError, GrantClient, NotFoundError, withGrant };
|
|
72
71
|
|
|
73
72
|
//# sourceMappingURL=next.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grantjs/server",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.3",
|
|
4
4
|
"description": "Server SDK for Grant authorization - Middleware and guards for Express, Fastify, NestJS, and Next.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"registry": "https://registry.npmjs.org/"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@grantjs/schema": "1.18.
|
|
75
|
+
"@grantjs/schema": "1.18.3"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@types/express": "^5.0.0",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"@nestjs/core": "^12.1.3",
|
|
87
87
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
88
88
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
89
|
-
"vite": "^8.3.
|
|
89
|
+
"vite": "^8.3.5",
|
|
90
90
|
"vite-plugin-dts": "^5.1.2",
|
|
91
91
|
"vitest": "^5.0.5"
|
|
92
92
|
},
|