From f402ff04ab2fdd3d57b4233d50975bbdd40e737f Mon Sep 17 00:00:00 2001 From: Danny Morabito Date: Mon, 24 Feb 2025 21:48:11 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=A6=20Add=20Linux=20packaging=20(AppIm?= =?UTF-8?q?age/Flatpak/DEB)=20=F0=9F=A7=B9=20Minor=20Codebase=20cleanup=20?= =?UTF-8?q?=E2=9A=A1=20Implement=20automatic=20starting=20of=20the=20relay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + electron-builder.yaml | 29 +++++ electron.vite.config.ts | 51 ++++++++ package.json | 35 +++-- public/icon512x512.png | Bin 0 -> 82016 bytes src/components/InitialSetup.ts | 72 ++++------- src/components/MarkdownContent.ts | 44 ++++--- src/electron/main.ts | 77 +++++++++++ src/electron/preload.ts | 21 +++ src/electron/relayManager.ts | 207 ++++++++++++++++++++++++++++++ index.html => src/index.html | 2 +- src/main.ts | 20 ++- src/ndk.ts | 5 +- src/relayManager.d.ts | 21 +++ src/routes/Profile.ts | 1 - src/routes/router.ts | 6 +- src/utils/sleep.ts | 3 + tsconfig.json | 3 +- vite.config.ts | 39 ------ 19 files changed, 519 insertions(+), 119 deletions(-) create mode 100644 electron-builder.yaml create mode 100644 electron.vite.config.ts create mode 100644 public/icon512x512.png create mode 100644 src/electron/main.ts create mode 100644 src/electron/preload.ts create mode 100644 src/electron/relayManager.ts rename index.html => src/index.html (85%) create mode 100644 src/relayManager.d.ts create mode 100644 src/utils/sleep.ts delete mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore index 9569838..a8ab3fb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ logs node_modules dist +out +extras # Editor directories and files .vscode/* diff --git a/electron-builder.yaml b/electron-builder.yaml new file mode 100644 index 0000000..07cb06a --- /dev/null +++ b/electron-builder.yaml @@ -0,0 +1,29 @@ +appId: com.arx-ccn.eve +productName: Eve +executableName: Eve +icon: public/icon512x512.png +linux: + category: Network + target: + - AppImage + - flatpak + - deb + desktop: + desktopActions: {} + extraFiles: + - from: extras/linux/relay + to: usr/bin/eve-relay +flatpak: + runtimeVersion: "24.08" + license: "LICENSE" +directories: + buildResources: build +files: + - '!**/.vscode/*' + - '!src/*' + - '!electron.vite.config.{js,ts,mjs,cjs}' + - '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' + - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' + - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}' +asarUnpack: + - resources/** \ No newline at end of file diff --git a/electron.vite.config.ts b/electron.vite.config.ts new file mode 100644 index 0000000..ad64ea2 --- /dev/null +++ b/electron.vite.config.ts @@ -0,0 +1,51 @@ +import { fileURLToPath, URL } from "node:url"; +import { defineConfig, externalizeDepsPlugin } from "electron-vite"; +import { resolve } from "path"; + +export default defineConfig({ + main: { + plugins: [externalizeDepsPlugin()], + build: { + lib: { + entry: resolve(__dirname, "src/electron/main.ts"), + }, + }, + }, + preload: { + plugins: [externalizeDepsPlugin()], + build: { + lib: { + entry: resolve(__dirname, "src/electron/preload.ts"), + }, + }, + }, + renderer: { + root: resolve(__dirname, "src"), + build: { + target: "es2024", + rollupOptions: { + input: { + index: resolve(__dirname, "src/index.html"), + }, + }, + }, + resolve: { + alias: { + "@utils": fileURLToPath(new URL("./src/utils", import.meta.url)), + "@routes": fileURLToPath(new URL("./src/routes", import.meta.url)), + "@styles": fileURLToPath(new URL("./src/styles", import.meta.url)), + "@widgets": fileURLToPath( + new URL("./src/components/Widgets", import.meta.url) + ), + "@components": fileURLToPath( + new URL("./src/components", import.meta.url) + ), + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + }, + // server: { + // port: 5173, + // open: true, + // }, + }, +}); diff --git a/package.json b/package.json index d97f2db..5d57864 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,31 @@ { "name": "eve", - "private": true, - "version": "0.0.0", + "description": "Closed Community Networks", + "version": "0.0.1", "type": "module", - "browserslist": ["not dead"], + "license": "AGPL-3.0-only", + "browserslist": [ + "electron >= 22.0.0" + ], + "main": "./out/main/main.js", + "homepage": "https://arx-ccn.com/eve", + "author": { + "name": "arx-ccn", + "email": "developers@arx-ccn.com" + }, "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" + "build": "tsc && electron-vite build", + "build:linux": "bun run build && electron-builder --linux", + "start": "electron-vite preview", + "dev": "electron-vite dev", + "prebuild": "electron-vite build" }, "devDependencies": { - "@biomejs/biome": "1.9.4", + "@electron-toolkit/preload": "^3.0.1", + "@electron-toolkit/utils": "^4.0.0", + "electron-builder": "^25.1.8", + "electron-vite": "^3.0.0", + "electron": "^34.2.0", "@tsconfig/node22": "^22.0.0", "@types/markdown-it": "^14.1.2", "@types/node": "^22.10.2", @@ -21,11 +36,13 @@ }, "dependencies": { "@lit-labs/motion": "^1.0.8", + "@noble/ciphers": "^1.2.1", "@nostr-dev-kit/ndk": "^2.10.7", + "@nostr/tools": "npm:@jsr/nostr__tools", "@open-wc/lit-helpers": "^0.7.0", + "@std/encoding": "npm:@jsr/std__encoding", "iconify-icon": "^2.2.0", "lit": "^3.2.1", - "markdown-it": "^14.1.0", - "nostr-tools": "^2.10.4" + "markdown-it": "^14.1.0" } } diff --git a/public/icon512x512.png b/public/icon512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..02e81ef6d8fd0b0e11bdf3f4eeab6fa60bcad757 GIT binary patch literal 82016 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%0At(sBkKQ?^-TuPzpE>eqOuh9(*!_Te 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 literal 0 HcmV?d00001 diff --git a/src/components/InitialSetup.ts b/src/components/InitialSetup.ts index d15d389..414a086 100644 --- a/src/components/InitialSetup.ts +++ b/src/components/InitialSetup.ts @@ -1,12 +1,14 @@ import { LitElement, html, css } from "lit"; -import { customElement, property, query, state } from "lit/decorators.js"; +import { customElement, state } from "lit/decorators.js"; import { animate } from "@lit-labs/motion"; -import * as nostrTools from "nostr-tools/pure"; -import * as nip06 from "nostr-tools/nip06"; -import * as nip19 from "nostr-tools/nip19"; -import * as nip49 from "nostr-tools/nip49"; +import * as nostrTools from "@nostr/tools/pure"; +import * as nip06 from "@nostr/tools/nip06"; +import * as nip19 from "@nostr/tools/nip19"; +import * as nip49 from "@nostr/tools/nip49"; import { ndk, setSigner } from "@/ndk"; import { NDKEvent, NDKKind, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; +import { encodeBase64 } from "@std/encoding/base64"; +import { randomBytes } from "@noble/ciphers/webcrypto"; @customElement("arx-initial-setup") export class InitialSetup extends LitElement { @@ -17,6 +19,15 @@ export class InitialSetup extends LitElement { @state() private profileImage = ""; @state() private lightningAddress = ""; + get encryptionPassphrase() { + let encryptionPassphrase = localStorage.getItem("encryption_key"); + if (!encryptionPassphrase) { + encryptionPassphrase = encodeBase64(randomBytes(32)); + localStorage.setItem("encryption_key", encryptionPassphrase); + } + return encryptionPassphrase; + } + static override styles = css` :host { display: block; @@ -409,32 +420,9 @@ export class InitialSetup extends LitElement { `; } - private getSetupCode() { - const userAgent = navigator.userAgent.toLowerCase(); - if (userAgent.includes("mac")) { - return ` - mkdir -p ~/.config/arx/eve && cd ~/.config/arx/eve - echo "${this.seedPhrase}" > ccn.seed - launchctl load ~/Library/LaunchAgents/com.user.eve-relay.plist - launchctl start com.user.eve-relay - ` - .split("\n") - .map((x) => x.trim()) - .join("\n"); - } - - if (userAgent.includes("linux")) { - return ` - mkdir -p ~/.config/arx/eve && cd ~/.config/arx/eve - echo "${this.seedPhrase}" > ccn.seed - systemctl --user enable eve-relay.service - systemctl --user start eve-relay.service - ` - .split("\n") - .map((x) => x.trim()) - .join("\n"); - } - return "Unsupported OS"; + private async startRelay() { + await window.relay.writeSeed(this.seedPhrase); + await window.relay.start(this.encryptionPassphrase); } private renderPageThree() { @@ -446,11 +434,10 @@ export class InitialSetup extends LitElement { During this alpha phase, manual relay configuration is required. This process will be automated in future releases.

