{"version":3,"sources":["../src/types/jwt.types.ts","../src/utils/timingSafe.ts","../src/jwt/index.ts"],"names":["JwtErrorType","stdResponse","jwt"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { VerifyOptions, SignOptions, DecodeOptions } from \"jsonwebtoken\"\r\nimport type { StdResponse } from \"@digicroz/js-kit/std-response\"\r\n\r\nexport enum JwtErrorType {\r\n  INVALID_TOKEN = \"invalid_token\",\r\n  EXPIRED_TOKEN = \"expired_token\",\r\n  MALFORMED_TOKEN = \"malformed_token\",\r\n  VERIFICATION_FAILED = \"verify_failed\",\r\n  SIGNING_FAILED = \"sign_failed\",\r\n  INVALID_SECRET = \"invalid_secret\",\r\n}\r\n\r\nexport type JwtResult<T> = StdResponse<T, JwtErrorType>\r\n\r\nexport interface JwtPayload {\r\n  [key: string]: unknown\r\n  iat?: number\r\n  exp?: number\r\n  nbf?: number\r\n  iss?: string\r\n  sub?: string\r\n  aud?: string | string[]\r\n  jti?: string\r\n}\r\n\r\nexport interface JwtVerifyOptions extends VerifyOptions {\r\n  debug?: boolean\r\n}\r\n\r\nexport type JwtSignOptions = SignOptions\r\n\r\nexport type JwtDecodeOptions = DecodeOptions\r\n","function timingSafeEqual(a: string, b: string): boolean {\r\n  if (typeof a !== \"string\" || typeof b !== \"string\") return false;\r\n  if (a.length !== b.length) return false;\r\n\r\n  try {\r\n    const crypto = require(\"crypto\");\r\n    return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));\r\n  } catch {\r\n    let result = 0;\r\n    for (let i = 0; i < a.length; i++) {\r\n      result |= a.charCodeAt(i) ^ b.charCodeAt(i);\r\n    }\r\n    return result === 0;\r\n  }\r\n}\r\n\r\nfunction parseTokenStructure(token: string): {\r\n  header: string;\r\n  payload: string;\r\n  signature: string;\r\n} | null {\r\n  if (typeof token !== \"string\") return null;\r\n  const parts = token.split(\".\");\r\n  if (parts.length !== 3) return null;\r\n  return { header: parts[0], payload: parts[1], signature: parts[2] };\r\n}\r\n\r\nfunction safeBase64UrlDecode(str: string): string | null {\r\n  try {\r\n    if (typeof str !== \"string\") return null;\r\n    let padded = str;\r\n    const padding = 4 - (str.length % 4);\r\n    if (padding && padding !== 4) padded = str + \"=\".repeat(padding);\r\n    return Buffer.from(padded, \"base64\").toString(\"utf-8\");\r\n  } catch {\r\n    return null;\r\n  }\r\n}\r\n\r\nexport function isValidTokenStructure(token: string): boolean {\r\n  const parsed = parseTokenStructure(token);\r\n  if (!parsed) return false;\r\n\r\n  const payload = safeBase64UrlDecode(parsed.payload);\r\n  if (!payload) return false;\r\n\r\n  try {\r\n    JSON.parse(payload);\r\n    return true;\r\n  } catch {\r\n    return false;\r\n  }\r\n}\r\n","import jwt from \"jsonwebtoken\"\r\nimport type { JwtPayload } from \"../types/jwt.types.js\"\r\nimport {\r\n  JwtErrorType,\r\n  type JwtResult,\r\n  type JwtVerifyOptions,\r\n  type JwtSignOptions,\r\n  type JwtDecodeOptions,\r\n} from \"../types/jwt.types.js\"\r\nimport { stdResponse } from \"@digicroz/js-kit/std-response\"\r\nimport { isValidTokenStructure } from \"../utils/timingSafe.js\"\r\n\r\ntype TJwtVerifyProps = {\r\n  token: string\r\n  secret: string | Buffer\r\n  options?: JwtVerifyOptions\r\n}\r\n\r\nexport async function jwtVerify<T extends JwtPayload = JwtPayload>({\r\n  token,\r\n  secret,\r\n  options,\r\n}: TJwtVerifyProps): Promise<JwtResult<T>> {\r\n  try {\r\n    if (!token || typeof token !== \"string\") {\r\n      return stdResponse.error(\r\n        JwtErrorType.INVALID_TOKEN,\r\n        \"token must be a non-empty string\",\r\n      )\r\n    }\r\n\r\n    if (!secret || (typeof secret !== \"string\" && !Buffer.isBuffer(secret))) {\r\n      return stdResponse.error(\r\n        JwtErrorType.INVALID_SECRET,\r\n        \"secret must be a string or Buffer\",\r\n      )\r\n    }\r\n\r\n    if (!isValidTokenStructure(token)) {\r\n      return stdResponse.error(\r\n        JwtErrorType.MALFORMED_TOKEN,\r\n        \"token is malformed\",\r\n      )\r\n    }\r\n\r\n    const payload = await new Promise<T>((resolve, reject) => {\r\n      jwt.verify(\r\n        token,\r\n        secret,\r\n        options || {},\r\n        (err: Error | null, decoded: unknown) => {\r\n          if (err) {\r\n            reject(err)\r\n          } else if (typeof decoded !== \"object\" || decoded === null) {\r\n            reject(new jwt.JsonWebTokenError(\"Payload must be an object\"))\r\n          } else {\r\n            resolve(decoded as T)\r\n          }\r\n        },\r\n      )\r\n    })\r\n\r\n    return stdResponse.success(payload)\r\n  } catch (error) {\r\n    const jwtError = error as jwt.VerifyErrors | Error\r\n\r\n    if (options?.debug) {\r\n      console.log(\"[JWT Debug]\", {\r\n        errorName: (jwtError as any)?.name,\r\n        errorMessage: (jwtError as any)?.message,\r\n        fullError: jwtError,\r\n      })\r\n    }\r\n\r\n    let errorType = JwtErrorType.VERIFICATION_FAILED\r\n    let message = \"token verification failed\"\r\n\r\n    if (\"name\" in jwtError) {\r\n      switch (jwtError.name) {\r\n        case \"TokenExpiredError\":\r\n          errorType = JwtErrorType.EXPIRED_TOKEN\r\n          message = `token expired at ${(jwtError as jwt.TokenExpiredError).expiredAt?.toISOString()}`\r\n          break\r\n        case \"JsonWebTokenError\":\r\n          errorType = JwtErrorType.INVALID_TOKEN\r\n          message = jwtError.message || \"invalid token\"\r\n          break\r\n        case \"NotBeforeError\":\r\n          errorType = JwtErrorType.INVALID_TOKEN\r\n          message = \"token not yet valid\"\r\n          break\r\n        case \"SyntaxError\":\r\n          errorType = JwtErrorType.MALFORMED_TOKEN\r\n          message = \"malformed token\"\r\n          break\r\n      }\r\n    }\r\n\r\n    return stdResponse.error(errorType, message)\r\n  }\r\n}\r\n\r\ntype TJwtSignProps<T extends JwtPayload> = {\r\n  payload: T\r\n  secret: string | Buffer\r\n  options?: JwtSignOptions\r\n}\r\n\r\nexport async function jwtSign<T extends JwtPayload = JwtPayload>({\r\n  payload,\r\n  secret,\r\n  options,\r\n}: TJwtSignProps<T>) {\r\n  try {\r\n    if (!payload || typeof payload !== \"object\") {\r\n      return stdResponse.error(\r\n        JwtErrorType.INVALID_TOKEN,\r\n        \"payload must be an object\",\r\n      )\r\n    }\r\n\r\n    if (!secret || (typeof secret !== \"string\" && !Buffer.isBuffer(secret))) {\r\n      return stdResponse.error(\r\n        JwtErrorType.INVALID_SECRET,\r\n        \"secret must be a string or Buffer\",\r\n      )\r\n    }\r\n\r\n    const token = await new Promise<string>((resolve, reject) => {\r\n      jwt.sign(\r\n        payload,\r\n        secret,\r\n        options || {},\r\n        (err: Error | null, encoded: string | undefined) => {\r\n          if (err) {\r\n            reject(err)\r\n          } else if (!encoded) {\r\n            reject(new Error(\"token signing produced no output\"))\r\n          } else {\r\n            resolve(encoded)\r\n          }\r\n        },\r\n      )\r\n    })\r\n\r\n    return stdResponse.success(token)\r\n  } catch (error) {\r\n    const jwtError = error as Error\r\n    return stdResponse.error(\r\n      JwtErrorType.SIGNING_FAILED,\r\n      jwtError.message || \"token signing failed\",\r\n    )\r\n  }\r\n}\r\n\r\ntype TJwtDecodeProps = {\r\n  token: string\r\n  options?: JwtDecodeOptions\r\n}\r\n\r\nexport function jwtDecode<T extends JwtPayload = JwtPayload>({\r\n  token,\r\n  options,\r\n}: TJwtDecodeProps): JwtResult<T> {\r\n  try {\r\n    if (!token || typeof token !== \"string\") {\r\n      return stdResponse.error(\r\n        JwtErrorType.INVALID_TOKEN,\r\n        \"token must be a non-empty string\",\r\n      )\r\n    }\r\n\r\n    if (!isValidTokenStructure(token)) {\r\n      return stdResponse.error(\r\n        JwtErrorType.MALFORMED_TOKEN,\r\n        \"token is malformed\",\r\n      )\r\n    }\r\n\r\n    const decoded = jwt.decode(token, options || {})\r\n\r\n    if (!decoded) {\r\n      return stdResponse.error(\r\n        JwtErrorType.MALFORMED_TOKEN,\r\n        \"failed to decode token\",\r\n      )\r\n    }\r\n\r\n    if (typeof decoded !== \"object\") {\r\n      return stdResponse.error(\r\n        JwtErrorType.INVALID_TOKEN,\r\n        \"Payload must be an object\",\r\n      )\r\n    }\r\n\r\n    return stdResponse.success(decoded as T)\r\n  } catch (error) {\r\n    const jwtError = error as Error\r\n    return stdResponse.error(\r\n      JwtErrorType.MALFORMED_TOKEN,\r\n      jwtError.message || \"failed to decode token\",\r\n    )\r\n  }\r\n}\r\n"]}