@zero-transfer/sdk 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import { SecureVersion, PeerCertificate } from 'node:tls';
3
3
  import { Readable } from 'node:stream';
4
4
  import { Buffer as Buffer$1 } from 'node:buffer';
5
5
  import { Socket } from 'node:net';
6
+ import { KeyObject } from 'node:crypto';
6
7
 
7
8
  /**
8
9
  * Structured logging contracts and helpers for ZeroTransfer.
@@ -1652,23 +1653,83 @@ interface RunConnectionDiagnosticsOptions {
1652
1653
  */
1653
1654
  declare function runConnectionDiagnostics(options: RunConnectionDiagnosticsOptions): Promise<ConnectionDiagnosticsResult>;
1654
1655
 
1656
+ /** Options for {@link createPooledTransferClient}. */
1657
+ interface ConnectionPoolOptions {
1658
+ /**
1659
+ * Maximum number of *idle* sessions retained per pool key.
1660
+ *
1661
+ * Active leases are not counted against this limit — the cap only applies
1662
+ * to sessions waiting in the pool. When more than `maxIdlePerKey` sessions
1663
+ * become idle simultaneously, the oldest ones are disconnected. Defaults
1664
+ * to `4`.
1665
+ */
1666
+ maxIdlePerKey?: number;
1667
+ /**
1668
+ * How long an idle session may sit unused before it is automatically
1669
+ * disconnected. Defaults to `60_000` ms. Set to `0` to disable the timer
1670
+ * (idle sessions persist until `drainPool()` is called).
1671
+ */
1672
+ idleTimeoutMs?: number;
1673
+ /**
1674
+ * Custom pool key derivation. Receives the resolved
1675
+ * {@link ConnectionProfile} (after TransferClient validation) and must
1676
+ * return a string. Sessions with matching keys are pooled together; never
1677
+ * include secrets in the key.
1678
+ *
1679
+ * The default derives the key from `provider`, `host`, `port`, and
1680
+ * `username`.
1681
+ */
1682
+ keyOf?: (profile: ConnectionProfile) => string;
1683
+ }
1684
+ /**
1685
+ * Pool-aware {@link TransferClient} returned by
1686
+ * {@link createPooledTransferClient}.
1687
+ */
1688
+ interface PooledTransferClient {
1689
+ /** Opens (or leases) a pooled provider session. */
1690
+ connect(profile: ConnectionProfile): Promise<TransferSession>;
1691
+ /** Inspects the registered providers (delegated to the underlying client). */
1692
+ hasProvider(providerId: ProviderId): boolean;
1693
+ /** Returns the registered capability snapshots (delegated). */
1694
+ getCapabilities(): CapabilitySet[];
1695
+ /** Returns a specific capability snapshot (delegated). */
1696
+ getCapabilities(providerId: ProviderId): CapabilitySet;
1697
+ /**
1698
+ * Disconnects every idle session and prevents further pooling. After
1699
+ * `drainPool()` resolves, subsequent `connect()` calls still work but
1700
+ * always create fresh sessions (and never return them to the pool).
1701
+ */
1702
+ drainPool(): Promise<void>;
1703
+ /** Returns the number of idle sessions currently held in the pool. */
1704
+ poolSize(): number;
1705
+ }
1706
+ /**
1707
+ * Wraps a {@link TransferClient} with connection pooling.
1708
+ *
1709
+ * @param inner - Underlying client used to create real provider sessions.
1710
+ * @param options - Pool sizing, eviction, and key-derivation overrides.
1711
+ * @returns A {@link PooledTransferClient} that reuses idle sessions.
1712
+ */
1713
+ declare function createPooledTransferClient(inner: TransferClient, options?: ConnectionPoolOptions): PooledTransferClient;
1714
+
1655
1715
  /**
1656
1716
  * Built-in provider capability matrix.
1657
1717
  *
1658
1718
  * Aggregates the {@link CapabilitySet} advertised by every shipped provider
1659
1719
  * factory so applications, docs, and diagnostics can compare features across
1660
1720
  * providers without instantiating each one. The S3 entry is captured twice —
1661
- * once with multipart upload disabled (default) and once with multipart
1662
- * upload enabled because that flag flips `resumeUpload`.
1721
+ * once with the new multipart-by-default configuration and once with
1722
+ * `multipart.enabled: false` for the legacy single-shot variant — because
1723
+ * that flag flips `resumeUpload`.
1663
1724
  *
1664
1725
  * @module providers/capabilityMatrix
1665
1726
  */
1666
1727
 
1667
1728
  /** Identifier for an entry in {@link getBuiltinCapabilityMatrix}. */
1668
- type BuiltinProviderMatrixId = ProviderId | "s3:multipart";
1729
+ type BuiltinProviderMatrixId = ProviderId | "s3:single-shot";
1669
1730
  /** Single entry in the built-in capability matrix. */
