import { Context, Effect, Layer } from "effect" import type * as JWT from "jsonwebtoken" import { ImportError } from "./ImportError" export class JSONWebToken extends Context.Tag("JSONWebToken")() {} export interface JSONWebTokenService { sign: ( payload: string | object | Buffer, secretOrPrivateKey: JWT.Secret, options: JWT.SignOptions, ) => Effect.Effect< string, Error, never > verify: ( token: string, secretOrPublicKey: JWT.Secret, options: JWT.VerifyOptions, ) => Effect.Effect< string | JWT.Jwt | JWT.JwtPayload, JWT.VerifyErrors | Error, never > } const importJWT = Effect.tryPromise({ try: () => import("jsonwebtoken"), catch: cause => new ImportError({ path: "jsonwebtoken", cause }), }) export const JSONWebTokenLive = Layer.effect(JSONWebToken, importJWT.pipe( Effect.map(jwt => JSONWebToken.of({ sign: (payload, secretOrPrivateKey, options) => Effect.async(resume => jwt.sign(payload, secretOrPrivateKey, options, (err, token) => { resume(token ? Effect.succeed(token) : Effect.fail(err || new Error("Unknown error")) ) }) ), verify: (token, secretOrPublicKey, options) => Effect.async(resume => jwt.verify(token, secretOrPublicKey, options, (err, decoded) => { resume(decoded ? Effect.succeed(decoded) : Effect.fail(err || new Error("Unknown error")) ) }) ), })) ))