Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
365 lines
15 KiB
TypeScript
365 lines
15 KiB
TypeScript
import type { S3Config, SyncedFile, WebDAVConfig } from "../../domain/sync";
|
|
import type { AppLockSettings } from "../../domain/appLock";
|
|
|
|
type AppLockRuntimeReason = 'startup' | 'idle' | 'manual' | 'background' | null;
|
|
|
|
interface AppLockRuntimeState {
|
|
initialized: boolean;
|
|
locked: boolean;
|
|
reason: AppLockRuntimeReason;
|
|
version: number;
|
|
lastLockedAt: number | null;
|
|
lastUnlockedAt: number | null;
|
|
lastActivityAt: number | null;
|
|
}
|
|
|
|
type AppLockSettingsMutationError =
|
|
| { ok: false; error: 'empty-current' | 'empty-next' | 'incorrect' };
|
|
|
|
type AppLockUnlockResult =
|
|
| { ok: true }
|
|
| { ok: false; error: 'empty' | 'incorrect' };
|
|
|
|
type AppLockSystemUnlockStatus = {
|
|
supported: boolean;
|
|
available: boolean;
|
|
enabled: boolean;
|
|
platform: 'darwin' | 'win32' | 'unsupported';
|
|
label: 'Touch ID' | 'Windows Hello' | null;
|
|
reason: string | null;
|
|
};
|
|
|
|
type AppLockSystemUnlockResult =
|
|
| { ok: true }
|
|
| { ok: false; error: 'disabled' | 'not-locked' | 'unsupported' | 'unavailable' | 'cancelled' | 'failed' };
|
|
|
|
type AppLockSystemUnlockSettingsResult =
|
|
| AppLockSettings
|
|
| { ok: false; error: 'empty-current' | 'incorrect' | 'locked' | 'unsupported' | 'unavailable' | 'cancelled' | 'failed' };
|
|
|
|
declare global {
|
|
interface NetcattyBridge {
|
|
setTheme?(theme: 'light' | 'dark' | 'system'): Promise<boolean>;
|
|
setBackgroundColor?(color: string): Promise<boolean>;
|
|
setWindowOpacity?(opacity: number): Promise<boolean>;
|
|
setAppIconVariant?(variant: import('../../domain/appIconVariant').AppIconVariant): Promise<boolean>;
|
|
setLanguage?(language: string): Promise<boolean>;
|
|
// Window controls for custom title bar (Windows/Linux)
|
|
windowMinimize?(): Promise<void>;
|
|
windowMaximize?(): Promise<boolean>;
|
|
windowClose?(): Promise<void>;
|
|
windowIsMaximized?(): Promise<boolean>;
|
|
windowIsFullscreen?(): Promise<boolean>;
|
|
windowFocus?(): Promise<boolean>;
|
|
setTerminalKeyboardFocus?(focused: boolean): void;
|
|
setWindowTitle?(title: string): Promise<boolean>;
|
|
openSessionInNewWindow?(payload: {
|
|
title: string;
|
|
sourceSession: import("../../domain/models").TerminalSession;
|
|
localShellType?: import("../../domain/models").TerminalSession['shellType'];
|
|
}): Promise<{ success: boolean; error?: string }>;
|
|
onOpenSessionInNewWindow?(cb: (payload: {
|
|
title: string;
|
|
sourceSession: import("../../domain/models").TerminalSession;
|
|
localShellType?: import("../../domain/models").TerminalSession['shellType'];
|
|
}) => void): () => void;
|
|
onWindowCommandCloseRequested?(cb: () => void): () => void;
|
|
onWindowFullScreenChanged?(cb: (isFullscreen: boolean) => void): () => void;
|
|
onWindowShown?(cb: () => void): () => void;
|
|
onWindowFocusRequested?(cb: () => void): () => void;
|
|
onWindowWillHide?(cb: () => void): () => void;
|
|
|
|
// Settings window
|
|
openSettingsWindow?(): Promise<boolean>;
|
|
closeSettingsWindow?(): Promise<void>;
|
|
|
|
// Cross-window settings sync
|
|
notifySettingsChanged?(payload: { key: string; value: unknown }): void;
|
|
onSettingsChanged?(cb: (payload: { key: string; value: unknown }) => void): () => void;
|
|
getAppLockRuntimeState?(): Promise<AppLockRuntimeState>;
|
|
getAppLockSettings?(): Promise<AppLockSettings>;
|
|
setAppLockTimeoutMinutes?(timeoutMinutes: number): Promise<AppLockSettings>;
|
|
requestAppLockEnable?(): Promise<AppLockSettings | AppLockSettingsMutationError>;
|
|
requestAppLockDisable?(currentPassword: string): Promise<AppLockSettings | AppLockSettingsMutationError>;
|
|
requestAppLockReset?(currentPassword: string): Promise<AppLockSettings | AppLockSettingsMutationError>;
|
|
requestAppLockPasswordChange?(input: {
|
|
currentPassword?: string;
|
|
nextPassword: string;
|
|
}): Promise<AppLockSettings | AppLockSettingsMutationError>;
|
|
setAppLockRuntimeLocked?(reason: Exclude<AppLockRuntimeReason, null>): Promise<AppLockRuntimeState>;
|
|
requestAppLockUnlock?(password: string): Promise<AppLockUnlockResult>;
|
|
getAppLockSystemUnlockStatus?(): Promise<AppLockSystemUnlockStatus>;
|
|
setAppLockSystemUnlockEnabled?(input: {
|
|
enabled: boolean;
|
|
currentPassword?: string;
|
|
autoPromptEnabled?: boolean;
|
|
}): Promise<AppLockSystemUnlockSettingsResult>;
|
|
requestAppLockSystemUnlock?(): Promise<AppLockSystemUnlockResult>;
|
|
reportAppLockActivity?(): Promise<void>;
|
|
onAppLockSettingsChanged?(cb: (settings: AppLockSettings) => void): () => void;
|
|
onAppLockRuntimeStateChanged?(cb: (state: AppLockRuntimeState) => void): () => void;
|
|
|
|
// Cloud sync master password (stored in-memory + persisted via Electron safeStorage)
|
|
cloudSyncSetSessionPassword?(password: string): Promise<boolean>;
|
|
cloudSyncGetSessionPassword?(): Promise<string | null>;
|
|
onCloudSyncSessionPasswordAvailable?(callback: () => void): () => void;
|
|
cloudSyncClearSessionPassword?(): Promise<boolean>;
|
|
|
|
// Cloud sync network operations (proxied via main process)
|
|
cloudSyncWebdavInitialize?(config: WebDAVConfig): Promise<{ resourceId: string | null }>;
|
|
cloudSyncWebdavUpload?(
|
|
config: WebDAVConfig,
|
|
syncedFile: SyncedFile
|
|
): Promise<{ resourceId: string }>;
|
|
cloudSyncWebdavDownload?(config: WebDAVConfig): Promise<{ syncedFile: SyncedFile | null }>;
|
|
cloudSyncWebdavDelete?(config: WebDAVConfig): Promise<{ ok: true }>;
|
|
|
|
cloudSyncS3Initialize?(config: S3Config): Promise<{ resourceId: string | null }>;
|
|
cloudSyncS3Upload?(
|
|
config: S3Config,
|
|
syncedFile: SyncedFile
|
|
): Promise<{ resourceId: string }>;
|
|
cloudSyncS3Download?(config: S3Config): Promise<{ syncedFile: SyncedFile | null }>;
|
|
cloudSyncS3Delete?(config: S3Config): Promise<{ ok: true }>;
|
|
|
|
// Port Forwarding
|
|
startPortForward?(options: PortForwardOptions): Promise<PortForwardResult>;
|
|
stopPortForward?(tunnelId: string): Promise<PortForwardResult>;
|
|
getPortForwardStatus?(tunnelId: string): Promise<PortForwardStatusResult>;
|
|
listPortForwards?(): Promise<{ ruleId?: string; tunnelId: string; type: string; status: string; error?: string }[]>;
|
|
getPortForwardSnapshot?(): Promise<PortForwardRuntimeSnapshot>;
|
|
subscribePortForwardRuntime?(): Promise<PortForwardRuntimeSnapshot>;
|
|
unsubscribePortForwardRuntime?(): Promise<{ success: boolean }>;
|
|
subscribePortForward?(tunnelId: string): Promise<{
|
|
tunnelId: string;
|
|
type?: string;
|
|
status: 'inactive' | 'connecting' | 'active' | 'error';
|
|
error?: string;
|
|
}>;
|
|
stopAllPortForwards?(): Promise<void>;
|
|
stopPortForwardByRuleId?(ruleId: string): Promise<{
|
|
stopped: number;
|
|
failed?: number;
|
|
errors?: string[];
|
|
}>;
|
|
onPortForwardStatus?(tunnelId: string, cb: PortForwardStatusCallback): () => void;
|
|
onPortForwardRuntime?(cb: PortForwardRuntimeEventCallback): () => void;
|
|
|
|
// Known Hosts
|
|
readKnownHosts?(): Promise<string | null>;
|
|
|
|
// Open URL in default browser. Resolves when the URL is handled by
|
|
// either the system browser or the in-app fallback BrowserWindow.
|
|
// Rejects only in the rare case where both paths fail.
|
|
openExternal?(url: string): Promise<void>;
|
|
openPath?(path: string): Promise<{ success: boolean; error?: string }>;
|
|
|
|
// App info (name/version/platform) for About screens
|
|
getAppInfo?(): Promise<{ name: string; version: string; platform: string }>;
|
|
ptyGetChildProcesses?(sessionId: string): Promise<Array<{ pid: number; command: string }>>;
|
|
confirmCloseBusy?(payload: {
|
|
command: string;
|
|
title?: string;
|
|
message?: string;
|
|
cancelLabel?: string;
|
|
closeLabel?: string;
|
|
}): Promise<boolean>;
|
|
getVaultBackupCapabilities?(): Promise<{ encryptionAvailable: boolean }>;
|
|
createVaultBackup?(payload: {
|
|
payload: import('./domain/sync').SyncPayload;
|
|
reason: 'app_version_change' | 'before_restore';
|
|
sourceAppVersion?: string;
|
|
targetAppVersion?: string;
|
|
syncDataVersion?: number;
|
|
maxCount?: number;
|
|
}): Promise<{
|
|
created: boolean;
|
|
backup: {
|
|
id: string;
|
|
createdAt: number;
|
|
reason: 'app_version_change' | 'before_restore';
|
|
sourceAppVersion?: string;
|
|
targetAppVersion?: string;
|
|
fingerprint: string;
|
|
preview: {
|
|
hostCount: number;
|
|
keyCount: number;
|
|
snippetCount: number;
|
|
noteCount: number;
|
|
identityCount: number;
|
|
portForwardingRuleCount: number;
|
|
};
|
|
} | null;
|
|
}>;
|
|
listVaultBackups?(): Promise<Array<{
|
|
id: string;
|
|
createdAt: number;
|
|
reason: 'app_version_change' | 'before_restore';
|
|
sourceAppVersion?: string;
|
|
targetAppVersion?: string;
|
|
fingerprint: string;
|
|
preview: {
|
|
hostCount: number;
|
|
keyCount: number;
|
|
snippetCount: number;
|
|
noteCount: number;
|
|
identityCount: number;
|
|
portForwardingRuleCount: number;
|
|
};
|
|
}>>;
|
|
readVaultBackup?(payload: { id: string }): Promise<{
|
|
backup: {
|
|
id: string;
|
|
createdAt: number;
|
|
reason: 'app_version_change' | 'before_restore';
|
|
sourceAppVersion?: string;
|
|
targetAppVersion?: string;
|
|
fingerprint: string;
|
|
preview: {
|
|
hostCount: number;
|
|
keyCount: number;
|
|
snippetCount: number;
|
|
noteCount: number;
|
|
identityCount: number;
|
|
portForwardingRuleCount: number;
|
|
};
|
|
};
|
|
payload: import('./domain/sync').SyncPayload;
|
|
}>;
|
|
trimVaultBackups?(payload: { maxCount: number }): Promise<{ deletedCount: number; keptCount: number }>;
|
|
openVaultBackupDir?(): Promise<{ success: boolean; path: string }>;
|
|
// Subscribe to main-process-driven "vault backups changed" events.
|
|
// Returns an unsubscribe callback. Undefined in non-Electron builds.
|
|
onVaultBackupsChanged?(handler: () => void): () => void;
|
|
|
|
// Notify main process the renderer has mounted/painted (used to avoid initial blank screen).
|
|
rendererReady?(): void;
|
|
// Fired when an existing main renderer window is shown again from tray,
|
|
// global hotkey, dock activation, or second-instance focusing.
|
|
onAppLockReopen?(listener: () => void): () => void;
|
|
|
|
// Quit guard: subscribe to main-process quit requests that query for dirty editors.
|
|
// Listener is called with no arguments; return value is an unsubscribe function.
|
|
onCheckDirtyEditors?(listener: () => void): () => void;
|
|
// Report the dirty-check result back to the main process.
|
|
reportDirtyEditorsResult?(hasDirty: boolean): void;
|
|
|
|
onLanguageChanged?(cb: (language: string) => void): () => void;
|
|
|
|
// Chain progress listener for jump host connections
|
|
// Callback receives: (sessionId: string, currentHop: number, totalHops: number, hostLabel: string, status: string, error?: string)
|
|
onChainProgress?(cb: (sessionId: string, hop: number, total: number, label: string, status: string, error?: string) => void): () => void;
|
|
|
|
// Fired when a requested SSH connection reuse cannot be honored and the
|
|
// session falls back to a regular fresh connection.
|
|
onConnectionReuseFallback?(cb: (sessionId: string, sourceSessionId?: string) => void): () => void;
|
|
|
|
// SFTP connection progress listener (auth method logs)
|
|
onSftpConnectionProgress?(cb: (sessionId: string, label: string, status: string, detail?: string) => void): () => void;
|
|
|
|
// OAuth callback server for cloud sync. `prepareOAuthCallback` binds the
|
|
// loopback listener and returns the chosen port (preferred 45678, falls
|
|
// back to an OS-assigned free port if busy). The caller then builds the
|
|
// OAuth URL against `redirectUri`, opens the browser, and finally awaits
|
|
// the code via `awaitOAuthCallback`.
|
|
prepareOAuthCallback?(): Promise<{ sessionId: string; port: number; redirectUri: string }>;
|
|
awaitOAuthCallback?(expectedState?: string, sessionId?: string): Promise<{ code: string; state?: string }>;
|
|
cancelOAuthCallback?(sessionId?: string): Promise<void>;
|
|
|
|
// GitHub Device Flow (cloud sync)
|
|
githubStartDeviceFlow?(options?: { clientId?: string; scope?: string }): Promise<{
|
|
deviceCode: string;
|
|
userCode: string;
|
|
verificationUri: string;
|
|
expiresAt: number;
|
|
interval: number;
|
|
}>;
|
|
githubPollDeviceFlowToken?(options: { clientId?: string; deviceCode: string; pollId?: string }): Promise<{
|
|
access_token?: string;
|
|
token_type?: string;
|
|
scope?: string;
|
|
error?: string;
|
|
error_description?: string;
|
|
}>;
|
|
githubCancelDeviceFlowPoll?(pollId: string): Promise<void>;
|
|
githubDownloadGistRawContent?(options: { accessToken: string; rawUrl: string }): Promise<string>;
|
|
|
|
// Google OAuth (cloud sync) - proxied via main process to avoid CORS
|
|
googleExchangeCodeForTokens?(options: {
|
|
clientId: string;
|
|
clientSecret?: string;
|
|
code: string;
|
|
codeVerifier: string;
|
|
redirectUri: string;
|
|
}): Promise<{
|
|
accessToken: string;
|
|
refreshToken?: string;
|
|
expiresAt?: number;
|
|
tokenType: string;
|
|
scope?: string;
|
|
}>;
|
|
googleRefreshAccessToken?(options: {
|
|
clientId: string;
|
|
clientSecret?: string;
|
|
refreshToken: string;
|
|
}): Promise<{
|
|
accessToken: string;
|
|
refreshToken: string;
|
|
expiresAt?: number;
|
|
tokenType: string;
|
|
scope?: string;
|
|
}>;
|
|
googleGetUserInfo?(options: { accessToken: string }): Promise<{
|
|
id: string;
|
|
email: string;
|
|
name: string;
|
|
picture?: string;
|
|
}>;
|
|
|
|
// Google Drive API (cloud sync) - proxied via main process to avoid CORS/COEP issues
|
|
googleDriveFindSyncFile?(options: { accessToken: string; fileName?: string }): Promise<{ fileId: string | null }>;
|
|
googleDriveCreateSyncFile?(options: { accessToken: string; fileName?: string; syncedFile: unknown }): Promise<{ fileId: string }>;
|
|
googleDriveUpdateSyncFile?(options: { accessToken: string; fileId: string; syncedFile: unknown }): Promise<{ ok: true }>;
|
|
googleDriveDownloadSyncFile?(options: { accessToken: string; fileId: string }): Promise<{ syncedFile: unknown | null }>;
|
|
googleDriveDeleteSyncFile?(options: { accessToken: string; fileId: string }): Promise<{ ok: true }>;
|
|
|
|
// OneDrive OAuth + Graph (cloud sync) - proxied via main process to avoid CORS
|
|
onedriveExchangeCodeForTokens?(options: {
|
|
clientId: string;
|
|
code: string;
|
|
codeVerifier: string;
|
|
redirectUri: string;
|
|
scope?: string;
|
|
}): Promise<{
|
|
accessToken: string;
|
|
refreshToken?: string;
|
|
expiresAt?: number;
|
|
tokenType: string;
|
|
scope?: string;
|
|
}>;
|
|
onedriveRefreshAccessToken?(options: {
|
|
clientId: string;
|
|
refreshToken: string;
|
|
scope?: string;
|
|
}): Promise<{
|
|
accessToken: string;
|
|
refreshToken: string;
|
|
expiresAt?: number;
|
|
tokenType: string;
|
|
scope?: string;
|
|
}>;
|
|
onedriveGetUserInfo?(options: { accessToken: string }): Promise<{
|
|
id: string;
|
|
email: string;
|
|
name: string;
|
|
avatarDataUrl?: string;
|
|
}>;
|
|
onedriveFindSyncFile?(options: { accessToken: string; fileName?: string }): Promise<{ fileId: string | null }>;
|
|
onedriveUploadSyncFile?(options: { accessToken: string; fileName?: string; syncedFile: unknown }): Promise<{ fileId: string | null }>;
|
|
onedriveDownloadSyncFile?(options: { accessToken: string; fileId?: string; fileName?: string }): Promise<{ syncedFile: unknown | null }>;
|
|
onedriveDeleteSyncFile?(options: { accessToken: string; fileId: string }): Promise<{ ok: true }>;
|
|
}
|
|
}
|
|
|
|
export {};
|