1670
1731
  interface BuiltinCapabilityMatrixEntry {
1671
- /** Stable matrix identifier (provider id, or `s3:multipart` for the multipart variant). */
1732
+ /** Stable matrix identifier (provider id, or `s3:single-shot` for the legacy variant). */
1672
1733
  id: BuiltinProviderMatrixId;
1673
1734
  /** Human-readable label, suitable for documentation tables. */
1674
1735
  label: string;
@@ -1892,6 +1953,24 @@ interface WebDavProviderOptions {
1892
1953
  fetch?: HttpFetch;
1893
1954
  /** Default headers applied to every request. */
1894
1955
  defaultHeaders?: Record<string, string>;
1956
+ /**
1957
+ * Streaming policy for `PUT` request bodies.
1958
+ *
1959
+ * - `"when-known-size"` (default) — stream when the caller declares
1960
+ * `request.totalBytes` (an explicit `Content-Length` is sent so all
1961
+ * WebDAV servers accept the upload); otherwise buffer the entire body in
1962
+ * memory before sending. This is the safe default that does not require
1963
+ * the server to accept HTTP/1.1 chunked transfer-encoding.
1964
+ * - `"always"` — always stream the body, even when the size is unknown
1965
+ * (the runtime will use chunked transfer-encoding). Some legacy WebDAV
1966
+ * servers reject `Transfer-Encoding: chunked` and will respond `411
1967
+ * Length Required` or `501 Not Implemented`; only enable this for
1968
+ * servers known to accept chunked uploads (modern Apache/nginx, IIS
1969
+ * with chunked transfer enabled, Nextcloud, ownCloud, sabre/dav).
1970
+ * - `"never"` — always buffer (legacy behaviour pre-0.4.0). Use for
1971
+ * maximum compatibility at the cost of memory.
1972
+ */
1973
+ uploadStreaming?: "when-known-size" | "always" | "never";
1895
1974
  }
1896
1975
  /**
1897
1976
  * Creates a WebDAV provider factory.
@@ -1926,7 +2005,14 @@ interface S3ProviderOptions {
1926
2005
  }
1927
2006
  /** Multipart upload tuning for the S3 provider. */
1928
2007
  interface S3MultipartOptions {
1929
- /** Enable multipart upload. Defaults to `false`. */
2008
+ /**
2009
+ * Enable multipart upload. **Defaults to `true`** so large objects stream
2010
+ * in fixed-size parts instead of being buffered in memory before a single
2011
+ * `PUT`. Payloads at or below {@link S3MultipartOptions.thresholdBytes}
2012
+ * still fall back to a single-shot `PUT` automatically. Set to `false` to
2013
+ * force the legacy single-shot behaviour (e.g. when targeting an
2014
+ * S3-compatible endpoint that does not support `CreateMultipartUpload`).
2015
+ */
1930
2016
  enabled?: boolean;
1931
2017
  /** Object size threshold in bytes above which multipart is used. Defaults to 8 MiB. */
1932
2018
  thresholdBytes?: number;
@@ -1972,6 +2058,41 @@ interface S3MultipartResumeStore {
1972
2058
  }
1973
2059
  /** Creates an in-memory {@link S3MultipartResumeStore}. */
1974
2060
  declare function createMemoryS3MultipartResumeStore(): S3MultipartResumeStore;
2061
+ /** Options for {@link createFileSystemS3MultipartResumeStore}. */
2062
+ interface FileSystemS3MultipartResumeStoreOptions {
2063
+ /**
2064
+ * Directory under which checkpoint JSON files are written. Created
2065
+ * recursively if it does not exist. Each upload occupies a single file
2066
+ * named after a SHA-256 hash of the resume key, so the directory is safe
2067
+ * to share across many concurrent uploads.
2068
+ */
2069
+ directory: string;
2070
+ }
2071
+ /**
2072
+ * File-system backed {@link S3MultipartResumeStore} that survives process
2073
+ * restarts. Each in-flight multipart upload is checkpointed to a single
2074
+ * JSON file in `options.directory` after every part. On retry the upload
2075
+ * reuses the stored `uploadId` and skips parts that S3 has already
2076
+ * accepted.
2077
+ *
2078
+ * The implementation writes atomically (`<file>.tmp` then `rename`) so a
2079
+ * crash mid-write cannot leave a corrupt checkpoint.
2080
+ *
2081
+ * @example
2082
+ * ```ts
2083
+ * import { createFileSystemS3MultipartResumeStore, createS3ProviderFactory }
2084
+ * from "@zero-transfer/sdk";
2085
+ *
2086
+ * const resumeStore = createFileSystemS3MultipartResumeStore({
2087
+ * directory: "./.zt-s3-resume",
2088
+ * });
2089
+ *
2090
+ * const factory = createS3ProviderFactory({
2091
+ * multipart: { enabled: true, resumeStore },
2092
+ * });
2093
+ * ```
2094
+ */
2095
+ declare function createFileSystemS3MultipartResumeStore(options: FileSystemS3MultipartResumeStoreOptions): S3MultipartResumeStore;
1975
2096
  /**
1976
2097
  * Creates an S3-compatible provider factory.
1977
2098
  *
@@ -2583,349 +2704,159 @@ declare function redactValue(value: unknown): unknown;
2583
2704
  */
2584
2705
  declare function redactObject(input: Record<string, unknown>): Record<string, unknown>;
2585
2706
 
2586
- /**
2587
- * FTPS control-channel TLS mode.
2588
- *
2589
- * `explicit` connects on a plain FTP control socket and upgrades with `AUTH TLS`;
2590
- * `implicit` starts TLS immediately, typically on port 990.
2591
- */
2592
- type FtpsMode = "explicit" | "implicit";
2593
- /**
2594
- * FTPS data-channel protection level requested after TLS negotiation.
2595
- *
2596
- * `private` sends `PROT P` and wraps passive data sockets in TLS. `clear` sends
2597
- * `PROT C`, keeping the control channel encrypted while leaving data sockets plain.
2598
- */
2599
- type FtpsDataProtection = "clear" | "private";
2600
- /**
2601
- * Host selection strategy for PASV data endpoints.
2602
- *
2603
- * `control` connects data sockets back to the control connection host, which avoids
2604
- * broken private or unroutable PASV addresses from NATed servers. `advertised` uses
2605
- * the host supplied by the server's PASV response for deployments that require it.
2606
- */
2607
- type FtpPassiveHostStrategy = "advertised" | "control";
2608
- /** Options used to create the classic FTP provider factory. */
2609
- interface FtpProviderOptions {
2610
- /** Default control port used when a connection profile omits `port`. */
2611
- defaultPort?: number;
2612
- /** PASV host selection strategy. Defaults to `control` for NAT-friendly compatibility. */
2613
- passiveHostStrategy?: FtpPassiveHostStrategy;
2707
+ /** Algorithm lists exchanged during SSH KEXINIT negotiation. */
2708
+ interface SshAlgorithmPreferences {
2709
+ compressionClientToServer: readonly string[];
2710
+ compressionServerToClient: readonly string[];
2711
+ encryptionClientToServer: readonly string[];
2712
+ encryptionServerToClient: readonly string[];
2713
+ kexAlgorithms: readonly string[];
2714
+ languagesClientToServer: readonly string[];
2715
+ languagesServerToClient: readonly string[];
2716
+ macClientToServer: readonly string[];
2717
+ macServerToClient: readonly string[];
2718
+ serverHostKeyAlgorithms: readonly string[];
2614
2719
  }
2615
- /** Options used to create the FTPS provider factory. */
2616
- interface FtpsProviderOptions extends FtpProviderOptions {
2617
- /** TLS mode used for the control connection. Defaults to explicit FTPS on port 21. */
2618
- mode?: FtpsMode;
2619
- /** Data channel protection requested through PROT. Defaults to private/encrypted data. */
2620
- dataProtection?: FtpsDataProtection;
2720
+ /** Selected algorithms after intersecting client preferences with server capabilities. */
2721
+ interface NegotiatedSshAlgorithms {
2722
+ compressionClientToServer: string;
2723
+ compressionServerToClient: string;
2724
+ encryptionClientToServer: string;
2725
+ encryptionServerToClient: string;
2726
+ kexAlgorithm: string;
2727
+ languageClientToServer?: string;
2728
+ languageServerToClient?: string;
2729
+ macClientToServer: string;
2730
+ macServerToClient: string;
2731
+ serverHostKeyAlgorithm: string;
2621
2732
  }
2622
2733
  /**
2623
- * Creates a provider factory for classic FTP connections.
2624
- *
2625
- * @param options - Optional provider defaults.
2626
- * @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
2627
- *
2628
- * @example Plain FTP (cleartext — prefer FTPS or SFTP whenever possible)
2629
- * ```ts
2630
- * import { createFtpProviderFactory, createTransferClient } from "@zero-transfer/sdk";
2631
- *
2632
- * const client = createTransferClient({ providers: [createFtpProviderFactory()] });
2633
- *
2634
- * const session = await client.connect({
2635
- * host: "ftp.example.com",
2636
- * provider: "ftp",
2637
- * username: "deploy",
2638
- * password: { env: "FTP_PASSWORD" },
2639
- * });
2640
- * ```
2734
+ * Baseline algorithm order for the initial native SSH transport implementation.
2641
2735
  */
2642
- declare function createFtpProviderFactory(options?: FtpProviderOptions): ProviderFactory;
2736
+ declare const DEFAULT_SSH_ALGORITHM_PREFERENCES: Readonly<SshAlgorithmPreferences>;
2643
2737
  /**
2644
- * Creates a provider factory for explicit or implicit FTPS connections.
2645
- *
2646
- * The factory resolves TLS material from each connection profile, upgrades explicit
2647
- * sessions with `AUTH TLS`, and applies the configured `PROT` data-channel policy.
2648
- *
2649
- * @param options - Optional provider defaults.
2650
- * @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
2651
- *
2652
- * @example FTPS with public-CA TLS (no extra TLS material needed)
2653
- * ```ts
2654
- * import { createFtpsProviderFactory, createTransferClient } from "@zero-transfer/sdk";
2655
- *
2656
- * const client = createTransferClient({ providers: [createFtpsProviderFactory()] });
2657
- *
2658
- * const session = await client.connect({
2659
- * host: "ftps.example.com",
2660
- * provider: "ftps",
2661
- * username: "deploy",
2662
- * password: { env: "FTPS_PASSWORD" },
2663
- * tls: { minVersion: "TLSv1.2" },
2664
- * });
2665
- * ```
2666
- *
2667
- * @example FTPS with private CA + certificate pinning (defence-in-depth)
2668
- * ```ts
2669
- * await client.connect({
2670
- * host: "ftps.internal.example",
2671
- * provider: "ftps",
2672
- * username: "audit",
2673
- * tls: {
2674
- * ca: { path: "./certs/ca-bundle.pem" },
2675
- * cert: { path: "./certs/client.crt" },
2676
- * key: { path: "./certs/client.key" },
2677
- * // Optional but recommended:
2678
- * pinnedFingerprint256: "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99",
2679
- * },
2680
- * });
2681
- * ```
2738
+ * Intersects client and server algorithm lists using SSH's client-priority selection model.
2682
2739
  */
2683
- declare function createFtpsProviderFactory(options?: FtpsProviderOptions): ProviderFactory;
2740
+ declare function negotiateSshAlgorithms(client: SshAlgorithmPreferences, server: SshAlgorithmPreferences): NegotiatedSshAlgorithms;
2684
2741
 
2685
- /** FTP response status family derived from the first digit of the reply code. */
2686
- type FtpResponseStatus = "preliminary" | "completion" | "intermediate" | "transientFailure" | "permanentFailure";
2687
- /**
2688
- * Complete parsed FTP response.
2689
- */
2690
- interface FtpResponse {
2691
- /** Numeric three-digit FTP reply code. */
2692
- code: number;
2693
- /** Response message with multi-line content joined by newlines. */
2694
- message: string;
2695
- /** Individual message lines without the reply-code prefix. */
2696
- lines: string[];
2697
- /** Raw response lines joined by newlines. */
2742
+ /** Parsed SSH identification components from the RFC 4253 banner line. */
2743
+ interface SshIdentification {
2744
+ protocolVersion: string;
2745
+ softwareVersion: string;
2746
+ comments?: string;
2698
2747
  raw: string;
2699
- /** Classified response status family. */
2700
- status: FtpResponseStatus;
2701
- /** Whether the response is a 1xx preliminary reply. */
2702
- preliminary: boolean;
2703
- /** Whether the response is a 2xx completion reply. */
2704
- completion: boolean;
2705
- /** Whether the response is a 3xx intermediate reply. */
2706
- intermediate: boolean;
2707
- /** Whether the response is a 4xx transient failure reply. */
2708
- transientFailure: boolean;
2709
- /** Whether the response is a 5xx permanent failure reply. */
2710
- permanentFailure: boolean;
2748
+ }
2749
+
2750
+ /** Parsed SSH_MSG_KEXINIT payload. */
2751
+ interface SshKexInitMessage extends SshAlgorithmPreferences {
2752
+ cookie: Buffer$1;
2753
+ firstKexPacketFollows: boolean;
2754
+ messageType: number;
2755
+ reserved: number;
2756
+ }
2757
+
2758
+ /** Directional key material used after SSH NEWKEYS. */
2759
+ interface SshTransportDirectionKeys {
2760
+ encryptionKey: Buffer$1;
2761
+ iv: Buffer$1;
2762
+ macKey: Buffer$1;
2763
+ }
2764
+ /** Session key bundle derived from K, H, and session id. */
2765
+ interface SshDerivedSessionKeys {
2766
+ clientToServer: SshTransportDirectionKeys;
2767
+ exchangeHash: Buffer$1;
2768
+ serverToClient: SshTransportDirectionKeys;
2769
+ sessionId: Buffer$1;
2770
+ }
2771
+
2772
+ /** Initial client-side handshake state before key exchange math starts. */
2773
+ interface SshTransportHandshakeResult {
2774
+ keyExchange: {
2775
+ algorithm: string;
2776
+ clientKexInitPayload: Buffer$1;
2777
+ clientPublicKey: Buffer$1;
2778
+ exchangeHash: Buffer$1;
2779
+ serverHostKey: Buffer$1;
2780
+ serverKexInitPayload: Buffer$1;
2781
+ serverPublicKey: Buffer$1;
2782
+ serverSignature: Buffer$1;
2783
+ sessionId: Buffer$1;
2784
+ sharedSecret: Buffer$1;
2785
+ transportKeys: {
2786
+ clientToServer: SshDerivedSessionKeys["clientToServer"];
2787
+ serverToClient: SshDerivedSessionKeys["serverToClient"];
2788
+ };
2789
+ };
2790
+ negotiatedAlgorithms: NegotiatedSshAlgorithms;
2791
+ serverIdentification: SshIdentification;
2792
+ serverKexInit: SshKexInitMessage;
2793
+ /**
2794
+ * Number of unencrypted packets the client sent during the handshake (KEXINIT,
2795
+ * KEX_ECDH_INIT, NEWKEYS). Per RFC 4253 §6.4, packet sequence numbers are never
2796
+ * reset across NEWKEYS, so this value seeds the outbound protector.
2797
+ */
2798
+ outboundPacketCount: number;
2799
+ /**
2800
+ * Number of unencrypted packets the client received from the server during the
2801
+ * handshake (server KEXINIT, KEX_ECDH_REPLY, NEWKEYS). Seeds the inbound unprotector.
2802
+ */
2803
+ inboundPacketCount: number;
2711
2804
  }
2712
2805
  /**
2713
- * Stateful parser for socket-delivered FTP response text.
2806
+ * Client-side SSH handshake coordinator for version exchange and KEXINIT negotiation.
2714
2807
  */
2715
- declare class FtpResponseParser {
2716
- private buffer;
2717
- private pendingResponse;
2808
+ declare class SshTransportHandshake {
2809
+ private readonly options;
2810
+ private readonly clientAlgorithms;
2811
+ private readonly clientIdentificationLine;
2812
+ private readonly clientKexInitPayload;
2813
+ private readonly identificationLines;
2814
+ private readonly packetFramer;
2815
+ private readonly pendingIdentification;
2816
+ private phase;
2817
+ private inboundPacketCount;
2818
+ private outboundPacketCount;
2819
+ private pendingCurve25519;
2820
+ private pendingKeyExchange;
2821
+ private serverIdentification;
2822
+ constructor(options?: {
2823
+ algorithms?: SshAlgorithmPreferences;
2824
+ clientComments?: string;
2825
+ clientSoftwareVersion?: string;
2826
+ kexCookie?: Uint8Array;
2827
+ /**
2828
+ * Verifies the server's host key after the signature check passes.
2829
+ * Receives the SSH wire-format host key blob and its SHA-256 digest.
2830
+ * Throwing rejects the handshake; resolving accepts it.
2831
+ *
2832
+ * If omitted, the host key is accepted as long as its signature over the
2833
+ * exchange hash verifies. Callers SHOULD supply this hook in production
2834
+ * to enforce known_hosts or pinned-fingerprint policies.
2835
+ */
2836
+ verifyHostKey?: (input: {
2837
+ hostKeyBlob: Buffer$1;
2838
+ hostKeySha256: Buffer$1;
2839
+ algorithmName: string;
2840
+ }) => void | Promise<void>;
2841
+ });
2842
+ /** Creates the first outbound bytes (client identification line). */
2843
+ createInitialClientBytes(): Buffer$1;
2718
2844
  /**
2719
- * Adds incoming socket data and returns any complete responses.
2720
- *
2721
- * @param chunk - Buffer or string chunk from the FTP control connection.
2722
- * @returns Zero or more complete parsed responses.
2723
- * @throws {@link ParseError} When a malformed standalone response line is received.
2845
+ * Feeds raw server bytes into the handshake state machine.
2724
2846
  */
2725
- push(chunk: Buffer | string): FtpResponse[];
2847
+ pushServerBytes(chunk: Uint8Array): {
2848
+ outbound: Buffer$1[];
2849
+ result?: SshTransportHandshakeResult;
2850
+ };
2851
+ getServerBannerLines(): readonly string[];
2852
+ isComplete(): boolean;
2726
2853
  /**
2727
- * Clears buffered text and any incomplete multi-line response state.
2728
- *
2729
- * @returns Nothing.
2730
- */
2731
- reset(): void;
2732
- /**
2733
- * Checks whether the parser is holding buffered or incomplete response data.
2734
- *
2735
- * @returns `true` when there is unconsumed text or an open multi-line response.
2736
- */
2737
- hasPendingResponse(): boolean;
2738
- /**
2739
- * Consumes one line of FTP response text.
2740
- *
2741
- * @param rawLine - Line without a trailing CRLF delimiter.
2742
- * @returns A complete response when the line finishes one, otherwise `undefined`.
2743
- * @throws {@link ParseError} When a malformed standalone line is encountered.
2744
- */
2745
- private consumeLine;
2746
- }
2747
- /**
2748
- * Parses an exact set of response lines into one complete FTP response.
2749
- *
2750
- * @param lines - Raw response lines without trailing newline delimiters.
2751
- * @returns A single complete parsed FTP response.
2752
- * @throws {@link ParseError} When the lines do not contain exactly one complete response.
2753
- */
2754
- declare function parseFtpResponseLines(lines: string[]): FtpResponse;
2755
-
2756
- /**
2757
- * FTP FEAT response parser.
2758
- *
2759
- * This module extracts advertised server capabilities and MLST facts from a parsed
2760
- * FTP response, raw response string, or pre-split response lines.
2761
- *
2762
- * @module providers/classic/ftp/FtpFeatureParser
2763
- */
2764
-
2765
- /**
2766
- * Normalized server features returned by an FTP FEAT command.
2767
- */
2768
- interface FtpFeatures {
2769
- /** Raw normalized feature lines. */
2770
- raw: string[];
2771
- /** Uppercase feature names for fast lookup. */
2772
- names: Set<string>;
2773
- /** MLST facts advertised by the server, preserving required-fact markers. */
2774
- mlstFacts: string[];
2775
- /**
2776
- * Checks whether a named feature is advertised.
2777
- *
2778
- * @param featureName - Feature name to search for, case-insensitively.
2779
- * @returns `true` when the feature appears in the FEAT response.
2780
- */
2781
- supports(featureName: string): boolean;
2782
- }
2783
- /**
2784
- * Parses FTP FEAT output into a normalized feature set.
2785
- *
2786
- * @param input - Parsed FTP response, raw string, or individual response lines.
2787
- * @returns Normalized feature names, raw feature lines, and MLST fact names.
2788
- */
2789
- declare function parseFtpFeatures(input: FtpResponse | string | string[]): FtpFeatures;
2790
-
2791
- /**
2792
- * Parses an MLSD directory listing into normalized remote entries.
2793
- *
2794
- * @param input - Raw MLSD response body.
2795
- * @param directory - Parent remote directory used to build entry paths.
2796
- * @returns Remote entries excluding the `.` and `..` pseudo entries.
2797
- * @throws {@link ParseError} When any listing line is malformed.
2798
- */
2799
- declare function parseMlsdList(input: string, directory?: string): RemoteEntry[];
2800
- /**
2801
- * Parses a Unix-style FTP `LIST` response into normalized remote entries.
2802
- *
2803
- * This parser covers the common `ls -l` shape returned by classic FTP daemons and
2804
- * is used as a compatibility fallback when a server does not support MLSD.
2805
- *
2806
- * @param input - Raw LIST response body.
2807
- * @param directory - Parent remote directory used to build entry paths.
2808
- * @param now - Reference date used when LIST entries include time but omit year.
2809
- * @returns Remote entries excluding `.` and `..` pseudo entries.
2810
- * @throws {@link ParseError} When any non-summary listing line is malformed.
2811
- */
2812
- declare function parseUnixList(input: string, directory?: string, now?: Date): RemoteEntry[];
2813
- /**
2814
- * Parses one Unix-style FTP `LIST` line.
2815
- *
2816
- * @param line - Raw listing line in an `ls -l` compatible format.
2817
- * @param directory - Parent remote directory used to build the entry path.
2818
- * @param now - Reference date used when the line omits a year.
2819
- * @returns Normalized remote entry with raw LIST metadata retained.
2820
- * @throws {@link ParseError} When the line is not a supported Unix LIST entry.
2821
- */
2822
- declare function parseUnixListLine(line: string, directory?: string, now?: Date): RemoteEntry;
2823
- /**
2824
- * Parses a single MLSD or MLST fact line.
2825
- *
2826
- * @param line - Raw fact line in `fact=value; name` format.
2827
- * @param directory - Parent remote directory used to build the entry path.
2828
- * @returns A normalized remote entry with parsed facts in `raw` metadata.
2829
- * @throws {@link ParseError} When the line does not contain facts and a name.
2830
- */
2831
- declare function parseMlsdLine(line: string, directory?: string): RemoteEntry;
2832
- /**
2833
- * Parses the UTC timestamp format used by MLST/MLSD `modify` facts.
2834
- *
2835
- * @param input - Timestamp text such as `20260427010203.123`.
2836
- * @returns A UTC Date when the timestamp is valid, otherwise `undefined`.
2837
- */
2838
- declare function parseMlstTimestamp(input: string | undefined): Date | undefined;
2839
-
2840
- /** Algorithm lists exchanged during SSH KEXINIT negotiation. */
2841
- interface SshAlgorithmPreferences {
2842
- compressionClientToServer: readonly string[];
2843
- compressionServerToClient: readonly string[];
2844
- encryptionClientToServer: readonly string[];
2845
- encryptionServerToClient: readonly string[];
2846
- kexAlgorithms: readonly string[];
2847
- languagesClientToServer: readonly string[];
2848
- languagesServerToClient: readonly string[];
2849
- macClientToServer: readonly string[];
2850
- macServerToClient: readonly string[];
2851
- serverHostKeyAlgorithms: readonly string[];
2852
- }
2853
- /** Selected algorithms after intersecting client preferences with server capabilities. */
2854
- interface NegotiatedSshAlgorithms {
2855
- compressionClientToServer: string;
2856
- compressionServerToClient: string;
2857
- encryptionClientToServer: string;
2858
- encryptionServerToClient: string;
2859
- kexAlgorithm: string;
2860
- languageClientToServer?: string;
2861
- languageServerToClient?: string;
2862
- macClientToServer: string;
2863
- macServerToClient: string;
2864
- serverHostKeyAlgorithm: string;
2865
- }
2866
-
2867
- /** Parsed SSH identification components from the RFC 4253 banner line. */
2868
- interface SshIdentification {
2869
- protocolVersion: string;
2870
- softwareVersion: string;
2871
- comments?: string;
2872
- raw: string;
2873
- }
2874
-
2875
- /** Parsed SSH_MSG_KEXINIT payload. */
2876
- interface SshKexInitMessage extends SshAlgorithmPreferences {
2877
- cookie: Buffer$1;
2878
- firstKexPacketFollows: boolean;
2879
- messageType: number;
2880
- reserved: number;
2881
- }
2882
-
2883
- /** Directional key material used after SSH NEWKEYS. */
2884
- interface SshTransportDirectionKeys {
2885
- encryptionKey: Buffer$1;
2886
- iv: Buffer$1;
2887
- macKey: Buffer$1;
2888
- }
2889
- /** Session key bundle derived from K, H, and session id. */
2890
- interface SshDerivedSessionKeys {
2891
- clientToServer: SshTransportDirectionKeys;
2892
- exchangeHash: Buffer$1;
2893
- serverToClient: SshTransportDirectionKeys;
2894
- sessionId: Buffer$1;
2895
- }
2896
-
2897
- /** Initial client-side handshake state before key exchange math starts. */
2898
- interface SshTransportHandshakeResult {
2899
- keyExchange: {
2900
- algorithm: string;
2901
- clientKexInitPayload: Buffer$1;
2902
- clientPublicKey: Buffer$1;
2903
- exchangeHash: Buffer$1;
2904
- serverHostKey: Buffer$1;
2905
- serverKexInitPayload: Buffer$1;
2906
- serverPublicKey: Buffer$1;
2907
- serverSignature: Buffer$1;
2908
- sessionId: Buffer$1;
2909
- sharedSecret: Buffer$1;
2910
- transportKeys: {
2911
- clientToServer: SshDerivedSessionKeys["clientToServer"];
2912
- serverToClient: SshDerivedSessionKeys["serverToClient"];
2913
- };
2914
- };
2915
- negotiatedAlgorithms: NegotiatedSshAlgorithms;
2916
- serverIdentification: SshIdentification;
2917
- serverKexInit: SshKexInitMessage;
2918
- /**
2919
- * Number of unencrypted packets the client sent during the handshake (KEXINIT,
2920
- * KEX_ECDH_INIT, NEWKEYS). Per RFC 4253 §6.4, packet sequence numbers are never
2921
- * reset across NEWKEYS, so this value seeds the outbound protector.
2922
- */
2923
- outboundPacketCount: number;
2924
- /**
2925
- * Number of unencrypted packets the client received from the server during the
2926
- * handshake (server KEXINIT, KEX_ECDH_REPLY, NEWKEYS). Seeds the inbound unprotector.
2854
+ * Returns any bytes received after the last complete handshake packet and clears the buffer.
2855
+ * Call this once after `pushServerBytes` returns a result to drain bytes that belong to the
2856
+ * post-NEWKEYS encrypted phase but arrived in the same TCP segment as NEWKEYS.
2927
2857
  */
2928
- inboundPacketCount: number;
2858
+ takeRemainingBytes(): Buffer$1;
2859
+ private pushServerBytesWithPhase;
2929
2860
  }
2930
2861
 
2931
2862
  /** Standard SSH disconnect reason codes (RFC 4253 §11.1). */
@@ -3048,6 +2979,78 @@ declare class SshTransportConnection {
3048
2979
  private sendKeepalivePing;
3049
2980
  }
3050
2981
 
2982
+ interface SshPasswordCredential {
2983
+ type: "password";
2984
+ username: string;
2985
+ password: string;
2986
+ }
2987
+ interface SshPublickeyCredential {
2988
+ type: "publickey";
2989
+ username: string;
2990
+ algorithmName: string;
2991
+ /** Raw public key blob in SSH wire format (e.g. the bytes returned by ssh-keygen -e -f key.pub). */
2992
+ publicKeyBlob: Uint8Array;
2993
+ /**
2994
+ * Signs the challenge data. The data is already the complete sign-data per RFC 4252 §7.
2995
+ * Should return the signature blob (without algorithm prefix; caller adds wrapping).
2996
+ */
2997
+ sign: (data: Uint8Array) => Promise<Uint8Array> | Uint8Array;
2998
+ }
2999
+ interface SshKeyboardInteractiveCredential {
3000
+ type: "keyboard-interactive";
3001
+ username: string;
3002
+ /**
3003
+ * Called for each INFO_REQUEST round. Return one string per prompt in order.
3004
+ */
3005
+ respond: (name: string, instruction: string, prompts: Array<{
3006
+ echo: boolean;
3007
+ prompt: string;
3008
+ }>) => Promise<string[]> | string[];
3009
+ }
3010
+ type SshCredential = SshPasswordCredential | SshPublickeyCredential | SshKeyboardInteractiveCredential;
3011
+ interface SshAuthOptions {
3012
+ credential: SshCredential;
3013
+ /** SSH session id (exchange hash) from key exchange — required for publickey signing. */
3014
+ sessionId: Uint8Array;
3015
+ /** Maximum number of USERAUTH_FAILURE retries before giving up. Defaults to 4. */
3016
+ maxAttempts?: number;
3017
+ }
3018
+ interface SshAuthResult {
3019
+ /** Banner lines received from the server during authentication. */
3020
+ bannerLines: string[];
3021
+ /** Auth method that succeeded. */
3022
+ method: string;
3023
+ }
3024
+ /**
3025
+ * Runs SSH user authentication over an encrypted transport connection.
3026
+ *
3027
+ * Call this after `SshTransportConnection.connect()` completes.
3028
+ * Returns a generator of inbound payloads for the upper (connection) layer to consume.
3029
+ * Resolves with an `SshAuthResult` on success; throws `AuthenticationError` on failure.
3030
+ */
3031
+ declare class SshAuthSession {
3032
+ private readonly transport;
3033
+ constructor(transport: SshTransportConnection);
3034
+ authenticate(options: SshAuthOptions): Promise<SshAuthResult>;
3035
+ private runKeyboardInteractiveRounds;
3036
+ private pendingPayload;
3037
+ private nextPayload;
3038
+ private nextPayloadSkippingBanners;
3039
+ }
3040
+
3041
+ interface BuildPublickeyCredentialOptions {
3042
+ /** Username to authenticate as. */
3043
+ username: string;
3044
+ /** Decoded private key (OpenSSH or PKCS8 PEM accepted by `crypto.createPrivateKey`). */
3045
+ privateKey: KeyObject;
3046
+ /**
3047
+ * For RSA keys, the SSH signature algorithm. Defaults to `rsa-sha2-512`.
3048
+ * Ignored for Ed25519 keys.
3049
+ */
3050
+ rsaSignatureAlgorithm?: "rsa-sha2-256" | "rsa-sha2-512";
3051
+ }
3052
+ declare function buildPublickeyCredential(options: BuildPublickeyCredentialOptions): SshPublickeyCredential;
3053
+
3051
3054
  /**
3052
3055
  * SSH session channel (RFC 4254 §6).
3053
3056
  *
@@ -3142,6 +3145,367 @@ declare class SshSessionChannel {
3142
3145
  private nextPayload;
3143
3146
  }
3144
3147
 
3148
+ /**
3149
+ * SSH connection protocol manager (RFC 4254).
3150
+ *
3151
+ * Drives the transport-level `receivePayloads()` generator and dispatches each
3152
+ * payload to the right `SshSessionChannel` by recipient channel id.
3153
+ *
3154
+ * Lifecycle:
3155
+ * 1. Create after auth succeeds.
3156
+ * 2. Call `openSubsystemChannel("sftp")` or `openExecChannel(cmd)` to get a channel.
3157
+ * 3. Drive the pump: `start()` returns a Promise that resolves when the transport
3158
+ * closes cleanly or rejects on a fatal error.
3159
+ */
3160
+
3161
+ declare class SshConnectionManager {
3162
+ private readonly transport;
3163
+ private readonly channels;
3164
+ private nextLocalId;
3165
+ private pumpPromise;
3166
+ private pumpResolve;
3167
+ private pumpReject;
3168
+ /** Payloads that arrived before any channel registered (buffered for the first channel). */
3169
+ private readonly pendingSetupPayloads;
3170
+ private setupPayloadConsumer;
3171
+ constructor(transport: SshTransportConnection);
3172
+ /**
3173
+ * Delivers the next connection-layer payload to callers during channel setup.
3174
+ * Called by `SshSessionChannel` during `openChannel()` / `requestSubsystem()`.
3175
+ *
3176
+ * Channel setup happens sequentially before `start()` begins pumping, so we
3177
+ * pull directly from the transport iterator here.
3178
+ */
3179
+ nextSetupPayload(): Promise<Buffer$1>;
3180
+ /**
3181
+ * Opens a session channel and starts the SFTP subsystem on it.
3182
+ * Must be called before `start()`.
3183
+ */
3184
+ openSubsystemChannel(subsystemName: string): Promise<SshSessionChannel>;
3185
+ /**
3186
+ * Opens a session channel and runs the given command on it.
3187
+ * Must be called before `start()`.
3188
+ */
3189
+ openExecChannel(command: string): Promise<SshSessionChannel>;
3190
+ /**
3191
+ * Starts the main dispatch loop. Returns a Promise that resolves when the
3192
+ * connection closes cleanly, or rejects on a fatal transport error.
3193
+ *
3194
+ * Call this after all channels have been opened and the application is ready
3195
+ * to receive data.
3196
+ */
3197
+ start(): Promise<void>;
3198
+ /**
3199
+ * Runs channel setup (open + request) with a dedicated payload pump that
3200
+ * pulls from the transport iterator and dispatches non-channel-setup messages
3201
+ * to `pendingSetupPayloads` for later processing.
3202
+ */
3203
+ private runChannelSetup;
3204
+ private pump;
3205
+ private dispatch;
3206
+ private terminateChannels;
3207
+ }
3208
+
3209
+ /**
3210
+ * Stateful SSH primitive decoder that reads sequential values from a packet payload.
3211
+ */
3212
+ declare class SshDataReader {
3213
+ private readonly source;
3214
+ private offset;
3215
+ constructor(source: Uint8Array);
3216
+ get remaining(): number;
3217
+ hasMore(): boolean;
3218
+ readByte(): number;
3219
+ readBoolean(): boolean;
3220
+ readBytes(length: number): Buffer$1;
3221
+ readUint32(): number;
3222
+ readUint64(): bigint;
3223
+ readString(): Buffer$1;
3224
+ readUtf8String(): string;
3225
+ readNameList(): string[];
3226
+ /**
3227
+ * Reads an SSH `mpint` value (RFC 4251 §5): a length-prefixed two's-complement
3228
+ * big-endian integer. Returns the raw magnitude bytes (non-negative integers
3229
+ * may have a leading 0x00 byte preserved by the caller as needed).
3230
+ */
3231
+ readMpint(): Buffer$1;
3232
+ assertFinished(): void;
3233
+ private ensureAvailable;
3234
+ }
3235
+
3236
+ /**
3237
+ * Minimal SSH primitive encoder for transport and authentication packets.
3238
+ */
3239
+ declare class SshDataWriter {
3240
+ private readonly chunks;
3241
+ private length;
3242
+ writeByte(value: number): this;
3243
+ writeBoolean(value: boolean): this;
3244
+ writeBytes(value: Uint8Array): this;
3245
+ writeUint32(value: number): this;
3246
+ writeUint64(value: bigint): this;
3247
+ writeString(value: string | Uint8Array, encoding?: BufferEncoding): this;
3248
+ writeMpint(value: Uint8Array): this;
3249
+ writeNameList(values: readonly string[]): this;
3250
+ toBuffer(): Buffer$1;
3251
+ private push;
3252
+ private assertByte;
3253
+ }
3254
+
3255
+ /**
3256
+ * FTPS control-channel TLS mode.
3257
+ *
3258
+ * `explicit` connects on a plain FTP control socket and upgrades with `AUTH TLS`;
3259
+ * `implicit` starts TLS immediately, typically on port 990.
3260
+ */
3261
+ type FtpsMode = "explicit" | "implicit";
3262
+ /**
3263
+ * FTPS data-channel protection level requested after TLS negotiation.
3264
+ *
3265
+ * `private` sends `PROT P` and wraps passive data sockets in TLS. `clear` sends
3266
+ * `PROT C`, keeping the control channel encrypted while leaving data sockets plain.
3267
+ */
3268
+ type FtpsDataProtection = "clear" | "private";
3269
+ /**
3270
+ * Host selection strategy for PASV data endpoints.
3271
+ *
3272
+ * `control` connects data sockets back to the control connection host, which avoids
3273
+ * broken private or unroutable PASV addresses from NATed servers. `advertised` uses
3274
+ * the host supplied by the server's PASV response for deployments that require it.
3275
+ */
3276
+ type FtpPassiveHostStrategy = "advertised" | "control";
3277
+ /** Options used to create the classic FTP provider factory. */
3278
+ interface FtpProviderOptions {
3279
+ /** Default control port used when a connection profile omits `port`. */
3280
+ defaultPort?: number;
3281
+ /** PASV host selection strategy. Defaults to `control` for NAT-friendly compatibility. */
3282
+ passiveHostStrategy?: FtpPassiveHostStrategy;
3283
+ }
3284
+ /** Options used to create the FTPS provider factory. */
3285
+ interface FtpsProviderOptions extends FtpProviderOptions {
3286
+ /** TLS mode used for the control connection. Defaults to explicit FTPS on port 21. */
3287
+ mode?: FtpsMode;
3288
+ /** Data channel protection requested through PROT. Defaults to private/encrypted data. */
3289
+ dataProtection?: FtpsDataProtection;
3290
+ }
3291
+ /**
3292
+ * Creates a provider factory for classic FTP connections.
3293
+ *
3294
+ * @param options - Optional provider defaults.
3295
+ * @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
3296
+ *
3297
+ * @example Plain FTP (cleartext — prefer FTPS or SFTP whenever possible)
3298
+ * ```ts
3299
+ * import { createFtpProviderFactory, createTransferClient } from "@zero-transfer/sdk";
3300
+ *
3301
+ * const client = createTransferClient({ providers: [createFtpProviderFactory()] });
3302
+ *
3303
+ * const session = await client.connect({
3304
+ * host: "ftp.example.com",
3305
+ * provider: "ftp",
3306
+ * username: "deploy",
3307
+ * password: { env: "FTP_PASSWORD" },
3308
+ * });
3309
+ * ```
3310
+ */
3311
+ declare function createFtpProviderFactory(options?: FtpProviderOptions): ProviderFactory;
3312
+ /**
3313
+ * Creates a provider factory for explicit or implicit FTPS connections.
3314
+ *
3315
+ * The factory resolves TLS material from each connection profile, upgrades explicit
3316
+ * sessions with `AUTH TLS`, and applies the configured `PROT` data-channel policy.
3317
+ *
3318
+ * @param options - Optional provider defaults.
3319
+ * @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
3320
+ *
3321
+ * @example FTPS with public-CA TLS (no extra TLS material needed)
3322
+ * ```ts
3323
+ * import { createFtpsProviderFactory, createTransferClient } from "@zero-transfer/sdk";
3324
+ *
3325
+ * const client = createTransferClient({ providers: [createFtpsProviderFactory()] });
3326
+ *
3327
+ * const session = await client.connect({
3328
+ * host: "ftps.example.com",
3329
+ * provider: "ftps",
3330
+ * username: "deploy",
3331
+ * password: { env: "FTPS_PASSWORD" },
3332
+ * tls: { minVersion: "TLSv1.2" },
3333
+ * });
3334
+ * ```
3335
+ *
3336
+ * @example FTPS with private CA + certificate pinning (defence-in-depth)
3337
+ * ```ts
3338
+ * await client.connect({
3339
+ * host: "ftps.internal.example",
3340
+ * provider: "ftps",
3341
+ * username: "audit",
3342
+ * tls: {
3343
+ * ca: { path: "./certs/ca-bundle.pem" },
3344
+ * cert: { path: "./certs/client.crt" },
3345
+ * key: { path: "./certs/client.key" },
3346
+ * // Optional but recommended:
3347
+ * pinnedFingerprint256: "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99",
3348
+ * },
3349
+ * });
3350
+ * ```
3351
+ */
3352
+ declare function createFtpsProviderFactory(options?: FtpsProviderOptions): ProviderFactory;
3353
+
3354
+ /** FTP response status family derived from the first digit of the reply code. */
3355
+ type FtpResponseStatus = "preliminary" | "completion" | "intermediate" | "transientFailure" | "permanentFailure";
3356
+ /**
3357
+ * Complete parsed FTP response.
3358
+ */
3359
+ interface FtpResponse {
3360
+ /** Numeric three-digit FTP reply code. */
3361
+ code: number;
3362
+ /** Response message with multi-line content joined by newlines. */
3363
+ message: string;
3364
+ /** Individual message lines without the reply-code prefix. */
3365
+ lines: string[];
3366
+ /** Raw response lines joined by newlines. */
3367
+ raw: string;
3368
+ /** Classified response status family. */
3369
+ status: FtpResponseStatus;
3370
+ /** Whether the response is a 1xx preliminary reply. */
3371
+ preliminary: boolean;
3372
+ /** Whether the response is a 2xx completion reply. */
3373
+ completion: boolean;
3374
+ /** Whether the response is a 3xx intermediate reply. */
3375
+ intermediate: boolean;
3376
+ /** Whether the response is a 4xx transient failure reply. */
3377
+ transientFailure: boolean;
3378
+ /** Whether the response is a 5xx permanent failure reply. */
3379
+ permanentFailure: boolean;
3380
+ }
3381
+ /**
3382
+ * Stateful parser for socket-delivered FTP response text.
3383
+ */
3384
+ declare class FtpResponseParser {
3385
+ private buffer;
3386
+ private pendingResponse;
3387
+ /**
3388
+ * Adds incoming socket data and returns any complete responses.
3389
+ *
3390
+ * @param chunk - Buffer or string chunk from the FTP control connection.
3391
+ * @returns Zero or more complete parsed responses.
3392
+ * @throws {@link ParseError} When a malformed standalone response line is received.
3393
+ */
3394
+ push(chunk: Buffer | string): FtpResponse[];
3395
+ /**
3396
+ * Clears buffered text and any incomplete multi-line response state.
3397
+ *
3398
+ * @returns Nothing.
3399
+ */
3400
+ reset(): void;
3401
+ /**
3402
+ * Checks whether the parser is holding buffered or incomplete response data.
3403
+ *
3404
+ * @returns `true` when there is unconsumed text or an open multi-line response.
3405
+ */
3406
+ hasPendingResponse(): boolean;
3407
+ /**
3408
+ * Consumes one line of FTP response text.
3409
+ *
3410
+ * @param rawLine - Line without a trailing CRLF delimiter.
3411
+ * @returns A complete response when the line finishes one, otherwise `undefined`.
3412
+ * @throws {@link ParseError} When a malformed standalone line is encountered.
3413
+ */
3414
+ private consumeLine;
3415
+ }
3416
+ /**
3417
+ * Parses an exact set of response lines into one complete FTP response.
3418
+ *
3419
+ * @param lines - Raw response lines without trailing newline delimiters.
3420
+ * @returns A single complete parsed FTP response.
3421
+ * @throws {@link ParseError} When the lines do not contain exactly one complete response.
3422
+ */
3423
+ declare function parseFtpResponseLines(lines: string[]): FtpResponse;
3424
+
3425
+ /**
3426
+ * FTP FEAT response parser.
3427
+ *
3428
+ * This module extracts advertised server capabilities and MLST facts from a parsed
3429
+ * FTP response, raw response string, or pre-split response lines.
3430
+ *
3431
+ * @module providers/classic/ftp/FtpFeatureParser
3432
+ */
3433
+
3434
+ /**
3435
+ * Normalized server features returned by an FTP FEAT command.
3436
+ */
3437
+ interface FtpFeatures {
3438
+ /** Raw normalized feature lines. */
3439
+ raw: string[];
3440
+ /** Uppercase feature names for fast lookup. */
3441
+ names: Set<string>;
3442
+ /** MLST facts advertised by the server, preserving required-fact markers. */
3443
+ mlstFacts: string[];
3444
+ /**
3445
+ * Checks whether a named feature is advertised.
3446
+ *
3447
+ * @param featureName - Feature name to search for, case-insensitively.
3448
+ * @returns `true` when the feature appears in the FEAT response.
3449
+ */
3450
+ supports(featureName: string): boolean;
3451
+ }
3452
+ /**
3453
+ * Parses FTP FEAT output into a normalized feature set.
3454
+ *
3455
+ * @param input - Parsed FTP response, raw string, or individual response lines.
3456
+ * @returns Normalized feature names, raw feature lines, and MLST fact names.
3457
+ */
3458
+ declare function parseFtpFeatures(input: FtpResponse | string | string[]): FtpFeatures;
3459
+
3460
+ /**
3461
+ * Parses an MLSD directory listing into normalized remote entries.
3462
+ *
3463
+ * @param input - Raw MLSD response body.
3464
+ * @param directory - Parent remote directory used to build entry paths.
3465
+ * @returns Remote entries excluding the `.` and `..` pseudo entries.
3466
+ * @throws {@link ParseError} When any listing line is malformed.
3467
+ */
3468
+ declare function parseMlsdList(input: string, directory?: string): RemoteEntry[];
3469
+ /**
3470
+ * Parses a Unix-style FTP `LIST` response into normalized remote entries.
3471
+ *
3472
+ * This parser covers the common `ls -l` shape returned by classic FTP daemons and
3473
+ * is used as a compatibility fallback when a server does not support MLSD.
3474
+ *
3475
+ * @param input - Raw LIST response body.
3476
+ * @param directory - Parent remote directory used to build entry paths.
3477
+ * @param now - Reference date used when LIST entries include time but omit year.
3478
+ * @returns Remote entries excluding `.` and `..` pseudo entries.
3479
+ * @throws {@link ParseError} When any non-summary listing line is malformed.
3480
+ */
3481
+ declare function parseUnixList(input: string, directory?: string, now?: Date): RemoteEntry[];
3482
+ /**
3483
+ * Parses one Unix-style FTP `LIST` line.
3484
+ *
3485
+ * @param line - Raw listing line in an `ls -l` compatible format.
3486
+ * @param directory - Parent remote directory used to build the entry path.
3487
+ * @param now - Reference date used when the line omits a year.
3488
+ * @returns Normalized remote entry with raw LIST metadata retained.
3489
+ * @throws {@link ParseError} When the line is not a supported Unix LIST entry.
3490
+ */
3491
+ declare function parseUnixListLine(line: string, directory?: string, now?: Date): RemoteEntry;
3492
+ /**
3493
+ * Parses a single MLSD or MLST fact line.
3494
+ *
3495
+ * @param line - Raw fact line in `fact=value; name` format.
3496
+ * @param directory - Parent remote directory used to build the entry path.
3497
+ * @returns A normalized remote entry with parsed facts in `raw` metadata.
3498
+ * @throws {@link ParseError} When the line does not contain facts and a name.
3499
+ */
3500
+ declare function parseMlsdLine(line: string, directory?: string): RemoteEntry;
3501
+ /**
3502
+ * Parses the UTC timestamp format used by MLST/MLSD `modify` facts.
3503
+ *
3504
+ * @param input - Timestamp text such as `20260427010203.123`.
3505
+ * @returns A UTC Date when the timestamp is valid, otherwise `undefined`.
3506
+ */
3507
+ declare function parseMlstTimestamp(input: string | undefined): Date | undefined;
3508
+
3145
3509
  /**
3146
3510
  * SFTP v3 file attribute encoding and decoding (draft-ietf-secsh-filexfer-02 §5).
3147
3511
  *
@@ -3311,6 +3675,15 @@ interface NativeSftpProviderOptions {
3311
3675
  * traffic. Disabled when omitted or `0`.
3312
3676
  */
3313
3677
  keepaliveIntervalMs?: number;
3678
+ /**
3679
+ * Maximum concurrent file-transfer operations the engine should schedule
3680
+ * against a single SFTP session. Each in-flight read/write occupies an
3681
+ * outstanding SFTP request slot multiplexed over the same SSH channel; the
3682
+ * default of `8` keeps memory bounded on commodity servers, but high-RTT
3683
+ * links and modern OpenSSH builds can comfortably handle 16\u201364. Must be
3684
+ * a positive integer.
3685
+ */
3686
+ maxConcurrency?: number;
3314
3687
  }
3315
3688
  /**
3316
3689
  * Low-level handles exposed by a native SFTP session for diagnostics and
@@ -5020,4 +5393,4 @@ declare function joinRemotePath(...segments: string[]): string;
5020
5393
  */
5021
5394
  declare function basenameRemotePath(input: string): string;
5022
5395
 
5023
- export { AbortError, type AgeRetentionPolicy, ApprovalRegistry, ApprovalRejectedError, type ApprovalRequest, type ApprovalStatus, type AtomicDeployActivateOperation, type AtomicDeployActivateStep, type AtomicDeployPlan, type AtomicDeployPruneStep, type AtomicDeployStrategy, type AuthenticationCapability, AuthenticationError, AuthorizationError, type AzureBlobProviderOptions, type BandwidthSleep, type BandwidthThrottle, type BandwidthThrottleOptions, type Base64EnvSecretSource, type BuiltInProviderId, type BuiltinCapabilityMatrixEntry, type BuiltinProviderMatrixId, CLASSIC_PROVIDER_IDS, type CapabilitySet, type ChecksumCapability, type ClassicProviderId, type ClientDiagnostics, type CompareRemoteManifestsOptions, ConfigurationError, type ConnectionDiagnosticTimings, type ConnectionDiagnosticsResult, ConnectionError, type ConnectionProfile, type ConventionEndpoint, type CopyBetweenOptions, type CountRetentionPolicy, type CreateApprovalGateOptions, type CreateAtomicDeployPlanOptions, type CreateInboxRouteOptions, type CreateOutboxRouteOptions, type CreateRemoteBrowserOptions, type CreateRemoteManifestOptions, type CreateSyncPlanOptions, type CreateWebhookAuditLogOptions, type CronExpression, type CronField, type CronScheduleTrigger, DEFAULT_FAILED_SUBDIR, DEFAULT_PROCESSED_SUBDIR, type DiffRemoteTreesOptions, type DispatchWebhookOptions, type DispatchWebhookResult, type DownloadFileOptions, type DropboxProviderOptions, type EnvSecretSource, type EvaluateRetentionOptions, type FileSecretSource, type FileZillaSite, type FriendlyTransferOptions, type FtpFeatures, type FtpPassiveHostStrategy, type FtpProviderOptions, type FtpReplyErrorInput, type FtpResponse, FtpResponseParser, type FtpResponseStatus, type FtpsDataProtection, type FtpsMode, type FtpsProviderOptions, type GcsProviderOptions, type GoogleDriveProviderOptions, type HttpFetch, type HttpProviderOptions, type ImportFileZillaSitesResult, type ImportOpenSshConfigOptions, type ImportOpenSshConfigResult, type ImportWinScpSessionsResult, InMemoryAuditLog, type IntervalScheduleTrigger, type JsonlWriter, type KnownHostsEntry, type KnownHostsMarker, type ListOptions, type LocalProviderOptions, type LogLevel, type LogRecord, type LogRecordInput, type LoggerMethod, type MemoryProviderEntry, type MemoryProviderOptions, type MetadataCapability, type MftAuditEntry, type MftAuditEntryType, type MftAuditLog, type MftInboxConvention, type MftOutboxConvention, type MftRoute, type MftRouteEndpoint, type MftRouteFilter, type MftRouteOperation, type MftSchedule, type MftScheduleTrigger, MftScheduler, type MftSchedulerOptions, type MkdirOptions, type NativeSftpProviderOptions, type NativeSftpRawSession, type OAuthAccessToken, type OAuthRefreshCallback, type OAuthTokenSecretSourceOptions, type OneDriveProviderOptions, type OpenSshConfigEntry, ParseError, PathAlreadyExistsError, PathNotFoundError, PermissionDeniedError, type ProgressEventInput, ProtocolError, type AuthenticationCapability as ProviderAuthenticationCapability, type CapabilitySet as ProviderCapabilities, type ChecksumCapability as ProviderChecksumCapability, type ProviderFactory, type ProviderId, type MetadataCapability as ProviderMetadataCapability, ProviderRegistry, type ProviderSelection, type ProviderTransferEndpointRole, type ProviderTransferExecutorOptions, type ProviderTransferOperations, type ProviderTransferReadRequest, type ProviderTransferReadResult, type ProviderTransferRequest, type ProviderTransferSessionResolver, type ProviderTransferSessionResolverInput, type ProviderTransferWriteRequest, type ProviderTransferWriteResult, REDACTED, REMOTE_MANIFEST_FORMAT_VERSION, type RemoteBreadcrumb, type RemoteBrowser, type RemoteBrowserFilter, type RemoteBrowserSnapshot, type RemoteEntry, type RemoteEntrySortKey, type RemoteEntrySortOrder, type RemoteEntryType, type RemoteFileAdapter, type RemoteFileEndpoint, type RemoteFileSystem, type RemoteManifest, type RemoteManifestEntry, type RemotePermissions, type RemoteProtocol, type RemoteStat, type RemoteTreeDiff, type RemoteTreeDiffEntry, type RemoteTreeDiffReason, type RemoteTreeDiffStatus, type RemoteTreeDiffSummary, type RemoteTreeEntry, type RemoteTreeFilter, type RemoveOptions, type RenameOptions, type ResolveSecretOptions, type ResolvedConnectionProfile, type ResolvedOpenSshHost, type ResolvedSshProfile, type ResolvedTlsProfile, type RetentionEvaluation, type RetentionPolicy, type RmdirOptions, RouteRegistry, type RunConnectionDiagnosticsOptions, type RunRouteOptions, type S3MultipartCheckpoint, type S3MultipartOptions, type S3MultipartPart, type S3MultipartResumeKey, type S3MultipartResumeStore, type S3ProviderOptions, ScheduleRegistry, type ScheduleRouteRunner, type ScheduleTimerHooks, type SecretProvider, type SecretSource, type SecretValue, type NativeSftpProviderOptions as SftpProviderOptions, type NativeSftpRawSession as SftpRawSession, type SpecializedErrorDetails, type SshAgentSource, type SshAlgorithms, type SshKeyboardInteractiveChallenge, type SshKeyboardInteractiveHandler, type SshKeyboardInteractivePrompt, type SshKnownHostsSource, type SshProfile, type SshSocketFactory, type SshSocketFactoryContext, type StatOptions, type SyncConflictPolicy, type SyncDeletePolicy, type SyncDirection, type SyncEndpointInput, TimeoutError, type TlsProfile, type TlsSecretSource, type TransferAttempt, type TransferAttemptError, type TransferBandwidthLimit, type TransferByteRange, TransferClient, type TransferClientOptions, type TransferDataChunk, type TransferDataSource, type TransferEndpoint, TransferEngine, type TransferEngineExecuteOptions, type TransferEngineOptions, TransferError, type TransferExecutionContext, type TransferExecutionResult, type TransferExecutor, type TransferJob, type TransferOperation, type TransferPlan, type TransferPlanAction, type TransferPlanInput, type TransferPlanStep, type TransferPlanSummary, type TransferProgressEvent, type TransferProvider, TransferQueue, type TransferQueueExecutorResolver, type TransferQueueItem, type TransferQueueItemStatus, type TransferQueueOptions, type TransferQueueRunOptions, type TransferQueueSummary, type TransferReceipt, type TransferResult, type TransferResultInput, type TransferRetryDecisionInput, type TransferRetryPolicy, type TransferSession, type TransferTimeoutPolicy, type TransferVerificationResult, UnsupportedFeatureError, type UploadFileOptions, type ValueSecretSource, VerificationError, type WalkRemoteTreeOptions, type WebDavProviderOptions, type WebhookRetryPolicy, type WebhookSignature, type WebhookTarget, type WinScpSession, ZeroTransfer, type ZeroTransferCapabilities, ZeroTransferError, type ZeroTransferErrorDetails, type ZeroTransferLogger, type ZeroTransferOptions, assertSafeFtpArgument, basenameRemotePath, buildRemoteBreadcrumbs, compareRemoteManifests, composeAuditLogs, copyBetween, createApprovalGate, createAtomicDeployPlan, createAzureBlobProviderFactory, createBandwidthThrottle, createDropboxProviderFactory, createFtpProviderFactory, createFtpsProviderFactory, createGcsProviderFactory, createGoogleDriveProviderFactory, createHttpProviderFactory, createInboxRoute, createJsonlAuditLog, createLocalProviderFactory, createMemoryProviderFactory, createMemoryS3MultipartResumeStore, createNativeSftpProviderFactory, createOAuthTokenSecretSource, createOneDriveProviderFactory, createOutboxRoute, createProgressEvent, createProviderTransferExecutor, createRemoteBrowser, createRemoteManifest, createS3ProviderFactory, createNativeSftpProviderFactory as createSftpProviderFactory, createSyncPlan, createTransferClient, createTransferJobsFromPlan, createTransferPlan, createTransferResult, createWebDavProviderFactory, createWebhookAuditLog, diffRemoteTrees, dispatchWebhook, downloadFile, emitLog, errorFromFtpReply, evaluateRetention, filterRemoteEntries, formatCapabilityMatrixMarkdown, freezeReceipt, getBuiltinCapabilityMatrix, importFileZillaSites, importOpenSshConfig, importWinScpSessions, inboxFailedPath, inboxProcessedPath, isClassicProviderId, isSensitiveKey, joinRemotePath, matchKnownHosts, matchKnownHostsEntry, nextCronFireAt, nextScheduleFireAt, noopLogger, normalizeRemotePath, parentRemotePath, parseCronExpression, parseFtpFeatures, parseFtpResponseLines, parseKnownHosts, parseMlsdLine, parseMlsdList, parseMlstTimestamp, parseOpenSshConfig, parseRemoteManifest, parseUnixList, parseUnixListLine, redactCommand, redactConnectionProfile, redactObject, redactSecretSource, redactValue, resolveConnectionProfileSecrets, resolveOpenSshHost, resolveProviderId, resolveSecret, runConnectionDiagnostics, runRoute, serializeRemoteManifest, signWebhookPayload, sortRemoteEntries, summarizeClientDiagnostics, summarizeError, summarizeTransferPlan, throttleByteIterable, uploadFile, validateConnectionProfile, validateSchedule, walkRemoteTree };
5396
+ export { AbortError, type AgeRetentionPolicy, ApprovalRegistry, ApprovalRejectedError, type ApprovalRequest, type ApprovalStatus, type AtomicDeployActivateOperation, type AtomicDeployActivateStep, type AtomicDeployPlan, type AtomicDeployPruneStep, type AtomicDeployStrategy, type AuthenticationCapability, AuthenticationError, AuthorizationError, type AzureBlobProviderOptions, type BandwidthSleep, type BandwidthThrottle, type BandwidthThrottleOptions, type Base64EnvSecretSource, type BuiltInProviderId, type BuiltinCapabilityMatrixEntry, type BuiltinProviderMatrixId, CLASSIC_PROVIDER_IDS, type CapabilitySet, type ChecksumCapability, type ClassicProviderId, type ClientDiagnostics, type CompareRemoteManifestsOptions, ConfigurationError, type ConnectionDiagnosticTimings, type ConnectionDiagnosticsResult, ConnectionError, type ConnectionPoolOptions, type ConnectionProfile, type ConventionEndpoint, type CopyBetweenOptions, type CountRetentionPolicy, type CreateApprovalGateOptions, type CreateAtomicDeployPlanOptions, type CreateInboxRouteOptions, type CreateOutboxRouteOptions, type CreateRemoteBrowserOptions, type CreateRemoteManifestOptions, type CreateSyncPlanOptions, type CreateWebhookAuditLogOptions, type CronExpression, type CronField, type CronScheduleTrigger, DEFAULT_FAILED_SUBDIR, DEFAULT_PROCESSED_SUBDIR, DEFAULT_SSH_ALGORITHM_PREFERENCES, type DiffRemoteTreesOptions, type DispatchWebhookOptions, type DispatchWebhookResult, type DownloadFileOptions, type DropboxProviderOptions, type EnvSecretSource, type EvaluateRetentionOptions, type FileSecretSource, type FileSystemS3MultipartResumeStoreOptions, type FileZillaSite, type FriendlyTransferOptions, type FtpFeatures, type FtpPassiveHostStrategy, type FtpProviderOptions, type FtpReplyErrorInput, type FtpResponse, FtpResponseParser, type FtpResponseStatus, type FtpsDataProtection, type FtpsMode, type FtpsProviderOptions, type GcsProviderOptions, type GoogleDriveProviderOptions, type HttpFetch, type HttpProviderOptions, type ImportFileZillaSitesResult, type ImportOpenSshConfigOptions, type ImportOpenSshConfigResult, type ImportWinScpSessionsResult, InMemoryAuditLog, type IntervalScheduleTrigger, type JsonlWriter, type KnownHostsEntry, type KnownHostsMarker, type ListOptions, type LocalProviderOptions, type LogLevel, type LogRecord, type LogRecordInput, type LoggerMethod, type MemoryProviderEntry, type MemoryProviderOptions, type MetadataCapability, type MftAuditEntry, type MftAuditEntryType, type MftAuditLog, type MftInboxConvention, type MftOutboxConvention, type MftRoute, type MftRouteEndpoint, type MftRouteFilter, type MftRouteOperation, type MftSchedule, type MftScheduleTrigger, MftScheduler, type MftSchedulerOptions, type MkdirOptions, type NativeSftpProviderOptions, type NativeSftpRawSession, type NegotiatedSshAlgorithms, type OAuthAccessToken, type OAuthRefreshCallback, type OAuthTokenSecretSourceOptions, type OneDriveProviderOptions, type OpenSshConfigEntry, ParseError, PathAlreadyExistsError, PathNotFoundError, PermissionDeniedError, type PooledTransferClient, type ProgressEventInput, ProtocolError, type AuthenticationCapability as ProviderAuthenticationCapability, type CapabilitySet as ProviderCapabilities, type ChecksumCapability as ProviderChecksumCapability, type ProviderFactory, type ProviderId, type MetadataCapability as ProviderMetadataCapability, ProviderRegistry, type ProviderSelection, type ProviderTransferEndpointRole, type ProviderTransferExecutorOptions, type ProviderTransferOperations, type ProviderTransferReadRequest, type ProviderTransferReadResult, type ProviderTransferRequest, type ProviderTransferSessionResolver, type ProviderTransferSessionResolverInput, type ProviderTransferWriteRequest, type ProviderTransferWriteResult, REDACTED, REMOTE_MANIFEST_FORMAT_VERSION, type RemoteBreadcrumb, type RemoteBrowser, type RemoteBrowserFilter, type RemoteBrowserSnapshot, type RemoteEntry, type RemoteEntrySortKey, type RemoteEntrySortOrder, type RemoteEntryType, type RemoteFileAdapter, type RemoteFileEndpoint, type RemoteFileSystem, type RemoteManifest, type RemoteManifestEntry, type RemotePermissions, type RemoteProtocol, type RemoteStat, type RemoteTreeDiff, type RemoteTreeDiffEntry, type RemoteTreeDiffReason, type RemoteTreeDiffStatus, type RemoteTreeDiffSummary, type RemoteTreeEntry, type RemoteTreeFilter, type RemoveOptions, type RenameOptions, type ResolveSecretOptions, type ResolvedConnectionProfile, type ResolvedOpenSshHost, type ResolvedSshProfile, type ResolvedTlsProfile, type RetentionEvaluation, type RetentionPolicy, type RmdirOptions, RouteRegistry, type RunConnectionDiagnosticsOptions, type RunRouteOptions, type S3MultipartCheckpoint, type S3MultipartOptions, type S3MultipartPart, type S3MultipartResumeKey, type S3MultipartResumeStore, type S3ProviderOptions, ScheduleRegistry, type ScheduleRouteRunner, type ScheduleTimerHooks, type SecretProvider, type SecretSource, type SecretValue, type NativeSftpProviderOptions as SftpProviderOptions, type NativeSftpRawSession as SftpRawSession, type SpecializedErrorDetails, type SshAgentSource, type SshAlgorithmPreferences, type SshAlgorithms, SshAuthSession, SshConnectionManager, SshDataReader, SshDataWriter, SshDisconnectReason, type SshKeyboardInteractiveChallenge, type SshKeyboardInteractiveCredential, type SshKeyboardInteractiveHandler, type SshKeyboardInteractivePrompt, type SshKnownHostsSource, type SshPasswordCredential, type SshProfile, type SshPublickeyCredential, SshSessionChannel, type SshSocketFactory, type SshSocketFactoryContext, SshTransportConnection, type SshTransportConnectionOptions, SshTransportHandshake, type SshTransportHandshakeResult, type StatOptions, type SyncConflictPolicy, type SyncDeletePolicy, type SyncDirection, type SyncEndpointInput, TimeoutError, type TlsProfile, type TlsSecretSource, type TransferAttempt, type TransferAttemptError, type TransferBandwidthLimit, type TransferByteRange, TransferClient, type TransferClientOptions, type TransferDataChunk, type TransferDataSource, type TransferEndpoint, TransferEngine, type TransferEngineExecuteOptions, type TransferEngineOptions, TransferError, type TransferExecutionContext, type TransferExecutionResult, type TransferExecutor, type TransferJob, type TransferOperation, type TransferPlan, type TransferPlanAction, type TransferPlanInput, type TransferPlanStep, type TransferPlanSummary, type TransferProgressEvent, type TransferProvider, TransferQueue, type TransferQueueExecutorResolver, type TransferQueueItem, type TransferQueueItemStatus, type TransferQueueOptions, type TransferQueueRunOptions, type TransferQueueSummary, type TransferReceipt, type TransferResult, type TransferResultInput, type TransferRetryDecisionInput, type TransferRetryPolicy, type TransferSession, type TransferTimeoutPolicy, type TransferVerificationResult, UnsupportedFeatureError, type UploadFileOptions, type ValueSecretSource, VerificationError, type WalkRemoteTreeOptions, type WebDavProviderOptions, type WebhookRetryPolicy, type WebhookSignature, type WebhookTarget, type WinScpSession, ZeroTransfer, type ZeroTransferCapabilities, ZeroTransferError, type ZeroTransferErrorDetails, type ZeroTransferLogger, type ZeroTransferOptions, assertSafeFtpArgument, basenameRemotePath, buildPublickeyCredential, buildRemoteBreadcrumbs, compareRemoteManifests, composeAuditLogs, copyBetween, createApprovalGate, createAtomicDeployPlan, createAzureBlobProviderFactory, createBandwidthThrottle, createDropboxProviderFactory, createFileSystemS3MultipartResumeStore, createFtpProviderFactory, createFtpsProviderFactory, createGcsProviderFactory, createGoogleDriveProviderFactory, createHttpProviderFactory, createInboxRoute, createJsonlAuditLog, createLocalProviderFactory, createMemoryProviderFactory, createMemoryS3MultipartResumeStore, createNativeSftpProviderFactory, createOAuthTokenSecretSource, createOneDriveProviderFactory, createOutboxRoute, createPooledTransferClient, createProgressEvent, createProviderTransferExecutor, createRemoteBrowser, createRemoteManifest, createS3ProviderFactory, createNativeSftpProviderFactory as createSftpProviderFactory, createSyncPlan, createTransferClient, createTransferJobsFromPlan, createTransferPlan, createTransferResult, createWebDavProviderFactory, createWebhookAuditLog, diffRemoteTrees, dispatchWebhook, downloadFile, emitLog, errorFromFtpReply, evaluateRetention, filterRemoteEntries, formatCapabilityMatrixMarkdown, freezeReceipt, getBuiltinCapabilityMatrix, importFileZillaSites, importOpenSshConfig, importWinScpSessions, inboxFailedPath, inboxProcessedPath, isClassicProviderId, isSensitiveKey, joinRemotePath, matchKnownHosts, matchKnownHostsEntry, negotiateSshAlgorithms, nextCronFireAt, nextScheduleFireAt, noopLogger, normalizeRemotePath, parentRemotePath, parseCronExpression, parseFtpFeatures, parseFtpResponseLines, parseKnownHosts, parseMlsdLine, parseMlsdList, parseMlstTimestamp, parseOpenSshConfig, parseRemoteManifest, parseUnixList, parseUnixListLine, redactCommand, redactConnectionProfile, redactObject, redactSecretSource, redactValue, resolveConnectionProfileSecrets, resolveOpenSshHost, resolveProviderId, resolveSecret, runConnectionDiagnostics, runRoute, serializeRemoteManifest, signWebhookPayload, sortRemoteEntries, summarizeClientDiagnostics, summarizeError, summarizeTransferPlan, throttleByteIterable, uploadFile, validateConnectionProfile, validateSchedule, walkRemoteTree };