From 289fff2f295cd41de0d623acf4a524abc5bc553d Mon Sep 17 00:00:00 2001
From: hzrd149 <github@hzrd149.com>
Date: Thu, 25 Apr 2024 16:59:55 -0500
Subject: [PATCH] Add REQUEST_PROXY, TOR_PROXY, and I2P_PROXY env options in
 docker image Remove CORS_PROXY env option in docker image

---
 .changeset/bright-eels-grab.md                |   5 +
 .changeset/few-readers-lay.md                 |   5 +
 README.md                                     |   3 +-
 docker-compose.yaml                           |  19 +-
 docker-entrypoint.sh                          |  67 ++++-
 dockerfile                                    |  35 ++-
 index.html                                    |   3 +-
 package.json                                  |   3 +
 server/index.js                               |  52 ++++
 server/package.json                           |  12 +
 server/yarn.lock                              | 269 ++++++++++++++++++
 src/classes/relay-pool.ts                     |   1 +
 .../external-embeds/types/image.tsx           |   2 +-
 src/components/reload-prompt.tsx              |   6 +-
 src/helpers/cors.ts                           |  31 --
 src/helpers/debug.ts                          |   3 +
 src/helpers/request.ts                        |  44 +++
 src/hooks/use-open-graph-data.ts              |   4 +-
 src/services/dns-identity.ts                  |   4 +-
 src/services/lnurl-metadata.ts                |   6 +-
 src/services/relay-info.ts                    |   4 +-
 src/types/window.d.ts                         |   2 +-
 src/views/settings/privacy-settings.tsx       |  31 +-
 tsconfig.json                                 |   2 +-
 vite.config.ts                                |   8 +
 25 files changed, 536 insertions(+), 85 deletions(-)
 create mode 100644 .changeset/bright-eels-grab.md
 create mode 100644 .changeset/few-readers-lay.md
 create mode 100644 server/index.js
 create mode 100644 server/package.json
 create mode 100644 server/yarn.lock
 delete mode 100644 src/helpers/cors.ts
 create mode 100644 src/helpers/request.ts

