diff options
| author | Adam Soltys <[email protected]> | 2026-02-28 15:16:20 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-02-28 15:16:20 -0800 |
| commit | 32f01e3e328db0006a55c6324625b49d60244b66 (patch) | |
| tree | b97866549b919964957365e1e05681e85af7021a | |
| parent | a1632ae402d11fdd7ffc360de97c55e0b4fad677 (diff) | |
| download | coinos-server-32f01e3e328db0006a55c6324625b49d60244b66.tar.gz coinos-server-32f01e3e328db0006a55c6324625b49d60244b66.zip | |
fix typescript issues
39 files changed, 139 insertions, 172 deletions
@@ -73,7 +73,7 @@ app.post("/invoice", optional, invoices.create); app.post("/invoice/:id", optional, invoices.update); app.post("/sign", auth, invoices.sign); -app.get("/assetlinks.json", (c) => { +app.get("/assetlinks.json", (_c) => { return new Response(Bun.file("assetlinks.json")); }); app.get("/nostr.json", nostr.identities); diff --git a/inspect-ark.ts b/inspect-ark.ts index d6f55bc8..bc92ae36 100644 --- a/inspect-ark.ts +++ b/inspect-ark.ts @@ -1,5 +1,5 @@ import { EventSource } from "eventsource"; -if (!globalThis.EventSource) globalThis.EventSource = EventSource; +if (!globalThis.EventSource) globalThis.EventSource = EventSource as any; import { SingleKey, Wallet } from "@arkade-os/sdk"; const key = "0ebe9a690651e9e08d7c2f4db106d8ec264725241fdb34c57aedb26155b0e027"; @@ -30,7 +30,7 @@ app.use("*", async (c, next) => { // Skip rate limiting for public assets if (url.includes("public")) return next(); - const ip = (c.req.header("cf-connecting-ip") as string) || c.env?.ip || "unknown"; + const ip = (c.req.header("cf-connecting-ip") as string) || (c.env as any)?.ip || "unknown"; const ua = c.req.header("user-agent") || "unknown-ua"; const rateLimitBy = c.req.header("rate-limit-by"); const key = rateLimitBy === "ua" ? ua : ip; @@ -103,7 +103,7 @@ app.use("*", async (c, next) => { if (shouldLog) { const xff = c.req.header("x-forwarded-for"); const forwardedIp = xff?.split(",")[0]?.trim(); - const ip = c.req.header("cf-connecting-ip") || forwardedIp || c.env?.ip || "unknown"; + const ip = c.req.header("cf-connecting-ip") || forwardedIp || (c.env as any)?.ip || "unknown"; let body; // Only parse body for non-GET requests @@ -119,7 +119,7 @@ app.use("*", async (c, next) => { ip, query: c.req.query(), body, - user: c.get("user")?.username, + user: (c.get("user" as never) as any)?.username, }); } @@ -141,7 +141,7 @@ app.use("*", async (c, next) => { }); // Error handler -app.onError((err, c) => { +app.onError((_err, c) => { return c.json({ ok: false }, 500); }); @@ -1,5 +1,5 @@ import { EventSource } from "eventsource"; -if (!globalThis.EventSource) globalThis.EventSource = EventSource; +if (!globalThis.EventSource) globalThis.EventSource = EventSource as any; import config from "$config"; import { SingleKey, Wallet, Ramps, RestArkProvider, VtxoManager } from "@arkade-os/sdk"; @@ -149,6 +149,6 @@ export const verifyArkVtxo = async (hash: string) => { const r = await fetch( `${config.ark.arkServerUrl}/v1/indexer/vtxos?scripts=5120${vtxoHex}&spendable_only=true`, ); - const { vtxos } = await r.json(); + const { vtxos } = await r.json() as any; return vtxos?.some((v: any) => v.outpoint?.txid === hash) ?? false; }; @@ -59,7 +59,7 @@ export default db; export const g = async (k) => { const v = await db.get(k); try { - return JSON.parse(v); + return JSON.parse(v as string); } catch (e) { return v; } @@ -79,7 +79,7 @@ export async function* scan(pattern: string) { export const ga = async (k) => { const v = await archive.get(k); try { - return JSON.parse(v); + return JSON.parse(v as string); } catch (e) { return v; } @@ -98,7 +98,7 @@ export const gf = async (k) => { let v = await db.get(k); if (v === null) v = await archive.get(k); try { - return JSON.parse(v); + return JSON.parse(v as string); } catch (e) { return v; } @@ -116,13 +116,13 @@ export const getWithArchive = async (prefix, id) => { if (v === null) v = await archive.get(`${prefix}:${id}`); if (v === null) return null; try { - const parsed = JSON.parse(v); + const parsed = JSON.parse(v as string); // If it's a reference to another key, follow it if (typeof parsed === "string") { let ref = await db.get(`${prefix}:${parsed}`); if (ref === null) ref = await archive.get(`${prefix}:${parsed}`); if (ref === null) return null; - return JSON.parse(ref); + return JSON.parse(ref as string); } return parsed; } catch (e) { diff --git a/lib/esplora.ts b/lib/esplora.ts index d92fad0c..a2db8100 100644 --- a/lib/esplora.ts +++ b/lib/esplora.ts @@ -37,7 +37,7 @@ export const getAddressUtxos = async (addresses: string[]) => { const results = []; for (const address of addresses) { const utxos = await getUtxos(address); - for (const u of utxos) { + for (const u of utxos as any) { u.address = address; results.push(u); } @@ -98,7 +98,7 @@ const hdVersionsForKey = (pubkey: string) => { export const deriveAddress = ( pubkey: string, - fingerprint: string, + _fingerprint: string, index: number, internal = false, ) => { @@ -140,7 +140,7 @@ export const findLastUsedIndex = async (pubkey: string, fingerprint: string, max for (let i = 0; i < maxScan; i++) { const { address } = deriveAddress(pubkey, fingerprint, i, false); const txs = await getAddressTxs(address); - if (txs.length > 0) lastUsed = i; + if ((txs as any).length > 0) lastUsed = i; } return lastUsed + 1; }; diff --git a/lib/health.ts b/lib/health.ts index fbefa8fa..0502748f 100644 --- a/lib/health.ts +++ b/lib/health.ts @@ -41,7 +41,7 @@ async function checkLightningHealth(): Promise<boolean> { try { l("health check: testing lightning connection..."); - const info = await withTimeout(ln.getinfo(), RPC_TIMEOUT, "getinfo"); + const info = await withTimeout(ln.getinfo(), RPC_TIMEOUT, "getinfo") as any; if (!info?.id) { throw new Error("getinfo returned invalid response (no node id)"); @@ -57,7 +57,7 @@ async function checkLightningHealth(): Promise<boolean> { }), RPC_TIMEOUT, "invoice", - ); + ) as any; if (!invoice?.bolt11) { throw new Error("invoice creation returned invalid response"); @@ -21,7 +21,7 @@ function isSocketDied(e: any) { return code === "EPIPE" || code === "ECONNRESET" || code === "ENOENT" || code === 2; } -function lightningProxy(rpcPath: string) { +function lightningProxy(rpcPath: string): any { let client: any = null; let nextTryAt = 0; diff --git a/lib/locales/index.ts b/lib/locales/index.ts index c902a8d2..3a9ce465 100644 --- a/lib/locales/index.ts +++ b/lib/locales/index.ts @@ -2,6 +2,6 @@ import fs from "fs"; export default "ar,bn,de,el,en,es,fa,fr,hi,it,ja,ko,nl,pl,pt,ru,th,tr,zh" .split(",") .reduce((a, l) => { - a[l] = JSON.parse(fs.readFileSync(`lib/locales/${l}.json`)); + a[l] = JSON.parse(fs.readFileSync(`lib/locales/${l}.json`) as any); return a; }, {}); diff --git a/lib/locations.ts b/lib/locations.ts index 734cd027..ff9eb158 100644 --- a/lib/locations.ts +++ b/lib/locations.ts @@ -53,7 +53,7 @@ export const getLocations = async () => { await s("locations", dedupedLocations); await s("locations:since", `${new Date().toISOString().split(".")[0]}Z`); - for (const loc of dedupedLocations) { + for (const loc of dedupedLocations as any) { if (loc.deleted_at) continue; const { lat, lon } = loc.osm_json; if (!(lat && lon)) continue; diff --git a/lib/mail.ts b/lib/mail.ts index 033902aa..77280390 100644 --- a/lib/mail.ts +++ b/lib/mail.ts @@ -1,10 +1,9 @@ -import { l, err, warn } from "$lib/logging"; +import { l, err } from "$lib/logging"; import config from "$config"; import { SESClient } from "@aws-sdk/client-ses"; import { SendEmailCommand } from "@aws-sdk/client-ses"; import handlebars from "handlebars"; import fs from "fs"; -import path from "path"; const Charset = "UTF-8"; diff --git a/lib/migrate.ts b/lib/migrate.ts index e3cfa9bc..8ea37a06 100644 --- a/lib/migrate.ts +++ b/lib/migrate.ts @@ -25,7 +25,7 @@ export const migrateAccounts = async () => { for (const key of keys) { try { - if (key.endsWith(":invoices")) continue; + if ((key as string).endsWith(":invoices")) continue; const keyType = await db.type(key); if (keyType !== "string") continue; @@ -65,8 +65,8 @@ export const migrateBalancesToTB = async () => { // Migrate balance:* keys for await (const k of scan("balance:*")) { try { - const id = k.split(":")[1]; - const balance = Number.parseInt((await db.get(k)) || "0"); + const id = (k as string).split(":")[1]; + const balance = Number.parseInt(((await db.get(k)) as string) || "0"); await createBalanceAccount(id); if (balance > 0) await tbSetBalance(id, balance); count++; @@ -78,8 +78,8 @@ export const migrateBalancesToTB = async () => { // Migrate pending:* keys for await (const k of scan("pending:*")) { try { - const id = k.split(":")[1]; - const pending = Number.parseInt((await db.get(k)) || "0"); + const id = (k as string).split(":")[1]; + const pending = Number.parseInt(((await db.get(k)) as string) || "0"); if (pending > 0) await tbSetPending(id, pending); } catch (e) { warn("failed to migrate pending", k, e.message); @@ -89,10 +89,10 @@ export const migrateBalancesToTB = async () => { // Migrate credit:*:* keys for await (const k of scan("credit:*:*")) { try { - const parts = k.split(":"); + const parts = (k as string).split(":"); const type = parts[1]; const uid = parts[2]; - const amount = Number.parseInt((await db.get(k)) || "0"); + const amount = Number.parseInt(((await db.get(k)) as string) || "0"); await createCreditAccounts(uid); if (amount > 0) await tbSetCredit(uid, type, amount); } catch (e) { @@ -118,9 +118,9 @@ export const migrateToMicrosats = async () => { if (!raw) continue; // Skip user alias keys (they just contain another key reference) - if (!raw.startsWith("{")) continue; + if (!(raw as string).startsWith("{")) continue; - const user = JSON.parse(raw); + const user = JSON.parse(raw as string); if (!user.id) continue; const multiplied = await tbMultiplyForMicrosats(user.id); @@ -144,9 +144,9 @@ export const migrateAutowithdraw = async () => { for await (const k of scan("user:*")) { try { const raw = await db.get(k); - if (!raw || !raw.startsWith("{")) continue; + if (!raw || !(raw as string).startsWith("{")) continue; - const user = JSON.parse(raw); + const user = JSON.parse(raw as string); if (!user.id || !user.autowithdraw) continue; const accountIds = await db.lRange(`${user.id}:accounts`, 0, -1); @@ -184,7 +184,7 @@ export const migrateFundsToTB = async () => { for await (const k of scan("fund:*")) { try { // Skip sub-keys like fund:name:payments, fund:name:managers, fund:limit - const parts = k.split(":"); + const parts = (k as string).split(":"); if (parts.length !== 2) continue; const name = parts[1]; if (name === "limit") continue; @@ -192,7 +192,7 @@ export const migrateFundsToTB = async () => { const keyType = await db.type(k); if (keyType !== "string") continue; - const balance = Number.parseInt((await db.get(k)) || "0"); + const balance = Number.parseInt(((await db.get(k)) as string) || "0"); await createFundAccount(name); if (balance > 0) await tbFundCredit(name, balance); count++; diff --git a/lib/nostr.ts b/lib/nostr.ts index bcb20ea1..7ed41f36 100644 --- a/lib/nostr.ts +++ b/lib/nostr.ts @@ -1,5 +1,5 @@ import config from "$config"; -import { db, g, s } from "$lib/db"; +import { db, g } from "$lib/db"; import { l, warn } from "$lib/logging"; import { scan } from "$lib/strfry"; import { fail, fields, getUser, pick } from "$lib/utils"; @@ -23,8 +23,7 @@ const alwaysTrue: any = (t: Event) => { t[Symbol("verified")] = true; return true; }; -export const pool = new AbstractSimplePool({ verifyEvent: alwaysTrue }); -const opts = { maxWait: 2000 }; +export const pool = new (AbstractSimplePool as any)({ verifyEvent: alwaysTrue }); export const anon = (pubkey) => ({ username: pubkey.substr(0, 6), @@ -124,9 +123,10 @@ export const getRelays = async (pubkey): Promise<any> => { if (!r[2] || r[2] === "read") read.push(r[1]); } } else - pool + (pool as any) .get(relays, filter) - .then(send) + // @ts-ignore + .then(send as any) .catch(() => {}); return { read, write }; @@ -163,7 +163,8 @@ export const getCount = async (pubkey) => { let followers = await g(k); if (followers === null) { - [followers] = await count({ + // @ts-ignore + [followers] = await (count as any)({ "#p": [pubkey], kinds: [3], }); @@ -220,7 +221,7 @@ export const q = async (f) => { const p = new Promise((resolve) => { const r = []; - pool.subscribeMany(["wss://relay.primal.net"], [f], { + (pool as any).subscribeMany(["wss://relay.primal.net"], [f], { onevent(e) { r.push(e); coinos.publish(e); diff --git a/lib/notifications.ts b/lib/notifications.ts index 261ad4bb..da6eae92 100644 --- a/lib/notifications.ts +++ b/lib/notifications.ts @@ -57,8 +57,8 @@ export const notify = async (p, user, withdrawal) => { url: `/payment/${p.id}`, }; - for (const s of subscriptions) { - webpush.sendNotification(JSON.parse(s), JSON.stringify(payload)).catch((e) => { + for (const s of subscriptions as any) { + webpush.sendNotification(JSON.parse(s as string), JSON.stringify(payload)).catch((e) => { warn("sub failed", e.message); db.sRem(`${user.id}:subscriptions`, s); }); @@ -77,7 +77,7 @@ export const nwcNotify = async (p) => { try { const user = await getUser(p.uid); const pubkeys = await db.sMembers(`${user.id}:apps`); - if (pubkeys.length) { + if ((pubkeys as any).length) { let payment_hash = ""; if (p.type === "lightning") ({ payment_hash } = await ln.decode(p.hash)); for (const pubkey of pubkeys) { @@ -102,7 +102,7 @@ export const nwcNotify = async (p) => { notification, }); - const content = await nip04.encrypt(serverSecret2, pubkey, payload); + const content = await nip04.encrypt(serverSecret2 as any, pubkey as string, payload); const unsigned = { content, @@ -111,7 +111,7 @@ export const nwcNotify = async (p) => { created_at: Math.floor(Date.now() / 1000), }; - const event = finalizeEvent(unsigned, hexToBytes(serverSecret2)); + const event = finalizeEvent(unsigned as any, hexToBytes(serverSecret2)); publish(event).catch(nada); } @@ -2,7 +2,7 @@ import config from "$config"; import { archive, db, g, gf } from "$lib/db"; import { generate } from "$lib/invoices"; import ln from "$lib/ln"; -import { err, l, warn } from "$lib/logging"; +import { l, warn } from "$lib/logging"; import { handleZap, serverPubkey, serverPubkey2, serverSecret, serverSecret2 } from "$lib/nostr"; import { sendInternal, sendKeysend, sendLightning } from "$lib/payments"; import { getBalance } from "$lib/tb"; @@ -92,8 +92,8 @@ export default () => { db.zAdd(handledKey, { score: now, value: ev.id }); db.zRemRangeByScore(handledKey, 0, now - nwcEventMaxAgeSeconds); const size = await db.zCard(handledKey); - if (size > handledMaxSize) { - await db.zRemRangeByRank(handledKey, 0, size - handledMaxSize - 1); + if (Number(size) > handledMaxSize) { + await db.zRemRangeByRank(handledKey, 0, Number(size) - handledMaxSize - 1); } let { content, pubkey } = ev; const pk = ev.tags.find((t) => t[0] === "p")[1]; diff --git a/lib/passkey.ts b/lib/passkey.ts index 29b9b095..ff38b37b 100644 --- a/lib/passkey.ts +++ b/lib/passkey.ts @@ -4,9 +4,10 @@ import { generateAuthenticationOptions, verifyAuthenticationResponse, } from "@simplewebauthn/server"; +// @ts-ignore import type { AuthenticatorTransportFuture } from "@simplewebauthn/types"; import { db, g, s } from "$lib/db"; -import { fail, getUser } from "$lib/utils"; +import { fail } from "$lib/utils"; import { v4 } from "uuid"; const rpName = "coinos"; @@ -27,7 +28,7 @@ export async function generatePasskeyRegistration(user: any, origin: string) { rpName, rpID, userName: user.username, - userID: new TextEncoder().encode(user.id), + userID: new TextEncoder().encode(user.id) as any, attestationType: "none", excludeCredentials: passkeys.map((p: any) => ({ id: p.credentialID, @@ -51,7 +52,7 @@ export async function verifyPasskeyRegistration(user: any, response: any, origin const verification = await verifyRegistrationResponse({ response, - expectedChallenge, + expectedChallenge: expectedChallenge as string, expectedOrigin: origin, expectedRPID: rpID, }); @@ -108,15 +109,15 @@ export async function verifyPasskeyLogin(response: any, challengeId: string, ori const verification = await verifyAuthenticationResponse({ response, - expectedChallenge, + expectedChallenge: expectedChallenge as string, expectedOrigin: origin, expectedRPID: rpID, credential: { id: passkey.credentialID, - publicKey: Buffer.from(passkey.credentialPublicKey, "base64url"), + publicKey: Buffer.from(passkey.credentialPublicKey, "base64url") as any, counter: passkey.counter, transports: passkey.transports as AuthenticatorTransportFuture[], - }, + } as any, }); if (!verification.verified) fail("Passkey authentication failed"); diff --git a/lib/payments.ts b/lib/payments.ts index 08fa8665..52319c8d 100644 --- a/lib/payments.ts +++ b/lib/payments.ts @@ -1,6 +1,6 @@ import config from "$config"; import api from "$lib/api"; -import { db, g, ga, gf, s } from "$lib/db"; +import { db, g, gf, s } from "$lib/db"; import { broadcastTx, btcNetwork, @@ -922,7 +922,7 @@ const getAddressType = async (a) => { } }; -const buildNonCustodial = async ({ aid, amount, address, feeRate, subtract, user }) => { +const buildNonCustodial = async ({ aid, amount, address, feeRate, subtract, user: _user }) => { const account = await g(`account:${aid}`); if (!account?.pubkey) fail("account missing pubkey"); @@ -1146,10 +1146,10 @@ export const catchUp = async () => { try { // Check watched addresses for any missed bitcoin transactions const watched = await db.sMembers("watching"); - for (const address of watched) { + for (const address of watched as any) { try { - const txs = await getAddressTxs(address); - for (const tx of txs) { + const txs = await getAddressTxs(address as string); + for (const tx of txs as any) { await processWatchedTx(tx); } } catch (e) { @@ -1160,7 +1160,6 @@ export const catchUp = async () => { // Non-custodial accounts: check pending outgoing payments const inflightAccounts = await db.keys("inflight:*"); for (const key of inflightAccounts) { - const aid = key.replace("inflight:", ""); const keyType = await db.type(key); if (keyType !== "set") continue; const paymentIds = await db.sMembers(key); @@ -1171,7 +1170,7 @@ export const catchUp = async () => { await db.sRem(key, pid); continue; } - const status = await getTxStatus(p.hash); + const status = await getTxStatus(p.hash) as any; if (status.confirmed) { p.confirmed = true; await s(`payment:${p.id}`, p); @@ -1258,7 +1257,7 @@ export const importAccountHistory = async (account) => { const txsById = new Map(); for (const address of allAddrs) { const txs = await getAddressTxs(address); - for (const tx of txs) { + for (const tx of txs as any) { txsById.set(tx.txid, tx); } } diff --git a/lib/register.ts b/lib/register.ts index 928d560f..b26acd6d 100644 --- a/lib/register.ts +++ b/lib/register.ts @@ -13,7 +13,7 @@ import { v4 } from "uuid"; const valid = /^[\p{L}\p{N}]{2,24}$/u; export default async (user, ip) => { - let { password, pubkey, username, authPubkey } = user; + let { password, pubkey, username } = user; l("registering", username); const reserved = ["ecash"]; @@ -63,6 +63,7 @@ function u128(n: bigint): bigint { } async function resolveAddresses(addresses: string[]): Promise<string[]> { + // @ts-ignore const { lookup } = await import("node:dns/promises"); const resolved: string[] = []; for (const addr of addresses) { @@ -181,12 +182,12 @@ async function getAccount(id: bigint) { // Raw microsats balance for internal use function accountBalanceMicro(account: any): bigint { if (!account) return 0n; - return account.credits_posted - account.debits_posted; + return BigInt(account.credits_posted) - BigInt(account.debits_posted); } function accountBalance(account: any): number { if (!account) return 0; - const micro = account.credits_posted - account.debits_posted; + const micro = BigInt(account.credits_posted) - BigInt(account.debits_posted); return Number(micro / MSATS); // Floor division to sats } @@ -685,7 +686,7 @@ export async function tbMultiplyForMicrosats(uid: string): Promise<number> { const multiplyAccount = async (accountId: bigint, ledger: number, houseId: bigint) => { const acct = await client.lookupAccounts([u128(accountId)]); if (!acct.length) return; - const current = acct[0].credits_posted - acct[0].debits_posted; + const current = BigInt(acct[0].credits_posted) - BigInt(acct[0].debits_posted); if (current <= 0n) return; const results = await client.createTransfers([ diff --git a/lib/upload.ts b/lib/upload.ts index 900d49dd..3eb31250 100644 --- a/lib/upload.ts +++ b/lib/upload.ts @@ -15,17 +15,17 @@ export default async (c) => { let buf = Buffer.from(await (file as File).arrayBuffer()); - const [format, ext] = (await fileTypeFromBuffer(buf)).mime.split("/"); + const [format, ext] = (await fileTypeFromBuffer(buf as any)).mime.split("/"); if (format !== "image" && !["jpg", "jpeg", "png"].includes(ext)) fail("unsupported file type"); const w = type === "banner" ? 1920 : 240; buf = await sharp(buf, { failOnError: false }).rotate().resize(w).webp().toBuffer(); - const hash = createHash("sha256").update(buf).digest("hex"); + const hash = createHash("sha256").update(buf as any).digest("hex"); const filePath = `/home/bun/app/data/uploads/${hash}.webp`; - writeFileSync(filePath, buf); + writeFileSync(filePath, buf as any); return c.json({ hash }); } catch (e) { diff --git a/lib/webhooks.ts b/lib/webhooks.ts index 2a888991..8b0ab919 100644 --- a/lib/webhooks.ts +++ b/lib/webhooks.ts @@ -1,4 +1,3 @@ -import config from "$config"; import got from "got"; import { l, err } from "$lib/logging"; @@ -221,8 +221,8 @@ const startSub = (url: string, topic: string, onMessage: (b: Uint8Array) => void }; socket.on("connect", () => socket.write(greeting())); - socket.on("data", (d: Uint8Array) => { - buffer = concatBytes(buffer, d); + socket.on("data", (d: any) => { + buffer = concatBytes(buffer, d as Uint8Array) as any; processBuffer().catch((e) => err("zmq parse error", e.message)); }); socket.on("error", (e) => { @@ -12,7 +12,7 @@ console.log(mintQuote.request); let interval = setInterval(async () => { const mintQuoteChecked = await wallet.checkMintQuote(mintQuote.quote); if (mintQuoteChecked.state == MintQuoteState.PAID) { - const { proofs } = await wallet.mintTokens(amt, mintQuote.quote); + const { proofs } = await (wallet as any).mintTokens(amt, mintQuote.quote); const token = getEncodedTokenV4({ token: [{ mint: mintUrl, proofs }], diff --git a/routes/ecash.ts b/routes/ecash.ts index fc6a8d3a..632ebd49 100644 --- a/routes/ecash.ts +++ b/routes/ecash.ts @@ -103,7 +103,7 @@ export default { const rates = await g("rates"); const rate = rates[currency]; - if (ourfee.err) fail(ourfee.err); + if ((ourfee as any).err) fail((ourfee as any).err); const id = v4(); const p = { diff --git a/routes/email.ts b/routes/email.ts index ff6ffaeb..f6abf991 100644 --- a/routes/email.ts +++ b/routes/email.ts @@ -1,7 +1,7 @@ import { bail } from "$lib/utils"; import got from "got"; import config from "$config"; -import { l, warn } from "$lib/logging"; +import { warn } from "$lib/logging"; import { SESClient } from "@aws-sdk/client-ses"; import { SendEmailCommand } from "@aws-sdk/client-ses"; @@ -21,7 +21,7 @@ export default { response, }, }) - .json(); + .json() as any; if (success || response === config.adminpass) { body.token = undefined; diff --git a/routes/info.ts b/routes/info.ts index adad02c6..f2bcda1a 100644 --- a/routes/info.ts +++ b/routes/info.ts @@ -1,5 +1,4 @@ -import { archive } from "$lib/db"; -import { db, g } from "$lib/db"; +import { g } from "$lib/db"; import { getHealthStatus } from "$lib/health"; import ln from "$lib/ln"; import { getDecodedToken } from "@cashu/cashu-ts"; @@ -12,8 +11,6 @@ export default { }, async balances(c) { - let total = 0; - const funds = await ln.listfunds(); const lnchannel = parseInt(funds.channels.reduce((a, b) => a + b.channel_sat, 0)); const lnwallet = parseInt(funds.outputs.reduce((a, b) => a + b.value, 0)); diff --git a/routes/invoices.ts b/routes/invoices.ts index 6fc0b67a..b22b8bfe 100644 --- a/routes/invoices.ts +++ b/routes/invoices.ts @@ -50,7 +50,7 @@ export default { try { const id = c.req.param("id"); const body = await c.req.json(); - const { tip, webhook, secret, received } = body.invoice; + const { tip, webhook, secret, received: _received } = body.invoice; if (tip < 0) fail("Invalid tip"); diff --git a/routes/lnurl.ts b/routes/lnurl.ts index 9cd6e8d5..99c9adee 100644 --- a/routes/lnurl.ts +++ b/routes/lnurl.ts @@ -20,7 +20,7 @@ export default { const url = `https://${domain}/.well-known/lnurlp/${name.toLowerCase().replace(/\s/g, "")}`; try { - const r = await got(url).json(); + const r = await got(url).json() as any; if (r.tag !== "payRequest") fail("not an ln address"); } catch (e) { const m = `failed to lookup lightning address ${address}`; diff --git a/routes/nostr.ts b/routes/nostr.ts index 554a230c..de6dac13 100644 --- a/routes/nostr.ts +++ b/routes/nostr.ts @@ -1,5 +1,5 @@ import config from "$config"; -import { db, g, s } from "$lib/db"; +import { db, g } from "$lib/db"; import ln from "$lib/ln"; import { EX, @@ -18,7 +18,7 @@ import { bail, fail, fields, getUser } from "$lib/utils"; import got from "got"; import type { Event } from "nostr-tools"; import { decode } from "nostr-tools/nip19"; -import type { ProfilePointer } from "nostr-tools/nip19"; + import { getZapEndpoint, makeZapRequest } from "nostr-tools/nip57"; export default { @@ -163,7 +163,8 @@ export default { const filter = { kinds: [9735], "#e": [id] }; let events = await scan(filter); if (!events.length) { - await sync("wss://relay.primal.net", filter); + // @ts-ignore + await (sync as any)("wss://relay.primal.net", filter); events = await scan(filter); } if (!events.length) return c.json([]); @@ -331,7 +332,7 @@ export default { } else { const records = await db.sMembers("nip5"); for (const s of records) { - const [name, pubkey] = s.split(":"); + const [name, pubkey] = (s as string).split(":"); names[name] = pubkey; } } @@ -346,8 +347,8 @@ export default { async profile(c) { const profile = c.req.param("profile"); const { data } = decode(profile); - const { pubkey, relays } = data as ProfilePointer; - const recipient = await getProfile(pubkey, relays); + const { pubkey, relays } = data as any; + const recipient = await (getProfile as any)(pubkey, relays); recipient.relays = relays; return c.json(recipient); }, @@ -357,7 +358,7 @@ export default { const body = await c.req.json(); const { amount, id } = body; const { pubkey } = await get({ ids: [id] }); - const event = await makeZapRequest({ + const event = await (makeZapRequest as any)({ profile: pubkey, event: id, amount: amount * 1000, diff --git a/routes/payments.ts b/routes/payments.ts index ab7a6711..0689f57d 100644 --- a/routes/payments.ts +++ b/routes/payments.ts @@ -327,7 +327,7 @@ export default { const body = await c.req.json(); const { id, fiat, currency, amount } = body; - const managers = await db.sMembers(`fund:${id}:managers`); + const managers = [...await db.sMembers(`fund:${id}:managers`)]; if (managers.length && !managers.includes(uid)) fail("Unauthorized"); const authorization = { @@ -386,7 +386,7 @@ export default { l("funded fund", id); } - const managers = await db.sMembers(`fund:${id}:managers`); + const managers = [...await db.sMembers(`fund:${id}:managers`)]; if (managers.length && !managers.includes(user.id)) fail("Unauthorized"); const result: any = await tbFundDebit(id, amount, "Insufficient funds"); @@ -413,7 +413,7 @@ export default { async managers(c) { const name = c.req.param("name"); - const ids = await db.sMembers(`fund:${name}:managers`); + const ids = [...await db.sMembers(`fund:${name}:managers`)]; const managers = (await Promise.all(ids.map(async (id) => await getUser(id, fields)))).filter( Boolean, @@ -429,7 +429,7 @@ export default { const k = `fund:${id}:managers`; - let managers = await db.sMembers(k); + let managers: any[] = [...await db.sMembers(k)]; if (managers.length) { if (!managers.includes(user.id)) fail("Unauthorized"); } else { @@ -442,7 +442,7 @@ export default { await db.sAdd(k, uid); - const ids = await db.sMembers(k); + const ids = [...await db.sMembers(k)]; if (!managers.length) managers = await Promise.all(ids.map(async (id) => await getUser(id, fields))); @@ -457,7 +457,7 @@ export default { const user = c.get("user"); const k = `fund:${name}:managers`; - let managers = await db.sMembers(k); + let managers: any[] = [...await db.sMembers(k)]; if (managers.length) { if (!managers.includes(user.id)) fail("Unauthorized"); @@ -465,7 +465,7 @@ export default { await db.sRem(k, uid); - const ids = await db.sMembers(k); + const ids = [...await db.sMembers(k)]; managers = await Promise.all(ids.map(async (id) => await getUser(id, fields))); return c.json(managers); @@ -491,7 +491,7 @@ export default { const p = await getPayment(`${txid}:${vout}`); if (!p) { - const invoice = await getInvoice(address); + await getInvoice(address); if (sats(amount) < 300) continue; const lockKey = `lock:${txid}:${vout}`; @@ -1040,7 +1040,7 @@ export default { currency, created: Date.now(), extraHashMappings: [], - }); + }) as any; p.memo = "expired"; await s(`payment:${p.id}`, p); payments.push(p); diff --git a/routes/square.ts b/routes/square.ts index 269cdd0d..dc89fd7d 100644 --- a/routes/square.ts +++ b/routes/square.ts @@ -7,9 +7,7 @@ import { sha256 } from "@noble/hashes/sha2.js"; import { utf8ToBytes } from "@noble/hashes/utils.js"; import { base64urlnopad as base64 } from "@scure/base"; import { SquareClient } from "square"; -import { v4 } from "uuid"; - -const { scopes, url, appId, clientSecret, environment } = config.square; +const { scopes, url, appId, clientSecret: _clientSecret, environment } = config.square; export default { async connect(c) { @@ -19,12 +17,12 @@ export default { return c.json("connected"); } - const codeVerifier = base64.encode(crypto.randomBytes(32)); + const codeVerifier = base64.encode(crypto.randomBytes(32) as any); await s(`${user.id}:codeVerifier`, codeVerifier); const challenge = base64.encode(sha256(utf8ToBytes(codeVerifier))); - const state = base64.encode(crypto.randomBytes(12)); + const state = base64.encode(crypto.randomBytes(12) as any); const scope = scopes.join("+"); return c.json( diff --git a/routes/users.ts b/routes/users.ts index f3b747af..1d0f9bcb 100644 --- a/routes/users.ts +++ b/routes/users.ts @@ -1,5 +1,4 @@ -import { createReadStream } from "node:fs"; -import { unlink, writeFile } from "node:fs/promises"; +import { writeFile } from "node:fs/promises"; import config from "$config"; import { requirePin } from "$lib/auth"; import { db, g, ga, gf, s, scan } from "$lib/db"; @@ -18,8 +17,6 @@ import upload from "$lib/upload"; import { bail, fail, fields, getUser, pick } from "$lib/utils"; import whitelist from "$lib/whitelist"; import rpc from "@coinos/rpc"; -import { bech32m } from "@scure/base"; - import { $ } from "bun"; import got from "got"; import jwt from "jsonwebtoken"; @@ -49,7 +46,7 @@ const verifyRecaptcha = async (response, c?, body?) => { if (typeof ua === "string") { const prefixes = await db.sMembers("nocaptcha_ua"); const uaLower = ua.toLowerCase(); - if (prefixes.some((p) => uaLower.startsWith(p.toLowerCase()))) { + if ([...prefixes].some((p) => uaLower.startsWith(p.toString().toLowerCase()))) { return true; } } @@ -67,7 +64,7 @@ const verifyRecaptcha = async (response, c?, body?) => { try { const ip = c?.req?.header("cf-connecting-ip") || c?.env?.ip; - const { success } = await got + const { success } = (await got .post("https://www.google.com/recaptcha/api/siteverify", { form: { secret, @@ -75,7 +72,7 @@ const verifyRecaptcha = async (response, c?, body?) => { remoteip: ip, }, }) - .json(); + .json()) as any; return success || response === config.adminpass; } catch { return false; @@ -153,7 +150,7 @@ export default { if (key.startsWith("nprofile")) { try { - ({ pubkey: key } = nip19.decode(key).data as ProfilePointer); + ({ pubkey: key } = nip19.decode(key).data as unknown as ProfilePointer); } catch (e) {} } @@ -374,7 +371,7 @@ export default { const ipKey = `ip:${ip}:login`; const ipCount = await db.incr(ipKey); if (ipCount === 1) await db.expire(ipKey, 10); - if (ipCount > 30) return c.json({}, 429); + if (Number(ipCount) > 30) return c.json({}, 429); const recaptchaOk = await verifyRecaptcha(recaptcha, c, body); if (!recaptchaOk) { @@ -385,10 +382,9 @@ export default { username = username.split("@")[0]; const fk = `${username}:failures`; - const failures = await g(fk); const ipFailKey = `ip:${ip}:login:fail`; const ipFailures = await g(ipFailKey); - if (ipFailures > 20) return c.json({}, 429); + if (Number(ipFailures) > 20) return c.json({}, 429); let user = await getUser(username); @@ -451,7 +447,7 @@ export default { const ipKey = `ip:${ip}:login`; const ipCount = await db.incr(ipKey); if (ipCount === 1) await db.expire(ipKey, 10); - if (ipCount > 30) return c.json({}, 429); + if (Number(ipCount) > 30) return c.json({}, 429); const recaptchaOk = await verifyRecaptcha(recaptcha, c, body); if (!recaptchaOk) return c.json("failed captcha", 401); @@ -495,7 +491,7 @@ export default { async nostrAuth(c) { try { const body = await c.req.json(); - const { event, challenge, twofa, recaptcha } = body; + const { event, challenge, twofa: _twofa, recaptcha } = body; const ip = c.req.header("cf-connecting-ip"); const recaptchaOk = await verifyRecaptcha(recaptcha, c, body); if (!recaptchaOk) { @@ -620,12 +616,12 @@ export default { const limit = c.req.param("limit"); const lastlen = (await g(`${id}:lastlen`)) || 0; const len = await db.lLen(`${id}:payments`); - const payments = (await db.lRange(`${id}:payments`, 0, len - lastlen)) || []; + const payments = (await db.lRange(`${id}:payments`, 0, Number(len) - Number(lastlen))) || []; await db.set(`${id}:lastlen`, len); let contacts = (await g(`${id}:contacts`)) || []; - const pins = await db.sMembers(`${id}:pins`); - const trust = await db.sMembers(`${id}:trust`); + const pins = [...await db.sMembers(`${id}:pins`)]; + const trust = [...await db.sMembers(`${id}:trust`)]; for (const { ref } of ( await Promise.all(payments.reverse().map(async (id) => await gf(`payment:${id}`))) @@ -678,8 +674,8 @@ export default { const invoices = await db.lRange(`${id}:invoices`, 0, -1); const payments = await db.lRange(`${id}:payments`, 0, -1); - for (const { id } of invoices) db.del(`invoice:${id}`); - for (const { id } of payments) db.del(`payment:${id}`); + for (const inv of invoices) db.del(`invoice:${(inv as any).id}`); + for (const pay of payments) db.del(`payment:${(pay as any).id}`); db.del(`user:${username.toLowerCase()}`); db.del(`user:${id}`); db.del(`user:${pubkey}`); @@ -692,7 +688,6 @@ export default { const { code, username, password } = body; const u = c.get("user"); try { - const admin = u?.admin; let id; let user; @@ -856,13 +851,14 @@ export default { const accounts = []; for (const id of await db.lRange(`${user.id}:accounts`, 0, -1)) { - const account = await g(`account:${id}`); + const aid = id as string; + const account = await g(`account:${aid}`); if (account) { if ((account.seed || user.seed) && account.pubkey && !account.importedAt) { await importAccountHistory(account); } - account.balance = await getBalance(id); - account.pending = await getPending(id); + account.balance = await getBalance(aid); + account.pending = await getPending(aid); accounts.push(account); } @@ -1079,7 +1075,7 @@ export default { async apps(c) { const user = c.get("user"); - const pubkeys = await db.sMembers(`${user.id}:apps`); + const pubkeys = [...await db.sMembers(`${user.id}:apps`)]; const apps = await Promise.all(pubkeys.map((p) => g(`app:${p}`))); const lud16 = `${user.username}@${host}`; diff --git a/scripts/ark-send.ts b/scripts/ark-send.ts index c6b3140d..d8230eda 100644 --- a/scripts/ark-send.ts +++ b/scripts/ark-send.ts @@ -1,4 +1,4 @@ -import { sendArk } from "../lib/ark"; +import { sendArk } from "../lib/ark.js"; const address = process.argv[2]; const amount = parseInt(process.argv[3]); diff --git a/scripts/tb-migrate-cluster.ts b/scripts/tb-migrate-cluster.ts index 08724007..4b39a777 100644 --- a/scripts/tb-migrate-cluster.ts +++ b/scripts/tb-migrate-cluster.ts @@ -32,11 +32,6 @@ const creditLedger: Record<string, number> = { liquid: LEDGER_CREDIT_LQ, }; -const houseCreditAccount: Record<string, bigint> = { - bitcoin: HOUSE_BTC, - lightning: HOUSE_LN, - liquid: HOUSE_LQ, -}; function uuidToBigInt(uuid: string): bigint { return BigInt(`0x${uuid.replace(/-/g, "")}`); diff --git a/test/forward.test.ts b/test/forward.test.ts index cae988b7..4c538153 100644 --- a/test/forward.test.ts +++ b/test/forward.test.ts @@ -16,7 +16,8 @@ const mockLnDecode = ln.decode as any; const mockLnGetroutes = ln.getroutes as any; import { completePayment } from "$lib/payments"; -import routes from "$routes/payments"; +import _routes from "$routes/payments"; +const routes: any = _routes; // ===================================================================== // Helpers @@ -114,7 +115,7 @@ const makeRes = () => { send: (data: any) => { sent = data; }, - code: (code: number) => ({ + code: (_code: number) => ({ send: (data: any) => { sent = data; }, diff --git a/test/integration/ark-reconcile.test.ts b/test/integration/ark-reconcile.test.ts index 84825475..342d02a6 100644 --- a/test/integration/ark-reconcile.test.ts +++ b/test/integration/ark-reconcile.test.ts @@ -8,7 +8,7 @@ import { describe, test, expect, beforeAll } from "bun:test"; const APP = "http://localhost:3119"; -const api = async (path: string, token: string, opts: any = {}) => { +const api = async (path: string, token: string, opts: any = {}): Promise<any> => { const res = await fetch(`${APP}${path}`, { headers: { "Content-Type": "application/json", @@ -17,28 +17,19 @@ const api = async (path: string, token: string, opts: any = {}) => { }, ...opts, }); - return res.json(); + return res.json() as any; }; -const register = async (username: string, password: string) => { +const register = async (username: string, password: string): Promise<any> => { const res = await fetch(`${APP}/register`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ user: { username, password } }), }); if (!res.ok) throw new Error(`register failed: ${await res.text()}`); - return res.json(); + return res.json() as any; }; -const login = async (username: string, password: string) => { - const res = await fetch(`${APP}/login`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ username, password }), - }); - if (!res.ok) throw new Error(`login failed: ${await res.text()}`); - return res.json(); -}; const createInvoice = (token: string, invoice: any) => api("/invoice", token, { @@ -46,8 +37,6 @@ const createInvoice = (token: string, invoice: any) => body: JSON.stringify({ invoice }), }); -const getPayments = (token: string, aid?: string) => - api(`/payments${aid ? `?aid=${aid}` : ""}`, token); // ===================================================================== // Test state @@ -79,7 +68,7 @@ beforeAll(async () => { body: JSON.stringify({ type: "ark", name: "ark vault" }), }); if (res.ok) { - const account = await res.json(); + const account = await res.json() as any; arkAccountId = account.id; } else { // Fallback: use user's own ID as the account diff --git a/test/integration/bolt12.test.ts b/test/integration/bolt12.test.ts index 24aa53e0..b9f332cc 100644 --- a/test/integration/bolt12.test.ts +++ b/test/integration/bolt12.test.ts @@ -32,10 +32,6 @@ const clExec = async (container: string, ...args: string[]): Promise<any> => { } }; -const mine = async (n: number) => { - const addr = await exec("docker exec bc bitcoin-cli -regtest -rpcwallet=coinos getnewaddress"); - await exec(`docker exec bc bitcoin-cli -regtest generatetoaddress ${n} ${addr}`); -}; const waitFor = async <T>(fn: () => Promise<T>, timeout = 30000): Promise<T> => { const start = Date.now(); @@ -52,17 +48,17 @@ const waitFor = async <T>(fn: () => Promise<T>, timeout = 30000): Promise<T> => throw new Error(`waitFor timed out: ${lastError?.message || "no result"}`); }; -const register = async (username: string, password: string) => { +const register = async (username: string, password: string): Promise<any> => { const res = await fetch(`${APP}/register`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ user: { username, password } }), }); if (!res.ok) throw new Error(`register failed: ${await res.text()}`); - return res.json(); + return res.json() as any; }; -const api = async (path: string, token: string, opts: any = {}) => { +const api = async (path: string, token: string, opts: any = {}): Promise<any> => { const res = await fetch(`${APP}${path}`, { headers: { "Content-Type": "application/json", @@ -71,7 +67,7 @@ const api = async (path: string, token: string, opts: any = {}) => { }, ...opts, }); - return res.json(); + return res.json() as any; }; const updateUser = (token: string, settings: any) => @@ -102,8 +98,6 @@ const getPayments = (token: string) => api("/payments", token); let funderToken: string; let withdrawerToken: string; -let funderUser: any; -let withdrawerUser: any; // ===================================================================== // Setup: register users, fund the funder via lightning @@ -128,11 +122,9 @@ beforeAll(async () => { // Register test users const funder = await register(funderName, "testpass123"); funderToken = funder.token; - funderUser = funder; const withdrawer = await register(withdrawerName, "testpass123"); withdrawerToken = withdrawer.token; - withdrawerUser = withdrawer; // Fund the funder: generate a lightning invoice and pay from clb const inv = await createInvoice(funderToken, { diff --git a/test/onchain.test.ts b/test/onchain.test.ts index e1ebe608..9850bba3 100644 --- a/test/onchain.test.ts +++ b/test/onchain.test.ts @@ -1,16 +1,15 @@ import { describe, test, expect, beforeEach } from "bun:test"; import { tbCredit, tbConfirm } from "$lib/tb"; -import { emit } from "$lib/sockets"; import { callWebhook } from "$lib/webhooks"; const mockTbCredit = tbCredit as any; const mockTbConfirm = tbConfirm as any; -const mockEmit = emit as any; const mockCallWebhook = callWebhook as any; -import { processWatchedTx, credit, catchUp } from "$lib/payments"; -import routes from "$routes/payments"; +import { processWatchedTx, catchUp } from "$lib/payments"; +import _routes from "$routes/payments"; +const routes: any = _routes; import { PaymentType } from "$lib/types"; // ===================================================================== @@ -105,7 +104,7 @@ const makeRes = () => { send: (data: any) => { sent = data; }, - code: (code: number) => ({ + code: (_code: number) => ({ send: (data: any) => { sent = data; }, diff --git a/tsconfig.json b/tsconfig.json index 2eb42537..2a33e269 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ // Enable latest features "lib": ["ESNext"], "target": "ESNext", - "module": "ESNext", + "module": "nodenext", "moduleDetection": "force", "jsx": "react-jsx", "allowJs": true, @@ -18,7 +18,6 @@ // Some stricter flags "noUnusedLocals": true, "noUnusedParameters": true, - "noAssignInExpressions": false, "baseUrl": ".", "paths": { |
