@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.
@@ -1,4 +1,4 @@
1
- //#region src/utils/debug.ts
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-F-NPwfWM.cjs.map
23
+ //# sourceMappingURL=debug-Bd3mwO_G.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"debug-F-NPwfWM.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
+ {"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
- //#region src/utils/debug.ts
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-BcdveYlv.js.map
18
+ //# sourceMappingURL=debug-DfEEZ0z2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"debug-BcdveYlv.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
+ {"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-CWj6832E.js";
2
- //#region src/errors.ts
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-Cln6JSBJ.js.map
65
+ //# sourceMappingURL=errors-CfqUl3ZG.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors-Cln6JSBJ.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
+ {"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-BtXpNZ6b.cjs");
2
- //#region src/errors.ts
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-BB6c22Du.cjs.map
94
+ //# sourceMappingURL=errors-M--U1x5o.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors-BB6c22Du.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"}
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-BtXpNZ6b.cjs");
3
- const require_errors = require("./errors-BB6c22Du.cjs");
4
- const require_debug = require("./debug-F-NPwfWM.cjs");
5
- //#region src/express/middleware.ts
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-CWj6832E.js";
2
- import { a as NotFoundError, i as GrantServerError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-Cln6JSBJ.js";
3
- import { t as debugGrant } from "./debug-BcdveYlv.js";
4
- //#region src/express/middleware.ts
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-BtXpNZ6b.cjs");
3
- const require_errors = require("./errors-BB6c22Du.cjs");
4
- const require_debug = require("./debug-F-NPwfWM.cjs");
5
- //#region src/fastify/plugin.ts
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-CWj6832E.js";
2
- import { a as NotFoundError, i as GrantServerError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-Cln6JSBJ.js";
3
- import { t as debugGrant } from "./debug-BcdveYlv.js";
4
- //#region src/fastify/plugin.ts
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
- //#region src/utils/token-extractor.ts
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
- //#endregion
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
- //#endregion
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
- //#endregion
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
- //#endregion
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
- //#endregion
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-CWj6832E.js.map
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
- //#region src/utils/token-extractor.ts
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
- //#endregion
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
- //#endregion
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
- //#endregion
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
- //#endregion
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
- //#endregion
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-BtXpNZ6b.cjs.map
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-BtXpNZ6b.cjs");
3
- const require_errors = require("./errors-BB6c22Du.cjs");
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-CWj6832E.js";
2
- import { a as NotFoundError, i as GrantServerError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-Cln6JSBJ.js";
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-BtXpNZ6b.cjs");
3
- const require_debug = require("./debug-F-NPwfWM.cjs");
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
- //#region src/nest/grant.decorator.ts
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
- //#endregion
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
- //#endregion
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
- //#endregion
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
- //#endregion
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
- //#endregion
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":";;;;;;;;;AAMA,IAAa,oBAAoB;AAkCjC,SAAgB,MACd,mBACA,QACgC;CAKhC,QAAA,GAAOA,eAAAA,YAAAA,CAAY,mBAHjB,OAAO,sBAAsB,YAAY,WAAW,KAAA,IAChD;EAAE,UAAU;EAAmB;CAAO,IACrC,iBACsC;AAC/C;;;;;;;;;;;;AC5CA,IAAa,eAAe;AAyBrB,IAAM,cAAA,eAAN,MAAM,YAAY;CACvB,OAAO,QAAQ,QAA0C;EACvD,MAAM,SAAS,IAAIC,qBAAAA,YAAY,MAAM;EACrC,OAAO;GACL,QAAA;GACA,WAAW,CACT;IAAE,SAASA,qBAAAA;IAAa,UAAU;GAAO,GACzC;IAAE,SAAS;IAAc,UAAU;GAAO,CAC5C;GACA,SAAS,CAACA,qBAAAA,aAAa,YAAY;EACrC;CACF;AACF;AAdC,cAAA,eAAAC,WAAA,EAAA,GAAAC,eAAAA,OAAAA,CAAO,IAAA,GACPC,eAAAA,OAAAA,CAAO,CAAC,CAAC,CAAA,GAAA,WAAA;;;;;;;;;;;;;;;;ACXV,IAAa,cAAc;;;;;;;;;;;;;;;;;AAqC3B,SAAS,oBAAoB,GAAoC;CAC/D,OACE,OAAO,MAAM,YACb,MAAM,QACN,cAAc,KACd,YAAY,KACZ,OAAQ,EAAwB,aAAa,YAC7C,OAAQ,EAAwB,WAAW;AAE/C;AAGO,IAAM,aAAN,MAAM,WAAkC;CAI7C,YACE,QACA,oBACA;EAFuC,qBAAA,gBAAA,MAAA,UAAA,KAAA,CAAA;EAJzC,qBAAA,gBAAA,MAAA,mBAAA,KAAA,CAAA;EACA,qBAAA,gBAAA,MAAA,aAAA,KAAA,CAAA;EAGyC,KAAA,SAAA;EAGvC,IAAI,sBAAsB,oBAAoB,kBAAkB,GAC9D,KAAK,kBAAkB;OAEvB,KAAK,YAAY;CAErB;CAEA,sBAA8B,SAAqD;EACjF,MAAM,UAAU,QAAQ,WAAW;EACnC,MAAM,QAAQ,QAAQ,SAAS;EAE/B,IAAI,KAAK,WAAW;GAClB,MAAM,cAAc,KAAK,UAAU,IAAkB,mBAAmB,OAAO;GAC/E,MAAM,YAAY,KAAK,UAAU,IAAkB,mBAAmB,KAAK;GAC3E,IAAI,aAAa,OAAO;GACxB,IAAI,WAAW,OAAO;EACxB;EAEA,IAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,gBAAgB,YAAY;GAC/E,MAAM,cAAc,QAAQ,YAAY,mBAAmB,OAAO;GAElE,MAAM,YAAY,QAAQ,YAAY,mBAAmB,KAAK;GAC9D,IAAI,aAAa,OAAO;GACxB,IAAI,WAAW,OAAO;EACxB;CAEF;CAEA,MAAM,YAAY,SAA6C;EAC7D,MAAM,UAAU,QAAQ,aAAa,CAAC,CAAC,WAAW;EAElD,MAAM,UAAU,KAAK,mBAAmB,KAAK,sBAAsB,OAAO;EAE1E,IAAI,SAAS,YAAY,SAAS,QAChC,cAAA,WAAW,QAAQ;GACjB,UAAU,QAAQ;GAClB,QAAQ,QAAQ;GAChB,cAAc,CAAC,CAAC,KAAK;GACrB,SAAS,QAAQ,WAAW,CAAC,EAAE;GAC/B,YAAY,QAAQ,SAAS,CAAC,EAAE;EAClC,CAAC;EAGH,IAAI,CAAC,WAAW,CAAC,QAAQ,YAAY,CAAC,QAAQ,QAC5C,MAAM,IAAIC,eAAAA,mBACR,wFACF;EAGF,IAAI,CAAC,KAAK,QACR,MAAM,IAAIA,eAAAA,mBACR,wHACF;EAIF,IAAI,CAAC,MADeC,qBAAAA,wBAAwB,SAAS,KAAK,OAAO,MAAM,GAErE,MAAM,IAAIC,eAAAA,sBAAsB;GAAE,OAAO;GAAgB,MAAM;EAAkB,CAAC;EAGpF,IAAI,mBAAmD;EAEvD,MAAM,OAAO;EACb,IAAI,KAAK,kBAAkB;GACzB,mBAAmB,MAAM,KAAK,iBAAiB;IAC7C,cAAc,QAAQ;IACtB;GACF,CAAC;GACD,IAAI,CAAC,kBACH,MAAM,IAAIC,eAAAA,kBAAkB;IAAE,OAAO;IAAsB,MAAM;GAAY,CAAC;EAElF;EAEA,MAAM,SAAS,MAAM,KAAK,OAAO,aAC/B,QAAQ,UACR,QAAQ,QACR,EACE,SAAS,EACP,UAAU,oBAAoB,KAAA,EAChC,EACF,GACA,OACF;EAEA,cAAA,WAAW,QAAQ;GACjB,UAAU,QAAQ;GAClB,QAAQ,QAAQ;GAChB,YAAY,OAAO;GACnB,GAAI,OAAO,aAAa,CAAC,IAAI,EAAE,QAAQ,OAAO,OAAO;EACvD,CAAC;EAED,IAAI,CAAC,OAAO,YACV,MAAM,IAAIH,eAAAA,mBAAmB;GAC3B,OAAO;GACP,MAAM;GACN,QAAQ,OAAO;EACjB,CAAC;EAGH,QAA+B,gBAAgB;EAC/C,OAAO;CACT;AACF;;EA/GCK,GAAAA,eAAAA,WAAAA,CAAW;CAMPC,gBAAA,IAAA,GAAAC,eAAAA,OAAAA,CAAO,YAAY,CAAA"}
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-CWj6832E.js";
2
- import { t as debugGrant } from "./debug-BcdveYlv.js";
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
- //#region src/nest/grant.decorator.ts
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
- //#endregion
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
- //#endregion
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
- //#endregion
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
- //#endregion
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
- //#endregion
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-BtXpNZ6b.cjs");
3
- const require_errors = require("./errors-BB6c22Du.cjs");
4
- const require_debug = require("./debug-F-NPwfWM.cjs");
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
- //#region src/next/with-grant.ts
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-CWj6832E.js";
2
- import { a as NotFoundError, n as AuthorizationError, r as BadRequestError, t as AuthenticationError } from "./errors-Cln6JSBJ.js";
3
- import { t as debugGrant } from "./debug-BcdveYlv.js";
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
- //#region src/next/with-grant.ts
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.2",
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.2"
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.4",
89
+ "vite": "^8.3.5",
90
90
  "vite-plugin-dts": "^5.1.2",
91
91
  "vitest": "^5.0.5"
92
92
  },