diff --git a/.changeset/bright-eels-grab.md b/.changeset/bright-eels-grab.md
new file mode 100644
index 000000000..2f2558c6d
--- /dev/null
+++ b/.changeset/bright-eels-grab.md
@@ -0,0 +1,5 @@
+---
+"nostrudel": minor
+---
+
+Remove CORS_PROXY env option in docker image
diff --git a/.changeset/few-readers-lay.md b/.changeset/few-readers-lay.md
new file mode 100644
index 000000000..7e6427937
--- /dev/null
+++ b/.changeset/few-readers-lay.md
@@ -0,0 +1,5 @@
+---
+"nostrudel": minor
+---
+
+Add REQUEST_PROXY, TOR_PROXY, and I2P_PROXY env options in docker image
diff --git a/README.md b/README.md
index 16eaf5814..cdb22f505 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,8 @@ noStrudels docker image has a few options for connecting to other services runni
 
 - `CACHE_RELAY`: if set the client will use the relay to cache all of its events instead of storing them in the browser cache
 - `IMAGE_PROXY`: can be set to a local [imageproxy](https://github.com/willnorris/imageproxy) instance so the app can resize profile images
-- `CORS_PROXY`: can be set to a local [cors-anywhere](https://github.com/Rob--W/cors-anywhere) instance so the app can proxy http request
+- `REQUEST_PROXY`: can be set to a local [cors-anywhere](https://github.com/Rob--W/cors-anywhere) instance so the app can proxy http request
+- `PROXY_FIRST`: if this is set to `true` all http requests will go through the request proxy first
 
 You can find a full example of all these services in the [docker-compose.yaml](./docker-compose.yaml)
 
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 6b925b43a..c7329b1b7 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -4,10 +4,14 @@ volumes:
   data: {}
 
 services:
-  cors:
-    image: ghcr.io/hzrd149/docker-cors-anywhere:0.4.5
-    environment:
-      CORSANYWHERE_REQUIRE_HEADERS: "host"
+  i2p-proxy:
+    image: purplei2p/i2pd:release-2.51.0
+  tor-proxy:
+    image: dockage/tor-privoxy:latest
+  # cors:
+  #   image: ghcr.io/hzrd149/docker-cors-anywhere:0.4.5
+  #   environment:
+  #     CORSANYWHERE_REQUIRE_HEADERS: "host"
   imageproxy:
     image: ghcr.io/willnorris/imageproxy:v0.11.2
   relay:
@@ -19,11 +23,14 @@ services:
     image: ghcr.io/hzrd149/nostrudel:latest
     depends_on:
       - relay
-      - cors
+      - tor-proxy
+      - i2p-proxy
       - imageproxy
     environment:
       CACHE_RELAY: relay:8080
       IMAGE_PROXY: imageproxy:8080
-      CORS_PROXY: cors:8080
+      TOR_PROXY: tor-proxy:9050
+      I2P_PROXY: i2p-proxy:4444
+      REQUEST_PROXY: "true"
     ports:
       - 8080:80
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
index 14e1715c7..3d81087eb 100755
--- a/docker-entrypoint.sh
+++ b/docker-entrypoint.sh
@@ -3,6 +3,41 @@ set -e
 
 PROXY_PASS_BLOCK=""
 
+# start tor if set to true
+if [ "$TOR_PROXY" = "true" ]; then
+  echo "Starting tor socks proxy"
+
+  tor &
+  tor_process=$!
+  TOR_PROXY="127.0.0.1:9050"
+fi
+
+# inject request proxy
+if [ -n "$REQUEST_PROXY" ]; then
+  REQUEST_PROXY_URL="$REQUEST_PROXY"
+
+  if [ "$REQUEST_PROXY" = "true" ]; then
+    REQUEST_PROXY_URL="127.0.0.1:8080"
+  fi
+
+  echo "Request proxy set to $REQUEST_PROXY"
+  sed -i 's/REQUEST_PROXY = ""/REQUEST_PROXY = "\/request-proxy"/g' /usr/share/nginx/html/index.html
+  PROXY_PASS_BLOCK="$PROXY_PASS_BLOCK
+    location /request-proxy/ {
+      proxy_pass http://$REQUEST_PROXY_URL;
+      rewrite ^/request-proxy/(.*) /\$1 break;
+    }
+  "
+
+  if [ -n "$PROXY_FIRST" ]; then
+    echo "Telling app to use request proxy first"
+    sed -i 's/PROXY_FIRST = false/PROXY_FIRST = true/g' /usr/share/nginx/html/index.html
+  fi
+else
+  echo "No request proxy set"
+fi
+
+# inject cache relay URL
 if [ -n "$CACHE_RELAY" ]; then
   echo "Cache relay set to $CACHE_RELAY"
   sed -i 's/CACHE_RELAY_ENABLED = false/CACHE_RELAY_ENABLED = true/g' /usr/share/nginx/html/index.html
@@ -18,19 +53,7 @@ else
   echo "No cache relay set"
 fi
 
-if [ -n "$CORS_PROXY" ]; then
-  echo "CORS proxy set to $CORS_PROXY"
-  sed -i 's/CORS_PROXY_PATH = ""/CORS_PROXY_PATH = "\/corsproxy"/g' /usr/share/nginx/html/index.html
-  PROXY_PASS_BLOCK="$PROXY_PASS_BLOCK
-    location /corsproxy/ {
-      proxy_pass http://$CORS_PROXY;
-      rewrite ^/corsproxy/(.*) /\$1 break;
-    }
-  "
-else
-  echo "No CORS proxy set"
-fi
-
+# inject image proxy URL
 if [ -n "$IMAGE_PROXY" ]; then
   echo "Image proxy set to $IMAGE_PROXY"
   sed -i 's/IMAGE_PROXY_PATH = ""/IMAGE_PROXY_PATH = "\/imageproxy"/g' /usr/share/nginx/html/index.html
@@ -99,9 +122,27 @@ echo "$NGINX_CONF" > $CONF_FILE
 
 _term() {
   echo "Caught SIGTERM signal!"
+
+  # stop node server
+  if [ "$REQUEST_PROXY" = "true" ]; then
+    kill -SIGTERM "$node_process" 2>/dev/null
+  fi
+
+  # stop tor if started
+  if [ "$TOR_PROXY" = "true" ]; then
+    kill -SIGTERM "$tor_process" 2>/dev/null
+  fi
+
+  # stop nginx
   kill -SIGTERM "$nginx_process" 2>/dev/null
 }
 
+if [ "$REQUEST_PROXY" = "true" ]; then
+  echo "Starting local request proxy"
+  node server/index.js &
+  node_process=$!
+fi
+
 nginx -g 'daemon off;' &
 nginx_process=$!
 
diff --git a/dockerfile b/dockerfile
index 73aae6599..af18a978d 100644
--- a/dockerfile
+++ b/dockerfile
@@ -1,5 +1,5 @@
 # syntax=docker/dockerfile:1
-FROM node:20.11 as builder
+FROM node:20-alpine as builder
 
 WORKDIR /app
 
@@ -17,12 +17,33 @@ RUN yarn build
 
 FROM nginx:stable-alpine-slim
 EXPOSE 80
+
+# install nodejs
+RUN apk add --no-cache libstdc++ wget
+RUN wget https://unofficial-builds.nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64-musl.tar.gz
+RUN tar -xf node-v20.12.2-linux-x64-musl.tar.gz && mv node-v20.12.2-linux-x64-musl node-v20.12.2
+RUN rm node-v20.12.2-linux-x64-musl.tar.gz
+
+# install tor
+# copied from https://github.com/klemmchr/tor-alpine/blob/master/Dockerfile
+RUN echo '@edge https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories && \
+    apk -U upgrade && \
+    apk -v add tor@edge torsocks@edge
+
+# remove tmp files
+RUN rm -rf /var/cache/apk/* /tmp/* /var/tmp/*
+
+ENV PATH="/node-v20.12.2/bin:$PATH"
+
+WORKDIR /app
 COPY --from=builder /app/dist /usr/share/nginx/html
 
-ENV CACHE_RELAY=""
-ENV IMAGE_PROXY=""
-ENV CORS_PROXY=""
-ADD ./docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
-RUN chmod a+x /usr/local/bin/docker-entrypoint.sh
+# copy server
+COPY server/ /app/server/
+RUN cd /app/server/ && npm install
 
-ENTRYPOINT "/usr/local/bin/docker-entrypoint.sh"
+# setup entrypoint
+ADD ./docker-entrypoint.sh docker-entrypoint.sh
+RUN chmod a+x docker-entrypoint.sh
+
+ENTRYPOINT "/app/docker-entrypoint.sh"
diff --git a/index.html b/index.html
index c59dd4b1f..7e53819c2 100644
--- a/index.html
+++ b/index.html
@@ -23,7 +23,8 @@
     <script>
       window.CACHE_RELAY_ENABLED = false;
       window.IMAGE_PROXY_PATH = "";
-      window.CORS_PROXY_PATH = "";
+      window.REQUEST_PROXY = "";
+      window.PROXY_FIRST = false;
     </script>
   </head>
   <body>
diff --git a/package.json b/package.json
index 27526463c..79a4fdd70 100644
--- a/package.json
+++ b/package.json
@@ -92,6 +92,9 @@
     "three-spritetext": "^1.8.1",
     "three-stdlib": "^2.29.4",
     "webln": "^0.3.2",
+    "workbox-core": "7.0.0",
+    "workbox-precaching": "7.0.0",
+    "workbox-routing": "7.0.0",
     "yet-another-react-lightbox": "^3.17.3",
     "zen-observable": "^0.10.0"
   },
diff --git a/server/index.js b/server/index.js
new file mode 100644
index 000000000..329bd0438
--- /dev/null
+++ b/server/index.js
@@ -0,0 +1,52 @@
+var cors_proxy = require("cors-anywhere");
+var { PacProxyAgent } = require("pac-proxy-agent");
+
+const { TOR_PROXY, I2P_PROXY } = process.env;
+
+if (TOR_PROXY) console.log("Tor Proxy:", TOR_PROXY);
+if (I2P_PROXY) console.log("I2P Proxy:", I2P_PROXY);
+
+const I2pConfig = I2P_PROXY
+  ? `
+if (shExpMatch(host, "*.i2p"))
+{
+  return "PROXY ${I2P_PROXY}";
+}`.trim()
+  : "";
+const TorConfig = TOR_PROXY
+  ? `
+if (shExpMatch(host, "*.onion"))
+{
+  return "SOCKS5 ${TOR_PROXY}";
+}`.trim()
+  : "";
+
+const PACFile = `
+// SPDX-License-Identifier: CC0-1.0
+
+function FindProxyForURL(url, host)
+{
+  ${I2pConfig}
+  ${TorConfig}
+  return "DIRECT";
+}
+`.trim();
+
+const PACURI = "pac+data:application/x-ns-proxy-autoconfig;base64," + btoa(PACFile);
+
+var host = "127.0.0.1";
+var port = 8080;
+
+cors_proxy
+  .createServer({
+    requireHeader: [],
+    removeHeaders: ["cookie", "cookie2"],
+    redirectSameOrigin: true,
+    httpProxyOptions: {
+      xfwd: false,
+      agent: new PacProxyAgent(PACURI),
+    },
+  })
+  .listen(port, host, () => {
+    console.log("Running HTTP request proxy on " + host + ":" + port);
+  });
diff --git a/server/package.json b/server/package.json
new file mode 100644
index 000000000..389591ce7
--- /dev/null
+++ b/server/package.json
@@ -0,0 +1,12 @@
+{
+  "name": "server",
+  "version": "1.0.0",
+  "private": true,
+  "main": "index.js",
+  "license": "MIT",
+  "dependencies": {
+    "cors-anywhere": "^0.4.4",
+    "pac-proxy-agent": "^7.0.1",
+    "workbox-precaching": "^7.1.0"
+  }
+}
diff --git a/server/yarn.lock b/server/yarn.lock
new file mode 100644
index 000000000..bd3d0bd25
--- /dev/null
+++ b/server/yarn.lock
@@ -0,0 +1,269 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@tootallnate/quickjs-emscripten@^0.23.0":
+  version "0.23.0"
+  resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c"
+  integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==
+
+agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317"
+  integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==
+  dependencies:
+    debug "^4.3.4"
+
+ast-types@^0.13.4:
+  version "0.13.4"
+  resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782"
+  integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==
+  dependencies:
+    tslib "^2.0.1"
+
+basic-ftp@^5.0.2:
+  version "5.0.5"
+  resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.0.5.tgz#14a474f5fffecca1f4f406f1c26b18f800225ac0"
+  integrity sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==
+
+cors-anywhere@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/cors-anywhere/-/cors-anywhere-0.4.4.tgz#98892fcab55f408fff13a63e125135c18dc22ca8"
+  integrity sha512-8OBFwnzMgR4mNrAeAyOLB2EruS2z7u02of2bOu7i9kKYlZG+niS7CTHLPgEXKWW2NAOJWRry9RRCaL9lJRjNqg==
+  dependencies:
+    http-proxy "1.11.1"
+    proxy-from-env "0.0.1"
+
+data-uri-to-buffer@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz#8a58bb67384b261a38ef18bea1810cb01badd28b"
+  integrity sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==
+
+debug@4, debug@^4.3.4:
+  version "4.3.4"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+  dependencies:
+    ms "2.1.2"
+
+degenerator@^5.0.0:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-5.0.1.tgz#9403bf297c6dad9a1ece409b37db27954f91f2f5"
+  integrity sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==
+  dependencies:
+    ast-types "^0.13.4"
+    escodegen "^2.1.0"
+    esprima "^4.0.1"
+
+escodegen@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17"
+  integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==
+  dependencies:
+    esprima "^4.0.1"
+    estraverse "^5.2.0"
+    esutils "^2.0.2"
+  optionalDependencies:
+    source-map "~0.6.1"
+
+esprima@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+  integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+estraverse@^5.2.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+  integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+esutils@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+  integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+eventemitter3@1.x.x:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508"
+  integrity sha512-DOFqA1MF46fmZl2xtzXR3MPCRsXqgoFqdXcrCVYM3JNnfUeHTm/fh/v/iU7gBFpwkuBmoJPAm5GuhdDfSEJMJA==
+
+fs-extra@^11.2.0:
+  version "11.2.0"
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b"
+  integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==
+  dependencies:
+    graceful-fs "^4.2.0"
+    jsonfile "^6.0.1"
+    universalify "^2.0.0"
+
+get-uri@^6.0.1:
+  version "6.0.3"
+  resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.3.tgz#0d26697bc13cf91092e519aa63aa60ee5b6f385a"
+  integrity sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==
+  dependencies:
+    basic-ftp "^5.0.2"
+    data-uri-to-buffer "^6.0.2"
+    debug "^4.3.4"
+    fs-extra "^11.2.0"
+
+graceful-fs@^4.1.6, graceful-fs@^4.2.0:
+  version "4.2.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+  integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
+http-proxy-agent@^7.0.0:
+  version "7.0.2"
+  resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e"
+  integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==
+  dependencies:
+    agent-base "^7.1.0"
+    debug "^4.3.4"
+
+http-proxy@1.11.1:
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.11.1.tgz#71df55757e802d58ea810df2244019dda05ae85d"
+  integrity sha512-qz7jZarkVG3G6GMq+4VRJPSN4NkIjL4VMTNhKGd8jc25BumeJjWWvnY3A7OkCGa8W1TTxbaK3dcE0ijFalITVA==
+  dependencies:
+    eventemitter3 "1.x.x"
+    requires-port "0.x.x"
+
+https-proxy-agent@^7.0.2:
+  version "7.0.4"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz#8e97b841a029ad8ddc8731f26595bad868cb4168"
+  integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==
+  dependencies:
+    agent-base "^7.0.2"
+    debug "4"
+
+ip-address@^9.0.5:
+  version "9.0.5"
+  resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a"
+  integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==
+  dependencies:
+    jsbn "1.1.0"
+    sprintf-js "^1.1.3"
+
+jsbn@1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
+  integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==
+
+jsonfile@^6.0.1:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
+  integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
+  dependencies:
+    universalify "^2.0.0"
+  optionalDependencies:
+    graceful-fs "^4.1.6"
+
+ms@2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+netmask@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7"
+  integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==
+
+pac-proxy-agent@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz#6b9ddc002ec3ff0ba5fdf4a8a21d363bcc612d75"
+  integrity sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==
+  dependencies:
+    "@tootallnate/quickjs-emscripten" "^0.23.0"
+    agent-base "^7.0.2"
+    debug "^4.3.4"
+    get-uri "^6.0.1"
+    http-proxy-agent "^7.0.0"
+    https-proxy-agent "^7.0.2"
+    pac-resolver "^7.0.0"
+    socks-proxy-agent "^8.0.2"
+
+pac-resolver@^7.0.0:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-7.0.1.tgz#54675558ea368b64d210fd9c92a640b5f3b8abb6"
+  integrity sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==
+  dependencies:
+    degenerator "^5.0.0"
+    netmask "^2.0.2"
+
+proxy-from-env@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-0.0.1.tgz#b27c4946e9e6d5dbadb7598a6435d3014c4cfd49"
+  integrity sha512-B9Hnta3CATuMS0q6kt5hEezOPM+V3dgaRewkFtFoaRQYTVNsHqUvFXmndH06z3QO1ZdDnRELv5vfY6zAj/gG7A==
+
+requires-port@0.x.x:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-0.0.1.tgz#4b4414411d9df7c855995dd899a8c78a2951c16d"
+  integrity sha512-AzPDCliPoWDSvEVYRQmpzuPhGGEnPrQz9YiOEvn+UdB9ixBpw+4IOZWtwctmpzySLZTy7ynpn47V14H4yaowtA==
+
+smart-buffer@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
+  integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
+
+socks-proxy-agent@^8.0.2:
+  version "8.0.3"
+  resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz#6b2da3d77364fde6292e810b496cb70440b9b89d"
+  integrity sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==
+  dependencies:
+    agent-base "^7.1.1"
+    debug "^4.3.4"
+    socks "^2.7.1"
+
+socks@^2.7.1:
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5"
+  integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==
+  dependencies:
+    ip-address "^9.0.5"
+    smart-buffer "^4.2.0"
+
+source-map@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+sprintf-js@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a"
+  integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
+
+tslib@^2.0.1:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
+  integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
+
+universalify@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
+  integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
+
+workbox-core@7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-7.1.0.tgz#1867576f994f20d9991b71a7d0b2581af22db170"
+  integrity sha512-5KB4KOY8rtL31nEF7BfvU7FMzKT4B5TkbYa2tzkS+Peqj0gayMT9SytSFtNzlrvMaWgv6y/yvP9C0IbpFjV30Q==
+
+workbox-precaching@^7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-7.1.0.tgz#71e27ec2e85661a41b48dec0c92dae707c429eaa"
+  integrity sha512-LyxzQts+UEpgtmfnolo0hHdNjoB7EoRWcF7EDslt+lQGd0lW4iTvvSe3v5JiIckQSB5KTW5xiCqjFviRKPj1zA==
+  dependencies:
+    workbox-core "7.1.0"
+    workbox-routing "7.1.0"
+    workbox-strategies "7.1.0"
+
+workbox-routing@7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-7.1.0.tgz#c44bda350d1c5eb633ee97a660e64ce5473250c4"
+  integrity sha512-oOYk+kLriUY2QyHkIilxUlVcFqwduLJB7oRZIENbqPGeBP/3TWHYNNdmGNhz1dvKuw7aqvJ7CQxn27/jprlTdg==
+  dependencies:
+    workbox-core "7.1.0"
+
+workbox-strategies@7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-7.1.0.tgz#a589f2adc0df8f33049c7f4d4cdf4c9556715918"
+  integrity sha512-/UracPiGhUNehGjRm/tLUQ+9PtWmCbRufWtV0tNrALuf+HZ4F7cmObSEK+E4/Bx1p8Syx2tM+pkIrvtyetdlew==
+  dependencies:
+    workbox-core "7.1.0"
diff --git a/src/classes/relay-pool.ts b/src/classes/relay-pool.ts
index 178552533..572d73710 100644
--- a/src/classes/relay-pool.ts
+++ b/src/classes/relay-pool.ts
@@ -28,6 +28,7 @@ export default class RelayPool {
 
   requestRelay(url: string | URL, connect = true) {
     url = validateRelayURL(url);
+
     const key = url.toString();
     if (!this.relays.has(key)) {
       const newRelay = new AbstractRelay(key, { verifyEvent: verifyEventMethod });
diff --git a/src/components/external-embeds/types/image.tsx b/src/components/external-embeds/types/image.tsx
index f735b6241..076f178de 100644
--- a/src/components/external-embeds/types/image.tsx
+++ b/src/components/external-embeds/types/image.tsx
@@ -40,7 +40,7 @@ export type EmbeddedImageProps = Omit<LinkProps, "children" | "href" | "onClick"
 };
 
 function useImageThumbnail(src?: string) {
-  return (src && buildImageProxyURL(src, "256,fit")) ?? src;
+  return (src && buildImageProxyURL(src, "512,fit")) ?? src;
 }
 
 export const EmbeddedImage = forwardRef<HTMLImageElement, EmbeddedImageProps>(
diff --git a/src/components/reload-prompt.tsx b/src/components/reload-prompt.tsx
index a22f37ae8..44158df0c 100644
--- a/src/components/reload-prompt.tsx
+++ b/src/components/reload-prompt.tsx
@@ -11,7 +11,8 @@ export function ReloadPrompt(props: Omit<AlertProps, "children" | "status">) {
     updateServiceWorker,
   } = useRegisterSW({
     onRegistered(r) {
-      console.log("SW Registered: " + r);
+      console.log("SW Registered");
+      console.log(r);
 
       if (r) {
         setInterval(() => r.update(), intervalMS);
@@ -21,7 +22,8 @@ export function ReloadPrompt(props: Omit<AlertProps, "children" | "status">) {
       toast({ status: "success", title: "App Installed", duration: 2000, isClosable: true });
     },
     onRegisterError(error) {
-      console.log("SW registration error", error);
+      console.log("SW registration error");
+      console.log(error);
     },
   });
 
diff --git a/src/helpers/cors.ts b/src/helpers/cors.ts
deleted file mode 100644
index eeaaacbb8..000000000
--- a/src/helpers/cors.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import appSettings from "../services/settings/app-settings";
-import { convertToUrl } from "./url";
-
-const corsFailedHosts = new Set();
-
-export function createCorsUrl(url: URL | string, corsProxy?: string) {
-  if (!corsProxy && window.CORS_PROXY_PATH) corsProxy = new URL(window.CORS_PROXY_PATH, location.origin).toString();
-  if (!corsProxy && appSettings.value.corsProxy) corsProxy = appSettings.value.corsProxy;
-  if (!corsProxy) return url;
-
-  if (corsProxy.includes("<url>")) {
-    return corsProxy.replace("<url>", "" + url);
-  } else if (corsProxy.includes("<encoded_url>")) {
-    return corsProxy.replace("<encoded_url>", encodeURIComponent("" + url));
-  } else {
-    return corsProxy.endsWith("/") ? corsProxy + url : corsProxy + "/" + url;
-  }
-}
-
-export function fetchWithCorsFallback(url: URL | string, opts?: RequestInit) {
-  if (!appSettings.value.corsProxy) return fetch(url, opts);
-
-  if (corsFailedHosts.has(convertToUrl(url).host)) {
-    return fetch(createCorsUrl(url), opts);
-  }
-
-  return fetch(url, opts).catch((e) => {
-    corsFailedHosts.add(convertToUrl(url).host);
-    return fetch(createCorsUrl(url), opts);
-  });
-}
diff --git a/src/helpers/debug.ts b/src/helpers/debug.ts
index 7fcc3c725..67674e351 100644
--- a/src/helpers/debug.ts
+++ b/src/helpers/debug.ts
@@ -1,2 +1,5 @@
 import debug from "debug";
+
+if (!localStorage.getItem("debug") && import.meta.env.DEV) debug.enable("noStrudel,noStrudel:*");
+
 export const logger = debug("noStrudel");
diff --git a/src/helpers/request.ts b/src/helpers/request.ts
new file mode 100644
index 000000000..f20ece136
--- /dev/null
+++ b/src/helpers/request.ts
@@ -0,0 +1,44 @@
+import appSettings from "../services/settings/app-settings";
+import { convertToUrl } from "./url";
+
+const clearNetFailedHosts = new Set();
+const proxyFailedHosts = new Set();
+
+export function createRequestProxyUrl(url: URL | string, corsProxy?: string) {
+  if (!corsProxy && window.REQUEST_PROXY) corsProxy = new URL(window.REQUEST_PROXY, location.origin).toString();
+  if (!corsProxy && appSettings.value.corsProxy) corsProxy = appSettings.value.corsProxy;
+  if (!corsProxy) return url;
+
+  if (corsProxy.includes("<url>")) {
+    return corsProxy.replace("<url>", "" + url);
+  } else if (corsProxy.includes("<encoded_url>")) {
+    return corsProxy.replace("<encoded_url>", encodeURIComponent("" + url));
+  } else {
+    return corsProxy.endsWith("/") ? corsProxy + url : corsProxy + "/" + url;
+  }
+}
+
+export function fetchWithProxy(url: URL | string, opts?: RequestInit) {
+  if (!appSettings.value.corsProxy && !window.REQUEST_PROXY) return fetch(url, opts);
+
+  const u = typeof url === "string" ? convertToUrl(url) : url;
+
+  // if its an onion domain try the request proxy first
+  if ((u.host.endsWith(".onion") || u.host.endsWith(".i2p")) && !proxyFailedHosts.has(u.host)) {
+    return fetch(createRequestProxyUrl(url), opts).catch((e) => {
+      proxyFailedHosts.add(u.host);
+      return fetch(url, opts);
+    });
+  }
+
+  // if the clear net request has failed. use the proxy
+  if (clearNetFailedHosts.has(u.host)) {
+    return fetch(createRequestProxyUrl(url), opts);
+  }
+
+  // try clear net first and fallback to request proxy
+  return fetch(url, opts).catch((e) => {
+    clearNetFailedHosts.add(u.host);
+    return fetch(createRequestProxyUrl(url), opts);
+  });
+}
diff --git a/src/hooks/use-open-graph-data.ts b/src/hooks/use-open-graph-data.ts
index b4e173758..7e85b74ef 100644
--- a/src/hooks/use-open-graph-data.ts
+++ b/src/hooks/use-open-graph-data.ts
@@ -1,5 +1,5 @@
 import { useAsync } from "react-use";
-import { fetchWithCorsFallback } from "../helpers/cors";
+import { fetchWithProxy } from "../helpers/request";
 import type { OgObjectInteral } from "../lib/open-graph-scraper/types";
 import useAppSettings from "./use-app-settings";
 
@@ -22,7 +22,7 @@ export default function useOpenGraphData(url: URL) {
 
     try {
       const controller = new AbortController();
-      const res = await fetchWithCorsFallback(url, { signal: controller.signal });
+      const res = await fetchWithProxy(url, { signal: controller.signal });
       const contentType = res.headers.get("content-type");
 
       if (contentType?.includes("text/html")) {
diff --git a/src/services/dns-identity.ts b/src/services/dns-identity.ts
index 1f9bd0f2b..e1ce83d22 100644
--- a/src/services/dns-identity.ts
+++ b/src/services/dns-identity.ts
@@ -2,7 +2,7 @@ import dayjs from "dayjs";
 import db from "./db";
 import _throttle from "lodash.throttle";
 
-import { fetchWithCorsFallback } from "../helpers/cors";
+import { fetchWithProxy } from "../helpers/request";
 import SuperMap from "../classes/super-map";
 import Subject from "../classes/subject";
 
@@ -42,7 +42,7 @@ class DnsIdentityService {
     const { name, domain } = parseAddress(address);
     if (!name || !domain) throw new Error("invalid address " + address);
 
-    const json = await fetchWithCorsFallback(`https://${domain}/.well-known/nostr.json?name=${name}`)
+    const json = await fetchWithProxy(`https://${domain}/.well-known/nostr.json?name=${name}`)
       .then((res) => res.json() as Promise<IdentityJson>)
       .then((json) => {
         // convert all keys in names, and relays to lower case
diff --git a/src/services/lnurl-metadata.ts b/src/services/lnurl-metadata.ts
index 00032c5c8..a5e31f43f 100644
--- a/src/services/lnurl-metadata.ts
+++ b/src/services/lnurl-metadata.ts
@@ -1,4 +1,4 @@
-import { fetchWithCorsFallback } from "../helpers/cors";
+import { fetchWithProxy } from "../helpers/request";
 import { getLudEndpoint } from "../helpers/lnurl";
 
 type LNURLPMetadata = {
@@ -24,9 +24,7 @@ class LNURLMetadataService {
     const url = getLudEndpoint(addressOrLNURL);
     if (!url) return;
     try {
-      const metadata = await fetchWithCorsFallback(url).then(
-        (res) => res.json() as Promise<LNURLError | LNURLPMetadata>,
-      );
+      const metadata = await fetchWithProxy(url).then((res) => res.json() as Promise<LNURLError | LNURLPMetadata>);
       if ((metadata as LNURLPMetadata).tag === "payRequest") {
         return metadata as LNURLPMetadata;
       }
diff --git a/src/services/relay-info.ts b/src/services/relay-info.ts
index 001145773..a9a843501 100644
--- a/src/services/relay-info.ts
+++ b/src/services/relay-info.ts
@@ -1,5 +1,5 @@
 import db from "./db";
-import { fetchWithCorsFallback } from "../helpers/cors";
+import { fetchWithProxy } from "../helpers/request";
 import { isHexKey } from "../helpers/nip19";
 import { validateRelayURL } from "../helpers/relay";
 
@@ -26,7 +26,7 @@ async function fetchInfo(relay: string) {
   const url = validateRelayURL(relay);
   url.protocol = url.protocol === "ws:" ? "http" : "https";
 
-  const infoDoc = await fetchWithCorsFallback(url, { headers: { Accept: "application/nostr+json" } }).then(
+  const infoDoc = await fetchWithProxy(url, { headers: { Accept: "application/nostr+json" } }).then(
     (res) => res.json() as Promise<RelayInformationDocument>,
   );
 
diff --git a/src/types/window.d.ts b/src/types/window.d.ts
index 1c90dc084..ec511bad4 100644
--- a/src/types/window.d.ts
+++ b/src/types/window.d.ts
@@ -1,5 +1,5 @@
 interface Window {
   CACHE_RELAY_ENABLED: boolean;
   IMAGE_PROXY_PATH: string;
-  CORS_PROXY_PATH: string;
+  REQUEST_PROXY: string;
 }
diff --git a/src/views/settings/privacy-settings.tsx b/src/views/settings/privacy-settings.tsx
index 1c1fbc80a..c18379dad 100644
--- a/src/views/settings/privacy-settings.tsx
+++ b/src/views/settings/privacy-settings.tsx
@@ -17,7 +17,7 @@ import {
 import { useFormContext } from "react-hook-form";
 import { safeUrl } from "../../helpers/parse";
 import { AppSettings } from "../../services/settings/migrations";
-import { createCorsUrl } from "../../helpers/cors";
+import { createRequestProxyUrl } from "../../helpers/request";
 import { SpyIcon } from "../../components/icons";
 
 async function validateInvidiousUrl(url?: string) {
@@ -30,12 +30,12 @@ async function validateInvidiousUrl(url?: string) {
   }
 }
 
-async function validateCorsProxy(url?: string) {
+async function validateRequestProxy(url?: string) {
   if (!url) return true;
   try {
     const controller = new AbortController();
     const timeoutId = setTimeout(() => controller.abort(), 2000);
-    const res = await fetch(createCorsUrl("https://example.com", url), { signal: controller.signal });
+    const res = await fetch(createRequestProxyUrl("https://example.com", url), { signal: controller.signal });
     return res.ok || "Cant reach instance";
   } catch (e) {
     return "Cant reach instance";
@@ -124,16 +124,25 @@ export default function PrivacySettings() {
           </FormControl>
 
           <FormControl isInvalid={!!formState.errors.corsProxy}>
-            <FormLabel>CORS Proxy</FormLabel>
-            <Input
-              type="url"
-              placeholder="https://corsproxy.io/?<encoded_url>"
-              {...register("corsProxy", { validate: validateCorsProxy })}
-            />
+            <FormLabel>Request Proxy</FormLabel>
+            {window.REQUEST_PROXY ? (
+              <>
+                <Input type="url" value={window.REQUEST_PROXY} onChange={() => {}} readOnly isDisabled />
+                <FormHelperText color="red.500">
+                  This noStrudel version has the request proxy hard coded to <Code>{window.REQUEST_PROXY}</Code>
+                </FormHelperText>
+              </>
+            ) : (
+              <Input
+                type="url"
+                placeholder="https://corsproxy.io/?<encoded_url>"
+                {...register("corsProxy", { validate: validateRequestProxy })}
+              />
+            )}
             {formState.errors.corsProxy && <FormErrorMessage>{formState.errors.corsProxy.message}</FormErrorMessage>}
             <FormHelperText>
-              This is used as a fallback ( to bypass CORS restrictions ) when verifying NIP-05 ids and fetching
-              open-graph metadata.
+              This is used as a fallback ( to bypass CORS restrictions ) or to make connections to .onion and .i2p
+              domains
               <br />
               This can either point to an instance of{" "}
               <Link href="https://github.com/Rob--W/cors-anywhere" isExternal color="blue.500">
diff --git a/tsconfig.json b/tsconfig.json
index c6544962e..f807c7fda 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -2,7 +2,7 @@
   "compilerOptions": {
     "target": "ESNext",
     "useDefineForClassFields": true,
-    "lib": ["DOM", "DOM.Iterable", "ESNext"],
+    "lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"],
     "allowJs": false,
     "skipLibCheck": true,
     "esModuleInterop": true,
diff --git a/vite.config.ts b/vite.config.ts
index ed28bf391..2fb4ed809 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -13,6 +13,14 @@ export default defineConfig({
     react(),
     VitePWA({
       registerType: "prompt",
+      // strategies: "injectManifest",
+      // srcDir: "src",
+      // filename: "sw.ts",
+      // devOptions: {
+      //   // NOTE: ESM service workers is not supported by firefox
+      //   type: "module",
+      //   enabled: true,
+      // },
       workbox: {
         // This increase the cache limit to 3mB
         maximumFileSizeToCacheInBytes: 2097152 * 1.5,