diff --git a/bun.lockb b/bun.lockb
deleted file mode 100755
index af68f95..0000000
Binary files a/bun.lockb and /dev/null differ
diff --git a/deno.json b/deno.json
new file mode 100644
index 0000000..a70a678
--- /dev/null
+++ b/deno.json
@@ -0,0 +1,19 @@
+{
+  "nodeModulesDir": "auto",
+  "tasks": {
+    "dev": "deno run --allow-all --watch src/index.ts"
+  },
+  "imports": {
+    "@cashu/cashu-ts": "npm:@cashu/cashu-ts@^2.0.0",
+    "@libsql/client": "npm:@libsql/client",
+    "@nostr-dev-kit/ndk": "npm:@nostr-dev-kit/ndk@^2.10.7",
+    "@std/bytes": "jsr:@std/bytes@^1.0.4",
+    "@std/dotenv": "jsr:@std/dotenv@^0.225.2",
+    "@std/encoding": "jsr:@std/encoding@^1.0.5",
+    "nostr-tools": "jsr:@nostr/tools@^2.10.4",
+    "@std/assert": "jsr:@std/assert@1",
+    "@arx/utils": "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/index.ts",
+    "smtp-server": "npm:smtp-server@^3.13.6",
+    "winston": "npm:winston@^3.17.0"
+  }
+}
diff --git a/deno.lock b/deno.lock
new file mode 100644
index 0000000..4154e3b
--- /dev/null
+++ b/deno.lock
@@ -0,0 +1,733 @@
+{
+  "version": "4",
+  "specifiers": {
+    "jsr:@nostr/tools@^2.10.4": "2.10.4",
+    "jsr:@std/assert@1": "1.0.8",
+    "jsr:@std/bytes@^1.0.4": "1.0.4",
+    "jsr:@std/dotenv@~0.225.2": "0.225.2",
+    "jsr:@std/encoding@^1.0.5": "1.0.5",
+    "jsr:@std/internal@^1.0.5": "1.0.5",
+    "npm:@cashu/cashu-ts@2": "2.0.0",
+    "npm:@libsql/client@*": "0.14.0",
+    "npm:@noble/ciphers@~0.5.1": "0.5.3",
+    "npm:@noble/curves@1.2.0": "1.2.0",
+    "npm:@noble/hashes@1.3.1": "1.3.1",
+    "npm:@nostr-dev-kit/ndk@^2.10.7": "2.10.7",
+    "npm:@scure/base@1.1.1": "1.1.1",
+    "npm:@scure/bip32@1.3.1": "1.3.1",
+    "npm:@scure/bip39@1.2.1": "1.2.1",
+    "npm:nostr-wasm@0.1.0": "0.1.0",
+    "npm:smtp-server@^3.13.6": "3.13.6",
+    "npm:winston@^3.17.0": "3.17.0"
+  },
+  "jsr": {
+    "@nostr/tools@2.10.4": {
+      "integrity": "7fda015c96b4f674727843aecb990e2af1989e4724588415ccf6f69066abfd4f",
+      "dependencies": [
+        "npm:@noble/ciphers",
+        "npm:@noble/curves",
+        "npm:@noble/hashes",
+        "npm:@scure/base",
+        "npm:@scure/bip32",
+        "npm:@scure/bip39",
+        "npm:nostr-wasm"
+      ]
+    },
+    "@std/assert@1.0.8": {
+      "integrity": "ebe0bd7eb488ee39686f77003992f389a06c3da1bbd8022184804852b2fa641b",
+      "dependencies": [
+        "jsr:@std/internal"
+      ]
+    },
+    "@std/bytes@1.0.4": {
+      "integrity": "11a0debe522707c95c7b7ef89b478c13fb1583a7cfb9a85674cd2cc2e3a28abc"
+    },
+    "@std/dotenv@0.225.2": {
+      "integrity": "e2025dce4de6c7bca21dece8baddd4262b09d5187217e231b033e088e0c4dd23"
+    },
+    "@std/encoding@1.0.5": {
+      "integrity": "ecf363d4fc25bd85bd915ff6733a7e79b67e0e7806334af15f4645c569fefc04"
+    },
+    "@std/internal@1.0.5": {
+      "integrity": "54a546004f769c1ac9e025abd15a76b6671ddc9687e2313b67376125650dc7ba"
+    }
+  },
+  "npm": {
+    "@cashu/cashu-ts@2.0.0": {
+      "integrity": "sha512-neVWZGviQGFf2RlpVpEerf8zQZDR4HvzmDj58gsae1gOQxzaZoU9BdAyRjVpcvz/dPTYQKZii9mUTAgR+fof2w==",
+      "dependencies": [
+        "@cashu/crypto",
+        "@noble/curves@1.7.0",
+        "@noble/hashes@1.6.1",
+        "@scure/bip32@1.6.0",
+        "buffer"
+      ]
+    },
+    "@cashu/crypto@0.3.4": {
+      "integrity": "sha512-mfv1Pj4iL1PXzUj9NKIJbmncCLMqYfnEDqh/OPxAX0nNBt6BOnVJJLjLWFlQeYxlnEfWABSNkrqPje1t5zcyhA==",
+      "dependencies": [
+        "@noble/curves@1.7.0",
+        "@noble/hashes@1.6.1",
+        "@scure/bip32@1.6.0",
+        "@scure/bip39@1.5.0",
+        "buffer"
+      ]
+    },
+    "@colors/colors@1.6.0": {
+      "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="
+    },
+    "@dabh/diagnostics@2.0.3": {
+      "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
+      "dependencies": [
+        "colorspace",
+        "enabled",
+        "kuler"
+      ]
+    },
+    "@libsql/client@0.14.0": {
+      "integrity": "sha512-/9HEKfn6fwXB5aTEEoMeFh4CtG0ZzbncBb1e++OCdVpgKZ/xyMsIVYXm0w7Pv4RUel803vE6LwniB3PqD72R0Q==",
+      "dependencies": [
+        "@libsql/core",
+        "@libsql/hrana-client",
+        "js-base64",
+        "libsql",
+        "promise-limit"
+      ]
+    },
+    "@libsql/core@0.14.0": {
+      "integrity": "sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q==",
+      "dependencies": [
+        "js-base64"
+      ]
+    },
+    "@libsql/darwin-arm64@0.4.7": {
+      "integrity": "sha512-yOL742IfWUlUevnI5PdnIT4fryY3LYTdLm56bnY0wXBw7dhFcnjuA7jrH3oSVz2mjZTHujxoITgAE7V6Z+eAbg=="
+    },
+    "@libsql/darwin-x64@0.4.7": {
+      "integrity": "sha512-ezc7V75+eoyyH07BO9tIyJdqXXcRfZMbKcLCeF8+qWK5nP8wWuMcfOVywecsXGRbT99zc5eNra4NEx6z5PkSsA=="
+    },
+    "@libsql/hrana-client@0.7.0": {
+      "integrity": "sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==",
+      "dependencies": [
+        "@libsql/isomorphic-fetch",
+        "@libsql/isomorphic-ws",
+        "js-base64",
+        "node-fetch"
+      ]
+    },
+    "@libsql/isomorphic-fetch@0.3.1": {
+      "integrity": "sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw=="
+    },
+    "@libsql/isomorphic-ws@0.1.5": {
+      "integrity": "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==",
+      "dependencies": [
+        "@types/ws",
+        "ws"
+      ]
+    },
+    "@libsql/linux-arm64-gnu@0.4.7": {
+      "integrity": "sha512-WlX2VYB5diM4kFfNaYcyhw5y+UJAI3xcMkEUJZPtRDEIu85SsSFrQ+gvoKfcVh76B//ztSeEX2wl9yrjF7BBCA=="
+    },
+    "@libsql/linux-arm64-musl@0.4.7": {
+      "integrity": "sha512-6kK9xAArVRlTCpWeqnNMCoXW1pe7WITI378n4NpvU5EJ0Ok3aNTIC2nRPRjhro90QcnmLL1jPcrVwO4WD1U0xw=="
+    },
+    "@libsql/linux-x64-gnu@0.4.7": {
+      "integrity": "sha512-CMnNRCmlWQqqzlTw6NeaZXzLWI8bydaXDke63JTUCvu8R+fj/ENsLrVBtPDlxQ0wGsYdXGlrUCH8Qi9gJep0yQ=="
+    },
+    "@libsql/linux-x64-musl@0.4.7": {
+      "integrity": "sha512-nI6tpS1t6WzGAt1Kx1n1HsvtBbZ+jHn0m7ogNNT6pQHZQj7AFFTIMeDQw/i/Nt5H38np1GVRNsFe99eSIMs9XA=="
+    },
+    "@libsql/win32-x64-msvc@0.4.7": {
+      "integrity": "sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw=="
+    },
+    "@neon-rs/load@0.0.4": {
+      "integrity": "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="
+    },
+    "@noble/ciphers@0.5.3": {
+      "integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w=="
+    },
+    "@noble/curves@1.1.0": {
+      "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==",
+      "dependencies": [
+        "@noble/hashes@1.3.1"
+      ]
+    },
+    "@noble/curves@1.2.0": {
+      "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
+      "dependencies": [
+        "@noble/hashes@1.3.2"
+      ]
+    },
+    "@noble/curves@1.7.0": {
+      "integrity": "sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==",
+      "dependencies": [
+        "@noble/hashes@1.6.0"
+      ]
+    },
+    "@noble/hashes@1.3.1": {
+      "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA=="
+    },
+    "@noble/hashes@1.3.2": {
+      "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ=="
+    },
+    "@noble/hashes@1.6.0": {
+      "integrity": "sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ=="
+    },
+    "@noble/hashes@1.6.1": {
+      "integrity": "sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w=="
+    },
+    "@noble/secp256k1@2.1.0": {
+      "integrity": "sha512-XLEQQNdablO0XZOIniFQimiXsZDNwaYgL96dZwC54Q30imSbAOFf3NKtepc+cXyuZf5Q1HCgbqgZ2UFFuHVcEw=="
+    },
+    "@nostr-dev-kit/ndk@2.10.7": {
+      "integrity": "sha512-cylva8jsaAGMijxAI32CnJWlzvwD4sWyl86/+RMS6xpZn4MIgeVUfBFc/pYkcfZzDP3v1Z9mIPsuiICRyvu9yQ==",
+      "dependencies": [
+        "@noble/curves@1.7.0",
+        "@noble/hashes@1.6.1",
+        "@noble/secp256k1",
+        "@scure/base@1.2.1",
+        "debug@4.3.7",
+        "light-bolt11-decoder",
+        "nostr-tools",
+        "tseep",
+        "typescript-lru-cache",
+        "utf8-buffer",
+        "websocket-polyfill"
+      ]
+    },
+    "@scure/base@1.1.1": {
+      "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA=="
+    },
+    "@scure/base@1.2.1": {
+      "integrity": "sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ=="
+    },
+    "@scure/bip32@1.3.1": {
+      "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==",
+      "dependencies": [
+        "@noble/curves@1.1.0",
+        "@noble/hashes@1.3.2",
+        "@scure/base@1.1.1"
+      ]
+    },
+    "@scure/bip32@1.6.0": {
+      "integrity": "sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA==",
+      "dependencies": [
+        "@noble/curves@1.7.0",
+        "@noble/hashes@1.6.1",
+        "@scure/base@1.2.1"
+      ]
+    },
+    "@scure/bip39@1.2.1": {
+      "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==",
+      "dependencies": [
+        "@noble/hashes@1.3.2",
+        "@scure/base@1.1.1"
+      ]
+    },
+    "@scure/bip39@1.5.0": {
+      "integrity": "sha512-Dop+ASYhnrwm9+HA/HwXg7j2ZqM6yk2fyLWb5znexjctFY3+E+eU8cIWI0Pql0Qx4hPZCijlGq4OL71g+Uz30A==",
+      "dependencies": [
+        "@noble/hashes@1.6.1",
+        "@scure/base@1.2.1"
+      ]
+    },
+    "@types/node@22.5.4": {
+      "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
+      "dependencies": [
+        "undici-types"
+      ]
+    },
+    "@types/triple-beam@1.3.5": {
+      "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="
+    },
+    "@types/ws@8.5.13": {
+      "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==",
+      "dependencies": [
+        "@types/node"
+      ]
+    },
+    "async@3.2.6": {
+      "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="
+    },
+    "base32.js@0.1.0": {
+      "integrity": "sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ=="
+    },
+    "base64-js@1.5.1": {
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+    },
+    "buffer@6.0.3": {
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "dependencies": [
+        "base64-js",
+        "ieee754"
+      ]
+    },
+    "bufferutil@4.0.8": {
+      "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
+      "dependencies": [
+        "node-gyp-build"
+      ]
+    },
+    "color-convert@1.9.3": {
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": [
+        "color-name"
+      ]
+    },
+    "color-name@1.1.3": {
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+    },
+    "color-string@1.9.1": {
+      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+      "dependencies": [
+        "color-name",
+        "simple-swizzle"
+      ]
+    },
+    "color@3.2.1": {
+      "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+      "dependencies": [
+        "color-convert",
+        "color-string"
+      ]
+    },
+    "colorspace@1.1.4": {
+      "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
+      "dependencies": [
+        "color",
+        "text-hex"
+      ]
+    },
+    "d@1.0.2": {
+      "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
+      "dependencies": [
+        "es5-ext",
+        "type"
+      ]
+    },
+    "data-uri-to-buffer@4.0.1": {
+      "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="
+    },
+    "debug@2.6.9": {
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dependencies": [
+        "ms@2.0.0"
+      ]
+    },
+    "debug@4.3.7": {
+      "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+      "dependencies": [
+        "ms@2.1.3"
+      ]
+    },
+    "detect-libc@2.0.2": {
+      "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="
+    },
+    "enabled@2.0.0": {
+      "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
+    },
+    "es5-ext@0.10.64": {
+      "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
+      "dependencies": [
+        "es6-iterator",
+        "es6-symbol",
+        "esniff",
+        "next-tick"
+      ]
+    },
+    "es6-iterator@2.0.3": {
+      "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+      "dependencies": [
+        "d",
+        "es5-ext",
+        "es6-symbol"
+      ]
+    },
+    "es6-symbol@3.1.4": {
+      "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
+      "dependencies": [
+        "d",
+        "ext"
+      ]
+    },
+    "esniff@2.0.1": {
+      "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
+      "dependencies": [
+        "d",
+        "es5-ext",
+        "event-emitter",
+        "type"
+      ]
+    },
+    "event-emitter@0.3.5": {
+      "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
+      "dependencies": [
+        "d",
+        "es5-ext"
+      ]
+    },
+    "ext@1.7.0": {
+      "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
+      "dependencies": [
+        "type"
+      ]
+    },
+    "fecha@4.2.3": {
+      "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
+    },
+    "fetch-blob@3.2.0": {
+      "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+      "dependencies": [
+        "node-domexception",
+        "web-streams-polyfill"
+      ]
+    },
+    "fn.name@1.1.0": {
+      "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
+    },
+    "formdata-polyfill@4.0.10": {
+      "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+      "dependencies": [
+        "fetch-blob"
+      ]
+    },
+    "ieee754@1.2.1": {
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+    },
+    "inherits@2.0.4": {
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "ipv6-normalize@1.0.1": {
+      "integrity": "sha512-Bm6H79i01DjgGTCWjUuCjJ6QDo1HB96PT/xCYuyJUP9WFbVDrLSbG4EZCvOCun2rNswZb0c3e4Jt/ws795esHA=="
+    },
+    "is-arrayish@0.3.2": {
+      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+    },
+    "is-stream@2.0.1": {
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="
+    },
+    "is-typedarray@1.0.0": {
+      "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
+    },
+    "js-base64@3.7.7": {
+      "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="
+    },
+    "kuler@2.0.0": {
+      "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
+    },
+    "libsql@0.4.7": {
+      "integrity": "sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==",
+      "dependencies": [
+        "@libsql/darwin-arm64",
+        "@libsql/darwin-x64",
+        "@libsql/linux-arm64-gnu",
+        "@libsql/linux-arm64-musl",
+        "@libsql/linux-x64-gnu",
+        "@libsql/linux-x64-musl",
+        "@libsql/win32-x64-msvc",
+        "@neon-rs/load",
+        "detect-libc"
+      ]
+    },
+    "light-bolt11-decoder@3.2.0": {
+      "integrity": "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ==",
+      "dependencies": [
+        "@scure/base@1.1.1"
+      ]
+    },
+    "logform@2.7.0": {
+      "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
+      "dependencies": [
+        "@colors/colors",
+        "@types/triple-beam",
+        "fecha",
+        "ms@2.1.3",
+        "safe-stable-stringify",
+        "triple-beam"
+      ]
+    },
+    "ms@2.0.0": {
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+    },
+    "ms@2.1.3": {
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+    },
+    "next-tick@1.1.0": {
+      "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
+    },
+    "node-domexception@1.0.0": {
+      "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="
+    },
+    "node-fetch@3.3.2": {
+      "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
+      "dependencies": [
+        "data-uri-to-buffer",
+        "fetch-blob",
+        "formdata-polyfill"
+      ]
+    },
+    "node-gyp-build@4.8.4": {
+      "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="
+    },
+    "nodemailer@6.9.15": {
+      "integrity": "sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ=="
+    },
+    "nostr-tools@2.10.4": {
+      "integrity": "sha512-biU7sk+jxHgVASfobg2T5ttxOGGSt69wEVBC51sHHOEaKAAdzHBLV/I2l9Rf61UzClhliZwNouYhqIso4a3HYg==",
+      "dependencies": [
+        "@noble/ciphers",
+        "@noble/curves@1.2.0",
+        "@noble/hashes@1.3.1",
+        "@scure/base@1.1.1",
+        "@scure/bip32@1.3.1",
+        "@scure/bip39@1.2.1",
+        "nostr-wasm"
+      ]
+    },
+    "nostr-wasm@0.1.0": {
+      "integrity": "sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA=="
+    },
+    "one-time@1.0.0": {
+      "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
+      "dependencies": [
+        "fn.name"
+      ]
+    },
+    "promise-limit@2.7.0": {
+      "integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw=="
+    },
+    "punycode.js@2.3.1": {
+      "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="
+    },
+    "readable-stream@3.6.2": {
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dependencies": [
+        "inherits",
+        "string_decoder",
+        "util-deprecate"
+      ]
+    },
+    "safe-buffer@5.2.1": {
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+    },
+    "safe-stable-stringify@2.5.0": {
+      "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="
+    },
+    "simple-swizzle@0.2.2": {
+      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+      "dependencies": [
+        "is-arrayish"
+      ]
+    },
+    "smtp-server@3.13.6": {
+      "integrity": "sha512-dqbSPKn3PCq3Gp5hxBM99u7PET7cQSAWrauhtArJbc+zrf5xNEOjm9+Ob3lySySrRoIEvNE0dz+w2H/xWFJNRw==",
+      "dependencies": [
+        "base32.js",
+        "ipv6-normalize",
+        "nodemailer",
+        "punycode.js"
+      ]
+    },
+    "stack-trace@0.0.10": {
+      "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="
+    },
+    "string_decoder@1.3.0": {
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dependencies": [
+        "safe-buffer"
+      ]
+    },
+    "text-hex@1.0.0": {
+      "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
+    },
+    "triple-beam@1.4.1": {
+      "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="
+    },
+    "tseep@1.3.1": {
+      "integrity": "sha512-ZPtfk1tQnZVyr7BPtbJ93qaAh2lZuIOpTMjhrYa4XctT8xe7t4SAW9LIxrySDuYMsfNNayE51E/WNGrNVgVicQ=="
+    },
+    "tstl@2.5.16": {
+      "integrity": "sha512-+O2ybLVLKcBwKm4HymCEwZIT0PpwS3gCYnxfSDEjJEKADvIFruaQjd3m7CAKNU1c7N3X3WjVz87re7TA2A5FUw=="
+    },
+    "type@2.7.3": {
+      "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="
+    },
+    "typedarray-to-buffer@3.1.5": {
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "dependencies": [
+        "is-typedarray"
+      ]
+    },
+    "typescript-lru-cache@2.0.0": {
+      "integrity": "sha512-Jp57Qyy8wXeMkdNuZiglE6v2Cypg13eDA1chHwDG6kq51X7gk4K7P7HaDdzZKCxkegXkVHNcPD0n5aW6OZH3aA=="
+    },
+    "undici-types@6.19.8": {
+      "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
+    },
+    "utf-8-validate@5.0.10": {
+      "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
+      "dependencies": [
+        "node-gyp-build"
+      ]
+    },
+    "utf8-buffer@1.0.0": {
+      "integrity": "sha512-ueuhzvWnp5JU5CiGSY4WdKbiN/PO2AZ/lpeLiz2l38qwdLy/cW40XobgyuIWucNyum0B33bVB0owjFCeGBSLqg=="
+    },
+    "util-deprecate@1.0.2": {
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+    },
+    "web-streams-polyfill@3.3.3": {
+      "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="
+    },
+    "websocket-polyfill@0.0.3": {
+      "integrity": "sha512-pF3kR8Uaoau78MpUmFfzbIRxXj9PeQrCuPepGE6JIsfsJ/o/iXr07Q2iQNzKSSblQJ0FiGWlS64N4pVSm+O3Dg==",
+      "dependencies": [
+        "tstl",
+        "websocket"
+      ]
+    },
+    "websocket@1.0.35": {
+      "integrity": "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==",
+      "dependencies": [
+        "bufferutil",
+        "debug@2.6.9",
+        "es5-ext",
+        "typedarray-to-buffer",
+        "utf-8-validate",
+        "yaeti"
+      ]
+    },
+    "winston-transport@4.9.0": {
+      "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
+      "dependencies": [
+        "logform",
+        "readable-stream",
+        "triple-beam"
+      ]
+    },
+    "winston@3.17.0": {
+      "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==",
+      "dependencies": [
+        "@colors/colors",
+        "@dabh/diagnostics",
+        "async",
+        "is-stream",
+        "logform",
+        "one-time",
+        "readable-stream",
+        "safe-stable-stringify",
+        "stack-trace",
+        "triple-beam",
+        "winston-transport"
+      ]
+    },
+    "ws@8.18.0": {
+      "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="
+    },
+    "yaeti@0.0.6": {
+      "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug=="
+    }
+  },
+  "remote": {
+    "https://deno.land/x/hono@v4.3.11/adapter/deno/serve-static.ts": "db226d30f08f1a8bb77653ead42a911357b2f8710d653e43c01eccebb424b295",
+    "https://deno.land/x/hono@v4.3.11/client/client.ts": "dcda3887257fa3164db7b32c56665c6e757f0ef047a14f3f9599ef41725c1525",
+    "https://deno.land/x/hono@v4.3.11/client/index.ts": "30def535310a37bede261f1b23d11a9758983b8e9d60a6c56309cee5f6746ab2",
+    "https://deno.land/x/hono@v4.3.11/client/utils.ts": "8be84b49c5c7952666875a8e901fde3044c85c853ea6ba3a7e2c0468478459c0",
+    "https://deno.land/x/hono@v4.3.11/compose.ts": "37d6e33b7db80e4c43a0629b12fd3a1e3406e7d9e62a4bfad4b30426ea7ae4f1",
+    "https://deno.land/x/hono@v4.3.11/context.ts": "facfd749d823a645039571d66d9d228f5ae6836818b65d3b6c4c6891adfe071e",
+    "https://deno.land/x/hono@v4.3.11/helper/adapter/index.ts": "ff7e11eb1ca1fbd74ca3c46cd1d24014582f91491ef6d3846d66ed1cede18ec4",
+    "https://deno.land/x/hono@v4.3.11/helper/cookie/index.ts": "689c84eae410f0444a4598f136a4f859b9122ec6f790dff74412d34405883db8",
+    "https://deno.land/x/hono@v4.3.11/helper/html/index.ts": "48a0ddc576c10452db6c3cab03dd4ee6986ab61ebdc667335b40a81fa0487f69",
+    "https://deno.land/x/hono@v4.3.11/hono-base.ts": "fd7e9c1bba1e13119e95158270011784da3a7c3014c149ba0700e700f840ae0d",
+    "https://deno.land/x/hono@v4.3.11/hono.ts": "23edd0140bf0bd5a68c14ae96e5856a5cec6b844277e853b91025e91ea74f416",
+    "https://deno.land/x/hono@v4.3.11/http-exception.ts": "f5dd375e61aa4b764eb9b99dd45a7160f8317fd36d3f79ae22585b9a5e8ad7c5",
+    "https://deno.land/x/hono@v4.3.11/jsx/base.ts": "33f1c302c8f72ae948abd9c3ef85f4b3be6525251a13b95fd18fe2910b7d4a0d",
+    "https://deno.land/x/hono@v4.3.11/jsx/children.ts": "26ead0f151faba5307883614b5b064299558f06798c695c432f32acbb1127d56",
+    "https://deno.land/x/hono@v4.3.11/jsx/components.ts": "f79ab215f59388f01a69e2d6ec0b841fd3b42ba38e0ee7c93a525cdf06e159f9",
+    "https://deno.land/x/hono@v4.3.11/jsx/constants.ts": "984e0797194be1fbc935cb688c8d0a60c112b21bc59301be5354c02232f18820",
+    "https://deno.land/x/hono@v4.3.11/jsx/context.ts": "2b7a86e6b35da171fab27aa05f09748bb3eba64b26c037ea1da655c07e8f6bc1",
+    "https://deno.land/x/hono@v4.3.11/jsx/dom/components.ts": "733da654edb3d4c178a4479649fac2c64e79069e37e848add0c3a49f90e7f2d7",
+    "https://deno.land/x/hono@v4.3.11/jsx/dom/context.ts": "06209d14553398750c69252cc826082018cefa277f5c82cbe58d7261c8a2d81e",
+    "https://deno.land/x/hono@v4.3.11/jsx/dom/jsx-dev-runtime.ts": "ba87562d14b77dd5f2a3cc30d41b1eb5edb0800e5f4a7337b5b87b2e66f8a099",
+    "https://deno.land/x/hono@v4.3.11/jsx/dom/jsx-runtime.ts": "6a50a65306771a9000030f494d92a5fdeeb055112e0126234b2fd9179de1d4f5",
+    "https://deno.land/x/hono@v4.3.11/jsx/dom/render.ts": "7db816d40de58c60e1cbdab64ac3f170b1e30696ed61ad449bbb823f60b46146",
+    "https://deno.land/x/hono@v4.3.11/jsx/dom/utils.ts": "5d3e8c14996902db9c1223041fb21480fa0e921a4ccdc59f8c7571c08b7810f2",
+    "https://deno.land/x/hono@v4.3.11/jsx/hooks/index.ts": "b7e0f0a754f31a1e1fbe0ac636b38b031603eb0ae195c32a30769a11d79fb871",
+    "https://deno.land/x/hono@v4.3.11/jsx/index.ts": "fe3e582c2a4e24e5f8b6027925bddccaae0283747d8f0161eb6f5a34616edd11",
+    "https://deno.land/x/hono@v4.3.11/jsx/streaming.ts": "5e5dde9a546041353b9a3860fc9020471f762813f10e1290009ab6bd40e7bdcf",
+    "https://deno.land/x/hono@v4.3.11/jsx/types.ts": "51c2bdbb373860e2570ad403546a7fdbbb1cf00a47ce7ed10b2aece922031ac4",
+    "https://deno.land/x/hono@v4.3.11/jsx/utils.ts": "4b8299d402ba5395472c552d1fe3297ee60112bfc32e0ef86cfe8e40086f7d54",
+    "https://deno.land/x/hono@v4.3.11/middleware.ts": "2e7c6062e36b0e5f84b44a62e7b0e1cef33a9827c19937c648be4b63e1b7d7c6",
+    "https://deno.land/x/hono@v4.3.11/middleware/basic-auth/index.ts": "2c8cb563f3b89df1a7a2232be37377c3df6194af38613dc0a823c6595816fc66",
+    "https://deno.land/x/hono@v4.3.11/middleware/bearer-auth/index.ts": "b3b7469bc0eb9543c6c47f3ff67de879210dd73063307a61536042ff30e8720e",
+    "https://deno.land/x/hono@v4.3.11/middleware/body-limit/index.ts": "3fefeaf7e6e576aa1b33f2694072d2eaab692842acd29cb360d98e20eebfe5aa",
+    "https://deno.land/x/hono@v4.3.11/middleware/cache/index.ts": "5e6273e5c9ea73ef387b25923ab23274c220b29d7c981b62ac0be26d6a1aa3d8",
+    "https://deno.land/x/hono@v4.3.11/middleware/compress/index.ts": "98c403a5fe7e9c5f5d776350b422b0a125fb34696851b8b14f825b9b7b06f2ac",
+    "https://deno.land/x/hono@v4.3.11/middleware/cors/index.ts": "976eb9ce8cefc214b403a2939503a13177cec76223274609a07ca554e0dc623b",
+    "https://deno.land/x/hono@v4.3.11/middleware/csrf/index.ts": "077bb0ce299d79d0d232cb9e462aaa4eaa901164f1310f74a7630f7e6cfe74e8",
+    "https://deno.land/x/hono@v4.3.11/middleware/etag/index.ts": "95e0270ea349cf00537ee6e58985a4cc7dba44091ca8e2dc42b6d8b2f01bcfe7",
+    "https://deno.land/x/hono@v4.3.11/middleware/jsx-renderer/index.ts": "229322c66ebc7f426cd2d71f282438025b4ee7ce8cb8e97e87c7efbc94530c19",
+    "https://deno.land/x/hono@v4.3.11/middleware/jwt/index.ts": "fce4e2db52b4816bfe6bb3a468bd596ab4705527bee1edf679bc28ca53b28ba3",
+    "https://deno.land/x/hono@v4.3.11/middleware/logger/index.ts": "52a2e968890ada2c11ce89a7a783692c5767b8ed7fb23ccf6b559d255d13ccbc",
+    "https://deno.land/x/hono@v4.3.11/middleware/method-override/index.ts": "bc13bdcf70c777b72b1300a5cca1b51a8bd126e0d922b991d89e96fe7c694b5b",
+    "https://deno.land/x/hono@v4.3.11/middleware/powered-by/index.ts": "6faba0cf042278d60b317b690640bb0b58747690cf280fa09024424c5174e66d",
+    "https://deno.land/x/hono@v4.3.11/middleware/pretty-json/index.ts": "2216ce4c9910be009fecac63367c3626b46137d4cf7cb9a82913e501104b4a88",
+    "https://deno.land/x/hono@v4.3.11/middleware/secure-headers/index.ts": "f2e4c3858d26ff47bc6909513607e6a3c31184aabe78fb272ed08e1d62a750f0",
+    "https://deno.land/x/hono@v4.3.11/middleware/serve-static/index.ts": "14b760bbbc4478cc3a7fb9728730bc6300581c890365b7101b80c16e70e4b21e",
+    "https://deno.land/x/hono@v4.3.11/middleware/timing/index.ts": "6fddbb3e47ae875c16907cf23b9bb503ec2ad858406418b5f38f1e7fbca8c6f6",
+    "https://deno.land/x/hono@v4.3.11/middleware/trailing-slash/index.ts": "419cf0af99a137f591b72cc71c053e524fe3574393ce81e0e9dbce84a4046e24",
+    "https://deno.land/x/hono@v4.3.11/mod.ts": "35fd2a2e14b52365e0ad66f168b067363fd0a60d75cbcb1b01685b04de97d60e",
+    "https://deno.land/x/hono@v4.3.11/request.ts": "7b08602858e642d1626c3106c0bedc2aa8d97e30691a079351d9acef7c5955e6",
+    "https://deno.land/x/hono@v4.3.11/router.ts": "880316f561918fc197481755aac2165fdbe2f530b925c5357a9f98d6e2cc85c7",
+    "https://deno.land/x/hono@v4.3.11/router/linear-router/index.ts": "8a2a7144c50b1f4a92d9ee99c2c396716af144c868e10608255f969695efccd0",
+    "https://deno.land/x/hono@v4.3.11/router/linear-router/router.ts": "928d29894e4b45b047a4f453c7f1745c8b1869cd68447e1cb710c7bbf99a4e29",
+    "https://deno.land/x/hono@v4.3.11/router/pattern-router/index.ts": "304a66c50e243872037ed41c7dd79ed0c89d815e17e172e7ad7cdc4bc07d3383",
+    "https://deno.land/x/hono@v4.3.11/router/pattern-router/router.ts": "1b5f68e6af942579d3a40ee834294fea3d1f05fd5f70514e46ae301dd0107e46",
+    "https://deno.land/x/hono@v4.3.11/router/reg-exp-router/index.ts": "52755829213941756159b7a963097bafde5cc4fc22b13b1c7c9184dc0512d1db",
+    "https://deno.land/x/hono@v4.3.11/router/reg-exp-router/node.ts": "7efaa6f4301efc2aad0519c84973061be8555da02e5868409293a1fd98536aaf",
+    "https://deno.land/x/hono@v4.3.11/router/reg-exp-router/router.ts": "632f2fa426b3e45a66aeed03f7205dad6d13e8081bed6f8d1d987b6cad8fb455",
+    "https://deno.land/x/hono@v4.3.11/router/reg-exp-router/trie.ts": "852ce7207e6701e47fa30889a0d2b8bfcd56d8862c97e7bc9831e0a64bd8835f",
+    "https://deno.land/x/hono@v4.3.11/router/smart-router/index.ts": "74f9b4fe15ea535900f2b9b048581915f12fe94e531dd2b0032f5610e61c3bef",
+    "https://deno.land/x/hono@v4.3.11/router/smart-router/router.ts": "dc22a8505a0f345476f07dca3054c0c50a64d7b81c9af5a904476490dfd5cbb4",
+    "https://deno.land/x/hono@v4.3.11/router/trie-router/index.ts": "3eb75e7f71ba81801631b30de6b1f5cefb2c7239c03797e2b2cbab5085911b41",
+    "https://deno.land/x/hono@v4.3.11/router/trie-router/node.ts": "d3e00e8f1ba7fb26896459d5bba882356891a07793387c4655d1864c519a91de",
+    "https://deno.land/x/hono@v4.3.11/router/trie-router/router.ts": "54ced78d35676302c8fcdda4204f7bdf5a7cc907fbf9967c75674b1e394f830d",
+    "https://deno.land/x/hono@v4.3.11/utils/body.ts": "774cb319dfbe886a9d39f12c43dea15a39f9d01e45de0323167cdd5d0aad14d4",
+    "https://deno.land/x/hono@v4.3.11/utils/buffer.ts": "2fae689954b427b51fb84ad02bed11a72eae96692c2973802b3b4c1e39cd5b9c",
+    "https://deno.land/x/hono@v4.3.11/utils/color.ts": "10575c221f48bc806887710da8285f859f51daf9e6878bbdf99cb406b8494457",
+    "https://deno.land/x/hono@v4.3.11/utils/cookie.ts": "662529d55703d2c0bad8736cb1274eb97524c0ef7882d99254fc7c8fa925b46c",
+    "https://deno.land/x/hono@v4.3.11/utils/crypto.ts": "bda0e141bbe46d3a4a20f8fbcb6380d473b617123d9fdfa93e4499410b537acc",
+    "https://deno.land/x/hono@v4.3.11/utils/encode.ts": "311dfdfae7eb0b6345e9680f7ebbb3a692e872ed964e2029aca38567af8d1f33",
+    "https://deno.land/x/hono@v4.3.11/utils/filepath.ts": "a83e5fe87396bb291a6c5c28e13356fcbea0b5547bad2c3ba9660100ff964000",
+    "https://deno.land/x/hono@v4.3.11/utils/html.ts": "6ea4f6bf41587a51607dff7a6d2865ef4d5001e4203b07e5c8a45b63a098e871",
+    "https://deno.land/x/hono@v4.3.11/utils/jwt/index.ts": "3b66f48cdd3fcc2caed5e908ca31776e11b1c30391008931276da3035e6ba1e9",
+    "https://deno.land/x/hono@v4.3.11/utils/jwt/jwa.ts": "6874cacd8b6dde386636b81b5ea2754f8e4c61757802fa908dd1ce54b91a52fa",
+    "https://deno.land/x/hono@v4.3.11/utils/jwt/jws.ts": "878fa7d1966b0db20ae231cfee279ba2bb198943e949049cab3f5845cd5ee2d1",
+    "https://deno.land/x/hono@v4.3.11/utils/jwt/jwt.ts": "80452edc3498c6670a211fdcd33cfc4d5c00dfac79aa9f403b0623dedc039554",
+    "https://deno.land/x/hono@v4.3.11/utils/jwt/types.ts": "b6659ac85e7f8fcdd8cdfc7d51f5d1a91107ad8dfb647a8e4ea9c80f0f02afee",
+    "https://deno.land/x/hono@v4.3.11/utils/jwt/utf8.ts": "17c507f68f23ccb82503ea6183e54b5f748a6fe621eb60994adfb4a8c2a3f561",
+    "https://deno.land/x/hono@v4.3.11/utils/mime.ts": "d1fc2c047191ccb01d736c6acf90df731324536298181dba0ecc2259e5f7d661",
+    "https://deno.land/x/hono@v4.3.11/utils/url.ts": "855169632c61d03703bd08cafb27664ba3fdb352892f01687d5cce8fd49e3cb1",
+    "https://deno.land/x/hono@v4.3.11/validator/index.ts": "6c986e8b91dcf857ecc8164a506ae8eea8665792a4ff7215471df669c632ae7c",
+    "https://deno.land/x/hono@v4.3.11/validator/validator.ts": "53f3d2ad442e22f0bc2d85b7d8d90320d4e5ecf5fdd58882f906055d33a18e13",
+    "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/cashu.ts": "9fe2676838da581a051ebc4bcfca78b4b5eb04e05b5fbdd7a487767c16fec6e7",
+    "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/email.ts": "ee77141a139894b10bbd0bc68338ebf1a6261a241b97732de547c791e6b0462c",
+    "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/general.ts": "692b4c44ec137cf7ef7128337f63a4a96ef8b09057beb7ec9940a6939a615bb4",
+    "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/index.ts": "fae9d057707d0632a2d82611e773a9627f199fc038cf823bfc4ecca0cfa0f064",
+    "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/nostr.ts": "c72faf0cb4a76a746f141965d366926868b8cbc36bec1b559f921481402521c4"
+  },
+  "workspace": {
+    "dependencies": [
+      "jsr:@nostr/tools@^2.10.4",
+      "jsr:@std/assert@1",
+      "jsr:@std/bytes@^1.0.4",
+      "jsr:@std/dotenv@~0.225.2",
+      "jsr:@std/encoding@^1.0.5",
+      "npm:@cashu/cashu-ts@2",
+      "npm:@libsql/client@*",
+      "npm:@nostr-dev-kit/ndk@^2.10.7",
+      "npm:smtp-server@^3.13.6",
+      "npm:winston@^3.17.0"
+    ]
+  }
+}
diff --git a/package.json b/package.json
deleted file mode 100644
index 582753b..0000000
--- a/package.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-  "name": "mail-server",
-  "version": "1.0.0",
-  "description": "",
-  "main": "src/index.ts",
-  "scripts": {
-    "start": "DEBUG='ndk:*' bun --watch src/index.ts",
-    "db:generate": "prisma generate",
-    "db:migrate": "prisma migrate dev"
-  },
-  "dependencies": {
-    "@arx/utils": "git+ssh://git@git.arx-ccn.com:222/Arx/ts-utils#v0.0.4",
-    "@elysiajs/cors": "^1.1.1",
-    "@elysiajs/server-timing": "^1.1.0",
-    "@elysiajs/swagger": "^1.1.6",
-    "@libsql/client": "^0.14.0",
-    "@nostr-dev-kit/ndk": "^2.10.7",
-    "@prisma/adapter-libsql": "^5.22.0",
-    "@prisma/client": "5.22.0",
-    "elysia": "^1.1.25",
-    "node-forge": "^1.3.1",
-    "smtp-server": "^3.13.6",
-    "websocket-polyfill": "^1.0.0",
-    "winston": "^3.17.0"
-  },
-  "devDependencies": {
-    "@types/node-forge": "^1.3.11",
-    "@types/smtp-server": "^3.5.10",
-    "bun-types": "latest",
-    "prisma": "5.22.0",
-    "typescript": "^5.7.2"
-  },
-  "private": true
-}
diff --git a/prisma/migrations/20241125122247_init/migration.sql b/prisma/migrations/20241125122247_init/migration.sql
deleted file mode 100644
index aa6b44d..0000000
--- a/prisma/migrations/20241125122247_init/migration.sql
+++ /dev/null
@@ -1,29 +0,0 @@
--- CreateTable
-CREATE TABLE "users" (
-    "npub" TEXT NOT NULL PRIMARY KEY,
-    "registeredAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "lastPayment" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "subscriptionDuration" INTEGER
-);
-
--- CreateTable
-CREATE TABLE "aliases" (
-    "npub" TEXT NOT NULL,
-    "alias" TEXT NOT NULL,
-
-    PRIMARY KEY ("npub", "alias"),
-    CONSTRAINT "aliases_npub_fkey" FOREIGN KEY ("npub") REFERENCES "users" ("npub") ON DELETE RESTRICT ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "mail_queue" (
-    "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
-    "alias" TEXT NOT NULL,
-    "sender" TEXT NOT NULL,
-    "data" TEXT NOT NULL,
-    "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    CONSTRAINT "mail_queue_alias_fkey" FOREIGN KEY ("alias") REFERENCES "aliases" ("alias") ON DELETE RESTRICT ON UPDATE CASCADE
-);
-
--- CreateIndex
-CREATE UNIQUE INDEX "aliases_alias_key" ON "aliases"("alias");
diff --git a/prisma/migrations/20241126193747_remove_mail_queue/migration.sql b/prisma/migrations/20241126193747_remove_mail_queue/migration.sql
deleted file mode 100644
index a0e1043..0000000
--- a/prisma/migrations/20241126193747_remove_mail_queue/migration.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
-  Warnings:
-
-  - You are about to drop the `mail_queue` table. If the table is not empty, all the data it contains will be lost.
-
-*/
--- DropTable
-PRAGMA foreign_keys=off;
-DROP TABLE "mail_queue";
-PRAGMA foreign_keys=on;
diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml
deleted file mode 100644
index e5e5c47..0000000
--- a/prisma/migrations/migration_lock.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-# Please do not edit this file manually
-# It should be added in your version-control system (i.e. Git)
-provider = "sqlite"
\ No newline at end of file
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
deleted file mode 100644
index 42ccefa..0000000
--- a/prisma/schema.prisma
+++ /dev/null
@@ -1,28 +0,0 @@
-generator client {
-  provider        = "prisma-client-js"
-  previewFeatures = ["driverAdapters"]
-}
-
-datasource db {
-  provider = "sqlite"
-  url      = env("DB_URL")
-}
-
-model User {
-  npub                 String   @id
-  registeredAt         DateTime @default(now())
-  lastPayment          DateTime @default(now())
-  subscriptionDuration Int?
-  aliases              Alias[]
-
-  @@map("users")
-}
-
-model Alias {
-  npub  String
-  alias String @unique
-  user  User   @relation(fields: [npub], references: [npub])
-
-  @@id([npub, alias])
-  @@map("aliases")
-}
diff --git a/src/httpServer.ts b/src/httpServer.ts
index e56b85e..997b897 100644
--- a/src/httpServer.ts
+++ b/src/httpServer.ts
@@ -1,247 +1,241 @@
+import {Context as HonoContext, Hono,} from "https://deno.land/x/hono@v4.3.11/mod.ts";
+import {cors} from "https://deno.land/x/hono@v4.3.11/middleware.ts";
 import {CashuMint, CashuWallet, getEncodedToken} from "@cashu/cashu-ts";
-import {logger} from "./utils";
+import {getAlias, getUserByNpub} from "./models.ts";
+import {logger} from "./utils/index.ts";
 import * as nip98 from "nostr-tools/nip98";
-import {Elysia, t} from "elysia";
-import {swagger} from "@elysiajs/swagger";
-import {serverTiming} from "@elysiajs/server-timing";
-import {PrismaClient} from "@prisma/client";
-import {TokenInfoWithMailSubscriptionDuration} from "@arx/utils/cashu.ts";
-import {npubToPubKeyString, pubKeyStringToNpub} from "@arx/utils/nostr.ts";
-import cors from "@elysiajs/cors";
+import {Client as LibSQL} from "@libsql/client";
+import {npubToPubKeyString, pubKeyStringToNpub, TokenInfoWithMailSubscriptionDuration,} from "@arx/utils";
 
-const npubType = t.String({
-  pattern: `^npub1[023456789acdefghjklmnpqrstuvwxyz]{58}$`,
-  error: 'Invalid npub format'
-});
-
-const cashuTokenType = t.String({
-  pattern: '^cashu[A-Za-z0-9+-_]*={0,3}$',
-  error: 'Invalid Cashu token format'
-})
+const NPUB_REGEX = /^npub1[023456789acdefghjklmnpqrstuvwxyz]{58}$/;
+const CASHU_REGEX = /^cashu[A-Za-z0-9+-_]*={0,3}$/;
 
 export class HttpServer {
-  constructor(private db: PrismaClient, port: number) {
-    new Elysia()
-      .use(swagger({
-        documentation: {
-          info: {
-            title: 'npub.email Documentation',
-            version: '0.0.1'
-          }
-        }
-      }))
-      .use(serverTiming())
-      .use(cors())
-      .get('/', 'nostr.email server')
-      .get('/subscription/:npub', this.getSubscriptionForNpub, {
-        params: t.Object({
-          npub: npubType
-        })
-      })
-      .get('/aliases/:npub', this.getAliasesForNpub, {
-        params: t.Object({
-          npub: npubType,
-        }),
-      })
-      .get('/alias/:alias', this.getNpubForAlias, {
-        params: t.Object({
-          alias: t.String(),
-        }),
-      })
-      .post('/addAlias', this.addAlias, {
-        body: t.Object({
-          alias: t.String()
-        })
-      })
-      .post('/addTime/:npub', this.addTimeToNpub, {
-        params: t.Object({
-          npub: npubType,
-        }),
-        body: t.Object({
-          tokenString: cashuTokenType
-        })
-      })
-      .listen(port)
+  private app: Hono;
+
+  constructor(private db: LibSQL, port: number) {
+    this.app = new Hono();
+
+    this.app
+      .use("*", cors())
+      .get("/", (c: HonoContext) => c.text("nostr.email server"))
+      .get("/subscription/:npub", this.getSubscriptionForNpub)
+      .get("/aliases/:npub", this.getAliasesForNpub)
+      .get("/alias/:alias", this.getNpubForAlias)
+      .post("/addAlias", this.addAlias)
+      .post("/addTime/:npub", this.addTimeToNpub);
+
+    Deno.serve({ port }, this.app.fetch);
     logger.info(`HTTP Server running on port ${port}`);
   }
 
-  getSubscriptionForNpub = async ({params: {npub}}: {
-    params: {
-      npub: string
+  getSubscriptionForNpub = async (c: HonoContext) => {
+    const npub = c.req.param("npub");
+    if (!NPUB_REGEX.test(npub)) {
+      return c.json({ error: "Invalid npub format" }, 400);
     }
-  }) => {
-    const user = await this.db.user.findFirst({
-      where: {
-        npub
-      },
-      include: {
-        aliases: true
-      }
-    });
-    if (!user) return {
-      subscribed: false
-    };
-    return {
+
+    const user = await getUserByNpub(this.db, npub);
+
+    if (!user) {
+      return c.json({
+        subscribed: false,
+      });
+    }
+    return c.json({
       subscribed: true,
-      subscribedUntil: user.subscriptionDuration == null ? Infinity : Math.floor(user.lastPayment.getTime() / 1000) + user.subscriptionDuration
-    };
-  }
+      subscribedUntil: user.subscriptionDuration == null
+        ? Infinity
+        : Math.floor(user.lastPayment.getTime() / 1000) +
+          user.subscriptionDuration,
+    });
+  };
 
-  getNpubForAlias = async ({params: {alias}}: {
-    params: {
-      alias: string
+  getNpubForAlias = async (c: HonoContext) => {
+    const aliasParam = c.req.param("alias");
+
+    const alias = await getAlias(this.db, aliasParam);
+
+    if (!alias) {
+      return c.json({ error: "Not found" }, 404);
     }
-  }) => {
-    const user = await this.db.user.findFirst({
-      where: {
-        aliases: {
-          some: {
-            alias
-          }
-        }
-      }
-    });
-    if (!user) return new Response('Not found', {
-      status: 404
-    });
-    return user.npub;
-  }
+    return c.json({ npub: alias.npub });
+  };
 
-  getAliasesForNpub = async ({params: {npub}, headers}: {
-    params: {
-      npub: string
-    },
-    headers: Record<string, string | undefined>
-  }) => {
-    const unpacked = await this.getUnpackedAuthHeader(headers, `/aliases/${npub}`);
-    const npubAsPubkey = npubToPubKeyString(npub);
-    if (unpacked.pubkey !== npubAsPubkey)
-      return new Response('Unauthorized', {
-        status: 401
-      })
-    const user = await this.db.user.findFirst({
-      where: {
-        npub
-      },
-      include: {
-        aliases: true
-      }
-    });
-    if (!user) return new Response('Not found', {
-      status: 404
-    });
-    return user.aliases.map(alias => alias.alias);
-  }
-
-  addAlias = async ({body: {alias}, headers}: {
-    body: {
-      alias: string
-    },
-    headers: Record<string, string | undefined>
-  }) => {
-    const unpacked = await this.getUnpackedAuthHeader(headers, '/addAlias');
-    const unpackedKeyToNpub = pubKeyStringToNpub(unpacked.pubkey);
-    const userInDb = await this.db.user.findFirst({
-      where: {
-        npub: unpackedKeyToNpub
-      }
-    });
-    if (!userInDb) return new Response('Unauthorized', {
-      status: 401
-    });
-
-    const stillHasSubscription = userInDb.subscriptionDuration === null || Math.floor(userInDb.lastPayment.getTime() / 1000) + userInDb.subscriptionDuration > Date.now() / 1000;
-    if (!stillHasSubscription) return new Response('User has no subscription', {
-      status: 400
-    });
-    const aliasInDb = await this.db.alias.findFirst({
-      where: {
-        alias
-      }
-    });
-    if (aliasInDb) return new Response('Alias already exists', {
-      status: 400
-    });
-    return this.db.user.update({
-      where: {
-        npub: unpackedKeyToNpub
-      },
-      data: {
-        aliases: {
-          create: {
-            alias
-          }
-        }
-      }
-    });
-  }
-
-  addTimeToNpub = async ({params: {npub}, body: {tokenString}}: {
-    params: {
-      npub: string
-    },
-    body: {
-      tokenString: string
+  getAliasesForNpub = async (c: HonoContext) => {
+    const npub = c.req.param("npub");
+    if (!NPUB_REGEX.test(npub)) {
+      return c.json({ error: "Invalid npub format" }, 400);
     }
-  }) => {
-    const userInDb = await this.db.user.findFirst({
-      where: {
-        npub
-      }
-    });
 
-    if (userInDb && (userInDb.subscriptionDuration === null || userInDb.subscriptionDuration === -1))
-      return new Response('User has unlimited subscription', {
-        status: 400
-      })
+    try {
+      const unpacked = await this.getUnpackedAuthHeader(
+        c.req.header("Authorization"),
+        `/aliases/${npub}`,
+      );
+      const npubAsPubkey = npubToPubKeyString(npub);
+
+      if (unpacked.pubkey !== npubAsPubkey) {
+        return c.json({ error: "Unauthorized" }, 401);
+      }
+
+      const user = await getUserByNpub(this.db, npub);
+
+      if (!user) {
+        return c.json({ error: "Not found" }, 404);
+      }
+
+      return c.json(user.aliases);
+    } catch (error) {
+      if (error instanceof Error) {
+        return c.json({ error: error.message }, 401);
+      } else {
+        return c.json({ error: `${error}` }, 401);
+      }
+    }
+  };
+
+  addAlias = async (c: HonoContext) => {
+    const { alias } = await c.req.json<{
+      alias: string;
+    }>();
+
+    try {
+      const unpacked = await this.getUnpackedAuthHeader(
+        c.req.header("Authorization"),
+        "/addAlias",
+      );
+      const unpackedKeyToNpub = pubKeyStringToNpub(unpacked.pubkey);
+
+      const user = await getUserByNpub(this.db, unpackedKeyToNpub);
+
+      if (!user) {
+        return c.json({ error: "Unauthorized" }, 401);
+      }
+
+      const stillHasSubscription = user.subscriptionDuration === null ||
+        Math.floor(user.lastPayment.getTime() / 1000) +
+              user.subscriptionDuration > Date.now() / 1000;
+
+      if (!stillHasSubscription) {
+        return c.json({ error: "User has no subscription" }, 400);
+      }
+
+      const aliasInDb = await getAlias(this.db, alias);
+
+      if (aliasInDb) {
+        return c.json({ error: "Alias already exists" }, 400);
+      }
+
+      await this.db.execute({
+        sql: `
+          INSERT INTO aliases (alias, npub)
+          VALUES ($alias, $npub)
+          ON CONFLICT (alias) DO NOTHING
+        `,
+        args: { alias, npub: unpackedKeyToNpub },
+      });
+
+      return c.json({ alias, npub: unpackedKeyToNpub });
+    } catch (error) {
+      if (error instanceof Error) {
+        return c.json({ error: error.message }, 401);
+      } else {
+        return c.json({ error: `${error}` }, 401);
+      }
+    }
+  };
+
+  addTimeToNpub = async (c: HonoContext) => {
+    const npub = c.req.param("npub");
+    const { tokenString } = await c.req.json();
+
+    if (!NPUB_REGEX.test(npub)) {
+      return c.json({ error: "Invalid npub format" }, 400);
+    }
+    if (!CASHU_REGEX.test(tokenString)) {
+      return c.json({ error: "Invalid Cashu token format" }, 400);
+    }
+
+    const user = await getUserByNpub(this.db, npub);
+
+    if (
+      user &&
+      (user.subscriptionDuration === null ||
+        user.subscriptionDuration === -1)
+    ) {
+      return c.json({ error: "User has unlimited subscription" }, 400);
+    }
 
     const tokenInfo = new TokenInfoWithMailSubscriptionDuration(tokenString);
     const mint = new CashuMint(tokenInfo.mint);
     const wallet = new CashuWallet(mint);
     const newToken = await wallet.receive(tokenString);
     const encodedToken = getEncodedToken({
-      token: [{
-        mint: tokenInfo.mint,
-        proofs: newToken
-      }]
+      mint: tokenInfo.mint,
+      proofs: newToken,
     });
     logger.info(`New cashu token: ${encodedToken}`);
-    if (userInDb) {
-      let timeRemaining = Math.max(0, Math.floor((+new Date(userInDb.lastPayment.getTime() + userInDb.subscriptionDuration! * 1000) - +new Date()) / 1000));
+    if (user) {
+      let timeRemaining = Math.max(
+        0,
+        Math.floor(
+          (+new Date(
+            user.lastPayment.getTime() +
+              user.subscriptionDuration! * 1000,
+          ) - +new Date()) / 1000,
+        ),
+      );
       timeRemaining += tokenInfo.duration;
-      await this.db.user.update({
-        where: {
-          npub
-        },
-        data: {
+      await this.db.execute({
+        sql: `
+          UPDATE users
+          SET lastPayment = $lastPayment, subscriptionDuration = $subscriptionDuration
+          WHERE npub = $npub
+        `,
+        args: {
           lastPayment: new Date(),
-          subscriptionDuration: timeRemaining
-        }
+          subscriptionDuration: timeRemaining,
+          npub,
+        },
+      });
+      return c.json({
+        newTimeRemaining: timeRemaining,
       });
-      return {
-        newTimeRemaining: timeRemaining
-      }
     }
-    await this.db.user.create({
-      data: {
+    await this.db.execute({
+      sql: `
+        INSERT INTO users (npub, registeredAt, lastPayment, subscriptionDuration)
+        VALUES ($npub, $registeredAt, $lastPayment, $subscriptionDuration)
+      `,
+      args: {
         npub,
         registeredAt: new Date(),
         lastPayment: new Date(),
-        subscriptionDuration: tokenInfo.duration
-      }
+        subscriptionDuration: tokenInfo.duration,
+      },
     });
-    return {
-      newTimeRemaining: tokenInfo.duration
-    }
-  }
+    return c.json({
+      newTimeRemaining: tokenInfo.duration,
+    });
+  };
 
-  private getUnpackedAuthHeader = async (headers: Record<string, string | undefined>, url: string) => {
-    if (!headers.authorization)
-      throw new Error('Unauthorized');
-    const authHeader = headers.authorization.split(' ')[1];
-    const validate = await nip98.validateToken(authHeader, `${process.env.PUBLIC_API_BASE_URL!}${url}`, "POST");
-    if (!validate)
-      throw new Error('Unauthorized');
+  private getUnpackedAuthHeader = async (
+    auth: string | undefined,
+    url: string,
+  ) => {
+    if (!auth) {
+      throw new Error("Unauthorized");
+    }
+    const authHeader = auth.split(" ")[1];
+    const validate = await nip98.validateToken(
+      authHeader,
+      `${Deno.env.get("PUBLIC_API_BASE_URL")!}${url}`,
+      "POST",
+    );
+    if (!validate) {
+      throw new Error("Unauthorized");
+    }
     return await nip98.unpackEventFromToken(authHeader);
-  }
+  };
 }
diff --git a/src/index.ts b/src/index.ts
index 2d87a08..b0323a2 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,26 +1,34 @@
-import {createClient as createLibSQLClient} from "@libsql/client";
-import "websocket-polyfill";
-import {PrismaClient} from "@prisma/client";
-import {PrismaLibSQL} from "@prisma/adapter-libsql";
-import {NostrSmtpServer} from "./smtpServer";
-import {HttpServer} from "./httpServer";
+import {NostrSmtpServer} from "./smtpServer.ts";
+import {HttpServer} from "./httpServer.ts";
+import {createClient as createDB} from "@libsql/client/sqlite3";
+import "@std/dotenv/load";
 
-if (!process.env.BASE_DOMAIN)
-  throw new Error("BASE_DOMAIN is not set");
-if (!process.env.DB_URL)
-  throw new Error("DB_URL is not set");
-if (!process.env.PUBLIC_API_BASE_URL)
-  throw new Error("PUBLIC_API_BASE_URL is not set");
-if (!process.env.MASTER_NSEC)
-  throw new Error("MASTER_NSEC is not set");
+const requiredEnvVars = [
+  "BASE_DOMAIN",
+  "DB_URL",
+  "PUBLIC_API_BASE_URL",
+  "MASTER_NSEC",
+];
 
-const dbClient = createLibSQLClient({
-  url: process.env.DB_URL,
+for (const envVar of requiredEnvVars) {
+  if (!Deno.env.has(envVar)) {
+    throw new Error(`${envVar} is not set`);
+  }
+}
+
+export const db = createDB({
+  url: Deno.env.get("DB_URL")!,
 });
 
-const db = new PrismaClient({
-  adapter: new PrismaLibSQL(dbClient)
-});
-
-new NostrSmtpServer(db, parseInt(process.env.SMTP_PORT || '6587'));
-new HttpServer(db, parseInt(process.env.HTTP_PORT || '3000'));
\ No newline at end of file
+new NostrSmtpServer(
+  db,
+  parseInt(
+    Deno.env.get("SMTP_PORT") || "6587",
+  ),
+);
+new HttpServer(
+  db,
+  parseInt(
+    Deno.env.get("HTTP_PORT") || "3000",
+  ),
+);
diff --git a/src/models.ts b/src/models.ts
new file mode 100644
index 0000000..f18303b
--- /dev/null
+++ b/src/models.ts
@@ -0,0 +1,113 @@
+import {Client as LibSQL} from "@libsql/client";
+
+type User = {
+  npub: string;
+  registeredAt: Date;
+  lastPayment: Date;
+  subscriptionDuration: number | null;
+};
+
+type Alias = {
+  alias: string;
+  npub: string;
+};
+
+type UserWithAliases = User & {
+  aliases: string[];
+};
+
+export type AliasRowResult = {
+  rows: Array<{
+    alias: string;
+    npub: string;
+  }>;
+  columns: string[];
+  rowsAffected: number;
+};
+
+export type UserRowResult = {
+  rows: Array<{
+    npub: string;
+    registeredAt: Date;
+    lastPayment: Date;
+    subscriptionDuration: number | null;
+    alias: string | null;
+  }>;
+  columns: string[];
+  rowsAffected: number;
+};
+
+export const mapSingleAlias = (rows: AliasRowResult["rows"]): Alias | null => {
+  if (rows.length === 0) {
+    return null;
+  }
+  const firstRow = rows[0];
+  return {
+    alias: firstRow.alias,
+    npub: firstRow.npub,
+  };
+};
+
+export const mapSingleUserWithAliases = (
+  rows: UserRowResult["rows"],
+): UserWithAliases | null => {
+  if (rows.length === 0) {
+    return null;
+  }
+  const firstRow = rows[0];
+  return {
+    npub: firstRow.npub,
+    registeredAt: firstRow.registeredAt,
+    lastPayment: new Date(firstRow.lastPayment),
+    subscriptionDuration: firstRow.subscriptionDuration,
+    aliases: rows
+      .filter((row) => row.alias !== null)
+      .map((row) => row.alias!),
+  };
+};
+
+export const getUserByNpub = async (
+  db: LibSQL,
+  npub: string,
+): Promise<UserWithAliases | null> => {
+  const result: UserRowResult = await db.execute({
+    sql: `
+        SELECT u.*, a.*
+        FROM users u LEFT JOIN aliases a ON u.npub = a.npub
+        WHERE u.npub = $npub;
+    `,
+    args: { npub },
+  }) as any as UserRowResult;
+
+  return mapSingleUserWithAliases(result.rows);
+};
+
+export const getUserByAlias = async (
+  db: LibSQL,
+  alias: string,
+): Promise<UserWithAliases | null> => {
+  const result: UserRowResult = await db.execute({
+    sql: `
+        SELECT u.*, a.*
+        FROM users u LEFT JOIN aliases a ON u.npub = a.npub
+        WHERE a.alias = $alias;
+    `,
+    args: { alias },
+  }) as any as UserRowResult;
+
+  return mapSingleUserWithAliases(result.rows);
+};
+
+export const getAlias = async (db: LibSQL, aliasParam: string) => {
+  const result: AliasRowResult = await db.execute({
+    sql: `
+      SELECT *
+      FROM aliases
+      WHERE alias = $alias
+      LIMIT 1;
+    `,
+    args: { alias: aliasParam },
+  }) as any as AliasRowResult;
+
+  return mapSingleAlias(result.rows);
+};
diff --git a/src/smtpServer.ts b/src/smtpServer.ts
index 933d387..1d83597 100644
--- a/src/smtpServer.ts
+++ b/src/smtpServer.ts
@@ -1,10 +1,12 @@
-import {SMTPServer, SMTPServerAddress, SMTPServerDataStream, SMTPServerSession} from "smtp-server";
-import {deriveNsecForEmail, getNDK, logger} from "./utils";
+import {SMTPServer, SMTPServerAddress, SMTPServerDataStream, SMTPServerSession,} from "smtp-server";
+import {deriveNsecForEmail, getNDK, getUserByAlias, logger,} from "./utils/index.ts";
 import {NDKEvent, NDKKind, NDKPrivateKeySigner} from "@nostr-dev-kit/ndk";
-import {PrismaClient} from "@prisma/client";
+import {Client as LibSQL} from "@libsql/client";
 import {encryptEventForRecipient, parseEmail} from "@arx/utils";
-import * as path from "node:path";
-import fs from 'node:fs/promises';
+import {concat} from "@std/bytes";
+import path from "node:path";
+import fs from "node:fs/promises";
+import process from "node:process";
 
 interface QueuedEmail {
   id: string;
@@ -19,20 +21,24 @@ export class NostrSmtpServer {
   private emailQueue: QueuedEmail[] = [];
   private isProcessing: boolean = false;
   private readonly MAX_RETRIES = 3;
-  private readonly BACKUP_DIR = path.join(process.cwd(), 'email-backups');
+  private readonly BACKUP_DIR = path.join(Deno.cwd(), "email-backups");
 
-  constructor(private db: PrismaClient, port: number) {
+  constructor(private db: LibSQL, port: number) {
     this.server = new SMTPServer({
       authOptional: true,
       logger: false,
-      onData: (stream, session, callback) => this.handleEmailData(stream, session, callback, db)
+      onData: (
+        stream: SMTPServerDataStream,
+        session: SMTPServerSession,
+        callback: () => void,
+      ) => this.handleEmailData(stream, session, callback),
     });
 
-    this.server.listen(port, '0.0.0.0');
+    this.server.listen(port, "0.0.0.0");
     logger.info(`SMTP Server running on port ${port}`);
 
-    fs.mkdir(this.BACKUP_DIR, {recursive: true}).catch(err => {
-      logger.error('Failed to create backup directory:', err);
+    fs.mkdir(this.BACKUP_DIR, { recursive: true }).catch((err) => {
+      logger.error("Failed to create backup directory:", err);
     });
 
     this.setupGracefulShutdown();
@@ -43,7 +49,9 @@ export class NostrSmtpServer {
     const files = await fs.readdir(this.BACKUP_DIR);
     for (const file of files) {
       try {
-        const data = JSON.parse(await fs.readFile(path.join(this.BACKUP_DIR, file), 'utf-8'));
+        const data = JSON.parse(
+          await fs.readFile(path.join(this.BACKUP_DIR, file), "utf-8"),
+        );
         this.emailQueue.push(data);
       } catch (error) {
         logger.error(`Failed to recover backup ${file}:`, error);
@@ -54,71 +62,78 @@ export class NostrSmtpServer {
 
   private setupGracefulShutdown(): void {
     const shutdown = async () => {
-      logger.info('Graceful shutdown initiated');
+      logger.info("Graceful shutdown initiated");
 
       this.server.close();
 
-      while (this.isProcessing)
-        await new Promise(resolve => setTimeout(resolve, 100));
+      while (this.isProcessing) {
+        await new Promise((resolve) => setTimeout(resolve, 100));
+      }
 
-      for (const email of this.emailQueue)
+      for (const email of this.emailQueue) {
         await this.backupEmail(email);
+      }
 
-      logger.info('Graceful shutdown completed');
+      logger.info("Graceful shutdown completed");
       process.exit(0);
     };
 
-    process.on('SIGTERM', shutdown);
-    process.on('SIGINT', shutdown);
+    process.on("SIGTERM", shutdown);
+    process.on("SIGINT", shutdown);
   }
 
-  private async handleEmailData(stream: SMTPServerDataStream, session: SMTPServerSession, callback: () => void, db: PrismaClient) {
-    const chunks: Buffer[] = [];
+  private async handleEmailData(
+    stream: SMTPServerDataStream,
+    session: SMTPServerSession,
+    callback: () => void,
+  ) {
+    const chunks: Uint8Array[] = [];
 
-    stream.on('data', (chunk: Buffer) => {
-      chunks.push(chunk);
-    });
+    try {
+      for await (const chunk of stream) {
+        chunks.push(chunk);
+      }
 
-    stream.on('end', async () => {
       if (!this.validateSender(session)) {
         callback();
         return;
       }
 
-      const mailData = Buffer.concat(chunks).toString();
+      const mailData = new TextDecoder().decode(
+        concat(chunks),
+      );
 
-      try {
-        const queuedEmail: QueuedEmail = {
-          id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
-          mailData,
-          session,
-          attempts: 0,
-          createdAt: Date.now()
-        };
+      const queuedEmail: QueuedEmail = {
+        id: `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
+        mailData,
+        session,
+        attempts: 0,
+        createdAt: Date.now(),
+      };
 
-        this.emailQueue.push(queuedEmail);
-        await this.backupEmail(queuedEmail);
-        this.processQueue();
-      } catch (e) {
-        logger.error(`Error processing recipients: ${e}`, e);
-      }
+      this.emailQueue.push(await this.backupEmail(queuedEmail));
+      this.processQueue();
+    } catch (e) {
+      logger.error(`Error processing recipients: ${e}`, e);
+    }
 
-      callback();
-    });
+    callback();
   }
 
-  private async backupEmail(email: QueuedEmail): Promise<void> {
+  private async backupEmail(email: QueuedEmail): Promise<QueuedEmail> {
     try {
       const backupPath = path.join(this.BACKUP_DIR, `${email.id}.json`);
       await fs.writeFile(backupPath, JSON.stringify(email));
     } catch (error) {
-      logger.error('Failed to backup email:', error);
+      logger.error("Failed to backup email:", error);
     }
+    return JSON.parse(JSON.stringify(email)) as QueuedEmail; // returning the email because of a weird bug with smtp-server
   }
 
   private async processQueue(): Promise<void> {
-    if (this.isProcessing)
+    if (this.isProcessing) {
       return;
+    }
     this.isProcessing = true;
     while (this.emailQueue.length > 0) {
       const email = this.emailQueue[0];
@@ -128,7 +143,9 @@ export class NostrSmtpServer {
       }
 
       try {
-        const parsedEmail: ReturnType<typeof parseEmail> = parseEmail(email.mailData);
+        const parsedEmail: ReturnType<typeof parseEmail> = parseEmail(
+          email.mailData,
+        );
         await this.processRecipients(email.session, parsedEmail, this.db);
 
         // Remove from queue and delete backup if successful
@@ -149,77 +166,93 @@ export class NostrSmtpServer {
       const backupPath = path.join(this.BACKUP_DIR, `${id}.json`);
       await fs.unlink(backupPath);
     } catch (error) {
-      logger.error(`[TOXIC DATA!!!] Failed to delete email backup ${id}.json:`, error);
+      logger.error(
+        `[TOXIC DATA!!!] Failed to delete email backup ${id}.json:`,
+        error,
+      );
     }
   }
 
   private validateSender(session: SMTPServerSession): boolean {
     if (!session.envelope.mailFrom) {
-      logger.warn('Ignoring email without sender');
+      logger.warn("Ignoring email without sender");
       return false;
     }
     return true;
   }
 
-  private async processRecipients(session: SMTPServerSession, parsedEmail: ReturnType<typeof parseEmail>, db: PrismaClient) {
+  private async processRecipients(
+    session: SMTPServerSession,
+    parsedEmail: ReturnType<typeof parseEmail>,
+    db: LibSQL,
+  ) {
     for (const recipientEmail of session.envelope.rcptTo) {
       const address = recipientEmail.address;
-      const [alias, domain] = address.split('@');
+      const [alias, domain] = address.split("@");
 
-      if (domain !== process.env.BASE_DOMAIN) {
-        logger.warn(`Not sending email to ${address} because it is not in the allowed domain`);
+      if (domain !== Deno.env.get("BASE_DOMAIN")) {
+        logger.warn(
+          `Not sending email to ${address} because it is not in the allowed domain`,
+        );
         continue;
       }
 
       const user = await this.getUser(alias, db);
-      if (!user || !this.isSubscriptionValid(user)) continue;
+      if (!user || !this.isSubscriptionValid(user)) return;
 
       await this.sendNostrLetter(session, parsedEmail, user.npub);
     }
   }
 
-  private async getUser(alias: string, db: PrismaClient) {
-    const user = await db.alias.findUnique({
-      where: {alias},
-      include: {user: true}
-    });
+  private async getUser(alias: string, db: LibSQL) {
+    const user = await getUserByAlias(db, alias);
 
     if (!user) {
-      logger.warn('No user found for', alias, 'skipping');
+      logger.warn("No user found for", alias, "skipping");
       return null;
     }
     return user;
   }
 
-  private isSubscriptionValid(user: NonNullable<Awaited<ReturnType<NostrSmtpServer['getUser']>>>): boolean {
+  private isSubscriptionValid(
+    user: NonNullable<Awaited<ReturnType<NostrSmtpServer["getUser"]>>>,
+  ): boolean {
     // If there's no duration set, it's an unlimited subscription
-    if (user.user.subscriptionDuration === null)
+    if (user.subscriptionDuration === null) {
       return true;
+    }
 
-    const subscriptionDurationMs = user.user.subscriptionDuration * 1000;
-    const lastPaymentTimestamp = user.user.lastPayment.getTime();
+    const subscriptionDurationMs = user.subscriptionDuration * 1000;
+    const lastPaymentTimestamp = user.lastPayment.getTime();
     const currentTimestamp = Date.now();
 
     const subscriptionEndTime = lastPaymentTimestamp + subscriptionDurationMs;
     const timeRemaining = subscriptionEndTime - currentTimestamp;
 
     if (timeRemaining <= 0) {
-      logger.warn(`Subscription has expired for ${user.alias}`);
+      logger.warn(`Subscription has expired for ${user.npub}`);
       return false;
     }
     return true;
   }
 
-  private async sendNostrLetter(session: SMTPServerSession, parsedEmail: ReturnType<typeof parseEmail>, recipient: string) {
+  private async sendNostrLetter(
+    session: SMTPServerSession,
+    parsedEmail: ReturnType<typeof parseEmail>,
+    recipient: string,
+  ) {
     const randomKeySinger = new NDKPrivateKeySigner(
-      deriveNsecForEmail(process.env.MASTER_NSEC!, (session.envelope.mailFrom as SMTPServerAddress).address)
+      deriveNsecForEmail(
+        Deno.env.get("MASTER_NSEC")!,
+        (session.envelope.mailFrom as SMTPServerAddress).address,
+      ),
     );
 
     const ndk = getNDK();
     ndk.signer = randomKeySinger;
     await ndk.connect();
 
-    const ndkUser = ndk.getUser({npub: recipient});
+    const ndkUser = ndk.getUser({ npub: recipient });
     const randomKeyUser = await randomKeySinger.user();
     const event = new NDKEvent();
     event.kind = NDKKind.Article;
@@ -227,17 +260,17 @@ export class NostrSmtpServer {
     event.created_at = Math.floor(Date.now() / 1000);
     event.pubkey = randomKeyUser.pubkey;
     event.tags.push(
-      ['p', ndkUser.pubkey],
-      ['subject', parsedEmail.subject],
-      ['email:localIP', session.localAddress],
-      ['email:remoteIP', session.remoteAddress],
-      ['email:isEmail', 'true'],
-      ['email:session', session.id],
-      ['email:from', (session.envelope.mailFrom as SMTPServerAddress).address]
+      ["p", ndkUser.pubkey],
+      ["subject", parsedEmail.subject],
+      ["email:localIP", session.localAddress],
+      ["email:remoteIP", session.remoteAddress],
+      ["email:isEmail", "true"],
+      ["email:session", session.id],
+      ["email:from", (session.envelope.mailFrom as SMTPServerAddress).address],
     );
 
     for (const to of session.envelope.rcptTo) {
-      event.tags.push(['email:to', to.address]);
+      event.tags.push(["email:to", to.address]);
     }
 
     for (const header of Object.keys(parsedEmail.headers)) {
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 43362bc..257f4ca 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -1,15 +1,16 @@
 import NDK from "@nostr-dev-kit/ndk";
 import * as crypto from "node:crypto";
+import {decodeHex} from "@std/encoding/hex";
 
-export * from "./logs";
+export * from "./logs.ts";
+export * from "../models.ts";
 
 export function getNDK() {
   return new NDK({
     explicitRelayUrls: [
-      'wss://relay.primal.net',
-      'wss://relay.damus.io',
-      'wss://relay.nostr.band',
-      'wss://offchain.pub'
+      "wss://relay.primal.net",
+      "wss://relay.nostr.band",
+      "wss://offchain.pub",
     ],
     autoConnectUserRelays: false,
     enableOutboxModel: true,
@@ -27,9 +28,16 @@ export function getNDK() {
  * @param email - The email address.
  * @returns The nostr private key derived from the master key and email address as a uint8array.
  */
-export function deriveNsecForEmail(masterNsec: string, email: string): Uint8Array {
-  const masterNsecHash = crypto.createHash('sha256').update(masterNsec).digest('hex');
-  const emailHash = crypto.createHash('sha256').update(email).digest('hex');
-  const sharedSecret = crypto.createHash('sha256').update(masterNsecHash + emailHash).digest('hex');
-  return Uint8Array.from(Buffer.from(sharedSecret, 'hex'));
-}
\ No newline at end of file
+export function deriveNsecForEmail(
+  masterNsec: string,
+  email: string,
+): Uint8Array {
+  const masterNsecHash = crypto.createHash("sha256").update(masterNsec).digest(
+    "hex",
+  );
+  const emailHash = crypto.createHash("sha256").update(email).digest("hex");
+  const sharedSecret = crypto.createHash("sha256").update(
+    masterNsecHash + emailHash,
+  ).digest("hex");
+  return decodeHex(sharedSecret);
+}
diff --git a/src/utils/logs.ts b/src/utils/logs.ts
index 80c0465..e95a6c0 100644
--- a/src/utils/logs.ts
+++ b/src/utils/logs.ts
@@ -1,22 +1,22 @@
 import winston from "winston";
 
-const {combine, timestamp, printf, align, colorize, json} = winston.format;
+const { combine, timestamp, printf, align, colorize, json } = winston.format;
 
 export const logger = winston.createLogger({
-  level: 'info',
+  level: "info",
   transports: [
     new winston.transports.Console({
       format: combine(
-        colorize({all: true}),
+        colorize({ all: true }),
         timestamp({
-          format: 'YYYY-MM-DD hh:mm:ss.SSS A',
+          format: "YYYY-MM-DD hh:mm:ss.SSS A",
         }),
         align(),
-        printf((info) => `[${info.timestamp}] ${info.level}: ${info.message}`)
+        printf((info) => `[${info.timestamp}] ${info.level}: ${info.message}`),
       ),
     }),
     new winston.transports.File({
-      filename: process.env.LOG_FILE || '/tmp/nostr-email.log',
+      filename: Deno.env.get("LOG_FILE") || "/tmp/nostr-email.log",
       format: combine(timestamp(), json()),
     }),
   ],