diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7da5ee14..42b02f52 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+# Current
+
+* Switch back to indexeddb to fix memory and performance
+* Add pay invoice functionality
+
# 1.5.3
* Add space edit form
diff --git a/package.json b/package.json
index c3623d9e..42bafec3 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,7 @@
"@capacitor/push-notifications": "^7.0.3",
"@capawesome/capacitor-android-dark-mode-support": "^7.0.0",
"@capawesome/capacitor-badge": "^7.0.1",
+ "@getalby/lightning-tools": "^6.0.0",
"@getalby/sdk": "^5.1.2",
"@poppanator/sveltekit-svg": "^4.2.1",
"@sentry/browser": "^8.55.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a5efe7e1..2b89cab2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -44,6 +44,9 @@ importers:
'@capawesome/capacitor-badge':
specifier: ^7.0.1
version: 7.0.1(@capacitor/core@7.4.3)
+ '@getalby/lightning-tools':
+ specifier: ^6.0.0
+ version: 6.0.0
'@getalby/sdk':
specifier: ^5.1.2
version: 5.1.2(typescript@5.9.3)
@@ -986,6 +989,10 @@ packages:
resolution: {integrity: sha512-dxOmJLJAh6qJ8rsbA5/Bwj7MSI9X3RkxxqmCedl5rfP+yKwNSdfu8i4EiCZN/tk2hNBJb8GHSCcPRNZfwfmEHg==}
engines: {node: '>=14'}
+ '@getalby/lightning-tools@6.0.0':
+ resolution: {integrity: sha512-jpTO+7o1N1KhV5qT6qetPK+et6ZQshCzUMCRV8+Ek1NVlVU4ITIqOWRQ3kOrb0PhSxkbGN5G3d60HCi535hbDw==}
+ engines: {node: '>=14'}
+
'@getalby/sdk@5.1.2':
resolution: {integrity: sha512-yUF9LhuvdIFOwjV1aG0ryzfwDiGBFk/CRLkRvrrM9dsE38SUjKsf1FDga5jxsKMu80nWcPZR9TiGGASWedoYPA==}
engines: {node: '>=14'}
@@ -5839,6 +5846,8 @@ snapshots:
'@getalby/lightning-tools@5.2.1': {}
+ '@getalby/lightning-tools@6.0.0': {}
+
'@getalby/sdk@5.1.2(typescript@5.9.3)':
dependencies:
'@getalby/lightning-tools': 5.2.1
diff --git a/src/app/components/WalletPay.svelte b/src/app/components/WalletPay.svelte
new file mode 100644
index 00000000..5ec3b964
--- /dev/null
+++ b/src/app/components/WalletPay.svelte
@@ -0,0 +1,111 @@
+
+
+
+
+ {#snippet title()}
+ Pay with Lightning
+ {/snippet}
+ {#snippet info()}
+ Use your Nostr wallet to send Bitcoin payments over lightning.
+ {/snippet}
+
+ {#if invoice}
+
+ {#if $session?.wallet?.type === "webln" && invoice.satoshi === 0}
+
+ Uh oh! It looks like your current wallet doesn't support invoices without an amount. See
+ if you can get a lightning invoice with a pre-set amount.
+
+ {:else}
+
+ {#snippet label()}
+ Amount (satoshis)
+ {/snippet}
+ {#snippet input()}
+
+
+
+ 0} />
+
+
+ {/snippet}
+
+
+ You're about to pay a bitcoin lightning invoice with the following description:
+ {invoice.description || "[no description]"} "
+
+ {/if}
+
+ {:else}
+
+
+ To make a payment, scan a lightning invoice with your camera.
+
+ {/if}
+
+
+
+ Go back
+
+
+ {#if loading}
+
+ {:else}
+
+ {/if}
+ Confirm Payment
+
+
+
diff --git a/src/app/core/commands.ts b/src/app/core/commands.ts
index d82241b0..5067d44f 100644
--- a/src/app/core/commands.ts
+++ b/src/app/core/commands.ts
@@ -592,7 +592,7 @@ export const publishLeaveRequest = (params: LeaveRequestParams) =>
export const getWebLn = () => (window as any).webln
-export const payInvoice = async (invoice: string) => {
+export const payInvoice = async (invoice: string, msats?: number) => {
const $session = session.get()
if (!$session?.wallet) {
@@ -600,8 +600,11 @@ export const payInvoice = async (invoice: string) => {
}
if ($session.wallet.type === "nwc") {
- return new nwc.NWCClient($session.wallet.info).payInvoice({invoice})
+ const params: {invoice: string; amount?: number} = {invoice}
+ if (msats) params.amount = msats
+ return new nwc.NWCClient($session.wallet.info).payInvoice(params)
} else if ($session.wallet.type === "webln") {
+ if (msats) throw new Error("Unable to pay zero invoices with webln")
return getWebLn()
.enable()
.then(() => getWebLn().sendPayment(invoice))
diff --git a/src/app/core/storage.ts b/src/app/core/storage.ts
index 44e22411..9c99b841 100644
--- a/src/app/core/storage.ts
+++ b/src/app/core/storage.ts
@@ -1,6 +1,6 @@
-import {reject, call, identity} from "@welshman/lib"
+import {call} from "@welshman/lib"
import {Preferences} from "@capacitor/preferences"
-import {Encoding, Filesystem, Directory} from "@capacitor/filesystem"
+import {Filesystem, Directory} from "@capacitor/filesystem"
import {IDB} from "@lib/indexeddb"
export const kv = call(() => {
diff --git a/src/app/util/storage.ts b/src/app/util/storage.ts
index 1e9efe83..4f5bfea1 100644
--- a/src/app/util/storage.ts
+++ b/src/app/util/storage.ts
@@ -1,4 +1,4 @@
-import {prop, call, on, throttle, fromPairs, batch} from "@welshman/lib"
+import {on, throttle, fromPairs, batch} from "@welshman/lib"
import {throttled, freshness} from "@welshman/store"
import {
ALERT_ANDROID,
diff --git a/src/lib/components/Scanner.svelte b/src/lib/components/Scanner.svelte
index 19d5e8bf..695eb2ea 100644
--- a/src/lib/components/Scanner.svelte
+++ b/src/lib/components/Scanner.svelte
@@ -5,11 +5,38 @@
const {onscan} = $props()
+ const changeCamera = async () => {
+ if (camera && scanner) {
+ loading = true
+ try {
+ await scanner.setCamera(camera)
+ } catch (error) {
+ console.error("Failed to switch camera:", error)
+ } finally {
+ loading = false
+ }
+ }
+ }
+
let video: HTMLVideoElement
let scanner: QrScanner
let loading = $state(true)
+ let cameras = $state([])
+ let camera = $state("")
onMount(() => {
+ QrScanner.listCameras(true)
+ .then(async () => {
+ cameras = await QrScanner.listCameras(true)
+
+ if (cameras.length > 0) {
+ camera = cameras[0].id
+ }
+ })
+ .catch(error => {
+ console.error("Failed to list cameras:", error)
+ })
+
scanner = new QrScanner(video, r => onscan(r.data), {
returnDetailedScanResult: true,
})
@@ -22,11 +49,21 @@
})
-
+
{#if loading}
Loading your camera...
{/if}
+ {#if cameras.length > 1}
+
+ {#each cameras as camera}
+ {camera.label || `Camera ${camera.id}`}
+ {/each}
+
+ {/if}
diff --git a/src/lib/indexeddb.ts b/src/lib/indexeddb.ts
index ce1efd81..2c434276 100644
--- a/src/lib/indexeddb.ts
+++ b/src/lib/indexeddb.ts
@@ -1,10 +1,8 @@
import {openDB, deleteDB} from "idb"
import type {IDBPDatabase} from "idb"
-import {writable} from "svelte/store"
import type {Unsubscriber} from "svelte/store"
-import {call, defer} from "@welshman/lib"
+import {call} from "@welshman/lib"
import type {Maybe} from "@welshman/lib"
-import {withGetter} from "@welshman/store"
export type IDBAdapter = {
name: string
@@ -83,11 +81,11 @@ export class IDB {
// If we're closing, ignore any lingering requests
if ([IDBStatus.Closed, IDBStatus.Closing].includes(this.status)) return
- return f(await this.idbp)
+ return f(await this.idbp!)
}
- getAll = async
(table: string): Promise =>
- this._withIDBP(async idbp => {
+ getAll = async (table: string): Promise => {
+ const result = await this._withIDBP(async idbp => {
const tx = idbp.transaction(table, "readwrite")
const store = tx.objectStore(table)
const result = await store.getAll()
@@ -97,6 +95,9 @@ export class IDB {
return result
})
+ return result || []
+ }
+
bulkPut = async (table: string, data: Iterable) =>
this._withIDBP(async idbp => {
const tx = idbp.transaction(table, "readwrite")
diff --git a/src/routes/settings/wallet/+page.svelte b/src/routes/settings/wallet/+page.svelte
index 12f05eed..4af6442a 100644
--- a/src/routes/settings/wallet/+page.svelte
+++ b/src/routes/settings/wallet/+page.svelte
@@ -3,8 +3,10 @@
import {LOCALE} from "@welshman/lib"
import {displayRelayUrl, isNWCWallet, fromMsats} from "@welshman/util"
import {session, pubkey, profilesByPubkey} from "@welshman/app"
+ import Bolt from "@assets/icons/bolt.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
+ import WalletPay from "@app/components/WalletPay.svelte"
import WalletConnect from "@app/components/WalletConnect.svelte"
import WalletDisconnect from "@app/components/WalletDisconnect.svelte"
import WalletUpdateReceivingAddress from "@app/components/WalletUpdateReceivingAddress.svelte"
@@ -27,6 +29,8 @@
const walletLud16 = $derived(
$session?.wallet && isNWCWallet($session.wallet) ? $session.wallet.info.lud16 : undefined,
)
+
+ const pay = () => pushModal(WalletPay)
@@ -118,4 +122,10 @@
{/if}
+
+
+
+ Pay With Lightning
+
+
diff --git a/vite.config.ts b/vite.config.ts
index 67ca6597..a6bcb04c 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -10,6 +10,15 @@ config({path: ".env.template"})
export default defineConfig({
server: {
port: 1847,
+ // host: "0.0.0.0",
+ // strictPort: true,
+ // allowedHosts: ["coracle-client.ngrok.io"],
+ // hmr: {
+ // protocol: "wss",
+ // host: "coracle-client.ngrok.io",
+ // clientPort: 443,
+ // },
+ // cors: true,
},
build: {
sourcemap: true,