Last active
April 10, 2025 16:27
-
-
Save titouancreach/8bf7ef004d03c6e560e30de75c81d77f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Effect, Function } from "effect"; | |
import { Pipeable, pipeArguments } from "effect/Pipeable"; | |
import { Predicate, Refinement } from "effect/Predicate"; | |
import { Profil, UnAuthorized } from "../Profil"; | |
import { UserSessionService } from "../UserSession/UserSessionServiceTag"; | |
export interface Policy<A, E = never, R = never> extends Pipeable { | |
run: (a: A) => Effect.Effect<boolean, E, R>; | |
readonly _tag: "Policy"; | |
} | |
export const run = | |
(msg: string) => | |
<E, R>(policy: Policy<Profil, E, R>) => | |
Effect.gen(function* () { | |
const user = yield* UserSessionService.pipe(Effect.flatten); | |
yield* Effect.if(policy.run(user.profil), { | |
onTrue: () => Effect.void, | |
onFalse: () => Effect.fail(new UnAuthorized({ message: msg })), | |
}); | |
}); | |
export const make = <A = Profil, E = never, R = never>( | |
run: (a: A) => Effect.Effect<boolean, E, R>, | |
): Policy<A, E, R> => ({ | |
run, | |
pipe() { | |
// biome-ignore lint/style/noArguments: <explanation> | |
return pipeArguments(this, arguments); | |
}, | |
_tag: "Policy", | |
}); | |
export const fromPredicate = <A, E = never, R = never>( | |
predicate: Predicate<A>, | |
): Policy<A, E, R> => make((a) => Effect.succeed(predicate(a))); | |
export const liftPredicate: { | |
<A, B extends A, E = never, R = never>( | |
refine: Refinement<A, B>, | |
): (self: Policy<B, E, R>) => Policy<A, E, R>; | |
<A, B extends A, E = never, R = never>( | |
self: Policy<B, E, R>, | |
refine: Refinement<A, B>, | |
): Policy<A, E, R>; | |
} = Function.dual( | |
2, | |
<A, B extends A, E = never, R = never>( | |
self: Policy<B, E, R>, | |
refine: Refinement<A, B>, | |
) => ({ | |
run: (a: A) => (refine(a) ? self.run(a) : Effect.succeed(false)), | |
pipe() { | |
// biome-ignore lint/style/noArguments: <explanation> | |
return pipeArguments(this, arguments); | |
}, | |
_tag: "Policy", | |
}), | |
); | |
export const mapInput: { | |
<A, B, E = never, R = never>( | |
self: Policy<B, E, R>, | |
f: (a: A) => B, | |
): Policy<A, E, R>; | |
<A, B, E = never, R = never>( | |
f: (a: A) => B, | |
): (p: Policy<B, E, R>) => Policy<A, E, R>; | |
} = Function.dual( | |
2, | |
<A, B, E = never, R = never>(self: Policy<B, E, R>, f: (a: A) => B) => ({ | |
run: (a: A) => self.run(f(a)), | |
pipe() { | |
// biome-ignore lint/style/noArguments: <explanation> | |
return pipeArguments(this, arguments); | |
}, | |
_tag: "Policy", | |
}), | |
); | |
export const mapInputEffect: { | |
<A, B, E, R>( | |
self: Policy<B, E, R>, | |
f: (a: A) => Effect.Effect<B, E, R>, | |
): Policy<A, E, R>; | |
<A, B, E, R>( | |
f: (a: A) => Effect.Effect<B, E, R>, | |
): (p: Policy<B, E, R>) => Policy<A, E, R>; | |
} = Function.dual( | |
2, | |
<A, B, E, R>(self: Policy<B, E, R>, f: (a: A) => Effect.Effect<B, E, R>) => ({ | |
run: (a: A) => Effect.flatMap(f(a), (b) => self.run(b)), | |
pipe() { | |
// biome-ignore lint/style/noArguments: <explanation> | |
return pipeArguments(this, arguments); | |
}, | |
_tag: "Policy", | |
}), | |
); | |
/** | |
* wrap an effect with a policy | |
*/ | |
export const withPolicy = | |
<A, E, R, E2, R2>(msg: string, policy: Policy<Profil, E, R>) => | |
(self: Effect.Effect<A, E | E2, R | R2>) => | |
Effect.zipRight(run(msg)(policy), self); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment