diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..5cda1d84
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,5 @@
+node_modules/
+.github/
+.vscode/
+build/
+yarn-error.log
\ No newline at end of file
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
new file mode 100644
index 00000000..648bbd07
--- /dev/null
+++ b/.eslintrc.cjs
@@ -0,0 +1,13 @@
+module.exports = {
+ extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
+ parser: "@typescript-eslint/parser",
+ plugins: ["@typescript-eslint"],
+ root: true,
+ ignorePatterns: ["build/"],
+ env: {
+ browser: true,
+ worker: true,
+ commonjs: true,
+ node: true,
+ },
+};
diff --git a/.github/workflows/eslint.yaml b/.github/workflows/eslint.yaml
new file mode 100644
index 00000000..af3ef571
--- /dev/null
+++ b/.github/workflows/eslint.yaml
@@ -0,0 +1,20 @@
+name: Linting
+on:
+ pull_request:
+ push:
+ branches: [main]
+jobs:
+ formatting:
+ timeout-minutes: 15
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16
+ - name: Install Dependencies
+ run: yarn install
+ - name: Check Eslint
+ run: yarn eslint
diff --git a/.github/workflows/formatting.yaml b/.github/workflows/formatting.yaml
new file mode 100644
index 00000000..849110cd
--- /dev/null
+++ b/.github/workflows/formatting.yaml
@@ -0,0 +1,18 @@
+name: Formatting
+on:
+ pull_request:
+jobs:
+ formatting:
+ timeout-minutes: 15
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16
+ - name: Install Dependencies
+ run: yarn install
+ - name: Check Formatting
+ run: yarn prettier --check .
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 00000000..567609b1
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1 @@
+build/
diff --git a/.prettierrc.json b/.prettierrc.json
index 0967ef42..e1280035 100644
--- a/.prettierrc.json
+++ b/.prettierrc.json
@@ -1 +1,5 @@
-{}
+{
+ "printWidth": 120,
+ "bracketSameLine": true,
+ "arrowParens": "avoid"
+}
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..e69de29b
diff --git a/d.ts b/d.ts
index 125a621e..8efeccf6 100644
--- a/d.ts
+++ b/d.ts
@@ -1,14 +1,28 @@
declare module "*.jpg" {
- const value: any;
+ const value: unknown;
export default value;
}
declare module "*.svg" {
- const value: any;
+ const value: unknown;
export default value;
}
declare module "*.webp" {
- const value: any;
+ const value: string;
export default value;
}
+
+declare module "light-bolt11-decoder" {
+ export function decode(pr?: string): ParsedInvoice;
+
+ export interface ParsedInvoice {
+ paymentRequest: string;
+ sections: Section[];
+ }
+
+ export interface Section {
+ name: string;
+ value: string | Uint8Array | number | undefined;
+ }
+}
diff --git a/package.json b/package.json
index a1266c3c..1c23b81d 100644
--- a/package.json
+++ b/package.json
@@ -56,7 +56,9 @@
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
- "generate-messages": "extract-messages -l=en,es,zh,ja -o src/translations -d en --flat true **/messages.js"
+ "generate-messages": "extract-messages -l=en,es,zh,ja -o src/translations -d en --flat true **/messages.js",
+ "format": "prettier --write .",
+ "eslint": "eslint ."
},
"eslintConfig": {
"extends": [
diff --git a/public/index.html b/public/index.html
index e8779ebf..1cbe83b2 100644
--- a/public/index.html
+++ b/public/index.html
@@ -3,16 +3,12 @@
-
+
+ content="default-src 'self'; child-src 'none'; worker-src 'self'; frame-src youtube.com www.youtube.com https://platform.twitter.com https://embed.tidal.com https://w.soundcloud.com https://www.mixcloud.com https://open.spotify.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; connect-src wss://* 'self' https://*; img-src * data:; font-src https://fonts.gstatic.com; media-src *; script-src 'self' https://static.cloudflareinsights.com https://platform.twitter.com https://embed.tidal.com;" />
diff --git a/src/Const.ts b/src/Const.ts
index 012f6e2e..a037de0d 100644
--- a/src/Const.ts
+++ b/src/Const.ts
@@ -18,14 +18,12 @@ export const VoidCatHost = "https://void.cat";
/**
* Kierans pubkey
*/
-export const KieranPubKey =
- "npub1v0lxxxxutpvrelsksy8cdhgfux9l6a42hsj2qzquu2zk7vc9qnkszrqj49";
+export const KieranPubKey = "npub1v0lxxxxutpvrelsksy8cdhgfux9l6a42hsj2qzquu2zk7vc9qnkszrqj49";
/**
* Official snort account
*/
-export const SnortPubKey =
- "npub1sn0rtcjcf543gj4wsg7fa59s700d5ztys5ctj0g69g2x6802npjqhjjtws";
+export const SnortPubKey = "npub1sn0rtcjcf543gj4wsg7fa59s700d5ztys5ctj0g69g2x6802npjqhjjtws";
/**
* Websocket re-connect timeout
@@ -49,9 +47,7 @@ export const DefaultRelays = new Map([
/**
* Default search relays
*/
-export const SearchRelays = new Map([
- ["wss://relay.nostr.band", { read: true, write: false }],
-]);
+export const SearchRelays = new Map([["wss://relay.nostr.band", { read: true, write: false }]]);
/**
* List of recommended follows for new users
@@ -83,17 +79,20 @@ export const RecommendedFollows = [
* Regex to match email address
*/
export const EmailRegex =
+ // eslint-disable-next-line no-useless-escape
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
/**
* Generic URL regex
*/
export const UrlRegex =
+ // eslint-disable-next-line no-useless-escape
/((?:http|ftp|https):\/\/(?:[\w+?\.\w+])+(?:[a-zA-Z0-9\~\!\@\#\$\%\^\&\*\(\)_\-\=\+\\\/\?\.\:\;\'\,]*)?)/i;
/**
* Extract file extensions regex
*/
+// eslint-disable-next-line no-useless-escape
export const FileExtensionRegex = /\.([\w]+)$/i;
/**
@@ -115,12 +114,12 @@ export const YoutubeUrlRegex =
/**
* Tweet Regex
*/
-export const TweetUrlRegex =
- /https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(?:es)?\/(\d+)/;
+export const TweetUrlRegex = /https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(?:es)?\/(\d+)/;
/**
* Hashtag regex
*/
+// eslint-disable-next-line no-useless-escape
export const HashtagRegex = /(#[^\s!@#$%^&*()=+.\/,\[{\]};:'"?><]+)/;
/**
@@ -131,15 +130,12 @@ export const TidalRegex = /tidal\.com\/(?:browse\/)?(\w+)\/([a-z0-9-]+)/i;
/**
* SoundCloud regex
*/
-export const SoundCloudRegex =
- /soundcloud\.com\/(?!live)([a-zA-Z0-9]+)\/([a-zA-Z0-9-]+)/;
+export const SoundCloudRegex = /soundcloud\.com\/(?!live)([a-zA-Z0-9]+)\/([a-zA-Z0-9-]+)/;
/**
* Mixcloud regex
*/
-export const MixCloudRegex =
- /mixcloud\.com\/(?!live)([a-zA-Z0-9]+)\/([a-zA-Z0-9-]+)/;
+export const MixCloudRegex = /mixcloud\.com\/(?!live)([a-zA-Z0-9]+)\/([a-zA-Z0-9-]+)/;
-export const SpotifyRegex =
- /open\.spotify\.com\/(track|album|playlist|episode)\/([a-zA-Z0-9]+)/;
+export const SpotifyRegex = /open\.spotify\.com\/(track|album|playlist|episode)\/([a-zA-Z0-9]+)/;
diff --git a/src/Db/index.ts b/src/Db/index.ts
index 59cf5fdf..89276478 100644
--- a/src/Db/index.ts
+++ b/src/Db/index.ts
@@ -28,11 +28,11 @@ export class SnortDB extends Dexie {
super(NAME);
this.version(VERSION)
.stores(STORES)
- .upgrade(async (tx) => {
+ .upgrade(async tx => {
await tx
.table("users")
.toCollection()
- .modify((user) => {
+ .modify(user => {
user.npub = hexToBech32("npub", user.pubkey);
});
});
diff --git a/src/Element/AsyncButton.tsx b/src/Element/AsyncButton.tsx
index d420aa37..59bdaf86 100644
--- a/src/Element/AsyncButton.tsx
+++ b/src/Element/AsyncButton.tsx
@@ -1,14 +1,19 @@
import { useState } from "react";
-export default function AsyncButton(props: any) {
+interface AsyncButtonProps extends React.ButtonHTMLAttributes {
+ onClick(e: React.MouseEvent): Promise | void;
+ children?: React.ReactNode;
+}
+
+export default function AsyncButton(props: AsyncButtonProps) {
const [loading, setLoading] = useState(false);
- async function handle(e: any) {
+ async function handle(e: React.MouseEvent) {
if (loading) return;
setLoading(true);
try {
if (typeof props.onClick === "function") {
- let f = props.onClick(e);
+ const f = props.onClick(e);
if (f instanceof Promise) {
await f;
}
@@ -19,12 +24,7 @@ export default function AsyncButton(props: any) {
}
return (
-