diff --git a/AUTHORS b/AUTHORS
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,8 +1,8 @@
 === Haskell stm-chans package AUTHORS/THANKS file ===
 
-The stm-chans package was written (predominantly) by wren ng thornton
+The stm-chans package was written (predominantly) by wren gayle romano
 and is released under the terms in the LICENSE file. I would also
-like to give thanks to the following contributers:
+like to give thanks to the following contributors:
 
 Thomas DuBuisson --- For important improvements to TBChan and
     TBMChan, incorporating parts of his bounded-tchan package. These
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,60 @@
+3.0.0.11 (2026-02-26):
+    - Updating the `Tested-With` field for ghc 9.14 (didn't actually need to
+      nudge the upper bound on 'base', because it's already lenient)
+    - Also silencing some warnings on ghc >=9.12 about deriving Typeable.
+3.0.0.10 (2024-08-28):
+    - Updating the `Tested-With` field for ghc 9.10 (didn't actually need to
+      nudge the upper bound on 'base', because it's already lenient)
+3.0.0.9 (2023-03-19):
+    - Added `Tested-With: GHC == 9.6.1` (didn't actually need to
+      nudge the upper bound on 'base', because it's already lenient)
+3.0.0.8 (2022-08-28):
+    - Added `Tested-With: GHC == 9.4.1` (didn't actually need to
+      nudge the upper bound on 'base', because it's already lenient)
+3.0.0.7 (2021-11-22):
+    - Added `Tested-With: GHC == 9.2.1` (didn't actually need to
+      nudge the upper bound on 'base', because it's already lenient)
+3.0.0.6 (2021-10-17):
+    - Removed old __HADDOCK__ hack
+    - Updating stale emails, urls, etc
+3.0.0.5 (2021-10-16):
+    - Fixed the cabal file for Cabal >1.24
+3.0.0.4 (2015-05-30):
+    - Moved VERSION to CHANGELOG
+3.0.0.3 (2015-03-29):
+    - Cleaning up headers to compile cleanly with GHC 7.10
+3.0.0 (2013-05-29):
+    - Removed the deprecated compatibility modules.
+
+2.1.0 (2013-05-29):
+    - Added UNPACK pragmas everywhere to reduce indirections.
+    - Added versions of newBroadcastT*Chan for TMChan
+    - Deprecated all the compatibility stuff, since newBroadcastTChan requires stm >= 2.4 anyways.
+2.0.0 (2013-05-12):
+    - Add TQueue support
+
+1.3.1 (2012-02-29):
+    - Corrected the CPP macros now that stm-2.3 is released.
+1.3.0 (2012-02-25):
+    - Added Control.Concurrent.STM.TMVar.Compat
+1.2.0.3 (2012-02-12):
+    - Change stability from experimental to provisional.
+1.2.0.2 (2012-02-12):
+    - Documentation fix for Control.Concurrent.STM.TMChan.writeTMChan
+1.2.0.1 (2011-05-07):
+    - Moved old TBChan,TBMChan implementations to ./test/bench/
+1.2.0 (2011-05-07):
+    - Various optimizations.
+    - Switched to using 2 TVars in TBChan and TBMChan, reducing
+      contention between readers and writers and improving throughput
+      considerably (when multiple OS threads are used).
+    - Control.Concurrent.STM.TBChan: added estimateFreeSlotsTBChan,
+      freeSlotsTBChan
+    - Control.Concurrent.STM.TBMChan: added estimateFreeSlotsTBMChan,
+      freeSlotsTBMChan
+1.1.0 (2011-04-05):
+    - Control.Concurrent.STM.TBChan: added tryWriteTBChan
+    - Control.Concurrent.STM.TBMChan: added tryWriteTBMChan
+1.0.0 (2011-04-03):
+    - Initial version forked from Posta-IPC.
+    - Added tryRead* and tryPeek* functions for the various channels.
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 === stm-chans license ===
 
-Copyright (c) 2011--2013, wren ng thornton.
+Copyright (c) 2011--2013, wren gayle romano.
 ALL RIGHTS RESERVED.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/README b/README
deleted file mode 100644
--- a/README
+++ /dev/null
@@ -1,24 +0,0 @@
-stm-chans
-=========
-
-In general, this is a simple package and should be easy to install.
-It does require GHC however, because it relies on the
-Control.Concurrent.STM.TChan type which (for some unknown reason)
-is GHC-only. With the cabal-install program you can just do:
-
-    $> cabal install stm-chans
-
-Or if you don't have cabal-install, then you can use the Cabal
-library:
-
-    $> runhaskell Setup.hs configure
-    $> runhaskell Setup.hs build
-    $> runhaskell Setup.hs test
-    $> runhaskell Setup.hs haddock --hyperlink-source
-    $> runhaskell Setup.hs copy
-    $> runhaskell Setup.hs register
-
-The test step is optional and currently does nothing. The Haddock
-step is also optional.
-
------------------------------------------------------------ fin.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,43 @@
+stm-chans
+=========
+[![CI Status](https://github.com/wrengr/stm-chans/actions/workflows/ci.yml/badge.svg)](https://github.com/wrengr/stm-chans/actions?query=workflow%3Aci+-event%3Apull_request)
+[![Hackage version](https://img.shields.io/hackage/v/stm-chans.svg?style=flat)](https://hackage.haskell.org/package/stm-chans) 
+[![Stackage LTS version](https://stackage.org/package/stm-chans/badge/lts)](https://stackage.org/lts/package/stm-chans)
+[![Stackage Nightly version](https://stackage.org/package/stm-chans/badge/nightly)](https://stackage.org/nightly/package/stm-chans)
+
+This package offers a collection of channel types, similar to
+`Control.Concurrent.STM.{TChan,TQueue}` but with additional features.
+In particular we offer the following data types:
+
+* `Control.Concurrent.STM.TBChan`:  Bounded FIFO channels.
+    When the channel is full, writers will block/retry. This ensures
+    that the writers do not get too far ahead of the readers, which
+    helps to  make sure that memory and cpu resources are used
+    responsibly.
+* `Control.Concurrent.STM.TMChan`:   Closeable FIFO channels.
+* `Control.Concurrent.STM.TMQueue`:  Closeable FIFO queues.
+    Like `TChan (Maybe a)` but with a monotonicity guarantee that
+    once `Nothing` is returned all future reads will be `Nothing`
+    as well.
+* `Control.Concurrent.STM.TBMChan`:  Bounded Closeable FIFO channels.
+* `Control.Concurrent.STM.TBMQueue`: Bounded Closeable FIFO queues.
+    Combines the capabilities of `TBChan` and `TMChan`.
+
+
+## Install
+
+In general, this is a simple package and should be easy to install.
+It does require GHC however, because it relies on the
+Control.Concurrent.STM.TChan type which (for some unknown reason)
+is GHC-only. With the cabal-install program you can just do:
+
+    $> cabal install stm-chans
+
+
+## Links
+
+* [Website](http://wrengr.org/)
+* [Blog](http://winterkoninkje.dreamwidth.org/)
+* [Twitter](https://twitter.com/wrengr)
+* [Hackage](http://hackage.haskell.org/package/stm-chans)
+* [GitHub](https://github.com/wrengr/stm-chans)
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,27 +1,7 @@
 #!/usr/bin/env runhaskell
--- Cf. <http://www.mail-archive.com/haskell-cafe@haskell.org/msg59984.html>
--- <http://www.haskell.org/pipermail/haskell-cafe/2008-December/051785.html>
 
-{-# OPTIONS_GHC -Wall -fwarn-tabs -fno-warn-missing-signatures #-}
 module Main (main) where
 import Distribution.Simple
-import Distribution.Simple.LocalBuildInfo (withPrograms)
-import Distribution.Simple.Program        (userSpecifyArgs)
-----------------------------------------------------------------
 
--- | Define __HADDOCK__ when building documentation.
 main :: IO ()
-main = defaultMainWithHooks
-    $ simpleUserHooks `modify_haddockHook` \oldHH pkg lbi hooks flags -> do
-        
-        -- Call the old haddockHook with a modified LocalBuildInfo
-        (\lbi' -> oldHH pkg lbi' hooks flags)
-            $ lbi `modify_withPrograms` \oldWP ->
-                userSpecifyArgs "haddock" ["--optghc=-D__HADDOCK__"] oldWP
-
-
-modify_haddockHook  hooks f = hooks { haddockHook  = f (haddockHook  hooks) }
-modify_withPrograms lbi   f = lbi   { withPrograms = f (withPrograms lbi)   }
-
-----------------------------------------------------------------
------------------------------------------------------------ fin.
+main  = defaultMain
diff --git a/VERSION b/VERSION
deleted file mode 100644
--- a/VERSION
+++ /dev/null
@@ -1,35 +0,0 @@
-3.0.0 (2013-05-29):
-    - Removed the deprecated compatibility modules.
-
-2.1.0 (2013-05-29):
-    - Added UNPACK pragmas everywhere to reduce indirections.
-    - Added versions of newBroadcastT*Chan for TMChan
-    - Deprecated all the compatibility stuff, since newBroadcastTChan requires stm >= 2.4 anyways.
-2.0.0 (2013-05-12):
-    - Add TQueue support
-
-1.3.1 (2012-02-29):
-    - Corrected the CPP macros now that stm-2.3 is released.
-1.3.0 (2012-02-25):
-    - Added Control.Concurrent.STM.TMVar.Compat
-1.2.0.3 (2012-02-12):
-    - Change stability from experimental to provisional.
-1.2.0.2 (2012-02-12):
-    - Documentation fix for Control.Concurrent.STM.TMChan.writeTMChan
-1.2.0.1 (2011-05-07):
-    - Moved old TBChan,TBMChan implementations to ./test/bench/
-1.2.0 (2011-05-07):
-    - Various optimizations.
-    - Switched to using 2 TVars in TBChan and TBMChan, reducing
-      contention between readers and writers and improving throughput
-      considerably (when multiple OS threads are used).
-    - Control.Concurrent.STM.TBChan: added estimateFreeSlotsTBChan,
-      freeSlotsTBChan
-    - Control.Concurrent.STM.TBMChan: added estimateFreeSlotsTBMChan,
-      freeSlotsTBMChan
-1.1.0 (2011-04-05):
-    - Control.Concurrent.STM.TBChan: added tryWriteTBChan
-    - Control.Concurrent.STM.TBMChan: added tryWriteTBMChan
-1.0.0 (2011-04-03):
-    - Initial version forked from Posta-IPC.
-    - Added tryRead* and tryPeek* functions for the various channels.
diff --git a/src/Control/Concurrent/STM/TBChan.hs b/src/Control/Concurrent/STM/TBChan.hs
--- a/src/Control/Concurrent/STM/TBChan.hs
+++ b/src/Control/Concurrent/STM/TBChan.hs
@@ -1,16 +1,21 @@
 {-# OPTIONS_GHC -Wall -fwarn-tabs #-}
-{-# LANGUAGE CPP, DeriveDataTypeable #-}
+{-# LANGUAGE CPP #-}
 
+#if __GLASGOW_HASKELL__ < 912
+-- ghc-9.12: "all types now auto-derive Typeable"
+{-# LANGUAGE DeriveDataTypeable #-}
+#endif
+
 #if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Trustworthy #-}
+{-# LANGUAGE Safe #-}
 #endif
 ----------------------------------------------------------------
---                                                    2013.05.29
+--                                                    2026-02-26
 -- |
 -- Module      :  Control.Concurrent.STM.TBChan
--- Copyright   :  Copyright (c) 2011--2013 wren ng thornton
+-- Copyright   :  Copyright (c) 2011--2026 wren gayle romano
 -- License     :  BSD
--- Maintainer  :  wren@community.haskell.org
+-- Maintainer  :  wren@cpan.org
 -- Stability   :  provisional
 -- Portability :  non-portable (GHC STM, DeriveDataTypeable)
 --
@@ -45,16 +50,12 @@
     ) where
 
 import Prelude           hiding (reads)
+#if __GLASGOW_HASKELL__ < 912
 import Data.Typeable     (Typeable)
+#endif
 import Control.Monad.STM (STM, retry)
 import Control.Concurrent.STM.TVar
 import Control.Concurrent.STM.TChan -- N.B., GHC only
-
--- N.B., we need a Custom cabal build-type for this to work.
-#ifdef __HADDOCK__
-import Control.Monad.STM (atomically)
-import System.IO.Unsafe  (unsafePerformIO)
-#endif
 ----------------------------------------------------------------
 
 -- | @TBChan@ is an abstract type representing a bounded FIFO
@@ -63,7 +64,9 @@
     {-# UNPACK #-} !(TVar Int)
     {-# UNPACK #-} !(TVar Int)
     {-# UNPACK #-} !(TChan a)
+#if __GLASGOW_HASKELL__ < 912
     deriving (Typeable)
+#endif
 -- The components are:
 -- * How many free slots we /know/ we have available.
 -- * How many slots have been freed up by successful reads since
@@ -84,8 +87,9 @@
 
 
 -- | @IO@ version of 'newTBChan'. This is useful for creating
--- top-level @TBChan@s using 'unsafePerformIO', because using
--- 'atomically' inside 'unsafePerformIO' isn't possible.
+-- top-level @TBChan@s using 'System.IO.Unsafe.unsafePerformIO',
+-- because using 'Control.Monad.STM.atomically' inside
+-- 'System.IO.Unsafe.unsafePerformIO' isn't possible.
 newTBChanIO :: Int -> IO (TBChan a)
 newTBChanIO n = do
     slots <- newTVarIO n
@@ -193,15 +197,15 @@
 
 
 -- | Returns @True@ if the supplied @TBChan@ is empty (i.e., has
--- no elements). /N.B./, a @TBChan@ can be both ``empty'' and
--- ``full'' at the same time, if the initial limit was non-positive.
+-- no elements). /N.B./, a @TBChan@ can be both \"empty\" and
+-- \"full\" at the same time, if the initial limit was non-positive.
 isEmptyTBChan :: TBChan a -> STM Bool
 isEmptyTBChan (TBChan _slots _reads chan) =
     isEmptyTChan chan
 
 
 -- | Returns @True@ if the supplied @TBChan@ is full (i.e., is over
--- its limit). /N.B./, a @TBChan@ can be both ``empty'' and ``full''
+-- its limit). /N.B./, a @TBChan@ can be both \"empty\" and \"full\"
 -- at the same time, if the initial limit was non-positive. /N.B./,
 -- a @TBChan@ may still be full after reading, if 'unGetTBChan' was
 -- used to go over the initial limit.
diff --git a/src/Control/Concurrent/STM/TBMChan.hs b/src/Control/Concurrent/STM/TBMChan.hs
--- a/src/Control/Concurrent/STM/TBMChan.hs
+++ b/src/Control/Concurrent/STM/TBMChan.hs
@@ -1,16 +1,21 @@
 {-# OPTIONS_GHC -Wall -fwarn-tabs #-}
-{-# LANGUAGE CPP, DeriveDataTypeable #-}
+{-# LANGUAGE CPP #-}
 
+#if __GLASGOW_HASKELL__ < 912
+-- ghc-9.12: "all types now auto-derive Typeable"
+{-# LANGUAGE DeriveDataTypeable #-}
+#endif
+
 #if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Trustworthy #-}
+{-# LANGUAGE Safe #-}
 #endif
 ----------------------------------------------------------------
---                                                    2013.05.29
+--                                                    2026-02-26
 -- |
 -- Module      :  Control.Concurrent.STM.TBMChan
--- Copyright   :  Copyright (c) 2011--2013 wren ng thornton
+-- Copyright   :  Copyright (c) 2011--2026 wren gayle romano
 -- License     :  BSD
--- Maintainer  :  wren@community.haskell.org
+-- Maintainer  :  wren@cpan.org
 -- Stability   :  provisional
 -- Portability :  non-portable (GHC STM, DeriveDataTypeable)
 --
@@ -50,17 +55,15 @@
     ) where
 
 import Prelude             hiding (reads)
+#if __GLASGOW_HASKELL__ < 912
 import Data.Typeable       (Typeable)
+#endif
+#if __GLASGOW_HASKELL__ < 710
 import Control.Applicative ((<$>))
+#endif
 import Control.Monad.STM   (STM, retry)
 import Control.Concurrent.STM.TVar
 import Control.Concurrent.STM.TChan -- N.B., GHC only
-
--- N.B., we need a Custom cabal build-type for this to work.
-#ifdef __HADDOCK__
-import Control.Monad.STM   (atomically)
-import System.IO.Unsafe    (unsafePerformIO)
-#endif
 ----------------------------------------------------------------
 
 -- | @TBMChan@ is an abstract type representing a bounded closeable
@@ -70,7 +73,9 @@
     {-# UNPACK #-} !(TVar Int)
     {-# UNPACK #-} !(TVar Int)
     {-# UNPACK #-} !(TChan a)
+#if __GLASGOW_HASKELL__ < 912
     deriving (Typeable)
+#endif
 -- The components are:
 -- * Whether the channel has been closed.
 -- * How many free slots we /know/ we have available.
@@ -93,8 +98,9 @@
 
 
 -- | @IO@ version of 'newTBMChan'. This is useful for creating
--- top-level @TBMChan@s using 'unsafePerformIO', because using
--- 'atomically' inside 'unsafePerformIO' isn't possible.
+-- top-level @TBMChan@s using 'System.IO.Unsafe.unsafePerformIO',
+-- because using 'Control.Monad.STM.atomically' inside
+-- 'System.IO.Unsafe.unsafePerformIO' isn't possible.
 newTBMChanIO :: Int -> IO (TBMChan a)
 newTBMChanIO n = do
     closed <- newTVarIO False
@@ -122,7 +128,7 @@
             x <- readTChan chan
             modifyTVar' reads (1 +)
             return (Just x)
-{- 
+{-
 -- The above is slightly optimized over the clearer:
 readTBMChan (TBMChan closed _slots reads chan) =
     b  <- readTVar closed
@@ -159,7 +165,7 @@
                 Just _x -> do
                     modifyTVar' reads (1 +)
                     return (Just mx)
-{- 
+{-
 -- The above is slightly optimized over the clearer:
 tryReadTBMChan (TBMChan closed _slots reads chan) =
     b  <- readTVar closed
@@ -194,7 +200,7 @@
 peekTBMChan (TBMChan closed _slots _reads chan) = do
     b  <- isEmptyTChan chan
     b' <- readTVar closed
-    if b && b' 
+    if b && b'
         then return Nothing
         else Just <$> peekTChan chan
 -- TODO: compare Core and benchmarks; is the loss of clarity worth it?
@@ -216,7 +222,7 @@
 tryPeekTBMChan (TBMChan closed _slots _reads chan) = do
     b  <- isEmptyTChan chan
     b' <- readTVar closed
-    if b && b' 
+    if b && b'
         then return Nothing
         else Just <$> tryPeekTChan chan
 -- TODO: compare Core and benchmarks; is the loss of clarity worth it?
@@ -296,16 +302,16 @@
 
 
 -- | Returns @True@ if the supplied @TBMChan@ is empty (i.e., has
--- no elements). /N.B./, a @TBMChan@ can be both ``empty'' and
--- ``full'' at the same time, if the initial limit was non-positive.
+-- no elements). /N.B./, a @TBMChan@ can be both \"empty\" and
+-- \"full\" at the same time, if the initial limit was non-positive.
 isEmptyTBMChan :: TBMChan a -> STM Bool
 isEmptyTBMChan (TBMChan _closed _slots _reads chan) =
     isEmptyTChan chan
 
 
 -- | Returns @True@ if the supplied @TBMChan@ is full (i.e., is
--- over its limit). /N.B./, a @TBMChan@ can be both ``empty'' and
--- ``full'' at the same time, if the initial limit was non-positive.
+-- over its limit). /N.B./, a @TBMChan@ can be both \"empty\" and
+-- \"full\" at the same time, if the initial limit was non-positive.
 -- /N.B./, a @TBMChan@ may still be full after reading, if
 -- 'unGetTBMChan' was used to go over the initial limit.
 --
diff --git a/src/Control/Concurrent/STM/TBMQueue.hs b/src/Control/Concurrent/STM/TBMQueue.hs
--- a/src/Control/Concurrent/STM/TBMQueue.hs
+++ b/src/Control/Concurrent/STM/TBMQueue.hs
@@ -1,16 +1,21 @@
 {-# OPTIONS_GHC -Wall -fwarn-tabs #-}
-{-# LANGUAGE CPP, DeriveDataTypeable #-}
+{-# LANGUAGE CPP #-}
 
+#if __GLASGOW_HASKELL__ < 912
+-- ghc-9.12: "all types now auto-derive Typeable"
+{-# LANGUAGE DeriveDataTypeable #-}
+#endif
+
 #if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Trustworthy #-}
+{-# LANGUAGE Safe #-}
 #endif
 ----------------------------------------------------------------
---                                                    2013.05.29
+--                                                    2026-02-26
 -- |
 -- Module      :  Control.Concurrent.STM.TBMQueue
--- Copyright   :  Copyright (c) 2011--2013 wren ng thornton
+-- Copyright   :  Copyright (c) 2011--2026 wren gayle romano
 -- License     :  BSD
--- Maintainer  :  wren@community.haskell.org
+-- Maintainer  :  wren@cpan.org
 -- Stability   :  provisional
 -- Portability :  non-portable (GHC STM, DeriveDataTypeable)
 --
@@ -48,17 +53,15 @@
     ) where
 
 import Prelude             hiding (reads)
+#if __GLASGOW_HASKELL__ < 912
 import Data.Typeable       (Typeable)
+#endif
+#if __GLASGOW_HASKELL__ < 710
 import Control.Applicative ((<$>))
+#endif
 import Control.Monad.STM   (STM, retry)
 import Control.Concurrent.STM.TVar
 import Control.Concurrent.STM.TQueue -- N.B., GHC only
-
--- N.B., we need a Custom cabal build-type for this to work.
-#ifdef __HADDOCK__
-import Control.Monad.STM   (atomically)
-import System.IO.Unsafe    (unsafePerformIO)
-#endif
 ----------------------------------------------------------------
 
 -- | @TBMQueue@ is an abstract type representing a bounded closeable
@@ -68,7 +71,9 @@
     {-# UNPACK #-} !(TVar Int)
     {-# UNPACK #-} !(TVar Int)
     {-# UNPACK #-} !(TQueue a)
+#if __GLASGOW_HASKELL__ < 912
     deriving (Typeable)
+#endif
 -- The components are:
 -- * Whether the queue has been closed.
 -- * How many free slots we /know/ we have available.
@@ -91,8 +96,9 @@
 
 
 -- | @IO@ version of 'newTBMQueue'. This is useful for creating
--- top-level @TBMQueue@s using 'unsafePerformIO', because using
--- 'atomically' inside 'unsafePerformIO' isn't possible.
+-- top-level @TBMQueue@s using 'System.IO.Unsafe.unsafePerformIO',
+-- because using 'Control.Monad.STM.atomically' inside
+-- 'System.IO.Unsafe.unsafePerformIO' isn't possible.
 newTBMQueueIO :: Int -> IO (TBMQueue a)
 newTBMQueueIO n = do
     closed <- newTVarIO False
@@ -294,16 +300,16 @@
 
 
 -- | Returns @True@ if the supplied @TBMQueue@ is empty (i.e., has
--- no elements). /N.B./, a @TBMQueue@ can be both ``empty'' and
--- ``full'' at the same time, if the initial limit was non-positive.
+-- no elements). /N.B./, a @TBMQueue@ can be both \"empty\" and
+-- \"full\" at the same time, if the initial limit was non-positive.
 isEmptyTBMQueue :: TBMQueue a -> STM Bool
 isEmptyTBMQueue (TBMQueue _closed _slots _reads queue) =
     isEmptyTQueue queue
 
 
 -- | Returns @True@ if the supplied @TBMQueue@ is full (i.e., is
--- over its limit). /N.B./, a @TBMQueue@ can be both ``empty'' and
--- ``full'' at the same time, if the initial limit was non-positive.
+-- over its limit). /N.B./, a @TBMQueue@ can be both \"empty\" and
+-- \"full\" at the same time, if the initial limit was non-positive.
 -- /N.B./, a @TBMQueue@ may still be full after reading, if
 -- 'unGetTBMQueue' was used to go over the initial limit.
 --
diff --git a/src/Control/Concurrent/STM/TMChan.hs b/src/Control/Concurrent/STM/TMChan.hs
--- a/src/Control/Concurrent/STM/TMChan.hs
+++ b/src/Control/Concurrent/STM/TMChan.hs
@@ -1,16 +1,21 @@
 {-# OPTIONS_GHC -Wall -fwarn-tabs #-}
-{-# LANGUAGE CPP, DeriveDataTypeable #-}
+{-# LANGUAGE CPP #-}
 
+#if __GLASGOW_HASKELL__ < 912
+-- ghc-9.12: "all types now auto-derive Typeable"
+{-# LANGUAGE DeriveDataTypeable #-}
+#endif
+
 #if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Trustworthy #-}
+{-# LANGUAGE Safe #-}
 #endif
 ----------------------------------------------------------------
---                                                    2013.05.29
+--                                                    2026-02-26
 -- |
 -- Module      :  Control.Concurrent.STM.TMChan
--- Copyright   :  Copyright (c) 2011--2013 wren ng thornton
+-- Copyright   :  Copyright (c) 2011--2026 wren gayle romano
 -- License     :  BSD
--- Maintainer  :  wren@community.haskell.org
+-- Maintainer  :  wren@cpan.org
 -- Stability   :  provisional
 -- Portability :  non-portable (GHC STM, DeriveDataTypeable)
 --
@@ -44,17 +49,15 @@
     , isEmptyTMChan
     ) where
 
+#if __GLASGOW_HASKELL__ < 912
 import Data.Typeable       (Typeable)
+#endif
+#if __GLASGOW_HASKELL__ < 710
 import Control.Applicative ((<$>))
+#endif
 import Control.Monad.STM   (STM)
 import Control.Concurrent.STM.TVar
 import Control.Concurrent.STM.TChan -- N.B., GHC only
-
--- N.B., we need a Custom cabal build-type for this to work.
-#ifdef __HADDOCK__
-import Control.Monad.STM   (atomically)
-import System.IO.Unsafe    (unsafePerformIO)
-#endif
 ----------------------------------------------------------------
 
 -- | @TMChan@ is an abstract type representing a closeable FIFO
@@ -62,7 +65,9 @@
 data TMChan a = TMChan
     {-# UNPACK #-} !(TVar Bool)
     {-# UNPACK #-} !(TChan a)
+#if __GLASGOW_HASKELL__ < 912
     deriving Typeable
+#endif
 
 
 -- | Build and returns a new instance of @TMChan@.
@@ -74,15 +79,16 @@
 
 
 -- | @IO@ version of 'newTMChan'. This is useful for creating
--- top-level @TMChan@s using 'unsafePerformIO', because using
--- 'atomically' inside 'unsafePerformIO' isn't possible.
+-- top-level @TMChan@s using 'System.IO.Unsafe.unsafePerformIO',
+-- because using 'Control.Monad.STM.atomically' inside
+-- 'System.IO.Unsafe.unsafePerformIO' isn't possible.
 newTMChanIO :: IO (TMChan a)
 newTMChanIO = do
     closed <- newTVarIO False
     chan   <- newTChanIO
     return (TMChan closed chan)
-    
 
+
 -- | Like 'newBroadcastTChan'.
 --
 -- /Since: 2.1.0/
@@ -91,8 +97,8 @@
     closed <- newTVar False
     chan   <- newBroadcastTChan
     return (TMChan closed chan)
-    
 
+
 -- | @IO@ version of 'newBroadcastTMChan'.
 --
 -- /Since: 2.1.0/
@@ -174,7 +180,7 @@
 peekTMChan (TMChan closed chan) = do
     b  <- isEmptyTChan chan
     b' <- readTVar closed
-    if b && b' 
+    if b && b'
         then return Nothing
         else Just <$> peekTChan chan
 -- TODO: compare Core and benchmarks; is the loss of clarity worth it?
@@ -196,7 +202,7 @@
 tryPeekTMChan (TMChan closed chan) = do
     b  <- isEmptyTChan chan
     b' <- readTVar closed
-    if b && b' 
+    if b && b'
         then return Nothing
         else Just <$> tryPeekTChan chan
 -- TODO: compare Core and benchmarks; is the loss of clarity worth it?
diff --git a/src/Control/Concurrent/STM/TMQueue.hs b/src/Control/Concurrent/STM/TMQueue.hs
--- a/src/Control/Concurrent/STM/TMQueue.hs
+++ b/src/Control/Concurrent/STM/TMQueue.hs
@@ -1,16 +1,21 @@
 {-# OPTIONS_GHC -Wall -fwarn-tabs #-}
-{-# LANGUAGE CPP, DeriveDataTypeable #-}
+{-# LANGUAGE CPP #-}
 
+#if __GLASGOW_HASKELL__ < 912
+-- ghc-9.12: "all types now auto-derive Typeable"
+{-# LANGUAGE DeriveDataTypeable #-}
+#endif
+
 #if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Trustworthy #-}
+{-# LANGUAGE Safe #-}
 #endif
 ----------------------------------------------------------------
---                                                    2013.05.29
+--                                                    2026-02-26
 -- |
 -- Module      :  Control.Concurrent.STM.TMQueue
--- Copyright   :  Copyright (c) 2011--2013 wren ng thornton
+-- Copyright   :  Copyright (c) 2011--2026 wren gayle romano
 -- License     :  BSD
--- Maintainer  :  wren@community.haskell.org
+-- Maintainer  :  wren@cpan.org
 -- Stability   :  provisional
 -- Portability :  non-portable (GHC STM, DeriveDataTypeable)
 --
@@ -43,17 +48,15 @@
     , isEmptyTMQueue
     ) where
 
+#if __GLASGOW_HASKELL__ < 912
 import Data.Typeable       (Typeable)
+#endif
+#if __GLASGOW_HASKELL__ < 710
 import Control.Applicative ((<$>))
+#endif
 import Control.Monad.STM   (STM)
 import Control.Concurrent.STM.TVar
 import Control.Concurrent.STM.TQueue -- N.B., GHC only
-
--- N.B., we need a Custom cabal build-type for this to work.
-#ifdef __HADDOCK__
-import Control.Monad.STM   (atomically)
-import System.IO.Unsafe    (unsafePerformIO)
-#endif
 ----------------------------------------------------------------
 
 -- | @TMQueue@ is an abstract type representing a closeable FIFO
@@ -61,7 +64,9 @@
 data TMQueue a = TMQueue
     {-# UNPACK #-} !(TVar Bool)
     {-# UNPACK #-} !(TQueue a)
+#if __GLASGOW_HASKELL__ < 912
     deriving Typeable
+#endif
 
 
 -- | Build and returns a new instance of @TMQueue@.
@@ -73,8 +78,9 @@
 
 
 -- | @IO@ version of 'newTMQueue'. This is useful for creating
--- top-level @TMQueue@s using 'unsafePerformIO', because using
--- 'atomically' inside 'unsafePerformIO' isn't possible.
+-- top-level @TMQueue@s using 'System.IO.Unsafe.unsafePerformIO',
+-- because using 'Control.Monad.STM.atomically' inside
+-- 'System.IO.Unsafe.unsafePerformIO' isn't possible.
 newTMQueueIO :: IO (TMQueue a)
 newTMQueueIO = do
     closed <- newTVarIO False
diff --git a/stm-chans.cabal b/stm-chans.cabal
--- a/stm-chans.cabal
+++ b/stm-chans.cabal
@@ -1,37 +1,60 @@
+Cabal-Version:  2.2
+-- Cabal >=2.2 is required for:
+--    <https://cabal.readthedocs.io/en/latest/cabal-package.html#common-stanzas>
+-- Since 2.1, the Cabal-Version must be the absolutely first thing
+-- in the file, even before comments.  Also, no longer uses ">=".
+--    <https://github.com/haskell/cabal/issues/4899>
+
 ----------------------------------------------------------------
--- wren ng thornton <wren@community.haskell.org>    ~ 2014.03.30
+-- wren gayle romano <wren@cpan.org>                ~ 2026-02-26
 ----------------------------------------------------------------
 
--- By and large Cabal >=1.2 is fine; but >= 1.6 gives tested-with:
--- and source-repository:.
-Cabal-Version:  >= 1.6
--- We need a custom build in order to define __HADDOCK__
-Build-Type:     Custom
-
 Name:           stm-chans
-Version:        3.0.0.2
+Version:        3.0.0.11
+Build-Type:     Simple
 Stability:      provisional
-Homepage:       http://code.haskell.org/~wren/
-Author:         wren ng thornton, Thomas DuBuisson
-Maintainer:     wren@community.haskell.org
-Copyright:      Copyright (c) 2011--2013 wren ng thornton
-License:        BSD3
+Homepage:       https://wrengr.org/software/hackage.html
+Bug-Reports:    https://github.com/wrengr/stm-chans/issues
+Author:         wren gayle romano, Thomas DuBuisson
+Maintainer:     wren@cpan.org
+Copyright:      2011–2025 wren romano
+-- Cabal-2.2 requires us to say "BSD-3-Clause" not "BSD3"
+License:        BSD-3-Clause
 License-File:   LICENSE
 
 Category:       Concurrency
 Synopsis:       Additional types of channels for STM.
 Description:    Additional types of channels for STM.
 
-Tested-With:
-    GHC ==7.6.1, GHC ==7.8.0
 Extra-source-files:
-    AUTHORS, README, VERSION
+    AUTHORS, README.md, CHANGELOG
+
+-- This used to be tested on 7.8.3 and 7.10.1, but we don't verify that by CI.
+-- <https://github.com/wrengr/stm-chans/actions?query=workflow%3Aci>
+Tested-With:
+    GHC ==8.0.2,
+    GHC ==8.2.2,
+    GHC ==8.4.4,
+    GHC ==8.6.5,
+    GHC ==8.8.4,
+    GHC ==8.10.3,
+    GHC ==9.0.1,
+    GHC ==9.2.4,
+    GHC ==9.4.8,
+    GHC ==9.6.5,
+    GHC ==9.8.2,
+    GHC ==9.10.1,
+    GHC ==9.12.1,
+    GHC ==9.14.1
+
+----------------------------------------------------------------
 Source-Repository head
-    Type:     darcs
-    Location: http://community.haskell.org/~wren/stm-chans
+    Type:     git
+    Location: https://github.com/wrengr/stm-chans.git
 
 ----------------------------------------------------------------
 Library
+    Default-Language: Haskell2010
     -- N.B., the following versions are required for:
     -- * stm >= 2.4:   T{,B}Queue and newBroadcastTChan{,IO}
     -- * stm >= 2.3.0: fast tryReadTChan, peekTChan, tryPeekTChan,
