aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-02-11 17:51:24 -0800
committerAdam Soltys <[email protected]>2026-02-11 17:51:24 -0800
commit13466248004327e9a026cb89f94926f9b060d1c1 (patch)
tree47b4972c33809ccdf866b043c92cd3e0ecf5dcd0 /src
parent3aa9ce1b5985397d7f568887ec6f881df13c1034 (diff)
downloadcoinos-ui-13466248004327e9a026cb89f94926f9b060d1c1.tar.gz
coinos-ui-13466248004327e9a026cb89f94926f9b060d1c1.zip
linting
Diffstat (limited to 'src')
-rw-r--r--src/app.css54
-rw-r--r--src/components/About.svelte3
-rw-r--r--src/components/Account.svelte53
-rw-r--r--src/components/Amount.svelte6
-rw-r--r--src/components/AppForm.svelte6
-rw-r--r--src/components/Avatar.svelte13
-rw-r--r--src/components/Balance.svelte7
-rw-r--r--src/components/DarkToggle.svelte5
-rw-r--r--src/components/FaqCard.svelte2
-rw-r--r--src/components/Footer.svelte7
-rw-r--r--src/components/HowItWorksCard.svelte6
-rw-r--r--src/components/ItemForm.svelte23
-rw-r--r--src/components/LandingHeader.svelte7
-rw-r--r--src/components/LandingHero.svelte8
-rw-r--r--src/components/LandingInfoCard.svelte2
-rw-r--r--src/components/Lnurlw.svelte5
-rw-r--r--src/components/LoadingSplash.svelte6
-rw-r--r--src/components/LocationsMap.svelte30
-rw-r--r--src/components/Menu.svelte3
-rw-r--r--src/components/Nostr.svelte9
-rw-r--r--src/components/Numpad.svelte14
-rw-r--r--src/components/Password.svelte4
-rw-r--r--src/components/Payments.svelte10
-rw-r--r--src/components/Pinpad.svelte8
-rw-r--r--src/components/SetAmount.svelte4
-rw-r--r--src/components/SetMemo.svelte4
-rw-r--r--src/components/SetType.svelte5
-rw-r--r--src/components/Slider.svelte1
-rw-r--r--src/components/Success.svelte12
-rw-r--r--src/components/Toggle.svelte2
-rw-r--r--src/components/WalletPass.svelte9
-rw-r--r--src/hooks.server.ts10
-rw-r--r--src/lib/ark.ts224
-rw-r--r--src/lib/bip21.ts74
-rw-r--r--src/lib/cache.ts3
-rw-r--r--src/lib/handler.ts16
-rw-r--r--src/lib/invoice.ts54
-rw-r--r--src/lib/locales.ts2
-rw-r--r--src/lib/nip01.ts26
-rw-r--r--src/lib/nip07.ts79
-rw-r--r--src/lib/nip11.ts18
-rw-r--r--src/lib/nip17.ts594
-rw-r--r--src/lib/nip40.ts18
-rw-r--r--src/lib/nip44.ts298
-rw-r--r--src/lib/nip51.ts113
-rw-r--r--src/lib/nostr.ts328
-rw-r--r--src/lib/parse.ts214
-rw-r--r--src/lib/passwordCache.ts77
-rw-r--r--src/lib/punks.ts128
-rw-r--r--src/lib/random.ts28
-rw-r--r--src/lib/rates.ts10
-rw-r--r--src/lib/samples.ts34
-rw-r--r--src/lib/settings.ts34
-rw-r--r--src/lib/socket.ts138
-rw-r--r--src/lib/store.ts110
-rw-r--r--src/lib/ticket.ts44
-rw-r--r--src/lib/tickets.ts100
-rw-r--r--src/lib/types.ts24
-rw-r--r--src/lib/upload.ts30
-rw-r--r--src/lib/utils.ts781
-rw-r--r--src/routes/(app)/+layout.server.ts104
-rw-r--r--src/routes/(app)/+layout.svelte11
-rw-r--r--src/routes/(app)/[username]/(profile)/+layout.server.ts8
-rw-r--r--src/routes/(app)/[username]/(profile)/+layout.svelte2
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.server.ts14
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.ts6
-rw-r--r--src/routes/(app)/[username]/(profile)/notes/+page.server.ts16
-rw-r--r--src/routes/(app)/[username]/+layout.server.ts30
-rw-r--r--src/routes/(app)/[username]/accepted/[text]/+page.server.ts8
-rw-r--r--src/routes/(app)/[username]/accepted/[text]/+page.svelte3
-rw-r--r--src/routes/(app)/[username]/accepted/[text]/raw/+server.ts20
-rw-r--r--src/routes/(app)/[username]/accepted/create/+page.svelte8
-rw-r--r--src/routes/(app)/[username]/receive/+page.server.js20
-rw-r--r--src/routes/(app)/account/+server.ts14
-rw-r--r--src/routes/(app)/account/[id]/+page.server.ts28
-rw-r--r--src/routes/(app)/account/[id]/+page.svelte1
-rw-r--r--src/routes/(app)/account/ark/+page.svelte42
-rw-r--r--src/routes/(app)/account/bitcoin/+page.svelte6
-rw-r--r--src/routes/(app)/account/cash/+page.svelte3
-rw-r--r--src/routes/(app)/account/new/+page.svelte8
-rw-r--r--src/routes/(app)/account/pass/+page.svelte7
-rw-r--r--src/routes/(app)/account/seed/+page.svelte3
-rw-r--r--src/routes/(app)/account/setup/+page.svelte6
-rw-r--r--src/routes/(app)/admin/+layout.server.ts22
-rw-r--r--src/routes/(app)/admin/+page.server.ts12
-rw-r--r--src/routes/(app)/apps/[pubkey]/+page.server.ts32
-rw-r--r--src/routes/(app)/apps/[pubkey]/payments/+page.server.ts4
-rw-r--r--src/routes/(app)/apps/new/+page.server.ts54
-rw-r--r--src/routes/(app)/contacts/+server.ts14
-rw-r--r--src/routes/(app)/disable2fa/+server.ts14
-rw-r--r--src/routes/(app)/dm/+page.svelte1028
-rw-r--r--src/routes/(app)/e/[id]/+page.server.ts16
-rw-r--r--src/routes/(app)/ecash/[id]/[...version]/+layout.server.ts34
-rw-r--r--src/routes/(app)/ecash/[id]/[...version]/+page.server.ts36
-rw-r--r--src/routes/(app)/ecash/[id]/[...version]/swap/+page.server.ts2
-rw-r--r--src/routes/(app)/ecash/mint/+server.ts4
-rw-r--r--src/routes/(app)/ecash/post/+server.ts14
-rw-r--r--src/routes/(app)/email/+server.ts4
-rw-r--r--src/routes/(app)/enable2fa/+server.ts6
-rw-r--r--src/routes/(app)/events/+server.ts14
-rw-r--r--src/routes/(app)/fund/[id]/+layout.server.ts14
-rw-r--r--src/routes/(app)/fund/[id]/+page.server.ts16
-rw-r--r--src/routes/(app)/fund/[id]/+page.svelte4
-rw-r--r--src/routes/(app)/fund/[id]/access/+page.server.ts24
-rw-r--r--src/routes/(app)/fund/[id]/authorize/[...amount]/+page.server.ts46
-rw-r--r--src/routes/(app)/fund/[id]/gift/+page.server.ts8
-rw-r--r--src/routes/(app)/fund/[id]/gift/+page.svelte3
-rw-r--r--src/routes/(app)/fund/[id]/sweep/[...amount]/+page.server.ts75
-rw-r--r--src/routes/(app)/fund/[id]/withdraw/+page.server.ts34
-rw-r--r--src/routes/(app)/fund/[id]/withdraw/+server.ts2
-rw-r--r--src/routes/(app)/funder/+page.svelte18
-rw-r--r--src/routes/(app)/invoice/+page.server.ts38
-rw-r--r--src/routes/(app)/invoice/+server.ts14
-rw-r--r--src/routes/(app)/invoice/[id]/+layout.server.ts66
-rw-r--r--src/routes/(app)/invoice/[id]/+page.server.ts2
-rw-r--r--src/routes/(app)/invoice/[id]/memo/+page.server.ts2
-rw-r--r--src/routes/(app)/invoice/[id]/tip/+page.server.ts84
-rw-r--r--src/routes/(app)/invoice/[id]/tip/+page.svelte6
-rw-r--r--src/routes/(app)/invoice/sent/+page.svelte3
-rw-r--r--src/routes/(app)/invoices/+page.server.ts4
-rw-r--r--src/routes/(app)/items/[id]/+page.server.ts24
-rw-r--r--src/routes/(app)/items/[id]/+page.svelte2
-rw-r--r--src/routes/(app)/items/create/+page.server.ts20
-rw-r--r--src/routes/(app)/items/create/+page.svelte2
-rw-r--r--src/routes/(app)/ln/[lnurl]/+page.server.ts176
-rw-r--r--src/routes/(app)/locations/+server.ts16
-rw-r--r--src/routes/(app)/logout/+page.server.ts24
-rw-r--r--src/routes/(app)/messages/+page.server.ts56
-rw-r--r--src/routes/(app)/messages/+page.svelte2
-rw-r--r--src/routes/(app)/messages/[recipient]/+page.server.ts32
-rw-r--r--src/routes/(app)/messages/[recipient]/+page.svelte12
-rw-r--r--src/routes/(app)/otpsecret/+server.ts18
-rw-r--r--src/routes/(app)/password/+server.ts4
-rw-r--r--src/routes/(app)/pay/[username]/[...amount]/+page.server.ts106
-rw-r--r--src/routes/(app)/payment/[id]/+page.server.ts6
-rw-r--r--src/routes/(app)/payment/[id]/bump/+server.ts14
-rw-r--r--src/routes/(app)/payment/[id]/plain/+page.server.ts4
-rw-r--r--src/routes/(app)/payment/[id]/plain/+page.svelte3
-rw-r--r--src/routes/(app)/payment/[id]/print/+server.ts4
-rw-r--r--src/routes/(app)/payments/[...page]/+page.server.ts46
-rw-r--r--src/routes/(app)/payments/[...page]/+server.ts20
-rw-r--r--src/routes/(app)/pin/+server.ts4
-rw-r--r--src/routes/(app)/pos/+page.server.ts36
-rw-r--r--src/routes/(app)/pos/+page.svelte73
-rw-r--r--src/routes/(app)/post/[...path]/+server.ts12
-rw-r--r--src/routes/(app)/printer/+page.server.ts24
-rw-r--r--src/routes/(app)/qr/[text]/+page.server.ts4
-rw-r--r--src/routes/(app)/qr/[text]/+page.svelte3
-rw-r--r--src/routes/(app)/qr/[text]/[icon]/+server.ts48
-rw-r--r--src/routes/(app)/qr/[text]/raw/+server.ts21
-rw-r--r--src/routes/(app)/qr/create/+page.svelte8
-rw-r--r--src/routes/(app)/receive/[...token]/+page.server.ts16
-rw-r--r--src/routes/(app)/receive/[...token]/+page.svelte15
-rw-r--r--src/routes/(app)/reset/+server.ts4
-rw-r--r--src/routes/(app)/reset/[code]/+page.server.ts44
-rw-r--r--src/routes/(app)/reset/[code]/+page.svelte6
-rw-r--r--src/routes/(app)/scan/[email protected]2
-rw-r--r--src/routes/(app)/scan/+page.svelte3
-rw-r--r--src/routes/(app)/send/+layout.server.ts4
-rw-r--r--src/routes/(app)/send/[...text]/+page.server.ts22
-rw-r--r--src/routes/(app)/send/[...text]/+page.svelte3
-rw-r--r--src/routes/(app)/send/ark/[address]/+layout.server.ts36
-rw-r--r--src/routes/(app)/send/ark/[address]/+page.server.ts10
-rw-r--r--src/routes/(app)/send/ark/[address]/+page.svelte6
-rw-r--r--src/routes/(app)/send/ark/[address]/[amount]/[...feeRate]/+page.server.ts81
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/+layout.server.ts34
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/+page.server.ts10
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/+page.svelte9
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.server.ts112
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte11
-rw-r--r--src/routes/(app)/send/fund/[...name]/[...amount]/+page.server.ts30
-rw-r--r--src/routes/(app)/send/invoice/[id]/+page.server.ts118
-rw-r--r--src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.server.ts90
-rw-r--r--src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.svelte25
-rw-r--r--src/routes/(app)/send/zap/[id]/[...amount]/+page.server.ts54
-rw-r--r--src/routes/(app)/send/zap/[id]/[...amount]/+page.svelte4
-rw-r--r--src/routes/(app)/sent/[id]/+page.server.ts6
-rw-r--r--src/routes/(app)/sent/[id]/+page.svelte9
-rw-r--r--src/routes/(app)/settings/+layout.server.ts14
-rw-r--r--src/routes/(app)/settings/+layout.svelte40
-rw-r--r--src/routes/(app)/settings/account/+page.server.ts8
-rw-r--r--src/routes/(app)/settings/account/+page.svelte3
-rw-r--r--src/routes/(app)/settings/nostr/+page.server.ts8
-rw-r--r--src/routes/(app)/settings/nostr/+page.svelte63
-rw-r--r--src/routes/(app)/settings/profile/+page.server.ts2
-rw-r--r--src/routes/(app)/settings/profile/+page.svelte11
-rw-r--r--src/routes/(app)/settings/security/+page.server.ts2
-rw-r--r--src/routes/(app)/settings/security/+page.svelte19
-rw-r--r--src/routes/(app)/settings/shopify/+page.server.ts2
-rw-r--r--src/routes/(app)/settings/square/+page.server.ts20
-rw-r--r--src/routes/(app)/sign/+page.server.ts24
-rw-r--r--src/routes/(app)/subscription/+server.ts6
-rw-r--r--src/routes/(app)/subscription/delete/+server.ts6
-rw-r--r--src/routes/(app)/thread/[id]/+page.server.ts14
-rw-r--r--src/routes/(app)/verify/[code]/+page.server.ts15
-rw-r--r--src/routes/(app)/withdraw/+server.ts10
-rw-r--r--src/routes/(static)/+layout.server.ts24
-rw-r--r--src/routes/(static)/bounties/+page.server.ts78
-rw-r--r--src/routes/(static)/docs/+page.server.ts8
-rw-r--r--src/routes/(static)/docs/+page.svelte10
-rw-r--r--src/routes/(static)/forgot/+page.server.ts18
-rw-r--r--src/routes/(static)/forgot/+page.svelte3
-rw-r--r--src/routes/(static)/login/+page.server.ts115
-rw-r--r--src/routes/(static)/login/+page.svelte14
-rw-r--r--src/routes/(static)/login/[token]/+page.server.ts14
-rw-r--r--src/routes/(static)/register/+page.server.ts30
-rw-r--r--src/routes/(static)/register/+page.svelte16
-rw-r--r--src/routes/(static)/support/+page.svelte12
-rw-r--r--src/routes/+layout.server.ts102
-rw-r--r--src/routes/+layout.svelte19
-rw-r--r--src/routes/+layout.ts72
-rw-r--r--src/routes/+page.server.ts2
-rw-r--r--src/routes/about/+server.ts2
-rw-r--r--src/routes/amber/[id]/[pubkey]/+server.ts4
-rw-r--r--src/routes/map/+page.server.ts10
-rw-r--r--src/routes/map/+page.svelte3
-rw-r--r--src/routes/phtest/+page.svelte4
-rw-r--r--src/routes/start/+server.ts14
-rw-r--r--src/routes/test/ark/send/+server.ts104
-rw-r--r--src/service-worker.js58
220 files changed, 4603 insertions, 4066 deletions
diff --git a/src/app.css b/src/app.css
index f310b65c..62997d50 100644
--- a/src/app.css
+++ b/src/app.css
@@ -6,21 +6,23 @@
/* 2) Register DaisyUI themes */
@plugin "daisyui" {
- themes: lofi --default, black --prefersdark;
+ themes:
+ lofi --default,
+ black --prefersdark;
}
@plugin "daisyui/theme" {
name: "lofi";
default: true;
- --gradient: #C3CFE2;
+ --gradient: #c3cfe2;
--color-error: #b91c1c;
}
@plugin "daisyui/theme" {
name: "black";
prefersdark: true;
- --gradient: #C3CFE2;
- --color-secondary: #CCC;
+ --gradient: #c3cfe2;
+ --color-secondary: #ccc;
--color-error: #f87171;
}
@@ -36,7 +38,8 @@
@font-face {
font-family: "PublicSans";
- src: url("/fonts/Public_Sans/static/PublicSans-Regular.ttf") format("truetype");
+ src: url("/fonts/Public_Sans/static/PublicSans-Regular.ttf")
+ format("truetype");
}
:root {
@@ -47,13 +50,22 @@
--toastBackground: #292929;
}
-html { font-family: PublicSans, sans-serif; }
+html {
+ font-family: PublicSans, sans-serif;
+}
-::selection { color: black; background: #eaf2ff; }
-:fullscreen { background-color: white; }
+::selection {
+ color: black;
+ background: #eaf2ff;
+}
+:fullscreen {
+ background-color: white;
+}
/* Note: @apply-ing DaisyUI component classes requires components reference */
-.input { @apply input-lg input-primary h-16 px-4; }
+.input {
+ @apply input-lg input-primary h-16 px-4;
+}
/* If you want to *turn* native inputs into DaisyUI inputs via @apply: */
input[type="text"],
@@ -65,14 +77,22 @@ input[type="url"],
input[type="tel"] {
@apply input input-lg input-primary h-16 px-4;
}
-textarea { @apply textarea textarea-lg textarea-primary py-4; }
-select { @apply select select-lg select-primary h-16 px-4; }
+textarea {
+ @apply textarea textarea-lg textarea-primary py-4;
+}
+select {
+ @apply select select-lg select-primary h-16 px-4;
+}
-input:not([type="range"]), textarea, select, .input {
+input:not([type="range"]),
+textarea,
+select,
+.input {
@apply rounded-2xl w-full;
}
-input.clean, textarea.clean {
+input.clean,
+textarea.clean {
border: none !important;
outline: none !important;
padding: 0 !important;
@@ -81,8 +101,12 @@ input.clean, textarea.clean {
box-shadow: none !important;
}
-button { cursor: pointer !important; }
-.btn { @apply rounded-2xl btn-lg btn-block outline-none h-16 cursor-pointer; }
+button {
+ cursor: pointer !important;
+}
+.btn {
+ @apply rounded-2xl btn-lg btn-block outline-none h-16 cursor-pointer;
+}
@layer components {
:where(input, textarea, select, .input, .textarea, .select) {
diff --git a/src/components/About.svelte b/src/components/About.svelte
index 5cc3603c..0c8be717 100644
--- a/src/components/About.svelte
+++ b/src/components/About.svelte
@@ -1,5 +1,6 @@
<script lang="ts">
- import { onMount } from "svelte"; import Image from "$comp/Image.svelte";
+ import { onMount } from "svelte";
+ import Image from "$comp/Image.svelte";
import { t } from "$lib/translations";
let team = [
diff --git a/src/components/Account.svelte b/src/components/Account.svelte
index d05addbe..c88c1118 100644
--- a/src/components/Account.svelte
+++ b/src/components/Account.svelte
@@ -4,7 +4,8 @@
import WalletPass from "$comp/WalletPass.svelte";
import { run } from "svelte/legacy";
import { onMount } from "svelte";
- import { goto } from "$app/navigation"; import Balance from "$comp/Balance.svelte";
+ import { goto } from "$app/navigation";
+ import Balance from "$comp/Balance.svelte";
import { t } from "$lib/translations";
import { versions } from "$lib/utils";
import { arkkey } from "$lib/ark";
@@ -44,15 +45,12 @@
$arkkey = hex.encode(decrypt(seed, cached) as Uint8Array);
} else if (user.seed) {
// Master seed: derive m/86'/0'/0'/0/0
- const [
- { HDKey },
- { entropyToMnemonic, mnemonicToSeed },
- { wordlist },
- ] = await Promise.all([
- import("@scure/bip32"),
- import("@scure/bip39"),
- import("@scure/bip39/wordlists/english.js"),
- ]);
+ const [{ HDKey }, { entropyToMnemonic, mnemonicToSeed }, { wordlist }] =
+ await Promise.all([
+ import("@scure/bip32"),
+ import("@scure/bip39"),
+ import("@scure/bip39/wordlists/english.js"),
+ ]);
let entropy = await decrypt(user.seed, cached);
let mnemonic = entropyToMnemonic(entropy, wordlist);
let s = await mnemonicToSeed(mnemonic, cached);
@@ -93,15 +91,12 @@
if (seed) {
$arkkey = hex.encode(decrypt(seed, password!) as Uint8Array);
} else if (user.seed) {
- const [
- { HDKey },
- { entropyToMnemonic, mnemonicToSeed },
- { wordlist },
- ] = await Promise.all([
- import("@scure/bip32"),
- import("@scure/bip39"),
- import("@scure/bip39/wordlists/english.js"),
- ]);
+ const [{ HDKey }, { entropyToMnemonic, mnemonicToSeed }, { wordlist }] =
+ await Promise.all([
+ import("@scure/bip32"),
+ import("@scure/bip39"),
+ import("@scure/bip39/wordlists/english.js"),
+ ]);
let entropy = await decrypt(user.seed, password!);
let mnemonic = entropyToMnemonic(entropy, wordlist);
let s = await mnemonicToSeed(mnemonic, password!);
@@ -164,10 +159,7 @@
alt="Ark"
/>
{:else if seed || (user.seed && fingerprint)}
- <iconify-icon
- noobserver
- icon="cryptocurrency-color:btc"
- width="32"
+ <iconify-icon noobserver icon="cryptocurrency-color:btc" width="32"
></iconify-icon>
{:else}
<img src="/images/icon.png" class="w-8 h-8" />
@@ -182,22 +174,23 @@
class="contents"
onclick={(e) => setAccount(e, "/invoice")}
>
- <button class="btn !w-auto flex-1 !bg-base-300" data-testid="account-receive">
+ <button
+ class="btn !w-auto flex-1 !bg-base-300"
+ data-testid="account-receive"
+ >
<iconify-icon
noobserver
icon="ph:hand-coins-bold"
width="32"
flip="horizontal"
></iconify-icon>
- <div class="my-auto hidden sm:block">{$t("user.dashboard.receive")}</div>
+ <div class="my-auto hidden sm:block">
+ {$t("user.dashboard.receive")}
+ </div>
</button>
</a>
- <a
- href={`/send`}
- class="contents"
- onclick={(e) => setAccount(e, "/send")}
- >
+ <a href={`/send`} class="contents" onclick={(e) => setAccount(e, "/send")}>
<button type="button" class="btn !w-auto flex-1 !bg-base-300">
<iconify-icon noobserver icon="ph:paper-plane-right-bold" width="32"
></iconify-icon>
diff --git a/src/components/Amount.svelte b/src/components/Amount.svelte
index 2587520a..8cfb9942 100644
--- a/src/components/Amount.svelte
+++ b/src/components/Amount.svelte
@@ -19,7 +19,6 @@
e.stopPropagation();
$fiat = !$fiat;
};
-
</script>
{#if typeof amount !== "undefined"}
@@ -35,10 +34,7 @@
aria-label="Toggle currency display"
>
{#if !canShowFiat}
- <iconify-icon
- noobserver
- icon={icon}
- class="text-yellow-300"
+ <iconify-icon noobserver {icon} class="text-yellow-300"
></iconify-icon>
{/if}
{#if canShowFiat}
diff --git a/src/components/AppForm.svelte b/src/components/AppForm.svelte
index 026e4aba..2f65372c 100644
--- a/src/components/AppForm.svelte
+++ b/src/components/AppForm.svelte
@@ -146,11 +146,7 @@
>{$t("accounts.secret")}</label
>
<div class="flex gap-1 items-center">
- <textarea
- rows={3}
- name="secret"
- bind:value={secret}
- class="grow"
+ <textarea rows={3} name="secret" bind:value={secret} class="grow"
></textarea>
<div class="space-y-2 w-24">
diff --git a/src/components/Avatar.svelte b/src/components/Avatar.svelte
index ca35fb35..c9bacf65 100644
--- a/src/components/Avatar.svelte
+++ b/src/components/Avatar.svelte
@@ -9,7 +9,12 @@
class?: string;
}
- let { user, size = 32, disabled = false, class: className = "" }: Props = $props();
+ let {
+ user,
+ size = 32,
+ disabled = false,
+ class: className = "",
+ }: Props = $props();
let s = $derived(size.toString());
let link = $derived(
@@ -23,7 +28,11 @@
let fallback = $derived(
`${base}/punks/` + punk(user?.pubkey || user?.id || "aa"),
);
- let tmp = $derived(($avatar as any)?.id && ($avatar as any).id === user?.id && ($avatar as any).src);
+ let tmp = $derived(
+ ($avatar as any)?.id &&
+ ($avatar as any).id === user?.id &&
+ ($avatar as any).src,
+ );
let src = $derived(tmp || profile || fallback);
</script>
diff --git a/src/components/Balance.svelte b/src/components/Balance.svelte
index b05d9ac5..41b55c7a 100644
--- a/src/components/Balance.svelte
+++ b/src/components/Balance.svelte
@@ -17,7 +17,12 @@
</script>
{#if show && user.haspin && $pin?.length !== 6}
- <Pin cancel={() => { show = false; return ""; }} />
+ <Pin
+ cancel={() => {
+ show = false;
+ return "";
+ }}
+ />
{/if}
<div>
diff --git a/src/components/DarkToggle.svelte b/src/components/DarkToggle.svelte
index fdc79110..ebeaf762 100644
--- a/src/components/DarkToggle.svelte
+++ b/src/components/DarkToggle.svelte
@@ -11,10 +11,11 @@
class="flex justify-center items-center hover:opacity-80 gap-2 font-bold"
onclick={dark}
>
- <iconify-icon noobserver
+ <iconify-icon
+ noobserver
icon={$theme === "dark" ? "ph:sun-bold" : "ph:moon-stars-bold"}
width="30"
-></iconify-icon>
+ ></iconify-icon>
{$t(`nav.${$theme === "dark" ? "light" : "dark"}`)}
</button>
diff --git a/src/components/FaqCard.svelte b/src/components/FaqCard.svelte
index a2d13bc8..c1739495 100644
--- a/src/components/FaqCard.svelte
+++ b/src/components/FaqCard.svelte
@@ -3,7 +3,7 @@
// this ID will be used to get the strings from the locale
// question is at faq.[questionID].question
-
+
interface Props {
// answer is at faq.[questionID].answer
questionID: any;
diff --git a/src/components/Footer.svelte b/src/components/Footer.svelte
index 27a57e55..92930300 100644
--- a/src/components/Footer.svelte
+++ b/src/components/Footer.svelte
@@ -73,5 +73,10 @@
</ul>
</div>
- <iconify-icon noobserver icon="coinos:shield" class="flex justify-center" width="96"></iconify-icon>
+ <iconify-icon
+ noobserver
+ icon="coinos:shield"
+ class="flex justify-center"
+ width="96"
+ ></iconify-icon>
</footer>
diff --git a/src/components/HowItWorksCard.svelte b/src/components/HowItWorksCard.svelte
index d69d7666..1012af46 100644
--- a/src/components/HowItWorksCard.svelte
+++ b/src/components/HowItWorksCard.svelte
@@ -1,9 +1,11 @@
-<script> import { t } from "$lib/translations";
+<script>
+ import { t } from "$lib/translations";
let { image, stepID } = $props();
</script>
<div class="space-y-5">
- <iconify-icon noobserver icon={image} class="mx-auto" width="128"></iconify-icon>
+ <iconify-icon noobserver icon={image} class="mx-auto" width="128"
+ ></iconify-icon>
<p class="text-2xl font-medium">{$t("howItWorks." + stepID + ".header")}</p>
<p class="text-secondary text-xl font-medium w-full md:w-2/3 mx-auto">
{$t("howItWorks." + stepID + ".description")}
diff --git a/src/components/ItemForm.svelte b/src/components/ItemForm.svelte
index d087e2bf..7215a239 100644
--- a/src/components/ItemForm.svelte
+++ b/src/components/ItemForm.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { preventDefault } from 'svelte/legacy';
+ import { preventDefault } from "svelte/legacy";
import { t } from "$lib/translations";
import { upload } from "$lib/upload";
@@ -8,12 +8,19 @@
import Spinner from "$comp/Spinner.svelte";
let { item = $bindable(), user } = $props();
- let fileInput: HTMLInputElement | undefined = $state(), formElement: HTMLFormElement | undefined = $state(), file: File, submitting = $state(), progress: any;
+ let fileInput: HTMLInputElement | undefined = $state(),
+ formElement: HTMLFormElement | undefined = $state(),
+ file: File,
+ submitting = $state(),
+ progress: any;
let select = () => fileInput!.click();
let src: string | undefined = $state();
let tooLarge: Record<string, boolean> = {};
- let handleFile = async ({ target }: { target: EventTarget | null }, type: string) => {
+ let handleFile = async (
+ { target }: { target: EventTarget | null },
+ type: string,
+ ) => {
tooLarge[type] = false;
file = (target as HTMLInputElement).files![0];
if (!file) return;
@@ -35,7 +42,9 @@
if (src) {
try {
- let { hash } = JSON.parse(await upload(file, "item", progress) as string);
+ let { hash } = JSON.parse(
+ (await upload(file, "item", progress)) as string,
+ );
data.set("image", hash);
@@ -107,11 +116,7 @@
onclick={select}
aria-label="Select image"
>
- <img
- {src}
- alt={item.name}
- class="object-cover w-full h-full"
- />
+ <img {src} alt={item.name} class="object-cover w-full h-full" />
</button>
{:else if item.image}
<button
diff --git a/src/components/LandingHeader.svelte b/src/components/LandingHeader.svelte
index 1a2af208..f1b6a2b4 100644
--- a/src/components/LandingHeader.svelte
+++ b/src/components/LandingHeader.svelte
@@ -7,7 +7,12 @@
import DarkToggle from "$comp/DarkToggle.svelte";
import LocaleSelector from "$comp/LocaleSelector.svelte";
- let { howItWorks = undefined, faq = undefined, about = undefined, user = undefined }: any = $props();
+ let {
+ howItWorks = undefined,
+ faq = undefined,
+ about = undefined,
+ user = undefined,
+ }: any = $props();
let showMobileMenu = $state(false);
let header = $state();
diff --git a/src/components/LandingHero.svelte b/src/components/LandingHero.svelte
index 2bd950da..42cc0695 100644
--- a/src/components/LandingHero.svelte
+++ b/src/components/LandingHero.svelte
@@ -1,6 +1,7 @@
<script lang="ts">
import { focus } from "$lib/utils";
- import { goto } from "$app/navigation"; import Image from "$comp/Image.svelte";
+ import { goto } from "$app/navigation";
+ import Image from "$comp/Image.svelte";
import { t } from "$lib/translations";
</script>
@@ -12,10 +13,11 @@
{$t("landing.header_before_icon")}
<span class="relative">
{$t("landing.header_with_icon")}
- <iconify-icon noobserver
+ <iconify-icon
+ noobserver
icon="coinos:rays"
class="absolute -top-16 left-5 md:left-8 lg:left-14 2xl:left-24"
-></iconify-icon>
+ ></iconify-icon>
</span>
{$t("landing.header_after_icon")}
</h1>
diff --git a/src/components/LandingInfoCard.svelte b/src/components/LandingInfoCard.svelte
index ca16a5a4..cb16c5dd 100644
--- a/src/components/LandingInfoCard.svelte
+++ b/src/components/LandingInfoCard.svelte
@@ -6,7 +6,7 @@
title,
description = undefined,
order = undefined,
- children
+ children,
} = $props();
</script>
diff --git a/src/components/Lnurlw.svelte b/src/components/Lnurlw.svelte
index ac79b101..006fda8b 100644
--- a/src/components/Lnurlw.svelte
+++ b/src/components/Lnurlw.svelte
@@ -89,7 +89,10 @@
disabled={submitting}
onkeydown={setMax}
>{#if $fiat}
- Max {f((Math.floor(maxWithdrawable / 1000) * rate) / sats, currency)}
+ Max {f(
+ (Math.floor(maxWithdrawable / 1000) * rate) / sats,
+ currency,
+ )}
{:else}
Max ⚡️{s(Math.floor(maxWithdrawable / 1000))}
{/if}</button
diff --git a/src/components/LoadingSplash.svelte b/src/components/LoadingSplash.svelte
index 8ed0429f..e629a494 100644
--- a/src/components/LoadingSplash.svelte
+++ b/src/components/LoadingSplash.svelte
@@ -1,4 +1,8 @@
<div class="flex justify-center items-center">
- <iconify-icon noobserver icon="coinos:logo" width="224" class="mt-[calc(50vh-72px)]"
+ <iconify-icon
+ noobserver
+ icon="coinos:logo"
+ width="224"
+ class="mt-[calc(50vh-72px)]"
></iconify-icon>
</div>
diff --git a/src/components/LocationsMap.svelte b/src/components/LocationsMap.svelte
index 26f32ee8..3ec50e38 100644
--- a/src/components/LocationsMap.svelte
+++ b/src/components/LocationsMap.svelte
@@ -181,21 +181,22 @@
maplibrePromise = new Promise((resolve, reject) => {
const existing = document.querySelector("script[data-maplibre]");
if (existing) {
- if ((window as any).maplibregl) return resolve((window as any).maplibregl);
- existing.addEventListener("load", () => resolve((window as any).maplibregl));
+ if ((window as any).maplibregl)
+ return resolve((window as any).maplibregl);
+ existing.addEventListener("load", () =>
+ resolve((window as any).maplibregl),
+ );
existing.addEventListener("error", reject);
return;
}
const css = document.createElement("link");
css.rel = "stylesheet";
- css.href =
- "https://unpkg.com/[email protected]/dist/maplibre-gl.css";
+ css.href = "https://unpkg.com/[email protected]/dist/maplibre-gl.css";
document.head.appendChild(css);
const script = document.createElement("script");
- script.src =
- "https://unpkg.com/[email protected]/dist/maplibre-gl.js";
+ script.src = "https://unpkg.com/[email protected]/dist/maplibre-gl.js";
script.async = true;
script.defer = true;
script.dataset.maplibre = "true";
@@ -299,11 +300,12 @@
></div>
<div class="absolute flex top-2 left-2 gap-2">
<button
- aria-label="Back"
+ aria-label="Back"
class="rounded-full border-2 border-black bg-base-100/80 w-16 h-16 flex items-center justify-center"
onclick={back}
>
- <iconify-icon noobserver icon="ph:arrow-left-bold" width="24"></iconify-icon>
+ <iconify-icon noobserver icon="ph:arrow-left-bold" width="24"
+ ></iconify-icon>
</button>
</div>
<div class="relative">
@@ -316,10 +318,12 @@
<div class="flex gap-1 absolute right-6 top-3">
{#if search}
<button type="button" onclick={clearSearch} aria-label="Clear">
- <iconify-icon noobserver icon="ph:x-bold" width="32"></iconify-icon>
+ <iconify-icon noobserver icon="ph:x-bold" width="32"
+ ></iconify-icon>
</button>
{:else}
- <iconify-icon noobserver icon="ph:search-bold" width="32"></iconify-icon>
+ <iconify-icon noobserver icon="ph:search-bold" width="32"
+ ></iconify-icon>
{/if}
</div>
</div>
@@ -350,9 +354,11 @@
aria-label={timeout ? "Resume map" : "Pause map"}
>
{#if timeout}
- <iconify-icon noobserver icon="ph:pause-bold" width="24"></iconify-icon>
+ <iconify-icon noobserver icon="ph:pause-bold" width="24"
+ ></iconify-icon>
{:else}
- <iconify-icon noobserver icon="ph:play-bold" width="24"></iconify-icon>
+ <iconify-icon noobserver icon="ph:play-bold" width="24"
+ ></iconify-icon>
{/if}
</button>
</div>
diff --git a/src/components/Menu.svelte b/src/components/Menu.svelte
index 7f04dff0..9b49a263 100644
--- a/src/components/Menu.svelte
+++ b/src/components/Menu.svelte
@@ -66,7 +66,8 @@
</ul>
<hr class="my-4" />
<a href="/?stay=true" aria-label="Coinos home"
- ><iconify-icon noobserver icon="coinos:logo" width="160"></iconify-icon></a
+ ><iconify-icon noobserver icon="coinos:logo" width="160"
+ ></iconify-icon></a
>
</div>
</OutClick>
diff --git a/src/components/Nostr.svelte b/src/components/Nostr.svelte
index e7fd0e58..74e85faf 100644
--- a/src/components/Nostr.svelte
+++ b/src/components/Nostr.svelte
@@ -32,9 +32,8 @@
let connectUrl: string | undefined = $state();
let nostrConnect = async () => {
const { Relay } = await import("nostr-tools/relay");
- const { nip04, generateSecretKey, getPublicKey } = await import(
- "nostr-tools"
- );
+ const { nip04, generateSecretKey, getPublicKey } =
+ await import("nostr-tools");
const { getConversationKey, decrypt } = await import("nostr-tools/nip44");
let connectionSecret = crypto.randomUUID();
@@ -119,9 +118,7 @@
</script>
{#if $eventToSign && !$signer?.ready}
- <div
- class="fixed inset-0 bg-base-100/90 overflow-y-auto h-full w-full z-50"
- >
+ <div class="fixed inset-0 bg-base-100/90 overflow-y-auto h-full w-full z-50">
<div
class="relative mx-auto mt-10 p-5 border w-96 shadow-lg rounded-md bg-base-100 space-y-5"
>
diff --git a/src/components/Numpad.svelte b/src/components/Numpad.svelte
index 6a9f3c6e..57e8dd24 100644
--- a/src/components/Numpad.svelte
+++ b/src/components/Numpad.svelte
@@ -77,14 +77,16 @@
if (fiat) {
const numericFiat =
parseFloat((fiatDigits || "0").replace(/\D/g, "")) / 100;
- amountFiat = isFinite(numericFiat) ? numericFiat.toFixed(2) : "0.00" as any;
+ amountFiat = isFinite(numericFiat)
+ ? numericFiat.toFixed(2)
+ : ("0.00" as any);
amount = numericFiat ? Math.round((numericFiat * sats) / rate) : 0;
} else {
// integer-only sats, already normalized
const a = parseInt((html || "0").replace(/[^\d]/g, "")) || 0;
amount = a || 0;
const fval = amount ? (amount * rate) / sats : 0;
- amountFiat = fval ? fval.toFixed(2) : "0.00" as any;
+ amountFiat = fval ? fval.toFixed(2) : ("0.00" as any);
}
};
@@ -211,7 +213,9 @@
element && (element.innerHTML = html);
} else {
// going -> fiat
- const cents = Math.round((parseFloat(String(amountFiat) || "0") || 0) * 100);
+ const cents = Math.round(
+ (parseFloat(String(amountFiat) || "0") || 0) * 100,
+ );
fiatDigits = Math.max(0, cents).toString();
fiat = true;
html = formatFiatFromDigits(fiatDigits, decimalChar);
@@ -255,7 +259,9 @@
onMount(() => {
fiat = $fiatStore;
if (fiat) {
- const cents = Math.round((parseFloat(String(amountFiat) || "0") || 0) * 100);
+ const cents = Math.round(
+ (parseFloat(String(amountFiat) || "0") || 0) * 100,
+ );
fiatDigits = Math.max(0, cents).toString();
html = formatFiatFromDigits(fiatDigits, decimalChar); // keep html in sync on mount
} else {
diff --git a/src/components/Password.svelte b/src/components/Password.svelte
index 02d65948..2c2319f6 100644
--- a/src/components/Password.svelte
+++ b/src/components/Password.svelte
@@ -23,9 +23,7 @@
};
</script>
-<div
- class="fixed inset-0 bg-base-100/90 overflow-y-auto h-full w-full z-50"
->
+<div class="fixed inset-0 bg-base-100/90 overflow-y-auto h-full w-full z-50">
<div
class="relative top-1/3 mx-auto p-5 border w-96 shadow-lg rounded-md bg-base-100 space-y-5"
>
diff --git a/src/components/Payments.svelte b/src/components/Payments.svelte
index ff3f0d19..046356ca 100644
--- a/src/components/Payments.svelte
+++ b/src/components/Payments.svelte
@@ -27,7 +27,9 @@
<div class="font-bold flex items-center">
<div class="flex items-center gap-1">
{#if $fiat}
- <div>{f(Math.abs(amount) * (p.rate / sats), p.currency, locale)}</div>
+ <div>
+ {f(Math.abs(amount) * (p.rate / sats), p.currency, locale)}
+ </div>
{:else}
<iconify-icon
noobserver
@@ -104,7 +106,11 @@
/>
</div>
{:else if p.type === types.ark}
- <img src="/images/ark.png" class="w-10 h-10 rounded-full object-cover" alt="Ark" />
+ <img
+ src="/images/ark.png"
+ class="w-10 h-10 rounded-full object-cover"
+ alt="Ark"
+ />
{/if}
<div class="my-auto">
diff --git a/src/components/Pinpad.svelte b/src/components/Pinpad.svelte
index 524e75f8..15dbc53e 100644
--- a/src/components/Pinpad.svelte
+++ b/src/components/Pinpad.svelte
@@ -1,5 +1,6 @@
<script lang="ts">
- import Left from "$comp/Left.svelte"; import { focus, post, warning } from "$lib/utils";
+ import Left from "$comp/Left.svelte";
+ import { focus, post, warning } from "$lib/utils";
import { t } from "$lib/translations";
let { v = $bindable(), cancel } = $props();
@@ -72,7 +73,10 @@
onclick={toggle}
aria-label={hide ? "Show PIN" : "Hide PIN"}
>
- <iconify-icon noobserver icon={hide ? "ph:eye-slash-bold" : "ph:eye-bold"} width="32"
+ <iconify-icon
+ noobserver
+ icon={hide ? "ph:eye-slash-bold" : "ph:eye-bold"}
+ width="32"
></iconify-icon></button
>
</label>
diff --git a/src/components/SetAmount.svelte b/src/components/SetAmount.svelte
index 8a1573bd..ce58e146 100644
--- a/src/components/SetAmount.svelte
+++ b/src/components/SetAmount.svelte
@@ -20,9 +20,7 @@
</script>
{#if settingAmount}
- <div
- class="fixed inset-0 bg-base-100/90 overflow-y-auto h-full w-full z-50"
- >
+ <div class="fixed inset-0 bg-base-100/90 overflow-y-auto h-full w-full z-50">
<div
class="relative mx-auto p-12 max-w-xl shadow-lg rounded-md bg-base-100 space-y-5"
>
diff --git a/src/components/SetMemo.svelte b/src/components/SetMemo.svelte
index 2c3fd617..54921f56 100644
--- a/src/components/SetMemo.svelte
+++ b/src/components/SetMemo.svelte
@@ -12,9 +12,7 @@
</script>
{#if settingMemo}
- <div
- class="fixed inset-0 bg-base-100/90 overflow-y-auto h-full w-full z-50"
- >
+ <div class="fixed inset-0 bg-base-100/90 overflow-y-auto h-full w-full z-50">
<div
class="relative mx-auto p-12 max-w-xl shadow-lg rounded-md bg-base-100 space-y-5"
>
diff --git a/src/components/SetType.svelte b/src/components/SetType.svelte
index 4734cb07..d06ca345 100644
--- a/src/components/SetType.svelte
+++ b/src/components/SetType.svelte
@@ -14,13 +14,10 @@
activeOnly = false,
t,
}: any = $props();
-
</script>
{#if settingType}
- <div
- class="fixed inset-0 bg-base-100/90 overflow-y-auto h-full w-full z-50"
- >
+ <div class="fixed inset-0 bg-base-100/90 overflow-y-auto h-full w-full z-50">
<div
class="relative mx-auto p-12 max-w-xl shadow-lg rounded-md bg-base-100 space-y-2"
>
diff --git a/src/components/Slider.svelte b/src/components/Slider.svelte
index 5b1573f7..846d32a6 100644
--- a/src/components/Slider.svelte
+++ b/src/components/Slider.svelte
@@ -18,4 +18,3 @@
class="range w-full"
oninput={handle}
/>
-
diff --git a/src/components/Success.svelte b/src/components/Success.svelte
index 6a0e8eae..ae54b6c1 100644
--- a/src/components/Success.svelte
+++ b/src/components/Success.svelte
@@ -2,7 +2,14 @@
import { browser } from "$app/environment";
import { scale } from "svelte/transition";
import Amount from "$comp/Amount.svelte";
- const { amount, tip = undefined, rate, currency, locale, title = "" }: any = $props();
+ const {
+ amount,
+ tip = undefined,
+ rate,
+ currency,
+ locale,
+ title = "",
+ }: any = $props();
let ConfettiComp: any = $state(null);
let loaded = $state(false);
@@ -57,7 +64,8 @@
</div>
</div>
- <iconify-icon noobserver
+ <iconify-icon
+ noobserver
icon="ph:check-fat-fill"
class="text-green-400"
width="160"
diff --git a/src/components/Toggle.svelte b/src/components/Toggle.svelte
index b8dc37f9..3f725d08 100644
--- a/src/components/Toggle.svelte
+++ b/src/components/Toggle.svelte
@@ -12,5 +12,5 @@
/>
<div
class="w-11 h-6 bg-gray-200 rounded-full peer dark:bg-gray-700 peer-focus:ring-4 peer-focus:ring-gray-300 dark:peer-focus:ring-gray-800 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-green-500"
-></div>
+ ></div>
</label>
diff --git a/src/components/WalletPass.svelte b/src/components/WalletPass.svelte
index f6d611d0..9e0b6cd2 100644
--- a/src/components/WalletPass.svelte
+++ b/src/components/WalletPass.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { preventDefault } from 'svelte/legacy';
+ import { preventDefault } from "svelte/legacy";
import { focus } from "$lib/utils";
import { t } from "$lib/translations";
@@ -23,9 +23,7 @@
};
</script>
-<div
- class="fixed inset-0 bg-gray-600/50 overflow-y-auto h-full w-full z-20"
->
+<div class="fixed inset-0 bg-gray-600/50 overflow-y-auto h-full w-full z-20">
<div
class="relative top-1/3 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white space-y-5"
>
@@ -75,7 +73,8 @@
id="rememberFor"
class="w-full"
value={rememberForMs}
- onchange={(e) => (rememberForMs = Number((e.target as HTMLSelectElement).value))}
+ onchange={(e) =>
+ (rememberForMs = Number((e.target as HTMLSelectElement).value))}
>
{#each rememberForOptions as option}
<option value={option.ms}>{option.label}</option>
diff --git a/src/hooks.server.ts b/src/hooks.server.ts
index bd9bbc01..780e62ad 100644
--- a/src/hooks.server.ts
+++ b/src/hooks.server.ts
@@ -5,10 +5,10 @@ import type { Handle } from "@sveltejs/kit";
setIpGetter(() => ipStore.getStore());
export const handle: Handle = async ({ event, resolve }) => {
- const ip =
- event.request.headers.get("cf-connecting-ip") ||
- event.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
- event.getClientAddress();
+ const ip =
+ event.request.headers.get("cf-connecting-ip") ||
+ event.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
+ event.getClientAddress();
- return ipStore.run(ip, () => resolve(event));
+ return ipStore.run(ip, () => resolve(event));
};
diff --git a/src/lib/ark.ts b/src/lib/ark.ts
index d045049e..51e378c3 100644
--- a/src/lib/ark.ts
+++ b/src/lib/ark.ts
@@ -4,8 +4,8 @@ import { post } from "$lib/utils";
import { get } from "svelte/store";
export const arkServerUrl = {
- bitcoin: "https://arkade.computer",
- regtest: "http://localhost:7070",
+ bitcoin: "https://arkade.computer",
+ regtest: "http://localhost:7070",
}[PUBLIC_COINOS_NETWORK || "regtest"];
export const arkkey = persistLocal("arkkey", "");
@@ -16,166 +16,166 @@ let walletInstance: any;
let walletKey: string | undefined;
export const getWallet = async () => {
- const key = get(arkkey);
- if (!key) {
- walletInstance = undefined;
- walletKey = undefined;
- return;
- }
- if (walletInstance && walletKey === key) return walletInstance;
+ const key = get(arkkey);
+ if (!key) {
+ walletInstance = undefined;
+ walletKey = undefined;
+ return;
+ }
+ if (walletInstance && walletKey === key) return walletInstance;
- const { SingleKey, Wallet } = await loadArkSdk();
- const identity = SingleKey.fromHex(key);
+ const { SingleKey, Wallet } = await loadArkSdk();
+ const identity = SingleKey.fromHex(key);
- walletInstance = await Wallet.create({
- identity,
- arkServerUrl,
- });
- walletKey = key;
- return walletInstance;
+ walletInstance = await Wallet.create({
+ identity,
+ arkServerUrl,
+ });
+ walletKey = key;
+ return walletInstance;
};
export const getAddress = async (): Promise<string> => {
- const wallet = await getWallet();
- return wallet.getAddress();
+ const wallet = await getWallet();
+ return wallet.getAddress();
};
export const getBalance = async (): Promise<{ available: number }> => {
- const wallet = await getWallet();
- return wallet.getBalance();
+ const wallet = await getWallet();
+ return wallet.getBalance();
};
export const getVtxos = async () => {
- const wallet = await getWallet();
- if (!wallet) return [];
- return wallet.getVtxos({ spendableOnly: false });
+ const wallet = await getWallet();
+ if (!wallet) return [];
+ return wallet.getVtxos({ spendableOnly: false });
};
export const syncTransactions = async (aid: string) => {
- const wallet = await getWallet();
- if (!wallet) return;
+ const wallet = await getWallet();
+ if (!wallet) return;
- const transactions: any[] = [];
+ const transactions: any[] = [];
- const history = await wallet.getTransactionHistory();
- const historyTxids = new Set<string>();
- console.log("arkSync: history", history.length, history);
+ const history = await wallet.getTransactionHistory();
+ const historyTxids = new Set<string>();
+ console.log("arkSync: history", history.length, history);
- for (const tx of history) {
- if (tx.key.arkTxid) historyTxids.add(tx.key.arkTxid);
- if (tx.key.commitmentTxid) historyTxids.add(tx.key.commitmentTxid);
- transactions.push({
- arkTxid: tx.key.arkTxid || null,
- commitmentTxid: tx.key.commitmentTxid || null,
- amount: tx.type === "RECEIVED" ? tx.amount : -tx.amount,
- settled: tx.settled,
- createdAt: tx.createdAt,
- });
- }
+ for (const tx of history) {
+ if (tx.key.arkTxid) historyTxids.add(tx.key.arkTxid);
+ if (tx.key.commitmentTxid) historyTxids.add(tx.key.commitmentTxid);
+ transactions.push({
+ arkTxid: tx.key.arkTxid || null,
+ commitmentTxid: tx.key.commitmentTxid || null,
+ amount: tx.type === "RECEIVED" ? tx.amount : -tx.amount,
+ settled: tx.settled,
+ createdAt: tx.createdAt,
+ });
+ }
- // Include preconfirmed VTXOs not yet in transaction history
- const vtxos = await wallet.getVtxos({ spendableOnly: false });
- console.log("arkSync: vtxos", vtxos.length, vtxos);
- for (const v of vtxos) {
- if (v.virtualStatus?.state !== "preconfirmed") continue;
- const id = v.arkTxId || v.txid;
- if (!id || historyTxids.has(id)) continue;
- historyTxids.add(id);
- transactions.push({
- arkTxid: v.arkTxId || null,
- commitmentTxid: v.txid || null,
- amount: Number(v.value),
- settled: false,
- createdAt: v.createdAt ? new Date(v.createdAt).getTime() : Date.now(),
- });
- }
+ // Include preconfirmed VTXOs not yet in transaction history
+ const vtxos = await wallet.getVtxos({ spendableOnly: false });
+ console.log("arkSync: vtxos", vtxos.length, vtxos);
+ for (const v of vtxos) {
+ if (v.virtualStatus?.state !== "preconfirmed") continue;
+ const id = v.arkTxId || v.txid;
+ if (!id || historyTxids.has(id)) continue;
+ historyTxids.add(id);
+ transactions.push({
+ arkTxid: v.arkTxId || null,
+ commitmentTxid: v.txid || null,
+ amount: Number(v.value),
+ settled: false,
+ createdAt: v.createdAt ? new Date(v.createdAt).getTime() : Date.now(),
+ });
+ }
- if (!transactions.length) return;
+ if (!transactions.length) return;
- return post("/post/ark/sync", { transactions, aid });
+ return post("/post/ark/sync", { transactions, aid });
};
export const vtxoKey = (v: { txid: string; vout: number }) =>
- `${v.txid}:${v.vout}`;
+ `${v.txid}:${v.vout}`;
export const getProcessedVtxos = (): Set<string> => {
- try {
- return new Set(
- JSON.parse(localStorage.getItem("processedArkVtxos") || "[]"),
- );
- } catch {
- return new Set();
- }
+ try {
+ return new Set(
+ JSON.parse(localStorage.getItem("processedArkVtxos") || "[]"),
+ );
+ } catch {
+ return new Set();
+ }
};
export const addProcessedVtxos = (keys: string[]) => {
- const processed = getProcessedVtxos();
- for (const k of keys) processed.add(k);
- const arr = [...processed].slice(-200);
- localStorage.setItem("processedArkVtxos", JSON.stringify(arr));
+ const processed = getProcessedVtxos();
+ for (const k of keys) processed.add(k);
+ const arr = [...processed].slice(-200);
+ localStorage.setItem("processedArkVtxos", JSON.stringify(arr));
};
// Flag to suppress notifyIncomingFunds during sends
export let arkSending = false;
export const sendArk = async (address: string, amount: number) => {
- const wallet = await getWallet();
- if (!wallet) throw new Error("Ark wallet not available");
+ const wallet = await getWallet();
+ if (!wallet) throw new Error("Ark wallet not available");
- // Suppress incoming notifications during send to prevent
- // change VTXOs from being credited as incoming payments
- arkSending = true;
+ // Suppress incoming notifications during send to prevent
+ // change VTXOs from being credited as incoming payments
+ arkSending = true;
- try {
- const txid = await wallet.sendBitcoin({ address, amount });
+ try {
+ const txid = await wallet.sendBitcoin({ address, amount });
- // Mark post-send VTXOs as processed so notifyIncomingFunds
- // ignores change VTXOs from this send
- const vtxos = await wallet.getVtxos({ spendableOnly: false });
- if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey));
+ // Mark post-send VTXOs as processed so notifyIncomingFunds
+ // ignores change VTXOs from this send
+ const vtxos = await wallet.getVtxos({ spendableOnly: false });
+ if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey));
- return txid;
- } finally {
- arkSending = false;
- }
+ return txid;
+ } finally {
+ arkSending = false;
+ }
};
export const sendArkViaForward = async ({
- serverArkAddress,
- amount,
- aid,
- forward,
- user,
+ serverArkAddress,
+ amount,
+ aid,
+ forward,
+ user,
}: {
- serverArkAddress: string;
- amount: number;
- aid: string;
- forward: string;
- user: any;
+ serverArkAddress: string;
+ amount: number;
+ aid: string;
+ forward: string;
+ user: any;
}) => {
- const txid = await sendArk(serverArkAddress, amount);
+ const txid = await sendArk(serverArkAddress, amount);
- await post("/post/ark/vault-send", { hash: txid, amount, aid });
+ await post("/post/ark/vault-send", { hash: txid, amount, aid });
- const inv = await post("/post/invoice", {
- invoice: { type: "ark", amount, forward, aid },
- user,
- });
+ const inv = await post("/post/invoice", {
+ invoice: { type: "ark", amount, forward, aid },
+ user,
+ });
- return post("/post/ark/receive", { amount, hash: txid, iid: inv.id });
+ return post("/post/ark/receive", { amount, hash: txid, iid: inv.id });
};
export const settle = async () => {
- const wallet = await getWallet();
- if (!wallet) return;
+ const wallet = await getWallet();
+ if (!wallet) return;
- const balance = await wallet.getBalance();
- if (!balance.preconfirmed) return;
+ const balance = await wallet.getBalance();
+ if (!balance.preconfirmed) return;
- await wallet.settle();
+ await wallet.settle();
- // Mark post-settle VTXOs as processed so notifyIncomingFunds
- // ignores renewed VTXOs (they get new txids after an Ark round)
- const vtxos = await wallet.getVtxos({ spendableOnly: false });
- if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey));
+ // Mark post-settle VTXOs as processed so notifyIncomingFunds
+ // ignores renewed VTXOs (they get new txids after an Ark round)
+ const vtxos = await wallet.getVtxos({ spendableOnly: false });
+ if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey));
};
diff --git a/src/lib/bip21.ts b/src/lib/bip21.ts
index 4689246e..842782a5 100644
--- a/src/lib/bip21.ts
+++ b/src/lib/bip21.ts
@@ -1,50 +1,50 @@
export function decode(uri, allowedSchemes = ["bitcoin", "liquidnetwork"]) {
- // Determine the scheme from the URI
- const split = uri.indexOf(":");
- if (split === -1) {
- throw new Error("Invalid URI: Missing scheme");
- }
+ // Determine the scheme from the URI
+ const split = uri.indexOf(":");
+ if (split === -1) {
+ throw new Error("Invalid URI: Missing scheme");
+ }
- const urnScheme = uri.slice(0, split).toLowerCase();
- if (!allowedSchemes.includes(urnScheme)) {
- throw new Error(`Invalid scheme: ${urnScheme}`);
- }
+ const urnScheme = uri.slice(0, split).toLowerCase();
+ if (!allowedSchemes.includes(urnScheme)) {
+ throw new Error(`Invalid scheme: ${urnScheme}`);
+ }
- // Extract address and query string
- const queryStart = uri.indexOf("?");
- const address = uri.slice(
- split + 1,
- queryStart === -1 ? undefined : queryStart,
- );
- const query = queryStart === -1 ? "" : uri.slice(queryStart + 1);
- const options = Object.fromEntries(new URLSearchParams(query));
+ // Extract address and query string
+ const queryStart = uri.indexOf("?");
+ const address = uri.slice(
+ split + 1,
+ queryStart === -1 ? undefined : queryStart,
+ );
+ const query = queryStart === -1 ? "" : uri.slice(queryStart + 1);
+ const options = Object.fromEntries(new URLSearchParams(query));
- if (options.amount) {
- const n = Number(options.amount);
- if (!Number.isFinite(n)) throw new Error("Invalid amount");
- if (n < 0) throw new Error("Invalid amount");
- }
+ if (options.amount) {
+ const n = Number(options.amount);
+ if (!Number.isFinite(n)) throw new Error("Invalid amount");
+ if (n < 0) throw new Error("Invalid amount");
+ }
- return { scheme: urnScheme, address, options };
+ return { scheme: urnScheme, address, options };
}
export function encode(
- address,
- options = { amount: "" },
- urnScheme = "bitcoin",
+ address,
+ options = { amount: "" },
+ urnScheme = "bitcoin",
) {
- if (!address || typeof address !== "string") {
- throw new TypeError("Invalid address");
- }
+ if (!address || typeof address !== "string") {
+ throw new TypeError("Invalid address");
+ }
- if (!["bitcoin", "liquidnetwork"].includes(urnScheme)) {
- throw new Error(`Unsupported scheme: ${urnScheme}`);
- }
+ if (!["bitcoin", "liquidnetwork"].includes(urnScheme)) {
+ throw new Error(`Unsupported scheme: ${urnScheme}`);
+ }
- const n = Number(options?.amount);
- if (!Number.isFinite(n)) throw new Error("Invalid amount");
- if (n < 0) throw new Error("Invalid amount");
+ const n = Number(options?.amount);
+ if (!Number.isFinite(n)) throw new Error("Invalid amount");
+ if (n < 0) throw new Error("Invalid amount");
- const query = new URLSearchParams(options).toString();
- return `${urnScheme}:${address}${query ? `?${query}` : ""}`;
+ const query = new URLSearchParams(options).toString();
+ return `${urnScheme}:${address}${query ? `?${query}` : ""}`;
}
diff --git a/src/lib/cache.ts b/src/lib/cache.ts
index 079c561b..064b4632 100644
--- a/src/lib/cache.ts
+++ b/src/lib/cache.ts
@@ -1,10 +1,9 @@
-
// src/lib/server/cache.ts
let cachedData: any = null;
async function fetchData() {
// Fetch data from your API
- const response = await fetch('https://api.example.com/data');
+ const response = await fetch("https://api.example.com/data");
cachedData = await response.json();
}
diff --git a/src/lib/handler.ts b/src/lib/handler.ts
index baca442d..559761f0 100644
--- a/src/lib/handler.ts
+++ b/src/lib/handler.ts
@@ -2,12 +2,12 @@ import { goto } from "$app/navigation";
import { applyAction } from "$app/forms";
export default (toggle) => () => {
- toggle();
- return async ({ result }) => {
- if (result.type === "redirect") {
- goto(result.location);
- } else {
- await applyAction(result);
- }
- };
+ toggle();
+ return async ({ result }) => {
+ if (result.type === "redirect") {
+ goto(result.location);
+ } else {
+ await applyAction(result);
+ }
+ };
};
diff --git a/src/lib/invoice.ts b/src/lib/invoice.ts
index 91a69d88..015f2837 100644
--- a/src/lib/invoice.ts
+++ b/src/lib/invoice.ts
@@ -3,37 +3,37 @@ import { auth, post } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export default async ({ cookies, request }) => {
- const form = await request.formData();
- const aid = form.get("aid") || cookies.get("aid");
+ const form = await request.formData();
+ const aid = form.get("aid") || cookies.get("aid");
- const amount = parseInt(form.get("amount"));
- const rates = await getRates();
+ const amount = parseInt(form.get("amount"));
+ const rates = await getRates();
- let invoice = {
- aid,
- amount,
- items: JSON.parse(form.get("items")),
- memo: form.get("memo"),
- memoPrompt: form.get("memoPrompt"),
- tip: form.get("tip") ?? null,
- type: form.get("type"),
- prompt: form.get("prompt") === "true",
- rate: parseFloat(form.get("rate")) || rates[form.get("currency")],
- id: undefined,
- };
+ let invoice = {
+ aid,
+ amount,
+ items: JSON.parse(form.get("items")),
+ memo: form.get("memo"),
+ memoPrompt: form.get("memoPrompt"),
+ tip: form.get("tip") ?? null,
+ type: form.get("type"),
+ prompt: form.get("prompt") === "true",
+ rate: parseFloat(form.get("rate")) || rates[form.get("currency")],
+ id: undefined,
+ };
- const user = {
- username: form.get("username"),
- currency: form.get("currency"),
- };
+ const user = {
+ username: form.get("username"),
+ currency: form.get("currency"),
+ };
- invoice = await post("/invoice", { invoice, user }, auth(cookies));
- const { id } = invoice;
+ invoice = await post("/invoice", { invoice, user }, auth(cookies));
+ const { id } = invoice;
- if (invoice.prompt && invoice.tip === null)
- redirect(307, `/invoice/${id}/tip`);
+ if (invoice.prompt && invoice.tip === null)
+ redirect(307, `/invoice/${id}/tip`);
- if (invoice.memoPrompt && !invoice.memo) {
- redirect(307, `/invoice/${id}/memo`);
- } else redirect(307, `/invoice/${id}`);
+ if (invoice.memoPrompt && !invoice.memo) {
+ redirect(307, `/invoice/${id}/memo`);
+ } else redirect(307, `/invoice/${id}`);
};
diff --git a/src/lib/locales.ts b/src/lib/locales.ts
index 282eac22..83e7a1bf 100644
--- a/src/lib/locales.ts
+++ b/src/lib/locales.ts
@@ -37,5 +37,5 @@ export default {
it,
nl,
th,
- pl
+ pl,
};
diff --git a/src/lib/nip01.ts b/src/lib/nip01.ts
index a5d3f4b5..b2718b6b 100644
--- a/src/lib/nip01.ts
+++ b/src/lib/nip01.ts
@@ -1,19 +1,21 @@
-import { PUBLIC_DM_RELAYS, PUBLIC_COINOS_RELAY } from '$env/static/public';
-const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(',');
-const USERINFO_RELAYS = [ ...DM_RELAYS_LIST, PUBLIC_COINOS_RELAY ];
+import { PUBLIC_DM_RELAYS, PUBLIC_COINOS_RELAY } from "$env/static/public";
+const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(",");
+const USERINFO_RELAYS = [...DM_RELAYS_LIST, PUBLIC_COINOS_RELAY];
-import { SimplePool } from 'nostr-tools/pool';
+import { SimplePool } from "nostr-tools/pool";
const pool = new SimplePool();
// Returns the content of the kind-0 event of the provided pubkey.
export const getNostrUserInfo = async (pubkey: string) => {
- const events = await pool.querySync(
- USERINFO_RELAYS, { kinds: [0], limit: 1, authors: [pubkey] }
- );
+ const events = await pool.querySync(USERINFO_RELAYS, {
+ kinds: [0],
+ limit: 1,
+ authors: [pubkey],
+ });
- if (events.length == 0) {
- return null;
- }
+ if (events.length == 0) {
+ return null;
+ }
- return JSON.parse(events[0].content);
-}
+ return JSON.parse(events[0].content);
+};
diff --git a/src/lib/nip07.ts b/src/lib/nip07.ts
index 85f68377..4b32512f 100644
--- a/src/lib/nip07.ts
+++ b/src/lib/nip07.ts
@@ -1,41 +1,52 @@
-import { bytesToHex } from '@noble/hashes/utils.js';
-import { finalizeEvent } from 'nostr-tools/pure';
-import { getPrivateKey } from '$lib/nostr';
-import * as libnip44 from '$lib/nip44';
-import { u } from '$lib/nip44';
+import { bytesToHex } from "@noble/hashes/utils.js";
+import { finalizeEvent } from "nostr-tools/pure";
+import { getPrivateKey } from "$lib/nostr";
+import * as libnip44 from "$lib/nip44";
+import { u } from "$lib/nip44";
// Signs an event using NIP-07 if available, otherwise getPrivateKey()
export const signEvent = async (event: any, user: any): Promise<any> => {
- if (await (window as any).nostr.getPublicKey() === user.pubkey) {
- return (window as any).nostr.signEvent(event);
- } else {
- const sk = await getPrivateKey(user);
- return finalizeEvent(event, sk);
- }
-}
+ if ((await (window as any).nostr.getPublicKey()) === user.pubkey) {
+ return (window as any).nostr.signEvent(event);
+ } else {
+ const sk = await getPrivateKey(user);
+ return finalizeEvent(event, sk);
+ }
+};
// Encrypts an event in NIP-44 using NIP-07 if available, otherwise getPrivateKey()
-export const encrypt = async (json: any, user: any, receiverPK: string): Promise<string> => {
- if (await (window as any).nostr.getPublicKey() === user.pubkey) {
- return (window as any).nostr.nip44.encrypt(
- receiverPK, JSON.stringify(json));
- } else {
- const senderSK = await getPrivateKey(user);
- const senderSKString = bytesToHex(senderSK);
- const ckey = u.getConversationKey(senderSKString, receiverPK);
- return libnip44.encrypt(JSON.stringify(json), ckey);
- }
-}
+export const encrypt = async (
+ json: any,
+ user: any,
+ receiverPK: string,
+): Promise<string> => {
+ if ((await (window as any).nostr.getPublicKey()) === user.pubkey) {
+ return (window as any).nostr.nip44.encrypt(
+ receiverPK,
+ JSON.stringify(json),
+ );
+ } else {
+ const senderSK = await getPrivateKey(user);
+ const senderSKString = bytesToHex(senderSK);
+ const ckey = u.getConversationKey(senderSKString, receiverPK);
+ return libnip44.encrypt(JSON.stringify(json), ckey);
+ }
+};
// Decrypts an event in NIP-44 using NIP-07 if available, otherwise getPrivateKey()
-export const decrypt = async (encrypted: string, user: any, receiverPK: string): Promise<any> => {
- if (await (window as any).nostr.getPublicKey() === user.pubkey) {
- return JSON.parse(await (window as any).nostr.nip44.decrypt(
- receiverPK, encrypted));
- } else {
- const senderSK = await getPrivateKey(user);
- const senderSKString = bytesToHex(senderSK);
- const ckey = u.getConversationKey(senderSKString, receiverPK);
- return JSON.parse(libnip44.decrypt(encrypted, ckey));
- }
-}
+export const decrypt = async (
+ encrypted: string,
+ user: any,
+ receiverPK: string,
+): Promise<any> => {
+ if ((await (window as any).nostr.getPublicKey()) === user.pubkey) {
+ return JSON.parse(
+ await (window as any).nostr.nip44.decrypt(receiverPK, encrypted),
+ );
+ } else {
+ const senderSK = await getPrivateKey(user);
+ const senderSKString = bytesToHex(senderSK);
+ const ckey = u.getConversationKey(senderSKString, receiverPK);
+ return JSON.parse(libnip44.decrypt(encrypted, ckey));
+ }
+};
diff --git a/src/lib/nip11.ts b/src/lib/nip11.ts
index af254b7e..6e827ccb 100644
--- a/src/lib/nip11.ts
+++ b/src/lib/nip11.ts
@@ -1,15 +1,15 @@
-import { fetchRelayInformation } from 'nostr-tools/nip11';
+import { fetchRelayInformation } from "nostr-tools/nip11";
// Accepts a list of relays, and returns a list of the relays that support all the provided NIPs.
export const relaysSupporting = async (relays: string[], nips: number[]) => {
- let supportingRelays = [];
+ let supportingRelays = [];
- for (const relay of relays) {
- const relayInfo = await fetchRelayInformation(relay);
- if (nips.every(relay => relayInfo.supported_nips.includes(relay))) {
- supportingRelays.push(relay);
- }
+ for (const relay of relays) {
+ const relayInfo = await fetchRelayInformation(relay);
+ if (nips.every((relay) => relayInfo.supported_nips.includes(relay))) {
+ supportingRelays.push(relay);
}
+ }
- return supportingRelays;
-}
+ return supportingRelays;
+};
diff --git a/src/lib/nip17.ts b/src/lib/nip17.ts
index b039ebf8..32a18bd8 100644
--- a/src/lib/nip17.ts
+++ b/src/lib/nip17.ts
@@ -1,84 +1,101 @@
-import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
-import { finalizeEvent, getEventHash, generateSecretKey, getPublicKey } from 'nostr-tools/pure';
-import { SimplePool } from 'nostr-tools/pool';
-import { Relay } from 'nostr-tools/relay';
-import { unwrapEvent } from 'nostr-tools/nip17';
+import {
+ finalizeEvent,
+ getEventHash,
+ generateSecretKey,
+ getPublicKey,
+} from "nostr-tools/pure";
+import { SimplePool } from "nostr-tools/pool";
+import { Relay } from "nostr-tools/relay";
+import { unwrapEvent } from "nostr-tools/nip17";
-import { relaysSupporting } from '$lib/nip11';
-import { expired, expiration } from '$lib/nip40';
-import { encrypt, u } from '$lib/nip44';
-import { eventToSign, signer } from '$lib/store';
-import { get } from 'svelte/store';
+import { relaysSupporting } from "$lib/nip11";
+import { expired, expiration } from "$lib/nip40";
+import { encrypt, u } from "$lib/nip44";
+import { eventToSign, signer } from "$lib/store";
+import { get } from "svelte/store";
const TWO_DAYS = 2 * 24 * 60 * 60;
-const randomTimestamp = () => Math.floor(
- Date.now() / 1000 - Math.random() * TWO_DAYS);
+const randomTimestamp = () =>
+ Math.floor(Date.now() / 1000 - Math.random() * TWO_DAYS);
const pool = new SimplePool();
let relayListCache = new Map();
-import { PUBLIC_DM_RELAYS } from '$env/static/public';
-const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(',');
+import { PUBLIC_DM_RELAYS } from "$env/static/public";
+const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(",");
const DM_FETCH_LIMIT = 256;
// Ensures we have access to a secret key, triggering the signer modal if needed.
// Returns the sk as Uint8Array, or null if using NIP-07 extension.
const ensureSigner = async (userPubkey: string): Promise<Uint8Array | null> => {
- // Check if NIP-07 extension is available and matches user
- if ((window as any).nostr) {
- try {
- const extPubkey = await (window as any).nostr.getPublicKey();
- if (extPubkey === userPubkey) {
- return null; // Use NIP-07
- }
- } catch (e) {
- // Extension didn't work, fall through to signer
- }
+ // Check if NIP-07 extension is available and matches user
+ if ((window as any).nostr) {
+ try {
+ const extPubkey = await (window as any).nostr.getPublicKey();
+ if (extPubkey === userPubkey) {
+ return null; // Use NIP-07
+ }
+ } catch {
+ // Extension didn't work, fall through to signer
}
+ }
- // Check if signer already has a valid sk (64 hex chars = 32 bytes)
- const currentSigner: any = get(signer);
- if (currentSigner?.ready && currentSigner?.params?.sk && currentSigner.params.sk.length === 64) {
- return hexToBytes(currentSigner.params.sk);
- }
+ // Check if signer already has a valid sk (64 hex chars = 32 bytes)
+ const currentSigner: any = get(signer);
+ if (
+ currentSigner?.ready &&
+ currentSigner?.params?.sk &&
+ currentSigner.params.sk.length === 64
+ ) {
+ return hexToBytes(currentSigner.params.sk);
+ }
- // Clear invalid signer state before triggering modal
- if (currentSigner?.ready && (!currentSigner?.params?.sk || currentSigner.params.sk.length !== 64)) {
- signer.set(undefined);
- }
+ // Clear invalid signer state before triggering modal
+ if (
+ currentSigner?.ready &&
+ (!currentSigner?.params?.sk || currentSigner.params.sk.length !== 64)
+ ) {
+ signer.set(undefined);
+ }
- // Trigger the signer modal with a dummy event
- const dummyEvent = { kind: 14, content: 'DM encryption', tags: [], created_at: Math.floor(Date.now() / 1000) };
- eventToSign.set(dummyEvent);
+ // Trigger the signer modal with a dummy event
+ const dummyEvent = {
+ kind: 14,
+ content: "DM encryption",
+ tags: [],
+ created_at: Math.floor(Date.now() / 1000),
+ };
+ eventToSign.set(dummyEvent);
- // Wait for signer to be ready
- const signerValue = await new Promise<any>((resolve, reject) => {
- let unsubscribe: () => void;
- unsubscribe = signer.subscribe((v: any) => {
- if (v === 'cancel') {
- setTimeout(() => unsubscribe?.());
- eventToSign.set(null);
- reject(new Error('cancelled'));
- }
- if (v?.ready) {
- setTimeout(() => unsubscribe?.());
- eventToSign.set(null);
- resolve(v);
- }
- });
+ // Wait for signer to be ready
+ const signerValue = await new Promise<any>((resolve, reject) => {
+ let unsubscribe: () => void;
+ unsubscribe = signer.subscribe((v: any) => {
+ if (v === "cancel") {
+ setTimeout(() => unsubscribe?.());
+ eventToSign.set(null);
+ reject(new Error("cancelled"));
+ }
+ if (v?.ready) {
+ setTimeout(() => unsubscribe?.());
+ eventToSign.set(null);
+ resolve(v);
+ }
});
+ });
- if (signerValue?.params?.sk) {
- return hexToBytes(signerValue.params.sk);
- }
+ if (signerValue?.params?.sk) {
+ return hexToBytes(signerValue.params.sk);
+ }
- // If extension method was selected
- if (signerValue?.method === 'extension') {
- return null; // Use NIP-07
- }
+ // If extension method was selected
+ if (signerValue?.method === "extension") {
+ return null; // Use NIP-07
+ }
- throw new Error('No signing method available');
-}
+ throw new Error("No signing method available");
+};
// Create a NIP-17 message using a provided sender secret key.
// If wrapPK is specified and different than receiverPK,
@@ -87,11 +104,22 @@ const ensureSigner = async (userPubkey: string): Promise<Uint8Array | null> => {
// If expiryDays is specified, the message will expire in that many days,
// plus a random amount from 0 to 2 for security.
// (expiration time = random creation time + expiryDays + 2 days)
-export const createNIP17MessageSK = (text: string, senderSK: Uint8Array, receiverPK: string, wrapPK: string | null = null, expiryDays: number | null = null) => {
- const rumour = createRumour(text, getPublicKey(senderSK), receiverPK);
- const sealed = sealRumourSK(rumour, senderSK, wrapPK || receiverPK, expiryDays);
- return giftWrap(sealed, wrapPK || receiverPK, expiryDays);
-}
+export const createNIP17MessageSK = (
+ text: string,
+ senderSK: Uint8Array,
+ receiverPK: string,
+ wrapPK: string | null = null,
+ expiryDays: number | null = null,
+) => {
+ const rumour = createRumour(text, getPublicKey(senderSK), receiverPK);
+ const sealed = sealRumourSK(
+ rumour,
+ senderSK,
+ wrapPK || receiverPK,
+ expiryDays,
+ );
+ return giftWrap(sealed, wrapPK || receiverPK, expiryDays);
+};
// Create a NIP-17 message using NIP-07, requiring no sender secret key.
// If wrapPK is specified and different than receiverPK,
@@ -100,241 +128,311 @@ export const createNIP17MessageSK = (text: string, senderSK: Uint8Array, receive
// If expiryDays is specified, the message will expire in that many days,
// plus a random amount from 0 to 2 for security.
// (expiration time = random creation time + expiryDays + 2 days)
-export const createNIP17MessageNIP07 = async (text: string, senderPK: string, receiverPK: string, wrapPK: string | null = null, expiryDays: number | null = null) => {
- const rumour = createRumour(text, senderPK, receiverPK);
- const sealed = await sealRumourNip07(rumour, wrapPK || receiverPK, expiryDays);
- return giftWrap(sealed, wrapPK || receiverPK, expiryDays);
-}
+export const createNIP17MessageNIP07 = async (
+ text: string,
+ senderPK: string,
+ receiverPK: string,
+ wrapPK: string | null = null,
+ expiryDays: number | null = null,
+) => {
+ const rumour = createRumour(text, senderPK, receiverPK);
+ const sealed = await sealRumourNip07(
+ rumour,
+ wrapPK || receiverPK,
+ expiryDays,
+ );
+ return giftWrap(sealed, wrapPK || receiverPK, expiryDays);
+};
const createRumour = (text: string, senderPK: string, receiverPK: string) => {
- const rumour: any = {
- kind: 14, // rumour
- created_at: Math.floor(Date.now() / 1000),
- tags: [["p", receiverPK]],
- pubkey: senderPK,
- content: text
- };
- rumour.id = getEventHash(rumour); // do NOT sign rumours!
- return rumour;
-}
+ const rumour: any = {
+ kind: 14, // rumour
+ created_at: Math.floor(Date.now() / 1000),
+ tags: [["p", receiverPK]],
+ pubkey: senderPK,
+ content: text,
+ };
+ rumour.id = getEventHash(rumour); // do NOT sign rumours!
+ return rumour;
+};
-const sealRumourSK = (rumour: any, senderSK: Uint8Array, receiverPK: string, expiryDays: number | null = null) => {
- const senderSKString = bytesToHex(senderSK);
- const conversationKey = u.getConversationKey(senderSKString, receiverPK);
- const encryptedRumour = encrypt(JSON.stringify(rumour), conversationKey);
+const sealRumourSK = (
+ rumour: any,
+ senderSK: Uint8Array,
+ receiverPK: string,
+ expiryDays: number | null = null,
+) => {
+ const senderSKString = bytesToHex(senderSK);
+ const conversationKey = u.getConversationKey(senderSKString, receiverPK);
+ const encryptedRumour = encrypt(JSON.stringify(rumour), conversationKey);
- const created = randomTimestamp();
- const sealEvent: any = {
- kind: 13, // seal
- created_at: created,
- tags: [],
- pubkey: getPublicKey(senderSK),
- content: encryptedRumour
- }
- if (expiryDays != null) {
- const expiration = created + (expiryDays + 2) * 86400;
- sealEvent.tags.push(["expiration", expiration.toString()]);
- }
+ const created = randomTimestamp();
+ const sealEvent: any = {
+ kind: 13, // seal
+ created_at: created,
+ tags: [],
+ pubkey: getPublicKey(senderSK),
+ content: encryptedRumour,
+ };
+ if (expiryDays != null) {
+ const expiration = created + (expiryDays + 2) * 86400;
+ sealEvent.tags.push(["expiration", expiration.toString()]);
+ }
- return finalizeEvent(sealEvent, senderSK);
-}
+ return finalizeEvent(sealEvent, senderSK);
+};
-const sealRumourNip07 = async (rumour: any, receiverPK: string, expiryDays: number | null = null) => {
- const encryptedRumour = await (window as any).nostr.nip44.encrypt(
- receiverPK, JSON.stringify(rumour));
+const sealRumourNip07 = async (
+ rumour: any,
+ receiverPK: string,
+ expiryDays: number | null = null,
+) => {
+ const encryptedRumour = await (window as any).nostr.nip44.encrypt(
+ receiverPK,
+ JSON.stringify(rumour),
+ );
- const created = randomTimestamp();
- const sealEvent: any = {
- kind: 13, // seal
- created_at: created,
- tags: [],
- content: encryptedRumour
- }
- if (expiryDays != null) {
- const expiration = created + (expiryDays + 2) * 86400;
- sealEvent.tags.push(["expiration", expiration.toString()]);
- }
+ const created = randomTimestamp();
+ const sealEvent: any = {
+ kind: 13, // seal
+ created_at: created,
+ tags: [],
+ content: encryptedRumour,
+ };
+ if (expiryDays != null) {
+ const expiration = created + (expiryDays + 2) * 86400;
+ sealEvent.tags.push(["expiration", expiration.toString()]);
+ }
- return (window as any).nostr.signEvent(sealEvent);
-}
+ return (window as any).nostr.signEvent(sealEvent);
+};
-const giftWrap = (event: any, receiverPK: string, expiryDays: number | null = null) => {
- const secretKey = generateSecretKey();
- const conversationKey = u.getConversationKey(bytesToHex(secretKey), receiverPK);
- const encryptedEvent = encrypt(JSON.stringify(event), conversationKey);
- const created = randomTimestamp();
+const giftWrap = (
+ event: any,
+ receiverPK: string,
+ expiryDays: number | null = null,
+) => {
+ const secretKey = generateSecretKey();
+ const conversationKey = u.getConversationKey(
+ bytesToHex(secretKey),
+ receiverPK,
+ );
+ const encryptedEvent = encrypt(JSON.stringify(event), conversationKey);
+ const created = randomTimestamp();
- const giftWrapEvent: any = {
- kind: 1059, // gift wrap
- created_at: created,
- tags: [["p", receiverPK]],
- pubkey: getPublicKey(secretKey),
- content: encryptedEvent
- }
- if (expiryDays != null) {
- const expiration = created + (expiryDays + 2) * 86400;
- giftWrapEvent.tags.push(["expiration", expiration.toString()]);
- }
+ const giftWrapEvent: any = {
+ kind: 1059, // gift wrap
+ created_at: created,
+ tags: [["p", receiverPK]],
+ pubkey: getPublicKey(secretKey),
+ content: encryptedEvent,
+ };
+ if (expiryDays != null) {
+ const expiration = created + (expiryDays + 2) * 86400;
+ giftWrapEvent.tags.push(["expiration", expiration.toString()]);
+ }
- return finalizeEvent(giftWrapEvent, secretKey);
-}
+ return finalizeEvent(giftWrapEvent, secretKey);
+};
const decryptNIP17MessageNIP07 = async (wrapped: any): Promise<any> => {
- const sealedText = await (window as any).nostr.nip44.decrypt(
- wrapped.pubkey, wrapped.content);
- const sealed = JSON.parse(sealedText);
- const rumourText = await (window as any).nostr.nip44.decrypt(
- sealed.pubkey, sealed.content);
- return JSON.parse(rumourText);
-}
+ const sealedText = await (window as any).nostr.nip44.decrypt(
+ wrapped.pubkey,
+ wrapped.content,
+ );
+ const sealed = JSON.parse(sealedText);
+ const rumourText = await (window as any).nostr.nip44.decrypt(
+ sealed.pubkey,
+ sealed.content,
+ );
+ return JSON.parse(rumourText);
+};
// Decrypts the provided message, addressed to the user.
// If NIP-07 is available, it uses that, otherwise it triggers the signer modal.
export const decrypt = async (wrapped: any, user: any): Promise<any> => {
- const sk = await ensureSigner(user.pubkey);
+ const sk = await ensureSigner(user.pubkey);
- if (sk === null) {
- return decryptNIP17MessageNIP07(wrapped);
- } else {
- return unwrapEvent(wrapped, sk);
- }
-}
+ if (sk === null) {
+ return decryptNIP17MessageNIP07(wrapped);
+ } else {
+ return unwrapEvent(wrapped, sk);
+ }
+};
// Returns the rumours of the messages the provided user has sent or received.
// If the events have an expiration timestamp,
// that timestamp is added to its rumour object as the property `expiration`.
export const getMessageRumours = async (user: any): Promise<any[]> => {
- const preferredRelays = await getPreferredRelays(user.pubkey);
- // Always include default relays to catch messages that might be there
- const relays = Array.from(new Set([...preferredRelays, ...DM_RELAYS_LIST]));
- const wrapped = await pool.querySync(
- relays, { kinds: [1059], "#p": [user.pubkey], limit: DM_FETCH_LIMIT }
- );
+ const preferredRelays = await getPreferredRelays(user.pubkey);
+ // Always include default relays to catch messages that might be there
+ const relays = Array.from(new Set([...preferredRelays, ...DM_RELAYS_LIST]));
+ const wrapped = await pool.querySync(relays, {
+ kinds: [1059],
+ "#p": [user.pubkey],
+ limit: DM_FETCH_LIMIT,
+ });
- let rumours: any[] = [];
- // intentionally decrypting sequentially to avoid having a bunch of popups
- for (const event of wrapped) {
- if (expired(event)) {
- console.log("relay(s) contain expired event", event.id);
- continue;
- }
+ let rumours: any[] = [];
+ // intentionally decrypting sequentially to avoid having a bunch of popups
+ for (const event of wrapped) {
+ if (expired(event)) {
+ console.log("relay(s) contain expired event", event.id);
+ continue;
+ }
- try {
- const rumour: any = await decrypt(event, user);
+ try {
+ const rumour: any = await decrypt(event, user);
- const expires = expiration(event);
- if (expires) {
- rumour.expiration = expires;
- }
+ const expires = expiration(event);
+ if (expires) {
+ rumour.expiration = expires;
+ }
- rumours.push(rumour);
- } catch (e) {
- console.error('Failed to decrypt event:', event.id, e);
- }
+ rumours.push(rumour);
+ } catch (e) {
+ console.error("Failed to decrypt event:", event.id, e);
}
+ }
- return rumours;
-}
+ return rumours;
+};
// Returns the preferred relays of the user with the provided pubkey,
// according to their kind-10050 event.
export const getPreferredRelays = async (pubkey: string): Promise<string[]> => {
- if (relayListCache.has(pubkey))
- return relayListCache.get(pubkey);
+ if (relayListCache.has(pubkey)) return relayListCache.get(pubkey);
- const events = await pool.querySync(
- DM_RELAYS_LIST, { kinds: [10050], limit: 1, authors: [pubkey] }
- );
+ const events = await pool.querySync(DM_RELAYS_LIST, {
+ kinds: [10050],
+ limit: 1,
+ authors: [pubkey],
+ });
- let relays: string[] = [];
- for (const event of events) {
- for (const tag of event.tags) {
- if (tag.length >= 2 && tag[0] == "relay") {
- relays.push(tag[1]);
- }
- }
+ let relays: string[] = [];
+ for (const event of events) {
+ for (const tag of event.tags) {
+ if (tag.length >= 2 && tag[0] == "relay") {
+ relays.push(tag[1]);
+ }
}
+ }
- // Fall back to default DM relays if user hasn't published their preferred relays
- if (relays.length === 0) {
- relays = DM_RELAYS_LIST;
- }
+ // Fall back to default DM relays if user hasn't published their preferred relays
+ if (relays.length === 0) {
+ relays = DM_RELAYS_LIST;
+ }
- relayListCache.set(pubkey, relays);
- return relays;
-}
+ relayListCache.set(pubkey, relays);
+ return relays;
+};
// Publish to a single relay with NIP-42 auth support
-const publishWithAuth = async (relayUrl: string, event: any, sk: Uint8Array | null): Promise<string> => {
- const relay = await Relay.connect(relayUrl);
+const publishWithAuth = async (
+ relayUrl: string,
+ event: any,
+ sk: Uint8Array | null,
+): Promise<string> => {
+ const relay = await Relay.connect(relayUrl);
- const signAuthEvent = async (authEvent: any) => {
- if (sk) {
- return finalizeEvent(authEvent, sk);
- } else if ((window as any).nostr) {
- return await (window as any).nostr.signEvent(authEvent);
- }
- throw new Error('No signing method for auth');
- };
+ const signAuthEvent = async (authEvent: any) => {
+ if (sk) {
+ return finalizeEvent(authEvent, sk);
+ } else if ((window as any).nostr) {
+ return await (window as any).nostr.signEvent(authEvent);
+ }
+ throw new Error("No signing method for auth");
+ };
- try {
- return await relay.publish(event);
- } catch (e: any) {
- // Check if it's an auth error
- if (e?.message?.includes('auth-required')) {
- // Authenticate and retry
- await relay.auth(signAuthEvent);
- return await relay.publish(event);
- }
- throw e;
+ try {
+ return await relay.publish(event);
+ } catch (e: any) {
+ // Check if it's an auth error
+ if (e?.message?.includes("auth-required")) {
+ // Authenticate and retry
+ await relay.auth(signAuthEvent);
+ return await relay.publish(event);
}
+ throw e;
+ }
};
// Store the current sk for use in publish
let currentSk: Uint8Array | null = null;
-const publishToPreferred = async (event: any, pubkey: string, expiryEnabled: boolean): Promise<string> => {
- let preferredRelays = await getPreferredRelays(pubkey);
- if (expiryEnabled) {
- preferredRelays = await relaysSupporting(preferredRelays, [40]);
- }
- if (preferredRelays.length === 0) {
- throw new Error('No relays available to publish to');
- }
+const publishToPreferred = async (
+ event: any,
+ pubkey: string,
+ expiryEnabled: boolean,
+): Promise<string> => {
+ let preferredRelays = await getPreferredRelays(pubkey);
+ if (expiryEnabled) {
+ preferredRelays = await relaysSupporting(preferredRelays, [40]);
+ }
+ if (preferredRelays.length === 0) {
+ throw new Error("No relays available to publish to");
+ }
- const promises = preferredRelays.map(url => publishWithAuth(url, event, currentSk));
- try {
- return await (Promise as any).any(promises);
- } catch (e) {
- const results = await Promise.allSettled(promises);
- console.error('All relay publishes failed:', results);
- throw e;
- }
-}
+ const promises = preferredRelays.map((url) =>
+ publishWithAuth(url, event, currentSk),
+ );
+ try {
+ return await (Promise as any).any(promises);
+ } catch (e) {
+ const results = await Promise.allSettled(promises);
+ console.error("All relay publishes failed:", results);
+ throw e;
+ }
+};
// Sends a NIP-17 message from `user` to `recipient`.
// If expiryDays is set, messages will expire after that many days.
-export const send = async (message: string, user: any, recipient: any, expiryDays?: number) => {
- let event1, event2;
- const sk = await ensureSigner(user.pubkey);
+export const send = async (
+ message: string,
+ user: any,
+ recipient: any,
+ expiryDays?: number,
+) => {
+ let event1, event2;
+ const sk = await ensureSigner(user.pubkey);
- // Store sk for auth handler
- currentSk = sk;
+ // Store sk for auth handler
+ currentSk = sk;
- if (sk === null) {
- // Use NIP-07 extension
- event1 = await createNIP17MessageNIP07(
- message, user.pubkey, recipient.pubkey, recipient.pubkey, expiryDays);
- event2 = await createNIP17MessageNIP07(
- message, user.pubkey, recipient.pubkey, user.pubkey, expiryDays);
- } else {
- event1 = createNIP17MessageSK(
- message, sk, recipient.pubkey, recipient.pubkey, expiryDays);
- event2 = createNIP17MessageSK(
- message, sk, recipient.pubkey, user.pubkey, expiryDays);
- }
+ if (sk === null) {
+ // Use NIP-07 extension
+ event1 = await createNIP17MessageNIP07(
+ message,
+ user.pubkey,
+ recipient.pubkey,
+ recipient.pubkey,
+ expiryDays,
+ );
+ event2 = await createNIP17MessageNIP07(
+ message,
+ user.pubkey,
+ recipient.pubkey,
+ user.pubkey,
+ expiryDays,
+ );
+ } else {
+ event1 = createNIP17MessageSK(
+ message,
+ sk,
+ recipient.pubkey,
+ recipient.pubkey,
+ expiryDays,
+ );
+ event2 = createNIP17MessageSK(
+ message,
+ sk,
+ recipient.pubkey,
+ user.pubkey,
+ expiryDays,
+ );
+ }
- const p1 = publishToPreferred(event1, recipient.pubkey, expiryDays != null);
- const p2 = publishToPreferred(event2, user.pubkey, expiryDays != null);
- return Promise.all([p1, p2]);
-}
+ const p1 = publishToPreferred(event1, recipient.pubkey, expiryDays != null);
+ const p2 = publishToPreferred(event2, user.pubkey, expiryDays != null);
+ return Promise.all([p1, p2]);
+};
diff --git a/src/lib/nip40.ts b/src/lib/nip40.ts
index 030fe0df..760a6680 100644
--- a/src/lib/nip40.ts
+++ b/src/lib/nip40.ts
@@ -1,16 +1,16 @@
// Returns true if the message has an expiration in the past, false otherwise.
export const expired = (event: object): boolean => {
- const expiryTime = expiration(event);
- return expiryTime !== null && Date.now() / 1000 >= expiryTime;
-}
+ const expiryTime = expiration(event);
+ return expiryTime !== null && Date.now() / 1000 >= expiryTime;
+};
// Returns the provided event's expiration time, as a Unix ms integer.
// If it has none, returns null.
export const expiration = (event: object): number | null => {
- for (const tag of event.tags) {
- if (tag[0] == "expiration") {
- return parseInt(tag[1]);
- }
+ for (const tag of event.tags) {
+ if (tag[0] == "expiration") {
+ return parseInt(tag[1]);
}
- return null;
-}
+ }
+ return null;
+};
diff --git a/src/lib/nip44.ts b/src/lib/nip44.ts
index bd7efdfc..e05fc685 100644
--- a/src/lib/nip44.ts
+++ b/src/lib/nip44.ts
@@ -1,135 +1,163 @@
-// Copied from this public-domain code:
-// https://github.com/paulmillr/nip44/blob/main/javascript/index.ts
-// Modified slightly to deal with a dependency issue
-
-import { chacha20 } from '@noble/ciphers/chacha.js';
-import { equalBytes } from '@noble/ciphers/utils.js';
-import { secp256k1 } from '@noble/curves/secp256k1.js';
-import { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js';
-import { hmac } from '@noble/hashes/hmac.js';
-import { sha256 } from '@noble/hashes/sha2.js';
-import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils.js';
-import { base64 } from '@scure/base';
-
-declare const TextDecoder: any;
-
-const decoder = new TextDecoder();
-export const u = {
- minPlaintextSize: 0x0001, // 1b msg => padded to 32b
- maxPlaintextSize: 0xffff, // 65535 (64kb-1) => padded to 64kb
-
- utf8Encode: utf8ToBytes,
- utf8Decode(bytes: Uint8Array) {
- return decoder.decode(bytes);
- },
-
- getConversationKey(privkeyA: string, pubkeyB: string): Uint8Array {
- const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33);
- return hkdf_extract(sha256, sharedX, 'nip44-v2');
- },
-
- getMessageKeys(conversationKey: Uint8Array, nonce: Uint8Array) {
- // ensureBytes(conversationKey, 32);
- // ensureBytes(nonce, 32);
- const keys = hkdf_expand(sha256, conversationKey, nonce, 76);
- return {
- chacha_key: keys.subarray(0, 32),
- chacha_nonce: keys.subarray(32, 44),
- hmac_key: keys.subarray(44, 76),
- };
- },
-
- calcPaddedLen(len: number): number {
- if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer');
- if (len <= 32) return 32;
- const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1);
- const chunk = nextPower <= 256 ? 32 : nextPower / 8;
- return chunk * (Math.floor((len - 1) / chunk) + 1);
- },
-
- writeU16BE(num: number) {
- if (!Number.isSafeInteger(num) || num < u.minPlaintextSize || num > u.maxPlaintextSize)
- throw new Error('invalid plaintext size: must be between 1 and 65535 bytes');
- const arr = new Uint8Array(2);
- new DataView(arr.buffer).setUint16(0, num, false);
- return arr;
- },
-
- pad(plaintext: string): Uint8Array {
- const unpadded = u.utf8Encode(plaintext);
- const unpaddedLen = unpadded.length;
- const prefix = u.writeU16BE(unpaddedLen);
- const suffix = new Uint8Array(u.calcPaddedLen(unpaddedLen) - unpaddedLen);
- return concatBytes(prefix, unpadded, suffix);
- },
-
- unpad(padded: Uint8Array): string {
- const unpaddedLen = new DataView(padded.buffer).getUint16(0);
- const unpadded = padded.subarray(2, 2 + unpaddedLen);
- if (
- unpaddedLen < u.minPlaintextSize ||
- unpaddedLen > u.maxPlaintextSize ||
- unpadded.length !== unpaddedLen ||
- padded.length !== 2 + u.calcPaddedLen(unpaddedLen)
- )
- throw new Error('invalid padding');
- return u.utf8Decode(unpadded);
- },
-
- hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array) {
- if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes');
- const combined = concatBytes(aad, message);
- return hmac(sha256, key, combined);
- },
-
- // metadata: always 65b (version: 1b, nonce: 32b, max: 32b)
- // plaintext: 1b to 0xffff
- // padded plaintext: 32b to 0xffff
- // ciphertext: 32b+2 to 0xffff+2
- // raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)
- // compressed payload (base64): 132b to 87472b
- decodePayload(payload: string) {
- if (typeof payload !== 'string') throw new Error('payload must be a valid string');
- const plen = payload.length;
- if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen);
- if (payload[0] === '#') throw new Error('unknown encryption version');
- let data: Uint8Array;
- try {
- data = base64.decode(payload);
- } catch (error) {
- throw new Error('invalid base64: ' + (error as any).message);
- }
- const dlen = data.length;
- if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen);
- const vers = data[0];
- if (vers !== 2) throw new Error('unknown encryption version ' + vers);
- return {
- nonce: data.subarray(1, 33),
- ciphertext: data.subarray(33, -32),
- mac: data.subarray(-32),
- };
- },
-};
-
-export function encrypt(plaintext: string, conversationKey: Uint8Array, nonce = randomBytes(32)): string {
- const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce);
- const padded = u.pad(plaintext);
- const ciphertext = chacha20(chacha_key, chacha_nonce, padded);
- const mac = u.hmacAad(hmac_key, ciphertext, nonce);
- return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac));
-}
-
-export function decrypt(payload: string, conversationKey: Uint8Array): string {
- const { nonce, ciphertext, mac } = u.decodePayload(payload);
- const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce);
- const calculatedMac = u.hmacAad(hmac_key, ciphertext, nonce);
- if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC');
- const padded = chacha20(chacha_key, chacha_nonce, ciphertext);
- return u.unpad(padded);
-}
-
-export const v2 = {
- utils: u,
- encrypt,
- decrypt,
-};
+// Copied from this public-domain code:
+// https://github.com/paulmillr/nip44/blob/main/javascript/index.ts
+// Modified slightly to deal with a dependency issue
+
+import { chacha20 } from "@noble/ciphers/chacha.js";
+import { equalBytes } from "@noble/ciphers/utils.js";
+import { secp256k1 } from "@noble/curves/secp256k1.js";
+import {
+ extract as hkdf_extract,
+ expand as hkdf_expand,
+} from "@noble/hashes/hkdf.js";
+import { hmac } from "@noble/hashes/hmac.js";
+import { sha256 } from "@noble/hashes/sha2.js";
+import { concatBytes, randomBytes, utf8ToBytes } from "@noble/hashes/utils.js";
+import { base64 } from "@scure/base";
+
+declare const TextDecoder: any;
+
+const decoder = new TextDecoder();
+export const u = {
+ minPlaintextSize: 0x0001, // 1b msg => padded to 32b
+ maxPlaintextSize: 0xffff, // 65535 (64kb-1) => padded to 64kb
+
+ utf8Encode: utf8ToBytes,
+ utf8Decode(bytes: Uint8Array) {
+ return decoder.decode(bytes);
+ },
+
+ getConversationKey(privkeyA: string, pubkeyB: string): Uint8Array {
+ const sharedX = secp256k1
+ .getSharedSecret(privkeyA, "02" + pubkeyB)
+ .subarray(1, 33);
+ return hkdf_extract(sha256, sharedX, "nip44-v2");
+ },
+
+ getMessageKeys(conversationKey: Uint8Array, nonce: Uint8Array) {
+ // ensureBytes(conversationKey, 32);
+ // ensureBytes(nonce, 32);
+ const keys = hkdf_expand(sha256, conversationKey, nonce, 76);
+ return {
+ chacha_key: keys.subarray(0, 32),
+ chacha_nonce: keys.subarray(32, 44),
+ hmac_key: keys.subarray(44, 76),
+ };
+ },
+
+ calcPaddedLen(len: number): number {
+ if (!Number.isSafeInteger(len) || len < 1)
+ throw new Error("expected positive integer");
+ if (len <= 32) return 32;
+ const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1);
+ const chunk = nextPower <= 256 ? 32 : nextPower / 8;
+ return chunk * (Math.floor((len - 1) / chunk) + 1);
+ },
+
+ writeU16BE(num: number) {
+ if (
+ !Number.isSafeInteger(num) ||
+ num < u.minPlaintextSize ||
+ num > u.maxPlaintextSize
+ )
+ throw new Error(
+ "invalid plaintext size: must be between 1 and 65535 bytes",
+ );
+ const arr = new Uint8Array(2);
+ new DataView(arr.buffer).setUint16(0, num, false);
+ return arr;
+ },
+
+ pad(plaintext: string): Uint8Array {
+ const unpadded = u.utf8Encode(plaintext);
+ const unpaddedLen = unpadded.length;
+ const prefix = u.writeU16BE(unpaddedLen);
+ const suffix = new Uint8Array(u.calcPaddedLen(unpaddedLen) - unpaddedLen);
+ return concatBytes(prefix, unpadded, suffix);
+ },
+
+ unpad(padded: Uint8Array): string {
+ const unpaddedLen = new DataView(padded.buffer).getUint16(0);
+ const unpadded = padded.subarray(2, 2 + unpaddedLen);
+ if (
+ unpaddedLen < u.minPlaintextSize ||
+ unpaddedLen > u.maxPlaintextSize ||
+ unpadded.length !== unpaddedLen ||
+ padded.length !== 2 + u.calcPaddedLen(unpaddedLen)
+ )
+ throw new Error("invalid padding");
+ return u.utf8Decode(unpadded);
+ },
+
+ hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array) {
+ if (aad.length !== 32)
+ throw new Error("AAD associated data must be 32 bytes");
+ const combined = concatBytes(aad, message);
+ return hmac(sha256, key, combined);
+ },
+
+ // metadata: always 65b (version: 1b, nonce: 32b, max: 32b)
+ // plaintext: 1b to 0xffff
+ // padded plaintext: 32b to 0xffff
+ // ciphertext: 32b+2 to 0xffff+2
+ // raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)
+ // compressed payload (base64): 132b to 87472b
+ decodePayload(payload: string) {
+ if (typeof payload !== "string")
+ throw new Error("payload must be a valid string");
+ const plen = payload.length;
+ if (plen < 132 || plen > 87472)
+ throw new Error("invalid payload length: " + plen);
+ if (payload[0] === "#") throw new Error("unknown encryption version");
+ let data: Uint8Array;
+ try {
+ data = base64.decode(payload);
+ } catch (error) {
+ throw new Error("invalid base64: " + (error as any).message);
+ }
+ const dlen = data.length;
+ if (dlen < 99 || dlen > 65603)
+ throw new Error("invalid data length: " + dlen);
+ const vers = data[0];
+ if (vers !== 2) throw new Error("unknown encryption version " + vers);
+ return {
+ nonce: data.subarray(1, 33),
+ ciphertext: data.subarray(33, -32),
+ mac: data.subarray(-32),
+ };
+ },
+};
+
+export function encrypt(
+ plaintext: string,
+ conversationKey: Uint8Array,
+ nonce = randomBytes(32),
+): string {
+ const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(
+ conversationKey,
+ nonce,
+ );
+ const padded = u.pad(plaintext);
+ const ciphertext = chacha20(chacha_key, chacha_nonce, padded);
+ const mac = u.hmacAad(hmac_key, ciphertext, nonce);
+ return base64.encode(
+ concatBytes(new Uint8Array([2]), nonce, ciphertext, mac),
+ );
+}
+
+export function decrypt(payload: string, conversationKey: Uint8Array): string {
+ const { nonce, ciphertext, mac } = u.decodePayload(payload);
+ const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(
+ conversationKey,
+ nonce,
+ );
+ const calculatedMac = u.hmacAad(hmac_key, ciphertext, nonce);
+ if (!equalBytes(calculatedMac, mac)) throw new Error("invalid MAC");
+ const padded = chacha20(chacha_key, chacha_nonce, ciphertext);
+ return u.unpad(padded);
+}
+
+export const v2 = {
+ utils: u,
+ encrypt,
+ decrypt,
+};
diff --git a/src/lib/nip51.ts b/src/lib/nip51.ts
index 0210bf8b..7560dd3d 100644
--- a/src/lib/nip51.ts
+++ b/src/lib/nip51.ts
@@ -1,70 +1,81 @@
-import { SimplePool } from 'nostr-tools/pool';
-import { signEvent, encrypt, decrypt } from '$lib/nip07';
+import { SimplePool } from "nostr-tools/pool";
+import { signEvent, encrypt, decrypt } from "$lib/nip07";
const pool = new SimplePool();
-import { PUBLIC_DM_RELAYS } from '$env/static/public';
-const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(',');
+import { PUBLIC_DM_RELAYS } from "$env/static/public";
+const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(",");
// Mute the provided pubkey, as the provided user.
export const mute = async (user: any, pubkey: string, hide: boolean) => {
- let { shown, hidden } = await getMuteLists(user);
- if (hide) {
- hidden.push(["p", pubkey]);
- } else {
- shown.push(["p", pubkey]);
- }
- await publishMuteList(user, shown, hidden);
-}
+ let { shown, hidden } = await getMuteLists(user);
+ if (hide) {
+ hidden.push(["p", pubkey]);
+ } else {
+ shown.push(["p", pubkey]);
+ }
+ await publishMuteList(user, shown, hidden);
+};
const tagMatches = (tag: string[], pubkey: string): boolean =>
- tag.length >= 2 && tag[0] === "p" && tag[1] === pubkey;
+ tag.length >= 2 && tag[0] === "p" && tag[1] === pubkey;
// Unmute the provided pubkey, as the provided user.
export const unmute = async (user: any, pubkey: string) => {
- let { shown, hidden } = await getMuteLists(user);
- shown = shown.filter((tag: string[]) => !tagMatches(tag, pubkey));
- hidden = hidden.filter((tag: string[]) => !tagMatches(tag, pubkey));
- await publishMuteList(user, shown, hidden);
-}
+ let { shown, hidden } = await getMuteLists(user);
+ shown = shown.filter((tag: string[]) => !tagMatches(tag, pubkey));
+ hidden = hidden.filter((tag: string[]) => !tagMatches(tag, pubkey));
+ await publishMuteList(user, shown, hidden);
+};
// Returns a set of the provided user's muted accounts.
export const mutedAccounts = async (user: any): Promise<Set<string>> => {
- const { shown, hidden } = await getMuteLists(user);
- let muted = new Set<string>();
- for (const tag of shown) {
- if (tag.length >= 2 && tag[0] === "p") {
- muted.add(tag[1]);
- }
+ const { shown, hidden } = await getMuteLists(user);
+ let muted = new Set<string>();
+ for (const tag of shown) {
+ if (tag.length >= 2 && tag[0] === "p") {
+ muted.add(tag[1]);
}
- for (const tag of hidden) {
- if (tag.length >= 2 && tag[0] === "p") {
- muted.add(tag[1]);
- }
+ }
+ for (const tag of hidden) {
+ if (tag.length >= 2 && tag[0] === "p") {
+ muted.add(tag[1]);
}
- return muted;
-}
+ }
+ return muted;
+};
const getMuteLists = async (user: any): Promise<any> => {
- const listEvents = await pool.querySync(
- DM_RELAYS_LIST, { kinds: [10000], "authors": [user.pubkey], limit: 1 }
- );
- if (listEvents.length == 0) {
- return { shown: [], hidden: [] };
- }
+ const listEvents = await pool.querySync(DM_RELAYS_LIST, {
+ kinds: [10000],
+ authors: [user.pubkey],
+ limit: 1,
+ });
+ if (listEvents.length == 0) {
+ return { shown: [], hidden: [] };
+ }
- return {
- shown: listEvents[0].tags,
- hidden: listEvents[0].content == "" ? [] :
- await decrypt(listEvents[0].content, user, user.pubkey)
- };
-}
+ return {
+ shown: listEvents[0].tags,
+ hidden:
+ listEvents[0].content == ""
+ ? []
+ : await decrypt(listEvents[0].content, user, user.pubkey),
+ };
+};
-const publishMuteList = async (user: any, shown: string[], hidden: string[]) => {
- const event = await signEvent({
- kind: 10000,
- created_at: Math.floor(Date.now() / 1000),
- tags: shown,
- content: await encrypt(hidden, user, user.pubkey)
- }, user);
- return Promise.any(pool.publish(DM_RELAYS_LIST, event));
-}
+const publishMuteList = async (
+ user: any,
+ shown: string[],
+ hidden: string[],
+) => {
+ const event = await signEvent(
+ {
+ kind: 10000,
+ created_at: Math.floor(Date.now() / 1000),
+ tags: shown,
+ content: await encrypt(hidden, user, user.pubkey),
+ },
+ user,
+ );
+ return Promise.any(pool.publish(DM_RELAYS_LIST, event));
+};
diff --git a/src/lib/nostr.ts b/src/lib/nostr.ts
index dd283987..50df6408 100644
--- a/src/lib/nostr.ts
+++ b/src/lib/nostr.ts
@@ -1,239 +1,239 @@
import { Buffer } from "buffer";
import { browser } from "$app/environment";
import {
- decrypted,
- eventToSign,
- password as pw,
- passwordPrompt,
- signer as $signer,
+ decrypted,
+ eventToSign,
+ password as pw,
+ passwordPrompt,
+ signer as $signer,
} from "$lib/store";
import { post, wait } from "$lib/utils";
import { bytesToHex } from "@noble/hashes/utils.js";
import type { EventTemplate } from "nostr-tools";
import { get } from "svelte/store";
-let nostrToolsPromise:
- | Promise<typeof import("nostr-tools")>
- | undefined;
+let nostrToolsPromise: Promise<typeof import("nostr-tools")> | undefined;
let nip44Promise: Promise<typeof import("nostr-tools/nip44")> | undefined;
let relayPromise: Promise<typeof import("nostr-tools/relay")> | undefined;
let nip49Promise: Promise<typeof import("nostr-tools/nip49")> | undefined;
-const loadNostrTools = () =>
- (nostrToolsPromise ||= import("nostr-tools"));
+const loadNostrTools = () => (nostrToolsPromise ||= import("nostr-tools"));
const loadNip44 = () => (nip44Promise ||= import("nostr-tools/nip44"));
const loadRelay = () => (relayPromise ||= import("nostr-tools/relay"));
const loadNip49 = () => (nip49Promise ||= import("nostr-tools/nip49"));
type User = {
- [key: string]: any;
+ [key: string]: any;
};
type EncryptParams = {
- message: string;
- recipient: string;
- user: User;
+ message: string;
+ recipient: string;
+ user: User;
};
export const encrypt = async ({ message, recipient, user }: EncryptParams) => {
- const sk = await getPrivateKey(user);
- const { nip04 } = await loadNostrTools();
- return nip04.encrypt(sk, recipient, message);
+ const sk = await getPrivateKey(user);
+ const { nip04 } = await loadNostrTools();
+ return nip04.encrypt(sk, recipient, message);
};
export const decrypt = async ({ event, user }: { event: any; user: any }) => {
- const cache = get(decrypted);
- try {
- let { content, pubkey, id } = event;
- if (cache[id]) return cache[id];
- if (pubkey === user.pubkey) pubkey = event.tags[0][1];
+ const cache = get(decrypted);
+ try {
+ let { content, pubkey, id } = event;
+ if (cache[id]) return cache[id];
+ if (pubkey === user.pubkey) pubkey = event.tags[0][1];
- const { nip04 } = await loadNostrTools();
- const message = await nip04.decrypt(
- await getPrivateKey(user),
- pubkey,
- content,
- );
+ const { nip04 } = await loadNostrTools();
+ const message = await nip04.decrypt(
+ await getPrivateKey(user),
+ pubkey,
+ content,
+ );
- cache[id] = Buffer.from(message).toString("utf8");
- decrypted.set(cache);
+ cache[id] = Buffer.from(message).toString("utf8");
+ decrypted.set(cache);
- return cache[id];
- } catch (e) {
- // console.log(e);
- }
+ return cache[id];
+ } catch {
+ // console.log(e);
+ }
};
export const getPrivateKey = async (user: User): Promise<Uint8Array> => {
- let k;
- if (browser) {
- k = localStorage.getItem("nsec");
- if (k) {
- const { nip19 } = await loadNostrTools();
- return nip19.decode(k).data as Uint8Array;
- }
- }
+ let k;
+ if (browser) {
+ k = localStorage.getItem("nsec");
+ if (k) {
+ const { nip19 } = await loadNostrTools();
+ return nip19.decode(k).data as Uint8Array;
+ }
+ }
- const { nsec } = user;
+ const { nsec } = user;
- if (nsec) {
- const { decrypt: nip49decrypt } = await loadNip49();
- k = nip49decrypt(nsec, await getPassword());
- } else {
- throw new Error("nsec not available");
- }
+ if (nsec) {
+ const { decrypt: nip49decrypt } = await loadNip49();
+ k = nip49decrypt(nsec, await getPassword());
+ } else {
+ throw new Error("nsec not available");
+ }
- const { nip19 } = await loadNostrTools();
- localStorage.setItem("nsec", nip19.nsecEncode(k));
- return k;
+ const { nip19 } = await loadNostrTools();
+ localStorage.setItem("nsec", nip19.nsecEncode(k));
+ return k;
};
const decodeNsec = async (nsec: string): Promise<Uint8Array> => {
- const { nip19 } = await loadNostrTools();
- const { type, data } = nip19.decode(nsec);
- if (type === "nsec" && data instanceof Uint8Array) return data;
- throw new Error("invalid nsec");
+ const { nip19 } = await loadNostrTools();
+ const { type, data } = nip19.decode(nsec);
+ if (type === "nsec" && data instanceof Uint8Array) return data;
+ throw new Error("invalid nsec");
};
export const getNsec = async (user: User) => {
- const { nip19 } = await loadNostrTools();
- return nip19.nsecEncode(await getPrivateKey(user));
+ const { nip19 } = await loadNostrTools();
+ return nip19.nsecEncode(await getPrivateKey(user));
};
export const setNsec = async (user: User, nsec: string) => {
- const { getPublicKey } = await loadNostrTools();
- user.pubkey = getPublicKey(await decodeNsec(nsec));
- user.nsec = await encryptNsec(nsec);
+ const { getPublicKey } = await loadNostrTools();
+ user.pubkey = getPublicKey(await decodeNsec(nsec));
+ user.nsec = await encryptNsec(nsec);
};
export const encryptNsec = async (nsec: string) => {
- const { encrypt: nip49encrypt } = await loadNip49();
- const d = await decodeNsec(nsec);
- return nip49encrypt(d, await getPassword());
+ const { encrypt: nip49encrypt } = await loadNip49();
+ const d = await decodeNsec(nsec);
+ return nip49encrypt(d, await getPassword());
};
export const sign = async (event: any, user?: any) => {
- if (user?.nsec && !get($signer)?.ready) {
- const sk = await getPrivateKey(user);
- const { getPublicKey } = await loadNostrTools();
+ if (user?.nsec && !get($signer)?.ready) {
+ const sk = await getPrivateKey(user);
+ const { getPublicKey } = await loadNostrTools();
- $signer.set({
- method: "nsec",
- ready: true,
- params: { sk: bytesToHex(sk), pk: getPublicKey(sk) },
- });
- }
+ $signer.set({
+ method: "nsec",
+ ready: true,
+ params: { sk: bytesToHex(sk), pk: getPublicKey(sk) },
+ });
+ }
- eventToSign.set(event);
- let unsubscribe;
- const { method, params } = await new Promise((r, j) => {
- unsubscribe = $signer.subscribe((v) => {
- if (v === "cancel") {
- j("cancelled");
- $signer.set(undefined);
- }
- v?.ready && r(v);
- });
- });
- await unsubscribe();
- const signedEvent = await signingMethods[method](event, params);
- eventToSign.set(signedEvent);
- setTimeout(() => eventToSign.set(null), 1000);
- return signedEvent;
+ eventToSign.set(event);
+ let unsubscribe;
+ const { method, params } = await new Promise((r, j) => {
+ unsubscribe = $signer.subscribe((v) => {
+ if (v === "cancel") {
+ j("cancelled");
+ $signer.set(undefined);
+ }
+ v?.ready && r(v);
+ });
+ });
+ await unsubscribe();
+ const signedEvent = await signingMethods[method](event, params);
+ eventToSign.set(signedEvent);
+ setTimeout(() => eventToSign.set(null), 1000);
+ return signedEvent;
};
export const send = (event: EventTemplate) => {
- return post("/events", { event });
+ return post("/events", { event });
};
const getPassword = async (): Promise<string> => {
- if (!get(pw)) passwordPrompt.set(true);
- await wait(() => !!get(pw));
- return get(pw) || "";
+ if (!get(pw)) passwordPrompt.set(true);
+ await wait(() => !!get(pw));
+ return get(pw) || "";
};
export const nostrConnectRelay = "wss://relay.nsec.app";
-const signingMethods: Record<string, (event: any, params: any) => Promise<any>> = {
- async connect(event: any, { sk, pk, pubkey }: any) {
- const id = crypto.randomUUID();
- const signEvent = {
- id,
- method: "sign_event",
- params: [JSON.stringify(event)],
- };
+const signingMethods: Record<
+ string,
+ (event: any, params: any) => Promise<any>
+> = {
+ async connect(event: any, { sk, pk, pubkey }: any) {
+ const id = crypto.randomUUID();
+ const signEvent = {
+ id,
+ method: "sign_event",
+ params: [JSON.stringify(event)],
+ };
- const { nip04, finalizeEvent } = await loadNostrTools();
- const content = await nip04.encrypt(sk, pk, JSON.stringify(signEvent));
+ const { nip04, finalizeEvent } = await loadNostrTools();
+ const content = await nip04.encrypt(sk, pk, JSON.stringify(signEvent));
- const signedSignEvent = finalizeEvent(
- {
- created_at: Math.round(Date.now() / 1000),
- kind: 24133,
- pubkey,
- content,
- tags: [["p", pk]],
- },
- sk,
- );
+ const signedSignEvent = finalizeEvent(
+ {
+ created_at: Math.round(Date.now() / 1000),
+ kind: 24133,
+ pubkey,
+ content,
+ tags: [["p", pk]],
+ },
+ sk,
+ );
- const { Relay } = await loadRelay();
- const relay = await Relay.connect(nostrConnectRelay);
- relay.publish(signedSignEvent);
+ const { Relay } = await loadRelay();
+ const relay = await Relay.connect(nostrConnectRelay);
+ relay.publish(signedSignEvent);
- return new Promise((resolve) => {
- relay.subscribe([{ kinds: [24133], "#p": [pubkey] }], {
- async onevent(event) {
- pk = event.pubkey;
- try {
- let response;
- try {
- const { nip04 } = await loadNostrTools();
- response = JSON.parse(await nip04.decrypt(sk, pk, event.content));
- } catch (e) {
- const { getConversationKey, decrypt: nip44decrypt } =
- await loadNip44();
- const ck = await getConversationKey(sk, pk);
- response = JSON.parse(await nip44decrypt(event.content, ck));
- }
+ return new Promise((resolve) => {
+ relay.subscribe([{ kinds: [24133], "#p": [pubkey] }], {
+ async onevent(event) {
+ pk = event.pubkey;
+ try {
+ let response;
+ try {
+ const { nip04 } = await loadNostrTools();
+ response = JSON.parse(await nip04.decrypt(sk, pk, event.content));
+ } catch {
+ const { getConversationKey, decrypt: nip44decrypt } =
+ await loadNip44();
+ const ck = await getConversationKey(sk, pk);
+ response = JSON.parse(await nip44decrypt(event.content, ck));
+ }
- if (response.id === id) resolve(JSON.parse(response.result));
- } catch (e) {
- console.log("failed to parse nostr connect event", e);
- }
- },
- });
- });
- },
+ if (response.id === id) resolve(JSON.parse(response.result));
+ } catch (e) {
+ console.log("failed to parse nostr connect event", e);
+ }
+ },
+ });
+ });
+ },
- async nsec(event: any, { sk }: any) {
- const { finalizeEvent } = await loadNostrTools();
- return finalizeEvent(event, sk);
- },
+ async nsec(event: any, { sk }: any) {
+ const { finalizeEvent } = await loadNostrTools();
+ return finalizeEvent(event, sk);
+ },
- async extension(event: any) {
- return window.nostr!.signEvent(event);
- },
+ async extension(event: any) {
+ return window.nostr!.signEvent(event);
+ },
- async signer(event: any, { pubkey, sig }: any) {
- event.pubkey = pubkey;
- const { getEventHash } = await loadNostrTools();
- const signedEvent = {
- ...event,
- id: getEventHash(event),
- sig,
- };
- return signedEvent;
- },
+ async signer(event: any, { pubkey, sig }: any) {
+ event.pubkey = pubkey;
+ const { getEventHash } = await loadNostrTools();
+ const signedEvent = {
+ ...event,
+ id: getEventHash(event),
+ sig,
+ };
+ return signedEvent;
+ },
};
// Returns all the keys mentioned in the provided event's 'p' tags.
export const pTagKeys = (event: any): string[] => {
- let keys: string[] = [];
- for (const tag of event.tags) {
- if (tag[0] === "p") {
- keys.push(tag[1]);
- }
- }
- return keys;
-}
+ let keys: string[] = [];
+ for (const tag of event.tags) {
+ if (tag[0] === "p") {
+ keys.push(tag[1]);
+ }
+ }
+ return keys;
+};
diff --git a/src/lib/parse.ts b/src/lib/parse.ts
index 3249b9db..38c32a54 100644
--- a/src/lib/parse.ts
+++ b/src/lib/parse.ts
@@ -4,137 +4,137 @@ import { auth, get, isLiquid, post, sats } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
let validatePromise:
- | Promise<typeof import("bitcoin-address-validation")>
- | undefined;
+ | Promise<typeof import("bitcoin-address-validation")>
+ | undefined;
const loadValidate = () =>
- (validatePromise ||= import("bitcoin-address-validation"));
+ (validatePromise ||= import("bitcoin-address-validation"));
export default async (s, host, cookies) => {
- if (!s) return;
- let t = s.trim();
- let amount;
- let invoice;
- let user;
+ if (!s) return;
+ let t = s.trim();
+ let amount;
+ let invoice;
+ let user;
- if (t.startsWith("ark") || t.startsWith("tark"))
- redirect(307, `/send/ark/${t}`);
+ if (t.startsWith("ark") || t.startsWith("tark"))
+ redirect(307, `/send/ark/${t}`);
- if (t.startsWith("http")) redirect(307, t);
- if (t.startsWith(host)) redirect(307, `http://${t}`);
+ if (t.startsWith("http")) redirect(307, t);
+ if (t.startsWith(host)) redirect(307, `http://${t}`);
- if (t.includes("lightning=")) {
- const url = new URL(t);
- const params = new URLSearchParams(url.search);
- t = params.get("lightning");
- }
+ if (t.includes("lightning=")) {
+ const url = new URL(t);
+ const params = new URLSearchParams(url.search);
+ t = params.get("lightning");
+ }
- if (t.startsWith("lightning:")) t = t.replace("lightning:", "");
- if (t.endsWith(`@${PUBLIC_DOMAIN}`)) t = t.split("@")[0];
- if (t.includes("@") && t.includes(".")) {
- try {
- t = await get(`/encode?address=${t}`);
- } catch (e) {}
- }
+ if (t.startsWith("lightning:")) t = t.replace("lightning:", "");
+ if (t.endsWith(`@${PUBLIC_DOMAIN}`)) t = t.split("@")[0];
+ if (t.includes("@") && t.includes(".")) {
+ try {
+ t = await get(`/encode?address=${t}`);
+ } catch {}
+ }
- if (t.toLowerCase().startsWith("nostr:")) {
- t = t.split(":")[1];
- }
+ if (t.toLowerCase().startsWith("nostr:")) {
+ t = t.split(":")[1];
+ }
- if (["note", "nevent"].some((p) => t.startsWith(p))) redirect(307, `/e/${t}`);
- if (["nprofile", "npub"].some((p) => t.startsWith(p))) redirect(307, `/${t}`);
+ if (["note", "nevent"].some((p) => t.startsWith(p))) redirect(307, `/e/${t}`);
+ if (["nprofile", "npub"].some((p) => t.startsWith(p))) redirect(307, `/${t}`);
- // bitcoin
- if (
- t.toLowerCase().startsWith("bitcoin:") ||
- t.toLowerCase().startsWith("liquidnetwork:")
- ) {
- ({
- address: t,
- options: { amount },
- } = decode(t));
- }
+ // bitcoin
+ if (
+ t.toLowerCase().startsWith("bitcoin:") ||
+ t.toLowerCase().startsWith("liquidnetwork:")
+ ) {
+ ({
+ address: t,
+ options: { amount },
+ } = decode(t));
+ }
- const { validate } = await loadValidate();
- if (validate(t) || isLiquid(t)) {
- let r = `/send/bitcoin/${t}`;
- if (amount) r += `/${Math.round(amount * sats)}`;
- redirect(307, r);
- }
+ const { validate } = await loadValidate();
+ if (validate(t) || isLiquid(t)) {
+ let r = `/send/bitcoin/${t}`;
+ if (amount) r += `/${Math.round(amount * sats)}`;
+ redirect(307, r);
+ }
- // lightning
- if (t.toLowerCase().startsWith("lightning:"))
- t = t.toLowerCase().replace("lightning:", "");
- if (t.toLowerCase().startsWith("lnurl")) redirect(307, `/ln/${t}`);
- if (t.includes(":")) t = t.split(":")[1];
+ // lightning
+ if (t.toLowerCase().startsWith("lightning:"))
+ t = t.toLowerCase().replace("lightning:", "");
+ if (t.toLowerCase().startsWith("lnurl")) redirect(307, `/ln/${t}`);
+ if (t.includes(":")) t = t.split(":")[1];
- if (t.toLowerCase().startsWith("lnr")) {
- const { iid } = await post("/sendinvoice", { invreq: t }, auth(cookies));
- invoice = { id: iid };
- } else if (t.toLowerCase().startsWith("ln")) {
- try {
- const aid = cookies.get("aid");
- invoice = await get(`/invoice/${t}`);
- if (invoice.user.username === "mint") throw new Error("mint payment");
- if (aid && aid !== invoice.aid) throw new Error("cross-account");
- } catch (e) {
- if (t.toLowerCase().startsWith("lno")) {
- const { offer_amount_msat: a } = await get(`/decode/${t}`);
- if (a) ({ invoice: t } = await post("/fetchinvoice", { offer: t }));
- }
- redirect(307, `/send/lightning/${t}`);
- }
- }
+ if (t.toLowerCase().startsWith("lnr")) {
+ const { iid } = await post("/sendinvoice", { invreq: t }, auth(cookies));
+ invoice = { id: iid };
+ } else if (t.toLowerCase().startsWith("ln")) {
+ try {
+ const aid = cookies.get("aid");
+ invoice = await get(`/invoice/${t}`);
+ if (invoice.user.username === "mint") throw new Error("mint payment");
+ if (aid && aid !== invoice.aid) throw new Error("cross-account");
+ } catch {
+ if (t.toLowerCase().startsWith("lno")) {
+ const { offer_amount_msat: a } = await get(`/decode/${t}`);
+ if (a) ({ invoice: t } = await post("/fetchinvoice", { offer: t }));
+ }
+ redirect(307, `/send/lightning/${t}`);
+ }
+ }
- if (invoice) redirect(307, `/invoice/${invoice.id}`);
+ if (invoice) redirect(307, `/invoice/${invoice.id}`);
- if (t.match(/^🥜([\uFE00-\uFE0F]|[\uE0100-\uE01EF]+)$/)) {
- t = Array.from(t)
- .slice(1)
- .map((char) => {
- const codePoint = char.codePointAt(0);
+ if (t.match(/^🥜([\uFE00-\uFE0F]|[\uE0100-\uE01EF]+)$/)) {
+ t = Array.from(t)
+ .slice(1)
+ .map((char) => {
+ const codePoint = char.codePointAt(0);
- // Handle Variation Selectors (VS1-VS16): U+FE00 to U+FE0F
- if (codePoint >= 0xfe00 && codePoint <= 0xfe0f) {
- const byteValue = codePoint - 0xfe00; // Maps FE00->0, FE01->1, ..., FE0F->15
- return String.fromCharCode(byteValue);
- }
+ // Handle Variation Selectors (VS1-VS16): U+FE00 to U+FE0F
+ if (codePoint >= 0xfe00 && codePoint <= 0xfe0f) {
+ const byteValue = codePoint - 0xfe00; // Maps FE00->0, FE01->1, ..., FE0F->15
+ return String.fromCharCode(byteValue);
+ }
- // Handle Variation Selectors Supplement (VS17-VS256): U+E0100 to U+E01EF
- if (codePoint >= 0xe0100 && codePoint <= 0xe01ef) {
- const byteValue = codePoint - 0xe0100 + 16; // Maps E0100->16, E0101->17, ..., E01EF->255
- return String.fromCharCode(byteValue);
- }
- })
- .join("");
- }
+ // Handle Variation Selectors Supplement (VS17-VS256): U+E0100 to U+E01EF
+ if (codePoint >= 0xe0100 && codePoint <= 0xe01ef) {
+ const byteValue = codePoint - 0xe0100 + 16; // Maps E0100->16, E0101->17, ..., E01EF->255
+ return String.fromCharCode(byteValue);
+ }
+ })
+ .join("");
+ }
- if (t.startsWith("cashu")) {
- const { id } = await post("/cash", { token: t });
- redirect(307, `/ecash/${id}`);
- }
+ if (t.startsWith("cashu")) {
+ const { id } = await post("/cash", { token: t });
+ redirect(307, `/ecash/${id}`);
+ }
- if (t.startsWith("creq")) redirect(307, `/send/ecash/${t}`);
+ if (t.startsWith("creq")) redirect(307, `/send/ecash/${t}`);
- // user
- try {
- user = await get(`/users/${t.split("/")[0]}`);
- if (user.anon) user = null;
- } catch (e) {}
+ // user
+ try {
+ user = await get(`/users/${t.split("/")[0]}`);
+ if (user.anon) user = null;
+ } catch {}
- if (user) redirect(307, `/pay/${t}`);
+ if (user) redirect(307, `/pay/${t}`);
- let fund;
- if (t.includes("/fund")) redirect(307, t.substring(t.indexOf("/fund")));
+ let fund;
+ if (t.includes("/fund")) redirect(307, t.substring(t.indexOf("/fund")));
- try {
- fund = await get(`/fund/${t}`);
- } catch (e) {}
+ try {
+ fund = await get(`/fund/${t}`);
+ } catch {}
- if (fund) redirect(307, `/send/fund/${t}`);
+ if (fund) redirect(307, `/send/fund/${t}`);
- try {
- invoice ||= await get(`/invoice/${t}`);
- } catch (e) {}
+ try {
+ invoice ||= await get(`/invoice/${t}`);
+ } catch {}
- if (invoice) redirect(307, `/invoice/${invoice.id}`);
+ if (invoice) redirect(307, `/invoice/${invoice.id}`);
};
diff --git a/src/lib/passwordCache.ts b/src/lib/passwordCache.ts
index 4f764698..a67113e3 100644
--- a/src/lib/passwordCache.ts
+++ b/src/lib/passwordCache.ts
@@ -5,57 +5,62 @@ const PASSWORD_KEY = "walletPassword";
const EXPIRES_KEY = "walletPasswordExpiresAt";
export const rememberForOptions = [
- { label: "Don't remember", ms: 0 },
- { label: "8 hours", ms: 8 * 60 * 60 * 1000 },
- { label: "1 day", ms: 24 * 60 * 60 * 1000 },
- { label: "1 week", ms: 7 * 24 * 60 * 60 * 1000 },
- { label: "1 month", ms: 30 * 24 * 60 * 60 * 1000 },
- { label: "1 year", ms: 365 * 24 * 60 * 60 * 1000 },
+ { label: "Don't remember", ms: 0 },
+ { label: "8 hours", ms: 8 * 60 * 60 * 1000 },
+ { label: "1 day", ms: 24 * 60 * 60 * 1000 },
+ { label: "1 week", ms: 7 * 24 * 60 * 60 * 1000 },
+ { label: "1 month", ms: 30 * 24 * 60 * 60 * 1000 },
+ { label: "1 year", ms: 365 * 24 * 60 * 60 * 1000 },
];
export const defaultRememberForMs = 30 * 24 * 60 * 60 * 1000;
const clearStoredPassword = () => {
- if (!browser) return;
- localStorage.removeItem(PASSWORD_KEY);
- localStorage.removeItem(EXPIRES_KEY);
+ if (!browser) return;
+ localStorage.removeItem(PASSWORD_KEY);
+ localStorage.removeItem(EXPIRES_KEY);
};
const loadStoredPassword = () => {
- if (!browser) return undefined;
- const password = localStorage.getItem(PASSWORD_KEY) || undefined;
- if (!password) return undefined;
- const expiresAtRaw = localStorage.getItem(EXPIRES_KEY);
- const expiresAt = expiresAtRaw ? Number(expiresAtRaw) : undefined;
- if (expiresAt && Date.now() > expiresAt) {
- clearStoredPassword();
- return undefined;
- }
- return password;
+ if (!browser) return undefined;
+ const password = localStorage.getItem(PASSWORD_KEY) || undefined;
+ if (!password) return undefined;
+ const expiresAtRaw = localStorage.getItem(EXPIRES_KEY);
+ const expiresAt = expiresAtRaw ? Number(expiresAtRaw) : undefined;
+ if (expiresAt && Date.now() > expiresAt) {
+ clearStoredPassword();
+ return undefined;
+ }
+ return password;
};
-export const walletPassword = writable<string | undefined>(loadStoredPassword());
+export const walletPassword = writable<string | undefined>(
+ loadStoredPassword(),
+);
-export const rememberWalletPassword = (password: string, durationMs: number) => {
- if (!browser) return;
- if (!durationMs) {
- clearStoredPassword();
- walletPassword.set(undefined);
- return;
- }
- const expiresAt = Date.now() + durationMs;
- localStorage.setItem(PASSWORD_KEY, password);
- localStorage.setItem(EXPIRES_KEY, String(expiresAt));
- walletPassword.set(password);
+export const rememberWalletPassword = (
+ password: string,
+ durationMs: number,
+) => {
+ if (!browser) return;
+ if (!durationMs) {
+ clearStoredPassword();
+ walletPassword.set(undefined);
+ return;
+ }
+ const expiresAt = Date.now() + durationMs;
+ localStorage.setItem(PASSWORD_KEY, password);
+ localStorage.setItem(EXPIRES_KEY, String(expiresAt));
+ walletPassword.set(password);
};
export const forgetWalletPassword = () => {
- clearStoredPassword();
- walletPassword.set(undefined);
+ clearStoredPassword();
+ walletPassword.set(undefined);
};
export const getRememberedWalletPassword = () => {
- const password = loadStoredPassword();
- walletPassword.set(password);
- return password;
+ const password = loadStoredPassword();
+ walletPassword.set(password);
+ return password;
};
diff --git a/src/lib/punks.ts b/src/lib/punks.ts
index 8b7b53df..e5551062 100644
--- a/src/lib/punks.ts
+++ b/src/lib/punks.ts
@@ -1,66 +1,66 @@
export default [
- "6e1f1626a9308abd0b7732fecbc7d49366ced46dead63ef3603fb0f4ec7aa53d",
- "96ea95735b61c48c6f465db8ca0246a62539f34c3a977be6338770d92461da89",
- "8c18c036b257d7b9c5a970a786efa04c320f3cf5afa73fa310a6603744d1ee3a",
- "a7a6187e54e83acdb893d456c8b4ad6877e4738ea9e0d47c9b2070bf2c98a35f",
- "836d72150b6f3033b6220d15ac9d49457d81041a700d12898bd3b8e737b4d265",
- "e3d1c40538a8aed282a430647e3ff16ff94b64b8ed0a7cf427e8b0e2780a9b2a",
- "2155224ef35cfb4bbdb06d982b42bb9b93d97b2bc691c22c804e1759a0a04882",
- "5f6549ad9dd15dd57c204b1a9b60c68c376e77d7d114cfa13219e6a1a71f901f",
- "ba8dd5a7070aee7102d4f8bc83ac497091e2e473a0f448a1c513569167dd0791",
- "4f07e1da3685a858970a9f39300564971e97257f5d37b55a6d9882014aecc421",
- "01aa9348244c4b65de3df758d49c98076e17a109aef04bc211abc77cf42dc51d",
- "080574eb9e0613926e0e5d9b667c132e12965a1b1d47218a0b290a2d55c55d2f",
- "08ce4840184f63a779bcd1f91bbcb56a2e8cba75c3ba2dbd290a559a57e4238e",
- "27caa38c14a85ad64b4c4469a34e61a3965a1cbc4cad9a85707da374301c830d",
- "eccc90741370ba4acc70bc65f4ccc38fddb1327d977c366156018974bc52fe4a",
- "3759946d9e875ac2fc5c51ed850686193bb1e0716219e42efd52f3965993b275",
- "db5fe28b8ddb9ae5e4f5e0e757ee60bc938bffbdfdd38de807939e212d3c5066",
- "3f8f861e663accee51e68b987705ce647a7446b7f118abc94c632e158acbb44f",
- "43bab95a047112dca6705506f916a97252363a20da4a4c0a5ab7b676e11083fc",
- "d3018e45c66dd485697f738ad191af98267e6255d562496dd06b1a662e0c7a88",
- "0ec2e8d07e053d686140857493ece653cde52764a60aa1d25651d81811d44a3d",
- "4595bb092682af7177799464364c047fbfa7ede767336734949bce5d085fce15",
- "6524936709e0719f9e28bf1caac91f86f323d1a79f10ab65a03fa9ea2e6b3270",
- "8ba4736edc68da8e5b21c23af4de1f9131f47778c2a5b2a970a799223a9380b3",
- "2aaba839e8546a8cb6d04a81ff5be83ac4e700ca4491607a16ebd60dc4995750",
- "5f88f7f579ce50d7bcf60d6e9556f77acf361ba54caf3eb61dc4f2ca9c94c6a2",
- "d1ca262272613d7386fecce7f1ad268188940b59ea83fdd1f8d7ab85771e3f43",
- "5211890e4128d8d730802cc75ee105867e8878581d5e72ffc98a0d60027a5398",
- "c1dececcbd7b623bfaa726392512e6ea110db93a0649dd01bf9e559318514f7c",
- "43ce93c9835e983403a01329918d184832c5516e1b0ea4e0878b4c4def042777",
- "c84724a398bda8d20436fb0663d059c196628fa71192bb720fa5adf6137bed9b",
- "f307620a90a36045fa550316d61be4755c1f6c7f3fc81c95fc4d590ac568b2c4",
- "78ae0118856a1f17c13f292628fcf3dccc150c7278578caaceb9f35ca8bc9f55",
- "9d9a9a40c490f05d7dbafde8bf60d68aab7dcb79a7976eef62d1448a4549816b",
- "f6017bec50563dbbb24b979214ae225f96b01dea5b090b174038ff2842a1c6b1",
- "6dbec748ea87e959390b0df429c005fccffe9e672864f555c14c7a407b940870",
- "11701e76233395ebdba8d1d50334d1a0cc3a158f3452260c9a7b9a067b78d753",
- "7354f3829dd05c838aa16d66b00316f7994797927a4d3b594c8af04a2b4ae86a",
- "14d254333c6240fbdacbbbe261f7ae15be2e83bffcf084f4f59f459bae0a4571",
- "7849ac0f31056265efb0110038f86e61effe17b7db836377d88433b73312e65a",
- "9018be885177c675baf9b36978428d841ca30a9185e11de1a31238a08e3ec1af",
- "777c5715de7423597fea6c03c496ea46414f0508cd96e119261f002965beb805",
- "b742b7509a97c2b346ea762f0510e8475b30dc988417f0f146ae00a800c6dd56",
- "7af3029a826e6dfba23ad502901a3632ef4ee047bd45d618b1f106717b0af7ea",
- "82390020b2bca461204cc49b20ee6fec1b93dad476726f377785d04040a4d6c3",
- "6bc2990699be7f610c9f6a49bc7a19b034040727bc3de63fee89a1573fe00673",
- "50c7c2e8e8c7f4aabffb195187a1ac1105f5712859f02d491d794ba2d8498e08",
- "5d1d3769cd141603ce907df5dca159e389ca4d75338eddbe1b7db1c0766cbfd6",
- "4d8ad7a761d068b7ef9b058fb4ba924b276e7a45a3ad47a79b767e08e821e038",
- "d5b5b2167602f7277cdac76cfda8bdad0befcb8ff12df495dfabf40c91d1120c",
- "6f2618272bb0164247e9b0f40b19f020c1c9253510dc658a3cc078d079ef01bf",
- "fd502d5007bfc62a91eb7a34c1ae23b9de4a20cf5e1bbd86dadc421d7083099c",
- "914813583b901044970b9c7d6dcdfde4344339325f5988d0dd681d377f1243fb",
- "85cb7cf0245613d08b3027f879f58a6db645bf0db107242beb856b340ee49ee8",
- "d6dbb18d5df5e92c8c74ee59aa86d19dff25a5d0f9d030e84285a686f86804d7",
- "65309f82cd9f9926a578d09e1ad13909f68a06d02b853760731a4225f7aecef4",
- "433519d13f2b64fe82a90cd054797d4779507fea93c1054bd51c35ba846a0f7f",
- "62a55d4d6e4b6f992a1c1840f041585c957affcdbf875202cf9e1db9def05aeb",
- "e19eb1eeabdeffa04ccd792eb09776690cf2121887b26a7c5d20d66e3e8fd0fb",
- "a80951fc593035abb2dda045a2076d29a30f5cc470e0a20db39c3ec588ed61d8",
- "4f1b39906714266a7a1936bfa8e08c5d891285dd2b188b4bcd4afb0107671004",
- "f46310b2e60727af071d09e759814f52f933688a0ff0995c7da373b381e70005",
- "2cc94821f56d21918ba4f2770d97f280e06fd99f4199167e2f4ddc780f404c8a",
- "698a2ca7a09e88fa6594801da037f4dbce6ae841d1d33736aebcf8f6fe104e01",
+ "6e1f1626a9308abd0b7732fecbc7d49366ced46dead63ef3603fb0f4ec7aa53d",
+ "96ea95735b61c48c6f465db8ca0246a62539f34c3a977be6338770d92461da89",
+ "8c18c036b257d7b9c5a970a786efa04c320f3cf5afa73fa310a6603744d1ee3a",
+ "a7a6187e54e83acdb893d456c8b4ad6877e4738ea9e0d47c9b2070bf2c98a35f",
+ "836d72150b6f3033b6220d15ac9d49457d81041a700d12898bd3b8e737b4d265",
+ "e3d1c40538a8aed282a430647e3ff16ff94b64b8ed0a7cf427e8b0e2780a9b2a",
+ "2155224ef35cfb4bbdb06d982b42bb9b93d97b2bc691c22c804e1759a0a04882",
+ "5f6549ad9dd15dd57c204b1a9b60c68c376e77d7d114cfa13219e6a1a71f901f",
+ "ba8dd5a7070aee7102d4f8bc83ac497091e2e473a0f448a1c513569167dd0791",
+ "4f07e1da3685a858970a9f39300564971e97257f5d37b55a6d9882014aecc421",
+ "01aa9348244c4b65de3df758d49c98076e17a109aef04bc211abc77cf42dc51d",
+ "080574eb9e0613926e0e5d9b667c132e12965a1b1d47218a0b290a2d55c55d2f",
+ "08ce4840184f63a779bcd1f91bbcb56a2e8cba75c3ba2dbd290a559a57e4238e",
+ "27caa38c14a85ad64b4c4469a34e61a3965a1cbc4cad9a85707da374301c830d",
+ "eccc90741370ba4acc70bc65f4ccc38fddb1327d977c366156018974bc52fe4a",
+ "3759946d9e875ac2fc5c51ed850686193bb1e0716219e42efd52f3965993b275",
+ "db5fe28b8ddb9ae5e4f5e0e757ee60bc938bffbdfdd38de807939e212d3c5066",
+ "3f8f861e663accee51e68b987705ce647a7446b7f118abc94c632e158acbb44f",
+ "43bab95a047112dca6705506f916a97252363a20da4a4c0a5ab7b676e11083fc",
+ "d3018e45c66dd485697f738ad191af98267e6255d562496dd06b1a662e0c7a88",
+ "0ec2e8d07e053d686140857493ece653cde52764a60aa1d25651d81811d44a3d",
+ "4595bb092682af7177799464364c047fbfa7ede767336734949bce5d085fce15",
+ "6524936709e0719f9e28bf1caac91f86f323d1a79f10ab65a03fa9ea2e6b3270",
+ "8ba4736edc68da8e5b21c23af4de1f9131f47778c2a5b2a970a799223a9380b3",
+ "2aaba839e8546a8cb6d04a81ff5be83ac4e700ca4491607a16ebd60dc4995750",
+ "5f88f7f579ce50d7bcf60d6e9556f77acf361ba54caf3eb61dc4f2ca9c94c6a2",
+ "d1ca262272613d7386fecce7f1ad268188940b59ea83fdd1f8d7ab85771e3f43",
+ "5211890e4128d8d730802cc75ee105867e8878581d5e72ffc98a0d60027a5398",
+ "c1dececcbd7b623bfaa726392512e6ea110db93a0649dd01bf9e559318514f7c",
+ "43ce93c9835e983403a01329918d184832c5516e1b0ea4e0878b4c4def042777",
+ "c84724a398bda8d20436fb0663d059c196628fa71192bb720fa5adf6137bed9b",
+ "f307620a90a36045fa550316d61be4755c1f6c7f3fc81c95fc4d590ac568b2c4",
+ "78ae0118856a1f17c13f292628fcf3dccc150c7278578caaceb9f35ca8bc9f55",
+ "9d9a9a40c490f05d7dbafde8bf60d68aab7dcb79a7976eef62d1448a4549816b",
+ "f6017bec50563dbbb24b979214ae225f96b01dea5b090b174038ff2842a1c6b1",
+ "6dbec748ea87e959390b0df429c005fccffe9e672864f555c14c7a407b940870",
+ "11701e76233395ebdba8d1d50334d1a0cc3a158f3452260c9a7b9a067b78d753",
+ "7354f3829dd05c838aa16d66b00316f7994797927a4d3b594c8af04a2b4ae86a",
+ "14d254333c6240fbdacbbbe261f7ae15be2e83bffcf084f4f59f459bae0a4571",
+ "7849ac0f31056265efb0110038f86e61effe17b7db836377d88433b73312e65a",
+ "9018be885177c675baf9b36978428d841ca30a9185e11de1a31238a08e3ec1af",
+ "777c5715de7423597fea6c03c496ea46414f0508cd96e119261f002965beb805",
+ "b742b7509a97c2b346ea762f0510e8475b30dc988417f0f146ae00a800c6dd56",
+ "7af3029a826e6dfba23ad502901a3632ef4ee047bd45d618b1f106717b0af7ea",
+ "82390020b2bca461204cc49b20ee6fec1b93dad476726f377785d04040a4d6c3",
+ "6bc2990699be7f610c9f6a49bc7a19b034040727bc3de63fee89a1573fe00673",
+ "50c7c2e8e8c7f4aabffb195187a1ac1105f5712859f02d491d794ba2d8498e08",
+ "5d1d3769cd141603ce907df5dca159e389ca4d75338eddbe1b7db1c0766cbfd6",
+ "4d8ad7a761d068b7ef9b058fb4ba924b276e7a45a3ad47a79b767e08e821e038",
+ "d5b5b2167602f7277cdac76cfda8bdad0befcb8ff12df495dfabf40c91d1120c",
+ "6f2618272bb0164247e9b0f40b19f020c1c9253510dc658a3cc078d079ef01bf",
+ "fd502d5007bfc62a91eb7a34c1ae23b9de4a20cf5e1bbd86dadc421d7083099c",
+ "914813583b901044970b9c7d6dcdfde4344339325f5988d0dd681d377f1243fb",
+ "85cb7cf0245613d08b3027f879f58a6db645bf0db107242beb856b340ee49ee8",
+ "d6dbb18d5df5e92c8c74ee59aa86d19dff25a5d0f9d030e84285a686f86804d7",
+ "65309f82cd9f9926a578d09e1ad13909f68a06d02b853760731a4225f7aecef4",
+ "433519d13f2b64fe82a90cd054797d4779507fea93c1054bd51c35ba846a0f7f",
+ "62a55d4d6e4b6f992a1c1840f041585c957affcdbf875202cf9e1db9def05aeb",
+ "e19eb1eeabdeffa04ccd792eb09776690cf2121887b26a7c5d20d66e3e8fd0fb",
+ "a80951fc593035abb2dda045a2076d29a30f5cc470e0a20db39c3ec588ed61d8",
+ "4f1b39906714266a7a1936bfa8e08c5d891285dd2b188b4bcd4afb0107671004",
+ "f46310b2e60727af071d09e759814f52f933688a0ff0995c7da373b381e70005",
+ "2cc94821f56d21918ba4f2770d97f280e06fd99f4199167e2f4ddc780f404c8a",
+ "698a2ca7a09e88fa6594801da037f4dbce6ae841d1d33736aebcf8f6fe104e01",
];
diff --git a/src/lib/random.ts b/src/lib/random.ts
index 36dde0cc..605471ac 100644
--- a/src/lib/random.ts
+++ b/src/lib/random.ts
@@ -1,20 +1,20 @@
import {
- NumberDictionary,
- animals,
- colors,
- uniqueNamesGenerator,
+ NumberDictionary,
+ animals,
+ colors,
+ uniqueNamesGenerator,
} from "unique-names-generator";
export const randomName = () =>
- uniqueNamesGenerator({
- dictionaries: [animals, NumberDictionary.generate({ min: 10, max: 99 })],
- length: 2,
- separator: "",
- });
+ uniqueNamesGenerator({
+ dictionaries: [animals, NumberDictionary.generate({ min: 10, max: 99 })],
+ length: 2,
+ separator: "",
+ });
export const randomPassword = () =>
- uniqueNamesGenerator({
- dictionaries: [colors, NumberDictionary.generate({ min: 100, max: 999 })],
- length: 2,
- separator: "",
- });
+ uniqueNamesGenerator({
+ dictionaries: [colors, NumberDictionary.generate({ min: 100, max: 999 })],
+ length: 2,
+ separator: "",
+ });
diff --git a/src/lib/rates.ts b/src/lib/rates.ts
index 96aaeac2..5d55550d 100644
--- a/src/lib/rates.ts
+++ b/src/lib/rates.ts
@@ -4,10 +4,10 @@ let last;
let rates;
export default async function getRates() {
- if (!rates || Date.now() - last > 60000) {
- rates = await get("/rates");
- last = Date.now();
- }
+ if (!rates || Date.now() - last > 60000) {
+ rates = await get("/rates");
+ last = Date.now();
+ }
- return rates;
+ return rates;
}
diff --git a/src/lib/samples.ts b/src/lib/samples.ts
index ae7ef6d5..172efca0 100644
--- a/src/lib/samples.ts
+++ b/src/lib/samples.ts
@@ -1,52 +1,52 @@
import { PUBLIC_COINOS_URL, PUBLIC_DOMAIN } from "$env/static/public";
const api = PUBLIC_DOMAIN.includes("localhost")
- ? `${PUBLIC_COINOS_URL}`
- : `https://${PUBLIC_DOMAIN}/api`;
+ ? `${PUBLIC_COINOS_URL}`
+ : `https://${PUBLIC_DOMAIN}/api`;
export default {
- me: `curl "${api}/me" -H "content-type: application/json"`,
- update: `curl "${api}/user" -H "content-type: application/json" -d '{
+ me: `curl "${api}/me" -H "content-type: application/json"`,
+ update: `curl "${api}/user" -H "content-type: application/json" -d '{
"username": "demo",
}'`,
- register: `curl "${api}/register" -H "content-type: application/json" -d '{
+ register: `curl "${api}/register" -H "content-type: application/json" -d '{
"user": {
"username": "demo",
"password": "hunter2"
}
}'`,
- login: `curl "${api}/login" -H "content-type: application/json" -d '{
+ login: `curl "${api}/login" -H "content-type: application/json" -d '{
"username": "demo",
"password": "hunter2"
}'`,
- payments: `curl "${api}/payments"
+ payments: `curl "${api}/payments"
-H "content-type: application/json"
-H "Authorization: Bearer $token"
`,
- lightning: `curl "${api}/payments"
+ lightning: `curl "${api}/payments"
-H "content-type: application/json"
-H "Authorization: Bearer $token"
-d '{
"payreq": "lnbc1pj94d8fsp5n77k340ps4m9jn7kp8he8yynpddvurv6mcsrrqpnq5l2jxdxzlwqpp5m96pqhc5nrlk8cqsu9ufdxxa43sarp8vwf9egvm2pg9nl0zu9r8qdq2vdhkjmn0wvxqztgcqpjrzjqwhmav82kntsppmkp8jp4vg4h9nns78tsy8mg7ve4lq5txrkp0h56zlarvqqdtcqqsqqqqqqqqqqp6cq9q9qyysgqzxlypywzphyujm3ga5j5csfcmqvlnae0fgnvymkaaw94eeg7py5rqzysyjkr3ev2snq63qpsc69vf54adkd0szvmvwt5cuadjnuy95sq4xfa40"
}'`,
- bitcoin: `curl "${api}/bitcoin/send"
+ bitcoin: `curl "${api}/bitcoin/send"
-H "content-type: application/json"
-H "Authorization: Bearer $token"
-d '{
"amount": 5000,
"address": "bc1q3unh97w4rmelflrm2hvdwz37d8kray3vn4d5ca"
}'`,
- internal: `curl "${api}/send"
+ internal: `curl "${api}/send"
-H "content-type: application/json"
-H "Authorization: Bearer $token"
-d '{
"amount": 5000,
"username": "alice"
}'`,
- rates: `curl "${api}/rates"
+ rates: `curl "${api}/rates"
-H "content-type: application/json"
}'`,
- lightningInvoice: `curl "${api}/invoice"
+ lightningInvoice: `curl "${api}/invoice"
-H "content-type: application/json"
-H "Authorization: Bearer $token"
-d '{
@@ -55,7 +55,7 @@ export default {
"type": "lightning"
}
}'`,
- bitcoinAddress: `curl "${api}/invoice"
+ bitcoinAddress: `curl "${api}/invoice"
-H "content-type: application/json"
-H "Authorization: Bearer $token"
-d '{
@@ -64,7 +64,7 @@ export default {
"type": "bitcoin"
}
}'`,
- webhook: `curl "${api}/invoice"
+ webhook: `curl "${api}/invoice"
-H "content-type: application/json"
-H "Authorization: Bearer $token"
-d '{
@@ -74,9 +74,9 @@ export default {
"secret": "webhooksecret"
}
}'`,
- fetchInvoice: `curl "${api}/invoice/bc1qmhfk9stzffhd9umzmld92vff7zg3mdlh7rvvaj"
+ fetchInvoice: `curl "${api}/invoice/bc1qmhfk9stzffhd9umzmld92vff7zg3mdlh7rvvaj"
-H "content-type: application/json"'`,
- invoiceResponse: `{
+ invoiceResponse: `{
"amount":3141
"tip":0
"type":"bitcoin"
@@ -89,5 +89,5 @@ export default {
"received":0
"created":1677537428134
}`,
- socketAuth: `echo '{"type":"login","data":{"username":"user","password":"password"}}' | websocat -n https://coinos.io/ws`,
+ socketAuth: `echo '{"type":"login","data":{"username":"user","password":"password"}}' | websocat -n https://coinos.io/ws`,
};
diff --git a/src/lib/settings.ts b/src/lib/settings.ts
index 6f4d3f62..a3b875c0 100644
--- a/src/lib/settings.ts
+++ b/src/lib/settings.ts
@@ -2,28 +2,28 @@ import { auth, fd, post } from "$lib/utils";
import { fail } from "@sveltejs/kit";
type Error = {
- message: string;
+ message: string;
};
export default async ({ cookies, request }) => {
- const form = await fd(request);
+ const form = await fd(request);
- if (form.tab === "account") {
- form.notify = form.notify === "on";
- form.push = form.push === "on";
- form.nip5 = form.nip5 === "on";
- form.prompt = form.prompt === "on";
- form.autowithdraw = form.autowithdraw === "on";
- }
+ if (form.tab === "account") {
+ form.notify = form.notify === "on";
+ form.push = form.push === "on";
+ form.nip5 = form.nip5 === "on";
+ form.prompt = form.prompt === "on";
+ form.autowithdraw = form.autowithdraw === "on";
+ }
- try {
- const { user } = await post("/user", form, auth(cookies));
+ try {
+ const { user } = await post("/user", form, auth(cookies));
- if (user.language) cookies.set("lang", user.language, { path: "/" });
+ if (user.language) cookies.set("lang", user.language, { path: "/" });
- return { user, success: true };
- } catch (e) {
- const { message } = e as Error;
- return fail(400, { message });
- }
+ return { user, success: true };
+ } catch (e) {
+ const { message } = e as Error;
+ return fail(400, { message });
+ }
};
diff --git a/src/lib/socket.ts b/src/lib/socket.ts
index b87cc165..e40eb39b 100644
--- a/src/lib/socket.ts
+++ b/src/lib/socket.ts
@@ -12,57 +12,57 @@ let token;
export const auth = () => token && send("login", token);
export const send = async (type, data) => {
- try {
- await wait(() => socket?.readyState === 1, 1000, 10);
- } catch (e) {
- const { message } = e as Error;
- if (message === "timeout") reconnectToWebsocket();
- }
+ try {
+ await wait(() => socket?.readyState === 1, 1000, 10);
+ } catch (e) {
+ const { message } = e as Error;
+ if (message === "timeout") reconnectToWebsocket();
+ }
- await wait(() => socket?.readyState === 1, 1000, 10);
- socket.send(JSON.stringify({ type, data }));
+ await wait(() => socket?.readyState === 1, 1000, 10);
+ socket.send(JSON.stringify({ type, data }));
};
export const messages = (data) => ({
- id() {
- last.set(Date.now());
- },
- invoice() {
- invoice.set(data);
- },
- event() {
- event.set(data);
- },
+ id() {
+ last.set(Date.now());
+ },
+ invoice() {
+ invoice.set(data);
+ },
+ event() {
+ event.set(data);
+ },
- request() {
- request.set(data);
- invalidate("app:invoice");
- },
+ request() {
+ request.set(data);
+ invalidate("app:invoice");
+ },
- async payment() {
- const { amount, confirmed, iid } = data;
- invalidate("app:user");
- invalidate("app:invoice");
- invalidate("app:payments");
+ async payment() {
+ const { amount, confirmed, iid } = data;
+ invalidate("app:user");
+ invalidate("app:invoice");
+ invalidate("app:payments");
- const {
- url: { pathname },
- } = get(page);
+ const {
+ url: { pathname },
+ } = get(page);
- const username = cookies.get("username");
+ const username = cookies.get("username");
- if (amount > 0) {
- if (
- pathname.includes(`/${username}`) ||
- pathname.includes("/receive") ||
- pathname.includes("/invoice")
- ) {
- if (!get(navigating)) goto(`/invoice/${iid}`);
- } else success(`${confirmed ? "Received" : "Detected"} ⚡️${s(amount)}!`);
- }
- },
+ if (amount > 0) {
+ if (
+ pathname.includes(`/${username}`) ||
+ pathname.includes("/receive") ||
+ pathname.includes("/invoice")
+ ) {
+ if (!get(navigating)) goto(`/invoice/${iid}`);
+ } else success(`${confirmed ? "Received" : "Detected"} ⚡️${s(amount)}!`);
+ }
+ },
- connected: auth,
+ connected: auth,
});
const initialReconnectDelay = 1000;
@@ -72,51 +72,51 @@ let currentReconnectDelay = initialReconnectDelay;
let connecting;
export function connect(t) {
- if (connecting) return;
- connecting = true;
- setTimeout(() => {
- connecting = false;
- }, 5000);
+ if (connecting) return;
+ connecting = true;
+ setTimeout(() => {
+ connecting = false;
+ }, 5000);
- token = t;
+ token = t;
- if (socket) return auth();
+ if (socket) return auth();
- socket = new WebSocket(PUBLIC_SOCKET);
- socket.addEventListener("open", onWebsocketOpen);
- socket.addEventListener("close", onWebsocketClose);
- socket.addEventListener("message", onWebsocketMessage);
+ socket = new WebSocket(PUBLIC_SOCKET);
+ socket.addEventListener("open", onWebsocketOpen);
+ socket.addEventListener("close", onWebsocketClose);
+ socket.addEventListener("message", onWebsocketMessage);
}
export function close() {
- if (socket) socket.close();
+ if (socket) socket.close();
}
async function onWebsocketMessage(msg) {
- const { type, data } = JSON.parse(msg.data);
- if (get(navigating)) await sleep(2000);
+ const { type, data } = JSON.parse(msg.data);
+ if (get(navigating)) await sleep(2000);
- if (messages(data)[type]) messages(data)[type]();
+ if (messages(data)[type]) messages(data)[type]();
}
function onWebsocketOpen() {
- currentReconnectDelay = initialReconnectDelay;
- send("heartbeat", token);
+ currentReconnectDelay = initialReconnectDelay;
+ send("heartbeat", token);
}
function onWebsocketClose() {
- socket = null;
- setTimeout(
- () => {
- reconnectToWebsocket();
- },
- currentReconnectDelay + Math.floor(Math.random() * 3000),
- );
+ socket = null;
+ setTimeout(
+ () => {
+ reconnectToWebsocket();
+ },
+ currentReconnectDelay + Math.floor(Math.random() * 3000),
+ );
}
function reconnectToWebsocket() {
- if (currentReconnectDelay < maxReconnectDelay) {
- currentReconnectDelay *= 2;
- }
- connect(token);
+ if (currentReconnectDelay < maxReconnectDelay) {
+ currentReconnectDelay *= 2;
+ }
+ connect(token);
}
diff --git a/src/lib/store.ts b/src/lib/store.ts
index 7cd17aec..e14d107f 100644
--- a/src/lib/store.ts
+++ b/src/lib/store.ts
@@ -2,73 +2,73 @@ import { browser } from "$app/environment";
import { writable } from "svelte/store";
export const persistSession = (key, defaultValue = undefined) => {
- const s = writable(
- browser &&
- sessionStorage.getItem(key) &&
- sessionStorage.getItem(key) !== "undefined"
- ? JSON.parse(sessionStorage.getItem(key) || "")
- : defaultValue,
- );
+ const s = writable(
+ browser &&
+ sessionStorage.getItem(key) &&
+ sessionStorage.getItem(key) !== "undefined"
+ ? JSON.parse(sessionStorage.getItem(key) || "")
+ : defaultValue,
+ );
- s.subscribe((v) => {
- browser && sessionStorage.setItem(key, JSON.stringify(v));
- });
+ s.subscribe((v) => {
+ browser && sessionStorage.setItem(key, JSON.stringify(v));
+ });
- return s;
+ return s;
};
export const persistLocal = (key, defaultValue: any = undefined) => {
- const s = writable(
- browser &&
- localStorage.getItem(key) &&
- localStorage.getItem(key) !== "undefined"
- ? JSON.parse(localStorage.getItem(key) || "")
- : defaultValue,
- );
+ const s = writable(
+ browser &&
+ localStorage.getItem(key) &&
+ localStorage.getItem(key) !== "undefined"
+ ? JSON.parse(localStorage.getItem(key) || "")
+ : defaultValue,
+ );
- s.subscribe((v) => {
- try {
- if (browser) {
- if (v) {
- localStorage.setItem(key, JSON.stringify(v));
- } else {
- localStorage.removeItem(key);
- }
- }
- } catch (e) {
- console.log("problem setting key", v);
- console.log(e);
- }
- });
+ s.subscribe((v) => {
+ try {
+ if (browser) {
+ if (v) {
+ localStorage.setItem(key, JSON.stringify(v));
+ } else {
+ localStorage.removeItem(key);
+ }
+ }
+ } catch (e) {
+ console.log("problem setting key", v);
+ console.log(e);
+ }
+ });
- return s;
+ return s;
};
export const persistLocalValue = (key, defaultValue: any = undefined) => {
- const s = writable(
- browser &&
- localStorage.getItem(key) &&
- localStorage.getItem(key) !== "undefined"
- ? JSON.parse(localStorage.getItem(key) || "")
- : defaultValue,
- );
+ const s = writable(
+ browser &&
+ localStorage.getItem(key) &&
+ localStorage.getItem(key) !== "undefined"
+ ? JSON.parse(localStorage.getItem(key) || "")
+ : defaultValue,
+ );
- s.subscribe((v) => {
- try {
- if (browser) {
- if (v === undefined) {
- localStorage.removeItem(key);
- } else {
- localStorage.setItem(key, JSON.stringify(v));
- }
- }
- } catch (e) {
- console.log("problem setting key", v);
- console.log(e);
- }
- });
+ s.subscribe((v) => {
+ try {
+ if (browser) {
+ if (v === undefined) {
+ localStorage.removeItem(key);
+ } else {
+ localStorage.setItem(key, JSON.stringify(v));
+ }
+ }
+ } catch (e) {
+ console.log("problem setting key", v);
+ console.log(e);
+ }
+ });
- return s;
+ return s;
};
export const account = writable();
diff --git a/src/lib/ticket.ts b/src/lib/ticket.ts
index 0d93f390..48ed1a66 100644
--- a/src/lib/ticket.ts
+++ b/src/lib/ticket.ts
@@ -3,29 +3,29 @@ import { env } from "$env/dynamic/private";
import tickets from "$lib/tickets";
export const createTicket = async (cookies, username) => {
- const { ticket } = await get("/ticket");
+ const { ticket } = await get("/ticket");
- const { address } = await post(
- `/${username}/invoice`,
- { invoice: { network: "liquid" }, user: { username } },
- auth(cookies),
- );
+ const { address } = await post(
+ `/${username}/invoice`,
+ { invoice: { network: "liquid" }, user: { username } },
+ auth(cookies),
+ );
- const { asset } = await post(
- "/assets",
- {
- address,
- name: `Launch Party Ticket ${ticket}`,
- ticker: "LPT",
- precision: 0,
- asset_amount: "1",
- token_amount: 0,
- domain: "coinos.io",
- filename: tickets[ticket],
- },
- { authorization: `Bearer ${env.LAUNCH}` },
- );
+ const { asset } = await post(
+ "/assets",
+ {
+ address,
+ name: `Launch Party Ticket ${ticket}`,
+ ticker: "LPT",
+ precision: 0,
+ asset_amount: "1",
+ token_amount: 0,
+ domain: "coinos.io",
+ filename: tickets[ticket],
+ },
+ { authorization: `Bearer ${env.LAUNCH}` },
+ );
- await post("/ticket", { asset }, { authorization: `Bearer ${env.LAUNCH}` });
- return asset;
+ await post("/ticket", { asset }, { authorization: `Bearer ${env.LAUNCH}` });
+ return asset;
};
diff --git a/src/lib/tickets.ts b/src/lib/tickets.ts
index f37fad78..1f8cbdac 100644
--- a/src/lib/tickets.ts
+++ b/src/lib/tickets.ts
@@ -1,52 +1,52 @@
export default [
- "QmPbFkiXNuaQyfwD4W9GcXP7qWaNd6wFd9KCnJir5mes1J",
- "QmPVjvbaMxSJRpDxMLYTdUWQbknej1vYLckBQ2pAgxZgJN",
- "QmVasycSFzCYhyXrcvTE7mN3d6W78RFnrhzg5cRF6Dp6Zq",
- "QmTmnhjpTBjZdeHwXgT9Dftc3uWMW73qsZpZ5ECrTyiKKZ",
- "QmWDBiyVPyFkzUrEdvy7DSJe1rBQpene1m6quKAtyjBP6a",
- "QmcxxzQZwgG7SE9QbHNvoTiCi6Dhs9rrz9roqvxm2JQA88",
- "Qmd9ThEpXLLHimEzRUWEFrAGLSw5PAHzn2SmwfCnjNLwWt",
- "Qmc7pWw1yxc2ARBWitDMYiyPkWK61NsXXU8oYAQwNAvcx1",
- "QmX9Hgw1rMFUgBBuq8QfZZDzLjN5xCED19fwFdDeDDqwmr",
- "QmconCAyNyaagqKvvfKCbG7Eu8c6vCtkv2ivvxMoFN9YwA",
- "QmWbFmvViy5gx4JdD5sw5YJETet4ZQcXtYgijYnrsnSZ3a",
- "QmP6QiiJwoqkduZMqdd5e5htHZ4aYHCsvEu7WEEUknKYa5",
- "QmefHk8hvBUHsuKugntok5u75Q8i886cnPwsj4LZZB6uWg",
- "QmdrSDK5ByYHxc88hfDu8hQgK5XYFpXSfPorUXdyTbE437",
- "QmZ6ZycjRzYpsjnLm1Lfgk1fXXDdhcYRkyfmqYJZVGwADy",
- "QmSkBxS5yLPjB2VPs89oQRZANsoyodK6s8s52E8GKXr2zt",
- "QmSn8TCPwq3UZ1Z4eyko76CvQo2H2Hyef1NGboDQN22m5i",
- "QmP6CTH5zrKMzZwtjy7VaK9NXiq4Gw53kmuRjUbJjeovoe",
- "QmdwT4yvz9Xf8g3t6irKRoh3Wa7MwRQrcUJckQxyQe1Bc5",
- "QmcwuHH3bD5JExqjDvKqRQ3V5xEVGqs94qPNVDzaCqJa5a",
- "QmRfVduHwn8sXwSoyfgZpxSi8L7EjP4LMp6fmijo9VApDp",
- "Qmc4TGj1Ahbg9HJ9WDXDm2bXsNkT4zRDp8Wdw9wqqdEwuH",
- "QmY8uQiHMWA8ztf2wAurNFW7eiTHQEUiLTQ2vGceMwVqz3",
- "QmXiXbaD12F4mkbUSQcKhWshkPU4oi29cUawZGnPk86VVU",
- "QmZaiAGjvBZBw4suz33s9JQNzY2Kshean2mQQPCa6gKMQe",
- "Qme8bDSdzX7tanPYf672xXW8vPdkLkeSLqLzHJqidRXsYJ",
- "QmRJirjuUKgh2AMyBF4jNquaXHFPBtDJf3gKFC614hX7qu",
- "QmdRoSKSgabcrpekNBPB6T47RBtJnCETYE8ry2a3P37MUe",
- "QmXoqArruHSghrUGW35vVQHPknBG5Cj939iWWHHXU3B616",
- "QmYCxtDuoHLMAFhNpifUsLU9ptAeFKwyxSiSEJhDQLMZtN",
- "QmQZQBw8wgzUsrmVDEejdePK23AEJbk9aUracvxLPyHz2x",
- "QmSsbu7U3i62AQKuYqfisRo5E6nqdMZfHRKWYJgouaXDxD",
- "QmaP4adVQuWyqtN4QCXeYXj4nr19Je4EqsaTG1zM9ywqFS",
- "QmPPsvgfXsiN3wNqdAwHAhQVpw6SZWNpry9Na6R2Xb7zXY",
- "QmR7z6wQmcfZUvRsVK83GRRboyvwZEDQujLwumMY33nAit",
- "QmQXgkgorDLPUyQpFbW8aLUW6jioQjUKamtXw5UuNCttDg",
- "QmcwYBeXt1BPfdSrtSrXFpWctRZ7RDHvmKTttC5hPPTSzG",
- "QmTUexZnw3xPy3YVdUsqJALwTvy2qFax5b3QpJVMvTCJQb",
- "QmNLkYXFUvctpfeeDTZxruZE2f834EUnYMM6JJUeTcUB4J",
- "QmT7544UaTPgKFYMCpPE4unXphNGX71BLZBPKLkxAijSmj",
- "QmTpVR4dqX1QV4fae5pZ1ACtRcANHwEWCLwpMXFmwE95Sm",
- "Qmdfyps5fW8d8wstXMfpvpei2DTmaADBWgmxLT7e7uan4P",
- "QmUSK8byipYoG3H97QpmPrHw9vYrvHygyhkiM81XmaKyxS",
- "QmQUGRvp96LTw5i8Ly9f5LoMvUpeQHCLGNqC88KV74wEHK",
- "Qma693TFLh9Z1MeBFzhPHi6Yk4tmTcZY2jogwJ8cPkU2B4",
- "QmNu8FyMpmkFdbCXGRVG8mKJtMvvCoLP8LNzFsxBQwxQeS",
- "QmWZHE87PKujL1MGLuFgP3D12o5GQxYbvbeTRgr12f1XMu",
- "QmcZJn8gPGd3poS9yuiNJh6iP4cn9uy5fnypky71r4sSSw",
- "QmTwrAF4E9ucpdnrUZFj6EfrQamGv7Qyn7ceSx1DUQYceC",
- "QmexssxU5iTXypgNqrmrQwMDJnTNxyZUxor5wDLnwb5TZp",
+ "QmPbFkiXNuaQyfwD4W9GcXP7qWaNd6wFd9KCnJir5mes1J",
+ "QmPVjvbaMxSJRpDxMLYTdUWQbknej1vYLckBQ2pAgxZgJN",
+ "QmVasycSFzCYhyXrcvTE7mN3d6W78RFnrhzg5cRF6Dp6Zq",
+ "QmTmnhjpTBjZdeHwXgT9Dftc3uWMW73qsZpZ5ECrTyiKKZ",
+ "QmWDBiyVPyFkzUrEdvy7DSJe1rBQpene1m6quKAtyjBP6a",
+ "QmcxxzQZwgG7SE9QbHNvoTiCi6Dhs9rrz9roqvxm2JQA88",
+ "Qmd9ThEpXLLHimEzRUWEFrAGLSw5PAHzn2SmwfCnjNLwWt",
+ "Qmc7pWw1yxc2ARBWitDMYiyPkWK61NsXXU8oYAQwNAvcx1",
+ "QmX9Hgw1rMFUgBBuq8QfZZDzLjN5xCED19fwFdDeDDqwmr",
+ "QmconCAyNyaagqKvvfKCbG7Eu8c6vCtkv2ivvxMoFN9YwA",
+ "QmWbFmvViy5gx4JdD5sw5YJETet4ZQcXtYgijYnrsnSZ3a",
+ "QmP6QiiJwoqkduZMqdd5e5htHZ4aYHCsvEu7WEEUknKYa5",
+ "QmefHk8hvBUHsuKugntok5u75Q8i886cnPwsj4LZZB6uWg",
+ "QmdrSDK5ByYHxc88hfDu8hQgK5XYFpXSfPorUXdyTbE437",
+ "QmZ6ZycjRzYpsjnLm1Lfgk1fXXDdhcYRkyfmqYJZVGwADy",
+ "QmSkBxS5yLPjB2VPs89oQRZANsoyodK6s8s52E8GKXr2zt",
+ "QmSn8TCPwq3UZ1Z4eyko76CvQo2H2Hyef1NGboDQN22m5i",
+ "QmP6CTH5zrKMzZwtjy7VaK9NXiq4Gw53kmuRjUbJjeovoe",
+ "QmdwT4yvz9Xf8g3t6irKRoh3Wa7MwRQrcUJckQxyQe1Bc5",
+ "QmcwuHH3bD5JExqjDvKqRQ3V5xEVGqs94qPNVDzaCqJa5a",
+ "QmRfVduHwn8sXwSoyfgZpxSi8L7EjP4LMp6fmijo9VApDp",
+ "Qmc4TGj1Ahbg9HJ9WDXDm2bXsNkT4zRDp8Wdw9wqqdEwuH",
+ "QmY8uQiHMWA8ztf2wAurNFW7eiTHQEUiLTQ2vGceMwVqz3",
+ "QmXiXbaD12F4mkbUSQcKhWshkPU4oi29cUawZGnPk86VVU",
+ "QmZaiAGjvBZBw4suz33s9JQNzY2Kshean2mQQPCa6gKMQe",
+ "Qme8bDSdzX7tanPYf672xXW8vPdkLkeSLqLzHJqidRXsYJ",
+ "QmRJirjuUKgh2AMyBF4jNquaXHFPBtDJf3gKFC614hX7qu",
+ "QmdRoSKSgabcrpekNBPB6T47RBtJnCETYE8ry2a3P37MUe",
+ "QmXoqArruHSghrUGW35vVQHPknBG5Cj939iWWHHXU3B616",
+ "QmYCxtDuoHLMAFhNpifUsLU9ptAeFKwyxSiSEJhDQLMZtN",
+ "QmQZQBw8wgzUsrmVDEejdePK23AEJbk9aUracvxLPyHz2x",
+ "QmSsbu7U3i62AQKuYqfisRo5E6nqdMZfHRKWYJgouaXDxD",
+ "QmaP4adVQuWyqtN4QCXeYXj4nr19Je4EqsaTG1zM9ywqFS",
+ "QmPPsvgfXsiN3wNqdAwHAhQVpw6SZWNpry9Na6R2Xb7zXY",
+ "QmR7z6wQmcfZUvRsVK83GRRboyvwZEDQujLwumMY33nAit",
+ "QmQXgkgorDLPUyQpFbW8aLUW6jioQjUKamtXw5UuNCttDg",
+ "QmcwYBeXt1BPfdSrtSrXFpWctRZ7RDHvmKTttC5hPPTSzG",
+ "QmTUexZnw3xPy3YVdUsqJALwTvy2qFax5b3QpJVMvTCJQb",
+ "QmNLkYXFUvctpfeeDTZxruZE2f834EUnYMM6JJUeTcUB4J",
+ "QmT7544UaTPgKFYMCpPE4unXphNGX71BLZBPKLkxAijSmj",
+ "QmTpVR4dqX1QV4fae5pZ1ACtRcANHwEWCLwpMXFmwE95Sm",
+ "Qmdfyps5fW8d8wstXMfpvpei2DTmaADBWgmxLT7e7uan4P",
+ "QmUSK8byipYoG3H97QpmPrHw9vYrvHygyhkiM81XmaKyxS",
+ "QmQUGRvp96LTw5i8Ly9f5LoMvUpeQHCLGNqC88KV74wEHK",
+ "Qma693TFLh9Z1MeBFzhPHi6Yk4tmTcZY2jogwJ8cPkU2B4",
+ "QmNu8FyMpmkFdbCXGRVG8mKJtMvvCoLP8LNzFsxBQwxQeS",
+ "QmWZHE87PKujL1MGLuFgP3D12o5GQxYbvbeTRgr12f1XMu",
+ "QmcZJn8gPGd3poS9yuiNJh6iP4cn9uy5fnypky71r4sSSw",
+ "QmTwrAF4E9ucpdnrUZFj6EfrQamGv7Qyn7ceSx1DUQYceC",
+ "QmexssxU5iTXypgNqrmrQwMDJnTNxyZUxor5wDLnwb5TZp",
];
diff --git a/src/lib/types.ts b/src/lib/types.ts
index 19277ec1..827f96aa 100644
--- a/src/lib/types.ts
+++ b/src/lib/types.ts
@@ -1,23 +1,23 @@
export interface Message {
- author: User;
- created_at: number;
- recipient: User;
+ author: User;
+ created_at: number;
+ recipient: User;
}
export interface Note {
- created_at: number;
- seen: number;
+ created_at: number;
+ seen: number;
}
export interface User {
- id: string;
+ id: string;
}
export interface Invoice {
- aid: string;
- id?: string;
- memoPrompt?: boolean;
- memo?: string;
- rate: number;
- type?: string;
+ aid: string;
+ id?: string;
+ memoPrompt?: boolean;
+ memo?: string;
+ rate: number;
+ type?: string;
}
diff --git a/src/lib/upload.ts b/src/lib/upload.ts
index 6d9d4230..aaeec007 100644
--- a/src/lib/upload.ts
+++ b/src/lib/upload.ts
@@ -1,18 +1,18 @@
export const upload = async (file, type, progress) => {
- const url = `/api/upload/${type}`;
- const formData = new FormData();
- formData.append("file", file);
+ const url = `/api/upload/${type}`;
+ const formData = new FormData();
+ formData.append("file", file);
- return new Promise((resolve, reject) => {
- const ajax = new XMLHttpRequest();
- ajax.addEventListener("load", () => {
- if (ajax.readyState === ajax.DONE) {
- if (ajax.status === 200) resolve(ajax.response);
- else reject(new Error(`Upload failed: ${ajax.response}`));
- }
- });
- ajax.upload.addEventListener("progress", progress, false);
- ajax.open("POST", url);
- ajax.send(formData);
- });
+ return new Promise((resolve, reject) => {
+ const ajax = new XMLHttpRequest();
+ ajax.addEventListener("load", () => {
+ if (ajax.readyState === ajax.DONE) {
+ if (ajax.status === 200) resolve(ajax.response);
+ else reject(new Error(`Upload failed: ${ajax.response}`));
+ }
+ });
+ ajax.upload.addEventListener("progress", progress, false);
+ ajax.open("POST", url);
+ ajax.send(formData);
+ });
};
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 45afb90b..ebec6caa 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -6,16 +6,16 @@ import { bytesToHex } from "@noble/hashes/utils.js";
import { fail as svelteFail, redirect } from "@sveltejs/kit";
import { toast } from "@zerodevx/svelte-toast";
import {
- differenceInDays,
- differenceInHours,
- differenceInMinutes,
- differenceInSeconds,
+ differenceInDays,
+ differenceInHours,
+ differenceInMinutes,
+ differenceInSeconds,
} from "date-fns";
import { get as getStore } from "svelte/store";
export function scroll(section: any) {
- if (getStore(page).url.pathname !== "/") goto("/");
- setTimeout(() => section.scrollIntoView({ behavior: "smooth" }), 500);
+ if (getStore(page).url.pathname !== "/") goto("/");
+ setTimeout(() => section.scrollIntoView({ behavior: "smooth" }), 500);
}
const base = browser ? "" : PUBLIC_COINOS_URL;
@@ -23,523 +23,530 @@ const base = browser ? "" : PUBLIC_COINOS_URL;
let getIp: (() => string | undefined) | undefined;
export const setIpGetter = (fn: () => string | undefined) => {
- getIp = fn;
+ getIp = fn;
};
const ipHeaders = (): Record<string, string> => {
- const ip = getIp?.();
- return ip ? { "cf-connecting-ip": ip } : {};
+ const ip = getIp?.();
+ return ip ? { "cf-connecting-ip": ip } : {};
};
export const punk = (k: string) =>
- `${Math.floor((parseInt(k.slice(-2), 16) / 256) * 64) + 1}.webp`;
+ `${Math.floor((parseInt(k.slice(-2), 16) / 256) * 64) + 1}.webp`;
export const g = (url: string, fetch: any, headers: object) =>
- fetch(base + url, { headers: { ...ipHeaders(), ...headers } })
- .then((r: Response) => r.text())
- .then((body: string) => {
- try {
- return JSON.parse(body);
- } catch (e) {
- throw new Error(body);
- }
- });
+ fetch(base + url, { headers: { ...ipHeaders(), ...headers } })
+ .then((r: Response) => r.text())
+ .then((body: string) => {
+ try {
+ return JSON.parse(body);
+ } catch {
+ throw new Error(body);
+ }
+ });
export const get = (url: string, headers = {}) => {
- return fetch(base + url, { headers: { ...ipHeaders(), ...headers } })
- .then(async (r) => {
- if (r.ok) return r.text();
- throw new Error(await r.text());
- })
- .then((body) => {
- try {
- return JSON.parse(body);
- } catch (e) {
- return body;
- }
- });
+ return fetch(base + url, { headers: { ...ipHeaders(), ...headers } })
+ .then(async (r) => {
+ if (r.ok) return r.text();
+ throw new Error(await r.text());
+ })
+ .then((body) => {
+ try {
+ return JSON.parse(body);
+ } catch {
+ return body;
+ }
+ });
};
export const post = async (
- url: string,
- body: object,
- headers: HeadersInit | undefined = undefined,
+ url: string,
+ body: object,
+ headers: HeadersInit | undefined = undefined,
) => {
- headers = {
- "content-type": "application/json",
- accept: "application/json",
- ...ipHeaders(),
- ...headers,
- };
+ headers = {
+ "content-type": "application/json",
+ accept: "application/json",
+ ...ipHeaders(),
+ ...headers,
+ };
- const response = await fetch(base + url, {
- method: "POST",
- body: JSON.stringify(body),
- headers,
- })
- .then(async (r) => {
- if (r.ok) return r.text();
- const text = await r.text();
+ const response = await fetch(base + url, {
+ method: "POST",
+ body: JSON.stringify(body),
+ headers,
+ })
+ .then(async (r) => {
+ if (r.ok) return r.text();
+ const text = await r.text();
- let message;
- try {
- ({ message } = JSON.parse(text));
- } catch (e) {}
+ let message;
+ try {
+ ({ message } = JSON.parse(text));
+ } catch {}
- if (message) throw new Error(message);
- throw new Error(text);
- })
- .then((body) => {
- let json;
- try {
- json = JSON.parse(body);
- } catch (e) {
- throw new Error(body);
- }
+ if (message) throw new Error(message);
+ throw new Error(text);
+ })
+ .then((body) => {
+ let json;
+ try {
+ json = JSON.parse(body);
+ } catch {
+ throw new Error(body);
+ }
- if (json.error instanceof Error) throw json.error;
- if (json instanceof Error) throw body;
- if (json.name === "Error") throw new Error(json.message);
+ if (json.error instanceof Error) throw json.error;
+ if (json instanceof Error) throw body;
+ if (json.name === "Error") throw new Error(json.message);
- return json;
- });
+ return json;
+ });
- return response;
+ return response;
};
export const copy = (text: string) => {
- navigator.clipboard.writeText(text);
- success("Copied!");
+ navigator.clipboard.writeText(text);
+ success("Copied!");
};
export const copyNoNewlines = (text: string) => {
- const stripped = text.replace(/\n/g, " ").replace(/\s+/g, " ");
- navigator.clipboard.writeText(stripped);
- success("Copied!");
+ const stripped = text.replace(/\n/g, " ").replace(/\s+/g, " ");
+ navigator.clipboard.writeText(stripped);
+ success("Copied!");
};
let recent: string[] = [];
export const success = (m: string, clear = true) => {
- if (recent.includes(m)) return;
- recent.push(m);
- setTimeout(() => (recent = []), 5000);
- if (clear) toast.pop();
- toast.push(m, {
- theme: {
- "--toastBarBackground": "#F5F7FA",
- },
- });
+ if (recent.includes(m)) return;
+ recent.push(m);
+ setTimeout(() => (recent = []), 5000);
+ if (clear) toast.pop();
+ toast.push(m, {
+ theme: {
+ "--toastBarBackground": "#F5F7FA",
+ },
+ });
};
export const warning = (m: string, clear = true) => {
- if (clear) toast.pop();
- toast.push(m, {
- theme: {
- "--toastBarBackground": "#FFCE22",
- },
- });
+ if (clear) toast.pop();
+ toast.push(m, {
+ theme: {
+ "--toastBarBackground": "#FFCE22",
+ },
+ });
};
export const fail = (m: string, clear = true) => {
- if (clear) toast.pop();
- toast.push(m, {
- theme: {
- "--toastBarBackground": "#E93535",
- },
- });
+ if (clear) toast.pop();
+ toast.push(m, {
+ theme: {
+ "--toastBarBackground": "#E93535",
+ },
+ });
};
export const info = (m: string) => {
- toast.pop();
- toast.push(m, {
- theme: {
- "--toastBarBackground": "white",
- },
- });
+ toast.pop();
+ toast.push(m, {
+ theme: {
+ "--toastBarBackground": "white",
+ },
+ });
};
export const login = async (
- user: {
- username: string;
- password: string;
- token?: string;
- challenge?: string;
- recaptcha?: string;
- },
- cookies,
- ip: string,
- host?: string,
- extraHeaders?: Record<string, string>,
+ user: {
+ username: string;
+ password: string;
+ token?: string;
+ challenge?: string;
+ recaptcha?: string;
+ },
+ cookies,
+ ip: string,
+ host?: string,
+ extraHeaders?: Record<string, string>,
) => {
- const maxAge = 380 * 24 * 60 * 60;
+ const maxAge = 380 * 24 * 60 * 60;
- const headers: Record<string, string> = {
- "content-type": "application/json",
- accept: "application/json",
- "cf-connecting-ip": ip,
- ...extraHeaders,
- };
- if (host) headers["x-forwarded-host"] = host;
+ const headers: Record<string, string> = {
+ "content-type": "application/json",
+ accept: "application/json",
+ "cf-connecting-ip": ip,
+ ...extraHeaders,
+ };
+ if (host) headers["x-forwarded-host"] = host;
- const res = await fetch(`${base}/login`, {
- method: "POST",
- body: JSON.stringify(user),
- headers,
- });
+ const res = await fetch(`${base}/login`, {
+ method: "POST",
+ body: JSON.stringify(user),
+ headers,
+ });
- const text = await res.text();
+ const text = await res.text();
- if (res.status === 401) {
- if (text.startsWith("2fa")) throw new Error("2fa");
- throw new Error(text);
- }
+ if (res.status === 401) {
+ if (text.startsWith("2fa")) throw new Error("2fa");
+ throw new Error(text);
+ }
- const { user: u, token } = JSON.parse(text);
- if (!token) throw new Error("Login failed");
+ const { user: u, token } = JSON.parse(text);
+ if (!token) throw new Error("Login failed");
- const expires = new Date();
- expires.setSeconds(expires.getSeconds() + maxAge);
+ const expires = new Date();
+ expires.setSeconds(expires.getSeconds() + maxAge);
- const opts = { path: "/", expires };
- if (u.language) cookies.set("lang", u.language, opts);
- cookies.set("username", user.username, opts);
- cookies.set("token", token, opts);
- if (u.nsec) {
- try {
- const { decrypt } = await import("nostr-tools/nip49");
- cookies.set("sk", bytesToHex(decrypt(u.nsec, user.password)), {
- ...opts,
- httpOnly: false,
- sameSite: "lax",
- });
- } catch (e) {}
- }
+ const opts = { path: "/", expires };
+ if (u.language) cookies.set("lang", u.language, opts);
+ cookies.set("username", user.username, opts);
+ cookies.set("token", token, opts);
+ if (u.nsec) {
+ try {
+ const { decrypt } = await import("nostr-tools/nip49");
+ cookies.set("sk", bytesToHex(decrypt(u.nsec, user.password)), {
+ ...opts,
+ httpOnly: false,
+ sameSite: "lax",
+ });
+ } catch {}
+ }
};
export const auth = (cookies) => ({
- authorization: `Bearer ${cookies.get("token")}`,
+ authorization: `Bearer ${cookies.get("token")}`,
});
export const isInvalidTokenError = (e: unknown) => {
- const message = (e as Error)?.message || "";
- if (!message) return false;
- const normalized = message.toLowerCase();
- return (
- normalized.includes("jwt") ||
- normalized.includes("invalid token") ||
- normalized.includes("token expired") ||
- normalized.includes("expired token") ||
- normalized.includes("unauthorized") ||
- normalized.includes("not authorized")
- );
+ const message = (e as Error)?.message || "";
+ if (!message) return false;
+ const normalized = message.toLowerCase();
+ return (
+ normalized.includes("jwt") ||
+ normalized.includes("invalid token") ||
+ normalized.includes("token expired") ||
+ normalized.includes("expired token") ||
+ normalized.includes("unauthorized") ||
+ normalized.includes("not authorized")
+ );
};
export const btc = (fiat: number, rate: number): number =>
- Math.round((fiat * sats) / rate);
+ Math.round((fiat * sats) / rate);
export const toFiat = (amount: number, rate: number): number =>
- (amount * rate) / sats;
+ (amount * rate) / sats;
export const fd = async (req: Request): Promise<any> => {
- const obj: Record<string, any> = Object.fromEntries(await req.formData());
- for (const k in obj)
- (obj[k] === "undefined" && (obj[k] = undefined)) ||
- (obj[k] === "false" && (obj[k] = false));
- return obj;
+ const obj: Record<string, any> = Object.fromEntries(await req.formData());
+ for (const k in obj)
+ (obj[k] === "undefined" && (obj[k] = undefined)) ||
+ (obj[k] === "false" && (obj[k] = false));
+ return obj;
};
const map = {
- en: {
- CAD: "en-CA",
- USD: "en-US",
- GBP: "en-GB",
- AUD: "en-AU",
- EUR: "en-IE", // Eurozone English (Ireland)
- NZD: "en-NZ",
- JPY: "en-JP", // English in Japan
- INR: "en-IN", // English in India
- ZAR: "en-ZA", // South Africa
- },
- fr: {
- CAD: "fr-CA", // French Canada
- EUR: "fr-FR", // France
- CHF: "fr-CH", // French Switzerland
- XOF: "fr-SN", // Francophone West Africa
- },
- de: {
- EUR: "de-DE", // Germany
- CHF: "de-CH", // German Switzerland
- USD: "de-US", // German for the US
- },
- es: {
- EUR: "es-ES", // Spain
- USD: "es-US", // Spanish for the US
- MXN: "es-MX", // Mexico
- ARS: "es-AR", // Argentina
- CLP: "es-CL", // Chile
- },
- pt: {
- EUR: "pt-PT", // Portugal
- BRL: "pt-BR", // Brazil
- },
- zh: {
- CNY: "zh-CN", // Simplified Chinese (Mainland China)
- HKD: "zh-HK", // Traditional Chinese (Hong Kong)
- TWD: "zh-TW", // Traditional Chinese (Taiwan)
- USD: "zh-US", // Chinese for the US
- },
- ja: {
- JPY: "ja-JP", // Japan
- USD: "ja-US", // Japanese for the US
- },
- ru: {
- RUB: "ru-RU", // Russia
- USD: "ru-US", // Russian for the US
- },
- el: {
- EUR: "el-GR", // Greece
- },
- fa: {
- IRR: "fa-IR", // Iran
- },
- // Global currency mappings (fallbacks)
- CAD: "en-CA",
- USD: "en-US",
- GBP: "en-GB",
- AUD: "en-AU",
- EUR: "en-IE",
- NZD: "en-NZ",
- JPY: "ja-JP",
- INR: "en-IN",
- ZAR: "en-ZA",
- CHF: "de-CH",
- MXN: "es-MX",
- BRL: "pt-BR",
- CNY: "zh-CN",
- HKD: "zh-HK",
- TWD: "zh-TW",
- RUB: "ru-RU",
- IRR: "fa-IR",
+ en: {
+ CAD: "en-CA",
+ USD: "en-US",
+ GBP: "en-GB",
+ AUD: "en-AU",
+ EUR: "en-IE", // Eurozone English (Ireland)
+ NZD: "en-NZ",
+ JPY: "en-JP", // English in Japan
+ INR: "en-IN", // English in India
+ ZAR: "en-ZA", // South Africa
+ },
+ fr: {
+ CAD: "fr-CA", // French Canada
+ EUR: "fr-FR", // France
+ CHF: "fr-CH", // French Switzerland
+ XOF: "fr-SN", // Francophone West Africa
+ },
+ de: {
+ EUR: "de-DE", // Germany
+ CHF: "de-CH", // German Switzerland
+ USD: "de-US", // German for the US
+ },
+ es: {
+ EUR: "es-ES", // Spain
+ USD: "es-US", // Spanish for the US
+ MXN: "es-MX", // Mexico
+ ARS: "es-AR", // Argentina
+ CLP: "es-CL", // Chile
+ },
+ pt: {
+ EUR: "pt-PT", // Portugal
+ BRL: "pt-BR", // Brazil
+ },
+ zh: {
+ CNY: "zh-CN", // Simplified Chinese (Mainland China)
+ HKD: "zh-HK", // Traditional Chinese (Hong Kong)
+ TWD: "zh-TW", // Traditional Chinese (Taiwan)
+ USD: "zh-US", // Chinese for the US
+ },
+ ja: {
+ JPY: "ja-JP", // Japan
+ USD: "ja-US", // Japanese for the US
+ },
+ ru: {
+ RUB: "ru-RU", // Russia
+ USD: "ru-US", // Russian for the US
+ },
+ el: {
+ EUR: "el-GR", // Greece
+ },
+ fa: {
+ IRR: "fa-IR", // Iran
+ },
+ // Global currency mappings (fallbacks)
+ CAD: "en-CA",
+ USD: "en-US",
+ GBP: "en-GB",
+ AUD: "en-AU",
+ EUR: "en-IE",
+ NZD: "en-NZ",
+ JPY: "ja-JP",
+ INR: "en-IN",
+ ZAR: "en-ZA",
+ CHF: "de-CH",
+ MXN: "es-MX",
+ BRL: "pt-BR",
+ CNY: "zh-CN",
+ HKD: "zh-HK",
+ TWD: "zh-TW",
+ RUB: "ru-RU",
+ IRR: "fa-IR",
};
export const loc = (user) => {
- if (!user) return;
- const { currency: c, language: l } = user;
- return map[l]?.[c] || map[c];
+ if (!user) return;
+ const { currency: c, language: l } = user;
+ return map[l]?.[c] || map[c];
};
export const f = (
- s: number,
- currency: string,
- locale = "en-US",
- minimumFractionDigits = 2,
- maximumFractionDigits = 2,
+ s: number,
+ currency: string,
+ locale = "en-US",
+ minimumFractionDigits = 2,
+ maximumFractionDigits = 2,
) => {
- const l = typeof locale === "function" ? locale() : locale || "en-US";
- const cur = currency || "USD";
- const region = l.length >= 2 ? l.slice(-2) : "";
- const currencyDisplay =
- region && cur.startsWith(region) ? "narrowSymbol" : "symbol";
- return new Intl.NumberFormat(l, {
- style: "currency",
- currency: cur,
- currencyDisplay,
- minimumFractionDigits,
- maximumFractionDigits,
- }).format(s);
+ const l = typeof locale === "function" ? locale() : locale || "en-US";
+ const cur = currency || "USD";
+ const region = l.length >= 2 ? l.slice(-2) : "";
+ const currencyDisplay =
+ region && cur.startsWith(region) ? "narrowSymbol" : "symbol";
+ return new Intl.NumberFormat(l, {
+ style: "currency",
+ currency: cur,
+ currencyDisplay,
+ minimumFractionDigits,
+ maximumFractionDigits,
+ }).format(s);
};
export const s = (s: number, locale = "en-US"): string => {
- const l = typeof locale === "function" ? locale() : locale || "en-US";
- return new Intl.NumberFormat(l, { maximumFractionDigits: 0 }).format(s);
+ const l = typeof locale === "function" ? locale() : locale || "en-US";
+ return new Intl.NumberFormat(l, { maximumFractionDigits: 0 }).format(s);
};
export const sat = (s: number): string => `${si(Math.abs(s)).toString()}`;
export const si = (
- n: number,
- minimumFractionDigits = 1,
- maximumFractionDigits = 2,
+ n: number,
+ minimumFractionDigits = 1,
+ maximumFractionDigits = 2,
) => {
- const units = ["", "K", "M", "G", "T", "P", "E", "Z"];
+ const units = ["", "K", "M", "G", "T", "P", "E", "Z"];
- let s = n;
- let d = 0;
- if (s >= 1000) {
- d = Math.floor(Math.log10(s) / 3); // Calculate the unit index
- s = n / 1000 ** d; // Scale the number to the correct unit
- }
+ let s = n;
+ let d = 0;
+ if (s >= 1000) {
+ d = Math.floor(Math.log10(s) / 3); // Calculate the unit index
+ s = n / 1000 ** d; // Scale the number to the correct unit
+ }
- return (
- new Intl.NumberFormat("en-US", {
- minimumFractionDigits,
- maximumFractionDigits,
- }).format(s) + units[d]
- );
+ return (
+ new Intl.NumberFormat("en-US", {
+ minimumFractionDigits,
+ maximumFractionDigits,
+ }).format(s) + units[d]
+ );
};
export const sats = 100000000;
export const back = (): any =>
- browser && (history.length ? history.go(-1) : goto("/"));
+ browser && (history.length ? history.go(-1) : goto("/"));
export const focus = (el: HTMLElement): any =>
- browser && screen.width > 1280 && setTimeout(() => el.focus(), 1);
+ browser && screen.width > 1280 && setTimeout(() => el.focus(), 1);
export const select = (el: HTMLInputElement): any =>
- browser && screen.width > 1280 && setTimeout(() => el.select(), 1);
+ browser && screen.width > 1280 && setTimeout(() => el.select(), 1);
export const sleep = (n: number): Promise<void> =>
- new Promise((r) => setTimeout(r, n));
+ new Promise((r) => setTimeout(r, n));
export const wait = async (
- f: () => boolean | Promise<boolean>,
- n = 100,
- s = 300,
+ f: () => boolean | Promise<boolean>,
+ n = 100,
+ s = 300,
): Promise<boolean> => {
- let i = 0;
- while (!(await f()) && i < s) {
- await sleep(n);
- i++;
- }
- if (i >= s) throw new Error("timeout");
- return f();
+ let i = 0;
+ while (!(await f()) && i < s) {
+ await sleep(n);
+ i++;
+ }
+ if (i >= s) throw new Error("timeout");
+ return f();
};
export const types = {
ark: "ark",
- bitcoin: "bitcoin",
- liquid: "liquid",
- lightning: "lightning",
- internal: "internal",
- fund: "fund",
- ecash: "ecash",
- bolt12: "bolt12",
+ bitcoin: "bitcoin",
+ liquid: "liquid",
+ lightning: "lightning",
+ internal: "internal",
+ fund: "fund",
+ ecash: "ecash",
+ bolt12: "bolt12",
};
export const ease = (t: number): number =>
- t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
+ t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
export function shuffleArray<T>(array: T[]): void {
- for (let i = array.length - 1; i > 0; i--) {
- const j = Math.floor(Math.random() * (i + 1));
- [array[i], array[j]] = [array[j], array[i]];
- }
+ for (let i = array.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [array[i], array[j]] = [array[j], array[i]];
+ }
}
export const closest = (a: number[], n: number): number =>
- a.reduce((prev, curr) =>
- Math.abs(curr - n) < Math.abs(prev - n) ? curr : prev,
- );
+ a.reduce((prev, curr) =>
+ Math.abs(curr - n) < Math.abs(prev - n) ? curr : prev,
+ );
export const isLiquid = (text: string): boolean =>
- text.startsWith("Az") ||
- text.startsWith("lq1") ||
- text.startsWith("VJL") ||
- text.startsWith("VT") ||
- text.startsWith("XR") ||
- text.startsWith("XC") ||
- ((text.startsWith("H") || text.startsWith("G") || text.startsWith("Q")) &&
- text.length === 34) ||
- (text.startsWith("ert1q") && text.length === 43) ||
- (text.startsWith("ex1q") && text.length === 42) ||
- text.startsWith("el1qq") ||
- text.startsWith("lq1qq");
+ text.startsWith("Az") ||
+ text.startsWith("lq1") ||
+ text.startsWith("VJL") ||
+ text.startsWith("VT") ||
+ text.startsWith("XR") ||
+ text.startsWith("XC") ||
+ ((text.startsWith("H") || text.startsWith("G") || text.startsWith("Q")) &&
+ text.length === 34) ||
+ (text.startsWith("ert1q") && text.length === 43) ||
+ (text.startsWith("ex1q") && text.length === 42) ||
+ text.startsWith("el1qq") ||
+ text.startsWith("lq1qq");
export function getCookie(name: string): string | null {
- const nameEQ = `${name}=`;
- const ca = document.cookie.split(";");
- for (let i = 0; i < ca.length; i++) {
- let c = ca[i];
- while (c.charAt(0) === " ") c = c.substring(1);
- if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
- }
- return null;
+ const nameEQ = `${name}=`;
+ const ca = document.cookie.split(";");
+ for (let i = 0; i < ca.length; i++) {
+ let c = ca[i];
+ while (c.charAt(0) === " ") c = c.substring(1);
+ if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
+ }
+ return null;
}
export function setCookie(name: string, value: string, seconds: number): void {
- const now = new Date();
- now.setTime(now.getTime() + seconds * 1000);
- const expires = `expires=${now.toUTCString()}`;
- document.cookie = `${name}=${value};${expires};path=/`;
+ const now = new Date();
+ now.setTime(now.getTime() + seconds * 1000);
+ const expires = `expires=${now.toUTCString()}`;
+ document.cookie = `${name}=${value};${expires};path=/`;
}
export const network = {
- bitcoin: {
- bech32: "bc",
- pubKeyHash: 0x00,
- scriptHash: 0x05,
- wif: 0x80,
- },
- regtest: {
- bech32: "bcrt",
- pubKeyHash: 0x6f,
- scriptHash: 0xc4,
- wif: 0xef,
- },
+ bitcoin: {
+ bech32: "bc",
+ pubKeyHash: 0x00,
+ scriptHash: 0x05,
+ wif: 0x80,
+ },
+ regtest: {
+ bech32: "bcrt",
+ pubKeyHash: 0x6f,
+ scriptHash: 0xc4,
+ wif: 0xef,
+ },
}[PUBLIC_COINOS_NETWORK];
export const versions = {
- bitcoin: {
- private: 0x0488ade4,
- public: 0x0488b21e,
- },
- regtest: {
- private: 0x04358394,
- public: 0x043587cf,
- },
+ bitcoin: {
+ private: 0x0488ade4,
+ public: 0x0488b21e,
+ },
+ regtest: {
+ private: 0x04358394,
+ public: 0x043587cf,
+ },
}[PUBLIC_COINOS_NETWORK];
export const str = (s) => s.toString();
export const ago = (t) => {
- const now = new Date();
- const date = new Date(t * 1000);
- const seconds = differenceInSeconds(now, date);
- if (seconds < 60) return `${seconds}s`;
+ const now = new Date();
+ const date = new Date(t * 1000);
+ const seconds = differenceInSeconds(now, date);
+ if (seconds < 60) return `${seconds}s`;
- const minutes = differenceInMinutes(now, date);
- if (minutes < 60) return `${minutes}m`;
+ const minutes = differenceInMinutes(now, date);
+ if (minutes < 60) return `${minutes}m`;
- const hours = differenceInHours(now, date);
- if (hours < 24) return `${hours}h`;
+ const hours = differenceInHours(now, date);
+ if (hours < 24) return `${hours}h`;
- const days = differenceInDays(now, date);
- return `${days}d`;
+ const days = differenceInDays(now, date);
+ return `${days}d`;
};
-export const register = async (user, ip, cookies, loginRedirect, host?, extraHeaders?: Record<string, string>) => {
- let error;
+export const register = async (
+ user,
+ ip,
+ cookies,
+ loginRedirect,
+ host?,
+ extraHeaders?: Record<string, string>,
+) => {
+ let error;
- const headers: Record<string, string> = {
- ...extraHeaders,
- };
- if (ip) headers["cf-connecting-ip"] = ip;
+ const headers: Record<string, string> = {
+ ...extraHeaders,
+ };
+ if (ip) headers["cf-connecting-ip"] = ip;
- let sk;
- try {
- ({ sk } = await post("/register", { user }, headers));
- } catch (e) {
- ({ message: error } = e as Error);
- }
+ let sk;
+ try {
+ ({ sk } = await post("/register", { user }, headers));
+ } catch (e) {
+ ({ message: error } = e as Error);
+ }
- try {
- await login(user, cookies, ip, host, extraHeaders);
- error = null;
- } catch (e) {
- const { message } = e as Error;
- error ||= message;
- }
+ try {
+ await login(user, cookies, ip, host, extraHeaders);
+ error = null;
+ } catch (e) {
+ const { message } = e as Error;
+ error ||= message;
+ }
- const expires = new Date();
- expires.setSeconds(expires.getSeconds() + 21000000);
- cookies.set("sk", sk, {
- path: "/",
- expires,
- httpOnly: false,
- sameSite: "lax",
- });
+ const expires = new Date();
+ expires.setSeconds(expires.getSeconds() + 21000000);
+ cookies.set("sk", sk, {
+ path: "/",
+ expires,
+ httpOnly: false,
+ sameSite: "lax",
+ });
- if (error) return svelteFail(400, { error });
- redirect(303, loginRedirect || `/${user.username}`);
+ if (error) return svelteFail(400, { error });
+ redirect(303, loginRedirect || `/${user.username}`);
};
diff --git a/src/routes/(app)/+layout.server.ts b/src/routes/(app)/+layout.server.ts
index 8b694241..3b29df70 100644
--- a/src/routes/(app)/+layout.server.ts
+++ b/src/routes/(app)/+layout.server.ts
@@ -2,63 +2,63 @@ import { auth, get, isInvalidTokenError, sleep } from "$lib/utils";
import { error, redirect } from "@sveltejs/kit";
export async function load({ cookies, request, url, params }) {
- const { pathname } = url;
- const { id, username } = params;
- const token = cookies.get("token");
+ const { pathname } = url;
+ const { id, username } = params;
+ const token = cookies.get("token");
- let user;
- if (token) {
- try {
- user = await get("/me", auth(cookies));
- } catch (e) {
- const { message } = e as Error;
- if (message.startsWith("Rate")) {
- await sleep(3000);
- try {
- user = await get("/me", auth(cookies));
- } catch (retryError) {
- if (isInvalidTokenError(retryError) && pathname !== "/logout") {
- redirect(307, "/logout");
- }
- throw retryError;
- }
- } else if (isInvalidTokenError(e) && pathname !== "/logout") {
- redirect(307, "/logout");
- } else {
- throw e;
- }
- }
- }
+ let user;
+ if (token) {
+ try {
+ user = await get("/me", auth(cookies));
+ } catch (e) {
+ const { message } = e as Error;
+ if (message.startsWith("Rate")) {
+ await sleep(3000);
+ try {
+ user = await get("/me", auth(cookies));
+ } catch (retryError) {
+ if (isInvalidTokenError(retryError) && pathname !== "/logout") {
+ redirect(307, "/logout");
+ }
+ throw retryError;
+ }
+ } else if (isInvalidTokenError(e) && pathname !== "/logout") {
+ redirect(307, "/logout");
+ } else {
+ throw e;
+ }
+ }
+ }
- let subject;
+ let subject;
- if (url.pathname.includes("/invoice") && id) {
- try {
- ({ user: subject } = await get(`/invoice/${id}`));
- } catch (e) {
- console.log("unable to fetch invoice", id, e);
- }
- } else if (username) {
- try {
- subject = await get(`/users/${username}`);
- } catch (e) {
- error(500, "Unable to retrieve user account data");
- }
- }
+ if (url.pathname.includes("/invoice") && id) {
+ try {
+ ({ user: subject } = await get(`/invoice/${id}`));
+ } catch (e) {
+ console.log("unable to fetch invoice", id, e);
+ }
+ } else if (username) {
+ try {
+ subject = await get(`/users/${username}`);
+ } catch {
+ error(500, "Unable to retrieve user account data");
+ }
+ }
- if (user?.needsMigration) {
- redirect(307, "/migrate");
- }
+ if (user?.needsMigration) {
+ redirect(307, "/migrate");
+ }
- if (
- user &&
- ["/login", "/register"].includes(pathname) &&
- request.method === "GET"
- ) {
- redirect(307, `/${user.username}`);
- }
+ if (
+ user &&
+ ["/login", "/register"].includes(pathname) &&
+ request.method === "GET"
+ ) {
+ redirect(307, `/${user.username}`);
+ }
- const theme = cookies.get("theme") || "light";
+ const theme = cookies.get("theme") || "light";
- return { user, token, subject, theme };
+ return { user, token, subject, theme };
}
diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte
index 6ac9bed5..346cc93e 100644
--- a/src/routes/(app)/+layout.svelte
+++ b/src/routes/(app)/+layout.svelte
@@ -24,7 +24,12 @@
import Password from "$comp/Password.svelte";
import { s, f, toFiat, success, getCookie, warning } from "$lib/utils";
import { t, locale, loading } from "$lib/translations";
- import { goto, invalidate, afterNavigate, preloadData } from "$app/navigation";
+ import {
+ goto,
+ invalidate,
+ afterNavigate,
+ preloadData,
+ } from "$app/navigation";
let { data, children } = $props();
@@ -58,7 +63,9 @@
if (result?.received > 0) {
if ($fiat && $rateStore && user?.currency) {
- success(`Received ${f(toFiat(result.received, $rateStore), user.currency)}!`);
+ success(
+ `Received ${f(toFiat(result.received, $rateStore), user.currency)}!`,
+ );
} else {
success(`Received ⚡️${s(result.received)}!`);
}
diff --git a/src/routes/(app)/[username]/(profile)/+layout.server.ts b/src/routes/(app)/[username]/(profile)/+layout.server.ts
index 251388e5..9c916d7a 100644
--- a/src/routes/(app)/[username]/(profile)/+layout.server.ts
+++ b/src/routes/(app)/[username]/(profile)/+layout.server.ts
@@ -1,10 +1,10 @@
import getRates from "$lib/rates";
export async function load({ depends, parent }) {
- depends("app:user");
+ depends("app:user");
- const rates = await getRates();
- const { subject, user } = await parent();
+ const rates = await getRates();
+ const { subject } = await parent();
- return { rate: rates[subject.currency] };
+ return { rate: rates[subject.currency] };
}
diff --git a/src/routes/(app)/[username]/(profile)/+layout.svelte b/src/routes/(app)/[username]/(profile)/+layout.svelte
index 8331c98e..1bb9447f 100644
--- a/src/routes/(app)/[username]/(profile)/+layout.svelte
+++ b/src/routes/(app)/[username]/(profile)/+layout.svelte
@@ -291,7 +291,7 @@
</div>
<div class="text-secondary flex ml-auto items-center gap-1">
{#if satsPerCurrency >= 1}
- <div>{f(1, currency, locale)} &#61; </div>
+ <div>{f(1, currency, locale)} &#61;</div>
<div class="flex items-center">
<iconify-icon
noobserver
diff --git a/src/routes/(app)/[username]/(profile)/+page.server.ts b/src/routes/(app)/[username]/(profile)/+page.server.ts
index 5f0e7579..9c97c947 100644
--- a/src/routes/(app)/[username]/(profile)/+page.server.ts
+++ b/src/routes/(app)/[username]/(profile)/+page.server.ts
@@ -2,14 +2,14 @@ import getRates from "$lib/rates";
import { auth, get } from "$lib/utils";
export async function load({ cookies, depends, parent }) {
- depends("app:payments");
- depends("app:items");
+ depends("app:payments");
+ depends("app:items");
- const { subject } = await parent();
+ const { subject } = await parent();
- let accounts = [];
- if (cookies.get("token")) accounts = await get("/accounts", auth(cookies));
+ let accounts = [];
+ if (cookies.get("token")) accounts = await get("/accounts", auth(cookies));
- const rates = await getRates();
- return { accounts, rate: rates[subject.currency] };
+ const rates = await getRates();
+ return { accounts, rate: rates[subject.currency] };
}
diff --git a/src/routes/(app)/[username]/(profile)/+page.ts b/src/routes/(app)/[username]/(profile)/+page.ts
index 7fe2192a..0a6c78b2 100644
--- a/src/routes/(app)/[username]/(profile)/+page.ts
+++ b/src/routes/(app)/[username]/(profile)/+page.ts
@@ -4,7 +4,7 @@ import { get } from "svelte/store";
export const ssr = false;
export async function load() {
- const sk = cookies.get("sk");
- if (sk && !get(signer))
- signer.set({ method: "nsec", params: { sk }, ready: true });
+ const sk = cookies.get("sk");
+ if (sk && !get(signer))
+ signer.set({ method: "nsec", params: { sk }, ready: true });
}
diff --git a/src/routes/(app)/[username]/(profile)/notes/+page.server.ts b/src/routes/(app)/[username]/(profile)/notes/+page.server.ts
index b7186bc0..4a898798 100644
--- a/src/routes/(app)/[username]/(profile)/notes/+page.server.ts
+++ b/src/routes/(app)/[username]/(profile)/notes/+page.server.ts
@@ -2,12 +2,12 @@ import { get } from "$lib/utils";
import { error } from "@sveltejs/kit";
export async function load({ parent }) {
- try {
- const { subject } = await parent();
- const events = await get(`/${subject.pubkey}/events`);
- return { events };
- } catch (e) {
- console.log(e);
- error(500, { message: "Failed to get events" });
- }
+ try {
+ const { subject } = await parent();
+ const events = await get(`/${subject.pubkey}/events`);
+ return { events };
+ } catch (e) {
+ console.log(e);
+ error(500, { message: "Failed to get events" });
+ }
}
diff --git a/src/routes/(app)/[username]/+layout.server.ts b/src/routes/(app)/[username]/+layout.server.ts
index bff8848c..ab755410 100644
--- a/src/routes/(app)/[username]/+layout.server.ts
+++ b/src/routes/(app)/[username]/+layout.server.ts
@@ -2,23 +2,23 @@ import { get } from "$lib/utils";
import { error } from "@sveltejs/kit";
export const load = async ({
- cookies,
- depends,
- params: { username },
- parent,
+ cookies,
+ depends,
+ params: { username },
+ parent,
}) => {
- depends("app:user");
+ depends("app:user");
- try {
- const subject = await get(`/users/${username}`);
- const { user } = await parent();
+ try {
+ const subject = await get(`/users/${username}`);
+ const { user } = await parent();
- const expires = new Date();
- expires.setSeconds(expires.getSeconds() + 380 * 24 * 60 * 60);
- cookies.set("username", username, { path: "/", expires, httpOnly: false });
+ const expires = new Date();
+ expires.setSeconds(expires.getSeconds() + 380 * 24 * 60 * 60);
+ cookies.set("username", username, { path: "/", expires, httpOnly: false });
- return { subject, user };
- } catch (e) {
- error(500, "Unable to retrieve user account data");
- }
+ return { subject, user };
+ } catch {
+ error(500, "Unable to retrieve user account data");
+ }
};
diff --git a/src/routes/(app)/[username]/accepted/[text]/+page.server.ts b/src/routes/(app)/[username]/accepted/[text]/+page.server.ts
index aa25ce7f..4da700e0 100644
--- a/src/routes/(app)/[username]/accepted/[text]/+page.server.ts
+++ b/src/routes/(app)/[username]/accepted/[text]/+page.server.ts
@@ -1,6 +1,6 @@
export async function load({ params, url }) {
- const { text } = params;
- const query = new URLSearchParams(url.search);
- const nfc = !!query.get("nfc");
- return { nfc, text };
+ const { text } = params;
+ const query = new URLSearchParams(url.search);
+ const nfc = !!query.get("nfc");
+ return { nfc, text };
}
diff --git a/src/routes/(app)/[username]/accepted/[text]/+page.svelte b/src/routes/(app)/[username]/accepted/[text]/+page.svelte
index fd2c7991..339f6c9c 100644
--- a/src/routes/(app)/[username]/accepted/[text]/+page.svelte
+++ b/src/routes/(app)/[username]/accepted/[text]/+page.svelte
@@ -1,4 +1,5 @@
-<script> import Qr from "$comp/Qr.svelte";
+<script>
+ import Qr from "$comp/Qr.svelte";
import { back, copy } from "$lib/utils";
import { bech32 } from "@scure/base";
import { page } from "$app/stores";
diff --git a/src/routes/(app)/[username]/accepted/[text]/raw/+server.ts b/src/routes/(app)/[username]/accepted/[text]/raw/+server.ts
index a24d3a3c..ad7fc6b1 100644
--- a/src/routes/(app)/[username]/accepted/[text]/raw/+server.ts
+++ b/src/routes/(app)/[username]/accepted/[text]/raw/+server.ts
@@ -1,16 +1,16 @@
import Qr from "qrcode-base64";
export async function GET({ params }) {
- const { text } = params;
+ const { text } = params;
- const dataUri = Qr.drawImg(text, { size: 600 });
- const base64Data = dataUri.split(",")[1];
- const binaryData = Buffer.from(base64Data, "base64");
+ const dataUri = Qr.drawImg(text, { size: 600 });
+ const base64Data = dataUri.split(",")[1];
+ const binaryData = Buffer.from(base64Data, "base64");
- return new Response(binaryData, {
- headers: {
- "Content-Type": "image/gif",
- "Cache-Control": "public, max-age=31536000, immutable",
- },
- });
+ return new Response(binaryData, {
+ headers: {
+ "Content-Type": "image/gif",
+ "Cache-Control": "public, max-age=31536000, immutable",
+ },
+ });
}
diff --git a/src/routes/(app)/[username]/accepted/create/+page.svelte b/src/routes/(app)/[username]/accepted/create/+page.svelte
index 339aae16..189a734d 100644
--- a/src/routes/(app)/[username]/accepted/create/+page.svelte
+++ b/src/routes/(app)/[username]/accepted/create/+page.svelte
@@ -1,10 +1,12 @@
<script lang="ts">
- import { run, preventDefault } from 'svelte/legacy';
+ import { run, preventDefault } from "svelte/legacy";
import { goto } from "$app/navigation";
import { browser } from "$app/environment";
import { t } from "$lib/translations";
- let el = $state(), text = $state(), pasted = $state();
+ let el = $state(),
+ text = $state(),
+ pasted = $state();
let keypress = (e) =>
e.key === "Enter" ? e.preventDefault() || el.click() : (pasted = false);
@@ -37,7 +39,7 @@
bind:value={text}
onpaste={() => (pasted = true)}
autocapitalize="none"
-></textarea>
+ ></textarea>
</div>
<div class="flex gap-2">
diff --git a/src/routes/(app)/[username]/receive/+page.server.js b/src/routes/(app)/[username]/receive/+page.server.js
index 777c1dd7..2aa875dd 100644
--- a/src/routes/(app)/[username]/receive/+page.server.js
+++ b/src/routes/(app)/[username]/receive/+page.server.js
@@ -2,15 +2,15 @@ import getRates from "$lib/rates";
import { redirect } from "@sveltejs/kit";
export const load = async ({ cookies, params: { username }, parent, url }) => {
- const token = cookies.get("token");
- const rates = await getRates();
- if (!token) redirect(307, `/pay/${username}`);
- const { subject, user } = await parent();
- const aid = cookies.get("aid");
+ const token = cookies.get("token");
+ const rates = await getRates();
+ if (!token) redirect(307, `/pay/${username}`);
+ const { subject, user } = await parent();
+ const aid = cookies.get("aid");
- if (aid && user?.id !== aid) redirect(307, "/invoice");
- return {
- rate: rates[subject.currency],
- text: `${username}@${url.host}`,
- };
+ if (aid && user?.id !== aid) redirect(307, "/invoice");
+ return {
+ rate: rates[subject.currency],
+ text: `${username}@${url.host}`,
+ };
};
diff --git a/src/routes/(app)/account/+server.ts b/src/routes/(app)/account/+server.ts
index e6dc7e0c..fbe1214b 100644
--- a/src/routes/(app)/account/+server.ts
+++ b/src/routes/(app)/account/+server.ts
@@ -2,11 +2,11 @@ import { auth, post } from "$lib/utils";
import { error, json } from "@sveltejs/kit";
export async function POST({ cookies, request }) {
- try {
- const body = await request.json();
- return json(await post("/accounts", body, auth(cookies)));
- } catch (e: any) {
- console.log(e);
- error(500, e.message);
- }
+ try {
+ const body = await request.json();
+ return json(await post("/accounts", body, auth(cookies)));
+ } catch (e: any) {
+ console.log(e);
+ error(500, e.message);
+ }
}
diff --git a/src/routes/(app)/account/[id]/+page.server.ts b/src/routes/(app)/account/[id]/+page.server.ts
index b91a0788..0fcfbdd9 100644
--- a/src/routes/(app)/account/[id]/+page.server.ts
+++ b/src/routes/(app)/account/[id]/+page.server.ts
@@ -2,23 +2,23 @@ import { error, redirect } from "@sveltejs/kit";
import { auth, get, post, fd } from "$lib/utils";
export const load = async ({ cookies, params }) => {
- const account = await get(`/account/${params.id}`, auth(cookies));
- return { account };
+ const account = await get(`/account/${params.id}`, auth(cookies));
+ return { account };
};
export const actions = {
- default: async ({ cookies, params, request }) => {
- const { id } = params;
- const body = await fd(request);
- const username = cookies.get("username");
+ default: async ({ cookies, params, request }) => {
+ const { id } = params;
+ const body = await fd(request);
+ const username = cookies.get("username");
- try {
- await post(`/account/${id}`, body, auth(cookies));
- } catch (e: any) {
- console.log(e);
- error(400, { message: e.message });
- }
+ try {
+ await post(`/account/${id}`, body, auth(cookies));
+ } catch (e: any) {
+ console.log(e);
+ error(400, { message: e.message });
+ }
- redirect(303, `/${username}`);
- },
+ redirect(303, `/${username}`);
+ },
};
diff --git a/src/routes/(app)/account/[id]/+page.svelte b/src/routes/(app)/account/[id]/+page.svelte
index 4a23a211..6b48bac2 100644
--- a/src/routes/(app)/account/[id]/+page.svelte
+++ b/src/routes/(app)/account/[id]/+page.svelte
@@ -71,7 +71,6 @@
fail(e.message);
}
};
-
</script>
<div class="space-y-5">
diff --git a/src/routes/(app)/account/ark/+page.svelte b/src/routes/(app)/account/ark/+page.svelte
index 0c4d8783..42329ef8 100644
--- a/src/routes/(app)/account/ark/+page.svelte
+++ b/src/routes/(app)/account/ark/+page.svelte
@@ -9,10 +9,7 @@
import { goto } from "$app/navigation";
import { arkServerUrl } from "$lib/ark";
import { HDKey } from "@scure/bip32";
- import {
- entropyToMnemonic,
- mnemonicToSeed,
- } from "@scure/bip39";
+ import { entropyToMnemonic, mnemonicToSeed } from "@scure/bip39";
import { wordlist } from "@scure/bip39/wordlists/english.js";
import {
rememberForOptions,
@@ -168,7 +165,8 @@
{#if hasMasterSeed}
<form onsubmit={preventDefault(submit)} class="space-y-5">
<p class="text-secondary">
- Your Ark wallet will be derived from your master seed. Enter your wallet password to continue.
+ Your Ark wallet will be derived from your master seed. Enter your
+ wallet password to continue.
</p>
<label
@@ -220,7 +218,8 @@
id="rememberFor"
class="w-full"
value={rememberForMs}
- onchange={(e) => (rememberForMs = Number((e.target as HTMLSelectElement).value))}
+ onchange={(e) =>
+ (rememberForMs = Number((e.target as HTMLSelectElement).value))}
>
{#each rememberForOptions as option}
<option value={option.ms}>{option.label}</option>
@@ -230,9 +229,7 @@
<div class="flex gap-2">
<a href={`/${user.username}`} class="contents">
- <button type="button" class="btn !w-auto grow">
- Back
- </button>
+ <button type="button" class="btn !w-auto grow"> Back </button>
</a>
<button
disabled={submitting}
@@ -250,7 +247,8 @@
{:else if !confirmed}
<div class="space-y-4">
<p class="text-secondary">
- Your Ark wallet is secured by a private key. Please copy it down somewhere safe.
+ Your Ark wallet is secured by a private key. Please copy it down
+ somewhere safe.
</p>
{#if showNsec}
@@ -266,14 +264,24 @@
</div>
<div class="flex gap-2">
- <button type="button" class="btn btn-accent flex-grow" onclick={confirmBackup}>
- <iconify-icon noobserver icon="ph:check-bold" width="24"></iconify-icon>
+ <button
+ type="button"
+ class="btn btn-accent flex-grow"
+ onclick={confirmBackup}
+ >
+ <iconify-icon noobserver icon="ph:check-bold" width="24"
+ ></iconify-icon>
I've backed it up
</button>
</div>
{:else}
- <button type="button" class="btn btn-warning w-full" onclick={revealNsec}>
- <iconify-icon noobserver icon="ph:eye-bold" width="24"></iconify-icon>
+ <button
+ type="button"
+ class="btn btn-warning w-full"
+ onclick={revealNsec}
+ >
+ <iconify-icon noobserver icon="ph:eye-bold" width="24"
+ ></iconify-icon>
Reveal backup key
</button>
{/if}
@@ -281,7 +289,8 @@
{:else}
<form onsubmit={preventDefault(submit)} class="space-y-5">
<p class="text-secondary">
- Set a password to encrypt your key. You'll need this password to send funds.
+ Set a password to encrypt your key. You'll need this password to send
+ funds.
</p>
<label
@@ -371,7 +380,8 @@
id="rememberFor"
class="w-full"
value={rememberForMs}
- onchange={(e) => (rememberForMs = Number((e.target as HTMLSelectElement).value))}
+ onchange={(e) =>
+ (rememberForMs = Number((e.target as HTMLSelectElement).value))}
>
{#each rememberForOptions as option}
<option value={option.ms}>{option.label}</option>
diff --git a/src/routes/(app)/account/bitcoin/+page.svelte b/src/routes/(app)/account/bitcoin/+page.svelte
index ca90c758..87dc32e2 100644
--- a/src/routes/(app)/account/bitcoin/+page.svelte
+++ b/src/routes/(app)/account/bitcoin/+page.svelte
@@ -11,7 +11,8 @@
<a href="/account/seed" class="block">
<div class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200">
<figure class="w-20 flex items-center justify-center">
- <iconify-icon noobserver icon="ph:file-plus-bold" width="64"></iconify-icon>
+ <iconify-icon noobserver icon="ph:file-plus-bold" width="64"
+ ></iconify-icon>
</figure>
<div>
<div class="text-xl">{$t("accounts.create")}</div>
@@ -22,7 +23,8 @@
<a href="/account/import" class="block">
<div class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200">
<figure class="w-20 flex items-center justify-center">
- <iconify-icon noobserver icon="ph:folder-open-bold" width="64"></iconify-icon>
+ <iconify-icon noobserver icon="ph:folder-open-bold" width="64"
+ ></iconify-icon>
</figure>
<div>
<div class="text-xl">{$t("accounts.import")}</div>
diff --git a/src/routes/(app)/account/cash/+page.svelte b/src/routes/(app)/account/cash/+page.svelte
index 378d36ee..188eaf66 100644
--- a/src/routes/(app)/account/cash/+page.svelte
+++ b/src/routes/(app)/account/cash/+page.svelte
@@ -1,5 +1,6 @@
<script lang="ts">
- import { t } from "$lib/translations";</script>
+ import { t } from "$lib/translations";
+</script>
<div class="space-y-5">
<h1 class="text-center text-3xl font-semibold">Choose your custodian</h1>
diff --git a/src/routes/(app)/account/new/+page.svelte b/src/routes/(app)/account/new/+page.svelte
index a514237a..4100e001 100644
--- a/src/routes/(app)/account/new/+page.svelte
+++ b/src/routes/(app)/account/new/+page.svelte
@@ -7,7 +7,9 @@
<div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5">
<a href="/account/bitcoin" class="block">
- <div class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200 gap-4 items-center">
+ <div
+ class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200 gap-4 items-center"
+ >
<iconify-icon noobserver icon="logos:bitcoin" width={48}></iconify-icon>
<div>
<div class="text-xl">Bitcoin (On-chain)</div>
@@ -18,7 +20,9 @@
</div>
</a>
<a href="/account/ark" class="block">
- <div class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200 gap-4 items-center">
+ <div
+ class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200 gap-4 items-center"
+ >
<img
src="/images/ark.png"
class="w-12 h-12 rounded-full object-cover"
diff --git a/src/routes/(app)/account/pass/+page.svelte b/src/routes/(app)/account/pass/+page.svelte
index 4e9573d4..2f62c38c 100644
--- a/src/routes/(app)/account/pass/+page.svelte
+++ b/src/routes/(app)/account/pass/+page.svelte
@@ -98,7 +98,9 @@
onsubmit={preventDefault(submit)}
class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5"
>
- <p class="text-secondary p-4 bg-warning/80 rounded-2xl border-warning border-2">
+ <p
+ class="text-secondary p-4 bg-warning/80 rounded-2xl border-warning border-2"
+ >
{$t("accounts.passwordWarning")}
</p>
@@ -188,7 +190,8 @@
id="rememberFor"
class="w-full"
value={rememberForMs}
- onchange={(e) => (rememberForMs = Number((e.target as HTMLSelectElement).value))}
+ onchange={(e) =>
+ (rememberForMs = Number((e.target as HTMLSelectElement).value))}
>
{#each rememberForOptions as option}
<option value={option.ms}>{option.label}</option>
diff --git a/src/routes/(app)/account/seed/+page.svelte b/src/routes/(app)/account/seed/+page.svelte
index 537121af..cbfe1024 100644
--- a/src/routes/(app)/account/seed/+page.svelte
+++ b/src/routes/(app)/account/seed/+page.svelte
@@ -32,8 +32,7 @@
{/if}
<button type="button" class="btn" onclick={() => copy($mnemonic)}>
- <iconify-icon noobserver icon="ph:copy-bold" width="32"
- ></iconify-icon>
+ <iconify-icon noobserver icon="ph:copy-bold" width="32"></iconify-icon>
<div class="my-auto">
{$t("payments.copy")}
</div>
diff --git a/src/routes/(app)/account/setup/+page.svelte b/src/routes/(app)/account/setup/+page.svelte
index 09703d92..9d747578 100644
--- a/src/routes/(app)/account/setup/+page.svelte
+++ b/src/routes/(app)/account/setup/+page.svelte
@@ -19,7 +19,11 @@
</a>
<a href="/account/new" class="block">
<div class="shadow p-8 rounded-xl flex gap-4 hover:bg-primary">
- <img src="/images/keys.png" class="w-20 my-auto" alt="Savings account" />
+ <img
+ src="/images/keys.png"
+ class="w-20 my-auto"
+ alt="Savings account"
+ />
<div>
<div class="text-xl">Savings</div>
<div class="text-secondary">
diff --git a/src/routes/(app)/admin/+layout.server.ts b/src/routes/(app)/admin/+layout.server.ts
index a2da1a90..01f328a0 100644
--- a/src/routes/(app)/admin/+layout.server.ts
+++ b/src/routes/(app)/admin/+layout.server.ts
@@ -2,16 +2,16 @@ import { auth, get, isInvalidTokenError } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export async function load({ cookies }) {
- const token = cookies.get("token");
- if (!token) redirect(307, "/login");
- let user;
- try {
- user = await get("/me", auth(cookies));
- } catch (e) {
- if (isInvalidTokenError(e)) redirect(307, "/logout");
- throw e;
- }
- if (!user) redirect(307, "/login");
+ const token = cookies.get("token");
+ if (!token) redirect(307, "/login");
+ let user;
+ try {
+ user = await get("/me", auth(cookies));
+ } catch (e) {
+ if (isInvalidTokenError(e)) redirect(307, "/logout");
+ throw e;
+ }
+ if (!user) redirect(307, "/login");
- return { user };
+ return { user };
}
diff --git a/src/routes/(app)/admin/+page.server.ts b/src/routes/(app)/admin/+page.server.ts
index 8c250026..7bb7d1f3 100644
--- a/src/routes/(app)/admin/+page.server.ts
+++ b/src/routes/(app)/admin/+page.server.ts
@@ -2,11 +2,11 @@ import { auth, get } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export async function load({ cookies, parent }) {
- const { user } = await parent();
- if (!user) redirect(307, "/login");
+ const { user } = await parent();
+ if (!user) redirect(307, "/login");
- const users = (await get("/users", auth(cookies))).sort(
- (a, b) => b.balance - a.balance,
- );
- return { users };
+ const users = (await get("/users", auth(cookies))).sort(
+ (a, b) => b.balance - a.balance,
+ );
+ return { users };
}
diff --git a/src/routes/(app)/apps/[pubkey]/+page.server.ts b/src/routes/(app)/apps/[pubkey]/+page.server.ts
index a2cc50e7..ff10668f 100644
--- a/src/routes/(app)/apps/[pubkey]/+page.server.ts
+++ b/src/routes/(app)/apps/[pubkey]/+page.server.ts
@@ -3,24 +3,24 @@ import { auth, fd, get, post } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export const load = async ({ cookies, params, parent }) => {
- const { pubkey } = params;
- const { user } = await parent();
- const rates = await getRates();
- const rate = rates[user.currency];
- const app = await get(`/app/${pubkey}`, auth(cookies));
- return { app, rate };
+ const { pubkey } = params;
+ const { user } = await parent();
+ const rates = await getRates();
+ const rate = rates[user.currency];
+ const app = await get(`/app/${pubkey}`, auth(cookies));
+ return { app, rate };
};
export const actions = {
- default: async ({ cookies, request }) => {
- try {
- const body = await fd(request);
- await post("/app", body, auth(cookies));
- } catch (e) {
- const { message: error } = e as Error;
- return fail(400, { error });
- }
+ default: async ({ cookies, request }) => {
+ try {
+ const body = await fd(request);
+ await post("/app", body, auth(cookies));
+ } catch (e) {
+ const { message: error } = e as Error;
+ return fail(400, { error });
+ }
- redirect(307, "/settings/nostr");
- },
+ redirect(307, "/settings/nostr");
+ },
};
diff --git a/src/routes/(app)/apps/[pubkey]/payments/+page.server.ts b/src/routes/(app)/apps/[pubkey]/payments/+page.server.ts
index 546dacdf..0df40562 100644
--- a/src/routes/(app)/apps/[pubkey]/payments/+page.server.ts
+++ b/src/routes/(app)/apps/[pubkey]/payments/+page.server.ts
@@ -1,6 +1,6 @@
import { auth, get } from "$lib/utils";
export const load = async ({ cookies, params }) => {
- const app = await get(`/app/${params.pubkey}`, auth(cookies));
- return { app };
+ const app = await get(`/app/${params.pubkey}`, auth(cookies));
+ return { app };
};
diff --git a/src/routes/(app)/apps/new/+page.server.ts b/src/routes/(app)/apps/new/+page.server.ts
index eaecfd68..a78b9093 100644
--- a/src/routes/(app)/apps/new/+page.server.ts
+++ b/src/routes/(app)/apps/new/+page.server.ts
@@ -3,39 +3,39 @@ import { auth, fd, post } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export const load = async ({ parent, url }) => {
- const { user } = await parent();
+ const { user } = await parent();
- if (!user)
- redirect(
- 307,
- `/login?redirect=${encodeURIComponent(url.pathname + url.search)}`,
- );
+ if (!user)
+ redirect(
+ 307,
+ `/login?redirect=${encodeURIComponent(url.pathname + url.search)}`,
+ );
- let max_amount = url.searchParams.get("max_amount");
- max_amount = max_amount ? Math.round(Number(max_amount) / 1000) : undefined;
+ let max_amount = url.searchParams.get("max_amount");
+ max_amount = max_amount ? Math.round(Number(max_amount) / 1000) : undefined;
- const app = {
- name: url.searchParams.get("name"),
- pubkey: url.searchParams.get("pubkey"),
- max_amount,
- budget_renewal: url.searchParams.get("budget_renewal"),
- };
+ const app = {
+ name: url.searchParams.get("name"),
+ pubkey: url.searchParams.get("pubkey"),
+ max_amount,
+ budget_renewal: url.searchParams.get("budget_renewal"),
+ };
- const rates = await getRates();
- const rate = rates[user.currency];
- return { app, rate };
+ const rates = await getRates();
+ const rate = rates[user.currency];
+ return { app, rate };
};
export const actions = {
- default: async ({ cookies, request }) => {
- try {
- const body = await fd(request);
- await post("/app", body, auth(cookies));
- } catch (e) {
- const { message: error } = e as Error;
- return fail(400, { error });
- }
+ default: async ({ cookies, request }) => {
+ try {
+ const body = await fd(request);
+ await post("/app", body, auth(cookies));
+ } catch (e) {
+ const { message: error } = e as Error;
+ return fail(400, { error });
+ }
- redirect(307, "/settings/nostr");
- },
+ redirect(307, "/settings/nostr");
+ },
};
diff --git a/src/routes/(app)/contacts/+server.ts b/src/routes/(app)/contacts/+server.ts
index e448bda2..2bc5d28e 100644
--- a/src/routes/(app)/contacts/+server.ts
+++ b/src/routes/(app)/contacts/+server.ts
@@ -2,11 +2,11 @@ import { auth, get } from "$lib/utils";
import { json } from "@sveltejs/kit";
export async function GET({ cookies }) {
- try {
- const contacts = await get("/contacts", auth(cookies));
- return json(contacts);
- } catch (e) {
- console.log(e);
- return json({});
- }
+ try {
+ const contacts = await get("/contacts", auth(cookies));
+ return json(contacts);
+ } catch (e) {
+ console.log(e);
+ return json({});
+ }
}
diff --git a/src/routes/(app)/disable2fa/+server.ts b/src/routes/(app)/disable2fa/+server.ts
index 81ee2ff2..0d1c4573 100644
--- a/src/routes/(app)/disable2fa/+server.ts
+++ b/src/routes/(app)/disable2fa/+server.ts
@@ -2,12 +2,12 @@ import { error, json } from "@sveltejs/kit";
import { auth, post } from "$lib/utils";
export async function POST({ cookies, request }) {
- try {
- const body = await request.json();
- const res = await post("/disable2fa", body, auth(cookies));
+ try {
+ const body = await request.json();
+ const res = await post("/disable2fa", body, auth(cookies));
- return json(res);
- } catch (e) {
- error(500, "Problem disabling 2fa");
- }
+ return json(res);
+ } catch {
+ error(500, "Problem disabling 2fa");
+ }
}
diff --git a/src/routes/(app)/dm/+page.svelte b/src/routes/(app)/dm/+page.svelte
index 95cb208e..173871c1 100644
--- a/src/routes/(app)/dm/+page.svelte
+++ b/src/routes/(app)/dm/+page.svelte
@@ -1,512 +1,664 @@
<script lang="ts">
- import { tick, onMount } from "svelte";
+ import { tick, onMount } from "svelte";
+ import { isValid, queryProfile } from "nostr-tools/nip05";
+ import * as toolsnip17 from "nostr-tools/nip17";
- import { isValid, queryProfile } from "nostr-tools/nip05";
- import * as toolsnip17 from 'nostr-tools/nip17';
+ import { getNostrUserInfo } from "$lib/nip01";
+ import { relaysSupporting } from "$lib/nip11";
+ import { getMessageRumours } from "$lib/nip17";
+ import * as libnip17 from "$lib/nip17";
+ import { npubEncode, decode } from "nostr-tools/nip19";
+ import { mute, unmute, mutedAccounts } from "$lib/nip51";
+ import { sign, getPrivateKey, pTagKeys } from "$lib/nostr";
+ import { t } from "$lib/translations";
+ import { theme } from "$lib/store";
- import { getNostrUserInfo } from '$lib/nip01';
- import { relaysSupporting } from '$lib/nip11';
- import { getMessageRumours } from '$lib/nip17';
- import * as libnip17 from '$lib/nip17';
- import { npubEncode, decode } from 'nostr-tools/nip19';
- import { mute, unmute, mutedAccounts } from '$lib/nip51';
- import { sign, getPrivateKey, pTagKeys } from '$lib/nostr';
- import { t } from "$lib/translations";
- import { theme } from "$lib/store";
+ let { data } = $props();
+ const { user } = data;
- let { data } = $props();
- const { user } = data;
+ if (!user) {
+ window.location.replace("/login");
+ }
- if (!user) {
- window.location.replace("/login");
- }
+ /// chat selection
+ const usernameFromPubkey = async (pubkey: string): Promise<string | null> => {
+ const response = await fetch(`/api/users/${pubkey}`);
+ if (response.ok) {
+ const userInfo = await response.json();
+ return userInfo.anon ? null : userInfo.username;
+ } else {
+ return null;
+ }
+ };
- /// chat selection
- const usernameFromPubkey = async (pubkey: string): Promise<string | null> => {
- const response = await fetch(`/api/users/${pubkey}`);
- if (response.ok) {
- const userInfo = await response.json();
- return userInfo.anon ? null : userInfo.username;
- } else {
- return null;
- }
- }
+ const userInfo = async (pubkey: string) => {
+ if (pubkey.slice(0, 4) === "npub") {
+ return userInfo(decode(pubkey).data as string);
+ }
- const userInfo = async (pubkey: string) => {
- if (pubkey.slice(0, 4) === "npub") {
- return userInfo(decode(pubkey).data as string);
- }
+ const nostrUserInfo = (await getNostrUserInfo(pubkey)) || {};
+ const valid =
+ "nip05" in nostrUserInfo && (await isValid(pubkey, nostrUserInfo.nip05));
+ const username = await usernameFromPubkey(pubkey);
+ return {
+ coinosUsername: username,
+ nostrName: nostrUserInfo?.name,
+ nip05: nostrUserInfo?.nip05,
+ nip05Valid: valid,
+ pubkey,
+ };
+ };
- const nostrUserInfo = await getNostrUserInfo(pubkey) || {};
- const valid = 'nip05' in nostrUserInfo && await isValid(pubkey, nostrUserInfo.nip05);
- const username = await usernameFromPubkey(pubkey);
- return {
- coinosUsername: username,
- nostrName: nostrUserInfo?.name,
- nip05: nostrUserInfo?.nip05,
- nip05Valid: valid, pubkey };
- }
+ const name = (userInfo: any): string => {
+ return userInfo.coinosUsername || userInfo.nostrName || $t("dm.anonymous");
+ };
- const name = (userInfo: any): string => {
- return userInfo.coinosUsername || userInfo.nostrName || $t("dm.anonymous");
- }
+ const id = (userInfo: any): string => {
+ if (userInfo.nip05 && userInfo.nip05.slice(0, 2) == "_@") {
+ return userInfo.nip05.slice(2);
+ }
- const id = (userInfo: any): string => {
- if (userInfo.nip05 && userInfo.nip05.slice(0, 2) == "_@") {
- return userInfo.nip05.slice(2);
- }
+ return userInfo.nip05 || npubEncode(userInfo.pubkey).slice(0, 16) + "...";
+ };
- return userInfo.nip05 || (npubEncode(userInfo.pubkey).slice(0, 16) + "...");
- }
+ const idValid = (userInfo: any): boolean => {
+ return !userInfo.nip05 || userInfo.nip05Valid;
+ };
- const idValid = (userInfo: any): boolean => {
- return !userInfo.nip05 || userInfo.nip05Valid;
- }
+ const rumourInvolves = (rumour: any, pubkey: string) => {
+ if (rumour.pubkey === pubkey) {
+ return true;
+ } else {
+ for (const tagPK of pTagKeys(rumour)) {
+ if (tagPK === pubkey) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
- const rumourInvolves = (rumour: any, pubkey: string) => {
- if (rumour.pubkey === pubkey) {
- return true;
- } else {
- for (const tagPK of pTagKeys(rumour)) {
- if (tagPK === pubkey) {
- return true;
- }
- }
- return false;
- }
- }
+ const mostRecentCommunication = (rumours: any[], pubkey: string) => {
+ let mostRecentTime = null;
+ for (const rumour of rumours.filter((r) => rumourInvolves(r, pubkey))) {
+ if (!mostRecentTime || rumour.created_at > mostRecentTime) {
+ mostRecentTime = rumour.created_at;
+ }
+ }
+ return mostRecentTime;
+ };
- const mostRecentCommunication = (rumours: any[], pubkey: string) => {
- let mostRecentTime = null;
- for (const rumour of rumours.filter((r) => rumourInvolves(r, pubkey))) {
- if (!mostRecentTime || rumour.created_at > mostRecentTime) {
- mostRecentTime = rumour.created_at;
- }
- }
- return mostRecentTime;
- }
+ const updateSendersRecipients = async (rumours: any[]) => {
+ const senders = new Set<any>();
+ const recipients = new Set<any>();
+ for (const rumour of rumours) {
+ if (rumour.pubkey !== user.pubkey) {
+ senders.add(await userInfo(rumour.pubkey));
+ } else {
+ for (const pubkey of pTagKeys(rumour)) {
+ recipients.add(await userInfo(pubkey));
+ }
+ }
+ }
+ messageSenders = Array.from(senders);
+ messageRecipients = Array.from(recipients);
- const updateSendersRecipients = async (rumours: any[]) => {
- const senders = new Set<any>();
- const recipients = new Set<any>();
- for (const rumour of rumours) {
- if (rumour.pubkey !== user.pubkey) {
- senders.add(await userInfo(rumour.pubkey));
- } else {
- for (const pubkey of pTagKeys(rumour)) {
- recipients.add(await userInfo(pubkey));
- }
- }
- }
- messageSenders = Array.from(senders);
- messageRecipients = Array.from(recipients);
+ const chatMap = new Map<string, any>();
+ for (const sender of senders) {
+ chatMap.set(sender.pubkey, sender);
+ }
+ for (const recipient of recipients) {
+ chatMap.set(recipient.pubkey, recipient);
+ }
+ chats = Array.from(chatMap.values());
+ chats.sort(
+ (a, b) =>
+ (mostRecentCommunication(rumours, b.pubkey) ?? 0) -
+ (mostRecentCommunication(rumours, a.pubkey) ?? 0),
+ );
+ };
- const chatMap = new Map<string, any>();
- for (const sender of senders) {
- chatMap.set(sender.pubkey, sender);
- }
- for (const recipient of recipients) {
- chatMap.set(recipient.pubkey, recipient);
- }
- chats = Array.from(chatMap.values());
- chats.sort((a, b) => (mostRecentCommunication(rumours, b.pubkey) ?? 0) - (mostRecentCommunication(rumours, a.pubkey) ?? 0));
- };
+ let messageSenders: any[] = $state([]);
+ let messageRecipients: any[] = $state([]);
+ let chats: any[] = $state([]);
+ getMessageRumours(user).then(updateSendersRecipients);
- let messageSenders: any[] = $state([]);
- let messageRecipients: any[] = $state([]);
- let chats: any[] = $state([]);
- getMessageRumours(user).then(updateSendersRecipients);
+ let selectedChat: any = $state(null);
+ let creatingNewChat = $state(false);
+ let searchQuery = $state("");
- let selectedChat: any = $state(null);
- let creatingNewChat = $state(false);
- let searchQuery = $state("");
+ /// individual chat
+ let text = $state("");
+ let allRumours: any[] = $state([]);
+ let messageRumours: any = $state([]);
+ let dates: any[] = $state([]);
+ let relayWarningShown = $state(false);
+ let expiryEnabled = $state(false);
+ let expiryDays = $state(7);
+ let canSend = $state(false);
+ let canSendExpiring = $state(false);
+ let nostrUserInfo: any = $state({});
- /// individual chat
- let text = $state("");
- let allRumours: any[] = $state([]);
- let messageRumours: any = $state([]);
- let dates: any[] = $state([]);
- let relayWarningShown = $state(false);
- let expiryEnabled = $state(false);
- let expiryDays = $state(7);
- let canSend = $state(false);
- let canSendExpiring = $state(false);
- let nostrUserInfo: any = $state({});
+ const includesPubkey = (chats: any[], pubkey: string) => {
+ for (const c of chats) {
+ if (c.pubkey === pubkey) {
+ return true;
+ }
+ }
+ return false;
+ };
- const includesPubkey = (chats: any[], pubkey: string) => {
- for (const c of chats) {
- if (c.pubkey === pubkey) {
- return true;
- }
- }
- return false;
- }
+ const selectChat = (c: any) => {
+ selectedChat = c;
+ if (!includesPubkey(chats, c.pubkey)) {
+ chats.unshift(c);
+ }
+ userInfo(selectedChat.pubkey).then((info) => (nostrUserInfo = info));
+ libnip17.getPreferredRelays(selectedChat.pubkey).then((relays) => {
+ canSend = relays && relays.length > 0;
+ relaysSupporting(relays, [40]).then(
+ (supporting) => (canSendExpiring = supporting.length > 0),
+ );
+ });
+ updateEvents();
+ };
- const selectChat = (c: any) => {
- selectedChat = c;
- if (!includesPubkey(chats, c.pubkey)) {
- chats.unshift(c);
- }
- userInfo(selectedChat.pubkey).then(info => nostrUserInfo = info);
- libnip17.getPreferredRelays(selectedChat.pubkey).then((relays) => {
- canSend = relays && relays.length > 0;
- relaysSupporting(relays, [40])
- .then((supporting) => canSendExpiring = supporting.length > 0);
- });
- updateEvents();
- }
+ const selectChatUsername = async (username: string) => {
+ const response = await fetch(`/api/users/${username}`);
+ if (!response.ok) {
+ alert("Invalid username");
+ return;
+ }
+ const coinosUserInfo = await response.json();
+ selectChatPubkey(coinosUserInfo.pubkey);
+ };
- const selectChatUsername = async (username: string) => {
- const response = await fetch(`/api/users/${username}`);
- if (!response.ok) {
- alert("Invalid username");
- return;
- }
- const coinosUserInfo = await response.json();
- selectChatPubkey(coinosUserInfo.pubkey);
- }
+ const selectChatNip05 = async (nip05: string) => {
+ const response = await queryProfile(nip05);
+ if (response == null) {
+ alert("Invalid nip-05");
+ return;
+ }
+ selectChatPubkey(response.pubkey);
+ };
- const selectChatNip05 = async (nip05: string) => {
- const response = await queryProfile(nip05);
- if (response == null) {
- alert("Invalid nip-05");
- return;
- }
- selectChatPubkey(response.pubkey);
- }
+ const selectChatPubkey = async (pubkey: string) => {
+ selectChat(await userInfo(pubkey));
+ creatingNewChat = false;
+ };
- const selectChatPubkey = async (pubkey: string) => {
- selectChat(await userInfo(pubkey));
- creatingNewChat = false;
- }
+ onMount(() => {
+ const urlParams = new URLSearchParams(window.location.search);
+ if (urlParams.get("username")) {
+ selectChatUsername(urlParams.get("username")!);
+ } else if (urlParams.get("nip05")) {
+ selectChatNip05(urlParams.get("nip05")!);
+ } else if (urlParams.get("pubkey")) {
+ selectChatPubkey(urlParams.get("pubkey")!);
+ }
+ });
- onMount(() => {
- const urlParams = new URLSearchParams(window.location.search);
- if (urlParams.get('username')) {
- selectChatUsername(urlParams.get('username')!);
- } else if (urlParams.get('nip05')) {
- selectChatNip05(urlParams.get('nip05')!);
- } else if (urlParams.get('pubkey')) {
- selectChatPubkey(urlParams.get('pubkey')!);
- }
- });
+ const appendMultimap = (map: Map<any, any>, key: any, value: any) => {
+ if (map.has(key)) {
+ map.get(key)!.push(value);
+ } else {
+ map.set(key, [value]);
+ }
+ };
- const appendMultimap = (map: Map<any, any>, key: any, value: any) => {
- if (map.has(key)) {
- map.get(key)!.push(value);
- } else {
- map.set(key, [value]);
- }
- }
+ const dateMap = (events: any[]): Map<any, any> => {
+ let eventsMap = new Map();
+ for (const event of events) {
+ const created = Math.floor(event.created_at / 86400);
+ appendMultimap(eventsMap, created, event);
+ }
+ for (const [date, dateEvents] of eventsMap) {
+ dateEvents.sort((ev1, ev2) => ev1.created_at - ev2.created_at);
+ }
+ return eventsMap;
+ };
- const dateMap = (events: any[]): Map<any, any> => {
- let eventsMap = new Map();
- for (const event of events) {
- const created = Math.floor(event.created_at / 86400);
- appendMultimap(eventsMap, created, event);
- }
- for (const [date, dateEvents] of eventsMap) {
- dateEvents.sort((ev1, ev2) => ev1.created_at - ev2.created_at);
- }
- return eventsMap;
- }
+ const updateEvents = async () => {
+ allRumours = await libnip17.getMessageRumours(user);
+ const rumours = allRumours.filter(
+ (r) =>
+ (r.pubkey === user.pubkey &&
+ pTagKeys(r).includes(selectedChat.pubkey)) ||
+ (r.pubkey === selectedChat.pubkey && pTagKeys(r).includes(user.pubkey)),
+ );
+ messageRumours = dateMap(rumours);
- const updateEvents = async () => {
- allRumours = await libnip17.getMessageRumours(user);
- const rumours = allRumours.filter((r) =>
- (r.pubkey === user.pubkey && pTagKeys(r).includes(selectedChat.pubkey)) ||
- (r.pubkey === selectedChat.pubkey && pTagKeys(r).includes(user.pubkey)));
- messageRumours = dateMap(rumours);
+ dates = Array.from(messageRumours.keys());
+ dates.sort((d1, d2) => d1 - d2);
- dates = Array.from(messageRumours.keys());
- dates.sort((d1, d2) => d1 - d2);
+ await tick();
+ const messages = document.getElementById("messages");
+ if (messages) {
+ messages.scrollTop = messages.scrollHeight;
+ }
+ };
- await tick();
- const messages = document.getElementById("messages");
- if (messages) {
- messages.scrollTop = messages.scrollHeight;
- }
- }
+ const TIME = new Intl.DateTimeFormat(undefined, {
+ hour: "numeric",
+ hour12: false,
+ minute: "numeric",
+ });
+ const NEAR_DATE = new Intl.DateTimeFormat(undefined, {
+ month: "short",
+ day: "numeric",
+ weekday: "short",
+ });
+ const FAR_DATE = new Intl.DateTimeFormat(undefined, {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ weekday: "short",
+ });
+ const NEAR_DISTANCE = 182 * 24 * 60 * 60 * 1000; // around 6 months
+ const formatDate = (date: Date): string => {
+ if (date.getTime() >= Date.now() - NEAR_DISTANCE) {
+ return NEAR_DATE.format(date);
+ } else {
+ return FAR_DATE.format(date);
+ }
+ };
- const TIME = new Intl.DateTimeFormat(
- undefined, { hour: "numeric", hour12: false, minute: "numeric" });
- const NEAR_DATE = new Intl.DateTimeFormat(
- undefined, { month: "short", day: "numeric", weekday: "short" });
- const FAR_DATE = new Intl.DateTimeFormat(
- undefined, { year: "numeric", month: "short", day: "numeric", weekday: "short" });
- const NEAR_DISTANCE = 182 * 24 * 60 * 60 * 1000; // around 6 months
- const formatDate = (date: Date): string => {
- if (date.getTime() >= Date.now() - NEAR_DISTANCE) {
- return NEAR_DATE.format(date);
- } else {
- return FAR_DATE.format(date);
- }
- }
+ const expirationClose = (expiration: number) => {
+ return expiration <= Date.now() / 1000 + 2 * 86400;
+ };
- const expirationClose = (expiration: number) => {
- return expiration <= (Date.now() / 1000 + 2 * 86400);
- }
+ const sendMessage = async (message: string) => {
+ const expiry = expiryEnabled ? expiryDays : undefined;
+ await libnip17.send(message, user, selectedChat, expiry);
+ updateEvents();
+ };
- const sendMessage = async (message: string) => {
- const expiry = expiryEnabled ? expiryDays : undefined;
- await libnip17.send(message, user, selectedChat, expiry);
- updateEvents();
- }
+ libnip17.getPreferredRelays(user.pubkey).then((relays) => {
+ if (!relays || relays.length == 0) {
+ relayWarningShown = true;
+ return;
+ }
+ relayWarningShown = false;
+ });
- libnip17.getPreferredRelays(user.pubkey).then((relays) => {
- if (!relays || relays.length == 0) {
- relayWarningShown = true;
- return;
- }
- relayWarningShown = false;
- });
+ let muted = $state(new Set<string>());
+ mutedAccounts(user).then((m) => (muted = m));
- let muted = $state(new Set<string>());
- mutedAccounts(user).then((m) => muted = m);
-
- const toggleMute = async (pubkey: string) => {
- if (muted && muted.has(pubkey)) {
- await unmute(user, pubkey);
- } else {
- await mute(user, pubkey, true);
- }
- muted = await mutedAccounts(user);
- }
+ const toggleMute = async (pubkey: string) => {
+ if (muted && muted.has(pubkey)) {
+ await unmute(user, pubkey);
+ } else {
+ await mute(user, pubkey, true);
+ }
+ muted = await mutedAccounts(user);
+ };
</script>
-<style>
- .warning {
- color: #ff7f00;
- }
+<div class="super-container">
+ <div
+ class={"sidebar " + ($theme === "light" ? "light-sidebar" : "dark-sidebar")}
+ >
+ <h2 class="text-xl chat-header">
+ {creatingNewChat ? $t("dm.newChatHeader") : $t("dm.chatHeader")}
+ <button
+ class={"chat-btn push-right " +
+ ($theme === "light" ? "light-chat-btn" : "dark-chat-btn") +
+ (creatingNewChat
+ ? $theme === "light"
+ ? " light-selected"
+ : " dark-selected"
+ : "")}
+ on:click={() => {
+ creatingNewChat = !creatingNewChat;
+ selectedChat = null;
+ }}>+</button
+ >
+ </h2>
+ {#if creatingNewChat}
+ <input
+ type="text"
+ class="short"
+ bind:value={searchQuery}
+ placeholder={$t("dm.searchPrompt")}
+ />
+ {/if}
+ {#if !creatingNewChat}
+ {#each chats as c}
+ {#if (selectedChat && selectedChat.pubkey === c.pubkey) || !(muted && muted.has(c.pubkey))}
+ <button
+ class={"chat-btn tall-btn " +
+ ($theme === "light" ? "light-chat-btn" : "dark-chat-btn") +
+ (selectedChat && selectedChat.pubkey == c.pubkey
+ ? $theme === "light"
+ ? " light-selected"
+ : " dark-selected"
+ : "")}
+ on:click={() => selectChat(c)}
+ >
+ <span
+ class={"text-xl" +
+ (muted && muted.has(c.pubkey) ? " secondary" : "")}
+ >{name(c)}</span
+ >
+ <span class={(idValid(c) ? "" : "invalid ") + "secondary text-xs"}
+ >{id(c)}</span
+ >
+ </button>
+ {/if}
+ {/each}
+ {:else if searchQuery !== ""}
+ <button
+ class={"chat-btn tall-btn " +
+ ($theme === "light" ? "light-chat-btn" : "dark-chat-btn")}
+ on:click={() => selectChatUsername(searchQuery)}
+ >
+ <span class="text-xl">{$t("dm.findByUsername")}</span>
+ </button>
+ {#if searchQuery.includes(".")}
+ <button
+ class={"chat-btn tall-btn " +
+ ($theme === "light" ? "light-chat-btn" : "dark-chat-btn")}
+ on:click={() => selectChatNip05(searchQuery)}
+ >
+ <span class="text-xl">{$t("dm.findByNIP05")}</span>
+ </button>
+ {/if}
+ {#if searchQuery.length === 64 || searchQuery.slice(0, 4) === "npub"}
+ <button
+ class={"chat-btn tall-btn " +
+ ($theme === "light" ? "light-chat-btn" : "dark-chat-btn")}
+ on:click={() => selectChatPubkey(searchQuery)}
+ >
+ <span class="text-xl">{$t("dm.findByPubkey")}</span>
+ </button>
+ {/if}
+ {/if}
+ </div>
+ <div
+ class="main container space-y-2 mx-auto space-y-5 lg:max-w-xl xl:max-w-2xl lg:pl-10 mt-5 lg:mt-0"
+ >
+ <h1
+ class="text-5xl font-medium text-left w-full mx-auto lg:mx-0 md:w-[500px]"
+ >
+ {$t("dm.header")}
+ </h1>
- .secondary {
- color: #7f7f7f;
- }
+ {#if selectedChat}
+ <h1>
+ {#if selectedChat.coinosUsername}
+ <a class="text-3xl" href="/{selectedChat.coinosUsername}"
+ >{name(selectedChat)}</a
+ >
+ {:else}
+ <span class="text-3xl">{name(selectedChat)}</span>
+ {/if}
+ <span
+ class={"secondary timestamp text-small" +
+ (idValid(selectedChat) ? "" : " invalid")}
+ title={npubEncode(selectedChat.pubkey)}>{id(selectedChat)}</span
+ >
+ <button
+ class={"small-btn push-right " +
+ ($theme === "light" ? "light-chat-btn" : "dark-chat-btn")}
+ on:click={() => toggleMute(selectedChat.pubkey)}
+ >{$t(
+ muted && muted.has(selectedChat.pubkey) ? "dm.unmute" : "dm.mute",
+ )}</button
+ >
+ </h1>
- .link {
- text-decoration-line: underline;
- }
+ {#if !(muted && muted.has(selectedChat.pubkey))}
+ <div id="messages" style="overflow-y: scroll; max-height: 600px;">
+ {#each dates as day}
+ <p class="date-header secondary">
+ {formatDate(new Date(day * 86400 * 1000))}
+ </p>
+ <ul>
+ {#each messageRumours.get(day) as rumour}
+ {#if rumour.pubkey === user.pubkey && pTagKeys(rumour).includes(selectedChat.pubkey)}
+ <li
+ class={(rumour.expiration &&
+ expirationClose(rumour.expiration)
+ ? "secondary "
+ : "") +
+ ($theme === "light"
+ ? "light-message "
+ : "dark-message ") +
+ "message by-user"}
+ >
+ {rumour.content}
+ <span class="timestamp secondary text-xs"
+ >{TIME.format(new Date(rumour.created_at * 1000))}</span
+ >
+ </li>
+ {:else if rumour.pubkey === selectedChat.pubkey && pTagKeys(rumour).includes(user.pubkey)}
+ <li
+ class={(rumour.expiration &&
+ expirationClose(rumour.expiration)
+ ? "secondary "
+ : "") +
+ ($theme === "light"
+ ? "light-message "
+ : "dark-message ") +
+ "message by-other"}
+ >
+ {rumour.content}
+ <span class="timestamp secondary text-xs"
+ >{TIME.format(new Date(rumour.created_at * 1000))}</span
+ >
+ </li>
+ {/if}
+ {/each}
+ </ul>
+ {/each}
+ </div>
- .inline {
- white-space: nowrap;
- }
+ <textarea id="message-contents" bind:value={text}></textarea>
+ <input
+ id="send-message"
+ type="button"
+ class="btn btn-accent"
+ disabled={!canSend}
+ value={canSend
+ ? $t("dm.sendMessage")
+ : $t("dm.relaysNotFound").replace("[R]", name(selectedChat))}
+ on:click={async () => sendMessage(text)}
+ />
+ {/if}
- .short {
- height: 1.5em;
- margin-bottom: 10px;
- }
+ {#if !(muted && muted.has(selectedChat.pubkey))}
+ <input
+ type="checkbox"
+ id="expiryCheckbox"
+ class="tiny"
+ bind:checked={expiryEnabled}
+ disabled={!canSendExpiring}
+ />
+ <label for="expiryCheckbox">{$t("dm.expiry")}</label>:
+ <input
+ type="number"
+ class="short small-width vcenter"
+ bind:value={expiryDays}
+ disabled={!expiryEnabled}
+ min="1"
+ step="1"
+ max="99999"
+ /> <label for="expiryCheckbox">{$t("dm.days")}</label>.
+ <p class="secondary">{$t("dm.fadedWarning")}</p>
+ {#if canSend && !canSendExpiring}
+ <p class="warning">
+ <em
+ >{$t("dm.cantSendExpiring").replace(
+ "[R]",
+ name(selectedChat),
+ )}</em
+ >
+ </p>
+ {/if}
+ {/if}
+ {:else if chats.length == 0}
+ <p>{$t("dm.noChats")}</p>
+ {:else}
+ <p>{$t("dm.selectChat")}</p>
+ {/if}
+ {#if relayWarningShown}
+ <p class="warning">
+ <em
+ >{$t("dm.noRelaysSet")}
+ <a class="link" href="/settings/nostr#dm-relays"
+ >{$t("dm.nostrSettingsLink")}</a
+ ></em
+ >
+ </p>
+ {/if}
+ </div>
+</div>
- .small-width {
- width: 6em;
- }
+<style>
+ .warning {
+ color: #ff7f00;
+ }
- .tiny {
- width: 2em;
- }
+ .secondary {
+ color: #7f7f7f;
+ }
- .invalid {
- text-decoration: line-through;
- }
+ .link {
+ text-decoration-line: underline;
+ }
- .super-container {
- display: flex;
- }
+ .inline {
+ white-space: nowrap;
+ }
- .sidebar {
- max-width: 300px;
- padding: 0px 10px 5px;
- margin: 0px 5px;
- height: 100%;
- border-radius: 10px;
- }
+ .short {
+ height: 1.5em;
+ margin-bottom: 10px;
+ }
- .light-sidebar {
- background-color: #eeeeee;
- }
+ .small-width {
+ width: 6em;
+ }
- .dark-sidebar {
- background-color: #222222;
- }
+ .tiny {
+ width: 2em;
+ }
- .chat-btn {
- margin: 2px 0px;
- padding: 0 25px;
- border-radius: 10px;
- min-width: 30px;
- text-align: left;
- }
+ .invalid {
+ text-decoration: line-through;
+ }
- .tall-btn {
- min-height: 3em;
- width: 100%;
- }
+ .super-container {
+ display: flex;
+ }
- .small-btn {
- padding: 0 15px;
- border-radius: 5px;
- text-align: left;
- }
+ .sidebar {
+ max-width: 300px;
+ padding: 0px 10px 5px;
+ margin: 0px 5px;
+ height: 100%;
+ border-radius: 10px;
+ }
- .push-right {
- margin-left: auto;
- }
+ .light-sidebar {
+ background-color: #eeeeee;
+ }
- .chat-header {
- margin: 1em 15px 0.5em;
- }
+ .dark-sidebar {
+ background-color: #222222;
+ }
- .light-chat-btn {
- background-color: #eeeeee;
- }
+ .chat-btn {
+ margin: 2px 0px;
+ padding: 0 25px;
+ border-radius: 10px;
+ min-width: 30px;
+ text-align: left;
+ }
- .dark-chat-btn {
- background-color: #222222;
- }
+ .tall-btn {
+ min-height: 3em;
+ width: 100%;
+ }
- .light-chat-btn:hover {
- background-color: #dddddd;
- }
+ .small-btn {
+ padding: 0 15px;
+ border-radius: 5px;
+ text-align: left;
+ }
- .dark-chat-btn:hover {
- background-color: #333333;
- }
+ .push-right {
+ margin-left: auto;
+ }
- .light-selected {
- background-color: #dddddd;
- }
+ .chat-header {
+ margin: 1em 15px 0.5em;
+ }
- .dark-selected {
- background-color: #333333;
- }
+ .light-chat-btn {
+ background-color: #eeeeee;
+ }
- .main {
- padding-left: 0px;
- margin-left: 30px;
- }
+ .dark-chat-btn {
+ background-color: #222222;
+ }
- .date-header {
- text-align: center;
- margin: 1.5em 0em;
- }
+ .light-chat-btn:hover {
+ background-color: #dddddd;
+ }
- .timestamp {
- margin-left: 0.5em;
- text-align: right;
- }
+ .dark-chat-btn:hover {
+ background-color: #333333;
+ }
- .message {
- padding: 0.25em 0.75em;
- width: fit-content;
- max-width: 75%;
- border-radius: 10px;
- }
+ .light-selected {
+ background-color: #dddddd;
+ }
- .light-message {
- background-color: #DDD;
- }
+ .dark-selected {
+ background-color: #333333;
+ }
- .dark-message {
- background-color: #222;
- }
+ .main {
+ padding-left: 0px;
+ margin-left: 30px;
+ }
- .by-user {
- margin: 3px 0px 3px auto;
- }
+ .date-header {
+ text-align: center;
+ margin: 1.5em 0em;
+ }
- .by-other {
- margin: 3px auto 3px 0px;
- }
+ .timestamp {
+ margin-left: 0.5em;
+ text-align: right;
+ }
- .vcenter {
- margin: auto 0px;
- }
-</style>
+ .message {
+ padding: 0.25em 0.75em;
+ width: fit-content;
+ max-width: 75%;
+ border-radius: 10px;
+ }
-<div class="super-container">
- <div class={"sidebar " + ($theme === "light" ? "light-sidebar" : "dark-sidebar")}>
- <h2 class="text-xl chat-header">
- {creatingNewChat ? $t("dm.newChatHeader") : $t("dm.chatHeader")}
- <button class={"chat-btn push-right " + ($theme === "light" ? "light-chat-btn" : "dark-chat-btn") + (creatingNewChat ? ($theme === "light" ? " light-selected" : " dark-selected") : "")} on:click={() => {creatingNewChat = !creatingNewChat; selectedChat = null}}>+</button>
- </h2>
- {#if creatingNewChat}
- <input type="text" class="short" bind:value={searchQuery} placeholder="{$t("dm.searchPrompt")}">
- {/if}
- {#if !creatingNewChat}
- {#each chats as c}
- {#if (selectedChat && selectedChat.pubkey === c.pubkey) || !(muted && muted.has(c.pubkey))}
- <button class={"chat-btn tall-btn " + ($theme === "light" ? "light-chat-btn" : "dark-chat-btn") + (selectedChat && selectedChat.pubkey == c.pubkey ? ($theme === "light" ? " light-selected" : " dark-selected") : "")} on:click={() => selectChat(c)}>
- <span class="{"text-xl" + (muted && muted.has(c.pubkey) ? " secondary" : "")}">{name(c)}</span> <span class={(idValid(c) ? "" : "invalid ") + "secondary text-xs"}>{id(c)}</span>
- </button>
- {/if}
- {/each}
- {:else if searchQuery !== ""}
- <button class={"chat-btn tall-btn " + ($theme === "light" ? "light-chat-btn" : "dark-chat-btn")} on:click={() => selectChatUsername(searchQuery)}>
- <span class="text-xl">{$t("dm.findByUsername")}</span>
- </button>
- {#if searchQuery.includes(".")}
- <button class={"chat-btn tall-btn " + ($theme === "light" ? "light-chat-btn" : "dark-chat-btn")} on:click={() => selectChatNip05(searchQuery)}>
- <span class="text-xl">{$t("dm.findByNIP05")}</span>
- </button>
- {/if}
- {#if searchQuery.length === 64 || searchQuery.slice(0, 4) === "npub"}
- <button class={"chat-btn tall-btn " + ($theme === "light" ? "light-chat-btn" : "dark-chat-btn")} on:click={() => selectChatPubkey(searchQuery)}>
- <span class="text-xl">{$t("dm.findByPubkey")}</span>
- </button>
- {/if}
- {/if}
- </div>
- <div class="main container space-y-2 mx-auto space-y-5 lg:max-w-xl xl:max-w-2xl lg:pl-10 mt-5 lg:mt-0">
- <h1
- class="text-5xl font-medium text-left w-full mx-auto lg:mx-0 md:w-[500px]"
- >{$t("dm.header")}</h1>
+ .light-message {
+ background-color: #ddd;
+ }
- {#if selectedChat}
- <h1>
- {#if selectedChat.coinosUsername}
- <a class="text-3xl" href="/{selectedChat.coinosUsername}">{name(selectedChat)}</a>
- {:else}
- <span class="text-3xl">{name(selectedChat)}</span>
- {/if}
- <span class={"secondary timestamp text-small" + (idValid(selectedChat) ? "" : " invalid")} title="{npubEncode(selectedChat.pubkey)}">{id(selectedChat)}</span>
- <button class={"small-btn push-right " + ($theme === "light" ? "light-chat-btn" : "dark-chat-btn")} on:click={() => toggleMute(selectedChat.pubkey)}>{$t(muted && muted.has(selectedChat.pubkey) ? "dm.unmute" : "dm.mute")}</button>
- </h1>
+ .dark-message {
+ background-color: #222;
+ }
- {#if !(muted && muted.has(selectedChat.pubkey))}
- <div id="messages" style="overflow-y: scroll; max-height: 600px;">
- {#each dates as day}
- <p class="date-header secondary">{formatDate(new Date(day * 86400 * 1000))}</p>
- <ul>
- {#each messageRumours.get(day) as rumour}
- {#if rumour.pubkey === user.pubkey && pTagKeys(rumour).includes(selectedChat.pubkey)}
- <li class={(rumour.expiration && expirationClose(rumour.expiration) ? "secondary " : "") + ($theme === "light" ? "light-message " : "dark-message ") + "message by-user"}>{rumour.content} <span class="timestamp secondary text-xs">{TIME.format(new Date(rumour.created_at * 1000))}</span></li>
- {:else if rumour.pubkey === selectedChat.pubkey && pTagKeys(rumour).includes(user.pubkey)}
- <li class={(rumour.expiration && expirationClose(rumour.expiration) ? "secondary " : "") + ($theme === "light" ? "light-message " : "dark-message ") + "message by-other"}>{rumour.content} <span class="timestamp secondary text-xs">{TIME.format(new Date(rumour.created_at * 1000))}</span></li>
- {/if}
- {/each}
- </ul>
- {/each}
- </div>
+ .by-user {
+ margin: 3px 0px 3px auto;
+ }
- <textarea id="message-contents" bind:value={text}></textarea>
- <input id="send-message" type="button" class="btn btn-accent" disabled={!canSend} value={canSend ? $t("dm.sendMessage") : $t("dm.relaysNotFound").replace("[R]", name(selectedChat))} on:click={async () => sendMessage(text)}>
- {/if}
+ .by-other {
+ margin: 3px auto 3px 0px;
+ }
- {#if !(muted && muted.has(selectedChat.pubkey))}
- <input type="checkbox" id="expiryCheckbox" class="tiny" bind:checked={expiryEnabled} disabled={!canSendExpiring}>
- <label for="expiryCheckbox">{$t("dm.expiry")}</label>: <input type="number" class="short small-width vcenter" bind:value={expiryDays} disabled={!expiryEnabled} min="1" step="1" max="99999"> <label for="expiryCheckbox">{$t("dm.days")}</label>.
- <p class="secondary">{$t("dm.fadedWarning")}</p>
- {#if canSend && !canSendExpiring}
- <p class="warning"><em>{$t("dm.cantSendExpiring").replace("[R]", name(selectedChat))}</em></p>
- {/if}
- {/if}
- {:else if chats.length == 0}
- <p>{$t("dm.noChats")}</p>
- {:else}
- <p>{$t("dm.selectChat")}</p>
- {/if}
- {#if relayWarningShown}
- <p class="warning"><em>{$t("dm.noRelaysSet")} <a class="link" href="/settings/nostr#dm-relays">{$t("dm.nostrSettingsLink")}</a></em></p>
- {/if}
- </div>
-</div>
+ .vcenter {
+ margin: auto 0px;
+ }
+</style>
diff --git a/src/routes/(app)/e/[id]/+page.server.ts b/src/routes/(app)/e/[id]/+page.server.ts
index 2a62dba0..8cb59334 100644
--- a/src/routes/(app)/e/[id]/+page.server.ts
+++ b/src/routes/(app)/e/[id]/+page.server.ts
@@ -1,12 +1,12 @@
-import { get, post } from "$lib/utils";
+import { get } from "$lib/utils";
import { error } from "@sveltejs/kit";
export async function load({ params }) {
- try {
- const event = await get(`/event/${params.id}/full`);
- return { event };
- } catch (e) {
- console.log(e);
- error(500, { message: "Failed to get event" });
- }
+ try {
+ const event = await get(`/event/${params.id}/full`);
+ return { event };
+ } catch (e) {
+ console.log(e);
+ error(500, { message: "Failed to get event" });
+ }
}
diff --git a/src/routes/(app)/ecash/[id]/[...version]/+layout.server.ts b/src/routes/(app)/ecash/[id]/[...version]/+layout.server.ts
index 50be6986..2093e8ec 100644
--- a/src/routes/(app)/ecash/[id]/[...version]/+layout.server.ts
+++ b/src/routes/(app)/ecash/[id]/[...version]/+layout.server.ts
@@ -2,22 +2,22 @@ import getRates from "$lib/rates";
import { get } from "$lib/utils";
export async function load({ params, parent }) {
- const { user } = await parent();
- const rates = await getRates();
- let { id, version } = params;
- version ||= 4;
- version = parseInt(version);
+ const { user } = await parent();
+ const rates = await getRates();
+ let { id, version } = params;
+ version ||= 4;
+ version = parseInt(version);
- const { token, status } = await get(`/cash/${id}/${version}`);
- const { spent, total, mint, external } = status;
- return {
- id,
- token,
- spent,
- total,
- mint,
- external,
- version,
- rate: rates[user?.currency || "USD"],
- };
+ const { token, status } = await get(`/cash/${id}/${version}`);
+ const { spent, total, mint, external } = status;
+ return {
+ id,
+ token,
+ spent,
+ total,
+ mint,
+ external,
+ version,
+ rate: rates[user?.currency || "USD"],
+ };
}
diff --git a/src/routes/(app)/ecash/[id]/[...version]/+page.server.ts b/src/routes/(app)/ecash/[id]/[...version]/+page.server.ts
index 26ccb307..08efb998 100644
--- a/src/routes/(app)/ecash/[id]/[...version]/+page.server.ts
+++ b/src/routes/(app)/ecash/[id]/[...version]/+page.server.ts
@@ -3,26 +3,26 @@ import { auth, fd, post } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export async function load({ parent }) {
- const { user } = await parent();
- const rates = await getRates();
- return { rate: rates[user?.currency || "USD"] };
+ const { user } = await parent();
+ const rates = await getRates();
+ return { rate: rates[user?.currency || "USD"] };
}
export const actions = {
- default: async ({ cookies, request, url }) => {
- if (!cookies.get("username"))
- redirect(307, `/register?redirect=${url.pathname}`);
+ default: async ({ cookies, request, url }) => {
+ if (!cookies.get("username"))
+ redirect(307, `/register?redirect=${url.pathname}`);
- const { token } = await fd(request);
- let claimed;
- try {
- claimed = await post("/claim", { token }, auth(cookies));
- claimed = { ok: true };
- } catch (e: any) {
- return fail(400, { error: e.message });
- }
- if (claimed?.ok) {
- redirect(307, "/payments");
- }
- },
+ const { token } = await fd(request);
+ let claimed;
+ try {
+ claimed = await post("/claim", { token }, auth(cookies));
+ claimed = { ok: true };
+ } catch (e: any) {
+ return fail(400, { error: e.message });
+ }
+ if (claimed?.ok) {
+ redirect(307, "/payments");
+ }
+ },
};
diff --git a/src/routes/(app)/ecash/[id]/[...version]/swap/+page.server.ts b/src/routes/(app)/ecash/[id]/[...version]/swap/+page.server.ts
index f82bdbb1..14e4767d 100644
--- a/src/routes/(app)/ecash/[id]/[...version]/swap/+page.server.ts
+++ b/src/routes/(app)/ecash/[id]/[...version]/swap/+page.server.ts
@@ -1,3 +1,3 @@
export async function load() {
- return { test: 123 };
+ return { test: 123 };
}
diff --git a/src/routes/(app)/ecash/mint/+server.ts b/src/routes/(app)/ecash/mint/+server.ts
index 02170650..e933208e 100644
--- a/src/routes/(app)/ecash/mint/+server.ts
+++ b/src/routes/(app)/ecash/mint/+server.ts
@@ -2,6 +2,6 @@ import { auth, post } from "$lib/utils";
import { json } from "@sveltejs/kit";
export async function POST({ cookies, request }) {
- const result = await post("/mint", await request.json(), auth(cookies));
- return json(result);
+ const result = await post("/mint", await request.json(), auth(cookies));
+ return json(result);
}
diff --git a/src/routes/(app)/ecash/post/+server.ts b/src/routes/(app)/ecash/post/+server.ts
index bc6cb099..371582bc 100644
--- a/src/routes/(app)/ecash/post/+server.ts
+++ b/src/routes/(app)/ecash/post/+server.ts
@@ -1,11 +1,11 @@
import { json } from "@sveltejs/kit";
export async function POST({ fetch, request }) {
- const { target, payload } = await request.json();
- const res = await fetch(target, {
- method: "POST",
- body: JSON.stringify(payload),
- headers: { "Content-Type": "application/json" },
- });
- return json(res);
+ const { target, payload } = await request.json();
+ const res = await fetch(target, {
+ method: "POST",
+ body: JSON.stringify(payload),
+ headers: { "Content-Type": "application/json" },
+ });
+ return json(res);
}
diff --git a/src/routes/(app)/email/+server.ts b/src/routes/(app)/email/+server.ts
index eb98a401..437c0ef0 100644
--- a/src/routes/(app)/email/+server.ts
+++ b/src/routes/(app)/email/+server.ts
@@ -2,6 +2,6 @@ import { auth, post } from "$lib/utils";
import { json } from "@sveltejs/kit";
export async function POST({ cookies, request }) {
- const result = await post("/request", await request.json(), auth(cookies));
- return json(result);
+ const result = await post("/request", await request.json(), auth(cookies));
+ return json(result);
}
diff --git a/src/routes/(app)/enable2fa/+server.ts b/src/routes/(app)/enable2fa/+server.ts
index 988dd0ed..76737968 100644
--- a/src/routes/(app)/enable2fa/+server.ts
+++ b/src/routes/(app)/enable2fa/+server.ts
@@ -1,8 +1,8 @@
import { auth, post } from "$lib/utils";
export async function POST({ cookies, request }) {
- const body = await request.json();
- const res = await post("/2fa", body, auth(cookies));
+ const body = await request.json();
+ const res = await post("/2fa", body, auth(cookies));
- return new Response(JSON.stringify(res));
+ return new Response(JSON.stringify(res));
}
diff --git a/src/routes/(app)/events/+server.ts b/src/routes/(app)/events/+server.ts
index f3010834..e2553753 100644
--- a/src/routes/(app)/events/+server.ts
+++ b/src/routes/(app)/events/+server.ts
@@ -2,11 +2,11 @@ import { auth, post } from "$lib/utils";
import { error, json } from "@sveltejs/kit";
export async function POST({ cookies, request }) {
- const body = await request.json();
- try {
- const result = await post("/event", body, auth(cookies));
- return json(result);
- } catch (e: any) {
- error(500, e.message);
- }
+ const body = await request.json();
+ try {
+ const result = await post("/event", body, auth(cookies));
+ return json(result);
+ } catch (e: any) {
+ error(500, e.message);
+ }
}
diff --git a/src/routes/(app)/fund/[id]/+layout.server.ts b/src/routes/(app)/fund/[id]/+layout.server.ts
index 3669eb7d..bf132e7b 100644
--- a/src/routes/(app)/fund/[id]/+layout.server.ts
+++ b/src/routes/(app)/fund/[id]/+layout.server.ts
@@ -2,11 +2,11 @@ import getRates from "$lib/rates";
import { get } from "$lib/utils";
export const load = async ({ depends, params: { id }, parent }) => {
- depends("app:payments");
- const data = await get(`/fund/${id}`);
- data.managers = await get(`/fund/${id}/managers`);
- const rates = await getRates();
- const { user } = await parent();
- data.rate = rates[user?.currency || "USD"];
- return data;
+ depends("app:payments");
+ const data = await get(`/fund/${id}`);
+ data.managers = await get(`/fund/${id}/managers`);
+ const rates = await getRates();
+ const { user } = await parent();
+ data.rate = rates[user?.currency || "USD"];
+ return data;
};
diff --git a/src/routes/(app)/fund/[id]/+page.server.ts b/src/routes/(app)/fund/[id]/+page.server.ts
index cd2bd979..5a30e560 100644
--- a/src/routes/(app)/fund/[id]/+page.server.ts
+++ b/src/routes/(app)/fund/[id]/+page.server.ts
@@ -2,14 +2,14 @@ import { auth, post } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export const actions = {
- default: async ({ cookies, locals, params }) => {
- const { user } = locals;
+ default: async ({ cookies, locals, params }) => {
+ const { user } = locals;
- if (user) {
- await post("/redeem", params, auth(cookies));
- redirect(307, "/payments");
- }
+ if (user) {
+ await post("/redeem", params, auth(cookies));
+ redirect(307, "/payments");
+ }
- redirect(307, "/register");
- },
+ redirect(307, "/register");
+ },
};
diff --git a/src/routes/(app)/fund/[id]/+page.svelte b/src/routes/(app)/fund/[id]/+page.svelte
index c3fa7ce1..34e0d503 100644
--- a/src/routes/(app)/fund/[id]/+page.svelte
+++ b/src/routes/(app)/fund/[id]/+page.svelte
@@ -21,7 +21,9 @@
let currency = user ? user.currency : "CAD";
let amountFiat = $derived(parseFloat(((amount * rate) / sats).toFixed(2)));
- $effect(() => { $loginRedirect = $page.url.pathname; });
+ $effect(() => {
+ $loginRedirect = $page.url.pathname;
+ });
let show = $state();
let toggle = () => (show = !show);
diff --git a/src/routes/(app)/fund/[id]/access/+page.server.ts b/src/routes/(app)/fund/[id]/access/+page.server.ts
index 36191643..6e995f1c 100644
--- a/src/routes/(app)/fund/[id]/access/+page.server.ts
+++ b/src/routes/(app)/fund/[id]/access/+page.server.ts
@@ -2,21 +2,21 @@ import { auth, fd, get, post } from "$lib/utils";
import { fail } from "@sveltejs/kit";
export const load = async ({ params: { id } }) => {
- const managers = await get(`/fund/${id}/managers`);
- return { managers, id };
+ const managers = await get(`/fund/${id}/managers`);
+ return { managers, id };
};
export const actions = {
- default: async ({ cookies, request }) => {
- const form = await fd(request);
+ default: async ({ cookies, request }) => {
+ const form = await fd(request);
- try {
- const managers = await post("/fund/managers", form, auth(cookies));
+ try {
+ const managers = await post("/fund/managers", form, auth(cookies));
- return { managers };
- } catch (e) {
- const { message } = e as Error;
- return fail(400, { message });
- }
- },
+ return { managers };
+ } catch (e) {
+ const { message } = e as Error;
+ return fail(400, { message });
+ }
+ },
};
diff --git a/src/routes/(app)/fund/[id]/authorize/[...amount]/+page.server.ts b/src/routes/(app)/fund/[id]/authorize/[...amount]/+page.server.ts
index e5683ae6..94d9ff62 100644
--- a/src/routes/(app)/fund/[id]/authorize/[...amount]/+page.server.ts
+++ b/src/routes/(app)/fund/[id]/authorize/[...amount]/+page.server.ts
@@ -3,34 +3,34 @@ import { auth, get, post, sats } from "$lib/utils";
import { error, redirect } from "@sveltejs/kit";
export async function load({ cookies, params, parent }) {
- const { user } = await parent();
- const { id } = params;
- let [amount, currency] = params.amount.split("/");
- let fiat;
+ const { user } = await parent();
+ const { id } = params;
+ let [amount, currency] = params.amount.split("/");
+ let fiat;
- if (!currency) currency = user?.currency;
+ if (!currency) currency = user?.currency;
if (currency) currency = currency.toUpperCase();
- const rates = await getRates();
- const rate = rates[currency || "USD"];
- if (currency && !rate) error(500, "Invalid currency symbol");
+ const rates = await getRates();
+ const rate = rates[currency || "USD"];
+ if (currency && !rate) error(500, "Invalid currency symbol");
- if (!amount) {
- const balance = await get(`/fund/${id}`);
- amount = balance.amount;
- } else if (currency) {
- fiat = amount;
- amount = Math.round((fiat * sats) / rate);
- }
+ if (!amount) {
+ const balance = await get(`/fund/${id}`);
+ amount = balance.amount;
+ } else if (currency) {
+ fiat = amount;
+ amount = Math.round((fiat * sats) / rate);
+ }
- if (!amount) redirect(307, `/fund/${id}`);
+ if (!amount) redirect(307, `/fund/${id}`);
- try {
- await post("/authorize", { amount, currency, fiat, id }, auth(cookies));
- } catch (e) {
- console.log("caught", e);
- redirect(307, `/fund/${id}`);
- }
+ try {
+ await post("/authorize", { amount, currency, fiat, id }, auth(cookies));
+ } catch (e) {
+ console.log("caught", e);
+ redirect(307, `/fund/${id}`);
+ }
- return { amount, currency, id, rate, rates };
+ return { amount, currency, id, rate, rates };
}
diff --git a/src/routes/(app)/fund/[id]/gift/+page.server.ts b/src/routes/(app)/fund/[id]/gift/+page.server.ts
index bd39d82b..549fc9d0 100644
--- a/src/routes/(app)/fund/[id]/gift/+page.server.ts
+++ b/src/routes/(app)/fund/[id]/gift/+page.server.ts
@@ -1,6 +1,6 @@
export const load = async ({ params, parent }) => {
- const p = await parent();
- const { amount, rate } = p;
- const { id } = params;
- return { amount, id, rate };
+ const p = await parent();
+ const { amount, rate } = p;
+ const { id } = params;
+ return { amount, id, rate };
};
diff --git a/src/routes/(app)/fund/[id]/gift/+page.svelte b/src/routes/(app)/fund/[id]/gift/+page.svelte
index 4e1efad3..9bef9c64 100644
--- a/src/routes/(app)/fund/[id]/gift/+page.svelte
+++ b/src/routes/(app)/fund/[id]/gift/+page.svelte
@@ -1,7 +1,8 @@
<script lang="ts">
import Amount from "$comp/Amount.svelte";
import { t } from "$lib/translations";
- import { page } from "$app/stores"; import Qr from "$comp/Qr.svelte";
+ import { page } from "$app/stores";
+ import Qr from "$comp/Qr.svelte";
import { loc, copy } from "$lib/utils";
let { data } = $props();
diff --git a/src/routes/(app)/fund/[id]/sweep/[...amount]/+page.server.ts b/src/routes/(app)/fund/[id]/sweep/[...amount]/+page.server.ts
index 8cc463c2..82854fb2 100644
--- a/src/routes/(app)/fund/[id]/sweep/[...amount]/+page.server.ts
+++ b/src/routes/(app)/fund/[id]/sweep/[...amount]/+page.server.ts
@@ -5,52 +5,51 @@ import { error, redirect } from "@sveltejs/kit";
import { env } from "$env/dynamic/private";
export async function load({ cookies, request, params, parent }) {
- let { user } = await parent();
- const { id } = params;
- let [amount, currency] = params.amount.split("/");
+ let { user } = await parent();
+ const { id } = params;
+ let [amount, currency] = params.amount.split("/");
- if (!currency) currency = user?.currency;
- if (currency) currency = currency.toUpperCase();
- const rates = await getRates();
- const rate = rates[currency || "USD"];
- if (currency && !rate) error(500, "Invalid currency symbol");
+ if (!currency) currency = user?.currency;
+ if (currency) currency = currency.toUpperCase();
+ const rates = await getRates();
+ const rate = rates[currency || "USD"];
+ if (currency && !rate) error(500, "Invalid currency symbol");
- if (!amount) {
- const balance = await get(`/fund/${id}`);
- amount = balance.authorization || balance.amount;
- } else if (currency) {
- amount = Math.round((amount * sats) / rate);
- }
+ if (!amount) {
+ const balance = await get(`/fund/${id}`);
+ amount = balance.authorization || balance.amount;
+ } else if (currency) {
+ amount = Math.round((amount * sats) / rate);
+ }
- const username = randomName() + Math.floor(Math.random() * 99) + 1;
- const password = randomPassword();
+ const username = randomName() + Math.floor(Math.random() * 99) + 1;
+ const password = randomPassword();
- if (!amount) redirect(307, `/fund/${id}`);
- if (!user) {
- const ip = request.headers.get("cf-connecting-ip");
+ if (!amount) redirect(307, `/fund/${id}`);
+ if (!user) {
+ const ip = request.headers.get("cf-connecting-ip");
- user = {
- username,
- password,
- fresh: true,
- };
+ user = {
+ username,
+ password,
+ fresh: true,
+ };
- let redirectUrl = `/fund/${id}/sweep`;
- if (params.amount && !params.currency) redirectUrl += `/${params.amount}`;
- if (params.currency) redirectUrl += `/${params.amount}/params.currency}`;
+ let redirectUrl = `/fund/${id}/sweep`;
+ if (params.amount && !params.currency) redirectUrl += `/${params.amount}`;
+ if (params.currency) redirectUrl += `/${params.amount}/params.currency}`;
- const extraHeaders: Record<string, string> = {};
- if (env.INTERNAL_API_KEY)
- extraHeaders["x-api-key"] = env.INTERNAL_API_KEY;
+ const extraHeaders: Record<string, string> = {};
+ if (env.INTERNAL_API_KEY) extraHeaders["x-api-key"] = env.INTERNAL_API_KEY;
- await register(user, ip, cookies, redirectUrl, undefined, extraHeaders);
- }
+ await register(user, ip, cookies, redirectUrl, undefined, extraHeaders);
+ }
- try {
- ({ amount } = await post("/take", { amount, id }, auth(cookies)));
- } catch (e) {
- redirect(307, `/fund/${id}`);
- }
+ try {
+ ({ amount } = await post("/take", { amount, id }, auth(cookies)));
+ } catch {
+ redirect(307, `/fund/${id}`);
+ }
- return { amount, currency, id, rate, rates, password };
+ return { amount, currency, id, rate, rates, password };
}
diff --git a/src/routes/(app)/fund/[id]/withdraw/+page.server.ts b/src/routes/(app)/fund/[id]/withdraw/+page.server.ts
index 696c52ff..d302b4c1 100644
--- a/src/routes/(app)/fund/[id]/withdraw/+page.server.ts
+++ b/src/routes/(app)/fund/[id]/withdraw/+page.server.ts
@@ -3,25 +3,25 @@ import { auth, fd, get, post } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export async function load({ params, parent }) {
- const { user } = await parent();
- if (!user) redirect(307, "/register");
- const rates = await getRates();
- const rate = rates[user.currency];
- const fund = await get(`/fund/${params.id}`);
- const { amount: balance } = fund;
- return { ...params, balance, rate };
+ const { user } = await parent();
+ if (!user) redirect(307, "/register");
+ const rates = await getRates();
+ const rate = rates[user.currency];
+ const fund = await get(`/fund/${params.id}`);
+ const { amount: balance } = fund;
+ return { ...params, balance, rate };
}
export const actions = {
- default: async ({ cookies, request }) => {
- const body = await fd(request);
- try {
- await post("/take", body, auth(cookies));
- } catch (e) {
- const { message } = e as Error;
- return fail(400, { message });
- }
+ default: async ({ cookies, request }) => {
+ const body = await fd(request);
+ try {
+ await post("/take", body, auth(cookies));
+ } catch (e) {
+ const { message } = e as Error;
+ return fail(400, { message });
+ }
- redirect(307, `/fund/${body.id}`);
- },
+ redirect(307, `/fund/${body.id}`);
+ },
};
diff --git a/src/routes/(app)/fund/[id]/withdraw/+server.ts b/src/routes/(app)/fund/[id]/withdraw/+server.ts
index dabef6f8..96d66413 100644
--- a/src/routes/(app)/fund/[id]/withdraw/+server.ts
+++ b/src/routes/(app)/fund/[id]/withdraw/+server.ts
@@ -2,5 +2,5 @@ import { json } from "@sveltejs/kit";
import { auth, post } from "$lib/utils";
export async function POST({ cookies, request }) {
- return json(await post("/take", await request.json(), auth(cookies)));
+ return json(await post("/take", await request.json(), auth(cookies)));
}
diff --git a/src/routes/(app)/funder/+page.svelte b/src/routes/(app)/funder/+page.svelte
index e6549360..408b1236 100644
--- a/src/routes/(app)/funder/+page.svelte
+++ b/src/routes/(app)/funder/+page.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
- import { onMount } from 'svelte';
-let here = false;
+ import { onMount } from "svelte";
+ let here = false;
let ready = false;
let success = false;
let controller: AbortController | null = null;
@@ -26,21 +26,21 @@ let here = false;
{
records: [
{
- recordType: 'url',
- data: 'https://coinos.io',
+ recordType: "url",
+ data: "https://coinos.io",
},
],
},
- { signal: controller.signal }
+ { signal: controller.signal },
);
success = true;
} catch (err) {
- if (err.name === 'AbortError') {
- console.warn('Previous write aborted');
+ if (err.name === "AbortError") {
+ console.warn("Previous write aborted");
} else {
- console.error('Write failed', err);
- alert('❌ Write failed: ' + err.message);
+ console.error("Write failed", err);
+ alert("❌ Write failed: " + err.message);
}
} finally {
await NfcWriter.disableExclusiveNfcMode();
diff --git a/src/routes/(app)/invoice/+page.server.ts b/src/routes/(app)/invoice/+page.server.ts
index 64c49ebc..dc024229 100644
--- a/src/routes/(app)/invoice/+page.server.ts
+++ b/src/routes/(app)/invoice/+page.server.ts
@@ -4,29 +4,29 @@ import { auth, post } from "$lib/utils";
import { error, redirect } from "@sveltejs/kit";
export const load = async ({ cookies, parent }) => {
- const aid = cookies.get("aid");
- let { subject, user } = await parent();
+ const aid = cookies.get("aid");
+ let { subject, user } = await parent();
- const rates = await getRates();
- if (aid === user.id) redirect(307, `/${user.username}/receive`);
+ const rates = await getRates();
+ if (aid === user.id) redirect(307, `/${user.username}/receive`);
- let invoice: Invoice = {
- aid,
- rate: rates[user?.currency || subject?.currency],
- };
+ let invoice: Invoice = {
+ aid,
+ rate: rates[user?.currency || subject?.currency],
+ };
- if (!user) user = subject;
+ if (!user) user = subject;
- try {
- invoice = await post("/invoice", { invoice, aid, user }, auth(cookies));
- } catch (e) {
- console.log(e);
- error(500, "Failed to generate invoice");
- }
+ try {
+ invoice = await post("/invoice", { invoice, aid, user }, auth(cookies));
+ } catch (e) {
+ console.log(e);
+ error(500, "Failed to generate invoice");
+ }
- const { id } = invoice;
+ const { id } = invoice;
- if (invoice.memoPrompt && !invoice.memo) {
- redirect(307, `/invoice/${id}/memo`);
- } else redirect(307, `/invoice/${id}`);
+ if (invoice.memoPrompt && !invoice.memo) {
+ redirect(307, `/invoice/${id}/memo`);
+ } else redirect(307, `/invoice/${id}`);
};
diff --git a/src/routes/(app)/invoice/+server.ts b/src/routes/(app)/invoice/+server.ts
index f494c153..b18eae15 100644
--- a/src/routes/(app)/invoice/+server.ts
+++ b/src/routes/(app)/invoice/+server.ts
@@ -2,11 +2,11 @@ import { auth, post } from "$lib/utils";
import { error, json } from "@sveltejs/kit";
export const POST = async ({ cookies, request }) => {
- try {
- const body = await request.json();
- return json(await post("/invoice", body, auth(cookies)));
- } catch (e) {
- const { message } = e as Error;
- error(500, message);
- }
+ try {
+ const body = await request.json();
+ return json(await post("/invoice", body, auth(cookies)));
+ } catch (e) {
+ const { message } = e as Error;
+ error(500, message);
+ }
};
diff --git a/src/routes/(app)/invoice/[id]/+layout.server.ts b/src/routes/(app)/invoice/[id]/+layout.server.ts
index ce76d150..d6ee4246 100644
--- a/src/routes/(app)/invoice/[id]/+layout.server.ts
+++ b/src/routes/(app)/invoice/[id]/+layout.server.ts
@@ -2,43 +2,43 @@ import { get } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export async function load({ cookies, depends, params, url, parent }) {
- depends("app:invoice");
+ depends("app:invoice");
- const token = cookies.get("token");
- let { subject, user } = await parent();
- const { id } = params;
- let invoice;
+ const token = cookies.get("token");
+ let { subject, user } = await parent();
+ const { id } = params;
+ let invoice;
- if (id) {
- invoice = await get(`/invoice/${id}`);
- const options = !!url.searchParams.get("options");
- let { amount, pending, received } = invoice;
- amount = parseInt(amount);
+ if (id) {
+ invoice = await get(`/invoice/${id}`);
+ const options = !!url.searchParams.get("options");
+ let { amount, pending, received } = invoice;
+ amount = parseInt(amount);
- const paid =
- (!amount && (pending || received)) ||
- (amount > 0 && (pending >= amount || received >= amount));
- if (paid && !url.pathname.endsWith("paid")) {
- redirect(307, `/invoice/${id}/paid` + (options ? "?options=true" : ""));
- }
+ const paid =
+ (!amount && (pending || received)) ||
+ (amount > 0 && (pending >= amount || received >= amount));
+ if (paid && !url.pathname.endsWith("paid")) {
+ redirect(307, `/invoice/${id}/paid` + (options ? "?options=true" : ""));
+ }
- subject = invoice.user;
+ subject = invoice.user;
- const aid = cookies.get("aid") || user?.id;
- if (
- user &&
- (invoice.uid !== user?.id || aid !== invoice.aid) &&
- !(url.pathname.includes("tip") || url.pathname.includes("memo")) &&
- !options
- ) {
- if (invoice.prompt && invoice.tip === null)
- redirect(307, `/invoice/${id}/tip`);
- else {
- redirect(307, `/send/invoice/${id}`);
- }
- }
- }
+ const aid = cookies.get("aid") || user?.id;
+ if (
+ user &&
+ (invoice.uid !== user?.id || aid !== invoice.aid) &&
+ !(url.pathname.includes("tip") || url.pathname.includes("memo")) &&
+ !options
+ ) {
+ if (invoice.prompt && invoice.tip === null)
+ redirect(307, `/invoice/${id}/tip`);
+ else {
+ redirect(307, `/send/invoice/${id}`);
+ }
+ }
+ }
- const theme = cookies.get("theme") || "light";
- return { id, invoice, subject, user, token, theme };
+ const theme = cookies.get("theme") || "light";
+ return { id, invoice, subject, user, token, theme };
}
diff --git a/src/routes/(app)/invoice/[id]/+page.server.ts b/src/routes/(app)/invoice/[id]/+page.server.ts
index d54ff30d..a57efa64 100644
--- a/src/routes/(app)/invoice/[id]/+page.server.ts
+++ b/src/routes/(app)/invoice/[id]/+page.server.ts
@@ -1,5 +1,5 @@
import invoice from "$lib/invoice";
export const actions = {
- default: invoice,
+ default: invoice,
};
diff --git a/src/routes/(app)/invoice/[id]/memo/+page.server.ts b/src/routes/(app)/invoice/[id]/memo/+page.server.ts
index d54ff30d..a57efa64 100644
--- a/src/routes/(app)/invoice/[id]/memo/+page.server.ts
+++ b/src/routes/(app)/invoice/[id]/memo/+page.server.ts
@@ -1,5 +1,5 @@
import invoice from "$lib/invoice";
export const actions = {
- default: invoice,
+ default: invoice,
};
diff --git a/src/routes/(app)/invoice/[id]/tip/+page.server.ts b/src/routes/(app)/invoice/[id]/tip/+page.server.ts
index 851d3f1b..16cc22fa 100644
--- a/src/routes/(app)/invoice/[id]/tip/+page.server.ts
+++ b/src/routes/(app)/invoice/[id]/tip/+page.server.ts
@@ -3,53 +3,53 @@ import { auth, fd, get, post } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export async function load({ cookies, params, parent }) {
- const { id } = params;
- const rates = await getRates();
- let { invoice, subject, user } = await parent();
- if (!invoice.amount) redirect(307, `/invoice/${invoice.id}`);
- const pin = cookies.get("pin");
+ const { id } = params;
+ const rates = await getRates();
+ let { invoice, subject, user } = await parent();
+ if (!invoice.amount) redirect(307, `/invoice/${invoice.id}`);
+ const pin = cookies.get("pin");
- if (user) {
- const trust = await get("/trust", auth(cookies));
- const trusted = trust.includes(invoice.uid);
- if (trusted && (pin || !user.haspin)) {
- let p;
- try {
- if (invoice.tip === null && invoice.user.prompt) {
- if (user.tip > 0) {
- invoice.tip = Math.round(invoice.amount * (user.tip / 100));
- invoice = await post(`/invoice/${id}`, { invoice }, auth(cookies));
- p = await post("/payments", { ...invoice, pin }, auth(cookies));
- }
- } else {
- p = await post("/payments", { ...invoice, pin }, auth(cookies));
- }
- } catch (e) {
- const { message } = e as Error;
- fail(400, { message });
- }
- if (p) redirect(307, `/sent/${p.id}`);
- }
- }
+ if (user) {
+ const trust = await get("/trust", auth(cookies));
+ const trusted = trust.includes(invoice.uid);
+ if (trusted && (pin || !user.haspin)) {
+ let p;
+ try {
+ if (invoice.tip === null && invoice.user.prompt) {
+ if (user.tip > 0) {
+ invoice.tip = Math.round(invoice.amount * (user.tip / 100));
+ invoice = await post(`/invoice/${id}`, { invoice }, auth(cookies));
+ p = await post("/payments", { ...invoice, pin }, auth(cookies));
+ }
+ } else {
+ p = await post("/payments", { ...invoice, pin }, auth(cookies));
+ }
+ } catch (e) {
+ const { message } = e as Error;
+ fail(400, { message });
+ }
+ if (p) redirect(307, `/sent/${p.id}`);
+ }
+ }
- const rate = rates[subject?.currency];
- const invoiceRate = rates[invoice.currency];
- return { rate, invoiceRate };
+ const rate = rates[subject?.currency];
+ const invoiceRate = rates[invoice.currency];
+ return { rate, invoiceRate };
}
export const actions = {
- default: async ({ cookies, request }) => {
- const form = await fd(request);
- const invoice = {
- tip: form.tip ?? null,
- };
+ default: async ({ cookies, request }) => {
+ const form = await fd(request);
+ const invoice = {
+ tip: form.tip ?? null,
+ };
- const { id } = await post(
- `/invoice/${form.id}`,
- { invoice },
- auth(cookies),
- );
+ const { id } = await post(
+ `/invoice/${form.id}`,
+ { invoice },
+ auth(cookies),
+ );
- redirect(307, `/invoice/${id}`);
- },
+ redirect(307, `/invoice/${id}`);
+ },
};
diff --git a/src/routes/(app)/invoice/[id]/tip/+page.svelte b/src/routes/(app)/invoice/[id]/tip/+page.svelte
index 4d3af188..1183093e 100644
--- a/src/routes/(app)/invoice/[id]/tip/+page.svelte
+++ b/src/routes/(app)/invoice/[id]/tip/+page.svelte
@@ -173,11 +173,7 @@
</div>
{/if}
- <button
- type="submit"
- bind:this={submit}
- aria-label="Submit tip"
- ></button>
+ <button type="submit" bind:this={submit} aria-label="Submit tip"></button>
</form>
{#if showCustomAmount}
diff --git a/src/routes/(app)/invoice/sent/+page.svelte b/src/routes/(app)/invoice/sent/+page.svelte
index f8a05801..457ff108 100644
--- a/src/routes/(app)/invoice/sent/+page.svelte
+++ b/src/routes/(app)/invoice/sent/+page.svelte
@@ -1,5 +1,6 @@
<script lang="ts">
- import Avatar from "$comp/Avatar.svelte"; import { request } from "$lib/store";
+ import Avatar from "$comp/Avatar.svelte";
+ import { request } from "$lib/store";
</script>
Invoice sent to
diff --git a/src/routes/(app)/invoices/+page.server.ts b/src/routes/(app)/invoices/+page.server.ts
index eb822802..9c599836 100644
--- a/src/routes/(app)/invoices/+page.server.ts
+++ b/src/routes/(app)/invoices/+page.server.ts
@@ -1,6 +1,6 @@
import { auth, get } from "$lib/utils";
export async function load({ cookies }) {
- const invoices = await get("/invoices", auth(cookies));
- return { invoices };
+ const invoices = await get("/invoices", auth(cookies));
+ return { invoices };
}
diff --git a/src/routes/(app)/items/[id]/+page.server.ts b/src/routes/(app)/items/[id]/+page.server.ts
index 32924d03..d160c051 100644
--- a/src/routes/(app)/items/[id]/+page.server.ts
+++ b/src/routes/(app)/items/[id]/+page.server.ts
@@ -2,20 +2,20 @@ import { fd, auth, get, post } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export const load = async ({ params: { id } }) => {
- const item = await get(`/items/${id}`);
- return { item };
+ const item = await get(`/items/${id}`);
+ return { item };
};
export const actions = {
- default: async ({ cookies, request, url }) => {
- const form = await fd(request);
- try {
- await post("/items", form, auth(cookies));
- } catch (e: any) {
- return fail(400, { message: e.message });
- }
+ default: async ({ cookies, request, url }) => {
+ const form = await fd(request);
+ try {
+ await post("/items", form, auth(cookies));
+ } catch (e: any) {
+ return fail(400, { message: e.message });
+ }
- const success = `/${url.pathname.split("/")[1]}`;
- redirect(307, success);
- },
+ const success = `/${url.pathname.split("/")[1]}`;
+ redirect(307, success);
+ },
};
diff --git a/src/routes/(app)/items/[id]/+page.svelte b/src/routes/(app)/items/[id]/+page.svelte
index 3128f34d..af5ce095 100644
--- a/src/routes/(app)/items/[id]/+page.svelte
+++ b/src/routes/(app)/items/[id]/+page.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { run } from 'svelte/legacy';
+ import { run } from "svelte/legacy";
import { t } from "$lib/translations";
import ItemForm from "$comp/ItemForm.svelte";
diff --git a/src/routes/(app)/items/create/+page.server.ts b/src/routes/(app)/items/create/+page.server.ts
index e125e047..1e6dacb4 100644
--- a/src/routes/(app)/items/create/+page.server.ts
+++ b/src/routes/(app)/items/create/+page.server.ts
@@ -2,15 +2,15 @@ import { fail, redirect } from "@sveltejs/kit";
import { fd, auth, post } from "$lib/utils";
export const actions = {
- default: async ({ cookies, request, url }) => {
- const form = await fd(request);
- try {
- await post("/items", form, auth(cookies));
- } catch (e: any) {
- return fail(400, { message: e.message });
- }
+ default: async ({ cookies, request, url }) => {
+ const form = await fd(request);
+ try {
+ await post("/items", form, auth(cookies));
+ } catch (e: any) {
+ return fail(400, { message: e.message });
+ }
- const success = `/${url.pathname.split("/")[1]}`;
- redirect(307, success);
- },
+ const success = `/${url.pathname.split("/")[1]}`;
+ redirect(307, success);
+ },
};
diff --git a/src/routes/(app)/items/create/+page.svelte b/src/routes/(app)/items/create/+page.svelte
index de400927..5bcb010f 100644
--- a/src/routes/(app)/items/create/+page.svelte
+++ b/src/routes/(app)/items/create/+page.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { run } from 'svelte/legacy';
+ import { run } from "svelte/legacy";
import { t } from "$lib/translations";
import ItemForm from "$comp/ItemForm.svelte";
diff --git a/src/routes/(app)/ln/[lnurl]/+page.server.ts b/src/routes/(app)/ln/[lnurl]/+page.server.ts
index 7348f96c..ae784401 100644
--- a/src/routes/(app)/ln/[lnurl]/+page.server.ts
+++ b/src/routes/(app)/ln/[lnurl]/+page.server.ts
@@ -6,120 +6,120 @@ import { error, fail, redirect } from "@sveltejs/kit";
const { decode, fromWords } = bech32;
export async function load({ params, parent }) {
- const { user } = await parent();
- const rates = await getRates();
+ const { user } = await parent();
+ const rates = await getRates();
- let data;
- const { lnurl } = params;
+ let data;
+ const { lnurl } = params;
- const url = Buffer.from(fromWords(decode(lnurl, 20000).words)).toString();
+ const url = Buffer.from(fromWords(decode(lnurl, 20000).words)).toString();
- try {
- data = await get(`/decode?text=${lnurl}`);
- } catch (e) {
- const { message } = e as Error;
- error(500, message);
- }
+ try {
+ data = await get(`/decode?text=${lnurl}`);
+ } catch (e) {
+ const { message } = e as Error;
+ error(500, message);
+ }
- let { callback, minSendable, maxSendable, comment, tag } = data;
- if (tag === "payRequest" && minSendable === maxSendable) {
- minSendable = Math.round(minSendable / 1000);
- maxSendable = Math.round(maxSendable / 1000);
- const amount = minSendable;
+ let { callback, minSendable, maxSendable, comment, tag } = data;
+ if (tag === "payRequest" && minSendable === maxSendable) {
+ minSendable = Math.round(minSendable / 1000);
+ maxSendable = Math.round(maxSendable / 1000);
+ const amount = minSendable;
- const urlObj = new URL(callback);
- urlObj.searchParams.set("amount", (amount * 1000).toString());
- if (comment) {
- urlObj.searchParams.set("comment", comment);
- }
- const url = urlObj.toString();
+ const urlObj = new URL(callback);
+ urlObj.searchParams.set("amount", (amount * 1000).toString());
+ if (comment) {
+ urlObj.searchParams.set("comment", comment);
+ }
+ const url = urlObj.toString();
- const { pr } = await fetch(url).then((r) => (r as Response).json());
+ const { pr } = await fetch(url).then((r) => (r as Response).json());
- let invoice;
- try {
- invoice = await get(`/invoice/${pr}`);
- } catch (e) {}
+ let invoice;
+ try {
+ invoice = await get(`/invoice/${pr}`);
+ } catch {}
- if (invoice) redirect(307, `/invoice/${invoice.id}`);
+ if (invoice) redirect(307, `/invoice/${invoice.id}`);
- let path = `/send/lightning/${pr}`;
- if (comment) path += `/${encodeURIComponent(comment)}`;
- redirect(307, path);
- } else if (callback.includes(PUBLIC_DOMAIN)) {
- const username = url.split(`https://${PUBLIC_DOMAIN}/p/`)[1];
- redirect(307, `/pay/${username}`);
- }
+ let path = `/send/lightning/${pr}`;
+ if (comment) path += `/${encodeURIComponent(comment)}`;
+ redirect(307, path);
+ } else if (callback.includes(PUBLIC_DOMAIN)) {
+ const username = url.split(`https://${PUBLIC_DOMAIN}/p/`)[1];
+ redirect(307, `/pay/${username}`);
+ }
- if (!["payRequest", "withdrawRequest"].includes(data.tag))
- error(500, "We only support LNURLp and LNURLw at this time");
+ if (!["payRequest", "withdrawRequest"].includes(data.tag))
+ error(500, "We only support LNURLp and LNURLw at this time");
- data.rate = rates[user?.currency || "USD"];
- return data;
+ data.rate = rates[user?.currency || "USD"];
+ return data;
}
export const actions = {
- pay: async ({ fetch, request }) => {
- let error;
+ pay: async ({ fetch, request }) => {
+ let error;
- let { callback, amount, minSendable, maxSendable, comment } =
- await fd(request);
- minSendable = Math.round(minSendable / 1000);
- maxSendable = Math.round(maxSendable / 1000);
+ let { callback, amount, minSendable, maxSendable, comment } =
+ await fd(request);
+ minSendable = Math.round(minSendable / 1000);
+ maxSendable = Math.round(maxSendable / 1000);
- if (amount < minSendable)
- error = `Amount must be at least ${minSendable} sats`;
- if (amount > maxSendable)
- error = `Amount must be at most ${maxSendable} sats`;
- if (error) return fail(400, { error });
+ if (amount < minSendable)
+ error = `Amount must be at least ${minSendable} sats`;
+ if (amount > maxSendable)
+ error = `Amount must be at most ${maxSendable} sats`;
+ if (error) return fail(400, { error });
- let url = `${callback}?amount=${amount * 1000}`;
- if (comment) url += `&comment=${comment}`;
+ let url = `${callback}?amount=${amount * 1000}`;
+ if (comment) url += `&comment=${comment}`;
- const { pr } = await fetch(url).then((r) => r.json());
+ const { pr } = await fetch(url).then((r) => r.json());
- let path = `/send/lightning/${pr}`;
- if (comment) path += `/${encodeURIComponent(comment)}`;
- redirect(307, path);
- },
+ let path = `/send/lightning/${pr}`;
+ if (comment) path += `/${encodeURIComponent(comment)}`;
+ redirect(307, path);
+ },
- withdraw: async ({ cookies, fetch, request }) => {
- let error;
+ withdraw: async ({ cookies, fetch, request }) => {
+ let error;
- let {
- callback,
- amount,
- username,
- currency,
- minWithdrawable,
- maxWithdrawable,
- k1,
- } = await fd(request);
+ let {
+ callback,
+ amount,
+ username,
+ currency,
+ minWithdrawable,
+ maxWithdrawable,
+ k1,
+ } = await fd(request);
- minWithdrawable = Math.round(minWithdrawable / 1000);
- maxWithdrawable = Math.round(maxWithdrawable / 1000);
+ minWithdrawable = Math.round(minWithdrawable / 1000);
+ maxWithdrawable = Math.round(maxWithdrawable / 1000);
- if (amount < minWithdrawable)
- error = `Amount must be at least ${minWithdrawable} sats`;
- if (amount > maxWithdrawable)
- error = `Amount must be at most ${maxWithdrawable} sats`;
- if (error) return fail(400, { error });
+ if (amount < minWithdrawable)
+ error = `Amount must be at least ${minWithdrawable} sats`;
+ if (amount > maxWithdrawable)
+ error = `Amount must be at most ${maxWithdrawable} sats`;
+ if (error) return fail(400, { error });
- const invoice = { amount, type: "lightning" };
- const user = { username, currency };
+ const invoice = { amount, type: "lightning" };
+ const user = { username, currency };
- const { text: pr } = await post(
- "/invoice",
- { invoice, user },
- auth(cookies),
- );
+ const { text: pr } = await post(
+ "/invoice",
+ { invoice, user },
+ auth(cookies),
+ );
- const url = new URL(callback);
- url.searchParams.append("k1", k1);
- url.searchParams.append("pr", pr);
+ const url = new URL(callback);
+ url.searchParams.append("k1", k1);
+ url.searchParams.append("pr", pr);
- await fetch(url.toString());
+ await fetch(url.toString());
- redirect(307, "/payments");
- },
+ redirect(307, "/payments");
+ },
};
diff --git a/src/routes/(app)/locations/+server.ts b/src/routes/(app)/locations/+server.ts
index 3184ebdf..9980c5fc 100644
--- a/src/routes/(app)/locations/+server.ts
+++ b/src/routes/(app)/locations/+server.ts
@@ -2,14 +2,14 @@ import { get } from "$lib/utils";
import { json } from "@sveltejs/kit";
export async function GET({ setHeaders }) {
- let locations = [];
+ let locations = [];
- try {
- ({ locations } = await get("/locations"));
- setHeaders({ "cache-control": "public, max-age=600" });
- } catch (e) {
- console.log("failed to fetch locations");
- }
+ try {
+ ({ locations } = await get("/locations"));
+ setHeaders({ "cache-control": "public, max-age=600" });
+ } catch {
+ console.log("failed to fetch locations");
+ }
- return json({ locations });
+ return json({ locations });
}
diff --git a/src/routes/(app)/logout/+page.server.ts b/src/routes/(app)/logout/+page.server.ts
index 1ecc7f87..0a8b5d3a 100644
--- a/src/routes/(app)/logout/+page.server.ts
+++ b/src/routes/(app)/logout/+page.server.ts
@@ -1,19 +1,19 @@
import { redirect } from "@sveltejs/kit";
const opts = {
- expires: new Date(0),
- path: "/",
+ expires: new Date(0),
+ path: "/",
};
export async function load({ cookies }) {
- const lang = cookies.get("lang");
- cookies.set("aid", "", opts);
- cookies.set("lang", "", opts);
- cookies.set("username", "", opts);
- cookies.set("token", "", opts);
- cookies.set("pin", "", opts);
- cookies.set("sk", "", opts);
- cookies.set("theme", "", opts);
- cookies.set("sid", "", opts);
- redirect(307, `/login?lang=${lang}`);
+ const lang = cookies.get("lang");
+ cookies.set("aid", "", opts);
+ cookies.set("lang", "", opts);
+ cookies.set("username", "", opts);
+ cookies.set("token", "", opts);
+ cookies.set("pin", "", opts);
+ cookies.set("sk", "", opts);
+ cookies.set("theme", "", opts);
+ cookies.set("sid", "", opts);
+ redirect(307, `/login?lang=${lang}`);
}
diff --git a/src/routes/(app)/messages/+page.server.ts b/src/routes/(app)/messages/+page.server.ts
index b64dfb42..ec83bede 100644
--- a/src/routes/(app)/messages/+page.server.ts
+++ b/src/routes/(app)/messages/+page.server.ts
@@ -2,43 +2,43 @@ import { get } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
interface Message {
- created_at: number;
+ created_at: number;
}
interface Note {
- created_at: number;
- seen: number;
+ created_at: number;
+ seen: number;
}
export async function load({ params, parent }) {
- const { user } = await parent();
- if (user.username !== params.username) redirect(307, `/${params.username}`);
- const { since = 0 } = params;
+ const { user } = await parent();
+ if (user.username !== params.username) redirect(307, `/${params.username}`);
+ const { since = 0 } = params;
- let messages = [];
- let notes = [];
+ let messages = [];
+ let notes = [];
- if (user?.pubkey) {
- const { pubkey } = user;
- try {
- messages = await get(`/${pubkey}/${since}/messages`);
- messages = messages.sort(
- (a: Message, b: Message) => b.created_at - a.created_at,
- );
- } catch (e) {
- console.log("failed to fetch nostr messages", e);
- }
+ if (user?.pubkey) {
+ const { pubkey } = user;
+ try {
+ messages = await get(`/${pubkey}/${since}/messages`);
+ messages = messages.sort(
+ (a: Message, b: Message) => b.created_at - a.created_at,
+ );
+ } catch (e) {
+ console.log("failed to fetch nostr messages", e);
+ }
- try {
- notes = await get(`/${pubkey}/notes`);
- } catch (e) {
- console.log(`failed to fetch nostr notes for ${pubkey}`, e);
- }
+ try {
+ notes = await get(`/${pubkey}/notes`);
+ } catch (e) {
+ console.log(`failed to fetch nostr notes for ${pubkey}`, e);
+ }
- notes.map((e: Note) => {
- e.seen = e.created_at;
- });
- }
+ notes.map((e: Note) => {
+ e.seen = e.created_at;
+ });
+ }
- return { messages, notes };
+ return { messages, notes };
}
diff --git a/src/routes/(app)/messages/+page.svelte b/src/routes/(app)/messages/+page.svelte
index 2de56e0b..3e97398f 100644
--- a/src/routes/(app)/messages/+page.svelte
+++ b/src/routes/(app)/messages/+page.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { run } from 'svelte/legacy';
+ import { run } from "svelte/legacy";
import { t } from "$lib/translations";
import Avatar from "$comp/Avatar.svelte";
diff --git a/src/routes/(app)/messages/[recipient]/+page.server.ts b/src/routes/(app)/messages/[recipient]/+page.server.ts
index 6e61e1b4..85deabbb 100644
--- a/src/routes/(app)/messages/[recipient]/+page.server.ts
+++ b/src/routes/(app)/messages/[recipient]/+page.server.ts
@@ -2,24 +2,24 @@ import { get } from "$lib/utils";
import type { Message } from "$lib/types";
export async function load({ params, parent }) {
- const { user } = await parent();
- const { since = 0 } = params;
+ const { user } = await parent();
+ const { since = 0 } = params;
- let messages: Message[] = [];
- const recipient = await get(`/users/${params.recipient}`);
+ let messages: Message[] = [];
+ const recipient = await get(`/users/${params.recipient}`);
- try {
- messages = await get(`/${user.pubkey}/${since}/messages`);
+ try {
+ messages = await get(`/${user.pubkey}/${since}/messages`);
- messages = messages
- .filter(
- (m: Message) =>
- m.recipient?.id === recipient.id || m.author?.id === recipient.id,
- )
- .sort((a, b) => a.created_at - b.created_at);
- } catch (e) {
- console.log("failed to fetch nostr messages", e);
- }
+ messages = messages
+ .filter(
+ (m: Message) =>
+ m.recipient?.id === recipient.id || m.author?.id === recipient.id,
+ )
+ .sort((a, b) => a.created_at - b.created_at);
+ } catch (e) {
+ console.log("failed to fetch nostr messages", e);
+ }
- return { messages, recipient, user };
+ return { messages, recipient, user };
}
diff --git a/src/routes/(app)/messages/[recipient]/+page.svelte b/src/routes/(app)/messages/[recipient]/+page.svelte
index f399ab25..654ddcca 100644
--- a/src/routes/(app)/messages/[recipient]/+page.svelte
+++ b/src/routes/(app)/messages/[recipient]/+page.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { run, preventDefault } from 'svelte/legacy';
+ import { run, preventDefault } from "svelte/legacy";
import { cubicInOut } from "svelte/easing";
import { browser } from "$app/environment";
@@ -36,7 +36,8 @@
}
let { messages, recipient, user }: any = $state(data);
- let input: any, pane: any = $state();
+ let input: any,
+ pane: any = $state();
let initialize = async (p: any) => {
await Promise.all(
@@ -59,7 +60,9 @@
}
});
- let sent: any, submitting: any, message: any = $state();
+ let sent: any,
+ submitting: any,
+ message: any = $state();
let submit = async () => {
submitting = true;
@@ -120,7 +123,8 @@
data-sveltekit-preload-data="false"
onclick={back}
>
- <iconify-icon noobserver icon="ph:arrow-left-bold" width="40"></iconify-icon>
+ <iconify-icon noobserver icon="ph:arrow-left-bold" width="40"
+ ></iconify-icon>
</button>
<div
diff --git a/src/routes/(app)/otpsecret/+server.ts b/src/routes/(app)/otpsecret/+server.ts
index c260b7da..510148fa 100644
--- a/src/routes/(app)/otpsecret/+server.ts
+++ b/src/routes/(app)/otpsecret/+server.ts
@@ -2,13 +2,13 @@ import { auth, post } from "$lib/utils";
import { error } from "@sveltejs/kit";
export async function POST({ cookies, request }) {
- try {
- const body = await request.json();
- const { username, secret } = await post("/otpsecret", body, auth(cookies));
- const uri = `otpauth://totp/coinos:${username}?secret=${secret}&period=30&digits=6&algorithm=SHA1&issuer=coinos`;
- return new Response(JSON.stringify({ secret, uri }));
- } catch (e: any) {
- if (e.message.includes("pin")) throw e;
- error(500, "Problem saving secret");
- }
+ try {
+ const body = await request.json();
+ const { username, secret } = await post("/otpsecret", body, auth(cookies));
+ const uri = `otpauth://totp/coinos:${username}?secret=${secret}&period=30&digits=6&algorithm=SHA1&issuer=coinos`;
+ return new Response(JSON.stringify({ secret, uri }));
+ } catch (e: any) {
+ if (e.message.includes("pin")) throw e;
+ error(500, "Problem saving secret");
+ }
}
diff --git a/src/routes/(app)/password/+server.ts b/src/routes/(app)/password/+server.ts
index 8e41b9c9..250dcfed 100644
--- a/src/routes/(app)/password/+server.ts
+++ b/src/routes/(app)/password/+server.ts
@@ -2,6 +2,6 @@ import { json } from "@sveltejs/kit";
import { auth, post } from "$lib/utils";
export async function POST({ cookies, request }) {
- const result = await post("/password", await request.json(), auth(cookies));
- return json(result);
+ const result = await post("/password", await request.json(), auth(cookies));
+ return json(result);
}
diff --git a/src/routes/(app)/pay/[username]/[...amount]/+page.server.ts b/src/routes/(app)/pay/[username]/[...amount]/+page.server.ts
index 9c2b1e3b..23918cb3 100644
--- a/src/routes/(app)/pay/[username]/[...amount]/+page.server.ts
+++ b/src/routes/(app)/pay/[username]/[...amount]/+page.server.ts
@@ -3,69 +3,69 @@ import { auth, fd, get, post, sats, types } from "$lib/utils";
import { error, fail, redirect } from "@sveltejs/kit";
export async function load({ cookies, params, parent }) {
- const { username } = params;
- const { user } = await parent();
- const rates = await getRates();
+ const { username } = params;
+ const { user } = await parent();
+ const rates = await getRates();
- if (user?.username === username) redirect(307, `/${username}/receive`);
- const subject = await get(`/users/${username}`);
+ if (user?.username === username) redirect(307, `/${username}/receive`);
+ const subject = await get(`/users/${username}`);
- let [amount, currency] = params.amount.split("/");
+ let [amount, currency] = params.amount.split("/");
- const rate = rates[currency ? currency.toUpperCase() : subject.currency];
- if (currency && !rate) error(500, "Invalid currency symbol");
+ const rate = rates[currency ? currency.toUpperCase() : subject.currency];
+ if (currency && !rate) error(500, "Invalid currency symbol");
- if (amount) {
- if (currency) amount = (amount * sats) / rate;
+ if (amount) {
+ if (currency) amount = (amount * sats) / rate;
- const { id } = await post(
- "/invoice",
- {
- invoice: {
- amount,
- currency: currency === subject.currency ? currency : undefined,
- prompt: false,
- rate: currency === subject.currency ? rate : undefined,
- type: types.lightning,
- },
- user: { username },
- },
- auth(cookies),
- );
+ const { id } = await post(
+ "/invoice",
+ {
+ invoice: {
+ amount,
+ currency: currency === subject.currency ? currency : undefined,
+ prompt: false,
+ rate: currency === subject.currency ? rate : undefined,
+ type: types.lightning,
+ },
+ user: { username },
+ },
+ auth(cookies),
+ );
- redirect(307, `/invoice/${id}`);
- }
+ redirect(307, `/invoice/${id}`);
+ }
- return { amount, rate, subject };
+ return { amount, rate, subject };
}
export const actions = {
- default: async ({ cookies, request }) => {
- let id;
- const body = await fd(request);
- const { amount, rate, prompt, type, username } = body;
+ default: async ({ cookies, request }) => {
+ let id;
+ const body = await fd(request);
+ const { amount, rate, prompt, type, username } = body;
- try {
- ({ id } = await post(
- "/invoice",
- {
- invoice: {
- amount,
- rate,
- prompt,
- type,
- },
- user: { username },
- },
- auth(cookies),
- ));
- } catch (e) {
- const { message } = e as Error;
- return fail(400, { message });
- }
+ try {
+ ({ id } = await post(
+ "/invoice",
+ {
+ invoice: {
+ amount,
+ rate,
+ prompt,
+ type,
+ },
+ user: { username },
+ },
+ auth(cookies),
+ ));
+ } catch (e) {
+ const { message } = e as Error;
+ return fail(400, { message });
+ }
- if (parseInt(amount) > 0 && prompt) redirect(307, `/invoice/${id}/tip`);
- else if (parseInt(amount) <= 0) redirect(307, `/${username}/receive`);
- redirect(307, `/invoice/${id}`);
- },
+ if (parseInt(amount) > 0 && prompt) redirect(307, `/invoice/${id}/tip`);
+ else if (parseInt(amount) <= 0) redirect(307, `/${username}/receive`);
+ redirect(307, `/invoice/${id}`);
+ },
};
diff --git a/src/routes/(app)/payment/[id]/+page.server.ts b/src/routes/(app)/payment/[id]/+page.server.ts
index fffdb451..74029a56 100644
--- a/src/routes/(app)/payment/[id]/+page.server.ts
+++ b/src/routes/(app)/payment/[id]/+page.server.ts
@@ -1,7 +1,7 @@
import { auth, get } from "$lib/utils";
export async function load({ cookies, depends, params }) {
- depends("app:payments");
- const payment = await get(`/payments/${params.id}`, auth(cookies));
- return { payment };
+ depends("app:payments");
+ const payment = await get(`/payments/${params.id}`, auth(cookies));
+ return { payment };
}
diff --git a/src/routes/(app)/payment/[id]/bump/+server.ts b/src/routes/(app)/payment/[id]/bump/+server.ts
index ae25999c..b24980a0 100644
--- a/src/routes/(app)/payment/[id]/bump/+server.ts
+++ b/src/routes/(app)/payment/[id]/bump/+server.ts
@@ -2,11 +2,11 @@ import { auth, post } from "$lib/utils";
import { json, error } from "@sveltejs/kit";
export async function POST({ cookies, request }) {
- const body = await request.json();
- try {
- const res = await post("/replace", body, auth(cookies));
- return json(res);
- } catch (e: any) {
- error(400, e.message);
- }
+ const body = await request.json();
+ try {
+ const res = await post("/replace", body, auth(cookies));
+ return json(res);
+ } catch (e: any) {
+ error(400, e.message);
+ }
}
diff --git a/src/routes/(app)/payment/[id]/plain/+page.server.ts b/src/routes/(app)/payment/[id]/plain/+page.server.ts
index 49d9b98b..18c3e8f6 100644
--- a/src/routes/(app)/payment/[id]/plain/+page.server.ts
+++ b/src/routes/(app)/payment/[id]/plain/+page.server.ts
@@ -1,6 +1,6 @@
import { auth, get } from "$lib/utils";
export async function load({ cookies, params }) {
- const payment = await get(`/payments/${params.id}`, auth(cookies));
- return { payment };
+ const payment = await get(`/payments/${params.id}`, auth(cookies));
+ return { payment };
}
diff --git a/src/routes/(app)/payment/[id]/plain/+page.svelte b/src/routes/(app)/payment/[id]/plain/+page.svelte
index 30b774a8..46197260 100644
--- a/src/routes/(app)/payment/[id]/plain/+page.svelte
+++ b/src/routes/(app)/payment/[id]/plain/+page.svelte
@@ -15,7 +15,8 @@
types,
} from "$lib/utils";
import { fiat } from "$lib/store";
- import Avatar from "$comp/Avatar.svelte"; import { format } from "date-fns";
+ import Avatar from "$comp/Avatar.svelte";
+ import { format } from "date-fns";
import { PUBLIC_EXPLORER as expl } from "$env/static/public";
let { data } = $props();
diff --git a/src/routes/(app)/payment/[id]/print/+server.ts b/src/routes/(app)/payment/[id]/print/+server.ts
index aab6d3f4..19f8941e 100644
--- a/src/routes/(app)/payment/[id]/print/+server.ts
+++ b/src/routes/(app)/payment/[id]/print/+server.ts
@@ -2,6 +2,6 @@ import { auth, post } from "$lib/utils";
import { json } from "@sveltejs/kit";
export async function POST({ cookies, request }) {
- const body = await request.json();
- return json(post("/print", body, auth(cookies)));
+ const body = await request.json();
+ return json(post("/print", body, auth(cookies)));
}
diff --git a/src/routes/(app)/payments/[...page]/+page.server.ts b/src/routes/(app)/payments/[...page]/+page.server.ts
index 153615b1..bf280937 100644
--- a/src/routes/(app)/payments/[...page]/+page.server.ts
+++ b/src/routes/(app)/payments/[...page]/+page.server.ts
@@ -3,34 +3,34 @@ import { auth, get, str } from "$lib/utils";
const limit = 10;
export async function load({ cookies, depends, params }) {
- depends("app:payments");
+ depends("app:payments");
- const aid = cookies.get("aid");
- const parts = params.page.split("/");
+ const aid = cookies.get("aid");
+ const parts = params.page.split("/");
- let start;
- let end;
- let page;
- if (parts.length === 1) [page] = parts;
- if (parts.length === 2) [start, page] = parts;
- if (parts.length === 3) [start, end, page] = parts;
- if (!parseInt(page)) page = 1;
+ let start;
+ let end;
+ let page;
+ if (parts.length === 1) [page] = parts;
+ if (parts.length === 2) [start, page] = parts;
+ if (parts.length === 3) [start, end, page] = parts;
+ if (!parseInt(page)) page = 1;
- const offset = (page - 1) * limit;
+ const offset = (page - 1) * limit;
- const q = new URLSearchParams();
- q.set("limit", str(limit));
- q.set("offset", str(offset));
- if (aid) q.set("aid", aid);
- if (start) q.set("start", str(start * 1000));
- if (end) q.set("end", str(end * 1000));
+ const q = new URLSearchParams();
+ q.set("limit", str(limit));
+ q.set("offset", str(offset));
+ if (aid) q.set("aid", aid);
+ if (start) q.set("start", str(start * 1000));
+ if (end) q.set("end", str(end * 1000));
- const { count, payments, incoming, outgoing } = await get(
- `/payments?${str(q)}`,
- auth(cookies),
- );
+ const { count, payments, incoming, outgoing } = await get(
+ `/payments?${str(q)}`,
+ auth(cookies),
+ );
- const pages = new Array(Math.ceil(count / limit));
+ const pages = Array.from({ length: Math.ceil(count / limit) });
- return { payments, page, pages, start, end, incoming, outgoing };
+ return { payments, page, pages, start, end, incoming, outgoing };
}
diff --git a/src/routes/(app)/payments/[...page]/+server.ts b/src/routes/(app)/payments/[...page]/+server.ts
index 20315da4..0d010222 100644
--- a/src/routes/(app)/payments/[...page]/+server.ts
+++ b/src/routes/(app)/payments/[...page]/+server.ts
@@ -2,18 +2,18 @@ import { get, auth } from "$lib/utils";
import { json } from "@sveltejs/kit";
export async function GET({ cookies, params }) {
- const parts = params.page.split("/");
+ const parts = params.page.split("/");
- let start;
- let end;
- if (parts.length === 1) [start] = parts;
- if (parts.length === 2) [start, end] = parts;
+ let start;
+ let end;
+ if (parts.length === 1) [start] = parts;
+ if (parts.length === 2) [start, end] = parts;
- if (!start) start = Date.now() / 1000 - 24 * 60 * 60;
+ if (!start) start = Date.now() / 1000 - 24 * 60 * 60;
- let url = `/payments?start=${start * 1000}`;
- if (end) url += `&end=${end * 1000}`;
+ let url = `/payments?start=${start * 1000}`;
+ if (end) url += `&end=${end * 1000}`;
- const { payments } = await get(url, auth(cookies));
- return json({ payments });
+ const { payments } = await get(url, auth(cookies));
+ return json({ payments });
}
diff --git a/src/routes/(app)/pin/+server.ts b/src/routes/(app)/pin/+server.ts
index d819ee5f..b24770d5 100644
--- a/src/routes/(app)/pin/+server.ts
+++ b/src/routes/(app)/pin/+server.ts
@@ -2,6 +2,6 @@ import { json } from "@sveltejs/kit";
import { auth, post } from "$lib/utils";
export async function POST({ cookies, request }) {
- const result = await post("/pin", await request.json(), auth(cookies));
- return json(result);
+ const result = await post("/pin", await request.json(), auth(cookies));
+ return json(result);
}
diff --git a/src/routes/(app)/pos/+page.server.ts b/src/routes/(app)/pos/+page.server.ts
index 1df1bb33..b8f8410c 100644
--- a/src/routes/(app)/pos/+page.server.ts
+++ b/src/routes/(app)/pos/+page.server.ts
@@ -3,28 +3,28 @@ import { auth, fd, get } from "$lib/utils";
import { hex } from "@scure/base";
export async function load({ cookies }) {
- let token;
+ let token;
- try {
- token = await get("/ro", auth(cookies));
- } catch (e) {}
+ try {
+ token = await get("/ro", auth(cookies));
+ } catch {}
- return { token };
+ return { token };
}
export const actions = {
- default: async ({ fetch, request }) => {
- const body = await fd(request);
- const res = await fetch(`${PUBLIC_COINOS_URL}/flash`, {
- method: "POST",
- body: JSON.stringify(body),
- headers: {
- "content-type": "application/json",
- accept: "application/octet-stream",
- },
- });
+ default: async ({ fetch, request }) => {
+ const body = await fd(request);
+ const res = await fetch(`${PUBLIC_COINOS_URL}/flash`, {
+ method: "POST",
+ body: JSON.stringify(body),
+ headers: {
+ "content-type": "application/json",
+ accept: "application/octet-stream",
+ },
+ });
- const buf = new Uint8Array(await res.arrayBuffer());
- return { bytes: hex.encode(buf) };
- },
+ const buf = new Uint8Array(await res.arrayBuffer());
+ return { bytes: hex.encode(buf) };
+ },
};
diff --git a/src/routes/(app)/pos/+page.svelte b/src/routes/(app)/pos/+page.svelte
index 6806fec3..056a9254 100644
--- a/src/routes/(app)/pos/+page.svelte
+++ b/src/routes/(app)/pos/+page.svelte
@@ -18,9 +18,9 @@
// --- Defaults ---
const LITTLEFS_ADDRESS_DEFAULT = 0x3d0000; // your existing LittleFS offset
- const FW_ADDRESS_DEFAULT = 0x10000; // typical app offset on ESP32-C3
- const CONNECT_BAUD = 115200; // initial
- const WORK_BAUD = 921600; // fast flashing
+ const FW_ADDRESS_DEFAULT = 0x10000; // typical app offset on ESP32-C3
+ const CONNECT_BAUD = 115200; // initial
+ const WORK_BAUD = 921600; // fast flashing
// --- Shared state ---
let esploader: any = $state();
@@ -38,7 +38,7 @@
// --- New firmware flashing path ---
let fwFile: any = $state(null);
- let fwBytes: Uint8Array | undefined = $state(); // Uint8Array
+ let fwBytes: Uint8Array | undefined = $state(); // Uint8Array
let fwAddress = $state(FW_ADDRESS_DEFAULT);
let fwEraseAll = $state(false);
let fwProgress = $state(0);
@@ -63,7 +63,9 @@
chip = await esploader.main();
connected = true;
- portInfo = (await device.getInfo?.()) ? JSON.stringify(await device.getInfo()) : "Connected";
+ portInfo = (await device.getInfo?.())
+ ? JSON.stringify(await device.getInfo())
+ : "Connected";
} catch (e) {
console.log(e);
connected = false;
@@ -151,17 +153,25 @@
</h1>
{#if !connected}
- <div class="text-center">
- <button class="btn" onclick={connect}>Connect</button>
- <div class="text-sm mt-2 opacity-70">{portInfo}</div>
- </div>
-{/if}
+ <div class="text-center">
+ <button class="btn" onclick={connect}>Connect</button>
+ <div class="text-sm mt-2 opacity-70">{portInfo}</div>
+ </div>
+ {/if}
{#if connected}
<!-- Tabs -->
<div class="flex gap-2 justify-center">
- <button class="btn" class:btn-neutral={tab === "config"} onclick={() => (tab = "config")}>Flash config</button>
- <button class="btn" class:btn-neutral={tab === "firmware"} onclick={() => (tab = "firmware")}>Flash firmware</button>
+ <button
+ class="btn"
+ class:btn-neutral={tab === "config"}
+ onclick={() => (tab = "config")}>Flash config</button
+ >
+ <button
+ class="btn"
+ class:btn-neutral={tab === "firmware"}
+ onclick={() => (tab = "firmware")}>Flash firmware</button
+ >
</div>
{#if tab === "config"}
@@ -178,18 +188,26 @@
id="littlefs-address"
class="input"
bind:value={littlefsAddress}
- onchange={(e) => (littlefsAddress = Number((e.target as HTMLInputElement).value))}
+ onchange={(e) =>
+ (littlefsAddress = Number((e.target as HTMLInputElement).value))}
/>
<div class="mt-3">
<button class="btn" onclick={flashConfig}>Flash config</button>
</div>
- {#if configProgress > 0}<div class="mt-2">Progress: {configProgress}%</div>{/if}
+ {#if configProgress > 0}<div class="mt-2">
+ Progress: {configProgress}%
+ </div>{/if}
{/if}
{:else}
<form method="POST" use:enhance class="space-y-2">
<input name="ssid" placeholder="Wifi SSID" class="input" />
<input name="key" placeholder="Wifi password" class="input" />
- <input name="token" bind:value={token} placeholder="Coinos API token" class="input" />
+ <input
+ name="token"
+ bind:value={token}
+ placeholder="Coinos API token"
+ class="input"
+ />
<button type="submit" class="btn">Generate Config</button>
</form>
{/if}
@@ -214,7 +232,8 @@
id="firmware-address"
class="input"
bind:value={fwAddress}
- onchange={(e) => (fwAddress = Number((e.target as HTMLInputElement).value))}
+ onchange={(e) =>
+ (fwAddress = Number((e.target as HTMLInputElement).value))}
/>
<label class="flex items-center gap-2 mt-2">
@@ -223,8 +242,10 @@
</label>
<div class="mt-3">
- <button class="btn" disabled={!fwBytes} onclick={flashFirmware}>Flash firmware</button>
- </div>
+ <button class="btn" disabled={!fwBytes} onclick={flashFirmware}
+ >Flash firmware</button
+ >
+ </div>
{#if fwProgress > 0 && !fwDone}
<div>Progress: {fwProgress}%</div>
@@ -243,8 +264,16 @@
<style>
@reference "../../../app.css";
- .btn { @apply px-4 py-2 rounded-2xl shadow; }
- .btn-neutral { @apply bg-gray-200; }
- .input { @apply w-full px-3 py-2 border rounded-xl; }
- .label { @apply text-sm opacity-70; }
+ .btn {
+ @apply px-4 py-2 rounded-2xl shadow;
+ }
+ .btn-neutral {
+ @apply bg-gray-200;
+ }
+ .input {
+ @apply w-full px-3 py-2 border rounded-xl;
+ }
+ .label {
+ @apply text-sm opacity-70;
+ }
</style>
diff --git a/src/routes/(app)/post/[...path]/+server.ts b/src/routes/(app)/post/[...path]/+server.ts
index 84df9a36..244683ee 100644
--- a/src/routes/(app)/post/[...path]/+server.ts
+++ b/src/routes/(app)/post/[...path]/+server.ts
@@ -2,11 +2,11 @@ import { PUBLIC_COINOS_URL as base } from "$env/static/public";
import { auth } from "$lib/utils";
export async function POST({ cookies, fetch, params, request }) {
- const { path } = params;
+ const { path } = params;
- return fetch(`${base}/${path}`, {
- method: "POST",
- body: JSON.stringify(await request.json()),
- headers: { "Content-Type": "application/json", ...auth(cookies) },
- });
+ return fetch(`${base}/${path}`, {
+ method: "POST",
+ body: JSON.stringify(await request.json()),
+ headers: { "Content-Type": "application/json", ...auth(cookies) },
+ });
}
diff --git a/src/routes/(app)/printer/+page.server.ts b/src/routes/(app)/printer/+page.server.ts
index 7a004848..e3fd9f81 100644
--- a/src/routes/(app)/printer/+page.server.ts
+++ b/src/routes/(app)/printer/+page.server.ts
@@ -3,17 +3,17 @@ import { fd } from "$lib/utils";
import { hex } from "@scure/base";
export const actions = {
- default: async ({ fetch, request }) => {
- const body = await fd(request);
- const res = await fetch(`${PUBLIC_COINOS_URL}/printer`, {
- method: "POST",
- body: JSON.stringify(body),
- headers: {
- "content-type": "application/json",
- accept: "application/octet-stream",
- },
- });
+ default: async ({ fetch, request }) => {
+ const body = await fd(request);
+ const res = await fetch(`${PUBLIC_COINOS_URL}/printer`, {
+ method: "POST",
+ body: JSON.stringify(body),
+ headers: {
+ "content-type": "application/json",
+ accept: "application/octet-stream",
+ },
+ });
- return { data: hex.encode(new Uint8Array(await res.arrayBuffer())) };
- },
+ return { data: hex.encode(new Uint8Array(await res.arrayBuffer())) };
+ },
};
diff --git a/src/routes/(app)/qr/[text]/+page.server.ts b/src/routes/(app)/qr/[text]/+page.server.ts
index 210c3c45..e2da11c2 100644
--- a/src/routes/(app)/qr/[text]/+page.server.ts
+++ b/src/routes/(app)/qr/[text]/+page.server.ts
@@ -1,4 +1,4 @@
export async function load({ params }) {
- const { text } = params;
- return { text };
+ const { text } = params;
+ return { text };
}
diff --git a/src/routes/(app)/qr/[text]/+page.svelte b/src/routes/(app)/qr/[text]/+page.svelte
index 2f6ca891..a337238e 100644
--- a/src/routes/(app)/qr/[text]/+page.svelte
+++ b/src/routes/(app)/qr/[text]/+page.svelte
@@ -1,4 +1,5 @@
-<script> import Qr from "$comp/Qr.svelte";
+<script>
+ import Qr from "$comp/Qr.svelte";
import { back, copy } from "$lib/utils";
let { data } = $props();
let { text } = $derived(data);
diff --git a/src/routes/(app)/qr/[text]/[icon]/+server.ts b/src/routes/(app)/qr/[text]/[icon]/+server.ts
index c2825877..4a1bb78e 100644
--- a/src/routes/(app)/qr/[text]/[icon]/+server.ts
+++ b/src/routes/(app)/qr/[text]/[icon]/+server.ts
@@ -2,32 +2,32 @@ import { createCanvas, loadImage } from "canvas";
import QRCode from "qrcode";
export async function GET({ params }) {
- const { icon, text } = params;
- const size = 600;
+ const { icon, text } = params;
+ const size = 600;
- const canvas = createCanvas(size, size);
- await QRCode.toCanvas(canvas, text, {
- errorCorrectionLevel: "H",
- width: size,
- });
+ const canvas = createCanvas(size, size);
+ await QRCode.toCanvas(canvas, text, {
+ errorCorrectionLevel: "H",
+ width: size,
+ });
- const ctx = canvas.getContext("2d");
+ const ctx = canvas.getContext("2d");
- const logo = await loadImage(`static/images/${icon}`);
- const logoSize = size * 0.3;
- ctx.drawImage(
- logo,
- (size - logoSize) / 2,
- (size - logoSize) / 2,
- logoSize,
- logoSize,
- );
+ const logo = await loadImage(`static/images/${icon}`);
+ const logoSize = size * 0.3;
+ ctx.drawImage(
+ logo,
+ (size - logoSize) / 2,
+ (size - logoSize) / 2,
+ logoSize,
+ logoSize,
+ );
- const buffer = canvas.toBuffer("image/png");
- return new Response(buffer, {
- headers: {
- "Content-Type": "image/png",
- "Cache-Control": "public, max-age=31536000, immutable",
- },
- });
+ const buffer = canvas.toBuffer("image/png");
+ return new Response(buffer, {
+ headers: {
+ "Content-Type": "image/png",
+ "Cache-Control": "public, max-age=31536000, immutable",
+ },
+ });
}
diff --git a/src/routes/(app)/qr/[text]/raw/+server.ts b/src/routes/(app)/qr/[text]/raw/+server.ts
index a2626c4d..ad7fc6b1 100644
--- a/src/routes/(app)/qr/[text]/raw/+server.ts
+++ b/src/routes/(app)/qr/[text]/raw/+server.ts
@@ -1,17 +1,16 @@
import Qr from "qrcode-base64";
export async function GET({ params }) {
- const { text } = params;
+ const { text } = params;
- const dataUri = Qr.drawImg(text, { size: 600 });
- const base64Data = dataUri.split(",")[1];
- const binaryData = Buffer.from(base64Data, "base64");
+ const dataUri = Qr.drawImg(text, { size: 600 });
+ const base64Data = dataUri.split(",")[1];
+ const binaryData = Buffer.from(base64Data, "base64");
- return new Response(binaryData, {
- headers: {
- "Content-Type": "image/gif",
- "Cache-Control": "public, max-age=31536000, immutable",
- },
- });
+ return new Response(binaryData, {
+ headers: {
+ "Content-Type": "image/gif",
+ "Cache-Control": "public, max-age=31536000, immutable",
+ },
+ });
}
-
diff --git a/src/routes/(app)/qr/create/+page.svelte b/src/routes/(app)/qr/create/+page.svelte
index 339aae16..189a734d 100644
--- a/src/routes/(app)/qr/create/+page.svelte
+++ b/src/routes/(app)/qr/create/+page.svelte
@@ -1,10 +1,12 @@
<script lang="ts">
- import { run, preventDefault } from 'svelte/legacy';
+ import { run, preventDefault } from "svelte/legacy";
import { goto } from "$app/navigation";
import { browser } from "$app/environment";
import { t } from "$lib/translations";
- let el = $state(), text = $state(), pasted = $state();
+ let el = $state(),
+ text = $state(),
+ pasted = $state();
let keypress = (e) =>
e.key === "Enter" ? e.preventDefault() || el.click() : (pasted = false);
@@ -37,7 +39,7 @@
bind:value={text}
onpaste={() => (pasted = true)}
autocapitalize="none"
-></textarea>
+ ></textarea>
</div>
<div class="flex gap-2">
diff --git a/src/routes/(app)/receive/[...token]/+page.server.ts b/src/routes/(app)/receive/[...token]/+page.server.ts
index 052d507f..edc47b80 100644
--- a/src/routes/(app)/receive/[...token]/+page.server.ts
+++ b/src/routes/(app)/receive/[...token]/+page.server.ts
@@ -3,15 +3,15 @@ import { fd } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export async function load({ cookies, params, parent, url }) {
- const { user } = await parent();
- if (!user) redirect(307, `/register?redirect=${url.pathname}`);
- await parse(params.token, url.host, cookies);
+ const { user } = await parent();
+ if (!user) redirect(307, `/register?redirect=${url.pathname}`);
+ await parse(params.token, url.host, cookies);
}
export const actions = {
- default: async ({ cookies, request, url }) => {
- const { text } = await fd(request);
- await parse(text, url.host, cookies);
- return fail(400, { error: "default" });
- },
+ default: async ({ cookies, request, url }) => {
+ const { text } = await fd(request);
+ await parse(text, url.host, cookies);
+ return fail(400, { error: "default" });
+ },
};
diff --git a/src/routes/(app)/receive/[...token]/+page.svelte b/src/routes/(app)/receive/[...token]/+page.svelte
index 59e13239..1f4c81fc 100644
--- a/src/routes/(app)/receive/[...token]/+page.svelte
+++ b/src/routes/(app)/receive/[...token]/+page.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { run } from 'svelte/legacy';
+ import { run } from "svelte/legacy";
import { page } from "$app/stores";
import { fly } from "svelte/transition";
@@ -16,7 +16,10 @@
let { token } = data;
data.subject = data.user;
- let el = $state(), text = $state(), pasted = $state(), w = $state();
+ let el = $state(),
+ text = $state(),
+ pasted = $state(),
+ w = $state();
let keypress = (e) => e.key === "Enter" && (e.preventDefault() || el.click());
@@ -57,19 +60,21 @@
bind:value={text}
onpaste={() => (pasted = true)}
autocapitalize="none"
-></textarea>
+ ></textarea>
</div>
<div class="flex gap-2">
<a href="/scan" class="contents">
<button type="button" class="btn !w-auto flex-grow">
- <iconify-icon noobserver icon="ph:camera-bold" width="32"></iconify-icon>
+ <iconify-icon noobserver icon="ph:camera-bold" width="32"
+ ></iconify-icon>
<div class="my-auto">{$t("user.send.scan")}</div>
</button>
</a>
<button type="button" class="btn !w-auto flex-grow" onclick={paste}>
- <iconify-icon noobserver icon="ph:clipboard-text-bold" width="32"></iconify-icon>
+ <iconify-icon noobserver icon="ph:clipboard-text-bold" width="32"
+ ></iconify-icon>
<div class="my-auto">{$t("user.send.paste")}</div>
</button>
</div>
diff --git a/src/routes/(app)/reset/+server.ts b/src/routes/(app)/reset/+server.ts
index 4e8deeaa..4b6692d5 100644
--- a/src/routes/(app)/reset/+server.ts
+++ b/src/routes/(app)/reset/+server.ts
@@ -2,6 +2,6 @@ import { json } from "@sveltejs/kit";
import { auth, post } from "$lib/utils";
export async function POST({ cookies, request }) {
- const result = await post("/reset", await request.json(), auth(cookies));
- return json(result);
+ const result = await post("/reset", await request.json(), auth(cookies));
+ return json(result);
}
diff --git a/src/routes/(app)/reset/[code]/+page.server.ts b/src/routes/(app)/reset/[code]/+page.server.ts
index 35d49be9..dc5b58f0 100644
--- a/src/routes/(app)/reset/[code]/+page.server.ts
+++ b/src/routes/(app)/reset/[code]/+page.server.ts
@@ -2,30 +2,30 @@ import { fail, redirect } from "@sveltejs/kit";
import { fd, post, login } from "$lib/utils";
export const actions = {
- default: async ({ cookies, params, request }) => {
- const ip = request.headers.get("cf-connecting-ip");
- let error;
+ default: async ({ cookies, params, request }) => {
+ const ip = request.headers.get("cf-connecting-ip");
+ let error;
- const { code } = params;
- const { password, recaptcha } = await fd(request);
+ const { code } = params;
+ const { password, recaptcha } = await fd(request);
- try {
- const user = await post("/reset", { code, password });
- user.password = password;
- user.recaptcha = recaptcha;
+ try {
+ const user = await post("/reset", { code, password });
+ user.password = password;
+ user.recaptcha = recaptcha;
- try {
- await login(user, cookies, ip);
- error = null;
- } catch (e: any) {
- error ||= e.message;
- }
+ try {
+ await login(user, cookies, ip);
+ error = null;
+ } catch (e: any) {
+ error ||= e.message;
+ }
- if (error) return fail(400, { error });
- redirect(307, `/${user.username}`);
- } catch (e: any) {
- console.log(e.message);
- return fail(400, { error: e.message });
- }
- },
+ if (error) return fail(400, { error });
+ redirect(307, `/${user.username}`);
+ } catch (e: any) {
+ console.log(e.message);
+ return fail(400, { error: e.message });
+ }
+ },
};
diff --git a/src/routes/(app)/reset/[code]/+page.svelte b/src/routes/(app)/reset/[code]/+page.svelte
index 57deedcd..93fdf8f9 100644
--- a/src/routes/(app)/reset/[code]/+page.svelte
+++ b/src/routes/(app)/reset/[code]/+page.svelte
@@ -19,7 +19,8 @@
onMount(() => {
if (!isTor && recaptchaSiteKey) {
let s = document.createElement("script");
- s.src = "https://www.google.com/recaptcha/api.js?render=" + recaptchaSiteKey;
+ s.src =
+ "https://www.google.com/recaptcha/api.js?render=" + recaptchaSiteKey;
document.head.appendChild(s);
}
});
@@ -27,7 +28,8 @@
const getRecaptchaToken = () =>
new Promise((resolve, reject) => {
if (isTor) return resolve("");
- if (!browser || !grecaptcha) return reject(new Error("captcha unavailable"));
+ if (!browser || !grecaptcha)
+ return reject(new Error("captcha unavailable"));
grecaptcha.ready(() => {
grecaptcha
.execute(recaptchaSiteKey, { action: "reset" })
diff --git a/src/routes/(app)/scan/[email protected] b/src/routes/(app)/scan/[email protected]
index 14b35465..a57fa3b9 100644
--- a/src/routes/(app)/scan/[email protected]
+++ b/src/routes/(app)/scan/[email protected]
@@ -1,6 +1,6 @@
<script lang="ts">
interface Props {
- children?: import('svelte').Snippet;
+ children?: import("svelte").Snippet;
}
let { children }: Props = $props();
diff --git a/src/routes/(app)/scan/+page.svelte b/src/routes/(app)/scan/+page.svelte
index bb64fbec..90e0e79c 100644
--- a/src/routes/(app)/scan/+page.svelte
+++ b/src/routes/(app)/scan/+page.svelte
@@ -1,5 +1,6 @@
<script lang="ts">
- import { tick } from "svelte"; import { onMount, onDestroy } from "svelte";
+ import { tick } from "svelte";
+ import { onMount, onDestroy } from "svelte";
import { back } from "$lib/utils";
import { goto } from "$app/navigation";
diff --git a/src/routes/(app)/send/+layout.server.ts b/src/routes/(app)/send/+layout.server.ts
index dbb3efad..38ed57cf 100644
--- a/src/routes/(app)/send/+layout.server.ts
+++ b/src/routes/(app)/send/+layout.server.ts
@@ -1,6 +1,6 @@
import { redirect } from "@sveltejs/kit";
export async function load({ cookies, url }) {
- if (!cookies.get("token"))
- redirect(307, `/register?redirect=${url.pathname}`);
+ if (!cookies.get("token"))
+ redirect(307, `/register?redirect=${url.pathname}`);
}
diff --git a/src/routes/(app)/send/[...text]/+page.server.ts b/src/routes/(app)/send/[...text]/+page.server.ts
index 59d53dbe..dc76da7f 100644
--- a/src/routes/(app)/send/[...text]/+page.server.ts
+++ b/src/routes/(app)/send/[...text]/+page.server.ts
@@ -5,20 +5,20 @@ import { fail, redirect } from "@sveltejs/kit";
const limit = 10;
export async function load({ cookies, depends, params, parent, url }) {
depends("app:contacts");
- const { user } = await parent();
- if (!user) redirect(307, "/login");
- const { text } = params;
+ const { user } = await parent();
+ if (!user) redirect(307, "/login");
+ const { text } = params;
- await parse(text, url.host, cookies);
- const contacts = await get(`/contacts/${limit}`, auth(cookies));
+ await parse(text, url.host, cookies);
+ const contacts = await get(`/contacts/${limit}`, auth(cookies));
- return { contacts };
+ return { contacts };
}
export const actions = {
- default: async ({ cookies, request, url }) => {
- const { text } = await fd(request);
- await parse(text, url.host, cookies);
- return fail(400, { error: "default" });
- },
+ default: async ({ cookies, request, url }) => {
+ const { text } = await fd(request);
+ await parse(text, url.host, cookies);
+ return fail(400, { error: "default" });
+ },
};
diff --git a/src/routes/(app)/send/[...text]/+page.svelte b/src/routes/(app)/send/[...text]/+page.svelte
index 34acb4b0..58db231a 100644
--- a/src/routes/(app)/send/[...text]/+page.svelte
+++ b/src/routes/(app)/send/[...text]/+page.svelte
@@ -6,7 +6,8 @@
import { tick } from "svelte";
import { browser } from "$app/environment";
import { t } from "$lib/translations";
- import Avatar from "$comp/Avatar.svelte"; import Spinner from "$comp/Spinner.svelte";
+ import Avatar from "$comp/Avatar.svelte";
+ import Spinner from "$comp/Spinner.svelte";
import { back, get, post, fail, focus } from "$lib/utils";
let { data = $bindable(), form } = $props();
diff --git a/src/routes/(app)/send/ark/[address]/+layout.server.ts b/src/routes/(app)/send/ark/[address]/+layout.server.ts
index cf16ea36..bb167d2d 100644
--- a/src/routes/(app)/send/ark/[address]/+layout.server.ts
+++ b/src/routes/(app)/send/ark/[address]/+layout.server.ts
@@ -2,25 +2,25 @@ import { auth, get } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export async function load({ cookies, params, parent }) {
- const { user } = await parent();
- const aid = cookies.get("aid") || user.id;
- const { address, amount } = params;
- const { balance } = await get(`/account/${aid}`, auth(cookies));
+ const { user } = await parent();
+ const aid = cookies.get("aid") || user.id;
+ const { address, amount } = params;
+ const { balance } = await get(`/account/${aid}`, auth(cookies));
- let invoice;
- try {
- invoice = await get(`/invoice/${address}`);
- } catch (e) {
- // invoice not found
- }
+ let invoice;
+ try {
+ invoice = await get(`/invoice/${address}`);
+ } catch {
+ // invoice not found
+ }
- if (invoice) {
- const recipient = await get(`/users/${invoice.uid}`);
- let r = `/pay/${recipient.username}`;
- if (amount) r += `/${amount}`;
- if (recipient?.id !== user.id && recipient.id === invoice.aid)
- redirect(307, r);
- }
+ if (invoice) {
+ const recipient = await get(`/users/${invoice.uid}`);
+ let r = `/pay/${recipient.username}`;
+ if (amount) r += `/${amount}`;
+ if (recipient?.id !== user.id && recipient.id === invoice.aid)
+ redirect(307, r);
+ }
- return { balance };
+ return { balance };
}
diff --git a/src/routes/(app)/send/ark/[address]/+page.server.ts b/src/routes/(app)/send/ark/[address]/+page.server.ts
index b7d3c5cf..fdf129a0 100644
--- a/src/routes/(app)/send/ark/[address]/+page.server.ts
+++ b/src/routes/(app)/send/ark/[address]/+page.server.ts
@@ -2,9 +2,9 @@ import getRates from "$lib/rates";
import { auth, get } from "$lib/utils";
export async function load({ cookies, parent }) {
- const { user } = await parent();
- const rates = await getRates();
- const aid = cookies.get("aid") || user.id;
- const { balance } = await get(`/account/${aid}`, auth(cookies));
- return { balance, rate: rates[user.currency] };
+ const { user } = await parent();
+ const rates = await getRates();
+ const aid = cookies.get("aid") || user.id;
+ const { balance } = await get(`/account/${aid}`, auth(cookies));
+ return { balance, rate: rates[user.currency] };
}
diff --git a/src/routes/(app)/send/ark/[address]/+page.svelte b/src/routes/(app)/send/ark/[address]/+page.svelte
index 531047fe..0bf9e0de 100644
--- a/src/routes/(app)/send/ark/[address]/+page.svelte
+++ b/src/routes/(app)/send/ark/[address]/+page.svelte
@@ -27,7 +27,6 @@
await tick();
submit.click();
};
-
</script>
<div class="container px-4 max-w-xl mx-auto space-y-5 text-center">
@@ -57,10 +56,7 @@
{/if}</button
>
- <form
- action={`/send/ark/${address}/${amount}`}
- class="contents"
- >
+ <form action={`/send/ark/${address}/${amount}`} class="contents">
<button
bind:this={submit}
type="submit"
diff --git a/src/routes/(app)/send/ark/[address]/[amount]/[...feeRate]/+page.server.ts b/src/routes/(app)/send/ark/[address]/[amount]/[...feeRate]/+page.server.ts
index 309d75fa..07972e6c 100644
--- a/src/routes/(app)/send/ark/[address]/[amount]/[...feeRate]/+page.server.ts
+++ b/src/routes/(app)/send/ark/[address]/[amount]/[...feeRate]/+page.server.ts
@@ -3,47 +3,58 @@ import { auth, fd, get, post } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export async function load({ params: { address, amount }, cookies, parent }) {
- const rates = await getRates();
- const { user } = await parent();
- const aid = cookies.get("aid") || user.id;
+ const rates = await getRates();
+ const { user } = await parent();
+ const aid = cookies.get("aid") || user.id;
- const account = await get(`/account/${aid}`, auth(cookies));
+ const account = await get(`/account/${aid}`, auth(cookies));
- if (account.type === "bitcoin") {
- const inv = await post(
- "/invoice",
- { invoice: { type: "bitcoin", amount: parseInt(amount), forward: address }, user },
- auth(cookies),
- );
- redirect(307, `/send/bitcoin/${inv.hash}/${amount}`);
- }
+ if (account.type === "bitcoin") {
+ const inv = await post(
+ "/invoice",
+ {
+ invoice: {
+ type: "bitcoin",
+ amount: parseInt(amount),
+ forward: address,
+ },
+ user,
+ },
+ auth(cookies),
+ );
+ redirect(307, `/send/bitcoin/${inv.hash}/${amount}`);
+ }
- const rate = rates[user.currency];
+ const rate = rates[user.currency];
- return {
- account,
- amount,
- address,
- rate,
- };
+ return {
+ account,
+ amount,
+ address,
+ rate,
+ };
}
export const actions = {
- default: async ({
- cookies,
- params: { address, amount, feeRate },
- request,
- }) => {
- let p;
- try {
- const body = await fd(request);
- p = await post("/ark/send", { ...body, address, amount: parseInt(amount) }, auth(cookies));
- } catch (e) {
- console.log("problem sending bitcoin", e);
- const { message } = e as Error;
- return fail(400, { address, amount, feeRate, message });
- }
+ default: async ({
+ cookies,
+ params: { address, amount, feeRate },
+ request,
+ }) => {
+ let p;
+ try {
+ const body = await fd(request);
+ p = await post(
+ "/ark/send",
+ { ...body, address, amount: parseInt(amount) },
+ auth(cookies),
+ );
+ } catch (e) {
+ console.log("problem sending bitcoin", e);
+ const { message } = e as Error;
+ return fail(400, { address, amount, feeRate, message });
+ }
- redirect(307, `/sent/${p.id}`);
- },
+ redirect(307, `/sent/${p.id}`);
+ },
};
diff --git a/src/routes/(app)/send/bitcoin/[address]/+layout.server.ts b/src/routes/(app)/send/bitcoin/[address]/+layout.server.ts
index e7a216d6..d8df1986 100644
--- a/src/routes/(app)/send/bitcoin/[address]/+layout.server.ts
+++ b/src/routes/(app)/send/bitcoin/[address]/+layout.server.ts
@@ -2,24 +2,24 @@ import { auth, get } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export async function load({ cookies, params, parent }) {
- const { user } = await parent();
- const aid = cookies.get("aid") || user.id;
- const { address, amount } = params;
- const { balance } = await get(`/account/${aid}`, auth(cookies));
+ const { user } = await parent();
+ const aid = cookies.get("aid") || user.id;
+ const { address, amount } = params;
+ const { balance } = await get(`/account/${aid}`, auth(cookies));
- let invoice;
- try {
- invoice = await get(`/invoice/${address}`);
- } catch (e) {
- // invoice not found
- }
+ let invoice;
+ try {
+ invoice = await get(`/invoice/${address}`);
+ } catch {
+ // invoice not found
+ }
- if (invoice) {
- const recipient = await get(`/users/${invoice.uid}`);
- let r = `/pay/${recipient.username}`;
- if (amount) r += `/${amount}`;
- if (recipient?.id !== user.id) redirect(307, r);
- }
+ if (invoice) {
+ const recipient = await get(`/users/${invoice.uid}`);
+ let r = `/pay/${recipient.username}`;
+ if (amount) r += `/${amount}`;
+ if (recipient?.id !== user.id) redirect(307, r);
+ }
- return { balance };
+ return { balance };
}
diff --git a/src/routes/(app)/send/bitcoin/[address]/+page.server.ts b/src/routes/(app)/send/bitcoin/[address]/+page.server.ts
index b7d3c5cf..fdf129a0 100644
--- a/src/routes/(app)/send/bitcoin/[address]/+page.server.ts
+++ b/src/routes/(app)/send/bitcoin/[address]/+page.server.ts
@@ -2,9 +2,9 @@ import getRates from "$lib/rates";
import { auth, get } from "$lib/utils";
export async function load({ cookies, parent }) {
- const { user } = await parent();
- const rates = await getRates();
- const aid = cookies.get("aid") || user.id;
- const { balance } = await get(`/account/${aid}`, auth(cookies));
- return { balance, rate: rates[user.currency] };
+ const { user } = await parent();
+ const rates = await getRates();
+ const aid = cookies.get("aid") || user.id;
+ const { balance } = await get(`/account/${aid}`, auth(cookies));
+ return { balance, rate: rates[user.currency] };
}
diff --git a/src/routes/(app)/send/bitcoin/[address]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/+page.svelte
index 96b3fbd9..6c49ad6c 100644
--- a/src/routes/(app)/send/bitcoin/[address]/+page.svelte
+++ b/src/routes/(app)/send/bitcoin/[address]/+page.svelte
@@ -34,7 +34,14 @@
<div class="text-xl text-secondary break-all">{address}</div>
- <Numpad bind:amount={a} bind:fiat {currency} {submit} bind:rate={$rate} {locale} />
+ <Numpad
+ bind:amount={a}
+ bind:fiat
+ {currency}
+ {submit}
+ bind:rate={$rate}
+ {locale}
+ />
<div class="flex justify-center gap-2">
<button
diff --git a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.server.ts b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.server.ts
index 9695247b..7cdd86f5 100644
--- a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.server.ts
+++ b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.server.ts
@@ -3,68 +3,68 @@ import { auth, fd, get, post } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export async function load({
- params: { address, amount, feeRate },
- cookies,
- parent,
+ params: { address, amount, feeRate },
+ cookies,
+ parent,
}) {
- const rates = await getRates();
- const { user } = await parent();
- const aid = cookies.get("aid") || user.id;
- const account = await get(`/account/${aid}`, auth(cookies));
+ const rates = await getRates();
+ const { user } = await parent();
+ const aid = cookies.get("aid") || user.id;
+ const account = await get(`/account/${aid}`, auth(cookies));
- if (account.type === "ark") {
- const serverArkAddress = await get("/ark/address");
- return {
- account,
- amount,
- address,
- rate: rates[user.currency],
- serverArkAddress,
- };
- }
+ if (account.type === "ark") {
+ const serverArkAddress = await get("/ark/address");
+ return {
+ account,
+ amount,
+ address,
+ rate: rates[user.currency],
+ serverArkAddress,
+ };
+ }
- try {
- const { fee, fees, inputs, ourfee, hex, subtract } = await post(
- "/bitcoin/fee",
- { address, amount, feeRate, aid },
- auth(cookies),
- );
+ try {
+ const { fee, fees, inputs, ourfee, hex, subtract } = await post(
+ "/bitcoin/fee",
+ { address, amount, feeRate, aid },
+ auth(cookies),
+ );
- return {
- account,
- amount,
- address,
- fee,
- fees,
- feeRate,
- rate: rates[user.currency],
- ourfee,
- subtract,
- hex,
- inputs,
- };
- } catch (e) {
- const { message } = e as Error;
- return { amount, address, feeRate, message };
- }
+ return {
+ account,
+ amount,
+ address,
+ fee,
+ fees,
+ feeRate,
+ rate: rates[user.currency],
+ ourfee,
+ subtract,
+ hex,
+ inputs,
+ };
+ } catch (e) {
+ const { message } = e as Error;
+ return { amount, address, feeRate, message };
+ }
}
export const actions = {
- default: async ({
- cookies,
- params: { address, amount, feeRate },
- request,
- }) => {
- let p;
- try {
- const body = await fd(request);
- p = await post("/bitcoin/send", body, auth(cookies));
- } catch (e) {
- console.log("problem sending bitcoin", e);
- const { message } = e as Error;
- return fail(400, { address, amount, feeRate, message });
- }
+ default: async ({
+ cookies,
+ params: { address, amount, feeRate },
+ request,
+ }) => {
+ let p;
+ try {
+ const body = await fd(request);
+ p = await post("/bitcoin/send", body, auth(cookies));
+ } catch (e) {
+ console.log("problem sending bitcoin", e);
+ const { message } = e as Error;
+ return fail(400, { address, amount, feeRate, message });
+ }
- redirect(307, `/sent/${p.id}`);
- },
+ redirect(307, `/sent/${p.id}`);
+ },
};
diff --git a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
index ecdb3b08..6581e12f 100644
--- a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
+++ b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
@@ -78,7 +78,8 @@
return;
}
- if ((account.seed || data.user.seed) && !signed) cancel(), void togglePassword();
+ if ((account.seed || data.user.seed) && !signed)
+ (cancel(), void togglePassword());
return async ({ result }) => {
if (result.type === "redirect") {
goto(result.location);
@@ -102,14 +103,18 @@
import("@scure/bip39"),
import("@scure/bip39/wordlists/english.js"),
]);
- let entropy = await decrypt(account.seed || data.user.seed, password as string);
+ let entropy = await decrypt(
+ account.seed || data.user.seed,
+ password as string,
+ );
let mnemonic = entropyToMnemonic(entropy, wordlist);
let seed = await mnemonicToSeed(mnemonic, password as string);
let master = HDKey.fromMasterSeed(seed, network as any);
let child = master.derive(`m/84'/0'/${account.accountIndex ?? 0}'`);
let raw = decode(hex);
- let isPSBT = raw[0] === 0x70 && raw[1] === 0x73 && raw[2] === 0x62 && raw[3] === 0x74;
+ let isPSBT =
+ raw[0] === 0x70 && raw[1] === 0x73 && raw[2] === 0x62 && raw[3] === 0x74;
let tx: any = isPSBT ? Transaction.fromPSBT(raw) : Transaction.fromRaw(raw);
for (let [i, input] of tx.inputs.entries()) {
diff --git a/src/routes/(app)/send/fund/[...name]/[...amount]/+page.server.ts b/src/routes/(app)/send/fund/[...name]/[...amount]/+page.server.ts
index 428d8d78..0c4b4d96 100644
--- a/src/routes/(app)/send/fund/[...name]/[...amount]/+page.server.ts
+++ b/src/routes/(app)/send/fund/[...name]/[...amount]/+page.server.ts
@@ -5,24 +5,24 @@ import { fail, redirect } from "@sveltejs/kit";
export async function load({ parent, params }) {
let { name, amount } = params;
if (!name) name = crypto.randomUUID();
- const { user } = await parent();
- const rates = await getRates();
- const rate = rates[user.currency];
- return { name, amount, rate };
+ const { user } = await parent();
+ const rates = await getRates();
+ const rate = rates[user.currency];
+ return { name, amount, rate };
}
export const actions = {
- default: async ({ cookies, request }) => {
- const body = await fd(request);
- let p;
+ default: async ({ cookies, request }) => {
+ const body = await fd(request);
+ let p;
- try {
- p = await post("/payments", body, auth(cookies));
- } catch (e) {
- const { message } = e as Error;
- return fail(400, { message });
- }
+ try {
+ p = await post("/payments", body, auth(cookies));
+ } catch (e) {
+ const { message } = e as Error;
+ return fail(400, { message });
+ }
- if (p) redirect(307, `/fund/${body.fund}`);
- },
+ if (p) redirect(307, `/fund/${body.fund}`);
+ },
};
diff --git a/src/routes/(app)/send/invoice/[id]/+page.server.ts b/src/routes/(app)/send/invoice/[id]/+page.server.ts
index c9c7dbd9..2e268b99 100644
--- a/src/routes/(app)/send/invoice/[id]/+page.server.ts
+++ b/src/routes/(app)/send/invoice/[id]/+page.server.ts
@@ -3,76 +3,76 @@ import { auth, fd, get, post, types } from "$lib/utils";
import { error, fail, redirect } from "@sveltejs/kit";
export async function load({ cookies, depends, params: { id }, parent }) {
- depends("app:trust");
- const { subject, user } = await parent();
- const aid = cookies.get("aid") || user.id;
- const pin = cookies.get("pin");
+ depends("app:trust");
+ const { user } = await parent();
+ const aid = cookies.get("aid") || user.id;
+ const pin = cookies.get("pin");
- let invoice = await get(`/invoice/${id}`);
+ let invoice = await get(`/invoice/${id}`);
- const trust = await get("/trust", auth(cookies));
- const trusted = trust.includes(invoice.uid);
- if (trusted && (pin || !user.haspin)) {
- let p;
- try {
- if (!invoice.tip && invoice.user.prompt) {
- if (user.tip > 0) {
- invoice.tip = Math.round(invoice.amount * (user.tip / 100));
- invoice = await post(`/invoice/${id}`, { invoice }, auth(cookies));
- } else {
- throw new Error("tip");
- }
- }
- p = await post("/payments", { ...invoice, pin }, auth(cookies));
- } catch (e) {
- const { message } = e as Error;
- if (message === "tip") redirect(307, `/invoice/${id}/tip`);
- fail(400, { message });
- }
- if (p) redirect(307, `/sent/${p.id}`);
- }
+ const trust = await get("/trust", auth(cookies));
+ const trusted = trust.includes(invoice.uid);
+ if (trusted && (pin || !user.haspin)) {
+ let p;
+ try {
+ if (!invoice.tip && invoice.user.prompt) {
+ if (user.tip > 0) {
+ invoice.tip = Math.round(invoice.amount * (user.tip / 100));
+ invoice = await post(`/invoice/${id}`, { invoice }, auth(cookies));
+ } else {
+ throw new Error("tip");
+ }
+ }
+ p = await post("/payments", { ...invoice, pin }, auth(cookies));
+ } catch (e) {
+ const { message } = e as Error;
+ if (message === "tip") redirect(307, `/invoice/${id}/tip`);
+ fail(400, { message });
+ }
+ if (p) redirect(307, `/sent/${p.id}`);
+ }
- if (invoice.amount && invoice.prompt && invoice.tip === null)
- redirect(307, `/invoice/${id}/tip`);
+ if (invoice.amount && invoice.prompt && invoice.tip === null)
+ redirect(307, `/invoice/${id}/tip`);
- if (invoice.memoPrompt && invoice.memo === null)
- redirect(307, `/invoice/${id}/memo`);
+ if (invoice.memoPrompt && invoice.memo === null)
+ redirect(307, `/invoice/${id}/memo`);
- if (user && invoice.aid === aid)
- error(500, { message: "Cannot send to self" });
- else if (user && ![types.lightning, types.bolt12].includes(invoice.type))
- redirect(
- 307,
- `/send/${invoice.type === types.ecash ? "ecash" : "bitcoin"}/${
- invoice.hash
- }`,
- );
+ if (user && invoice.aid === aid)
+ error(500, { message: "Cannot send to self" });
+ else if (user && ![types.lightning, types.bolt12].includes(invoice.type))
+ redirect(
+ 307,
+ `/send/${invoice.type === types.ecash ? "ecash" : "bitcoin"}/${
+ invoice.hash
+ }`,
+ );
- if (!user) redirect(307, `/invoice/${id}`);
+ if (!user) redirect(307, `/invoice/${id}`);
- const rates = await getRates();
- const rate = rates[user.currency];
- const invoiceRate = rates[invoice.currency];
+ const rates = await getRates();
+ const rate = rates[user.currency];
+ const invoiceRate = rates[invoice.currency];
- const { balance } = await get(`/account/${aid}`, auth(cookies));
- return { balance, invoice, user, rate, invoiceRate, trusted };
+ const { balance } = await get(`/account/${aid}`, auth(cookies));
+ return { balance, invoice, user, rate, invoiceRate, trusted };
}
export const actions = {
- default: async ({ cookies, params: { id }, request }) => {
- let p;
- try {
- const body = await fd(request);
- body.hash = id;
- body.aid = cookies.get("aid");
+ default: async ({ cookies, params: { id }, request }) => {
+ let p;
+ try {
+ const body = await fd(request);
+ body.hash = id;
+ body.aid = cookies.get("aid");
- p = await post("/payments", body, auth(cookies));
- } catch (e) {
- const { message } = e as Error;
- console.log("payment failed", id, e);
- error(500, { message });
- }
+ p = await post("/payments", body, auth(cookies));
+ } catch (e) {
+ const { message } = e as Error;
+ console.log("payment failed", id, e);
+ error(500, { message });
+ }
- redirect(307, `/sent/${p.id}`);
- },
+ redirect(307, `/sent/${p.id}`);
+ },
};
diff --git a/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.server.ts b/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.server.ts
index 7a5514e8..de123e2e 100644
--- a/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.server.ts
+++ b/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.server.ts
@@ -3,61 +3,61 @@ import { auth, fd, get, post } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export async function load({ cookies, params, parent }) {
- const { user } = await parent();
- let data: any = { ...params };
- const rates = await getRates();
- if (!params.payreq.startsWith("lno")) {
- data = { ...data, ...(await post("/parse", params, auth(cookies))) };
- }
+ const { user } = await parent();
+ let data: any = { ...params };
+ const rates = await getRates();
+ if (!params.payreq.startsWith("lno")) {
+ data = { ...data, ...(await post("/parse", params, auth(cookies))) };
+ }
- data.rate = rates[user.currency];
+ data.rate = rates[user.currency];
- const aid = cookies.get("aid") || user.id;
- if (aid !== user.id) {
- const account = await get(`/account/${aid}`, auth(cookies));
- if (account.type === "ark") {
- data.account = account;
- data.serverArkAddress = await get("/ark/address");
- } else if (account.type === "bitcoin") {
- data.account = account;
- }
- }
+ const aid = cookies.get("aid") || user.id;
+ if (aid !== user.id) {
+ const account = await get(`/account/${aid}`, auth(cookies));
+ if (account.type === "ark") {
+ data.account = account;
+ data.serverArkAddress = await get("/ark/address");
+ } else if (account.type === "bitcoin") {
+ data.account = account;
+ }
+ }
- return data;
+ return data;
}
export const actions = {
- setAmount: async ({ cookies, params, request }) => {
- let data = await fd(request);
- const { payreq } = params;
- const { amount } = data;
- if (payreq.startsWith("lno")) {
- const { invoice } = await post("/fetchinvoice", {
- amount,
- offer: payreq,
- });
+ setAmount: async ({ cookies, params, request }) => {
+ let data = await fd(request);
+ const { payreq } = params;
+ const { amount } = data;
+ if (payreq.startsWith("lno")) {
+ const { invoice } = await post("/fetchinvoice", {
+ amount,
+ offer: payreq,
+ });
- data = await post("/parse", { payreq: invoice }, auth(cookies));
- data.payreq = invoice;
- }
+ data = await post("/parse", { payreq: invoice }, auth(cookies));
+ data.payreq = invoice;
+ }
- return data;
- },
+ return data;
+ },
- send: async ({ cookies, request }) => {
- let p;
- try {
- const body = await fd(request);
- body.aid = cookies.get("aid");
+ send: async ({ cookies, request }) => {
+ let p;
+ try {
+ const body = await fd(request);
+ body.aid = cookies.get("aid");
- console.log("BODY", body);
+ console.log("BODY", body);
- p = await post("/payments", body, auth(cookies));
- } catch (e) {
- const { message } = e as Error;
- return fail(400, { message });
- }
+ p = await post("/payments", body, auth(cookies));
+ } catch (e) {
+ const { message } = e as Error;
+ return fail(400, { message });
+ }
- redirect(307, `/sent/${p.id}`);
- },
+ redirect(307, `/sent/${p.id}`);
+ },
};
diff --git a/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.svelte b/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.svelte
index 526038fa..718f3ee2 100644
--- a/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.svelte
+++ b/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.svelte
@@ -18,8 +18,12 @@
let { currency, locked } = $derived(user);
let locale = $derived(loc(user));
- $effect(() => { $rate ||= data.rate; });
- $effect(() => { if (form) loading = false; });
+ $effect(() => {
+ $rate ||= data.rate;
+ });
+ $effect(() => {
+ if (form) loading = false;
+ });
let showMax = $state();
let error = $state("");
@@ -33,7 +37,9 @@
let maxfee = $state(
Math.max(5, Math.round(untrack(() => amount) * 0.02 || 0)),
);
- $effect(() => { maxfee = Math.max(5, Math.round(amount * 0.02) || 0); });
+ $effect(() => {
+ maxfee = Math.max(5, Math.round(amount * 0.02) || 0);
+ });
let handler = ({ cancel }) => {
loading = true;
@@ -67,7 +73,11 @@
(async () => {
try {
const inv = await post("/post/invoice", {
- invoice: { type: "bitcoin", amount: parseInt(amount), forward: payreq },
+ invoice: {
+ type: "bitcoin",
+ amount: parseInt(amount),
+ forward: payreq,
+ },
user,
});
@@ -126,12 +136,7 @@
</div>
{/if}
- <form
- method="POST"
- use:enhance={handler}
- action="?/send"
- class="space-y-2"
- >
+ <form method="POST" use:enhance={handler} action="?/send" class="space-y-2">
<input name="payreq" value={payreq} type="hidden" />
<input name="amount" value={amount} type="hidden" />
<input name="pin" value={$pin} type="hidden" />
diff --git a/src/routes/(app)/send/zap/[id]/[...amount]/+page.server.ts b/src/routes/(app)/send/zap/[id]/[...amount]/+page.server.ts
index 2219c370..a658a5c1 100644
--- a/src/routes/(app)/send/zap/[id]/[...amount]/+page.server.ts
+++ b/src/routes/(app)/send/zap/[id]/[...amount]/+page.server.ts
@@ -3,41 +3,41 @@ import { auth, fd, post } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export async function load({ cookies, params, parent }) {
- const { user } = await parent();
- const { amount, id } = params;
- const rates = await getRates();
+ const { user } = await parent();
+ const { amount, id } = params;
+ const rates = await getRates();
- let request;
- if (amount)
- request = await post("/zapRequest", { amount, id }, auth(cookies));
+ let request;
+ if (amount)
+ request = await post("/zapRequest", { amount, id }, auth(cookies));
- const rate = rates[user.currency];
- return { amount, id, rates, rate, request };
+ const rate = rates[user.currency];
+ return { amount, id, rates, rate, request };
}
export const actions = {
- setAmount: async ({ cookies, params, request }) => {
- const data = await fd(request);
- const { id } = params;
- const { amount } = data;
+ setAmount: async ({ cookies, params, request }) => {
+ const data = await fd(request);
+ const { id } = params;
+ const { amount } = data;
- data.request = await post("/zapRequest", { amount, id }, auth(cookies));
+ data.request = await post("/zapRequest", { amount, id }, auth(cookies));
- return data;
- },
+ return data;
+ },
- send: async ({ cookies, request }) => {
- let p;
- try {
- const body = await fd(request);
+ send: async ({ cookies, request }) => {
+ let p;
+ try {
+ const body = await fd(request);
- p = await post("/payments", body, auth(cookies));
- console.log("P", p);
- } catch (_) {
- console.log("WHAT", _);
- return fail(400, { message: "payments.failedToRoute" });
- }
+ p = await post("/payments", body, auth(cookies));
+ console.log("P", p);
+ } catch (_) {
+ console.log("WHAT", _);
+ return fail(400, { message: "payments.failedToRoute" });
+ }
- redirect(307, `/sent/${p.id}`);
- },
+ redirect(307, `/sent/${p.id}`);
+ },
};
diff --git a/src/routes/(app)/send/zap/[id]/[...amount]/+page.svelte b/src/routes/(app)/send/zap/[id]/[...amount]/+page.svelte
index 78b4d64f..3d0d144c 100644
--- a/src/routes/(app)/send/zap/[id]/[...amount]/+page.svelte
+++ b/src/routes/(app)/send/zap/[id]/[...amount]/+page.svelte
@@ -20,7 +20,9 @@
let locale = $derived(loc(user));
let event = $state();
- $effect(() => { $rate ||= data.rate; });
+ $effect(() => {
+ $rate ||= data.rate;
+ });
$effect(() => {
if (form || request) {
(async () => {
diff --git a/src/routes/(app)/sent/[id]/+page.server.ts b/src/routes/(app)/sent/[id]/+page.server.ts
index 31bf4dd1..b27d2ad8 100644
--- a/src/routes/(app)/sent/[id]/+page.server.ts
+++ b/src/routes/(app)/sent/[id]/+page.server.ts
@@ -1,7 +1,7 @@
import { auth, get } from "$lib/utils";
export const load = async ({ cookies, params }) => {
- const { id } = params;
- const p = await get(`/payments/${id}`, auth(cookies));
- return p;
+ const { id } = params;
+ const p = await get(`/payments/${id}`, auth(cookies));
+ return p;
};
diff --git a/src/routes/(app)/sent/[id]/+page.svelte b/src/routes/(app)/sent/[id]/+page.svelte
index 3dde854f..ba2b7366 100644
--- a/src/routes/(app)/sent/[id]/+page.svelte
+++ b/src/routes/(app)/sent/[id]/+page.svelte
@@ -10,7 +10,14 @@
let locale = $derived(loc(user));
</script>
-<Success {amount} {rate} {tip} {currency} {locale} title={`${$t("payments.sent")}!`} />
+<Success
+ {amount}
+ {rate}
+ {tip}
+ {currency}
+ {locale}
+ title={`${$t("payments.sent")}!`}
+/>
<a href={`/${username}`} use:focus aria-label="Continue">
<div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50"></div>
</a>
diff --git a/src/routes/(app)/settings/+layout.server.ts b/src/routes/(app)/settings/+layout.server.ts
index bcb7dbe2..29874012 100644
--- a/src/routes/(app)/settings/+layout.server.ts
+++ b/src/routes/(app)/settings/+layout.server.ts
@@ -2,11 +2,11 @@ import { auth, get } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export async function load({ cookies, params, parent, url }) {
- const { user } = await parent();
- if (!user) redirect(307, `/register?redirect=${url.pathname}`);
- const tab = url.pathname.split("/").filter(Boolean).pop();
- if (tab === "settings") redirect(307, `${url.pathname}/account`);
- params.cookies = cookies.getAll();
- const subscriptions = await get("/subscriptions", auth(cookies));
- return { cookies: cookies.getAll(), subscriptions, tab };
+ const { user } = await parent();
+ if (!user) redirect(307, `/register?redirect=${url.pathname}`);
+ const tab = url.pathname.split("/").filter(Boolean).pop();
+ if (tab === "settings") redirect(307, `${url.pathname}/account`);
+ params.cookies = cookies.getAll();
+ const subscriptions = await get("/subscriptions", auth(cookies));
+ return { cookies: cookies.getAll(), subscriptions, tab };
}
diff --git a/src/routes/(app)/settings/+layout.svelte b/src/routes/(app)/settings/+layout.svelte
index a8792333..b670737f 100644
--- a/src/routes/(app)/settings/+layout.svelte
+++ b/src/routes/(app)/settings/+layout.svelte
@@ -2,7 +2,8 @@
import { browser } from "$app/environment";
import { onMount, tick } from "svelte";
import { fly } from "svelte/transition";
- import { applyAction, deserialize } from "$app/forms"; import Spinner from "$comp/Spinner.svelte";
+ import { applyAction, deserialize } from "$app/forms";
+ import Spinner from "$comp/Spinner.svelte";
import Pin from "$comp/Pin.svelte";
import { loading, t } from "$lib/translations";
import { fd, fail, auth, post, sleep, warning, success } from "$lib/utils";
@@ -14,8 +15,8 @@
import { getPublicKey } from "nostr-tools";
import { bytesToHex } from "@noble/hashes/utils.js";
- import { SimplePool } from 'nostr-tools/pool';
- import { finalizeEvent } from 'nostr-tools/pure';
+ import { SimplePool } from "nostr-tools/pool";
+ import { finalizeEvent } from "nostr-tools/pure";
let { children, data, form }: any = $props();
@@ -45,14 +46,15 @@
let submitting = $state();
const pool = new SimplePool();
- import { PUBLIC_DM_RELAYS } from '$env/static/public';
- const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(',');
+ import { PUBLIC_DM_RELAYS } from "$env/static/public";
+ const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(",");
const updateRelaysIfAvailable = async () => {
- const relayEntry = document.getElementById('dmRelays') as HTMLTextAreaElement | null;
+ const relayEntry = document.getElementById(
+ "dmRelays",
+ ) as HTMLTextAreaElement | null;
if (!relayEntry || relayEntry.value.length === 0) return;
- const newRelays = relayEntry.value.split(/[ \r\n\t]+/)
- .filter(isValidURL);
+ const newRelays = relayEntry.value.split(/[ \r\n\t]+/).filter(isValidURL);
if (newRelays.length === 0) {
warning($t("user.settings.noDMURLsWarning"));
return;
@@ -61,18 +63,18 @@
const event = {
kind: 10050,
created_at: Math.floor(Date.now() / 1000),
- tags: newRelays.map(r => ["relay", r]),
- content: ""
+ tags: newRelays.map((r) => ["relay", r]),
+ content: "",
};
let signed;
- if (await window.nostr!.getPublicKey() === user.pubkey) {
+ if ((await window.nostr!.getPublicKey()) === user.pubkey) {
signed = await window.nostr!.signEvent(event);
} else {
const sk = await getPrivateKey(user);
signed = finalizeEvent(event, sk);
}
await Promise.any(pool.publish(DM_RELAYS_LIST, signed));
- }
+ };
const isValidURL = (url: string) => {
try {
@@ -81,7 +83,7 @@
} catch (err: any) {
return false;
}
- }
+ };
async function handleSubmit(e: any) {
updateRelaysIfAvailable();
@@ -122,7 +124,11 @@
if ($avatar) {
try {
let { hash } = JSON.parse(
- await upload(($avatar as any).file, ($avatar as any).type, ($avatar as any).progress) as string,
+ (await upload(
+ ($avatar as any).file,
+ ($avatar as any).type,
+ ($avatar as any).progress,
+ )) as string,
);
let url = `${$page.url.origin}/api/public/${hash}.webp`;
@@ -137,7 +143,11 @@
if ($banner) {
try {
let { hash } = JSON.parse(
- await upload(($banner as any).file, ($banner as any).type, ($banner as any).progress) as string,
+ (await upload(
+ ($banner as any).file,
+ ($banner as any).type,
+ ($banner as any).progress,
+ )) as string,
);
let url = `${$page.url.origin}/api/public/${hash}.webp`;
diff --git a/src/routes/(app)/settings/account/+page.server.ts b/src/routes/(app)/settings/account/+page.server.ts
index ebb90f05..33359425 100644
--- a/src/routes/(app)/settings/account/+page.server.ts
+++ b/src/routes/(app)/settings/account/+page.server.ts
@@ -3,11 +3,11 @@ import updateUser from "$lib/settings";
import { auth, get } from "$lib/utils";
export async function load({ cookies }) {
- const rates = await getRates();
- const connect = await get("/square/connect", auth(cookies));
- return { connect, rates };
+ const rates = await getRates();
+ const connect = await get("/square/connect", auth(cookies));
+ return { connect, rates };
}
export const actions = {
- default: updateUser,
+ default: updateUser,
};
diff --git a/src/routes/(app)/settings/account/+page.svelte b/src/routes/(app)/settings/account/+page.svelte
index a3cc24fd..fb182887 100644
--- a/src/routes/(app)/settings/account/+page.svelte
+++ b/src/routes/(app)/settings/account/+page.svelte
@@ -20,7 +20,8 @@
let fiats = Object.keys(rates).sort((a, b) => a.localeCompare(b));
let el: any;
- let keypress = (e: any) => e.key === "Enter" && (e.preventDefault() || el.click());
+ let keypress = (e: any) =>
+ e.key === "Enter" && (e.preventDefault() || el.click());
let editingReserve = $state(),
editingThreshold = $state(),
diff --git a/src/routes/(app)/settings/nostr/+page.server.ts b/src/routes/(app)/settings/nostr/+page.server.ts
index 1767ebaf..b4622384 100644
--- a/src/routes/(app)/settings/nostr/+page.server.ts
+++ b/src/routes/(app)/settings/nostr/+page.server.ts
@@ -2,11 +2,11 @@ import updateUser from "$lib/settings";
import { auth, get } from "$lib/utils";
export const load = async ({ cookies }) => {
- const { challenge } = await get("/challenge");
- const apps = await get("/apps", auth(cookies));
- return { apps, challenge };
+ const { challenge } = await get("/challenge");
+ const apps = await get("/apps", auth(cookies));
+ return { apps, challenge };
};
export const actions = {
- default: updateUser,
+ default: updateUser,
};
diff --git a/src/routes/(app)/settings/nostr/+page.svelte b/src/routes/(app)/settings/nostr/+page.svelte
index ae074d30..c91150a3 100644
--- a/src/routes/(app)/settings/nostr/+page.svelte
+++ b/src/routes/(app)/settings/nostr/+page.svelte
@@ -15,7 +15,7 @@
let extensionAvailable = $derived(browser && (window as any).nostr);
let { locale } = $derived(user);
- import { SimplePool } from 'nostr-tools/pool';
+ import { SimplePool } from "nostr-tools/pool";
let newNsec = $state(),
nsec: any = $state(),
@@ -42,11 +42,13 @@
($save as any).click();
};
- import { PUBLIC_DM_RELAYS } from '$env/static/public';
- const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(',');
+ import { PUBLIC_DM_RELAYS } from "$env/static/public";
+ const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(",");
const pool = new SimplePool();
- getPreferredRelays(user.pubkey).then(relays => {
- const relayEntry = document.getElementById('dmRelays') as HTMLTextAreaElement | null;
+ getPreferredRelays(user.pubkey).then((relays) => {
+ const relayEntry = document.getElementById(
+ "dmRelays",
+ ) as HTMLTextAreaElement | null;
if (relayEntry) relayEntry.value = relays.join("\n");
});
</script>
@@ -78,8 +80,16 @@
class="text-yellow-300"
></iconify-icon>
{#if $fiat && $rate}
- {f((app.spent * ($rate as number)) / sats, user.currency, locale)} /
- {f((app.max_amount * ($rate as number)) / sats, user.currency, locale)}
+ {f(
+ (app.spent * ($rate as number)) / sats,
+ user.currency,
+ locale,
+ )} /
+ {f(
+ (app.max_amount * ($rate as number)) / sats,
+ user.currency,
+ locale,
+ )}
{:else}
{s(app.spent, locale)} /
{s(app.max_amount, locale)}
@@ -177,24 +187,25 @@
<div class="font-bold">{$t("user.nostrPubkey")}</div>
<textarea name="pubkey" bind:value={npub} rows={3}></textarea>
<div>
- <div class="flex my-auto gap-1">
- <button
- type="button"
- class="my-auto btn btn-circle !w-auto grow"
- onclick={() => copy(npub)}
- aria-label="Copy"
- ><iconify-icon noobserver icon="ph:copy-bold" width="32"
- ></iconify-icon> {$t("accounts.copy")}</button
- >
+ <div class="flex my-auto gap-1">
+ <button
+ type="button"
+ class="my-auto btn btn-circle !w-auto grow"
+ onclick={() => copy(npub)}
+ aria-label="Copy"
+ ><iconify-icon noobserver icon="ph:copy-bold" width="32"></iconify-icon>
+ {$t("accounts.copy")}</button
+ >
- <a
- href={`/qr/${encodeURIComponent(npub)}`}
- class="my-auto btn btn-circle !w-auto grow"
- aria-label="QR"
- >
- <iconify-icon noobserver icon="ph:qr-code-bold" width="32"></iconify-icon>
-{$t("accounts.qr")}
- </a>
+ <a
+ href={`/qr/${encodeURIComponent(npub)}`}
+ class="my-auto btn btn-circle !w-auto grow"
+ aria-label="QR"
+ >
+ <iconify-icon noobserver icon="ph:qr-code-bold" width="32"
+ ></iconify-icon>
+ {$t("accounts.qr")}
+ </a>
</div>
</div>
@@ -245,10 +256,10 @@
{/if}
<span class="font-bold" id="dm-relays">
- {$t("user.settings.preferredDM")}
+ {$t("user.settings.preferredDM")}
</span>
<p class="text-secondary mb-1">
- {$t("user.settings.preferredDMDescription")}
+ {$t("user.settings.preferredDMDescription")}
</p>
<textarea id="dmRelays" name="dmRelays" rows={3}></textarea>
diff --git a/src/routes/(app)/settings/profile/+page.server.ts b/src/routes/(app)/settings/profile/+page.server.ts
index 4145935e..e3311c99 100644
--- a/src/routes/(app)/settings/profile/+page.server.ts
+++ b/src/routes/(app)/settings/profile/+page.server.ts
@@ -1,5 +1,5 @@
import updateUser from "$lib/settings";
export const actions = {
- default: updateUser,
+ default: updateUser,
};
diff --git a/src/routes/(app)/settings/profile/+page.svelte b/src/routes/(app)/settings/profile/+page.svelte
index e7a60677..5cb4f7ae 100644
--- a/src/routes/(app)/settings/profile/+page.svelte
+++ b/src/routes/(app)/settings/profile/+page.svelte
@@ -86,7 +86,10 @@
>{$t("user.settings.newPassword")}</label
>
- <PasswordInput bind:value={password} placeholder="(Leave blank to keep unchanged)" />
+ <PasswordInput
+ bind:value={password}
+ placeholder="(Leave blank to keep unchanged)"
+ />
</div>
<div>
@@ -104,7 +107,8 @@
<div
class="relative rounded-full overflow-hidden text-center w-20 h-20 my-auto hover:opacity-80 cursor-pointer"
onclick={selectAvatar}
- onkeydown={(e) => (e.key === "Enter" || e.key === " ") && selectAvatar()}
+ onkeydown={(e) =>
+ (e.key === "Enter" || e.key === " ") && selectAvatar()}
role="button"
tabindex="0"
>
@@ -118,7 +122,8 @@
<div
class="rounded-full border-4 border-base-100 p-4 bg-base-200 w-24 h-24 my-auto hover:opacity-80 cursor-pointer"
onclick={selectAvatar}
- onkeydown={(e) => (e.key === "Enter" || e.key === " ") && selectAvatar()}
+ onkeydown={(e) =>
+ (e.key === "Enter" || e.key === " ") && selectAvatar()}
role="button"
tabindex="0"
></div>
diff --git a/src/routes/(app)/settings/security/+page.server.ts b/src/routes/(app)/settings/security/+page.server.ts
index 4145935e..e3311c99 100644
--- a/src/routes/(app)/settings/security/+page.server.ts
+++ b/src/routes/(app)/settings/security/+page.server.ts
@@ -1,5 +1,5 @@
import updateUser from "$lib/settings";
export const actions = {
- default: updateUser,
+ default: updateUser,
};
diff --git a/src/routes/(app)/settings/security/+page.svelte b/src/routes/(app)/settings/security/+page.svelte
index 7ce68d11..193cd91b 100644
--- a/src/routes/(app)/settings/security/+page.svelte
+++ b/src/routes/(app)/settings/security/+page.svelte
@@ -149,9 +149,15 @@
};
let verifying = $derived(pin?.length > 5);
- $effect(() => { if (verify) checkPin(pin as any); });
- $effect(() => { if (setting2fa) enable2fa(token as any); });
- $effect(() => { if (disabling2fa) disable2fa(token as any); });
+ $effect(() => {
+ if (verify) checkPin(pin as any);
+ });
+ $effect(() => {
+ if (setting2fa) enable2fa(token as any);
+ });
+ $effect(() => {
+ if (disabling2fa) disable2fa(token as any);
+ });
</script>
<input type="hidden" name="newpin" value={disablingPin ? "delete" : pin} />
@@ -223,12 +229,7 @@
{/if}
{#if confirming2fa || disabling2fa}
- <Pin
- bind:value={token}
- title="Enter 2FA Code"
- {cancel}
- notify={false}
- />
+ <Pin bind:value={token} title="Enter 2FA Code" {cancel} notify={false} />
{/if}
</div>
diff --git a/src/routes/(app)/settings/shopify/+page.server.ts b/src/routes/(app)/settings/shopify/+page.server.ts
index 4145935e..e3311c99 100644
--- a/src/routes/(app)/settings/shopify/+page.server.ts
+++ b/src/routes/(app)/settings/shopify/+page.server.ts
@@ -1,5 +1,5 @@
import updateUser from "$lib/settings";
export const actions = {
- default: updateUser,
+ default: updateUser,
};
diff --git a/src/routes/(app)/settings/square/+page.server.ts b/src/routes/(app)/settings/square/+page.server.ts
index e00bdf1b..5d4c21e6 100644
--- a/src/routes/(app)/settings/square/+page.server.ts
+++ b/src/routes/(app)/settings/square/+page.server.ts
@@ -2,17 +2,17 @@ import { auth, get } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export async function load({ cookies, url }) {
- let connected;
+ let connected;
- const query = url.searchParams.toString();
+ const query = url.searchParams.toString();
- try {
- await get(`/square/auth?${query}`, auth(cookies));
- connected = true;
- } catch (e) {
- const { message } = e as Error;
- fail(400, { message });
- }
+ try {
+ await get(`/square/auth?${query}`, auth(cookies));
+ connected = true;
+ } catch (e) {
+ const { message } = e as Error;
+ fail(400, { message });
+ }
- if (connected) redirect(307, "/settings/account");
+ if (connected) redirect(307, "/settings/account");
}
diff --git a/src/routes/(app)/sign/+page.server.ts b/src/routes/(app)/sign/+page.server.ts
index b0e319f0..ddafcb60 100644
--- a/src/routes/(app)/sign/+page.server.ts
+++ b/src/routes/(app)/sign/+page.server.ts
@@ -2,22 +2,22 @@ import { auth, fd, post, types } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export async function load({ cookies, parent, url }) {
- const { user } = await parent();
- if (!user) redirect(307, `/register?redirect=${url.pathname}`);
+ const { user } = await parent();
+ if (!user) redirect(307, `/register?redirect=${url.pathname}`);
- const invoice = {
- address_type: "legacy",
- type: types.bitcoin,
- };
+ const invoice = {
+ address_type: "legacy",
+ type: types.bitcoin,
+ };
- const { text: address } = await post("/invoice", { invoice }, auth(cookies));
+ const { text: address } = await post("/invoice", { invoice }, auth(cookies));
- return { address };
+ return { address };
}
export const actions = {
- default: async ({ cookies, request }) => {
- const body = await fd(request);
- return post("/sign", body, auth(cookies));
- },
+ default: async ({ cookies, request }) => {
+ const body = await fd(request);
+ return post("/sign", body, auth(cookies));
+ },
};
diff --git a/src/routes/(app)/subscription/+server.ts b/src/routes/(app)/subscription/+server.ts
index 47dfc770..f25db99a 100644
--- a/src/routes/(app)/subscription/+server.ts
+++ b/src/routes/(app)/subscription/+server.ts
@@ -2,7 +2,7 @@ import { auth, post } from "$lib/utils";
import { json } from "@sveltejs/kit";
export async function POST({ cookies, request }) {
- const body = await request.json();
- const result = await post("/subscription", body, auth(cookies));
- return json(result);
+ const body = await request.json();
+ const result = await post("/subscription", body, auth(cookies));
+ return json(result);
}
diff --git a/src/routes/(app)/subscription/delete/+server.ts b/src/routes/(app)/subscription/delete/+server.ts
index f4c8357c..1e6c1fdd 100644
--- a/src/routes/(app)/subscription/delete/+server.ts
+++ b/src/routes/(app)/subscription/delete/+server.ts
@@ -2,7 +2,7 @@ import { auth, post } from "$lib/utils";
import { json } from "@sveltejs/kit";
export async function POST({ cookies, request }) {
- const body = await request.json();
- const result = await post("/subscription/delete", body, auth(cookies));
- return json(result);
+ const body = await request.json();
+ const result = await post("/subscription/delete", body, auth(cookies));
+ return json(result);
}
diff --git a/src/routes/(app)/thread/[id]/+page.server.ts b/src/routes/(app)/thread/[id]/+page.server.ts
index 931e9cb8..548c43fb 100644
--- a/src/routes/(app)/thread/[id]/+page.server.ts
+++ b/src/routes/(app)/thread/[id]/+page.server.ts
@@ -2,11 +2,11 @@ import { get } from "$lib/utils";
import { error } from "@sveltejs/kit";
export async function load({ params }) {
- try {
- const thread = await get(`/thread/${params.id}`);
- return { thread };
- } catch (e) {
- console.log(e);
- error(500, { message: "Failed to get thread" });
- }
+ try {
+ const thread = await get(`/thread/${params.id}`);
+ return { thread };
+ } catch (e) {
+ console.log(e);
+ error(500, { message: "Failed to get thread" });
+ }
}
diff --git a/src/routes/(app)/verify/[code]/+page.server.ts b/src/routes/(app)/verify/[code]/+page.server.ts
index a7edede6..a782d4f8 100644
--- a/src/routes/(app)/verify/[code]/+page.server.ts
+++ b/src/routes/(app)/verify/[code]/+page.server.ts
@@ -2,13 +2,12 @@ import { get } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export const load = async ({ params: { code } }) => {
- let user;
- try {
- user = await get(`/verify/${code}`);
- } catch (e) {
- console.log(e);
- return { error: "Verification failed" };
- }
+ try {
+ await get(`/verify/${code}`);
+ } catch (e) {
+ console.log(e);
+ return { error: "Verification failed" };
+ }
- redirect(307, "/settings/account?verified=true");
+ redirect(307, "/settings/account?verified=true");
};
diff --git a/src/routes/(app)/withdraw/+server.ts b/src/routes/(app)/withdraw/+server.ts
index 51f6e3d0..f8e093ef 100644
--- a/src/routes/(app)/withdraw/+server.ts
+++ b/src/routes/(app)/withdraw/+server.ts
@@ -1,10 +1,10 @@
import { auth, post } from "$lib/utils";
export async function POST({ cookies, request }) {
- const body = await request.json();
- await post("/payments", body, auth(cookies));
+ const body = await request.json();
+ await post("/payments", body, auth(cookies));
- return new Response(JSON.stringify("ok"), {
- headers: { "content-type": "application/json" },
- });
+ return new Response(JSON.stringify("ok"), {
+ headers: { "content-type": "application/json" },
+ });
}
diff --git a/src/routes/(static)/+layout.server.ts b/src/routes/(static)/+layout.server.ts
index 5de752fa..bd8ce5a8 100644
--- a/src/routes/(static)/+layout.server.ts
+++ b/src/routes/(static)/+layout.server.ts
@@ -2,18 +2,18 @@ import { auth, get, isInvalidTokenError } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export async function load({ cookies }) {
- const token = cookies.get("token");
+ const token = cookies.get("token");
- let user;
- if (token) {
- try {
- user = await get("/me", auth(cookies));
- } catch (e) {
- if (isInvalidTokenError(e)) {
- redirect(307, "/logout");
- }
- }
- }
+ let user;
+ if (token) {
+ try {
+ user = await get("/me", auth(cookies));
+ } catch (e) {
+ if (isInvalidTokenError(e)) {
+ redirect(307, "/logout");
+ }
+ }
+ }
- return { user };
+ return { user };
}
diff --git a/src/routes/(static)/bounties/+page.server.ts b/src/routes/(static)/bounties/+page.server.ts
index 8378e2f2..00a94d76 100644
--- a/src/routes/(static)/bounties/+page.server.ts
+++ b/src/routes/(static)/bounties/+page.server.ts
@@ -1,44 +1,44 @@
import { get } from "$lib/utils";
export const load = async () => {
- const users = [
- {
- username: "fustler",
- merchant: "rrdrive",
- type: "Bakery",
- amount: 1000000,
- },
- {
- username: "laluna",
- merchant: "butchersguild",
- type: "Butcher Shop",
- amount: 1000000,
- },
- {
- username: "ica547",
- merchant: "vanlove",
- type: "Sushi Restaurant",
- amount: 1000000,
- },
- {
- username: "reverendhodl",
- merchant: "laughingbean",
- type: "Cafe",
- amount: 1000000,
- },
- {
- username: "kimsrepair",
- merchant: "kimsrepair",
- type: "Kims Repair",
- amount: 100000,
- },
- ];
+ const users = [
+ {
+ username: "fustler",
+ merchant: "rrdrive",
+ type: "Bakery",
+ amount: 1000000,
+ },
+ {
+ username: "laluna",
+ merchant: "butchersguild",
+ type: "Butcher Shop",
+ amount: 1000000,
+ },
+ {
+ username: "ica547",
+ merchant: "vanlove",
+ type: "Sushi Restaurant",
+ amount: 1000000,
+ },
+ {
+ username: "reverendhodl",
+ merchant: "laughingbean",
+ type: "Cafe",
+ amount: 1000000,
+ },
+ {
+ username: "kimsrepair",
+ merchant: "kimsrepair",
+ type: "Kims Repair",
+ amount: 100000,
+ },
+ ];
- for (const user of users) {
- const { username, merchant } = user;
- console.log(username, merchant);
- user.user = await get(`/users/${username}`);
- user.merchant = await get(`/users/${merchant}`);
- }
+ for (const user of users) {
+ const { username, merchant } = user;
+ console.log(username, merchant);
+ user.user = await get(`/users/${username}`);
+ user.merchant = await get(`/users/${merchant}`);
+ }
- return { users };
+ return { users };
};
diff --git a/src/routes/(static)/docs/+page.server.ts b/src/routes/(static)/docs/+page.server.ts
index 93ba544c..ec5ace69 100644
--- a/src/routes/(static)/docs/+page.server.ts
+++ b/src/routes/(static)/docs/+page.server.ts
@@ -1,7 +1,7 @@
import { auth, get } from "$lib/utils";
export const load = async ({ cookies }) => {
- const token = cookies.get("token");
- let ro;
- if (token) ro = await get("/ro", auth(cookies));
- return { ro, token };
+ const token = cookies.get("token");
+ let ro;
+ if (token) ro = await get("/ro", auth(cookies));
+ return { ro, token };
};
diff --git a/src/routes/(static)/docs/+page.svelte b/src/routes/(static)/docs/+page.svelte
index 76e487c5..51b1f54e 100644
--- a/src/routes/(static)/docs/+page.svelte
+++ b/src/routes/(static)/docs/+page.svelte
@@ -2,7 +2,8 @@
import { copyNoNewlines as copy } from "$lib/utils";
import { PUBLIC_DOMAIN, PUBLIC_COINOS_URL } from "$env/static/public";
- import Code from "$comp/Code.svelte"; let { data } = $props();
+ import Code from "$comp/Code.svelte";
+ let { data } = $props();
let { user, ro, token } = data;
@@ -63,7 +64,8 @@
or get one from the /login endpoint.
{/if}
- Save it in a variable called <b>$token</b> to run the examples. It gives full access to your account so keep it safe.
+ Save it in a variable called <b>$token</b> to run the examples. It gives full
+ access to your account so keep it safe.
</p>
<div
@@ -75,8 +77,8 @@
{#if ro}
<p class="text-secondary">
- This read-only token has permission to create invoices and fetch
- payments but can't be used to make withdrawals
+ This read-only token has permission to create invoices and fetch payments
+ but can't be used to make withdrawals
</p>
<div
class="bg-primary text-primary-content rounded-lg p-4 flex gap-4 items-center"
diff --git a/src/routes/(static)/forgot/+page.server.ts b/src/routes/(static)/forgot/+page.server.ts
index 55169a5e..e7476c2d 100644
--- a/src/routes/(static)/forgot/+page.server.ts
+++ b/src/routes/(static)/forgot/+page.server.ts
@@ -2,13 +2,13 @@ import { fail } from "@sveltejs/kit";
import { fd, post } from "$lib/utils";
export const actions = {
- default: async ({ request }) => {
- try {
- const { email } = await fd(request);
- await post("/forgot", { email });
- return { success: true };
- } catch (e: any) {
- return fail(400, { error: e.message });
- }
- },
+ default: async ({ request }) => {
+ try {
+ const { email } = await fd(request);
+ await post("/forgot", { email });
+ return { success: true };
+ } catch (e: any) {
+ return fail(400, { error: e.message });
+ }
+ },
};
diff --git a/src/routes/(static)/forgot/+page.svelte b/src/routes/(static)/forgot/+page.svelte
index 186655a5..711c5568 100644
--- a/src/routes/(static)/forgot/+page.svelte
+++ b/src/routes/(static)/forgot/+page.svelte
@@ -1,7 +1,8 @@
<script lang="ts">
import { focus } from "$lib/utils";
import { enhance } from "$app/forms";
- import { t } from "$lib/translations"; import Spinner from "$comp/Spinner.svelte";
+ import { t } from "$lib/translations";
+ import Spinner from "$comp/Spinner.svelte";
import { fly } from "svelte/transition";
let loading;
diff --git a/src/routes/(static)/login/+page.server.ts b/src/routes/(static)/login/+page.server.ts
index ce343790..e4fb3815 100644
--- a/src/routes/(static)/login/+page.server.ts
+++ b/src/routes/(static)/login/+page.server.ts
@@ -1,77 +1,82 @@
import { PUBLIC_COINOS_URL } from "$env/static/public";
-import { fd, get, login, post } from "$lib/utils";
+import { fd, get, login } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
export const load = async ({ parent }) => {
- const { user } = await parent();
- if (user?.pubkey) redirect(307, `/${user.username}`);
- const { challenge } = await get("/challenge");
- return { challenge };
+ const { user } = await parent();
+ if (user?.pubkey) redirect(307, `/${user.username}`);
+ const { challenge } = await get("/challenge");
+ return { challenge };
};
export const actions = {
- login: async ({ cookies, request }) => {
- const form = await fd(request);
- let { username, password, token, loginRedirect, recaptcha } = form;
+ login: async ({ cookies, request }) => {
+ const form = await fd(request);
+ let { username, password, token, loginRedirect, recaptcha } = form;
username = username.split("@")[0];
- const user = {
- username,
- password,
- token,
- recaptcha,
- };
+ const user = {
+ username,
+ password,
+ token,
+ recaptcha,
+ };
- if (loginRedirect === "undefined") loginRedirect = undefined;
+ if (loginRedirect === "undefined") loginRedirect = undefined;
- try {
- await login(user, cookies, request.headers.get("cf-connecting-ip"), request.headers.get("host"));
- } catch (e) {
- const { message } = e as Error;
- return fail(400, { error: "Login failed", message, ...form });
- }
+ try {
+ await login(
+ user,
+ cookies,
+ request.headers.get("cf-connecting-ip"),
+ request.headers.get("host"),
+ );
+ } catch (e) {
+ const { message } = e as Error;
+ return fail(400, { error: "Login failed", message, ...form });
+ }
- redirect(307, loginRedirect || `/${user.username}`);
- },
+ redirect(307, loginRedirect || `/${user.username}`);
+ },
- nostr: async ({ cookies, fetch, request }) => {
- const form = await fd(request);
- let { challenge, event, loginRedirect, recaptcha } = form;
- if (loginRedirect === "null") loginRedirect = undefined;
- event = JSON.parse(event);
+ nostr: async ({ cookies, fetch, request }) => {
+ const form = await fd(request);
+ let { challenge, event, loginRedirect, recaptcha } = form;
+ if (loginRedirect === "null") loginRedirect = undefined;
+ event = JSON.parse(event);
- const maxAge = 380 * 24 * 60 * 60;
+ const maxAge = 380 * 24 * 60 * 60;
- const res = await fetch(`${PUBLIC_COINOS_URL}/nostrAuth`, {
- method: "POST",
- body: JSON.stringify({ challenge, event, recaptcha }),
- headers: {
- "content-type": "application/json",
- accept: "application/json",
- "cf-connecting-ip": request.headers.get("cf-connecting-ip"),
- "x-forwarded-host": request.headers.get("host"),
- },
- });
+ const res = await fetch(`${PUBLIC_COINOS_URL}/nostrAuth`, {
+ method: "POST",
+ body: JSON.stringify({ challenge, event, recaptcha }),
+ headers: {
+ "content-type": "application/json",
+ accept: "application/json",
+ "cf-connecting-ip": request.headers.get("cf-connecting-ip"),
+ "x-forwarded-host": request.headers.get("host"),
+ },
+ });
- const text = await res.text();
+ const text = await res.text();
- if (res.status === 401) {
- if (text.startsWith("2fa")) throw new Error("2fa");
- throw new Error(text);
- }
+ if (res.status === 401) {
+ if (text.startsWith("2fa")) throw new Error("2fa");
+ throw new Error(text);
+ }
- const { user, token } = JSON.parse(text);
- if (!token) throw new Error("Login failed");
- const { username, language } = user;
+ const { user, token } = JSON.parse(text);
+ if (!token) throw new Error("Login failed");
+ const { username, language } = user;
- const expires = new Date();
- expires.setSeconds(expires.getSeconds() + maxAge);
+ const expires = new Date();
+ expires.setSeconds(expires.getSeconds() + maxAge);
- const opts = { path: "/", expires };
- if (language) cookies.set("lang", language, opts);
- cookies.set("username", username, opts);
- cookies.set("token", token, opts);
+ const opts = { path: "/", expires };
+ if (language) cookies.set("lang", language, opts);
+ cookies.set("username", username, opts);
+ cookies.set("token", token, opts);
- redirect(307, loginRedirect || `/${username}`);
- },
+ redirect(307, loginRedirect || `/${username}`);
+ },
};
diff --git a/src/routes/(static)/login/+page.svelte b/src/routes/(static)/login/+page.svelte
index 2f67b48e..08694cd8 100644
--- a/src/routes/(static)/login/+page.svelte
+++ b/src/routes/(static)/login/+page.svelte
@@ -45,18 +45,23 @@
onMount(() => {
if (!isTor && recaptchaSiteKey) {
let s = document.createElement("script");
- s.src = "https://www.google.com/recaptcha/api.js?render=" + recaptchaSiteKey;
+ s.src =
+ "https://www.google.com/recaptcha/api.js?render=" + recaptchaSiteKey;
document.head.appendChild(s);
}
});
- let cancel: any = () => { need2fa = false; };
+ let cancel: any = () => {
+ need2fa = false;
+ };
let username: string | undefined = $state(),
email: any,
btn: HTMLButtonElement = $state() as any;
- $effect(() => { if (form) ({ username, password: $password } = form); });
+ $effect(() => {
+ if (form) ({ username, password: $password } = form);
+ });
let need2fa = $derived(form?.message === "2fa");
$effect(() => {
if (need2fa && form?.token === token) token = "";
@@ -67,7 +72,8 @@
const getRecaptchaToken = () =>
new Promise((resolve, reject) => {
if (isTor || !recaptchaSiteKey) return resolve("");
- if (!browser || !grecaptcha) return reject(new Error("captcha unavailable"));
+ if (!browser || !grecaptcha)
+ return reject(new Error("captcha unavailable"));
grecaptcha.ready(() => {
grecaptcha
.execute(recaptchaSiteKey, { action: "login" })
diff --git a/src/routes/(static)/login/[token]/+page.server.ts b/src/routes/(static)/login/[token]/+page.server.ts
index 8fe49578..f2750036 100644
--- a/src/routes/(static)/login/[token]/+page.server.ts
+++ b/src/routes/(static)/login/[token]/+page.server.ts
@@ -1,13 +1,13 @@
import { redirect } from "@sveltejs/kit";
export const load = async ({ cookies, params }) => {
- const { token } = params;
- const maxAge = 380 * 24 * 60 * 60;
+ const { token } = params;
+ const maxAge = 380 * 24 * 60 * 60;
- const expires = new Date();
- expires.setSeconds(expires.getSeconds() + maxAge);
+ const expires = new Date();
+ expires.setSeconds(expires.getSeconds() + maxAge);
- const opts = { path: "/", expires };
- cookies.set("token", token, opts);
- redirect(307, "/login");
+ const opts = { path: "/", expires };
+ cookies.set("token", token, opts);
+ redirect(307, "/login");
};
diff --git a/src/routes/(static)/register/+page.server.ts b/src/routes/(static)/register/+page.server.ts
index 2bcf6f2d..7fde82aa 100644
--- a/src/routes/(static)/register/+page.server.ts
+++ b/src/routes/(static)/register/+page.server.ts
@@ -2,25 +2,25 @@ import { fd, get, register } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export const load = async ({ parent }) => {
- const { user } = await parent();
- if (user) redirect(307, `/${user.username}`);
+ const { user } = await parent();
+ if (user) redirect(307, `/${user.username}`);
- const index = Math.floor(Math.random() * 64) + 1;
- const { challenge } = await get("/challenge");
+ const index = Math.floor(Math.random() * 64) + 1;
+ const { challenge } = await get("/challenge");
- return { index, challenge };
+ return { index, challenge };
};
export const actions = {
- default: async ({ cookies, request }) => {
- const ip = request.headers.get("cf-connecting-ip");
- const host = request.headers.get("host");
- const form = await fd(request);
- const { picture, username, password, challenge, recaptcha } = form;
- let { loginRedirect } = form;
- if (loginRedirect === "undefined") loginRedirect = undefined;
+ default: async ({ cookies, request }) => {
+ const ip = request.headers.get("cf-connecting-ip");
+ const host = request.headers.get("host");
+ const form = await fd(request);
+ const { picture, username, password, challenge, recaptcha } = form;
+ let { loginRedirect } = form;
+ if (loginRedirect === "undefined") loginRedirect = undefined;
- const user = { picture, username, password, challenge, recaptcha };
- return register(user, ip, cookies, loginRedirect, host);
- },
+ const user = { picture, username, password, challenge, recaptcha };
+ return register(user, ip, cookies, loginRedirect, host);
+ },
};
diff --git a/src/routes/(static)/register/+page.svelte b/src/routes/(static)/register/+page.svelte
index 29aac7df..0200b15b 100644
--- a/src/routes/(static)/register/+page.svelte
+++ b/src/routes/(static)/register/+page.svelte
@@ -34,7 +34,8 @@
onMount(() => {
if (!isTor && recaptchaSiteKey) {
let s = document.createElement("script");
- s.src = "https://www.google.com/recaptcha/api.js?render=" + recaptchaSiteKey;
+ s.src =
+ "https://www.google.com/recaptcha/api.js?render=" + recaptchaSiteKey;
document.head.appendChild(s);
}
});
@@ -97,7 +98,9 @@
let code: any[] = [];
let redirect: any;
- let cancel: any = () => { need2fa = false; };
+ let cancel: any = () => {
+ need2fa = false;
+ };
let email: any,
btn: HTMLButtonElement = $state() as any;
@@ -106,7 +109,8 @@
const getRecaptchaToken = () =>
new Promise((resolve, reject) => {
if (isTor) return resolve("");
- if (!browser || !grecaptcha) return reject(new Error("captcha unavailable"));
+ if (!browser || !grecaptcha)
+ return reject(new Error("captcha unavailable"));
grecaptcha.ready(() => {
grecaptcha
.execute(recaptchaSiteKey, { action: "register" })
@@ -141,7 +145,11 @@
if ($avatar) {
try {
let { hash } = JSON.parse(
- await upload(($avatar as any).file, ($avatar as any).type, ($avatar as any).progress) as string,
+ (await upload(
+ ($avatar as any).file,
+ ($avatar as any).type,
+ ($avatar as any).progress,
+ )) as string,
);
let url = `${$page.url.origin}/api/public/${hash}.webp`;
diff --git a/src/routes/(static)/support/+page.svelte b/src/routes/(static)/support/+page.svelte
index c82a6cf9..dd5439d5 100644
--- a/src/routes/(static)/support/+page.svelte
+++ b/src/routes/(static)/support/+page.svelte
@@ -3,7 +3,8 @@
import { browser } from "$app/environment";
import { onDestroy, onMount } from "svelte";
import { fail, success, post } from "$lib/utils";
- import { scale } from "svelte/transition"; import { t } from "$lib/translations";
+ import { scale } from "svelte/transition";
+ import { t } from "$lib/translations";
let { data } = $props();
let user = $derived(data.user);
@@ -22,7 +23,8 @@
onMount(() => {
if (!isTor && recaptchaSiteKey) {
let s = document.createElement("script");
- s.src = "https://www.google.com/recaptcha/api.js?render=" + recaptchaSiteKey;
+ s.src =
+ "https://www.google.com/recaptcha/api.js?render=" + recaptchaSiteKey;
document.head.appendChild(s);
}
});
@@ -117,11 +119,7 @@
<label for="message" class="font-semibold"
>{$t("user.support.message")}</label
>
- <textarea
- rows={5}
- name="message"
- bind:value={message}
- required
+ <textarea rows={5} name="message" bind:value={message} required
></textarea>
</div>
diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts
index c1f77695..9997183d 100644
--- a/src/routes/+layout.server.ts
+++ b/src/routes/+layout.server.ts
@@ -1,65 +1,65 @@
import {
- defaultLocale,
- loadTranslations,
- locales,
+ defaultLocale,
+ loadTranslations,
+ locales,
} from "$lib/translations/index";
import { auth, get, isInvalidTokenError, sleep } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export const load = async ({ cookies, request, url }) => {
- const { host, pathname } = url;
- let user;
- const token = cookies.get("token");
- if (token) {
- try {
- user = await get("/me", auth(cookies));
- } catch (e) {
- const { message } = e as Error;
- if (message.startsWith("Rate")) {
- await sleep(3000);
- try {
- user = await get("/me", auth(cookies));
- } catch (retryError) {
- if (isInvalidTokenError(retryError) && pathname !== "/logout") {
- redirect(307, "/logout");
- }
- throw retryError;
- }
- } else if (isInvalidTokenError(e) && pathname !== "/logout") {
- redirect(307, "/logout");
- } else {
- throw e;
- }
- }
- }
+ const { host, pathname } = url;
+ let user;
+ const token = cookies.get("token");
+ if (token) {
+ try {
+ user = await get("/me", auth(cookies));
+ } catch (e) {
+ const { message } = e as Error;
+ if (message.startsWith("Rate")) {
+ await sleep(3000);
+ try {
+ user = await get("/me", auth(cookies));
+ } catch (retryError) {
+ if (isInvalidTokenError(retryError) && pathname !== "/logout") {
+ redirect(307, "/logout");
+ }
+ throw retryError;
+ }
+ } else if (isInvalidTokenError(e) && pathname !== "/logout") {
+ redirect(307, "/logout");
+ } else {
+ throw e;
+ }
+ }
+ }
- // Try to get the locale from cookie
- let locale = user?.language || (cookies.get("lang") || "").toLowerCase();
+ // Try to get the locale from cookie
+ let locale = user?.language || (cookies.get("lang") || "").toLowerCase();
- // Get user preferred locale
- if (!locale) {
- locale = `${`${request.headers.get("accept-language")}`.match(
- /[a-zA-Z]+?(?=-|_|,|;)/,
- )}`.toLowerCase();
- }
+ // Get user preferred locale
+ if (!locale) {
+ locale = `${`${request.headers.get("accept-language")}`.match(
+ /[a-zA-Z]+?(?=-|_|,|;)/,
+ )}`.toLowerCase();
+ }
- // Get defined locales
- const supportedLocales = locales.get().map((l) => l.toLowerCase());
+ // Get defined locales
+ const supportedLocales = locales.get().map((l) => l.toLowerCase());
- // Use default locale if current locale is not supported
- if (!supportedLocales.includes(locale)) {
- locale = defaultLocale;
- }
+ // Use default locale if current locale is not supported
+ if (!supportedLocales.includes(locale)) {
+ locale = defaultLocale;
+ }
- await loadTranslations(locale, pathname); // keep this just before the `return`
+ await loadTranslations(locale, pathname); // keep this just before the `return`
- const theme = cookies.get("theme") || "light";
+ const theme = cookies.get("theme") || "light";
- return {
- theme,
- host,
- pathname,
- i18n: { locale, route: pathname },
- user,
- };
+ return {
+ theme,
+ host,
+ pathname,
+ i18n: { locale, route: pathname },
+ user,
+ };
};
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index b40b363a..88454d85 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -7,22 +7,21 @@
import { onMount } from "svelte";
import { installPrompt, theme as themeStore } from "$lib/store";
-
-const map = { light: 'lofi', dark: 'black', system: 'system' };
+ const map = { light: "lofi", dark: "black", system: "system" };
let { data, children } = $props();
let pathname = $derived(data.pathname);
let theme = $derived(data.theme);
$effect(() => ($themeStore = theme));
$effect(() => (theme = $themeStore));
-$effect(() => {
- const v = map[theme] ?? theme;
- if (!v || v === 'system') {
- document.documentElement.removeAttribute('data-theme');
- } else {
- document.documentElement.setAttribute('data-theme', v);
- }
-});
+ $effect(() => {
+ const v = map[theme] ?? theme;
+ if (!v || v === "system") {
+ document.documentElement.removeAttribute("data-theme");
+ } else {
+ document.documentElement.setAttribute("data-theme", v);
+ }
+ });
let host = PUBLIC_DOMAIN.includes("localhost")
? `http://${PUBLIC_DOMAIN}`
diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts
index af4a6a5c..1feee3e6 100644
--- a/src/routes/+layout.ts
+++ b/src/routes/+layout.ts
@@ -11,67 +11,67 @@ const opts = { path: "/", expires };
/** @type {import('@sveltejs/kit').Load} */
export const load = async ({ data }) => {
- const { i18n, translations } = data;
- const { locale, route } = i18n;
+ const { i18n, translations } = data;
+ const { locale, route } = i18n;
- addTranslations(translations);
+ addTranslations(translations);
- await setRoute(route);
- await setLocale(locale);
+ await setRoute(route);
+ await setLocale(locale);
- if (browser) {
- let theme = cookies.get("theme");
+ if (browser) {
+ let theme = cookies.get("theme");
- if (!theme) {
- theme = matchMedia("(prefers-color-scheme: dark)").matches
- ? "dark"
- : "light";
+ if (!theme) {
+ theme = matchMedia("(prefers-color-scheme: dark)").matches
+ ? "dark"
+ : "light";
- cookies.set("theme", theme, opts);
+ cookies.set("theme", theme, opts);
- if (theme === "dark") setTimeout(() => themeStore.set(theme), 100);
- }
- }
+ if (theme === "dark") setTimeout(() => themeStore.set(theme), 100);
+ }
+ }
};
addIcon("coinos:logo", {
- body: ' <svg width="224" height="72" viewBox="0 0 224 72" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M69.8823 36C69.8823 54.7127 54.7127 69.8823 36 69.8823C17.2873 69.8823 2.11764 54.7127 2.11764 36C2.11764 17.2873 17.2873 2.11761 36 2.11761C54.7127 2.11761 69.8823 17.2873 69.8823 36Z" /><path fill-rule="evenodd" clip-rule="evenodd" d="M36 4.23529C18.4568 4.23529 4.23529 18.4568 4.23529 36C4.23529 53.5432 18.4568 67.7647 36 67.7647C53.5432 67.7647 67.7647 53.5432 67.7647 36C67.7647 18.4568 53.5432 4.23529 36 4.23529ZM0 36C0 16.1177 16.1177 0 36 0C55.8823 0 72 16.1177 72 36C72 55.8823 55.8823 72 36 72C16.1177 72 0 55.8823 0 36Z" fill="currentColor"/><path fill-rule="evenodd" clip-rule="evenodd" d="M36 58.5882C48.4751 58.5882 58.5882 48.4751 58.5882 36C58.5882 23.5248 48.4751 13.4117 36 13.4117C23.5249 13.4117 13.4118 23.5248 13.4118 36C13.4118 48.4751 23.5249 58.5882 36 58.5882ZM36 54C45.9411 54 54 45.9411 54 36C54 26.0589 45.9411 18 36 18C26.0589 18 18 26.0589 18 36C18 45.9411 26.0589 54 36 54Z" fill="currentColor"/><path fill-rule="evenodd" clip-rule="evenodd" d="M36.0001 22.8988C36.0001 22.8988 36 22.8988 36 22.8988C28.7644 22.8988 22.8988 28.7644 22.8988 36C22.8988 43.2356 28.7644 49.1012 36 49.1012C36 49.1012 36.0001 49.1012 36.0001 49.1012V22.8988Z" fill="currentColor"/><path d="M97.608 27.704C99.544 27.704 101.248 28.088 102.72 28.856C104.192 29.624 105.368 30.688 106.248 32.048C107.144 33.408 107.68 34.952 107.856 36.68H102.864C102.752 35.928 102.48 35.216 102.048 34.544C101.616 33.856 101.032 33.304 100.296 32.888C99.56 32.456 98.672 32.24 97.632 32.24C95.776 32.24 94.264 32.928 93.096 34.304C91.944 35.68 91.368 37.792 91.368 40.64C91.368 43.264 91.92 45.352 93.024 46.904C94.128 48.456 95.704 49.232 97.752 49.232C98.776 49.232 99.648 49.008 100.368 48.56C101.104 48.096 101.68 47.528 102.096 46.856C102.528 46.168 102.808 45.48 102.936 44.792H107.784C107.64 46.472 107.112 47.968 106.2 49.28C105.304 50.592 104.12 51.624 102.648 52.376C101.192 53.112 99.512 53.48 97.608 53.48C95.336 53.48 93.312 52.984 91.536 51.992C89.776 50.984 88.392 49.528 87.384 47.624C86.376 45.704 85.872 43.392 85.872 40.688C85.872 38.112 86.344 35.856 87.288 33.92C88.232 31.968 89.584 30.448 91.344 29.36C93.104 28.256 95.192 27.704 97.608 27.704ZM122.09 53.48C119.722 53.48 117.658 52.976 115.898 51.968C114.138 50.944 112.77 49.48 111.794 47.576C110.834 45.672 110.354 43.384 110.354 40.712C110.354 38.12 110.818 35.848 111.746 33.896C112.69 31.944 114.042 30.424 115.802 29.336C117.562 28.248 119.666 27.704 122.114 27.704C124.482 27.704 126.538 28.224 128.282 29.264C130.026 30.304 131.37 31.792 132.314 33.728C133.274 35.664 133.754 37.992 133.754 40.712C133.754 43.224 133.298 45.44 132.386 47.36C131.49 49.264 130.17 50.76 128.426 51.848C126.698 52.936 124.586 53.48 122.09 53.48ZM122.114 49.04C123.458 49.04 124.562 48.672 125.426 47.936C126.306 47.2 126.954 46.192 127.37 44.912C127.802 43.632 128.018 42.176 128.018 40.544C128.018 39.024 127.826 37.624 127.442 36.344C127.074 35.064 126.45 34.04 125.57 33.272C124.706 32.488 123.554 32.096 122.114 32.096C120.754 32.096 119.626 32.456 118.73 33.176C117.85 33.88 117.186 34.872 116.738 36.152C116.306 37.416 116.09 38.88 116.09 40.544C116.09 42.048 116.282 43.448 116.666 44.744C117.066 46.024 117.706 47.064 118.586 47.864C119.466 48.648 120.642 49.04 122.114 49.04ZM143.518 28.184V53H137.902V28.184H143.518ZM143.59 18.32V23.84H137.806V18.32H143.59ZM149.367 53V28.184H155.079V31.736C155.463 31.096 155.983 30.48 156.639 29.888C157.311 29.296 158.135 28.816 159.111 28.448C160.087 28.08 161.231 27.896 162.543 27.896C164.079 27.896 165.503 28.2 166.815 28.808C168.143 29.416 169.207 30.368 170.007 31.664C170.823 32.96 171.231 34.632 171.231 36.68V53H165.375V37.376C165.375 35.744 164.927 34.536 164.031 33.752C163.135 32.952 162.007 32.552 160.647 32.552C159.719 32.552 158.839 32.712 158.007 33.032C157.175 33.336 156.495 33.808 155.967 34.448C155.455 35.072 155.199 35.856 155.199 36.8V53H149.367ZM186.348 53.48C183.98 53.48 181.916 52.976 180.156 51.968C178.396 50.944 177.028 49.48 176.052 47.576C175.092 45.672 174.612 43.384 174.612 40.712C174.612 38.12 175.076 35.848 176.004 33.896C176.948 31.944 178.3 30.424 180.06 29.336C181.82 28.248 183.924 27.704 186.372 27.704C188.74 27.704 190.796 28.224 192.54 29.264C194.284 30.304 195.628 31.792 196.572 33.728C197.532 35.664 198.012 37.992 198.012 40.712C198.012 43.224 197.556 45.44 196.644 47.36C195.748 49.264 194.428 50.76 192.684 51.848C190.956 52.936 188.844 53.48 186.348 53.48ZM186.372 49.04C187.716 49.04 188.82 48.672 189.684 47.936C190.564 47.2 191.212 46.192 191.628 44.912C192.06 43.632 192.276 42.176 192.276 40.544C192.276 39.024 192.084 37.624 191.7 36.344C191.332 35.064 190.708 34.04 189.828 33.272C188.964 32.488 187.812 32.096 186.372 32.096C185.012 32.096 183.884 32.456 182.988 33.176C182.108 33.88 181.444 34.872 180.996 36.152C180.564 37.416 180.348 38.88 180.348 40.544C180.348 42.048 180.54 43.448 180.924 44.744C181.324 46.024 181.964 47.064 182.844 47.864C183.724 48.648 184.9 49.04 186.372 49.04ZM210.995 53.48C209.267 53.48 207.627 53.208 206.075 52.664C204.539 52.104 203.243 51.232 202.187 50.048C201.147 48.864 200.491 47.336 200.219 45.464H205.355C205.579 46.376 205.971 47.12 206.531 47.696C207.107 48.272 207.787 48.696 208.571 48.968C209.355 49.224 210.155 49.352 210.971 49.352C212.459 49.352 213.659 49.096 214.571 48.584C215.499 48.072 215.963 47.28 215.963 46.208C215.963 45.424 215.707 44.8 215.195 44.336C214.683 43.872 213.867 43.52 212.747 43.28L208.019 42.2C205.923 41.736 204.235 40.968 202.955 39.896C201.691 38.824 201.051 37.312 201.035 35.36C201.019 33.888 201.387 32.576 202.139 31.424C202.891 30.272 204.011 29.368 205.499 28.712C206.987 28.04 208.827 27.704 211.019 27.704C213.915 27.704 216.235 28.352 217.979 29.648C219.723 30.928 220.619 32.76 220.667 35.144H215.699C215.523 34.072 215.019 33.24 214.187 32.648C213.355 32.04 212.275 31.736 210.947 31.736C209.571 31.736 208.443 32 207.563 32.528C206.683 33.056 206.243 33.864 206.243 34.952C206.243 35.704 206.579 36.296 207.251 36.728C207.923 37.16 208.931 37.528 210.275 37.832L214.739 38.912C216.019 39.232 217.067 39.664 217.883 40.208C218.699 40.752 219.339 41.352 219.803 42.008C220.267 42.648 220.587 43.312 220.763 44C220.955 44.672 221.051 45.296 221.051 45.872C221.051 47.472 220.635 48.84 219.803 49.976C218.987 51.096 217.827 51.96 216.323 52.568C214.819 53.176 213.043 53.48 210.995 53.48Z" fill="currentColor"/></svg>',
- width: 224,
- height: 72,
+ body: ' <svg width="224" height="72" viewBox="0 0 224 72" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M69.8823 36C69.8823 54.7127 54.7127 69.8823 36 69.8823C17.2873 69.8823 2.11764 54.7127 2.11764 36C2.11764 17.2873 17.2873 2.11761 36 2.11761C54.7127 2.11761 69.8823 17.2873 69.8823 36Z" /><path fill-rule="evenodd" clip-rule="evenodd" d="M36 4.23529C18.4568 4.23529 4.23529 18.4568 4.23529 36C4.23529 53.5432 18.4568 67.7647 36 67.7647C53.5432 67.7647 67.7647 53.5432 67.7647 36C67.7647 18.4568 53.5432 4.23529 36 4.23529ZM0 36C0 16.1177 16.1177 0 36 0C55.8823 0 72 16.1177 72 36C72 55.8823 55.8823 72 36 72C16.1177 72 0 55.8823 0 36Z" fill="currentColor"/><path fill-rule="evenodd" clip-rule="evenodd" d="M36 58.5882C48.4751 58.5882 58.5882 48.4751 58.5882 36C58.5882 23.5248 48.4751 13.4117 36 13.4117C23.5249 13.4117 13.4118 23.5248 13.4118 36C13.4118 48.4751 23.5249 58.5882 36 58.5882ZM36 54C45.9411 54 54 45.9411 54 36C54 26.0589 45.9411 18 36 18C26.0589 18 18 26.0589 18 36C18 45.9411 26.0589 54 36 54Z" fill="currentColor"/><path fill-rule="evenodd" clip-rule="evenodd" d="M36.0001 22.8988C36.0001 22.8988 36 22.8988 36 22.8988C28.7644 22.8988 22.8988 28.7644 22.8988 36C22.8988 43.2356 28.7644 49.1012 36 49.1012C36 49.1012 36.0001 49.1012 36.0001 49.1012V22.8988Z" fill="currentColor"/><path d="M97.608 27.704C99.544 27.704 101.248 28.088 102.72 28.856C104.192 29.624 105.368 30.688 106.248 32.048C107.144 33.408 107.68 34.952 107.856 36.68H102.864C102.752 35.928 102.48 35.216 102.048 34.544C101.616 33.856 101.032 33.304 100.296 32.888C99.56 32.456 98.672 32.24 97.632 32.24C95.776 32.24 94.264 32.928 93.096 34.304C91.944 35.68 91.368 37.792 91.368 40.64C91.368 43.264 91.92 45.352 93.024 46.904C94.128 48.456 95.704 49.232 97.752 49.232C98.776 49.232 99.648 49.008 100.368 48.56C101.104 48.096 101.68 47.528 102.096 46.856C102.528 46.168 102.808 45.48 102.936 44.792H107.784C107.64 46.472 107.112 47.968 106.2 49.28C105.304 50.592 104.12 51.624 102.648 52.376C101.192 53.112 99.512 53.48 97.608 53.48C95.336 53.48 93.312 52.984 91.536 51.992C89.776 50.984 88.392 49.528 87.384 47.624C86.376 45.704 85.872 43.392 85.872 40.688C85.872 38.112 86.344 35.856 87.288 33.92C88.232 31.968 89.584 30.448 91.344 29.36C93.104 28.256 95.192 27.704 97.608 27.704ZM122.09 53.48C119.722 53.48 117.658 52.976 115.898 51.968C114.138 50.944 112.77 49.48 111.794 47.576C110.834 45.672 110.354 43.384 110.354 40.712C110.354 38.12 110.818 35.848 111.746 33.896C112.69 31.944 114.042 30.424 115.802 29.336C117.562 28.248 119.666 27.704 122.114 27.704C124.482 27.704 126.538 28.224 128.282 29.264C130.026 30.304 131.37 31.792 132.314 33.728C133.274 35.664 133.754 37.992 133.754 40.712C133.754 43.224 133.298 45.44 132.386 47.36C131.49 49.264 130.17 50.76 128.426 51.848C126.698 52.936 124.586 53.48 122.09 53.48ZM122.114 49.04C123.458 49.04 124.562 48.672 125.426 47.936C126.306 47.2 126.954 46.192 127.37 44.912C127.802 43.632 128.018 42.176 128.018 40.544C128.018 39.024 127.826 37.624 127.442 36.344C127.074 35.064 126.45 34.04 125.57 33.272C124.706 32.488 123.554 32.096 122.114 32.096C120.754 32.096 119.626 32.456 118.73 33.176C117.85 33.88 117.186 34.872 116.738 36.152C116.306 37.416 116.09 38.88 116.09 40.544C116.09 42.048 116.282 43.448 116.666 44.744C117.066 46.024 117.706 47.064 118.586 47.864C119.466 48.648 120.642 49.04 122.114 49.04ZM143.518 28.184V53H137.902V28.184H143.518ZM143.59 18.32V23.84H137.806V18.32H143.59ZM149.367 53V28.184H155.079V31.736C155.463 31.096 155.983 30.48 156.639 29.888C157.311 29.296 158.135 28.816 159.111 28.448C160.087 28.08 161.231 27.896 162.543 27.896C164.079 27.896 165.503 28.2 166.815 28.808C168.143 29.416 169.207 30.368 170.007 31.664C170.823 32.96 171.231 34.632 171.231 36.68V53H165.375V37.376C165.375 35.744 164.927 34.536 164.031 33.752C163.135 32.952 162.007 32.552 160.647 32.552C159.719 32.552 158.839 32.712 158.007 33.032C157.175 33.336 156.495 33.808 155.967 34.448C155.455 35.072 155.199 35.856 155.199 36.8V53H149.367ZM186.348 53.48C183.98 53.48 181.916 52.976 180.156 51.968C178.396 50.944 177.028 49.48 176.052 47.576C175.092 45.672 174.612 43.384 174.612 40.712C174.612 38.12 175.076 35.848 176.004 33.896C176.948 31.944 178.3 30.424 180.06 29.336C181.82 28.248 183.924 27.704 186.372 27.704C188.74 27.704 190.796 28.224 192.54 29.264C194.284 30.304 195.628 31.792 196.572 33.728C197.532 35.664 198.012 37.992 198.012 40.712C198.012 43.224 197.556 45.44 196.644 47.36C195.748 49.264 194.428 50.76 192.684 51.848C190.956 52.936 188.844 53.48 186.348 53.48ZM186.372 49.04C187.716 49.04 188.82 48.672 189.684 47.936C190.564 47.2 191.212 46.192 191.628 44.912C192.06 43.632 192.276 42.176 192.276 40.544C192.276 39.024 192.084 37.624 191.7 36.344C191.332 35.064 190.708 34.04 189.828 33.272C188.964 32.488 187.812 32.096 186.372 32.096C185.012 32.096 183.884 32.456 182.988 33.176C182.108 33.88 181.444 34.872 180.996 36.152C180.564 37.416 180.348 38.88 180.348 40.544C180.348 42.048 180.54 43.448 180.924 44.744C181.324 46.024 181.964 47.064 182.844 47.864C183.724 48.648 184.9 49.04 186.372 49.04ZM210.995 53.48C209.267 53.48 207.627 53.208 206.075 52.664C204.539 52.104 203.243 51.232 202.187 50.048C201.147 48.864 200.491 47.336 200.219 45.464H205.355C205.579 46.376 205.971 47.12 206.531 47.696C207.107 48.272 207.787 48.696 208.571 48.968C209.355 49.224 210.155 49.352 210.971 49.352C212.459 49.352 213.659 49.096 214.571 48.584C215.499 48.072 215.963 47.28 215.963 46.208C215.963 45.424 215.707 44.8 215.195 44.336C214.683 43.872 213.867 43.52 212.747 43.28L208.019 42.2C205.923 41.736 204.235 40.968 202.955 39.896C201.691 38.824 201.051 37.312 201.035 35.36C201.019 33.888 201.387 32.576 202.139 31.424C202.891 30.272 204.011 29.368 205.499 28.712C206.987 28.04 208.827 27.704 211.019 27.704C213.915 27.704 216.235 28.352 217.979 29.648C219.723 30.928 220.619 32.76 220.667 35.144H215.699C215.523 34.072 215.019 33.24 214.187 32.648C213.355 32.04 212.275 31.736 210.947 31.736C209.571 31.736 208.443 32 207.563 32.528C206.683 33.056 206.243 33.864 206.243 34.952C206.243 35.704 206.579 36.296 207.251 36.728C207.923 37.16 208.931 37.528 210.275 37.832L214.739 38.912C216.019 39.232 217.067 39.664 217.883 40.208C218.699 40.752 219.339 41.352 219.803 42.008C220.267 42.648 220.587 43.312 220.763 44C220.955 44.672 221.051 45.296 221.051 45.872C221.051 47.472 220.635 48.84 219.803 49.976C218.987 51.096 217.827 51.96 216.323 52.568C214.819 53.176 213.043 53.48 210.995 53.48Z" fill="currentColor"/></svg>',
+ width: 224,
+ height: 72,
});
addIcon("coinos:rays", {
- body: '<svg width="158" height="60" viewBox="0 0 158 60" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M30.9439 8.95955C30.653 9.76766 32.7864 14.1314 36.4713 20.2731C49.1102 41.2516 47.4293 41.4455 49.7243 41.4455C52.181 41.4455 51.8254 40.5404 44.3262 26.641C36.2774 11.7394 32.0429 6.115 30.9439 8.95955Z" fill="currentColor"/><path d="M28.7782 44.8716C28.3579 45.2918 28.5842 45.6477 30.0711 47.2639C32.3015 49.6559 36.0188 50.6579 36.0188 48.8801C35.9865 47.4255 29.7156 43.9341 28.7782 44.8716Z" fill="currentColor"/><path d="M23.5093 55.2477C7.92899 50.0758 2.53086 48.7828 0.688371 49.8818C-0.830874 50.7546 0.0742067 51.4011 4.3087 52.4678C7.92902 53.3405 14.5232 55.3447 20.9881 57.5104C26.2892 59.2882 27.5175 59.4822 29.0044 58.9327C31.0409 58.1245 29.8449 57.3488 23.5093 55.2477Z" fill="currentColor"/><path d="M56.4801 1.16938C56.1892 1.94516 57.8378 9.31479 59.2924 13.8725C59.6479 14.9715 60.3591 17.8807 60.8763 20.3051C61.846 25.0244 62.0076 25.2833 63.8501 25.2833C65.5956 25.2833 65.5956 25.3477 63.4945 17.4605C59.8419 3.72268 57.5468 -1.61052 56.4801 1.16938Z" fill="currentColor"/><path d="M18.2728 35.0776C20.7618 37.3403 21.5376 39.3121 23.9295 39.3121C27.7761 39.3121 27.9377 39.0535 23.3477 34.4311C14.8464 25.8651 6.70073 19.9175 4.95522 21.0165C3.30668 22.1155 9.57757 26.0914 18.2728 35.0776Z" fill="currentColor"/><path d="M135.351 28.0309C137.808 25.9621 139.424 23.8287 139.424 22.665C139.424 21.0488 137.42 20.5636 135.707 21.8243C124.297 30.1316 112.757 42.2856 114.664 43.9341C116.539 45.5503 118.446 44.322 126.786 36.144C130.471 32.5559 134.317 28.9036 135.351 28.0309Z" fill="currentColor"/><path d="M90.2267 2.07445C89.2247 5.33921 88.1903 13.0324 84.1498 29.2915C83.3417 32.524 83.3417 32.5883 84.376 33.558C85.2165 34.3338 86.8327 34.6251 87.6408 34.1079C88.3196 33.6877 93.7178 11.0606 95.0107 3.27045C95.4633 0.231962 91.3581 -1.67517 90.2267 2.07445Z" fill="currentColor"/><path d="M149.93 41.4455C140.103 44.1931 122.196 51.4011 121.193 53.0496C120.482 54.181 123.359 55.28 125.299 54.6012L132.507 52.0152C143.594 48.0394 157.235 42.221 157.235 41.4775C157.203 39.9583 155.231 39.9586 149.93 41.4455Z" fill="currentColor"/><path d="M114.502 8.24841C113.953 9.18582 112.304 11.7394 107.326 18.6245C105.064 21.7277 101.314 28.1925 101.314 28.9683C101.314 30.5199 105.71 25.154 113.209 14.4224C114.826 12.095 116.442 9.92928 116.83 9.60603C118.575 8.02214 115.537 6.5029 114.502 8.24841Z" fill="currentColor"/></svg>',
- width: 158,
- height: 60,
+ body: '<svg width="158" height="60" viewBox="0 0 158 60" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M30.9439 8.95955C30.653 9.76766 32.7864 14.1314 36.4713 20.2731C49.1102 41.2516 47.4293 41.4455 49.7243 41.4455C52.181 41.4455 51.8254 40.5404 44.3262 26.641C36.2774 11.7394 32.0429 6.115 30.9439 8.95955Z" fill="currentColor"/><path d="M28.7782 44.8716C28.3579 45.2918 28.5842 45.6477 30.0711 47.2639C32.3015 49.6559 36.0188 50.6579 36.0188 48.8801C35.9865 47.4255 29.7156 43.9341 28.7782 44.8716Z" fill="currentColor"/><path d="M23.5093 55.2477C7.92899 50.0758 2.53086 48.7828 0.688371 49.8818C-0.830874 50.7546 0.0742067 51.4011 4.3087 52.4678C7.92902 53.3405 14.5232 55.3447 20.9881 57.5104C26.2892 59.2882 27.5175 59.4822 29.0044 58.9327C31.0409 58.1245 29.8449 57.3488 23.5093 55.2477Z" fill="currentColor"/><path d="M56.4801 1.16938C56.1892 1.94516 57.8378 9.31479 59.2924 13.8725C59.6479 14.9715 60.3591 17.8807 60.8763 20.3051C61.846 25.0244 62.0076 25.2833 63.8501 25.2833C65.5956 25.2833 65.5956 25.3477 63.4945 17.4605C59.8419 3.72268 57.5468 -1.61052 56.4801 1.16938Z" fill="currentColor"/><path d="M18.2728 35.0776C20.7618 37.3403 21.5376 39.3121 23.9295 39.3121C27.7761 39.3121 27.9377 39.0535 23.3477 34.4311C14.8464 25.8651 6.70073 19.9175 4.95522 21.0165C3.30668 22.1155 9.57757 26.0914 18.2728 35.0776Z" fill="currentColor"/><path d="M135.351 28.0309C137.808 25.9621 139.424 23.8287 139.424 22.665C139.424 21.0488 137.42 20.5636 135.707 21.8243C124.297 30.1316 112.757 42.2856 114.664 43.9341C116.539 45.5503 118.446 44.322 126.786 36.144C130.471 32.5559 134.317 28.9036 135.351 28.0309Z" fill="currentColor"/><path d="M90.2267 2.07445C89.2247 5.33921 88.1903 13.0324 84.1498 29.2915C83.3417 32.524 83.3417 32.5883 84.376 33.558C85.2165 34.3338 86.8327 34.6251 87.6408 34.1079C88.3196 33.6877 93.7178 11.0606 95.0107 3.27045C95.4633 0.231962 91.3581 -1.67517 90.2267 2.07445Z" fill="currentColor"/><path d="M149.93 41.4455C140.103 44.1931 122.196 51.4011 121.193 53.0496C120.482 54.181 123.359 55.28 125.299 54.6012L132.507 52.0152C143.594 48.0394 157.235 42.221 157.235 41.4775C157.203 39.9583 155.231 39.9586 149.93 41.4455Z" fill="currentColor"/><path d="M114.502 8.24841C113.953 9.18582 112.304 11.7394 107.326 18.6245C105.064 21.7277 101.314 28.1925 101.314 28.9683C101.314 30.5199 105.71 25.154 113.209 14.4224C114.826 12.095 116.442 9.92928 116.83 9.60603C118.575 8.02214 115.537 6.5029 114.502 8.24841Z" fill="currentColor"/></svg>',
+ width: 158,
+ height: 60,
});
addIcon("coinos:shield", {
- body: '<svg width="96" height="122" viewBox="0 0 96 122" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M36.9721 93.8449C34.3435 92.6292 33.6075 92.6292 33.187 93.7392C32.6087 95.272 38.2338 99.1835 41.1252 99.1835C44.0167 99.1835 41.4932 95.9063 36.9721 93.8449Z" fill="currentColor"/><path d="M20.5703 79.9963C19.3086 80.472 19.8869 81.6348 22.6732 84.172C27.2469 88.3477 29.8755 88.7177 27.8777 84.912C26.248 81.8991 22.3577 79.2563 20.5703 79.9963Z" fill="currentColor"/><path d="M15.523 67.6268C14.6818 70.7454 15.8384 73.8116 17.8361 73.8116C19.6761 73.8116 20.2544 69.054 18.7298 67.0983C17.8361 65.9354 15.8384 66.3054 15.523 67.6268Z" fill="currentColor"/><path d="M16.4172 25.3949C17.9943 21.272 15.6286 14.3478 13.4206 16.5678C12.7898 17.2021 13.0526 24.3377 13.7886 25.342C14.6298 26.452 15.9966 26.5049 16.4172 25.3949Z" fill="currentColor"/><path d="M17.5732 58.2712C18.7298 57.8484 18.5726 52.5627 17.3634 51.4527C15.3657 49.6027 14.6292 50.2898 14.6292 53.9898C14.6292 57.5312 15.6281 58.9584 17.5732 58.2712Z" fill="currentColor"/><path d="M16.8898 41.1987C17.5207 37.8158 16.2589 33.6406 14.6292 33.6406C13.7355 33.6406 13.6304 34.0101 13.6304 36.9701C13.5778 41.6215 16.1538 44.9515 16.8898 41.1987Z" fill="currentColor"/><path d="M77.5572 35.5959C76.8738 36.2831 77.1892 40.9874 78.0304 41.7802C82.4989 46.1674 80.7641 32.3188 77.5572 35.5959Z" fill="currentColor"/><path d="M81.395 67.2044C81.395 65.3016 78.9241 64.1387 77.8201 65.513C76.979 66.5173 77.347 69.6887 76.243 71.8559C75.4544 73.4416 75.7173 74.023 77.5047 74.5516C78.8716 74.9216 81.395 73.5473 81.395 67.2044Z" fill="currentColor"/><path d="M79.555 26.7684C81.3424 26.7684 81.6052 26.1341 81.1847 22.2227C80.659 17.0958 77.8201 15.2455 76.7161 19.2627C75.4544 23.7027 76.611 26.7684 79.555 26.7684Z" fill="currentColor"/><path d="M94.2229 8.84999C93.8023 2.08427 87.3355 0.12898 80.659 0.0232653C62.9949 -0.293878 67.6218 2.71898 5.90264 3.72327C2.59064 3.77612 1.43386 3.51173 0.960713 7.05316C0.802999 8.32173 2.22232 55.417 2.69546 69.107C3.01089 78.6213 3.79941 77.0356 8.11027 82.427C12.6841 88.1356 22.0944 100.028 38.6018 117.048C49.2738 128.043 58.2635 118.212 93.0658 77.459C93.9595 76.4018 94.4852 75.1333 94.5378 73.759C95.3264 59.4876 95.5898 30.3627 94.2229 8.84999ZM90.3321 73.019C90.2795 73.0718 52.376 116.943 49.0115 116.943C47.8023 116.943 33.6601 104.68 25.4064 95.219C18.9401 87.819 13.8407 82.7447 9.8978 78.7804C8.89895 77.7761 8.32092 76.4542 8.26835 75.027C7.90035 63.9799 6.27027 15.0343 6.27027 14.9286C5.42913 8.47999 5.11365 8.5858 27.0361 8.69152C58.8418 8.90295 66.5698 5.67877 89.5961 5.8902C89.5435 49.709 91.9618 72.0676 90.3321 73.019Z" fill="currentColor"/><path d="M70.1447 80.2073C68.7252 81.3702 66.1492 85.0174 66.1492 85.9159C66.1492 87.8188 70.9858 85.3345 72.7207 82.5859C74.8235 79.1502 73.2464 77.6702 70.1447 80.2073Z" fill="currentColor"/><path d="M54.6361 96.0114C51.7446 99.5 51.64 99.7114 52.5863 100.663C54.1109 102.196 61.2601 96.4877 60.7869 94.1091C60.3664 91.6777 57.5275 92.5228 54.6361 96.0114Z" fill="currentColor"/><path d="M78.8715 59.1699C80.6064 59.8042 81.6058 55.1004 80.2915 52.6161C79.5029 51.189 77.347 51.2941 76.979 52.827C76.1904 55.9984 76.9264 58.4299 78.8715 59.1699Z" fill="currentColor"/></svg>',
- width: 96,
- height: 122,
+ body: '<svg width="96" height="122" viewBox="0 0 96 122" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M36.9721 93.8449C34.3435 92.6292 33.6075 92.6292 33.187 93.7392C32.6087 95.272 38.2338 99.1835 41.1252 99.1835C44.0167 99.1835 41.4932 95.9063 36.9721 93.8449Z" fill="currentColor"/><path d="M20.5703 79.9963C19.3086 80.472 19.8869 81.6348 22.6732 84.172C27.2469 88.3477 29.8755 88.7177 27.8777 84.912C26.248 81.8991 22.3577 79.2563 20.5703 79.9963Z" fill="currentColor"/><path d="M15.523 67.6268C14.6818 70.7454 15.8384 73.8116 17.8361 73.8116C19.6761 73.8116 20.2544 69.054 18.7298 67.0983C17.8361 65.9354 15.8384 66.3054 15.523 67.6268Z" fill="currentColor"/><path d="M16.4172 25.3949C17.9943 21.272 15.6286 14.3478 13.4206 16.5678C12.7898 17.2021 13.0526 24.3377 13.7886 25.342C14.6298 26.452 15.9966 26.5049 16.4172 25.3949Z" fill="currentColor"/><path d="M17.5732 58.2712C18.7298 57.8484 18.5726 52.5627 17.3634 51.4527C15.3657 49.6027 14.6292 50.2898 14.6292 53.9898C14.6292 57.5312 15.6281 58.9584 17.5732 58.2712Z" fill="currentColor"/><path d="M16.8898 41.1987C17.5207 37.8158 16.2589 33.6406 14.6292 33.6406C13.7355 33.6406 13.6304 34.0101 13.6304 36.9701C13.5778 41.6215 16.1538 44.9515 16.8898 41.1987Z" fill="currentColor"/><path d="M77.5572 35.5959C76.8738 36.2831 77.1892 40.9874 78.0304 41.7802C82.4989 46.1674 80.7641 32.3188 77.5572 35.5959Z" fill="currentColor"/><path d="M81.395 67.2044C81.395 65.3016 78.9241 64.1387 77.8201 65.513C76.979 66.5173 77.347 69.6887 76.243 71.8559C75.4544 73.4416 75.7173 74.023 77.5047 74.5516C78.8716 74.9216 81.395 73.5473 81.395 67.2044Z" fill="currentColor"/><path d="M79.555 26.7684C81.3424 26.7684 81.6052 26.1341 81.1847 22.2227C80.659 17.0958 77.8201 15.2455 76.7161 19.2627C75.4544 23.7027 76.611 26.7684 79.555 26.7684Z" fill="currentColor"/><path d="M94.2229 8.84999C93.8023 2.08427 87.3355 0.12898 80.659 0.0232653C62.9949 -0.293878 67.6218 2.71898 5.90264 3.72327C2.59064 3.77612 1.43386 3.51173 0.960713 7.05316C0.802999 8.32173 2.22232 55.417 2.69546 69.107C3.01089 78.6213 3.79941 77.0356 8.11027 82.427C12.6841 88.1356 22.0944 100.028 38.6018 117.048C49.2738 128.043 58.2635 118.212 93.0658 77.459C93.9595 76.4018 94.4852 75.1333 94.5378 73.759C95.3264 59.4876 95.5898 30.3627 94.2229 8.84999ZM90.3321 73.019C90.2795 73.0718 52.376 116.943 49.0115 116.943C47.8023 116.943 33.6601 104.68 25.4064 95.219C18.9401 87.819 13.8407 82.7447 9.8978 78.7804C8.89895 77.7761 8.32092 76.4542 8.26835 75.027C7.90035 63.9799 6.27027 15.0343 6.27027 14.9286C5.42913 8.47999 5.11365 8.5858 27.0361 8.69152C58.8418 8.90295 66.5698 5.67877 89.5961 5.8902C89.5435 49.709 91.9618 72.0676 90.3321 73.019Z" fill="currentColor"/><path d="M70.1447 80.2073C68.7252 81.3702 66.1492 85.0174 66.1492 85.9159C66.1492 87.8188 70.9858 85.3345 72.7207 82.5859C74.8235 79.1502 73.2464 77.6702 70.1447 80.2073Z" fill="currentColor"/><path d="M54.6361 96.0114C51.7446 99.5 51.64 99.7114 52.5863 100.663C54.1109 102.196 61.2601 96.4877 60.7869 94.1091C60.3664 91.6777 57.5275 92.5228 54.6361 96.0114Z" fill="currentColor"/><path d="M78.8715 59.1699C80.6064 59.8042 81.6058 55.1004 80.2915 52.6161C79.5029 51.189 77.347 51.2941 76.979 52.827C76.1904 55.9984 76.9264 58.4299 78.8715 59.1699Z" fill="currentColor"/></svg>',
+ width: 96,
+ height: 122,
});
addIcon("coinos:hand", {
- body: '<svg width="106" height="100" viewBox="0 0 106 100" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M79.11 1.52264C73.8346 3.89945 70.9939 8.53715 70.5881 15.3777C70.0664 24.5371 67.9794 27.6676 65.6026 22.914C56.9649 5.87048 27.2838 1.05889 24.2693 16.2473C23.9215 17.8705 23.8634 17.8705 20.0953 17.8705C3.5156 17.7545 -6.04939 50.3922 5.83467 66.5661C6.64626 67.6676 5.48684 71.5516 2.06655 79.1459C0.153509 83.3777 0.385336 84.0734 3.74766 85.5806C6.82012 86.9719 7.80568 85.5227 13.9506 70.4502C14.8781 68.1893 14.8781 65.6386 13.9506 63.3777C12.5593 60.0154 10.8781 56.3053 9.54476 53.8125C5.13896 45.1748 8.03757 33.0009 16.2695 25.6966C23.8057 19.0299 31.5158 24.5371 24.9071 31.8995C15.8056 41.9864 24.4432 54.2183 37.8345 50.2183C49.8345 46.6821 50.2983 29.9284 38.4722 26.74C32.2114 25.0589 29.5446 16.2473 34.2982 13.0589C46.1243 5.05889 60.849 21.4647 59.2838 40.9429C58.4722 51.0879 68.6752 46.4502 68.6752 39.4937C68.6752 37.6966 69.139 36.711 70.994 34.5661C74.9361 29.9864 76.7911 25.1748 77.6607 16.885C78.4723 9.23279 88.4433 2.85597 91.2839 8.18931C93.081 11.5516 90.2402 29.5226 87.0518 34.6821C84.5011 38.856 75.4576 49.1168 72.5591 51.0879C68.791 53.6386 69.197 55.8415 73.6608 56.5951C75.8637 56.9429 76.2115 56.827 80.3274 53.4067C90.5883 44.885 93.8347 40.7111 96.2695 32.7111C98.0086 27.0299 100.559 28.3053 100.617 34.2183C100.675 46.3343 87.9794 60.4792 75.8055 65.4647C72.907 66.6821 72.7331 68.0154 75.2258 69.8705C78.936 72.5951 85.5446 69.7546 93.1388 62.1603C97.8924 57.4067 98.1244 57.2908 97.6027 59.2038C94.7621 70.2183 85.6028 79.3198 73.9506 82.7401C66.2405 85.0009 59.0521 86.6241 53.6608 87.3197C52.9071 87.5516 48.3273 87.3777 44.5012 91.4357C38.878 97.4067 47.5158 102.16 50.4724 97.4067C52.6753 93.8125 53.3708 93.4647 57.6607 93.4067C61.8926 93.4067 62.1244 93.3488 74.1244 89.9864C84.3273 87.1459 90.3563 84.1893 94.7041 79.9575C103.864 70.9719 107.69 57.9864 102.936 51.7256C101.893 50.3343 101.892 50.2763 103.574 46.6241C106.994 39.3198 106.182 29.6966 101.661 24.2473C100.037 22.2763 99.9216 21.7545 99.7477 17.0009C99.5158 5.75453 88.3274 -2.65127 79.11 1.52264ZM37.5446 30.2763C42.3562 32.7111 39.5158 45.2908 33.8926 46.6821C31.9216 47.2038 23.1678 42.6821 30.0084 33.2328C33.1388 28.885 34.0664 28.4792 37.5446 30.2763Z" fill="currentColor"/></svg>',
- width: 106,
- height: 100,
+ body: '<svg width="106" height="100" viewBox="0 0 106 100" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M79.11 1.52264C73.8346 3.89945 70.9939 8.53715 70.5881 15.3777C70.0664 24.5371 67.9794 27.6676 65.6026 22.914C56.9649 5.87048 27.2838 1.05889 24.2693 16.2473C23.9215 17.8705 23.8634 17.8705 20.0953 17.8705C3.5156 17.7545 -6.04939 50.3922 5.83467 66.5661C6.64626 67.6676 5.48684 71.5516 2.06655 79.1459C0.153509 83.3777 0.385336 84.0734 3.74766 85.5806C6.82012 86.9719 7.80568 85.5227 13.9506 70.4502C14.8781 68.1893 14.8781 65.6386 13.9506 63.3777C12.5593 60.0154 10.8781 56.3053 9.54476 53.8125C5.13896 45.1748 8.03757 33.0009 16.2695 25.6966C23.8057 19.0299 31.5158 24.5371 24.9071 31.8995C15.8056 41.9864 24.4432 54.2183 37.8345 50.2183C49.8345 46.6821 50.2983 29.9284 38.4722 26.74C32.2114 25.0589 29.5446 16.2473 34.2982 13.0589C46.1243 5.05889 60.849 21.4647 59.2838 40.9429C58.4722 51.0879 68.6752 46.4502 68.6752 39.4937C68.6752 37.6966 69.139 36.711 70.994 34.5661C74.9361 29.9864 76.7911 25.1748 77.6607 16.885C78.4723 9.23279 88.4433 2.85597 91.2839 8.18931C93.081 11.5516 90.2402 29.5226 87.0518 34.6821C84.5011 38.856 75.4576 49.1168 72.5591 51.0879C68.791 53.6386 69.197 55.8415 73.6608 56.5951C75.8637 56.9429 76.2115 56.827 80.3274 53.4067C90.5883 44.885 93.8347 40.7111 96.2695 32.7111C98.0086 27.0299 100.559 28.3053 100.617 34.2183C100.675 46.3343 87.9794 60.4792 75.8055 65.4647C72.907 66.6821 72.7331 68.0154 75.2258 69.8705C78.936 72.5951 85.5446 69.7546 93.1388 62.1603C97.8924 57.4067 98.1244 57.2908 97.6027 59.2038C94.7621 70.2183 85.6028 79.3198 73.9506 82.7401C66.2405 85.0009 59.0521 86.6241 53.6608 87.3197C52.9071 87.5516 48.3273 87.3777 44.5012 91.4357C38.878 97.4067 47.5158 102.16 50.4724 97.4067C52.6753 93.8125 53.3708 93.4647 57.6607 93.4067C61.8926 93.4067 62.1244 93.3488 74.1244 89.9864C84.3273 87.1459 90.3563 84.1893 94.7041 79.9575C103.864 70.9719 107.69 57.9864 102.936 51.7256C101.893 50.3343 101.892 50.2763 103.574 46.6241C106.994 39.3198 106.182 29.6966 101.661 24.2473C100.037 22.2763 99.9216 21.7545 99.7477 17.0009C99.5158 5.75453 88.3274 -2.65127 79.11 1.52264ZM37.5446 30.2763C42.3562 32.7111 39.5158 45.2908 33.8926 46.6821C31.9216 47.2038 23.1678 42.6821 30.0084 33.2328C33.1388 28.885 34.0664 28.4792 37.5446 30.2763Z" fill="currentColor"/></svg>',
+ width: 106,
+ height: 100,
});
addIcon("coinos:bolt", {
- body: '<svg width="96" height="121" viewBox="0 0 96 121" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M36.3513 0.537301C35.0349 1.04923 34.3767 1.7805 34.523 2.58495C34.7424 3.8282 7.90261 40.1019 1.02817 62.1147C-1.09267 68.9891 2.3447 69.9398 17.995 66.9414C27.5022 65.1131 27.1365 63.2117 20.8471 80.9098C16.1666 93.9273 12.7296 104.824 11.1206 111.479C8.92668 120.255 13.5339 124.862 24.9426 112.942C29.8425 107.822 40.9586 96.3407 66.9937 66.649C89.0797 41.4914 89.0064 42.1496 71.6009 41.4914L60.8506 41.0526C65.8968 35.714 84.7646 15.3831 90.5421 10.6295C96.3195 5.80278 98.1481 3.82826 90.396 2.73127C81.4008 1.41489 50.9776 0.902981 42.0555 0.0985249C40.0078 -0.120872 37.4483 0.098507 36.3513 0.537301ZM79.7186 7.92365L75.9156 11.0684C66.6278 18.6741 48.2717 40.5406 48.2717 43.9047C48.2717 47.5613 54.4149 47.1957 70.2846 47.1957C46.8823 74.3278 28.5991 95.463 28.1603 95.463C28.0141 95.463 29.6963 90.6364 31.9634 84.6395C40.4467 61.8953 40.8855 57.6536 34.8887 58.385C24.5039 59.6282 14.3385 61.0177 12.949 61.4565C11.7057 61.8222 12.51 59.8476 17.1905 51.0717C25.5276 35.1289 28.8917 30.5215 43.5181 6.16846C71.3816 7.41171 71.089 7.41172 79.7186 7.92365Z" fill="currentColor"/></svg>',
- width: 96,
- height: 121,
+ body: '<svg width="96" height="121" viewBox="0 0 96 121" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M36.3513 0.537301C35.0349 1.04923 34.3767 1.7805 34.523 2.58495C34.7424 3.8282 7.90261 40.1019 1.02817 62.1147C-1.09267 68.9891 2.3447 69.9398 17.995 66.9414C27.5022 65.1131 27.1365 63.2117 20.8471 80.9098C16.1666 93.9273 12.7296 104.824 11.1206 111.479C8.92668 120.255 13.5339 124.862 24.9426 112.942C29.8425 107.822 40.9586 96.3407 66.9937 66.649C89.0797 41.4914 89.0064 42.1496 71.6009 41.4914L60.8506 41.0526C65.8968 35.714 84.7646 15.3831 90.5421 10.6295C96.3195 5.80278 98.1481 3.82826 90.396 2.73127C81.4008 1.41489 50.9776 0.902981 42.0555 0.0985249C40.0078 -0.120872 37.4483 0.098507 36.3513 0.537301ZM79.7186 7.92365L75.9156 11.0684C66.6278 18.6741 48.2717 40.5406 48.2717 43.9047C48.2717 47.5613 54.4149 47.1957 70.2846 47.1957C46.8823 74.3278 28.5991 95.463 28.1603 95.463C28.0141 95.463 29.6963 90.6364 31.9634 84.6395C40.4467 61.8953 40.8855 57.6536 34.8887 58.385C24.5039 59.6282 14.3385 61.0177 12.949 61.4565C11.7057 61.8222 12.51 59.8476 17.1905 51.0717C25.5276 35.1289 28.8917 30.5215 43.5181 6.16846C71.3816 7.41171 71.089 7.41172 79.7186 7.92365Z" fill="currentColor"/></svg>',
+ width: 96,
+ height: 121,
});
addIcon("coinos:smile", {
- body: '<svg width="112" height="108" viewBox="0 0 112 108" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M108.05 39.1961L105.823 31.6789L108.329 28.4074C117.586 16.2267 100.394 -2.84494 86.7513 4.46352C85.2896 5.22917 83.5497 5.29877 81.0439 4.67233C76.45 3.48905 61.4154 0.983301 58.3528 0.635279C48.1905 -0.617602 50.9745 4.32429 55.3596 4.74192C65.2434 5.78598 65.0347 5.22916 62.3897 8.01334C58.283 12.3984 61.8329 29.5211 68.3757 36.9688C74.2921 43.7204 88.6307 47.3399 93.0853 43.1636C101.925 34.8111 99.489 73.5111 90.3708 85.3439C61.9722 122.304 2.11214 86.6664 12.9008 39.1961L14.1539 33.6278L19.3046 37.0384C28.2836 43.0244 31.9725 40.0314 25.0816 32.3749C13.8057 19.9157 17.6341 4.04587 29.4669 14.1385C33.4344 17.5491 38.3067 18.0364 40.3253 15.3218C46.3113 7.10848 49.8608 10.0319 49.7912 18.802C49.7912 23.5351 47.564 26.7369 38.4458 35.2287C30.4413 42.6763 30.0933 45.1821 37.0537 45.1821C41.7172 45.1821 56.8213 27.2938 58.1438 20.2637C60.0231 10.3799 46.6591 2.30578 38.7242 8.50058C36.9145 9.96227 35.801 10.2407 35.1049 9.54464C34.4089 8.8486 34.548 7.59569 36.7754 6.34281C39.0027 5.08993 42.4133 4.1155 41.6477 2.02737C40.6036 -0.756811 32.8775 2.8626 31.8334 3.48905C30.7893 4.04588 27.0307 6.48203 23.8289 6.48203C12.8314 6.48203 8.6551 9.82303 9.55996 17.8275C10.0472 22.2822 9.76891 23.5351 7.26315 27.9898C-12.2957 62.6529 14.1539 106.434 55.1509 107.269C96.844 108.244 119.744 78.6619 108.05 39.1961ZM93.9901 31.9573C86.4728 40.3098 85.3592 40.6578 79.1644 37.0384C74.2225 34.115 70.1854 26.5281 69.3501 18.5236C68.5149 10.1015 72.8304 7.87413 80.2085 12.8856L83.8281 15.3914L87.4473 13.0249C97.8184 6.13402 111.461 12.6072 93.9901 31.9573Z" fill="currentColor"/><path d="M21.6716 54.7179C22.1588 56.1796 23.2028 61.0519 24.038 65.5762C30.2328 99.3344 84.3853 98.7079 87.1694 64.8802C87.5175 60.7039 88.283 57.0149 88.8399 56.6668C93.7122 53.5346 80.6962 49.3584 71.5084 51.1681C68.6546 51.7249 57.7267 51.8641 44.7107 51.5161C20.6276 50.8201 20.4883 50.82 21.6716 54.7179ZM80.6964 57.0149V62.1656C80.6964 81.3068 46.5203 91.8171 35.1748 76.0865C31.2769 70.7269 31.3466 67.4555 30.7898 57.3629C62.8079 56.3188 63.5737 56.458 80.6964 57.0149Z" fill="currentColor"/></svg>',
- width: 112,
- height: 108,
+ body: '<svg width="112" height="108" viewBox="0 0 112 108" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M108.05 39.1961L105.823 31.6789L108.329 28.4074C117.586 16.2267 100.394 -2.84494 86.7513 4.46352C85.2896 5.22917 83.5497 5.29877 81.0439 4.67233C76.45 3.48905 61.4154 0.983301 58.3528 0.635279C48.1905 -0.617602 50.9745 4.32429 55.3596 4.74192C65.2434 5.78598 65.0347 5.22916 62.3897 8.01334C58.283 12.3984 61.8329 29.5211 68.3757 36.9688C74.2921 43.7204 88.6307 47.3399 93.0853 43.1636C101.925 34.8111 99.489 73.5111 90.3708 85.3439C61.9722 122.304 2.11214 86.6664 12.9008 39.1961L14.1539 33.6278L19.3046 37.0384C28.2836 43.0244 31.9725 40.0314 25.0816 32.3749C13.8057 19.9157 17.6341 4.04587 29.4669 14.1385C33.4344 17.5491 38.3067 18.0364 40.3253 15.3218C46.3113 7.10848 49.8608 10.0319 49.7912 18.802C49.7912 23.5351 47.564 26.7369 38.4458 35.2287C30.4413 42.6763 30.0933 45.1821 37.0537 45.1821C41.7172 45.1821 56.8213 27.2938 58.1438 20.2637C60.0231 10.3799 46.6591 2.30578 38.7242 8.50058C36.9145 9.96227 35.801 10.2407 35.1049 9.54464C34.4089 8.8486 34.548 7.59569 36.7754 6.34281C39.0027 5.08993 42.4133 4.1155 41.6477 2.02737C40.6036 -0.756811 32.8775 2.8626 31.8334 3.48905C30.7893 4.04588 27.0307 6.48203 23.8289 6.48203C12.8314 6.48203 8.6551 9.82303 9.55996 17.8275C10.0472 22.2822 9.76891 23.5351 7.26315 27.9898C-12.2957 62.6529 14.1539 106.434 55.1509 107.269C96.844 108.244 119.744 78.6619 108.05 39.1961ZM93.9901 31.9573C86.4728 40.3098 85.3592 40.6578 79.1644 37.0384C74.2225 34.115 70.1854 26.5281 69.3501 18.5236C68.5149 10.1015 72.8304 7.87413 80.2085 12.8856L83.8281 15.3914L87.4473 13.0249C97.8184 6.13402 111.461 12.6072 93.9901 31.9573Z" fill="currentColor"/><path d="M21.6716 54.7179C22.1588 56.1796 23.2028 61.0519 24.038 65.5762C30.2328 99.3344 84.3853 98.7079 87.1694 64.8802C87.5175 60.7039 88.283 57.0149 88.8399 56.6668C93.7122 53.5346 80.6962 49.3584 71.5084 51.1681C68.6546 51.7249 57.7267 51.8641 44.7107 51.5161C20.6276 50.8201 20.4883 50.82 21.6716 54.7179ZM80.6964 57.0149V62.1656C80.6964 81.3068 46.5203 91.8171 35.1748 76.0865C31.2769 70.7269 31.3466 67.4555 30.7898 57.3629C62.8079 56.3188 63.5737 56.458 80.6964 57.0149Z" fill="currentColor"/></svg>',
+ width: 112,
+ height: 108,
});
addIcon("coinos:symbol", {
- body: `<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M36 72C55.8823 72 72 55.8823 72 36C72 16.1177 55.8823 0 36 0C16.1177 0 0 16.1177 0 36C0 55.8823 16.1177 72 36 72ZM36 67.2C53.2313 67.2 67.2 53.2313 67.2 36C67.2 18.7687 53.2313 4.8 36 4.8C18.7687 4.8 4.8 18.7687 4.8 36C4.8 53.2313 18.7687 67.2 36 67.2Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M36.001 12.7998C36.0009 12.7998 36.0008 12.7998 36.0008 12.7998C23.1878 12.7998 12.8008 23.1868 12.8008 35.9998C12.8008 48.8128 23.1878 59.1998 36.0008 59.1998C36.0008 59.1998 36.0009 59.1998 36.001 59.1998V12.7998Z" fill="white"/></svg>`,
- width: 72,
- height: 72,
+ body: `<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M36 72C55.8823 72 72 55.8823 72 36C72 16.1177 55.8823 0 36 0C16.1177 0 0 16.1177 0 36C0 55.8823 16.1177 72 36 72ZM36 67.2C53.2313 67.2 67.2 53.2313 67.2 36C67.2 18.7687 53.2313 4.8 36 4.8C18.7687 4.8 4.8 18.7687 4.8 36C4.8 53.2313 18.7687 67.2 36 67.2Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M36.001 12.7998C36.0009 12.7998 36.0008 12.7998 36.0008 12.7998C23.1878 12.7998 12.8008 23.1868 12.8008 35.9998C12.8008 48.8128 23.1878 59.1998 36.0008 59.1998C36.0008 59.1998 36.0009 59.1998 36.001 59.1998V12.7998Z" fill="white"/></svg>`,
+ width: 72,
+ height: 72,
});
diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts
index 97184d3d..c6ef99ae 100644
--- a/src/routes/+page.server.ts
+++ b/src/routes/+page.server.ts
@@ -1,3 +1,3 @@
export const load = async () => {
- return { faqs: ["cost", "compatibility", "pos", "bitcoin"] };
+ return { faqs: ["cost", "compatibility", "pos", "bitcoin"] };
};
diff --git a/src/routes/about/+server.ts b/src/routes/about/+server.ts
index 7cc1b7e8..eb3d9729 100644
--- a/src/routes/about/+server.ts
+++ b/src/routes/about/+server.ts
@@ -1,5 +1,5 @@
import { redirect } from "@sveltejs/kit";
export async function GET() {
- redirect(307, "/#about");
+ redirect(307, "/#about");
}
diff --git a/src/routes/amber/[id]/[pubkey]/+server.ts b/src/routes/amber/[id]/[pubkey]/+server.ts
index 6a6f69cf..e0c67145 100644
--- a/src/routes/amber/[id]/[pubkey]/+server.ts
+++ b/src/routes/amber/[id]/[pubkey]/+server.ts
@@ -1,6 +1,6 @@
import { json } from "@sveltejs/kit";
export async function GET({ params }) {
- console.log(params);
- return json({});
+ console.log(params);
+ return json({});
}
diff --git a/src/routes/map/+page.server.ts b/src/routes/map/+page.server.ts
index b921cc22..c3b14d0f 100644
--- a/src/routes/map/+page.server.ts
+++ b/src/routes/map/+page.server.ts
@@ -1,11 +1,11 @@
import { get } from "$lib/utils";
export const load = async () => {
- let data = { locations: [] };
+ let data = { locations: [] };
- try {
- data = await get("/locations");
- } catch (e) {}
+ try {
+ data = await get("/locations");
+ } catch {}
- return data;
+ return data;
};
diff --git a/src/routes/map/+page.svelte b/src/routes/map/+page.svelte
index 61d7823c..49953479 100644
--- a/src/routes/map/+page.svelte
+++ b/src/routes/map/+page.svelte
@@ -1,4 +1,5 @@
-<script> import LocationsMap from "$comp/LocationsMap.svelte";
+<script>
+ import LocationsMap from "$comp/LocationsMap.svelte";
let { data } = $props();
let locations = $derived(data.locations);
diff --git a/src/routes/phtest/+page.svelte b/src/routes/phtest/+page.svelte
index 625f0465..f526d546 100644
--- a/src/routes/phtest/+page.svelte
+++ b/src/routes/phtest/+page.svelte
@@ -1 +1,3 @@
-<a href="bitcoin:lnurl1dp68gurn8ghj7cm0d9hx7uewd9hj7up0v9kxjcm9lgkapg">Bitcoin link</a>
+<a href="bitcoin:lnurl1dp68gurn8ghj7cm0d9hx7uewd9hj7up0v9kxjcm9lgkapg"
+ >Bitcoin link</a
+>
diff --git a/src/routes/start/+server.ts b/src/routes/start/+server.ts
index b80fc762..d31d1b3d 100644
--- a/src/routes/start/+server.ts
+++ b/src/routes/start/+server.ts
@@ -1,12 +1,12 @@
import { redirect } from "@sveltejs/kit";
export async function GET({ cookies }) {
- const pathname = cookies.get("pathname");
- const username = cookies.get("username");
- if (username) {
- if (pathname) redirect(307, pathname);
- else redirect(307, `/${username}/receive`);
- }
+ const pathname = cookies.get("pathname");
+ const username = cookies.get("username");
+ if (username) {
+ if (pathname) redirect(307, pathname);
+ else redirect(307, `/${username}/receive`);
+ }
- redirect(307, "/");
+ redirect(307, "/");
}
diff --git a/src/routes/test/ark/send/+server.ts b/src/routes/test/ark/send/+server.ts
index b077c793..8562c6b1 100644
--- a/src/routes/test/ark/send/+server.ts
+++ b/src/routes/test/ark/send/+server.ts
@@ -5,72 +5,72 @@ import { error, json } from "@sveltejs/kit";
let walletPromise: Promise<any> | undefined;
const getWallet = async () => {
- if (!walletPromise) {
- const privateKey = env.ARK_SERVER_WALLET_PRIVATE_KEY;
- const arkServerUrl = env.ARK_SERVER_URL || "http://localhost:7070";
+ if (!walletPromise) {
+ const privateKey = env.ARK_SERVER_WALLET_PRIVATE_KEY;
+ const arkServerUrl = env.ARK_SERVER_URL || "http://localhost:7070";
- if (!privateKey) {
- throw new Error("ARK_SERVER_WALLET_PRIVATE_KEY is not configured");
- }
+ if (!privateKey) {
+ throw new Error("ARK_SERVER_WALLET_PRIVATE_KEY is not configured");
+ }
- const { SingleKey, Wallet } = await import("@arkade-os/sdk");
- const identity = SingleKey.fromHex(privateKey);
- walletPromise = Wallet.create({ identity, arkServerUrl });
- }
+ const { SingleKey, Wallet } = await import("@arkade-os/sdk");
+ const identity = SingleKey.fromHex(privateKey);
+ walletPromise = Wallet.create({ identity, arkServerUrl });
+ }
- return walletPromise;
+ return walletPromise;
};
export async function POST({ request, cookies, fetch }) {
- // Never expose this in production.
- if (env.NODE_ENV === "production") error(404, "Not found");
+ // Never expose this in production.
+ if (env.NODE_ENV === "production") error(404, "Not found");
- // Require explicit opt-in for local/integration test environments.
- if (env.ENABLE_E2E_TEST_ENDPOINTS !== "true") {
- error(404, "Not found");
- }
+ // Require explicit opt-in for local/integration test environments.
+ if (env.ENABLE_E2E_TEST_ENDPOINTS !== "true") {
+ error(404, "Not found");
+ }
- const expectedSecret = env.E2E_TEST_SECRET;
- const providedSecret = request.headers.get("x-test-secret");
- if (!expectedSecret || providedSecret !== expectedSecret) {
- error(401, "Unauthorized");
- }
+ const expectedSecret = env.E2E_TEST_SECRET;
+ const providedSecret = request.headers.get("x-test-secret");
+ if (!expectedSecret || providedSecret !== expectedSecret) {
+ error(401, "Unauthorized");
+ }
- const body = await request.json();
- const address = String(body?.address || "").trim();
- const amount = Number(body?.amount || 1000);
- const iid = typeof body?.iid === "string" ? body.iid : undefined;
+ const body = await request.json();
+ const address = String(body?.address || "").trim();
+ const amount = Number(body?.amount || 1000);
+ const iid = typeof body?.iid === "string" ? body.iid : undefined;
- if (!/^t?ark1[a-z0-9]+$/i.test(address)) {
- error(400, "Invalid ark address");
- }
+ if (!/^t?ark1[a-z0-9]+$/i.test(address)) {
+ error(400, "Invalid ark address");
+ }
- if (!Number.isInteger(amount) || amount <= 0 || amount > 1_000_000) {
- error(400, "Invalid amount");
- }
+ if (!Number.isInteger(amount) || amount <= 0 || amount > 1_000_000) {
+ error(400, "Invalid amount");
+ }
- const wallet = await getWallet();
- const txid = await wallet.sendBitcoin({ address, amount });
+ const wallet = await getWallet();
+ const txid = await wallet.sendBitcoin({ address, amount });
- // Optional: mark an Ark invoice as received right after send.
- if (iid) {
- const token = cookies.get("token");
- if (!token) error(401, "Missing auth token cookie");
+ // Optional: mark an Ark invoice as received right after send.
+ if (iid) {
+ const token = cookies.get("token");
+ if (!token) error(401, "Missing auth token cookie");
- const response = await fetch(`${PUBLIC_COINOS_URL}/ark/receive`, {
- method: "POST",
- headers: {
- "content-type": "application/json",
- accept: "application/json",
- authorization: `Bearer ${token}`,
- },
- body: JSON.stringify({ iid, amount, hash: txid }),
- });
+ const response = await fetch(`${PUBLIC_COINOS_URL}/ark/receive`, {
+ method: "POST",
+ headers: {
+ "content-type": "application/json",
+ accept: "application/json",
+ authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify({ iid, amount, hash: txid }),
+ });
- if (!response.ok) {
- error(response.status, await response.text());
- }
- }
+ if (!response.ok) {
+ error(response.status, await response.text());
+ }
+ }
- return json({ ok: true, txid, amount, address, iid: iid || null });
+ return json({ ok: true, txid, amount, address, iid: iid || null });
}
diff --git a/src/service-worker.js b/src/service-worker.js
index fa934333..383f62d0 100644
--- a/src/service-worker.js
+++ b/src/service-worker.js
@@ -1,37 +1,35 @@
-import { build, files, version } from "$service-worker";
-
-self.addEventListener("install", (event) => {});
-self.addEventListener("activate", (event) => {});
-self.addEventListener("fetch", (event) => {});
+self.addEventListener("install", () => {});
+self.addEventListener("activate", () => {});
+self.addEventListener("fetch", () => {});
self.addEventListener("push", (event) => {
- const { title, body, url } = event.data.json();
- const icon = "/images/icon.png";
- const badge = "/images/badge.png";
- self.registration.showNotification(title, {
- body,
- icon,
- badge,
- data: { url },
- });
+ const { title, body, url } = event.data.json();
+ const icon = "/images/icon.png";
+ const badge = "/images/badge.png";
+ self.registration.showNotification(title, {
+ body,
+ icon,
+ badge,
+ data: { url },
+ });
});
self.addEventListener("notificationclick", (event) => {
- event.notification.close();
+ event.notification.close();
- const url = event.notification.data.url || "/";
+ const url = event.notification.data.url || "/";
- event.waitUntil(
- clients
- .matchAll({ type: "window", includeUncontrolled: true })
- .then((clientList) => {
- for (const client of clientList) {
- if (client.url === url && "focus" in client) {
- return client.focus();
- }
- }
- if (clients.openWindow) {
- return clients.openWindow(url);
- }
- }),
- );
+ event.waitUntil(
+ clients
+ .matchAll({ type: "window", includeUncontrolled: true })
+ .then((clientList) => {
+ for (const client of clientList) {
+ if (client.url === url && "focus" in client) {
+ return client.focus();
+ }
+ }
+ if (clients.openWindow) {
+ return clients.openWindow(url);
+ }
+ }),
+ );
});