diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
 # Revision history for jsaddle-wasm
 
+## 0.1.1.0 -- 2025-05-01
+
+ * Bug fix: make GHCJS helpers globally available.
+
+   This bug manifested itself in error messages like
+   ```
+   TypeError: jsaddle_values.get(...) is undefined
+   ```
+   when calling certain JSaddle functions like `jsTypeOf` or `createFromArrayBuffer`.
+
 ## 0.1.0.0 -- 2025-03-06
 
  * Add support for synchronous callbacks (when using `run`, but not `runWorker`) using the new synchronous Wasm JSFFI exports feature.
diff --git a/jsaddle-wasm.cabal b/jsaddle-wasm.cabal
--- a/jsaddle-wasm.cabal
+++ b/jsaddle-wasm.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: jsaddle-wasm
-version: 0.1.0.0
+version: 0.1.1.0
 synopsis: Run JSaddle JSM with the GHC Wasm backend
 description: Run JSaddle @JSM@ with the GHC Wasm backend.
 category: Web, Javascript
diff --git a/src-wasm/Language/Javascript/JSaddle/Wasm/Internal.hs b/src-wasm/Language/Javascript/JSaddle/Wasm/Internal.hs
--- a/src-wasm/Language/Javascript/JSaddle/Wasm/Internal.hs
+++ b/src-wasm/Language/Javascript/JSaddle/Wasm/Internal.hs
@@ -7,7 +7,7 @@
 
 import Control.Concurrent.STM
 import Control.Exception (evaluate)
-import Control.Monad ((<=<))
+import Control.Monad ((<=<), (>=>))
 import Data.Aeson qualified as A
 import Data.ByteString (ByteString)
 import Data.ByteString.Internal qualified as BI
@@ -18,7 +18,7 @@
 import GHC.Wasm.Prim qualified
 import Language.Javascript.JSaddle.Run (runJavaScript)
 import Language.Javascript.JSaddle.Run.Files qualified as JSaddle.Files
-import Language.Javascript.JSaddle.Types (Batch, JSM)
+import Language.Javascript.JSaddle.Types (Batch, JSM, Results)
 
 -- Note: It is also possible to implement this succinctly on top of 'runWorker'
 -- and 'jsaddleScript' (using MessageChannel), but then e.g.
@@ -39,8 +39,7 @@
       jsaddleRunner processResultCallback processResultSyncCallback = do
         s <-
           byteStringToJSString . BLC8.toStrict . BLC8.unlines $
-            [ JSaddle.Files.ghcjsHelpers,
-              JSaddle.Files.initState,
+            [ JSaddle.Files.initState,
               "(async () => {",
               "  while (true) {",
               "    const batch = JSON.parse(await readBatch());",
@@ -50,8 +49,16 @@
               "  }",
               "})();"
             ]
-        evaluate =<< js_eval s processResultCallback processResultSyncCallback readBatchCallback
+        evaluate
+          =<< js_eval_jsaddle
+            s
+            processResultCallback
+            processResultSyncCallback
+            readBatchCallback
 
+  -- The GHCJS helpers need to be available in the global scope.
+  js_global_eval =<< byteStringToJSString (BLC8.toStrict JSaddle.Files.ghcjsHelpers)
+
   runHelper entryPoint sendOutgoingMessage jsaddleRunner
 
 runWorker :: JSM () -> JSVal -> IO ()
@@ -74,18 +81,10 @@
     runJavaScript sendBatch entryPoint
 
   let receiveBatch :: JSString -> IO ()
-      receiveBatch s = do
-        bs <- jsStringToByteString s
-        case A.eitherDecodeStrict bs of
-          Left e -> fail $ "jsaddle: received invalid JSON: " <> show e
-          Right r -> processResult r
+      receiveBatch = decodeResults >=> processResult
 
       processBatchSync :: JSString -> IO JSString
-      processBatchSync s = do
-        bs <- jsStringToByteString s
-        case A.eitherDecodeStrict bs of
-          Left e -> fail $ "jsaddle: received invalid JSON: " <> show e
-          Right r -> byteStringToJSString . BLC8.toStrict . A.encode =<< processSyncResult r
+      processBatchSync = decodeResults >=> processSyncResult >=> encodeBatch
 
   processResultCallback <- mkPullCallback receiveBatch
   processResultSyncCallback <- mkSyncCallback processBatchSync
@@ -95,10 +94,18 @@
   start
   where
     sendBatch :: Batch -> IO ()
-    sendBatch batch = do
-      encodedBatch <- byteStringToJSString $ BLC8.toStrict $ A.encode batch
-      sendOutgoingMessage encodedBatch
+    sendBatch = encodeBatch >=> sendOutgoingMessage
 
+    encodeBatch :: Batch -> IO JSString
+    encodeBatch = byteStringToJSString . BLC8.toStrict . A.encode
+
+    decodeResults :: JSString -> IO Results
+    decodeResults s = do
+      bs <- jsStringToByteString s
+      case A.eitherDecodeStrict bs of
+        Left e -> fail $ "jsaddle: received invalid JSON: " <> show e
+        Right r -> pure r
+
 -- Utilities:
 
 foreign import javascript "wrapper" mkPullCallback :: (JSString -> IO ()) -> IO JSVal
@@ -107,8 +114,10 @@
 
 foreign import javascript "wrapper" mkPushCallback :: IO JSString -> IO JSVal
 
+foreign import javascript unsafe "eval.call(globalThis, $1)" js_global_eval :: JSString -> IO ()
+
 foreign import javascript safe "new Function('processResult','processResultSync','readBatch',`(()=>{${$1}})()`)($2, $3, $4)"
-  js_eval :: JSString -> JSVal -> JSVal -> JSVal -> IO ()
+  js_eval_jsaddle :: JSString -> JSVal -> JSVal -> JSVal -> IO ()
 
 -- Worker
 
