{
  "slug": "jwt-utils",
  "runtimes": {
    "node": {
      "frameworks": {
        "express": {
          "dependencies": {
            "runtime": [
              "jsonwebtoken",
              "zod"
            ],
            "dev": [
              "@types/jsonwebtoken"
            ]
          },
          "env": [
            "JWT_ACCESS_SECRET",
            "JWT_REFRESH_SECRET"
          ],
          "architectures": {
            "mvc": {
              "files": [
                {
                  "type": "file",
                  "path": "src/utils/jwt.ts",
                  "content": "import jwt from \"jsonwebtoken\";\nimport env from \"../configs/env\";\n\nconst ACCESS_TOKEN_EXPIRY = \"15m\";\nconst REFRESH_TOKEN_EXPIRY = \"7d\";\n\nexport function generateAccessToken(user: { _id: string }) {\n  return jwt.sign({ _id: user._id }, env.JWT_ACCESS_SECRET!, {\n    expiresIn: ACCESS_TOKEN_EXPIRY\n  });\n}\n\nexport function generateRefreshToken(userId: string) {\n  return jwt.sign({ userId }, env.JWT_REFRESH_SECRET!, {\n    expiresIn: REFRESH_TOKEN_EXPIRY\n  });\n}\n\nexport function verifyAccessToken(token: string) {\n  return jwt.verify(token, env.JWT_ACCESS_SECRET!) as {\n    _id: string;\n  };\n}\n\nexport function verifyRefreshToken(token: string) {\n  return jwt.verify(token, env.JWT_REFRESH_SECRET!) as {\n    userId: string;\n  };\n}\n"
                },
                {
                  "type": "file",
                  "path": "src/configs/env.ts",
                  "content": "import \"dotenv-flow/config\";\nimport { z } from \"zod\";\n\nexport const envSchema = z.object({\n  NODE_ENV: z\n    .enum([\"development\", \"test\", \"production\"])\n    .default(\"development\"),\n\n  PORT: z.string().regex(/^\\d+$/, \"PORT must be a number\").transform(Number),\n\n  LOG_LEVEL: z\n    .enum([\"fatal\", \"error\", \"warn\", \"info\", \"debug\", \"trace\"])\n    .default(\"info\"),\n  \n  JWT_REFRESH_SECRET: z.string().nonempty(\"JWT_REFRESH_SECRET is required\"),\n  JWT_ACCESS_SECRET: z.string().nonempty(\"JWT_ACCESS_SECRET is required\"),\n});\n\nexport type Env = z.infer<typeof envSchema>;\n\nconst result = envSchema.safeParse(process.env);\n\nif (!result.success) {\n  console.error(\"❌ Invalid environment configuration\");\n  console.error(z.prettifyError(result.error));\n  process.exit(1);\n}\n\nexport const env: Readonly<Env> = Object.freeze(result.data);\n\nexport default env;\n"
                }
              ]
            },
            "feature": {
              "files": [
                {
                  "type": "file",
                  "path": "src/shared/helpers/jwt.helpers.ts",
                  "content": "import jwt from \"jsonwebtoken\";\nimport env from \"../configs/env\";\n\nconst ACCESS_TOKEN_EXPIRY = \"15m\";\nconst REFRESH_TOKEN_EXPIRY = \"7d\";\n\nexport function generateAccessToken(user: { _id: string }) {\n  return jwt.sign({ _id: user._id }, env.JWT_ACCESS_SECRET!, {\n    expiresIn: ACCESS_TOKEN_EXPIRY\n  });\n}\n\nexport function generateRefreshToken(userId: string) {\n  return jwt.sign({ userId }, env.JWT_REFRESH_SECRET!, {\n    expiresIn: REFRESH_TOKEN_EXPIRY\n  });\n}\n\nexport function verifyAccessToken(token: string) {\n  return jwt.verify(token, env.JWT_ACCESS_SECRET!) as {\n    _id: string;\n  };\n}\n\nexport function verifyRefreshToken(token: string) {\n  return jwt.verify(token, env.JWT_REFRESH_SECRET!) as {\n    userId: string;\n  };\n}\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/configs/env.ts",
                  "content": "import \"dotenv-flow/config\";\nimport { z } from \"zod\";\n\nexport const envSchema = z.object({\n  NODE_ENV: z\n    .enum([\"development\", \"test\", \"production\"])\n    .default(\"development\"),\n\n  PORT: z.string().regex(/^\\d+$/, \"PORT must be a number\").transform(Number),\n\n  LOG_LEVEL: z\n    .enum([\"fatal\", \"error\", \"warn\", \"info\", \"debug\", \"trace\"])\n    .default(\"info\"),\n\n  JWT_REFRESH_SECRET: z.string().nonempty(\"JWT_REFRESH_SECRET is required\"),\n  JWT_ACCESS_SECRET: z.string().nonempty(\"JWT_ACCESS_SECRET is required\")\n});\n\nexport type Env = z.infer<typeof envSchema>;\n\nconst result = envSchema.safeParse(process.env);\n\nif (!result.success) {\n  console.error(\"❌ Invalid environment configuration\");\n  console.error(z.prettifyError(result.error));\n  process.exit(1);\n}\n\nexport const env: Readonly<Env> = Object.freeze(result.data);\n\nexport default env;\n"
                }
              ]
            }
          }
        },
        "nextjs": {
          "dependencies": {
            "runtime": [
              "jsonwebtoken",
              "zod"
            ],
            "dev": [
              "@types/jsonwebtoken"
            ]
          },
          "env": [
            "JWT_ACCESS_SECRET",
            "JWT_REFRESH_SECRET"
          ],
          "architectures": {
            "file-api": {
              "files": [
                {
                  "type": "file",
                  "path": "src/lib/jwt/jwt.verify.ts",
                  "content": "import jwt from \"jsonwebtoken\";\r\nimport {\r\n  AccessTokenPayload,\r\n  JwtPayload,\r\n  RefreshTokenPayload\r\n} from \"./jwt.types\";\r\nimport { JwtExpiredError, JwtInvalidError } from \"./jwt.errors\";\r\n\r\nfunction verifyToken<T extends JwtPayload>(token: string, secret: string): T {\r\n  try {\r\n    return jwt.verify(token, secret) as T;\r\n  } catch (err: any) {\r\n    if (err.name === \"TokenExpiredError\") {\r\n      throw new JwtExpiredError();\r\n    }\r\n    throw new JwtInvalidError();\r\n  }\r\n}\r\n\r\nexport function verifyAccessToken(token: string) {\r\n  return verifyToken(\r\n    token,\r\n    process.env.JWT_ACCESS_SECRET as string\r\n  ) as AccessTokenPayload;\r\n}\r\n\r\nexport function verifyRefreshToken(token: string) {\r\n  return verifyToken(\r\n    token,\r\n    process.env.JWT_REFRESH_SECRET as string\r\n  ) as RefreshTokenPayload;\r\n}\r\n"
                },
                {
                  "type": "file",
                  "path": "src/lib/jwt/jwt.utils.ts",
                  "content": "import jwt from \"jsonwebtoken\";\r\n\r\nexport function decodeToken<T = unknown>(token: string): T | null {\r\n  return jwt.decode(token) as T | null;\r\n}\r\n\r\nexport function extractTokenFromHeader(authHeader?: string): string | null {\r\n  if (!authHeader) return null;\r\n\r\n  const parts = authHeader.split(\" \");\r\n  if (parts.length !== 2 || parts[0] !== \"Bearer\") {\r\n    return null;\r\n  }\r\n\r\n  return parts[1];\r\n}\r\n"
                },
                {
                  "type": "file",
                  "path": "src/lib/jwt/jwt.types.ts",
                  "content": "export enum JwtType {\r\n  ACCESS = \"access\",\r\n  REFRESH = \"refresh\"\r\n}\r\n\r\nexport type JwtPayloadBase = {\r\n  sub: string;\r\n  iat?: number;\r\n  exp?: number;\r\n};\r\n\r\nexport type AccessTokenPayload = JwtPayloadBase & {\r\n  type: JwtType.ACCESS;\r\n  email: string;\r\n  sid: string;\r\n};\r\n\r\nexport type RefreshTokenPayload = JwtPayloadBase & {\r\n  type: JwtType.REFRESH;\r\n  sid: string;\r\n};\r\n\r\nexport type JwtPayload = AccessTokenPayload | RefreshTokenPayload;\r\n"
                },
                {
                  "type": "file",
                  "path": "src/lib/jwt/jwt.sign.ts",
                  "content": "import jwt from \"jsonwebtoken\";\r\nimport { AccessTokenPayload, JwtType, RefreshTokenPayload } from \"./jwt.types\";\r\n\r\nexport function signAccessToken(payload: {\r\n  sub: string;\r\n  email: string;\r\n  sid: string;\r\n}): string {\r\n  const tokenPayload: AccessTokenPayload = {\r\n    sub: payload.sub,\r\n    type: JwtType.ACCESS,\r\n    email: payload.email,\r\n    sid: payload.sid\r\n  };\r\n\r\n  return jwt.sign(tokenPayload, process.env.JWT_ACCESS_SECRET as string, {\r\n    expiresIn: \"15m\"\r\n  });\r\n}\r\n\r\nexport function signRefreshToken(payload: {\r\n  sub: string;\r\n  sid: string;\r\n}): string {\r\n  const tokenPayload: RefreshTokenPayload = {\r\n    sub: payload.sub,\r\n    type: JwtType.REFRESH,\r\n    sid: payload.sid\r\n  };\r\n\r\n  return jwt.sign(tokenPayload, process.env.JWT_REFRESH_SECRET as string, {\r\n    expiresIn: \"7d\"\r\n  });\r\n}\r\n"
                },
                {
                  "type": "file",
                  "path": "src/lib/jwt/jwt.errors.ts",
                  "content": "export class JwtError extends Error {\r\n  constructor(message: string) {\r\n    super(message);\r\n    this.name = \"JwtError\";\r\n  }\r\n}\r\n\r\nexport class JwtExpiredError extends JwtError {\r\n  constructor() {\r\n    super(\"Token expired\");\r\n  }\r\n}\r\n\r\nexport class JwtInvalidError extends JwtError {\r\n  constructor() {\r\n    super(\"Invalid token\");\r\n  }\r\n}\r\n"
                },
                {
                  "type": "file",
                  "path": "src/lib/jwt/index.ts",
                  "content": "export * from \"./jwt.types\";\r\nexport * from \"./jwt.sign\";\r\nexport * from \"./jwt.verify\";\r\nexport * from \"./jwt.utils\";\r\nexport * from \"./jwt.errors\";\r\n"
                }
              ]
            }
          }
        }
      }
    }
  }
}
