Safe supports multiple signature types, and most of the interfaces use the off-chain ECDSA signatures, which are not tracked anywhere in the contract except events emitted in the L2 version of the Safe singleton.
There are "on-chain" signatures, and the approvedHashes
mapping is used in the pre-validated signature type. Most apps do not use this signature type for UX reasons. You can build an app that would exclusively use this type of signatures. From Safe docs:
Pre-Validated Signatures
signature type == 1
Constant Part:
{32-bytes hash validator}{32-bytes ignored}{1-byte signature type}.
Hash validator - Padded address of the account that pre-validated the hash that should be validated. The Safe keeps track of all hashes that have been pre validated. This is done with a mapping address to mapping of bytes32 to boolean where it is possible to set a hash as validated by a certain address (hash validator). To add an entry to this mapping use approveHash. Also if the validator is the sender of transaction that executed the Safe transaction it is not required to use approveHash to add an entry to the mapping.
Learn more about the signatures here:
https://docs.safe.global/learn/safe-core/safe-core-protocol/signatures
You can also check out the legacy Gnosis Multisig that exclusively uses on-chain transaction approvals.