Fix command launcher in event preview (#42)

* fix(CommandLauncher): redirect to dashboard when executing commands from preview routes

NIP-19 preview routes (/nevent..., /npub..., etc.) don't render the
window system, so commands executed there appeared to do nothing.
Now detects preview routes and navigates to the dashboard before
creating the window, so the command actually takes effect.

* fix(test): add WebSocket polyfill for Node.js test environment

nostr-tools relay code requires WebSocket which isn't available in
Node.js by default. Adding the ws package polyfill prevents
"ReferenceError: WebSocket is not defined" errors in tests.

* fix(test): add @types/ws and fix type cast for WebSocket polyfill

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Alejandro
2026-01-07 11:09:59 +01:00
committed by GitHub
parent 3e84feb450
commit 1d61d095a8
4 changed files with 41 additions and 2 deletions

11
package-lock.json generated
View File

@@ -73,6 +73,7 @@
"@types/react-dom": "^19.2.3",
"@types/shell-quote": "^1.7.5",
"@types/uuid": "^10.0.0",
"@types/ws": "^8.18.1",
"@vitejs/plugin-react": "^4.3.4",
"@vitest/ui": "^4.0.15",
"autoprefixer": "^10.4.20",
@@ -4389,6 +4390,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz",

View File

@@ -81,6 +81,7 @@
"@types/react-dom": "^19.2.3",
"@types/shell-quote": "^1.7.5",
"@types/uuid": "^10.0.0",
"@types/ws": "^8.18.1",
"@vitejs/plugin-react": "^4.3.4",
"@vitest/ui": "^4.0.15",
"autoprefixer": "^10.4.20",

View File

@@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
import { Command } from "cmdk";
import { useAtom } from "jotai";
import { useLiveQuery } from "dexie-react-hooks";
import { useNavigate, useLocation } from "react-router";
import db from "@/services/db";
import { useGrimoire } from "@/core/state";
import { manPages } from "@/types/man";
@@ -11,6 +12,19 @@ import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
import { VisuallyHidden } from "@/components/ui/visually-hidden";
import "./command-launcher.css";
/** Check if current path is a NIP-19 preview route (no window system) */
function isNip19PreviewRoute(pathname: string): boolean {
// NIP-19 preview routes are single-segment paths starting with npub1, note1, nevent1, naddr1
const segment = pathname.slice(1); // Remove leading /
if (segment.includes("/")) return false; // Multi-segment paths are not NIP-19 previews
return (
segment.startsWith("npub1") ||
segment.startsWith("note1") ||
segment.startsWith("nevent1") ||
segment.startsWith("naddr1")
);
}
interface CommandLauncherProps {
open: boolean;
onOpenChange: (open: boolean) => void;
@@ -23,6 +37,8 @@ export default function CommandLauncher({
const [input, setInput] = useState("");
const [editMode, setEditMode] = useAtom(commandLauncherEditModeAtom);
const { state, addWindow, updateWindow } = useGrimoire();
const navigate = useNavigate();
const location = useLocation();
// Fetch spells with aliases
const aliasedSpells =
@@ -107,6 +123,12 @@ export default function CommandLauncher({
});
setEditMode(null); // Clear edit mode
} else {
// If on a NIP-19 preview route (no window system), navigate to dashboard first
// The window will appear after navigation since state persists
if (isNip19PreviewRoute(location.pathname)) {
navigate("/");
}
// Normal mode: create new window
addWindow(
recognizedCommand.appId,

View File

@@ -1,7 +1,12 @@
/**
* Vitest setup file
*
* Polyfills IndexedDB for Node.js test environment.
* This allows Dexie to work in tests without a browser.
* Polyfills browser APIs for Node.js test environment.
*/
// Polyfill IndexedDB - allows Dexie to work in tests
import "fake-indexeddb/auto";
// Polyfill WebSocket - required by nostr-tools relay code
import { WebSocket } from "ws";
globalThis.WebSocket = WebSocket as unknown as typeof globalThis.WebSocket;