import { NgZone } from '@angular/core'; import { PlatformService } from 'tabby-core'; import { SFTPFile, SFTPPanelComponent } from 'tabby-ssh'; import { SidebarPlusDropLocator } from './dropLocator.service'; import { SidebarPlusNoticesService } from './notices.service'; import { SidebarPlusTransfersService } from './transfersRegistry.service'; /** The live SFTP transport, borrowed from the one member that publicly exposes its type. */ type SftpSession = SFTPPanelComponent['sftp']; /** * A real drag-and-drop out of the panel: the transfer starts **on drop**. * * `webContents.startDrag()` cannot do this — it demands a file that already * exists locally, which is what forced the two-step gesture (prepare, then * drag). Chromium has another route: a `DownloadURL` entry in the drag's * `DataTransfer` announces a name, a type and a URL, and the content is only * fetched when the drop lands. That is Windows' own delayed-rendering * behaviour, reached through the engine rather than through an Electron API. * * This server is the other end of that URL. It listens on the loopback * interface only, on an ephemeral port, and answers exactly one request per * randomly generated token — a URL that has been served, or was never handed * out, is a 404. Nothing is reachable from the network, and no listing exists. */ export declare class SidebarPlusDragOutServer { private transfers; private locator; private notifications; private zone; private server; private port; private offers; /** Transfers of the marker route, reported like every other transfer of the panel. */ private fileTransfers; constructor(transfers: SidebarPlusTransfersService, locator: SidebarPlusDropLocator, notifications: SidebarPlusNoticesService, zone: NgZone, platform: PlatformService); private start; /** True once a URL can be handed out — checked before offering, never assumed. */ get ready(): boolean; /** * Announces a file and returns the URL that will serve it. * * Synchronous by necessity: it is called from `dragstart`, where an `await` * would let the gesture start without the announcement. */ offer(sftp: SftpSession, item: SFTPFile, sessionLabel?: string): string | null; /** * Announces an empty marker standing in for an entry that cannot be served * as bytes, and returns both the URL and the name to announce it under. * * The name matters as much as the URL here: it is what the shell writes at * the drop site, and therefore what the sweep looks for. Unique per gesture, * so two drags in flight cannot be confused for one another. */ offerMarker(sftp: SftpSession, item: SFTPFile, sessionLabel?: string): { url: string; markerName: string; } | null; private announce; private pruneExpired; private handle; /** * Answers a marker request, then goes looking for where it landed. * * The request *is* the drop: the shell only fetches the URL once it has a * destination to write into. That is the signal no API gives — until this * moment nothing distinguishes a drag that was dropped from one that was * abandoned. The response is deliberately empty and answered at once; the * search and the delivery come after, because the shell is waiting on this * socket to finish writing the marker we are about to look for. */ private serveMarker; /** * Writes the announced entry into the folder the drop landed in. * * Collisions are not overwritten: this is a copy the user asked for by * dropping, and the panel's rule everywhere else is to refuse rather than * arbitrate — here refusing outright would leave the gesture with nothing to * show, so the copy is renamed the way Explorer does it. */ private deliver; /** See `freeLocalName()` — one rule for every route that writes into a chosen folder. */ private freeName; /** * Everything here resumes outside the Angular zone. * * The HTTP request is a Node callback and the SFTP promises are native * bindings zone.js never patched, so a notice raised from this code would * mutate state nothing repaints (piège #41). */ private notify; private notifyError; /** * Stops listening and forgets every pending offer. * * Nothing calls this today, and that is deliberate rather than an oversight: * the service is `providedIn: 'root'`, so it lives as long as the window, * and tearing it down when the last SFTP panel closes would leave `ready` * false for good — the constructor is the only thing that ever starts the * server. What would otherwise justify the teardown is already covered: * the socket listens on the loopback interface only, on a port the OS * picks, each offer is a one-shot random token consumed before it is * served, and `pruneExpired()` drops anything a gesture abandoned. */ dispose(): void; } export {};