P1: typed RPC bridge + FileSystemProvider + dual-panel local browsing
- shared/types + shared/rpc: full wire contract (Result envelope, no exceptions cross the bridge) - FileSystemProvider interface, LocalProvider, SessionRegistry with built-in 'local' - walk.ts: provider-generic recursive walk + removeRecursive - rpc-handlers wired into BrowserWindow; 10min request timeout for slow SFTP ops - Angular: RpcService (Electroview bridge + plain-browser guard), PanelsService with signals-based PanelState (sort/cursor/selection), FilePanel component with keyboard nav (arrows/Space/Enter/Backspace/Tab), path bar, toasts - verified: both panels listDir home over the bridge in the running app Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { Injectable, signal } from '@angular/core';
|
||||
import { Electroview } from 'electrobun/view';
|
||||
import type { AppRPC } from '@shared/rpc';
|
||||
import type { TransferSnapshot } from '@shared/types';
|
||||
|
||||
// Matches MAX_REQUEST_TIME_MS on the bun side — SFTP ops can be slow.
|
||||
const MAX_REQUEST_TIME_MS = 10 * 60_000;
|
||||
|
||||
export type SessionClosedEvent = { sessionId: string; reason: string };
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class RpcService {
|
||||
/** False when the page is opened in a plain browser instead of the app. */
|
||||
readonly available: boolean;
|
||||
|
||||
readonly transferUpdate = signal<TransferSnapshot | null>(null);
|
||||
readonly sessionClosed = signal<SessionClosedEvent | null>(null);
|
||||
|
||||
private rpc: ReturnType<typeof Electroview.defineRPC<AppRPC>> | undefined;
|
||||
|
||||
constructor() {
|
||||
this.available = typeof window !== 'undefined' && '__electrobun' in window;
|
||||
if (!this.available) return;
|
||||
|
||||
this.rpc = Electroview.defineRPC<AppRPC>({
|
||||
maxRequestTime: MAX_REQUEST_TIME_MS,
|
||||
handlers: {
|
||||
messages: {
|
||||
transferUpdate: (snapshot) => this.transferUpdate.set(snapshot),
|
||||
sessionClosed: (event) => this.sessionClosed.set(event),
|
||||
},
|
||||
},
|
||||
});
|
||||
new Electroview({ rpc: this.rpc });
|
||||
}
|
||||
|
||||
/** Typed request proxy: `await rpc.request.listDir({...})`. */
|
||||
get request() {
|
||||
if (!this.rpc) throw new Error('RPC is only available inside the desktop app');
|
||||
return this.rpc.request;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user