import { PlatformService } from 'tabby-core'; import { SidebarPlusI18nService } from './i18n'; import { SidebarPlusNoticesService } from './notices.service'; import { SidebarPlusTransfersService, TransferContext } from './transfersRegistry.service'; import { SFTPPanelComponent } from 'tabby-ssh'; /** The live SFTP transport, borrowed from the one member that publicly exposes its type. */ type SftpSession = SFTPPanelComponent['sftp']; /** * Every transfer between a remote path and a local file of our choosing. * * Goes through `PlatformService` rather than through hand-written * `FileDownload`/`FileUpload` subclasses. The published typings suggest those * methods always raise a file dialog, which is what led to the hand-written * ones; the installed app takes a path and then opens nothing (piège #48). * * What that buys, beyond less code: `startDownload()`/`startUpload()` publish * the transfer on `fileTransferStarted$`, and Tabby's tab bar subscribes to it * — so progress, the transfer list and cancellation come for free, on transfers * that until now ran completely invisibly. */ export declare class SftpTransfers { private platform; private notifications; private registry; private i18n; /** * The display name of the SSH tab this instance works for, shown on the * transfer lines. A plain mutable field rather than a constructor argument: * the browser component that owns this instance only learns its tab's name * after construction, when the host panel binds it. */ sessionLabel: string | null; constructor(platform: PlatformService, notifications: SidebarPlusNoticesService, registry: SidebarPlusTransfersService, i18n: SidebarPlusI18nService); /** * Runs a transfer and tells the registry when it dies. * * A rejection here is the *only* sign that a transfer is over without * having finished — losing the SSH transport mid-download rejects the * promise, but leaves `isCancelled()` and `isComplete()` both false, so the * line would otherwise stay "en cours" for the rest of the session. The * error is re-thrown untouched: reporting is not handling, and every caller * already has its own idea of what to say. */ private report; /** * Whether the installed app takes an imposed path. * * Read off the function's arity rather than a version number: the extra * parameter is the only thing that matters, and a version test would have * to guess which release introduced it. An older Tabby falls back to the * hand-written transfers, which still work — they just show no progress. */ private get imposesPath(); download(sftp: SftpSession, remotePath: string, localPath: string, name: string, size: number, mode: number, context?: TransferContext): Promise; /** * Confirms that what `download()` wrote is actually at `localPath`, whole. * * This is the one route where the question is answerable at all: the * destination is a path this plugin chose. A drag-out served over HTTP has * no destination to inspect — that is what the `handover` state is for. * * The expected size comes from the caller's `readdir` listing, which can be * legitimately stale: a file rewritten remotely between the listing and the * download arrives at its *new* size. Before crying wolf, the entry is * re-read from the parent listing (never `stat()`, piège #50) and the local * size is accepted if it matches either figure. A remote re-read that fails * proves nothing either way and is not treated as a verdict. */ private verifyArrival; /** * Sends a local file back to a remote path, then restores its mode. * * The chmod is not a refinement: `SFTPSession.upload()` writes to * `.tabby-upload` and renames it over the target *without ever * calling `getMode()`*, so the file that lands carries the temporary file's * mode — the server's umask. Every save of a `0755` script therefore * dropped it to a non-executable mode, silently. Restoring the mode we read * before the edit is the only thing that keeps a script runnable. */ upload(sftp: SftpSession, remotePath: string, localPath: string, name: string, size: number, mode: number, context?: TransferContext): Promise; } export {};