-

Open your terminal and run following commands:

-
-            ${this.getSetupCode()}
-          
+

Please press the button below to start the relay.

+

Having trouble? Our team is here to help if you encounter any issues. @@ -586,15 +573,11 @@ export class InitialSetup extends LitElement { } private async goToFinalStep() { - let encryptionPassphrase = localStorage.getItem("encryption_key"); - if (!encryptionPassphrase) { - encryptionPassphrase = - Math.random().toString(36).substring(2, 15) + - Math.random().toString(36).substring(2, 15); - localStorage.setItem("encryption_key", encryptionPassphrase); - } const randomPrivateKey = nostrTools.generateSecretKey(); - const encryptedNsec = nip49.encrypt(randomPrivateKey, encryptionPassphrase); + const encryptedNsec = nip49.encrypt( + randomPrivateKey, + this.encryptionPassphrase + ); const npub = nip19.npubEncode(nostrTools.getPublicKey(randomPrivateKey)); if (!this.lightningAddress) this.lightningAddress = `${npub}@npub.cash`; @@ -602,6 +585,7 @@ export class InitialSetup extends LitElement { localStorage.setItem("ncryptsec", encryptedNsec); setSigner(new NDKPrivateKeySigner(randomPrivateKey)); + await ndk.connect(5000); const event = new NDKEvent(ndk); event.kind = NDKKind.Metadata; diff --git a/src/components/MarkdownContent.ts b/src/components/MarkdownContent.ts index 20b2c62..b318e60 100644 --- a/src/components/MarkdownContent.ts +++ b/src/components/MarkdownContent.ts @@ -1,18 +1,18 @@ -import { css, LitElement } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; -import { unsafeHTML } from 'lit/directives/unsafe-html.js'; -import MarkdownIt, { type StateCore, type Token } from 'markdown-it'; +import { css, LitElement } from "lit"; +import { customElement, property } from "lit/decorators.js"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; +import MarkdownIt, { type StateCore, type Token } from "markdown-it"; function nostrPlugin(md: MarkdownIt): void { const npubRegex = /(npub[0-9a-zA-Z]{59})/g; - md.core.ruler.after('inline', 'nostr_npub', (state: StateCore): boolean => { + md.core.ruler.after("inline", "nostr_npub", (state: StateCore): boolean => { for (const token of state.tokens) { - if (token.type === 'inline' && token.children) { + if (token.type === "inline" && token.children) { for (let i = 0; i < token.children.length; i++) { const child = token.children[i]; - if (child.type === 'text') { + if (child.type === "text") { const matches = child.content.match(npubRegex); if (!matches) continue; @@ -21,28 +21,29 @@ function nostrPlugin(md: MarkdownIt): void { child.content.replace( npubRegex, + // @ts-ignore this is an issue with the types (match: string, npub: string, offset: number) => { if (offset > lastIndex) { - const textToken = new state.Token('text', '', 0); + const textToken = new state.Token("text", "", 0); textToken.content = child.content.slice(lastIndex, offset); newTokens.push(textToken); } - const linkOpen = new state.Token('link_open', 'a', 1); - linkOpen.attrs = [['href', `nostr:${npub}`]]; + const linkOpen = new state.Token("link_open", "a", 1); + linkOpen.attrs = [["href", `nostr:${npub}`]]; - const text = new state.Token('text', '', 0); + const text = new state.Token("text", "", 0); text.content = npub; - const linkClose = new state.Token('link_close', 'a', -1); + const linkClose = new state.Token("link_close", "a", -1); newTokens.push(linkOpen, text, linkClose); lastIndex = offset + match.length; - }, + } ); if (lastIndex < child.content.length) { - const textToken = new state.Token('text', '', 0); + const textToken = new state.Token("text", "", 0); textToken.content = child.content.slice(lastIndex); newTokens.push(textToken); } @@ -58,7 +59,7 @@ function nostrPlugin(md: MarkdownIt): void { }); } -@customElement('arx-markdown-content') +@customElement("arx-markdown-content") export class MarkdownContent extends LitElement { private md = new MarkdownIt({ html: false, @@ -68,7 +69,7 @@ export class MarkdownContent extends LitElement { }); @property({ type: String }) - content = ''; + content = ""; static override styles = [ css` @@ -94,7 +95,16 @@ export class MarkdownContent extends LitElement { display: contents; } - h1, h2, h3, h4, h5, h6, code, ul, ol, blockquote { + h1, + h2, + h3, + h4, + h5, + h6, + code, + ul, + ol, + blockquote { width: 100%; margin: 0; display: block; diff --git a/src/electron/main.ts b/src/electron/main.ts new file mode 100644 index 0000000..f6f3371 --- /dev/null +++ b/src/electron/main.ts @@ -0,0 +1,77 @@ +import { app, shell, BrowserWindow, ipcMain } from "electron"; +import { optimizer, is } from "@electron-toolkit/utils"; +import { RelayManager } from "./relayManager"; +import path from "node:path"; +import fs from "node:fs"; +import os from "node:os"; + +const relay = new RelayManager(); + +ipcMain.handle("relay:writeSeed", (_, ...args: any) => { + if (!args[0]) throw new Error("No seed provided"); + const seed = args[0] as string; + const configPath = path.join(os.homedir(), ".config", "arx", "Eve"); + const seedPath = path.join(configPath, "ccn.seed"); + fs.mkdirSync(configPath, { recursive: true }); + fs.writeFileSync(seedPath, seed); +}); + +ipcMain.handle("relay:start", (_, ...args: any) => { + if (!args[0]) throw new Error("No encryption key provided"); + const encryptionKey = args[0] as string; + return relay.start(encryptionKey); +}); + +ipcMain.handle("relay:stop", () => { + return relay.stop(); +}); + +ipcMain.handle("relay:status", () => { + return { + running: relay.isRunning, + pid: relay.pid, + logs: relay.getLogs(), + }; +}); + +ipcMain.handle("relay:getLogs", () => { + return relay.getLogs(); +}); + +function createWindow(): void { + const mainWindow = new BrowserWindow({ + width: 1024, + height: 768, + show: false, + autoHideMenuBar: true, + webPreferences: { + preload: path.join(__dirname, "../preload/preload.mjs"), + sandbox: false, + }, + }); + + mainWindow.on("ready-to-show", () => { + mainWindow.show(); + }); + + mainWindow.webContents.setWindowOpenHandler((details) => { + shell.openExternal(details.url); + return { action: "deny" }; + }); + + if (is.dev && process.env["ELECTRON_RENDERER_URL"]) + mainWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]); + else mainWindow.loadFile(path.join(__dirname, "../renderer/index.html")); +} + +app.whenReady().then(() => { + app.on("browser-window-created", (_, window) => { + optimizer.watchWindowShortcuts(window); + }); + + createWindow(); +}); + +app.on("window-all-closed", () => { + app.quit(); +}); diff --git a/src/electron/preload.ts b/src/electron/preload.ts new file mode 100644 index 0000000..42eeb40 --- /dev/null +++ b/src/electron/preload.ts @@ -0,0 +1,21 @@ +import { contextBridge, ipcRenderer } from "electron"; +import { electronAPI } from "@electron-toolkit/preload"; + +if (process.contextIsolated) { + try { + contextBridge.exposeInMainWorld("electron", electronAPI); + contextBridge.exposeInMainWorld("relay", { + writeSeed: (seed: string) => ipcRenderer.invoke("relay:writeSeed", seed), + start: (encryptionKey: string) => + ipcRenderer.invoke("relay:start", encryptionKey), + stop: () => ipcRenderer.invoke("relay:stop"), + getStatus: () => ipcRenderer.invoke("relay:status"), + getLogs: () => ipcRenderer.invoke("relay:logs"), + }); + } catch (error) { + console.error(error); + } +} else { + // @ts-ignore (define in dts) + window.electron = electronAPI; +} diff --git a/src/electron/relayManager.ts b/src/electron/relayManager.ts new file mode 100644 index 0000000..7ab941f --- /dev/null +++ b/src/electron/relayManager.ts @@ -0,0 +1,207 @@ +import { spawn, ChildProcess } from "child_process"; +import { join } from "path"; +import { is } from "@electron-toolkit/utils"; + +type PackageEnvironment = "flatpak" | "appimage" | "system" | "dev"; + +export class RelayManager { + private process: ChildProcess | null; + private readonly relayPath: string; + private isShuttingDown: boolean; + private restartAttempts: number; + private readonly maxRestartAttempts: number; + private readonly restartDelay: number; + private restartTimeout: NodeJS.Timeout | null; + private relayLogs: string[]; + private readonly maxLogs: number; + private encryptionKey: string | null; + + /** + * Checks if the relay is currently running. + * + * @returns {boolean} True if the relay is running, otherwise false. + */ + get isRunning(): boolean { + return !!this.process; + } + + /** + * Retrieves the process identifier (PID) of the running relay process. + * + * @returns {number | undefined} The PID of the relay process if it is running, otherwise undefined. + */ + + get pid(): number | undefined { + return this.process?.pid; + } + + constructor(maxRestartAttempts = 5, restartDelay = 1000, maxLogs = 100) { + this.process = null; + this.relayPath = this.getRelayPath(); + this.isShuttingDown = false; + this.restartAttempts = 0; + this.maxRestartAttempts = maxRestartAttempts; + this.restartDelay = restartDelay; + this.restartTimeout = null; + this.relayLogs = []; + this.maxLogs = maxLogs; + this.encryptionKey = null; + } + + private detectEnvironment(): PackageEnvironment { + if (is.dev) return "dev"; + if (process.env.FLATPAK_ID) return "flatpak"; + if (process.env.APPIMAGE) return "appimage"; + return "system"; + } + + private getRelayPath(): string { + const environment = this.detectEnvironment(); + + switch (environment) { + case "dev": + return join(__dirname, "../../extras/linux/relay"); + case "flatpak": + return "/app/lib/com.arx_ccn.eve/usr/bin/eve-relay"; + case "appimage": + return join(process.env.APPDIR || "", "usr/bin/eve-relay"); + case "system": + return "/usr/bin/eve-relay"; + } + } + + private handleProcessExit(code: number | null): void { + this.process = null; + console.log(`Relay exited with code ${code}`); + + if (!this.isShuttingDown) this.restartProcess(); + } + + private restartProcess(): void { + if (this.restartAttempts >= this.maxRestartAttempts) { + console.error( + `Failed to restart relay after ${this.maxRestartAttempts} attempts` + ); + return; + } + + this.restartAttempts++; + console.log( + `Attempting restart #${this.restartAttempts} in ${this.restartDelay}ms...` + ); + + if (this.restartTimeout) clearTimeout(this.restartTimeout); + + this.restartTimeout = setTimeout(() => { + this.start(this.encryptionKey!); + }, this.restartDelay); + } + + private addLog(data: string): void { + this.relayLogs.push(data); + if (this.relayLogs.length > this.maxLogs) { + this.relayLogs = this.relayLogs.slice(-this.maxLogs); + } + } + + /** + * Start the Eve Relay. + * + * If the process is already running, do nothing. + * + * Logs from the Relay process are captured and can be retrieved with the + * `getLogs()` method. + * + * If the process exits unexpectedly, it will be restarted according to the + * configured restart policy. + * + * @param {string} encryptionKey - The key to use for encrypting data saved in + * the Relay. + */ + public start(encryptionKey: string): void { + if (this.process) return; + + this.encryptionKey = encryptionKey; + + try { + this.process = spawn(this.relayPath, [], { + env: { + ...process.env, + LD_LIBRARY_PATH: process.env.LD_LIBRARY_PATH, + PATH: process.env.PATH, + ENCRYPTION_KEY: encryptionKey, + }, + }); + + if (this.process.stdout) { + this.process.stdout.on("data", (data: Buffer) => { + const logLine = data.toString().trim(); + this.addLog(logLine); + console.log(logLine); + }); + } + + if (this.process.stderr) { + this.process.stderr.on("data", (data: Buffer) => { + const logLine = data.toString().trim(); + this.addLog(logLine); + console.error(logLine); + }); + } + + this.process.on("error", (err: Error) => { + console.error(`Failed to start Relay: ${err.message}`); + this.process = null; + this.restartProcess(); + }); + + this.process.on("exit", this.handleProcessExit.bind(this)); + + if (this.process.pid) { + this.restartAttempts = 0; + } + } catch (error) { + console.error( + `Error starting Relay: ${ + error instanceof Error ? error.message : "Unknown error" + }` + ); + this.restartProcess(); + } + } + + /** + * Stop the Eve Relay. + * + * If the Relay process is currently running, it will be terminated. + * + * If the process is not running, do nothing. + * + * All pending restarts will be cancelled. + */ + public stop(): void { + this.isShuttingDown = true; + + if (this.restartTimeout) { + clearTimeout(this.restartTimeout); + this.restartTimeout = null; + } + + if (this.process) { + this.process.kill(); + this.process = null; + } + } + + /** + * Returns a copy of all the log lines the Relay has written to date. + * + * The returned array is a copy of the internal log state, and will not be + * modified by future log activity. + * + * @returns A copy of all log lines from the Relay since it was last started. + */ + public getLogs(): string[] { + return [...this.relayLogs]; + } +} diff --git a/index.html b/src/index.html similarity index 85% rename from index.html rename to src/index.html index a566c23..44a6910 100644 --- a/index.html +++ b/src/index.html @@ -7,6 +7,6 @@ - + diff --git a/src/main.ts b/src/main.ts index 310f4c9..9acc892 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,8 +7,22 @@ import "@components/NostrProfile"; import "@components/Breadcrumbs"; import "@components/Header"; import "@routes/router"; +import "@components/LoadingView"; import type EveRouter from "@routes/router"; +import { sleep } from "./utils/sleep"; -const router = document.createElement("arx-eve-router") as EveRouter; -router.ccnSetup = localStorage.getItem("ncryptsec"); -document.body.appendChild(router); +async function startRelay() { + if (localStorage.getItem("ncryptsec")) { + const loadingIndicator = document.createElement("arx-loading-view"); + document.body.appendChild(loadingIndicator); + await window.relay.start(localStorage.getItem("encryption_key")!); + await sleep(5000); + loadingIndicator.remove(); + } +} + +startRelay().then(() => { + const router = document.createElement("arx-eve-router") as EveRouter; + router.ccnSetup = !!localStorage.getItem("ncryptsec"); + document.body.appendChild(router); +}); diff --git a/src/ndk.ts b/src/ndk.ts index cde8b30..2cfafd0 100644 --- a/src/ndk.ts +++ b/src/ndk.ts @@ -1,5 +1,5 @@ import NDK, { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; -import * as nip49 from "nostr-tools/nip49"; +import * as nip49 from "@nostr/tools/nip49"; export const ndk = new NDK({ explicitRelayUrls: ["ws://localhost:6942"], @@ -13,8 +13,9 @@ export async function getSigner() { await ndk.connect(); if (ndk.signer) return; const encryptionPassphrase = localStorage.getItem("encryption_key"); + if (!encryptionPassphrase) throw new Error("Encryption passphrase not found"); const signer = new NDKPrivateKeySigner( - nip49.decrypt(localStorage.getItem("ncryptsec"), encryptionPassphrase) + nip49.decrypt(localStorage.getItem("ncryptsec")!, encryptionPassphrase) ); setSigner(signer); } diff --git a/src/relayManager.d.ts b/src/relayManager.d.ts new file mode 100644 index 0000000..c16961d --- /dev/null +++ b/src/relayManager.d.ts @@ -0,0 +1,21 @@ +interface RelayStatus { + running: boolean; + pid: number | null; + logs: string[]; +} + +interface RelayBridge { + writeSeed: (seed: string) => Promise; + start: (encryptionKey: string) => Promise; + stop: () => Promise; + getStatus: () => Promise; + getLogs: () => Promise; +} + +declare global { + interface Window { + relay: RelayBridge; + } +} + +export {}; diff --git a/src/routes/Profile.ts b/src/routes/Profile.ts index 2970097..af14361 100644 --- a/src/routes/Profile.ts +++ b/src/routes/Profile.ts @@ -1,7 +1,6 @@ import { LitElement, html, css } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { when } from "lit/directives/when.js"; -import { styleMap } from "lit/directives/style-map.js"; import type { NDKUserProfile } from "@nostr-dev-kit/ndk"; import { getUserProfile } from "../ndk"; diff --git a/src/routes/router.ts b/src/routes/router.ts index c6c953d..433ccff 100644 --- a/src/routes/router.ts +++ b/src/routes/router.ts @@ -78,7 +78,7 @@ export default class EveRouter extends LitElement { private currentIndex = -1; @property() - private ccnSetup = false; + public ccnSetup = false; private beforeEachGuards: ((to: Route, from: Route | null) => boolean)[] = []; private afterEachHooks: ((to: Route, from: Route | null) => void)[] = []; @@ -116,6 +116,8 @@ export default class EveRouter extends LitElement { constructor() { super(); this.initializeRouter(); + if (this.ccnSetup) + window.relay.start(localStorage.getItem("encryption_key")!); } override connectedCallback(): void { @@ -276,7 +278,7 @@ export default class EveRouter extends LitElement { ?canGoBack=${this.currentIndex > 0} ?canGoForward=${this.currentIndex < this.history.length - 1} url="eve://${this.currentPath}" - @navigate=${(e) => this.navigate(e.detail)} + @navigate=${(e: CustomEvent) => this.navigate(e.detail)} @go-back=${this.goBack} @go-forward=${this.goForward} title="Eve" diff --git a/src/utils/sleep.ts b/src/utils/sleep.ts new file mode 100644 index 0000000..0d7f188 --- /dev/null +++ b/src/utils/sleep.ts @@ -0,0 +1,3 @@ +export function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/tsconfig.json b/tsconfig.json index aebdc7b..b55f9c5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,5 +31,6 @@ "@components/*": ["./src/components/*"], "@widgets/*": ["./src/components/Widgets/*"] } - } + }, + "include": ["./src/**/*"] } diff --git a/vite.config.ts b/vite.config.ts deleted file mode 100644 index 0cbea18..0000000 --- a/vite.config.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { fileURLToPath, URL } from "node:url"; -import { defineConfig } from "vite"; -import { resolve } from "path"; - -export default defineConfig({ - plugins: [], - build: { - target: "es2024", - outDir: "dist", - rollupOptions: { - input: { - main: resolve(__dirname, "index.html"), - }, - }, - }, - resolve: { - alias: { - "@utils": fileURLToPath(new URL("./src/utils", import.meta.url)), - "@routes": fileURLToPath(new URL("./src/routes", import.meta.url)), - "@styles": fileURLToPath(new URL("./src/styles", import.meta.url)), - "@widgets": fileURLToPath( - new URL("./src/components/Widgets", import.meta.url) - ), - "@components": fileURLToPath( - new URL("./src/components", import.meta.url) - ), - "@": fileURLToPath(new URL("./src", import.meta.url)), - }, - }, - server: { - port: 5173, - open: true, - }, - optimizeDeps: { - esbuildOptions: { - target: "es2024", - }, - }, -});