Add support for remembering SSH key passphrases and update UI accordingly
This commit is contained in:
69
App.tsx
69
App.tsx
@@ -37,7 +37,9 @@ import { AlertTriangle, Download, Trash2 } from 'lucide-react';
|
|||||||
import {
|
import {
|
||||||
STORAGE_KEY_DEBUG_HOTKEYS,
|
STORAGE_KEY_DEBUG_HOTKEYS,
|
||||||
STORAGE_KEY_PORT_FORWARDING,
|
STORAGE_KEY_PORT_FORWARDING,
|
||||||
|
STORAGE_KEY_DEFAULT_KEY_PASSPHRASES,
|
||||||
} from './infrastructure/config/storageKeys';
|
} from './infrastructure/config/storageKeys';
|
||||||
|
import { encryptField, decryptField } from './infrastructure/persistence/secureFieldAdapter';
|
||||||
import { getEffectiveKnownHosts } from './infrastructure/syncHelpers';
|
import { getEffectiveKnownHosts } from './infrastructure/syncHelpers';
|
||||||
import { TopTabs } from './components/TopTabs';
|
import { TopTabs } from './components/TopTabs';
|
||||||
import { Button } from './components/ui/button';
|
import { Button } from './components/ui/button';
|
||||||
@@ -180,6 +182,27 @@ const TerminalLayerMount: React.FC<TerminalLayerProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper functions for default SSH key passphrase persistence
|
||||||
|
async function saveDefaultKeyPassphrase(keyPath: string, passphrase: string): Promise<void> {
|
||||||
|
const store = localStorageAdapter.read<Record<string, string>>(STORAGE_KEY_DEFAULT_KEY_PASSPHRASES) ?? {};
|
||||||
|
store[keyPath] = await encryptField(passphrase) ?? passphrase;
|
||||||
|
localStorageAdapter.write(STORAGE_KEY_DEFAULT_KEY_PASSPHRASES, store);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadDefaultKeyPassphrase(keyPath: string): Promise<string | null> {
|
||||||
|
const store = localStorageAdapter.read<Record<string, string>>(STORAGE_KEY_DEFAULT_KEY_PASSPHRASES);
|
||||||
|
const enc = store?.[keyPath];
|
||||||
|
if (!enc) return null;
|
||||||
|
return (await decryptField(enc)) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeDefaultKeyPassphrase(keyPath: string): Promise<void> {
|
||||||
|
const store = localStorageAdapter.read<Record<string, string>>(STORAGE_KEY_DEFAULT_KEY_PASSPHRASES);
|
||||||
|
if (!store) return;
|
||||||
|
delete store[keyPath];
|
||||||
|
localStorageAdapter.write(STORAGE_KEY_DEFAULT_KEY_PASSPHRASES, store);
|
||||||
|
}
|
||||||
|
|
||||||
function App({ settings }: { settings: SettingsState }) {
|
function App({ settings }: { settings: SettingsState }) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@@ -203,6 +226,8 @@ function App({ settings }: { settings: SettingsState }) {
|
|||||||
const [keyboardInteractiveQueue, setKeyboardInteractiveQueue] = useState<KeyboardInteractiveRequest[]>([]);
|
const [keyboardInteractiveQueue, setKeyboardInteractiveQueue] = useState<KeyboardInteractiveRequest[]>([]);
|
||||||
// Passphrase request queue for encrypted SSH keys
|
// Passphrase request queue for encrypted SSH keys
|
||||||
const [passphraseQueue, setPassphraseQueue] = useState<PassphraseRequest[]>([]);
|
const [passphraseQueue, setPassphraseQueue] = useState<PassphraseRequest[]>([]);
|
||||||
|
// Track keys that were auto-responded in this session (to detect wrong saved passphrases)
|
||||||
|
const autoRespondedKeysRef = useRef<Set<string>>(new Set());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
theme,
|
theme,
|
||||||
@@ -983,8 +1008,34 @@ function App({ settings }: { settings: SettingsState }) {
|
|||||||
const bridge = netcattyBridge.get();
|
const bridge = netcattyBridge.get();
|
||||||
if (!bridge?.onPassphraseRequest) return;
|
if (!bridge?.onPassphraseRequest) return;
|
||||||
|
|
||||||
const unsubscribe = bridge.onPassphraseRequest((request) => {
|
const unsubscribe = bridge.onPassphraseRequest(async (request) => {
|
||||||
console.log('[App] Passphrase request received:', request);
|
console.log('[App] Passphrase request received:', request);
|
||||||
|
|
||||||
|
// Check if this key was already auto-responded in this session
|
||||||
|
// If so, the saved passphrase was wrong - remove it and show modal
|
||||||
|
if (autoRespondedKeysRef.current.has(request.keyPath)) {
|
||||||
|
console.log('[App] Key was auto-responded before but failed, removing saved passphrase');
|
||||||
|
autoRespondedKeysRef.current.delete(request.keyPath);
|
||||||
|
await removeDefaultKeyPassphrase(request.keyPath);
|
||||||
|
setPassphraseQueue(prev => [...prev, {
|
||||||
|
requestId: request.requestId,
|
||||||
|
keyPath: request.keyPath,
|
||||||
|
keyName: request.keyName,
|
||||||
|
hostname: request.hostname,
|
||||||
|
}]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load saved passphrase
|
||||||
|
const saved = await loadDefaultKeyPassphrase(request.keyPath);
|
||||||
|
if (saved) {
|
||||||
|
console.log('[App] Auto-responding with saved passphrase for:', request.keyPath);
|
||||||
|
autoRespondedKeysRef.current.add(request.keyPath);
|
||||||
|
void bridge.respondPassphrase?.(request.requestId, saved, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No saved passphrase, show modal
|
||||||
setPassphraseQueue(prev => [...prev, {
|
setPassphraseQueue(prev => [...prev, {
|
||||||
requestId: request.requestId,
|
requestId: request.requestId,
|
||||||
keyPath: request.keyPath,
|
keyPath: request.keyPath,
|
||||||
@@ -999,13 +1050,25 @@ function App({ settings }: { settings: SettingsState }) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Handle passphrase submit
|
// Handle passphrase submit
|
||||||
const handlePassphraseSubmit = useCallback((requestId: string, passphrase: string) => {
|
const handlePassphraseSubmit = useCallback(async (requestId: string, passphrase: string, remember: boolean) => {
|
||||||
const bridge = netcattyBridge.get();
|
const bridge = netcattyBridge.get();
|
||||||
if (bridge?.respondPassphrase) {
|
if (bridge?.respondPassphrase) {
|
||||||
void bridge.respondPassphrase(requestId, passphrase, false);
|
void bridge.respondPassphrase(requestId, passphrase, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save passphrase if requested
|
||||||
|
if (remember) {
|
||||||
|
const request = passphraseQueue.find(r => r.requestId === requestId);
|
||||||
|
if (request?.keyPath) {
|
||||||
|
console.log('[App] Saving passphrase for:', request.keyPath);
|
||||||
|
void saveDefaultKeyPassphrase(request.keyPath, passphrase);
|
||||||
|
// Clear from auto-responded tracking since user manually entered it
|
||||||
|
autoRespondedKeysRef.current.delete(request.keyPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setPassphraseQueue(prev => prev.filter(r => r.requestId !== requestId));
|
setPassphraseQueue(prev => prev.filter(r => r.requestId !== requestId));
|
||||||
}, []);
|
}, [passphraseQueue]);
|
||||||
|
|
||||||
// Handle passphrase cancel
|
// Handle passphrase cancel
|
||||||
const handlePassphraseCancel = useCallback((requestId: string) => {
|
const handlePassphraseCancel = useCallback((requestId: string) => {
|
||||||
|
|||||||
@@ -1814,6 +1814,7 @@ const en: Messages = {
|
|||||||
'passphrase.unlock': 'Unlock',
|
'passphrase.unlock': 'Unlock',
|
||||||
'passphrase.unlocking': 'Unlocking...',
|
'passphrase.unlocking': 'Unlocking...',
|
||||||
'passphrase.skip': 'Skip',
|
'passphrase.skip': 'Skip',
|
||||||
|
'passphrase.remember': 'Remember this passphrase',
|
||||||
|
|
||||||
// Text Editor
|
// Text Editor
|
||||||
'sftp.editor.wordWrap': 'Word Wrap',
|
'sftp.editor.wordWrap': 'Word Wrap',
|
||||||
|
|||||||
@@ -1823,6 +1823,7 @@ const zhCN: Messages = {
|
|||||||
'passphrase.unlock': '解锁',
|
'passphrase.unlock': '解锁',
|
||||||
'passphrase.unlocking': '解锁中...',
|
'passphrase.unlocking': '解锁中...',
|
||||||
'passphrase.skip': '跳过',
|
'passphrase.skip': '跳过',
|
||||||
|
'passphrase.remember': '记住此密码',
|
||||||
|
|
||||||
// Text Editor
|
// Text Editor
|
||||||
'sftp.editor.wordWrap': '自动换行',
|
'sftp.editor.wordWrap': '自动换行',
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export interface PassphraseRequest {
|
|||||||
|
|
||||||
interface PassphraseModalProps {
|
interface PassphraseModalProps {
|
||||||
request: PassphraseRequest | null;
|
request: PassphraseRequest | null;
|
||||||
onSubmit: (requestId: string, passphrase: string) => void;
|
onSubmit: (requestId: string, passphrase: string, remember: boolean) => void;
|
||||||
onCancel: (requestId: string) => void;
|
onCancel: (requestId: string) => void;
|
||||||
onSkip?: (requestId: string) => void;
|
onSkip?: (requestId: string) => void;
|
||||||
}
|
}
|
||||||
@@ -40,6 +40,7 @@ export const PassphraseModal: React.FC<PassphraseModalProps> = ({
|
|||||||
const [passphrase, setPassphrase] = useState("");
|
const [passphrase, setPassphrase] = useState("");
|
||||||
const [showPassphrase, setShowPassphrase] = useState(false);
|
const [showPassphrase, setShowPassphrase] = useState(false);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
const [rememberPassphrase, setRememberPassphrase] = useState(true);
|
||||||
|
|
||||||
// Reset state when request changes
|
// Reset state when request changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -47,14 +48,15 @@ export const PassphraseModal: React.FC<PassphraseModalProps> = ({
|
|||||||
setPassphrase("");
|
setPassphrase("");
|
||||||
setShowPassphrase(false);
|
setShowPassphrase(false);
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
|
setRememberPassphrase(true);
|
||||||
}
|
}
|
||||||
}, [request]);
|
}, [request]);
|
||||||
|
|
||||||
const handleSubmit = useCallback(() => {
|
const handleSubmit = useCallback(() => {
|
||||||
if (!request || isSubmitting || !passphrase) return;
|
if (!request || isSubmitting || !passphrase) return;
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
onSubmit(request.requestId, passphrase);
|
onSubmit(request.requestId, passphrase, rememberPassphrase);
|
||||||
}, [request, passphrase, onSubmit, isSubmitting]);
|
}, [request, passphrase, onSubmit, isSubmitting, rememberPassphrase]);
|
||||||
|
|
||||||
const handleCancel = useCallback(() => {
|
const handleCancel = useCallback(() => {
|
||||||
if (!request) return;
|
if (!request) return;
|
||||||
@@ -82,15 +84,15 @@ export const PassphraseModal: React.FC<PassphraseModalProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={!!request} onOpenChange={(open) => !open && handleCancel()}>
|
<Dialog open={!!request} onOpenChange={(open) => !open && handleCancel()}>
|
||||||
<DialogContent className="sm:max-w-[425px]" hideCloseButton>
|
<DialogContent className="sm:max-w-[500px]" hideCloseButton>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<div className="flex items-center gap-3 mb-2">
|
<div className="flex items-center gap-3 mb-2">
|
||||||
<div className="h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center">
|
<div className="h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center">
|
||||||
<KeyRound className="h-5 w-5 text-primary" />
|
<KeyRound className="h-5 w-5 text-primary" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="min-w-0 flex-1">
|
||||||
<DialogTitle>{t("passphrase.title")}</DialogTitle>
|
<DialogTitle>{t("passphrase.title")}</DialogTitle>
|
||||||
<DialogDescription className="mt-1">
|
<DialogDescription className="mt-1 break-words">
|
||||||
{request.hostname
|
{request.hostname
|
||||||
? t("passphrase.descWithHost", { keyName: keyDisplayName, hostname: request.hostname })
|
? t("passphrase.descWithHost", { keyName: keyDisplayName, hostname: request.hostname })
|
||||||
: t("passphrase.desc", { keyName: keyDisplayName })}
|
: t("passphrase.desc", { keyName: keyDisplayName })}
|
||||||
@@ -125,9 +127,21 @@ export const PassphraseModal: React.FC<PassphraseModalProps> = ({
|
|||||||
{showPassphrase ? <EyeOff size={16} /> : <Eye size={16} />}
|
{showPassphrase ? <EyeOff size={16} /> : <Eye size={16} />}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground break-all">
|
||||||
{t("passphrase.keyPath")}: <code className="text-xs">{request.keyPath}</code>
|
{t("passphrase.keyPath")}: <code className="text-xs break-all">{request.keyPath}</code>
|
||||||
</p>
|
</p>
|
||||||
|
<label className="flex items-center gap-2 cursor-pointer select-none mt-2">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={rememberPassphrase}
|
||||||
|
onChange={(e) => setRememberPassphrase(e.target.checked)}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
className="accent-primary"
|
||||||
|
/>
|
||||||
|
<span className="text-xs text-muted-foreground">
|
||||||
|
{t("passphrase.remember")}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -156,6 +156,9 @@ export const STORAGE_KEY_WORKSPACE_FOCUS_SIDEBAR_WIDTH = 'netcatty_workspace_foc
|
|||||||
// Port Forwarding (transient cross-window broadcast key)
|
// Port Forwarding (transient cross-window broadcast key)
|
||||||
export const STORAGE_KEY_PF_RECONNECT_CANCEL = '__netcatty_pf_cancel_reconnect';
|
export const STORAGE_KEY_PF_RECONNECT_CANCEL = '__netcatty_pf_cancel_reconnect';
|
||||||
|
|
||||||
|
// Default SSH Key Passphrases (for ~/.ssh keys not managed in the vault)
|
||||||
|
export const STORAGE_KEY_DEFAULT_KEY_PASSPHRASES = 'netcatty_default_key_passphrases_v1';
|
||||||
|
|
||||||
// Debug Flags (no _v1 suffix — developer-only, not persisted data)
|
// Debug Flags (no _v1 suffix — developer-only, not persisted data)
|
||||||
export const STORAGE_KEY_DEBUG_HOTKEYS = 'debug.hotkeys';
|
export const STORAGE_KEY_DEBUG_HOTKEYS = 'debug.hotkeys';
|
||||||
export const STORAGE_KEY_DEBUG_UPDATE_DEMO = 'debug.updateDemo';
|
export const STORAGE_KEY_DEBUG_UPDATE_DEMO = 'debug.updateDemo';
|
||||||
|
|||||||
39
package-lock.json
generated
39
package-lock.json
generated
@@ -1158,6 +1158,7 @@
|
|||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.0",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.0",
|
||||||
@@ -1803,7 +1804,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-dirname": "^0.1.0",
|
"cross-dirname": "^0.1.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
@@ -1825,7 +1825,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graceful-fs": "^4.2.0",
|
"graceful-fs": "^4.2.0",
|
||||||
"jsonfile": "^6.0.1",
|
"jsonfile": "^6.0.1",
|
||||||
@@ -1842,7 +1841,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"universalify": "^2.0.0"
|
"universalify": "^2.0.0"
|
||||||
},
|
},
|
||||||
@@ -1857,7 +1855,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10.0.0"
|
"node": ">= 10.0.0"
|
||||||
}
|
}
|
||||||
@@ -3290,6 +3287,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz",
|
||||||
"integrity": "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==",
|
"integrity": "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hono/node-server": "^1.19.9",
|
"@hono/node-server": "^1.19.9",
|
||||||
"ajv": "^8.17.1",
|
"ajv": "^8.17.1",
|
||||||
@@ -6338,6 +6336,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
|
||||||
"integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",
|
"integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/unist": "*"
|
"@types/unist": "*"
|
||||||
}
|
}
|
||||||
@@ -6418,6 +6417,7 @@
|
|||||||
"integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
|
"integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.12.2",
|
"@eslint-community/regexpp": "^4.12.2",
|
||||||
"@typescript-eslint/scope-manager": "8.54.0",
|
"@typescript-eslint/scope-manager": "8.54.0",
|
||||||
@@ -6447,6 +6447,7 @@
|
|||||||
"integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==",
|
"integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.54.0",
|
"@typescript-eslint/scope-manager": "8.54.0",
|
||||||
"@typescript-eslint/types": "8.54.0",
|
"@typescript-eslint/types": "8.54.0",
|
||||||
@@ -6997,6 +6998,7 @@
|
|||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -7047,6 +7049,7 @@
|
|||||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
@@ -7630,6 +7633,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@@ -8372,8 +8376,7 @@
|
|||||||
"integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==",
|
"integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/cross-env": {
|
"node_modules/cross-env": {
|
||||||
"version": "10.1.0",
|
"version": "10.1.0",
|
||||||
@@ -8657,6 +8660,7 @@
|
|||||||
"integrity": "sha512-uOOBA3f+kW3o4KpSoMQ6SNpdXU7WtxlJRb9vCZgOvqhTz4b3GjcoWKstdisizNZLsylhTMv8TLHFPFW0Uxsj/g==",
|
"integrity": "sha512-uOOBA3f+kW3o4KpSoMQ6SNpdXU7WtxlJRb9vCZgOvqhTz4b3GjcoWKstdisizNZLsylhTMv8TLHFPFW0Uxsj/g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"app-builder-lib": "26.7.0",
|
"app-builder-lib": "26.7.0",
|
||||||
"builder-util": "26.4.1",
|
"builder-util": "26.4.1",
|
||||||
@@ -9038,7 +9042,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/asar": "^3.2.1",
|
"@electron/asar": "^3.2.1",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
@@ -9059,7 +9062,6 @@
|
|||||||
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graceful-fs": "^4.1.2",
|
"graceful-fs": "^4.1.2",
|
||||||
"jsonfile": "^4.0.0",
|
"jsonfile": "^4.0.0",
|
||||||
@@ -9289,6 +9291,7 @@
|
|||||||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@@ -10667,6 +10670,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.14.tgz",
|
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.14.tgz",
|
||||||
"integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==",
|
"integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.9.0"
|
"node": ">=16.9.0"
|
||||||
}
|
}
|
||||||
@@ -12156,6 +12160,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/debug": "^4.0.0",
|
"@types/debug": "^4.0.0",
|
||||||
"debug": "^4.0.0",
|
"debug": "^4.0.0",
|
||||||
@@ -12773,7 +12778,8 @@
|
|||||||
"url": "https://opencollective.com/unified"
|
"url": "https://opencollective.com/unified"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/micromatch": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
@@ -13028,7 +13034,6 @@
|
|||||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.6"
|
"minimist": "^1.2.6"
|
||||||
},
|
},
|
||||||
@@ -13041,6 +13046,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz",
|
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz",
|
||||||
"integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==",
|
"integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dompurify": "3.2.7",
|
"dompurify": "3.2.7",
|
||||||
"marked": "14.0.0"
|
"marked": "14.0.0"
|
||||||
@@ -13815,7 +13821,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^9.4.0"
|
"commander": "^9.4.0"
|
||||||
},
|
},
|
||||||
@@ -13833,7 +13838,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.20.0 || >=14"
|
"node": "^12.20.0 || >=14"
|
||||||
}
|
}
|
||||||
@@ -14024,6 +14028,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
||||||
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -14033,6 +14038,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
||||||
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@@ -15363,7 +15369,6 @@
|
|||||||
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
|
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"rimraf": "~2.6.2"
|
"rimraf": "~2.6.2"
|
||||||
@@ -15428,7 +15433,6 @@
|
|||||||
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"glob": "^7.1.3"
|
"glob": "^7.1.3"
|
||||||
},
|
},
|
||||||
@@ -15503,6 +15507,7 @@
|
|||||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -15617,6 +15622,7 @@
|
|||||||
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
|
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "~0.27.0",
|
"esbuild": "~0.27.0",
|
||||||
"get-tsconfig": "^4.7.5"
|
"get-tsconfig": "^4.7.5"
|
||||||
@@ -15715,6 +15721,7 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -15735,6 +15742,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
|
||||||
"integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==",
|
"integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/unist": "^3.0.0",
|
"@types/unist": "^3.0.0",
|
||||||
"bail": "^2.0.0",
|
"bail": "^2.0.0",
|
||||||
@@ -16073,6 +16081,7 @@
|
|||||||
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
|
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
@@ -16166,6 +16175,7 @@
|
|||||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -16444,6 +16454,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
||||||
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user