@zero-transfer/ssh 0.4.6 → 0.4.8
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/README.md +0 -2
- package/dist/index.cjs +405 -164
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +229 -25
- package/dist/index.d.ts +229 -25
- package/dist/index.mjs +402 -164
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/client/ZeroTransfer.ts","../../../src/errors/ZeroTransferError.ts","../../../src/logging/Logger.ts","../../../src/profiles/ProfileValidator.ts","../../../src/core/ProviderId.ts","../../../src/core/ProviderRegistry.ts","../../../src/core/TransferClient.ts","../../../src/core/createTransferClient.ts","../../../src/client/operations.ts","../../../src/transfers/BandwidthThrottle.ts","../../../src/transfers/createProviderTransferExecutor.ts","../../../src/services/TransferService.ts","../../../src/transfers/TransferEngine.ts","../../../src/mft/runRoute.ts","../../../src/logging/redaction.ts","../../../src/profiles/SecretSource.ts","../../../src/profiles/ProfileRedactor.ts","../../../src/diagnostics/index.ts","../../../src/core/ConnectionPool.ts","../../../src/providers/local/LocalProvider.ts","../../../src/utils/path.ts","../../../src/providers/memory/MemoryProvider.ts","../../../src/profiles/resolveConnectionProfileSecrets.ts","../../../src/profiles/OAuthTokenSource.ts","../../../src/profiles/importers/KnownHostsParser.ts","../../../src/profiles/importers/OpenSshConfigImporter.ts","../../../src/profiles/importers/FileZillaImporter.ts","../../../src/profiles/importers/WinScpImporter.ts","../../../src/errors/errorFactory.ts","../../../src/transfers/TransferPlan.ts","../../../src/transfers/TransferQueue.ts","../../../src/sync/createRemoteBrowser.ts","../../../src/sync/createSyncPlan.ts","../../../src/sync/createAtomicDeployPlan.ts","../../../src/sync/walkRemoteTree.ts","../../../src/sync/diffRemoteTrees.ts","../../../src/sync/manifest.ts","../../../src/utils/mainModule.ts","../../../src/protocols/ssh/transport/SshTransportConnection.ts","../../../src/protocols/ssh/binary/SshDataReader.ts","../../../src/protocols/ssh/binary/SshDataWriter.ts","../../../src/protocols/ssh/transport/SshTransportHandshake.ts","../../../src/protocols/ssh/transport/SshAlgorithmNegotiation.ts","../../../src/protocols/ssh/transport/SshIdentification.ts","../../../src/protocols/ssh/transport/SshKexInit.ts","../../../src/protocols/ssh/transport/SshKexCurve25519.ts","../../../src/protocols/ssh/transport/SshKeyDerivation.ts","../../../src/protocols/ssh/transport/SshNewKeys.ts","../../../src/protocols/ssh/transport/SshTransportPacket.ts","../../../src/protocols/ssh/transport/SshHostKeyVerification.ts","../../../src/protocols/ssh/transport/SshTransportProtection.ts","../../../src/protocols/ssh/auth/SshAuthMessages.ts","../../../src/protocols/ssh/auth/SshAuthSession.ts","../../../src/protocols/ssh/auth/SshPublickeyCredentialBuilder.ts","../../../src/protocols/ssh/connection/SshConnectionMessages.ts","../../../src/protocols/ssh/connection/SshSessionChannel.ts","../../../src/protocols/ssh/connection/SshConnectionManager.ts","../../../src/protocols/ssh/runSshCommand.ts"],"sourcesContent":["/**\n * Client facade for the ZeroTransfer SDK foundation.\n *\n * This module intentionally keeps the top-level API small while protocol-specific\n * behavior is delegated to injected adapters. The facade owns lifecycle state,\n * event emission, logging coordination, and common capability discovery.\n *\n * @module client/ZeroTransfer\n */\nimport { EventEmitter } from \"node:events\";\nimport { createTransferClient } from \"../core/createTransferClient\";\nimport { isClassicProviderId } from \"../core/ProviderId\";\nimport { UnsupportedFeatureError } from \"../errors/ZeroTransferError\";\nimport { emitLog, noopLogger, type ZeroTransferLogger } from \"../logging/Logger\";\nimport type { RemoteFileAdapter } from \"../protocols/RemoteFileAdapter\";\nimport type {\n ConnectionProfile,\n ListOptions,\n RemoteEntry,\n RemoteProtocol,\n RemoteStat,\n StatOptions,\n} from \"../types/public\";\n\n/**\n * Construction options for a {@link ZeroTransfer} instance.\n *\n * @remarks\n * The adapter option is primarily used by protocol implementations and tests. Until\n * the built-in FTP, FTPS, and SFTP adapters are implemented, callers can inject a\n * compatible adapter to exercise the facade contract.\n */\nexport interface ZeroTransferOptions {\n /** Protocol used when the connection profile does not provide one. */\n protocol?: RemoteProtocol;\n /** Structured logger used for lifecycle and operation records. */\n logger?: ZeroTransferLogger;\n /** Protocol adapter that performs concrete remote file operations. */\n adapter?: RemoteFileAdapter;\n}\n\n/**\n * Lightweight capability snapshot for the current client instance.\n */\nexport interface ZeroTransferCapabilities {\n /** The protocol selected for this client facade. */\n protocol: RemoteProtocol;\n /** Whether a concrete protocol adapter has been supplied. */\n adapterReady: boolean;\n}\n\n/**\n * SDK entry point for FTP, FTPS, and SFTP workflows.\n *\n * @remarks\n * ZeroTransfer extends Node.js EventEmitter so applications can observe lifecycle\n * events while still using promise-based APIs for operations. The facade is\n * deliberately protocol-neutral; concrete behavior lives behind\n * {@link RemoteFileAdapter}.\n *\n */\nexport class ZeroTransfer extends EventEmitter {\n /** Creates a provider-neutral transfer client with the built-in provider registry. */\n static readonly createTransferClient = createTransferClient;\n\n /** Protocol selected for this client instance. */\n readonly protocol: RemoteProtocol;\n\n private readonly logger: ZeroTransferLogger;\n private readonly adapter: RemoteFileAdapter | undefined;\n private connected = false;\n\n /**\n * Creates a client facade without opening a network connection.\n *\n * @param options - Optional facade configuration, logger, and protocol adapter.\n */\n constructor(options: ZeroTransferOptions = {}) {\n super();\n this.protocol = options.protocol ?? \"ftp\";\n this.logger = options.logger ?? noopLogger;\n this.adapter = options.adapter;\n }\n\n /**\n * Creates a new client facade using the provided options.\n *\n * @param options - Optional facade configuration, logger, and adapter.\n * @returns A disconnected {@link ZeroTransfer} instance.\n */\n static create(options: ZeroTransferOptions = {}): ZeroTransfer {\n return new ZeroTransfer(options);\n }\n\n /**\n * Creates a client and connects it in one step.\n *\n * @param profile - Remote host, authentication, and protocol connection settings.\n * @param options - Optional facade settings that can be overridden by the profile.\n * @returns A connected {@link ZeroTransfer} instance.\n * @throws {@link UnsupportedFeatureError} When no adapter is available for the protocol.\n */\n static async connect(\n profile: ConnectionProfile,\n options: ZeroTransferOptions = {},\n ): Promise<ZeroTransfer> {\n const clientOptions: ZeroTransferOptions = { ...options };\n\n if (profile.logger !== undefined) {\n clientOptions.logger = profile.logger;\n }\n\n if (profile.protocol !== undefined) {\n clientOptions.protocol = profile.protocol;\n } else if (isClassicProviderId(profile.provider)) {\n clientOptions.protocol = profile.provider;\n }\n\n const client = new ZeroTransfer(clientOptions);\n await client.connect(profile);\n return client;\n }\n\n /**\n * Opens a remote connection through the configured protocol adapter.\n *\n * @param profile - Remote host, authentication, timeout, logger, and protocol settings.\n * @returns A promise that resolves after the adapter reports a successful connection.\n * @throws {@link UnsupportedFeatureError} When the client does not have an adapter.\n */\n async connect(profile: ConnectionProfile): Promise<void> {\n const adapter = this.requireAdapter();\n const protocol =\n profile.protocol ??\n (isClassicProviderId(profile.provider) ? profile.provider : this.protocol);\n emitLog(this.logger, \"info\", {\n component: \"client\",\n host: profile.host,\n message: \"Connecting\",\n protocol,\n });\n await adapter.connect({\n ...profile,\n protocol,\n });\n this.connected = true;\n this.emit(\"connect\", {\n host: profile.host,\n protocol,\n });\n }\n\n /**\n * Closes the active remote connection if one exists.\n *\n * @returns A promise that resolves after the adapter disconnects or immediately when idle.\n */\n async disconnect(): Promise<void> {\n if (this.adapter !== undefined && this.connected) {\n await this.adapter.disconnect();\n }\n\n this.connected = false;\n this.emit(\"disconnect\");\n }\n\n /**\n * Checks whether the facade currently considers the adapter connected.\n *\n * @returns `true` after a successful connection and before disconnection.\n */\n isConnected(): boolean {\n return this.connected;\n }\n\n /**\n * Describes protocol and adapter readiness for feature discovery.\n *\n * @returns A capability snapshot for diagnostics and UI state.\n */\n getCapabilities(): ZeroTransferCapabilities {\n return {\n adapterReady: this.adapter !== undefined,\n protocol: this.protocol,\n };\n }\n\n /**\n * Lists remote entries for a path using the configured adapter.\n *\n * @param path - Remote directory path to inspect.\n * @param options - Optional listing controls such as recursion and abort signal.\n * @returns Normalized remote entries for the requested directory.\n * @throws {@link UnsupportedFeatureError} When the client does not have an adapter.\n */\n async list(path: string, options?: ListOptions): Promise<RemoteEntry[]> {\n return this.requireAdapter().list(path, options);\n }\n\n /**\n * Reads metadata for a remote path using the configured adapter.\n *\n * @param path - Remote file, directory, or symbolic-link path to inspect.\n * @param options - Optional stat controls such as abort signal.\n * @returns Normalized metadata for an existing remote entry.\n * @throws {@link UnsupportedFeatureError} When the client does not have an adapter.\n */\n async stat(path: string, options?: StatOptions): Promise<RemoteStat> {\n return this.requireAdapter().stat(path, options);\n }\n\n /**\n * Returns the configured adapter or raises the alpha unsupported-feature error.\n *\n * @returns A concrete remote file adapter ready to execute operations.\n * @throws {@link UnsupportedFeatureError} When no adapter has been provided.\n */\n private requireAdapter(): RemoteFileAdapter {\n if (this.adapter === undefined) {\n throw new UnsupportedFeatureError({\n message: `The ${this.protocol.toUpperCase()} adapter is not implemented in this alpha foundation yet`,\n protocol: this.protocol,\n retryable: false,\n });\n }\n\n return this.adapter;\n }\n}\n","/**\n * Structured ZeroTransfer error hierarchy.\n *\n * The classes in this module preserve protocol details, retryability, command/path\n * context, and machine-readable codes so application code does not need to parse\n * human error messages.\n *\n * @module errors/ZeroTransferError\n */\nimport type { RemoteProtocol } from \"../types/public\";\n\n/**\n * Complete set of fields required to create a ZeroTransfer error.\n */\nexport interface ZeroTransferErrorDetails {\n /** Stable machine-readable error code. */\n code: string;\n /** Human-readable error message safe to show in logs or diagnostics. */\n message: string;\n /** Original error or exception that caused this error. */\n cause?: unknown;\n /** Protocol active when the error occurred. */\n protocol?: RemoteProtocol;\n /** Remote host associated with the failing operation. */\n host?: string;\n /** Protocol command associated with the failure, if any. */\n command?: string;\n /** FTP response code associated with the failure. */\n ftpCode?: number;\n /** SFTP status code associated with the failure. */\n sftpCode?: number;\n /** Remote path associated with the failure. */\n path?: string;\n /** Whether retry policy may safely retry this failure. */\n retryable: boolean;\n /** Additional structured details for diagnostics. */\n details?: Record<string, unknown>;\n}\n\n/**\n * Error construction input for subclasses that provide default codes.\n */\nexport type SpecializedErrorDetails = Omit<ZeroTransferErrorDetails, \"code\"> & {\n /** Optional override for the subclass default code. */\n code?: string;\n};\n\n/**\n * Base class for all typed ZeroTransfer errors.\n */\nexport class ZeroTransferError extends Error {\n /** Stable machine-readable error code. */\n readonly code: string;\n /** Protocol active when the error occurred. */\n readonly protocol?: RemoteProtocol;\n /** Remote host associated with the failing operation. */\n readonly host?: string;\n /** Protocol command associated with the failure, if any. */\n readonly command?: string;\n /** FTP response code associated with the failure. */\n readonly ftpCode?: number;\n /** SFTP status code associated with the failure. */\n readonly sftpCode?: number;\n /** Remote path associated with the failure. */\n readonly path?: string;\n /** Whether retry policy may safely retry this failure. */\n readonly retryable: boolean;\n /** Additional structured details for diagnostics. */\n readonly details?: Record<string, unknown>;\n\n /**\n * Creates a structured SDK error.\n *\n * @param details - Code, message, retryability, and optional protocol context.\n */\n constructor(details: ZeroTransferErrorDetails) {\n super(details.message, details.cause === undefined ? undefined : { cause: details.cause });\n this.name = new.target.name;\n this.code = details.code;\n this.retryable = details.retryable;\n\n if (details.protocol !== undefined) this.protocol = details.protocol;\n if (details.host !== undefined) this.host = details.host;\n if (details.command !== undefined) this.command = details.command;\n if (details.ftpCode !== undefined) this.ftpCode = details.ftpCode;\n if (details.sftpCode !== undefined) this.sftpCode = details.sftpCode;\n if (details.path !== undefined) this.path = details.path;\n if (details.details !== undefined) this.details = details.details;\n }\n\n /**\n * Serializes the error into a plain object suitable for logs or API responses.\n *\n * @returns A JSON-safe object containing public structured error fields.\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n protocol: this.protocol,\n host: this.host,\n command: this.command,\n ftpCode: this.ftpCode,\n sftpCode: this.sftpCode,\n path: this.path,\n retryable: this.retryable,\n details: this.details,\n };\n }\n}\n\n/**\n * Applies a subclass default code while preserving caller overrides.\n *\n * @param details - Subclass error details with optional code override.\n * @param code - Default code for the specific subclass.\n * @returns Complete base error details.\n */\nfunction withDefaultCode(details: SpecializedErrorDetails, code: string): ZeroTransferErrorDetails {\n return {\n ...details,\n code: details.code ?? code,\n };\n}\n\n/** Error raised when a remote connection cannot be opened or is lost unexpectedly. */\nexport class ConnectionError extends ZeroTransferError {\n /**\n * Creates a connection failure.\n *\n * @param details - Error context with optional host, protocol, and retryability details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_CONNECTION_ERROR\"));\n }\n}\n\n/** Error raised when authentication credentials are rejected. */\nexport class AuthenticationError extends ZeroTransferError {\n /**\n * Creates an authentication failure.\n *\n * @param details - Error context with optional host, protocol, and command details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_AUTHENTICATION_ERROR\"));\n }\n}\n\n/** Error raised when authenticated credentials are not authorized for an operation. */\nexport class AuthorizationError extends ZeroTransferError {\n /**\n * Creates an authorization failure.\n *\n * @param details - Error context with optional path and protocol details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_AUTHORIZATION_ERROR\"));\n }\n}\n\n/** Error raised when a requested remote path does not exist. */\nexport class PathNotFoundError extends ZeroTransferError {\n /**\n * Creates a missing-path failure.\n *\n * @param details - Error context with optional path and protocol details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_PATH_NOT_FOUND\"));\n }\n}\n\n/** Error raised when a create or rename operation targets an existing path. */\nexport class PathAlreadyExistsError extends ZeroTransferError {\n /**\n * Creates an already-exists failure.\n *\n * @param details - Error context with optional path and command details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_PATH_ALREADY_EXISTS\"));\n }\n}\n\n/** Error raised when the remote server denies access to a path or command. */\nexport class PermissionDeniedError extends ZeroTransferError {\n /**\n * Creates a permission failure.\n *\n * @param details - Error context with optional path, command, and protocol details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_PERMISSION_DENIED\"));\n }\n}\n\n/** Error raised when an operation exceeds its configured timeout. */\nexport class TimeoutError extends ZeroTransferError {\n /**\n * Creates a timeout failure.\n *\n * @param details - Error context with optional duration and retryability details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_TIMEOUT\"));\n }\n}\n\n/** Error raised when an operation is cancelled by an AbortSignal or caller action. */\nexport class AbortError extends ZeroTransferError {\n /**\n * Creates an aborted-operation failure.\n *\n * @param details - Error context with optional operation and path details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_ABORTED\"));\n }\n}\n\n/** Error raised when a server response violates protocol expectations. */\nexport class ProtocolError extends ZeroTransferError {\n /**\n * Creates a protocol failure.\n *\n * @param details - Error context with optional response code and command details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_PROTOCOL_ERROR\"));\n }\n}\n\n/** Error raised when protocol text or metadata cannot be parsed safely. */\nexport class ParseError extends ZeroTransferError {\n /**\n * Creates a parser failure.\n *\n * @param details - Error context with malformed input details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_PARSE_ERROR\"));\n }\n}\n\n/** Error raised when an upload, download, or stream transfer fails. */\nexport class TransferError extends ZeroTransferError {\n /**\n * Creates a transfer failure.\n *\n * @param details - Error context with optional path, bytes, and retryability details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_TRANSFER_ERROR\"));\n }\n}\n\n/** Error raised when post-transfer verification fails. */\nexport class VerificationError extends ZeroTransferError {\n /**\n * Creates a verification failure.\n *\n * @param details - Error context with checksum, size, or timestamp mismatch details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_VERIFICATION_ERROR\"));\n }\n}\n\n/** Error raised when a requested protocol feature is not implemented or unavailable. */\nexport class UnsupportedFeatureError extends ZeroTransferError {\n /**\n * Creates an unsupported-feature failure.\n *\n * @param details - Error context describing the missing feature or adapter.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_UNSUPPORTED_FEATURE\"));\n }\n}\n\n/** Error raised when user-provided options or paths are invalid before network I/O. */\nexport class ConfigurationError extends ZeroTransferError {\n /**\n * Creates a configuration failure.\n *\n * @param details - Error context describing the invalid option or argument.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_CONFIGURATION_ERROR\"));\n }\n}\n","/**\n * Structured logging contracts and helpers for ZeroTransfer.\n *\n * The logger shape is intentionally compatible with popular structured loggers while\n * staying small enough for applications to implement directly.\n *\n * @module logging/Logger\n */\n/** Supported ZeroTransfer log levels. */\nexport type LogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n\n/**\n * Complete structured log record emitted by ZeroTransfer helpers.\n */\nexport interface LogRecord {\n /** Severity level for the record. */\n level: LogLevel;\n /** Human-readable summary message. */\n message: string;\n /** SDK component that produced the record. */\n component?: string;\n /** Active protocol for the record. */\n protocol?: string;\n /** Remote host associated with the record. */\n host?: string;\n /** Correlation id for a connection lifecycle. */\n connectionId?: string;\n /** Correlation id for a protocol command. */\n commandId?: string;\n /** Correlation id for a transfer lifecycle. */\n transferId?: string;\n /** Remote or local path associated with the record. */\n path?: string;\n /** Operation duration in milliseconds. */\n durationMs?: number;\n /** Byte count associated with the operation. */\n bytes?: number;\n /** Additional structured fields supplied by adapters or services. */\n [key: string]: unknown;\n}\n\n/**\n * Log record input accepted by {@link emitLog}; the helper adds the level.\n */\nexport interface LogRecordInput extends Omit<LogRecord, \"level\"> {\n /** Human-readable summary message. */\n message: string;\n}\n\n/**\n * Logger method signature used for each severity level.\n *\n * @param record - Structured log record.\n * @param message - Convenience message argument for console-like loggers.\n */\nexport type LoggerMethod = (record: LogRecord, message?: string) => void;\n\n/**\n * Partial structured logger accepted by ZeroTransfer.\n */\nexport interface ZeroTransferLogger {\n /** Receives highly detailed diagnostic records. */\n trace?: LoggerMethod;\n /** Receives development/debugging records. */\n debug?: LoggerMethod;\n /** Receives normal lifecycle records. */\n info?: LoggerMethod;\n /** Receives recoverable issue records. */\n warn?: LoggerMethod;\n /** Receives failed operation records. */\n error?: LoggerMethod;\n}\n\n/**\n * Logger implementation that intentionally drops every record.\n */\nexport const noopLogger: Required<ZeroTransferLogger> = {\n trace() {},\n debug() {},\n info() {},\n warn() {},\n error() {},\n};\n\n/**\n * Emits a structured log record if the logger implements the requested level.\n *\n * @param logger - Logger that may contain a method for the requested level.\n * @param level - Severity level to emit.\n * @param record - Log record fields without the level property.\n * @returns Nothing; missing logger methods are ignored.\n */\nexport function emitLog(logger: ZeroTransferLogger, level: LogLevel, record: LogRecordInput): void {\n const method = logger[level];\n\n if (method === undefined) {\n return;\n }\n\n const logRecord: LogRecord = {\n ...record,\n level,\n };\n\n method(logRecord, logRecord.message);\n}\n","/**\n * Connection profile validation helpers.\n *\n * @module profiles/ProfileValidator\n */\nimport { Buffer } from \"node:buffer\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { ConnectionProfile, SshProfile, TlsProfile } from \"../types/public\";\nimport { resolveProviderId } from \"../core/ProviderId\";\n\n/** TLS protocol versions accepted by Node's `SecureVersion` option. */\nconst TLS_VERSIONS = new Set([\"TLSv1\", \"TLSv1.1\", \"TLSv1.2\", \"TLSv1.3\"]);\n/** Hex characters in a SHA-256 certificate fingerprint after separators are removed. */\nconst SHA256_FINGERPRINT_HEX_LENGTH = 64;\n/** Raw SHA-256 digest byte length. */\nconst SHA256_DIGEST_BYTE_LENGTH = 32;\n\n/**\n * Validates provider-neutral connection profile fields before provider lookup.\n *\n * @param profile - Profile to validate.\n * @returns The original profile when valid.\n * @throws {@link ConfigurationError} When required provider, host, or numeric fields are invalid.\n */\nexport function validateConnectionProfile(profile: ConnectionProfile): ConnectionProfile {\n if (resolveProviderId(profile) === undefined) {\n throw new ConfigurationError({\n message: \"Connection profiles must include a provider or protocol\",\n retryable: false,\n });\n }\n\n if (profile.host.trim().length === 0) {\n throw new ConfigurationError({\n message: \"Connection profiles must include a non-empty host\",\n retryable: false,\n });\n }\n\n if (profile.port !== undefined && !isValidPort(profile.port)) {\n throw new ConfigurationError({\n details: { port: profile.port },\n message: \"Connection profile port must be an integer between 1 and 65535\",\n retryable: false,\n });\n }\n\n if (profile.timeoutMs !== undefined && !isPositiveFiniteNumber(profile.timeoutMs)) {\n throw new ConfigurationError({\n details: { timeoutMs: profile.timeoutMs },\n message: \"Connection profile timeoutMs must be a positive finite number\",\n retryable: false,\n });\n }\n\n if (profile.tls !== undefined) {\n validateTlsProfile(profile.tls);\n }\n\n if (profile.ssh !== undefined) {\n validateSshProfile(profile.ssh);\n }\n\n return profile;\n}\n\n/**\n * Validates SSH profile policy fields that can be checked without resolving secrets.\n *\n * @param profile - SSH profile to validate.\n * @throws {@link ConfigurationError} When host-key pin values are invalid.\n */\nfunction validateSshProfile(profile: SshProfile): void {\n validatePinnedHostKeySha256(profile.pinnedHostKeySha256);\n\n if (profile.algorithms !== undefined) {\n validateSshAlgorithms(profile.algorithms);\n }\n\n if (profile.agent !== undefined) {\n validateSshAgentSource(profile.agent);\n }\n\n if (\n profile.keyboardInteractive !== undefined &&\n typeof profile.keyboardInteractive !== \"function\"\n ) {\n throw new ConfigurationError({\n details: { keyboardInteractive: typeof profile.keyboardInteractive },\n message: \"Connection profile ssh.keyboardInteractive must be a function when provided\",\n retryable: false,\n });\n }\n\n if (profile.socketFactory !== undefined && typeof profile.socketFactory !== \"function\") {\n throw new ConfigurationError({\n details: { socketFactory: typeof profile.socketFactory },\n message: \"Connection profile ssh.socketFactory must be a function when provided\",\n retryable: false,\n });\n }\n}\n\n/**\n * Validates SSH algorithm override shape without duplicating ssh2's literal unions.\n *\n * @param value - Algorithm override object from an SSH profile.\n * @throws {@link ConfigurationError} When overrides are not object-shaped or contain empty lists.\n */\nfunction validateSshAlgorithms(value: SshProfile[\"algorithms\"]): void {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw createSshAlgorithmsError(value);\n }\n\n const algorithms = value as Record<string, unknown>;\n\n for (const [name, list] of Object.entries(algorithms)) {\n if (list === undefined) {\n continue;\n }\n\n if (Array.isArray(list)) {\n if (!isNonEmptyStringArray(list)) {\n throw createSshAlgorithmsError({ [name]: list });\n }\n\n continue;\n }\n\n if (typeof list !== \"object\" || list === null || Array.isArray(list)) {\n throw createSshAlgorithmsError({ [name]: list });\n }\n\n const operationLists = list as Record<string, unknown>;\n\n for (const [operation, operationList] of Object.entries(operationLists)) {\n if (![\"append\", \"prepend\", \"remove\"].includes(operation)) {\n throw createSshAlgorithmsError({ [name]: list });\n }\n\n if (\n typeof operationList !== \"string\" &&\n (!Array.isArray(operationList) || !isNonEmptyStringArray(operationList))\n ) {\n throw createSshAlgorithmsError({ [name]: list });\n }\n }\n }\n}\n\nfunction isNonEmptyStringArray(value: unknown[]): value is string[] {\n return value.length > 0 && value.every((item) => typeof item === \"string\" && item.length > 0);\n}\n\n/**\n * Validates SSH agent source values.\n *\n * @param value - Agent socket path or agent implementation.\n * @throws {@link ConfigurationError} When the value is neither a non-empty path nor an agent object.\n */\nfunction validateSshAgentSource(value: SshProfile[\"agent\"]): void {\n if (typeof value === \"string\") {\n if (value.trim().length > 0) {\n return;\n }\n } else if (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { getIdentities?: unknown }).getIdentities === \"function\" &&\n typeof (value as { sign?: unknown }).sign === \"function\"\n ) {\n return;\n }\n\n throw new ConfigurationError({\n details: { agent: typeof value },\n message: \"Connection profile ssh.agent must be a non-empty socket path or agent object\",\n retryable: false,\n });\n}\n\n/**\n * Validates TLS profile policy fields that can be checked without resolving secrets.\n *\n * @param profile - TLS profile to validate.\n * @throws {@link ConfigurationError} When server name, boolean, or TLS-version fields are invalid.\n */\nfunction validateTlsProfile(profile: TlsProfile): void {\n if (profile.servername !== undefined && profile.servername.trim().length === 0) {\n throw new ConfigurationError({\n message: \"Connection profile tls.servername must be non-empty when provided\",\n retryable: false,\n });\n }\n\n if (profile.rejectUnauthorized !== undefined && typeof profile.rejectUnauthorized !== \"boolean\") {\n throw new ConfigurationError({\n details: { rejectUnauthorized: profile.rejectUnauthorized },\n message: \"Connection profile tls.rejectUnauthorized must be a boolean\",\n retryable: false,\n });\n }\n\n validateTlsVersion(profile.minVersion, \"minVersion\");\n validateTlsVersion(profile.maxVersion, \"maxVersion\");\n validatePinnedFingerprint256(profile.pinnedFingerprint256);\n}\n\n/**\n * Validates SHA-256 certificate fingerprint pinning values.\n *\n * @param value - Single fingerprint or allowed fingerprint set from the TLS profile.\n * @throws {@link ConfigurationError} When a fingerprint is empty or not SHA-256 hex.\n */\nfunction validatePinnedFingerprint256(value: TlsProfile[\"pinnedFingerprint256\"]): void {\n if (value === undefined) {\n return;\n }\n\n const fingerprints = Array.isArray(value) ? value : [value];\n\n if (fingerprints.length === 0) {\n throw createPinnedFingerprintError(value);\n }\n\n for (const fingerprint of fingerprints) {\n if (typeof fingerprint !== \"string\" || !isSha256Fingerprint(fingerprint)) {\n throw createPinnedFingerprintError(value);\n }\n }\n}\n\n/**\n * Validates SHA-256 SSH host-key pinning values.\n *\n * @param value - Single fingerprint or allowed fingerprint set from the SSH profile.\n * @throws {@link ConfigurationError} When a fingerprint is empty or not a SHA-256 digest.\n */\nfunction validatePinnedHostKeySha256(value: SshProfile[\"pinnedHostKeySha256\"]): void {\n if (value === undefined) {\n return;\n }\n\n const fingerprints = Array.isArray(value) ? value : [value];\n\n if (fingerprints.length === 0) {\n throw createPinnedHostKeyError(value);\n }\n\n for (const fingerprint of fingerprints) {\n if (typeof fingerprint !== \"string\" || !isSshHostKeySha256Fingerprint(fingerprint)) {\n throw createPinnedHostKeyError(value);\n }\n }\n}\n\n/**\n * Checks whether a string is a supported SHA-256 certificate fingerprint.\n *\n * @param value - Candidate fingerprint string.\n * @returns `true` when the value is 64 hex characters after optional colons are removed.\n */\nfunction isSha256Fingerprint(value: string): boolean {\n const normalized = value.trim().replace(/:/g, \"\");\n return normalized.length === SHA256_FINGERPRINT_HEX_LENGTH && /^[a-f0-9]+$/i.test(normalized);\n}\n\n/**\n * Checks whether a string is a supported SSH SHA-256 host-key fingerprint.\n *\n * @param value - Candidate fingerprint string.\n * @returns `true` when the value is OpenSSH SHA256 base64, bare base64, or SHA-256 hex.\n */\nfunction isSshHostKeySha256Fingerprint(value: string): boolean {\n const trimmed = value.trim();\n\n if (isSha256Fingerprint(trimmed)) {\n return true;\n }\n\n const bare = trimmed.startsWith(\"SHA256:\") ? trimmed.slice(\"SHA256:\".length) : trimmed;\n const padded = padBase64(bare);\n\n if (!/^[a-z0-9+/]+={0,2}$/i.test(padded)) {\n return false;\n }\n\n try {\n return Buffer.from(padded, \"base64\").byteLength === SHA256_DIGEST_BYTE_LENGTH;\n } catch {\n return false;\n }\n}\n\nfunction padBase64(value: string): string {\n const remainder = value.length % 4;\n\n return remainder === 0 ? value : `${value}${\"=\".repeat(4 - remainder)}`;\n}\n\n/**\n * Creates a consistent validation error for invalid certificate pin values.\n *\n * @param value - Invalid profile value included in diagnostics.\n * @returns Configuration error describing the supported fingerprint format.\n */\nfunction createPinnedFingerprintError(value: unknown): ConfigurationError {\n return new ConfigurationError({\n details: { pinnedFingerprint256: value },\n message:\n \"Connection profile tls.pinnedFingerprint256 must be a SHA-256 hex fingerprint or non-empty array of fingerprints\",\n retryable: false,\n });\n}\n\n/**\n * Creates a consistent validation error for invalid SSH host-key pin values.\n *\n * @param value - Invalid profile value included in diagnostics.\n * @returns Configuration error describing the supported fingerprint formats.\n */\nfunction createPinnedHostKeyError(value: unknown): ConfigurationError {\n return new ConfigurationError({\n details: { pinnedHostKeySha256: value },\n message:\n \"Connection profile ssh.pinnedHostKeySha256 must be an OpenSSH SHA256, base64, or hex fingerprint or non-empty array of fingerprints\",\n retryable: false,\n });\n}\n\n/**\n * Creates a consistent validation error for invalid SSH algorithm overrides.\n *\n * @param value - Invalid profile value included in diagnostics.\n * @returns Configuration error describing the expected ssh2-compatible shape.\n */\nfunction createSshAlgorithmsError(value: unknown): ConfigurationError {\n return new ConfigurationError({\n details: { algorithms: value },\n message: \"Connection profile ssh.algorithms must use SSH-compatible non-empty algorithm lists\",\n retryable: false,\n });\n}\n\n/**\n * Validates a configured TLS protocol version string.\n *\n * @param value - TLS version value from the profile, if provided.\n * @param field - Profile field name used in diagnostics.\n * @throws {@link ConfigurationError} When the value is not one of Node's supported TLS versions.\n */\nfunction validateTlsVersion(value: TlsProfile[\"minVersion\"], field: string): void {\n if (value === undefined) {\n return;\n }\n\n if (!TLS_VERSIONS.has(value)) {\n throw new ConfigurationError({\n details: { [field]: value },\n message: `Connection profile tls.${field} must be a supported TLS version`,\n retryable: false,\n });\n }\n}\n\nfunction isValidPort(value: number): boolean {\n return Number.isInteger(value) && value >= 1 && value <= 65_535;\n}\n\nfunction isPositiveFiniteNumber(value: number): boolean {\n return Number.isFinite(value) && value > 0;\n}\n","/**\n * Provider identifiers used by the provider-neutral ZeroTransfer core.\n *\n * @module core/ProviderId\n */\n\n/** Classic remote-transfer providers kept compatible with the original protocol field. */\nexport const CLASSIC_PROVIDER_IDS = [\"ftp\", \"ftps\", \"sftp\"] as const;\n\n/** Provider ids that map directly to the original protocol-focused alpha facade. */\nexport type ClassicProviderId = (typeof CLASSIC_PROVIDER_IDS)[number];\n\n/** Provider ids reserved for first-party ZeroTransfer adapters. */\nexport type BuiltInProviderId =\n | ClassicProviderId\n | \"memory\"\n | \"local\"\n | \"http\"\n | \"https\"\n | \"webdav\"\n | \"s3\"\n | \"azure-blob\"\n | \"gcs\"\n | \"dropbox\"\n | \"google-drive\"\n | \"one-drive\";\n\n/** Provider identifier accepted by registries, profiles, and provider factories. */\nexport type ProviderId = BuiltInProviderId | (string & {});\n\n/** Minimal shape used to resolve a provider from new and compatibility profile fields. */\nexport interface ProviderSelection {\n /** Provider id for provider-neutral ZeroTransfer profiles. */\n provider?: ProviderId;\n /** Compatibility protocol field accepted while the provider-neutral API rolls out. */\n protocol?: ClassicProviderId;\n}\n\n/**\n * Checks whether a provider id belongs to the classic FTP/FTPS/SFTP family.\n *\n * @param providerId - Provider id to inspect.\n * @returns `true` when the id is one of the classic protocol providers.\n */\nexport function isClassicProviderId(\n providerId: ProviderId | undefined,\n): providerId is ClassicProviderId {\n return (\n typeof providerId === \"string\" && CLASSIC_PROVIDER_IDS.includes(providerId as ClassicProviderId)\n );\n}\n\n/**\n * Resolves the provider id from a profile, preferring the new `provider` field.\n *\n * @param selection - Profile-like object containing provider and/or protocol fields.\n * @returns The selected provider id, or `undefined` when neither field is present.\n */\nexport function resolveProviderId(selection: ProviderSelection): ProviderId | undefined {\n return selection.provider ?? selection.protocol;\n}\n","/**\n * Provider registry for the provider-neutral ZeroTransfer core.\n *\n * @module core/ProviderRegistry\n */\nimport { ConfigurationError, UnsupportedFeatureError } from \"../errors/ZeroTransferError\";\nimport type { ProviderFactory } from \"../providers/ProviderFactory\";\nimport type { CapabilitySet } from \"./CapabilitySet\";\nimport type { ProviderId } from \"./ProviderId\";\n\n/** Mutable registry of provider factories available to a transfer client. */\nexport class ProviderRegistry {\n private readonly factories = new Map<ProviderId, ProviderFactory>();\n\n /**\n * Creates a registry and optionally seeds it with provider factories.\n *\n * @param providers - Provider factories to register immediately.\n */\n constructor(providers: Iterable<ProviderFactory> = []) {\n for (const provider of providers) {\n this.register(provider);\n }\n }\n\n /**\n * Registers a provider factory.\n *\n * @param provider - Provider factory to add.\n * @returns This registry for fluent setup.\n * @throws {@link ConfigurationError} When a provider id is registered twice.\n */\n register(provider: ProviderFactory): this {\n if (this.factories.has(provider.id)) {\n throw new ConfigurationError({\n details: { provider: provider.id },\n message: `Provider \"${provider.id}\" is already registered`,\n retryable: false,\n });\n }\n\n this.factories.set(provider.id, provider);\n return this;\n }\n\n /**\n * Removes a provider factory from the registry.\n *\n * @param providerId - Provider id to remove.\n * @returns `true` when a provider was removed.\n */\n unregister(providerId: ProviderId): boolean {\n return this.factories.delete(providerId);\n }\n\n /**\n * Checks whether a provider id is registered.\n *\n * @param providerId - Provider id to inspect.\n * @returns `true` when a provider factory exists.\n */\n has(providerId: ProviderId): boolean {\n return this.factories.has(providerId);\n }\n\n /**\n * Gets a provider factory when registered.\n *\n * @param providerId - Provider id to retrieve.\n * @returns The provider factory, or `undefined` when missing.\n */\n get(providerId: ProviderId): ProviderFactory | undefined {\n return this.factories.get(providerId);\n }\n\n /**\n * Gets a registered provider factory or throws a typed SDK error.\n *\n * @param providerId - Provider id to retrieve.\n * @returns The registered provider factory.\n * @throws {@link UnsupportedFeatureError} When no provider has been registered.\n */\n require(providerId: ProviderId): ProviderFactory {\n const provider = this.get(providerId);\n\n if (provider === undefined) {\n throw new UnsupportedFeatureError({\n details: { provider: providerId },\n message: `Provider \"${providerId}\" is not registered`,\n retryable: false,\n });\n }\n\n return provider;\n }\n\n /**\n * Gets a provider capability snapshot when registered.\n *\n * @param providerId - Provider id to inspect.\n * @returns Capability snapshot, or `undefined` when missing.\n */\n getCapabilities(providerId: ProviderId): CapabilitySet | undefined {\n return this.get(providerId)?.capabilities;\n }\n\n /**\n * Gets a provider capability snapshot or throws a typed SDK error.\n *\n * @param providerId - Provider id to inspect.\n * @returns Capability snapshot for the registered provider.\n * @throws {@link UnsupportedFeatureError} When no provider has been registered.\n */\n requireCapabilities(providerId: ProviderId): CapabilitySet {\n return this.require(providerId).capabilities;\n }\n\n /**\n * Lists registered provider factories in insertion order.\n *\n * @returns Registered provider factories.\n */\n list(): ProviderFactory[] {\n return [...this.factories.values()];\n }\n\n /**\n * Lists registered provider capabilities in insertion order.\n *\n * @returns Capability snapshots for every registered provider.\n */\n listCapabilities(): CapabilitySet[] {\n return this.list().map((provider) => provider.capabilities);\n }\n}\n","/**\n * Provider-neutral transfer client foundation.\n *\n * @module core/TransferClient\n */\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport {\n emitLog,\n noopLogger,\n type LogRecordInput,\n type ZeroTransferLogger,\n} from \"../logging/Logger\";\nimport { validateConnectionProfile } from \"../profiles/ProfileValidator\";\nimport type { ProviderFactory } from \"../providers/ProviderFactory\";\nimport type { ConnectionProfile } from \"../types/public\";\nimport type { CapabilitySet } from \"./CapabilitySet\";\nimport type { ProviderId } from \"./ProviderId\";\nimport { isClassicProviderId, resolveProviderId } from \"./ProviderId\";\nimport { ProviderRegistry } from \"./ProviderRegistry\";\nimport type { TransferSession } from \"./TransferSession\";\n\n/** Options used to create a provider-neutral transfer client. */\nexport interface TransferClientOptions {\n /** Existing registry to reuse. When omitted, a fresh empty registry is created. */\n registry?: ProviderRegistry;\n /** Provider factories to register with the client registry. */\n providers?: ProviderFactory[];\n /** Structured logger used for client lifecycle records. */\n logger?: ZeroTransferLogger;\n}\n\n/** Small provider-neutral client that owns provider lookup and connection setup. */\nexport class TransferClient {\n /** Provider registry used by this client. */\n readonly registry: ProviderRegistry;\n\n private readonly logger: ZeroTransferLogger;\n\n /**\n * Creates a transfer client without opening any provider connections.\n *\n * @param options - Optional registry, provider factories, and logger.\n */\n constructor(options: TransferClientOptions = {}) {\n this.registry = options.registry ?? new ProviderRegistry();\n this.logger = options.logger ?? noopLogger;\n\n for (const provider of options.providers ?? []) {\n this.registry.register(provider);\n }\n }\n\n /**\n * Registers a provider factory with this client's registry.\n *\n * @param provider - Provider factory to register.\n * @returns This client for fluent setup.\n */\n registerProvider(provider: ProviderFactory): this {\n this.registry.register(provider);\n return this;\n }\n\n /**\n * Checks whether this client can create sessions for a provider id.\n *\n * @param providerId - Provider id to inspect.\n * @returns `true` when a provider factory is registered.\n */\n hasProvider(providerId: ProviderId): boolean {\n return this.registry.has(providerId);\n }\n\n /** Lists all registered provider capability snapshots. */\n getCapabilities(): CapabilitySet[];\n /** Gets a specific provider capability snapshot. */\n getCapabilities(providerId: ProviderId): CapabilitySet;\n getCapabilities(providerId?: ProviderId): CapabilitySet | CapabilitySet[] {\n if (providerId === undefined) {\n return this.registry.listCapabilities();\n }\n\n return this.registry.requireCapabilities(providerId);\n }\n\n /**\n * Opens a provider session using `profile.provider`, with `profile.protocol` as compatibility fallback.\n *\n * @param profile - Connection profile containing a provider or legacy protocol field.\n * @returns A connected provider session.\n * @throws {@link ConfigurationError} When neither provider nor protocol is present.\n */\n async connect(profile: ConnectionProfile): Promise<TransferSession> {\n const validProfile = validateConnectionProfile(profile);\n const providerId = resolveProviderId(validProfile);\n\n if (providerId === undefined) {\n throw new ConfigurationError({\n message: \"Connection profiles must include a provider or protocol\",\n retryable: false,\n });\n }\n\n const providerFactory = this.registry.require(providerId);\n const provider = providerFactory.create();\n const normalizedProfile: ConnectionProfile = {\n ...validProfile,\n provider: providerId,\n };\n\n if (normalizedProfile.protocol === undefined && isClassicProviderId(providerId)) {\n normalizedProfile.protocol = providerId;\n }\n\n emitLog(this.logger, \"info\", createConnectLogRecord(normalizedProfile, providerId));\n\n return provider.connect(normalizedProfile);\n }\n}\n\nfunction createConnectLogRecord(\n profile: ConnectionProfile,\n providerId: ProviderId,\n): LogRecordInput {\n const record: LogRecordInput = {\n component: \"core\",\n host: profile.host,\n message: \"Connecting through provider\",\n provider: providerId,\n };\n\n if (isClassicProviderId(providerId)) {\n record.protocol = providerId;\n }\n\n return record;\n}\n","/**\n * Factory for provider-neutral ZeroTransfer clients.\n *\n * @module core/createTransferClient\n */\nimport { TransferClient, type TransferClientOptions } from \"./TransferClient\";\n\n/**\n * Creates a provider-neutral transfer client.\n *\n * The returned client owns a registry of provider factories and produces\n * `TransferSession` instances on demand via {@link TransferClient.connect}.\n * Registering only the providers you actually use keeps bundle size small\n * (each factory pulls in its own SDK dependencies).\n *\n * @param options - Optional registry, provider factories, and logger.\n * @returns A disconnected {@link TransferClient} instance.\n *\n * @example Multi-provider client\n * ```ts\n * import {\n * createS3ProviderFactory,\n * createSftpProviderFactory,\n * createTransferClient,\n * } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({\n * providers: [createSftpProviderFactory(), createS3ProviderFactory()],\n * });\n *\n * const session = await client.connect({\n * host: \"sftp.example.com\",\n * provider: \"sftp\",\n * username: \"deploy\",\n * ssh: { privateKey: { path: \"./keys/id_ed25519\" } },\n * });\n * try {\n * const list = await session.fs.list(\"/uploads\");\n * console.log(list);\n * } finally {\n * await session.disconnect();\n * }\n * ```\n *\n * @example Friendly one-shot helpers\n * ```ts\n * import { uploadFile } from \"@zero-transfer/sdk\";\n *\n * await uploadFile({\n * client,\n * destination: { path: \"/uploads/report.csv\", profile },\n * localPath: \"./out/report.csv\",\n * });\n * ```\n */\nexport function createTransferClient(options: TransferClientOptions = {}): TransferClient {\n return new TransferClient(options);\n}\n","/**\n * Friendly one-call helpers built on top of {@link runRoute}.\n *\n * These helpers give applications a quick surface for the common single-file flows\n * (`uploadFile`, `downloadFile`, `copyBetween`) without forcing them to assemble\n * {@link MftRoute} objects directly. Each helper composes a one-shot route and\n * delegates execution to the existing route runner so retry, abort, progress,\n * timeout, and bandwidth controls behave identically to scheduled runs.\n *\n * @module client/operations\n */\nimport { isAbsolute, resolve as resolvePath } from \"node:path\";\nimport type { TransferClient } from \"../core/TransferClient\";\nimport type { MftRoute } from \"../mft/MftRoute\";\nimport { runRoute, type RunRouteOptions } from \"../mft/runRoute\";\nimport type { TransferReceipt } from \"../transfers/TransferJob\";\nimport type { ConnectionProfile } from \"../types/public\";\n\n/** Endpoint shape accepted by the friendly helpers. */\nexport interface RemoteFileEndpoint {\n /** Provider profile used to open the session. */\n profile: ConnectionProfile;\n /** Provider, remote, or local path the helper operates on. */\n path: string;\n}\n\n/** Shared options consumed by {@link uploadFile}, {@link downloadFile}, and {@link copyBetween}. */\nexport type FriendlyTransferOptions = Omit<RunRouteOptions, \"client\" | \"route\"> & {\n /** Stable route id assigned to the synthetic route. Defaults to `\"upload:...\"`, `\"download:...\"`, or `\"copy:...\"`. */\n routeId?: string;\n /** Optional human-readable route name forwarded to telemetry. */\n routeName?: string;\n};\n\n/** Connection profile for the local filesystem provider. */\nconst LOCAL_PROFILE: ConnectionProfile = { host: \"local\", provider: \"local\" };\n\n/** Options for {@link uploadFile}. */\nexport interface UploadFileOptions extends FriendlyTransferOptions {\n /** Transfer client used to resolve both endpoint providers. */\n client: TransferClient;\n /** Local source path. Relative paths are resolved against `process.cwd()`. */\n localPath: string;\n /** Remote destination endpoint. */\n destination: RemoteFileEndpoint;\n}\n\n/**\n * Uploads a single local file to a remote endpoint.\n *\n * The remote provider is resolved from `destination.profile.provider`, so any\n * provider factory you registered with {@link createTransferClient} can be used\n * as the destination.\n *\n * @param options - Friendly upload options.\n * @returns Receipt produced by the underlying transfer engine.\n *\n * @example Upload to SFTP with public-key auth\n * ```ts\n * import {\n * createSftpProviderFactory,\n * createTransferClient,\n * uploadFile,\n * } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({ providers: [createSftpProviderFactory()] });\n *\n * await uploadFile({\n * client,\n * destination: {\n * path: \"/uploads/report.csv\",\n * profile: {\n * host: \"sftp.example.com\",\n * provider: \"sftp\",\n * username: \"deploy\",\n * ssh: { privateKey: { path: \"./keys/id_ed25519\" } },\n * },\n * },\n * localPath: \"./out/report.csv\",\n * });\n * ```\n */\nexport function uploadFile(options: UploadFileOptions): Promise<TransferReceipt> {\n const { client, destination, localPath, routeId, routeName, ...rest } = options;\n const route = buildRoute({\n destination: { path: destination.path, profile: destination.profile },\n id: routeId ?? `upload:${defaultRouteSuffix(localPath, destination.path)}`,\n name: routeName,\n operation: \"upload\",\n source: { path: absolutePath(localPath), profile: LOCAL_PROFILE },\n });\n return runRoute({ client, route, ...rest });\n}\n\n/** Options for {@link downloadFile}. */\nexport interface DownloadFileOptions extends FriendlyTransferOptions {\n /** Transfer client used to resolve both endpoint providers. */\n client: TransferClient;\n /** Remote source endpoint. */\n source: RemoteFileEndpoint;\n /** Local destination path. Relative paths are resolved against `process.cwd()`. */\n localPath: string;\n}\n\n/**\n * Downloads a single remote file to a local path.\n *\n * The remote provider is resolved from `source.profile.provider`. The local\n * destination path is created (including parent directories) on demand.\n *\n * @param options - Friendly download options.\n * @returns Receipt produced by the underlying transfer engine.\n *\n * @example Download from S3\n * ```ts\n * import {\n * createS3ProviderFactory,\n * createTransferClient,\n * downloadFile,\n * } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({ providers: [createS3ProviderFactory()] });\n *\n * await downloadFile({\n * client,\n * localPath: \"./tmp/snapshot.tar.gz\",\n * source: {\n * path: \"snapshots/2026-04-28/snapshot.tar.gz\",\n * profile: {\n * host: \"snapshots\", // S3 bucket\n * provider: \"s3\",\n * s3: { region: \"us-east-1\" },\n * },\n * },\n * });\n * ```\n */\nexport function downloadFile(options: DownloadFileOptions): Promise<TransferReceipt> {\n const { client, localPath, routeId, routeName, source, ...rest } = options;\n const route = buildRoute({\n destination: { path: absolutePath(localPath), profile: LOCAL_PROFILE },\n id: routeId ?? `download:${defaultRouteSuffix(source.path, localPath)}`,\n name: routeName,\n operation: \"download\",\n source: { path: source.path, profile: source.profile },\n });\n return runRoute({ client, route, ...rest });\n}\n\n/** Options for {@link copyBetween}. */\nexport interface CopyBetweenOptions extends FriendlyTransferOptions {\n /** Transfer client used to resolve both endpoint providers. */\n client: TransferClient;\n /** Source remote endpoint. */\n source: RemoteFileEndpoint;\n /** Destination remote endpoint. */\n destination: RemoteFileEndpoint;\n}\n\n/**\n * Copies a file between two remote endpoints in a single call.\n *\n * Both source and destination providers must be registered with the\n * {@link TransferClient}. Streams are piped end-to-end without staging the file\n * on the local disk.\n *\n * @param options - Friendly copy options.\n * @returns Receipt produced by the underlying transfer engine.\n *\n * @example Copy from SFTP to S3\n * ```ts\n * import {\n * copyBetween,\n * createS3ProviderFactory,\n * createSftpProviderFactory,\n * createTransferClient,\n * } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({\n * providers: [createSftpProviderFactory(), createS3ProviderFactory()],\n * });\n *\n * await copyBetween({\n * client,\n * source: {\n * path: \"/exports/daily.csv\",\n * profile: { host: \"sftp.example.com\", provider: \"sftp\", username: \"etl\" },\n * },\n * destination: {\n * path: \"warehouse/daily.csv\",\n * profile: { host: \"warehouse\", provider: \"s3\", s3: { region: \"us-east-1\" } },\n * },\n * });\n * ```\n */\nexport function copyBetween(options: CopyBetweenOptions): Promise<TransferReceipt> {\n const { client, destination, routeId, routeName, source, ...rest } = options;\n const route = buildRoute({\n destination: { path: destination.path, profile: destination.profile },\n id: routeId ?? `copy:${defaultRouteSuffix(source.path, destination.path)}`,\n name: routeName,\n operation: \"copy\",\n source: { path: source.path, profile: source.profile },\n });\n return runRoute({ client, route, ...rest });\n}\n\ninterface BuildRouteInput {\n id: string;\n name?: string | undefined;\n operation: NonNullable<MftRoute[\"operation\"]>;\n source: MftRoute[\"source\"];\n destination: MftRoute[\"destination\"];\n}\n\nfunction buildRoute(input: BuildRouteInput): MftRoute {\n const route: MftRoute = {\n destination: input.destination,\n id: input.id,\n operation: input.operation,\n source: input.source,\n };\n if (input.name !== undefined) route.name = input.name;\n return route;\n}\n\nfunction absolutePath(localPath: string): string {\n return isAbsolute(localPath) ? localPath : resolvePath(localPath);\n}\n\nfunction defaultRouteSuffix(source: string, destination: string): string {\n return `${source}->${destination}`;\n}\n","/**\n * Token-bucket bandwidth throttle for transfer streams.\n *\n * @module transfers/BandwidthThrottle\n */\nimport { AbortError, ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { TransferBandwidthLimit } from \"./TransferJob\";\n\n/** Sleep helper signature used by {@link createBandwidthThrottle}. */\nexport type BandwidthSleep = (delayMs: number, signal?: AbortSignal) => Promise<void>;\n\n/** Construction overrides for deterministic tests. */\nexport interface BandwidthThrottleOptions {\n /** Monotonic clock returning milliseconds since an arbitrary epoch. Defaults to `Date.now`. */\n now?: () => number;\n /** Sleep implementation honoring an optional abort signal. Defaults to a `setTimeout` helper. */\n sleep?: BandwidthSleep;\n}\n\n/** Token-bucket throttle used to pace transfer chunks. */\nexport interface BandwidthThrottle {\n /** Maximum sustained transfer rate in bytes per second. */\n readonly bytesPerSecond: number;\n /** Burst capacity in bytes available before throttling kicks in. */\n readonly burstBytes: number;\n /**\n * Consumes `bytes` from the bucket, awaiting refill when not enough tokens are available.\n *\n * @param bytes - Non-negative byte count being released by the throttle.\n * @param signal - Optional abort signal that interrupts pending waits.\n * @throws {@link AbortError} When the signal is aborted while waiting.\n */\n consume(bytes: number, signal?: AbortSignal): Promise<void>;\n}\n\n/**\n * Creates a token-bucket throttle that paces an asynchronous data pipeline to\n * a sustained {@link TransferBandwidthLimit}.\n *\n * Returns `undefined` when no limit is supplied so callers can omit throttling\n * without conditional branches at the call site.\n *\n * @param limit - Optional throughput limit. Returns `undefined` when omitted.\n * @param options - Optional clock/sleep overrides for deterministic tests.\n * @returns Throttle implementation when a limit is supplied, otherwise `undefined`.\n * @throws {@link ConfigurationError} When the supplied limit shape is invalid.\n */\nexport function createBandwidthThrottle(\n limit: TransferBandwidthLimit | undefined,\n options: BandwidthThrottleOptions = {},\n): BandwidthThrottle | undefined {\n if (limit === undefined) return undefined;\n\n const bytesPerSecond = normalizeRate(limit.bytesPerSecond);\n const burstBytes = normalizeBurst(limit.burstBytes, bytesPerSecond);\n const now = options.now ?? Date.now;\n const sleep = options.sleep ?? defaultSleep;\n\n let tokens = burstBytes;\n let lastRefillAt = now();\n\n function refill(): void {\n const current = now();\n const elapsedMs = Math.max(0, current - lastRefillAt);\n\n if (elapsedMs > 0) {\n tokens = Math.min(burstBytes, tokens + (elapsedMs / 1000) * bytesPerSecond);\n lastRefillAt = current;\n }\n }\n\n async function consume(bytes: number, signal?: AbortSignal): Promise<void> {\n if (!Number.isFinite(bytes) || bytes < 0) {\n throw new ConfigurationError({\n details: { bytes },\n message: \"Bandwidth throttle byte count must be a non-negative number\",\n retryable: false,\n });\n }\n\n if (bytes === 0) return;\n\n let remaining = bytes;\n\n while (remaining > 0) {\n throwIfAborted(signal);\n refill();\n\n if (tokens >= remaining) {\n tokens -= remaining;\n return;\n }\n\n if (tokens >= burstBytes) {\n // Bucket is full but the request still exceeds the burst. Drain the\n // full bucket and wait for the remainder at the sustained rate.\n const drained = tokens;\n tokens = 0;\n remaining -= drained;\n const waitMs = Math.ceil((Math.min(remaining, burstBytes) / bytesPerSecond) * 1000);\n await sleep(waitMs, signal);\n continue;\n }\n\n const deficit = Math.min(remaining, burstBytes) - tokens;\n const waitMs = Math.max(1, Math.ceil((deficit / bytesPerSecond) * 1000));\n await sleep(waitMs, signal);\n }\n }\n\n return { burstBytes, bytesPerSecond, consume };\n}\n\n/**\n * Wraps an async iterable of byte chunks so each chunk is released only after\n * the throttle has admitted its byte count.\n *\n * When `throttle` is `undefined`, the source iterable is returned unchanged.\n *\n * @param source - Async iterable that produces byte chunks.\n * @param throttle - Optional throttle that paces chunk emission.\n * @param signal - Optional abort signal interrupting pending waits.\n * @returns Async generator emitting the original chunks at the throttled rate.\n */\nexport function throttleByteIterable(\n source: AsyncIterable<Uint8Array>,\n throttle: BandwidthThrottle | undefined,\n signal?: AbortSignal,\n): AsyncIterable<Uint8Array> {\n if (throttle === undefined) return source;\n\n return {\n [Symbol.asyncIterator]: async function* () {\n for await (const chunk of source) {\n throwIfAborted(signal);\n if (chunk.byteLength > 0) {\n await throttle.consume(chunk.byteLength, signal);\n }\n yield chunk;\n }\n },\n };\n}\n\nfunction normalizeRate(value: number): number {\n if (!Number.isFinite(value) || value <= 0) {\n throw new ConfigurationError({\n details: { bytesPerSecond: value },\n message: \"Bandwidth limit bytesPerSecond must be a positive number\",\n retryable: false,\n });\n }\n\n return value;\n}\n\nfunction normalizeBurst(value: number | undefined, bytesPerSecond: number): number {\n if (value === undefined) return bytesPerSecond;\n\n if (!Number.isFinite(value) || value <= 0) {\n throw new ConfigurationError({\n details: { burstBytes: value },\n message: \"Bandwidth limit burstBytes must be a positive number when provided\",\n retryable: false,\n });\n }\n\n return value;\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted === true) {\n throw new AbortError({\n message: \"Bandwidth throttle wait aborted\",\n retryable: false,\n });\n }\n}\n\nfunction defaultSleep(delayMs: number, signal?: AbortSignal): Promise<void> {\n if (delayMs <= 0) return Promise.resolve();\n\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n cleanup();\n resolve();\n }, delayMs);\n\n const onAbort = () => {\n cleanup();\n reject(\n new AbortError({\n message: \"Bandwidth throttle wait aborted\",\n retryable: false,\n }),\n );\n };\n\n function cleanup(): void {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n }\n\n if (signal !== undefined) {\n if (signal.aborted) {\n onAbort();\n return;\n }\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n });\n}\n","/**\n * Transfer executor bridge for provider-backed read/write sessions.\n *\n * @module transfers/createProviderTransferExecutor\n */\nimport type { TransferSession } from \"../core/TransferSession\";\nimport { ConfigurationError, UnsupportedFeatureError } from \"../errors/ZeroTransferError\";\nimport type {\n ProviderTransferOperations,\n ProviderTransferReadRequest,\n ProviderTransferReadResult,\n ProviderTransferWriteRequest,\n ProviderTransferWriteResult,\n} from \"../providers/ProviderTransferOperations\";\nimport {\n createBandwidthThrottle,\n throttleByteIterable,\n type BandwidthThrottleOptions,\n} from \"./BandwidthThrottle\";\nimport type { TransferExecutionContext, TransferExecutor } from \"./TransferEngine\";\nimport type {\n TransferEndpoint,\n TransferExecutionResult,\n TransferJob,\n TransferOperation,\n TransferVerificationResult,\n} from \"./TransferJob\";\n\n/** Endpoint role used while resolving provider sessions for a transfer job. */\nexport type ProviderTransferEndpointRole = \"source\" | \"destination\";\n\n/** Input passed to provider transfer session resolvers. */\nexport interface ProviderTransferSessionResolverInput {\n /** Endpoint being resolved. */\n endpoint: TransferEndpoint;\n /** Whether the endpoint is the source or destination side of the transfer. */\n role: ProviderTransferEndpointRole;\n /** Job currently being executed. */\n job: TransferJob;\n}\n\n/** Resolves the connected provider session that owns an endpoint. */\nexport type ProviderTransferSessionResolver = (\n input: ProviderTransferSessionResolverInput,\n) => TransferSession | undefined;\n\n/** Options for {@link createProviderTransferExecutor}. */\nexport interface ProviderTransferExecutorOptions {\n /** Resolves connected provider sessions for source and destination endpoints. */\n resolveSession: ProviderTransferSessionResolver;\n /** Optional clock/sleep overrides for the bandwidth throttle. */\n throttle?: BandwidthThrottleOptions;\n}\n\n/**\n * Creates a {@link TransferExecutor} that reads from a source provider and writes to a destination provider.\n *\n * The returned executor supports single-object `upload`, `download`, and `copy` jobs. Provider sessions must\n * expose `session.transfers.read()` and `session.transfers.write()`; concrete providers remain responsible for\n * the actual streaming implementation.\n *\n * @param options - Session resolver used for source and destination endpoints.\n * @returns Transfer executor suitable for {@link TransferEngine.execute} or {@link TransferQueue}.\n */\nexport function createProviderTransferExecutor(\n options: ProviderTransferExecutorOptions,\n): TransferExecutor {\n return async (context) => {\n const { job } = context;\n\n if (!isReadWriteOperation(job.operation)) {\n throw new UnsupportedFeatureError({\n details: { jobId: job.id, operation: job.operation },\n message: `Provider read/write executor does not support transfer operation: ${job.operation}`,\n retryable: false,\n });\n }\n\n const source = requireEndpoint(job, \"source\");\n const destination = requireEndpoint(job, \"destination\");\n const sourceSession = options.resolveSession({ endpoint: source, job, role: \"source\" });\n const destinationSession = options.resolveSession({\n endpoint: destination,\n job,\n role: \"destination\",\n });\n const sourceTransfers = requireTransferOperations(sourceSession, source, \"source\", job);\n const destinationTransfers = requireTransferOperations(\n destinationSession,\n destination,\n \"destination\",\n job,\n );\n\n context.throwIfAborted();\n const readResult = await sourceTransfers.read(createReadRequest(context, source));\n context.throwIfAborted();\n const throttledReadResult = applyBandwidthThrottle(readResult, context, options.throttle);\n const writeResult = await destinationTransfers.write(\n createWriteRequest(context, destination, throttledReadResult),\n );\n\n return mergeProviderTransferResult(readResult, writeResult, job);\n };\n}\n\nfunction applyBandwidthThrottle(\n readResult: ProviderTransferReadResult,\n context: TransferExecutionContext,\n options: BandwidthThrottleOptions | undefined,\n): ProviderTransferReadResult {\n const throttle = createBandwidthThrottle(context.bandwidthLimit, options);\n\n if (throttle === undefined) return readResult;\n\n return {\n ...readResult,\n content: throttleByteIterable(readResult.content, throttle, context.signal),\n };\n}\n\nfunction isReadWriteOperation(operation: TransferOperation): boolean {\n return operation === \"copy\" || operation === \"download\" || operation === \"upload\";\n}\n\nfunction requireEndpoint(job: TransferJob, role: ProviderTransferEndpointRole): TransferEndpoint {\n const endpoint = role === \"source\" ? job.source : job.destination;\n\n if (endpoint === undefined) {\n throw new ConfigurationError({\n details: { jobId: job.id, operation: job.operation, role },\n message: `Transfer job requires a ${role} endpoint: ${job.id}`,\n retryable: false,\n });\n }\n\n return endpoint;\n}\n\nfunction requireTransferOperations(\n session: TransferSession | undefined,\n endpoint: TransferEndpoint,\n role: ProviderTransferEndpointRole,\n job: TransferJob,\n): ProviderTransferOperations {\n if (session === undefined) {\n throw new UnsupportedFeatureError({\n details: { endpoint: cloneEndpoint(endpoint), jobId: job.id, operation: job.operation, role },\n message: `No provider session resolved for ${role} endpoint: ${endpoint.path}`,\n retryable: false,\n });\n }\n\n if (session.transfers === undefined) {\n throw new UnsupportedFeatureError({\n details: {\n endpoint: cloneEndpoint(endpoint),\n jobId: job.id,\n operation: job.operation,\n provider: session.provider,\n role,\n },\n message: `Provider session does not expose transfer operations: ${session.provider}`,\n retryable: false,\n });\n }\n\n return session.transfers;\n}\n\nfunction createReadRequest(\n context: TransferExecutionContext,\n endpoint: TransferEndpoint,\n): ProviderTransferReadRequest {\n const request: ProviderTransferReadRequest = {\n attempt: context.attempt,\n endpoint: cloneEndpoint(endpoint),\n job: context.job,\n reportProgress: (bytesTransferred, totalBytes) =>\n context.reportProgress(bytesTransferred, totalBytes),\n throwIfAborted: () => context.throwIfAborted(),\n };\n\n if (context.signal !== undefined) request.signal = context.signal;\n if (context.bandwidthLimit !== undefined) {\n request.bandwidthLimit = { ...context.bandwidthLimit };\n }\n\n return request;\n}\n\nfunction createWriteRequest(\n context: TransferExecutionContext,\n endpoint: TransferEndpoint,\n readResult: ProviderTransferReadResult,\n): ProviderTransferWriteRequest {\n const request: ProviderTransferWriteRequest = {\n attempt: context.attempt,\n content: readResult.content,\n endpoint: cloneEndpoint(endpoint),\n job: context.job,\n reportProgress: (bytesTransferred, totalBytes) =>\n context.reportProgress(bytesTransferred, totalBytes),\n throwIfAborted: () => context.throwIfAborted(),\n };\n const totalBytes = readResult.totalBytes ?? context.job.totalBytes;\n\n if (context.signal !== undefined) request.signal = context.signal;\n if (context.bandwidthLimit !== undefined) {\n request.bandwidthLimit = { ...context.bandwidthLimit };\n }\n if (totalBytes !== undefined) request.totalBytes = totalBytes;\n if (context.job.resumed === true) request.offset = readResult.bytesRead ?? 0;\n if (readResult.verification !== undefined) {\n request.verification = cloneVerification(readResult.verification);\n }\n\n return request;\n}\n\nfunction mergeProviderTransferResult(\n readResult: ProviderTransferReadResult,\n writeResult: ProviderTransferWriteResult,\n job: TransferJob,\n): TransferExecutionResult {\n const result: TransferExecutionResult = {\n bytesTransferred: writeResult.bytesTransferred,\n };\n const totalBytes = writeResult.totalBytes ?? readResult.totalBytes ?? job.totalBytes;\n const warnings = [...(readResult.warnings ?? []), ...(writeResult.warnings ?? [])];\n\n if (totalBytes !== undefined) result.totalBytes = totalBytes;\n if (writeResult.resumed !== undefined) result.resumed = writeResult.resumed;\n if (writeResult.verified !== undefined) result.verified = writeResult.verified;\n if (writeResult.checksum !== undefined) result.checksum = writeResult.checksum;\n else if (readResult.checksum !== undefined) result.checksum = readResult.checksum;\n if (writeResult.verification !== undefined) {\n result.verification = cloneVerification(writeResult.verification);\n } else if (readResult.verification !== undefined) {\n result.verification = cloneVerification(readResult.verification);\n }\n if (warnings.length > 0) result.warnings = warnings;\n\n return result;\n}\n\nfunction cloneEndpoint(endpoint: TransferEndpoint): TransferEndpoint {\n const clone: TransferEndpoint = { path: endpoint.path };\n\n if (endpoint.provider !== undefined) clone.provider = endpoint.provider;\n\n return clone;\n}\n\nfunction cloneVerification(verification: TransferVerificationResult): TransferVerificationResult {\n const clone: TransferVerificationResult = { verified: verification.verified };\n\n if (verification.method !== undefined) clone.method = verification.method;\n if (verification.checksum !== undefined) clone.checksum = verification.checksum;\n if (verification.expectedChecksum !== undefined) {\n clone.expectedChecksum = verification.expectedChecksum;\n }\n if (verification.actualChecksum !== undefined) clone.actualChecksum = verification.actualChecksum;\n if (verification.details !== undefined) clone.details = { ...verification.details };\n\n return clone;\n}\n","/**\n * Transfer result and progress calculation helpers.\n *\n * These helpers are pure functions so future FTP, FTPS, and SFTP adapters can share\n * timing, throughput, and progress calculations without coupling to transport code.\n *\n * @module services/TransferService\n */\nimport type { TransferProgressEvent, TransferResult } from \"../types/public\";\n\n/**\n * Input used to create a final transfer result.\n */\nexport interface TransferResultInput {\n /** Local or remote source path when known. */\n sourcePath?: string;\n /** Local or remote destination path for the transfer. */\n destinationPath: string;\n /** Total bytes transferred. */\n bytesTransferred: number;\n /** Time the transfer began. */\n startedAt: Date;\n /** Time the transfer completed. */\n completedAt: Date;\n /** Whether the transfer resumed from an earlier partial state. */\n resumed?: boolean;\n /** Whether post-transfer verification succeeded. */\n verified?: boolean;\n /** Optional checksum value produced or verified by the transfer. */\n checksum?: string;\n}\n\n/**\n * Input used to create a transfer progress event.\n */\nexport interface ProgressEventInput {\n /** Stable transfer identifier for correlation. */\n transferId: string;\n /** Bytes transferred so far. */\n bytesTransferred: number;\n /** Time the transfer began. */\n startedAt: Date;\n /** Time to use for the progress calculation; defaults to current time. */\n now?: Date;\n /** Total expected bytes when known. */\n totalBytes?: number;\n}\n\n/**\n * Creates a final transfer result with duration and average throughput.\n *\n * @param input - Transfer paths, byte count, timestamps, and optional verification metadata.\n * @returns A normalized transfer result.\n */\nexport function createTransferResult(input: TransferResultInput): TransferResult {\n const durationMs = Math.max(0, input.completedAt.getTime() - input.startedAt.getTime());\n const result: TransferResult = {\n destinationPath: input.destinationPath,\n bytesTransferred: input.bytesTransferred,\n startedAt: input.startedAt,\n completedAt: input.completedAt,\n durationMs,\n averageBytesPerSecond: calculateBytesPerSecond(input.bytesTransferred, durationMs),\n resumed: input.resumed ?? false,\n verified: input.verified ?? false,\n };\n\n if (input.sourcePath !== undefined) result.sourcePath = input.sourcePath;\n if (input.checksum !== undefined) result.checksum = input.checksum;\n\n return result;\n}\n\n/**\n * Creates a progress event with elapsed time, rate, and optional percentage.\n *\n * @param input - Transfer id, byte count, start time, optional current time, and total bytes.\n * @returns A normalized transfer progress event.\n */\nexport function createProgressEvent(input: ProgressEventInput): TransferProgressEvent {\n const now = input.now ?? new Date();\n const elapsedMs = Math.max(0, now.getTime() - input.startedAt.getTime());\n const event: TransferProgressEvent = {\n transferId: input.transferId,\n bytesTransferred: input.bytesTransferred,\n startedAt: input.startedAt,\n elapsedMs,\n bytesPerSecond: calculateBytesPerSecond(input.bytesTransferred, elapsedMs),\n };\n\n if (input.totalBytes !== undefined) {\n event.totalBytes = input.totalBytes;\n event.percent = input.totalBytes > 0 ? (input.bytesTransferred / input.totalBytes) * 100 : 0;\n }\n\n return event;\n}\n\n/**\n * Calculates average throughput for a byte count and duration.\n *\n * @param bytes - Number of bytes transferred.\n * @param durationMs - Transfer duration in milliseconds.\n * @returns Average bytes per second, falling back to bytes for zero-duration samples.\n */\nfunction calculateBytesPerSecond(bytes: number, durationMs: number): number {\n if (durationMs <= 0) {\n return bytes;\n }\n\n return bytes / (durationMs / 1000);\n}\n","/**\n * Abort-aware transfer engine foundation.\n *\n * @module transfers/TransferEngine\n */\nimport {\n AbortError,\n TimeoutError,\n TransferError,\n ZeroTransferError,\n} from \"../errors/ZeroTransferError\";\nimport { createProgressEvent } from \"../services/TransferService\";\nimport type { TransferProgressEvent } from \"../types/public\";\nimport type {\n TransferAttempt,\n TransferAttemptError,\n TransferBandwidthLimit,\n TransferExecutionResult,\n TransferJob,\n TransferReceipt,\n TransferTimeoutPolicy,\n TransferVerificationResult,\n} from \"./TransferJob\";\n\n/** Context passed to a concrete transfer operation. */\nexport interface TransferExecutionContext {\n /** Job being executed. */\n job: TransferJob;\n /** One-based attempt number. */\n attempt: number;\n /** Abort signal active for this execution when supplied. */\n signal?: AbortSignal;\n /** Optional throughput limit shape for concrete executors to honor. */\n bandwidthLimit?: TransferBandwidthLimit;\n /** Throws an SDK abort error when the active signal has been cancelled. */\n throwIfAborted(): void;\n /** Emits a normalized progress event through engine options. */\n reportProgress(bytesTransferred: number, totalBytes?: number): TransferProgressEvent;\n}\n\n/** Concrete transfer operation implementation used by the engine. */\nexport type TransferExecutor = (\n context: TransferExecutionContext,\n) => Promise<TransferExecutionResult> | TransferExecutionResult;\n\n/** Input used by retry policy hooks. */\nexport interface TransferRetryDecisionInput {\n /** Error thrown by the failed attempt. */\n error: unknown;\n /** One-based attempt number that failed. */\n attempt: number;\n /** Job being executed. */\n job: TransferJob;\n}\n\n/** Retry policy for transfer execution. */\nexport interface TransferRetryPolicy {\n /** Maximum total attempts, including the first attempt. Defaults to `1`. */\n maxAttempts?: number;\n /** Decides whether a failed attempt should be retried. Defaults to SDK retryability metadata. */\n shouldRetry?(input: TransferRetryDecisionInput): boolean;\n /** Observes retry decisions before the next attempt starts. */\n onRetry?(input: TransferRetryDecisionInput): void;\n}\n\n/** Options used by {@link TransferEngine.execute}. */\nexport interface TransferEngineExecuteOptions {\n /** Abort signal used to cancel the job. */\n signal?: AbortSignal;\n /** Retry policy used for failed attempts. */\n retry?: TransferRetryPolicy;\n /** Progress observer for normalized transfer progress events. */\n onProgress?(event: TransferProgressEvent): void;\n /** Timeout policy enforced by the engine. */\n timeout?: TransferTimeoutPolicy;\n /** Optional throughput limit shape passed through to concrete executors. */\n bandwidthLimit?: TransferBandwidthLimit;\n}\n\n/** Construction options for deterministic tests and host integration. */\nexport interface TransferEngineOptions {\n /** Clock used for receipts and progress events. Defaults to `new Date()`. */\n now?: () => Date;\n}\n\n/**\n * Executes transfer jobs and produces audit-friendly receipts.\n *\n * The engine is the lowest-level entry point in the transfer stack: it owns\n * retry policy, attempt history, abort propagation, progress event\n * normalization, and receipt construction. Most callers reach the engine\n * indirectly through {@link runRoute}, {@link uploadFile}, {@link downloadFile},\n * {@link copyBetween}, or {@link TransferQueue}; instantiate it directly when\n * you need full control over execution semantics.\n *\n * @example Execute a single job with a custom executor\n * ```ts\n * import { TransferEngine, type TransferExecutor, type TransferJob } from \"@zero-transfer/sdk\";\n *\n * const engine = new TransferEngine();\n *\n * const executor: TransferExecutor = async ({ job, signal, onProgress }) => {\n * onProgress?.({ jobId: job.id, bytesTransferred: 0 });\n * // … perform the bytes here, honoring `signal` …\n * return { jobId: job.id, bytesTransferred: 1234, completedAt: new Date() };\n * };\n *\n * const job: TransferJob = {\n * id: \"manual-1\",\n * operation: \"upload\",\n * source: { profile: localProfile, path: \"./data.bin\" },\n * destination: { profile: s3Profile, path: \"/data/data.bin\" },\n * };\n *\n * const receipt = await engine.execute(job, executor, {\n * retry: { maxAttempts: 3, baseDelayMs: 250 },\n * });\n * console.log(receipt.attempts.length); // 1 on success\n * ```\n */\nexport class TransferEngine {\n private readonly now: () => Date;\n\n /**\n * Creates a transfer engine.\n *\n * @param options - Optional clock override for deterministic tests.\n */\n constructor(options: TransferEngineOptions = {}) {\n this.now = options.now ?? (() => new Date());\n }\n\n /**\n * Executes a transfer job through a caller-supplied operation.\n *\n * @param job - Job metadata used for correlation and receipts.\n * @param executor - Concrete transfer operation implementation.\n * @param options - Optional abort, retry, and progress hooks.\n * @returns Receipt for the completed transfer.\n * @throws {@link AbortError} When execution is cancelled.\n * @throws {@link TransferError} When all attempts fail.\n */\n async execute(\n job: TransferJob,\n executor: TransferExecutor,\n options: TransferEngineExecuteOptions = {},\n ): Promise<TransferReceipt> {\n const maxAttempts = normalizeMaxAttempts(options.retry?.maxAttempts);\n const attempts: TransferAttempt[] = [];\n const startedAt = this.now();\n const abortScope = createAbortScope(options.signal, options.timeout, job);\n let latestBytesTransferred = 0;\n\n try {\n for (let attemptNumber = 1; attemptNumber <= maxAttempts; attemptNumber += 1) {\n this.throwIfAborted(abortScope.signal, job);\n\n const attemptStartedAt = this.now();\n const context = this.createExecutionContext(\n job,\n attemptNumber,\n attemptStartedAt,\n options,\n abortScope.signal,\n (bytesTransferred) => {\n latestBytesTransferred = bytesTransferred;\n },\n );\n\n try {\n const result = await runExecutor(executor, context, abortScope.signal, job);\n context.throwIfAborted();\n latestBytesTransferred = result.bytesTransferred;\n\n const completedAt = this.now();\n attempts.push(\n createAttempt(attemptNumber, attemptStartedAt, completedAt, result.bytesTransferred),\n );\n\n return createReceipt(job, result, attempts, startedAt, completedAt);\n } catch (error) {\n const completedAt = this.now();\n const attempt = createAttempt(\n attemptNumber,\n attemptStartedAt,\n completedAt,\n latestBytesTransferred,\n summarizeError(error),\n );\n attempts.push(attempt);\n\n if (error instanceof AbortError || error instanceof TimeoutError) {\n throw error;\n }\n\n const retryInput: TransferRetryDecisionInput = { attempt: attemptNumber, error, job };\n const shouldRetry =\n attemptNumber < maxAttempts &&\n (options.retry?.shouldRetry?.(retryInput) ?? isRetryable(error));\n\n if (shouldRetry) {\n options.retry?.onRetry?.(retryInput);\n continue;\n }\n\n throw createTransferFailure(job, error, attempts);\n }\n }\n\n throw createTransferFailure(job, undefined, attempts);\n } finally {\n abortScope.dispose();\n }\n }\n\n private createExecutionContext(\n job: TransferJob,\n attempt: number,\n startedAt: Date,\n options: TransferEngineExecuteOptions,\n signal: AbortSignal | undefined,\n updateBytesTransferred: (bytesTransferred: number) => void,\n ): TransferExecutionContext {\n const context: TransferExecutionContext = {\n attempt,\n job,\n reportProgress: (bytesTransferred, totalBytes) => {\n this.throwIfAborted(signal, job);\n updateBytesTransferred(bytesTransferred);\n const progressInput = {\n bytesTransferred,\n now: this.now(),\n startedAt,\n transferId: job.id,\n };\n const resolvedTotalBytes = totalBytes ?? job.totalBytes;\n const event = createProgressEvent(\n resolvedTotalBytes === undefined\n ? progressInput\n : { ...progressInput, totalBytes: resolvedTotalBytes },\n );\n options.onProgress?.(event);\n return event;\n },\n throwIfAborted: () => this.throwIfAborted(signal, job),\n };\n\n if (signal !== undefined) {\n context.signal = signal;\n }\n\n if (options.bandwidthLimit !== undefined) {\n context.bandwidthLimit = { ...options.bandwidthLimit };\n }\n\n return context;\n }\n\n private throwIfAborted(signal: AbortSignal | undefined, job: TransferJob): void {\n if (signal?.aborted === true) {\n if (signal.reason instanceof ZeroTransferError) {\n throw signal.reason;\n }\n\n throw new AbortError({\n details: { jobId: job.id, operation: job.operation },\n message: `Transfer job aborted: ${job.id}`,\n retryable: false,\n });\n }\n }\n}\n\ninterface AbortScope {\n signal?: AbortSignal;\n dispose(): void;\n}\n\nfunction createAbortScope(\n parentSignal: AbortSignal | undefined,\n timeout: TransferTimeoutPolicy | undefined,\n job: TransferJob,\n): AbortScope {\n const timeoutMs = normalizeTimeoutMs(timeout?.timeoutMs);\n\n if (parentSignal === undefined && timeoutMs === undefined) {\n return { dispose: () => undefined };\n }\n\n const controller = new AbortController();\n const abortFromParent = (): void => controller.abort(parentSignal?.reason);\n const timeoutHandle =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n controller.abort(\n new TimeoutError({\n details: { jobId: job.id, operation: job.operation, timeoutMs },\n message: `Transfer job timed out after ${timeoutMs}ms: ${job.id}`,\n retryable: timeout?.retryable ?? true,\n }),\n );\n }, timeoutMs);\n\n if (parentSignal?.aborted === true) {\n abortFromParent();\n } else {\n parentSignal?.addEventListener(\"abort\", abortFromParent, { once: true });\n }\n\n return {\n dispose: () => {\n if (timeoutHandle !== undefined) {\n clearTimeout(timeoutHandle);\n }\n parentSignal?.removeEventListener(\"abort\", abortFromParent);\n },\n signal: controller.signal,\n };\n}\n\nfunction normalizeTimeoutMs(value: number | undefined): number | undefined {\n if (value === undefined || !Number.isFinite(value) || value <= 0) {\n return undefined;\n }\n\n return Math.floor(value);\n}\n\nasync function runExecutor(\n executor: TransferExecutor,\n context: TransferExecutionContext,\n signal: AbortSignal | undefined,\n job: TransferJob,\n): Promise<TransferExecutionResult> {\n if (signal === undefined) {\n return executor(context);\n }\n\n return Promise.race([executor(context), rejectWhenAborted(signal, job)]);\n}\n\nfunction rejectWhenAborted(\n signal: AbortSignal,\n job: TransferJob,\n): Promise<TransferExecutionResult> {\n return new Promise((_, reject) => {\n const rejectAbort = (): void => {\n if (signal.reason instanceof ZeroTransferError) {\n reject(signal.reason);\n return;\n }\n\n reject(\n new AbortError({\n details: { jobId: job.id, operation: job.operation },\n message: `Transfer job aborted: ${job.id}`,\n retryable: false,\n }),\n );\n };\n\n if (signal.aborted) {\n rejectAbort();\n return;\n }\n\n signal.addEventListener(\"abort\", rejectAbort, { once: true });\n });\n}\n\nfunction normalizeMaxAttempts(value: number | undefined): number {\n if (value === undefined) {\n return 1;\n }\n\n return Math.max(1, Math.floor(value));\n}\n\nfunction createAttempt(\n attempt: number,\n startedAt: Date,\n completedAt: Date,\n bytesTransferred: number,\n error?: TransferAttemptError,\n): TransferAttempt {\n const result: TransferAttempt = {\n attempt,\n bytesTransferred,\n completedAt,\n durationMs: Math.max(0, completedAt.getTime() - startedAt.getTime()),\n startedAt,\n };\n\n if (error !== undefined) {\n result.error = error;\n }\n\n return result;\n}\n\nfunction createReceipt(\n job: TransferJob,\n result: TransferExecutionResult,\n attempts: TransferAttempt[],\n startedAt: Date,\n completedAt: Date,\n): TransferReceipt {\n const durationMs = Math.max(0, completedAt.getTime() - startedAt.getTime());\n const verification = normalizeVerificationResult(result);\n const receipt: TransferReceipt = {\n attempts,\n averageBytesPerSecond: calculateBytesPerSecond(result.bytesTransferred, durationMs),\n bytesTransferred: result.bytesTransferred,\n completedAt,\n durationMs,\n jobId: job.id,\n operation: job.operation,\n resumed: result.resumed ?? job.resumed ?? false,\n startedAt,\n transferId: job.id,\n verified: verification?.verified ?? result.verified ?? false,\n warnings: [...(result.warnings ?? [])],\n };\n\n if (job.source !== undefined) receipt.source = { ...job.source };\n if (job.destination !== undefined) receipt.destination = { ...job.destination };\n if (result.totalBytes !== undefined) receipt.totalBytes = result.totalBytes;\n else if (job.totalBytes !== undefined) receipt.totalBytes = job.totalBytes;\n if (result.checksum !== undefined) receipt.checksum = result.checksum;\n else if (verification?.checksum !== undefined) receipt.checksum = verification.checksum;\n if (verification !== undefined) receipt.verification = verification;\n if (job.metadata !== undefined) receipt.metadata = { ...job.metadata };\n\n return receipt;\n}\n\nfunction normalizeVerificationResult(\n result: TransferExecutionResult,\n): TransferVerificationResult | undefined {\n const verification = result.verification;\n\n if (verification !== undefined) {\n const normalized: TransferVerificationResult = { verified: verification.verified };\n\n if (verification.method !== undefined) normalized.method = verification.method;\n if (verification.checksum !== undefined) normalized.checksum = verification.checksum;\n if (verification.expectedChecksum !== undefined) {\n normalized.expectedChecksum = verification.expectedChecksum;\n }\n if (verification.actualChecksum !== undefined)\n normalized.actualChecksum = verification.actualChecksum;\n if (verification.details !== undefined) normalized.details = { ...verification.details };\n\n return normalized;\n }\n\n if (result.verified === undefined && result.checksum === undefined) {\n return undefined;\n }\n\n const normalized: TransferVerificationResult = { verified: result.verified ?? false };\n\n if (result.checksum !== undefined) {\n normalized.checksum = result.checksum;\n }\n\n return normalized;\n}\n\nfunction createTransferFailure(\n job: TransferJob,\n error: unknown,\n attempts: TransferAttempt[],\n): TransferError {\n return new TransferError({\n cause: error,\n details: {\n attempts,\n jobId: job.id,\n operation: job.operation,\n },\n message: `Transfer job failed: ${job.id}`,\n retryable: isRetryable(error),\n });\n}\n\nfunction summarizeError(error: unknown): TransferAttemptError {\n if (error instanceof ZeroTransferError) {\n return {\n code: error.code,\n message: error.message,\n name: error.name,\n retryable: error.retryable,\n };\n }\n\n if (error instanceof Error) {\n return {\n message: error.message,\n name: error.name,\n };\n }\n\n return {\n message: String(error),\n name: \"Error\",\n };\n}\n\nfunction isRetryable(error: unknown): boolean {\n return error instanceof ZeroTransferError && error.retryable;\n}\n\nfunction calculateBytesPerSecond(bytes: number, durationMs: number): number {\n if (durationMs <= 0) {\n return bytes;\n }\n\n return bytes / (durationMs / 1000);\n}\n","/**\n * Route executor that dispatches a single transfer through {@link TransferEngine}.\n *\n * `runRoute` opens both endpoints through the supplied {@link TransferClient},\n * builds a {@link TransferJob} with route correlation metadata, and runs the\n * provider read/write executor under retry, abort, progress, timeout, and\n * bandwidth-limit hooks. Sessions are released in `finally` blocks even when\n * the transfer fails, throws, or is aborted.\n *\n * @module mft/runRoute\n */\nimport type { TransferClient } from \"../core/TransferClient\";\nimport type { TransferSession } from \"../core/TransferSession\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { TransferProgressEvent } from \"../types/public\";\nimport { createProviderTransferExecutor } from \"../transfers/createProviderTransferExecutor\";\nimport { TransferEngine } from \"../transfers/TransferEngine\";\nimport type {\n TransferEngineExecuteOptions,\n TransferRetryPolicy,\n} from \"../transfers/TransferEngine\";\nimport type {\n TransferBandwidthLimit,\n TransferEndpoint,\n TransferJob,\n TransferReceipt,\n TransferTimeoutPolicy,\n} from \"../transfers/TransferJob\";\nimport type { MftRoute } from \"./MftRoute\";\n\n/** Options accepted by {@link runRoute}. */\nexport interface RunRouteOptions {\n /** Transfer client whose registry can resolve both endpoint providers. */\n client: TransferClient;\n /** Route to execute. */\n route: MftRoute;\n /** Optional transfer engine override. A fresh engine is created when omitted. */\n engine?: TransferEngine;\n /** Optional explicit job id. Defaults to a deterministic route-derived id. */\n jobId?: string;\n /** Optional clock used to derive the default job id. Defaults to `Date.now`. */\n now?: () => Date;\n /** Abort signal used to cancel the route execution. */\n signal?: AbortSignal;\n /** Retry policy forwarded to the engine. */\n retry?: TransferRetryPolicy;\n /** Progress observer forwarded to the engine. */\n onProgress?: (event: TransferProgressEvent) => void;\n /** Timeout policy forwarded to the engine. */\n timeout?: TransferTimeoutPolicy;\n /** Optional bandwidth limit forwarded to the engine. */\n bandwidthLimit?: TransferBandwidthLimit;\n /** Caller-defined metadata merged into the resulting transfer job. */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Executes an MFT route as a single transfer through the supplied client.\n *\n * Connects the source and destination profiles, runs the route's transfer\n * through the engine, and returns the resulting receipt. The friendly helpers\n * {@link uploadFile}, {@link downloadFile}, and {@link copyBetween} synthesize\n * routes and delegate to this function, so behaviour around retry, abort,\n * progress, timeout, and bandwidth limits is identical.\n *\n * @param options - Client, route, and optional engine/abort/retry hooks.\n * @returns Receipt produced by the underlying transfer engine.\n * @throws {@link ConfigurationError} When the route is disabled.\n *\n * @example Run a pre-built route with progress + retry\n * ```ts\n * import { createTransferClient, runRoute, type MftRoute } from \"@zero-transfer/sdk\";\n *\n * const route: MftRoute = {\n * id: \"nightly-export\",\n * operation: \"copy\",\n * source: {\n * path: \"/exports/daily.csv\",\n * profile: { host: \"sftp.example.com\", provider: \"sftp\", username: \"etl\" },\n * },\n * destination: {\n * path: \"warehouse/daily.csv\",\n * profile: { host: \"warehouse\", provider: \"s3\", s3: { region: \"us-east-1\" } },\n * },\n * };\n *\n * const receipt = await runRoute({\n * client,\n * route,\n * onProgress: (e) => console.log(`${e.bytesTransferred}/${e.totalBytes ?? \"?\"}`),\n * retry: { maxAttempts: 3, baseDelayMs: 500 },\n * });\n * console.log(`Job ${receipt.jobId} moved ${receipt.bytesTransferred} bytes…`);\n * ```\n */\nexport async function runRoute(options: RunRouteOptions): Promise<TransferReceipt> {\n const { client, route } = options;\n\n if (route.enabled === false) {\n throw new ConfigurationError({\n details: { routeId: route.id },\n message: `MFT route \"${route.id}\" is disabled`,\n retryable: false,\n });\n }\n\n const sourceSession = await client.connect(route.source.profile);\n\n let destinationSession: TransferSession | undefined;\n try {\n destinationSession = await client.connect(route.destination.profile);\n const engine = options.engine ?? new TransferEngine();\n const job = createRouteJob(route, sourceSession, destinationSession, options);\n const sessions = new Map<string, TransferSession>([\n [\"source\", sourceSession],\n [\"destination\", destinationSession],\n ]);\n const executor = createProviderTransferExecutor({\n resolveSession: ({ role }) => sessions.get(role),\n });\n\n return await engine.execute(job, executor, buildExecuteOptions(options));\n } finally {\n if (destinationSession !== undefined) {\n await destinationSession.disconnect();\n }\n await sourceSession.disconnect();\n }\n}\n\nfunction createRouteJob(\n route: MftRoute,\n sourceSession: TransferSession,\n destinationSession: TransferSession,\n options: RunRouteOptions,\n): TransferJob {\n const operation = route.operation ?? \"copy\";\n const source: TransferEndpoint = {\n path: route.source.path,\n provider: sourceSession.provider,\n };\n const destination: TransferEndpoint = {\n path: route.destination.path,\n provider: destinationSession.provider,\n };\n\n const baseMetadata: Record<string, unknown> = { routeId: route.id };\n if (route.name !== undefined) baseMetadata[\"routeName\"] = route.name;\n if (route.metadata !== undefined) Object.assign(baseMetadata, route.metadata);\n if (options.metadata !== undefined) Object.assign(baseMetadata, options.metadata);\n\n const job: TransferJob = {\n destination,\n id: options.jobId ?? defaultJobId(route, options.now),\n operation,\n source,\n };\n\n if (Object.keys(baseMetadata).length > 0) {\n job.metadata = baseMetadata;\n }\n\n return job;\n}\n\nfunction defaultJobId(route: MftRoute, now: (() => Date) | undefined): string {\n const timestamp = (now?.() ?? new Date()).getTime();\n return `route:${route.id}:${timestamp.toString(36)}`;\n}\n\nfunction buildExecuteOptions(options: RunRouteOptions): TransferEngineExecuteOptions {\n const execute: TransferEngineExecuteOptions = {};\n if (options.signal !== undefined) execute.signal = options.signal;\n if (options.retry !== undefined) execute.retry = options.retry;\n if (options.onProgress !== undefined) execute.onProgress = options.onProgress;\n if (options.timeout !== undefined) execute.timeout = options.timeout;\n if (options.bandwidthLimit !== undefined) execute.bandwidthLimit = options.bandwidthLimit;\n return execute;\n}\n","/**\n * Secret redaction helpers for logs, events, and diagnostics.\n *\n * These functions focus on preserving useful operational context while removing\n * credentials and command payloads that should not appear in logs.\n *\n * @module logging/redaction\n */\n/** Placeholder used when sensitive content has been removed. */\nexport const REDACTED = \"[REDACTED]\";\n\nconst SENSITIVE_KEY_PATTERN = /(?:password|passphrase|privatekey|token|secret|username|user)$/i;\nconst SECRET_COMMAND_PATTERN = /^(PASS|USER|ACCT)\\s+(.+)$/i;\n\n/**\n * Checks whether an object key is likely to contain sensitive data.\n *\n * @param key - Object key to inspect.\n * @returns `true` when the key name should be redacted.\n */\nexport function isSensitiveKey(key: string): boolean {\n return SENSITIVE_KEY_PATTERN.test(key.replace(/[_-]/g, \"\"));\n}\n\n/**\n * Redacts sensitive FTP command payloads while preserving the command name.\n *\n * @param command - Raw command text such as `PASS secret` or `USER deploy`.\n * @returns Command text with secret arguments replaced by {@link REDACTED}.\n */\nexport function redactCommand(command: string): string {\n return command.replace(SECRET_COMMAND_PATTERN, (_fullMatch, commandName: string) => {\n return `${commandName.toUpperCase()} ${REDACTED}`;\n });\n}\n\n/**\n * Recursively redacts strings, arrays, and plain object values.\n *\n * @param value - Arbitrary value to sanitize for diagnostics.\n * @returns A redacted copy for arrays and objects, or the original primitive value.\n */\nexport function redactValue(value: unknown): unknown {\n if (typeof value === \"string\") {\n return redactCommand(value);\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => redactValue(item));\n }\n\n if (value !== null && typeof value === \"object\") {\n return redactObject(value as Record<string, unknown>);\n }\n\n return value;\n}\n\n/**\n * Redacts sensitive keys and nested values in a plain object.\n *\n * @param input - Object containing diagnostic fields.\n * @returns A shallow object copy with sensitive fields and nested secrets redacted.\n */\nexport function redactObject(input: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(input).map(([key, value]) => {\n if (isSensitiveKey(key)) {\n return [key, REDACTED];\n }\n\n return [key, redactValue(value)];\n }),\n );\n}\n","/**\n * Secret source contracts and resolution helpers for connection profiles.\n *\n * @module profiles/SecretSource\n */\nimport { Buffer } from \"node:buffer\";\nimport { readFile } from \"node:fs/promises\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport { REDACTED } from \"../logging/redaction\";\n\n/** Resolved secret value accepted by profile credential fields. */\nexport type SecretValue = string | Buffer;\n\n/** Callback source used by applications to integrate vaults or credential brokers. */\nexport type SecretProvider = () => SecretValue | Promise<SecretValue>;\n\n/** Inline secret descriptor. Prefer env, path, or callback sources for real applications. */\nexport interface ValueSecretSource {\n /** Inline secret value. */\n value: SecretValue;\n}\n\n/** Environment variable descriptor for text secrets. */\nexport interface EnvSecretSource {\n /** Environment variable containing the secret. */\n env: string;\n}\n\n/** Environment variable descriptor for base64-encoded binary secrets. */\nexport interface Base64EnvSecretSource {\n /** Environment variable containing a base64-encoded secret. */\n base64Env: string;\n}\n\n/** File-backed secret descriptor. */\nexport interface FileSecretSource {\n /** Path to the file containing the secret. */\n path: string;\n /** Text encoding to use, or `buffer` to return raw bytes. Defaults to `utf8`. */\n encoding?: BufferEncoding | \"buffer\";\n}\n\n/** Secret source accepted by profile credential fields. */\nexport type SecretSource =\n | SecretValue\n | SecretProvider\n | ValueSecretSource\n | EnvSecretSource\n | Base64EnvSecretSource\n | FileSecretSource;\n\n/** Injectable dependencies used by tests or host applications during secret resolution. */\nexport interface ResolveSecretOptions {\n /** Environment source. Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv;\n /** File reader. Defaults to `fs.promises.readFile`. */\n readFile?: (path: string) => Promise<Buffer> | Buffer;\n}\n\n/**\n * Resolves a secret source into a string or Buffer without logging the value.\n *\n * @param source - Secret source to resolve.\n * @param options - Optional env and file-reader overrides.\n * @returns Resolved secret value.\n * @throws {@link ConfigurationError} When a descriptor is invalid or unavailable.\n */\nexport async function resolveSecret(\n source: SecretSource,\n options: ResolveSecretOptions = {},\n): Promise<SecretValue> {\n if (isSecretValue(source)) {\n return cloneSecretValue(source);\n }\n\n if (typeof source === \"function\") {\n return cloneSecretValue(await source());\n }\n\n if (isValueSecretSource(source)) {\n return cloneSecretValue(source.value);\n }\n\n if (isEnvSecretSource(source)) {\n const value = (options.env ?? process.env)[source.env];\n\n if (value === undefined) {\n throw createSecretConfigurationError(\n \"Secret environment variable is not set\",\n \"env\",\n source.env,\n );\n }\n\n return value;\n }\n\n if (isBase64EnvSecretSource(source)) {\n const value = (options.env ?? process.env)[source.base64Env];\n\n if (value === undefined) {\n throw createSecretConfigurationError(\n \"Secret environment variable is not set\",\n \"base64Env\",\n source.base64Env,\n );\n }\n\n return Buffer.from(value, \"base64\");\n }\n\n if (isFileSecretSource(source)) {\n const fileReader = options.readFile ?? readFile;\n const value = await fileReader(source.path);\n\n if (source.encoding === \"buffer\") {\n return Buffer.from(value);\n }\n\n return value.toString(source.encoding ?? \"utf8\");\n }\n\n throw createSecretConfigurationError(\"Unsupported secret source\", \"source\", \"unknown\");\n}\n\n/**\n * Redacts a secret source or resolved secret for safe diagnostics.\n *\n * @param source - Secret source or resolved value to sanitize.\n * @returns Redacted placeholder or descriptor shape.\n */\nexport function redactSecretSource(source: SecretSource | SecretValue): unknown {\n if (isSecretValue(source) || typeof source === \"function\") {\n return REDACTED;\n }\n\n if (isValueSecretSource(source)) return { value: REDACTED };\n if (isEnvSecretSource(source)) return { env: REDACTED };\n if (isBase64EnvSecretSource(source)) return { base64Env: REDACTED };\n if (isFileSecretSource(source)) return { encoding: source.encoding, path: REDACTED };\n\n return REDACTED;\n}\n\nfunction isSecretValue(value: unknown): value is SecretValue {\n return typeof value === \"string\" || Buffer.isBuffer(value);\n}\n\nfunction isValueSecretSource(value: unknown): value is ValueSecretSource {\n return isRecord(value) && \"value\" in value && isSecretValue(value.value);\n}\n\nfunction isEnvSecretSource(value: unknown): value is EnvSecretSource {\n return isRecord(value) && typeof value.env === \"string\";\n}\n\nfunction isBase64EnvSecretSource(value: unknown): value is Base64EnvSecretSource {\n return isRecord(value) && typeof value.base64Env === \"string\";\n}\n\nfunction isFileSecretSource(value: unknown): value is FileSecretSource {\n return isRecord(value) && typeof value.path === \"string\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction cloneSecretValue(value: SecretValue): SecretValue {\n return Buffer.isBuffer(value) ? Buffer.from(value) : value;\n}\n\nfunction createSecretConfigurationError(\n message: string,\n sourceType: string,\n sourceName: string,\n): ConfigurationError {\n return new ConfigurationError({\n details: { sourceName, sourceType },\n message,\n retryable: false,\n });\n}\n","/**\n * Connection profile redaction helpers.\n *\n * @module profiles/ProfileRedactor\n */\nimport type { ConnectionProfile, SshProfile, TlsProfile, TlsSecretSource } from \"../types/public\";\nimport { REDACTED, redactObject } from \"../logging/redaction\";\nimport { redactSecretSource } from \"./SecretSource\";\n\n/**\n * Produces a diagnostics-safe profile copy with credentials and runtime hooks redacted.\n *\n * @param profile - Connection profile to sanitize.\n * @returns Plain object safe to include in logs, traces, or validation reports.\n */\nexport function redactConnectionProfile(profile: ConnectionProfile): Record<string, unknown> {\n const { logger, password, signal, ssh, tls, username, ...rest } = profile;\n const redacted = redactObject(rest);\n\n if (username !== undefined) redacted.username = redactSecretSource(username);\n if (password !== undefined) redacted.password = redactSecretSource(password);\n if (ssh !== undefined) redacted.ssh = redactSshProfile(ssh);\n if (tls !== undefined) redacted.tls = redactTlsProfile(tls);\n if (signal !== undefined) redacted.signal = \"[AbortSignal]\";\n if (logger !== undefined) redacted.logger = REDACTED;\n\n return redacted;\n}\n\n/**\n * Redacts SSH private-key profile fields while preserving non-sensitive policy settings.\n *\n * @param profile - SSH profile to sanitize.\n * @returns Plain object safe to include in diagnostics.\n */\nfunction redactSshProfile(profile: SshProfile): Record<string, unknown> {\n const { agent, keyboardInteractive, knownHosts, passphrase, privateKey, socketFactory, ...rest } =\n profile;\n const redacted = redactObject(rest);\n\n if (agent !== undefined) redacted.agent = REDACTED;\n if (privateKey !== undefined) redacted.privateKey = redactSecretSource(privateKey);\n if (passphrase !== undefined) redacted.passphrase = redactSecretSource(passphrase);\n if (knownHosts !== undefined) redacted.knownHosts = redactSshKnownHostsSource(knownHosts);\n if (keyboardInteractive !== undefined) redacted.keyboardInteractive = REDACTED;\n if (socketFactory !== undefined) redacted.socketFactory = REDACTED;\n\n return redacted;\n}\n\n/**\n * Redacts an SSH known_hosts source, preserving array shape for diagnostics.\n *\n * @param source - Single known_hosts source or ordered source array.\n * @returns Redacted source descriptor.\n */\nfunction redactSshKnownHostsSource(source: NonNullable<SshProfile[\"knownHosts\"]>): unknown {\n if (Array.isArray(source)) {\n return source.map((item) => redactSecretSource(item));\n }\n\n return redactSecretSource(source);\n}\n\n/**\n * Redacts certificate-bearing TLS profile fields while preserving non-sensitive policy settings.\n *\n * @param profile - TLS profile to sanitize.\n * @returns Plain object safe to include in diagnostics.\n */\nfunction redactTlsProfile(profile: TlsProfile): Record<string, unknown> {\n const { ca, cert, checkServerIdentity, key, passphrase, pfx, ...rest } = profile;\n const redacted = redactObject(rest);\n\n if (ca !== undefined) redacted.ca = redactTlsSecretSource(ca);\n if (cert !== undefined) redacted.cert = redactSecretSource(cert);\n if (key !== undefined) redacted.key = redactSecretSource(key);\n if (passphrase !== undefined) redacted.passphrase = redactSecretSource(passphrase);\n if (pfx !== undefined) redacted.pfx = redactSecretSource(pfx);\n if (checkServerIdentity !== undefined) redacted.checkServerIdentity = REDACTED;\n\n return redacted;\n}\n\n/**\n * Redacts a TLS material source, preserving array shape for CA bundle diagnostics.\n *\n * @param source - Single secret source or ordered source array.\n * @returns Redacted source descriptor.\n */\nfunction redactTlsSecretSource(source: TlsSecretSource): unknown {\n if (Array.isArray(source)) {\n return source.map((item) => redactSecretSource(item));\n }\n\n return redactSecretSource(source);\n}\n","/**\n * Diagnostics helpers for inspecting a {@link TransferClient} and probing connection profiles.\n *\n * These helpers are intentionally side-effect-light: they exercise an existing client without\n * mutating registry state and never log secret material. Use them to render setup screens,\n * collect bug-report payloads, or verify a profile after an importer run.\n *\n * @module diagnostics\n */\nimport type { TransferClient } from \"../core/TransferClient\";\nimport type { CapabilitySet } from \"../core/CapabilitySet\";\nimport type { ProviderId } from \"../core/ProviderId\";\nimport { redactConnectionProfile } from \"../profiles/ProfileRedactor\";\nimport type { ConnectionProfile, RemoteEntry } from \"../types/public\";\n\n/** Snapshot of the providers registered with a client. */\nexport interface ClientDiagnostics {\n /** Providers currently registered, keyed by id. */\n providers: ReadonlyArray<{ id: ProviderId; capabilities: CapabilitySet }>;\n}\n\n/**\n * Returns a redaction-safe snapshot of the providers registered with a client.\n *\n * Use this when rendering a setup screen, generating a support bundle, or\n * asserting in tests that the expected provider factories were registered.\n *\n * @param client - Transfer client to inspect.\n * @returns Provider id and capability snapshot tuples.\n *\n * @example List registered providers\n * ```ts\n * import { summarizeClientDiagnostics } from \"@zero-transfer/sdk\";\n *\n * for (const { id, capabilities } of summarizeClientDiagnostics(client).providers) {\n * console.log(`${id}: streaming=${capabilities.readStream} resume=${capabilities.resumeDownload}`);\n * }\n * ```\n */\nexport function summarizeClientDiagnostics(client: TransferClient): ClientDiagnostics {\n const capabilities = client.getCapabilities();\n return {\n providers: capabilities.map((entry) => ({ capabilities: entry, id: entry.provider })),\n };\n}\n\n/** Per-step duration measurements collected by {@link runConnectionDiagnostics}. */\nexport interface ConnectionDiagnosticTimings {\n /** Total time spent inside `client.connect`. */\n connectMs?: number;\n /** Time spent inside the optional `fs.list` probe. */\n listMs?: number;\n /** Time spent inside the optional `session.disconnect`. */\n disconnectMs?: number;\n}\n\n/** Result returned by {@link runConnectionDiagnostics}. */\nexport interface ConnectionDiagnosticsResult {\n /** Resolved provider id used to open the session. */\n provider?: ProviderId;\n /** Profile host (after redaction). */\n host: string;\n /** Capability snapshot reported by the connected session. */\n capabilities?: CapabilitySet;\n /** Redacted connection profile mirroring {@link redactConnectionProfile}. */\n redactedProfile: Record<string, unknown>;\n /** Per-step duration measurements. */\n timings: ConnectionDiagnosticTimings;\n /** Sample of entries returned by the optional `fs.list` probe. */\n sample?: readonly RemoteEntry[];\n /** Whether all probes ran without throwing. */\n ok: boolean;\n /** Captured error summary when the diagnostics could not complete. */\n error?: { message: string; name?: string; code?: string };\n}\n\n/** Options accepted by {@link runConnectionDiagnostics}. */\nexport interface RunConnectionDiagnosticsOptions {\n /** Transfer client used to open the session. */\n client: TransferClient;\n /** Connection profile to probe. */\n profile: ConnectionProfile;\n /** Path passed to the optional `fs.list` probe. Defaults to `\"/\"`. */\n listPath?: string;\n /** When `false`, skips the `fs.list` probe. Defaults to `true`. */\n probeList?: boolean;\n /** Maximum number of entries retained in the result sample. Defaults to `5`. */\n sampleSize?: number;\n /** Optional clock injected for deterministic test timings. Defaults to `performance.now`. */\n now?: () => number;\n}\n\n/**\n * Connects to a profile, captures capability and listing samples, and returns a redaction-safe report.\n *\n * Useful for connectivity \"ping\" pages, smoke tests, and bug reports. Secrets\n * in the profile are redacted via {@link redactConnectionProfile} before being\n * returned. The session is always disconnected before the function returns,\n * including when probes throw.\n *\n * @param options - Diagnostic probe options.\n * @returns Diagnostic report including timings and any captured error.\n *\n * @example Probe an SFTP connection\n * ```ts\n * import { runConnectionDiagnostics } from \"@zero-transfer/sdk\";\n *\n * const report = await runConnectionDiagnostics({\n * client,\n * profile: {\n * host: \"sftp.example.com\",\n * provider: \"sftp\",\n * username: \"deploy\",\n * ssh: { privateKey: { path: \"./keys/id_ed25519\" } },\n * },\n * listPath: \"/uploads\",\n * });\n *\n * if (!report.ok) {\n * console.error(\"connection failed:\", report.error);\n * } else {\n * console.log(`connect=${report.timings.connectMs}ms list=${report.timings.listMs}ms`);\n * console.log(report.sample); // up to 5 entries from /uploads\n * }\n * ```\n */\nexport async function runConnectionDiagnostics(\n options: RunConnectionDiagnosticsOptions,\n): Promise<ConnectionDiagnosticsResult> {\n const now = options.now ?? (() => performance.now());\n const probeList = options.probeList !== false;\n const listPath = options.listPath ?? \"/\";\n const sampleSize = Math.max(0, options.sampleSize ?? 5);\n const redactedProfile = redactConnectionProfile(options.profile);\n\n const result: ConnectionDiagnosticsResult = {\n host: options.profile.host,\n ok: false,\n redactedProfile,\n timings: {},\n };\n\n const connectStart = now();\n try {\n const session = await options.client.connect(options.profile);\n result.timings.connectMs = now() - connectStart;\n result.provider = session.provider;\n result.capabilities = session.capabilities;\n try {\n if (probeList) {\n const listStart = now();\n const entries = await session.fs.list(listPath);\n result.timings.listMs = now() - listStart;\n result.sample = entries.slice(0, sampleSize);\n }\n result.ok = true;\n } finally {\n const disconnectStart = now();\n await session.disconnect();\n result.timings.disconnectMs = now() - disconnectStart;\n }\n } catch (error) {\n result.error = summarizeDiagnosticError(error);\n }\n return result;\n}\n\nfunction summarizeDiagnosticError(error: unknown): {\n message: string;\n name?: string;\n code?: string;\n} {\n if (error instanceof Error) {\n const summary: { message: string; name?: string; code?: string } = { message: error.message };\n if (error.name !== \"Error\") summary.name = error.name;\n const code = (error as { code?: unknown }).code;\n if (typeof code === \"string\") summary.code = code;\n return summary;\n }\n return { message: String(error) };\n}\n","/**\n * Connection pooling for {@link TransferClient}.\n *\n * Wraps an existing {@link TransferClient} and reuses idle provider sessions\n * keyed by `(provider, host, port, username)` so successive transfers to the\n * same endpoint avoid the cost of repeated TCP/TLS handshakes, FTP login\n * round-trips, SFTP key exchange, and similar per-session setup work. This is\n * an opt-in wrapper: workloads that prefer fresh sessions per call should\n * keep using `TransferClient` directly.\n *\n * Pooling preserves the public {@link TransferSession} surface - callers\n * still call `disconnect()` when finished, but rather than tearing down the\n * underlying transport the wrapper marks the session idle and returns it to\n * the pool for reuse. Idle sessions are evicted automatically after\n * {@link ConnectionPoolOptions.idleTimeoutMs} milliseconds, and the pool can\n * be drained explicitly via the returned {@link PooledTransferClient.drainPool}\n * helper.\n *\n * Sessions that surface {@link ConnectionError}, {@link TimeoutError}, or\n * {@link ProtocolError} during use are considered \"tainted\" and discarded\n * instead of returned to the pool, since the underlying transport may be in\n * an inconsistent state. Application errors such as\n * {@link PathNotFoundError} or {@link PermissionDeniedError} do not taint\n * the session.\n *\n * @module core/ConnectionPool\n */\nimport { ConnectionError, ProtocolError, TimeoutError } from \"../errors/ZeroTransferError\";\nimport type { ProviderTransferOperations } from \"../providers/ProviderTransferOperations\";\nimport type { RemoteFileSystem } from \"../providers/RemoteFileSystem\";\nimport type { ConnectionProfile } from \"../types/public\";\nimport type { CapabilitySet } from \"./CapabilitySet\";\nimport type { ProviderId } from \"./ProviderId\";\nimport type { TransferClient } from \"./TransferClient\";\nimport type { TransferSession } from \"./TransferSession\";\n\n/** Options for {@link createPooledTransferClient}. */\nexport interface ConnectionPoolOptions {\n /**\n * Maximum number of *idle* sessions retained per pool key.\n *\n * Active leases are not counted against this limit - the cap only applies\n * to sessions waiting in the pool. When more than `maxIdlePerKey` sessions\n * become idle simultaneously, the oldest ones are disconnected. Defaults\n * to `4`.\n */\n maxIdlePerKey?: number;\n /**\n * How long an idle session may sit unused before it is automatically\n * disconnected. Defaults to `60_000` ms. Set to `0` to disable the timer\n * (idle sessions persist until `drainPool()` is called).\n */\n idleTimeoutMs?: number;\n /**\n * Custom pool key derivation. Receives the resolved\n * {@link ConnectionProfile} (after TransferClient validation) and must\n * return a string. Sessions with matching keys are pooled together; never\n * include secrets in the key.\n *\n * The default derives the key from `provider`, `host`, `port`, and\n * `username`.\n */\n keyOf?: (profile: ConnectionProfile) => string;\n}\n\n/**\n * Pool-aware {@link TransferClient} returned by\n * {@link createPooledTransferClient}.\n */\nexport interface PooledTransferClient {\n /** Opens (or leases) a pooled provider session. */\n connect(profile: ConnectionProfile): Promise<TransferSession>;\n /** Inspects the registered providers (delegated to the underlying client). */\n hasProvider(providerId: ProviderId): boolean;\n /** Returns the registered capability snapshots (delegated). */\n getCapabilities(): CapabilitySet[];\n /** Returns a specific capability snapshot (delegated). */\n getCapabilities(providerId: ProviderId): CapabilitySet;\n /**\n * Disconnects every idle session and prevents further pooling. After\n * `drainPool()` resolves, subsequent `connect()` calls still work but\n * always create fresh sessions (and never return them to the pool).\n */\n drainPool(): Promise<void>;\n /** Returns the number of idle sessions currently held in the pool. */\n poolSize(): number;\n}\n\ninterface PoolEntry {\n session: TransferSession;\n /** Timer that disconnects this entry after `idleTimeoutMs`. */\n idleTimer?: ReturnType<typeof setTimeout>;\n}\n\ninterface InternalState {\n drained: boolean;\n /** Idle sessions keyed by pool key. */\n idle: Map<string, PoolEntry[]>;\n}\n\nconst DEFAULT_MAX_IDLE_PER_KEY = 4;\nconst DEFAULT_IDLE_TIMEOUT_MS = 60_000;\n\n/**\n * Wraps a {@link TransferClient} with connection pooling.\n *\n * @param inner - Underlying client used to create real provider sessions.\n * @param options - Pool sizing, eviction, and key-derivation overrides.\n * @returns A {@link PooledTransferClient} that reuses idle sessions.\n */\nexport function createPooledTransferClient(\n inner: TransferClient,\n options: ConnectionPoolOptions = {},\n): PooledTransferClient {\n const maxIdlePerKey = Math.max(1, options.maxIdlePerKey ?? DEFAULT_MAX_IDLE_PER_KEY);\n const idleTimeoutMs = Math.max(0, options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS);\n const keyOf = options.keyOf ?? defaultKeyOf;\n\n const state: InternalState = {\n drained: false,\n idle: new Map(),\n };\n\n const release = (key: string, session: TransferSession, tainted: boolean): Promise<void> => {\n if (tainted || state.drained) {\n return safelyDisconnect(session);\n }\n\n let bucket = state.idle.get(key);\n if (bucket === undefined) {\n bucket = [];\n state.idle.set(key, bucket);\n }\n\n const entry: PoolEntry = { session };\n if (idleTimeoutMs > 0) {\n entry.idleTimer = setTimeout(() => {\n evictEntry(state, key, entry);\n }, idleTimeoutMs);\n // Avoid keeping the Node.js event loop alive solely for idle pool\n // entries (e.g. in CLI tools).\n const timer = entry.idleTimer as { unref?: () => void } | undefined;\n if (timer !== undefined && typeof timer.unref === \"function\") {\n timer.unref();\n }\n }\n\n bucket.push(entry);\n\n // Trim the oldest entries when the bucket exceeds the cap.\n while (bucket.length > maxIdlePerKey) {\n const dropped = bucket.shift();\n if (dropped !== undefined) {\n clearEntryTimer(dropped);\n void safelyDisconnect(dropped.session);\n }\n }\n return Promise.resolve();\n };\n\n const acquire = async (\n profile: ConnectionProfile,\n ): Promise<{ session: TransferSession; key: string }> => {\n const key = keyOf(profile);\n const bucket = state.idle.get(key);\n if (bucket !== undefined && bucket.length > 0) {\n const entry = bucket.pop();\n if (entry !== undefined) {\n clearEntryTimer(entry);\n if (bucket.length === 0) state.idle.delete(key);\n return { key, session: entry.session };\n }\n }\n const session = await inner.connect(profile);\n return { key, session };\n };\n\n return {\n connect: async (profile) => {\n const { key, session } = await acquire(profile);\n return wrapPooledSession(session, key, release);\n },\n drainPool: async () => {\n state.drained = true;\n const entries: PoolEntry[] = [];\n for (const bucket of state.idle.values()) {\n for (const entry of bucket) {\n clearEntryTimer(entry);\n entries.push(entry);\n }\n }\n state.idle.clear();\n await Promise.all(entries.map((entry) => safelyDisconnect(entry.session)));\n },\n getCapabilities: ((providerId?: ProviderId): CapabilitySet | CapabilitySet[] => {\n if (providerId === undefined) return inner.getCapabilities();\n return inner.getCapabilities(providerId);\n }) as PooledTransferClient[\"getCapabilities\"],\n hasProvider: (providerId) => inner.hasProvider(providerId),\n poolSize: () => {\n let total = 0;\n for (const bucket of state.idle.values()) total += bucket.length;\n return total;\n },\n };\n}\n\n/** Default pool key - never includes secrets. */\nfunction defaultKeyOf(profile: ConnectionProfile): string {\n const provider = profile.provider ?? profile.protocol ?? \"unknown\";\n const host = profile.host ?? \"\";\n const port = profile.port ?? \"\";\n const username = typeof profile.username === \"string\" ? profile.username : \"\";\n return `${provider}|${host}|${String(port)}|${username}`;\n}\n\nfunction evictEntry(state: InternalState, key: string, entry: PoolEntry): void {\n const bucket = state.idle.get(key);\n if (bucket === undefined) return;\n const index = bucket.indexOf(entry);\n if (index < 0) return;\n bucket.splice(index, 1);\n if (bucket.length === 0) state.idle.delete(key);\n clearEntryTimer(entry);\n void safelyDisconnect(entry.session);\n}\n\nfunction clearEntryTimer(entry: PoolEntry): void {\n if (entry.idleTimer !== undefined) {\n clearTimeout(entry.idleTimer);\n delete entry.idleTimer;\n }\n}\n\nasync function safelyDisconnect(session: TransferSession): Promise<void> {\n try {\n await session.disconnect();\n } catch {\n // Pool teardown errors are not actionable; swallow them.\n }\n}\n\n/** Errors that indicate the underlying transport may be in a bad state. */\nfunction isTaintingError(error: unknown): boolean {\n return (\n error instanceof ConnectionError ||\n error instanceof TimeoutError ||\n error instanceof ProtocolError\n );\n}\n\n/**\n * Wraps a real {@link TransferSession} so that:\n * - operation errors that indicate transport corruption taint the lease,\n * - `disconnect()` returns the (untainted) session to the pool,\n * - subsequent calls on a disconnected lease throw rather than racing.\n */\nfunction wrapPooledSession(\n session: TransferSession,\n key: string,\n release: (key: string, session: TransferSession, tainted: boolean) => Promise<void>,\n): TransferSession {\n let tainted = false;\n let released = false;\n\n const guard = <T>(fn: () => Promise<T>): Promise<T> => {\n let promise: Promise<T>;\n try {\n promise = fn();\n } catch (error) {\n if (isTaintingError(error)) tainted = true;\n return Promise.reject(error instanceof Error ? error : new Error(String(error)));\n }\n return promise.catch((error: unknown) => {\n if (isTaintingError(error)) tainted = true;\n throw error;\n });\n };\n\n const fs = wrapFs(session.fs, guard);\n const transfers =\n session.transfers === undefined ? undefined : wrapTransfers(session.transfers, guard);\n\n const wrapped: TransferSession = {\n capabilities: session.capabilities,\n disconnect: async () => {\n if (released) return;\n released = true;\n await release(key, session, tainted);\n },\n fs,\n provider: session.provider,\n ...(transfers !== undefined ? { transfers } : {}),\n };\n\n if (typeof session.raw === \"function\") {\n const rawFn = session.raw.bind(session);\n wrapped.raw = () => rawFn();\n }\n\n return wrapped;\n}\n\nfunction wrapFs(\n fs: RemoteFileSystem,\n guard: <T>(fn: () => Promise<T>) => Promise<T>,\n): RemoteFileSystem {\n const wrapped: RemoteFileSystem = {\n list: (path, options) =>\n guard(() => (options !== undefined ? fs.list(path, options) : fs.list(path))),\n stat: (path, options) =>\n guard(() => (options !== undefined ? fs.stat(path, options) : fs.stat(path))),\n };\n if (typeof fs.remove === \"function\") {\n const remove = fs.remove.bind(fs);\n wrapped.remove = (path, options) =>\n guard(() => (options !== undefined ? remove(path, options) : remove(path)));\n }\n if (typeof fs.rename === \"function\") {\n const rename = fs.rename.bind(fs);\n wrapped.rename = (from, to, options) =>\n guard(() => (options !== undefined ? rename(from, to, options) : rename(from, to)));\n }\n if (typeof fs.mkdir === \"function\") {\n const mkdir = fs.mkdir.bind(fs);\n wrapped.mkdir = (path, options) =>\n guard(() => (options !== undefined ? mkdir(path, options) : mkdir(path)));\n }\n if (typeof fs.rmdir === \"function\") {\n const rmdir = fs.rmdir.bind(fs);\n wrapped.rmdir = (path, options) =>\n guard(() => (options !== undefined ? rmdir(path, options) : rmdir(path)));\n }\n return wrapped;\n}\n\nfunction wrapTransfers(\n transfers: ProviderTransferOperations,\n guard: <T>(fn: () => Promise<T>) => Promise<T>,\n): ProviderTransferOperations {\n return {\n read: (request) => guard(() => Promise.resolve(transfers.read(request))),\n write: (request) => guard(() => Promise.resolve(transfers.write(request))),\n };\n}\n","/**\n * Local file-system provider for deterministic provider contract coverage.\n *\n * @module providers/local/LocalProvider\n */\nimport { createReadStream } from \"node:fs\";\nimport {\n lstat,\n mkdir,\n open,\n readdir,\n readlink,\n rename,\n rm,\n unlink,\n writeFile,\n} from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { Buffer } from \"node:buffer\";\nimport type { Stats } from \"node:fs\";\nimport type { CapabilitySet } from \"../../core/CapabilitySet\";\nimport type { TransferSession } from \"../../core/TransferSession\";\nimport {\n ConfigurationError,\n PathNotFoundError,\n PermissionDeniedError,\n} from \"../../errors/ZeroTransferError\";\nimport type { TransferVerificationResult } from \"../../transfers/TransferJob\";\nimport type {\n ConnectionProfile,\n MkdirOptions,\n RemoteEntry,\n RemoteEntryType,\n RemoteStat,\n RemoveOptions,\n RmdirOptions,\n} from \"../../types/public\";\nimport { basenameRemotePath, joinRemotePath, normalizeRemotePath } from \"../../utils/path\";\nimport type { TransferProvider } from \"../Provider\";\nimport type { ProviderFactory } from \"../ProviderFactory\";\nimport type {\n ProviderTransferOperations,\n ProviderTransferReadRequest,\n ProviderTransferReadResult,\n ProviderTransferWriteRequest,\n ProviderTransferWriteResult,\n} from \"../ProviderTransferOperations\";\nimport type { RemoteFileSystem } from \"../RemoteFileSystem\";\n\nconst LOCAL_PROVIDER_ID = \"local\";\n\nconst LOCAL_PROVIDER_CAPABILITIES: CapabilitySet = {\n provider: LOCAL_PROVIDER_ID,\n authentication: [\"anonymous\"],\n list: true,\n stat: true,\n readStream: true,\n writeStream: true,\n serverSideCopy: false,\n serverSideMove: false,\n resumeDownload: true,\n resumeUpload: true,\n checksum: [],\n atomicRename: false,\n chmod: false,\n chown: false,\n symlink: true,\n metadata: [\"accessedAt\", \"createdAt\", \"modifiedAt\", \"permissions\", \"symlinkTarget\", \"uniqueId\"],\n maxConcurrency: 16,\n notes: [\"Local filesystem provider for tests and local-only workflows\"],\n};\n\n/** Options used to create a local file-system provider factory. */\nexport interface LocalProviderOptions {\n /** Root directory exposed as `/`. When omitted, `profile.host` is treated as the root path. */\n rootPath?: string;\n}\n\n/**\n * Creates a provider factory backed by the local filesystem.\n *\n * Useful for copying files between two remote endpoints via a local staging\n * area, or as the destination for `downloadFile`. The friendly `uploadFile`\n * helper registers a local provider implicitly.\n *\n * @param options - Optional local root path exposed through provider sessions.\n * @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.\n *\n * @example Use a fixed root directory\n * ```ts\n * import { createLocalProviderFactory, createTransferClient } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({\n * providers: [createLocalProviderFactory({ rootPath: \"/var/lib/zt-staging\" })],\n * });\n *\n * const session = await client.connect({ host: \"staging\", provider: \"local\" });\n * const list = await session.fs.list(\"/\");\n * ```\n */\nexport function createLocalProviderFactory(options: LocalProviderOptions = {}): ProviderFactory {\n return {\n id: LOCAL_PROVIDER_ID,\n capabilities: LOCAL_PROVIDER_CAPABILITIES,\n create: () => new LocalProvider(options.rootPath),\n };\n}\n\nclass LocalProvider implements TransferProvider {\n readonly id = LOCAL_PROVIDER_ID;\n readonly capabilities = LOCAL_PROVIDER_CAPABILITIES;\n\n constructor(private readonly configuredRootPath: string | undefined) {}\n\n connect(profile: ConnectionProfile): Promise<TransferSession> {\n return Promise.resolve().then(() => {\n const rootPath = path.resolve(this.configuredRootPath ?? profile.host);\n return new LocalTransferSession(rootPath);\n });\n }\n}\n\nclass LocalTransferSession implements TransferSession {\n readonly provider = LOCAL_PROVIDER_ID;\n readonly capabilities = LOCAL_PROVIDER_CAPABILITIES;\n readonly fs: RemoteFileSystem;\n readonly transfers: ProviderTransferOperations;\n\n constructor(rootPath: string) {\n this.fs = new LocalFileSystem(rootPath);\n this.transfers = new LocalTransferOperations(rootPath);\n }\n\n disconnect(): Promise<void> {\n return Promise.resolve();\n }\n}\n\nclass LocalTransferOperations implements ProviderTransferOperations {\n constructor(private readonly rootPath: string) {}\n\n async read(request: ProviderTransferReadRequest): Promise<ProviderTransferReadResult> {\n request.throwIfAborted();\n const remotePath = normalizeLocalProviderPath(request.endpoint.path);\n const entry = await readLocalEntry(this.rootPath, remotePath);\n\n if (entry.type !== \"file\") {\n throw createPathNotFoundError(remotePath, `Local provider path is not a file: ${remotePath}`);\n }\n\n const range = resolveReadRange(entry.size ?? 0, request.range);\n const result: ProviderTransferReadResult = {\n content: createLocalReadSource(resolveLocalPath(this.rootPath, remotePath), range),\n totalBytes: range.length,\n };\n\n if (range.offset > 0) {\n result.bytesRead = range.offset;\n }\n\n return result;\n }\n\n async write(request: ProviderTransferWriteRequest): Promise<ProviderTransferWriteResult> {\n request.throwIfAborted();\n const remotePath = normalizeLocalProviderPath(request.endpoint.path);\n const localPath = resolveLocalPath(this.rootPath, remotePath);\n const content = await collectTransferContent(request);\n const offset = normalizeOptionalByteCount(request.offset, \"offset\", remotePath);\n\n await ensureLocalParentDirectory(localPath, remotePath);\n await writeLocalContent(localPath, remotePath, content, offset);\n\n const stat = await readLocalEntry(this.rootPath, remotePath);\n const result: ProviderTransferWriteResult = {\n bytesTransferred: content.byteLength,\n resumed: offset !== undefined && offset > 0,\n verified: request.verification?.verified ?? false,\n };\n\n if (stat.size !== undefined) {\n result.totalBytes = stat.size;\n }\n\n if (request.verification !== undefined) {\n result.verification = cloneVerification(request.verification);\n }\n\n return result;\n }\n}\n\nclass LocalFileSystem implements RemoteFileSystem {\n constructor(private readonly rootPath: string) {}\n\n async list(path: string): Promise<RemoteEntry[]> {\n const remotePath = normalizeLocalProviderPath(path);\n const directory = await this.stat(remotePath);\n\n if (directory.type !== \"directory\") {\n throw createPathNotFoundError(\n remotePath,\n `Local provider path is not a directory: ${remotePath}`,\n );\n }\n\n const localPath = resolveLocalPath(this.rootPath, remotePath);\n const names = await readLocalDirectory(localPath, remotePath);\n const entries = await Promise.all(\n names.map((name) => readLocalEntry(this.rootPath, joinRemotePath(remotePath, name))),\n );\n\n return entries.sort(compareEntries);\n }\n\n async stat(path: string): Promise<RemoteStat> {\n return readLocalEntry(this.rootPath, normalizeLocalProviderPath(path));\n }\n\n async remove(remote: string, options: RemoveOptions = {}): Promise<void> {\n const remotePath = normalizeLocalProviderPath(remote);\n const localPath = resolveLocalPath(this.rootPath, remotePath);\n try {\n await unlink(localPath);\n } catch (error) {\n if (options.ignoreMissing && isNodeErrno(error, \"ENOENT\")) return;\n if (isNodeErrno(error, \"ENOENT\")) {\n throw createPathNotFoundError(remotePath, `Local path not found: ${remotePath}`);\n }\n throw error;\n }\n }\n\n async rename(from: string, to: string): Promise<void> {\n const fromRemote = normalizeLocalProviderPath(from);\n const toRemote = normalizeLocalProviderPath(to);\n const fromLocal = resolveLocalPath(this.rootPath, fromRemote);\n const toLocal = resolveLocalPath(this.rootPath, toRemote);\n try {\n await rename(fromLocal, toLocal);\n } catch (error) {\n if (isNodeErrno(error, \"ENOENT\")) {\n throw createPathNotFoundError(fromRemote, `Local path not found: ${fromRemote}`);\n }\n throw error;\n }\n }\n\n async mkdir(remote: string, options: MkdirOptions = {}): Promise<void> {\n const remotePath = normalizeLocalProviderPath(remote);\n const localPath = resolveLocalPath(this.rootPath, remotePath);\n await mkdir(localPath, { recursive: options.recursive === true });\n }\n\n async rmdir(remote: string, options: RmdirOptions = {}): Promise<void> {\n const remotePath = normalizeLocalProviderPath(remote);\n const localPath = resolveLocalPath(this.rootPath, remotePath);\n try {\n await rm(localPath, { recursive: options.recursive === true, force: false });\n } catch (error) {\n if (isNodeErrno(error, \"ENOENT\")) {\n if (options.ignoreMissing) return;\n throw createPathNotFoundError(remotePath, `Local path not found: ${remotePath}`);\n }\n throw error;\n }\n }\n}\n\nfunction isNodeErrno(error: unknown, code: string): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as { code?: unknown }).code === code\n );\n}\n\ninterface ResolvedReadRange {\n offset: number;\n length: number;\n}\n\nfunction resolveReadRange(\n size: number,\n range: ProviderTransferReadRequest[\"range\"],\n): ResolvedReadRange {\n if (range === undefined) {\n return { length: size, offset: 0 };\n }\n\n const requestedOffset = normalizeByteCount(range.offset, \"offset\", \"/\");\n const requestedLength =\n range.length === undefined\n ? size - Math.min(requestedOffset, size)\n : normalizeByteCount(range.length, \"length\", \"/\");\n const offset = Math.min(requestedOffset, size);\n const length = Math.max(0, Math.min(requestedLength, size - offset));\n\n return { length, offset };\n}\n\nasync function* createLocalReadSource(\n localPath: string,\n range: ResolvedReadRange,\n): AsyncGenerator<Uint8Array> {\n if (range.length <= 0) {\n return;\n }\n\n const stream = createReadStream(localPath, {\n end: range.offset + range.length - 1,\n start: range.offset,\n }) as AsyncIterable<Buffer>;\n\n for await (const chunk of stream) {\n yield new Uint8Array(chunk);\n }\n}\n\nasync function collectTransferContent(request: ProviderTransferWriteRequest): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n let byteLength = 0;\n\n for await (const chunk of request.content) {\n request.throwIfAborted();\n const clonedChunk = new Uint8Array(chunk);\n chunks.push(clonedChunk);\n byteLength += clonedChunk.byteLength;\n request.reportProgress(byteLength, request.totalBytes);\n }\n\n return concatChunks(chunks, byteLength);\n}\n\nfunction concatChunks(chunks: Uint8Array[], byteLength: number): Uint8Array {\n const content = new Uint8Array(byteLength);\n let offset = 0;\n\n for (const chunk of chunks) {\n content.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return content;\n}\n\nasync function ensureLocalParentDirectory(localPath: string, remotePath: string): Promise<void> {\n try {\n await mkdir(path.dirname(localPath), { recursive: true });\n } catch (error) {\n throw mapLocalFileSystemError(error, remotePath);\n }\n}\n\nasync function writeLocalContent(\n localPath: string,\n remotePath: string,\n content: Uint8Array,\n offset: number | undefined,\n): Promise<void> {\n try {\n if (offset === undefined) {\n await writeFile(localPath, content);\n return;\n }\n\n const handle = await openLocalFileForOffsetWrite(localPath);\n\n try {\n await handle.write(content, 0, content.byteLength, offset);\n } finally {\n await handle.close();\n }\n } catch (error) {\n throw mapLocalFileSystemError(error, remotePath);\n }\n}\n\nasync function openLocalFileForOffsetWrite(localPath: string) {\n try {\n return await open(localPath, \"r+\");\n } catch (error) {\n if (getErrorCode(error) === \"ENOENT\") {\n return open(localPath, \"w+\");\n }\n\n throw error;\n }\n}\n\nfunction normalizeOptionalByteCount(\n value: number | undefined,\n field: string,\n remotePath: string,\n): number | undefined {\n return value === undefined ? undefined : normalizeByteCount(value, field, remotePath);\n}\n\nfunction normalizeByteCount(value: number, field: string, remotePath: string): number {\n if (!Number.isFinite(value) || value < 0) {\n throw new ConfigurationError({\n details: { field, provider: LOCAL_PROVIDER_ID },\n message: `Local provider ${field} must be a non-negative number`,\n path: remotePath,\n retryable: false,\n });\n }\n\n return Math.floor(value);\n}\n\nfunction cloneVerification(verification: TransferVerificationResult): TransferVerificationResult {\n const clone: TransferVerificationResult = { verified: verification.verified };\n\n if (verification.method !== undefined) clone.method = verification.method;\n if (verification.checksum !== undefined) clone.checksum = verification.checksum;\n if (verification.expectedChecksum !== undefined) {\n clone.expectedChecksum = verification.expectedChecksum;\n }\n if (verification.actualChecksum !== undefined) clone.actualChecksum = verification.actualChecksum;\n if (verification.details !== undefined) clone.details = { ...verification.details };\n\n return clone;\n}\n\nasync function readLocalDirectory(localPath: string, remotePath: string): Promise<string[]> {\n try {\n return await readdir(localPath);\n } catch (error) {\n throw mapLocalFileSystemError(error, remotePath);\n }\n}\n\nasync function readLocalEntry(rootPath: string, remotePath: string): Promise<RemoteStat> {\n const localPath = resolveLocalPath(rootPath, remotePath);\n let stats: Stats;\n\n try {\n stats = await lstat(localPath);\n } catch (error) {\n throw mapLocalFileSystemError(error, remotePath);\n }\n\n const entry: RemoteEntry = {\n accessedAt: cloneDate(stats.atime),\n createdAt: cloneDate(stats.birthtime),\n modifiedAt: cloneDate(stats.mtime),\n name: basenameRemotePath(remotePath),\n path: remotePath,\n permissions: { raw: formatMode(stats.mode) },\n size: stats.size,\n type: getLocalEntryType(stats),\n uniqueId: `${stats.dev}:${stats.ino}`,\n };\n\n if (entry.type === \"symlink\") {\n const symlinkTarget = await readSymlinkTarget(localPath);\n\n if (symlinkTarget !== undefined) {\n entry.symlinkTarget = symlinkTarget;\n }\n }\n\n return {\n ...entry,\n exists: true,\n };\n}\n\nasync function readSymlinkTarget(localPath: string): Promise<string | undefined> {\n try {\n return await readlink(localPath);\n } catch {\n return undefined;\n }\n}\n\nfunction normalizeLocalProviderPath(input: string): string {\n const normalized = normalizeRemotePath(input);\n\n if (normalized === \"..\" || normalized.startsWith(\"../\")) {\n throw new ConfigurationError({\n details: { provider: LOCAL_PROVIDER_ID },\n message: `Local provider path escapes the configured root: ${normalized}`,\n path: normalized,\n retryable: false,\n });\n }\n\n if (normalized === \".\" || normalized === \"/\") {\n return \"/\";\n }\n\n return normalized.startsWith(\"/\") ? normalized : `/${normalized}`;\n}\n\nfunction resolveLocalPath(rootPath: string, remotePath: string): string {\n const normalizedRemotePath = normalizeLocalProviderPath(remotePath);\n\n // If the remote path is already an absolute filesystem path inside rootPath\n // (e.g. friendly upload/download passes the host path as the endpoint path),\n // honour it directly instead of double-prepending rootPath.\n const resolvedRootPath = path.resolve(rootPath);\n const candidateAbsolute = path.resolve(normalizedRemotePath.split(\"/\").join(path.sep));\n if (\n candidateAbsolute === resolvedRootPath ||\n candidateAbsolute.startsWith(resolvedRootPath + path.sep)\n ) {\n return candidateAbsolute;\n }\n\n const relativePath = normalizedRemotePath === \"/\" ? \".\" : normalizedRemotePath.slice(1);\n const resolvedPath = path.resolve(rootPath, relativePath.split(\"/\").join(path.sep));\n const relativeToRoot = path.relative(rootPath, resolvedPath);\n\n if (\n relativeToRoot === \"\" ||\n (!relativeToRoot.startsWith(\"..\") && !path.isAbsolute(relativeToRoot))\n ) {\n return resolvedPath;\n }\n\n throw new ConfigurationError({\n details: { provider: LOCAL_PROVIDER_ID, rootPath },\n message: `Local provider path escapes the configured root: ${normalizedRemotePath}`,\n path: normalizedRemotePath,\n retryable: false,\n });\n}\n\nfunction getLocalEntryType(stats: Stats): RemoteEntryType {\n if (stats.isFile()) return \"file\";\n if (stats.isDirectory()) return \"directory\";\n if (stats.isSymbolicLink()) return \"symlink\";\n return \"unknown\";\n}\n\nfunction formatMode(mode: number): string {\n return (mode & 0o777).toString(8).padStart(3, \"0\");\n}\n\nfunction cloneDate(value: Date): Date {\n return new Date(value.getTime());\n}\n\nfunction compareEntries(left: RemoteEntry, right: RemoteEntry): number {\n return left.path.localeCompare(right.path);\n}\n\nfunction mapLocalFileSystemError(error: unknown, remotePath: string): Error {\n const code = getErrorCode(error);\n\n if (code === \"ENOENT\" || code === \"ENOTDIR\") {\n return createPathNotFoundError(remotePath, `Local provider path not found: ${remotePath}`);\n }\n\n if (code === \"EACCES\" || code === \"EPERM\") {\n return new PermissionDeniedError({\n cause: error,\n details: { provider: LOCAL_PROVIDER_ID },\n message: `Local provider permission denied: ${remotePath}`,\n path: remotePath,\n retryable: false,\n });\n }\n\n return new ConfigurationError({\n cause: error,\n details: { code, provider: LOCAL_PROVIDER_ID },\n message: `Local provider filesystem operation failed: ${remotePath}`,\n path: remotePath,\n retryable: false,\n });\n}\n\nfunction createPathNotFoundError(path: string, message: string): PathNotFoundError {\n return new PathNotFoundError({\n details: { provider: LOCAL_PROVIDER_ID },\n message,\n path,\n retryable: false,\n });\n}\n\nfunction getErrorCode(error: unknown): string | undefined {\n return typeof error === \"object\" && error !== null && \"code\" in error\n ? String((error as { code?: unknown }).code)\n : undefined;\n}\n","/**\n * Remote path normalization and FTP command-argument safety helpers.\n *\n * The functions in this module avoid platform-specific local path behavior and reject\n * CR/LF characters before values can be interpolated into FTP commands.\n *\n * @module utils/path\n */\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\n\nconst UNSAFE_FTP_ARGUMENT_PATTERN = /[\\r\\n]/;\n\n/**\n * Validates that an FTP command argument cannot inject additional command lines.\n *\n * @param value - Argument value to validate.\n * @param label - Human-readable argument label used in error messages.\n * @returns The original value when it is safe.\n * @throws {@link ConfigurationError} When the value contains CR or LF characters.\n */\nexport function assertSafeFtpArgument(value: string, label = \"path\"): string {\n if (UNSAFE_FTP_ARGUMENT_PATTERN.test(value)) {\n throw new ConfigurationError({\n message: `Unsafe FTP ${label}: CR and LF characters are not allowed`,\n retryable: false,\n details: {\n label,\n },\n });\n }\n\n return value;\n}\n\n/**\n * Normalizes a remote path using POSIX-style separators without escaping absolute roots.\n *\n * @param input - Remote path that may contain duplicate separators or dot segments.\n * @returns A normalized remote path, `/` for absolute root, or `.` for an empty relative path.\n * @throws {@link ConfigurationError} When the input contains unsafe CR or LF characters.\n */\nexport function normalizeRemotePath(input: string): string {\n assertSafeFtpArgument(input);\n\n if (input.length === 0) {\n return \".\";\n }\n\n const isAbsolute = input.startsWith(\"/\");\n const segments: string[] = [];\n\n for (const segment of input.split(/[\\\\/]+/)) {\n if (segment.length === 0 || segment === \".\") {\n continue;\n }\n\n if (segment === \"..\") {\n if (segments.length > 0 && segments[segments.length - 1] !== \"..\") {\n segments.pop();\n } else if (!isAbsolute) {\n segments.push(segment);\n }\n continue;\n }\n\n segments.push(segment);\n }\n\n const normalized = segments.join(\"/\");\n\n if (isAbsolute) {\n return normalized.length > 0 ? `/${normalized}` : \"/\";\n }\n\n return normalized.length > 0 ? normalized : \".\";\n}\n\n/**\n * Joins remote path segments and normalizes the result.\n *\n * @param segments - Remote path segments to concatenate.\n * @returns A normalized remote path.\n * @throws {@link ConfigurationError} When any joined segment contains unsafe characters.\n */\nexport function joinRemotePath(...segments: string[]): string {\n if (segments.length === 0) {\n return \".\";\n }\n\n return normalizeRemotePath(segments.join(\"/\"));\n}\n\n/**\n * Extracts the final name segment from a normalized remote path.\n *\n * @param input - Remote path to inspect.\n * @returns The final path segment, or `/` when the input is the absolute root.\n * @throws {@link ConfigurationError} When the input contains unsafe characters.\n */\nexport function basenameRemotePath(input: string): string {\n const normalized = normalizeRemotePath(input);\n const parts = normalized.split(\"/\").filter(Boolean);\n return parts[parts.length - 1] ?? normalized;\n}\n","/**\n * Deterministic in-memory provider for contract and unit tests.\n *\n * @module providers/memory/MemoryProvider\n */\nimport { Buffer } from \"node:buffer\";\nimport type { CapabilitySet } from \"../../core/CapabilitySet\";\nimport type { TransferSession } from \"../../core/TransferSession\";\nimport { ConfigurationError, PathNotFoundError } from \"../../errors/ZeroTransferError\";\nimport type { TransferVerificationResult } from \"../../transfers/TransferJob\";\nimport type { ProviderFactory } from \"../ProviderFactory\";\nimport type { TransferProvider } from \"../Provider\";\nimport type {\n ProviderTransferOperations,\n ProviderTransferReadRequest,\n ProviderTransferReadResult,\n ProviderTransferWriteRequest,\n ProviderTransferWriteResult,\n} from \"../ProviderTransferOperations\";\nimport type { RemoteFileSystem } from \"../RemoteFileSystem\";\nimport type {\n MkdirOptions,\n RemoteEntry,\n RemotePermissions,\n RemoteStat,\n RemoveOptions,\n RmdirOptions,\n} from \"../../types/public\";\nimport { basenameRemotePath, normalizeRemotePath } from \"../../utils/path\";\n\nconst MEMORY_PROVIDER_ID = \"memory\";\n\nconst MEMORY_PROVIDER_CAPABILITIES: CapabilitySet = {\n provider: MEMORY_PROVIDER_ID,\n authentication: [\"anonymous\"],\n list: true,\n stat: true,\n readStream: true,\n writeStream: true,\n serverSideCopy: false,\n serverSideMove: false,\n resumeDownload: true,\n resumeUpload: true,\n checksum: [],\n atomicRename: false,\n chmod: false,\n chown: false,\n symlink: true,\n metadata: [\n \"accessedAt\",\n \"createdAt\",\n \"group\",\n \"modifiedAt\",\n \"owner\",\n \"permissions\",\n \"symlinkTarget\",\n \"uniqueId\",\n ],\n maxConcurrency: 32,\n notes: [\"Deterministic in-memory provider for tests and provider contract validation\"],\n};\n\n/** Fixture entry used to seed a memory provider instance. */\nexport interface MemoryProviderEntry extends Omit<RemoteEntry, \"name\"> {\n /** Entry basename. When omitted, it is derived from `path`. */\n name?: string;\n /** Optional byte content for file entries. Strings are encoded as UTF-8. */\n content?: string | Uint8Array;\n}\n\n/** Options used to create a deterministic memory provider factory. */\nexport interface MemoryProviderOptions {\n /** Entries available to sessions created by this provider factory. */\n entries?: Iterable<MemoryProviderEntry>;\n}\n\n/**\n * Creates a provider factory backed by deterministic in-memory fixture entries.\n *\n * Useful for tests and examples where you want a real `TransferSession` without\n * touching disk or the network. Entries are pre-seeded; mutations made through\n * the session are visible to subsequent operations on the same provider.\n *\n * @param options - Optional fixture entries to expose through the memory provider.\n * @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.\n *\n * @example Seed entries and read them back\n * ```ts\n * import { createMemoryProviderFactory, createTransferClient } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({\n * providers: [createMemoryProviderFactory({\n * entries: [\n * { path: \"/fixtures/hello.txt\", content: \"hello world\" },\n * { path: \"/fixtures/data.bin\", content: new Uint8Array([1, 2, 3]) },\n * ],\n * })],\n * });\n *\n * const session = await client.connect({ host: \"fixtures\", provider: \"memory\" });\n * console.log(await session.fs.list(\"/fixtures\"));\n * ```\n */\nexport function createMemoryProviderFactory(options: MemoryProviderOptions = {}): ProviderFactory {\n const state = createMemoryState(options.entries ?? []);\n\n return {\n id: MEMORY_PROVIDER_ID,\n capabilities: MEMORY_PROVIDER_CAPABILITIES,\n create: () => new MemoryProvider(state),\n };\n}\n\nclass MemoryProvider implements TransferProvider {\n readonly id = MEMORY_PROVIDER_ID;\n readonly capabilities = MEMORY_PROVIDER_CAPABILITIES;\n\n constructor(private readonly state: MemoryProviderState) {}\n\n connect(): Promise<TransferSession> {\n return Promise.resolve(new MemoryTransferSession(this.state));\n }\n}\n\nclass MemoryTransferSession implements TransferSession {\n readonly provider = MEMORY_PROVIDER_ID;\n readonly capabilities = MEMORY_PROVIDER_CAPABILITIES;\n readonly fs: RemoteFileSystem;\n readonly transfers: ProviderTransferOperations;\n\n constructor(state: MemoryProviderState) {\n this.fs = new MemoryFileSystem(state);\n this.transfers = new MemoryTransferOperations(state);\n }\n\n disconnect(): Promise<void> {\n return Promise.resolve();\n }\n}\n\ninterface MemoryProviderState {\n entries: Map<string, RemoteStat>;\n content: Map<string, Uint8Array>;\n}\n\nclass MemoryFileSystem implements RemoteFileSystem {\n constructor(private readonly state: MemoryProviderState) {}\n\n list(path: string): Promise<RemoteEntry[]> {\n return Promise.resolve().then(() => {\n const normalizedPath = normalizeMemoryPath(path);\n const directory = this.requireEntry(normalizedPath);\n\n if (directory.type !== \"directory\") {\n throw createPathNotFoundError(\n normalizedPath,\n `Memory path is not a directory: ${normalizedPath}`,\n );\n }\n\n return [...this.state.entries.values()]\n .filter(\n (entry) => entry.path !== normalizedPath && getParentPath(entry.path) === normalizedPath,\n )\n .map(cloneRemoteEntry)\n .sort(compareEntries);\n });\n }\n\n stat(path: string): Promise<RemoteStat> {\n return Promise.resolve().then(() =>\n cloneRemoteStat(this.requireEntry(normalizeMemoryPath(path))),\n );\n }\n\n remove(path: string, options: RemoveOptions = {}): Promise<void> {\n return Promise.resolve().then(() => {\n const normalized = normalizeMemoryPath(path);\n const entry = this.state.entries.get(normalized);\n if (entry === undefined) {\n if (options.ignoreMissing) return;\n throw createPathNotFoundError(normalized, `Memory path not found: ${normalized}`);\n }\n if (entry.type === \"directory\") {\n throw createPathNotFoundError(\n normalized,\n `Memory path is a directory; use rmdir: ${normalized}`,\n );\n }\n this.state.entries.delete(normalized);\n this.state.content.delete(normalized);\n });\n }\n\n rename(from: string, to: string): Promise<void> {\n return Promise.resolve().then(() => {\n const fromPath = normalizeMemoryPath(from);\n const toPath = normalizeMemoryPath(to);\n const entry = this.state.entries.get(fromPath);\n if (entry === undefined) {\n throw createPathNotFoundError(fromPath, `Memory path not found: ${fromPath}`);\n }\n ensureParentDirectories(this.state.entries, toPath);\n const moved: RemoteStat = { ...entry, path: toPath, name: basenameRemotePath(toPath) };\n this.state.entries.delete(fromPath);\n this.state.entries.set(toPath, moved);\n const content = this.state.content.get(fromPath);\n if (content !== undefined) {\n this.state.content.delete(fromPath);\n this.state.content.set(toPath, content);\n }\n });\n }\n\n mkdir(path: string, options: MkdirOptions = {}): Promise<void> {\n return Promise.resolve().then(() => {\n const normalized = normalizeMemoryPath(path);\n const existing = this.state.entries.get(normalized);\n if (existing !== undefined) {\n if (existing.type === \"directory\" && options.recursive) return;\n throw createInvalidFixtureError(normalized, `Memory path already exists: ${normalized}`);\n }\n if (options.recursive) {\n ensureParentDirectories(this.state.entries, normalized);\n } else {\n const parent = getParentPath(normalized);\n if (parent !== undefined && !this.state.entries.has(parent)) {\n throw createPathNotFoundError(parent, `Memory parent not found: ${parent}`);\n }\n }\n this.state.entries.set(normalized, createDirectoryEntry(normalized));\n });\n }\n\n rmdir(path: string, options: RmdirOptions = {}): Promise<void> {\n return Promise.resolve().then(() => {\n const normalized = normalizeMemoryPath(path);\n const entry = this.state.entries.get(normalized);\n if (entry === undefined) {\n if (options.ignoreMissing) return;\n throw createPathNotFoundError(normalized, `Memory path not found: ${normalized}`);\n }\n if (entry.type !== \"directory\") {\n throw createPathNotFoundError(normalized, `Memory path is not a directory: ${normalized}`);\n }\n const children = [...this.state.entries.values()].filter(\n (child) => child.path !== normalized && getParentPath(child.path) === normalized,\n );\n if (children.length > 0 && !options.recursive) {\n throw createInvalidFixtureError(normalized, `Memory directory not empty: ${normalized}`);\n }\n const stack = [...children];\n while (stack.length > 0) {\n const next = stack.pop();\n if (!next) continue;\n if (next.type === \"directory\") {\n for (const grand of this.state.entries.values()) {\n if (grand.path !== next.path && getParentPath(grand.path) === next.path) {\n stack.push(grand);\n }\n }\n }\n this.state.entries.delete(next.path);\n this.state.content.delete(next.path);\n }\n this.state.entries.delete(normalized);\n });\n }\n\n private requireEntry(path: string): RemoteStat {\n const entry = this.state.entries.get(path);\n\n if (entry === undefined) {\n throw createPathNotFoundError(path, `Memory path not found: ${path}`);\n }\n\n return entry;\n }\n}\n\nclass MemoryTransferOperations implements ProviderTransferOperations {\n constructor(private readonly state: MemoryProviderState) {}\n\n read(request: ProviderTransferReadRequest): Promise<ProviderTransferReadResult> {\n return Promise.resolve().then(() => {\n request.throwIfAborted();\n const path = normalizeMemoryPath(request.endpoint.path);\n const entry = requireFileEntry(this.state, path);\n const content = this.state.content.get(path) ?? new Uint8Array(entry.size ?? 0);\n const range = resolveByteRange(content.byteLength, request.range);\n const chunk = content.slice(range.offset, range.offset + range.length);\n const result: ProviderTransferReadResult = {\n content: createMemoryContentSource(chunk),\n totalBytes: chunk.byteLength,\n };\n\n if (range.offset > 0) {\n result.bytesRead = range.offset;\n }\n\n return result;\n });\n }\n\n async write(request: ProviderTransferWriteRequest): Promise<ProviderTransferWriteResult> {\n request.throwIfAborted();\n const path = normalizeMemoryPath(request.endpoint.path);\n const existing = this.state.entries.get(path);\n\n if (existing?.type === \"directory\") {\n throw createInvalidFixtureError(path, `Memory path is a directory: ${path}`);\n }\n\n const writtenContent = await collectTransferContent(request);\n const offset = normalizeOptionalByteCount(request.offset, \"offset\");\n const previousContent = this.state.content.get(path) ?? new Uint8Array(0);\n const content =\n offset === undefined\n ? writtenContent\n : mergeContentAtOffset(previousContent, writtenContent, offset);\n\n ensureParentDirectories(this.state.entries, path);\n this.state.entries.set(path, createWrittenFileEntry(path, content.byteLength));\n this.state.content.set(path, content);\n\n const result: ProviderTransferWriteResult = {\n bytesTransferred: writtenContent.byteLength,\n resumed: offset !== undefined && offset > 0,\n totalBytes: content.byteLength,\n verified: request.verification?.verified ?? false,\n };\n\n if (request.verification !== undefined) {\n result.verification = cloneVerification(request.verification);\n }\n\n return result;\n }\n}\n\nfunction createMemoryState(entries: Iterable<MemoryProviderEntry>): MemoryProviderState {\n const state: MemoryProviderState = {\n content: new Map(),\n entries: new Map([[\"/\", createDirectoryEntry(\"/\")]]),\n };\n\n for (const input of entries) {\n const entry = createMemoryEntry(input);\n const content = createMemoryContent(input, entry);\n\n if (entry.path === \"/\" && entry.type !== \"directory\") {\n throw createInvalidFixtureError(entry.path, \"Memory provider root must be a directory\");\n }\n\n ensureParentDirectories(state.entries, entry.path);\n state.entries.set(entry.path, entry);\n\n if (content !== undefined) {\n state.content.set(entry.path, content);\n }\n }\n\n return state;\n}\n\nfunction createMemoryEntry(input: MemoryProviderEntry): RemoteStat {\n const path = normalizeMemoryPath(input.path);\n const entry: RemoteEntry = {\n name: input.name ?? basenameRemotePath(path),\n path,\n type: input.type,\n };\n\n copyOptionalEntryFields(entry, input);\n\n const content = normalizeMemoryContent(input.content);\n\n if (content !== undefined) {\n entry.size = content.byteLength;\n }\n\n return {\n ...entry,\n exists: true,\n };\n}\n\nfunction createMemoryContent(\n input: MemoryProviderEntry,\n entry: RemoteStat,\n): Uint8Array | undefined {\n const content = normalizeMemoryContent(input.content);\n\n if (content !== undefined) {\n if (entry.type !== \"file\") {\n throw createInvalidFixtureError(\n entry.path,\n `Memory fixture content requires a file: ${entry.path}`,\n );\n }\n\n return content;\n }\n\n if (entry.type === \"file\") {\n return new Uint8Array(entry.size ?? 0);\n }\n\n return undefined;\n}\n\nfunction normalizeMemoryContent(content: string | Uint8Array | undefined): Uint8Array | undefined {\n if (content === undefined) {\n return undefined;\n }\n\n return typeof content === \"string\" ? Buffer.from(content) : new Uint8Array(content);\n}\n\nfunction createWrittenFileEntry(path: string, size: number): RemoteStat {\n return {\n exists: true,\n modifiedAt: new Date(),\n name: basenameRemotePath(path),\n path,\n size,\n type: \"file\",\n };\n}\n\nfunction createDirectoryEntry(path: string): RemoteStat {\n return {\n exists: true,\n name: basenameRemotePath(path),\n path,\n type: \"directory\",\n };\n}\n\nfunction ensureParentDirectories(state: Map<string, RemoteStat>, path: string): void {\n for (const parentPath of getAncestorPaths(path)) {\n const parent = state.get(parentPath);\n\n if (parent !== undefined && parent.type !== \"directory\") {\n throw createInvalidFixtureError(\n parentPath,\n `Memory fixture parent is not a directory: ${parentPath}`,\n );\n }\n\n if (parent === undefined) {\n state.set(parentPath, createDirectoryEntry(parentPath));\n }\n }\n}\n\nfunction normalizeMemoryPath(path: string): string {\n const normalized = normalizeRemotePath(path);\n\n if (normalized === \".\" || normalized === \"/\") {\n return \"/\";\n }\n\n return normalized.startsWith(\"/\") ? normalized : `/${normalized}`;\n}\n\nfunction getAncestorPaths(path: string): string[] {\n const ancestors: string[] = [];\n let parentPath = getParentPath(path);\n\n while (parentPath !== undefined && parentPath !== \"/\") {\n ancestors.unshift(parentPath);\n parentPath = getParentPath(parentPath);\n }\n\n return ancestors;\n}\n\nfunction getParentPath(path: string): string | undefined {\n if (path === \"/\") {\n return undefined;\n }\n\n const parentEnd = path.lastIndexOf(\"/\");\n return parentEnd <= 0 ? \"/\" : path.slice(0, parentEnd);\n}\n\nfunction requireFileEntry(state: MemoryProviderState, path: string): RemoteStat {\n const entry = state.entries.get(path);\n\n if (entry === undefined) {\n throw createPathNotFoundError(path, `Memory path not found: ${path}`);\n }\n\n if (entry.type !== \"file\") {\n throw createPathNotFoundError(path, `Memory path is not a file: ${path}`);\n }\n\n return entry;\n}\n\nfunction resolveByteRange(\n size: number,\n range: ProviderTransferReadRequest[\"range\"],\n): { offset: number; length: number } {\n if (range === undefined) {\n return { length: size, offset: 0 };\n }\n\n const requestedOffset = normalizeByteCount(range.offset, \"offset\");\n const requestedLength =\n range.length === undefined\n ? size - Math.min(requestedOffset, size)\n : normalizeByteCount(range.length, \"length\");\n const offset = Math.min(requestedOffset, size);\n const length = Math.max(0, Math.min(requestedLength, size - offset));\n\n return { length, offset };\n}\n\nasync function collectTransferContent(request: ProviderTransferWriteRequest): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n let byteLength = 0;\n\n for await (const chunk of request.content) {\n request.throwIfAborted();\n const clonedChunk = new Uint8Array(chunk);\n chunks.push(clonedChunk);\n byteLength += clonedChunk.byteLength;\n request.reportProgress(byteLength, request.totalBytes);\n }\n\n return concatChunks(chunks, byteLength);\n}\n\nfunction concatChunks(chunks: Uint8Array[], byteLength: number): Uint8Array {\n const content = new Uint8Array(byteLength);\n let offset = 0;\n\n for (const chunk of chunks) {\n content.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return content;\n}\n\nfunction mergeContentAtOffset(\n previousContent: Uint8Array,\n writtenContent: Uint8Array,\n offset: number,\n): Uint8Array {\n const content = new Uint8Array(\n Math.max(previousContent.byteLength, offset + writtenContent.byteLength),\n );\n content.set(previousContent);\n content.set(writtenContent, offset);\n return content;\n}\n\nasync function* createMemoryContentSource(content: Uint8Array): AsyncGenerator<Uint8Array> {\n await Promise.resolve();\n yield new Uint8Array(content);\n}\n\nfunction normalizeOptionalByteCount(value: number | undefined, field: string): number | undefined {\n return value === undefined ? undefined : normalizeByteCount(value, field);\n}\n\nfunction normalizeByteCount(value: number, field: string): number {\n if (!Number.isFinite(value) || value < 0) {\n throw createInvalidFixtureError(\"/\", `Memory provider ${field} must be a non-negative number`);\n }\n\n return Math.floor(value);\n}\n\nfunction cloneVerification(verification: TransferVerificationResult): TransferVerificationResult {\n const clone: TransferVerificationResult = { verified: verification.verified };\n\n if (verification.method !== undefined) clone.method = verification.method;\n if (verification.checksum !== undefined) clone.checksum = verification.checksum;\n if (verification.expectedChecksum !== undefined) {\n clone.expectedChecksum = verification.expectedChecksum;\n }\n if (verification.actualChecksum !== undefined) clone.actualChecksum = verification.actualChecksum;\n if (verification.details !== undefined) clone.details = { ...verification.details };\n\n return clone;\n}\n\nfunction cloneRemoteEntry(entry: RemoteEntry): RemoteEntry {\n const clone: RemoteEntry = {\n name: entry.name,\n path: entry.path,\n type: entry.type,\n };\n\n copyOptionalEntryFields(clone, entry);\n return clone;\n}\n\nfunction cloneRemoteStat(entry: RemoteStat): RemoteStat {\n return {\n ...cloneRemoteEntry(entry),\n exists: true,\n };\n}\n\nfunction copyOptionalEntryFields(target: RemoteEntry, source: Partial<RemoteEntry>): void {\n if (source.size !== undefined) target.size = source.size;\n if (source.modifiedAt !== undefined) target.modifiedAt = cloneDate(source.modifiedAt);\n if (source.createdAt !== undefined) target.createdAt = cloneDate(source.createdAt);\n if (source.accessedAt !== undefined) target.accessedAt = cloneDate(source.accessedAt);\n if (source.permissions !== undefined) target.permissions = clonePermissions(source.permissions);\n if (source.owner !== undefined) target.owner = source.owner;\n if (source.group !== undefined) target.group = source.group;\n if (source.symlinkTarget !== undefined) target.symlinkTarget = source.symlinkTarget;\n if (source.uniqueId !== undefined) target.uniqueId = source.uniqueId;\n if (source.raw !== undefined) target.raw = source.raw;\n}\n\nfunction cloneDate(value: Date): Date {\n return new Date(value.getTime());\n}\n\nfunction clonePermissions(permissions: RemotePermissions): RemotePermissions {\n return { ...permissions };\n}\n\nfunction compareEntries(left: RemoteEntry, right: RemoteEntry): number {\n return left.path.localeCompare(right.path);\n}\n\nfunction createPathNotFoundError(path: string, message: string): PathNotFoundError {\n return new PathNotFoundError({\n details: { provider: MEMORY_PROVIDER_ID },\n message,\n path,\n retryable: false,\n });\n}\n\nfunction createInvalidFixtureError(path: string, message: string): ConfigurationError {\n return new ConfigurationError({\n details: { provider: MEMORY_PROVIDER_ID },\n message,\n path,\n retryable: false,\n });\n}\n","/**\n * Connection profile secret resolution helpers.\n *\n * @module profiles/resolveConnectionProfileSecrets\n */\nimport type { ConnectionProfile, SshProfile, TlsProfile, TlsSecretSource } from \"../types/public\";\nimport { resolveSecret, type ResolveSecretOptions, type SecretValue } from \"./SecretSource\";\n\n/** SSH profile with private-key and known-host material resolved. */\nexport interface ResolvedSshProfile extends Omit<\n SshProfile,\n \"knownHosts\" | \"passphrase\" | \"privateKey\"\n> {\n /** Resolved private key material. */\n privateKey?: SecretValue;\n /** Resolved private-key passphrase. */\n passphrase?: SecretValue;\n /** Resolved OpenSSH known_hosts material. */\n knownHosts?: SecretValue | SecretValue[];\n}\n\n/** TLS profile with certificate-bearing secret sources resolved. */\nexport interface ResolvedTlsProfile extends Omit<\n TlsProfile,\n \"ca\" | \"cert\" | \"key\" | \"passphrase\" | \"pfx\"\n> {\n /** Resolved certificate authority bundle. */\n ca?: SecretValue | SecretValue[];\n /** Resolved client certificate PEM. */\n cert?: SecretValue;\n /** Resolved client private key PEM. */\n key?: SecretValue;\n /** Resolved encrypted private-key or PFX/P12 passphrase. */\n passphrase?: SecretValue;\n /** Resolved PFX/P12 client certificate bundle. */\n pfx?: SecretValue;\n}\n\n/** Connection profile with username, password, TLS, and SSH material sources resolved. */\nexport interface ResolvedConnectionProfile extends Omit<\n ConnectionProfile,\n \"password\" | \"ssh\" | \"tls\" | \"username\"\n> {\n /** Resolved username or account identifier. */\n username?: SecretValue;\n /** Resolved password or credential bytes. */\n password?: SecretValue;\n /** Resolved TLS profile when certificate material is configured. */\n tls?: ResolvedTlsProfile;\n /** Resolved SSH profile when private-key material is configured. */\n ssh?: ResolvedSshProfile;\n}\n\n/**\n * Resolves credential and TLS material secret sources without mutating the original profile.\n *\n * @param profile - Profile containing optional secret sources.\n * @param options - Optional env and file-reader overrides.\n * @returns Profile copy with username, password, TLS material, and SSH material resolved when present.\n */\nexport async function resolveConnectionProfileSecrets(\n profile: ConnectionProfile,\n options: ResolveSecretOptions = {},\n): Promise<ResolvedConnectionProfile> {\n const { password, ssh, tls, username, ...rest } = profile;\n const resolved: ResolvedConnectionProfile = { ...rest };\n\n if (username !== undefined) {\n resolved.username = await resolveSecret(username, options);\n }\n\n if (password !== undefined) {\n resolved.password = await resolveSecret(password, options);\n }\n\n if (tls !== undefined) {\n resolved.tls = await resolveTlsProfile(tls, options);\n }\n\n if (ssh !== undefined) {\n resolved.ssh = await resolveSshProfile(ssh, options);\n }\n\n return resolved;\n}\n\n/**\n * Resolves SSH private-key, passphrase, and known-host source descriptors.\n *\n * @param profile - SSH profile containing optional secret-backed material.\n * @param options - Optional env and file-reader overrides.\n * @returns SSH profile copy with private-key material resolved.\n */\nasync function resolveSshProfile(\n profile: SshProfile,\n options: ResolveSecretOptions,\n): Promise<ResolvedSshProfile> {\n const { knownHosts, passphrase, privateKey, ...rest } = profile;\n const resolved: ResolvedSshProfile = { ...rest };\n\n if (privateKey !== undefined) resolved.privateKey = await resolveSecret(privateKey, options);\n if (passphrase !== undefined) resolved.passphrase = await resolveSecret(passphrase, options);\n if (knownHosts !== undefined)\n resolved.knownHosts = await resolveKnownHostsSource(knownHosts, options);\n\n return resolved;\n}\n\n/**\n * Resolves known_hosts material while preserving ordered source arrays.\n *\n * @param source - Single known_hosts source or source array.\n * @param options - Optional env and file-reader overrides.\n * @returns Resolved known_hosts value or value array.\n */\nasync function resolveKnownHostsSource(\n source: NonNullable<SshProfile[\"knownHosts\"]>,\n options: ResolveSecretOptions,\n): Promise<SecretValue | SecretValue[]> {\n if (Array.isArray(source)) {\n return Promise.all(source.map((item) => resolveSecret(item, options)));\n }\n\n return resolveSecret(source, options);\n}\n\n/**\n * Resolves TLS certificate, key, PFX, passphrase, and CA source descriptors.\n *\n * @param profile - TLS profile containing optional secret-backed material.\n * @param options - Optional env and file-reader overrides.\n * @returns TLS profile copy with material sources resolved.\n */\nasync function resolveTlsProfile(\n profile: TlsProfile,\n options: ResolveSecretOptions,\n): Promise<ResolvedTlsProfile> {\n const { ca, cert, key, passphrase, pfx, ...rest } = profile;\n const resolved: ResolvedTlsProfile = { ...rest };\n\n if (ca !== undefined) resolved.ca = await resolveTlsSecretSource(ca, options);\n if (cert !== undefined) resolved.cert = await resolveSecret(cert, options);\n if (key !== undefined) resolved.key = await resolveSecret(key, options);\n if (passphrase !== undefined) resolved.passphrase = await resolveSecret(passphrase, options);\n if (pfx !== undefined) resolved.pfx = await resolveSecret(pfx, options);\n\n return resolved;\n}\n\n/**\n * Resolves a TLS material source while preserving ordered CA bundle arrays.\n *\n * @param source - Single secret source or source array.\n * @param options - Optional env and file-reader overrides.\n * @returns Resolved secret value or resolved value array.\n */\nasync function resolveTlsSecretSource(\n source: TlsSecretSource,\n options: ResolveSecretOptions,\n): Promise<SecretValue | SecretValue[]> {\n if (Array.isArray(source)) {\n return Promise.all(source.map((item) => resolveSecret(item, options)));\n }\n\n return resolveSecret(source, options);\n}\n","/**\n * OAuth bearer-token helpers for cloud-drive and object-storage providers.\n *\n * Cloud providers in this SDK accept a bearer token via `profile.password`,\n * which is resolved as a {@link SecretSource}. Long-lived access tokens are\n * rare in OAuth flows; instead, applications hold a refresh token (or use a\n * client-credentials grant) and exchange it for short-lived access tokens.\n *\n * {@link createOAuthTokenSecretSource} adapts an arbitrary refresh callback\n * into a `SecretProvider` (one of the accepted `SecretSource` shapes) that\n * caches the most recent access token until its expiry approaches, then\n * silently re-runs the refresh callback. The cache honours an optional\n * `skewMs` margin so tokens are renewed before they expire on the wire.\n *\n * @module profiles/OAuthTokenSource\n */\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { SecretProvider } from \"./SecretSource\";\n\n/** Token material returned by {@link OAuthRefreshCallback}. */\nexport interface OAuthAccessToken {\n /** Access token value. Required. */\n accessToken: string;\n /**\n * Lifetime in seconds (`expires_in`-style). When provided, the helper caches\n * the token until `now + (expiresInSeconds - skewSeconds)`.\n */\n expiresInSeconds?: number;\n /** Absolute expiry. Wins over `expiresInSeconds` when both are provided. */\n expiresAt?: Date;\n}\n\n/** Refresh callback invoked when no valid cached token is available. */\nexport type OAuthRefreshCallback = () => OAuthAccessToken | Promise<OAuthAccessToken>;\n\n/** Options accepted by {@link createOAuthTokenSecretSource}. */\nexport interface OAuthTokenSecretSourceOptions {\n /**\n * Safety margin (in milliseconds) subtracted from the token's expiry to\n * trigger a refresh before the wire deadline. Defaults to `60_000` (60s).\n */\n skewMs?: number;\n /** Clock used to evaluate expiry. Defaults to `Date.now`. */\n now?: () => number;\n}\n\ninterface CachedToken {\n accessToken: string;\n /** Absolute expiry in epoch milliseconds, or `undefined` for non-expiring tokens. */\n expiresAtMs: number | undefined;\n}\n\n/**\n * Builds a {@link SecretProvider} that exchanges a refresh callback for\n * cached, auto-renewing access tokens.\n *\n * The returned function can be passed directly as `profile.password` for any\n * provider that accepts bearer tokens (Dropbox, Google Drive, OneDrive, GCS,\n * Azure Blob via AAD).\n *\n * @example\n * ```ts\n * const password = createOAuthTokenSecretSource(async () => {\n * const res = await fetch(\"https://example.com/oauth/token\", { ... });\n * const body = (await res.json()) as { access_token: string; expires_in: number };\n * return { accessToken: body.access_token, expiresInSeconds: body.expires_in };\n * });\n * const session = await factory.create().connect({ host: \"\", protocol: \"ftp\", password });\n * ```\n */\nexport function createOAuthTokenSecretSource(\n refresh: OAuthRefreshCallback,\n options: OAuthTokenSecretSourceOptions = {},\n): SecretProvider {\n if (typeof refresh !== \"function\") {\n throw new ConfigurationError({\n message: \"createOAuthTokenSecretSource requires a refresh callback\",\n retryable: false,\n });\n }\n const skewMs = options.skewMs ?? 60_000;\n const now = options.now ?? (() => Date.now());\n if (skewMs < 0) {\n throw new ConfigurationError({\n message: \"OAuthTokenSecretSourceOptions.skewMs must be non-negative\",\n retryable: false,\n });\n }\n\n let cache: CachedToken | undefined;\n let pending: Promise<CachedToken> | undefined;\n\n const renew = async (): Promise<CachedToken> => {\n const result = await refresh();\n if (typeof result.accessToken !== \"string\" || result.accessToken === \"\") {\n throw new ConfigurationError({\n message: \"OAuth refresh callback returned an empty access token\",\n retryable: false,\n });\n }\n let expiresAtMs: number | undefined;\n if (result.expiresAt !== undefined) {\n const ts = result.expiresAt.getTime();\n if (Number.isFinite(ts)) expiresAtMs = ts;\n } else if (typeof result.expiresInSeconds === \"number\") {\n if (!Number.isFinite(result.expiresInSeconds) || result.expiresInSeconds <= 0) {\n throw new ConfigurationError({\n message: \"OAuth refresh callback returned a non-positive expiresInSeconds\",\n retryable: false,\n });\n }\n expiresAtMs = now() + result.expiresInSeconds * 1000;\n }\n const cached: CachedToken = { accessToken: result.accessToken, expiresAtMs };\n cache = cached;\n return cached;\n };\n\n return async () => {\n const current = cache;\n if (current !== undefined && isFresh(current, skewMs, now)) {\n return current.accessToken;\n }\n if (pending === undefined) {\n pending = renew().finally(() => {\n pending = undefined;\n });\n }\n const refreshed = await pending;\n return refreshed.accessToken;\n };\n}\n\nfunction isFresh(token: CachedToken, skewMs: number, now: () => number): boolean {\n if (token.expiresAtMs === undefined) return true;\n return token.expiresAtMs - skewMs > now();\n}\n","/**\n * OpenSSH `known_hosts` parsing helpers used by SFTP profile imports and host-key verification.\n *\n * @module profiles/importers/KnownHostsParser\n */\nimport { Buffer } from \"node:buffer\";\nimport { createHmac } from \"node:crypto\";\n\n/** Marker prefixing a known_hosts line (`@cert-authority` or `@revoked`). */\nexport type KnownHostsMarker = \"cert-authority\" | \"revoked\";\n\n/** Parsed entry from an OpenSSH `known_hosts` file. */\nexport interface KnownHostsEntry {\n /** Optional line marker (`@cert-authority` or `@revoked`). */\n marker?: KnownHostsMarker;\n /** Raw, comma-separated host patterns. Negation patterns retain their leading `!`. */\n hostPatterns: readonly string[];\n /** Hashed-salt component for `|1|salt|hash` entries. Mutually exclusive with plain patterns. */\n hashedSalt?: string;\n /** Hashed-hash component for `|1|salt|hash` entries. Mutually exclusive with plain patterns. */\n hashedHash?: string;\n /** SSH key algorithm identifier (e.g. `ssh-ed25519`, `ecdsa-sha2-nistp256`). */\n keyType: string;\n /** Base64-encoded public key blob. */\n keyBase64: string;\n /** Trailing comment text, if any. */\n comment?: string;\n /** Original line text without trailing newline. */\n raw: string;\n}\n\n/**\n * Parses OpenSSH `known_hosts` content into structured entries. Comment and blank lines are skipped.\n * Lines that cannot be parsed are silently dropped so callers can tolerate hand-edited files.\n *\n * @param text - Raw `known_hosts` file contents.\n * @returns Parsed entries in source order.\n */\nexport function parseKnownHosts(text: string): KnownHostsEntry[] {\n const entries: KnownHostsEntry[] = [];\n const lines = text.split(/\\r?\\n/);\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed === \"\" || trimmed.startsWith(\"#\")) continue;\n const entry = parseKnownHostsLine(line);\n if (entry !== undefined) entries.push(entry);\n }\n return entries;\n}\n\nfunction parseKnownHostsLine(line: string): KnownHostsEntry | undefined {\n const tokens = line.trim().split(/\\s+/);\n if (tokens.length < 3) return undefined;\n let index = 0;\n let marker: KnownHostsMarker | undefined;\n const first = tokens[index];\n if (first === \"@cert-authority\" || first === \"@revoked\") {\n marker = first === \"@cert-authority\" ? \"cert-authority\" : \"revoked\";\n index += 1;\n }\n const hostField = tokens[index];\n const keyType = tokens[index + 1];\n const keyBase64 = tokens[index + 2];\n if (hostField === undefined || keyType === undefined || keyBase64 === undefined) return undefined;\n const commentTokens = tokens.slice(index + 3);\n const comment = commentTokens.length > 0 ? commentTokens.join(\" \") : undefined;\n\n let hostPatterns: readonly string[] = [];\n let hashedSalt: string | undefined;\n let hashedHash: string | undefined;\n if (hostField.startsWith(\"|1|\")) {\n const parts = hostField.split(\"|\");\n if (parts.length < 4) return undefined;\n hashedSalt = parts[2];\n hashedHash = parts[3];\n } else {\n hostPatterns = hostField.split(\",\").filter((token) => token !== \"\");\n }\n\n const entry: KnownHostsEntry = {\n hostPatterns,\n keyBase64,\n keyType,\n raw: line,\n };\n if (marker !== undefined) entry.marker = marker;\n if (comment !== undefined) entry.comment = comment;\n if (hashedSalt !== undefined) entry.hashedSalt = hashedSalt;\n if (hashedHash !== undefined) entry.hashedHash = hashedHash;\n return entry;\n}\n\n/** Default OpenSSH port used when matching host patterns without an explicit `[host]:port`. */\nconst DEFAULT_SSH_PORT = 22;\n\n/**\n * Returns true when the given host (and optional port) matches the entry's host patterns.\n * Hashed entries use HMAC-SHA1 verification per OpenSSH semantics.\n *\n * @param entry - Parsed `known_hosts` entry to test.\n * @param host - Hostname or IP literal to match.\n * @param port - Optional connection port. Defaults to {@link DEFAULT_SSH_PORT}.\n * @returns Whether the entry matches and is not negated.\n */\nexport function matchKnownHostsEntry(\n entry: KnownHostsEntry,\n host: string,\n port: number = DEFAULT_SSH_PORT,\n): boolean {\n if (entry.hashedSalt !== undefined && entry.hashedHash !== undefined) {\n return matchesHashedEntry(entry.hashedSalt, entry.hashedHash, host, port);\n }\n let matched = false;\n for (const pattern of entry.hostPatterns) {\n if (pattern.startsWith(\"!\")) {\n const negated = pattern.slice(1);\n if (matchesPlainPattern(negated, host, port)) return false;\n continue;\n }\n if (matchesPlainPattern(pattern, host, port)) matched = true;\n }\n return matched;\n}\n\n/**\n * Filters parsed entries down to those that match the given host/port. Negations are honored.\n *\n * @param entries - Entries returned by {@link parseKnownHosts}.\n * @param host - Hostname or IP literal to match.\n * @param port - Optional connection port. Defaults to {@link DEFAULT_SSH_PORT}.\n * @returns Matching entries in source order.\n */\nexport function matchKnownHosts(\n entries: readonly KnownHostsEntry[],\n host: string,\n port: number = DEFAULT_SSH_PORT,\n): KnownHostsEntry[] {\n return entries.filter((entry) => matchKnownHostsEntry(entry, host, port));\n}\n\nfunction matchesPlainPattern(pattern: string, host: string, port: number): boolean {\n const portMatch = pattern.match(/^\\[(.+)\\]:(\\d+)$/);\n if (portMatch) {\n const [, hostPattern, portText] = portMatch;\n if (hostPattern === undefined || portText === undefined) return false;\n const expectedPort = Number.parseInt(portText, 10);\n if (Number.isNaN(expectedPort) || expectedPort !== port) return false;\n return globMatch(hostPattern, host);\n }\n return port === DEFAULT_SSH_PORT && globMatch(pattern, host);\n}\n\nfunction globMatch(pattern: string, value: string): boolean {\n const regex = new RegExp(\n `^${pattern\n .replace(/[.+^${}()|\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\")}$`,\n \"i\",\n );\n return regex.test(value);\n}\n\nfunction matchesHashedEntry(salt: string, hash: string, host: string, port: number): boolean {\n const saltBuffer = Buffer.from(salt, \"base64\");\n if (saltBuffer.length === 0) return false;\n const candidates = port === DEFAULT_SSH_PORT ? [host] : [`[${host}]:${String(port)}`, host];\n for (const candidate of candidates) {\n const expected = createHmac(\"sha1\", saltBuffer).update(candidate).digest(\"base64\");\n if (expected === hash) return true;\n }\n return false;\n}\n","/**\n * OpenSSH `ssh_config` parser and {@link ConnectionProfile} importer.\n *\n * Supports the directives most commonly used by SFTP profiles: `HostName`, `Port`, `User`,\n * `IdentityFile`, `UserKnownHostsFile`, `ProxyJump`, `ConnectTimeout`, plus the SSH algorithm\n * controls (`KexAlgorithms`, `Ciphers`, `MACs`, `HostKeyAlgorithms`).\n *\n * @module profiles/importers/OpenSshConfigImporter\n */\nimport { ConfigurationError } from \"../../errors/ZeroTransferError\";\nimport type { ConnectionProfile } from \"../../types/public\";\n\n/** Parsed `Host` block from an OpenSSH config file. */\nexport interface OpenSshConfigEntry {\n /** Host patterns declared on the `Host` line. */\n patterns: readonly string[];\n /** Lower-cased directive name to ordered values. Multi-valued directives (e.g. `IdentityFile`) preserve order. */\n options: Readonly<Record<string, readonly string[]>>;\n}\n\n/**\n * Parses OpenSSH `ssh_config` text into structured `Host` blocks.\n *\n * The parser is intentionally permissive: unknown directives are retained and `Match` blocks are skipped.\n *\n * @param text - Contents of the `ssh_config` file.\n * @returns Parsed `Host` entries in source order.\n */\nexport function parseOpenSshConfig(text: string): OpenSshConfigEntry[] {\n const entries: OpenSshConfigEntry[] = [];\n let current: { patterns: string[]; options: Record<string, string[]> } | undefined;\n let skipping = false;\n const lines = text.split(/\\r?\\n/);\n for (const rawLine of lines) {\n const line = rawLine.replace(/#.*$/, \"\").trim();\n if (line === \"\") continue;\n const match = line.match(/^([A-Za-z][A-Za-z0-9_-]*)\\s*=?\\s*(.*)$/);\n if (!match) continue;\n const [, keywordRaw, valueRaw] = match;\n if (keywordRaw === undefined || valueRaw === undefined) continue;\n const keyword = keywordRaw.toLowerCase();\n const value = valueRaw.trim();\n if (keyword === \"host\") {\n if (current !== undefined) entries.push(current);\n current = { options: {}, patterns: tokenizeValues(value) };\n skipping = false;\n continue;\n }\n if (keyword === \"match\") {\n if (current !== undefined) entries.push(current);\n current = undefined;\n skipping = true;\n continue;\n }\n if (skipping || current === undefined) continue;\n const values = tokenizeValues(value);\n const existing = current.options[keyword];\n if (existing === undefined) {\n current.options[keyword] = [...values];\n } else {\n existing.push(...values);\n }\n }\n if (current !== undefined) entries.push(current);\n return entries;\n}\n\nfunction tokenizeValues(value: string): string[] {\n if (value === \"\") return [];\n const tokens: string[] = [];\n const regex = /\"([^\"]*)\"|(\\S+)/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(value)) !== null) {\n tokens.push(match[1] ?? match[2] ?? \"\");\n }\n return tokens;\n}\n\n/**\n * Resolved set of directives for a given host alias. Values from later-declared blocks are\n * merged after earlier ones so wildcard fallbacks (e.g. `Host *`) only fill gaps.\n */\nexport interface ResolvedOpenSshHost {\n /** Host alias the lookup was performed against. */\n alias: string;\n /** Per-directive ordered values, keyed by lower-cased directive name. */\n options: Readonly<Record<string, readonly string[]>>;\n /** Source entries that contributed to the resolved set, in match order. */\n matched: readonly OpenSshConfigEntry[];\n}\n\n/**\n * Resolves the merged option set for an OpenSSH host alias.\n *\n * @param entries - Parsed entries from {@link parseOpenSshConfig}.\n * @param alias - Host alias to resolve.\n * @returns Merged directive set with the matching entries.\n */\nexport function resolveOpenSshHost(\n entries: readonly OpenSshConfigEntry[],\n alias: string,\n): ResolvedOpenSshHost {\n const merged: Record<string, string[]> = {};\n const matched: OpenSshConfigEntry[] = [];\n for (const entry of entries) {\n if (!entryMatchesAlias(entry, alias)) continue;\n matched.push(entry);\n for (const [key, values] of Object.entries(entry.options)) {\n if (merged[key] === undefined) merged[key] = [...values];\n }\n }\n return { alias, matched, options: merged };\n}\n\nfunction entryMatchesAlias(entry: OpenSshConfigEntry, alias: string): boolean {\n let matched = false;\n for (const pattern of entry.patterns) {\n if (pattern.startsWith(\"!\")) {\n if (globMatch(pattern.slice(1), alias)) return false;\n continue;\n }\n if (globMatch(pattern, alias)) matched = true;\n }\n return matched;\n}\n\nfunction globMatch(pattern: string, value: string): boolean {\n const regex = new RegExp(\n `^${pattern\n .replace(/[.+^${}()|\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\")}$`,\n \"i\",\n );\n return regex.test(value);\n}\n\n/** Options accepted by {@link importOpenSshConfig}. */\nexport interface ImportOpenSshConfigOptions {\n /** Raw `ssh_config` text. Either this or {@link entries} must be provided. */\n text?: string;\n /** Pre-parsed entries from {@link parseOpenSshConfig}. */\n entries?: readonly OpenSshConfigEntry[];\n /** Host alias to import. */\n alias: string;\n}\n\n/** Result of {@link importOpenSshConfig}. */\nexport interface ImportOpenSshConfigResult {\n /** Generated SFTP connection profile. */\n profile: ConnectionProfile;\n /** Resolved directive set used to build the profile. */\n resolved: ResolvedOpenSshHost;\n /** Identity file paths declared in the config, in declaration order. */\n identityFiles: readonly string[];\n /** Optional `ProxyJump` value preserved from the config. */\n proxyJump?: string;\n}\n\n/**\n * Builds a {@link ConnectionProfile} for the given SSH alias from `ssh_config` text or pre-parsed entries.\n *\n * @param options - Import options.\n * @returns Importer result with the generated profile and supporting metadata.\n * @throws {@link ConfigurationError} When neither text nor entries is supplied.\n */\nexport function importOpenSshConfig(\n options: ImportOpenSshConfigOptions,\n): ImportOpenSshConfigResult {\n const { alias } = options;\n const entries =\n options.entries ?? (options.text !== undefined ? parseOpenSshConfig(options.text) : undefined);\n if (entries === undefined) {\n throw new ConfigurationError({\n code: \"openssh_config_input_missing\",\n message: \"importOpenSshConfig requires either text or pre-parsed entries.\",\n retryable: false,\n });\n }\n const resolved = resolveOpenSshHost(entries, alias);\n const optionsMap = resolved.options;\n\n const host = first(optionsMap, \"hostname\") ?? alias;\n const portText = first(optionsMap, \"port\");\n const port = portText !== undefined ? safeInt(portText) : undefined;\n const user = first(optionsMap, \"user\");\n const identityFiles = optionsMap[\"identityfile\"] ?? [];\n const knownHostsFiles = optionsMap[\"userknownhostsfile\"] ?? [];\n const connectTimeoutText = first(optionsMap, \"connecttimeout\");\n const proxyJump = first(optionsMap, \"proxyjump\");\n const kex = optionsMap[\"kexalgorithms\"] ?? [];\n const ciphers = optionsMap[\"ciphers\"] ?? [];\n const macs = optionsMap[\"macs\"] ?? [];\n const serverHostKey = optionsMap[\"hostkeyalgorithms\"] ?? [];\n\n const profile: ConnectionProfile = { host, provider: \"sftp\" };\n if (port !== undefined) profile.port = port;\n if (user !== undefined) profile.username = { value: user };\n if (connectTimeoutText !== undefined) {\n const seconds = safeInt(connectTimeoutText);\n if (seconds !== undefined) profile.timeoutMs = seconds * 1000;\n }\n\n const ssh: NonNullable<ConnectionProfile[\"ssh\"]> = {};\n if (identityFiles.length > 0) {\n const firstKey = identityFiles[0];\n if (firstKey !== undefined) ssh.privateKey = { path: expandHome(firstKey) };\n }\n if (knownHostsFiles.length > 0) {\n ssh.knownHosts = knownHostsFiles.map((path) => ({ path: expandHome(path) }));\n }\n const algorithms: Record<string, string[]> = {};\n if (kex.length > 0) algorithms[\"kex\"] = expandAlgorithms(kex);\n if (ciphers.length > 0) algorithms[\"cipher\"] = expandAlgorithms(ciphers);\n if (macs.length > 0) algorithms[\"hmac\"] = expandAlgorithms(macs);\n if (serverHostKey.length > 0) algorithms[\"serverHostKey\"] = expandAlgorithms(serverHostKey);\n if (Object.keys(algorithms).length > 0) {\n ssh.algorithms = algorithms;\n }\n if (Object.keys(ssh).length > 0) profile.ssh = ssh;\n\n const result: ImportOpenSshConfigResult = {\n identityFiles: identityFiles.map(expandHome),\n profile,\n resolved,\n };\n if (proxyJump !== undefined) result.proxyJump = proxyJump;\n return result;\n}\n\nfunction first(\n options: Readonly<Record<string, readonly string[]>>,\n key: string,\n): string | undefined {\n const values = options[key];\n return values !== undefined && values.length > 0 ? values[0] : undefined;\n}\n\nfunction safeInt(text: string): number | undefined {\n const value = Number.parseInt(text, 10);\n return Number.isFinite(value) ? value : undefined;\n}\n\nfunction expandHome(path: string): string {\n if (!path.startsWith(\"~\")) return path;\n const home = process.env[\"HOME\"] ?? process.env[\"USERPROFILE\"];\n if (home === undefined) return path;\n if (path === \"~\") return home;\n if (path.startsWith(\"~/\") || path.startsWith(\"~\\\\\")) return `${home}${path.slice(1)}`;\n return path;\n}\n\nfunction expandAlgorithms(values: readonly string[]): string[] {\n const out: string[] = [];\n for (const value of values) {\n for (const part of value.split(\",\")) {\n const trimmed = part.trim();\n if (trimmed !== \"\") out.push(trimmed);\n }\n }\n return out;\n}\n","/**\n * FileZilla `sitemanager.xml` importer.\n *\n * Walks FileZilla's nested folder/server hierarchy and emits {@link ConnectionProfile} entries\n * for each saved site. The importer ignores cloud providers and other entries it cannot map\n * to a {@link RemoteProtocol}.\n *\n * @module profiles/importers/FileZillaImporter\n */\nimport { Buffer } from \"node:buffer\";\nimport { ConfigurationError } from \"../../errors/ZeroTransferError\";\nimport type { ConnectionProfile } from \"../../types/public\";\n\n/** Imported FileZilla site with the folder hierarchy that contained it. */\nexport interface FileZillaSite {\n /** Site display name. */\n name: string;\n /** Ordered folder names leading to the site (top-level first). Empty for root sites. */\n folder: readonly string[];\n /** Generated connection profile. */\n profile: ConnectionProfile;\n /** Encoded password value retained from the file, if any. */\n password?: string;\n /** Logon type code preserved from the file (`0`=anonymous, `1`=normal, etc.). */\n logonType?: number;\n}\n\n/** Result returned by {@link importFileZillaSites}. */\nexport interface ImportFileZillaSitesResult {\n /** Sites successfully mapped to a connection profile. */\n sites: readonly FileZillaSite[];\n /** Sites that were skipped because their protocol is not supported. */\n skipped: readonly { name: string; folder: readonly string[]; protocol?: number }[];\n}\n\n/**\n * Parses FileZilla `sitemanager.xml` text and returns generated profiles.\n *\n * @param xml - Contents of `sitemanager.xml`.\n * @returns Imported sites and any skipped entries.\n * @throws {@link ConfigurationError} When the XML root cannot be located.\n */\nexport function importFileZillaSites(xml: string): ImportFileZillaSitesResult {\n const events = tokenizeXml(xml);\n if (events.length === 0) {\n throw new ConfigurationError({\n code: \"filezilla_xml_empty\",\n message: \"FileZilla sitemanager XML is empty.\",\n retryable: false,\n });\n }\n const sites: FileZillaSite[] = [];\n const skipped: { name: string; folder: readonly string[]; protocol?: number }[] = [];\n const folderStack: string[] = [];\n const folderNamePending: boolean[] = [];\n let inServer = false;\n let serverFields: Record<string, string> = {};\n let serverPasswordEncoding: string | undefined;\n let activeTag: string | undefined;\n let captureFolderName = false;\n\n for (const event of events) {\n if (event.kind === \"open\") {\n if (event.name === \"Folder\") {\n folderStack.push(\"\");\n folderNamePending.push(true);\n continue;\n }\n if (event.name === \"Server\") {\n inServer = true;\n serverFields = {};\n serverPasswordEncoding = undefined;\n continue;\n }\n activeTag = event.name;\n if (event.name === \"Pass\" && inServer) {\n serverPasswordEncoding = event.attributes[\"encoding\"];\n }\n if (event.name === \"Name\" && !inServer && folderNamePending.length > 0) {\n captureFolderName = true;\n }\n continue;\n }\n if (event.kind === \"text\") {\n if (captureFolderName) {\n const top = folderStack.length - 1;\n if (top >= 0) folderStack[top] = event.text.trim();\n captureFolderName = false;\n continue;\n }\n if (inServer && activeTag !== undefined) {\n serverFields[activeTag] = (serverFields[activeTag] ?? \"\") + event.text;\n }\n continue;\n }\n if (event.kind === \"close\") {\n if (event.name === \"Folder\") {\n folderStack.pop();\n folderNamePending.pop();\n continue;\n }\n if (event.name === \"Server\") {\n const folder = folderStack.filter((segment) => segment !== \"\");\n const result = buildSiteFromFields(serverFields, serverPasswordEncoding);\n if (result.kind === \"site\") {\n sites.push({ ...result.site, folder });\n } else {\n skipped.push({\n folder,\n name: result.name,\n ...(result.protocol !== undefined ? { protocol: result.protocol } : {}),\n });\n }\n inServer = false;\n serverFields = {};\n serverPasswordEncoding = undefined;\n activeTag = undefined;\n continue;\n }\n if (activeTag === event.name) activeTag = undefined;\n }\n }\n return { sites, skipped };\n}\n\ninterface BuiltSite {\n kind: \"site\";\n site: Omit<FileZillaSite, \"folder\">;\n}\n\ninterface SkippedSite {\n kind: \"skipped\";\n name: string;\n protocol?: number;\n}\n\nfunction buildSiteFromFields(\n fields: Record<string, string>,\n passwordEncoding: string | undefined,\n): BuiltSite | SkippedSite {\n const name = (fields[\"Name\"] ?? fields[\"Host\"] ?? \"Untitled\").trim();\n const host = (fields[\"Host\"] ?? \"\").trim();\n if (host === \"\") return { kind: \"skipped\", name };\n const protocolText = fields[\"Protocol\"];\n const protocol = protocolText !== undefined ? Number.parseInt(protocolText.trim(), 10) : 0;\n const mapped = mapFileZillaProtocol(protocol);\n if (mapped === undefined) {\n return Number.isFinite(protocol)\n ? { kind: \"skipped\", name, protocol }\n : { kind: \"skipped\", name };\n }\n const profile: ConnectionProfile = { host, provider: mapped.provider };\n if (mapped.secure !== undefined) profile.secure = mapped.secure;\n const portText = fields[\"Port\"];\n if (portText !== undefined) {\n const port = Number.parseInt(portText.trim(), 10);\n if (Number.isFinite(port)) profile.port = port;\n }\n const user = fields[\"User\"]?.trim();\n if (user !== undefined && user !== \"\") profile.username = { value: user };\n\n let password: string | undefined;\n const rawPass = fields[\"Pass\"];\n if (rawPass !== undefined && rawPass !== \"\") {\n if (passwordEncoding === \"base64\") {\n password = Buffer.from(rawPass, \"base64\").toString(\"utf8\");\n } else {\n password = rawPass;\n }\n if (password !== undefined && password !== \"\") profile.password = { value: password };\n }\n\n const site: Omit<FileZillaSite, \"folder\"> = { name, profile };\n if (password !== undefined) site.password = password;\n const logonText = fields[\"Logontype\"];\n if (logonText !== undefined) {\n const logonType = Number.parseInt(logonText.trim(), 10);\n if (Number.isFinite(logonType)) site.logonType = logonType;\n }\n return { kind: \"site\", site };\n}\n\nfunction mapFileZillaProtocol(\n code: number,\n): { provider: NonNullable<ConnectionProfile[\"provider\"]>; secure?: boolean } | undefined {\n switch (code) {\n case 0:\n return { provider: \"ftp\" };\n case 1:\n return { provider: \"sftp\" };\n case 4:\n return { provider: \"ftps\", secure: true };\n case 5:\n return { provider: \"ftps\", secure: true };\n case 6:\n return { provider: \"ftp\", secure: false };\n default:\n return undefined;\n }\n}\n\ninterface XmlOpenEvent {\n kind: \"open\";\n name: string;\n attributes: Record<string, string>;\n selfClosing: boolean;\n}\ninterface XmlCloseEvent {\n kind: \"close\";\n name: string;\n}\ninterface XmlTextEvent {\n kind: \"text\";\n text: string;\n}\ntype XmlEvent = XmlOpenEvent | XmlCloseEvent | XmlTextEvent;\n\nfunction tokenizeXml(xml: string): XmlEvent[] {\n const events: XmlEvent[] = [];\n let index = 0;\n const length = xml.length;\n while (index < length) {\n const lt = xml.indexOf(\"<\", index);\n if (lt === -1) {\n const text = xml.slice(index);\n if (text.trim() !== \"\") events.push({ kind: \"text\", text: decodeEntities(text) });\n break;\n }\n if (lt > index) {\n const text = xml.slice(index, lt);\n if (text.trim() !== \"\") events.push({ kind: \"text\", text: decodeEntities(text) });\n }\n if (xml.startsWith(\"<!--\", lt)) {\n const end = xml.indexOf(\"-->\", lt + 4);\n index = end === -1 ? length : end + 3;\n continue;\n }\n if (xml.startsWith(\"<![CDATA[\", lt)) {\n const end = xml.indexOf(\"]]>\", lt + 9);\n const cdataEnd = end === -1 ? length : end;\n events.push({ kind: \"text\", text: xml.slice(lt + 9, cdataEnd) });\n index = end === -1 ? length : end + 3;\n continue;\n }\n if (xml[lt + 1] === \"?\" || xml[lt + 1] === \"!\") {\n const gt = xml.indexOf(\">\", lt + 1);\n index = gt === -1 ? length : gt + 1;\n continue;\n }\n const gt = xml.indexOf(\">\", lt + 1);\n if (gt === -1) break;\n const tagBody = xml.slice(lt + 1, gt);\n if (tagBody.startsWith(\"/\")) {\n events.push({ kind: \"close\", name: tagBody.slice(1).trim() });\n } else {\n const selfClosing = tagBody.endsWith(\"/\");\n const body = selfClosing ? tagBody.slice(0, -1) : tagBody;\n const { name, attributes } = parseTagBody(body.trim());\n events.push({ attributes, kind: \"open\", name, selfClosing });\n if (selfClosing) events.push({ kind: \"close\", name });\n }\n index = gt + 1;\n }\n return events;\n}\n\nfunction parseTagBody(body: string): { name: string; attributes: Record<string, string> } {\n const match = body.match(/^([A-Za-z_:][\\w:.-]*)\\s*(.*)$/);\n if (!match) return { attributes: {}, name: body };\n const name = match[1] ?? \"\";\n const rest = match[2] ?? \"\";\n const attributes: Record<string, string> = {};\n const attrRegex = /([A-Za-z_:][\\w:.-]*)\\s*=\\s*(\"([^\"]*)\"|'([^']*)')/g;\n let attrMatch: RegExpExecArray | null;\n while ((attrMatch = attrRegex.exec(rest)) !== null) {\n const key = attrMatch[1];\n const value = attrMatch[3] ?? attrMatch[4] ?? \"\";\n if (key !== undefined) attributes[key] = decodeEntities(value);\n }\n return { attributes, name };\n}\n\nfunction decodeEntities(text: string): string {\n return text\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/&/g, \"&\");\n}\n","/**\n * WinSCP `WinSCP.ini` importer.\n *\n * Parses the INI session sections produced by WinSCP and emits {@link ConnectionProfile} entries.\n * Sessions whose `FSProtocol` cannot be mapped to a classic provider are skipped.\n *\n * @module profiles/importers/WinScpImporter\n */\nimport { ConfigurationError } from \"../../errors/ZeroTransferError\";\nimport type { ConnectionProfile } from \"../../types/public\";\n\n/** Imported WinSCP session entry. */\nexport interface WinScpSession {\n /** Decoded session name (URL-decoded path under the `Sessions\\\\` namespace). */\n name: string;\n /** Hierarchical path segments derived from the session name (folders separated by `/`). */\n folder: readonly string[];\n /** Generated connection profile. */\n profile: ConnectionProfile;\n /** Raw FSProtocol code preserved from the file. */\n fsProtocol?: number;\n /** Raw Ftps code preserved from the file (`0`=none, `1`=implicit, `2`/`3`=explicit). */\n ftps?: number;\n}\n\n/** Result of {@link importWinScpSessions}. */\nexport interface ImportWinScpSessionsResult {\n /** Successfully mapped sessions. */\n sessions: readonly WinScpSession[];\n /** Sessions skipped because their protocol is not supported. */\n skipped: readonly { name: string; folder: readonly string[]; fsProtocol?: number }[];\n}\n\n/**\n * Parses WinSCP `WinSCP.ini` text and returns generated profiles.\n *\n * @param ini - Contents of the WinSCP configuration file.\n * @returns Imported sessions and any skipped entries.\n * @throws {@link ConfigurationError} When no session sections are found.\n */\nexport function importWinScpSessions(ini: string): ImportWinScpSessionsResult {\n const sections = parseIni(ini);\n const sessionSections = sections.filter((section) => section.name.startsWith(\"Sessions\\\\\"));\n if (sessionSections.length === 0) {\n throw new ConfigurationError({\n code: \"winscp_ini_no_sessions\",\n message: \"WinSCP INI does not contain any [Sessions\\\\...] sections.\",\n retryable: false,\n });\n }\n const sessions: WinScpSession[] = [];\n const skipped: { name: string; folder: readonly string[]; fsProtocol?: number }[] = [];\n for (const section of sessionSections) {\n const decodedPath = decodeSessionPath(section.name.slice(\"Sessions\\\\\".length));\n const segments = decodedPath.split(\"/\").filter((segment) => segment !== \"\");\n const name = segments[segments.length - 1] ?? decodedPath;\n const folder = segments.slice(0, -1);\n const built = buildSessionProfile(name, section.values);\n if (built.kind === \"session\") {\n sessions.push({ ...built.session, folder });\n } else {\n skipped.push({\n folder,\n name,\n ...(built.fsProtocol !== undefined ? { fsProtocol: built.fsProtocol } : {}),\n });\n }\n }\n return { sessions, skipped };\n}\n\ninterface BuiltSession {\n kind: \"session\";\n session: Omit<WinScpSession, \"folder\">;\n}\ninterface SkippedSession {\n kind: \"skipped\";\n fsProtocol?: number;\n}\n\nfunction buildSessionProfile(\n name: string,\n values: Readonly<Record<string, string>>,\n): BuiltSession | SkippedSession {\n const host = values[\"HostName\"]?.trim();\n if (host === undefined || host === \"\") return { kind: \"skipped\" };\n const fsProtocolText = values[\"FSProtocol\"];\n const fsProtocol = fsProtocolText !== undefined ? Number.parseInt(fsProtocolText, 10) : 1;\n const ftpsText = values[\"Ftps\"];\n const ftps = ftpsText !== undefined ? Number.parseInt(ftpsText, 10) : 0;\n const mapped = mapWinScpProtocol(fsProtocol, ftps);\n if (mapped === undefined) {\n return Number.isFinite(fsProtocol) ? { fsProtocol, kind: \"skipped\" } : { kind: \"skipped\" };\n }\n\n const profile: ConnectionProfile = { host, provider: mapped.provider };\n if (mapped.secure !== undefined) profile.secure = mapped.secure;\n const portText = values[\"PortNumber\"];\n if (portText !== undefined) {\n const port = Number.parseInt(portText, 10);\n if (Number.isFinite(port)) profile.port = port;\n }\n const user = values[\"UserName\"]?.trim();\n if (user !== undefined && user !== \"\") profile.username = { value: user };\n\n if (mapped.provider === \"sftp\") {\n const ssh: NonNullable<ConnectionProfile[\"ssh\"]> = {};\n const keyPath = values[\"PublicKeyFile\"]?.trim();\n if (keyPath !== undefined && keyPath !== \"\") ssh.privateKey = { path: keyPath };\n if (Object.keys(ssh).length > 0) profile.ssh = ssh;\n }\n\n const session: Omit<WinScpSession, \"folder\"> = { name, profile };\n if (Number.isFinite(fsProtocol)) session.fsProtocol = fsProtocol;\n if (Number.isFinite(ftps) && ftps !== 0) session.ftps = ftps;\n return { kind: \"session\", session };\n}\n\nfunction mapWinScpProtocol(\n fsProtocol: number,\n ftps: number,\n): { provider: NonNullable<ConnectionProfile[\"provider\"]>; secure?: boolean } | undefined {\n switch (fsProtocol) {\n case 0:\n case 1:\n case 2:\n return { provider: \"sftp\" };\n case 5:\n return ftps === 0 ? { provider: \"ftp\" } : { provider: \"ftps\", secure: ftps === 1 };\n default:\n return undefined;\n }\n}\n\ninterface IniSection {\n name: string;\n values: Record<string, string>;\n}\n\nfunction parseIni(text: string): IniSection[] {\n const sections: IniSection[] = [];\n let current: IniSection | undefined;\n const lines = text.split(/\\r?\\n/);\n for (const rawLine of lines) {\n const line = rawLine.replace(/^\\s*[#;].*$/, \"\").trim();\n if (line === \"\") continue;\n const sectionMatch = line.match(/^\\[(.+)\\]$/);\n if (sectionMatch && sectionMatch[1] !== undefined) {\n current = { name: sectionMatch[1], values: {} };\n sections.push(current);\n continue;\n }\n if (current === undefined) continue;\n const eq = line.indexOf(\"=\");\n if (eq === -1) continue;\n const key = line.slice(0, eq).trim();\n const value = line.slice(eq + 1).trim();\n if (key !== \"\") current.values[key] = value;\n }\n return sections;\n}\n\nfunction decodeSessionPath(name: string): string {\n // WinSCP encodes special characters in session names (e.g. spaces as %20, backslashes as %5C).\n try {\n return decodeURIComponent(name);\n } catch {\n return name;\n }\n}\n","/**\n * Protocol error factory helpers.\n *\n * This module translates raw FTP status replies into typed ZeroTransfer errors so\n * adapters can keep protocol parsing separate from application-facing failures.\n *\n * @module errors/errorFactory\n */\nimport {\n AuthenticationError,\n ConnectionError,\n PathAlreadyExistsError,\n PathNotFoundError,\n PermissionDeniedError,\n ProtocolError,\n TransferError,\n type SpecializedErrorDetails,\n type ZeroTransferError,\n} from \"./ZeroTransferError\";\nimport type { RemoteProtocol } from \"../types/public\";\n\n/**\n * Input used to map an FTP reply into a structured ZeroTransfer error.\n */\nexport interface FtpReplyErrorInput {\n /** Numeric FTP response code returned by the server. */\n ftpCode: number;\n /** Server-provided response message. */\n message: string;\n /** FTP command that produced the response, if known. */\n command?: string;\n /** Remote path involved in the command, if any. */\n path?: string;\n /** Protocol variant used by the adapter. */\n protocol?: RemoteProtocol;\n /** Original lower-level failure that accompanied the reply. */\n cause?: unknown;\n}\n\n/**\n * Maps an FTP reply into the closest typed ZeroTransfer error.\n *\n * @param input - FTP code, message, and optional operation context.\n * @returns A structured error subclass with stable code and retryability metadata.\n */\nexport function errorFromFtpReply(input: FtpReplyErrorInput): ZeroTransferError {\n const details: SpecializedErrorDetails = {\n ftpCode: input.ftpCode,\n message: input.message,\n protocol: input.protocol ?? \"ftp\",\n retryable: false,\n };\n\n if (input.command !== undefined) details.command = input.command;\n if (input.path !== undefined) details.path = input.path;\n if (input.cause !== undefined) details.cause = input.cause;\n\n if (input.ftpCode === 530) {\n return new AuthenticationError(details);\n }\n\n if (input.ftpCode === 421) {\n return new ConnectionError({\n ...details,\n retryable: true,\n });\n }\n\n if (input.ftpCode === 550) {\n return mapFtp550(details);\n }\n\n if ([450, 451, 452].includes(input.ftpCode)) {\n return new TransferError({\n ...details,\n retryable: true,\n });\n }\n\n if (input.ftpCode >= 400 && input.ftpCode < 500) {\n return new ConnectionError({\n ...details,\n retryable: true,\n });\n }\n\n return new ProtocolError(details);\n}\n\n/**\n * Maps ambiguous FTP 550 replies to the most specific path or permission error.\n *\n * @param details - Shared error details derived from the original reply.\n * @returns A typed path or permission error.\n */\nfunction mapFtp550(details: SpecializedErrorDetails): ZeroTransferError {\n const lowerMessage = details.message.toLowerCase();\n\n if (lowerMessage.includes(\"already\") || lowerMessage.includes(\"exists\")) {\n return new PathAlreadyExistsError(details);\n }\n\n if (\n lowerMessage.includes(\"not found\") ||\n lowerMessage.includes(\"no such\") ||\n lowerMessage.includes(\"unavailable\")\n ) {\n return new PathNotFoundError(details);\n }\n\n return new PermissionDeniedError(details);\n}\n","/**\n * Transfer plan and dry-run primitives.\n *\n * @module transfers/TransferPlan\n */\nimport type { TransferEndpoint, TransferJob, TransferOperation } from \"./TransferJob\";\n\n/** Non-executing plan action used to explain an intentionally skipped step. */\nexport type TransferPlanAction = TransferOperation | \"skip\";\n\n/** Step inside a transfer plan. */\nexport interface TransferPlanStep {\n /** Stable step identifier within the plan. */\n id: string;\n /** Action the step would perform. */\n action: TransferPlanAction;\n /** Source endpoint when the action reads data. */\n source?: TransferEndpoint;\n /** Destination endpoint when the action writes data. */\n destination?: TransferEndpoint;\n /** Expected bytes affected by the step when known. */\n expectedBytes?: number;\n /** Whether this step may remove or replace data. */\n destructive?: boolean;\n /** Human-readable reason for planned or skipped work. */\n reason?: string;\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\n/** Input used to create a transfer plan. */\nexport interface TransferPlanInput {\n /** Stable plan identifier. */\n id: string;\n /** Planned steps in execution order. */\n steps: TransferPlanStep[];\n /** Whether the plan is informational only. Defaults to `true`. */\n dryRun?: boolean;\n /** Clock used for deterministic tests. Defaults to `new Date()`. */\n now?: () => Date;\n /** Non-fatal plan warnings. */\n warnings?: string[];\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\n/** Provider-neutral transfer plan. */\nexport interface TransferPlan {\n /** Stable plan identifier. */\n id: string;\n /** Whether this plan should be treated as a dry run. */\n dryRun: boolean;\n /** Time the plan was created. */\n createdAt: Date;\n /** Planned steps in execution order. */\n steps: TransferPlanStep[];\n /** Non-fatal plan warnings. */\n warnings: string[];\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\n/** Summary of a transfer plan. */\nexport interface TransferPlanSummary {\n /** Total number of steps. */\n totalSteps: number;\n /** Number of executable steps. */\n executableSteps: number;\n /** Number of skipped steps. */\n skippedSteps: number;\n /** Number of destructive steps. */\n destructiveSteps: number;\n /** Sum of expected bytes for steps that provide sizes. */\n totalExpectedBytes: number;\n /** Counts grouped by action. */\n actions: Record<string, number>;\n}\n\n/**\n * Creates a transfer plan from dry-run planning input.\n *\n * Plans are immutable, structured descriptions of intended work. Pair with\n * {@link createSyncPlan} or {@link createAtomicDeployPlan} for end-to-end\n * planning, or build steps by hand when you need full control. Pass the plan\n * to {@link createTransferJobsFromPlan} to materialize executable jobs.\n *\n * @example Build a plan with two upload steps and inspect it\n * ```ts\n * import { createTransferPlan, summarizeTransferPlan } from \"@zero-transfer/sdk\";\n *\n * const plan = createTransferPlan({\n * id: \"manual-batch\",\n * steps: [\n * { action: \"upload\", source: \"./a.bin\", destination: \"/lake/a.bin\", expectedBytes: 1024 },\n * { action: \"upload\", source: \"./b.bin\", destination: \"/lake/b.bin\", expectedBytes: 2048 },\n * ],\n * });\n *\n * console.table(summarizeTransferPlan(plan));\n * ```\n */\nexport function createTransferPlan(input: TransferPlanInput): TransferPlan {\n const plan: TransferPlan = {\n createdAt: input.now?.() ?? new Date(),\n dryRun: input.dryRun ?? true,\n id: input.id,\n steps: input.steps.map(clonePlanStep),\n warnings: [...(input.warnings ?? [])],\n };\n\n if (input.metadata !== undefined) {\n plan.metadata = { ...input.metadata };\n }\n\n return plan;\n}\n\n/**\n * Summarizes a transfer plan for diagnostics, previews, and tests.\n *\n * Returns aggregate counts (total / executable / skipped / destructive),\n * total expected bytes, and a per-action histogram. Useful for printing a\n * one-line plan summary before executing or for asserting plan shape in\n * tests.\n *\n * @example Print a plan preview\n * ```ts\n * import { summarizeTransferPlan } from \"@zero-transfer/sdk\";\n *\n * const summary = summarizeTransferPlan(plan);\n * console.log(`${summary.executableSteps} steps, ${summary.totalExpectedBytes} bytes total`);\n * console.log(\"Actions:\", summary.actions);\n * ```\n */\nexport function summarizeTransferPlan(plan: TransferPlan): TransferPlanSummary {\n const actions: Record<string, number> = {};\n let destructiveSteps = 0;\n let executableSteps = 0;\n let skippedSteps = 0;\n let totalExpectedBytes = 0;\n\n for (const step of plan.steps) {\n actions[step.action] = (actions[step.action] ?? 0) + 1;\n destructiveSteps += step.destructive === true ? 1 : 0;\n skippedSteps += step.action === \"skip\" ? 1 : 0;\n executableSteps += step.action === \"skip\" ? 0 : 1;\n totalExpectedBytes += step.expectedBytes ?? 0;\n }\n\n return {\n actions,\n destructiveSteps,\n executableSteps,\n skippedSteps,\n totalExpectedBytes,\n totalSteps: plan.steps.length,\n };\n}\n\n/** Converts executable plan steps into transfer jobs while preserving order. */\nexport function createTransferJobsFromPlan(plan: TransferPlan): TransferJob[] {\n return plan.steps.flatMap((step) => {\n if (step.action === \"skip\") {\n return [];\n }\n\n const job: TransferJob = {\n id: `${plan.id}:${step.id}`,\n operation: step.action,\n };\n\n if (step.source !== undefined) job.source = cloneEndpoint(step.source);\n if (step.destination !== undefined) job.destination = cloneEndpoint(step.destination);\n if (step.expectedBytes !== undefined) job.totalBytes = step.expectedBytes;\n if (step.metadata !== undefined) job.metadata = { ...step.metadata };\n\n return [job];\n });\n}\n\nfunction clonePlanStep(step: TransferPlanStep): TransferPlanStep {\n const clone: TransferPlanStep = {\n action: step.action,\n id: step.id,\n };\n\n if (step.source !== undefined) clone.source = cloneEndpoint(step.source);\n if (step.destination !== undefined) clone.destination = cloneEndpoint(step.destination);\n if (step.expectedBytes !== undefined) clone.expectedBytes = step.expectedBytes;\n if (step.destructive !== undefined) clone.destructive = step.destructive;\n if (step.reason !== undefined) clone.reason = step.reason;\n if (step.metadata !== undefined) clone.metadata = { ...step.metadata };\n\n return clone;\n}\n\nfunction cloneEndpoint(endpoint: TransferEndpoint): TransferEndpoint {\n const clone: TransferEndpoint = { path: endpoint.path };\n\n if (endpoint.provider !== undefined) {\n clone.provider = endpoint.provider;\n }\n\n return clone;\n}\n","/**\n * Transfer queue primitives built on top of {@link TransferEngine}.\n *\n * @module transfers/TransferQueue\n */\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { TransferProgressEvent } from \"../types/public\";\nimport {\n TransferEngine,\n type TransferEngineExecuteOptions,\n type TransferExecutor,\n type TransferRetryPolicy,\n} from \"./TransferEngine\";\nimport type {\n TransferBandwidthLimit,\n TransferJob,\n TransferReceipt,\n TransferTimeoutPolicy,\n} from \"./TransferJob\";\n\n/** Queue item lifecycle state. */\nexport type TransferQueueItemStatus = \"queued\" | \"running\" | \"completed\" | \"failed\" | \"canceled\";\n\n/** Resolver used when jobs do not provide an executor at enqueue time. */\nexport type TransferQueueExecutorResolver = (job: TransferJob) => TransferExecutor;\n\n/** Options used to create a transfer queue. */\nexport interface TransferQueueOptions {\n /** Transfer engine used to execute queued jobs. Defaults to a new engine. */\n engine?: TransferEngine;\n /** Maximum jobs to execute at the same time. Defaults to `1`. */\n concurrency?: number;\n /** Default executor used for jobs that do not provide one directly. */\n executor?: TransferExecutor;\n /** Dynamic executor resolver used when no per-job executor or default executor exists. */\n resolveExecutor?: TransferQueueExecutorResolver;\n /** Retry policy passed to engine executions. */\n retry?: TransferRetryPolicy;\n /** Timeout policy passed to engine executions. */\n timeout?: TransferTimeoutPolicy;\n /** Optional throughput limit shape passed to transfer executors. */\n bandwidthLimit?: TransferBandwidthLimit;\n /** Progress observer shared across queued jobs. */\n onProgress?: (event: TransferProgressEvent) => void;\n /** Completion observer for successful jobs. */\n onReceipt?: (receipt: TransferReceipt) => void;\n /** Failure observer for failed jobs. */\n onError?: (item: TransferQueueItem, error: unknown) => void;\n}\n\n/** Options used when draining a queue. */\nexport interface TransferQueueRunOptions {\n /** Abort signal used to cancel running jobs during this drain. */\n signal?: AbortSignal;\n /** Retry policy override for this drain. */\n retry?: TransferRetryPolicy;\n /** Timeout policy override for this drain. */\n timeout?: TransferTimeoutPolicy;\n /** Bandwidth limit override for this drain. */\n bandwidthLimit?: TransferBandwidthLimit;\n /** Progress observer override for this drain. */\n onProgress?: (event: TransferProgressEvent) => void;\n}\n\n/** Enqueued transfer job state. */\nexport interface TransferQueueItem {\n /** Queued job identifier. */\n id: string;\n /** Original transfer job. */\n job: TransferJob;\n /** Current queue status. */\n status: TransferQueueItemStatus;\n /** Successful transfer receipt when completed. */\n receipt?: TransferReceipt;\n /** Failure or cancellation reason when available. */\n error?: unknown;\n}\n\ninterface InternalTransferQueueItem extends TransferQueueItem {\n controller: AbortController;\n executor?: TransferExecutor;\n}\n\n/** Summary returned after a queue drain. */\nexport interface TransferQueueSummary {\n /** Number of items currently known to the queue. */\n total: number;\n /** Number of successfully completed jobs. */\n completed: number;\n /** Number of failed jobs. */\n failed: number;\n /** Number of canceled jobs. */\n canceled: number;\n /** Number of jobs still queued because the queue was paused. */\n queued: number;\n /** Number of jobs currently running. */\n running: number;\n /** Successful receipts in queue order. */\n receipts: TransferReceipt[];\n /** Failed queue items in queue order. */\n failures: TransferQueueItem[];\n}\n\n/**\n * Minimal transfer queue with concurrency, pause/resume, cancellation, and drain summaries.\n *\n * Wrap a {@link TransferEngine} with a queue when you need to run many transfers\n * concurrently with bounded parallelism, observe per-job progress, or drive\n * a UI from a single source of truth. Items are FIFO; failures and successes\n * are surfaced via observers and in the final {@link TransferQueueSummary}.\n *\n * @example Run a batch of uploads with concurrency=4\n * ```ts\n * import {\n * TransferQueue,\n * createProviderTransferExecutor,\n * } from \"@zero-transfer/sdk\";\n *\n * const queue = new TransferQueue({\n * concurrency: 4,\n * executor: createProviderTransferExecutor({ client }),\n * onProgress: (e) => console.log(`${e.jobId}: ${e.bytesTransferred}`),\n * onError: (item, err) => console.error(`${item.job.id} failed`, err),\n * });\n *\n * for (const file of files) {\n * queue.enqueue({\n * id: file.name,\n * operation: \"upload\",\n * source: { profile: localProfile, path: file.path },\n * destination: { profile: s3Profile, path: `/lake/${file.name}` },\n * });\n * }\n *\n * const summary = await queue.drain();\n * console.log(`Completed ${summary.completed} / ${summary.total}`);\n * ```\n */\nexport class TransferQueue {\n private readonly engine: TransferEngine;\n private readonly items: InternalTransferQueueItem[] = [];\n private readonly defaultExecutor: TransferExecutor | undefined;\n private readonly resolveExecutor: TransferQueueExecutorResolver | undefined;\n private readonly retry: TransferRetryPolicy | undefined;\n private readonly timeout: TransferTimeoutPolicy | undefined;\n private readonly bandwidthLimit: TransferBandwidthLimit | undefined;\n private readonly onProgress: ((event: TransferProgressEvent) => void) | undefined;\n private readonly onReceipt: ((receipt: TransferReceipt) => void) | undefined;\n private readonly onError: ((item: TransferQueueItem, error: unknown) => void) | undefined;\n private concurrency: number;\n private paused = false;\n\n /**\n * Creates a transfer queue.\n *\n * @param options - Queue engine, concurrency, executor, and observer options.\n */\n constructor(options: TransferQueueOptions = {}) {\n this.engine = options.engine ?? new TransferEngine();\n this.concurrency = normalizeConcurrency(options.concurrency);\n this.defaultExecutor = options.executor;\n this.resolveExecutor = options.resolveExecutor;\n this.retry = options.retry;\n this.timeout = options.timeout;\n this.bandwidthLimit = options.bandwidthLimit;\n this.onProgress = options.onProgress;\n this.onReceipt = options.onReceipt;\n this.onError = options.onError;\n }\n\n /** Adds a transfer job to the queue. */\n add(job: TransferJob, executor?: TransferExecutor): TransferQueueItem {\n if (this.items.some((item) => item.id === job.id)) {\n throw new ConfigurationError({\n details: { jobId: job.id },\n message: `Transfer queue already contains job: ${job.id}`,\n retryable: false,\n });\n }\n\n const item: InternalTransferQueueItem = {\n controller: new AbortController(),\n id: job.id,\n job: cloneTransferJob(job),\n status: \"queued\",\n };\n\n if (executor !== undefined) {\n item.executor = executor;\n }\n\n this.items.push(item);\n return toPublicItem(item);\n }\n\n /** Pauses dispatch of new queued jobs. Running jobs are allowed to finish. */\n pause(): void {\n this.paused = true;\n }\n\n /** Resumes dispatch of queued jobs on the next `run()` call. */\n resume(): void {\n this.paused = false;\n }\n\n /** Updates queue concurrency for subsequent drains. */\n setConcurrency(concurrency: number): void {\n this.concurrency = normalizeConcurrency(concurrency);\n }\n\n /** Cancels a queued or running job. */\n cancel(jobId: string): boolean {\n const item = this.items.find((candidate) => candidate.id === jobId);\n\n if (\n item === undefined ||\n item.status === \"completed\" ||\n item.status === \"failed\" ||\n item.status === \"canceled\"\n ) {\n return false;\n }\n\n item.controller.abort();\n\n if (item.status === \"queued\") {\n item.status = \"canceled\";\n }\n\n return true;\n }\n\n /** Returns a queued item snapshot by id. */\n get(jobId: string): TransferQueueItem | undefined {\n const item = this.items.find((candidate) => candidate.id === jobId);\n return item === undefined ? undefined : toPublicItem(item);\n }\n\n /** Lists queue item snapshots in insertion order. */\n list(): TransferQueueItem[] {\n return this.items.map(toPublicItem);\n }\n\n /** Drains currently queued jobs until complete, failed, canceled, or paused. */\n async run(options: TransferQueueRunOptions = {}): Promise<TransferQueueSummary> {\n const workerCount = Math.max(1, Math.min(this.concurrency, this.countDispatchableItems()));\n const workers = Array.from({ length: workerCount }, () => this.runWorker(options));\n\n await Promise.all(workers);\n return this.summarize();\n }\n\n /** Returns a queue summary without executing more work. */\n summarize(): TransferQueueSummary {\n const publicItems = this.items.map(toPublicItem);\n\n return {\n canceled: publicItems.filter((item) => item.status === \"canceled\").length,\n completed: publicItems.filter((item) => item.status === \"completed\").length,\n failed: publicItems.filter((item) => item.status === \"failed\").length,\n failures: publicItems.filter((item) => item.status === \"failed\"),\n queued: publicItems.filter((item) => item.status === \"queued\").length,\n receipts: publicItems\n .filter(\n (item): item is TransferQueueItem & { receipt: TransferReceipt } =>\n item.receipt !== undefined,\n )\n .map((item) => item.receipt),\n running: publicItems.filter((item) => item.status === \"running\").length,\n total: publicItems.length,\n };\n }\n\n private async runWorker(options: TransferQueueRunOptions): Promise<void> {\n for (;;) {\n const item = this.nextQueuedItem();\n\n if (item === undefined) {\n return;\n }\n\n await this.runItem(item, options);\n }\n }\n\n private nextQueuedItem(): InternalTransferQueueItem | undefined {\n if (this.paused) {\n return undefined;\n }\n\n const item = this.items.find((candidate) => candidate.status === \"queued\");\n\n if (item !== undefined) {\n item.status = item.controller.signal.aborted ? \"canceled\" : \"running\";\n }\n\n return item?.status === \"running\" ? item : undefined;\n }\n\n private async runItem(\n item: InternalTransferQueueItem,\n options: TransferQueueRunOptions,\n ): Promise<void> {\n const abortListener = createAbortForwarder(options.signal, item.controller);\n\n try {\n const executeOptions: TransferEngineExecuteOptions = {\n signal: item.controller.signal,\n };\n const onProgress = options.onProgress ?? this.onProgress;\n const retry = options.retry ?? this.retry;\n const timeout = options.timeout ?? this.timeout;\n const bandwidthLimit = options.bandwidthLimit ?? this.bandwidthLimit;\n\n if (onProgress !== undefined) {\n executeOptions.onProgress = onProgress;\n }\n\n if (retry !== undefined) {\n executeOptions.retry = retry;\n }\n\n if (timeout !== undefined) {\n executeOptions.timeout = timeout;\n }\n\n if (bandwidthLimit !== undefined) {\n executeOptions.bandwidthLimit = bandwidthLimit;\n }\n\n const receipt = await this.engine.execute(\n item.job,\n this.requireExecutor(item),\n executeOptions,\n );\n\n item.receipt = receipt;\n item.status = \"completed\";\n this.onReceipt?.(receipt);\n } catch (error) {\n item.error = error;\n item.status = item.controller.signal.aborted ? \"canceled\" : \"failed\";\n\n if (item.status === \"failed\") {\n this.onError?.(toPublicItem(item), error);\n }\n } finally {\n abortListener.dispose();\n }\n }\n\n private requireExecutor(item: InternalTransferQueueItem): TransferExecutor {\n const executor = item.executor ?? this.defaultExecutor ?? this.resolveExecutor?.(item.job);\n\n if (executor === undefined) {\n throw new ConfigurationError({\n details: { jobId: item.job.id },\n message: `Transfer queue job has no executor: ${item.job.id}`,\n retryable: false,\n });\n }\n\n return executor;\n }\n\n private countDispatchableItems(): number {\n return this.items.filter((item) => item.status === \"queued\" && !item.controller.signal.aborted)\n .length;\n }\n}\n\nfunction normalizeConcurrency(value: number | undefined): number {\n if (value === undefined || !Number.isFinite(value)) {\n return 1;\n }\n\n return Math.max(1, Math.floor(value));\n}\n\nfunction createAbortForwarder(\n source: AbortSignal | undefined,\n target: AbortController,\n): { dispose(): void } {\n if (source === undefined) {\n return { dispose: () => undefined };\n }\n\n const abort = (): void => target.abort();\n\n if (source.aborted) {\n abort();\n return { dispose: () => undefined };\n }\n\n source.addEventListener(\"abort\", abort, { once: true });\n\n return {\n dispose: () => source.removeEventListener(\"abort\", abort),\n };\n}\n\nfunction toPublicItem(item: InternalTransferQueueItem): TransferQueueItem {\n const snapshot: TransferQueueItem = {\n id: item.id,\n job: cloneTransferJob(item.job),\n status: item.status,\n };\n\n if (item.receipt !== undefined) snapshot.receipt = item.receipt;\n if (item.error !== undefined) snapshot.error = item.error;\n\n return snapshot;\n}\n\nfunction cloneTransferJob(job: TransferJob): TransferJob {\n const clone: TransferJob = {\n id: job.id,\n operation: job.operation,\n };\n\n if (job.source !== undefined) clone.source = { ...job.source };\n if (job.destination !== undefined) clone.destination = { ...job.destination };\n if (job.totalBytes !== undefined) clone.totalBytes = job.totalBytes;\n if (job.resumed !== undefined) clone.resumed = job.resumed;\n if (job.metadata !== undefined) clone.metadata = { ...job.metadata };\n\n return clone;\n}\n","/**\n * Browser-friendly directory navigation helpers for file-manager UIs.\n *\n * Wraps a {@link RemoteFileSystem} with stateful current-directory tracking,\n * breadcrumb generation, and pure sort/filter utilities so consumers can render\n * directory views without re-implementing common navigation glue.\n *\n * @module sync/createRemoteBrowser\n */\nimport type { RemoteFileSystem } from \"../providers/RemoteFileSystem\";\nimport type { RemoteEntry } from \"../types/public\";\nimport { normalizeRemotePath } from \"../utils/path\";\n\n/** Sort key supported by {@link sortRemoteEntries}. */\nexport type RemoteEntrySortKey = \"name\" | \"size\" | \"modifiedAt\" | \"type\";\n\n/** Sort direction supported by {@link sortRemoteEntries}. */\nexport type RemoteEntrySortOrder = \"asc\" | \"desc\";\n\n/** Crumb describing one segment in the current path. */\nexport interface RemoteBreadcrumb {\n /** Display name. `\"\"` is replaced with `\"/\"` for the root crumb. */\n name: string;\n /** Absolute path the crumb resolves to. */\n path: string;\n}\n\n/** Filter callback applied to a directory listing. */\nexport type RemoteBrowserFilter = (entry: RemoteEntry) => boolean;\n\n/** Options accepted by {@link createRemoteBrowser}. */\nexport interface CreateRemoteBrowserOptions {\n /** Remote file system to browse. */\n fs: RemoteFileSystem;\n /** Initial path. Defaults to `\"/\"`. */\n initialPath?: string;\n /** Sort key applied to listings. Defaults to `\"name\"`. */\n sortKey?: RemoteEntrySortKey;\n /** Sort order applied to listings. Defaults to `\"asc\"`. */\n sortOrder?: RemoteEntrySortOrder;\n /** Whether dotfile entries (names starting with `.`) are included. Defaults to `true`. */\n showHidden?: boolean;\n /** Optional filter applied after sort/hidden filtering. */\n filter?: RemoteBrowserFilter;\n}\n\n/** Snapshot returned by browser navigation methods. */\nexport interface RemoteBrowserSnapshot {\n /** Current absolute path. */\n path: string;\n /** Directory entries after sorting and filtering. */\n entries: RemoteEntry[];\n /** Breadcrumb trail leading from `/` to {@link path}. */\n breadcrumbs: RemoteBreadcrumb[];\n}\n\n/** Stateful directory browser returned by {@link createRemoteBrowser}. */\nexport interface RemoteBrowser {\n /** Current absolute path. */\n readonly path: string;\n /** Last loaded sorted/filtered entries. */\n readonly entries: readonly RemoteEntry[];\n /** Reload the current directory and return the latest snapshot. */\n refresh(): Promise<RemoteBrowserSnapshot>;\n /** Navigate to the supplied absolute or relative path. */\n navigate(target: string): Promise<RemoteBrowserSnapshot>;\n /** Descend into the supplied directory entry. Throws when the entry is not a directory. */\n open(entry: RemoteEntry): Promise<RemoteBrowserSnapshot>;\n /** Move to the parent directory; no-op when already at the root. */\n up(): Promise<RemoteBrowserSnapshot>;\n /** Compute breadcrumbs for the current path without re-listing. */\n breadcrumbs(): RemoteBreadcrumb[];\n /** Update the sort key. The next refresh re-sorts the cached entries. */\n setSort(key: RemoteEntrySortKey, order?: RemoteEntrySortOrder): void;\n /** Toggle hidden-entry visibility. The next refresh re-applies the filter. */\n setShowHidden(showHidden: boolean): void;\n}\n\n/**\n * Returns the parent directory of a remote path, or `\"/\"` for root inputs.\n *\n * @param input - Remote path to inspect.\n * @returns The parent path normalized to an absolute form.\n */\nexport function parentRemotePath(input: string): string {\n const normalized = normalizeRemotePath(input);\n if (normalized === \"/\") return \"/\";\n const parts = normalized.split(\"/\").filter(Boolean);\n parts.pop();\n if (parts.length === 0) return \"/\";\n return `/${parts.join(\"/\")}`;\n}\n\n/**\n * Builds breadcrumbs from `/` down to the supplied path.\n *\n * @param input - Absolute remote path.\n * @returns Ordered crumbs starting with the root.\n */\nexport function buildRemoteBreadcrumbs(input: string): RemoteBreadcrumb[] {\n const normalized = normalizeRemotePath(input);\n const crumbs: RemoteBreadcrumb[] = [{ name: \"/\", path: \"/\" }];\n if (normalized === \"/\") return crumbs;\n\n const parts = normalized.split(\"/\").filter(Boolean);\n let cursor = \"\";\n for (const part of parts) {\n cursor += `/${part}`;\n crumbs.push({ name: part, path: cursor });\n }\n return crumbs;\n}\n\n/**\n * Returns a copy of the supplied entries sorted by the requested key. Directories\n * are grouped before files within ascending sorts, matching common file-manager UX.\n *\n * @param entries - Entries to sort.\n * @param key - Sort key.\n * @param order - Sort order.\n * @returns Sorted copy of the entries.\n */\nexport function sortRemoteEntries(\n entries: readonly RemoteEntry[],\n key: RemoteEntrySortKey = \"name\",\n order: RemoteEntrySortOrder = \"asc\",\n): RemoteEntry[] {\n const direction = order === \"asc\" ? 1 : -1;\n return [...entries].sort((left, right) => {\n if (key !== \"type\") {\n const leftIsDir = left.type === \"directory\";\n const rightIsDir = right.type === \"directory\";\n if (leftIsDir !== rightIsDir) return leftIsDir ? -1 : 1;\n }\n\n const compared = compareEntriesByKey(left, right, key);\n if (compared !== 0) return compared * direction;\n return compareNames(left, right);\n });\n}\n\n/**\n * Filters entries using the optional predicate plus an optional hidden-file rule.\n *\n * @param entries - Entries to filter.\n * @param options - Filtering controls.\n * @returns Entries matching the supplied rules.\n */\nexport function filterRemoteEntries(\n entries: readonly RemoteEntry[],\n options: { filter?: RemoteBrowserFilter; showHidden?: boolean } = {},\n): RemoteEntry[] {\n const showHidden = options.showHidden ?? true;\n const filter = options.filter;\n return entries.filter((entry) => {\n if (!showHidden && entry.name.startsWith(\".\")) return false;\n if (filter !== undefined && !filter(entry)) return false;\n return true;\n });\n}\n\n/**\n * Creates a stateful directory browser around a remote file system.\n *\n * The returned browser caches the most recent listing and applies sort/filter\n * settings on each refresh. Navigation methods return a snapshot so UI layers can\n * render synchronously without re-reading state.\n *\n * @param options - Browser configuration.\n * @returns Stateful browser bound to the supplied file system.\n */\nexport function createRemoteBrowser(options: CreateRemoteBrowserOptions): RemoteBrowser {\n const { fs } = options;\n let currentPath = normalizeRemotePath(options.initialPath ?? \"/\");\n let cachedEntries: RemoteEntry[] = [];\n let sortKey: RemoteEntrySortKey = options.sortKey ?? \"name\";\n let sortOrder: RemoteEntrySortOrder = options.sortOrder ?? \"asc\";\n let showHidden = options.showHidden ?? true;\n const filter = options.filter;\n\n async function loadCurrent(): Promise<RemoteBrowserSnapshot> {\n const raw = await fs.list(currentPath);\n const projected = projectEntries(raw);\n cachedEntries = projected;\n return snapshot();\n }\n\n function projectEntries(raw: readonly RemoteEntry[]): RemoteEntry[] {\n const filterOptions: { filter?: RemoteBrowserFilter; showHidden: boolean } = { showHidden };\n if (filter !== undefined) filterOptions.filter = filter;\n const filtered = filterRemoteEntries(raw, filterOptions);\n return sortRemoteEntries(filtered, sortKey, sortOrder);\n }\n\n function snapshot(): RemoteBrowserSnapshot {\n return {\n breadcrumbs: buildRemoteBreadcrumbs(currentPath),\n entries: [...cachedEntries],\n path: currentPath,\n };\n }\n\n async function navigate(target: string): Promise<RemoteBrowserSnapshot> {\n currentPath = resolveTarget(currentPath, target);\n return loadCurrent();\n }\n\n async function open(entry: RemoteEntry): Promise<RemoteBrowserSnapshot> {\n if (entry.type !== \"directory\") {\n throw new TypeError(`Cannot open non-directory entry \"${entry.path}\" (type: ${entry.type})`);\n }\n return navigate(entry.path);\n }\n\n return {\n breadcrumbs: () => buildRemoteBreadcrumbs(currentPath),\n get entries() {\n return cachedEntries;\n },\n navigate,\n open,\n get path() {\n return currentPath;\n },\n refresh: loadCurrent,\n setShowHidden(value: boolean) {\n showHidden = value;\n },\n setSort(key: RemoteEntrySortKey, order: RemoteEntrySortOrder = sortOrder) {\n sortKey = key;\n sortOrder = order;\n },\n up: () => navigate(parentRemotePath(currentPath)),\n };\n}\n\nfunction resolveTarget(currentPath: string, target: string): string {\n if (target.startsWith(\"/\")) return normalizeRemotePath(target);\n if (target === \"\" || target === \".\") return currentPath;\n if (target === \"..\") return parentRemotePath(currentPath);\n const base = currentPath === \"/\" ? \"\" : currentPath;\n return normalizeRemotePath(`${base}/${target}`);\n}\n\nfunction compareEntriesByKey(\n left: RemoteEntry,\n right: RemoteEntry,\n key: RemoteEntrySortKey,\n): number {\n switch (key) {\n case \"size\":\n return (left.size ?? 0) - (right.size ?? 0);\n case \"modifiedAt\": {\n const leftTime = left.modifiedAt?.getTime() ?? 0;\n const rightTime = right.modifiedAt?.getTime() ?? 0;\n return leftTime - rightTime;\n }\n case \"type\":\n return left.type.localeCompare(right.type);\n case \"name\":\n default:\n return compareNames(left, right);\n }\n}\n\nfunction compareNames(left: RemoteEntry, right: RemoteEntry): number {\n return left.name.localeCompare(right.name, undefined, { numeric: true, sensitivity: \"base\" });\n}\n","/**\n * Sync planning primitives that build a {@link TransferPlan} from a remote-tree diff.\n *\n * @module sync/createSyncPlan\n */\nimport type { ProviderId } from \"../core/ProviderId\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport {\n createTransferPlan,\n type TransferPlan,\n type TransferPlanStep,\n} from \"../transfers/TransferPlan\";\nimport { joinRemotePath, normalizeRemotePath } from \"../utils/path\";\nimport type { RemoteTreeDiff, RemoteTreeDiffEntry } from \"./diffRemoteTrees\";\n\n/** Sync direction used by {@link createSyncPlan}. */\nexport type SyncDirection = \"source-to-destination\" | \"destination-to-source\";\n\n/** How {@link createSyncPlan} reacts to entries that exist only on the destination. */\nexport type SyncDeletePolicy =\n /** Never delete destination entries that are missing on the source. */\n | \"never\"\n /** Plan destination deletions when running source-to-destination sync. */\n | \"mirror\"\n /** Plan destination deletions only when paired with a same-path file on the source. */\n | \"replace-only\";\n\n/** How {@link createSyncPlan} reacts to entries flagged as modified on both sides. */\nexport type SyncConflictPolicy =\n /** Overwrite the destination with the source. */\n | \"overwrite\"\n /** Overwrite the source with the destination. */\n | \"prefer-destination\"\n /** Skip conflicting entries with a `skip` step. */\n | \"skip\"\n /** Fail planning with a {@link ConfigurationError} when a conflict is encountered. */\n | \"error\";\n\n/** Endpoint shape supplied to {@link createSyncPlan}. */\nexport interface SyncEndpointInput {\n /** Provider that owns the endpoint when known. */\n provider?: ProviderId;\n /** Root path on the provider being synced. */\n rootPath: string;\n}\n\n/** Options accepted by {@link createSyncPlan}. */\nexport interface CreateSyncPlanOptions {\n /** Stable plan identifier. */\n id: string;\n /** Diff produced by {@link diffRemoteTrees} or an equivalent source. */\n diff: RemoteTreeDiff;\n /** Source-side endpoint that produced the diff. */\n source: SyncEndpointInput;\n /** Destination-side endpoint that produced the diff. */\n destination: SyncEndpointInput;\n /** Sync direction. Defaults to `\"source-to-destination\"`. */\n direction?: SyncDirection;\n /** Delete policy. Defaults to `\"never\"`. */\n deletePolicy?: SyncDeletePolicy;\n /** Conflict policy. Defaults to `\"overwrite\"`. */\n conflictPolicy?: SyncConflictPolicy;\n /** Whether to plan upload/download steps for directories. Defaults to `false`. */\n includeDirectoryActions?: boolean;\n /** Whether the plan is informational only. Defaults to `true`. */\n dryRun?: boolean;\n /** Clock used for deterministic tests. Defaults to `new Date()`. */\n now?: () => Date;\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Builds a {@link TransferPlan} that reconciles two remote subtrees.\n *\n * Plan steps are derived from a {@link RemoteTreeDiff}; the function does not perform\n * any I/O. Direction, delete policy, and conflict policy control which entries\n * become executable transfers and which become `skip` steps.\n *\n * @param options - Inputs and policies that shape the plan.\n * @returns Transfer plan ready for `createTransferJobsFromPlan` or queue execution.\n * @throws {@link ConfigurationError} When `conflictPolicy: \"error\"` encounters a conflict.\n *\n * @example Mirror SFTP → S3 with deletes\n * ```ts\n * import {\n * createSyncPlan,\n * diffRemoteTrees,\n * summarizeTransferPlan,\n * } from \"@zero-transfer/sdk\";\n *\n * const diff = await diffRemoteTrees(\n * srcSession.fs, \"/dist\",\n * dstSession.fs, \"/releases/current\",\n * );\n *\n * const plan = createSyncPlan({\n * id: \"release-mirror\",\n * diff,\n * source: { provider: \"sftp\", rootPath: \"/dist\" },\n * destination: { provider: \"s3\", rootPath: \"/releases/current\" },\n * deletePolicy: \"mirror\",\n * conflictPolicy: \"overwrite\",\n * });\n *\n * console.table(summarizeTransferPlan(plan));\n * ```\n */\nexport function createSyncPlan(options: CreateSyncPlanOptions): TransferPlan {\n const direction: SyncDirection = options.direction ?? \"source-to-destination\";\n const deletePolicy: SyncDeletePolicy = options.deletePolicy ?? \"never\";\n const conflictPolicy: SyncConflictPolicy = options.conflictPolicy ?? \"overwrite\";\n const includeDirectoryActions = options.includeDirectoryActions ?? false;\n const sourceRoot = normalizeRemotePath(options.source.rootPath);\n const destinationRoot = normalizeRemotePath(options.destination.rootPath);\n const warnings: string[] = [];\n const steps: TransferPlanStep[] = [];\n\n for (const entry of options.diff.entries) {\n const context: PlanEntryContext = {\n conflictPolicy,\n deletePolicy,\n destinationRoot,\n direction,\n entry,\n includeDirectoryActions,\n sourceRoot,\n warnings,\n };\n if (options.source.provider !== undefined) context.sourceProvider = options.source.provider;\n if (options.destination.provider !== undefined) {\n context.destinationProvider = options.destination.provider;\n }\n const step = planEntry(context);\n\n if (step !== undefined) steps.push(step);\n }\n\n const planInput: Parameters<typeof createTransferPlan>[0] = {\n id: options.id,\n steps,\n warnings,\n };\n if (options.dryRun !== undefined) planInput.dryRun = options.dryRun;\n if (options.now !== undefined) planInput.now = options.now;\n if (options.metadata !== undefined) planInput.metadata = options.metadata;\n\n return createTransferPlan(planInput);\n}\n\ninterface PlanEntryContext {\n conflictPolicy: SyncConflictPolicy;\n deletePolicy: SyncDeletePolicy;\n destinationProvider?: ProviderId;\n destinationRoot: string;\n direction: SyncDirection;\n entry: RemoteTreeDiffEntry;\n includeDirectoryActions: boolean;\n sourceProvider?: ProviderId;\n sourceRoot: string;\n warnings: string[];\n}\n\nfunction planEntry(context: PlanEntryContext): TransferPlanStep | undefined {\n const { entry } = context;\n const isDirectory = isDirectoryEntry(entry);\n\n if (isDirectory && !context.includeDirectoryActions) {\n return undefined;\n }\n\n switch (entry.status) {\n case \"added\":\n return planAdded(context);\n case \"removed\":\n return planRemoved(context);\n case \"modified\":\n return planModified(context);\n case \"unchanged\":\n return planUnchanged(context);\n default:\n // Unreachable when callers pass a normalized RemoteTreeDiff.\n return undefined;\n }\n}\n\nfunction planAdded(context: PlanEntryContext): TransferPlanStep {\n if (context.direction === \"source-to-destination\") {\n return createCopyStep(context, \"source\", \"destination\", expectedBytesFor(context.entry));\n }\n\n // Direction is destination-to-source: source-only entries should be deleted.\n if (context.deletePolicy === \"never\") {\n return createSkipStep(context, \"Source-only entry preserved by delete policy\");\n }\n\n return createDeleteStep(context, \"source\");\n}\n\nfunction planRemoved(context: PlanEntryContext): TransferPlanStep {\n if (context.direction === \"destination-to-source\") {\n return createCopyStep(context, \"destination\", \"source\", expectedBytesFor(context.entry));\n }\n\n // Direction is source-to-destination: destination-only entries.\n if (context.deletePolicy === \"never\") {\n return createSkipStep(context, \"Destination-only entry preserved by delete policy\");\n }\n\n if (context.deletePolicy === \"replace-only\") {\n return createSkipStep(\n context,\n \"Destination-only entry preserved (no source replacement available)\",\n );\n }\n\n return createDeleteStep(context, \"destination\");\n}\n\nfunction planModified(context: PlanEntryContext): TransferPlanStep {\n switch (context.conflictPolicy) {\n case \"overwrite\":\n return createCopyStep(context, \"source\", \"destination\", expectedBytesFor(context.entry), {\n destructive: true,\n });\n case \"prefer-destination\":\n return createCopyStep(context, \"destination\", \"source\", expectedBytesFor(context.entry), {\n destructive: true,\n });\n case \"skip\":\n return createSkipStep(context, `Conflict skipped: ${context.entry.reasons.join(\",\")}`);\n case \"error\":\n throw new ConfigurationError({\n details: {\n path: context.entry.path,\n reasons: context.entry.reasons,\n },\n message: `Sync plan conflict at ${context.entry.path} with reasons: ${context.entry.reasons.join(\", \")}`,\n retryable: false,\n });\n default:\n return createSkipStep(context, \"Conflict skipped\");\n }\n}\n\nfunction planUnchanged(context: PlanEntryContext): TransferPlanStep {\n return createSkipStep(context, \"Entry already in sync\");\n}\n\nfunction createCopyStep(\n context: PlanEntryContext,\n fromSide: \"source\" | \"destination\",\n toSide: \"source\" | \"destination\",\n expectedBytes: number | undefined,\n overrides: Partial<TransferPlanStep> = {},\n): TransferPlanStep {\n const step: TransferPlanStep = {\n action: \"copy\",\n id: makeStepId(context.entry, `copy-${fromSide}-to-${toSide}`),\n reason: describeReasons(context.entry, `Copy ${fromSide} to ${toSide}`),\n };\n\n step.source = endpointFor(context, fromSide);\n step.destination = endpointFor(context, toSide);\n if (expectedBytes !== undefined) step.expectedBytes = expectedBytes;\n if (overrides.destructive === true) step.destructive = true;\n if (overrides.metadata !== undefined) step.metadata = { ...overrides.metadata };\n\n return step;\n}\n\nfunction createDeleteStep(\n context: PlanEntryContext,\n side: \"source\" | \"destination\",\n): TransferPlanStep {\n return {\n action: \"delete\",\n destination: endpointFor(context, side),\n destructive: true,\n id: makeStepId(context.entry, `delete-${side}`),\n reason: `Delete ${side} entry not present on the other side`,\n };\n}\n\nfunction createSkipStep(context: PlanEntryContext, reason: string): TransferPlanStep {\n return {\n action: \"skip\",\n id: makeStepId(context.entry, \"skip\"),\n reason,\n source: endpointFor(context, \"source\"),\n destination: endpointFor(context, \"destination\"),\n };\n}\n\nfunction endpointFor(\n context: PlanEntryContext,\n side: \"source\" | \"destination\",\n): NonNullable<TransferPlanStep[\"source\"]> {\n const root = side === \"source\" ? context.sourceRoot : context.destinationRoot;\n const provider = side === \"source\" ? context.sourceProvider : context.destinationProvider;\n const endpoint: NonNullable<TransferPlanStep[\"source\"]> = {\n path: joinRootAndRelative(root, context.entry.path),\n };\n if (provider !== undefined) endpoint.provider = provider;\n return endpoint;\n}\n\nfunction joinRootAndRelative(rootPath: string, relativePath: string): string {\n if (rootPath === \"/\") return relativePath;\n if (relativePath === \"/\") return rootPath;\n return joinRemotePath(rootPath, relativePath);\n}\n\nfunction makeStepId(entry: RemoteTreeDiffEntry, suffix: string): string {\n return `${entry.path}#${suffix}`;\n}\n\nfunction describeReasons(entry: RemoteTreeDiffEntry, prefix: string): string {\n if (entry.reasons.length === 0) return prefix;\n return `${prefix} (${entry.reasons.join(\",\")})`;\n}\n\nfunction expectedBytesFor(entry: RemoteTreeDiffEntry): number | undefined {\n return entry.source?.size ?? entry.destination?.size;\n}\n\nfunction isDirectoryEntry(entry: RemoteTreeDiffEntry): boolean {\n return entry.source?.type === \"directory\" || entry.destination?.type === \"directory\";\n}\n","/**\n * Atomic deploy planning helpers.\n *\n * Produces a structured plan that stages a release under `<liveRoot>/<releasesDir>/<releaseId>`,\n * activates it via rename or symlink swap, and prunes older releases beyond a retain count.\n *\n * The plan is provider-neutral and execution-free: callers wire the upload {@link TransferPlan}\n * through the transfer engine and execute the activate/prune steps using their provider's\n * filesystem mutation primitives (rename, symlink, delete).\n *\n * @module sync/createAtomicDeployPlan\n */\nimport type { ProviderId } from \"../core/ProviderId\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { TransferPlan } from \"../transfers/TransferPlan\";\nimport { joinRemotePath, normalizeRemotePath } from \"../utils/path\";\nimport { createSyncPlan, type SyncEndpointInput } from \"./createSyncPlan\";\nimport type { RemoteTreeDiff } from \"./diffRemoteTrees\";\n\n/** Activation strategy used to swap a staged release into place. */\nexport type AtomicDeployStrategy =\n /** Rename `<liveRoot>` aside, then rename the staging path to `<liveRoot>`. */\n | \"rename\"\n /** Update a symlink at `<liveRoot>` to point at the staging path. */\n | \"symlink\";\n\n/** Operation kind for an activation step. */\nexport type AtomicDeployActivateOperation = \"rename\" | \"symlink\" | \"delete\";\n\n/** Kind of activation step described by the plan. */\nexport interface AtomicDeployActivateStep {\n /** Stable identifier within the activation list. */\n id: string;\n /** Operation the step would perform. */\n operation: AtomicDeployActivateOperation;\n /** Source path the operation reads or moves from. */\n fromPath?: string;\n /** Destination path the operation writes to. */\n toPath: string;\n /** Provider identifier that owns the affected paths when known. */\n provider?: ProviderId;\n /** Whether the step replaces or removes data. */\n destructive?: boolean;\n /** Human-readable description for previews and logs. */\n reason: string;\n}\n\n/** Pruning step describing an old release directory marked for deletion. */\nexport interface AtomicDeployPruneStep {\n /** Stable identifier within the prune list. */\n id: string;\n /** Absolute release directory path to delete. */\n path: string;\n /** Provider identifier that owns the path when known. */\n provider?: ProviderId;\n /** Reason the release was selected for pruning. */\n reason: string;\n}\n\n/** Result returned by {@link createAtomicDeployPlan}. */\nexport interface AtomicDeployPlan {\n /** Stable plan identifier. */\n id: string;\n /** Release identifier embedded into the staging path. */\n releaseId: string;\n /** Activation strategy chosen for the swap. */\n strategy: AtomicDeployStrategy;\n /** Provider identifier for the live destination when known. */\n provider?: ProviderId;\n /** Live target path the release activates onto. */\n livePath: string;\n /** Staging directory the upload populates. */\n stagingPath: string;\n /** Releases root directory under which staging and prior releases live. */\n releasesRoot: string;\n /** Optional backup path used by the rename strategy. */\n backupPath?: string;\n /** Upload plan that populates the staging directory. */\n uploadPlan: TransferPlan;\n /** Activation steps that swap staging into the live path. */\n activate: AtomicDeployActivateStep[];\n /** Prune steps that remove older releases beyond {@link retain}. */\n prune: AtomicDeployPruneStep[];\n /** Number of releases to retain (including the new release). */\n retain: number;\n /** Time the plan was created. */\n createdAt: Date;\n /** Non-fatal plan warnings. */\n warnings: string[];\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\n/** Options accepted by {@link createAtomicDeployPlan}. */\nexport interface CreateAtomicDeployPlanOptions {\n /** Stable plan identifier. */\n id: string;\n /** Diff describing source vs. staging contents (typically diffed against an empty staging directory). */\n diff: RemoteTreeDiff;\n /** Source-side endpoint feeding the release. */\n source: SyncEndpointInput;\n /** Live destination endpoint the release activates onto. */\n destination: SyncEndpointInput;\n /** Activation strategy. Defaults to `\"rename\"`. */\n strategy?: AtomicDeployStrategy;\n /** Release identifier. Defaults to a timestamp derived from {@link now}. */\n releaseId?: string;\n /** Releases directory name under the destination root. Defaults to `\".releases\"`. */\n releasesDirectory?: string;\n /** Number of releases to retain after the new release, including the new one. Defaults to `3`. */\n retain?: number;\n /** Existing release directory paths under the releases root that may be pruned. */\n existingReleases?: string[];\n /** Whether the plan is informational only. Defaults to `true`. */\n dryRun?: boolean;\n /** Clock used for deterministic tests. Defaults to `new Date()`. */\n now?: () => Date;\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\nconst DEFAULT_RELEASES_DIRECTORY = \".releases\";\nconst DEFAULT_RETAIN = 3;\n\n/**\n * Builds an {@link AtomicDeployPlan} that stages a release, swaps it live, and prunes old releases.\n *\n * The plan describes a blue/green-style deploy:\n * 1. Upload to a timestamped staging directory under `<destination>/.releases/`.\n * 2. Atomically swap the `current` symlink/rename to point at the new release.\n * 3. Optionally prune old releases beyond `retain`.\n *\n * No I/O is performed - the host executes the plan steps. Pair with\n * {@link createTransferPlan} or {@link createTransferJobsFromPlan} to execute.\n *\n * @param options - Inputs and policies that shape the deploy.\n * @returns Structured deploy plan ready for execution by the calling host.\n * @throws {@link ConfigurationError} When `retain` is less than `1` or the destination root is empty.\n *\n * @example Plan a release with rollback path\n * ```ts\n * import { createAtomicDeployPlan } from \"@zero-transfer/sdk\";\n *\n * const plan = createAtomicDeployPlan({\n * id: \"web-2026-04-28\",\n * source: { rootPath: \"./dist\" },\n * destination: {\n * profile: { host: \"web1.example.com\", provider: \"sftp\", username: \"deploy\" },\n * rootPath: \"/srv/www\",\n * },\n * retain: 5,\n * existingReleases: [\n * \"/srv/www/.releases/2026-04-21T00-00-00Z\",\n * \"/srv/www/.releases/2026-04-14T00-00-00Z\",\n * ],\n * });\n *\n * console.log(plan.swap); // staging → current rename\n * console.log(plan.prune); // releases scheduled for removal\n * ```\n */\nexport function createAtomicDeployPlan(options: CreateAtomicDeployPlanOptions): AtomicDeployPlan {\n const retain = options.retain ?? DEFAULT_RETAIN;\n if (retain < 1) {\n throw new ConfigurationError({\n details: { retain },\n message: \"Atomic deploy retain count must be at least 1\",\n retryable: false,\n });\n }\n\n const livePath = normalizeRemotePath(options.destination.rootPath);\n if (livePath === \"/\") {\n throw new ConfigurationError({\n message: \"Atomic deploy destination rootPath must not be the filesystem root\",\n retryable: false,\n });\n }\n\n const strategy: AtomicDeployStrategy = options.strategy ?? \"rename\";\n const now = options.now?.() ?? new Date();\n const releaseId = options.releaseId ?? defaultReleaseId(now);\n const releasesRoot = joinRemotePath(\n livePath,\n options.releasesDirectory ?? DEFAULT_RELEASES_DIRECTORY,\n );\n const stagingPath = joinRemotePath(releasesRoot, releaseId);\n const backupPath =\n strategy === \"rename\" ? joinRemotePath(releasesRoot, `${releaseId}.previous`) : undefined;\n const provider = options.destination.provider ?? options.source.provider;\n const warnings: string[] = [];\n\n const uploadPlan = createSyncPlan({\n conflictPolicy: \"overwrite\",\n deletePolicy: \"never\",\n destination: {\n ...(options.destination.provider !== undefined\n ? { provider: options.destination.provider }\n : {}),\n rootPath: stagingPath,\n },\n diff: options.diff,\n direction: \"source-to-destination\",\n dryRun: options.dryRun ?? true,\n id: `${options.id}/upload`,\n includeDirectoryActions: false,\n ...(options.now !== undefined ? { now: options.now } : {}),\n source: options.source,\n });\n\n const activate = buildActivateSteps({\n backupPath,\n livePath,\n planId: options.id,\n provider,\n stagingPath,\n strategy,\n });\n\n const prune = buildPruneSteps({\n existingReleases: options.existingReleases ?? [],\n planId: options.id,\n provider,\n releaseId,\n releasesRoot,\n retain,\n });\n\n const plan: AtomicDeployPlan = {\n activate,\n createdAt: now,\n id: options.id,\n livePath,\n prune,\n releaseId,\n releasesRoot,\n retain,\n stagingPath,\n strategy,\n uploadPlan,\n warnings,\n };\n if (provider !== undefined) plan.provider = provider;\n if (backupPath !== undefined) plan.backupPath = backupPath;\n if (options.metadata !== undefined) plan.metadata = { ...options.metadata };\n return plan;\n}\n\ninterface BuildActivateContext {\n backupPath: string | undefined;\n livePath: string;\n planId: string;\n provider: ProviderId | undefined;\n stagingPath: string;\n strategy: AtomicDeployStrategy;\n}\n\nfunction buildActivateSteps(context: BuildActivateContext): AtomicDeployActivateStep[] {\n if (context.strategy === \"symlink\") {\n const step: AtomicDeployActivateStep = {\n destructive: true,\n fromPath: context.stagingPath,\n id: `${context.planId}/activate/symlink`,\n operation: \"symlink\",\n reason: \"Update live symlink to point at the new release\",\n toPath: context.livePath,\n };\n if (context.provider !== undefined) step.provider = context.provider;\n return [step];\n }\n\n const steps: AtomicDeployActivateStep[] = [];\n if (context.backupPath !== undefined) {\n const backup: AtomicDeployActivateStep = {\n destructive: true,\n fromPath: context.livePath,\n id: `${context.planId}/activate/backup`,\n operation: \"rename\",\n reason: \"Rename current live path aside as a release backup\",\n toPath: context.backupPath,\n };\n if (context.provider !== undefined) backup.provider = context.provider;\n steps.push(backup);\n }\n\n const promote: AtomicDeployActivateStep = {\n destructive: true,\n fromPath: context.stagingPath,\n id: `${context.planId}/activate/promote`,\n operation: \"rename\",\n reason: \"Promote the staged release to the live path\",\n toPath: context.livePath,\n };\n if (context.provider !== undefined) promote.provider = context.provider;\n steps.push(promote);\n return steps;\n}\n\ninterface BuildPruneContext {\n existingReleases: string[];\n planId: string;\n provider: ProviderId | undefined;\n releaseId: string;\n releasesRoot: string;\n retain: number;\n}\n\nfunction buildPruneSteps(context: BuildPruneContext): AtomicDeployPruneStep[] {\n if (context.existingReleases.length === 0) return [];\n\n const normalizedRoot = normalizeRemotePath(context.releasesRoot);\n const newReleasePath = joinRemotePath(normalizedRoot, context.releaseId);\n const candidates = [...new Set(context.existingReleases.map((path) => normalizeRemotePath(path)))]\n .filter((path) => path !== newReleasePath)\n .sort();\n\n const releasesToRetain = Math.max(0, context.retain - 1);\n if (candidates.length <= releasesToRetain) return [];\n\n const toPrune = candidates.slice(0, candidates.length - releasesToRetain);\n return toPrune.map((path, index) => {\n const step: AtomicDeployPruneStep = {\n id: `${context.planId}/prune/${index}`,\n path,\n reason: \"Older release exceeds retain window\",\n };\n if (context.provider !== undefined) step.provider = context.provider;\n return step;\n });\n}\n\nfunction defaultReleaseId(now: Date): string {\n // ISO timestamp with characters safe for filesystem path segments (no `:` or `.`).\n return now.toISOString().replace(/[:.]/g, \"-\");\n}\n","/**\n * Recursive remote-tree traversal helpers.\n *\n * @module sync/walkRemoteTree\n */\nimport { AbortError } from \"../errors/ZeroTransferError\";\nimport type { RemoteFileSystem } from \"../providers/RemoteFileSystem\";\nimport type { RemoteEntry } from \"../types/public\";\nimport { joinRemotePath, normalizeRemotePath } from \"../utils/path\";\n\n/** Filter callback applied to each visited entry. Returning `false` skips the entry. */\nexport type RemoteTreeFilter = (entry: RemoteEntry) => boolean;\n\n/** Options accepted by {@link walkRemoteTree}. */\nexport interface WalkRemoteTreeOptions {\n /** Whether to descend into subdirectories. Defaults to `true`. */\n recursive?: boolean;\n /** Maximum traversal depth. `0` walks only the root listing. Unbounded by default. */\n maxDepth?: number;\n /** Whether to include directory entries in the output. Defaults to `true`. */\n includeDirectories?: boolean;\n /** Whether to include file entries in the output. Defaults to `true`. */\n includeFiles?: boolean;\n /** Whether to follow symlinks during traversal. Defaults to `false`. */\n followSymlinks?: boolean;\n /** Optional filter applied before yielding and before descending into directories. */\n filter?: RemoteTreeFilter;\n /** Optional abort signal that interrupts traversal between listings. */\n signal?: AbortSignal;\n}\n\n/** Walk record yielded by {@link walkRemoteTree}. */\nexport interface RemoteTreeEntry {\n /** Visited remote entry. */\n entry: RemoteEntry;\n /** Zero-based depth relative to the traversal root. */\n depth: number;\n /** Normalized parent directory path. */\n parentPath: string;\n}\n\n/**\n * Walks a remote file system depth-first, yielding entries in a stable order.\n *\n * Listings are sorted by entry path within each directory so output is deterministic\n * across providers. Errors thrown by `fs.list()` propagate; callers can supply a\n * filter to skip directories that should not be traversed.\n *\n * @param fs - Remote file system used for listings.\n * @param rootPath - Root directory to walk.\n * @param options - Optional traversal controls.\n * @returns Async generator emitting {@link RemoteTreeEntry} records.\n * @throws {@link AbortError} When the supplied abort signal is cancelled mid-walk.\n */\nexport async function* walkRemoteTree(\n fs: RemoteFileSystem,\n rootPath: string,\n options: WalkRemoteTreeOptions = {},\n): AsyncGenerator<RemoteTreeEntry> {\n const recursive = options.recursive ?? true;\n const includeDirectories = options.includeDirectories ?? true;\n const includeFiles = options.includeFiles ?? true;\n const followSymlinks = options.followSymlinks ?? false;\n const root = normalizeRemotePath(rootPath);\n const normalized: NormalizedWalkOptions = {\n followSymlinks,\n includeDirectories,\n includeFiles,\n recursive,\n };\n if (options.maxDepth !== undefined) normalized.maxDepth = options.maxDepth;\n if (options.filter !== undefined) normalized.filter = options.filter;\n if (options.signal !== undefined) normalized.signal = options.signal;\n\n yield* walkDirectory(fs, root, 0, normalized);\n}\n\ninterface NormalizedWalkOptions {\n recursive: boolean;\n includeDirectories: boolean;\n includeFiles: boolean;\n followSymlinks: boolean;\n maxDepth?: number;\n filter?: RemoteTreeFilter;\n signal?: AbortSignal;\n}\n\nasync function* walkDirectory(\n fs: RemoteFileSystem,\n path: string,\n depth: number,\n options: NormalizedWalkOptions,\n): AsyncGenerator<RemoteTreeEntry> {\n throwIfAborted(options.signal);\n const entries = await fs.list(path);\n const sorted = [...entries].sort(compareEntries);\n\n for (const entry of sorted) {\n if (options.filter !== undefined && !options.filter(entry)) continue;\n\n if (matchesEntryKind(entry, options.includeDirectories, options.includeFiles)) {\n yield { depth, entry, parentPath: path };\n }\n\n if (\n options.recursive &&\n canDescendInto(entry, options.followSymlinks) &&\n (options.maxDepth === undefined || depth < options.maxDepth)\n ) {\n yield* walkDirectory(fs, ensureDescendPath(entry, path), depth + 1, options);\n }\n }\n}\n\nfunction matchesEntryKind(\n entry: RemoteEntry,\n includeDirectories: boolean,\n includeFiles: boolean,\n): boolean {\n if (entry.type === \"directory\") return includeDirectories;\n if (entry.type === \"file\") return includeFiles;\n return true;\n}\n\nfunction canDescendInto(entry: RemoteEntry, followSymlinks: boolean): boolean {\n if (entry.type === \"directory\") return true;\n return followSymlinks && entry.type === \"symlink\";\n}\n\nfunction ensureDescendPath(entry: RemoteEntry, parentPath: string): string {\n if (entry.path !== \"\" && entry.path !== entry.name) {\n return normalizeRemotePath(entry.path);\n }\n\n return joinRemotePath(parentPath, entry.name);\n}\n\nfunction compareEntries(left: RemoteEntry, right: RemoteEntry): number {\n if (left.path < right.path) return -1;\n if (left.path > right.path) return 1;\n return 0;\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted === true) {\n throw new AbortError({\n message: \"Remote tree walk aborted\",\n retryable: false,\n });\n }\n}\n","/**\n * Directory diffing primitives that compare two remote trees.\n *\n * @module sync/diffRemoteTrees\n */\nimport type { RemoteFileSystem } from \"../providers/RemoteFileSystem\";\nimport type { RemoteEntry } from \"../types/public\";\nimport { normalizeRemotePath } from \"../utils/path\";\nimport {\n walkRemoteTree,\n type RemoteTreeFilter,\n type WalkRemoteTreeOptions,\n} from \"./walkRemoteTree\";\n\n/** Outcome category for an entry across the two compared trees. */\nexport type RemoteTreeDiffStatus = \"added\" | \"removed\" | \"modified\" | \"unchanged\";\n\n/** Reason an entry is considered modified. */\nexport type RemoteTreeDiffReason = \"type\" | \"size\" | \"modifiedAt\" | \"checksum\";\n\n/** Single diff record produced by {@link diffRemoteTrees}. */\nexport interface RemoteTreeDiffEntry {\n /** Path relative to the traversal root, beginning with `/`. */\n path: string;\n /** Outcome category for this entry. */\n status: RemoteTreeDiffStatus;\n /** Reasons the entry is considered modified. Empty for unchanged/added/removed records. */\n reasons: RemoteTreeDiffReason[];\n /** Source-side entry, when present. */\n source?: RemoteEntry;\n /** Destination-side entry, when present. */\n destination?: RemoteEntry;\n}\n\n/** Compact summary of a diff result. */\nexport interface RemoteTreeDiffSummary {\n /** Number of entries present only on the source side. */\n added: number;\n /** Number of entries present only on the destination side. */\n removed: number;\n /** Number of entries present on both sides whose contents differ. */\n modified: number;\n /** Number of entries present on both sides with identical contents. */\n unchanged: number;\n /** Total entries inspected across both sides. */\n total: number;\n}\n\n/** Result returned by {@link diffRemoteTrees}. */\nexport interface RemoteTreeDiff {\n /** Diff records sorted by path. */\n entries: RemoteTreeDiffEntry[];\n /** Compact counts for the diff. */\n summary: RemoteTreeDiffSummary;\n}\n\n/** Options accepted by {@link diffRemoteTrees}. */\nexport interface DiffRemoteTreesOptions {\n /** Optional traversal controls applied to both sides. */\n walk?: Pick<\n WalkRemoteTreeOptions,\n \"filter\" | \"followSymlinks\" | \"includeDirectories\" | \"includeFiles\" | \"maxDepth\" | \"recursive\"\n >;\n /** Filter applied only to the source side. Overrides `walk.filter` when set. */\n sourceFilter?: RemoteTreeFilter;\n /** Filter applied only to the destination side. Overrides `walk.filter` when set. */\n destinationFilter?: RemoteTreeFilter;\n /** Whether unchanged entries are included in `entries`. Defaults to `false`. */\n includeUnchanged?: boolean;\n /** Tolerance in milliseconds when comparing modification timestamps. Defaults to `1000`. */\n modifiedAtToleranceMs?: number;\n /** Whether modification timestamps participate in the comparison. Defaults to `true`. */\n compareModifiedAt?: boolean;\n /** Whether sizes participate in the comparison. Defaults to `true`. */\n compareSize?: boolean;\n /** Whether to require matching `uniqueId` checksums when both entries expose one. Defaults to `false`. */\n compareUniqueId?: boolean;\n /** Optional abort signal threaded through both walks. */\n signal?: AbortSignal;\n}\n\n/**\n * Compares two remote subtrees and produces an entry-level diff.\n *\n * Source and destination paths are walked independently; entries are then aligned by\n * the relative path from each tree root. Directory equality is structural - directories\n * are equal when their relative paths match and the entry types agree.\n *\n * @param source - Source-side remote file system.\n * @param sourcePath - Source-side root path being compared.\n * @param destination - Destination-side remote file system.\n * @param destinationPath - Destination-side root path being compared.\n * @param options - Optional comparison controls.\n * @returns Diff result containing entries and a summary.\n *\n * @example Diff two SFTP subtrees and feed the result into createSyncPlan\n * ```ts\n * import { createSyncPlan, diffRemoteTrees } from \"@zero-transfer/sdk\";\n *\n * const diff = await diffRemoteTrees(\n * srcSession.fs, \"/exports\",\n * dstSession.fs, \"/exports\",\n * { compareUniqueId: true },\n * );\n *\n * console.log(diff.summary); // { added, removed, changed, unchanged }\n *\n * const plan = createSyncPlan({\n * id: \"exports-sync\",\n * diff,\n * source: { provider: \"sftp\", rootPath: \"/exports\" },\n * destination: { provider: \"sftp\", rootPath: \"/exports\" },\n * });\n * ```\n */\nexport async function diffRemoteTrees(\n source: RemoteFileSystem,\n sourcePath: string,\n destination: RemoteFileSystem,\n destinationPath: string,\n options: DiffRemoteTreesOptions = {},\n): Promise<RemoteTreeDiff> {\n const includeUnchanged = options.includeUnchanged ?? false;\n const sourceRoot = normalizeRemotePath(sourcePath);\n const destinationRoot = normalizeRemotePath(destinationPath);\n const sourceWalk = createWalkOptions(options, options.sourceFilter);\n const destinationWalk = createWalkOptions(options, options.destinationFilter);\n\n const [sourceEntries, destinationEntries] = await Promise.all([\n collectEntries(source, sourceRoot, sourceWalk),\n collectEntries(destination, destinationRoot, destinationWalk),\n ]);\n\n const aligned = alignEntries(sourceEntries, destinationEntries);\n const entries: RemoteTreeDiffEntry[] = [];\n const summary: RemoteTreeDiffSummary = {\n added: 0,\n modified: 0,\n removed: 0,\n total: 0,\n unchanged: 0,\n };\n\n for (const { path, source: sourceEntry, destination: destinationEntry } of aligned) {\n summary.total += 1;\n const reasons: RemoteTreeDiffReason[] = [];\n let status: RemoteTreeDiffStatus;\n\n if (sourceEntry !== undefined && destinationEntry === undefined) {\n status = \"added\";\n summary.added += 1;\n } else if (sourceEntry === undefined && destinationEntry !== undefined) {\n status = \"removed\";\n summary.removed += 1;\n } else if (sourceEntry !== undefined && destinationEntry !== undefined) {\n const computedReasons = compareEntries(sourceEntry, destinationEntry, options);\n\n if (computedReasons.length === 0) {\n status = \"unchanged\";\n summary.unchanged += 1;\n } else {\n status = \"modified\";\n reasons.push(...computedReasons);\n summary.modified += 1;\n }\n } else {\n // Both entries undefined cannot happen because alignEntries only emits aligned pairs.\n continue;\n }\n\n if (status === \"unchanged\" && !includeUnchanged) continue;\n\n const record: RemoteTreeDiffEntry = { path, reasons, status };\n if (sourceEntry !== undefined) record.source = sourceEntry;\n if (destinationEntry !== undefined) record.destination = destinationEntry;\n entries.push(record);\n }\n\n entries.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));\n\n return { entries, summary };\n}\n\nfunction createWalkOptions(\n options: DiffRemoteTreesOptions,\n filter: RemoteTreeFilter | undefined,\n): WalkRemoteTreeOptions {\n const walk = options.walk ?? {};\n const merged: WalkRemoteTreeOptions = {};\n\n if (walk.recursive !== undefined) merged.recursive = walk.recursive;\n if (walk.maxDepth !== undefined) merged.maxDepth = walk.maxDepth;\n if (walk.includeDirectories !== undefined) merged.includeDirectories = walk.includeDirectories;\n if (walk.includeFiles !== undefined) merged.includeFiles = walk.includeFiles;\n if (walk.followSymlinks !== undefined) merged.followSymlinks = walk.followSymlinks;\n const resolvedFilter = filter ?? walk.filter;\n if (resolvedFilter !== undefined) merged.filter = resolvedFilter;\n if (options.signal !== undefined) merged.signal = options.signal;\n\n return merged;\n}\n\ninterface CollectedEntry {\n relativePath: string;\n entry: RemoteEntry;\n}\n\nasync function collectEntries(\n fs: RemoteFileSystem,\n rootPath: string,\n walkOptions: WalkRemoteTreeOptions,\n): Promise<Map<string, RemoteEntry>> {\n const map = new Map<string, RemoteEntry>();\n\n for await (const record of walkRemoteTree(fs, rootPath, walkOptions)) {\n const collected = toCollectedEntry(record.entry, rootPath);\n if (collected !== undefined) map.set(collected.relativePath, collected.entry);\n }\n\n return map;\n}\n\nfunction toCollectedEntry(entry: RemoteEntry, rootPath: string): CollectedEntry | undefined {\n const root = normalizeRemotePath(rootPath);\n const path = normalizeRemotePath(entry.path);\n\n if (path === root) return undefined;\n if (root === \"/\") return { entry, relativePath: path };\n if (path.startsWith(`${root}/`)) {\n return { entry, relativePath: path.slice(root.length) };\n }\n\n return undefined;\n}\n\ninterface AlignedPair {\n path: string;\n source?: RemoteEntry;\n destination?: RemoteEntry;\n}\n\nfunction alignEntries(\n sourceEntries: Map<string, RemoteEntry>,\n destinationEntries: Map<string, RemoteEntry>,\n): AlignedPair[] {\n const paths = new Set<string>([...sourceEntries.keys(), ...destinationEntries.keys()]);\n const aligned: AlignedPair[] = [];\n\n for (const path of paths) {\n const pair: AlignedPair = { path };\n const source = sourceEntries.get(path);\n const destination = destinationEntries.get(path);\n\n if (source !== undefined) pair.source = source;\n if (destination !== undefined) pair.destination = destination;\n aligned.push(pair);\n }\n\n return aligned;\n}\n\nfunction compareEntries(\n source: RemoteEntry,\n destination: RemoteEntry,\n options: DiffRemoteTreesOptions,\n): RemoteTreeDiffReason[] {\n const reasons: RemoteTreeDiffReason[] = [];\n const compareSize = options.compareSize ?? true;\n const compareModifiedAt = options.compareModifiedAt ?? true;\n const compareUniqueId = options.compareUniqueId ?? false;\n const tolerance = options.modifiedAtToleranceMs ?? 1000;\n\n if (source.type !== destination.type) {\n reasons.push(\"type\");\n }\n\n if (compareSize && isSizeRelevant(source, destination) && source.size !== destination.size) {\n reasons.push(\"size\");\n }\n\n if (compareModifiedAt && isModifiedAtDifferent(source, destination, tolerance)) {\n reasons.push(\"modifiedAt\");\n }\n\n if (\n compareUniqueId &&\n source.uniqueId !== undefined &&\n destination.uniqueId !== undefined &&\n source.uniqueId !== destination.uniqueId\n ) {\n reasons.push(\"checksum\");\n }\n\n return reasons;\n}\n\nfunction isSizeRelevant(source: RemoteEntry, destination: RemoteEntry): boolean {\n if (source.type !== \"file\" || destination.type !== \"file\") return false;\n return source.size !== undefined && destination.size !== undefined;\n}\n\nfunction isModifiedAtDifferent(\n source: RemoteEntry,\n destination: RemoteEntry,\n toleranceMs: number,\n): boolean {\n if (source.modifiedAt === undefined || destination.modifiedAt === undefined) return false;\n const delta = Math.abs(source.modifiedAt.getTime() - destination.modifiedAt.getTime());\n return delta > toleranceMs;\n}\n","/**\n * Remote manifest read/write/compare helpers.\n *\n * A manifest is a serializable snapshot of a remote subtree produced by walking\n * the live tree once and persisting the result. Manifests can be diffed against\n * each other to detect drift without re-listing both sides.\n *\n * @module sync/manifest\n */\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { ProviderId } from \"../core/ProviderId\";\nimport type { RemoteFileSystem } from \"../providers/RemoteFileSystem\";\nimport type { RemoteEntry, RemoteEntryType } from \"../types/public\";\nimport { normalizeRemotePath } from \"../utils/path\";\nimport type {\n RemoteTreeDiff,\n RemoteTreeDiffEntry,\n RemoteTreeDiffReason,\n RemoteTreeDiffStatus,\n RemoteTreeDiffSummary,\n} from \"./diffRemoteTrees\";\nimport {\n walkRemoteTree,\n type RemoteTreeFilter,\n type WalkRemoteTreeOptions,\n} from \"./walkRemoteTree\";\n\n/** Schema version for the manifest payload. Bumped on incompatible format changes. */\nexport const REMOTE_MANIFEST_FORMAT_VERSION = 1;\n\n/** Manifest entry recorded for each visited remote node. */\nexport interface RemoteManifestEntry {\n /** Path relative to {@link RemoteManifest.root}, beginning with `/`. */\n path: string;\n /** Entry kind. */\n type: RemoteEntryType;\n /** Entry size in bytes when known. */\n size?: number;\n /** Last modification time as an ISO 8601 timestamp when known. */\n modifiedAt?: string;\n /** Protocol-specific stable identity when available. */\n uniqueId?: string;\n /** Target path for symbolic links when known. */\n symlinkTarget?: string;\n}\n\n/** Persisted snapshot of a remote subtree. */\nexport interface RemoteManifest {\n /** Schema version. Must equal {@link REMOTE_MANIFEST_FORMAT_VERSION}. */\n formatVersion: number;\n /** ISO 8601 timestamp recording when the manifest was generated. */\n generatedAt: string;\n /** Normalized absolute root path the manifest snapshot is anchored to. */\n root: string;\n /** Optional provider identifier the snapshot was captured from. */\n provider?: ProviderId;\n /** Manifest entries sorted by path. */\n entries: RemoteManifestEntry[];\n}\n\n/** Options accepted by {@link createRemoteManifest}. */\nexport interface CreateRemoteManifestOptions {\n /** Optional traversal controls forwarded to {@link walkRemoteTree}. */\n walk?: Pick<\n WalkRemoteTreeOptions,\n \"filter\" | \"followSymlinks\" | \"includeDirectories\" | \"includeFiles\" | \"maxDepth\" | \"recursive\"\n >;\n /** Filter applied during traversal. Overrides `walk.filter` when provided. */\n filter?: RemoteTreeFilter;\n /** Provider identifier embedded into the manifest header. */\n provider?: ProviderId;\n /** Clock used to stamp `generatedAt`. Defaults to `Date.now`. */\n now?: () => Date;\n /** Optional abort signal threaded through the walk. */\n signal?: AbortSignal;\n}\n\n/** Options accepted by {@link compareRemoteManifests}. */\nexport interface CompareRemoteManifestsOptions {\n /** Whether unchanged entries are included in the result. Defaults to `false`. */\n includeUnchanged?: boolean;\n /** Tolerance in milliseconds applied to `modifiedAt` comparisons. Defaults to `1000`. */\n modifiedAtToleranceMs?: number;\n /** Whether modification timestamps participate in the comparison. Defaults to `true`. */\n compareModifiedAt?: boolean;\n /** Whether sizes participate in the comparison. Defaults to `true`. */\n compareSize?: boolean;\n /** Whether to require matching `uniqueId` checksums when both entries expose one. Defaults to `false`. */\n compareUniqueId?: boolean;\n}\n\n/**\n * Walks a remote subtree and produces a serializable manifest snapshot.\n *\n * @param fs - Remote file system to capture.\n * @param rootPath - Root path the manifest is anchored to.\n * @param options - Optional capture controls.\n * @returns Manifest snapshot suitable for serialization or comparison.\n */\nexport async function createRemoteManifest(\n fs: RemoteFileSystem,\n rootPath: string,\n options: CreateRemoteManifestOptions = {},\n): Promise<RemoteManifest> {\n const root = normalizeRemotePath(rootPath);\n const walkOptions: WalkRemoteTreeOptions = { ...(options.walk ?? {}) };\n const resolvedFilter = options.filter ?? options.walk?.filter;\n if (resolvedFilter !== undefined) walkOptions.filter = resolvedFilter;\n if (options.signal !== undefined) walkOptions.signal = options.signal;\n\n const entries: RemoteManifestEntry[] = [];\n\n for await (const record of walkRemoteTree(fs, root, walkOptions)) {\n const relativePath = relativeFromRoot(record.entry.path, root);\n if (relativePath === undefined) continue;\n entries.push(toManifestEntry(record.entry, relativePath));\n }\n\n entries.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));\n\n const generatedAt = (options.now?.() ?? new Date()).toISOString();\n const manifest: RemoteManifest = {\n entries,\n formatVersion: REMOTE_MANIFEST_FORMAT_VERSION,\n generatedAt,\n root,\n };\n if (options.provider !== undefined) manifest.provider = options.provider;\n return manifest;\n}\n\n/**\n * Serializes a manifest to a JSON string suitable for persistence.\n *\n * @param manifest - Manifest snapshot to serialize.\n * @param indent - Optional indentation passed to `JSON.stringify`. Defaults to `2`.\n * @returns Stable JSON representation of the manifest.\n */\nexport function serializeRemoteManifest(manifest: RemoteManifest, indent: number = 2): string {\n return JSON.stringify(manifest, undefined, indent);\n}\n\n/**\n * Parses a JSON-encoded manifest, validating the schema version and entry shape.\n *\n * @param text - JSON payload produced by {@link serializeRemoteManifest}.\n * @returns Parsed manifest snapshot.\n * @throws {@link ConfigurationError} When the payload is invalid or has an unsupported version.\n */\nexport function parseRemoteManifest(text: string): RemoteManifest {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n throw new ConfigurationError({\n cause: error,\n message: \"Failed to parse remote manifest payload as JSON\",\n retryable: false,\n });\n }\n\n if (parsed === null || typeof parsed !== \"object\") {\n throw new ConfigurationError({\n message: \"Remote manifest payload must be a JSON object\",\n retryable: false,\n });\n }\n\n const candidate = parsed as Partial<RemoteManifest> & Record<string, unknown>;\n if (candidate.formatVersion !== REMOTE_MANIFEST_FORMAT_VERSION) {\n throw new ConfigurationError({\n details: {\n expected: REMOTE_MANIFEST_FORMAT_VERSION,\n received: candidate.formatVersion,\n },\n message: `Unsupported remote manifest formatVersion: ${String(candidate.formatVersion)}`,\n retryable: false,\n });\n }\n\n if (typeof candidate.root !== \"string\" || candidate.root.length === 0) {\n throw new ConfigurationError({\n message: \"Remote manifest root must be a non-empty string\",\n retryable: false,\n });\n }\n\n if (typeof candidate.generatedAt !== \"string\") {\n throw new ConfigurationError({\n message: \"Remote manifest generatedAt must be an ISO timestamp string\",\n retryable: false,\n });\n }\n\n if (!Array.isArray(candidate.entries)) {\n throw new ConfigurationError({\n message: \"Remote manifest entries must be an array\",\n retryable: false,\n });\n }\n\n const entries = candidate.entries.map((entry, index) => normalizeManifestEntry(entry, index));\n const manifest: RemoteManifest = {\n entries,\n formatVersion: REMOTE_MANIFEST_FORMAT_VERSION,\n generatedAt: candidate.generatedAt,\n root: normalizeRemotePath(candidate.root),\n };\n if (typeof candidate.provider === \"string\") manifest.provider = candidate.provider;\n return manifest;\n}\n\n/**\n * Compares two manifests and produces an entry-level diff.\n *\n * The comparison is performed on the relative-path keys recorded inside each manifest;\n * the absolute roots may differ between snapshots (e.g. captured against `/site` on the\n * source and `/var/www/site` on the destination).\n *\n * @param source - Source-side manifest snapshot.\n * @param destination - Destination-side manifest snapshot.\n * @param options - Optional comparison controls.\n * @returns Diff result mirroring {@link RemoteTreeDiff}.\n */\nexport function compareRemoteManifests(\n source: RemoteManifest,\n destination: RemoteManifest,\n options: CompareRemoteManifestsOptions = {},\n): RemoteTreeDiff {\n const includeUnchanged = options.includeUnchanged ?? false;\n const sourceMap = indexEntries(source);\n const destinationMap = indexEntries(destination);\n const paths = new Set<string>([...sourceMap.keys(), ...destinationMap.keys()]);\n\n const entries: RemoteTreeDiffEntry[] = [];\n const summary: RemoteTreeDiffSummary = {\n added: 0,\n modified: 0,\n removed: 0,\n total: 0,\n unchanged: 0,\n };\n\n for (const path of paths) {\n summary.total += 1;\n const sourceEntry = sourceMap.get(path);\n const destinationEntry = destinationMap.get(path);\n const reasons: RemoteTreeDiffReason[] = [];\n let status: RemoteTreeDiffStatus;\n\n if (sourceEntry !== undefined && destinationEntry === undefined) {\n status = \"added\";\n summary.added += 1;\n } else if (sourceEntry === undefined && destinationEntry !== undefined) {\n status = \"removed\";\n summary.removed += 1;\n } else if (sourceEntry !== undefined && destinationEntry !== undefined) {\n const computed = compareManifestEntries(sourceEntry, destinationEntry, options);\n if (computed.length === 0) {\n status = \"unchanged\";\n summary.unchanged += 1;\n } else {\n status = \"modified\";\n reasons.push(...computed);\n summary.modified += 1;\n }\n } else {\n continue;\n }\n\n if (status === \"unchanged\" && !includeUnchanged) continue;\n\n const record: RemoteTreeDiffEntry = { path, reasons, status };\n if (sourceEntry !== undefined) {\n record.source = manifestEntryToRemote(sourceEntry, source.root);\n }\n if (destinationEntry !== undefined) {\n record.destination = manifestEntryToRemote(destinationEntry, destination.root);\n }\n entries.push(record);\n }\n\n entries.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));\n return { entries, summary };\n}\n\nfunction relativeFromRoot(entryPath: string, root: string): string | undefined {\n const path = normalizeRemotePath(entryPath);\n if (path === root) return undefined;\n if (root === \"/\") return path;\n if (path.startsWith(`${root}/`)) return path.slice(root.length);\n return undefined;\n}\n\nfunction toManifestEntry(entry: RemoteEntry, relativePath: string): RemoteManifestEntry {\n const manifestEntry: RemoteManifestEntry = {\n path: relativePath,\n type: entry.type,\n };\n if (entry.size !== undefined) manifestEntry.size = entry.size;\n if (entry.modifiedAt !== undefined) manifestEntry.modifiedAt = entry.modifiedAt.toISOString();\n if (entry.uniqueId !== undefined) manifestEntry.uniqueId = entry.uniqueId;\n if (entry.symlinkTarget !== undefined) manifestEntry.symlinkTarget = entry.symlinkTarget;\n return manifestEntry;\n}\n\nfunction normalizeManifestEntry(value: unknown, index: number): RemoteManifestEntry {\n if (value === null || typeof value !== \"object\") {\n throw new ConfigurationError({\n details: { index },\n message: `Remote manifest entry at index ${index} must be an object`,\n retryable: false,\n });\n }\n\n const candidate = value as Partial<RemoteManifestEntry> & Record<string, unknown>;\n if (typeof candidate.path !== \"string\" || candidate.path.length === 0) {\n throw new ConfigurationError({\n details: { index },\n message: `Remote manifest entry at index ${index} must have a non-empty path`,\n retryable: false,\n });\n }\n if (!isRemoteEntryType(candidate.type)) {\n throw new ConfigurationError({\n details: { index, received: candidate.type },\n message: `Remote manifest entry at index ${index} has an invalid type`,\n retryable: false,\n });\n }\n\n const entry: RemoteManifestEntry = {\n path: candidate.path,\n type: candidate.type,\n };\n if (typeof candidate.size === \"number\") entry.size = candidate.size;\n if (typeof candidate.modifiedAt === \"string\") entry.modifiedAt = candidate.modifiedAt;\n if (typeof candidate.uniqueId === \"string\") entry.uniqueId = candidate.uniqueId;\n if (typeof candidate.symlinkTarget === \"string\") entry.symlinkTarget = candidate.symlinkTarget;\n return entry;\n}\n\nfunction isRemoteEntryType(value: unknown): value is RemoteEntryType {\n return value === \"file\" || value === \"directory\" || value === \"symlink\" || value === \"unknown\";\n}\n\nfunction indexEntries(manifest: RemoteManifest): Map<string, RemoteManifestEntry> {\n const map = new Map<string, RemoteManifestEntry>();\n for (const entry of manifest.entries) map.set(entry.path, entry);\n return map;\n}\n\nfunction manifestEntryToRemote(entry: RemoteManifestEntry, root: string): RemoteEntry {\n const absolutePath = root === \"/\" ? entry.path : `${root}${entry.path}`;\n const remote: RemoteEntry = {\n name: deriveName(entry.path),\n path: absolutePath,\n type: entry.type,\n };\n if (entry.size !== undefined) remote.size = entry.size;\n if (entry.modifiedAt !== undefined) {\n const parsed = new Date(entry.modifiedAt);\n if (!Number.isNaN(parsed.getTime())) remote.modifiedAt = parsed;\n }\n if (entry.uniqueId !== undefined) remote.uniqueId = entry.uniqueId;\n if (entry.symlinkTarget !== undefined) remote.symlinkTarget = entry.symlinkTarget;\n return remote;\n}\n\nfunction deriveName(path: string): string {\n const segments = path.split(\"/\").filter(Boolean);\n return segments.length === 0 ? \"/\" : (segments[segments.length - 1] ?? \"/\");\n}\n\nfunction compareManifestEntries(\n source: RemoteManifestEntry,\n destination: RemoteManifestEntry,\n options: CompareRemoteManifestsOptions,\n): RemoteTreeDiffReason[] {\n const reasons: RemoteTreeDiffReason[] = [];\n const compareSize = options.compareSize ?? true;\n const compareModifiedAt = options.compareModifiedAt ?? true;\n const compareUniqueId = options.compareUniqueId ?? false;\n const tolerance = options.modifiedAtToleranceMs ?? 1000;\n\n if (source.type !== destination.type) reasons.push(\"type\");\n\n if (\n compareSize &&\n source.type === \"file\" &&\n destination.type === \"file\" &&\n source.size !== undefined &&\n destination.size !== undefined &&\n source.size !== destination.size\n ) {\n reasons.push(\"size\");\n }\n\n if (compareModifiedAt && isModifiedAtDifferent(source, destination, tolerance)) {\n reasons.push(\"modifiedAt\");\n }\n\n if (\n compareUniqueId &&\n source.uniqueId !== undefined &&\n destination.uniqueId !== undefined &&\n source.uniqueId !== destination.uniqueId\n ) {\n reasons.push(\"checksum\");\n }\n\n return reasons;\n}\n\nfunction isModifiedAtDifferent(\n source: RemoteManifestEntry,\n destination: RemoteManifestEntry,\n toleranceMs: number,\n): boolean {\n if (source.modifiedAt === undefined || destination.modifiedAt === undefined) return false;\n const sourceTime = Date.parse(source.modifiedAt);\n const destinationTime = Date.parse(destination.modifiedAt);\n if (Number.isNaN(sourceTime) || Number.isNaN(destinationTime)) return false;\n return Math.abs(sourceTime - destinationTime) > toleranceMs;\n}\n","/**\n * @file `isMainModule` - small helper for the rare case a script needs to\n * branch on whether it is the process entry point.\n *\n * Most code does not need this. Examples and CLIs should just put their work\n * at the top level of an ES module - top-level `await` is allowed, and any\n * thrown error propagates up so Node prints it and exits non-zero. No guard,\n * no wrapper, no `import.meta.url` plumbing required.\n *\n * If you do need the boolean (e.g. a file that is both a library and a CLI),\n * call `isMainModule(import.meta.url)`.\n */\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Returns `true` when the file containing `import.meta.url` is the entry point\n * of the current Node.js process. Returns `false` outside Node.\n */\nexport function isMainModule(importMetaUrl: string): boolean {\n if (typeof process === \"undefined\" || !process.argv || process.argv.length < 2) {\n return false;\n }\n try {\n return process.argv[1] === fileURLToPath(importMetaUrl);\n } catch {\n return false;\n }\n}\n","import { Buffer } from \"node:buffer\";\nimport type { Socket } from \"node:net\";\nimport { ConnectionError, ProtocolError, TimeoutError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader } from \"../binary/SshDataReader\";\nimport { SshDataWriter } from \"../binary/SshDataWriter\";\nimport type { SshAlgorithmPreferences } from \"./SshAlgorithmNegotiation\";\nimport { SshTransportHandshake, type SshTransportHandshakeResult } from \"./SshTransportHandshake\";\nimport type {\n SshTransportPacketProtector,\n SshTransportPacketUnprotector,\n} from \"./SshTransportProtection\";\nimport { createSshTransportProtectionContext } from \"./SshTransportProtection\";\n\n/** Standard SSH disconnect reason codes (RFC 4253 §11.1). */\nexport const SshDisconnectReason = {\n HOST_NOT_ALLOWED_TO_CONNECT: 1,\n PROTOCOL_ERROR: 2,\n KEY_EXCHANGE_FAILED: 3,\n MAC_ERROR: 5,\n COMPRESSION_ERROR: 6,\n SERVICE_NOT_AVAILABLE: 7,\n PROTOCOL_VERSION_NOT_SUPPORTED: 8,\n HOST_KEY_NOT_VERIFIABLE: 9,\n CONNECTION_LOST: 10,\n BY_APPLICATION: 11,\n TOO_MANY_CONNECTIONS: 12,\n AUTH_CANCELLED_BY_USER: 13,\n NO_MORE_AUTH_METHODS: 14,\n ILLEGAL_USER_NAME: 15,\n} as const;\n\nexport type SshDisconnectReason = (typeof SshDisconnectReason)[keyof typeof SshDisconnectReason];\n\nconst MSG_DISCONNECT = 1;\nconst MSG_IGNORE = 2;\nconst MSG_DEBUG = 4;\n\nexport interface SshTransportConnectionOptions {\n /** AbortSignal that cancels the in-flight `connect()` call and tears down the socket. */\n abortSignal?: AbortSignal;\n /** Algorithm preference overrides. Defaults to the library defaults. */\n algorithms?: SshAlgorithmPreferences;\n /** SSH software version string embedded in the identification line. */\n clientSoftwareVersion?: string;\n /**\n * Hard cap (milliseconds) on the SSH identification + key exchange + first\n * NEWKEYS handshake. If exceeded the socket is destroyed and `connect()`\n * rejects with a `TimeoutError`. Has no effect once `connect()` resolves.\n */\n handshakeTimeoutMs?: number;\n /**\n * If set, sends a `SSH_MSG_IGNORE` packet every `keepaliveIntervalMs`\n * milliseconds while the transport is connected and idle. This prevents\n * stateful NAT / firewall devices from dropping long-lived idle sessions\n * (e.g. between batches in a transfer queue). The timer is reset on every\n * outbound payload, so active transfers do not generate extra traffic.\n */\n keepaliveIntervalMs?: number;\n /**\n * Synchronous host-key policy hook invoked after the signature on the SSH\n * exchange hash is verified. Throw to reject the server's identity.\n */\n verifyHostKey?: (input: {\n hostKeyBlob: Buffer;\n hostKeySha256: Buffer;\n algorithmName: string;\n }) => void;\n}\n\ntype InboundQueueEntry =\n | { type: \"payload\"; payload: Buffer }\n | { type: \"error\"; error: Error }\n | { type: \"end\" };\n\n/**\n * Live SSH transport connection over a TCP socket.\n *\n * Runs the SSH identification exchange and key exchange handshake on the supplied socket,\n * then provides an encrypted packet send/receive interface for higher-level SSH layers\n * (authentication, connection, SFTP subsystem).\n *\n * Usage:\n * ```ts\n * const conn = new SshTransportConnection();\n * const result = await conn.connect(socket); // runs handshake\n * conn.sendPayload(payload); // post-NEWKEYS send\n * for await (const payload of conn.receivePayloads()) { ... }\n * conn.disconnect();\n * ```\n */\nexport class SshTransportConnection {\n private connected = false;\n private disposed = false;\n private protector: SshTransportPacketProtector | undefined;\n private unprotector: SshTransportPacketUnprotector | undefined;\n private socket: Socket | undefined;\n private keepaliveTimer: ReturnType<typeof setInterval> | undefined;\n\n private readonly inboundQueue: InboundQueueEntry[] = [];\n /**\n * FIFO of waiters when the queue is empty. Multiple iterators may suspend on\n * the same transport (auth session, channel setup, connection-manager pump);\n * each receives exactly one entry in arrival order. A single-slot field would\n * lose wakeups when a second consumer suspends before the first is resolved.\n */\n private readonly waitingConsumers: Array<(entry: InboundQueueEntry) => void> = [];\n\n constructor(private readonly options: SshTransportConnectionOptions = {}) {}\n\n /**\n * Runs the SSH handshake on a TCP-connected socket.\n * Resolves when NEWKEYS completes and the transport is ready for encrypted messages.\n * Rejects on socket error, abort, or protocol failure.\n */\n connect(socket: Socket): Promise<SshTransportHandshakeResult> {\n if (this.connected || this.socket !== undefined) {\n throw new ProtocolError({\n message: \"SshTransportConnection.connect() called more than once\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n this.socket = socket;\n\n const handshake = new SshTransportHandshake({\n ...(this.options.algorithms === undefined ? {} : { algorithms: this.options.algorithms }),\n ...(this.options.clientSoftwareVersion === undefined\n ? {}\n : { clientSoftwareVersion: this.options.clientSoftwareVersion }),\n ...(this.options.verifyHostKey === undefined\n ? {}\n : { verifyHostKey: this.options.verifyHostKey }),\n });\n\n return new Promise<SshTransportHandshakeResult>((resolve, reject) => {\n const { abortSignal, handshakeTimeoutMs } = this.options;\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n\n // Declare all handlers before any early-return path so const bindings are\n // never in the temporal dead zone when cleanup() is called.\n const onError = (err: Error): void => {\n cleanup();\n reject(\n new ConnectionError({\n message: `SSH socket error during handshake: ${err.message}`,\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n };\n\n const onClose = (): void => {\n cleanup();\n reject(\n new ConnectionError({\n message: \"SSH socket closed before handshake completed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n };\n\n const onAbort = (): void => {\n cleanup();\n socket.destroy();\n reject(\n new ConnectionError({\n message: \"SSH connection aborted before handshake completed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n };\n\n const onTimeout = (): void => {\n cleanup();\n socket.destroy();\n reject(\n new TimeoutError({\n details: { handshakeTimeoutMs },\n message: `SSH handshake did not complete within ${handshakeTimeoutMs}ms`,\n protocol: \"sftp\",\n retryable: true,\n }),\n );\n };\n\n function cleanup(): void {\n if (timeoutHandle !== undefined) {\n clearTimeout(timeoutHandle);\n timeoutHandle = undefined;\n }\n abortSignal?.removeEventListener(\"abort\", onAbort);\n socket.off(\"error\", onError);\n socket.off(\"close\", onClose);\n }\n\n // If the signal is already aborted, reject immediately before registering\n // any listeners (nothing to clean up yet in that case).\n if (abortSignal?.aborted) {\n socket.destroy();\n reject(\n new ConnectionError({\n message: \"SSH connection aborted before handshake completed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n return;\n }\n\n abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n socket.on(\"error\", onError);\n socket.on(\"close\", onClose);\n\n if (handshakeTimeoutMs !== undefined && handshakeTimeoutMs > 0) {\n timeoutHandle = setTimeout(onTimeout, handshakeTimeoutMs);\n }\n\n const handshakeDataHandler = (chunk: Buffer): void => {\n let handshakeResult: SshTransportHandshakeResult | undefined;\n try {\n const { outbound, result } = handshake.pushServerBytes(chunk);\n for (const outbuf of outbound) {\n socket.write(outbuf);\n }\n handshakeResult = result;\n } catch (err) {\n cleanup();\n socket.off(\"data\", handshakeDataHandler);\n socket.destroy();\n reject(\n err instanceof Error\n ? err\n : new ProtocolError({\n message: \"SSH handshake failed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n return;\n }\n\n if (handshakeResult !== undefined) {\n cleanup();\n socket.off(\"data\", handshakeDataHandler);\n\n let protection;\n try {\n protection = createSshTransportProtectionContext({\n keys: {\n clientToServer: handshakeResult.keyExchange.transportKeys.clientToServer,\n serverToClient: handshakeResult.keyExchange.transportKeys.serverToClient,\n },\n negotiatedAlgorithms: handshakeResult.negotiatedAlgorithms,\n // RFC 4253 §6.4: sequence numbers are never reset across NEWKEYS;\n // they continue counting from the unencrypted handshake packets.\n initialInboundSequence: handshakeResult.inboundPacketCount,\n initialOutboundSequence: handshakeResult.outboundPacketCount,\n });\n } catch (err) {\n socket.destroy();\n reject(\n err instanceof Error\n ? err\n : new ProtocolError({\n message: \"SSH transport protection context creation failed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n return;\n }\n\n this.protector = protection.outbound;\n this.unprotector = protection.inbound;\n this.connected = true;\n\n socket.on(\"data\", this.onEncryptedData.bind(this));\n socket.on(\"error\", this.onSocketError.bind(this));\n socket.on(\"close\", this.onSocketClose.bind(this));\n\n this.startKeepalive();\n\n // Feed any bytes that arrived after NEWKEYS in the same TCP segment.\n const leftover = handshake.takeRemainingBytes();\n if (leftover.length > 0) {\n this.onEncryptedData(leftover);\n }\n\n resolve(handshakeResult);\n }\n };\n\n // Send the initial client identification line, then listen for server bytes.\n socket.write(handshake.createInitialClientBytes());\n socket.on(\"data\", handshakeDataHandler);\n });\n }\n\n /**\n * Sends an SSH payload over the encrypted transport.\n * The payload must start with the SSH message type byte.\n */\n sendPayload(payload: Buffer | Uint8Array): void {\n this.assertConnected();\n const frame = this.protector!.protectPayload(Buffer.from(payload));\n this.socket!.write(frame);\n // Suppress an imminent keepalive ping after real outbound traffic.\n this.resetKeepaliveTimer();\n }\n\n /**\n * Async generator that yields inbound SSH payloads (post-NEWKEYS).\n *\n * Transparent handling:\n * - SSH_MSG_IGNORE (2) and SSH_MSG_DEBUG (4) are silently dropped.\n * - SSH_MSG_DISCONNECT (1) from the server throws a `ConnectionError`.\n * - Socket error or close terminates the generator.\n */\n async *receivePayloads(): AsyncGenerator<Buffer> {\n this.assertConnected();\n while (true) {\n const entry = await this.dequeuePayload();\n if (entry.type === \"end\") return;\n if (entry.type === \"error\") throw entry.error;\n yield entry.payload;\n }\n }\n\n /**\n * Sends SSH_MSG_DISCONNECT and ends the socket.\n * Safe to call multiple times; subsequent calls are no-ops.\n */\n disconnect(\n reason: SshDisconnectReason = SshDisconnectReason.BY_APPLICATION,\n description = \"\",\n ): void {\n if (this.disposed || this.socket === undefined) return;\n this.disposed = true;\n\n this.stopKeepalive();\n\n if (this.connected && this.protector !== undefined) {\n try {\n const payload = new SshDataWriter()\n .writeByte(MSG_DISCONNECT)\n .writeUint32(reason)\n .writeString(description, \"utf8\")\n .writeString(\"\", \"utf8\") // language tag (RFC 4253 §11.1)\n .toBuffer();\n this.socket.write(this.protector.protectPayload(payload));\n } catch {\n // best-effort: socket may already be closing\n }\n }\n\n this.socket.end();\n this.enqueueEntry({ type: \"end\" });\n }\n\n isConnected(): boolean {\n return this.connected && !this.disposed;\n }\n\n private onEncryptedData(chunk: Buffer): void {\n try {\n const payloads = this.unprotector!.pushBytes(chunk);\n for (const payload of payloads) {\n const msgType = payload[0];\n if (msgType === MSG_IGNORE || msgType === MSG_DEBUG) continue;\n if (msgType === MSG_DISCONNECT) {\n this.enqueueEntry({ type: \"error\", error: parseDisconnectPayload(payload) });\n this.socket?.destroy();\n return;\n }\n this.enqueueEntry({ type: \"payload\", payload });\n }\n } catch (err) {\n this.enqueueEntry({\n type: \"error\",\n error:\n err instanceof Error\n ? err\n : new ProtocolError({\n message: \"SSH encrypted data processing error\",\n protocol: \"sftp\",\n retryable: false,\n }),\n });\n this.socket?.destroy();\n }\n }\n\n private onSocketError(err: Error): void {\n this.stopKeepalive();\n if (!this.disposed) {\n this.enqueueEntry({\n type: \"error\",\n error: new ConnectionError({\n message: `SSH socket error: ${err.message}`,\n protocol: \"sftp\",\n retryable: false,\n }),\n });\n }\n }\n\n private onSocketClose(): void {\n this.stopKeepalive();\n if (!this.disposed) {\n this.enqueueEntry({ type: \"end\" });\n }\n }\n\n private enqueueEntry(entry: InboundQueueEntry): void {\n if (this.waitingConsumers.length > 0) {\n const resolve = this.waitingConsumers.shift()!;\n resolve(entry);\n } else {\n this.inboundQueue.push(entry);\n }\n }\n\n private dequeuePayload(): Promise<InboundQueueEntry> {\n if (this.inboundQueue.length > 0) {\n return Promise.resolve(this.inboundQueue.shift()!);\n }\n return new Promise((resolve) => {\n this.waitingConsumers.push(resolve);\n });\n }\n\n private assertConnected(): void {\n if (!this.connected) {\n throw new ProtocolError({\n message: \"SshTransportConnection is not yet connected - call connect() first\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n }\n\n private startKeepalive(): void {\n const intervalMs = this.options.keepaliveIntervalMs;\n if (intervalMs === undefined || intervalMs <= 0) return;\n this.keepaliveTimer = setInterval(() => this.sendKeepalivePing(), intervalMs);\n // Don't keep the Node event loop alive solely for keepalives - when the\n // process is otherwise idle the consumer should be free to exit.\n this.keepaliveTimer.unref?.();\n }\n\n private stopKeepalive(): void {\n if (this.keepaliveTimer !== undefined) {\n clearInterval(this.keepaliveTimer);\n this.keepaliveTimer = undefined;\n }\n }\n\n private resetKeepaliveTimer(): void {\n if (this.keepaliveTimer === undefined) return;\n this.stopKeepalive();\n this.startKeepalive();\n }\n\n private sendKeepalivePing(): void {\n if (!this.connected || this.disposed || this.protector === undefined) return;\n try {\n // SSH_MSG_IGNORE: a benign packet the server discards, sufficient to keep\n // stateful intermediaries (NAT, firewalls) from idling out the TCP flow.\n // Body is a single empty SSH string per RFC 4253 §11.2.\n const payload = new SshDataWriter().writeByte(MSG_IGNORE).writeString(\"\", \"utf8\").toBuffer();\n this.socket!.write(this.protector.protectPayload(payload));\n } catch {\n // Best-effort: a write failure here will surface via the socket error\n // handler; keepalive should never throw to the caller.\n }\n }\n}\n\nfunction parseDisconnectPayload(payload: Buffer): ConnectionError {\n try {\n const reader = new SshDataReader(payload.subarray(1)); // skip message type byte\n const reasonCode = reader.readUint32();\n const description = reader.readString().toString(\"utf8\");\n return new ConnectionError({\n details: { reasonCode },\n message: `SSH_MSG_DISCONNECT: ${description.length > 0 ? description : \"connection closed by server\"} (code ${reasonCode})`,\n protocol: \"sftp\",\n retryable: false,\n });\n } catch {\n return new ConnectionError({\n message: \"SSH_MSG_DISCONNECT received from server\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n","import { Buffer } from \"node:buffer\";\nimport { ParseError } from \"../../../errors/ZeroTransferError\";\n\n/**\n * Stateful SSH primitive decoder that reads sequential values from a packet payload.\n */\nexport class SshDataReader {\n private offset = 0;\n\n constructor(private readonly source: Uint8Array) {}\n\n get remaining(): number {\n return this.source.length - this.offset;\n }\n\n hasMore(): boolean {\n return this.remaining > 0;\n }\n\n readByte(): number {\n this.ensureAvailable(1, \"byte\");\n const value = this.source[this.offset]!;\n this.offset += 1;\n return value;\n }\n\n readBoolean(): boolean {\n return this.readByte() !== 0;\n }\n\n readBytes(length: number): Buffer {\n this.ensureAvailable(length, \"bytes\");\n const data = this.source.subarray(this.offset, this.offset + length);\n this.offset += length;\n return Buffer.from(data);\n }\n\n readUint32(): number {\n this.ensureAvailable(4, \"uint32\");\n const buffer = Buffer.from(this.source);\n const value = buffer.readUInt32BE(this.offset);\n this.offset += 4;\n return value;\n }\n\n readUint64(): bigint {\n this.ensureAvailable(8, \"uint64\");\n const buffer = Buffer.from(this.source);\n const value = buffer.readBigUInt64BE(this.offset);\n this.offset += 8;\n return value;\n }\n\n readString(): Buffer {\n const length = this.readUint32();\n this.ensureAvailable(length, \"string\");\n const data = this.source.subarray(this.offset, this.offset + length);\n this.offset += length;\n return Buffer.from(data);\n }\n\n readUtf8String(): string {\n return this.readString().toString(\"utf8\");\n }\n\n readNameList(): string[] {\n const value = this.readString().toString(\"ascii\");\n\n if (value.length === 0) {\n return [];\n }\n\n return value.split(\",\").filter((item) => item.length > 0);\n }\n\n /**\n * Reads an SSH `mpint` value (RFC 4251 §5): a length-prefixed two's-complement\n * big-endian integer. Returns the raw magnitude bytes (non-negative integers\n * may have a leading 0x00 byte preserved by the caller as needed).\n */\n readMpint(): Buffer {\n return this.readString();\n }\n\n assertFinished(): void {\n if (this.remaining !== 0) {\n throw new ParseError({\n details: { remaining: this.remaining },\n message: \"Unexpected trailing SSH packet bytes\",\n retryable: false,\n });\n }\n }\n\n private ensureAvailable(bytes: number, type: string): void {\n if (this.remaining >= bytes) {\n return;\n }\n\n throw new ParseError({\n details: {\n available: this.remaining,\n needed: bytes,\n },\n message: `Unexpected end of SSH packet while reading ${type}`,\n retryable: false,\n });\n }\n}\n","import { Buffer } from \"node:buffer\";\nimport { ConfigurationError } from \"../../../errors/ZeroTransferError\";\n\nconst MAX_UINT32 = 0xffff_ffff;\nconst MAX_UINT64 = (1n << 64n) - 1n;\n\n/**\n * Minimal SSH primitive encoder for transport and authentication packets.\n */\nexport class SshDataWriter {\n private readonly chunks: Buffer[] = [];\n private length = 0;\n\n writeByte(value: number): this {\n this.assertByte(value, \"byte\");\n const chunk = Buffer.alloc(1);\n chunk.writeUInt8(value, 0);\n return this.push(chunk);\n }\n\n writeBoolean(value: boolean): this {\n return this.writeByte(value ? 1 : 0);\n }\n\n writeBytes(value: Uint8Array): this {\n return this.push(Buffer.from(value));\n }\n\n writeUint32(value: number): this {\n if (!Number.isInteger(value) || value < 0 || value > MAX_UINT32) {\n throw new ConfigurationError({\n details: { value },\n message: \"SSH uint32 values must be integers in the range 0..2^32-1\",\n retryable: false,\n });\n }\n\n const chunk = Buffer.alloc(4);\n chunk.writeUInt32BE(value, 0);\n return this.push(chunk);\n }\n\n writeUint64(value: bigint): this {\n if (value < 0n || value > MAX_UINT64) {\n throw new ConfigurationError({\n details: { value: value.toString() },\n message: \"SSH uint64 values must be in the range 0..2^64-1\",\n retryable: false,\n });\n }\n\n const chunk = Buffer.alloc(8);\n chunk.writeBigUInt64BE(value, 0);\n return this.push(chunk);\n }\n\n writeString(value: string | Uint8Array, encoding: BufferEncoding = \"utf8\"): this {\n const payload = typeof value === \"string\" ? Buffer.from(value, encoding) : Buffer.from(value);\n this.writeUint32(payload.length);\n return this.push(payload);\n }\n\n writeMpint(value: Uint8Array): this {\n const normalized = normalizePositiveMpint(value);\n this.writeUint32(normalized.length);\n return this.push(normalized);\n }\n\n writeNameList(values: readonly string[]): this {\n for (const name of values) {\n if (name.includes(\",\")) {\n throw new ConfigurationError({\n details: { name },\n message: \"SSH name-list entries cannot contain commas\",\n retryable: false,\n });\n }\n }\n\n return this.writeString(values.join(\",\"), \"ascii\");\n }\n\n toBuffer(): Buffer {\n return Buffer.concat(this.chunks, this.length);\n }\n\n private push(chunk: Buffer): this {\n this.chunks.push(chunk);\n this.length += chunk.length;\n return this;\n }\n\n private assertByte(value: number, label: string): void {\n if (!Number.isInteger(value) || value < 0 || value > 0xff) {\n throw new ConfigurationError({\n details: { value },\n message: `SSH ${label} values must be integers in the range 0..255`,\n retryable: false,\n });\n }\n }\n}\n\nfunction normalizePositiveMpint(value: Uint8Array): Buffer {\n const input = Buffer.from(value);\n\n let offset = 0;\n while (offset < input.length && input[offset] === 0x00) {\n offset += 1;\n }\n\n if (offset >= input.length) {\n return Buffer.alloc(0);\n }\n\n const stripped = input.subarray(offset);\n if ((stripped[0]! & 0x80) === 0x80) {\n return Buffer.concat([Buffer.from([0x00]), stripped]);\n }\n\n return stripped;\n}\n","import { Buffer } from \"node:buffer\";\nimport { ParseError, ProtocolError } from \"../../../errors/ZeroTransferError\";\nimport type { NegotiatedSshAlgorithms, SshAlgorithmPreferences } from \"./SshAlgorithmNegotiation\";\nimport {\n DEFAULT_SSH_ALGORITHM_PREFERENCES,\n negotiateSshAlgorithms,\n} from \"./SshAlgorithmNegotiation\";\nimport {\n buildSshIdentificationLine,\n parseSshIdentificationLine,\n type SshIdentification,\n} from \"./SshIdentification\";\nimport {\n decodeSshKexInitMessage,\n encodeSshKexInitMessage,\n type SshKexInitMessage,\n} from \"./SshKexInit\";\nimport {\n createCurve25519Ephemeral,\n decodeSshKexEcdhReplyMessage,\n encodeSshKexEcdhInitMessage,\n} from \"./SshKexCurve25519\";\nimport { deriveSshSessionKeys, type SshDerivedSessionKeys } from \"./SshKeyDerivation\";\nimport { decodeSshNewKeysMessage, encodeSshNewKeysMessage } from \"./SshNewKeys\";\nimport { SshTransportPacketFramer, encodeSshTransportPacket } from \"./SshTransportPacket\";\nimport { verifySshHostKeySignature } from \"./SshHostKeyVerification\";\n\n/** Initial client-side handshake state before key exchange math starts. */\nexport interface SshTransportHandshakeResult {\n keyExchange: {\n algorithm: string;\n clientKexInitPayload: Buffer;\n clientPublicKey: Buffer;\n exchangeHash: Buffer;\n serverHostKey: Buffer;\n serverKexInitPayload: Buffer;\n serverPublicKey: Buffer;\n serverSignature: Buffer;\n sessionId: Buffer;\n sharedSecret: Buffer;\n transportKeys: {\n clientToServer: SshDerivedSessionKeys[\"clientToServer\"];\n serverToClient: SshDerivedSessionKeys[\"serverToClient\"];\n };\n };\n negotiatedAlgorithms: NegotiatedSshAlgorithms;\n serverIdentification: SshIdentification;\n serverKexInit: SshKexInitMessage;\n /**\n * Number of unencrypted packets the client sent during the handshake (KEXINIT,\n * KEX_ECDH_INIT, NEWKEYS). Per RFC 4253 §6.4, packet sequence numbers are never\n * reset across NEWKEYS, so this value seeds the outbound protector.\n */\n outboundPacketCount: number;\n /**\n * Number of unencrypted packets the client received from the server during the\n * handshake (server KEXINIT, KEX_ECDH_REPLY, NEWKEYS). Seeds the inbound unprotector.\n */\n inboundPacketCount: number;\n}\n\ntype HandshakePhase =\n | \"awaiting-server-identification\"\n | \"awaiting-server-kexinit\"\n | \"awaiting-server-kexreply\"\n | \"awaiting-server-newkeys\"\n | \"complete\";\n\n/**\n * Client-side SSH handshake coordinator for version exchange and KEXINIT negotiation.\n */\nexport class SshTransportHandshake {\n private readonly clientAlgorithms: SshAlgorithmPreferences;\n private readonly clientIdentificationLine: string;\n private readonly clientKexInitPayload: Buffer;\n private readonly identificationLines: string[] = [];\n private readonly packetFramer = new SshTransportPacketFramer();\n private readonly pendingIdentification = new SshIdentificationAccumulator();\n private phase: HandshakePhase = \"awaiting-server-identification\";\n private inboundPacketCount = 0;\n private outboundPacketCount = 0;\n private pendingCurve25519:\n | {\n deriveSharedSecret: (serverPublicKey: Uint8Array) => Buffer;\n publicKey: Buffer;\n }\n | undefined;\n private pendingKeyExchange:\n | {\n clientIdentification: string;\n algorithm: string;\n clientKexInitPayload: Buffer;\n clientPublicKey: Buffer;\n serverHostKey: Buffer;\n serverIdentification: string;\n serverKexInitPayload: Buffer;\n serverPublicKey: Buffer;\n serverSignature: Buffer;\n sharedSecret: Buffer;\n negotiatedAlgorithms: NegotiatedSshAlgorithms;\n }\n | undefined;\n private serverIdentification: SshIdentification | undefined;\n\n constructor(\n private readonly options: {\n algorithms?: SshAlgorithmPreferences;\n clientComments?: string;\n clientSoftwareVersion?: string;\n kexCookie?: Uint8Array;\n /**\n * Verifies the server's host key after the signature check passes.\n * Receives the SSH wire-format host key blob and its SHA-256 digest.\n * Throwing rejects the handshake; resolving accepts it.\n *\n * If omitted, the host key is accepted as long as its signature over the\n * exchange hash verifies. Callers SHOULD supply this hook in production\n * to enforce known_hosts or pinned-fingerprint policies.\n */\n verifyHostKey?: (input: {\n hostKeyBlob: Buffer;\n hostKeySha256: Buffer;\n algorithmName: string;\n }) => void | Promise<void>;\n } = {},\n ) {\n this.clientAlgorithms = options.algorithms ?? DEFAULT_SSH_ALGORITHM_PREFERENCES;\n this.clientIdentificationLine = buildSshIdentificationLine({\n ...(options.clientComments === undefined ? {} : { comments: options.clientComments }),\n softwareVersion: options.clientSoftwareVersion ?? \"ZeroTransfer_Dev\",\n });\n this.clientKexInitPayload = encodeSshKexInitMessage({\n algorithms: this.clientAlgorithms,\n ...(options.kexCookie === undefined ? {} : { cookie: options.kexCookie }),\n });\n }\n\n /** Creates the first outbound bytes (client identification line). */\n createInitialClientBytes(): Buffer {\n return Buffer.from(`${this.clientIdentificationLine}\\r\\n`, \"ascii\");\n }\n\n /**\n * Feeds raw server bytes into the handshake state machine.\n */\n pushServerBytes(chunk: Uint8Array): {\n outbound: Buffer[];\n result?: SshTransportHandshakeResult;\n } {\n const outbound: Buffer[] = [];\n\n if (this.phase === \"awaiting-server-identification\") {\n const scan = this.pendingIdentification.push(chunk);\n for (const banner of scan.bannerLines) {\n this.identificationLines.push(banner);\n }\n\n if (scan.identLine !== undefined) {\n this.serverIdentification = parseSshIdentificationLine(scan.identLine);\n this.phase = \"awaiting-server-kexinit\";\n outbound.push(encodeSshTransportPacket(this.clientKexInitPayload));\n this.outboundPacketCount += 1;\n\n if (scan.remainder.length > 0) {\n return this.pushServerBytesWithPhase(outbound, scan.remainder);\n }\n }\n\n return { outbound };\n }\n\n return this.pushServerBytesWithPhase(outbound, Buffer.from(chunk));\n }\n\n getServerBannerLines(): readonly string[] {\n return this.identificationLines;\n }\n\n isComplete(): boolean {\n return this.phase === \"complete\";\n }\n\n /**\n * Returns any bytes received after the last complete handshake packet and clears the buffer.\n * Call this once after `pushServerBytes` returns a result to drain bytes that belong to the\n * post-NEWKEYS encrypted phase but arrived in the same TCP segment as NEWKEYS.\n */\n takeRemainingBytes(): Buffer {\n return this.packetFramer.takeRemainingBytes();\n }\n\n private pushServerBytesWithPhase(\n outbound: Buffer[],\n chunk: Uint8Array,\n ): {\n outbound: Buffer[];\n result?: SshTransportHandshakeResult;\n } {\n if (this.phase === \"awaiting-server-identification\") {\n return { outbound };\n }\n\n for (const packet of this.packetFramer.push(chunk)) {\n const messageType = packet.payload[0];\n this.inboundPacketCount += 1;\n\n if (this.phase === \"awaiting-server-kexinit\") {\n if (messageType !== 20) {\n throw new ProtocolError({\n details: { messageType },\n message: \"Expected SSH_MSG_KEXINIT from server during initial handshake\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const serverKexInit = decodeSshKexInitMessage(packet.payload);\n const negotiatedAlgorithms = negotiateSshAlgorithms(this.clientAlgorithms, serverKexInit);\n\n if (\n negotiatedAlgorithms.kexAlgorithm !== \"curve25519-sha256\" &&\n negotiatedAlgorithms.kexAlgorithm !== \"curve25519-sha256@libssh.org\"\n ) {\n throw new ProtocolError({\n details: { kexAlgorithm: negotiatedAlgorithms.kexAlgorithm },\n message: \"Native SSH transport currently supports only Curve25519 key exchange\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n this.pendingCurve25519 = createCurve25519Ephemeral();\n this.phase = \"awaiting-server-kexreply\";\n outbound.push(\n encodeSshTransportPacket(encodeSshKexEcdhInitMessage(this.pendingCurve25519.publicKey)),\n );\n this.outboundPacketCount += 1;\n\n // Preserve KEXINIT artifacts required for exchange hash in the next wave.\n this.pendingKeyExchange = {\n clientIdentification: this.clientIdentificationLine,\n algorithm: negotiatedAlgorithms.kexAlgorithm,\n clientKexInitPayload: this.clientKexInitPayload,\n clientPublicKey: this.pendingCurve25519.publicKey,\n negotiatedAlgorithms,\n serverHostKey: Buffer.alloc(0),\n serverIdentification: (this.serverIdentification ?? missingServerIdentificationError())\n .raw,\n serverKexInitPayload: Buffer.from(packet.payload),\n serverPublicKey: Buffer.alloc(0),\n serverSignature: Buffer.alloc(0),\n sharedSecret: Buffer.alloc(0),\n };\n\n continue;\n }\n\n if (this.phase === \"awaiting-server-kexreply\") {\n if (messageType !== 31) {\n throw new ProtocolError({\n details: { messageType },\n message: \"Expected SSH_MSG_KEX_ECDH_REPLY from server\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n if (this.pendingCurve25519 === undefined || this.pendingKeyExchange === undefined) {\n throw new ProtocolError({\n message:\n \"Curve25519 client key state missing while processing server key exchange reply\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const reply = decodeSshKexEcdhReplyMessage(packet.payload);\n const sharedSecret = this.pendingCurve25519.deriveSharedSecret(reply.serverPublicKey);\n\n this.pendingKeyExchange = {\n ...this.pendingKeyExchange,\n serverHostKey: reply.hostKey,\n serverPublicKey: reply.serverPublicKey,\n serverSignature: reply.signature,\n sharedSecret,\n };\n\n this.phase = \"awaiting-server-newkeys\";\n outbound.push(encodeSshTransportPacket(encodeSshNewKeysMessage()));\n this.outboundPacketCount += 1;\n continue;\n }\n\n if (this.phase === \"awaiting-server-newkeys\") {\n decodeSshNewKeysMessage(packet.payload);\n\n const keyExchange = this.pendingKeyExchange ?? missingPendingKeyExchangeError();\n const derivedKeys = deriveSshSessionKeys({\n clientIdentification: keyExchange.clientIdentification,\n clientKexInitPayload: keyExchange.clientKexInitPayload,\n clientPublicKey: keyExchange.clientPublicKey,\n kexAlgorithm: keyExchange.algorithm,\n negotiatedAlgorithms: keyExchange.negotiatedAlgorithms,\n serverHostKey: keyExchange.serverHostKey,\n serverIdentification: keyExchange.serverIdentification,\n serverKexInitPayload: keyExchange.serverKexInitPayload,\n serverPublicKey: keyExchange.serverPublicKey,\n sharedSecret: keyExchange.sharedSecret,\n });\n\n // RFC 4253 §8: the client MUST verify the host key signature over the\n // exchange hash before transitioning to the encrypted phase. Without\n // this check the entire transport is open to a man-in-the-middle.\n const hostKeyVerification = verifySshHostKeySignature({\n exchangeHash: derivedKeys.exchangeHash,\n hostKeyBlob: keyExchange.serverHostKey,\n signatureBlob: keyExchange.serverSignature,\n });\n\n // Optional caller-supplied policy gate (known_hosts, pinned fingerprint, …).\n const verifyHook = this.options.verifyHostKey;\n if (verifyHook !== undefined) {\n // The hook may throw to reject; we surface that as a ProtocolError below.\n // Promise-returning hooks are not awaited inside this synchronous\n // state machine - callers requiring async policy must perform it\n // before initiating connect().\n const maybe = verifyHook({\n algorithmName: hostKeyVerification.algorithmName,\n hostKeyBlob: keyExchange.serverHostKey,\n hostKeySha256: hostKeyVerification.hostKeySha256,\n });\n if (maybe instanceof Promise) {\n throw new ProtocolError({\n message:\n \"verifyHostKey must be synchronous; perform any async lookups before calling connect()\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n }\n\n const serverKexInit = decodeSshKexInitMessage(keyExchange.serverKexInitPayload);\n const result: SshTransportHandshakeResult = {\n keyExchange: {\n algorithm: keyExchange.algorithm,\n clientKexInitPayload: keyExchange.clientKexInitPayload,\n clientPublicKey: keyExchange.clientPublicKey,\n exchangeHash: derivedKeys.exchangeHash,\n serverHostKey: keyExchange.serverHostKey,\n serverKexInitPayload: keyExchange.serverKexInitPayload,\n serverPublicKey: keyExchange.serverPublicKey,\n serverSignature: keyExchange.serverSignature,\n sessionId: derivedKeys.sessionId,\n sharedSecret: keyExchange.sharedSecret,\n transportKeys: {\n clientToServer: derivedKeys.clientToServer,\n serverToClient: derivedKeys.serverToClient,\n },\n },\n negotiatedAlgorithms: keyExchange.negotiatedAlgorithms,\n serverIdentification: this.serverIdentification ?? missingServerIdentificationError(),\n serverKexInit,\n inboundPacketCount: this.inboundPacketCount,\n outboundPacketCount: this.outboundPacketCount,\n };\n\n this.phase = \"complete\";\n this.pendingCurve25519 = undefined;\n this.pendingKeyExchange = undefined;\n return { outbound, result };\n }\n\n throw new ProtocolError({\n details: { phase: this.phase },\n message: \"SSH transport handshake received unexpected packets after completion\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n return { outbound };\n }\n}\n\nclass SshIdentificationAccumulator {\n private pending = Buffer.alloc(0);\n\n push(chunk: Uint8Array): { bannerLines: string[]; identLine?: string; remainder: Buffer } {\n this.pending = Buffer.concat([this.pending, Buffer.from(chunk)]);\n const bannerLines: string[] = [];\n\n while (true) {\n const lfIndex = this.pending.indexOf(0x0a);\n if (lfIndex < 0) break;\n\n // Capture the line as text (safe: identification exchange is ASCII-only).\n const lineText = trimLineEndings(this.pending.subarray(0, lfIndex + 1).toString(\"ascii\"));\n\n // Capture everything AFTER the \\n as raw binary before any string conversion.\n const remainder = Buffer.from(this.pending.subarray(lfIndex + 1));\n this.pending = remainder;\n\n if (lineText.startsWith(\"SSH-\")) {\n // Found the identification line. Everything in pending is binary packet data.\n this.pending = Buffer.alloc(0);\n return { bannerLines, identLine: lineText, remainder };\n }\n\n bannerLines.push(lineText);\n }\n\n return { bannerLines, remainder: Buffer.alloc(0) };\n }\n}\n\nfunction trimLineEndings(value: string): string {\n if (value.endsWith(\"\\r\\n\")) {\n return value.slice(0, -2);\n }\n\n if (value.endsWith(\"\\n\")) {\n return value.slice(0, -1);\n }\n\n return value;\n}\n\nfunction missingServerIdentificationError(): never {\n throw new ParseError({\n message: \"Missing server SSH identification while negotiating KEXINIT\",\n protocol: \"sftp\",\n retryable: false,\n });\n}\n\nfunction missingPendingKeyExchangeError(): never {\n throw new ProtocolError({\n message: \"SSH transport key exchange state was not initialized\",\n protocol: \"sftp\",\n retryable: false,\n });\n}\n","import { UnsupportedFeatureError } from \"../../../errors/ZeroTransferError\";\n\n/** Algorithm lists exchanged during SSH KEXINIT negotiation. */\nexport interface SshAlgorithmPreferences {\n compressionClientToServer: readonly string[];\n compressionServerToClient: readonly string[];\n encryptionClientToServer: readonly string[];\n encryptionServerToClient: readonly string[];\n kexAlgorithms: readonly string[];\n languagesClientToServer: readonly string[];\n languagesServerToClient: readonly string[];\n macClientToServer: readonly string[];\n macServerToClient: readonly string[];\n serverHostKeyAlgorithms: readonly string[];\n}\n\n/** Selected algorithms after intersecting client preferences with server capabilities. */\nexport interface NegotiatedSshAlgorithms {\n compressionClientToServer: string;\n compressionServerToClient: string;\n encryptionClientToServer: string;\n encryptionServerToClient: string;\n kexAlgorithm: string;\n languageClientToServer?: string;\n languageServerToClient?: string;\n macClientToServer: string;\n macServerToClient: string;\n serverHostKeyAlgorithm: string;\n}\n\n/**\n * Baseline algorithm order for the initial native SSH transport implementation.\n */\nexport const DEFAULT_SSH_ALGORITHM_PREFERENCES: Readonly<SshAlgorithmPreferences> = {\n compressionClientToServer: [\"none\"],\n compressionServerToClient: [\"none\"],\n encryptionClientToServer: [\n \"chacha20-poly1305@openssh.com\",\n \"aes256-gcm@openssh.com\",\n \"aes128-gcm@openssh.com\",\n \"aes256-ctr\",\n \"aes128-ctr\",\n ],\n encryptionServerToClient: [\n \"chacha20-poly1305@openssh.com\",\n \"aes256-gcm@openssh.com\",\n \"aes128-gcm@openssh.com\",\n \"aes256-ctr\",\n \"aes128-ctr\",\n ],\n kexAlgorithms: [\"curve25519-sha256\", \"curve25519-sha256@libssh.org\"],\n languagesClientToServer: [],\n languagesServerToClient: [],\n macClientToServer: [\"hmac-sha2-512\", \"hmac-sha2-256\"],\n macServerToClient: [\"hmac-sha2-512\", \"hmac-sha2-256\"],\n serverHostKeyAlgorithms: [\n \"ssh-ed25519\",\n \"ecdsa-sha2-nistp256\",\n \"ecdsa-sha2-nistp384\",\n \"ecdsa-sha2-nistp521\",\n \"rsa-sha2-512\",\n \"rsa-sha2-256\",\n ],\n};\n\n/**\n * Intersects client and server algorithm lists using SSH's client-priority selection model.\n */\nexport function negotiateSshAlgorithms(\n client: SshAlgorithmPreferences,\n server: SshAlgorithmPreferences,\n): NegotiatedSshAlgorithms {\n const languageClientToServer = chooseLanguage(\n \"languages client->server\",\n client.languagesClientToServer,\n server.languagesClientToServer,\n );\n const languageServerToClient = chooseLanguage(\n \"languages server->client\",\n client.languagesServerToClient,\n server.languagesServerToClient,\n );\n\n return {\n compressionClientToServer: chooseRequired(\n \"compression client->server\",\n client.compressionClientToServer,\n server.compressionClientToServer,\n ),\n compressionServerToClient: chooseRequired(\n \"compression server->client\",\n client.compressionServerToClient,\n server.compressionServerToClient,\n ),\n encryptionClientToServer: chooseRequired(\n \"encryption client->server\",\n client.encryptionClientToServer,\n server.encryptionClientToServer,\n ),\n encryptionServerToClient: chooseRequired(\n \"encryption server->client\",\n client.encryptionServerToClient,\n server.encryptionServerToClient,\n ),\n kexAlgorithm: chooseRequired(\"kex\", client.kexAlgorithms, server.kexAlgorithms),\n ...(languageClientToServer === undefined ? {} : { languageClientToServer }),\n ...(languageServerToClient === undefined ? {} : { languageServerToClient }),\n macClientToServer: chooseRequired(\n \"mac client->server\",\n client.macClientToServer,\n server.macClientToServer,\n ),\n macServerToClient: chooseRequired(\n \"mac server->client\",\n client.macServerToClient,\n server.macServerToClient,\n ),\n serverHostKeyAlgorithm: chooseRequired(\n \"server host key\",\n client.serverHostKeyAlgorithms,\n server.serverHostKeyAlgorithms,\n ),\n };\n}\n\nfunction chooseRequired(\n label: string,\n preferred: readonly string[],\n supported: readonly string[],\n): string {\n const selected = preferred.find((candidate) => supported.includes(candidate));\n\n if (selected !== undefined) {\n return selected;\n }\n\n throw new UnsupportedFeatureError({\n details: {\n preferred,\n supported,\n },\n message: `Unable to negotiate SSH ${label} algorithm`,\n protocol: \"sftp\",\n retryable: false,\n });\n}\n\nfunction chooseLanguage(\n label: string,\n preferred: readonly string[],\n supported: readonly string[],\n): string | undefined {\n if (preferred.length === 0 || supported.length === 0) {\n return undefined;\n }\n\n return chooseRequired(label, preferred, supported);\n}\n","import { ParseError } from \"../../../errors/ZeroTransferError\";\n\nconst SSH_IDENT_PREFIX = \"SSH-\";\nconst SSH_PROTOCOL_VERSION = \"2.0\";\n\n/** Parsed SSH identification components from the RFC 4253 banner line. */\nexport interface SshIdentification {\n protocolVersion: string;\n softwareVersion: string;\n comments?: string;\n raw: string;\n}\n\n/**\n * Builds an SSH identification line without CRLF terminators.\n */\nexport function buildSshIdentificationLine(options: {\n softwareVersion: string;\n comments?: string;\n protocolVersion?: string;\n}): string {\n const protocolVersion = options.protocolVersion ?? SSH_PROTOCOL_VERSION;\n\n if (protocolVersion.trim().length === 0 || options.softwareVersion.trim().length === 0) {\n throw new ParseError({\n message: \"SSH identification protocol and software versions must be non-empty\",\n retryable: false,\n });\n }\n\n const base = `${SSH_IDENT_PREFIX}${protocolVersion}-${options.softwareVersion}`;\n if (options.comments === undefined || options.comments.length === 0) {\n return base;\n }\n\n return `${base} ${options.comments}`;\n}\n\n/**\n * Parses a single SSH identification line without the trailing CRLF.\n */\nexport function parseSshIdentificationLine(line: string): SshIdentification {\n if (!line.startsWith(SSH_IDENT_PREFIX)) {\n throw new ParseError({\n details: { line },\n message: \"SSH identification line must start with 'SSH-'\",\n retryable: false,\n });\n }\n\n const firstSpace = line.indexOf(\" \");\n const header = firstSpace === -1 ? line : line.slice(0, firstSpace);\n const comments = firstSpace === -1 ? undefined : line.slice(firstSpace + 1);\n const headerParts = header.split(\"-\");\n\n if (headerParts.length < 3) {\n throw new ParseError({\n details: { line },\n message: \"SSH identification line is malformed\",\n retryable: false,\n });\n }\n\n const protocolVersion = headerParts[1] ?? \"\";\n const softwareVersion = headerParts.slice(2).join(\"-\");\n\n if (protocolVersion.length === 0 || softwareVersion.length === 0) {\n throw new ParseError({\n details: { line },\n message: \"SSH identification line must include protocol and software versions\",\n retryable: false,\n });\n }\n\n return {\n protocolVersion,\n softwareVersion,\n raw: line,\n ...(comments === undefined || comments.length === 0 ? {} : { comments }),\n };\n}\n","import { Buffer } from \"node:buffer\";\nimport { randomBytes } from \"node:crypto\";\nimport { ConfigurationError, ParseError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader, SshDataWriter } from \"../binary\";\nimport type { SshAlgorithmPreferences } from \"./SshAlgorithmNegotiation\";\n\nconst SSH_MSG_KEXINIT = 20;\nconst KEXINIT_COOKIE_LENGTH = 16;\n\n/** Parsed SSH_MSG_KEXINIT payload. */\nexport interface SshKexInitMessage extends SshAlgorithmPreferences {\n cookie: Buffer;\n firstKexPacketFollows: boolean;\n messageType: number;\n reserved: number;\n}\n\n/**\n * Encodes SSH_MSG_KEXINIT payload bytes (starting with message number 20).\n */\nexport function encodeSshKexInitMessage(options: {\n algorithms: SshAlgorithmPreferences;\n cookie?: Uint8Array;\n firstKexPacketFollows?: boolean;\n}): Buffer {\n const cookie =\n options.cookie === undefined ? randomBytes(KEXINIT_COOKIE_LENGTH) : Buffer.from(options.cookie);\n\n if (cookie.length !== KEXINIT_COOKIE_LENGTH) {\n throw new ConfigurationError({\n details: { actualLength: cookie.length, expectedLength: KEXINIT_COOKIE_LENGTH },\n message: \"SSH KEXINIT cookie must be 16 bytes\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const writer = new SshDataWriter();\n writer.writeByte(SSH_MSG_KEXINIT);\n writer.writeBytes(cookie);\n writer.writeNameList(options.algorithms.kexAlgorithms);\n writer.writeNameList(options.algorithms.serverHostKeyAlgorithms);\n writer.writeNameList(options.algorithms.encryptionClientToServer);\n writer.writeNameList(options.algorithms.encryptionServerToClient);\n writer.writeNameList(options.algorithms.macClientToServer);\n writer.writeNameList(options.algorithms.macServerToClient);\n writer.writeNameList(options.algorithms.compressionClientToServer);\n writer.writeNameList(options.algorithms.compressionServerToClient);\n writer.writeNameList(options.algorithms.languagesClientToServer);\n writer.writeNameList(options.algorithms.languagesServerToClient);\n writer.writeBoolean(options.firstKexPacketFollows ?? false);\n writer.writeUint32(0);\n return writer.toBuffer();\n}\n\n/**\n * Decodes SSH_MSG_KEXINIT payload bytes into algorithm lists and flags.\n */\nexport function decodeSshKexInitMessage(payload: Uint8Array): SshKexInitMessage {\n const reader = new SshDataReader(payload);\n const messageType = reader.readByte();\n\n if (messageType !== SSH_MSG_KEXINIT) {\n throw new ParseError({\n details: { messageType },\n message: \"Expected SSH_MSG_KEXINIT payload\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const cookie = reader.readBytes(KEXINIT_COOKIE_LENGTH);\n const kexAlgorithms = reader.readNameList();\n const serverHostKeyAlgorithms = reader.readNameList();\n const encryptionClientToServer = reader.readNameList();\n const encryptionServerToClient = reader.readNameList();\n const macClientToServer = reader.readNameList();\n const macServerToClient = reader.readNameList();\n const compressionClientToServer = reader.readNameList();\n const compressionServerToClient = reader.readNameList();\n const languagesClientToServer = reader.readNameList();\n const languagesServerToClient = reader.readNameList();\n const firstKexPacketFollows = reader.readBoolean();\n const reserved = reader.readUint32();\n\n reader.assertFinished();\n\n return {\n compressionClientToServer,\n compressionServerToClient,\n cookie,\n encryptionClientToServer,\n encryptionServerToClient,\n firstKexPacketFollows,\n kexAlgorithms,\n languagesClientToServer,\n languagesServerToClient,\n macClientToServer,\n macServerToClient,\n messageType,\n reserved,\n serverHostKeyAlgorithms,\n };\n}\n","import { Buffer } from \"node:buffer\";\nimport { createPublicKey, diffieHellman, generateKeyPairSync, type KeyObject } from \"node:crypto\";\nimport { ConfigurationError, ParseError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader, SshDataWriter } from \"../binary\";\n\nconst SSH_MSG_KEX_ECDH_INIT = 30;\nconst SSH_MSG_KEX_ECDH_REPLY = 31;\nconst X25519_PUBLIC_KEY_LENGTH = 32;\n\n// DER SubjectPublicKeyInfo prefix for X25519 public keys (RFC 8410).\nconst X25519_SPKI_PREFIX = Buffer.from(\"302a300506032b656e032100\", \"hex\");\n\n/** Parsed SSH_MSG_KEX_ECDH_INIT payload. */\nexport interface SshKexEcdhInitMessage {\n clientPublicKey: Buffer;\n messageType: number;\n}\n\n/** Parsed SSH_MSG_KEX_ECDH_REPLY payload. */\nexport interface SshKexEcdhReplyMessage {\n hostKey: Buffer;\n messageType: number;\n serverPublicKey: Buffer;\n signature: Buffer;\n}\n\n/**\n * Generates a client Curve25519 ephemeral keypair with SSH wire-format helpers.\n */\nexport function createCurve25519Ephemeral(): {\n deriveSharedSecret: (serverPublicKey: Uint8Array) => Buffer;\n publicKey: Buffer;\n} {\n const { privateKey, publicKey } = generateKeyPairSync(\"x25519\");\n const encodedPublicKey = exportX25519PublicKeyRaw(publicKey);\n\n return {\n deriveSharedSecret: (serverPublicKey) => {\n const peer = importX25519PublicKeyRaw(serverPublicKey);\n return diffieHellman({ privateKey, publicKey: peer });\n },\n publicKey: encodedPublicKey,\n };\n}\n\n/**\n * Encodes SSH_MSG_KEX_ECDH_INIT payload bytes.\n */\nexport function encodeSshKexEcdhInitMessage(publicKey: Uint8Array): Buffer {\n const normalized = normalizeX25519PublicKey(publicKey, \"client\");\n return new SshDataWriter().writeByte(SSH_MSG_KEX_ECDH_INIT).writeString(normalized).toBuffer();\n}\n\n/**\n * Decodes SSH_MSG_KEX_ECDH_INIT payload bytes.\n */\nexport function decodeSshKexEcdhInitMessage(payload: Uint8Array): SshKexEcdhInitMessage {\n const reader = new SshDataReader(payload);\n const messageType = reader.readByte();\n\n if (messageType !== SSH_MSG_KEX_ECDH_INIT) {\n throw new ParseError({\n details: { messageType },\n message: \"Expected SSH_MSG_KEX_ECDH_INIT payload\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const clientPublicKey = normalizeX25519PublicKey(reader.readString(), \"client\");\n reader.assertFinished();\n return { clientPublicKey, messageType };\n}\n\n/**\n * Encodes SSH_MSG_KEX_ECDH_REPLY payload bytes.\n */\nexport function encodeSshKexEcdhReplyMessage(input: {\n hostKey: Uint8Array;\n serverPublicKey: Uint8Array;\n signature: Uint8Array;\n}): Buffer {\n const serverPublicKey = normalizeX25519PublicKey(input.serverPublicKey, \"server\");\n\n return new SshDataWriter()\n .writeByte(SSH_MSG_KEX_ECDH_REPLY)\n .writeString(input.hostKey)\n .writeString(serverPublicKey)\n .writeString(input.signature)\n .toBuffer();\n}\n\n/**\n * Decodes SSH_MSG_KEX_ECDH_REPLY payload bytes.\n */\nexport function decodeSshKexEcdhReplyMessage(payload: Uint8Array): SshKexEcdhReplyMessage {\n const reader = new SshDataReader(payload);\n const messageType = reader.readByte();\n\n if (messageType !== SSH_MSG_KEX_ECDH_REPLY) {\n throw new ParseError({\n details: { messageType },\n message: \"Expected SSH_MSG_KEX_ECDH_REPLY payload\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const hostKey = reader.readString();\n const serverPublicKey = normalizeX25519PublicKey(reader.readString(), \"server\");\n const signature = reader.readString();\n reader.assertFinished();\n\n return {\n hostKey,\n messageType,\n serverPublicKey,\n signature,\n };\n}\n\nfunction exportX25519PublicKeyRaw(publicKey: KeyObject): Buffer {\n const der = publicKey.export({ format: \"der\", type: \"spki\" });\n const raw = der.subarray(der.length - X25519_PUBLIC_KEY_LENGTH);\n return normalizeX25519PublicKey(raw, \"client\");\n}\n\nfunction importX25519PublicKeyRaw(raw: Uint8Array): KeyObject {\n const normalized = normalizeX25519PublicKey(raw, \"server\");\n const der = Buffer.concat([X25519_SPKI_PREFIX, normalized]);\n return createPublicKey({\n format: \"der\",\n key: der,\n type: \"spki\",\n });\n}\n\nfunction normalizeX25519PublicKey(value: Uint8Array, label: \"client\" | \"server\"): Buffer {\n const key = Buffer.from(value);\n if (key.length !== X25519_PUBLIC_KEY_LENGTH) {\n throw new ConfigurationError({\n details: { keyLength: key.length, label },\n message: `SSH ${label} Curve25519 public key must be 32 bytes`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n return key;\n}\n","import { Buffer } from \"node:buffer\";\nimport { createHash } from \"node:crypto\";\nimport { ProtocolError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataWriter } from \"../binary\";\nimport type { NegotiatedSshAlgorithms } from \"./SshAlgorithmNegotiation\";\n\n/** Directional key material used after SSH NEWKEYS. */\nexport interface SshTransportDirectionKeys {\n encryptionKey: Buffer;\n iv: Buffer;\n macKey: Buffer;\n}\n\n/** Session key bundle derived from K, H, and session id. */\nexport interface SshDerivedSessionKeys {\n clientToServer: SshTransportDirectionKeys;\n exchangeHash: Buffer;\n serverToClient: SshTransportDirectionKeys;\n sessionId: Buffer;\n}\n\n/** Input transcript used to compute SSH exchange hash for curve25519 KEX. */\nexport interface SshExchangeHashInput {\n clientIdentification: string;\n clientKexInitPayload: Uint8Array;\n clientPublicKey: Uint8Array;\n kexAlgorithm: string;\n negotiatedAlgorithms: NegotiatedSshAlgorithms;\n serverHostKey: Uint8Array;\n serverIdentification: string;\n serverKexInitPayload: Uint8Array;\n serverPublicKey: Uint8Array;\n sharedSecret: Uint8Array;\n}\n\n/**\n * Computes exchange hash and derives initial transport key material for the negotiated algorithms.\n */\nexport function deriveSshSessionKeys(input: SshExchangeHashInput): SshDerivedSessionKeys {\n const hashAlgorithm = resolveKexHashAlgorithm(input.kexAlgorithm);\n const exchangeHash = computeCurve25519ExchangeHash(input, hashAlgorithm);\n const sessionId = exchangeHash;\n\n const c2sEncryptionLength = resolveEncryptionKeyLength(\n input.negotiatedAlgorithms.encryptionClientToServer,\n );\n const s2cEncryptionLength = resolveEncryptionKeyLength(\n input.negotiatedAlgorithms.encryptionServerToClient,\n );\n const c2sIvLength = resolveIvLength(input.negotiatedAlgorithms.encryptionClientToServer);\n const s2cIvLength = resolveIvLength(input.negotiatedAlgorithms.encryptionServerToClient);\n const c2sMacLength = resolveMacKeyLength(\n input.negotiatedAlgorithms.encryptionClientToServer,\n input.negotiatedAlgorithms.macClientToServer,\n );\n const s2cMacLength = resolveMacKeyLength(\n input.negotiatedAlgorithms.encryptionServerToClient,\n input.negotiatedAlgorithms.macServerToClient,\n );\n\n const sharedSecret = Buffer.from(input.sharedSecret);\n\n return {\n clientToServer: {\n encryptionKey: deriveMaterial(\n sharedSecret,\n exchangeHash,\n sessionId,\n \"C\",\n c2sEncryptionLength,\n hashAlgorithm,\n ),\n iv: deriveMaterial(sharedSecret, exchangeHash, sessionId, \"A\", c2sIvLength, hashAlgorithm),\n macKey: deriveMaterial(\n sharedSecret,\n exchangeHash,\n sessionId,\n \"E\",\n c2sMacLength,\n hashAlgorithm,\n ),\n },\n exchangeHash,\n serverToClient: {\n encryptionKey: deriveMaterial(\n sharedSecret,\n exchangeHash,\n sessionId,\n \"D\",\n s2cEncryptionLength,\n hashAlgorithm,\n ),\n iv: deriveMaterial(sharedSecret, exchangeHash, sessionId, \"B\", s2cIvLength, hashAlgorithm),\n macKey: deriveMaterial(\n sharedSecret,\n exchangeHash,\n sessionId,\n \"F\",\n s2cMacLength,\n hashAlgorithm,\n ),\n },\n sessionId,\n };\n}\n\nfunction computeCurve25519ExchangeHash(\n input: SshExchangeHashInput,\n hashAlgorithm: \"sha256\",\n): Buffer {\n const transcript = new SshDataWriter()\n .writeString(input.clientIdentification, \"ascii\")\n .writeString(input.serverIdentification, \"ascii\")\n .writeString(input.clientKexInitPayload)\n .writeString(input.serverKexInitPayload)\n .writeString(input.serverHostKey)\n .writeString(input.clientPublicKey)\n .writeString(input.serverPublicKey)\n .writeMpint(input.sharedSecret)\n .toBuffer();\n\n return createHash(hashAlgorithm).update(transcript).digest();\n}\n\nfunction deriveMaterial(\n sharedSecret: Buffer,\n exchangeHash: Buffer,\n sessionId: Buffer,\n letter: string,\n length: number,\n hashAlgorithm: \"sha256\",\n): Buffer {\n if (length <= 0) {\n return Buffer.alloc(0);\n }\n\n const result: Buffer[] = [];\n\n const first = createHash(hashAlgorithm)\n .update(\n new SshDataWriter()\n .writeMpint(sharedSecret)\n .writeBytes(exchangeHash)\n .writeByte(letter.charCodeAt(0))\n .writeBytes(sessionId)\n .toBuffer(),\n )\n .digest();\n result.push(first);\n\n while (Buffer.concat(result).length < length) {\n const previous = Buffer.concat(result);\n const next = createHash(hashAlgorithm)\n .update(\n new SshDataWriter()\n .writeMpint(sharedSecret)\n .writeBytes(exchangeHash)\n .writeBytes(previous)\n .toBuffer(),\n )\n .digest();\n result.push(next);\n }\n\n return Buffer.concat(result).subarray(0, length);\n}\n\nfunction resolveKexHashAlgorithm(kexAlgorithm: string): \"sha256\" {\n if (kexAlgorithm === \"curve25519-sha256\" || kexAlgorithm === \"curve25519-sha256@libssh.org\") {\n return \"sha256\";\n }\n\n throw new ProtocolError({\n details: { kexAlgorithm },\n message: \"Unsupported key exchange hash algorithm\",\n protocol: \"sftp\",\n retryable: false,\n });\n}\n\nfunction resolveEncryptionKeyLength(algorithm: string): number {\n switch (algorithm) {\n case \"chacha20-poly1305@openssh.com\":\n return 64;\n case \"aes128-gcm@openssh.com\":\n case \"aes128-ctr\":\n return 16;\n case \"aes256-gcm@openssh.com\":\n case \"aes256-ctr\":\n return 32;\n default:\n throw new ProtocolError({\n details: { algorithm },\n message: \"Unsupported SSH encryption algorithm for key derivation\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveIvLength(algorithm: string): number {\n switch (algorithm) {\n case \"chacha20-poly1305@openssh.com\":\n return 0;\n case \"aes128-gcm@openssh.com\":\n case \"aes256-gcm@openssh.com\":\n return 12;\n case \"aes128-ctr\":\n case \"aes256-ctr\":\n return 16;\n default:\n throw new ProtocolError({\n details: { algorithm },\n message: \"Unsupported SSH encryption algorithm for IV derivation\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveMacKeyLength(encryptionAlgorithm: string, macAlgorithm: string): number {\n if (\n encryptionAlgorithm.endsWith(\"-gcm@openssh.com\") ||\n encryptionAlgorithm === \"chacha20-poly1305@openssh.com\"\n ) {\n return 0;\n }\n\n switch (macAlgorithm) {\n case \"hmac-sha2-256\":\n return 32;\n case \"hmac-sha2-512\":\n return 64;\n default:\n throw new ProtocolError({\n details: { macAlgorithm },\n message: \"Unsupported SSH MAC algorithm for key derivation\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n","import { ParseError } from \"../../../errors/ZeroTransferError\";\n\nexport const SSH_MSG_NEWKEYS = 21;\n\n/**\n * Encodes an SSH_MSG_NEWKEYS payload.\n */\nexport function encodeSshNewKeysMessage(): Buffer {\n return Buffer.from([SSH_MSG_NEWKEYS]);\n}\n\n/**\n * Validates and decodes an SSH_MSG_NEWKEYS payload.\n */\nexport function decodeSshNewKeysMessage(payload: Uint8Array): { messageType: number } {\n if (payload.length !== 1 || payload[0] !== SSH_MSG_NEWKEYS) {\n throw new ParseError({\n details: { length: payload.length, messageType: payload[0] },\n message: \"Expected SSH_MSG_NEWKEYS payload\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n return { messageType: SSH_MSG_NEWKEYS };\n}\n","import { Buffer } from \"node:buffer\";\nimport { randomBytes } from \"node:crypto\";\nimport { ConfigurationError, ParseError } from \"../../../errors/ZeroTransferError\";\n\nconst MIN_PADDING_LENGTH = 4;\nconst MIN_PACKET_LENGTH = 1 + MIN_PADDING_LENGTH;\n\n/** Decoded SSH transport packet before decryption/MAC pipelines are applied. */\nexport interface SshTransportPacket {\n padding: Buffer;\n paddingLength: number;\n payload: Buffer;\n}\n\n/**\n * Encodes an SSH binary packet using RFC 4253 framing for the cleartext phase.\n */\nexport function encodeSshTransportPacket(\n payload: Uint8Array,\n options: {\n blockSize?: number;\n randomPadding?: boolean;\n } = {},\n): Buffer {\n const body = Buffer.from(payload);\n const blockSize = normalizeBlockSize(options.blockSize ?? 8);\n\n // packet_length covers padding_length + payload + padding, and packet_length+4\n // must align to the transport block size.\n let paddingLength = MIN_PADDING_LENGTH;\n while ((1 + body.length + paddingLength + 4) % blockSize !== 0) {\n paddingLength += 1;\n }\n\n const padding =\n options.randomPadding === false ? Buffer.alloc(paddingLength) : randomBytes(paddingLength);\n const packetLength = 1 + body.length + paddingLength;\n // Use Buffer.alloc (zero-init) for defense-in-depth: every byte of the frame\n // is overwritten below, but a zeroed buffer eliminates any chance of leaking\n // residual heap memory if a future code path mis-counts.\n const frame = Buffer.alloc(4 + packetLength);\n\n frame.writeUInt32BE(packetLength, 0);\n frame.writeUInt8(paddingLength, 4);\n body.copy(frame, 5);\n padding.copy(frame, 5 + body.length);\n\n return frame;\n}\n\n/**\n * Decodes a complete SSH transport frame into payload and padding metadata.\n */\nexport function decodeSshTransportPacket(frame: Uint8Array): SshTransportPacket {\n const bytes = Buffer.from(frame);\n if (bytes.length < 4 + MIN_PACKET_LENGTH) {\n throw new ParseError({\n details: { length: bytes.length },\n message: \"SSH transport frame is too short\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const packetLength = bytes.readUInt32BE(0);\n if (packetLength < MIN_PACKET_LENGTH) {\n throw new ParseError({\n details: { packetLength },\n message: \"SSH transport packet length is invalid\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const totalLength = 4 + packetLength;\n if (bytes.length !== totalLength) {\n throw new ParseError({\n details: { actualLength: bytes.length, expectedLength: totalLength },\n message: \"SSH transport packet length prefix does not match frame size\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const paddingLength = bytes.readUInt8(4);\n if (paddingLength < MIN_PADDING_LENGTH) {\n throw new ParseError({\n details: { paddingLength },\n message: \"SSH transport packet padding length is invalid\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const payloadLength = packetLength - 1 - paddingLength;\n if (payloadLength < 0) {\n throw new ParseError({\n details: { packetLength, paddingLength },\n message: \"SSH transport packet payload length is negative\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const payloadStart = 5;\n const payloadEnd = payloadStart + payloadLength;\n\n return {\n padding: bytes.subarray(payloadEnd, payloadEnd + paddingLength),\n paddingLength,\n payload: bytes.subarray(payloadStart, payloadEnd),\n };\n}\n\n/**\n * Streaming framer for SSH transport packets from arbitrary TCP chunk boundaries.\n */\nexport class SshTransportPacketFramer {\n private pending = Buffer.alloc(0);\n\n push(chunk: Uint8Array): SshTransportPacket[] {\n this.pending = Buffer.concat([this.pending, Buffer.from(chunk)]);\n const packets: SshTransportPacket[] = [];\n\n while (this.pending.length >= 4) {\n const packetLength = this.pending.readUInt32BE(0);\n const frameLength = 4 + packetLength;\n\n if (this.pending.length < frameLength) {\n break;\n }\n\n const frame = this.pending.subarray(0, frameLength);\n packets.push(decodeSshTransportPacket(frame));\n this.pending = this.pending.subarray(frameLength);\n }\n\n return packets;\n }\n\n getBufferedByteLength(): number {\n return this.pending.length;\n }\n\n /** Returns and clears any bytes buffered but not yet part of a complete packet. */\n takeRemainingBytes(): Buffer {\n const remaining = Buffer.from(this.pending);\n this.pending = Buffer.alloc(0);\n return remaining;\n }\n}\n\nfunction normalizeBlockSize(blockSize: number): number {\n if (!Number.isInteger(blockSize) || blockSize < 8 || blockSize > 255) {\n throw new ConfigurationError({\n details: { blockSize },\n message: \"SSH transport block size must be an integer between 8 and 255\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n return blockSize;\n}\n","/**\n * SSH server host key signature verification (RFC 4253 §6.6, §8).\n *\n * The KEX_ECDH_REPLY message carries:\n * - K_S: the server's public host key blob (algorithm-prefixed, SSH wire format)\n * - signature: H signed with the host private key\n *\n * The client MUST verify the signature against H using the algorithm advertised\n * by the K_S blob. Without this check, the server's identity is unauthenticated\n * and the entire transport is vulnerable to a man-in-the-middle attack.\n */\nimport { Buffer } from \"node:buffer\";\nimport { createHash, createPublicKey, verify as cryptoVerify, type KeyObject } from \"node:crypto\";\nimport { ProtocolError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader } from \"../binary/SshDataReader\";\n\nconst ED25519_RAW_KEY_LENGTH = 32;\n// DER SubjectPublicKeyInfo prefix for Ed25519 public keys (RFC 8410).\nconst ED25519_SPKI_PREFIX = Buffer.from(\"302a300506032b6570032100\", \"hex\");\n\n/**\n * Verifies the server's host key signature over the SSH exchange hash.\n *\n * @throws ProtocolError if the signature is invalid, the algorithm is unsupported,\n * or the host key blob is malformed.\n */\nexport function verifySshHostKeySignature(input: {\n exchangeHash: Uint8Array;\n hostKeyBlob: Uint8Array;\n signatureBlob: Uint8Array;\n}): { algorithmName: string; hostKeySha256: Buffer } {\n const { algorithmName, publicKey } = parseHostKey(input.hostKeyBlob);\n const { signatureAlgorithm, signatureBytes } = parseSignatureBlob(input.signatureBlob);\n\n if (!isCompatibleSignatureAlgorithm(algorithmName, signatureAlgorithm)) {\n throw new ProtocolError({\n details: { hostKeyAlgorithm: algorithmName, signatureAlgorithm },\n message: \"SSH host key signature algorithm does not match host key type\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const verified = verifySignature({\n data: Buffer.from(input.exchangeHash),\n publicKey,\n signature: Buffer.from(signatureBytes),\n signatureAlgorithm,\n });\n\n if (!verified) {\n throw new ProtocolError({\n details: { signatureAlgorithm },\n message: \"SSH host key signature verification failed\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const hostKeySha256 = createHash(\"sha256\").update(input.hostKeyBlob).digest();\n return { algorithmName, hostKeySha256 };\n}\n\ninterface ParsedHostKey {\n algorithmName: string;\n publicKey: KeyObject;\n}\n\nfunction parseHostKey(blob: Uint8Array): ParsedHostKey {\n const reader = new SshDataReader(blob);\n const algorithmName = reader.readString().toString(\"ascii\");\n\n switch (algorithmName) {\n case \"ssh-ed25519\": {\n const raw = reader.readString();\n reader.assertFinished();\n if (raw.length !== ED25519_RAW_KEY_LENGTH) {\n throw new ProtocolError({\n details: { actualLength: raw.length, expectedLength: ED25519_RAW_KEY_LENGTH },\n message: \"Ed25519 host key has invalid length\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const spki = Buffer.concat([ED25519_SPKI_PREFIX, raw]);\n return {\n algorithmName,\n publicKey: createPublicKey({ format: \"der\", key: spki, type: \"spki\" }),\n };\n }\n\n case \"rsa-sha2-256\":\n case \"rsa-sha2-512\":\n case \"ssh-rsa\": {\n // RSA public keys: mpint e, mpint n.\n const e = reader.readMpint();\n const n = reader.readMpint();\n reader.assertFinished();\n return {\n algorithmName,\n publicKey: rsaPublicKeyFromComponents(e, n),\n };\n }\n\n case \"ecdsa-sha2-nistp256\":\n case \"ecdsa-sha2-nistp384\":\n case \"ecdsa-sha2-nistp521\": {\n // RFC 5656 §3.1: string \"ecdsa-sha2-[identifier]\" || string identifier || string Q\n // where Q is the uncompressed point bytes.\n const curveIdentifier = reader.readString().toString(\"ascii\");\n const expectedIdentifier = algorithmName.slice(\"ecdsa-sha2-\".length);\n if (curveIdentifier !== expectedIdentifier) {\n throw new ProtocolError({\n details: { algorithmName, curveIdentifier },\n message: \"ECDSA host key curve identifier does not match algorithm\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const point = reader.readString();\n reader.assertFinished();\n return {\n algorithmName,\n publicKey: ecdsaPublicKeyFromPoint(curveIdentifier, point),\n };\n }\n\n default:\n throw new ProtocolError({\n details: { algorithmName },\n message: \"Unsupported SSH host key algorithm\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\ninterface ParsedSignatureBlob {\n signatureAlgorithm: string;\n signatureBytes: Buffer;\n}\n\nfunction parseSignatureBlob(blob: Uint8Array): ParsedSignatureBlob {\n const reader = new SshDataReader(blob);\n const signatureAlgorithm = reader.readString().toString(\"ascii\");\n const signatureBytes = reader.readString();\n // Some servers append nothing more; do not assertFinished to remain forgiving\n // of trailing bytes from extension formats.\n return { signatureAlgorithm, signatureBytes };\n}\n\nfunction isCompatibleSignatureAlgorithm(\n hostKeyAlgorithm: string,\n signatureAlgorithm: string,\n): boolean {\n if (hostKeyAlgorithm === signatureAlgorithm) return true;\n // RFC 8332: an \"ssh-rsa\" host key can sign with either rsa-sha2-256 or rsa-sha2-512.\n if (hostKeyAlgorithm === \"ssh-rsa\") {\n return signatureAlgorithm === \"rsa-sha2-256\" || signatureAlgorithm === \"rsa-sha2-512\";\n }\n return false;\n}\n\nfunction verifySignature(input: {\n data: Buffer;\n publicKey: KeyObject;\n signature: Buffer;\n signatureAlgorithm: string;\n}): boolean {\n switch (input.signatureAlgorithm) {\n case \"ssh-ed25519\":\n // Ed25519 signs over the raw data; Node's verify() with `null` algorithm.\n return cryptoVerify(null, input.data, input.publicKey, input.signature);\n\n case \"rsa-sha2-256\":\n return cryptoVerify(\"sha256\", input.data, input.publicKey, input.signature);\n\n case \"rsa-sha2-512\":\n return cryptoVerify(\"sha512\", input.data, input.publicKey, input.signature);\n\n case \"ecdsa-sha2-nistp256\":\n return cryptoVerify(\n \"sha256\",\n input.data,\n input.publicKey,\n sshEcdsaSignatureToDer(input.signature),\n );\n\n case \"ecdsa-sha2-nistp384\":\n return cryptoVerify(\n \"sha384\",\n input.data,\n input.publicKey,\n sshEcdsaSignatureToDer(input.signature),\n );\n\n case \"ecdsa-sha2-nistp521\":\n return cryptoVerify(\n \"sha512\",\n input.data,\n input.publicKey,\n sshEcdsaSignatureToDer(input.signature),\n );\n\n case \"ssh-rsa\":\n // Legacy SHA-1 RSA. Disabled by default for security; reject explicitly.\n throw new ProtocolError({\n message: \"Legacy ssh-rsa (SHA-1) host key signatures are not accepted\",\n protocol: \"sftp\",\n retryable: false,\n });\n\n default:\n throw new ProtocolError({\n details: { signatureAlgorithm: input.signatureAlgorithm },\n message: \"Unsupported SSH host key signature algorithm\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\n/**\n * Builds a Node KeyObject from RSA components (e, n) encoded as SSH mpints.\n * Uses ASN.1 DER SubjectPublicKeyInfo so that crypto.verify accepts the result.\n */\nfunction rsaPublicKeyFromComponents(e: Buffer, n: Buffer): KeyObject {\n const eDer = encodeAsn1Integer(e);\n const nDer = encodeAsn1Integer(n);\n const rsaPublicKeyDer = encodeAsn1Sequence(Buffer.concat([nDer, eDer]));\n // BIT STRING wrap: 0x03 LEN 0x00 (unused-bits) || rsaPublicKeyDer\n const bitStringContent = Buffer.concat([Buffer.from([0x00]), rsaPublicKeyDer]);\n const bitString = Buffer.concat([\n Buffer.from([0x03]),\n encodeAsn1Length(bitStringContent.length),\n bitStringContent,\n ]);\n // AlgorithmIdentifier for rsaEncryption: SEQUENCE { OID 1.2.840.113549.1.1.1, NULL }.\n const algoId = Buffer.from(\"300d06092a864886f70d010101 0500\".replace(/\\s+/g, \"\"), \"hex\");\n const spki = encodeAsn1Sequence(Buffer.concat([algoId, bitString]));\n return createPublicKey({ format: \"der\", key: spki, type: \"spki\" });\n}\n\nfunction encodeAsn1Integer(value: Buffer): Buffer {\n // Strip leading zero bytes but preserve a single zero if value is exactly 0.\n let body = value;\n while (body.length > 1 && body[0] === 0x00) body = body.subarray(1);\n // Prepend a 0x00 if the high bit is set so the integer remains positive.\n if (body.length > 0 && (body[0]! & 0x80) !== 0) {\n body = Buffer.concat([Buffer.from([0x00]), body]);\n }\n return Buffer.concat([Buffer.from([0x02]), encodeAsn1Length(body.length), body]);\n}\n\nfunction encodeAsn1Sequence(content: Buffer): Buffer {\n return Buffer.concat([Buffer.from([0x30]), encodeAsn1Length(content.length), content]);\n}\n\nfunction encodeAsn1Length(length: number): Buffer {\n if (length < 0x80) return Buffer.from([length]);\n const bytes: number[] = [];\n let n = length;\n while (n > 0) {\n bytes.unshift(n & 0xff);\n n >>>= 8;\n }\n return Buffer.from([0x80 | bytes.length, ...bytes]);\n}\n\n// -- ECDSA helpers -------------------------------------------------------------\n\n// Named-curve OIDs (RFC 5480).\nconst ECDSA_OID_BY_CURVE = {\n nistp256: \"06082a8648ce3d030107\", // secp256r1 / prime256v1\n nistp384: \"06052b81040022\", // secp384r1\n nistp521: \"06052b81040023\", // secp521r1\n} as const;\n\n// id-ecPublicKey: 1.2.840.10045.2.1\nconst ECDSA_ALGORITHM_OID_HEX = \"06072a8648ce3d0201\";\n\n/**\n * Builds a Node KeyObject from an SSH-encoded ECDSA point. The point is the\n * uncompressed SEC1 encoding (0x04 || X || Y) for nistp256/384/521.\n */\nfunction ecdsaPublicKeyFromPoint(curveIdentifier: string, point: Buffer): KeyObject {\n const oidHex = ECDSA_OID_BY_CURVE[curveIdentifier as keyof typeof ECDSA_OID_BY_CURVE];\n if (oidHex === undefined) {\n throw new ProtocolError({\n details: { curveIdentifier },\n message: \"Unsupported ECDSA curve\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n // AlgorithmIdentifier: SEQUENCE { id-ecPublicKey, namedCurve OID }\n const algoIdContent = Buffer.from(ECDSA_ALGORITHM_OID_HEX + oidHex, \"hex\");\n const algoId = encodeAsn1Sequence(algoIdContent);\n // BIT STRING wrap of the point bytes: 0x03 LEN 0x00 (unused-bits) || point\n const bitStringContent = Buffer.concat([Buffer.from([0x00]), point]);\n const bitString = Buffer.concat([\n Buffer.from([0x03]),\n encodeAsn1Length(bitStringContent.length),\n bitStringContent,\n ]);\n const spki = encodeAsn1Sequence(Buffer.concat([algoId, bitString]));\n return createPublicKey({ format: \"der\", key: spki, type: \"spki\" });\n}\n\n/**\n * Converts an SSH-format ECDSA signature blob (RFC 5656 §3.1.2:\n * `mpint r || mpint s`) into the ASN.1 DER `Ecdsa-Sig-Value` SEQUENCE that\n * `crypto.verify` expects.\n */\nfunction sshEcdsaSignatureToDer(sshSignature: Buffer): Buffer {\n const reader = new SshDataReader(sshSignature);\n const r = reader.readMpint();\n const s = reader.readMpint();\n // Trailing bytes are tolerated for the same forgiveness reasons as the outer\n // signature blob parser.\n const rDer = encodeAsn1Integer(r);\n const sDer = encodeAsn1Integer(s);\n return encodeAsn1Sequence(Buffer.concat([rDer, sDer]));\n}\n","import { Buffer } from \"node:buffer\";\nimport {\n createCipheriv,\n createDecipheriv,\n createHmac,\n timingSafeEqual,\n type Cipheriv,\n type Decipheriv,\n} from \"node:crypto\";\nimport { ProtocolError } from \"../../../errors/ZeroTransferError\";\nimport type { NegotiatedSshAlgorithms } from \"./SshAlgorithmNegotiation\";\nimport type { SshTransportDirectionKeys } from \"./SshKeyDerivation\";\nimport { decodeSshTransportPacket, encodeSshTransportPacket } from \"./SshTransportPacket\";\n\n/** Bidirectional packet protection pair for SSH transport after NEWKEYS. */\nexport interface SshTransportProtectionContext {\n inbound: SshTransportPacketUnprotector;\n outbound: SshTransportPacketProtector;\n}\n\n/**\n * Creates directional packet protectors for the currently negotiated transport algorithms.\n */\nexport function createSshTransportProtectionContext(input: {\n keys: {\n clientToServer: SshTransportDirectionKeys;\n serverToClient: SshTransportDirectionKeys;\n };\n negotiatedAlgorithms: NegotiatedSshAlgorithms;\n deterministicPadding?: boolean;\n initialInboundSequence?: number;\n initialOutboundSequence?: number;\n}): SshTransportProtectionContext {\n return {\n inbound: new SshTransportPacketUnprotector({\n encryptionAlgorithm: input.negotiatedAlgorithms.encryptionServerToClient,\n initialSequence: input.initialInboundSequence ?? 0,\n macAlgorithm: input.negotiatedAlgorithms.macServerToClient,\n keys: input.keys.serverToClient,\n }),\n outbound: new SshTransportPacketProtector({\n deterministicPadding: input.deterministicPadding ?? false,\n encryptionAlgorithm: input.negotiatedAlgorithms.encryptionClientToServer,\n initialSequence: input.initialOutboundSequence ?? 0,\n macAlgorithm: input.negotiatedAlgorithms.macClientToServer,\n keys: input.keys.clientToServer,\n }),\n };\n}\n\n/** Encrypts and authenticates outbound SSH transport packets. */\nexport class SshTransportPacketProtector {\n private readonly blockLength: number;\n private readonly cipher: Cipheriv | undefined;\n private readonly encryptionAlgorithm: string;\n private readonly macAlgorithm: string;\n private readonly macLength: number;\n private sequenceNumber: number;\n\n constructor(\n private readonly options: {\n deterministicPadding: boolean;\n encryptionAlgorithm: string;\n initialSequence: number;\n macAlgorithm: string;\n keys: SshTransportDirectionKeys;\n },\n ) {\n this.encryptionAlgorithm = options.encryptionAlgorithm;\n this.macAlgorithm = options.macAlgorithm;\n this.sequenceNumber = options.initialSequence >>> 0;\n this.blockLength = resolveBlockLength(options.encryptionAlgorithm);\n this.macLength = resolveMacLength(options.encryptionAlgorithm, options.macAlgorithm);\n this.cipher = createCipher(\n options.encryptionAlgorithm,\n options.keys.encryptionKey,\n options.keys.iv,\n );\n }\n\n getSequenceNumber(): number {\n return this.sequenceNumber;\n }\n\n protectPayload(payload: Uint8Array): Buffer {\n const clearPacket = encodeSshTransportPacket(payload, {\n blockSize: this.blockLength,\n randomPadding: !this.options.deterministicPadding,\n });\n const mac = computeMac(\n this.macAlgorithm,\n this.options.keys.macKey,\n this.sequenceNumber,\n clearPacket,\n this.macLength,\n );\n const encrypted = this.cipher === undefined ? clearPacket : this.cipher.update(clearPacket);\n\n this.sequenceNumber = (this.sequenceNumber + 1) >>> 0;\n return Buffer.concat([encrypted, mac]);\n }\n}\n\n/** Verifies and decrypts inbound SSH transport packets. */\nexport class SshTransportPacketUnprotector {\n private readonly blockLength: number;\n private readonly decipher: Decipheriv | undefined;\n private readonly encryptionAlgorithm: string;\n private readonly macAlgorithm: string;\n private readonly macLength: number;\n private sequenceNumber: number;\n\n // Streaming framing state for pushBytes()\n private framePartialDecrypted: Buffer | undefined;\n private framePendingRaw = Buffer.alloc(0);\n private frameRemainingNeeded: number | undefined;\n\n constructor(\n private readonly options: {\n encryptionAlgorithm: string;\n initialSequence: number;\n macAlgorithm: string;\n keys: SshTransportDirectionKeys;\n },\n ) {\n this.encryptionAlgorithm = options.encryptionAlgorithm;\n this.macAlgorithm = options.macAlgorithm;\n this.sequenceNumber = options.initialSequence >>> 0;\n this.blockLength = resolveBlockLength(options.encryptionAlgorithm);\n this.macLength = resolveMacLength(options.encryptionAlgorithm, options.macAlgorithm);\n this.decipher = createDecipher(\n options.encryptionAlgorithm,\n options.keys.encryptionKey,\n options.keys.iv,\n );\n }\n\n getSequenceNumber(): number {\n return this.sequenceNumber;\n }\n\n /**\n * Feeds raw encrypted bytes from the socket and returns any fully decoded payloads.\n * Maintains internal framing state across calls - pass each `data` event chunk directly.\n */\n pushBytes(chunk: Buffer): Buffer[] {\n this.framePendingRaw = Buffer.concat([this.framePendingRaw, chunk]);\n const results: Buffer[] = [];\n\n while (true) {\n if (this.framePartialDecrypted === undefined) {\n // Phase 1: buffer the first cipher block to read the encrypted packet_length.\n if (this.framePendingRaw.length < this.blockLength) break;\n const firstBlock = this.framePendingRaw.subarray(0, this.blockLength);\n this.framePendingRaw = Buffer.from(this.framePendingRaw.subarray(this.blockLength));\n this.framePartialDecrypted = this.decipher\n ? Buffer.from(this.decipher.update(firstBlock))\n : Buffer.from(firstBlock);\n const packetLength = this.framePartialDecrypted.readUInt32BE(0);\n // Total encrypted bytes = 4 (length field) + packetLength.\n // Remaining raw after first block = (4 + packetLength - blockLength) + macLength.\n const remaining = 4 + packetLength - this.blockLength + this.macLength;\n if (remaining < 0) {\n throw new ProtocolError({\n details: { blockLength: this.blockLength, packetLength },\n message: \"SSH encrypted packet_length is smaller than one cipher block\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n this.frameRemainingNeeded = remaining;\n }\n\n const needed = this.frameRemainingNeeded!;\n if (this.framePendingRaw.length < needed) break;\n\n const encryptedRest = this.framePendingRaw.subarray(0, needed - this.macLength);\n const receivedMac = this.framePendingRaw.subarray(needed - this.macLength, needed);\n this.framePendingRaw = Buffer.from(this.framePendingRaw.subarray(needed));\n\n const decryptedRest =\n encryptedRest.length > 0\n ? this.decipher\n ? Buffer.from(this.decipher.update(encryptedRest))\n : Buffer.from(encryptedRest)\n : Buffer.alloc(0);\n\n const clearPacket = Buffer.concat([this.framePartialDecrypted, decryptedRest]);\n const expectedMac = computeMac(\n this.macAlgorithm,\n this.options.keys.macKey,\n this.sequenceNumber,\n clearPacket,\n this.macLength,\n );\n\n if (!timingSafeEqual(receivedMac, expectedMac)) {\n throw new ProtocolError({\n message: \"SSH packet MAC verification failed\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n this.sequenceNumber = (this.sequenceNumber + 1) >>> 0;\n results.push(decodeSshTransportPacket(clearPacket).payload);\n\n this.framePartialDecrypted = undefined;\n this.frameRemainingNeeded = undefined;\n }\n\n return results;\n }\n\n unprotectPayload(packet: Uint8Array): Buffer {\n const frame = Buffer.from(packet);\n if (frame.length < this.macLength) {\n throw new ProtocolError({\n details: { length: frame.length, macLength: this.macLength },\n message: \"SSH packet is shorter than its expected MAC length\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const macOffset = frame.length - this.macLength;\n const encryptedPacket = frame.subarray(0, macOffset);\n const receivedMac = frame.subarray(macOffset);\n const clearPacket =\n this.decipher === undefined ? encryptedPacket : this.decipher.update(encryptedPacket);\n const expectedMac = computeMac(\n this.macAlgorithm,\n this.options.keys.macKey,\n this.sequenceNumber,\n clearPacket,\n this.macLength,\n );\n\n if (!timingSafeEqual(receivedMac, expectedMac)) {\n throw new ProtocolError({\n message: \"SSH packet MAC verification failed\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n this.sequenceNumber = (this.sequenceNumber + 1) >>> 0;\n return decodeSshTransportPacket(clearPacket).payload;\n }\n}\n\nfunction createCipher(algorithm: string, key: Buffer, iv: Buffer): Cipheriv | undefined {\n if (algorithm === \"none\") {\n return undefined;\n }\n\n validateCipherMaterial(algorithm, key, iv);\n const cipher = createCipheriv(toOpenSslCipherName(algorithm), key, iv);\n cipher.setAutoPadding(false);\n return cipher;\n}\n\nfunction createDecipher(algorithm: string, key: Buffer, iv: Buffer): Decipheriv | undefined {\n if (algorithm === \"none\") {\n return undefined;\n }\n\n validateCipherMaterial(algorithm, key, iv);\n const decipher = createDecipheriv(toOpenSslCipherName(algorithm), key, iv);\n decipher.setAutoPadding(false);\n return decipher;\n}\n\nfunction toOpenSslCipherName(algorithm: string): string {\n switch (algorithm) {\n case \"aes128-ctr\":\n return \"aes-128-ctr\";\n case \"aes256-ctr\":\n return \"aes-256-ctr\";\n default:\n return algorithm;\n }\n}\n\nfunction validateCipherMaterial(algorithm: string, key: Buffer, iv: Buffer): void {\n const expectedKeyLength = resolveCipherKeyLength(algorithm);\n const expectedIvLength = resolveCipherIvLength(algorithm);\n\n if (key.length !== expectedKeyLength || iv.length !== expectedIvLength) {\n throw new ProtocolError({\n details: {\n algorithm,\n ivLength: iv.length,\n keyLength: key.length,\n },\n message: \"SSH cipher key material does not match algorithm requirements\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveCipherKeyLength(algorithm: string): number {\n switch (algorithm) {\n case \"aes128-ctr\":\n return 16;\n case \"aes256-ctr\":\n return 32;\n default:\n throw new ProtocolError({\n details: { algorithm },\n message: \"Unsupported SSH cipher algorithm for transport protection\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveCipherIvLength(algorithm: string): number {\n switch (algorithm) {\n case \"aes128-ctr\":\n case \"aes256-ctr\":\n return 16;\n default:\n throw new ProtocolError({\n details: { algorithm },\n message: \"Unsupported SSH cipher IV length for transport protection\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveBlockLength(algorithm: string): number {\n switch (algorithm) {\n case \"aes128-ctr\":\n case \"aes256-ctr\":\n return 16;\n case \"none\":\n return 8; // RFC 4253 §6.1: minimum block size for framing with no cipher\n default:\n throw new ProtocolError({\n details: { algorithm },\n message: \"Unsupported SSH cipher block length for transport protection\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveMacLength(encryptionAlgorithm: string, macAlgorithm: string): number {\n if (encryptionAlgorithm === \"none\") {\n return 0;\n }\n\n switch (macAlgorithm) {\n case \"hmac-sha2-256\":\n return 32;\n case \"hmac-sha2-512\":\n return 64;\n default:\n throw new ProtocolError({\n details: { macAlgorithm },\n message: \"Unsupported SSH MAC algorithm for transport protection\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction computeMac(\n macAlgorithm: string,\n macKey: Buffer,\n sequence: number,\n packet: Buffer,\n macLength: number,\n): Buffer {\n if (macLength === 0) {\n return Buffer.alloc(0);\n }\n\n const hashName = macAlgorithm === \"hmac-sha2-512\" ? \"sha512\" : \"sha256\";\n // Defense-in-depth: zero-init this small buffer so any future change in MAC\n // input length cannot leak uninitialized memory into the HMAC tag.\n const sequenceBuffer = Buffer.alloc(4);\n sequenceBuffer.writeUInt32BE(sequence >>> 0, 0);\n\n return createHmac(hashName, macKey)\n .update(sequenceBuffer)\n .update(packet)\n .digest()\n .subarray(0, macLength);\n}\n","/**\n * SSH Authentication Protocol message codecs (RFC 4252).\n *\n * Covers:\n * - SSH_MSG_SERVICE_REQUEST / SSH_MSG_SERVICE_ACCEPT\n * - SSH_MSG_USERAUTH_REQUEST (none, password, publickey)\n * - SSH_MSG_USERAUTH_SUCCESS / SSH_MSG_USERAUTH_FAILURE\n * - SSH_MSG_USERAUTH_BANNER\n * - SSH_MSG_USERAUTH_PK_OK (publickey pre-auth query response)\n * - SSH_MSG_USERAUTH_INFO_REQUEST / SSH_MSG_USERAUTH_INFO_RESPONSE (keyboard-interactive, RFC 4256)\n */\nimport type { Buffer } from \"node:buffer\";\nimport { ParseError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader } from \"../binary/SshDataReader\";\nimport { SshDataWriter } from \"../binary/SshDataWriter\";\n\n// -- Message type constants --------------------------------------------------\n\nexport const SSH_MSG_SERVICE_REQUEST = 5;\nexport const SSH_MSG_SERVICE_ACCEPT = 6;\nexport const SSH_MSG_USERAUTH_REQUEST = 50;\nexport const SSH_MSG_USERAUTH_FAILURE = 51;\nexport const SSH_MSG_USERAUTH_SUCCESS = 52;\nexport const SSH_MSG_USERAUTH_BANNER = 53;\nexport const SSH_MSG_USERAUTH_PK_OK = 60;\nexport const SSH_MSG_USERAUTH_INFO_REQUEST = 60; // keyboard-interactive\nexport const SSH_MSG_USERAUTH_INFO_RESPONSE = 61; // keyboard-interactive\n\n// -- Service request / accept ------------------------------------------------\n\n/**\n * Encodes SSH_MSG_SERVICE_REQUEST payload (RFC 4253 §10).\n * The service name is always \"ssh-userauth\" before authentication.\n */\nexport function encodeSshServiceRequest(serviceName: string): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_SERVICE_REQUEST)\n .writeString(serviceName, \"utf8\")\n .toBuffer();\n}\n\n/**\n * Decodes SSH_MSG_SERVICE_ACCEPT payload.\n * Returns the echoed service name.\n */\nexport function decodeSshServiceAccept(payload: Uint8Array): { serviceName: string } {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_SERVICE_ACCEPT) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_SERVICE_ACCEPT\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n return { serviceName: reader.readString().toString(\"utf8\") };\n}\n\n// -- USERAUTH REQUEST ---------------------------------------------------------\n\n/** Common fields for all USERAUTH request methods. */\ninterface UserauthRequestBase {\n serviceName: string;\n username: string;\n}\n\n/** SSH_MSG_USERAUTH_REQUEST with method \"none\" - probes allowed methods. */\nexport function encodeUserauthRequestNone(args: UserauthRequestBase): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_USERAUTH_REQUEST)\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"none\", \"ascii\")\n .toBuffer();\n}\n\n/** SSH_MSG_USERAUTH_REQUEST with method \"password\". */\nexport function encodeUserauthRequestPassword(\n args: UserauthRequestBase & { password: string },\n): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_USERAUTH_REQUEST)\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"password\", \"ascii\")\n .writeBoolean(false) // change-password is not supported\n .writeString(args.password, \"utf8\")\n .toBuffer();\n}\n\n/**\n * SSH_MSG_USERAUTH_REQUEST with method \"publickey\" - pre-auth query.\n * Asks the server if it would accept a signature from this key, without providing one.\n */\nexport function encodeUserauthRequestPublickeyQuery(\n args: UserauthRequestBase & { algorithmName: string; publicKeyBlob: Uint8Array },\n): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_USERAUTH_REQUEST)\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"publickey\", \"ascii\")\n .writeBoolean(false)\n .writeString(args.algorithmName, \"ascii\")\n .writeString(args.publicKeyBlob)\n .toBuffer();\n}\n\n/**\n * SSH_MSG_USERAUTH_REQUEST with method \"publickey\" - actual signature.\n * sessionId is the exchange hash / session identifier from key exchange.\n */\nexport function encodeUserauthRequestPublickeySign(\n args: UserauthRequestBase & {\n algorithmName: string;\n publicKeyBlob: Uint8Array;\n signature: Uint8Array;\n },\n): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_USERAUTH_REQUEST)\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"publickey\", \"ascii\")\n .writeBoolean(true)\n .writeString(args.algorithmName, \"ascii\")\n .writeString(args.publicKeyBlob)\n .writeString(args.signature)\n .toBuffer();\n}\n\n/**\n * Builds the exact byte sequence that must be signed for publickey auth (RFC 4252 §7).\n * The signature covers: session_id || SSH_MSG_USERAUTH_REQUEST || fields.\n */\nexport function buildPublickeySignData(\n args: UserauthRequestBase & {\n algorithmName: string;\n publicKeyBlob: Uint8Array;\n sessionId: Uint8Array;\n },\n): Buffer {\n return new SshDataWriter()\n .writeString(args.sessionId) // length-prefixed session_id\n .writeByte(SSH_MSG_USERAUTH_REQUEST)\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"publickey\", \"ascii\")\n .writeBoolean(true)\n .writeString(args.algorithmName, \"ascii\")\n .writeString(args.publicKeyBlob)\n .toBuffer();\n}\n\n// -- USERAUTH FAILURE ---------------------------------------------------------\n\nexport interface SshUserauthFailure {\n allowedAuthentications: string[];\n partialSuccess: boolean;\n}\n\n/**\n * Decodes SSH_MSG_USERAUTH_FAILURE payload.\n */\nexport function decodeSshUserauthFailure(payload: Uint8Array): SshUserauthFailure {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_USERAUTH_FAILURE) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_USERAUTH_FAILURE\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const nameList = reader.readString().toString(\"ascii\");\n const allowedAuthentications = nameList.length === 0 ? [] : nameList.split(\",\");\n const partialSuccess = reader.readBoolean();\n return { allowedAuthentications, partialSuccess };\n}\n\n// -- USERAUTH BANNER ---------------------------------------------------------\n\nexport interface SshUserauthBanner {\n languageTag: string;\n message: string;\n}\n\nexport function decodeSshUserauthBanner(payload: Uint8Array): SshUserauthBanner {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_USERAUTH_BANNER) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_USERAUTH_BANNER\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const message = reader.readString().toString(\"utf8\");\n const languageTag = reader.readString().toString(\"ascii\");\n return { languageTag, message };\n}\n\n// -- USERAUTH_PK_OK -----------------------------------------------------------\n\nexport interface SshUserauthPkOk {\n algorithmName: string;\n publicKeyBlob: Buffer;\n}\n\nexport function decodeSshUserauthPkOk(payload: Uint8Array): SshUserauthPkOk {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_USERAUTH_PK_OK) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_USERAUTH_PK_OK\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n return {\n algorithmName: reader.readString().toString(\"ascii\"),\n publicKeyBlob: reader.readString(),\n };\n}\n\n// -- Keyboard-interactive (RFC 4256) -----------------------------------------\n\nexport interface SshUserauthInfoRequest {\n instruction: string;\n languageTag: string;\n name: string;\n prompts: Array<{ echo: boolean; prompt: string }>;\n}\n\nexport function decodeSshUserauthInfoRequest(payload: Uint8Array): SshUserauthInfoRequest {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_USERAUTH_INFO_REQUEST) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_USERAUTH_INFO_REQUEST\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const name = reader.readString().toString(\"utf8\");\n const instruction = reader.readString().toString(\"utf8\");\n const languageTag = reader.readString().toString(\"ascii\");\n const count = reader.readUint32();\n const prompts: Array<{ echo: boolean; prompt: string }> = [];\n for (let i = 0; i < count; i++) {\n const prompt = reader.readString().toString(\"utf8\");\n const echo = reader.readBoolean();\n prompts.push({ echo, prompt });\n }\n return { instruction, languageTag, name, prompts };\n}\n\nexport function encodeSshUserauthInfoResponse(responses: string[]): Buffer {\n const writer = new SshDataWriter()\n .writeByte(SSH_MSG_USERAUTH_INFO_RESPONSE)\n .writeUint32(responses.length);\n for (const r of responses) {\n writer.writeString(r, \"utf8\");\n }\n return writer.toBuffer();\n}\n","/**\n * SSH authentication session (RFC 4252).\n *\n * Drives service-request → USERAUTH exchange over an already-encrypted\n * SshTransportConnection. Supports:\n * - none (probes allowed methods, satisfies some servers)\n * - password\n * - publickey (query + sign; external signing callback)\n * - keyboard-interactive (caller supplies responses via callback)\n */\nimport type { Buffer } from \"node:buffer\";\nimport { AuthenticationError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataWriter } from \"../binary/SshDataWriter\";\nimport {\n SSH_MSG_USERAUTH_BANNER,\n SSH_MSG_USERAUTH_FAILURE,\n SSH_MSG_USERAUTH_INFO_REQUEST,\n SSH_MSG_USERAUTH_PK_OK,\n SSH_MSG_USERAUTH_SUCCESS,\n buildPublickeySignData,\n decodeSshServiceAccept,\n decodeSshUserauthBanner,\n decodeSshUserauthFailure,\n decodeSshUserauthInfoRequest,\n decodeSshUserauthPkOk,\n encodeUserauthRequestPassword,\n encodeUserauthRequestPublickeyQuery,\n encodeUserauthRequestPublickeySign,\n encodeSshServiceRequest,\n encodeSshUserauthInfoResponse,\n} from \"./SshAuthMessages\";\nimport type { SshTransportConnection } from \"../transport/SshTransportConnection\";\n\nconst SSH_USERAUTH_SERVICE = \"ssh-userauth\";\nconst SSH_CONNECTION_SERVICE = \"ssh-connection\";\n\n// -- Credential shapes --------------------------------------------------------\n\nexport interface SshPasswordCredential {\n type: \"password\";\n username: string;\n password: string;\n}\n\nexport interface SshPublickeyCredential {\n type: \"publickey\";\n username: string;\n algorithmName: string;\n /** Raw public key blob in SSH wire format (e.g. the bytes returned by ssh-keygen -e -f key.pub). */\n publicKeyBlob: Uint8Array;\n /**\n * Signs the challenge data. The data is already the complete sign-data per RFC 4252 §7.\n * Should return the signature blob (without algorithm prefix; caller adds wrapping).\n */\n sign: (data: Uint8Array) => Promise<Uint8Array> | Uint8Array;\n}\n\nexport interface SshKeyboardInteractiveCredential {\n type: \"keyboard-interactive\";\n username: string;\n /**\n * Called for each INFO_REQUEST round. Return one string per prompt in order.\n */\n respond: (\n name: string,\n instruction: string,\n prompts: Array<{ echo: boolean; prompt: string }>,\n ) => Promise<string[]> | string[];\n}\n\nexport type SshCredential =\n | SshPasswordCredential\n | SshPublickeyCredential\n | SshKeyboardInteractiveCredential;\n\nexport interface SshAuthOptions {\n credential: SshCredential;\n /** SSH session id (exchange hash) from key exchange - required for publickey signing. */\n sessionId: Uint8Array;\n /** Maximum number of USERAUTH_FAILURE retries before giving up. Defaults to 4. */\n maxAttempts?: number;\n}\n\nexport interface SshAuthResult {\n /** Banner lines received from the server during authentication. */\n bannerLines: string[];\n /** Auth method that succeeded. */\n method: string;\n}\n\n/**\n * Runs SSH user authentication over an encrypted transport connection.\n *\n * Call this after `SshTransportConnection.connect()` completes.\n * Returns a generator of inbound payloads for the upper (connection) layer to consume.\n * Resolves with an `SshAuthResult` on success; throws `AuthenticationError` on failure.\n */\nexport class SshAuthSession {\n constructor(private readonly transport: SshTransportConnection) {}\n\n async authenticate(options: SshAuthOptions): Promise<SshAuthResult> {\n const { credential, sessionId, maxAttempts = 4 } = options;\n const bannerLines: string[] = [];\n\n // 1. Request the ssh-userauth service.\n this.transport.sendPayload(encodeSshServiceRequest(SSH_USERAUTH_SERVICE));\n\n // Wait for SERVICE_ACCEPT.\n const serviceAcceptPayload = await this.nextPayload();\n decodeSshServiceAccept(serviceAcceptPayload);\n\n // 2. Run the auth exchange.\n let attempts = 0;\n\n while (attempts < maxAttempts) {\n attempts += 1;\n\n const method = credential.type;\n\n switch (credential.type) {\n case \"password\": {\n this.transport.sendPayload(\n encodeUserauthRequestPassword({\n password: credential.password,\n serviceName: SSH_CONNECTION_SERVICE,\n username: credential.username,\n }),\n );\n break;\n }\n\n case \"publickey\": {\n // Phase 1: query whether server accepts this key.\n this.transport.sendPayload(\n encodeUserauthRequestPublickeyQuery({\n algorithmName: credential.algorithmName,\n publicKeyBlob: credential.publicKeyBlob,\n serviceName: SSH_CONNECTION_SERVICE,\n username: credential.username,\n }),\n );\n\n const queryResponse = await this.nextPayloadSkippingBanners(bannerLines);\n const queryMsgType = queryResponse[0];\n\n if (queryMsgType === SSH_MSG_USERAUTH_FAILURE) {\n const failure = decodeSshUserauthFailure(queryResponse);\n throw new AuthenticationError({\n details: { allowed: failure.allowedAuthentications },\n message: `SSH server does not accept public key for user \"${credential.username}\"`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n if (queryMsgType !== SSH_MSG_USERAUTH_PK_OK) {\n throw new AuthenticationError({\n details: { msgType: queryMsgType },\n message: \"Unexpected server response to publickey query\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n decodeSshUserauthPkOk(queryResponse); // validates structure\n\n // Phase 2: sign and send.\n const signData = buildPublickeySignData({\n algorithmName: credential.algorithmName,\n publicKeyBlob: credential.publicKeyBlob,\n serviceName: SSH_CONNECTION_SERVICE,\n sessionId,\n username: credential.username,\n });\n\n const rawSignature = await credential.sign(signData);\n const signatureBlob = buildSignatureBlob(credential.algorithmName, rawSignature);\n\n this.transport.sendPayload(\n encodeUserauthRequestPublickeySign({\n algorithmName: credential.algorithmName,\n publicKeyBlob: credential.publicKeyBlob,\n serviceName: SSH_CONNECTION_SERVICE,\n signature: signatureBlob,\n username: credential.username,\n }),\n );\n break;\n }\n\n case \"keyboard-interactive\": {\n // RFC 4256 §3.1: send the keyboard-interactive USERAUTH_REQUEST\n // directly. The server then drives one or more INFO_REQUEST rounds.\n await this.runKeyboardInteractiveRounds(credential, bannerLines);\n const kiResult = await this.nextPayloadSkippingBanners(bannerLines);\n if (kiResult[0] === SSH_MSG_USERAUTH_SUCCESS) {\n return { bannerLines, method: \"keyboard-interactive\" };\n }\n if (kiResult[0] === SSH_MSG_USERAUTH_FAILURE) {\n throw new AuthenticationError({\n details: { allowed: decodeSshUserauthFailure(kiResult).allowedAuthentications },\n message: `SSH keyboard-interactive authentication failed for user \"${credential.username}\"`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n throw new AuthenticationError({\n details: { msgType: kiResult[0] },\n message: \"Unexpected message type after keyboard-interactive exchange\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n }\n\n const response = await this.nextPayloadSkippingBanners(bannerLines);\n const responseMsgType = response[0];\n\n if (responseMsgType === SSH_MSG_USERAUTH_SUCCESS) {\n return { bannerLines, method };\n }\n\n if (responseMsgType === SSH_MSG_USERAUTH_FAILURE) {\n const failure = decodeSshUserauthFailure(response);\n\n if (attempts >= maxAttempts || !failure.allowedAuthentications.includes(credential.type)) {\n throw new AuthenticationError({\n details: { allowed: failure.allowedAuthentications, attempts },\n message: `SSH authentication failed for user \"${credential.username}\" after ${attempts} attempt(s)`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n // Server rejected this attempt but allows retry - loop.\n continue;\n }\n\n throw new AuthenticationError({\n details: { msgType: responseMsgType },\n message: \"Unexpected message type during SSH authentication\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n throw new AuthenticationError({\n details: { maxAttempts },\n message: `SSH authentication exceeded maximum attempts (${maxAttempts})`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n // -- Private helpers ------------------------------------------------------\n\n private async runKeyboardInteractiveRounds(\n credential: SshKeyboardInteractiveCredential,\n bannerLines: string[],\n ): Promise<void> {\n // Send the keyboard-interactive auth request now that we know the server accepts it.\n this.transport.sendPayload(\n buildKiRequest({ serviceName: SSH_CONNECTION_SERVICE, username: credential.username }),\n );\n\n while (true) {\n const payload = await this.nextPayloadSkippingBanners(bannerLines);\n const msgType = payload[0];\n\n if (msgType === SSH_MSG_USERAUTH_INFO_REQUEST) {\n const infoReq = decodeSshUserauthInfoRequest(payload);\n let responses: string[];\n try {\n responses = await credential.respond(infoReq.name, infoReq.instruction, infoReq.prompts);\n } catch (cause) {\n throw new AuthenticationError({\n cause,\n message: `SSH keyboard-interactive callback failed for user \"${credential.username}\"`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n this.transport.sendPayload(encodeSshUserauthInfoResponse(responses));\n continue;\n }\n\n // Put the payload back in the caller's view by re-emitting - handled by returning.\n this.pendingPayload = payload;\n return;\n }\n }\n\n private pendingPayload: Buffer | undefined;\n\n private async nextPayload(): Promise<Buffer> {\n if (this.pendingPayload !== undefined) {\n const p = this.pendingPayload;\n this.pendingPayload = undefined;\n return p;\n }\n const result = await this.transport.receivePayloads().next();\n if (result.done === true) {\n throw new AuthenticationError({\n message: \"SSH connection closed during authentication\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n return result.value;\n }\n\n private async nextPayloadSkippingBanners(bannerLines: string[]): Promise<Buffer> {\n while (true) {\n const payload = await this.nextPayload();\n if (payload[0] === SSH_MSG_USERAUTH_BANNER) {\n bannerLines.push(decodeSshUserauthBanner(payload).message);\n continue;\n }\n return payload;\n }\n }\n}\n\n// -- Helpers ------------------------------------------------------------------\n\n/**\n * Wraps a raw signature value in an SSH \"sig\" blob:\n * string algorithm-name\n * string signature-bytes\n */\nfunction buildSignatureBlob(algorithmName: string, rawSignature: Uint8Array): Buffer {\n return new SshDataWriter()\n .writeString(algorithmName, \"ascii\")\n .writeString(rawSignature)\n .toBuffer();\n}\n\n/**\n * Encodes keyboard-interactive USERAUTH_REQUEST (RFC 4256 §3.1).\n */\nfunction buildKiRequest(args: { serviceName: string; username: string }): Buffer {\n return new SshDataWriter()\n .writeByte(50) // SSH_MSG_USERAUTH_REQUEST\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"keyboard-interactive\", \"ascii\")\n .writeString(\"\", \"utf8\") // language tag (deprecated, empty)\n .writeString(\"\", \"utf8\") // submethods (empty = server chooses)\n .toBuffer();\n}\n","/**\n * Builds an {@link SshPublickeyCredential} from a Node `KeyObject` private key.\n *\n * Supported algorithms:\n * - Ed25519 → signature algorithm `ssh-ed25519`\n * - RSA → signature algorithm `rsa-sha2-512` (preferred) or `rsa-sha2-256`\n *\n * Node 17+ accepts OpenSSH-format private keys (the `-----BEGIN OPENSSH PRIVATE KEY-----`\n * envelope) directly via `crypto.createPrivateKey`, so the caller can pass either\n * OpenSSH or PKCS#8 PEM material.\n *\n * Encrypted keys are supported by passing a `passphrase` to `createPrivateKey`\n * before calling this helper; this module does not perform decryption.\n */\nimport { Buffer } from \"node:buffer\";\nimport { createPublicKey, sign as cryptoSign, type KeyObject } from \"node:crypto\";\nimport { ConfigurationError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataWriter } from \"../binary/SshDataWriter\";\nimport type { SshPublickeyCredential } from \"./SshAuthSession\";\n\nconst ED25519_RAW_KEY_LENGTH = 32;\n// DER SubjectPublicKeyInfo prefix for Ed25519 public keys (RFC 8410).\nconst ED25519_SPKI_PREFIX_LENGTH = 12;\n\nexport interface BuildPublickeyCredentialOptions {\n /** Username to authenticate as. */\n username: string;\n /** Decoded private key (OpenSSH or PKCS8 PEM accepted by `crypto.createPrivateKey`). */\n privateKey: KeyObject;\n /**\n * For RSA keys, the SSH signature algorithm. Defaults to `rsa-sha2-512`.\n * Ignored for Ed25519 keys.\n */\n rsaSignatureAlgorithm?: \"rsa-sha2-256\" | \"rsa-sha2-512\";\n}\n\nexport function buildPublickeyCredential(\n options: BuildPublickeyCredentialOptions,\n): SshPublickeyCredential {\n const { privateKey, username } = options;\n const publicKey = createPublicKey(privateKey);\n\n switch (privateKey.asymmetricKeyType) {\n case \"ed25519\": {\n const spki = publicKey.export({ format: \"der\", type: \"spki\" });\n if (spki.length !== ED25519_SPKI_PREFIX_LENGTH + ED25519_RAW_KEY_LENGTH) {\n throw createInvalidKeyError(\"Ed25519 SPKI export has unexpected length\");\n }\n const raw = spki.subarray(ED25519_SPKI_PREFIX_LENGTH);\n const publicKeyBlob = new SshDataWriter()\n .writeString(\"ssh-ed25519\", \"ascii\")\n .writeString(raw)\n .toBuffer();\n return {\n algorithmName: \"ssh-ed25519\",\n publicKeyBlob,\n sign: (data: Uint8Array): Buffer => cryptoSign(null, Buffer.from(data), privateKey),\n type: \"publickey\",\n username,\n };\n }\n\n case \"rsa\": {\n const algorithmName = options.rsaSignatureAlgorithm ?? \"rsa-sha2-512\";\n const hash = algorithmName === \"rsa-sha2-256\" ? \"sha256\" : \"sha512\";\n const jwk = publicKey.export({ format: \"jwk\" });\n if (jwk.n === undefined || jwk.e === undefined) {\n throw createInvalidKeyError(\"RSA public key is missing modulus or exponent\");\n }\n // SSH wire format uses two's-complement mpints. base64url JWK fields are\n // unsigned big-endian, so prepend a 0x00 if the high bit is set.\n const n = base64UrlToMpint(jwk.n);\n const e = base64UrlToMpint(jwk.e);\n const publicKeyBlob = new SshDataWriter()\n .writeString(\"ssh-rsa\", \"ascii\")\n .writeMpint(e)\n .writeMpint(n)\n .toBuffer();\n return {\n algorithmName,\n publicKeyBlob,\n sign: (data: Uint8Array): Buffer => cryptoSign(hash, Buffer.from(data), privateKey),\n type: \"publickey\",\n username,\n };\n }\n\n default:\n throw createInvalidKeyError(\n `Unsupported SSH private key type: ${privateKey.asymmetricKeyType ?? \"unknown\"}`,\n );\n }\n}\n\nfunction base64UrlToMpint(value: string): Buffer {\n // base64url → base64\n const padded = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const buffer = Buffer.from(padded, \"base64\");\n // writeMpint will add the required leading 0x00 if the high bit is set.\n return buffer;\n}\n\nfunction createInvalidKeyError(message: string): ConfigurationError {\n return new ConfigurationError({\n message,\n protocol: \"sftp\",\n retryable: false,\n });\n}\n","/**\n * SSH Connection Protocol message codecs (RFC 4254).\n *\n * Covers:\n * - SSH_MSG_CHANNEL_OPEN / CHANNEL_OPEN_CONFIRMATION / CHANNEL_OPEN_FAILURE\n * - SSH_MSG_CHANNEL_REQUEST (exec, subsystem, pty-req, env, signal, exit-status)\n * - SSH_MSG_CHANNEL_SUCCESS / CHANNEL_FAILURE\n * - SSH_MSG_CHANNEL_DATA / CHANNEL_EXTENDED_DATA\n * - SSH_MSG_CHANNEL_WINDOW_ADJUST\n * - SSH_MSG_CHANNEL_EOF / CHANNEL_CLOSE\n */\nimport type { Buffer } from \"node:buffer\";\nimport { ParseError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader } from \"../binary/SshDataReader\";\nimport { SshDataWriter } from \"../binary/SshDataWriter\";\n\n// -- Message type constants --------------------------------------------------\n\nexport const SSH_MSG_CHANNEL_OPEN = 90;\nexport const SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91;\nexport const SSH_MSG_CHANNEL_OPEN_FAILURE = 92;\nexport const SSH_MSG_CHANNEL_WINDOW_ADJUST = 93;\nexport const SSH_MSG_CHANNEL_DATA = 94;\nexport const SSH_MSG_CHANNEL_EXTENDED_DATA = 95;\nexport const SSH_MSG_CHANNEL_EOF = 96;\nexport const SSH_MSG_CHANNEL_CLOSE = 97;\nexport const SSH_MSG_CHANNEL_REQUEST = 98;\nexport const SSH_MSG_CHANNEL_SUCCESS = 99;\nexport const SSH_MSG_CHANNEL_FAILURE = 100;\n\n/** Channel open failure reason codes (RFC 4254 §5.1). */\nexport const SshChannelOpenFailureReason = {\n ADMINISTRATIVELY_PROHIBITED: 1,\n CONNECT_FAILED: 2,\n UNKNOWN_CHANNEL_TYPE: 3,\n RESOURCE_SHORTAGE: 4,\n} as const;\n\n// -- CHANNEL_OPEN -------------------------------------------------------------\n\nexport interface SshChannelOpenArgs {\n channelType: string;\n senderChannel: number;\n /** Initial local window size (bytes). */\n initialWindowSize: number;\n /** Maximum packet size the sender can accept. */\n maxPacketSize: number;\n}\n\nexport function encodeSshChannelOpen(args: SshChannelOpenArgs): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_OPEN)\n .writeString(args.channelType, \"ascii\")\n .writeUint32(args.senderChannel)\n .writeUint32(args.initialWindowSize)\n .writeUint32(args.maxPacketSize)\n .toBuffer();\n}\n\n// -- CHANNEL_OPEN_CONFIRMATION -------------------------------------------------\n\nexport interface SshChannelOpenConfirmation {\n recipientChannel: number;\n senderChannel: number;\n initialWindowSize: number;\n maxPacketSize: number;\n}\n\nexport function decodeSshChannelOpenConfirmation(payload: Uint8Array): SshChannelOpenConfirmation {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_OPEN_CONFIRMATION\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const recipientChannel = reader.readUint32();\n const senderChannel = reader.readUint32();\n const initialWindowSize = reader.readUint32();\n const maxPacketSize = reader.readUint32();\n return { initialWindowSize, maxPacketSize, recipientChannel, senderChannel };\n}\n\n// -- CHANNEL_OPEN_FAILURE ------------------------------------------------------\n\nexport interface SshChannelOpenFailure {\n recipientChannel: number;\n reasonCode: number;\n description: string;\n languageTag: string;\n}\n\nexport function decodeSshChannelOpenFailure(payload: Uint8Array): SshChannelOpenFailure {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_CHANNEL_OPEN_FAILURE) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_OPEN_FAILURE\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const recipientChannel = reader.readUint32();\n const reasonCode = reader.readUint32();\n const description = reader.readString().toString(\"utf8\");\n const languageTag = reader.readString().toString(\"ascii\");\n return { description, languageTag, reasonCode, recipientChannel };\n}\n\n// -- CHANNEL_REQUEST -----------------------------------------------------------\n\nexport function encodeSshChannelRequestSubsystem(args: {\n recipientChannel: number;\n subsystemName: string;\n wantReply: boolean;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_REQUEST)\n .writeUint32(args.recipientChannel)\n .writeString(\"subsystem\", \"ascii\")\n .writeBoolean(args.wantReply)\n .writeString(args.subsystemName, \"ascii\")\n .toBuffer();\n}\n\nexport function encodeSshChannelRequestExec(args: {\n recipientChannel: number;\n command: string;\n wantReply: boolean;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_REQUEST)\n .writeUint32(args.recipientChannel)\n .writeString(\"exec\", \"ascii\")\n .writeBoolean(args.wantReply)\n .writeString(args.command, \"utf8\")\n .toBuffer();\n}\n\nexport function encodeSshChannelRequestEnv(args: {\n recipientChannel: number;\n variableName: string;\n variableValue: string;\n wantReply: boolean;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_REQUEST)\n .writeUint32(args.recipientChannel)\n .writeString(\"env\", \"ascii\")\n .writeBoolean(args.wantReply)\n .writeString(args.variableName, \"utf8\")\n .writeString(args.variableValue, \"utf8\")\n .toBuffer();\n}\n\nexport function encodeSshChannelRequestSignal(args: {\n recipientChannel: number;\n signalName: string;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_REQUEST)\n .writeUint32(args.recipientChannel)\n .writeString(\"signal\", \"ascii\")\n .writeBoolean(false) // RFC 4254 §6.9 says wantReply MUST be false\n .writeString(args.signalName, \"ascii\")\n .toBuffer();\n}\n\n// -- CHANNEL_SUCCESS / CHANNEL_FAILURE -----------------------------------------\n\nexport function encodeSshChannelSuccess(recipientChannel: number): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_SUCCESS)\n .writeUint32(recipientChannel)\n .toBuffer();\n}\n\nexport function encodeSshChannelFailure(recipientChannel: number): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_FAILURE)\n .writeUint32(recipientChannel)\n .toBuffer();\n}\n\n// -- CHANNEL_DATA --------------------------------------------------------------\n\nexport function encodeSshChannelData(args: { recipientChannel: number; data: Uint8Array }): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_DATA)\n .writeUint32(args.recipientChannel)\n .writeString(args.data)\n .toBuffer();\n}\n\nexport interface SshChannelDataMessage {\n recipientChannel: number;\n data: Buffer;\n}\n\nexport function decodeSshChannelData(payload: Uint8Array): SshChannelDataMessage {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_CHANNEL_DATA) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_DATA\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const recipientChannel = reader.readUint32();\n const data = reader.readString();\n return { data, recipientChannel };\n}\n\n/** Standard extended data type codes. */\nexport const SSH_EXTENDED_DATA_STDERR = 1;\n\nexport function encodeSshChannelExtendedData(args: {\n recipientChannel: number;\n dataTypeCode: number;\n data: Uint8Array;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_EXTENDED_DATA)\n .writeUint32(args.recipientChannel)\n .writeUint32(args.dataTypeCode)\n .writeString(args.data)\n .toBuffer();\n}\n\nexport interface SshChannelExtendedDataMessage {\n recipientChannel: number;\n dataTypeCode: number;\n data: Buffer;\n}\n\nexport function decodeSshChannelExtendedData(payload: Uint8Array): SshChannelExtendedDataMessage {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_CHANNEL_EXTENDED_DATA) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_EXTENDED_DATA\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const recipientChannel = reader.readUint32();\n const dataTypeCode = reader.readUint32();\n const data = reader.readString();\n return { data, dataTypeCode, recipientChannel };\n}\n\n// -- CHANNEL_WINDOW_ADJUST -----------------------------------------------------\n\nexport function encodeSshChannelWindowAdjust(args: {\n recipientChannel: number;\n bytesToAdd: number;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_WINDOW_ADJUST)\n .writeUint32(args.recipientChannel)\n .writeUint32(args.bytesToAdd)\n .toBuffer();\n}\n\nexport interface SshChannelWindowAdjustMessage {\n recipientChannel: number;\n bytesToAdd: number;\n}\n\nexport function decodeSshChannelWindowAdjust(payload: Uint8Array): SshChannelWindowAdjustMessage {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_CHANNEL_WINDOW_ADJUST) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_WINDOW_ADJUST\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const recipientChannel = reader.readUint32();\n const bytesToAdd = reader.readUint32();\n return { bytesToAdd, recipientChannel };\n}\n\n// -- CHANNEL_EOF / CHANNEL_CLOSE -----------------------------------------------\n\nexport function encodeSshChannelEof(recipientChannel: number): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_EOF)\n .writeUint32(recipientChannel)\n .toBuffer();\n}\n\nexport function encodeSshChannelClose(recipientChannel: number): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_CLOSE)\n .writeUint32(recipientChannel)\n .toBuffer();\n}\n","/**\n * SSH session channel (RFC 4254 §6).\n *\n * Manages a single \"session\" channel from the client side:\n * CHANNEL_OPEN → OPEN_CONFIRMATION → CHANNEL_REQUEST (subsystem/exec) →\n * bidirectional CHANNEL_DATA with window management → CHANNEL_EOF/CLOSE.\n *\n * Window management strategy:\n * - Local window starts at INITIAL_WINDOW_SIZE.\n * - When consumed bytes exceed WINDOW_REFILL_THRESHOLD, a WINDOW_ADJUST is sent.\n * - Outbound data respects the remote window; excess is queued and flushed\n * as the remote issues WINDOW_ADJUST messages.\n */\nimport { Buffer } from \"node:buffer\";\nimport { ConnectionError, ProtocolError } from \"../../../errors/ZeroTransferError\";\nimport {\n SSH_MSG_CHANNEL_CLOSE,\n SSH_MSG_CHANNEL_DATA,\n SSH_MSG_CHANNEL_EOF,\n SSH_MSG_CHANNEL_EXTENDED_DATA,\n SSH_MSG_CHANNEL_FAILURE,\n SSH_MSG_CHANNEL_OPEN_CONFIRMATION,\n SSH_MSG_CHANNEL_OPEN_FAILURE,\n SSH_MSG_CHANNEL_SUCCESS,\n SSH_MSG_CHANNEL_WINDOW_ADJUST,\n decodeSshChannelData,\n decodeSshChannelExtendedData,\n decodeSshChannelOpenConfirmation,\n decodeSshChannelOpenFailure,\n decodeSshChannelWindowAdjust,\n encodeSshChannelClose,\n encodeSshChannelData,\n encodeSshChannelEof,\n encodeSshChannelOpen,\n encodeSshChannelRequestExec,\n encodeSshChannelRequestSubsystem,\n encodeSshChannelWindowAdjust,\n} from \"./SshConnectionMessages\";\nimport type { SshTransportConnection } from \"../transport/SshTransportConnection\";\n\nconst INITIAL_WINDOW_SIZE = 256 * 1024; // 256 KiB\nconst MAX_PACKET_SIZE = 32 * 1024; // 32 KiB\nconst WINDOW_REFILL_THRESHOLD = 64 * 1024;\n\n// -- Channel state -------------------------------------------------------------\n\ntype ChannelPhase = \"opening\" | \"requesting\" | \"open\" | \"closing\" | \"closed\";\n\ntype InboundEntry =\n | { type: \"data\"; data: Buffer }\n | { type: \"eof\" }\n | { type: \"close\" }\n | { type: \"error\"; error: Error };\n\nexport interface SshSessionChannelOptions {\n /**\n * Local channel id allocated by the caller.\n * If omitted, defaults to 0 (single-channel use case).\n */\n localChannelId?: number;\n}\n\n/**\n * A single SSH session channel.\n * Not safe to share across concurrent callers; each SftpSession should own one.\n */\nexport class SshSessionChannel {\n private phase: ChannelPhase = \"opening\";\n\n /** Remote channel id assigned by the server in OPEN_CONFIRMATION. */\n private remoteChannelId = 0;\n /** Bytes the remote side can still receive before we must stop sending. */\n private remoteWindowRemaining = 0;\n /** Maximum packet data size the remote accepts. */\n private remoteMaxPacketSize = MAX_PACKET_SIZE;\n\n /** Local window: bytes we can still accept from remote. */\n private localWindowConsumed = 0;\n private localWindowSize = INITIAL_WINDOW_SIZE;\n\n /** Queue of inbound data for the `receiveData()` generator. */\n private readonly inboundQueue: InboundEntry[] = [];\n private waitingConsumer: (() => void) | undefined;\n\n /** Queue of outbound data waiting for remote window space. */\n private readonly outboundQueue: Buffer[] = [];\n /**\n * FIFO of waiters blocked on remote window credit. Each WINDOW_ADJUST wakes\n * exactly one waiter; concurrent senders must not lose wakeups.\n */\n private readonly outboundDrainedWaiters: Array<() => void> = [];\n /** Serializes sendData() calls so byte order on the wire matches call order. */\n private sendChain: Promise<void> = Promise.resolve();\n\n private readonly localChannelId: number;\n\n constructor(\n private readonly transport: SshTransportConnection,\n options: SshSessionChannelOptions = {},\n ) {\n this.localChannelId = options.localChannelId ?? 0;\n }\n\n // -- Lifecycle ---------------------------------------------------------------\n\n /**\n * Opens the channel and requests a subsystem.\n * Resolves once the server confirms both CHANNEL_OPEN and the subsystem request.\n */\n async openSubsystem(subsystemName: string): Promise<void> {\n await this.openChannel();\n await this.requestSubsystem(subsystemName);\n }\n\n /**\n * Opens the channel and executes a command.\n */\n async openExec(command: string): Promise<void> {\n await this.openChannel();\n await this.requestExec(command);\n }\n\n private async openChannel(): Promise<void> {\n this.transport.sendPayload(\n encodeSshChannelOpen({\n channelType: \"session\",\n initialWindowSize: INITIAL_WINDOW_SIZE,\n maxPacketSize: MAX_PACKET_SIZE,\n senderChannel: this.localChannelId,\n }),\n );\n\n const payload = await this.nextPayload();\n const msgType = payload[0];\n\n if (msgType === SSH_MSG_CHANNEL_OPEN_FAILURE) {\n const failure = decodeSshChannelOpenFailure(payload);\n throw new ConnectionError({\n details: { reason: failure.reasonCode, description: failure.description },\n message: `SSH channel open failed: ${failure.description}`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n if (msgType !== SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {\n throw new ProtocolError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_OPEN_CONFIRMATION\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const confirmation = decodeSshChannelOpenConfirmation(payload);\n this.remoteChannelId = confirmation.senderChannel;\n this.remoteWindowRemaining = confirmation.initialWindowSize;\n this.remoteMaxPacketSize = confirmation.maxPacketSize;\n this.phase = \"requesting\";\n }\n\n private async requestSubsystem(subsystemName: string): Promise<void> {\n this.transport.sendPayload(\n encodeSshChannelRequestSubsystem({\n recipientChannel: this.remoteChannelId,\n subsystemName,\n wantReply: true,\n }),\n );\n await this.awaitChannelRequestReply(\"subsystem\");\n }\n\n private async requestExec(command: string): Promise<void> {\n this.transport.sendPayload(\n encodeSshChannelRequestExec({\n command,\n recipientChannel: this.remoteChannelId,\n wantReply: true,\n }),\n );\n await this.awaitChannelRequestReply(\"exec\");\n }\n\n private async awaitChannelRequestReply(requestType: string): Promise<void> {\n const payload = await this.nextPayload();\n const msgType = payload[0];\n\n if (msgType === SSH_MSG_CHANNEL_SUCCESS) {\n this.phase = \"open\";\n return;\n }\n\n if (msgType === SSH_MSG_CHANNEL_FAILURE) {\n throw new ConnectionError({\n details: { requestType },\n message: `SSH channel request \"${requestType}\" was rejected by the server`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n throw new ProtocolError({\n details: { msgType },\n message: `Unexpected response to channel request \"${requestType}\"`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n // -- Send --------------------------------------------------------------------\n\n /**\n * Sends data on the channel. Respects the remote window; if there is no space,\n * splits the data and queues the remainder for when WINDOW_ADJUST arrives.\n *\n * Concurrent calls are serialized so wire byte order matches call order.\n */\n sendData(data: Uint8Array): Promise<void> {\n const next = this.sendChain.then(() => this.sendDataLocked(data));\n // Keep the chain alive even if a single send rejects, so subsequent sends\n // are not blocked on a poisoned promise.\n this.sendChain = next.catch(() => undefined);\n return next;\n }\n\n private async sendDataLocked(data: Uint8Array): Promise<void> {\n if (this.phase !== \"open\") {\n throw new ProtocolError({\n message: \"Cannot send data on a channel that is not open\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n let offset = 0;\n while (offset < data.length) {\n if (this.remoteWindowRemaining <= 0) {\n // Backpressure: wait for remote to issue WINDOW_ADJUST.\n await new Promise<void>((resolve) => {\n this.outboundDrainedWaiters.push(resolve);\n });\n continue;\n }\n\n const chunkSize = Math.min(\n data.length - offset,\n this.remoteWindowRemaining,\n this.remoteMaxPacketSize,\n );\n const chunk = Buffer.from(data.subarray(offset, offset + chunkSize));\n this.transport.sendPayload(\n encodeSshChannelData({ data: chunk, recipientChannel: this.remoteChannelId }),\n );\n this.remoteWindowRemaining -= chunkSize;\n offset += chunkSize;\n }\n }\n\n // -- Receive -----------------------------------------------------------------\n\n /**\n * Async generator that yields raw data buffers from the channel.\n * Returns (done) when the channel receives EOF or CLOSE.\n */\n async *receiveData(): AsyncGenerator<Buffer, void, undefined> {\n while (true) {\n const entry = await this.dequeueInbound();\n if (entry.type === \"error\") throw entry.error;\n if (entry.type === \"eof\" || entry.type === \"close\") return;\n yield entry.data;\n }\n }\n\n // -- Close -------------------------------------------------------------------\n\n /**\n * Sends EOF and CLOSE. Should be called when the client is done sending.\n */\n close(): void {\n if (this.phase === \"closed\" || this.phase === \"closing\") return;\n this.phase = \"closing\";\n this.transport.sendPayload(encodeSshChannelEof(this.remoteChannelId));\n this.transport.sendPayload(encodeSshChannelClose(this.remoteChannelId));\n }\n\n // -- Dispatch (called by SshConnectionManager) -----------------------------\n\n /**\n * Feed an inbound transport payload to this channel.\n * Called by the channel multiplexer (`SshConnectionManager`).\n */\n dispatch(payload: Buffer): void {\n const msgType = payload[0];\n\n switch (msgType) {\n case SSH_MSG_CHANNEL_DATA: {\n const msg = decodeSshChannelData(payload);\n this.consumeLocalWindow(msg.data.length);\n this.enqueueInbound({ type: \"data\", data: msg.data });\n break;\n }\n\n case SSH_MSG_CHANNEL_EXTENDED_DATA: {\n // Consume window credit; we discard STDERR data (SFTP doesn't use it).\n const msg = decodeSshChannelExtendedData(payload);\n this.consumeLocalWindow(msg.data.length);\n break;\n }\n\n case SSH_MSG_CHANNEL_WINDOW_ADJUST: {\n const msg = decodeSshChannelWindowAdjust(payload);\n this.remoteWindowRemaining += msg.bytesToAdd;\n // Wake all waiters; sendDataLocked re-checks the window in its loop.\n const waiters = this.outboundDrainedWaiters.splice(0);\n for (const cb of waiters) cb();\n break;\n }\n\n case SSH_MSG_CHANNEL_EOF: {\n this.enqueueInbound({ type: \"eof\" });\n break;\n }\n\n case SSH_MSG_CHANNEL_CLOSE: {\n this.phase = \"closed\";\n this.enqueueInbound({ type: \"close\" });\n // Wake any waiters blocked on remote window credit so they can observe\n // the channel is no longer open and reject.\n const waiters = this.outboundDrainedWaiters.splice(0);\n for (const cb of waiters) cb();\n break;\n }\n\n default:\n // Unknown or ignored channel message types.\n break;\n }\n }\n\n dispatchError(error: Error): void {\n this.enqueueInbound({ type: \"error\", error });\n // Unblock any senders so they observe the failure rather than hanging.\n const waiters = this.outboundDrainedWaiters.splice(0);\n for (const cb of waiters) cb();\n }\n\n // -- Private helpers ------------------------------------------------------\n\n private consumeLocalWindow(bytes: number): void {\n this.localWindowConsumed += bytes;\n if (this.localWindowConsumed >= WINDOW_REFILL_THRESHOLD) {\n const bytesToAdd = this.localWindowConsumed;\n this.localWindowConsumed = 0;\n this.transport.sendPayload(\n encodeSshChannelWindowAdjust({\n bytesToAdd,\n recipientChannel: this.remoteChannelId,\n }),\n );\n }\n }\n\n private enqueueInbound(entry: InboundEntry): void {\n this.inboundQueue.push(entry);\n if (this.waitingConsumer !== undefined) {\n const cb = this.waitingConsumer;\n this.waitingConsumer = undefined;\n cb();\n }\n }\n\n private dequeueInbound(): Promise<InboundEntry> {\n if (this.inboundQueue.length > 0) {\n return Promise.resolve(this.inboundQueue.shift()!);\n }\n return new Promise<InboundEntry>((resolve) => {\n this.waitingConsumer = () => {\n resolve(this.inboundQueue.shift()!);\n };\n });\n }\n\n /** Pull the next payload from the transport (used during channel setup only). */\n private async nextPayload(): Promise<Buffer> {\n const result = await this.transport.receivePayloads().next();\n if (result.done === true) {\n throw new ConnectionError({\n message: \"SSH connection closed during channel setup\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n return result.value;\n }\n}\n","/**\n * SSH connection protocol manager (RFC 4254).\n *\n * Drives the transport-level `receivePayloads()` generator and dispatches each\n * payload to the right `SshSessionChannel` by recipient channel id.\n *\n * Lifecycle:\n * 1. Create after auth succeeds.\n * 2. Call `openSubsystemChannel(\"sftp\")` or `openExecChannel(cmd)` to get a channel.\n * 3. Drive the pump: `start()` returns a Promise that resolves when the transport\n * closes cleanly or rejects on a fatal error.\n */\nimport type { Buffer } from \"node:buffer\";\nimport { ConnectionError } from \"../../../errors/ZeroTransferError\";\nimport {\n SSH_MSG_CHANNEL_CLOSE,\n SSH_MSG_CHANNEL_DATA,\n SSH_MSG_CHANNEL_EXTENDED_DATA,\n SSH_MSG_CHANNEL_EOF,\n SSH_MSG_CHANNEL_FAILURE,\n SSH_MSG_CHANNEL_OPEN_CONFIRMATION,\n SSH_MSG_CHANNEL_OPEN_FAILURE,\n SSH_MSG_CHANNEL_REQUEST,\n SSH_MSG_CHANNEL_SUCCESS,\n SSH_MSG_CHANNEL_WINDOW_ADJUST,\n} from \"./SshConnectionMessages\";\nimport { SshSessionChannel } from \"./SshSessionChannel\";\nimport type { SshTransportConnection } from \"../transport/SshTransportConnection\";\n\n/** Channel messages that carry a recipient-channel id at byte offset 1 (uint32 BE). */\nconst CHANNEL_MSG_TYPES = new Set([\n SSH_MSG_CHANNEL_OPEN_CONFIRMATION,\n SSH_MSG_CHANNEL_OPEN_FAILURE,\n SSH_MSG_CHANNEL_WINDOW_ADJUST,\n SSH_MSG_CHANNEL_DATA,\n SSH_MSG_CHANNEL_EXTENDED_DATA,\n SSH_MSG_CHANNEL_EOF,\n SSH_MSG_CHANNEL_CLOSE,\n SSH_MSG_CHANNEL_REQUEST,\n SSH_MSG_CHANNEL_SUCCESS,\n SSH_MSG_CHANNEL_FAILURE,\n]);\n\nexport class SshConnectionManager {\n private readonly channels = new Map<number, SshSessionChannel>();\n private nextLocalId = 0;\n private pumpPromise: Promise<void> | undefined;\n private pumpResolve: (() => void) | undefined;\n private pumpReject: ((e: Error) => void) | undefined;\n\n /** Payloads that arrived before any channel registered (buffered for the first channel). */\n private readonly pendingSetupPayloads: Buffer[] = [];\n private setupPayloadConsumer: ((payload: Buffer) => void) | undefined;\n\n constructor(private readonly transport: SshTransportConnection) {}\n\n // -- Setup-phase payload delivery (for channel open/request handshakes) -----\n\n /**\n * Delivers the next connection-layer payload to callers during channel setup.\n * Called by `SshSessionChannel` during `openChannel()` / `requestSubsystem()`.\n *\n * Channel setup happens sequentially before `start()` begins pumping, so we\n * pull directly from the transport iterator here.\n */\n async nextSetupPayload(): Promise<Buffer> {\n // If there are buffered payloads from before, drain them first.\n if (this.pendingSetupPayloads.length > 0) {\n return this.pendingSetupPayloads.shift()!;\n }\n\n const result = await this.transport.receivePayloads().next();\n if (result.done === true) {\n throw new ConnectionError({\n message: \"SSH connection closed during channel setup\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n return result.value;\n }\n\n // -- Channel factory -------------------------------------------------------\n\n /**\n * Opens a session channel and starts the SFTP subsystem on it.\n * Must be called before `start()`.\n */\n async openSubsystemChannel(subsystemName: string): Promise<SshSessionChannel> {\n const localId = this.nextLocalId++;\n const channel = new SshSessionChannel(this.transport, { localChannelId: localId });\n this.channels.set(localId, channel);\n\n // Temporarily replace the channel's transport.receivePayloads with our setup pump.\n await this.runChannelSetup(channel, () => channel.openSubsystem(subsystemName));\n return channel;\n }\n\n /**\n * Opens a session channel and runs the given command on it.\n * Must be called before `start()`.\n */\n async openExecChannel(command: string): Promise<SshSessionChannel> {\n const localId = this.nextLocalId++;\n const channel = new SshSessionChannel(this.transport, { localChannelId: localId });\n this.channels.set(localId, channel);\n await this.runChannelSetup(channel, () => channel.openExec(command));\n return channel;\n }\n\n // -- Pump --------------------------------------------------------------------\n\n /**\n * Starts the main dispatch loop. Returns a Promise that resolves when the\n * connection closes cleanly, or rejects on a fatal transport error.\n *\n * Call this after all channels have been opened and the application is ready\n * to receive data.\n */\n start(): Promise<void> {\n if (this.pumpPromise !== undefined) return this.pumpPromise;\n\n this.pumpPromise = new Promise<void>((resolve, reject) => {\n this.pumpResolve = resolve;\n this.pumpReject = reject;\n void this.pump();\n });\n\n return this.pumpPromise;\n }\n\n // -- Private --------------------------------------------------------------\n\n /**\n * Runs channel setup (open + request) with a dedicated payload pump that\n * pulls from the transport iterator and dispatches non-channel-setup messages\n * to `pendingSetupPayloads` for later processing.\n */\n private async runChannelSetup(\n channel: SshSessionChannel,\n setup: () => Promise<void>,\n ): Promise<void> {\n // Intercept transport.receivePayloads to route through our setup-phase consumer.\n // We achieve this by temporarily wrapping the channel's nextPayload calls via\n // `nextSetupPayload`. SshSessionChannel's private `nextPayload()` already calls\n // `transport.receivePayloads().next()` - so we cannot intercept it without changing\n // the design. Instead, we create a shim transport that the channel talks to.\n await setup();\n }\n\n private async pump(): Promise<void> {\n try {\n for await (const payload of this.transport.receivePayloads()) {\n this.dispatch(payload);\n }\n // Generator exhausted cleanly.\n this.terminateChannels(\n new ConnectionError({\n message: \"SSH connection closed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n this.pumpResolve?.();\n } catch (err) {\n const error =\n err instanceof Error\n ? err\n : new ConnectionError({\n message: String(err),\n protocol: \"sftp\",\n retryable: false,\n });\n this.terminateChannels(error);\n this.pumpReject?.(error);\n }\n }\n\n private dispatch(payload: Buffer): void {\n const msgType = payload[0];\n if (msgType === undefined) return;\n\n if (CHANNEL_MSG_TYPES.has(msgType)) {\n // All channel messages carry recipient channel id at bytes 1-4.\n const recipientChannel = payload.readUInt32BE(1);\n const channel = this.channels.get(recipientChannel);\n if (channel !== undefined) {\n channel.dispatch(payload);\n }\n // Unknown channel ids are silently ignored (server may send late CLOSE).\n }\n // Global connection-layer messages (SSH_MSG_REQUEST_SUCCESS/FAILURE, etc.) are\n // silently dropped here. Extend as needed.\n }\n\n private terminateChannels(error: Error): void {\n for (const channel of this.channels.values()) {\n channel.dispatchError(error);\n }\n }\n}\n","/**\n * @file `runSshCommand` - high-level helper that opens an SSH connection,\n * authenticates, runs a single command on an `exec` channel, captures stdout,\n * and tears the connection down. Eliminates the manual TCP socket / transport\n * / auth / channel choreography for the common one-shot use case.\n */\nimport { connect, type Socket } from \"node:net\";\n\nimport { SshAuthSession, type SshCredential } from \"./auth/SshAuthSession\";\nimport { SshConnectionManager } from \"./connection/SshConnectionManager\";\nimport {\n SshTransportConnection,\n type SshTransportConnectionOptions,\n} from \"./transport/SshTransportConnection\";\n\n/**\n * Options for {@link runSshCommand}.\n */\nexport interface RunSshCommandOptions {\n /** Hostname or IP of the SSH server. */\n host: string;\n /** TCP port. Defaults to `22`. */\n port?: number;\n /** Command to execute on the remote shell. */\n command: string;\n /**\n * Authentication credential. Use one of:\n *\n * - `{ type: \"password\", username, password }`\n * - `{ type: \"publickey\", username, algorithmName, publicKeyBlob, sign }`\n * (build one from a private-key file with `buildPublickeyCredential`)\n * - `{ type: \"keyboard-interactive\", username, respond }`\n */\n auth: SshCredential;\n /**\n * Forwarded to {@link SshTransportConnection}; covers host-key pinning,\n * algorithm overrides, and handshake timeout. The default\n * `handshakeTimeoutMs` is 10 seconds.\n */\n transport?: SshTransportConnectionOptions;\n /** TCP connect timeout in milliseconds. Defaults to 10 000. */\n connectTimeoutMs?: number;\n /** Maximum total bytes captured from stdout. Defaults to 16 MiB. */\n maxOutputBytes?: number;\n}\n\n/**\n * Result of {@link runSshCommand}. The full captured stdout is provided as\n * both a `Buffer` (for binary output) and as a UTF-8 decoded `string`.\n *\n * Note: stderr (CHANNEL_EXTENDED_DATA) and exit-status are not currently\n * surfaced - drop down to {@link SshConnectionManager}/{@link SshSessionChannel}\n * directly if you need them.\n */\nexport interface RunSshCommandResult {\n /** Captured stdout as raw bytes. */\n stdout: Buffer;\n /** Captured stdout decoded as UTF-8. */\n stdoutText: string;\n /** Bytes received before the channel closed. */\n bytesReceived: number;\n}\n\nconst DEFAULT_PORT = 22;\nconst DEFAULT_CONNECT_TIMEOUT_MS = 10_000;\nconst DEFAULT_HANDSHAKE_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_OUTPUT_BYTES = 16 * 1024 * 1024;\n\n/**\n * Connects, authenticates, runs `command` on a fresh exec channel, drains\n * stdout, and disconnects. The TCP socket, transport, auth session, and\n * channel are all owned by this helper and torn down before it returns.\n *\n * @example Run `uname -a` with a password credential\n * ```ts\n * import { runSshCommand } from \"@zero-transfer/ssh\";\n *\n * const { stdoutText } = await runSshCommand({\n * host: \"ssh.example.com\",\n * auth: { type: \"password\", username: \"deploy\", password: process.env.SSH_PASSWORD! },\n * command: \"uname -a\",\n * });\n * console.log(stdoutText);\n * ```\n */\nexport async function runSshCommand(options: RunSshCommandOptions): Promise<RunSshCommandResult> {\n const {\n host,\n port = DEFAULT_PORT,\n command,\n auth,\n transport: transportOptions,\n connectTimeoutMs = DEFAULT_CONNECT_TIMEOUT_MS,\n maxOutputBytes = DEFAULT_MAX_OUTPUT_BYTES,\n } = options;\n\n const socket = await openTcpSocket(host, port, connectTimeoutMs);\n const transport = new SshTransportConnection({\n handshakeTimeoutMs: DEFAULT_HANDSHAKE_TIMEOUT_MS,\n ...transportOptions,\n });\n\n try {\n const handshake = await transport.connect(socket);\n\n const authSession = new SshAuthSession(transport);\n await authSession.authenticate({\n credential: auth,\n sessionId: handshake.keyExchange.sessionId,\n });\n\n const conn = new SshConnectionManager(transport);\n const channel = await conn.openExecChannel(command);\n\n const pump = conn.start();\n pump.catch(() => {\n // Errors surface through the receiveData() iterator below.\n });\n\n const chunks: Buffer[] = [];\n let bytesReceived = 0;\n try {\n for await (const chunk of channel.receiveData()) {\n bytesReceived += chunk.length;\n if (bytesReceived > maxOutputBytes) {\n throw new Error(\n `runSshCommand: stdout exceeded ${maxOutputBytes} bytes (set maxOutputBytes to allow more)`,\n );\n }\n chunks.push(chunk);\n }\n } finally {\n channel.close();\n }\n\n const stdout = Buffer.concat(chunks);\n return {\n stdout,\n stdoutText: stdout.toString(\"utf8\"),\n bytesReceived,\n };\n } finally {\n transport.disconnect();\n }\n}\n\n/**\n * Opens a TCP socket with a timeout, returning it in the connected state.\n * @internal\n */\nfunction openTcpSocket(host: string, port: number, timeoutMs: number): Promise<Socket> {\n return new Promise<Socket>((resolve, reject) => {\n const socket = connect({ host, port });\n const timer = setTimeout(() => {\n socket.destroy();\n reject(\n new Error(`runSshCommand: TCP connect to ${host}:${port} timed out after ${timeoutMs}ms`),\n );\n }, timeoutMs);\n socket.once(\"connect\", () => {\n clearTimeout(timer);\n resolve(socket);\n });\n socket.once(\"error\", (error) => {\n clearTimeout(timer);\n reject(error);\n });\n });\n}\n"],"mappings":"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","names":["Buffer","Buffer","path","waitMs","totalBytes","calculateBytesPerSecond","normalized","Buffer","Buffer","path","rename","mkdir","isAbsolute","cloneVerification","path","Buffer","path","createPathNotFoundError","compareEntries","collectTransferContent","normalizeOptionalByteCount","cloneVerification","Buffer","normalizeByteCount","concatChunks","cloneDate","Buffer","first","globMatch","path","Buffer","Buffer","gt","cloneEndpoint","item","open","path","path","throwIfAborted","compareEntries","path","compareEntries","path","absolutePath","isModifiedAtDifferent","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","first","Buffer","randomBytes","Buffer","randomBytes","Buffer","createHash","createPublicKey","Buffer","createHash","createPublicKey","Buffer","Buffer","createHmac","Buffer","createHmac","Buffer","Buffer","createPublicKey","ED25519_RAW_KEY_LENGTH","createPublicKey","Buffer","Buffer","Buffer"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/client/ZeroTransfer.ts","../../../src/logging/redaction.ts","../../../src/errors/ZeroTransferError.ts","../../../src/logging/Logger.ts","../../../src/profiles/ProfileValidator.ts","../../../src/core/ProviderId.ts","../../../src/core/ProviderRegistry.ts","../../../src/core/TransferClient.ts","../../../src/core/createTransferClient.ts","../../../src/client/operations.ts","../../../src/transfers/BandwidthThrottle.ts","../../../src/transfers/createProviderTransferExecutor.ts","../../../src/services/TransferService.ts","../../../src/transfers/TransferEngine.ts","../../../src/mft/runRoute.ts","../../../src/profiles/SecretSource.ts","../../../src/profiles/ProfileRedactor.ts","../../../src/diagnostics/index.ts","../../../src/core/ConnectionPool.ts","../../../src/providers/local/LocalProvider.ts","../../../src/utils/path.ts","../../../src/providers/memory/MemoryProvider.ts","../../../src/profiles/resolveConnectionProfileSecrets.ts","../../../src/profiles/OAuthTokenSource.ts","../../../src/profiles/importers/KnownHostsParser.ts","../../../src/profiles/importers/OpenSshConfigImporter.ts","../../../src/profiles/importers/FileZillaImporter.ts","../../../src/profiles/importers/WinScpImporter.ts","../../../src/errors/errorFactory.ts","../../../src/transfers/createDefaultRetryPolicy.ts","../../../src/transfers/TransferPlan.ts","../../../src/transfers/TransferQueue.ts","../../../src/sync/createRemoteBrowser.ts","../../../src/sync/createSyncPlan.ts","../../../src/sync/createAtomicDeployPlan.ts","../../../src/sync/walkRemoteTree.ts","../../../src/sync/diffRemoteTrees.ts","../../../src/sync/manifest.ts","../../../src/utils/mainModule.ts","../../../src/protocols/ssh/transport/SshTransportConnection.ts","../../../src/protocols/ssh/binary/SshDataReader.ts","../../../src/protocols/ssh/binary/SshDataWriter.ts","../../../src/protocols/ssh/transport/SshTransportHandshake.ts","../../../src/protocols/ssh/transport/SshAlgorithmNegotiation.ts","../../../src/protocols/ssh/transport/SshIdentification.ts","../../../src/protocols/ssh/transport/SshKexInit.ts","../../../src/protocols/ssh/transport/SshKexCurve25519.ts","../../../src/protocols/ssh/transport/SshKeyDerivation.ts","../../../src/protocols/ssh/transport/SshNewKeys.ts","../../../src/protocols/ssh/transport/SshTransportPacket.ts","../../../src/protocols/ssh/transport/SshHostKeyVerification.ts","../../../src/protocols/ssh/transport/SshTransportProtection.ts","../../../src/protocols/ssh/auth/SshAuthMessages.ts","../../../src/protocols/ssh/auth/SshAuthSession.ts","../../../src/protocols/ssh/auth/SshPublickeyCredentialBuilder.ts","../../../src/protocols/ssh/connection/SshConnectionMessages.ts","../../../src/protocols/ssh/connection/SshSessionChannel.ts","../../../src/protocols/ssh/connection/SshConnectionManager.ts","../../../src/protocols/ssh/runSshCommand.ts"],"sourcesContent":["/**\n * Client facade for the ZeroTransfer SDK foundation.\n *\n * This module intentionally keeps the top-level API small while protocol-specific\n * behavior is delegated to injected adapters. The facade owns lifecycle state,\n * event emission, logging coordination, and common capability discovery.\n *\n * @module client/ZeroTransfer\n */\nimport { EventEmitter } from \"node:events\";\nimport { createTransferClient } from \"../core/createTransferClient\";\nimport { isClassicProviderId } from \"../core/ProviderId\";\nimport { UnsupportedFeatureError } from \"../errors/ZeroTransferError\";\nimport { emitLog, noopLogger, type ZeroTransferLogger } from \"../logging/Logger\";\nimport type { RemoteFileAdapter } from \"../protocols/RemoteFileAdapter\";\nimport type {\n ConnectionProfile,\n ListOptions,\n RemoteEntry,\n RemoteProtocol,\n RemoteStat,\n StatOptions,\n} from \"../types/public\";\n\n/**\n * Construction options for a {@link ZeroTransfer} instance.\n *\n * @remarks\n * The adapter option is primarily used by protocol implementations and tests. Until\n * the built-in FTP, FTPS, and SFTP adapters are implemented, callers can inject a\n * compatible adapter to exercise the facade contract.\n */\nexport interface ZeroTransferOptions {\n /** Protocol used when the connection profile does not provide one. */\n protocol?: RemoteProtocol;\n /** Structured logger used for lifecycle and operation records. */\n logger?: ZeroTransferLogger;\n /** Protocol adapter that performs concrete remote file operations. */\n adapter?: RemoteFileAdapter;\n}\n\n/**\n * Lightweight capability snapshot for the current client instance.\n */\nexport interface ZeroTransferCapabilities {\n /** The protocol selected for this client facade. */\n protocol: RemoteProtocol;\n /** Whether a concrete protocol adapter has been supplied. */\n adapterReady: boolean;\n}\n\n/**\n * SDK entry point for FTP, FTPS, and SFTP workflows.\n *\n * @remarks\n * ZeroTransfer extends Node.js EventEmitter so applications can observe lifecycle\n * events while still using promise-based APIs for operations. The facade is\n * deliberately protocol-neutral; concrete behavior lives behind\n * {@link RemoteFileAdapter}.\n *\n */\nexport class ZeroTransfer extends EventEmitter {\n /** Creates a provider-neutral transfer client with the built-in provider registry. */\n static readonly createTransferClient = createTransferClient;\n\n /** Protocol selected for this client instance. */\n readonly protocol: RemoteProtocol;\n\n private readonly logger: ZeroTransferLogger;\n private readonly adapter: RemoteFileAdapter | undefined;\n private connected = false;\n\n /**\n * Creates a client facade without opening a network connection.\n *\n * @param options - Optional facade configuration, logger, and protocol adapter.\n */\n constructor(options: ZeroTransferOptions = {}) {\n super();\n this.protocol = options.protocol ?? \"ftp\";\n this.logger = options.logger ?? noopLogger;\n this.adapter = options.adapter;\n }\n\n /**\n * Creates a new client facade using the provided options.\n *\n * @param options - Optional facade configuration, logger, and adapter.\n * @returns A disconnected {@link ZeroTransfer} instance.\n */\n static create(options: ZeroTransferOptions = {}): ZeroTransfer {\n return new ZeroTransfer(options);\n }\n\n /**\n * Creates a client and connects it in one step.\n *\n * @param profile - Remote host, authentication, and protocol connection settings.\n * @param options - Optional facade settings that can be overridden by the profile.\n * @returns A connected {@link ZeroTransfer} instance.\n * @throws {@link UnsupportedFeatureError} When no adapter is available for the protocol.\n */\n static async connect(\n profile: ConnectionProfile,\n options: ZeroTransferOptions = {},\n ): Promise<ZeroTransfer> {\n const clientOptions: ZeroTransferOptions = { ...options };\n\n if (profile.logger !== undefined) {\n clientOptions.logger = profile.logger;\n }\n\n if (profile.protocol !== undefined) {\n clientOptions.protocol = profile.protocol;\n } else if (isClassicProviderId(profile.provider)) {\n clientOptions.protocol = profile.provider;\n }\n\n const client = new ZeroTransfer(clientOptions);\n await client.connect(profile);\n return client;\n }\n\n /**\n * Opens a remote connection through the configured protocol adapter.\n *\n * @param profile - Remote host, authentication, timeout, logger, and protocol settings.\n * @returns A promise that resolves after the adapter reports a successful connection.\n * @throws {@link UnsupportedFeatureError} When the client does not have an adapter.\n */\n async connect(profile: ConnectionProfile): Promise<void> {\n const adapter = this.requireAdapter();\n const protocol =\n profile.protocol ??\n (isClassicProviderId(profile.provider) ? profile.provider : this.protocol);\n emitLog(this.logger, \"info\", {\n component: \"client\",\n host: profile.host,\n message: \"Connecting\",\n protocol,\n });\n await adapter.connect({\n ...profile,\n protocol,\n });\n this.connected = true;\n this.emit(\"connect\", {\n host: profile.host,\n protocol,\n });\n }\n\n /**\n * Closes the active remote connection if one exists.\n *\n * @returns A promise that resolves after the adapter disconnects or immediately when idle.\n */\n async disconnect(): Promise<void> {\n if (this.adapter !== undefined && this.connected) {\n await this.adapter.disconnect();\n }\n\n this.connected = false;\n this.emit(\"disconnect\");\n }\n\n /**\n * Checks whether the facade currently considers the adapter connected.\n *\n * @returns `true` after a successful connection and before disconnection.\n */\n isConnected(): boolean {\n return this.connected;\n }\n\n /**\n * Describes protocol and adapter readiness for feature discovery.\n *\n * @returns A capability snapshot for diagnostics and UI state.\n */\n getCapabilities(): ZeroTransferCapabilities {\n return {\n adapterReady: this.adapter !== undefined,\n protocol: this.protocol,\n };\n }\n\n /**\n * Lists remote entries for a path using the configured adapter.\n *\n * @param path - Remote directory path to inspect.\n * @param options - Optional listing controls such as recursion and abort signal.\n * @returns Normalized remote entries for the requested directory.\n * @throws {@link UnsupportedFeatureError} When the client does not have an adapter.\n */\n async list(path: string, options?: ListOptions): Promise<RemoteEntry[]> {\n return this.requireAdapter().list(path, options);\n }\n\n /**\n * Reads metadata for a remote path using the configured adapter.\n *\n * @param path - Remote file, directory, or symbolic-link path to inspect.\n * @param options - Optional stat controls such as abort signal.\n * @returns Normalized metadata for an existing remote entry.\n * @throws {@link UnsupportedFeatureError} When the client does not have an adapter.\n */\n async stat(path: string, options?: StatOptions): Promise<RemoteStat> {\n return this.requireAdapter().stat(path, options);\n }\n\n /**\n * Returns the configured adapter or raises the alpha unsupported-feature error.\n *\n * @returns A concrete remote file adapter ready to execute operations.\n * @throws {@link UnsupportedFeatureError} When no adapter has been provided.\n */\n private requireAdapter(): RemoteFileAdapter {\n if (this.adapter === undefined) {\n throw new UnsupportedFeatureError({\n message: `The ${this.protocol.toUpperCase()} adapter is not implemented in this alpha foundation yet`,\n protocol: this.protocol,\n retryable: false,\n });\n }\n\n return this.adapter;\n }\n}\n","/**\n * Secret redaction helpers for logs, events, and diagnostics.\n *\n * These functions focus on preserving useful operational context while removing\n * credentials and command payloads that should not appear in logs.\n *\n * @module logging/redaction\n */\n/** Placeholder used when sensitive content has been removed. */\nexport const REDACTED = \"[REDACTED]\";\n\nconst SENSITIVE_KEY_PATTERN = /(?:password|passphrase|privatekey|token|secret|username|user)$/i;\nconst SECRET_COMMAND_PATTERN = /^(PASS|USER|ACCT)\\s+(.+)$/i;\nconst URL_KEY_PATTERN = /(?:url|uri|href)$/i;\n\n/**\n * Checks whether an object key is likely to contain sensitive data.\n *\n * @param key - Object key to inspect.\n * @returns `true` when the key name should be redacted.\n */\nexport function isSensitiveKey(key: string): boolean {\n return SENSITIVE_KEY_PATTERN.test(key.replace(/[_-]/g, \"\"));\n}\n\n/**\n * Redacts sensitive FTP command payloads while preserving the command name.\n *\n * @param command - Raw command text such as `PASS secret` or `USER deploy`.\n * @returns Command text with secret arguments replaced by {@link REDACTED}.\n */\nexport function redactCommand(command: string): string {\n return command.replace(SECRET_COMMAND_PATTERN, (_fullMatch, commandName: string) => {\n return `${commandName.toUpperCase()} ${REDACTED}`;\n });\n}\n\n/**\n * Recursively redacts strings, arrays, and plain object values.\n *\n * @param value - Arbitrary value to sanitize for diagnostics.\n * @returns A redacted copy for arrays and objects, or the original primitive value.\n */\nexport function redactValue(value: unknown): unknown {\n if (typeof value === \"string\") {\n return redactCommand(value);\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => redactValue(item));\n }\n\n if (value !== null && typeof value === \"object\") {\n return redactObject(value as Record<string, unknown>);\n }\n\n return value;\n}\n\n/**\n * Redacts sensitive keys and nested values in a plain object.\n *\n * @param input - Object containing diagnostic fields.\n * @returns A shallow object copy with sensitive fields and nested secrets redacted.\n */\nexport function redactObject(input: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(input).map(([key, value]) => {\n if (isSensitiveKey(key)) {\n return [key, REDACTED];\n }\n\n if (URL_KEY_PATTERN.test(key) && typeof value === \"string\") {\n return [key, redactUrlForLogging(value)];\n }\n\n return [key, redactValue(value)];\n }),\n );\n}\n\n/**\n * Strips credentials and query/fragment content from a URL before logging.\n *\n * Query strings routinely carry bearer material - SigV4 `X-Amz-Signature`\n * values, SAS tokens, signed-URL parameters - so the entire search and hash\n * segments are replaced rather than filtered key-by-key. Embedded\n * `user:password@` userinfo is removed. Origin and pathname are preserved\n * because they are what operators need to correlate a failing request.\n *\n * @param url - Absolute URL string or `URL` instance to sanitize.\n * @returns A loggable URL string, or {@link REDACTED} when the value cannot be\n * parsed as a URL (an unparsable value may still embed credentials).\n */\nexport function redactUrlForLogging(url: string | URL): string {\n let parsed: URL;\n try {\n parsed = typeof url === \"string\" ? new URL(url) : url;\n } catch {\n return REDACTED;\n }\n\n const origin = parsed.host.length > 0 ? `${parsed.protocol}//${parsed.host}` : parsed.protocol;\n const query = parsed.search.length > 0 ? `?${REDACTED}` : \"\";\n return `${origin}${parsed.pathname}${query}`;\n}\n\n/**\n * Converts an arbitrary thrown value into a JSON-safe, secret-free record.\n *\n * Structured SDK errors are serialized through their `toJSON()` (which already\n * redacts details); plain errors contribute name/message/stack-free context;\n * other values are stringified. Use this at every internal log site that\n * records a caught error.\n *\n * @param error - Caught value of unknown shape.\n * @returns A redacted, JSON-safe object describing the error.\n */\nexport function redactErrorForLogging(error: unknown): Record<string, unknown> {\n if (error !== null && typeof error === \"object\") {\n const candidate = error as { toJSON?: () => Record<string, unknown> };\n if (typeof candidate.toJSON === \"function\") {\n return redactObject(candidate.toJSON());\n }\n }\n\n if (error instanceof Error) {\n return redactObject({ message: error.message, name: error.name });\n }\n\n return { message: redactValue(typeof error === \"string\" ? error : String(error)) };\n}\n","/**\n * Structured ZeroTransfer error hierarchy.\n *\n * The classes in this module preserve protocol details, retryability, command/path\n * context, and machine-readable codes so application code does not need to parse\n * human error messages.\n *\n * @module errors/ZeroTransferError\n */\nimport { redactCommand, redactObject } from \"../logging/redaction\";\nimport type { RemoteProtocol } from \"../types/public\";\n\n/**\n * Complete set of fields required to create a ZeroTransfer error.\n */\nexport interface ZeroTransferErrorDetails {\n /** Stable machine-readable error code. */\n code: string;\n /** Human-readable error message safe to show in logs or diagnostics. */\n message: string;\n /** Original error or exception that caused this error. */\n cause?: unknown;\n /** Protocol active when the error occurred. */\n protocol?: RemoteProtocol;\n /** Remote host associated with the failing operation. */\n host?: string;\n /** Protocol command associated with the failure, if any. */\n command?: string;\n /** FTP response code associated with the failure. */\n ftpCode?: number;\n /** SFTP status code associated with the failure. */\n sftpCode?: number;\n /** Remote path associated with the failure. */\n path?: string;\n /** Whether retry policy may safely retry this failure. */\n retryable: boolean;\n /** Additional structured details for diagnostics. */\n details?: Record<string, unknown>;\n}\n\n/**\n * Error construction input for subclasses that provide default codes.\n */\nexport type SpecializedErrorDetails = Omit<ZeroTransferErrorDetails, \"code\"> & {\n /** Optional override for the subclass default code. */\n code?: string;\n};\n\n/**\n * Base class for all typed ZeroTransfer errors.\n */\nexport class ZeroTransferError extends Error {\n /** Stable machine-readable error code. */\n readonly code: string;\n /** Protocol active when the error occurred. */\n readonly protocol?: RemoteProtocol;\n /** Remote host associated with the failing operation. */\n readonly host?: string;\n /** Protocol command associated with the failure, if any. */\n readonly command?: string;\n /** FTP response code associated with the failure. */\n readonly ftpCode?: number;\n /** SFTP status code associated with the failure. */\n readonly sftpCode?: number;\n /** Remote path associated with the failure. */\n readonly path?: string;\n /** Whether retry policy may safely retry this failure. */\n readonly retryable: boolean;\n /** Additional structured details for diagnostics. */\n readonly details?: Record<string, unknown>;\n\n /**\n * Creates a structured SDK error.\n *\n * @param details - Code, message, retryability, and optional protocol context.\n */\n constructor(details: ZeroTransferErrorDetails) {\n super(details.message, details.cause === undefined ? undefined : { cause: details.cause });\n this.name = new.target.name;\n this.code = details.code;\n this.retryable = details.retryable;\n\n if (details.protocol !== undefined) this.protocol = details.protocol;\n if (details.host !== undefined) this.host = details.host;\n if (details.command !== undefined) this.command = details.command;\n if (details.ftpCode !== undefined) this.ftpCode = details.ftpCode;\n if (details.sftpCode !== undefined) this.sftpCode = details.sftpCode;\n if (details.path !== undefined) this.path = details.path;\n if (details.details !== undefined) this.details = details.details;\n }\n\n /**\n * Serializes the error into a plain object suitable for logs or API responses.\n *\n * `details` and `command` are passed through secret redaction so serialized\n * errors never leak credentials, signed URLs, or raw protocol commands. The\n * live {@link ZeroTransferError.details | details} property stays unredacted\n * for programmatic consumers.\n *\n * @returns A JSON-safe object containing public structured error fields.\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n protocol: this.protocol,\n host: this.host,\n command: this.command === undefined ? undefined : redactCommand(this.command),\n ftpCode: this.ftpCode,\n sftpCode: this.sftpCode,\n path: this.path,\n retryable: this.retryable,\n details: this.details === undefined ? undefined : redactObject(this.details),\n };\n }\n}\n\n/**\n * Applies a subclass default code while preserving caller overrides.\n *\n * @param details - Subclass error details with optional code override.\n * @param code - Default code for the specific subclass.\n * @returns Complete base error details.\n */\nfunction withDefaultCode(details: SpecializedErrorDetails, code: string): ZeroTransferErrorDetails {\n return {\n ...details,\n code: details.code ?? code,\n };\n}\n\n/** Error raised when a remote connection cannot be opened or is lost unexpectedly. */\nexport class ConnectionError extends ZeroTransferError {\n /**\n * Creates a connection failure.\n *\n * @param details - Error context with optional host, protocol, and retryability details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_CONNECTION_ERROR\"));\n }\n}\n\n/** Error raised when authentication credentials are rejected. */\nexport class AuthenticationError extends ZeroTransferError {\n /**\n * Creates an authentication failure.\n *\n * @param details - Error context with optional host, protocol, and command details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_AUTHENTICATION_ERROR\"));\n }\n}\n\n/** Error raised when authenticated credentials are not authorized for an operation. */\nexport class AuthorizationError extends ZeroTransferError {\n /**\n * Creates an authorization failure.\n *\n * @param details - Error context with optional path and protocol details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_AUTHORIZATION_ERROR\"));\n }\n}\n\n/** Error raised when a requested remote path does not exist. */\nexport class PathNotFoundError extends ZeroTransferError {\n /**\n * Creates a missing-path failure.\n *\n * @param details - Error context with optional path and protocol details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_PATH_NOT_FOUND\"));\n }\n}\n\n/** Error raised when a create or rename operation targets an existing path. */\nexport class PathAlreadyExistsError extends ZeroTransferError {\n /**\n * Creates an already-exists failure.\n *\n * @param details - Error context with optional path and command details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_PATH_ALREADY_EXISTS\"));\n }\n}\n\n/** Error raised when the remote server denies access to a path or command. */\nexport class PermissionDeniedError extends ZeroTransferError {\n /**\n * Creates a permission failure.\n *\n * @param details - Error context with optional path, command, and protocol details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_PERMISSION_DENIED\"));\n }\n}\n\n/** Error raised when an operation exceeds its configured timeout. */\nexport class TimeoutError extends ZeroTransferError {\n /**\n * Creates a timeout failure.\n *\n * @param details - Error context with optional duration and retryability details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_TIMEOUT\"));\n }\n}\n\n/** Error raised when an operation is cancelled by an AbortSignal or caller action. */\nexport class AbortError extends ZeroTransferError {\n /**\n * Creates an aborted-operation failure.\n *\n * @param details - Error context with optional operation and path details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_ABORTED\"));\n }\n}\n\n/** Error raised when a server response violates protocol expectations. */\nexport class ProtocolError extends ZeroTransferError {\n /**\n * Creates a protocol failure.\n *\n * @param details - Error context with optional response code and command details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_PROTOCOL_ERROR\"));\n }\n}\n\n/** Error raised when protocol text or metadata cannot be parsed safely. */\nexport class ParseError extends ZeroTransferError {\n /**\n * Creates a parser failure.\n *\n * @param details - Error context with malformed input details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_PARSE_ERROR\"));\n }\n}\n\n/** Error raised when an upload, download, or stream transfer fails. */\nexport class TransferError extends ZeroTransferError {\n /**\n * Creates a transfer failure.\n *\n * @param details - Error context with optional path, bytes, and retryability details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_TRANSFER_ERROR\"));\n }\n}\n\n/** Error raised when post-transfer verification fails. */\nexport class VerificationError extends ZeroTransferError {\n /**\n * Creates a verification failure.\n *\n * @param details - Error context with checksum, size, or timestamp mismatch details.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_VERIFICATION_ERROR\"));\n }\n}\n\n/** Error raised when a requested protocol feature is not implemented or unavailable. */\nexport class UnsupportedFeatureError extends ZeroTransferError {\n /**\n * Creates an unsupported-feature failure.\n *\n * @param details - Error context describing the missing feature or adapter.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_UNSUPPORTED_FEATURE\"));\n }\n}\n\n/** Error raised when user-provided options or paths are invalid before network I/O. */\nexport class ConfigurationError extends ZeroTransferError {\n /**\n * Creates a configuration failure.\n *\n * @param details - Error context describing the invalid option or argument.\n */\n constructor(details: SpecializedErrorDetails) {\n super(withDefaultCode(details, \"ZERO_TRANSFER_CONFIGURATION_ERROR\"));\n }\n}\n","/**\n * Structured logging contracts and helpers for ZeroTransfer.\n *\n * The logger shape is intentionally compatible with popular structured loggers while\n * staying small enough for applications to implement directly.\n *\n * @module logging/Logger\n */\n/** Supported ZeroTransfer log levels. */\nexport type LogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n\n/**\n * Complete structured log record emitted by ZeroTransfer helpers.\n */\nexport interface LogRecord {\n /** Severity level for the record. */\n level: LogLevel;\n /** Human-readable summary message. */\n message: string;\n /** SDK component that produced the record. */\n component?: string;\n /** Active protocol for the record. */\n protocol?: string;\n /** Remote host associated with the record. */\n host?: string;\n /** Correlation id for a connection lifecycle. */\n connectionId?: string;\n /** Correlation id for a protocol command. */\n commandId?: string;\n /** Correlation id for a transfer lifecycle. */\n transferId?: string;\n /** Remote or local path associated with the record. */\n path?: string;\n /** Operation duration in milliseconds. */\n durationMs?: number;\n /** Byte count associated with the operation. */\n bytes?: number;\n /** Additional structured fields supplied by adapters or services. */\n [key: string]: unknown;\n}\n\n/**\n * Log record input accepted by {@link emitLog}; the helper adds the level.\n */\nexport interface LogRecordInput extends Omit<LogRecord, \"level\"> {\n /** Human-readable summary message. */\n message: string;\n}\n\n/**\n * Logger method signature used for each severity level.\n *\n * @param record - Structured log record.\n * @param message - Convenience message argument for console-like loggers.\n */\nexport type LoggerMethod = (record: LogRecord, message?: string) => void;\n\n/**\n * Partial structured logger accepted by ZeroTransfer.\n */\nexport interface ZeroTransferLogger {\n /** Receives highly detailed diagnostic records. */\n trace?: LoggerMethod;\n /** Receives development/debugging records. */\n debug?: LoggerMethod;\n /** Receives normal lifecycle records. */\n info?: LoggerMethod;\n /** Receives recoverable issue records. */\n warn?: LoggerMethod;\n /** Receives failed operation records. */\n error?: LoggerMethod;\n}\n\n/**\n * Logger implementation that intentionally drops every record.\n */\nexport const noopLogger: Required<ZeroTransferLogger> = {\n trace() {},\n debug() {},\n info() {},\n warn() {},\n error() {},\n};\n\n/**\n * Emits a structured log record if the logger implements the requested level.\n *\n * @param logger - Logger that may contain a method for the requested level.\n * @param level - Severity level to emit.\n * @param record - Log record fields without the level property.\n * @returns Nothing; missing logger methods are ignored.\n */\nexport function emitLog(logger: ZeroTransferLogger, level: LogLevel, record: LogRecordInput): void {\n const method = logger[level];\n\n if (method === undefined) {\n return;\n }\n\n const logRecord: LogRecord = {\n ...record,\n level,\n };\n\n method(logRecord, logRecord.message);\n}\n","/**\n * Connection profile validation helpers.\n *\n * @module profiles/ProfileValidator\n */\nimport { Buffer } from \"node:buffer\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { ConnectionProfile, SshProfile, TlsProfile } from \"../types/public\";\nimport { resolveProviderId } from \"../core/ProviderId\";\n\n/** TLS protocol versions accepted by Node's `SecureVersion` option. */\nconst TLS_VERSIONS = new Set([\"TLSv1\", \"TLSv1.1\", \"TLSv1.2\", \"TLSv1.3\"]);\n/** Hex characters in a SHA-256 certificate fingerprint after separators are removed. */\nconst SHA256_FINGERPRINT_HEX_LENGTH = 64;\n/** Raw SHA-256 digest byte length. */\nconst SHA256_DIGEST_BYTE_LENGTH = 32;\n\n/**\n * Validates provider-neutral connection profile fields before provider lookup.\n *\n * @param profile - Profile to validate.\n * @returns The original profile when valid.\n * @throws {@link ConfigurationError} When required provider, host, or numeric fields are invalid.\n */\nexport function validateConnectionProfile(profile: ConnectionProfile): ConnectionProfile {\n if (resolveProviderId(profile) === undefined) {\n throw new ConfigurationError({\n message: \"Connection profiles must include a provider or protocol\",\n retryable: false,\n });\n }\n\n if (profile.host.trim().length === 0) {\n throw new ConfigurationError({\n message: \"Connection profiles must include a non-empty host\",\n retryable: false,\n });\n }\n\n if (profile.port !== undefined && !isValidPort(profile.port)) {\n throw new ConfigurationError({\n details: { port: profile.port },\n message: \"Connection profile port must be an integer between 1 and 65535\",\n retryable: false,\n });\n }\n\n if (profile.timeoutMs !== undefined && !isPositiveFiniteNumber(profile.timeoutMs)) {\n throw new ConfigurationError({\n details: { timeoutMs: profile.timeoutMs },\n message: \"Connection profile timeoutMs must be a positive finite number\",\n retryable: false,\n });\n }\n\n if (profile.tls !== undefined) {\n validateTlsProfile(profile.tls);\n }\n\n if (profile.ssh !== undefined) {\n validateSshProfile(profile.ssh);\n }\n\n return profile;\n}\n\n/**\n * Validates SSH profile policy fields that can be checked without resolving secrets.\n *\n * @param profile - SSH profile to validate.\n * @throws {@link ConfigurationError} When host-key pin values are invalid.\n */\nfunction validateSshProfile(profile: SshProfile): void {\n validatePinnedHostKeySha256(profile.pinnedHostKeySha256);\n\n if (profile.algorithms !== undefined) {\n validateSshAlgorithms(profile.algorithms);\n }\n\n if (profile.agent !== undefined) {\n validateSshAgentSource(profile.agent);\n }\n\n if (\n profile.keyboardInteractive !== undefined &&\n typeof profile.keyboardInteractive !== \"function\"\n ) {\n throw new ConfigurationError({\n details: { keyboardInteractive: typeof profile.keyboardInteractive },\n message: \"Connection profile ssh.keyboardInteractive must be a function when provided\",\n retryable: false,\n });\n }\n\n if (profile.socketFactory !== undefined && typeof profile.socketFactory !== \"function\") {\n throw new ConfigurationError({\n details: { socketFactory: typeof profile.socketFactory },\n message: \"Connection profile ssh.socketFactory must be a function when provided\",\n retryable: false,\n });\n }\n}\n\n/**\n * Validates SSH algorithm override shape without duplicating ssh2's literal unions.\n *\n * @param value - Algorithm override object from an SSH profile.\n * @throws {@link ConfigurationError} When overrides are not object-shaped or contain empty lists.\n */\nfunction validateSshAlgorithms(value: SshProfile[\"algorithms\"]): void {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw createSshAlgorithmsError(value);\n }\n\n const algorithms = value as Record<string, unknown>;\n\n for (const [name, list] of Object.entries(algorithms)) {\n if (list === undefined) {\n continue;\n }\n\n if (Array.isArray(list)) {\n if (!isNonEmptyStringArray(list)) {\n throw createSshAlgorithmsError({ [name]: list });\n }\n\n continue;\n }\n\n if (typeof list !== \"object\" || list === null || Array.isArray(list)) {\n throw createSshAlgorithmsError({ [name]: list });\n }\n\n const operationLists = list as Record<string, unknown>;\n\n for (const [operation, operationList] of Object.entries(operationLists)) {\n if (![\"append\", \"prepend\", \"remove\"].includes(operation)) {\n throw createSshAlgorithmsError({ [name]: list });\n }\n\n if (\n typeof operationList !== \"string\" &&\n (!Array.isArray(operationList) || !isNonEmptyStringArray(operationList))\n ) {\n throw createSshAlgorithmsError({ [name]: list });\n }\n }\n }\n}\n\nfunction isNonEmptyStringArray(value: unknown[]): value is string[] {\n return value.length > 0 && value.every((item) => typeof item === \"string\" && item.length > 0);\n}\n\n/**\n * Validates SSH agent source values.\n *\n * @param value - Agent socket path or agent implementation.\n * @throws {@link ConfigurationError} When the value is neither a non-empty path nor an agent object.\n */\nfunction validateSshAgentSource(value: SshProfile[\"agent\"]): void {\n if (typeof value === \"string\") {\n if (value.trim().length > 0) {\n return;\n }\n } else if (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { getIdentities?: unknown }).getIdentities === \"function\" &&\n typeof (value as { sign?: unknown }).sign === \"function\"\n ) {\n return;\n }\n\n throw new ConfigurationError({\n details: { agent: typeof value },\n message: \"Connection profile ssh.agent must be a non-empty socket path or agent object\",\n retryable: false,\n });\n}\n\n/**\n * Validates TLS profile policy fields that can be checked without resolving secrets.\n *\n * @param profile - TLS profile to validate.\n * @throws {@link ConfigurationError} When server name, boolean, or TLS-version fields are invalid.\n */\nfunction validateTlsProfile(profile: TlsProfile): void {\n if (profile.servername !== undefined && profile.servername.trim().length === 0) {\n throw new ConfigurationError({\n message: \"Connection profile tls.servername must be non-empty when provided\",\n retryable: false,\n });\n }\n\n if (profile.rejectUnauthorized !== undefined && typeof profile.rejectUnauthorized !== \"boolean\") {\n throw new ConfigurationError({\n details: { rejectUnauthorized: profile.rejectUnauthorized },\n message: \"Connection profile tls.rejectUnauthorized must be a boolean\",\n retryable: false,\n });\n }\n\n validateTlsVersion(profile.minVersion, \"minVersion\");\n validateTlsVersion(profile.maxVersion, \"maxVersion\");\n validatePinnedFingerprint256(profile.pinnedFingerprint256);\n}\n\n/**\n * Validates SHA-256 certificate fingerprint pinning values.\n *\n * @param value - Single fingerprint or allowed fingerprint set from the TLS profile.\n * @throws {@link ConfigurationError} When a fingerprint is empty or not SHA-256 hex.\n */\nfunction validatePinnedFingerprint256(value: TlsProfile[\"pinnedFingerprint256\"]): void {\n if (value === undefined) {\n return;\n }\n\n const fingerprints = Array.isArray(value) ? value : [value];\n\n if (fingerprints.length === 0) {\n throw createPinnedFingerprintError(value);\n }\n\n for (const fingerprint of fingerprints) {\n if (typeof fingerprint !== \"string\" || !isSha256Fingerprint(fingerprint)) {\n throw createPinnedFingerprintError(value);\n }\n }\n}\n\n/**\n * Validates SHA-256 SSH host-key pinning values.\n *\n * @param value - Single fingerprint or allowed fingerprint set from the SSH profile.\n * @throws {@link ConfigurationError} When a fingerprint is empty or not a SHA-256 digest.\n */\nfunction validatePinnedHostKeySha256(value: SshProfile[\"pinnedHostKeySha256\"]): void {\n if (value === undefined) {\n return;\n }\n\n const fingerprints = Array.isArray(value) ? value : [value];\n\n if (fingerprints.length === 0) {\n throw createPinnedHostKeyError(value);\n }\n\n for (const fingerprint of fingerprints) {\n if (typeof fingerprint !== \"string\" || !isSshHostKeySha256Fingerprint(fingerprint)) {\n throw createPinnedHostKeyError(value);\n }\n }\n}\n\n/**\n * Checks whether a string is a supported SHA-256 certificate fingerprint.\n *\n * @param value - Candidate fingerprint string.\n * @returns `true` when the value is 64 hex characters after optional colons are removed.\n */\nfunction isSha256Fingerprint(value: string): boolean {\n const normalized = value.trim().replace(/:/g, \"\");\n return normalized.length === SHA256_FINGERPRINT_HEX_LENGTH && /^[a-f0-9]+$/i.test(normalized);\n}\n\n/**\n * Checks whether a string is a supported SSH SHA-256 host-key fingerprint.\n *\n * @param value - Candidate fingerprint string.\n * @returns `true` when the value is OpenSSH SHA256 base64, bare base64, or SHA-256 hex.\n */\nfunction isSshHostKeySha256Fingerprint(value: string): boolean {\n const trimmed = value.trim();\n\n if (isSha256Fingerprint(trimmed)) {\n return true;\n }\n\n const bare = trimmed.startsWith(\"SHA256:\") ? trimmed.slice(\"SHA256:\".length) : trimmed;\n const padded = padBase64(bare);\n\n if (!/^[a-z0-9+/]+={0,2}$/i.test(padded)) {\n return false;\n }\n\n try {\n return Buffer.from(padded, \"base64\").byteLength === SHA256_DIGEST_BYTE_LENGTH;\n } catch {\n return false;\n }\n}\n\nfunction padBase64(value: string): string {\n const remainder = value.length % 4;\n\n return remainder === 0 ? value : `${value}${\"=\".repeat(4 - remainder)}`;\n}\n\n/**\n * Creates a consistent validation error for invalid certificate pin values.\n *\n * @param value - Invalid profile value included in diagnostics.\n * @returns Configuration error describing the supported fingerprint format.\n */\nfunction createPinnedFingerprintError(value: unknown): ConfigurationError {\n return new ConfigurationError({\n details: { pinnedFingerprint256: value },\n message:\n \"Connection profile tls.pinnedFingerprint256 must be a SHA-256 hex fingerprint or non-empty array of fingerprints\",\n retryable: false,\n });\n}\n\n/**\n * Creates a consistent validation error for invalid SSH host-key pin values.\n *\n * @param value - Invalid profile value included in diagnostics.\n * @returns Configuration error describing the supported fingerprint formats.\n */\nfunction createPinnedHostKeyError(value: unknown): ConfigurationError {\n return new ConfigurationError({\n details: { pinnedHostKeySha256: value },\n message:\n \"Connection profile ssh.pinnedHostKeySha256 must be an OpenSSH SHA256, base64, or hex fingerprint or non-empty array of fingerprints\",\n retryable: false,\n });\n}\n\n/**\n * Creates a consistent validation error for invalid SSH algorithm overrides.\n *\n * @param value - Invalid profile value included in diagnostics.\n * @returns Configuration error describing the expected ssh2-compatible shape.\n */\nfunction createSshAlgorithmsError(value: unknown): ConfigurationError {\n return new ConfigurationError({\n details: { algorithms: value },\n message: \"Connection profile ssh.algorithms must use SSH-compatible non-empty algorithm lists\",\n retryable: false,\n });\n}\n\n/**\n * Validates a configured TLS protocol version string.\n *\n * @param value - TLS version value from the profile, if provided.\n * @param field - Profile field name used in diagnostics.\n * @throws {@link ConfigurationError} When the value is not one of Node's supported TLS versions.\n */\nfunction validateTlsVersion(value: TlsProfile[\"minVersion\"], field: string): void {\n if (value === undefined) {\n return;\n }\n\n if (!TLS_VERSIONS.has(value)) {\n throw new ConfigurationError({\n details: { [field]: value },\n message: `Connection profile tls.${field} must be a supported TLS version`,\n retryable: false,\n });\n }\n}\n\nfunction isValidPort(value: number): boolean {\n return Number.isInteger(value) && value >= 1 && value <= 65_535;\n}\n\nfunction isPositiveFiniteNumber(value: number): boolean {\n return Number.isFinite(value) && value > 0;\n}\n","/**\n * Provider identifiers used by the provider-neutral ZeroTransfer core.\n *\n * @module core/ProviderId\n */\n\n/** Classic remote-transfer providers kept compatible with the original protocol field. */\nexport const CLASSIC_PROVIDER_IDS = [\"ftp\", \"ftps\", \"sftp\"] as const;\n\n/** Provider ids that map directly to the original protocol-focused alpha facade. */\nexport type ClassicProviderId = (typeof CLASSIC_PROVIDER_IDS)[number];\n\n/** Provider ids reserved for first-party ZeroTransfer adapters. */\nexport type BuiltInProviderId =\n | ClassicProviderId\n | \"memory\"\n | \"local\"\n | \"http\"\n | \"https\"\n | \"webdav\"\n | \"s3\"\n | \"azure-blob\"\n | \"gcs\"\n | \"dropbox\"\n | \"google-drive\"\n | \"one-drive\";\n\n/** Provider identifier accepted by registries, profiles, and provider factories. */\nexport type ProviderId = BuiltInProviderId | (string & {});\n\n/** Minimal shape used to resolve a provider from new and compatibility profile fields. */\nexport interface ProviderSelection {\n /** Provider id for provider-neutral ZeroTransfer profiles. */\n provider?: ProviderId;\n /** Compatibility protocol field accepted while the provider-neutral API rolls out. */\n protocol?: ClassicProviderId;\n}\n\n/**\n * Checks whether a provider id belongs to the classic FTP/FTPS/SFTP family.\n *\n * @param providerId - Provider id to inspect.\n * @returns `true` when the id is one of the classic protocol providers.\n */\nexport function isClassicProviderId(\n providerId: ProviderId | undefined,\n): providerId is ClassicProviderId {\n return (\n typeof providerId === \"string\" && CLASSIC_PROVIDER_IDS.includes(providerId as ClassicProviderId)\n );\n}\n\n/**\n * Resolves the provider id from a profile, preferring the new `provider` field.\n *\n * @param selection - Profile-like object containing provider and/or protocol fields.\n * @returns The selected provider id, or `undefined` when neither field is present.\n */\nexport function resolveProviderId(selection: ProviderSelection): ProviderId | undefined {\n return selection.provider ?? selection.protocol;\n}\n","/**\n * Provider registry for the provider-neutral ZeroTransfer core.\n *\n * @module core/ProviderRegistry\n */\nimport { ConfigurationError, UnsupportedFeatureError } from \"../errors/ZeroTransferError\";\nimport type { ProviderFactory } from \"../providers/ProviderFactory\";\nimport type { CapabilitySet } from \"./CapabilitySet\";\nimport type { ProviderId } from \"./ProviderId\";\n\n/** Mutable registry of provider factories available to a transfer client. */\nexport class ProviderRegistry {\n private readonly factories = new Map<ProviderId, ProviderFactory>();\n\n /**\n * Creates a registry and optionally seeds it with provider factories.\n *\n * @param providers - Provider factories to register immediately.\n */\n constructor(providers: Iterable<ProviderFactory> = []) {\n for (const provider of providers) {\n this.register(provider);\n }\n }\n\n /**\n * Registers a provider factory.\n *\n * @param provider - Provider factory to add.\n * @returns This registry for fluent setup.\n * @throws {@link ConfigurationError} When a provider id is registered twice.\n */\n register(provider: ProviderFactory): this {\n if (this.factories.has(provider.id)) {\n throw new ConfigurationError({\n details: { provider: provider.id },\n message: `Provider \"${provider.id}\" is already registered`,\n retryable: false,\n });\n }\n\n this.factories.set(provider.id, provider);\n return this;\n }\n\n /**\n * Removes a provider factory from the registry.\n *\n * @param providerId - Provider id to remove.\n * @returns `true` when a provider was removed.\n */\n unregister(providerId: ProviderId): boolean {\n return this.factories.delete(providerId);\n }\n\n /**\n * Checks whether a provider id is registered.\n *\n * @param providerId - Provider id to inspect.\n * @returns `true` when a provider factory exists.\n */\n has(providerId: ProviderId): boolean {\n return this.factories.has(providerId);\n }\n\n /**\n * Gets a provider factory when registered.\n *\n * @param providerId - Provider id to retrieve.\n * @returns The provider factory, or `undefined` when missing.\n */\n get(providerId: ProviderId): ProviderFactory | undefined {\n return this.factories.get(providerId);\n }\n\n /**\n * Gets a registered provider factory or throws a typed SDK error.\n *\n * @param providerId - Provider id to retrieve.\n * @returns The registered provider factory.\n * @throws {@link UnsupportedFeatureError} When no provider has been registered.\n */\n require(providerId: ProviderId): ProviderFactory {\n const provider = this.get(providerId);\n\n if (provider === undefined) {\n throw new UnsupportedFeatureError({\n details: { provider: providerId },\n message: `Provider \"${providerId}\" is not registered`,\n retryable: false,\n });\n }\n\n return provider;\n }\n\n /**\n * Gets a provider capability snapshot when registered.\n *\n * @param providerId - Provider id to inspect.\n * @returns Capability snapshot, or `undefined` when missing.\n */\n getCapabilities(providerId: ProviderId): CapabilitySet | undefined {\n return this.get(providerId)?.capabilities;\n }\n\n /**\n * Gets a provider capability snapshot or throws a typed SDK error.\n *\n * @param providerId - Provider id to inspect.\n * @returns Capability snapshot for the registered provider.\n * @throws {@link UnsupportedFeatureError} When no provider has been registered.\n */\n requireCapabilities(providerId: ProviderId): CapabilitySet {\n return this.require(providerId).capabilities;\n }\n\n /**\n * Lists registered provider factories in insertion order.\n *\n * @returns Registered provider factories.\n */\n list(): ProviderFactory[] {\n return [...this.factories.values()];\n }\n\n /**\n * Lists registered provider capabilities in insertion order.\n *\n * @returns Capability snapshots for every registered provider.\n */\n listCapabilities(): CapabilitySet[] {\n return this.list().map((provider) => provider.capabilities);\n }\n}\n","/**\n * Provider-neutral transfer client foundation.\n *\n * @module core/TransferClient\n */\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport {\n emitLog,\n noopLogger,\n type LogRecordInput,\n type ZeroTransferLogger,\n} from \"../logging/Logger\";\nimport { validateConnectionProfile } from \"../profiles/ProfileValidator\";\nimport type { ProviderFactory } from \"../providers/ProviderFactory\";\nimport type { TransferRetryPolicy } from \"../transfers/TransferEngine\";\nimport type { TransferTimeoutPolicy } from \"../transfers/TransferJob\";\nimport type { ConnectionProfile } from \"../types/public\";\nimport type { CapabilitySet } from \"./CapabilitySet\";\nimport type { ProviderId } from \"./ProviderId\";\nimport { isClassicProviderId, resolveProviderId } from \"./ProviderId\";\nimport { ProviderRegistry } from \"./ProviderRegistry\";\nimport type { TransferSession } from \"./TransferSession\";\n\n/**\n * Client-level execution defaults applied when a call site does not supply\n * its own value.\n *\n * Defaults are consumed by {@link runRoute}, the one-shot helpers\n * ({@link uploadFile}, {@link downloadFile}, {@link copyBetween}),\n * {@link TransferQueue} (via its `client` option), and scheduled routes fired\n * through {@link MftScheduler}. The {@link TransferEngine} primitive stays\n * fully explicit: defaults never reach `engine.execute()` directly.\n *\n * Per-call options always win over client defaults.\n *\n * Additional default slots (`verify`, `resume`, `compression`, `policy`) land\n * here as their features ship in later releases; the shape is additive.\n *\n * @example Resilient defaults for every transfer in an application\n * ```ts\n * import { createDefaultRetryPolicy, createTransferClient } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({\n * providers: [createSftpProviderFactory(), createS3ProviderFactory()],\n * defaults: {\n * retry: createDefaultRetryPolicy(),\n * timeout: { stallTimeoutMs: 30_000 },\n * },\n * });\n * ```\n */\nexport interface TransferClientDefaults {\n /** Default retry policy for transfers executed through this client. */\n retry?: TransferRetryPolicy;\n /** Default timeout policy for transfers executed through this client. */\n timeout?: TransferTimeoutPolicy;\n}\n\n/** Options used to create a provider-neutral transfer client. */\nexport interface TransferClientOptions {\n /** Existing registry to reuse. When omitted, a fresh empty registry is created. */\n registry?: ProviderRegistry;\n /** Provider factories to register with the client registry. */\n providers?: ProviderFactory[];\n /** Structured logger used for client lifecycle records. */\n logger?: ZeroTransferLogger;\n /** Execution defaults applied when call sites omit their own values. */\n defaults?: TransferClientDefaults;\n}\n\n/** Small provider-neutral client that owns provider lookup and connection setup. */\nexport class TransferClient {\n /** Provider registry used by this client. */\n readonly registry: ProviderRegistry;\n\n /** Execution defaults applied when call sites omit their own values. */\n readonly defaults?: TransferClientDefaults;\n\n private readonly logger: ZeroTransferLogger;\n\n /**\n * Creates a transfer client without opening any provider connections.\n *\n * @param options - Optional registry, provider factories, logger, and execution defaults.\n */\n constructor(options: TransferClientOptions = {}) {\n this.registry = options.registry ?? new ProviderRegistry();\n this.logger = options.logger ?? noopLogger;\n if (options.defaults !== undefined) {\n this.defaults = { ...options.defaults };\n }\n\n for (const provider of options.providers ?? []) {\n this.registry.register(provider);\n }\n }\n\n /**\n * Registers a provider factory with this client's registry.\n *\n * @param provider - Provider factory to register.\n * @returns This client for fluent setup.\n */\n registerProvider(provider: ProviderFactory): this {\n this.registry.register(provider);\n return this;\n }\n\n /**\n * Checks whether this client can create sessions for a provider id.\n *\n * @param providerId - Provider id to inspect.\n * @returns `true` when a provider factory is registered.\n */\n hasProvider(providerId: ProviderId): boolean {\n return this.registry.has(providerId);\n }\n\n /** Lists all registered provider capability snapshots. */\n getCapabilities(): CapabilitySet[];\n /** Gets a specific provider capability snapshot. */\n getCapabilities(providerId: ProviderId): CapabilitySet;\n getCapabilities(providerId?: ProviderId): CapabilitySet | CapabilitySet[] {\n if (providerId === undefined) {\n return this.registry.listCapabilities();\n }\n\n return this.registry.requireCapabilities(providerId);\n }\n\n /**\n * Opens a provider session using `profile.provider`, with `profile.protocol` as compatibility fallback.\n *\n * @param profile - Connection profile containing a provider or legacy protocol field.\n * @returns A connected provider session.\n * @throws {@link ConfigurationError} When neither provider nor protocol is present.\n */\n async connect(profile: ConnectionProfile): Promise<TransferSession> {\n const validProfile = validateConnectionProfile(profile);\n const providerId = resolveProviderId(validProfile);\n\n if (providerId === undefined) {\n throw new ConfigurationError({\n message: \"Connection profiles must include a provider or protocol\",\n retryable: false,\n });\n }\n\n const providerFactory = this.registry.require(providerId);\n const provider = providerFactory.create();\n const normalizedProfile: ConnectionProfile = {\n ...validProfile,\n provider: providerId,\n };\n\n if (normalizedProfile.protocol === undefined && isClassicProviderId(providerId)) {\n normalizedProfile.protocol = providerId;\n }\n\n emitLog(this.logger, \"info\", createConnectLogRecord(normalizedProfile, providerId));\n\n return provider.connect(normalizedProfile);\n }\n}\n\nfunction createConnectLogRecord(\n profile: ConnectionProfile,\n providerId: ProviderId,\n): LogRecordInput {\n const record: LogRecordInput = {\n component: \"core\",\n host: profile.host,\n message: \"Connecting through provider\",\n provider: providerId,\n };\n\n if (isClassicProviderId(providerId)) {\n record.protocol = providerId;\n }\n\n return record;\n}\n","/**\n * Factory for provider-neutral ZeroTransfer clients.\n *\n * @module core/createTransferClient\n */\nimport { TransferClient, type TransferClientOptions } from \"./TransferClient\";\n\n/**\n * Creates a provider-neutral transfer client.\n *\n * The returned client owns a registry of provider factories and produces\n * `TransferSession` instances on demand via {@link TransferClient.connect}.\n * Registering only the providers you actually use keeps bundle size small\n * (each factory pulls in its own SDK dependencies).\n *\n * @param options - Optional registry, provider factories, and logger.\n * @returns A disconnected {@link TransferClient} instance.\n *\n * @example Multi-provider client\n * ```ts\n * import {\n * createS3ProviderFactory,\n * createSftpProviderFactory,\n * createTransferClient,\n * } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({\n * providers: [createSftpProviderFactory(), createS3ProviderFactory()],\n * });\n *\n * const session = await client.connect({\n * host: \"sftp.example.com\",\n * provider: \"sftp\",\n * username: \"deploy\",\n * ssh: { privateKey: { path: \"./keys/id_ed25519\" } },\n * });\n * try {\n * const list = await session.fs.list(\"/uploads\");\n * console.log(list);\n * } finally {\n * await session.disconnect();\n * }\n * ```\n *\n * @example Friendly one-shot helpers\n * ```ts\n * import { uploadFile } from \"@zero-transfer/sdk\";\n *\n * await uploadFile({\n * client,\n * destination: { path: \"/uploads/report.csv\", profile },\n * localPath: \"./out/report.csv\",\n * });\n * ```\n */\nexport function createTransferClient(options: TransferClientOptions = {}): TransferClient {\n return new TransferClient(options);\n}\n","/**\n * Friendly one-call helpers built on top of {@link runRoute}.\n *\n * These helpers give applications a quick surface for the common single-file flows\n * (`uploadFile`, `downloadFile`, `copyBetween`) without forcing them to assemble\n * {@link MftRoute} objects directly. Each helper composes a one-shot route and\n * delegates execution to the existing route runner so retry, abort, progress,\n * timeout, and bandwidth controls behave identically to scheduled runs.\n *\n * @module client/operations\n */\nimport { isAbsolute, resolve as resolvePath } from \"node:path\";\nimport type { TransferClient } from \"../core/TransferClient\";\nimport type { MftRoute } from \"../mft/MftRoute\";\nimport { runRoute, type RunRouteOptions } from \"../mft/runRoute\";\nimport type { TransferReceipt } from \"../transfers/TransferJob\";\nimport type { ConnectionProfile } from \"../types/public\";\n\n/** Endpoint shape accepted by the friendly helpers. */\nexport interface RemoteFileEndpoint {\n /** Provider profile used to open the session. */\n profile: ConnectionProfile;\n /** Provider, remote, or local path the helper operates on. */\n path: string;\n}\n\n/** Shared options consumed by {@link uploadFile}, {@link downloadFile}, and {@link copyBetween}. */\nexport type FriendlyTransferOptions = Omit<RunRouteOptions, \"client\" | \"route\"> & {\n /** Stable route id assigned to the synthetic route. Defaults to `\"upload:...\"`, `\"download:...\"`, or `\"copy:...\"`. */\n routeId?: string;\n /** Optional human-readable route name forwarded to telemetry. */\n routeName?: string;\n};\n\n/** Connection profile for the local filesystem provider. */\nconst LOCAL_PROFILE: ConnectionProfile = { host: \"local\", provider: \"local\" };\n\n/** Options for {@link uploadFile}. */\nexport interface UploadFileOptions extends FriendlyTransferOptions {\n /** Transfer client used to resolve both endpoint providers. */\n client: TransferClient;\n /** Local source path. Relative paths are resolved against `process.cwd()`. */\n localPath: string;\n /** Remote destination endpoint. */\n destination: RemoteFileEndpoint;\n}\n\n/**\n * Uploads a single local file to a remote endpoint.\n *\n * The remote provider is resolved from `destination.profile.provider`, so any\n * provider factory you registered with {@link createTransferClient} can be used\n * as the destination.\n *\n * @param options - Friendly upload options.\n * @returns Receipt produced by the underlying transfer engine.\n *\n * @example Upload to SFTP with public-key auth\n * ```ts\n * import {\n * createSftpProviderFactory,\n * createTransferClient,\n * uploadFile,\n * } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({ providers: [createSftpProviderFactory()] });\n *\n * await uploadFile({\n * client,\n * destination: {\n * path: \"/uploads/report.csv\",\n * profile: {\n * host: \"sftp.example.com\",\n * provider: \"sftp\",\n * username: \"deploy\",\n * ssh: { privateKey: { path: \"./keys/id_ed25519\" } },\n * },\n * },\n * localPath: \"./out/report.csv\",\n * });\n * ```\n */\nexport function uploadFile(options: UploadFileOptions): Promise<TransferReceipt> {\n const { client, destination, localPath, routeId, routeName, ...rest } = options;\n const route = buildRoute({\n destination: { path: destination.path, profile: destination.profile },\n id: routeId ?? `upload:${defaultRouteSuffix(localPath, destination.path)}`,\n name: routeName,\n operation: \"upload\",\n source: { path: absolutePath(localPath), profile: LOCAL_PROFILE },\n });\n return runRoute({ client, route, ...rest });\n}\n\n/** Options for {@link downloadFile}. */\nexport interface DownloadFileOptions extends FriendlyTransferOptions {\n /** Transfer client used to resolve both endpoint providers. */\n client: TransferClient;\n /** Remote source endpoint. */\n source: RemoteFileEndpoint;\n /** Local destination path. Relative paths are resolved against `process.cwd()`. */\n localPath: string;\n}\n\n/**\n * Downloads a single remote file to a local path.\n *\n * The remote provider is resolved from `source.profile.provider`. The local\n * destination path is created (including parent directories) on demand.\n *\n * @param options - Friendly download options.\n * @returns Receipt produced by the underlying transfer engine.\n *\n * @example Download from S3\n * ```ts\n * import {\n * createS3ProviderFactory,\n * createTransferClient,\n * downloadFile,\n * } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({ providers: [createS3ProviderFactory()] });\n *\n * await downloadFile({\n * client,\n * localPath: \"./tmp/snapshot.tar.gz\",\n * source: {\n * path: \"snapshots/2026-04-28/snapshot.tar.gz\",\n * profile: {\n * host: \"snapshots\", // S3 bucket\n * provider: \"s3\",\n * s3: { region: \"us-east-1\" },\n * },\n * },\n * });\n * ```\n */\nexport function downloadFile(options: DownloadFileOptions): Promise<TransferReceipt> {\n const { client, localPath, routeId, routeName, source, ...rest } = options;\n const route = buildRoute({\n destination: { path: absolutePath(localPath), profile: LOCAL_PROFILE },\n id: routeId ?? `download:${defaultRouteSuffix(source.path, localPath)}`,\n name: routeName,\n operation: \"download\",\n source: { path: source.path, profile: source.profile },\n });\n return runRoute({ client, route, ...rest });\n}\n\n/** Options for {@link copyBetween}. */\nexport interface CopyBetweenOptions extends FriendlyTransferOptions {\n /** Transfer client used to resolve both endpoint providers. */\n client: TransferClient;\n /** Source remote endpoint. */\n source: RemoteFileEndpoint;\n /** Destination remote endpoint. */\n destination: RemoteFileEndpoint;\n}\n\n/**\n * Copies a file between two remote endpoints in a single call.\n *\n * Both source and destination providers must be registered with the\n * {@link TransferClient}. Streams are piped end-to-end without staging the file\n * on the local disk.\n *\n * @param options - Friendly copy options.\n * @returns Receipt produced by the underlying transfer engine.\n *\n * @example Copy from SFTP to S3\n * ```ts\n * import {\n * copyBetween,\n * createS3ProviderFactory,\n * createSftpProviderFactory,\n * createTransferClient,\n * } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({\n * providers: [createSftpProviderFactory(), createS3ProviderFactory()],\n * });\n *\n * await copyBetween({\n * client,\n * source: {\n * path: \"/exports/daily.csv\",\n * profile: { host: \"sftp.example.com\", provider: \"sftp\", username: \"etl\" },\n * },\n * destination: {\n * path: \"warehouse/daily.csv\",\n * profile: { host: \"warehouse\", provider: \"s3\", s3: { region: \"us-east-1\" } },\n * },\n * });\n * ```\n */\nexport function copyBetween(options: CopyBetweenOptions): Promise<TransferReceipt> {\n const { client, destination, routeId, routeName, source, ...rest } = options;\n const route = buildRoute({\n destination: { path: destination.path, profile: destination.profile },\n id: routeId ?? `copy:${defaultRouteSuffix(source.path, destination.path)}`,\n name: routeName,\n operation: \"copy\",\n source: { path: source.path, profile: source.profile },\n });\n return runRoute({ client, route, ...rest });\n}\n\ninterface BuildRouteInput {\n id: string;\n name?: string | undefined;\n operation: NonNullable<MftRoute[\"operation\"]>;\n source: MftRoute[\"source\"];\n destination: MftRoute[\"destination\"];\n}\n\nfunction buildRoute(input: BuildRouteInput): MftRoute {\n const route: MftRoute = {\n destination: input.destination,\n id: input.id,\n operation: input.operation,\n source: input.source,\n };\n if (input.name !== undefined) route.name = input.name;\n return route;\n}\n\nfunction absolutePath(localPath: string): string {\n return isAbsolute(localPath) ? localPath : resolvePath(localPath);\n}\n\nfunction defaultRouteSuffix(source: string, destination: string): string {\n return `${source}->${destination}`;\n}\n","/**\n * Token-bucket bandwidth throttle for transfer streams.\n *\n * @module transfers/BandwidthThrottle\n */\nimport { AbortError, ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { TransferBandwidthLimit } from \"./TransferJob\";\n\n/** Sleep helper signature used by {@link createBandwidthThrottle}. */\nexport type BandwidthSleep = (delayMs: number, signal?: AbortSignal) => Promise<void>;\n\n/** Construction overrides for deterministic tests. */\nexport interface BandwidthThrottleOptions {\n /** Monotonic clock returning milliseconds since an arbitrary epoch. Defaults to `Date.now`. */\n now?: () => number;\n /** Sleep implementation honoring an optional abort signal. Defaults to a `setTimeout` helper. */\n sleep?: BandwidthSleep;\n}\n\n/** Token-bucket throttle used to pace transfer chunks. */\nexport interface BandwidthThrottle {\n /** Maximum sustained transfer rate in bytes per second. */\n readonly bytesPerSecond: number;\n /** Burst capacity in bytes available before throttling kicks in. */\n readonly burstBytes: number;\n /**\n * Consumes `bytes` from the bucket, awaiting refill when not enough tokens are available.\n *\n * @param bytes - Non-negative byte count being released by the throttle.\n * @param signal - Optional abort signal that interrupts pending waits.\n * @throws {@link AbortError} When the signal is aborted while waiting.\n */\n consume(bytes: number, signal?: AbortSignal): Promise<void>;\n}\n\n/**\n * Creates a token-bucket throttle that paces an asynchronous data pipeline to\n * a sustained {@link TransferBandwidthLimit}.\n *\n * Returns `undefined` when no limit is supplied so callers can omit throttling\n * without conditional branches at the call site.\n *\n * @param limit - Optional throughput limit. Returns `undefined` when omitted.\n * @param options - Optional clock/sleep overrides for deterministic tests.\n * @returns Throttle implementation when a limit is supplied, otherwise `undefined`.\n * @throws {@link ConfigurationError} When the supplied limit shape is invalid.\n */\nexport function createBandwidthThrottle(\n limit: TransferBandwidthLimit | undefined,\n options: BandwidthThrottleOptions = {},\n): BandwidthThrottle | undefined {\n if (limit === undefined) return undefined;\n\n const bytesPerSecond = normalizeRate(limit.bytesPerSecond);\n const burstBytes = normalizeBurst(limit.burstBytes, bytesPerSecond);\n const now = options.now ?? Date.now;\n const sleep = options.sleep ?? defaultSleep;\n\n let tokens = burstBytes;\n let lastRefillAt = now();\n\n function refill(): void {\n const current = now();\n const elapsedMs = Math.max(0, current - lastRefillAt);\n\n if (elapsedMs > 0) {\n tokens = Math.min(burstBytes, tokens + (elapsedMs / 1000) * bytesPerSecond);\n lastRefillAt = current;\n }\n }\n\n async function consume(bytes: number, signal?: AbortSignal): Promise<void> {\n if (!Number.isFinite(bytes) || bytes < 0) {\n throw new ConfigurationError({\n details: { bytes },\n message: \"Bandwidth throttle byte count must be a non-negative number\",\n retryable: false,\n });\n }\n\n if (bytes === 0) return;\n\n let remaining = bytes;\n\n while (remaining > 0) {\n throwIfAborted(signal);\n refill();\n\n if (tokens >= remaining) {\n tokens -= remaining;\n return;\n }\n\n if (tokens >= burstBytes) {\n // Bucket is full but the request still exceeds the burst. Drain the\n // full bucket and wait for the remainder at the sustained rate.\n const drained = tokens;\n tokens = 0;\n remaining -= drained;\n const waitMs = Math.ceil((Math.min(remaining, burstBytes) / bytesPerSecond) * 1000);\n await sleep(waitMs, signal);\n continue;\n }\n\n const deficit = Math.min(remaining, burstBytes) - tokens;\n const waitMs = Math.max(1, Math.ceil((deficit / bytesPerSecond) * 1000));\n await sleep(waitMs, signal);\n }\n }\n\n return { burstBytes, bytesPerSecond, consume };\n}\n\n/**\n * Wraps an async iterable of byte chunks so each chunk is released only after\n * the throttle has admitted its byte count.\n *\n * When `throttle` is `undefined`, the source iterable is returned unchanged.\n *\n * @param source - Async iterable that produces byte chunks.\n * @param throttle - Optional throttle that paces chunk emission.\n * @param signal - Optional abort signal interrupting pending waits.\n * @returns Async generator emitting the original chunks at the throttled rate.\n */\nexport function throttleByteIterable(\n source: AsyncIterable<Uint8Array>,\n throttle: BandwidthThrottle | undefined,\n signal?: AbortSignal,\n): AsyncIterable<Uint8Array> {\n if (throttle === undefined) return source;\n\n return {\n [Symbol.asyncIterator]: async function* () {\n for await (const chunk of source) {\n throwIfAborted(signal);\n if (chunk.byteLength > 0) {\n await throttle.consume(chunk.byteLength, signal);\n }\n yield chunk;\n }\n },\n };\n}\n\nfunction normalizeRate(value: number): number {\n if (!Number.isFinite(value) || value <= 0) {\n throw new ConfigurationError({\n details: { bytesPerSecond: value },\n message: \"Bandwidth limit bytesPerSecond must be a positive number\",\n retryable: false,\n });\n }\n\n return value;\n}\n\nfunction normalizeBurst(value: number | undefined, bytesPerSecond: number): number {\n if (value === undefined) return bytesPerSecond;\n\n if (!Number.isFinite(value) || value <= 0) {\n throw new ConfigurationError({\n details: { burstBytes: value },\n message: \"Bandwidth limit burstBytes must be a positive number when provided\",\n retryable: false,\n });\n }\n\n return value;\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted === true) {\n throw new AbortError({\n message: \"Bandwidth throttle wait aborted\",\n retryable: false,\n });\n }\n}\n\nfunction defaultSleep(delayMs: number, signal?: AbortSignal): Promise<void> {\n if (delayMs <= 0) return Promise.resolve();\n\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n cleanup();\n resolve();\n }, delayMs);\n\n const onAbort = () => {\n cleanup();\n reject(\n new AbortError({\n message: \"Bandwidth throttle wait aborted\",\n retryable: false,\n }),\n );\n };\n\n function cleanup(): void {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n }\n\n if (signal !== undefined) {\n if (signal.aborted) {\n onAbort();\n return;\n }\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n });\n}\n","/**\n * Transfer executor bridge for provider-backed read/write sessions.\n *\n * @module transfers/createProviderTransferExecutor\n */\nimport type { TransferSession } from \"../core/TransferSession\";\nimport { ConfigurationError, UnsupportedFeatureError } from \"../errors/ZeroTransferError\";\nimport type {\n ProviderTransferOperations,\n ProviderTransferReadRequest,\n ProviderTransferReadResult,\n ProviderTransferWriteRequest,\n ProviderTransferWriteResult,\n} from \"../providers/ProviderTransferOperations\";\nimport {\n createBandwidthThrottle,\n throttleByteIterable,\n type BandwidthThrottleOptions,\n} from \"./BandwidthThrottle\";\nimport type { TransferExecutionContext, TransferExecutor } from \"./TransferEngine\";\nimport type {\n TransferEndpoint,\n TransferExecutionResult,\n TransferJob,\n TransferOperation,\n TransferVerificationResult,\n} from \"./TransferJob\";\n\n/** Endpoint role used while resolving provider sessions for a transfer job. */\nexport type ProviderTransferEndpointRole = \"source\" | \"destination\";\n\n/** Input passed to provider transfer session resolvers. */\nexport interface ProviderTransferSessionResolverInput {\n /** Endpoint being resolved. */\n endpoint: TransferEndpoint;\n /** Whether the endpoint is the source or destination side of the transfer. */\n role: ProviderTransferEndpointRole;\n /** Job currently being executed. */\n job: TransferJob;\n}\n\n/** Resolves the connected provider session that owns an endpoint. */\nexport type ProviderTransferSessionResolver = (\n input: ProviderTransferSessionResolverInput,\n) => TransferSession | undefined;\n\n/** Options for {@link createProviderTransferExecutor}. */\nexport interface ProviderTransferExecutorOptions {\n /** Resolves connected provider sessions for source and destination endpoints. */\n resolveSession: ProviderTransferSessionResolver;\n /** Optional clock/sleep overrides for the bandwidth throttle. */\n throttle?: BandwidthThrottleOptions;\n}\n\n/**\n * Creates a {@link TransferExecutor} that reads from a source provider and writes to a destination provider.\n *\n * The returned executor supports single-object `upload`, `download`, and `copy` jobs. Provider sessions must\n * expose `session.transfers.read()` and `session.transfers.write()`; concrete providers remain responsible for\n * the actual streaming implementation.\n *\n * @param options - Session resolver used for source and destination endpoints.\n * @returns Transfer executor suitable for {@link TransferEngine.execute} or {@link TransferQueue}.\n */\nexport function createProviderTransferExecutor(\n options: ProviderTransferExecutorOptions,\n): TransferExecutor {\n return async (context) => {\n const { job } = context;\n\n if (!isReadWriteOperation(job.operation)) {\n throw new UnsupportedFeatureError({\n details: { jobId: job.id, operation: job.operation },\n message: `Provider read/write executor does not support transfer operation: ${job.operation}`,\n retryable: false,\n });\n }\n\n const source = requireEndpoint(job, \"source\");\n const destination = requireEndpoint(job, \"destination\");\n const sourceSession = options.resolveSession({ endpoint: source, job, role: \"source\" });\n const destinationSession = options.resolveSession({\n endpoint: destination,\n job,\n role: \"destination\",\n });\n const sourceTransfers = requireTransferOperations(sourceSession, source, \"source\", job);\n const destinationTransfers = requireTransferOperations(\n destinationSession,\n destination,\n \"destination\",\n job,\n );\n\n context.throwIfAborted();\n const readResult = await sourceTransfers.read(createReadRequest(context, source));\n context.throwIfAborted();\n const throttledReadResult = applyBandwidthThrottle(readResult, context, options.throttle);\n const writeResult = await destinationTransfers.write(\n createWriteRequest(context, destination, throttledReadResult),\n );\n\n return mergeProviderTransferResult(readResult, writeResult, job);\n };\n}\n\nfunction applyBandwidthThrottle(\n readResult: ProviderTransferReadResult,\n context: TransferExecutionContext,\n options: BandwidthThrottleOptions | undefined,\n): ProviderTransferReadResult {\n const throttle = createBandwidthThrottle(context.bandwidthLimit, options);\n\n if (throttle === undefined) return readResult;\n\n return {\n ...readResult,\n content: throttleByteIterable(readResult.content, throttle, context.signal),\n };\n}\n\nfunction isReadWriteOperation(operation: TransferOperation): boolean {\n return operation === \"copy\" || operation === \"download\" || operation === \"upload\";\n}\n\nfunction requireEndpoint(job: TransferJob, role: ProviderTransferEndpointRole): TransferEndpoint {\n const endpoint = role === \"source\" ? job.source : job.destination;\n\n if (endpoint === undefined) {\n throw new ConfigurationError({\n details: { jobId: job.id, operation: job.operation, role },\n message: `Transfer job requires a ${role} endpoint: ${job.id}`,\n retryable: false,\n });\n }\n\n return endpoint;\n}\n\nfunction requireTransferOperations(\n session: TransferSession | undefined,\n endpoint: TransferEndpoint,\n role: ProviderTransferEndpointRole,\n job: TransferJob,\n): ProviderTransferOperations {\n if (session === undefined) {\n throw new UnsupportedFeatureError({\n details: { endpoint: cloneEndpoint(endpoint), jobId: job.id, operation: job.operation, role },\n message: `No provider session resolved for ${role} endpoint: ${endpoint.path}`,\n retryable: false,\n });\n }\n\n if (session.transfers === undefined) {\n throw new UnsupportedFeatureError({\n details: {\n endpoint: cloneEndpoint(endpoint),\n jobId: job.id,\n operation: job.operation,\n provider: session.provider,\n role,\n },\n message: `Provider session does not expose transfer operations: ${session.provider}`,\n retryable: false,\n });\n }\n\n return session.transfers;\n}\n\nfunction createReadRequest(\n context: TransferExecutionContext,\n endpoint: TransferEndpoint,\n): ProviderTransferReadRequest {\n const request: ProviderTransferReadRequest = {\n attempt: context.attempt,\n endpoint: cloneEndpoint(endpoint),\n job: context.job,\n reportProgress: (bytesTransferred, totalBytes) =>\n context.reportProgress(bytesTransferred, totalBytes),\n throwIfAborted: () => context.throwIfAborted(),\n };\n\n if (context.signal !== undefined) request.signal = context.signal;\n if (context.bandwidthLimit !== undefined) {\n request.bandwidthLimit = { ...context.bandwidthLimit };\n }\n\n return request;\n}\n\nfunction createWriteRequest(\n context: TransferExecutionContext,\n endpoint: TransferEndpoint,\n readResult: ProviderTransferReadResult,\n): ProviderTransferWriteRequest {\n const request: ProviderTransferWriteRequest = {\n attempt: context.attempt,\n content: readResult.content,\n endpoint: cloneEndpoint(endpoint),\n job: context.job,\n reportProgress: (bytesTransferred, totalBytes) =>\n context.reportProgress(bytesTransferred, totalBytes),\n throwIfAborted: () => context.throwIfAborted(),\n };\n const totalBytes = readResult.totalBytes ?? context.job.totalBytes;\n\n if (context.signal !== undefined) request.signal = context.signal;\n if (context.bandwidthLimit !== undefined) {\n request.bandwidthLimit = { ...context.bandwidthLimit };\n }\n if (totalBytes !== undefined) request.totalBytes = totalBytes;\n if (context.job.resumed === true) request.offset = readResult.bytesRead ?? 0;\n if (readResult.verification !== undefined) {\n request.verification = cloneVerification(readResult.verification);\n }\n\n return request;\n}\n\nfunction mergeProviderTransferResult(\n readResult: ProviderTransferReadResult,\n writeResult: ProviderTransferWriteResult,\n job: TransferJob,\n): TransferExecutionResult {\n const result: TransferExecutionResult = {\n bytesTransferred: writeResult.bytesTransferred,\n };\n const totalBytes = writeResult.totalBytes ?? readResult.totalBytes ?? job.totalBytes;\n const warnings = [...(readResult.warnings ?? []), ...(writeResult.warnings ?? [])];\n\n if (totalBytes !== undefined) result.totalBytes = totalBytes;\n if (writeResult.resumed !== undefined) result.resumed = writeResult.resumed;\n if (writeResult.verified !== undefined) result.verified = writeResult.verified;\n if (writeResult.checksum !== undefined) result.checksum = writeResult.checksum;\n else if (readResult.checksum !== undefined) result.checksum = readResult.checksum;\n if (writeResult.verification !== undefined) {\n result.verification = cloneVerification(writeResult.verification);\n } else if (readResult.verification !== undefined) {\n result.verification = cloneVerification(readResult.verification);\n }\n if (warnings.length > 0) result.warnings = warnings;\n\n return result;\n}\n\nfunction cloneEndpoint(endpoint: TransferEndpoint): TransferEndpoint {\n const clone: TransferEndpoint = { path: endpoint.path };\n\n if (endpoint.provider !== undefined) clone.provider = endpoint.provider;\n\n return clone;\n}\n\nfunction cloneVerification(verification: TransferVerificationResult): TransferVerificationResult {\n const clone: TransferVerificationResult = { verified: verification.verified };\n\n if (verification.method !== undefined) clone.method = verification.method;\n if (verification.checksum !== undefined) clone.checksum = verification.checksum;\n if (verification.expectedChecksum !== undefined) {\n clone.expectedChecksum = verification.expectedChecksum;\n }\n if (verification.actualChecksum !== undefined) clone.actualChecksum = verification.actualChecksum;\n if (verification.details !== undefined) clone.details = { ...verification.details };\n\n return clone;\n}\n","/**\n * Transfer result and progress calculation helpers.\n *\n * These helpers are pure functions so future FTP, FTPS, and SFTP adapters can share\n * timing, throughput, and progress calculations without coupling to transport code.\n *\n * @module services/TransferService\n */\nimport type { TransferProgressEvent, TransferResult } from \"../types/public\";\n\n/**\n * Input used to create a final transfer result.\n */\nexport interface TransferResultInput {\n /** Local or remote source path when known. */\n sourcePath?: string;\n /** Local or remote destination path for the transfer. */\n destinationPath: string;\n /** Total bytes transferred. */\n bytesTransferred: number;\n /** Time the transfer began. */\n startedAt: Date;\n /** Time the transfer completed. */\n completedAt: Date;\n /** Whether the transfer resumed from an earlier partial state. */\n resumed?: boolean;\n /** Whether post-transfer verification succeeded. */\n verified?: boolean;\n /** Optional checksum value produced or verified by the transfer. */\n checksum?: string;\n}\n\n/**\n * Input used to create a transfer progress event.\n */\nexport interface ProgressEventInput {\n /** Stable transfer identifier for correlation. */\n transferId: string;\n /** Bytes transferred so far. */\n bytesTransferred: number;\n /** Time the transfer began. */\n startedAt: Date;\n /** Time to use for the progress calculation; defaults to current time. */\n now?: Date;\n /** Total expected bytes when known. */\n totalBytes?: number;\n}\n\n/**\n * Creates a final transfer result with duration and average throughput.\n *\n * @param input - Transfer paths, byte count, timestamps, and optional verification metadata.\n * @returns A normalized transfer result.\n */\nexport function createTransferResult(input: TransferResultInput): TransferResult {\n const durationMs = Math.max(0, input.completedAt.getTime() - input.startedAt.getTime());\n const result: TransferResult = {\n destinationPath: input.destinationPath,\n bytesTransferred: input.bytesTransferred,\n startedAt: input.startedAt,\n completedAt: input.completedAt,\n durationMs,\n averageBytesPerSecond: calculateBytesPerSecond(input.bytesTransferred, durationMs),\n resumed: input.resumed ?? false,\n verified: input.verified ?? false,\n };\n\n if (input.sourcePath !== undefined) result.sourcePath = input.sourcePath;\n if (input.checksum !== undefined) result.checksum = input.checksum;\n\n return result;\n}\n\n/**\n * Creates a progress event with elapsed time, rate, and optional percentage.\n *\n * @param input - Transfer id, byte count, start time, optional current time, and total bytes.\n * @returns A normalized transfer progress event.\n */\nexport function createProgressEvent(input: ProgressEventInput): TransferProgressEvent {\n const now = input.now ?? new Date();\n const elapsedMs = Math.max(0, now.getTime() - input.startedAt.getTime());\n const event: TransferProgressEvent = {\n transferId: input.transferId,\n bytesTransferred: input.bytesTransferred,\n startedAt: input.startedAt,\n elapsedMs,\n bytesPerSecond: calculateBytesPerSecond(input.bytesTransferred, elapsedMs),\n };\n\n if (input.totalBytes !== undefined) {\n event.totalBytes = input.totalBytes;\n event.percent = input.totalBytes > 0 ? (input.bytesTransferred / input.totalBytes) * 100 : 0;\n }\n\n return event;\n}\n\n/**\n * Calculates average throughput for a byte count and duration.\n *\n * @param bytes - Number of bytes transferred.\n * @param durationMs - Transfer duration in milliseconds.\n * @returns Average bytes per second, falling back to bytes for zero-duration samples.\n */\nfunction calculateBytesPerSecond(bytes: number, durationMs: number): number {\n if (durationMs <= 0) {\n return bytes;\n }\n\n return bytes / (durationMs / 1000);\n}\n","/**\n * Abort-aware transfer engine foundation.\n *\n * @module transfers/TransferEngine\n */\nimport {\n AbortError,\n TimeoutError,\n TransferError,\n ZeroTransferError,\n} from \"../errors/ZeroTransferError\";\nimport { createProgressEvent } from \"../services/TransferService\";\nimport type { TransferProgressEvent } from \"../types/public\";\nimport type {\n TransferAttempt,\n TransferAttemptError,\n TransferBandwidthLimit,\n TransferExecutionResult,\n TransferJob,\n TransferReceipt,\n TransferTimeoutPolicy,\n TransferVerificationResult,\n} from \"./TransferJob\";\n\n/** Context passed to a concrete transfer operation. */\nexport interface TransferExecutionContext {\n /** Job being executed. */\n job: TransferJob;\n /** One-based attempt number. */\n attempt: number;\n /** Abort signal active for this execution when supplied. */\n signal?: AbortSignal;\n /** Optional throughput limit shape for concrete executors to honor. */\n bandwidthLimit?: TransferBandwidthLimit;\n /** Throws an SDK abort error when the active signal has been cancelled. */\n throwIfAborted(): void;\n /** Emits a normalized progress event through engine options. */\n reportProgress(bytesTransferred: number, totalBytes?: number): TransferProgressEvent;\n}\n\n/** Concrete transfer operation implementation used by the engine. */\nexport type TransferExecutor = (\n context: TransferExecutionContext,\n) => Promise<TransferExecutionResult> | TransferExecutionResult;\n\n/** Input used by retry policy hooks. */\nexport interface TransferRetryDecisionInput {\n /** Error thrown by the failed attempt. */\n error: unknown;\n /** One-based attempt number that failed. */\n attempt: number;\n /** Milliseconds elapsed since the engine execution started, including prior attempts and delays. */\n elapsedMs: number;\n /** Job being executed. */\n job: TransferJob;\n}\n\n/**\n * Retry policy for transfer execution.\n *\n * Use {@link createDefaultRetryPolicy} for a production-ready policy with\n * exponential backoff, full jitter, and `Retry-After` support, or implement\n * the hooks directly for full control.\n */\nexport interface TransferRetryPolicy {\n /** Maximum total attempts, including the first attempt. Defaults to `1`. */\n maxAttempts?: number;\n /** Decides whether a failed attempt should be retried. Defaults to SDK retryability metadata. */\n shouldRetry?(input: TransferRetryDecisionInput): boolean;\n /**\n * Computes the delay before the next attempt in milliseconds.\n *\n * The engine sleeps for the returned duration with an abort-aware timer:\n * cancelling the job during the delay rejects immediately instead of\n * waiting out the backoff. Non-positive or missing values retry at once.\n */\n getDelayMs?(input: TransferRetryDecisionInput): number;\n /** Observes retry decisions before the next attempt starts. */\n onRetry?(input: TransferRetryDecisionInput): void;\n}\n\n/** Options used by {@link TransferEngine.execute}. */\nexport interface TransferEngineExecuteOptions {\n /** Abort signal used to cancel the job. */\n signal?: AbortSignal;\n /** Retry policy used for failed attempts. */\n retry?: TransferRetryPolicy;\n /** Progress observer for normalized transfer progress events. */\n onProgress?(event: TransferProgressEvent): void;\n /** Timeout policy enforced by the engine. */\n timeout?: TransferTimeoutPolicy;\n /** Optional throughput limit shape passed through to concrete executors. */\n bandwidthLimit?: TransferBandwidthLimit;\n}\n\n/** Construction options for deterministic tests and host integration. */\nexport interface TransferEngineOptions {\n /** Clock used for receipts and progress events. Defaults to `new Date()`. */\n now?: () => Date;\n}\n\n/**\n * Executes transfer jobs and produces audit-friendly receipts.\n *\n * The engine is the lowest-level entry point in the transfer stack: it owns\n * retry policy, attempt history, abort propagation, progress event\n * normalization, and receipt construction. Most callers reach the engine\n * indirectly through {@link runRoute}, {@link uploadFile}, {@link downloadFile},\n * {@link copyBetween}, or {@link TransferQueue}; instantiate it directly when\n * you need full control over execution semantics.\n *\n * @example Execute a single job with a custom executor\n * ```ts\n * import {\n * TransferEngine,\n * createDefaultRetryPolicy,\n * type TransferExecutor,\n * type TransferJob,\n * } from \"@zero-transfer/sdk\";\n *\n * const engine = new TransferEngine();\n *\n * const executor: TransferExecutor = async ({ job, signal, onProgress }) => {\n * onProgress?.({ jobId: job.id, bytesTransferred: 0 });\n * // … perform the bytes here, honoring `signal` …\n * return { jobId: job.id, bytesTransferred: 1234, completedAt: new Date() };\n * };\n *\n * const job: TransferJob = {\n * id: \"manual-1\",\n * operation: \"upload\",\n * source: { profile: localProfile, path: \"./data.bin\" },\n * destination: { profile: s3Profile, path: \"/data/data.bin\" },\n * };\n *\n * const receipt = await engine.execute(job, executor, {\n * retry: createDefaultRetryPolicy(),\n * timeout: { stallTimeoutMs: 30_000 },\n * });\n * console.log(receipt.attempts.length); // 1 on success\n * ```\n */\nexport class TransferEngine {\n private readonly now: () => Date;\n\n /**\n * Creates a transfer engine.\n *\n * @param options - Optional clock override for deterministic tests.\n */\n constructor(options: TransferEngineOptions = {}) {\n this.now = options.now ?? (() => new Date());\n }\n\n /**\n * Executes a transfer job through a caller-supplied operation.\n *\n * @param job - Job metadata used for correlation and receipts.\n * @param executor - Concrete transfer operation implementation.\n * @param options - Optional abort, retry, and progress hooks.\n * @returns Receipt for the completed transfer.\n * @throws {@link AbortError} When execution is cancelled.\n * @throws {@link TransferError} When all attempts fail.\n */\n async execute(\n job: TransferJob,\n executor: TransferExecutor,\n options: TransferEngineExecuteOptions = {},\n ): Promise<TransferReceipt> {\n const maxAttempts = normalizeMaxAttempts(options.retry?.maxAttempts);\n const attempts: TransferAttempt[] = [];\n const startedAt = this.now();\n const abortScope = createAbortScope(options.signal, options.timeout, job);\n let latestBytesTransferred = 0;\n\n try {\n for (let attemptNumber = 1; attemptNumber <= maxAttempts; attemptNumber += 1) {\n this.throwIfAborted(abortScope.signal, job);\n\n const attemptStartedAt = this.now();\n const attemptScope = createAttemptScope(\n abortScope.signal,\n options.timeout,\n job,\n attemptNumber,\n );\n const context = this.createExecutionContext(\n job,\n attemptNumber,\n attemptStartedAt,\n options,\n attemptScope.signal,\n (bytesTransferred) => {\n latestBytesTransferred = bytesTransferred;\n },\n attemptScope.notifyProgress,\n );\n\n try {\n const result = await runExecutor(executor, context, attemptScope.signal, job);\n context.throwIfAborted();\n latestBytesTransferred = result.bytesTransferred;\n\n const completedAt = this.now();\n attempts.push(\n createAttempt(attemptNumber, attemptStartedAt, completedAt, result.bytesTransferred),\n );\n\n return createReceipt(job, result, attempts, startedAt, completedAt);\n } catch (error) {\n const completedAt = this.now();\n const attempt = createAttempt(\n attemptNumber,\n attemptStartedAt,\n completedAt,\n latestBytesTransferred,\n summarizeError(error),\n );\n attempts.push(attempt);\n\n // Job-scope failures (caller abort or whole-job timeout) end execution\n // unconditionally. Attempt-scope timeouts and stalls fall through to the\n // retry decision like any other attempt failure.\n if (error instanceof AbortError || abortScope.signal?.aborted === true) {\n throw error;\n }\n\n const retryInput: TransferRetryDecisionInput = {\n attempt: attemptNumber,\n elapsedMs: Math.max(0, completedAt.getTime() - startedAt.getTime()),\n error,\n job,\n };\n const shouldRetry =\n attemptNumber < maxAttempts &&\n (options.retry?.shouldRetry?.(retryInput) ?? isRetryable(error));\n\n if (shouldRetry) {\n options.retry?.onRetry?.(retryInput);\n const delayMs = normalizeDelayMs(options.retry?.getDelayMs?.(retryInput));\n if (delayMs > 0) {\n await sleepWithAbort(delayMs, abortScope.signal, job);\n }\n continue;\n }\n\n throw createTransferFailure(job, error, attempts);\n } finally {\n attemptScope.dispose();\n }\n }\n\n throw createTransferFailure(job, undefined, attempts);\n } finally {\n abortScope.dispose();\n }\n }\n\n private createExecutionContext(\n job: TransferJob,\n attempt: number,\n startedAt: Date,\n options: TransferEngineExecuteOptions,\n signal: AbortSignal | undefined,\n updateBytesTransferred: (bytesTransferred: number) => void,\n notifyProgress: () => void,\n ): TransferExecutionContext {\n const context: TransferExecutionContext = {\n attempt,\n job,\n reportProgress: (bytesTransferred, totalBytes) => {\n this.throwIfAborted(signal, job);\n notifyProgress();\n updateBytesTransferred(bytesTransferred);\n const progressInput = {\n bytesTransferred,\n now: this.now(),\n startedAt,\n transferId: job.id,\n };\n const resolvedTotalBytes = totalBytes ?? job.totalBytes;\n const event = createProgressEvent(\n resolvedTotalBytes === undefined\n ? progressInput\n : { ...progressInput, totalBytes: resolvedTotalBytes },\n );\n options.onProgress?.(event);\n return event;\n },\n throwIfAborted: () => this.throwIfAborted(signal, job),\n };\n\n if (signal !== undefined) {\n context.signal = signal;\n }\n\n if (options.bandwidthLimit !== undefined) {\n context.bandwidthLimit = { ...options.bandwidthLimit };\n }\n\n return context;\n }\n\n private throwIfAborted(signal: AbortSignal | undefined, job: TransferJob): void {\n if (signal?.aborted === true) {\n if (signal.reason instanceof ZeroTransferError) {\n throw signal.reason;\n }\n\n throw new AbortError({\n details: { jobId: job.id, operation: job.operation },\n message: `Transfer job aborted: ${job.id}`,\n retryable: false,\n });\n }\n }\n}\n\ninterface AbortScope {\n signal?: AbortSignal;\n dispose(): void;\n}\n\nfunction createAbortScope(\n parentSignal: AbortSignal | undefined,\n timeout: TransferTimeoutPolicy | undefined,\n job: TransferJob,\n): AbortScope {\n const timeoutMs = normalizeTimeoutMs(timeout?.timeoutMs);\n\n if (parentSignal === undefined && timeoutMs === undefined) {\n return { dispose: () => undefined };\n }\n\n const controller = new AbortController();\n const abortFromParent = (): void => controller.abort(parentSignal?.reason);\n const timeoutHandle =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n controller.abort(\n new TimeoutError({\n details: { jobId: job.id, operation: job.operation, timeoutMs },\n message: `Transfer job timed out after ${timeoutMs}ms: ${job.id}`,\n retryable: timeout?.retryable ?? true,\n }),\n );\n }, timeoutMs);\n\n if (parentSignal?.aborted === true) {\n abortFromParent();\n } else {\n parentSignal?.addEventListener(\"abort\", abortFromParent, { once: true });\n }\n\n return {\n dispose: () => {\n if (timeoutHandle !== undefined) {\n clearTimeout(timeoutHandle);\n }\n parentSignal?.removeEventListener(\"abort\", abortFromParent);\n },\n signal: controller.signal,\n };\n}\n\ninterface AttemptScope {\n signal?: AbortSignal;\n /** Resets the stall watchdog. Wired into the engine's progress interception. */\n notifyProgress: () => void;\n dispose: () => void;\n}\n\n/**\n * Builds the per-attempt abort scope nested under the job-scope signal.\n *\n * The attempt controller aborts on parent abort (propagating the parent\n * reason), on attempt timeout, and on stall (no progress reports within\n * `stallTimeoutMs`). Attempt-scope timeout errors are retryable by default so\n * they flow into the retry policy; job-scope failures are handled upstream.\n */\nfunction createAttemptScope(\n parentSignal: AbortSignal | undefined,\n timeout: TransferTimeoutPolicy | undefined,\n job: TransferJob,\n attempt: number,\n): AttemptScope {\n const attemptTimeoutMs = normalizeTimeoutMs(timeout?.attemptTimeoutMs);\n const stallTimeoutMs = normalizeTimeoutMs(timeout?.stallTimeoutMs);\n\n if (attemptTimeoutMs === undefined && stallTimeoutMs === undefined) {\n const scope: AttemptScope = {\n dispose: () => undefined,\n notifyProgress: () => undefined,\n };\n if (parentSignal !== undefined) scope.signal = parentSignal;\n return scope;\n }\n\n const controller = new AbortController();\n const retryable = timeout?.retryable ?? true;\n const abortFromParent = (): void => controller.abort(parentSignal?.reason);\n\n if (parentSignal?.aborted === true) {\n abortFromParent();\n } else {\n parentSignal?.addEventListener(\"abort\", abortFromParent, { once: true });\n }\n\n const attemptTimer =\n attemptTimeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n controller.abort(\n new TimeoutError({\n details: { attempt, attemptTimeoutMs, jobId: job.id, operation: job.operation },\n message: `Transfer attempt ${String(attempt)} timed out after ${String(attemptTimeoutMs)}ms: ${job.id}`,\n retryable,\n }),\n );\n }, attemptTimeoutMs);\n\n let stallTimer: ReturnType<typeof setTimeout> | undefined;\n const armStallWatchdog = (): void => {\n if (stallTimeoutMs === undefined || controller.signal.aborted) return;\n if (stallTimer !== undefined) clearTimeout(stallTimer);\n stallTimer = setTimeout(() => {\n controller.abort(\n new TimeoutError({\n details: { attempt, jobId: job.id, operation: job.operation, stallTimeoutMs },\n message:\n `Transfer attempt ${String(attempt)} stalled ` +\n `(no progress for ${String(stallTimeoutMs)}ms): ${job.id}`,\n retryable,\n }),\n );\n }, stallTimeoutMs);\n };\n armStallWatchdog();\n\n return {\n dispose: () => {\n if (attemptTimer !== undefined) clearTimeout(attemptTimer);\n if (stallTimer !== undefined) clearTimeout(stallTimer);\n parentSignal?.removeEventListener(\"abort\", abortFromParent);\n },\n notifyProgress: armStallWatchdog,\n signal: controller.signal,\n };\n}\n\n/** Sleeps between retry attempts, rejecting immediately when the job aborts. */\nfunction sleepWithAbort(\n delayMs: number,\n signal: AbortSignal | undefined,\n job: TransferJob,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal === undefined) {\n setTimeout(resolve, delayMs);\n return;\n }\n\n if (signal.aborted) {\n reject(toAbortFailure(signal, job));\n return;\n }\n\n const rejectAbort = (): void => {\n clearTimeout(timer);\n reject(toAbortFailure(signal, job));\n };\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", rejectAbort);\n resolve();\n }, delayMs);\n signal.addEventListener(\"abort\", rejectAbort, { once: true });\n });\n}\n\n/** Normalizes an aborted signal into the SDK error to surface for the job. */\nfunction toAbortFailure(signal: AbortSignal, job: TransferJob): ZeroTransferError {\n if (signal.reason instanceof ZeroTransferError) {\n return signal.reason;\n }\n\n return new AbortError({\n details: { jobId: job.id, operation: job.operation },\n message: `Transfer job aborted: ${job.id}`,\n retryable: false,\n });\n}\n\nfunction normalizeDelayMs(value: number | undefined): number {\n if (value === undefined || !Number.isFinite(value) || value <= 0) {\n return 0;\n }\n\n return Math.floor(value);\n}\n\nfunction normalizeTimeoutMs(value: number | undefined): number | undefined {\n if (value === undefined || !Number.isFinite(value) || value <= 0) {\n return undefined;\n }\n\n return Math.floor(value);\n}\n\nasync function runExecutor(\n executor: TransferExecutor,\n context: TransferExecutionContext,\n signal: AbortSignal | undefined,\n job: TransferJob,\n): Promise<TransferExecutionResult> {\n if (signal === undefined) {\n return executor(context);\n }\n\n return Promise.race([executor(context), rejectWhenAborted(signal, job)]);\n}\n\nfunction rejectWhenAborted(\n signal: AbortSignal,\n job: TransferJob,\n): Promise<TransferExecutionResult> {\n return new Promise((_, reject) => {\n const rejectAbort = (): void => {\n if (signal.reason instanceof ZeroTransferError) {\n reject(signal.reason);\n return;\n }\n\n reject(\n new AbortError({\n details: { jobId: job.id, operation: job.operation },\n message: `Transfer job aborted: ${job.id}`,\n retryable: false,\n }),\n );\n };\n\n if (signal.aborted) {\n rejectAbort();\n return;\n }\n\n signal.addEventListener(\"abort\", rejectAbort, { once: true });\n });\n}\n\nfunction normalizeMaxAttempts(value: number | undefined): number {\n if (value === undefined) {\n return 1;\n }\n\n return Math.max(1, Math.floor(value));\n}\n\nfunction createAttempt(\n attempt: number,\n startedAt: Date,\n completedAt: Date,\n bytesTransferred: number,\n error?: TransferAttemptError,\n): TransferAttempt {\n const result: TransferAttempt = {\n attempt,\n bytesTransferred,\n completedAt,\n durationMs: Math.max(0, completedAt.getTime() - startedAt.getTime()),\n startedAt,\n };\n\n if (error !== undefined) {\n result.error = error;\n }\n\n return result;\n}\n\nfunction createReceipt(\n job: TransferJob,\n result: TransferExecutionResult,\n attempts: TransferAttempt[],\n startedAt: Date,\n completedAt: Date,\n): TransferReceipt {\n const durationMs = Math.max(0, completedAt.getTime() - startedAt.getTime());\n const verification = normalizeVerificationResult(result);\n const receipt: TransferReceipt = {\n attempts,\n averageBytesPerSecond: calculateBytesPerSecond(result.bytesTransferred, durationMs),\n bytesTransferred: result.bytesTransferred,\n completedAt,\n durationMs,\n jobId: job.id,\n operation: job.operation,\n resumed: result.resumed ?? job.resumed ?? false,\n startedAt,\n transferId: job.id,\n verified: verification?.verified ?? result.verified ?? false,\n warnings: [...(result.warnings ?? [])],\n };\n\n if (job.source !== undefined) receipt.source = { ...job.source };\n if (job.destination !== undefined) receipt.destination = { ...job.destination };\n if (result.totalBytes !== undefined) receipt.totalBytes = result.totalBytes;\n else if (job.totalBytes !== undefined) receipt.totalBytes = job.totalBytes;\n if (result.checksum !== undefined) receipt.checksum = result.checksum;\n else if (verification?.checksum !== undefined) receipt.checksum = verification.checksum;\n if (verification !== undefined) receipt.verification = verification;\n if (job.metadata !== undefined) receipt.metadata = { ...job.metadata };\n\n return receipt;\n}\n\nfunction normalizeVerificationResult(\n result: TransferExecutionResult,\n): TransferVerificationResult | undefined {\n const verification = result.verification;\n\n if (verification !== undefined) {\n const normalized: TransferVerificationResult = { verified: verification.verified };\n\n if (verification.method !== undefined) normalized.method = verification.method;\n if (verification.checksum !== undefined) normalized.checksum = verification.checksum;\n if (verification.expectedChecksum !== undefined) {\n normalized.expectedChecksum = verification.expectedChecksum;\n }\n if (verification.actualChecksum !== undefined)\n normalized.actualChecksum = verification.actualChecksum;\n if (verification.details !== undefined) normalized.details = { ...verification.details };\n\n return normalized;\n }\n\n if (result.verified === undefined && result.checksum === undefined) {\n return undefined;\n }\n\n const normalized: TransferVerificationResult = { verified: result.verified ?? false };\n\n if (result.checksum !== undefined) {\n normalized.checksum = result.checksum;\n }\n\n return normalized;\n}\n\nfunction createTransferFailure(\n job: TransferJob,\n error: unknown,\n attempts: TransferAttempt[],\n): TransferError {\n return new TransferError({\n cause: error,\n details: {\n attempts,\n jobId: job.id,\n operation: job.operation,\n },\n message: `Transfer job failed: ${job.id}`,\n retryable: isRetryable(error),\n });\n}\n\nfunction summarizeError(error: unknown): TransferAttemptError {\n if (error instanceof ZeroTransferError) {\n return {\n code: error.code,\n message: error.message,\n name: error.name,\n retryable: error.retryable,\n };\n }\n\n if (error instanceof Error) {\n return {\n message: error.message,\n name: error.name,\n };\n }\n\n return {\n message: String(error),\n name: \"Error\",\n };\n}\n\nfunction isRetryable(error: unknown): boolean {\n return error instanceof ZeroTransferError && error.retryable;\n}\n\nfunction calculateBytesPerSecond(bytes: number, durationMs: number): number {\n if (durationMs <= 0) {\n return bytes;\n }\n\n return bytes / (durationMs / 1000);\n}\n","/**\n * Route executor that dispatches a single transfer through {@link TransferEngine}.\n *\n * `runRoute` opens both endpoints through the supplied {@link TransferClient},\n * builds a {@link TransferJob} with route correlation metadata, and runs the\n * provider read/write executor under retry, abort, progress, timeout, and\n * bandwidth-limit hooks. Sessions are released in `finally` blocks even when\n * the transfer fails, throws, or is aborted.\n *\n * @module mft/runRoute\n */\nimport type { TransferClient } from \"../core/TransferClient\";\nimport type { TransferSession } from \"../core/TransferSession\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { TransferProgressEvent } from \"../types/public\";\nimport { createProviderTransferExecutor } from \"../transfers/createProviderTransferExecutor\";\nimport { TransferEngine } from \"../transfers/TransferEngine\";\nimport type {\n TransferEngineExecuteOptions,\n TransferRetryPolicy,\n} from \"../transfers/TransferEngine\";\nimport type {\n TransferBandwidthLimit,\n TransferEndpoint,\n TransferJob,\n TransferReceipt,\n TransferTimeoutPolicy,\n} from \"../transfers/TransferJob\";\nimport type { MftRoute } from \"./MftRoute\";\n\n/** Options accepted by {@link runRoute}. */\nexport interface RunRouteOptions {\n /** Transfer client whose registry can resolve both endpoint providers. */\n client: TransferClient;\n /** Route to execute. */\n route: MftRoute;\n /** Optional transfer engine override. A fresh engine is created when omitted. */\n engine?: TransferEngine;\n /** Optional explicit job id. Defaults to a deterministic route-derived id. */\n jobId?: string;\n /** Optional clock used to derive the default job id. Defaults to `Date.now`. */\n now?: () => Date;\n /** Abort signal used to cancel the route execution. */\n signal?: AbortSignal;\n /** Retry policy forwarded to the engine. Falls back to `client.defaults.retry`. */\n retry?: TransferRetryPolicy;\n /** Progress observer forwarded to the engine. */\n onProgress?: (event: TransferProgressEvent) => void;\n /** Timeout policy forwarded to the engine. Falls back to `client.defaults.timeout`. */\n timeout?: TransferTimeoutPolicy;\n /** Optional bandwidth limit forwarded to the engine. */\n bandwidthLimit?: TransferBandwidthLimit;\n /** Caller-defined metadata merged into the resulting transfer job. */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Executes an MFT route as a single transfer through the supplied client.\n *\n * Connects the source and destination profiles, runs the route's transfer\n * through the engine, and returns the resulting receipt. The friendly helpers\n * {@link uploadFile}, {@link downloadFile}, and {@link copyBetween} synthesize\n * routes and delegate to this function, so behaviour around retry, abort,\n * progress, timeout, and bandwidth limits is identical.\n *\n * @param options - Client, route, and optional engine/abort/retry hooks.\n * @returns Receipt produced by the underlying transfer engine.\n * @throws {@link ConfigurationError} When the route is disabled.\n *\n * @example Run a pre-built route with progress + retry\n * ```ts\n * import {\n * createDefaultRetryPolicy,\n * createTransferClient,\n * runRoute,\n * type MftRoute,\n * } from \"@zero-transfer/sdk\";\n *\n * const route: MftRoute = {\n * id: \"nightly-export\",\n * operation: \"copy\",\n * source: {\n * path: \"/exports/daily.csv\",\n * profile: { host: \"sftp.example.com\", provider: \"sftp\", username: \"etl\" },\n * },\n * destination: {\n * path: \"warehouse/daily.csv\",\n * profile: { host: \"warehouse\", provider: \"s3\", s3: { region: \"us-east-1\" } },\n * },\n * };\n *\n * const receipt = await runRoute({\n * client,\n * route,\n * onProgress: (e) => console.log(`${e.bytesTransferred}/${e.totalBytes ?? \"?\"}`),\n * retry: createDefaultRetryPolicy({ maxAttempts: 3 }),\n * });\n * console.log(`Job ${receipt.jobId} moved ${receipt.bytesTransferred} bytes…`);\n * ```\n */\nexport async function runRoute(options: RunRouteOptions): Promise<TransferReceipt> {\n const { client, route } = options;\n\n if (route.enabled === false) {\n throw new ConfigurationError({\n details: { routeId: route.id },\n message: `MFT route \"${route.id}\" is disabled`,\n retryable: false,\n });\n }\n\n const sourceSession = await client.connect(route.source.profile);\n\n let destinationSession: TransferSession | undefined;\n try {\n destinationSession = await client.connect(route.destination.profile);\n const engine = options.engine ?? new TransferEngine();\n const job = createRouteJob(route, sourceSession, destinationSession, options);\n const sessions = new Map<string, TransferSession>([\n [\"source\", sourceSession],\n [\"destination\", destinationSession],\n ]);\n const executor = createProviderTransferExecutor({\n resolveSession: ({ role }) => sessions.get(role),\n });\n\n return await engine.execute(job, executor, buildExecuteOptions(options, client));\n } finally {\n if (destinationSession !== undefined) {\n await destinationSession.disconnect();\n }\n await sourceSession.disconnect();\n }\n}\n\nfunction createRouteJob(\n route: MftRoute,\n sourceSession: TransferSession,\n destinationSession: TransferSession,\n options: RunRouteOptions,\n): TransferJob {\n const operation = route.operation ?? \"copy\";\n const source: TransferEndpoint = {\n path: route.source.path,\n provider: sourceSession.provider,\n };\n const destination: TransferEndpoint = {\n path: route.destination.path,\n provider: destinationSession.provider,\n };\n\n const baseMetadata: Record<string, unknown> = { routeId: route.id };\n if (route.name !== undefined) baseMetadata[\"routeName\"] = route.name;\n if (route.metadata !== undefined) Object.assign(baseMetadata, route.metadata);\n if (options.metadata !== undefined) Object.assign(baseMetadata, options.metadata);\n\n const job: TransferJob = {\n destination,\n id: options.jobId ?? defaultJobId(route, options.now),\n operation,\n source,\n };\n\n if (Object.keys(baseMetadata).length > 0) {\n job.metadata = baseMetadata;\n }\n\n return job;\n}\n\nfunction defaultJobId(route: MftRoute, now: (() => Date) | undefined): string {\n const timestamp = (now?.() ?? new Date()).getTime();\n return `route:${route.id}:${timestamp.toString(36)}`;\n}\n\nfunction buildExecuteOptions(\n options: RunRouteOptions,\n client: TransferClient,\n): TransferEngineExecuteOptions {\n const execute: TransferEngineExecuteOptions = {};\n const retry = options.retry ?? client.defaults?.retry;\n const timeout = options.timeout ?? client.defaults?.timeout;\n if (options.signal !== undefined) execute.signal = options.signal;\n if (retry !== undefined) execute.retry = retry;\n if (options.onProgress !== undefined) execute.onProgress = options.onProgress;\n if (timeout !== undefined) execute.timeout = timeout;\n if (options.bandwidthLimit !== undefined) execute.bandwidthLimit = options.bandwidthLimit;\n return execute;\n}\n","/**\n * Secret source contracts and resolution helpers for connection profiles.\n *\n * @module profiles/SecretSource\n */\nimport { Buffer } from \"node:buffer\";\nimport { readFile } from \"node:fs/promises\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport { REDACTED } from \"../logging/redaction\";\n\n/** Resolved secret value accepted by profile credential fields. */\nexport type SecretValue = string | Buffer;\n\n/** Callback source used by applications to integrate vaults or credential brokers. */\nexport type SecretProvider = () => SecretValue | Promise<SecretValue>;\n\n/** Inline secret descriptor. Prefer env, path, or callback sources for real applications. */\nexport interface ValueSecretSource {\n /** Inline secret value. */\n value: SecretValue;\n}\n\n/** Environment variable descriptor for text secrets. */\nexport interface EnvSecretSource {\n /** Environment variable containing the secret. */\n env: string;\n}\n\n/** Environment variable descriptor for base64-encoded binary secrets. */\nexport interface Base64EnvSecretSource {\n /** Environment variable containing a base64-encoded secret. */\n base64Env: string;\n}\n\n/** File-backed secret descriptor. */\nexport interface FileSecretSource {\n /** Path to the file containing the secret. */\n path: string;\n /** Text encoding to use, or `buffer` to return raw bytes. Defaults to `utf8`. */\n encoding?: BufferEncoding | \"buffer\";\n}\n\n/** Secret source accepted by profile credential fields. */\nexport type SecretSource =\n | SecretValue\n | SecretProvider\n | ValueSecretSource\n | EnvSecretSource\n | Base64EnvSecretSource\n | FileSecretSource;\n\n/** Injectable dependencies used by tests or host applications during secret resolution. */\nexport interface ResolveSecretOptions {\n /** Environment source. Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv;\n /** File reader. Defaults to `fs.promises.readFile`. */\n readFile?: (path: string) => Promise<Buffer> | Buffer;\n}\n\n/**\n * Resolves a secret source into a string or Buffer without logging the value.\n *\n * @param source - Secret source to resolve.\n * @param options - Optional env and file-reader overrides.\n * @returns Resolved secret value.\n * @throws {@link ConfigurationError} When a descriptor is invalid or unavailable.\n */\nexport async function resolveSecret(\n source: SecretSource,\n options: ResolveSecretOptions = {},\n): Promise<SecretValue> {\n if (isSecretValue(source)) {\n return cloneSecretValue(source);\n }\n\n if (typeof source === \"function\") {\n return cloneSecretValue(await source());\n }\n\n if (isValueSecretSource(source)) {\n return cloneSecretValue(source.value);\n }\n\n if (isEnvSecretSource(source)) {\n const value = (options.env ?? process.env)[source.env];\n\n if (value === undefined) {\n throw createSecretConfigurationError(\n \"Secret environment variable is not set\",\n \"env\",\n source.env,\n );\n }\n\n return value;\n }\n\n if (isBase64EnvSecretSource(source)) {\n const value = (options.env ?? process.env)[source.base64Env];\n\n if (value === undefined) {\n throw createSecretConfigurationError(\n \"Secret environment variable is not set\",\n \"base64Env\",\n source.base64Env,\n );\n }\n\n return Buffer.from(value, \"base64\");\n }\n\n if (isFileSecretSource(source)) {\n const fileReader = options.readFile ?? readFile;\n const value = await fileReader(source.path);\n\n if (source.encoding === \"buffer\") {\n return Buffer.from(value);\n }\n\n return value.toString(source.encoding ?? \"utf8\");\n }\n\n throw createSecretConfigurationError(\"Unsupported secret source\", \"source\", \"unknown\");\n}\n\n/**\n * Redacts a secret source or resolved secret for safe diagnostics.\n *\n * @param source - Secret source or resolved value to sanitize.\n * @returns Redacted placeholder or descriptor shape.\n */\nexport function redactSecretSource(source: SecretSource | SecretValue): unknown {\n if (isSecretValue(source) || typeof source === \"function\") {\n return REDACTED;\n }\n\n if (isValueSecretSource(source)) return { value: REDACTED };\n if (isEnvSecretSource(source)) return { env: REDACTED };\n if (isBase64EnvSecretSource(source)) return { base64Env: REDACTED };\n if (isFileSecretSource(source)) return { encoding: source.encoding, path: REDACTED };\n\n return REDACTED;\n}\n\nfunction isSecretValue(value: unknown): value is SecretValue {\n return typeof value === \"string\" || Buffer.isBuffer(value);\n}\n\nfunction isValueSecretSource(value: unknown): value is ValueSecretSource {\n return isRecord(value) && \"value\" in value && isSecretValue(value.value);\n}\n\nfunction isEnvSecretSource(value: unknown): value is EnvSecretSource {\n return isRecord(value) && typeof value.env === \"string\";\n}\n\nfunction isBase64EnvSecretSource(value: unknown): value is Base64EnvSecretSource {\n return isRecord(value) && typeof value.base64Env === \"string\";\n}\n\nfunction isFileSecretSource(value: unknown): value is FileSecretSource {\n return isRecord(value) && typeof value.path === \"string\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction cloneSecretValue(value: SecretValue): SecretValue {\n return Buffer.isBuffer(value) ? Buffer.from(value) : value;\n}\n\nfunction createSecretConfigurationError(\n message: string,\n sourceType: string,\n sourceName: string,\n): ConfigurationError {\n return new ConfigurationError({\n details: { sourceName, sourceType },\n message,\n retryable: false,\n });\n}\n","/**\n * Connection profile redaction helpers.\n *\n * @module profiles/ProfileRedactor\n */\nimport type { ConnectionProfile, SshProfile, TlsProfile, TlsSecretSource } from \"../types/public\";\nimport { REDACTED, redactObject } from \"../logging/redaction\";\nimport { redactSecretSource } from \"./SecretSource\";\n\n/**\n * Produces a diagnostics-safe profile copy with credentials and runtime hooks redacted.\n *\n * @param profile - Connection profile to sanitize.\n * @returns Plain object safe to include in logs, traces, or validation reports.\n */\nexport function redactConnectionProfile(profile: ConnectionProfile): Record<string, unknown> {\n const { logger, password, signal, ssh, tls, username, ...rest } = profile;\n const redacted = redactObject(rest);\n\n if (username !== undefined) redacted.username = redactSecretSource(username);\n if (password !== undefined) redacted.password = redactSecretSource(password);\n if (ssh !== undefined) redacted.ssh = redactSshProfile(ssh);\n if (tls !== undefined) redacted.tls = redactTlsProfile(tls);\n if (signal !== undefined) redacted.signal = \"[AbortSignal]\";\n if (logger !== undefined) redacted.logger = REDACTED;\n\n return redacted;\n}\n\n/**\n * Redacts SSH private-key profile fields while preserving non-sensitive policy settings.\n *\n * @param profile - SSH profile to sanitize.\n * @returns Plain object safe to include in diagnostics.\n */\nfunction redactSshProfile(profile: SshProfile): Record<string, unknown> {\n const { agent, keyboardInteractive, knownHosts, passphrase, privateKey, socketFactory, ...rest } =\n profile;\n const redacted = redactObject(rest);\n\n if (agent !== undefined) redacted.agent = REDACTED;\n if (privateKey !== undefined) redacted.privateKey = redactSecretSource(privateKey);\n if (passphrase !== undefined) redacted.passphrase = redactSecretSource(passphrase);\n if (knownHosts !== undefined) redacted.knownHosts = redactSshKnownHostsSource(knownHosts);\n if (keyboardInteractive !== undefined) redacted.keyboardInteractive = REDACTED;\n if (socketFactory !== undefined) redacted.socketFactory = REDACTED;\n\n return redacted;\n}\n\n/**\n * Redacts an SSH known_hosts source, preserving array shape for diagnostics.\n *\n * @param source - Single known_hosts source or ordered source array.\n * @returns Redacted source descriptor.\n */\nfunction redactSshKnownHostsSource(source: NonNullable<SshProfile[\"knownHosts\"]>): unknown {\n if (Array.isArray(source)) {\n return source.map((item) => redactSecretSource(item));\n }\n\n return redactSecretSource(source);\n}\n\n/**\n * Redacts certificate-bearing TLS profile fields while preserving non-sensitive policy settings.\n *\n * @param profile - TLS profile to sanitize.\n * @returns Plain object safe to include in diagnostics.\n */\nfunction redactTlsProfile(profile: TlsProfile): Record<string, unknown> {\n const { ca, cert, checkServerIdentity, key, passphrase, pfx, ...rest } = profile;\n const redacted = redactObject(rest);\n\n if (ca !== undefined) redacted.ca = redactTlsSecretSource(ca);\n if (cert !== undefined) redacted.cert = redactSecretSource(cert);\n if (key !== undefined) redacted.key = redactSecretSource(key);\n if (passphrase !== undefined) redacted.passphrase = redactSecretSource(passphrase);\n if (pfx !== undefined) redacted.pfx = redactSecretSource(pfx);\n if (checkServerIdentity !== undefined) redacted.checkServerIdentity = REDACTED;\n\n return redacted;\n}\n\n/**\n * Redacts a TLS material source, preserving array shape for CA bundle diagnostics.\n *\n * @param source - Single secret source or ordered source array.\n * @returns Redacted source descriptor.\n */\nfunction redactTlsSecretSource(source: TlsSecretSource): unknown {\n if (Array.isArray(source)) {\n return source.map((item) => redactSecretSource(item));\n }\n\n return redactSecretSource(source);\n}\n","/**\n * Diagnostics helpers for inspecting a {@link TransferClient} and probing connection profiles.\n *\n * These helpers are intentionally side-effect-light: they exercise an existing client without\n * mutating registry state and never log secret material. Use them to render setup screens,\n * collect bug-report payloads, or verify a profile after an importer run.\n *\n * @module diagnostics\n */\nimport type { TransferClient } from \"../core/TransferClient\";\nimport type { CapabilitySet } from \"../core/CapabilitySet\";\nimport type { ProviderId } from \"../core/ProviderId\";\nimport { redactConnectionProfile } from \"../profiles/ProfileRedactor\";\nimport type { ConnectionProfile, RemoteEntry } from \"../types/public\";\n\n/** Snapshot of the providers registered with a client. */\nexport interface ClientDiagnostics {\n /** Providers currently registered, keyed by id. */\n providers: ReadonlyArray<{ id: ProviderId; capabilities: CapabilitySet }>;\n}\n\n/**\n * Returns a redaction-safe snapshot of the providers registered with a client.\n *\n * Use this when rendering a setup screen, generating a support bundle, or\n * asserting in tests that the expected provider factories were registered.\n *\n * @param client - Transfer client to inspect.\n * @returns Provider id and capability snapshot tuples.\n *\n * @example List registered providers\n * ```ts\n * import { summarizeClientDiagnostics } from \"@zero-transfer/sdk\";\n *\n * for (const { id, capabilities } of summarizeClientDiagnostics(client).providers) {\n * console.log(`${id}: streaming=${capabilities.readStream} resume=${capabilities.resumeDownload}`);\n * }\n * ```\n */\nexport function summarizeClientDiagnostics(client: TransferClient): ClientDiagnostics {\n const capabilities = client.getCapabilities();\n return {\n providers: capabilities.map((entry) => ({ capabilities: entry, id: entry.provider })),\n };\n}\n\n/** Per-step duration measurements collected by {@link runConnectionDiagnostics}. */\nexport interface ConnectionDiagnosticTimings {\n /** Total time spent inside `client.connect`. */\n connectMs?: number;\n /** Time spent inside the optional `fs.list` probe. */\n listMs?: number;\n /** Time spent inside the optional `session.disconnect`. */\n disconnectMs?: number;\n}\n\n/** Result returned by {@link runConnectionDiagnostics}. */\nexport interface ConnectionDiagnosticsResult {\n /** Resolved provider id used to open the session. */\n provider?: ProviderId;\n /** Profile host (after redaction). */\n host: string;\n /** Capability snapshot reported by the connected session. */\n capabilities?: CapabilitySet;\n /** Redacted connection profile mirroring {@link redactConnectionProfile}. */\n redactedProfile: Record<string, unknown>;\n /** Per-step duration measurements. */\n timings: ConnectionDiagnosticTimings;\n /** Sample of entries returned by the optional `fs.list` probe. */\n sample?: readonly RemoteEntry[];\n /** Whether all probes ran without throwing. */\n ok: boolean;\n /** Captured error summary when the diagnostics could not complete. */\n error?: { message: string; name?: string; code?: string };\n}\n\n/** Options accepted by {@link runConnectionDiagnostics}. */\nexport interface RunConnectionDiagnosticsOptions {\n /** Transfer client used to open the session. */\n client: TransferClient;\n /** Connection profile to probe. */\n profile: ConnectionProfile;\n /** Path passed to the optional `fs.list` probe. Defaults to `\"/\"`. */\n listPath?: string;\n /** When `false`, skips the `fs.list` probe. Defaults to `true`. */\n probeList?: boolean;\n /** Maximum number of entries retained in the result sample. Defaults to `5`. */\n sampleSize?: number;\n /** Optional clock injected for deterministic test timings. Defaults to `performance.now`. */\n now?: () => number;\n}\n\n/**\n * Connects to a profile, captures capability and listing samples, and returns a redaction-safe report.\n *\n * Useful for connectivity \"ping\" pages, smoke tests, and bug reports. Secrets\n * in the profile are redacted via {@link redactConnectionProfile} before being\n * returned. The session is always disconnected before the function returns,\n * including when probes throw.\n *\n * @param options - Diagnostic probe options.\n * @returns Diagnostic report including timings and any captured error.\n *\n * @example Probe an SFTP connection\n * ```ts\n * import { runConnectionDiagnostics } from \"@zero-transfer/sdk\";\n *\n * const report = await runConnectionDiagnostics({\n * client,\n * profile: {\n * host: \"sftp.example.com\",\n * provider: \"sftp\",\n * username: \"deploy\",\n * ssh: { privateKey: { path: \"./keys/id_ed25519\" } },\n * },\n * listPath: \"/uploads\",\n * });\n *\n * if (!report.ok) {\n * console.error(\"connection failed:\", report.error);\n * } else {\n * console.log(`connect=${report.timings.connectMs}ms list=${report.timings.listMs}ms`);\n * console.log(report.sample); // up to 5 entries from /uploads\n * }\n * ```\n */\nexport async function runConnectionDiagnostics(\n options: RunConnectionDiagnosticsOptions,\n): Promise<ConnectionDiagnosticsResult> {\n const now = options.now ?? (() => performance.now());\n const probeList = options.probeList !== false;\n const listPath = options.listPath ?? \"/\";\n const sampleSize = Math.max(0, options.sampleSize ?? 5);\n const redactedProfile = redactConnectionProfile(options.profile);\n\n const result: ConnectionDiagnosticsResult = {\n host: options.profile.host,\n ok: false,\n redactedProfile,\n timings: {},\n };\n\n const connectStart = now();\n try {\n const session = await options.client.connect(options.profile);\n result.timings.connectMs = now() - connectStart;\n result.provider = session.provider;\n result.capabilities = session.capabilities;\n try {\n if (probeList) {\n const listStart = now();\n const entries = await session.fs.list(listPath);\n result.timings.listMs = now() - listStart;\n result.sample = entries.slice(0, sampleSize);\n }\n result.ok = true;\n } finally {\n const disconnectStart = now();\n await session.disconnect();\n result.timings.disconnectMs = now() - disconnectStart;\n }\n } catch (error) {\n result.error = summarizeDiagnosticError(error);\n }\n return result;\n}\n\nfunction summarizeDiagnosticError(error: unknown): {\n message: string;\n name?: string;\n code?: string;\n} {\n if (error instanceof Error) {\n const summary: { message: string; name?: string; code?: string } = { message: error.message };\n if (error.name !== \"Error\") summary.name = error.name;\n const code = (error as { code?: unknown }).code;\n if (typeof code === \"string\") summary.code = code;\n return summary;\n }\n return { message: String(error) };\n}\n","/**\n * Connection pooling for {@link TransferClient}.\n *\n * Wraps an existing {@link TransferClient} and reuses idle provider sessions\n * keyed by `(provider, host, port, username)` so successive transfers to the\n * same endpoint avoid the cost of repeated TCP/TLS handshakes, FTP login\n * round-trips, SFTP key exchange, and similar per-session setup work. This is\n * an opt-in wrapper: workloads that prefer fresh sessions per call should\n * keep using `TransferClient` directly.\n *\n * Pooling preserves the public {@link TransferSession} surface - callers\n * still call `disconnect()` when finished, but rather than tearing down the\n * underlying transport the wrapper marks the session idle and returns it to\n * the pool for reuse. Idle sessions are evicted automatically after\n * {@link ConnectionPoolOptions.idleTimeoutMs} milliseconds, and the pool can\n * be drained explicitly via the returned {@link PooledTransferClient.drainPool}\n * helper.\n *\n * Sessions that surface {@link ConnectionError}, {@link TimeoutError}, or\n * {@link ProtocolError} during use are considered \"tainted\" and discarded\n * instead of returned to the pool, since the underlying transport may be in\n * an inconsistent state. Application errors such as\n * {@link PathNotFoundError} or {@link PermissionDeniedError} do not taint\n * the session.\n *\n * @module core/ConnectionPool\n */\nimport { ConnectionError, ProtocolError, TimeoutError } from \"../errors/ZeroTransferError\";\nimport type { ProviderTransferOperations } from \"../providers/ProviderTransferOperations\";\nimport type { RemoteFileSystem } from \"../providers/RemoteFileSystem\";\nimport type { ConnectionProfile } from \"../types/public\";\nimport type { CapabilitySet } from \"./CapabilitySet\";\nimport type { ProviderId } from \"./ProviderId\";\nimport type { TransferClient } from \"./TransferClient\";\nimport type { TransferSession } from \"./TransferSession\";\n\n/** Options for {@link createPooledTransferClient}. */\nexport interface ConnectionPoolOptions {\n /**\n * Maximum number of *idle* sessions retained per pool key.\n *\n * Active leases are not counted against this limit - the cap only applies\n * to sessions waiting in the pool. When more than `maxIdlePerKey` sessions\n * become idle simultaneously, the oldest ones are disconnected. Defaults\n * to `4`.\n */\n maxIdlePerKey?: number;\n /**\n * How long an idle session may sit unused before it is automatically\n * disconnected. Defaults to `60_000` ms. Set to `0` to disable the timer\n * (idle sessions persist until `drainPool()` is called).\n */\n idleTimeoutMs?: number;\n /**\n * Custom pool key derivation. Receives the resolved\n * {@link ConnectionProfile} (after TransferClient validation) and must\n * return a string. Sessions with matching keys are pooled together; never\n * include secrets in the key.\n *\n * The default derives the key from `provider`, `host`, `port`, and\n * `username`.\n */\n keyOf?: (profile: ConnectionProfile) => string;\n}\n\n/**\n * Pool-aware {@link TransferClient} returned by\n * {@link createPooledTransferClient}.\n */\nexport interface PooledTransferClient {\n /** Opens (or leases) a pooled provider session. */\n connect(profile: ConnectionProfile): Promise<TransferSession>;\n /** Inspects the registered providers (delegated to the underlying client). */\n hasProvider(providerId: ProviderId): boolean;\n /** Returns the registered capability snapshots (delegated). */\n getCapabilities(): CapabilitySet[];\n /** Returns a specific capability snapshot (delegated). */\n getCapabilities(providerId: ProviderId): CapabilitySet;\n /**\n * Disconnects every idle session and prevents further pooling. After\n * `drainPool()` resolves, subsequent `connect()` calls still work but\n * always create fresh sessions (and never return them to the pool).\n */\n drainPool(): Promise<void>;\n /** Returns the number of idle sessions currently held in the pool. */\n poolSize(): number;\n}\n\ninterface PoolEntry {\n session: TransferSession;\n /** Timer that disconnects this entry after `idleTimeoutMs`. */\n idleTimer?: ReturnType<typeof setTimeout>;\n}\n\ninterface InternalState {\n drained: boolean;\n /** Idle sessions keyed by pool key. */\n idle: Map<string, PoolEntry[]>;\n}\n\nconst DEFAULT_MAX_IDLE_PER_KEY = 4;\nconst DEFAULT_IDLE_TIMEOUT_MS = 60_000;\n\n/**\n * Wraps a {@link TransferClient} with connection pooling.\n *\n * @param inner - Underlying client used to create real provider sessions.\n * @param options - Pool sizing, eviction, and key-derivation overrides.\n * @returns A {@link PooledTransferClient} that reuses idle sessions.\n */\nexport function createPooledTransferClient(\n inner: TransferClient,\n options: ConnectionPoolOptions = {},\n): PooledTransferClient {\n const maxIdlePerKey = Math.max(1, options.maxIdlePerKey ?? DEFAULT_MAX_IDLE_PER_KEY);\n const idleTimeoutMs = Math.max(0, options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS);\n const keyOf = options.keyOf ?? defaultKeyOf;\n\n const state: InternalState = {\n drained: false,\n idle: new Map(),\n };\n\n const release = (key: string, session: TransferSession, tainted: boolean): Promise<void> => {\n if (tainted || state.drained) {\n return safelyDisconnect(session);\n }\n\n let bucket = state.idle.get(key);\n if (bucket === undefined) {\n bucket = [];\n state.idle.set(key, bucket);\n }\n\n const entry: PoolEntry = { session };\n if (idleTimeoutMs > 0) {\n entry.idleTimer = setTimeout(() => {\n evictEntry(state, key, entry);\n }, idleTimeoutMs);\n // Avoid keeping the Node.js event loop alive solely for idle pool\n // entries (e.g. in CLI tools).\n const timer = entry.idleTimer as { unref?: () => void } | undefined;\n if (timer !== undefined && typeof timer.unref === \"function\") {\n timer.unref();\n }\n }\n\n bucket.push(entry);\n\n // Trim the oldest entries when the bucket exceeds the cap.\n while (bucket.length > maxIdlePerKey) {\n const dropped = bucket.shift();\n if (dropped !== undefined) {\n clearEntryTimer(dropped);\n void safelyDisconnect(dropped.session);\n }\n }\n return Promise.resolve();\n };\n\n const acquire = async (\n profile: ConnectionProfile,\n ): Promise<{ session: TransferSession; key: string }> => {\n const key = keyOf(profile);\n const bucket = state.idle.get(key);\n if (bucket !== undefined && bucket.length > 0) {\n const entry = bucket.pop();\n if (entry !== undefined) {\n clearEntryTimer(entry);\n if (bucket.length === 0) state.idle.delete(key);\n return { key, session: entry.session };\n }\n }\n const session = await inner.connect(profile);\n return { key, session };\n };\n\n return {\n connect: async (profile) => {\n const { key, session } = await acquire(profile);\n return wrapPooledSession(session, key, release);\n },\n drainPool: async () => {\n state.drained = true;\n const entries: PoolEntry[] = [];\n for (const bucket of state.idle.values()) {\n for (const entry of bucket) {\n clearEntryTimer(entry);\n entries.push(entry);\n }\n }\n state.idle.clear();\n await Promise.all(entries.map((entry) => safelyDisconnect(entry.session)));\n },\n getCapabilities: ((providerId?: ProviderId): CapabilitySet | CapabilitySet[] => {\n if (providerId === undefined) return inner.getCapabilities();\n return inner.getCapabilities(providerId);\n }) as PooledTransferClient[\"getCapabilities\"],\n hasProvider: (providerId) => inner.hasProvider(providerId),\n poolSize: () => {\n let total = 0;\n for (const bucket of state.idle.values()) total += bucket.length;\n return total;\n },\n };\n}\n\n/** Default pool key - never includes secrets. */\nfunction defaultKeyOf(profile: ConnectionProfile): string {\n const provider = profile.provider ?? profile.protocol ?? \"unknown\";\n const host = profile.host ?? \"\";\n const port = profile.port ?? \"\";\n const username = typeof profile.username === \"string\" ? profile.username : \"\";\n return `${provider}|${host}|${String(port)}|${username}`;\n}\n\nfunction evictEntry(state: InternalState, key: string, entry: PoolEntry): void {\n const bucket = state.idle.get(key);\n if (bucket === undefined) return;\n const index = bucket.indexOf(entry);\n if (index < 0) return;\n bucket.splice(index, 1);\n if (bucket.length === 0) state.idle.delete(key);\n clearEntryTimer(entry);\n void safelyDisconnect(entry.session);\n}\n\nfunction clearEntryTimer(entry: PoolEntry): void {\n if (entry.idleTimer !== undefined) {\n clearTimeout(entry.idleTimer);\n delete entry.idleTimer;\n }\n}\n\nasync function safelyDisconnect(session: TransferSession): Promise<void> {\n try {\n await session.disconnect();\n } catch {\n // Pool teardown errors are not actionable; swallow them.\n }\n}\n\n/** Errors that indicate the underlying transport may be in a bad state. */\nfunction isTaintingError(error: unknown): boolean {\n return (\n error instanceof ConnectionError ||\n error instanceof TimeoutError ||\n error instanceof ProtocolError\n );\n}\n\n/**\n * Wraps a real {@link TransferSession} so that:\n * - operation errors that indicate transport corruption taint the lease,\n * - `disconnect()` returns the (untainted) session to the pool,\n * - subsequent calls on a disconnected lease throw rather than racing.\n */\nfunction wrapPooledSession(\n session: TransferSession,\n key: string,\n release: (key: string, session: TransferSession, tainted: boolean) => Promise<void>,\n): TransferSession {\n let tainted = false;\n let released = false;\n\n const guard = <T>(fn: () => Promise<T>): Promise<T> => {\n let promise: Promise<T>;\n try {\n promise = fn();\n } catch (error) {\n if (isTaintingError(error)) tainted = true;\n return Promise.reject(error instanceof Error ? error : new Error(String(error)));\n }\n return promise.catch((error: unknown) => {\n if (isTaintingError(error)) tainted = true;\n throw error;\n });\n };\n\n const fs = wrapFs(session.fs, guard);\n const transfers =\n session.transfers === undefined ? undefined : wrapTransfers(session.transfers, guard);\n\n const wrapped: TransferSession = {\n capabilities: session.capabilities,\n disconnect: async () => {\n if (released) return;\n released = true;\n await release(key, session, tainted);\n },\n fs,\n provider: session.provider,\n ...(transfers !== undefined ? { transfers } : {}),\n };\n\n if (typeof session.raw === \"function\") {\n const rawFn = session.raw.bind(session);\n wrapped.raw = () => rawFn();\n }\n\n return wrapped;\n}\n\nfunction wrapFs(\n fs: RemoteFileSystem,\n guard: <T>(fn: () => Promise<T>) => Promise<T>,\n): RemoteFileSystem {\n const wrapped: RemoteFileSystem = {\n list: (path, options) =>\n guard(() => (options !== undefined ? fs.list(path, options) : fs.list(path))),\n stat: (path, options) =>\n guard(() => (options !== undefined ? fs.stat(path, options) : fs.stat(path))),\n };\n if (typeof fs.remove === \"function\") {\n const remove = fs.remove.bind(fs);\n wrapped.remove = (path, options) =>\n guard(() => (options !== undefined ? remove(path, options) : remove(path)));\n }\n if (typeof fs.rename === \"function\") {\n const rename = fs.rename.bind(fs);\n wrapped.rename = (from, to, options) =>\n guard(() => (options !== undefined ? rename(from, to, options) : rename(from, to)));\n }\n if (typeof fs.mkdir === \"function\") {\n const mkdir = fs.mkdir.bind(fs);\n wrapped.mkdir = (path, options) =>\n guard(() => (options !== undefined ? mkdir(path, options) : mkdir(path)));\n }\n if (typeof fs.rmdir === \"function\") {\n const rmdir = fs.rmdir.bind(fs);\n wrapped.rmdir = (path, options) =>\n guard(() => (options !== undefined ? rmdir(path, options) : rmdir(path)));\n }\n return wrapped;\n}\n\nfunction wrapTransfers(\n transfers: ProviderTransferOperations,\n guard: <T>(fn: () => Promise<T>) => Promise<T>,\n): ProviderTransferOperations {\n return {\n read: (request) => guard(() => Promise.resolve(transfers.read(request))),\n write: (request) => guard(() => Promise.resolve(transfers.write(request))),\n };\n}\n","/**\n * Local file-system provider for deterministic provider contract coverage.\n *\n * @module providers/local/LocalProvider\n */\nimport { createReadStream } from \"node:fs\";\nimport {\n lstat,\n mkdir,\n open,\n readdir,\n readlink,\n rename,\n rm,\n unlink,\n writeFile,\n} from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { Buffer } from \"node:buffer\";\nimport type { Stats } from \"node:fs\";\nimport type { CapabilitySet } from \"../../core/CapabilitySet\";\nimport type { TransferSession } from \"../../core/TransferSession\";\nimport {\n ConfigurationError,\n PathNotFoundError,\n PermissionDeniedError,\n} from \"../../errors/ZeroTransferError\";\nimport type { TransferVerificationResult } from \"../../transfers/TransferJob\";\nimport type {\n ConnectionProfile,\n MkdirOptions,\n RemoteEntry,\n RemoteEntryType,\n RemoteStat,\n RemoveOptions,\n RmdirOptions,\n} from \"../../types/public\";\nimport { basenameRemotePath, joinRemotePath, normalizeRemotePath } from \"../../utils/path\";\nimport type { TransferProvider } from \"../Provider\";\nimport type { ProviderFactory } from \"../ProviderFactory\";\nimport type {\n ProviderTransferOperations,\n ProviderTransferReadRequest,\n ProviderTransferReadResult,\n ProviderTransferWriteRequest,\n ProviderTransferWriteResult,\n} from \"../ProviderTransferOperations\";\nimport type { RemoteFileSystem } from \"../RemoteFileSystem\";\n\nconst LOCAL_PROVIDER_ID = \"local\";\n\nconst LOCAL_PROVIDER_CAPABILITIES: CapabilitySet = {\n provider: LOCAL_PROVIDER_ID,\n authentication: [\"anonymous\"],\n list: true,\n stat: true,\n readStream: true,\n writeStream: true,\n serverSideCopy: false,\n serverSideMove: false,\n resumeDownload: true,\n resumeUpload: true,\n checksum: [],\n atomicRename: false,\n chmod: false,\n chown: false,\n symlink: true,\n metadata: [\"accessedAt\", \"createdAt\", \"modifiedAt\", \"permissions\", \"symlinkTarget\", \"uniqueId\"],\n maxConcurrency: 16,\n notes: [\"Local filesystem provider for tests and local-only workflows\"],\n};\n\n/** Options used to create a local file-system provider factory. */\nexport interface LocalProviderOptions {\n /** Root directory exposed as `/`. When omitted, `profile.host` is treated as the root path. */\n rootPath?: string;\n}\n\n/**\n * Creates a provider factory backed by the local filesystem.\n *\n * Useful for copying files between two remote endpoints via a local staging\n * area, or as the destination for `downloadFile`. The friendly `uploadFile`\n * helper registers a local provider implicitly.\n *\n * @param options - Optional local root path exposed through provider sessions.\n * @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.\n *\n * @example Use a fixed root directory\n * ```ts\n * import { createLocalProviderFactory, createTransferClient } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({\n * providers: [createLocalProviderFactory({ rootPath: \"/var/lib/zt-staging\" })],\n * });\n *\n * const session = await client.connect({ host: \"staging\", provider: \"local\" });\n * const list = await session.fs.list(\"/\");\n * ```\n */\nexport function createLocalProviderFactory(options: LocalProviderOptions = {}): ProviderFactory {\n return {\n id: LOCAL_PROVIDER_ID,\n capabilities: LOCAL_PROVIDER_CAPABILITIES,\n create: () => new LocalProvider(options.rootPath),\n };\n}\n\nclass LocalProvider implements TransferProvider {\n readonly id = LOCAL_PROVIDER_ID;\n readonly capabilities = LOCAL_PROVIDER_CAPABILITIES;\n\n constructor(private readonly configuredRootPath: string | undefined) {}\n\n connect(profile: ConnectionProfile): Promise<TransferSession> {\n return Promise.resolve().then(() => {\n const rootPath = path.resolve(this.configuredRootPath ?? profile.host);\n return new LocalTransferSession(rootPath);\n });\n }\n}\n\nclass LocalTransferSession implements TransferSession {\n readonly provider = LOCAL_PROVIDER_ID;\n readonly capabilities = LOCAL_PROVIDER_CAPABILITIES;\n readonly fs: RemoteFileSystem;\n readonly transfers: ProviderTransferOperations;\n\n constructor(rootPath: string) {\n this.fs = new LocalFileSystem(rootPath);\n this.transfers = new LocalTransferOperations(rootPath);\n }\n\n disconnect(): Promise<void> {\n return Promise.resolve();\n }\n}\n\nclass LocalTransferOperations implements ProviderTransferOperations {\n constructor(private readonly rootPath: string) {}\n\n async read(request: ProviderTransferReadRequest): Promise<ProviderTransferReadResult> {\n request.throwIfAborted();\n const remotePath = normalizeLocalProviderPath(request.endpoint.path);\n const entry = await readLocalEntry(this.rootPath, remotePath);\n\n if (entry.type !== \"file\") {\n throw createPathNotFoundError(remotePath, `Local provider path is not a file: ${remotePath}`);\n }\n\n const range = resolveReadRange(entry.size ?? 0, request.range);\n const result: ProviderTransferReadResult = {\n content: createLocalReadSource(resolveLocalPath(this.rootPath, remotePath), range),\n totalBytes: range.length,\n };\n\n if (range.offset > 0) {\n result.bytesRead = range.offset;\n }\n\n return result;\n }\n\n async write(request: ProviderTransferWriteRequest): Promise<ProviderTransferWriteResult> {\n request.throwIfAborted();\n const remotePath = normalizeLocalProviderPath(request.endpoint.path);\n const localPath = resolveLocalPath(this.rootPath, remotePath);\n const content = await collectTransferContent(request);\n const offset = normalizeOptionalByteCount(request.offset, \"offset\", remotePath);\n\n await ensureLocalParentDirectory(localPath, remotePath);\n await writeLocalContent(localPath, remotePath, content, offset);\n\n const stat = await readLocalEntry(this.rootPath, remotePath);\n const result: ProviderTransferWriteResult = {\n bytesTransferred: content.byteLength,\n resumed: offset !== undefined && offset > 0,\n verified: request.verification?.verified ?? false,\n };\n\n if (stat.size !== undefined) {\n result.totalBytes = stat.size;\n }\n\n if (request.verification !== undefined) {\n result.verification = cloneVerification(request.verification);\n }\n\n return result;\n }\n}\n\nclass LocalFileSystem implements RemoteFileSystem {\n constructor(private readonly rootPath: string) {}\n\n async list(path: string): Promise<RemoteEntry[]> {\n const remotePath = normalizeLocalProviderPath(path);\n const directory = await this.stat(remotePath);\n\n if (directory.type !== \"directory\") {\n throw createPathNotFoundError(\n remotePath,\n `Local provider path is not a directory: ${remotePath}`,\n );\n }\n\n const localPath = resolveLocalPath(this.rootPath, remotePath);\n const names = await readLocalDirectory(localPath, remotePath);\n const entries = await Promise.all(\n names.map((name) => readLocalEntry(this.rootPath, joinRemotePath(remotePath, name))),\n );\n\n return entries.sort(compareEntries);\n }\n\n async stat(path: string): Promise<RemoteStat> {\n return readLocalEntry(this.rootPath, normalizeLocalProviderPath(path));\n }\n\n async remove(remote: string, options: RemoveOptions = {}): Promise<void> {\n const remotePath = normalizeLocalProviderPath(remote);\n const localPath = resolveLocalPath(this.rootPath, remotePath);\n try {\n await unlink(localPath);\n } catch (error) {\n if (options.ignoreMissing && isNodeErrno(error, \"ENOENT\")) return;\n if (isNodeErrno(error, \"ENOENT\")) {\n throw createPathNotFoundError(remotePath, `Local path not found: ${remotePath}`);\n }\n throw error;\n }\n }\n\n async rename(from: string, to: string): Promise<void> {\n const fromRemote = normalizeLocalProviderPath(from);\n const toRemote = normalizeLocalProviderPath(to);\n const fromLocal = resolveLocalPath(this.rootPath, fromRemote);\n const toLocal = resolveLocalPath(this.rootPath, toRemote);\n try {\n await rename(fromLocal, toLocal);\n } catch (error) {\n if (isNodeErrno(error, \"ENOENT\")) {\n throw createPathNotFoundError(fromRemote, `Local path not found: ${fromRemote}`);\n }\n throw error;\n }\n }\n\n async mkdir(remote: string, options: MkdirOptions = {}): Promise<void> {\n const remotePath = normalizeLocalProviderPath(remote);\n const localPath = resolveLocalPath(this.rootPath, remotePath);\n await mkdir(localPath, { recursive: options.recursive === true });\n }\n\n async rmdir(remote: string, options: RmdirOptions = {}): Promise<void> {\n const remotePath = normalizeLocalProviderPath(remote);\n const localPath = resolveLocalPath(this.rootPath, remotePath);\n try {\n await rm(localPath, { recursive: options.recursive === true, force: false });\n } catch (error) {\n if (isNodeErrno(error, \"ENOENT\")) {\n if (options.ignoreMissing) return;\n throw createPathNotFoundError(remotePath, `Local path not found: ${remotePath}`);\n }\n throw error;\n }\n }\n}\n\nfunction isNodeErrno(error: unknown, code: string): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as { code?: unknown }).code === code\n );\n}\n\ninterface ResolvedReadRange {\n offset: number;\n length: number;\n}\n\nfunction resolveReadRange(\n size: number,\n range: ProviderTransferReadRequest[\"range\"],\n): ResolvedReadRange {\n if (range === undefined) {\n return { length: size, offset: 0 };\n }\n\n const requestedOffset = normalizeByteCount(range.offset, \"offset\", \"/\");\n const requestedLength =\n range.length === undefined\n ? size - Math.min(requestedOffset, size)\n : normalizeByteCount(range.length, \"length\", \"/\");\n const offset = Math.min(requestedOffset, size);\n const length = Math.max(0, Math.min(requestedLength, size - offset));\n\n return { length, offset };\n}\n\nasync function* createLocalReadSource(\n localPath: string,\n range: ResolvedReadRange,\n): AsyncGenerator<Uint8Array> {\n if (range.length <= 0) {\n return;\n }\n\n const stream = createReadStream(localPath, {\n end: range.offset + range.length - 1,\n start: range.offset,\n }) as AsyncIterable<Buffer>;\n\n for await (const chunk of stream) {\n yield new Uint8Array(chunk);\n }\n}\n\nasync function collectTransferContent(request: ProviderTransferWriteRequest): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n let byteLength = 0;\n\n for await (const chunk of request.content) {\n request.throwIfAborted();\n const clonedChunk = new Uint8Array(chunk);\n chunks.push(clonedChunk);\n byteLength += clonedChunk.byteLength;\n request.reportProgress(byteLength, request.totalBytes);\n }\n\n return concatChunks(chunks, byteLength);\n}\n\nfunction concatChunks(chunks: Uint8Array[], byteLength: number): Uint8Array {\n const content = new Uint8Array(byteLength);\n let offset = 0;\n\n for (const chunk of chunks) {\n content.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return content;\n}\n\nasync function ensureLocalParentDirectory(localPath: string, remotePath: string): Promise<void> {\n try {\n await mkdir(path.dirname(localPath), { recursive: true });\n } catch (error) {\n throw mapLocalFileSystemError(error, remotePath);\n }\n}\n\nasync function writeLocalContent(\n localPath: string,\n remotePath: string,\n content: Uint8Array,\n offset: number | undefined,\n): Promise<void> {\n try {\n if (offset === undefined) {\n await writeFile(localPath, content);\n return;\n }\n\n const handle = await openLocalFileForOffsetWrite(localPath);\n\n try {\n await handle.write(content, 0, content.byteLength, offset);\n } finally {\n await handle.close();\n }\n } catch (error) {\n throw mapLocalFileSystemError(error, remotePath);\n }\n}\n\nasync function openLocalFileForOffsetWrite(localPath: string) {\n try {\n return await open(localPath, \"r+\");\n } catch (error) {\n if (getErrorCode(error) === \"ENOENT\") {\n return open(localPath, \"w+\");\n }\n\n throw error;\n }\n}\n\nfunction normalizeOptionalByteCount(\n value: number | undefined,\n field: string,\n remotePath: string,\n): number | undefined {\n return value === undefined ? undefined : normalizeByteCount(value, field, remotePath);\n}\n\nfunction normalizeByteCount(value: number, field: string, remotePath: string): number {\n if (!Number.isFinite(value) || value < 0) {\n throw new ConfigurationError({\n details: { field, provider: LOCAL_PROVIDER_ID },\n message: `Local provider ${field} must be a non-negative number`,\n path: remotePath,\n retryable: false,\n });\n }\n\n return Math.floor(value);\n}\n\nfunction cloneVerification(verification: TransferVerificationResult): TransferVerificationResult {\n const clone: TransferVerificationResult = { verified: verification.verified };\n\n if (verification.method !== undefined) clone.method = verification.method;\n if (verification.checksum !== undefined) clone.checksum = verification.checksum;\n if (verification.expectedChecksum !== undefined) {\n clone.expectedChecksum = verification.expectedChecksum;\n }\n if (verification.actualChecksum !== undefined) clone.actualChecksum = verification.actualChecksum;\n if (verification.details !== undefined) clone.details = { ...verification.details };\n\n return clone;\n}\n\nasync function readLocalDirectory(localPath: string, remotePath: string): Promise<string[]> {\n try {\n return await readdir(localPath);\n } catch (error) {\n throw mapLocalFileSystemError(error, remotePath);\n }\n}\n\nasync function readLocalEntry(rootPath: string, remotePath: string): Promise<RemoteStat> {\n const localPath = resolveLocalPath(rootPath, remotePath);\n let stats: Stats;\n\n try {\n stats = await lstat(localPath);\n } catch (error) {\n throw mapLocalFileSystemError(error, remotePath);\n }\n\n const entry: RemoteEntry = {\n accessedAt: cloneDate(stats.atime),\n createdAt: cloneDate(stats.birthtime),\n modifiedAt: cloneDate(stats.mtime),\n name: basenameRemotePath(remotePath),\n path: remotePath,\n permissions: { raw: formatMode(stats.mode) },\n size: stats.size,\n type: getLocalEntryType(stats),\n uniqueId: `${stats.dev}:${stats.ino}`,\n };\n\n if (entry.type === \"symlink\") {\n const symlinkTarget = await readSymlinkTarget(localPath);\n\n if (symlinkTarget !== undefined) {\n entry.symlinkTarget = symlinkTarget;\n }\n }\n\n return {\n ...entry,\n exists: true,\n };\n}\n\nasync function readSymlinkTarget(localPath: string): Promise<string | undefined> {\n try {\n return await readlink(localPath);\n } catch {\n return undefined;\n }\n}\n\nfunction normalizeLocalProviderPath(input: string): string {\n const normalized = normalizeRemotePath(input);\n\n if (normalized === \"..\" || normalized.startsWith(\"../\")) {\n throw new ConfigurationError({\n details: { provider: LOCAL_PROVIDER_ID },\n message: `Local provider path escapes the configured root: ${normalized}`,\n path: normalized,\n retryable: false,\n });\n }\n\n if (normalized === \".\" || normalized === \"/\") {\n return \"/\";\n }\n\n return normalized.startsWith(\"/\") ? normalized : `/${normalized}`;\n}\n\nfunction resolveLocalPath(rootPath: string, remotePath: string): string {\n const normalizedRemotePath = normalizeLocalProviderPath(remotePath);\n\n // If the remote path is already an absolute filesystem path inside rootPath\n // (e.g. friendly upload/download passes the host path as the endpoint path),\n // honour it directly instead of double-prepending rootPath.\n const resolvedRootPath = path.resolve(rootPath);\n const candidateAbsolute = path.resolve(normalizedRemotePath.split(\"/\").join(path.sep));\n if (\n candidateAbsolute === resolvedRootPath ||\n candidateAbsolute.startsWith(resolvedRootPath + path.sep)\n ) {\n return candidateAbsolute;\n }\n\n const relativePath = normalizedRemotePath === \"/\" ? \".\" : normalizedRemotePath.slice(1);\n const resolvedPath = path.resolve(rootPath, relativePath.split(\"/\").join(path.sep));\n const relativeToRoot = path.relative(rootPath, resolvedPath);\n\n if (\n relativeToRoot === \"\" ||\n (!relativeToRoot.startsWith(\"..\") && !path.isAbsolute(relativeToRoot))\n ) {\n return resolvedPath;\n }\n\n throw new ConfigurationError({\n details: { provider: LOCAL_PROVIDER_ID, rootPath },\n message: `Local provider path escapes the configured root: ${normalizedRemotePath}`,\n path: normalizedRemotePath,\n retryable: false,\n });\n}\n\nfunction getLocalEntryType(stats: Stats): RemoteEntryType {\n if (stats.isFile()) return \"file\";\n if (stats.isDirectory()) return \"directory\";\n if (stats.isSymbolicLink()) return \"symlink\";\n return \"unknown\";\n}\n\nfunction formatMode(mode: number): string {\n return (mode & 0o777).toString(8).padStart(3, \"0\");\n}\n\nfunction cloneDate(value: Date): Date {\n return new Date(value.getTime());\n}\n\nfunction compareEntries(left: RemoteEntry, right: RemoteEntry): number {\n return left.path.localeCompare(right.path);\n}\n\nfunction mapLocalFileSystemError(error: unknown, remotePath: string): Error {\n const code = getErrorCode(error);\n\n if (code === \"ENOENT\" || code === \"ENOTDIR\") {\n return createPathNotFoundError(remotePath, `Local provider path not found: ${remotePath}`);\n }\n\n if (code === \"EACCES\" || code === \"EPERM\") {\n return new PermissionDeniedError({\n cause: error,\n details: { provider: LOCAL_PROVIDER_ID },\n message: `Local provider permission denied: ${remotePath}`,\n path: remotePath,\n retryable: false,\n });\n }\n\n return new ConfigurationError({\n cause: error,\n details: { code, provider: LOCAL_PROVIDER_ID },\n message: `Local provider filesystem operation failed: ${remotePath}`,\n path: remotePath,\n retryable: false,\n });\n}\n\nfunction createPathNotFoundError(path: string, message: string): PathNotFoundError {\n return new PathNotFoundError({\n details: { provider: LOCAL_PROVIDER_ID },\n message,\n path,\n retryable: false,\n });\n}\n\nfunction getErrorCode(error: unknown): string | undefined {\n return typeof error === \"object\" && error !== null && \"code\" in error\n ? String((error as { code?: unknown }).code)\n : undefined;\n}\n","/**\n * Remote path normalization and FTP command-argument safety helpers.\n *\n * The functions in this module avoid platform-specific local path behavior and reject\n * CR/LF and NUL characters before values can be interpolated into FTP commands or\n * handed to filesystem APIs.\n *\n * @module utils/path\n */\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\n\nconst UNSAFE_FTP_ARGUMENT_PATTERN = /[\\r\\n\\0]/;\n\n/**\n * Validates that an FTP command argument cannot inject additional command lines.\n *\n * NUL bytes are rejected alongside CR/LF: C-string-based servers and filesystem\n * APIs truncate at the first NUL, which lets a crafted path smuggle a different\n * effective target past validation.\n *\n * @param value - Argument value to validate.\n * @param label - Human-readable argument label used in error messages.\n * @returns The original value when it is safe.\n * @throws {@link ConfigurationError} When the value contains CR, LF, or NUL characters.\n */\nexport function assertSafeFtpArgument(value: string, label = \"path\"): string {\n if (UNSAFE_FTP_ARGUMENT_PATTERN.test(value)) {\n throw new ConfigurationError({\n message: `Unsafe FTP ${label}: CR, LF, and NUL characters are not allowed`,\n retryable: false,\n details: {\n label,\n },\n });\n }\n\n return value;\n}\n\n/**\n * Normalizes a remote path using POSIX-style separators without escaping absolute roots.\n *\n * @param input - Remote path that may contain duplicate separators or dot segments.\n * @returns A normalized remote path, `/` for absolute root, or `.` for an empty relative path.\n * @throws {@link ConfigurationError} When the input contains unsafe CR, LF, or NUL characters.\n */\nexport function normalizeRemotePath(input: string): string {\n assertSafeFtpArgument(input);\n\n if (input.length === 0) {\n return \".\";\n }\n\n const isAbsolute = input.startsWith(\"/\");\n const segments: string[] = [];\n\n for (const segment of input.split(/[\\\\/]+/)) {\n if (segment.length === 0 || segment === \".\") {\n continue;\n }\n\n if (segment === \"..\") {\n if (segments.length > 0 && segments[segments.length - 1] !== \"..\") {\n segments.pop();\n } else if (!isAbsolute) {\n segments.push(segment);\n }\n continue;\n }\n\n segments.push(segment);\n }\n\n const normalized = segments.join(\"/\");\n\n if (isAbsolute) {\n return normalized.length > 0 ? `/${normalized}` : \"/\";\n }\n\n return normalized.length > 0 ? normalized : \".\";\n}\n\n/**\n * Joins remote path segments and normalizes the result.\n *\n * @param segments - Remote path segments to concatenate.\n * @returns A normalized remote path.\n * @throws {@link ConfigurationError} When any joined segment contains unsafe characters.\n */\nexport function joinRemotePath(...segments: string[]): string {\n if (segments.length === 0) {\n return \".\";\n }\n\n return normalizeRemotePath(segments.join(\"/\"));\n}\n\n/**\n * Extracts the final name segment from a normalized remote path.\n *\n * @param input - Remote path to inspect.\n * @returns The final path segment, or `/` when the input is the absolute root.\n * @throws {@link ConfigurationError} When the input contains unsafe characters.\n */\nexport function basenameRemotePath(input: string): string {\n const normalized = normalizeRemotePath(input);\n const parts = normalized.split(\"/\").filter(Boolean);\n return parts[parts.length - 1] ?? normalized;\n}\n","/**\n * Deterministic in-memory provider for contract and unit tests.\n *\n * @module providers/memory/MemoryProvider\n */\nimport { Buffer } from \"node:buffer\";\nimport type { CapabilitySet } from \"../../core/CapabilitySet\";\nimport type { TransferSession } from \"../../core/TransferSession\";\nimport { ConfigurationError, PathNotFoundError } from \"../../errors/ZeroTransferError\";\nimport type { TransferVerificationResult } from \"../../transfers/TransferJob\";\nimport type { ProviderFactory } from \"../ProviderFactory\";\nimport type { TransferProvider } from \"../Provider\";\nimport type {\n ProviderTransferOperations,\n ProviderTransferReadRequest,\n ProviderTransferReadResult,\n ProviderTransferWriteRequest,\n ProviderTransferWriteResult,\n} from \"../ProviderTransferOperations\";\nimport type { RemoteFileSystem } from \"../RemoteFileSystem\";\nimport type {\n MkdirOptions,\n RemoteEntry,\n RemotePermissions,\n RemoteStat,\n RemoveOptions,\n RmdirOptions,\n} from \"../../types/public\";\nimport { basenameRemotePath, normalizeRemotePath } from \"../../utils/path\";\n\nconst MEMORY_PROVIDER_ID = \"memory\";\n\nconst MEMORY_PROVIDER_CAPABILITIES: CapabilitySet = {\n provider: MEMORY_PROVIDER_ID,\n authentication: [\"anonymous\"],\n list: true,\n stat: true,\n readStream: true,\n writeStream: true,\n serverSideCopy: false,\n serverSideMove: false,\n resumeDownload: true,\n resumeUpload: true,\n checksum: [],\n atomicRename: false,\n chmod: false,\n chown: false,\n symlink: true,\n metadata: [\n \"accessedAt\",\n \"createdAt\",\n \"group\",\n \"modifiedAt\",\n \"owner\",\n \"permissions\",\n \"symlinkTarget\",\n \"uniqueId\",\n ],\n maxConcurrency: 32,\n notes: [\"Deterministic in-memory provider for tests and provider contract validation\"],\n};\n\n/** Fixture entry used to seed a memory provider instance. */\nexport interface MemoryProviderEntry extends Omit<RemoteEntry, \"name\"> {\n /** Entry basename. When omitted, it is derived from `path`. */\n name?: string;\n /** Optional byte content for file entries. Strings are encoded as UTF-8. */\n content?: string | Uint8Array;\n}\n\n/** Options used to create a deterministic memory provider factory. */\nexport interface MemoryProviderOptions {\n /** Entries available to sessions created by this provider factory. */\n entries?: Iterable<MemoryProviderEntry>;\n}\n\n/**\n * Creates a provider factory backed by deterministic in-memory fixture entries.\n *\n * Useful for tests and examples where you want a real `TransferSession` without\n * touching disk or the network. Entries are pre-seeded; mutations made through\n * the session are visible to subsequent operations on the same provider.\n *\n * @param options - Optional fixture entries to expose through the memory provider.\n * @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.\n *\n * @example Seed entries and read them back\n * ```ts\n * import { createMemoryProviderFactory, createTransferClient } from \"@zero-transfer/sdk\";\n *\n * const client = createTransferClient({\n * providers: [createMemoryProviderFactory({\n * entries: [\n * { path: \"/fixtures/hello.txt\", content: \"hello world\" },\n * { path: \"/fixtures/data.bin\", content: new Uint8Array([1, 2, 3]) },\n * ],\n * })],\n * });\n *\n * const session = await client.connect({ host: \"fixtures\", provider: \"memory\" });\n * console.log(await session.fs.list(\"/fixtures\"));\n * ```\n */\nexport function createMemoryProviderFactory(options: MemoryProviderOptions = {}): ProviderFactory {\n const state = createMemoryState(options.entries ?? []);\n\n return {\n id: MEMORY_PROVIDER_ID,\n capabilities: MEMORY_PROVIDER_CAPABILITIES,\n create: () => new MemoryProvider(state),\n };\n}\n\nclass MemoryProvider implements TransferProvider {\n readonly id = MEMORY_PROVIDER_ID;\n readonly capabilities = MEMORY_PROVIDER_CAPABILITIES;\n\n constructor(private readonly state: MemoryProviderState) {}\n\n connect(): Promise<TransferSession> {\n return Promise.resolve(new MemoryTransferSession(this.state));\n }\n}\n\nclass MemoryTransferSession implements TransferSession {\n readonly provider = MEMORY_PROVIDER_ID;\n readonly capabilities = MEMORY_PROVIDER_CAPABILITIES;\n readonly fs: RemoteFileSystem;\n readonly transfers: ProviderTransferOperations;\n\n constructor(state: MemoryProviderState) {\n this.fs = new MemoryFileSystem(state);\n this.transfers = new MemoryTransferOperations(state);\n }\n\n disconnect(): Promise<void> {\n return Promise.resolve();\n }\n}\n\ninterface MemoryProviderState {\n entries: Map<string, RemoteStat>;\n content: Map<string, Uint8Array>;\n}\n\nclass MemoryFileSystem implements RemoteFileSystem {\n constructor(private readonly state: MemoryProviderState) {}\n\n list(path: string): Promise<RemoteEntry[]> {\n return Promise.resolve().then(() => {\n const normalizedPath = normalizeMemoryPath(path);\n const directory = this.requireEntry(normalizedPath);\n\n if (directory.type !== \"directory\") {\n throw createPathNotFoundError(\n normalizedPath,\n `Memory path is not a directory: ${normalizedPath}`,\n );\n }\n\n return [...this.state.entries.values()]\n .filter(\n (entry) => entry.path !== normalizedPath && getParentPath(entry.path) === normalizedPath,\n )\n .map(cloneRemoteEntry)\n .sort(compareEntries);\n });\n }\n\n stat(path: string): Promise<RemoteStat> {\n return Promise.resolve().then(() =>\n cloneRemoteStat(this.requireEntry(normalizeMemoryPath(path))),\n );\n }\n\n remove(path: string, options: RemoveOptions = {}): Promise<void> {\n return Promise.resolve().then(() => {\n const normalized = normalizeMemoryPath(path);\n const entry = this.state.entries.get(normalized);\n if (entry === undefined) {\n if (options.ignoreMissing) return;\n throw createPathNotFoundError(normalized, `Memory path not found: ${normalized}`);\n }\n if (entry.type === \"directory\") {\n throw createPathNotFoundError(\n normalized,\n `Memory path is a directory; use rmdir: ${normalized}`,\n );\n }\n this.state.entries.delete(normalized);\n this.state.content.delete(normalized);\n });\n }\n\n rename(from: string, to: string): Promise<void> {\n return Promise.resolve().then(() => {\n const fromPath = normalizeMemoryPath(from);\n const toPath = normalizeMemoryPath(to);\n const entry = this.state.entries.get(fromPath);\n if (entry === undefined) {\n throw createPathNotFoundError(fromPath, `Memory path not found: ${fromPath}`);\n }\n ensureParentDirectories(this.state.entries, toPath);\n const moved: RemoteStat = { ...entry, path: toPath, name: basenameRemotePath(toPath) };\n this.state.entries.delete(fromPath);\n this.state.entries.set(toPath, moved);\n const content = this.state.content.get(fromPath);\n if (content !== undefined) {\n this.state.content.delete(fromPath);\n this.state.content.set(toPath, content);\n }\n });\n }\n\n mkdir(path: string, options: MkdirOptions = {}): Promise<void> {\n return Promise.resolve().then(() => {\n const normalized = normalizeMemoryPath(path);\n const existing = this.state.entries.get(normalized);\n if (existing !== undefined) {\n if (existing.type === \"directory\" && options.recursive) return;\n throw createInvalidFixtureError(normalized, `Memory path already exists: ${normalized}`);\n }\n if (options.recursive) {\n ensureParentDirectories(this.state.entries, normalized);\n } else {\n const parent = getParentPath(normalized);\n if (parent !== undefined && !this.state.entries.has(parent)) {\n throw createPathNotFoundError(parent, `Memory parent not found: ${parent}`);\n }\n }\n this.state.entries.set(normalized, createDirectoryEntry(normalized));\n });\n }\n\n rmdir(path: string, options: RmdirOptions = {}): Promise<void> {\n return Promise.resolve().then(() => {\n const normalized = normalizeMemoryPath(path);\n const entry = this.state.entries.get(normalized);\n if (entry === undefined) {\n if (options.ignoreMissing) return;\n throw createPathNotFoundError(normalized, `Memory path not found: ${normalized}`);\n }\n if (entry.type !== \"directory\") {\n throw createPathNotFoundError(normalized, `Memory path is not a directory: ${normalized}`);\n }\n const children = [...this.state.entries.values()].filter(\n (child) => child.path !== normalized && getParentPath(child.path) === normalized,\n );\n if (children.length > 0 && !options.recursive) {\n throw createInvalidFixtureError(normalized, `Memory directory not empty: ${normalized}`);\n }\n const stack = [...children];\n while (stack.length > 0) {\n const next = stack.pop();\n if (!next) continue;\n if (next.type === \"directory\") {\n for (const grand of this.state.entries.values()) {\n if (grand.path !== next.path && getParentPath(grand.path) === next.path) {\n stack.push(grand);\n }\n }\n }\n this.state.entries.delete(next.path);\n this.state.content.delete(next.path);\n }\n this.state.entries.delete(normalized);\n });\n }\n\n private requireEntry(path: string): RemoteStat {\n const entry = this.state.entries.get(path);\n\n if (entry === undefined) {\n throw createPathNotFoundError(path, `Memory path not found: ${path}`);\n }\n\n return entry;\n }\n}\n\nclass MemoryTransferOperations implements ProviderTransferOperations {\n constructor(private readonly state: MemoryProviderState) {}\n\n read(request: ProviderTransferReadRequest): Promise<ProviderTransferReadResult> {\n return Promise.resolve().then(() => {\n request.throwIfAborted();\n const path = normalizeMemoryPath(request.endpoint.path);\n const entry = requireFileEntry(this.state, path);\n const content = this.state.content.get(path) ?? new Uint8Array(entry.size ?? 0);\n const range = resolveByteRange(content.byteLength, request.range);\n const chunk = content.slice(range.offset, range.offset + range.length);\n const result: ProviderTransferReadResult = {\n content: createMemoryContentSource(chunk),\n totalBytes: chunk.byteLength,\n };\n\n if (range.offset > 0) {\n result.bytesRead = range.offset;\n }\n\n return result;\n });\n }\n\n async write(request: ProviderTransferWriteRequest): Promise<ProviderTransferWriteResult> {\n request.throwIfAborted();\n const path = normalizeMemoryPath(request.endpoint.path);\n const existing = this.state.entries.get(path);\n\n if (existing?.type === \"directory\") {\n throw createInvalidFixtureError(path, `Memory path is a directory: ${path}`);\n }\n\n const writtenContent = await collectTransferContent(request);\n const offset = normalizeOptionalByteCount(request.offset, \"offset\");\n const previousContent = this.state.content.get(path) ?? new Uint8Array(0);\n const content =\n offset === undefined\n ? writtenContent\n : mergeContentAtOffset(previousContent, writtenContent, offset);\n\n ensureParentDirectories(this.state.entries, path);\n this.state.entries.set(path, createWrittenFileEntry(path, content.byteLength));\n this.state.content.set(path, content);\n\n const result: ProviderTransferWriteResult = {\n bytesTransferred: writtenContent.byteLength,\n resumed: offset !== undefined && offset > 0,\n totalBytes: content.byteLength,\n verified: request.verification?.verified ?? false,\n };\n\n if (request.verification !== undefined) {\n result.verification = cloneVerification(request.verification);\n }\n\n return result;\n }\n}\n\nfunction createMemoryState(entries: Iterable<MemoryProviderEntry>): MemoryProviderState {\n const state: MemoryProviderState = {\n content: new Map(),\n entries: new Map([[\"/\", createDirectoryEntry(\"/\")]]),\n };\n\n for (const input of entries) {\n const entry = createMemoryEntry(input);\n const content = createMemoryContent(input, entry);\n\n if (entry.path === \"/\" && entry.type !== \"directory\") {\n throw createInvalidFixtureError(entry.path, \"Memory provider root must be a directory\");\n }\n\n ensureParentDirectories(state.entries, entry.path);\n state.entries.set(entry.path, entry);\n\n if (content !== undefined) {\n state.content.set(entry.path, content);\n }\n }\n\n return state;\n}\n\nfunction createMemoryEntry(input: MemoryProviderEntry): RemoteStat {\n const path = normalizeMemoryPath(input.path);\n const entry: RemoteEntry = {\n name: input.name ?? basenameRemotePath(path),\n path,\n type: input.type,\n };\n\n copyOptionalEntryFields(entry, input);\n\n const content = normalizeMemoryContent(input.content);\n\n if (content !== undefined) {\n entry.size = content.byteLength;\n }\n\n return {\n ...entry,\n exists: true,\n };\n}\n\nfunction createMemoryContent(\n input: MemoryProviderEntry,\n entry: RemoteStat,\n): Uint8Array | undefined {\n const content = normalizeMemoryContent(input.content);\n\n if (content !== undefined) {\n if (entry.type !== \"file\") {\n throw createInvalidFixtureError(\n entry.path,\n `Memory fixture content requires a file: ${entry.path}`,\n );\n }\n\n return content;\n }\n\n if (entry.type === \"file\") {\n return new Uint8Array(entry.size ?? 0);\n }\n\n return undefined;\n}\n\nfunction normalizeMemoryContent(content: string | Uint8Array | undefined): Uint8Array | undefined {\n if (content === undefined) {\n return undefined;\n }\n\n return typeof content === \"string\" ? Buffer.from(content) : new Uint8Array(content);\n}\n\nfunction createWrittenFileEntry(path: string, size: number): RemoteStat {\n return {\n exists: true,\n modifiedAt: new Date(),\n name: basenameRemotePath(path),\n path,\n size,\n type: \"file\",\n };\n}\n\nfunction createDirectoryEntry(path: string): RemoteStat {\n return {\n exists: true,\n name: basenameRemotePath(path),\n path,\n type: \"directory\",\n };\n}\n\nfunction ensureParentDirectories(state: Map<string, RemoteStat>, path: string): void {\n for (const parentPath of getAncestorPaths(path)) {\n const parent = state.get(parentPath);\n\n if (parent !== undefined && parent.type !== \"directory\") {\n throw createInvalidFixtureError(\n parentPath,\n `Memory fixture parent is not a directory: ${parentPath}`,\n );\n }\n\n if (parent === undefined) {\n state.set(parentPath, createDirectoryEntry(parentPath));\n }\n }\n}\n\nfunction normalizeMemoryPath(path: string): string {\n const normalized = normalizeRemotePath(path);\n\n if (normalized === \".\" || normalized === \"/\") {\n return \"/\";\n }\n\n return normalized.startsWith(\"/\") ? normalized : `/${normalized}`;\n}\n\nfunction getAncestorPaths(path: string): string[] {\n const ancestors: string[] = [];\n let parentPath = getParentPath(path);\n\n while (parentPath !== undefined && parentPath !== \"/\") {\n ancestors.unshift(parentPath);\n parentPath = getParentPath(parentPath);\n }\n\n return ancestors;\n}\n\nfunction getParentPath(path: string): string | undefined {\n if (path === \"/\") {\n return undefined;\n }\n\n const parentEnd = path.lastIndexOf(\"/\");\n return parentEnd <= 0 ? \"/\" : path.slice(0, parentEnd);\n}\n\nfunction requireFileEntry(state: MemoryProviderState, path: string): RemoteStat {\n const entry = state.entries.get(path);\n\n if (entry === undefined) {\n throw createPathNotFoundError(path, `Memory path not found: ${path}`);\n }\n\n if (entry.type !== \"file\") {\n throw createPathNotFoundError(path, `Memory path is not a file: ${path}`);\n }\n\n return entry;\n}\n\nfunction resolveByteRange(\n size: number,\n range: ProviderTransferReadRequest[\"range\"],\n): { offset: number; length: number } {\n if (range === undefined) {\n return { length: size, offset: 0 };\n }\n\n const requestedOffset = normalizeByteCount(range.offset, \"offset\");\n const requestedLength =\n range.length === undefined\n ? size - Math.min(requestedOffset, size)\n : normalizeByteCount(range.length, \"length\");\n const offset = Math.min(requestedOffset, size);\n const length = Math.max(0, Math.min(requestedLength, size - offset));\n\n return { length, offset };\n}\n\nasync function collectTransferContent(request: ProviderTransferWriteRequest): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n let byteLength = 0;\n\n for await (const chunk of request.content) {\n request.throwIfAborted();\n const clonedChunk = new Uint8Array(chunk);\n chunks.push(clonedChunk);\n byteLength += clonedChunk.byteLength;\n request.reportProgress(byteLength, request.totalBytes);\n }\n\n return concatChunks(chunks, byteLength);\n}\n\nfunction concatChunks(chunks: Uint8Array[], byteLength: number): Uint8Array {\n const content = new Uint8Array(byteLength);\n let offset = 0;\n\n for (const chunk of chunks) {\n content.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return content;\n}\n\nfunction mergeContentAtOffset(\n previousContent: Uint8Array,\n writtenContent: Uint8Array,\n offset: number,\n): Uint8Array {\n const content = new Uint8Array(\n Math.max(previousContent.byteLength, offset + writtenContent.byteLength),\n );\n content.set(previousContent);\n content.set(writtenContent, offset);\n return content;\n}\n\nasync function* createMemoryContentSource(content: Uint8Array): AsyncGenerator<Uint8Array> {\n await Promise.resolve();\n yield new Uint8Array(content);\n}\n\nfunction normalizeOptionalByteCount(value: number | undefined, field: string): number | undefined {\n return value === undefined ? undefined : normalizeByteCount(value, field);\n}\n\nfunction normalizeByteCount(value: number, field: string): number {\n if (!Number.isFinite(value) || value < 0) {\n throw createInvalidFixtureError(\"/\", `Memory provider ${field} must be a non-negative number`);\n }\n\n return Math.floor(value);\n}\n\nfunction cloneVerification(verification: TransferVerificationResult): TransferVerificationResult {\n const clone: TransferVerificationResult = { verified: verification.verified };\n\n if (verification.method !== undefined) clone.method = verification.method;\n if (verification.checksum !== undefined) clone.checksum = verification.checksum;\n if (verification.expectedChecksum !== undefined) {\n clone.expectedChecksum = verification.expectedChecksum;\n }\n if (verification.actualChecksum !== undefined) clone.actualChecksum = verification.actualChecksum;\n if (verification.details !== undefined) clone.details = { ...verification.details };\n\n return clone;\n}\n\nfunction cloneRemoteEntry(entry: RemoteEntry): RemoteEntry {\n const clone: RemoteEntry = {\n name: entry.name,\n path: entry.path,\n type: entry.type,\n };\n\n copyOptionalEntryFields(clone, entry);\n return clone;\n}\n\nfunction cloneRemoteStat(entry: RemoteStat): RemoteStat {\n return {\n ...cloneRemoteEntry(entry),\n exists: true,\n };\n}\n\nfunction copyOptionalEntryFields(target: RemoteEntry, source: Partial<RemoteEntry>): void {\n if (source.size !== undefined) target.size = source.size;\n if (source.modifiedAt !== undefined) target.modifiedAt = cloneDate(source.modifiedAt);\n if (source.createdAt !== undefined) target.createdAt = cloneDate(source.createdAt);\n if (source.accessedAt !== undefined) target.accessedAt = cloneDate(source.accessedAt);\n if (source.permissions !== undefined) target.permissions = clonePermissions(source.permissions);\n if (source.owner !== undefined) target.owner = source.owner;\n if (source.group !== undefined) target.group = source.group;\n if (source.symlinkTarget !== undefined) target.symlinkTarget = source.symlinkTarget;\n if (source.uniqueId !== undefined) target.uniqueId = source.uniqueId;\n if (source.raw !== undefined) target.raw = source.raw;\n}\n\nfunction cloneDate(value: Date): Date {\n return new Date(value.getTime());\n}\n\nfunction clonePermissions(permissions: RemotePermissions): RemotePermissions {\n return { ...permissions };\n}\n\nfunction compareEntries(left: RemoteEntry, right: RemoteEntry): number {\n return left.path.localeCompare(right.path);\n}\n\nfunction createPathNotFoundError(path: string, message: string): PathNotFoundError {\n return new PathNotFoundError({\n details: { provider: MEMORY_PROVIDER_ID },\n message,\n path,\n retryable: false,\n });\n}\n\nfunction createInvalidFixtureError(path: string, message: string): ConfigurationError {\n return new ConfigurationError({\n details: { provider: MEMORY_PROVIDER_ID },\n message,\n path,\n retryable: false,\n });\n}\n","/**\n * Connection profile secret resolution helpers.\n *\n * @module profiles/resolveConnectionProfileSecrets\n */\nimport type { ConnectionProfile, SshProfile, TlsProfile, TlsSecretSource } from \"../types/public\";\nimport { resolveSecret, type ResolveSecretOptions, type SecretValue } from \"./SecretSource\";\n\n/** SSH profile with private-key and known-host material resolved. */\nexport interface ResolvedSshProfile extends Omit<\n SshProfile,\n \"knownHosts\" | \"passphrase\" | \"privateKey\"\n> {\n /** Resolved private key material. */\n privateKey?: SecretValue;\n /** Resolved private-key passphrase. */\n passphrase?: SecretValue;\n /** Resolved OpenSSH known_hosts material. */\n knownHosts?: SecretValue | SecretValue[];\n}\n\n/** TLS profile with certificate-bearing secret sources resolved. */\nexport interface ResolvedTlsProfile extends Omit<\n TlsProfile,\n \"ca\" | \"cert\" | \"key\" | \"passphrase\" | \"pfx\"\n> {\n /** Resolved certificate authority bundle. */\n ca?: SecretValue | SecretValue[];\n /** Resolved client certificate PEM. */\n cert?: SecretValue;\n /** Resolved client private key PEM. */\n key?: SecretValue;\n /** Resolved encrypted private-key or PFX/P12 passphrase. */\n passphrase?: SecretValue;\n /** Resolved PFX/P12 client certificate bundle. */\n pfx?: SecretValue;\n}\n\n/** Connection profile with username, password, TLS, and SSH material sources resolved. */\nexport interface ResolvedConnectionProfile extends Omit<\n ConnectionProfile,\n \"password\" | \"ssh\" | \"tls\" | \"username\"\n> {\n /** Resolved username or account identifier. */\n username?: SecretValue;\n /** Resolved password or credential bytes. */\n password?: SecretValue;\n /** Resolved TLS profile when certificate material is configured. */\n tls?: ResolvedTlsProfile;\n /** Resolved SSH profile when private-key material is configured. */\n ssh?: ResolvedSshProfile;\n}\n\n/**\n * Resolves credential and TLS material secret sources without mutating the original profile.\n *\n * @param profile - Profile containing optional secret sources.\n * @param options - Optional env and file-reader overrides.\n * @returns Profile copy with username, password, TLS material, and SSH material resolved when present.\n */\nexport async function resolveConnectionProfileSecrets(\n profile: ConnectionProfile,\n options: ResolveSecretOptions = {},\n): Promise<ResolvedConnectionProfile> {\n const { password, ssh, tls, username, ...rest } = profile;\n const resolved: ResolvedConnectionProfile = { ...rest };\n\n if (username !== undefined) {\n resolved.username = await resolveSecret(username, options);\n }\n\n if (password !== undefined) {\n resolved.password = await resolveSecret(password, options);\n }\n\n if (tls !== undefined) {\n resolved.tls = await resolveTlsProfile(tls, options);\n }\n\n if (ssh !== undefined) {\n resolved.ssh = await resolveSshProfile(ssh, options);\n }\n\n return resolved;\n}\n\n/**\n * Resolves SSH private-key, passphrase, and known-host source descriptors.\n *\n * @param profile - SSH profile containing optional secret-backed material.\n * @param options - Optional env and file-reader overrides.\n * @returns SSH profile copy with private-key material resolved.\n */\nasync function resolveSshProfile(\n profile: SshProfile,\n options: ResolveSecretOptions,\n): Promise<ResolvedSshProfile> {\n const { knownHosts, passphrase, privateKey, ...rest } = profile;\n const resolved: ResolvedSshProfile = { ...rest };\n\n if (privateKey !== undefined) resolved.privateKey = await resolveSecret(privateKey, options);\n if (passphrase !== undefined) resolved.passphrase = await resolveSecret(passphrase, options);\n if (knownHosts !== undefined)\n resolved.knownHosts = await resolveKnownHostsSource(knownHosts, options);\n\n return resolved;\n}\n\n/**\n * Resolves known_hosts material while preserving ordered source arrays.\n *\n * @param source - Single known_hosts source or source array.\n * @param options - Optional env and file-reader overrides.\n * @returns Resolved known_hosts value or value array.\n */\nasync function resolveKnownHostsSource(\n source: NonNullable<SshProfile[\"knownHosts\"]>,\n options: ResolveSecretOptions,\n): Promise<SecretValue | SecretValue[]> {\n if (Array.isArray(source)) {\n return Promise.all(source.map((item) => resolveSecret(item, options)));\n }\n\n return resolveSecret(source, options);\n}\n\n/**\n * Resolves TLS certificate, key, PFX, passphrase, and CA source descriptors.\n *\n * @param profile - TLS profile containing optional secret-backed material.\n * @param options - Optional env and file-reader overrides.\n * @returns TLS profile copy with material sources resolved.\n */\nasync function resolveTlsProfile(\n profile: TlsProfile,\n options: ResolveSecretOptions,\n): Promise<ResolvedTlsProfile> {\n const { ca, cert, key, passphrase, pfx, ...rest } = profile;\n const resolved: ResolvedTlsProfile = { ...rest };\n\n if (ca !== undefined) resolved.ca = await resolveTlsSecretSource(ca, options);\n if (cert !== undefined) resolved.cert = await resolveSecret(cert, options);\n if (key !== undefined) resolved.key = await resolveSecret(key, options);\n if (passphrase !== undefined) resolved.passphrase = await resolveSecret(passphrase, options);\n if (pfx !== undefined) resolved.pfx = await resolveSecret(pfx, options);\n\n return resolved;\n}\n\n/**\n * Resolves a TLS material source while preserving ordered CA bundle arrays.\n *\n * @param source - Single secret source or source array.\n * @param options - Optional env and file-reader overrides.\n * @returns Resolved secret value or resolved value array.\n */\nasync function resolveTlsSecretSource(\n source: TlsSecretSource,\n options: ResolveSecretOptions,\n): Promise<SecretValue | SecretValue[]> {\n if (Array.isArray(source)) {\n return Promise.all(source.map((item) => resolveSecret(item, options)));\n }\n\n return resolveSecret(source, options);\n}\n","/**\n * OAuth bearer-token helpers for cloud-drive and object-storage providers.\n *\n * Cloud providers in this SDK accept a bearer token via `profile.password`,\n * which is resolved as a {@link SecretSource}. Long-lived access tokens are\n * rare in OAuth flows; instead, applications hold a refresh token (or use a\n * client-credentials grant) and exchange it for short-lived access tokens.\n *\n * {@link createOAuthTokenSecretSource} adapts an arbitrary refresh callback\n * into a `SecretProvider` (one of the accepted `SecretSource` shapes) that\n * caches the most recent access token until its expiry approaches, then\n * silently re-runs the refresh callback. The cache honours an optional\n * `skewMs` margin so tokens are renewed before they expire on the wire.\n *\n * @module profiles/OAuthTokenSource\n */\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { SecretProvider } from \"./SecretSource\";\n\n/** Token material returned by {@link OAuthRefreshCallback}. */\nexport interface OAuthAccessToken {\n /** Access token value. Required. */\n accessToken: string;\n /**\n * Lifetime in seconds (`expires_in`-style). When provided, the helper caches\n * the token until `now + (expiresInSeconds - skewSeconds)`.\n */\n expiresInSeconds?: number;\n /** Absolute expiry. Wins over `expiresInSeconds` when both are provided. */\n expiresAt?: Date;\n}\n\n/** Refresh callback invoked when no valid cached token is available. */\nexport type OAuthRefreshCallback = () => OAuthAccessToken | Promise<OAuthAccessToken>;\n\n/** Options accepted by {@link createOAuthTokenSecretSource}. */\nexport interface OAuthTokenSecretSourceOptions {\n /**\n * Safety margin (in milliseconds) subtracted from the token's expiry to\n * trigger a refresh before the wire deadline. Defaults to `60_000` (60s).\n */\n skewMs?: number;\n /** Clock used to evaluate expiry. Defaults to `Date.now`. */\n now?: () => number;\n}\n\ninterface CachedToken {\n accessToken: string;\n /** Absolute expiry in epoch milliseconds, or `undefined` for non-expiring tokens. */\n expiresAtMs: number | undefined;\n}\n\n/**\n * Builds a {@link SecretProvider} that exchanges a refresh callback for\n * cached, auto-renewing access tokens.\n *\n * The returned function can be passed directly as `profile.password` for any\n * provider that accepts bearer tokens (Dropbox, Google Drive, OneDrive, GCS,\n * Azure Blob via AAD).\n *\n * @example\n * ```ts\n * const password = createOAuthTokenSecretSource(async () => {\n * const res = await fetch(\"https://example.com/oauth/token\", { ... });\n * const body = (await res.json()) as { access_token: string; expires_in: number };\n * return { accessToken: body.access_token, expiresInSeconds: body.expires_in };\n * });\n * const session = await factory.create().connect({ host: \"\", protocol: \"ftp\", password });\n * ```\n */\nexport function createOAuthTokenSecretSource(\n refresh: OAuthRefreshCallback,\n options: OAuthTokenSecretSourceOptions = {},\n): SecretProvider {\n if (typeof refresh !== \"function\") {\n throw new ConfigurationError({\n message: \"createOAuthTokenSecretSource requires a refresh callback\",\n retryable: false,\n });\n }\n const skewMs = options.skewMs ?? 60_000;\n const now = options.now ?? (() => Date.now());\n if (skewMs < 0) {\n throw new ConfigurationError({\n message: \"OAuthTokenSecretSourceOptions.skewMs must be non-negative\",\n retryable: false,\n });\n }\n\n let cache: CachedToken | undefined;\n let pending: Promise<CachedToken> | undefined;\n\n const renew = async (): Promise<CachedToken> => {\n const result = await refresh();\n if (typeof result.accessToken !== \"string\" || result.accessToken === \"\") {\n throw new ConfigurationError({\n message: \"OAuth refresh callback returned an empty access token\",\n retryable: false,\n });\n }\n let expiresAtMs: number | undefined;\n if (result.expiresAt !== undefined) {\n const ts = result.expiresAt.getTime();\n if (Number.isFinite(ts)) expiresAtMs = ts;\n } else if (typeof result.expiresInSeconds === \"number\") {\n if (!Number.isFinite(result.expiresInSeconds) || result.expiresInSeconds <= 0) {\n throw new ConfigurationError({\n message: \"OAuth refresh callback returned a non-positive expiresInSeconds\",\n retryable: false,\n });\n }\n expiresAtMs = now() + result.expiresInSeconds * 1000;\n }\n const cached: CachedToken = { accessToken: result.accessToken, expiresAtMs };\n cache = cached;\n return cached;\n };\n\n return async () => {\n const current = cache;\n if (current !== undefined && isFresh(current, skewMs, now)) {\n return current.accessToken;\n }\n if (pending === undefined) {\n pending = renew().finally(() => {\n pending = undefined;\n });\n }\n const refreshed = await pending;\n return refreshed.accessToken;\n };\n}\n\nfunction isFresh(token: CachedToken, skewMs: number, now: () => number): boolean {\n if (token.expiresAtMs === undefined) return true;\n return token.expiresAtMs - skewMs > now();\n}\n","/**\n * OpenSSH `known_hosts` parsing helpers used by SFTP profile imports and host-key verification.\n *\n * @module profiles/importers/KnownHostsParser\n */\nimport { Buffer } from \"node:buffer\";\nimport { createHmac } from \"node:crypto\";\n\n/** Marker prefixing a known_hosts line (`@cert-authority` or `@revoked`). */\nexport type KnownHostsMarker = \"cert-authority\" | \"revoked\";\n\n/** Parsed entry from an OpenSSH `known_hosts` file. */\nexport interface KnownHostsEntry {\n /** Optional line marker (`@cert-authority` or `@revoked`). */\n marker?: KnownHostsMarker;\n /** Raw, comma-separated host patterns. Negation patterns retain their leading `!`. */\n hostPatterns: readonly string[];\n /** Hashed-salt component for `|1|salt|hash` entries. Mutually exclusive with plain patterns. */\n hashedSalt?: string;\n /** Hashed-hash component for `|1|salt|hash` entries. Mutually exclusive with plain patterns. */\n hashedHash?: string;\n /** SSH key algorithm identifier (e.g. `ssh-ed25519`, `ecdsa-sha2-nistp256`). */\n keyType: string;\n /** Base64-encoded public key blob. */\n keyBase64: string;\n /** Trailing comment text, if any. */\n comment?: string;\n /** Original line text without trailing newline. */\n raw: string;\n}\n\n/**\n * Parses OpenSSH `known_hosts` content into structured entries. Comment and blank lines are skipped.\n * Lines that cannot be parsed are silently dropped so callers can tolerate hand-edited files.\n *\n * @param text - Raw `known_hosts` file contents.\n * @returns Parsed entries in source order.\n */\nexport function parseKnownHosts(text: string): KnownHostsEntry[] {\n const entries: KnownHostsEntry[] = [];\n const lines = text.split(/\\r?\\n/);\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed === \"\" || trimmed.startsWith(\"#\")) continue;\n const entry = parseKnownHostsLine(line);\n if (entry !== undefined) entries.push(entry);\n }\n return entries;\n}\n\nfunction parseKnownHostsLine(line: string): KnownHostsEntry | undefined {\n const tokens = line.trim().split(/\\s+/);\n if (tokens.length < 3) return undefined;\n let index = 0;\n let marker: KnownHostsMarker | undefined;\n const first = tokens[index];\n if (first === \"@cert-authority\" || first === \"@revoked\") {\n marker = first === \"@cert-authority\" ? \"cert-authority\" : \"revoked\";\n index += 1;\n }\n const hostField = tokens[index];\n const keyType = tokens[index + 1];\n const keyBase64 = tokens[index + 2];\n if (hostField === undefined || keyType === undefined || keyBase64 === undefined) return undefined;\n const commentTokens = tokens.slice(index + 3);\n const comment = commentTokens.length > 0 ? commentTokens.join(\" \") : undefined;\n\n let hostPatterns: readonly string[] = [];\n let hashedSalt: string | undefined;\n let hashedHash: string | undefined;\n if (hostField.startsWith(\"|1|\")) {\n const parts = hostField.split(\"|\");\n if (parts.length < 4) return undefined;\n hashedSalt = parts[2];\n hashedHash = parts[3];\n } else {\n hostPatterns = hostField.split(\",\").filter((token) => token !== \"\");\n }\n\n const entry: KnownHostsEntry = {\n hostPatterns,\n keyBase64,\n keyType,\n raw: line,\n };\n if (marker !== undefined) entry.marker = marker;\n if (comment !== undefined) entry.comment = comment;\n if (hashedSalt !== undefined) entry.hashedSalt = hashedSalt;\n if (hashedHash !== undefined) entry.hashedHash = hashedHash;\n return entry;\n}\n\n/** Default OpenSSH port used when matching host patterns without an explicit `[host]:port`. */\nconst DEFAULT_SSH_PORT = 22;\n\n/**\n * Returns true when the given host (and optional port) matches the entry's host patterns.\n * Hashed entries use HMAC-SHA1 verification per OpenSSH semantics.\n *\n * @param entry - Parsed `known_hosts` entry to test.\n * @param host - Hostname or IP literal to match.\n * @param port - Optional connection port. Defaults to {@link DEFAULT_SSH_PORT}.\n * @returns Whether the entry matches and is not negated.\n */\nexport function matchKnownHostsEntry(\n entry: KnownHostsEntry,\n host: string,\n port: number = DEFAULT_SSH_PORT,\n): boolean {\n if (entry.hashedSalt !== undefined && entry.hashedHash !== undefined) {\n return matchesHashedEntry(entry.hashedSalt, entry.hashedHash, host, port);\n }\n let matched = false;\n for (const pattern of entry.hostPatterns) {\n if (pattern.startsWith(\"!\")) {\n const negated = pattern.slice(1);\n if (matchesPlainPattern(negated, host, port)) return false;\n continue;\n }\n if (matchesPlainPattern(pattern, host, port)) matched = true;\n }\n return matched;\n}\n\n/**\n * Filters parsed entries down to those that match the given host/port. Negations are honored.\n *\n * @param entries - Entries returned by {@link parseKnownHosts}.\n * @param host - Hostname or IP literal to match.\n * @param port - Optional connection port. Defaults to {@link DEFAULT_SSH_PORT}.\n * @returns Matching entries in source order.\n */\nexport function matchKnownHosts(\n entries: readonly KnownHostsEntry[],\n host: string,\n port: number = DEFAULT_SSH_PORT,\n): KnownHostsEntry[] {\n return entries.filter((entry) => matchKnownHostsEntry(entry, host, port));\n}\n\nfunction matchesPlainPattern(pattern: string, host: string, port: number): boolean {\n const portMatch = pattern.match(/^\\[(.+)\\]:(\\d+)$/);\n if (portMatch) {\n const [, hostPattern, portText] = portMatch;\n if (hostPattern === undefined || portText === undefined) return false;\n const expectedPort = Number.parseInt(portText, 10);\n if (Number.isNaN(expectedPort) || expectedPort !== port) return false;\n return globMatch(hostPattern, host);\n }\n return port === DEFAULT_SSH_PORT && globMatch(pattern, host);\n}\n\nfunction globMatch(pattern: string, value: string): boolean {\n const regex = new RegExp(\n `^${pattern\n .replace(/[.+^${}()|\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\")}$`,\n \"i\",\n );\n return regex.test(value);\n}\n\nfunction matchesHashedEntry(salt: string, hash: string, host: string, port: number): boolean {\n const saltBuffer = Buffer.from(salt, \"base64\");\n if (saltBuffer.length === 0) return false;\n const candidates = port === DEFAULT_SSH_PORT ? [host] : [`[${host}]:${String(port)}`, host];\n for (const candidate of candidates) {\n const expected = createHmac(\"sha1\", saltBuffer).update(candidate).digest(\"base64\");\n if (expected === hash) return true;\n }\n return false;\n}\n","/**\n * OpenSSH `ssh_config` parser and {@link ConnectionProfile} importer.\n *\n * Supports the directives most commonly used by SFTP profiles: `HostName`, `Port`, `User`,\n * `IdentityFile`, `UserKnownHostsFile`, `ProxyJump`, `ConnectTimeout`, plus the SSH algorithm\n * controls (`KexAlgorithms`, `Ciphers`, `MACs`, `HostKeyAlgorithms`).\n *\n * @module profiles/importers/OpenSshConfigImporter\n */\nimport { ConfigurationError } from \"../../errors/ZeroTransferError\";\nimport type { ConnectionProfile } from \"../../types/public\";\n\n/** Parsed `Host` block from an OpenSSH config file. */\nexport interface OpenSshConfigEntry {\n /** Host patterns declared on the `Host` line. */\n patterns: readonly string[];\n /** Lower-cased directive name to ordered values. Multi-valued directives (e.g. `IdentityFile`) preserve order. */\n options: Readonly<Record<string, readonly string[]>>;\n}\n\n/**\n * Parses OpenSSH `ssh_config` text into structured `Host` blocks.\n *\n * The parser is intentionally permissive: unknown directives are retained and `Match` blocks are skipped.\n *\n * @param text - Contents of the `ssh_config` file.\n * @returns Parsed `Host` entries in source order.\n */\nexport function parseOpenSshConfig(text: string): OpenSshConfigEntry[] {\n const entries: OpenSshConfigEntry[] = [];\n let current: { patterns: string[]; options: Record<string, string[]> } | undefined;\n let skipping = false;\n const lines = text.split(/\\r?\\n/);\n for (const rawLine of lines) {\n const line = rawLine.replace(/#.*$/, \"\").trim();\n if (line === \"\") continue;\n const match = line.match(/^([A-Za-z][A-Za-z0-9_-]*)\\s*=?\\s*(.*)$/);\n if (!match) continue;\n const [, keywordRaw, valueRaw] = match;\n if (keywordRaw === undefined || valueRaw === undefined) continue;\n const keyword = keywordRaw.toLowerCase();\n const value = valueRaw.trim();\n if (keyword === \"host\") {\n if (current !== undefined) entries.push(current);\n current = { options: {}, patterns: tokenizeValues(value) };\n skipping = false;\n continue;\n }\n if (keyword === \"match\") {\n if (current !== undefined) entries.push(current);\n current = undefined;\n skipping = true;\n continue;\n }\n if (skipping || current === undefined) continue;\n const values = tokenizeValues(value);\n const existing = current.options[keyword];\n if (existing === undefined) {\n current.options[keyword] = [...values];\n } else {\n existing.push(...values);\n }\n }\n if (current !== undefined) entries.push(current);\n return entries;\n}\n\nfunction tokenizeValues(value: string): string[] {\n if (value === \"\") return [];\n const tokens: string[] = [];\n const regex = /\"([^\"]*)\"|(\\S+)/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(value)) !== null) {\n tokens.push(match[1] ?? match[2] ?? \"\");\n }\n return tokens;\n}\n\n/**\n * Resolved set of directives for a given host alias. Values from later-declared blocks are\n * merged after earlier ones so wildcard fallbacks (e.g. `Host *`) only fill gaps.\n */\nexport interface ResolvedOpenSshHost {\n /** Host alias the lookup was performed against. */\n alias: string;\n /** Per-directive ordered values, keyed by lower-cased directive name. */\n options: Readonly<Record<string, readonly string[]>>;\n /** Source entries that contributed to the resolved set, in match order. */\n matched: readonly OpenSshConfigEntry[];\n}\n\n/**\n * Resolves the merged option set for an OpenSSH host alias.\n *\n * @param entries - Parsed entries from {@link parseOpenSshConfig}.\n * @param alias - Host alias to resolve.\n * @returns Merged directive set with the matching entries.\n */\nexport function resolveOpenSshHost(\n entries: readonly OpenSshConfigEntry[],\n alias: string,\n): ResolvedOpenSshHost {\n const merged: Record<string, string[]> = {};\n const matched: OpenSshConfigEntry[] = [];\n for (const entry of entries) {\n if (!entryMatchesAlias(entry, alias)) continue;\n matched.push(entry);\n for (const [key, values] of Object.entries(entry.options)) {\n if (merged[key] === undefined) merged[key] = [...values];\n }\n }\n return { alias, matched, options: merged };\n}\n\nfunction entryMatchesAlias(entry: OpenSshConfigEntry, alias: string): boolean {\n let matched = false;\n for (const pattern of entry.patterns) {\n if (pattern.startsWith(\"!\")) {\n if (globMatch(pattern.slice(1), alias)) return false;\n continue;\n }\n if (globMatch(pattern, alias)) matched = true;\n }\n return matched;\n}\n\nfunction globMatch(pattern: string, value: string): boolean {\n const regex = new RegExp(\n `^${pattern\n .replace(/[.+^${}()|\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\")}$`,\n \"i\",\n );\n return regex.test(value);\n}\n\n/** Options accepted by {@link importOpenSshConfig}. */\nexport interface ImportOpenSshConfigOptions {\n /** Raw `ssh_config` text. Either this or {@link entries} must be provided. */\n text?: string;\n /** Pre-parsed entries from {@link parseOpenSshConfig}. */\n entries?: readonly OpenSshConfigEntry[];\n /** Host alias to import. */\n alias: string;\n}\n\n/** Result of {@link importOpenSshConfig}. */\nexport interface ImportOpenSshConfigResult {\n /** Generated SFTP connection profile. */\n profile: ConnectionProfile;\n /** Resolved directive set used to build the profile. */\n resolved: ResolvedOpenSshHost;\n /** Identity file paths declared in the config, in declaration order. */\n identityFiles: readonly string[];\n /** Optional `ProxyJump` value preserved from the config. */\n proxyJump?: string;\n}\n\n/**\n * Builds a {@link ConnectionProfile} for the given SSH alias from `ssh_config` text or pre-parsed entries.\n *\n * @param options - Import options.\n * @returns Importer result with the generated profile and supporting metadata.\n * @throws {@link ConfigurationError} When neither text nor entries is supplied.\n */\nexport function importOpenSshConfig(\n options: ImportOpenSshConfigOptions,\n): ImportOpenSshConfigResult {\n const { alias } = options;\n const entries =\n options.entries ?? (options.text !== undefined ? parseOpenSshConfig(options.text) : undefined);\n if (entries === undefined) {\n throw new ConfigurationError({\n code: \"openssh_config_input_missing\",\n message: \"importOpenSshConfig requires either text or pre-parsed entries.\",\n retryable: false,\n });\n }\n const resolved = resolveOpenSshHost(entries, alias);\n const optionsMap = resolved.options;\n\n const host = first(optionsMap, \"hostname\") ?? alias;\n const portText = first(optionsMap, \"port\");\n const port = portText !== undefined ? safeInt(portText) : undefined;\n const user = first(optionsMap, \"user\");\n const identityFiles = optionsMap[\"identityfile\"] ?? [];\n const knownHostsFiles = optionsMap[\"userknownhostsfile\"] ?? [];\n const connectTimeoutText = first(optionsMap, \"connecttimeout\");\n const proxyJump = first(optionsMap, \"proxyjump\");\n const kex = optionsMap[\"kexalgorithms\"] ?? [];\n const ciphers = optionsMap[\"ciphers\"] ?? [];\n const macs = optionsMap[\"macs\"] ?? [];\n const serverHostKey = optionsMap[\"hostkeyalgorithms\"] ?? [];\n\n const profile: ConnectionProfile = { host, provider: \"sftp\" };\n if (port !== undefined) profile.port = port;\n if (user !== undefined) profile.username = { value: user };\n if (connectTimeoutText !== undefined) {\n const seconds = safeInt(connectTimeoutText);\n if (seconds !== undefined) profile.timeoutMs = seconds * 1000;\n }\n\n const ssh: NonNullable<ConnectionProfile[\"ssh\"]> = {};\n if (identityFiles.length > 0) {\n const firstKey = identityFiles[0];\n if (firstKey !== undefined) ssh.privateKey = { path: expandHome(firstKey) };\n }\n if (knownHostsFiles.length > 0) {\n ssh.knownHosts = knownHostsFiles.map((path) => ({ path: expandHome(path) }));\n }\n const algorithms: Record<string, string[]> = {};\n if (kex.length > 0) algorithms[\"kex\"] = expandAlgorithms(kex);\n if (ciphers.length > 0) algorithms[\"cipher\"] = expandAlgorithms(ciphers);\n if (macs.length > 0) algorithms[\"hmac\"] = expandAlgorithms(macs);\n if (serverHostKey.length > 0) algorithms[\"serverHostKey\"] = expandAlgorithms(serverHostKey);\n if (Object.keys(algorithms).length > 0) {\n ssh.algorithms = algorithms;\n }\n if (Object.keys(ssh).length > 0) profile.ssh = ssh;\n\n const result: ImportOpenSshConfigResult = {\n identityFiles: identityFiles.map(expandHome),\n profile,\n resolved,\n };\n if (proxyJump !== undefined) result.proxyJump = proxyJump;\n return result;\n}\n\nfunction first(\n options: Readonly<Record<string, readonly string[]>>,\n key: string,\n): string | undefined {\n const values = options[key];\n return values !== undefined && values.length > 0 ? values[0] : undefined;\n}\n\nfunction safeInt(text: string): number | undefined {\n const value = Number.parseInt(text, 10);\n return Number.isFinite(value) ? value : undefined;\n}\n\nfunction expandHome(path: string): string {\n if (!path.startsWith(\"~\")) return path;\n const home = process.env[\"HOME\"] ?? process.env[\"USERPROFILE\"];\n if (home === undefined) return path;\n if (path === \"~\") return home;\n if (path.startsWith(\"~/\") || path.startsWith(\"~\\\\\")) return `${home}${path.slice(1)}`;\n return path;\n}\n\nfunction expandAlgorithms(values: readonly string[]): string[] {\n const out: string[] = [];\n for (const value of values) {\n for (const part of value.split(\",\")) {\n const trimmed = part.trim();\n if (trimmed !== \"\") out.push(trimmed);\n }\n }\n return out;\n}\n","/**\n * FileZilla `sitemanager.xml` importer.\n *\n * Walks FileZilla's nested folder/server hierarchy and emits {@link ConnectionProfile} entries\n * for each saved site. The importer ignores cloud providers and other entries it cannot map\n * to a {@link RemoteProtocol}. Stored passwords are never decoded or returned; sites that\n * carry one are flagged via {@link FileZillaSite.hasStoredPassword} so callers can prompt\n * for the credential through a SecretSource instead.\n *\n * @module profiles/importers/FileZillaImporter\n */\nimport { ConfigurationError } from \"../../errors/ZeroTransferError\";\nimport type { ConnectionProfile } from \"../../types/public\";\n\n/** Imported FileZilla site with the folder hierarchy that contained it. */\nexport interface FileZillaSite {\n /** Site display name. */\n name: string;\n /** Ordered folder names leading to the site (top-level first). Empty for root sites. */\n folder: readonly string[];\n /** Generated connection profile. */\n profile: ConnectionProfile;\n /**\n * Whether the FileZilla entry stored a password. The importer never decodes\n * or returns stored passwords; supply the credential via a\n * {@link ConnectionProfile.password | SecretSource} (for example\n * `{ env: \"SITE_PASSWORD\" }` or `{ path: \"./secret\" }`) before connecting.\n */\n hasStoredPassword: boolean;\n /** Logon type code preserved from the file (`0`=anonymous, `1`=normal, etc.). */\n logonType?: number;\n}\n\n/** Result returned by {@link importFileZillaSites}. */\nexport interface ImportFileZillaSitesResult {\n /** Sites successfully mapped to a connection profile. */\n sites: readonly FileZillaSite[];\n /** Sites that were skipped because their protocol is not supported. */\n skipped: readonly { name: string; folder: readonly string[]; protocol?: number }[];\n}\n\n/**\n * Parses FileZilla `sitemanager.xml` text and returns generated profiles.\n *\n * @param xml - Contents of `sitemanager.xml`.\n * @returns Imported sites and any skipped entries.\n * @throws {@link ConfigurationError} When the XML root cannot be located.\n */\nexport function importFileZillaSites(xml: string): ImportFileZillaSitesResult {\n const events = tokenizeXml(xml);\n if (events.length === 0) {\n throw new ConfigurationError({\n code: \"filezilla_xml_empty\",\n message: \"FileZilla sitemanager XML is empty.\",\n retryable: false,\n });\n }\n const sites: FileZillaSite[] = [];\n const skipped: { name: string; folder: readonly string[]; protocol?: number }[] = [];\n const folderStack: string[] = [];\n const folderNamePending: boolean[] = [];\n let inServer = false;\n let serverFields: Record<string, string> = {};\n let activeTag: string | undefined;\n let captureFolderName = false;\n\n for (const event of events) {\n if (event.kind === \"open\") {\n if (event.name === \"Folder\") {\n folderStack.push(\"\");\n folderNamePending.push(true);\n continue;\n }\n if (event.name === \"Server\") {\n inServer = true;\n serverFields = {};\n continue;\n }\n activeTag = event.name;\n if (event.name === \"Name\" && !inServer && folderNamePending.length > 0) {\n captureFolderName = true;\n }\n continue;\n }\n if (event.kind === \"text\") {\n if (captureFolderName) {\n const top = folderStack.length - 1;\n if (top >= 0) folderStack[top] = event.text.trim();\n captureFolderName = false;\n continue;\n }\n if (inServer && activeTag !== undefined) {\n serverFields[activeTag] = (serverFields[activeTag] ?? \"\") + event.text;\n }\n continue;\n }\n if (event.kind === \"close\") {\n if (event.name === \"Folder\") {\n folderStack.pop();\n folderNamePending.pop();\n continue;\n }\n if (event.name === \"Server\") {\n const folder = folderStack.filter((segment) => segment !== \"\");\n const result = buildSiteFromFields(serverFields);\n if (result.kind === \"site\") {\n sites.push({ ...result.site, folder });\n } else {\n skipped.push({\n folder,\n name: result.name,\n ...(result.protocol !== undefined ? { protocol: result.protocol } : {}),\n });\n }\n inServer = false;\n serverFields = {};\n activeTag = undefined;\n continue;\n }\n if (activeTag === event.name) activeTag = undefined;\n }\n }\n return { sites, skipped };\n}\n\ninterface BuiltSite {\n kind: \"site\";\n site: Omit<FileZillaSite, \"folder\">;\n}\n\ninterface SkippedSite {\n kind: \"skipped\";\n name: string;\n protocol?: number;\n}\n\nfunction buildSiteFromFields(fields: Record<string, string>): BuiltSite | SkippedSite {\n const name = (fields[\"Name\"] ?? fields[\"Host\"] ?? \"Untitled\").trim();\n const host = (fields[\"Host\"] ?? \"\").trim();\n if (host === \"\") return { kind: \"skipped\", name };\n const protocolText = fields[\"Protocol\"];\n const protocol = protocolText !== undefined ? Number.parseInt(protocolText.trim(), 10) : 0;\n const mapped = mapFileZillaProtocol(protocol);\n if (mapped === undefined) {\n return Number.isFinite(protocol)\n ? { kind: \"skipped\", name, protocol }\n : { kind: \"skipped\", name };\n }\n const profile: ConnectionProfile = { host, provider: mapped.provider };\n if (mapped.secure !== undefined) profile.secure = mapped.secure;\n const portText = fields[\"Port\"];\n if (portText !== undefined) {\n const port = Number.parseInt(portText.trim(), 10);\n if (Number.isFinite(port)) profile.port = port;\n }\n const user = fields[\"User\"]?.trim();\n if (user !== undefined && user !== \"\") profile.username = { value: user };\n\n const rawPass = fields[\"Pass\"];\n const hasStoredPassword = rawPass !== undefined && rawPass !== \"\";\n\n const site: Omit<FileZillaSite, \"folder\"> = { hasStoredPassword, name, profile };\n const logonText = fields[\"Logontype\"];\n if (logonText !== undefined) {\n const logonType = Number.parseInt(logonText.trim(), 10);\n if (Number.isFinite(logonType)) site.logonType = logonType;\n }\n return { kind: \"site\", site };\n}\n\nfunction mapFileZillaProtocol(\n code: number,\n): { provider: NonNullable<ConnectionProfile[\"provider\"]>; secure?: boolean } | undefined {\n switch (code) {\n case 0:\n return { provider: \"ftp\" };\n case 1:\n return { provider: \"sftp\" };\n case 4:\n return { provider: \"ftps\", secure: true };\n case 5:\n return { provider: \"ftps\", secure: true };\n case 6:\n return { provider: \"ftp\", secure: false };\n default:\n return undefined;\n }\n}\n\ninterface XmlOpenEvent {\n kind: \"open\";\n name: string;\n attributes: Record<string, string>;\n selfClosing: boolean;\n}\ninterface XmlCloseEvent {\n kind: \"close\";\n name: string;\n}\ninterface XmlTextEvent {\n kind: \"text\";\n text: string;\n}\ntype XmlEvent = XmlOpenEvent | XmlCloseEvent | XmlTextEvent;\n\nfunction tokenizeXml(xml: string): XmlEvent[] {\n const events: XmlEvent[] = [];\n let index = 0;\n const length = xml.length;\n while (index < length) {\n const lt = xml.indexOf(\"<\", index);\n if (lt === -1) {\n const text = xml.slice(index);\n if (text.trim() !== \"\") events.push({ kind: \"text\", text: decodeEntities(text) });\n break;\n }\n if (lt > index) {\n const text = xml.slice(index, lt);\n if (text.trim() !== \"\") events.push({ kind: \"text\", text: decodeEntities(text) });\n }\n if (xml.startsWith(\"<!--\", lt)) {\n const end = xml.indexOf(\"-->\", lt + 4);\n index = end === -1 ? length : end + 3;\n continue;\n }\n if (xml.startsWith(\"<![CDATA[\", lt)) {\n const end = xml.indexOf(\"]]>\", lt + 9);\n const cdataEnd = end === -1 ? length : end;\n events.push({ kind: \"text\", text: xml.slice(lt + 9, cdataEnd) });\n index = end === -1 ? length : end + 3;\n continue;\n }\n if (xml[lt + 1] === \"?\" || xml[lt + 1] === \"!\") {\n const gt = xml.indexOf(\">\", lt + 1);\n index = gt === -1 ? length : gt + 1;\n continue;\n }\n const gt = xml.indexOf(\">\", lt + 1);\n if (gt === -1) break;\n const tagBody = xml.slice(lt + 1, gt);\n if (tagBody.startsWith(\"/\")) {\n events.push({ kind: \"close\", name: tagBody.slice(1).trim() });\n } else {\n const selfClosing = tagBody.endsWith(\"/\");\n const body = selfClosing ? tagBody.slice(0, -1) : tagBody;\n const { name, attributes } = parseTagBody(body.trim());\n events.push({ attributes, kind: \"open\", name, selfClosing });\n if (selfClosing) events.push({ kind: \"close\", name });\n }\n index = gt + 1;\n }\n return events;\n}\n\nfunction parseTagBody(body: string): { name: string; attributes: Record<string, string> } {\n const match = body.match(/^([A-Za-z_:][\\w:.-]*)\\s*(.*)$/);\n if (!match) return { attributes: {}, name: body };\n const name = match[1] ?? \"\";\n const rest = match[2] ?? \"\";\n const attributes: Record<string, string> = {};\n const attrRegex = /([A-Za-z_:][\\w:.-]*)\\s*=\\s*(\"([^\"]*)\"|'([^']*)')/g;\n let attrMatch: RegExpExecArray | null;\n while ((attrMatch = attrRegex.exec(rest)) !== null) {\n const key = attrMatch[1];\n const value = attrMatch[3] ?? attrMatch[4] ?? \"\";\n if (key !== undefined) attributes[key] = decodeEntities(value);\n }\n return { attributes, name };\n}\n\nfunction decodeEntities(text: string): string {\n return text\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/&/g, \"&\");\n}\n","/**\n * WinSCP `WinSCP.ini` importer.\n *\n * Parses the INI session sections produced by WinSCP and emits {@link ConnectionProfile} entries.\n * Sessions whose `FSProtocol` cannot be mapped to a classic provider are skipped.\n *\n * @module profiles/importers/WinScpImporter\n */\nimport { ConfigurationError } from \"../../errors/ZeroTransferError\";\nimport type { ConnectionProfile } from \"../../types/public\";\n\n/** Imported WinSCP session entry. */\nexport interface WinScpSession {\n /** Decoded session name (URL-decoded path under the `Sessions\\\\` namespace). */\n name: string;\n /** Hierarchical path segments derived from the session name (folders separated by `/`). */\n folder: readonly string[];\n /** Generated connection profile. */\n profile: ConnectionProfile;\n /** Raw FSProtocol code preserved from the file. */\n fsProtocol?: number;\n /** Raw Ftps code preserved from the file (`0`=none, `1`=implicit, `2`/`3`=explicit). */\n ftps?: number;\n}\n\n/** Result of {@link importWinScpSessions}. */\nexport interface ImportWinScpSessionsResult {\n /** Successfully mapped sessions. */\n sessions: readonly WinScpSession[];\n /** Sessions skipped because their protocol is not supported. */\n skipped: readonly { name: string; folder: readonly string[]; fsProtocol?: number }[];\n}\n\n/**\n * Parses WinSCP `WinSCP.ini` text and returns generated profiles.\n *\n * @param ini - Contents of the WinSCP configuration file.\n * @returns Imported sessions and any skipped entries.\n * @throws {@link ConfigurationError} When no session sections are found.\n */\nexport function importWinScpSessions(ini: string): ImportWinScpSessionsResult {\n const sections = parseIni(ini);\n const sessionSections = sections.filter((section) => section.name.startsWith(\"Sessions\\\\\"));\n if (sessionSections.length === 0) {\n throw new ConfigurationError({\n code: \"winscp_ini_no_sessions\",\n message: \"WinSCP INI does not contain any [Sessions\\\\...] sections.\",\n retryable: false,\n });\n }\n const sessions: WinScpSession[] = [];\n const skipped: { name: string; folder: readonly string[]; fsProtocol?: number }[] = [];\n for (const section of sessionSections) {\n const decodedPath = decodeSessionPath(section.name.slice(\"Sessions\\\\\".length));\n const segments = decodedPath.split(\"/\").filter((segment) => segment !== \"\");\n const name = segments[segments.length - 1] ?? decodedPath;\n const folder = segments.slice(0, -1);\n const built = buildSessionProfile(name, section.values);\n if (built.kind === \"session\") {\n sessions.push({ ...built.session, folder });\n } else {\n skipped.push({\n folder,\n name,\n ...(built.fsProtocol !== undefined ? { fsProtocol: built.fsProtocol } : {}),\n });\n }\n }\n return { sessions, skipped };\n}\n\ninterface BuiltSession {\n kind: \"session\";\n session: Omit<WinScpSession, \"folder\">;\n}\ninterface SkippedSession {\n kind: \"skipped\";\n fsProtocol?: number;\n}\n\nfunction buildSessionProfile(\n name: string,\n values: Readonly<Record<string, string>>,\n): BuiltSession | SkippedSession {\n const host = values[\"HostName\"]?.trim();\n if (host === undefined || host === \"\") return { kind: \"skipped\" };\n const fsProtocolText = values[\"FSProtocol\"];\n const fsProtocol = fsProtocolText !== undefined ? Number.parseInt(fsProtocolText, 10) : 1;\n const ftpsText = values[\"Ftps\"];\n const ftps = ftpsText !== undefined ? Number.parseInt(ftpsText, 10) : 0;\n const mapped = mapWinScpProtocol(fsProtocol, ftps);\n if (mapped === undefined) {\n return Number.isFinite(fsProtocol) ? { fsProtocol, kind: \"skipped\" } : { kind: \"skipped\" };\n }\n\n const profile: ConnectionProfile = { host, provider: mapped.provider };\n if (mapped.secure !== undefined) profile.secure = mapped.secure;\n const portText = values[\"PortNumber\"];\n if (portText !== undefined) {\n const port = Number.parseInt(portText, 10);\n if (Number.isFinite(port)) profile.port = port;\n }\n const user = values[\"UserName\"]?.trim();\n if (user !== undefined && user !== \"\") profile.username = { value: user };\n\n if (mapped.provider === \"sftp\") {\n const ssh: NonNullable<ConnectionProfile[\"ssh\"]> = {};\n const keyPath = values[\"PublicKeyFile\"]?.trim();\n if (keyPath !== undefined && keyPath !== \"\") ssh.privateKey = { path: keyPath };\n if (Object.keys(ssh).length > 0) profile.ssh = ssh;\n }\n\n const session: Omit<WinScpSession, \"folder\"> = { name, profile };\n if (Number.isFinite(fsProtocol)) session.fsProtocol = fsProtocol;\n if (Number.isFinite(ftps) && ftps !== 0) session.ftps = ftps;\n return { kind: \"session\", session };\n}\n\nfunction mapWinScpProtocol(\n fsProtocol: number,\n ftps: number,\n): { provider: NonNullable<ConnectionProfile[\"provider\"]>; secure?: boolean } | undefined {\n switch (fsProtocol) {\n case 0:\n case 1:\n case 2:\n return { provider: \"sftp\" };\n case 5:\n return ftps === 0 ? { provider: \"ftp\" } : { provider: \"ftps\", secure: ftps === 1 };\n default:\n return undefined;\n }\n}\n\ninterface IniSection {\n name: string;\n values: Record<string, string>;\n}\n\nfunction parseIni(text: string): IniSection[] {\n const sections: IniSection[] = [];\n let current: IniSection | undefined;\n const lines = text.split(/\\r?\\n/);\n for (const rawLine of lines) {\n const line = rawLine.replace(/^\\s*[#;].*$/, \"\").trim();\n if (line === \"\") continue;\n const sectionMatch = line.match(/^\\[(.+)\\]$/);\n if (sectionMatch && sectionMatch[1] !== undefined) {\n current = { name: sectionMatch[1], values: {} };\n sections.push(current);\n continue;\n }\n if (current === undefined) continue;\n const eq = line.indexOf(\"=\");\n if (eq === -1) continue;\n const key = line.slice(0, eq).trim();\n const value = line.slice(eq + 1).trim();\n if (key !== \"\") current.values[key] = value;\n }\n return sections;\n}\n\nfunction decodeSessionPath(name: string): string {\n // WinSCP encodes special characters in session names (e.g. spaces as %20, backslashes as %5C).\n try {\n return decodeURIComponent(name);\n } catch {\n return name;\n }\n}\n","/**\n * Protocol error factory helpers.\n *\n * This module translates raw FTP status replies into typed ZeroTransfer errors so\n * adapters can keep protocol parsing separate from application-facing failures.\n *\n * @module errors/errorFactory\n */\nimport {\n AuthenticationError,\n ConnectionError,\n PathAlreadyExistsError,\n PathNotFoundError,\n PermissionDeniedError,\n ProtocolError,\n TransferError,\n type SpecializedErrorDetails,\n type ZeroTransferError,\n} from \"./ZeroTransferError\";\nimport type { RemoteProtocol } from \"../types/public\";\n\n/**\n * Input used to map an FTP reply into a structured ZeroTransfer error.\n */\nexport interface FtpReplyErrorInput {\n /** Numeric FTP response code returned by the server. */\n ftpCode: number;\n /** Server-provided response message. */\n message: string;\n /** FTP command that produced the response, if known. */\n command?: string;\n /** Remote path involved in the command, if any. */\n path?: string;\n /** Protocol variant used by the adapter. */\n protocol?: RemoteProtocol;\n /** Original lower-level failure that accompanied the reply. */\n cause?: unknown;\n}\n\n/**\n * Maps an FTP reply into the closest typed ZeroTransfer error.\n *\n * @param input - FTP code, message, and optional operation context.\n * @returns A structured error subclass with stable code and retryability metadata.\n */\nexport function errorFromFtpReply(input: FtpReplyErrorInput): ZeroTransferError {\n const details: SpecializedErrorDetails = {\n ftpCode: input.ftpCode,\n message: input.message,\n protocol: input.protocol ?? \"ftp\",\n retryable: false,\n };\n\n if (input.command !== undefined) details.command = input.command;\n if (input.path !== undefined) details.path = input.path;\n if (input.cause !== undefined) details.cause = input.cause;\n\n if (input.ftpCode === 530) {\n return new AuthenticationError(details);\n }\n\n if (input.ftpCode === 421) {\n return new ConnectionError({\n ...details,\n retryable: true,\n });\n }\n\n if (input.ftpCode === 550) {\n return mapFtp550(details);\n }\n\n if ([450, 451, 452].includes(input.ftpCode)) {\n return new TransferError({\n ...details,\n retryable: true,\n });\n }\n\n if (input.ftpCode >= 400 && input.ftpCode < 500) {\n return new ConnectionError({\n ...details,\n retryable: true,\n });\n }\n\n return new ProtocolError(details);\n}\n\n/**\n * Maps ambiguous FTP 550 replies to the most specific path or permission error.\n *\n * @param details - Shared error details derived from the original reply.\n * @returns A typed path or permission error.\n */\nfunction mapFtp550(details: SpecializedErrorDetails): ZeroTransferError {\n const lowerMessage = details.message.toLowerCase();\n\n if (lowerMessage.includes(\"already\") || lowerMessage.includes(\"exists\")) {\n return new PathAlreadyExistsError(details);\n }\n\n if (\n lowerMessage.includes(\"not found\") ||\n lowerMessage.includes(\"no such\") ||\n lowerMessage.includes(\"unavailable\")\n ) {\n return new PathNotFoundError(details);\n }\n\n return new PermissionDeniedError(details);\n}\n","/**\n * Production-ready retry policy with exponential backoff and full jitter.\n *\n * @module transfers/createDefaultRetryPolicy\n */\nimport { ZeroTransferError } from \"../errors/ZeroTransferError\";\nimport type { TransferRetryDecisionInput, TransferRetryPolicy } from \"./TransferEngine\";\n\n/** Options for {@link createDefaultRetryPolicy}. */\nexport interface DefaultRetryPolicyOptions {\n /** Maximum total attempts, including the first attempt. Defaults to `4`. */\n maxAttempts?: number;\n /** Base backoff delay before jitter in milliseconds. Defaults to `250`. */\n baseDelayMs?: number;\n /** Upper bound for a single computed backoff delay in milliseconds. Defaults to `30_000`. */\n maxDelayMs?: number;\n /**\n * Total elapsed-time budget across all attempts and delays in milliseconds.\n * Once exceeded, no further retries are attempted. Defaults to `300_000` (5 minutes).\n */\n maxElapsedMs?: number;\n /**\n * Random source in `[0, 1)` used for jitter. Defaults to `Math.random`.\n * Inject a deterministic source in tests.\n */\n random?: () => number;\n}\n\nconst DEFAULT_MAX_ATTEMPTS = 4;\nconst DEFAULT_BASE_DELAY_MS = 250;\nconst DEFAULT_MAX_DELAY_MS = 30_000;\nconst DEFAULT_MAX_ELAPSED_MS = 300_000;\n\n/**\n * Creates the SDK's recommended retry policy for transfer execution.\n *\n * The policy retries only failures the SDK has marked as safe to retry\n * (`error.retryable === true` on a {@link ZeroTransferError}), backing off\n * exponentially with full jitter: each delay is drawn uniformly from\n * `[0, min(maxDelayMs, baseDelayMs * 2^(attempt - 1)))`, the schedule that\n * minimizes contention when many clients retry against the same server.\n *\n * Server pacing hints are honored: when the failed attempt carries\n * `details.retryAfterMs` (parsed from an HTTP `Retry-After` header on 429/503\n * responses by the web-family providers), the next delay is exactly that\n * value rather than the jittered backoff. A hint that does not fit in the\n * remaining `maxElapsedMs` budget stops retrying instead of retrying early.\n *\n * Retries also stop once `maxElapsedMs` has elapsed since execution started,\n * regardless of how many attempts remain.\n *\n * @param options - Optional overrides for attempts, delays, and the elapsed budget.\n * @returns A {@link TransferRetryPolicy} for {@link TransferEngine.execute},\n * {@link runRoute}, {@link TransferQueue}, or client-level defaults.\n *\n * @example Default policy on a one-shot helper\n * ```ts\n * import { createDefaultRetryPolicy, uploadFile } from \"@zero-transfer/sdk\";\n *\n * await uploadFile({\n * client,\n * destination: { path: \"/uploads/report.csv\", profile },\n * localPath: \"./out/report.csv\",\n * retry: createDefaultRetryPolicy(),\n * });\n * ```\n *\n * @example Tighter schedule for latency-sensitive work\n * ```ts\n * const retry = createDefaultRetryPolicy({\n * maxAttempts: 3,\n * baseDelayMs: 100,\n * maxDelayMs: 2_000,\n * maxElapsedMs: 15_000,\n * });\n * ```\n *\n * @see {@link TransferRetryPolicy} for the underlying hook contract.\n */\nexport function createDefaultRetryPolicy(\n options: DefaultRetryPolicyOptions = {},\n): TransferRetryPolicy {\n const maxAttempts = normalizePositiveInteger(options.maxAttempts, DEFAULT_MAX_ATTEMPTS);\n const baseDelayMs = normalizeNonNegative(options.baseDelayMs, DEFAULT_BASE_DELAY_MS);\n const maxDelayMs = normalizeNonNegative(options.maxDelayMs, DEFAULT_MAX_DELAY_MS);\n const maxElapsedMs = normalizeNonNegative(options.maxElapsedMs, DEFAULT_MAX_ELAPSED_MS);\n const random = options.random ?? Math.random;\n\n return {\n getDelayMs(input: TransferRetryDecisionInput): number {\n const retryAfterMs = readRetryAfterMs(input.error);\n if (retryAfterMs !== undefined) {\n return retryAfterMs;\n }\n\n const exponentialMs = baseDelayMs * 2 ** (input.attempt - 1);\n const cappedMs = Math.min(maxDelayMs, exponentialMs);\n return Math.floor(random() * cappedMs);\n },\n maxAttempts,\n shouldRetry(input: TransferRetryDecisionInput): boolean {\n if (!(input.error instanceof ZeroTransferError) || !input.error.retryable) {\n return false;\n }\n\n if (input.elapsedMs >= maxElapsedMs) {\n return false;\n }\n\n const retryAfterMs = readRetryAfterMs(input.error);\n if (retryAfterMs !== undefined && input.elapsedMs + retryAfterMs > maxElapsedMs) {\n return false;\n }\n\n return true;\n },\n };\n}\n\n/** Reads a server-provided `Retry-After` hint from a failed attempt's error details. */\nfunction readRetryAfterMs(error: unknown): number | undefined {\n if (!(error instanceof ZeroTransferError)) return undefined;\n const value = error.details?.[\"retryAfterMs\"];\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) return undefined;\n return Math.floor(value);\n}\n\nfunction normalizePositiveInteger(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value) || value < 1) {\n return fallback;\n }\n\n return Math.floor(value);\n}\n\nfunction normalizeNonNegative(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value) || value < 0) {\n return fallback;\n }\n\n return Math.floor(value);\n}\n","/**\n * Transfer plan and dry-run primitives.\n *\n * @module transfers/TransferPlan\n */\nimport type { TransferEndpoint, TransferJob, TransferOperation } from \"./TransferJob\";\n\n/** Non-executing plan action used to explain an intentionally skipped step. */\nexport type TransferPlanAction = TransferOperation | \"skip\";\n\n/** Step inside a transfer plan. */\nexport interface TransferPlanStep {\n /** Stable step identifier within the plan. */\n id: string;\n /** Action the step would perform. */\n action: TransferPlanAction;\n /** Source endpoint when the action reads data. */\n source?: TransferEndpoint;\n /** Destination endpoint when the action writes data. */\n destination?: TransferEndpoint;\n /** Expected bytes affected by the step when known. */\n expectedBytes?: number;\n /** Whether this step may remove or replace data. */\n destructive?: boolean;\n /** Human-readable reason for planned or skipped work. */\n reason?: string;\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\n/** Input used to create a transfer plan. */\nexport interface TransferPlanInput {\n /** Stable plan identifier. */\n id: string;\n /** Planned steps in execution order. */\n steps: TransferPlanStep[];\n /** Whether the plan is informational only. Defaults to `true`. */\n dryRun?: boolean;\n /** Clock used for deterministic tests. Defaults to `new Date()`. */\n now?: () => Date;\n /** Non-fatal plan warnings. */\n warnings?: string[];\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\n/** Provider-neutral transfer plan. */\nexport interface TransferPlan {\n /** Stable plan identifier. */\n id: string;\n /** Whether this plan should be treated as a dry run. */\n dryRun: boolean;\n /** Time the plan was created. */\n createdAt: Date;\n /** Planned steps in execution order. */\n steps: TransferPlanStep[];\n /** Non-fatal plan warnings. */\n warnings: string[];\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\n/** Summary of a transfer plan. */\nexport interface TransferPlanSummary {\n /** Total number of steps. */\n totalSteps: number;\n /** Number of executable steps. */\n executableSteps: number;\n /** Number of skipped steps. */\n skippedSteps: number;\n /** Number of destructive steps. */\n destructiveSteps: number;\n /** Sum of expected bytes for steps that provide sizes. */\n totalExpectedBytes: number;\n /** Counts grouped by action. */\n actions: Record<string, number>;\n}\n\n/**\n * Creates a transfer plan from dry-run planning input.\n *\n * Plans are immutable, structured descriptions of intended work. Pair with\n * {@link createSyncPlan} or {@link createAtomicDeployPlan} for end-to-end\n * planning, or build steps by hand when you need full control. Pass the plan\n * to {@link createTransferJobsFromPlan} to materialize executable jobs.\n *\n * @example Build a plan with two upload steps and inspect it\n * ```ts\n * import { createTransferPlan, summarizeTransferPlan } from \"@zero-transfer/sdk\";\n *\n * const plan = createTransferPlan({\n * id: \"manual-batch\",\n * steps: [\n * { action: \"upload\", source: \"./a.bin\", destination: \"/lake/a.bin\", expectedBytes: 1024 },\n * { action: \"upload\", source: \"./b.bin\", destination: \"/lake/b.bin\", expectedBytes: 2048 },\n * ],\n * });\n *\n * console.table(summarizeTransferPlan(plan));\n * ```\n */\nexport function createTransferPlan(input: TransferPlanInput): TransferPlan {\n const plan: TransferPlan = {\n createdAt: input.now?.() ?? new Date(),\n dryRun: input.dryRun ?? true,\n id: input.id,\n steps: input.steps.map(clonePlanStep),\n warnings: [...(input.warnings ?? [])],\n };\n\n if (input.metadata !== undefined) {\n plan.metadata = { ...input.metadata };\n }\n\n return plan;\n}\n\n/**\n * Summarizes a transfer plan for diagnostics, previews, and tests.\n *\n * Returns aggregate counts (total / executable / skipped / destructive),\n * total expected bytes, and a per-action histogram. Useful for printing a\n * one-line plan summary before executing or for asserting plan shape in\n * tests.\n *\n * @example Print a plan preview\n * ```ts\n * import { summarizeTransferPlan } from \"@zero-transfer/sdk\";\n *\n * const summary = summarizeTransferPlan(plan);\n * console.log(`${summary.executableSteps} steps, ${summary.totalExpectedBytes} bytes total`);\n * console.log(\"Actions:\", summary.actions);\n * ```\n */\nexport function summarizeTransferPlan(plan: TransferPlan): TransferPlanSummary {\n const actions: Record<string, number> = {};\n let destructiveSteps = 0;\n let executableSteps = 0;\n let skippedSteps = 0;\n let totalExpectedBytes = 0;\n\n for (const step of plan.steps) {\n actions[step.action] = (actions[step.action] ?? 0) + 1;\n destructiveSteps += step.destructive === true ? 1 : 0;\n skippedSteps += step.action === \"skip\" ? 1 : 0;\n executableSteps += step.action === \"skip\" ? 0 : 1;\n totalExpectedBytes += step.expectedBytes ?? 0;\n }\n\n return {\n actions,\n destructiveSteps,\n executableSteps,\n skippedSteps,\n totalExpectedBytes,\n totalSteps: plan.steps.length,\n };\n}\n\n/** Converts executable plan steps into transfer jobs while preserving order. */\nexport function createTransferJobsFromPlan(plan: TransferPlan): TransferJob[] {\n return plan.steps.flatMap((step) => {\n if (step.action === \"skip\") {\n return [];\n }\n\n const job: TransferJob = {\n id: `${plan.id}:${step.id}`,\n operation: step.action,\n };\n\n if (step.source !== undefined) job.source = cloneEndpoint(step.source);\n if (step.destination !== undefined) job.destination = cloneEndpoint(step.destination);\n if (step.expectedBytes !== undefined) job.totalBytes = step.expectedBytes;\n if (step.metadata !== undefined) job.metadata = { ...step.metadata };\n\n return [job];\n });\n}\n\nfunction clonePlanStep(step: TransferPlanStep): TransferPlanStep {\n const clone: TransferPlanStep = {\n action: step.action,\n id: step.id,\n };\n\n if (step.source !== undefined) clone.source = cloneEndpoint(step.source);\n if (step.destination !== undefined) clone.destination = cloneEndpoint(step.destination);\n if (step.expectedBytes !== undefined) clone.expectedBytes = step.expectedBytes;\n if (step.destructive !== undefined) clone.destructive = step.destructive;\n if (step.reason !== undefined) clone.reason = step.reason;\n if (step.metadata !== undefined) clone.metadata = { ...step.metadata };\n\n return clone;\n}\n\nfunction cloneEndpoint(endpoint: TransferEndpoint): TransferEndpoint {\n const clone: TransferEndpoint = { path: endpoint.path };\n\n if (endpoint.provider !== undefined) {\n clone.provider = endpoint.provider;\n }\n\n return clone;\n}\n","/**\n * Transfer queue primitives built on top of {@link TransferEngine}.\n *\n * @module transfers/TransferQueue\n */\nimport type { TransferClient } from \"../core/TransferClient\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { TransferProgressEvent } from \"../types/public\";\nimport {\n TransferEngine,\n type TransferEngineExecuteOptions,\n type TransferExecutor,\n type TransferRetryPolicy,\n} from \"./TransferEngine\";\nimport type {\n TransferBandwidthLimit,\n TransferJob,\n TransferReceipt,\n TransferTimeoutPolicy,\n} from \"./TransferJob\";\n\n/** Queue item lifecycle state. */\nexport type TransferQueueItemStatus = \"queued\" | \"running\" | \"completed\" | \"failed\" | \"canceled\";\n\n/** Resolver used when jobs do not provide an executor at enqueue time. */\nexport type TransferQueueExecutorResolver = (job: TransferJob) => TransferExecutor;\n\n/** Options used to create a transfer queue. */\nexport interface TransferQueueOptions {\n /** Transfer engine used to execute queued jobs. Defaults to a new engine. */\n engine?: TransferEngine;\n /**\n * Transfer client whose {@link TransferClientDefaults | defaults} seed the\n * queue's retry and timeout policies when not set here or per drain.\n */\n client?: TransferClient;\n /** Maximum jobs to execute at the same time. Defaults to `1`. */\n concurrency?: number;\n /** Default executor used for jobs that do not provide one directly. */\n executor?: TransferExecutor;\n /** Dynamic executor resolver used when no per-job executor or default executor exists. */\n resolveExecutor?: TransferQueueExecutorResolver;\n /** Retry policy passed to engine executions. Falls back to `client.defaults.retry`. */\n retry?: TransferRetryPolicy;\n /** Timeout policy passed to engine executions. Falls back to `client.defaults.timeout`. */\n timeout?: TransferTimeoutPolicy;\n /** Optional throughput limit shape passed to transfer executors. */\n bandwidthLimit?: TransferBandwidthLimit;\n /** Progress observer shared across queued jobs. */\n onProgress?: (event: TransferProgressEvent) => void;\n /** Completion observer for successful jobs. */\n onReceipt?: (receipt: TransferReceipt) => void;\n /** Failure observer for failed jobs. */\n onError?: (item: TransferQueueItem, error: unknown) => void;\n}\n\n/** Options used when draining a queue. */\nexport interface TransferQueueRunOptions {\n /** Abort signal used to cancel running jobs during this drain. */\n signal?: AbortSignal;\n /** Retry policy override for this drain. */\n retry?: TransferRetryPolicy;\n /** Timeout policy override for this drain. */\n timeout?: TransferTimeoutPolicy;\n /** Bandwidth limit override for this drain. */\n bandwidthLimit?: TransferBandwidthLimit;\n /** Progress observer override for this drain. */\n onProgress?: (event: TransferProgressEvent) => void;\n}\n\n/** Enqueued transfer job state. */\nexport interface TransferQueueItem {\n /** Queued job identifier. */\n id: string;\n /** Original transfer job. */\n job: TransferJob;\n /** Current queue status. */\n status: TransferQueueItemStatus;\n /** Successful transfer receipt when completed. */\n receipt?: TransferReceipt;\n /** Failure or cancellation reason when available. */\n error?: unknown;\n}\n\ninterface InternalTransferQueueItem extends TransferQueueItem {\n controller: AbortController;\n executor?: TransferExecutor;\n}\n\n/** Summary returned after a queue drain. */\nexport interface TransferQueueSummary {\n /** Number of items currently known to the queue. */\n total: number;\n /** Number of successfully completed jobs. */\n completed: number;\n /** Number of failed jobs. */\n failed: number;\n /** Number of canceled jobs. */\n canceled: number;\n /** Number of jobs still queued because the queue was paused. */\n queued: number;\n /** Number of jobs currently running. */\n running: number;\n /** Successful receipts in queue order. */\n receipts: TransferReceipt[];\n /** Failed queue items in queue order. */\n failures: TransferQueueItem[];\n}\n\n/**\n * Minimal transfer queue with concurrency, pause/resume, cancellation, and drain summaries.\n *\n * Wrap a {@link TransferEngine} with a queue when you need to run many transfers\n * concurrently with bounded parallelism, observe per-job progress, or drive\n * a UI from a single source of truth. Items are FIFO; failures and successes\n * are surfaced via observers and in the final {@link TransferQueueSummary}.\n *\n * @example Run a batch of uploads with concurrency=4\n * ```ts\n * import {\n * TransferQueue,\n * createProviderTransferExecutor,\n * } from \"@zero-transfer/sdk\";\n *\n * const queue = new TransferQueue({\n * concurrency: 4,\n * executor: createProviderTransferExecutor({ client }),\n * onProgress: (e) => console.log(`${e.jobId}: ${e.bytesTransferred}`),\n * onError: (item, err) => console.error(`${item.job.id} failed`, err),\n * });\n *\n * for (const file of files) {\n * queue.enqueue({\n * id: file.name,\n * operation: \"upload\",\n * source: { profile: localProfile, path: file.path },\n * destination: { profile: s3Profile, path: `/lake/${file.name}` },\n * });\n * }\n *\n * const summary = await queue.drain();\n * console.log(`Completed ${summary.completed} / ${summary.total}`);\n * ```\n */\nexport class TransferQueue {\n private readonly engine: TransferEngine;\n private readonly items: InternalTransferQueueItem[] = [];\n private readonly defaultExecutor: TransferExecutor | undefined;\n private readonly resolveExecutor: TransferQueueExecutorResolver | undefined;\n private readonly retry: TransferRetryPolicy | undefined;\n private readonly timeout: TransferTimeoutPolicy | undefined;\n private readonly bandwidthLimit: TransferBandwidthLimit | undefined;\n private readonly onProgress: ((event: TransferProgressEvent) => void) | undefined;\n private readonly onReceipt: ((receipt: TransferReceipt) => void) | undefined;\n private readonly onError: ((item: TransferQueueItem, error: unknown) => void) | undefined;\n private concurrency: number;\n private paused = false;\n\n /**\n * Creates a transfer queue.\n *\n * @param options - Queue engine, concurrency, executor, and observer options.\n */\n constructor(options: TransferQueueOptions = {}) {\n this.engine = options.engine ?? new TransferEngine();\n this.concurrency = normalizeConcurrency(options.concurrency);\n this.defaultExecutor = options.executor;\n this.resolveExecutor = options.resolveExecutor;\n this.retry = options.retry ?? options.client?.defaults?.retry;\n this.timeout = options.timeout ?? options.client?.defaults?.timeout;\n this.bandwidthLimit = options.bandwidthLimit;\n this.onProgress = options.onProgress;\n this.onReceipt = options.onReceipt;\n this.onError = options.onError;\n }\n\n /** Adds a transfer job to the queue. */\n add(job: TransferJob, executor?: TransferExecutor): TransferQueueItem {\n if (this.items.some((item) => item.id === job.id)) {\n throw new ConfigurationError({\n details: { jobId: job.id },\n message: `Transfer queue already contains job: ${job.id}`,\n retryable: false,\n });\n }\n\n const item: InternalTransferQueueItem = {\n controller: new AbortController(),\n id: job.id,\n job: cloneTransferJob(job),\n status: \"queued\",\n };\n\n if (executor !== undefined) {\n item.executor = executor;\n }\n\n this.items.push(item);\n return toPublicItem(item);\n }\n\n /** Pauses dispatch of new queued jobs. Running jobs are allowed to finish. */\n pause(): void {\n this.paused = true;\n }\n\n /** Resumes dispatch of queued jobs on the next `run()` call. */\n resume(): void {\n this.paused = false;\n }\n\n /** Updates queue concurrency for subsequent drains. */\n setConcurrency(concurrency: number): void {\n this.concurrency = normalizeConcurrency(concurrency);\n }\n\n /** Cancels a queued or running job. */\n cancel(jobId: string): boolean {\n const item = this.items.find((candidate) => candidate.id === jobId);\n\n if (\n item === undefined ||\n item.status === \"completed\" ||\n item.status === \"failed\" ||\n item.status === \"canceled\"\n ) {\n return false;\n }\n\n item.controller.abort();\n\n if (item.status === \"queued\") {\n item.status = \"canceled\";\n }\n\n return true;\n }\n\n /** Returns a queued item snapshot by id. */\n get(jobId: string): TransferQueueItem | undefined {\n const item = this.items.find((candidate) => candidate.id === jobId);\n return item === undefined ? undefined : toPublicItem(item);\n }\n\n /** Lists queue item snapshots in insertion order. */\n list(): TransferQueueItem[] {\n return this.items.map(toPublicItem);\n }\n\n /** Drains currently queued jobs until complete, failed, canceled, or paused. */\n async run(options: TransferQueueRunOptions = {}): Promise<TransferQueueSummary> {\n const workerCount = Math.max(1, Math.min(this.concurrency, this.countDispatchableItems()));\n const workers = Array.from({ length: workerCount }, () => this.runWorker(options));\n\n await Promise.all(workers);\n return this.summarize();\n }\n\n /** Returns a queue summary without executing more work. */\n summarize(): TransferQueueSummary {\n const publicItems = this.items.map(toPublicItem);\n\n return {\n canceled: publicItems.filter((item) => item.status === \"canceled\").length,\n completed: publicItems.filter((item) => item.status === \"completed\").length,\n failed: publicItems.filter((item) => item.status === \"failed\").length,\n failures: publicItems.filter((item) => item.status === \"failed\"),\n queued: publicItems.filter((item) => item.status === \"queued\").length,\n receipts: publicItems\n .filter(\n (item): item is TransferQueueItem & { receipt: TransferReceipt } =>\n item.receipt !== undefined,\n )\n .map((item) => item.receipt),\n running: publicItems.filter((item) => item.status === \"running\").length,\n total: publicItems.length,\n };\n }\n\n private async runWorker(options: TransferQueueRunOptions): Promise<void> {\n for (;;) {\n const item = this.nextQueuedItem();\n\n if (item === undefined) {\n return;\n }\n\n await this.runItem(item, options);\n }\n }\n\n private nextQueuedItem(): InternalTransferQueueItem | undefined {\n if (this.paused) {\n return undefined;\n }\n\n const item = this.items.find((candidate) => candidate.status === \"queued\");\n\n if (item !== undefined) {\n item.status = item.controller.signal.aborted ? \"canceled\" : \"running\";\n }\n\n return item?.status === \"running\" ? item : undefined;\n }\n\n private async runItem(\n item: InternalTransferQueueItem,\n options: TransferQueueRunOptions,\n ): Promise<void> {\n const abortListener = createAbortForwarder(options.signal, item.controller);\n\n try {\n const executeOptions: TransferEngineExecuteOptions = {\n signal: item.controller.signal,\n };\n const onProgress = options.onProgress ?? this.onProgress;\n const retry = options.retry ?? this.retry;\n const timeout = options.timeout ?? this.timeout;\n const bandwidthLimit = options.bandwidthLimit ?? this.bandwidthLimit;\n\n if (onProgress !== undefined) {\n executeOptions.onProgress = onProgress;\n }\n\n if (retry !== undefined) {\n executeOptions.retry = retry;\n }\n\n if (timeout !== undefined) {\n executeOptions.timeout = timeout;\n }\n\n if (bandwidthLimit !== undefined) {\n executeOptions.bandwidthLimit = bandwidthLimit;\n }\n\n const receipt = await this.engine.execute(\n item.job,\n this.requireExecutor(item),\n executeOptions,\n );\n\n item.receipt = receipt;\n item.status = \"completed\";\n this.onReceipt?.(receipt);\n } catch (error) {\n item.error = error;\n item.status = item.controller.signal.aborted ? \"canceled\" : \"failed\";\n\n if (item.status === \"failed\") {\n this.onError?.(toPublicItem(item), error);\n }\n } finally {\n abortListener.dispose();\n }\n }\n\n private requireExecutor(item: InternalTransferQueueItem): TransferExecutor {\n const executor = item.executor ?? this.defaultExecutor ?? this.resolveExecutor?.(item.job);\n\n if (executor === undefined) {\n throw new ConfigurationError({\n details: { jobId: item.job.id },\n message: `Transfer queue job has no executor: ${item.job.id}`,\n retryable: false,\n });\n }\n\n return executor;\n }\n\n private countDispatchableItems(): number {\n return this.items.filter((item) => item.status === \"queued\" && !item.controller.signal.aborted)\n .length;\n }\n}\n\nfunction normalizeConcurrency(value: number | undefined): number {\n if (value === undefined || !Number.isFinite(value)) {\n return 1;\n }\n\n return Math.max(1, Math.floor(value));\n}\n\nfunction createAbortForwarder(\n source: AbortSignal | undefined,\n target: AbortController,\n): { dispose(): void } {\n if (source === undefined) {\n return { dispose: () => undefined };\n }\n\n const abort = (): void => target.abort();\n\n if (source.aborted) {\n abort();\n return { dispose: () => undefined };\n }\n\n source.addEventListener(\"abort\", abort, { once: true });\n\n return {\n dispose: () => source.removeEventListener(\"abort\", abort),\n };\n}\n\nfunction toPublicItem(item: InternalTransferQueueItem): TransferQueueItem {\n const snapshot: TransferQueueItem = {\n id: item.id,\n job: cloneTransferJob(item.job),\n status: item.status,\n };\n\n if (item.receipt !== undefined) snapshot.receipt = item.receipt;\n if (item.error !== undefined) snapshot.error = item.error;\n\n return snapshot;\n}\n\nfunction cloneTransferJob(job: TransferJob): TransferJob {\n const clone: TransferJob = {\n id: job.id,\n operation: job.operation,\n };\n\n if (job.source !== undefined) clone.source = { ...job.source };\n if (job.destination !== undefined) clone.destination = { ...job.destination };\n if (job.totalBytes !== undefined) clone.totalBytes = job.totalBytes;\n if (job.resumed !== undefined) clone.resumed = job.resumed;\n if (job.metadata !== undefined) clone.metadata = { ...job.metadata };\n\n return clone;\n}\n","/**\n * Browser-friendly directory navigation helpers for file-manager UIs.\n *\n * Wraps a {@link RemoteFileSystem} with stateful current-directory tracking,\n * breadcrumb generation, and pure sort/filter utilities so consumers can render\n * directory views without re-implementing common navigation glue.\n *\n * @module sync/createRemoteBrowser\n */\nimport type { RemoteFileSystem } from \"../providers/RemoteFileSystem\";\nimport type { RemoteEntry } from \"../types/public\";\nimport { normalizeRemotePath } from \"../utils/path\";\n\n/** Sort key supported by {@link sortRemoteEntries}. */\nexport type RemoteEntrySortKey = \"name\" | \"size\" | \"modifiedAt\" | \"type\";\n\n/** Sort direction supported by {@link sortRemoteEntries}. */\nexport type RemoteEntrySortOrder = \"asc\" | \"desc\";\n\n/** Crumb describing one segment in the current path. */\nexport interface RemoteBreadcrumb {\n /** Display name. `\"\"` is replaced with `\"/\"` for the root crumb. */\n name: string;\n /** Absolute path the crumb resolves to. */\n path: string;\n}\n\n/** Filter callback applied to a directory listing. */\nexport type RemoteBrowserFilter = (entry: RemoteEntry) => boolean;\n\n/** Options accepted by {@link createRemoteBrowser}. */\nexport interface CreateRemoteBrowserOptions {\n /** Remote file system to browse. */\n fs: RemoteFileSystem;\n /** Initial path. Defaults to `\"/\"`. */\n initialPath?: string;\n /** Sort key applied to listings. Defaults to `\"name\"`. */\n sortKey?: RemoteEntrySortKey;\n /** Sort order applied to listings. Defaults to `\"asc\"`. */\n sortOrder?: RemoteEntrySortOrder;\n /** Whether dotfile entries (names starting with `.`) are included. Defaults to `true`. */\n showHidden?: boolean;\n /** Optional filter applied after sort/hidden filtering. */\n filter?: RemoteBrowserFilter;\n}\n\n/** Snapshot returned by browser navigation methods. */\nexport interface RemoteBrowserSnapshot {\n /** Current absolute path. */\n path: string;\n /** Directory entries after sorting and filtering. */\n entries: RemoteEntry[];\n /** Breadcrumb trail leading from `/` to {@link path}. */\n breadcrumbs: RemoteBreadcrumb[];\n}\n\n/** Stateful directory browser returned by {@link createRemoteBrowser}. */\nexport interface RemoteBrowser {\n /** Current absolute path. */\n readonly path: string;\n /** Last loaded sorted/filtered entries. */\n readonly entries: readonly RemoteEntry[];\n /** Reload the current directory and return the latest snapshot. */\n refresh(): Promise<RemoteBrowserSnapshot>;\n /** Navigate to the supplied absolute or relative path. */\n navigate(target: string): Promise<RemoteBrowserSnapshot>;\n /** Descend into the supplied directory entry. Throws when the entry is not a directory. */\n open(entry: RemoteEntry): Promise<RemoteBrowserSnapshot>;\n /** Move to the parent directory; no-op when already at the root. */\n up(): Promise<RemoteBrowserSnapshot>;\n /** Compute breadcrumbs for the current path without re-listing. */\n breadcrumbs(): RemoteBreadcrumb[];\n /** Update the sort key. The next refresh re-sorts the cached entries. */\n setSort(key: RemoteEntrySortKey, order?: RemoteEntrySortOrder): void;\n /** Toggle hidden-entry visibility. The next refresh re-applies the filter. */\n setShowHidden(showHidden: boolean): void;\n}\n\n/**\n * Returns the parent directory of a remote path, or `\"/\"` for root inputs.\n *\n * @param input - Remote path to inspect.\n * @returns The parent path normalized to an absolute form.\n */\nexport function parentRemotePath(input: string): string {\n const normalized = normalizeRemotePath(input);\n if (normalized === \"/\") return \"/\";\n const parts = normalized.split(\"/\").filter(Boolean);\n parts.pop();\n if (parts.length === 0) return \"/\";\n return `/${parts.join(\"/\")}`;\n}\n\n/**\n * Builds breadcrumbs from `/` down to the supplied path.\n *\n * @param input - Absolute remote path.\n * @returns Ordered crumbs starting with the root.\n */\nexport function buildRemoteBreadcrumbs(input: string): RemoteBreadcrumb[] {\n const normalized = normalizeRemotePath(input);\n const crumbs: RemoteBreadcrumb[] = [{ name: \"/\", path: \"/\" }];\n if (normalized === \"/\") return crumbs;\n\n const parts = normalized.split(\"/\").filter(Boolean);\n let cursor = \"\";\n for (const part of parts) {\n cursor += `/${part}`;\n crumbs.push({ name: part, path: cursor });\n }\n return crumbs;\n}\n\n/**\n * Returns a copy of the supplied entries sorted by the requested key. Directories\n * are grouped before files within ascending sorts, matching common file-manager UX.\n *\n * @param entries - Entries to sort.\n * @param key - Sort key.\n * @param order - Sort order.\n * @returns Sorted copy of the entries.\n */\nexport function sortRemoteEntries(\n entries: readonly RemoteEntry[],\n key: RemoteEntrySortKey = \"name\",\n order: RemoteEntrySortOrder = \"asc\",\n): RemoteEntry[] {\n const direction = order === \"asc\" ? 1 : -1;\n return [...entries].sort((left, right) => {\n if (key !== \"type\") {\n const leftIsDir = left.type === \"directory\";\n const rightIsDir = right.type === \"directory\";\n if (leftIsDir !== rightIsDir) return leftIsDir ? -1 : 1;\n }\n\n const compared = compareEntriesByKey(left, right, key);\n if (compared !== 0) return compared * direction;\n return compareNames(left, right);\n });\n}\n\n/**\n * Filters entries using the optional predicate plus an optional hidden-file rule.\n *\n * @param entries - Entries to filter.\n * @param options - Filtering controls.\n * @returns Entries matching the supplied rules.\n */\nexport function filterRemoteEntries(\n entries: readonly RemoteEntry[],\n options: { filter?: RemoteBrowserFilter; showHidden?: boolean } = {},\n): RemoteEntry[] {\n const showHidden = options.showHidden ?? true;\n const filter = options.filter;\n return entries.filter((entry) => {\n if (!showHidden && entry.name.startsWith(\".\")) return false;\n if (filter !== undefined && !filter(entry)) return false;\n return true;\n });\n}\n\n/**\n * Creates a stateful directory browser around a remote file system.\n *\n * The returned browser caches the most recent listing and applies sort/filter\n * settings on each refresh. Navigation methods return a snapshot so UI layers can\n * render synchronously without re-reading state.\n *\n * @param options - Browser configuration.\n * @returns Stateful browser bound to the supplied file system.\n */\nexport function createRemoteBrowser(options: CreateRemoteBrowserOptions): RemoteBrowser {\n const { fs } = options;\n let currentPath = normalizeRemotePath(options.initialPath ?? \"/\");\n let cachedEntries: RemoteEntry[] = [];\n let sortKey: RemoteEntrySortKey = options.sortKey ?? \"name\";\n let sortOrder: RemoteEntrySortOrder = options.sortOrder ?? \"asc\";\n let showHidden = options.showHidden ?? true;\n const filter = options.filter;\n\n async function loadCurrent(): Promise<RemoteBrowserSnapshot> {\n const raw = await fs.list(currentPath);\n const projected = projectEntries(raw);\n cachedEntries = projected;\n return snapshot();\n }\n\n function projectEntries(raw: readonly RemoteEntry[]): RemoteEntry[] {\n const filterOptions: { filter?: RemoteBrowserFilter; showHidden: boolean } = { showHidden };\n if (filter !== undefined) filterOptions.filter = filter;\n const filtered = filterRemoteEntries(raw, filterOptions);\n return sortRemoteEntries(filtered, sortKey, sortOrder);\n }\n\n function snapshot(): RemoteBrowserSnapshot {\n return {\n breadcrumbs: buildRemoteBreadcrumbs(currentPath),\n entries: [...cachedEntries],\n path: currentPath,\n };\n }\n\n async function navigate(target: string): Promise<RemoteBrowserSnapshot> {\n currentPath = resolveTarget(currentPath, target);\n return loadCurrent();\n }\n\n async function open(entry: RemoteEntry): Promise<RemoteBrowserSnapshot> {\n if (entry.type !== \"directory\") {\n throw new TypeError(`Cannot open non-directory entry \"${entry.path}\" (type: ${entry.type})`);\n }\n return navigate(entry.path);\n }\n\n return {\n breadcrumbs: () => buildRemoteBreadcrumbs(currentPath),\n get entries() {\n return cachedEntries;\n },\n navigate,\n open,\n get path() {\n return currentPath;\n },\n refresh: loadCurrent,\n setShowHidden(value: boolean) {\n showHidden = value;\n },\n setSort(key: RemoteEntrySortKey, order: RemoteEntrySortOrder = sortOrder) {\n sortKey = key;\n sortOrder = order;\n },\n up: () => navigate(parentRemotePath(currentPath)),\n };\n}\n\nfunction resolveTarget(currentPath: string, target: string): string {\n if (target.startsWith(\"/\")) return normalizeRemotePath(target);\n if (target === \"\" || target === \".\") return currentPath;\n if (target === \"..\") return parentRemotePath(currentPath);\n const base = currentPath === \"/\" ? \"\" : currentPath;\n return normalizeRemotePath(`${base}/${target}`);\n}\n\nfunction compareEntriesByKey(\n left: RemoteEntry,\n right: RemoteEntry,\n key: RemoteEntrySortKey,\n): number {\n switch (key) {\n case \"size\":\n return (left.size ?? 0) - (right.size ?? 0);\n case \"modifiedAt\": {\n const leftTime = left.modifiedAt?.getTime() ?? 0;\n const rightTime = right.modifiedAt?.getTime() ?? 0;\n return leftTime - rightTime;\n }\n case \"type\":\n return left.type.localeCompare(right.type);\n case \"name\":\n default:\n return compareNames(left, right);\n }\n}\n\nfunction compareNames(left: RemoteEntry, right: RemoteEntry): number {\n return left.name.localeCompare(right.name, undefined, { numeric: true, sensitivity: \"base\" });\n}\n","/**\n * Sync planning primitives that build a {@link TransferPlan} from a remote-tree diff.\n *\n * @module sync/createSyncPlan\n */\nimport type { ProviderId } from \"../core/ProviderId\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport {\n createTransferPlan,\n type TransferPlan,\n type TransferPlanStep,\n} from \"../transfers/TransferPlan\";\nimport { joinRemotePath, normalizeRemotePath } from \"../utils/path\";\nimport type { RemoteTreeDiff, RemoteTreeDiffEntry } from \"./diffRemoteTrees\";\n\n/** Sync direction used by {@link createSyncPlan}. */\nexport type SyncDirection = \"source-to-destination\" | \"destination-to-source\";\n\n/** How {@link createSyncPlan} reacts to entries that exist only on the destination. */\nexport type SyncDeletePolicy =\n /** Never delete destination entries that are missing on the source. */\n | \"never\"\n /** Plan destination deletions when running source-to-destination sync. */\n | \"mirror\"\n /** Plan destination deletions only when paired with a same-path file on the source. */\n | \"replace-only\";\n\n/** How {@link createSyncPlan} reacts to entries flagged as modified on both sides. */\nexport type SyncConflictPolicy =\n /** Overwrite the destination with the source. */\n | \"overwrite\"\n /** Overwrite the source with the destination. */\n | \"prefer-destination\"\n /** Skip conflicting entries with a `skip` step. */\n | \"skip\"\n /** Fail planning with a {@link ConfigurationError} when a conflict is encountered. */\n | \"error\";\n\n/** Endpoint shape supplied to {@link createSyncPlan}. */\nexport interface SyncEndpointInput {\n /** Provider that owns the endpoint when known. */\n provider?: ProviderId;\n /** Root path on the provider being synced. */\n rootPath: string;\n}\n\n/** Options accepted by {@link createSyncPlan}. */\nexport interface CreateSyncPlanOptions {\n /** Stable plan identifier. */\n id: string;\n /** Diff produced by {@link diffRemoteTrees} or an equivalent source. */\n diff: RemoteTreeDiff;\n /** Source-side endpoint that produced the diff. */\n source: SyncEndpointInput;\n /** Destination-side endpoint that produced the diff. */\n destination: SyncEndpointInput;\n /** Sync direction. Defaults to `\"source-to-destination\"`. */\n direction?: SyncDirection;\n /** Delete policy. Defaults to `\"never\"`. */\n deletePolicy?: SyncDeletePolicy;\n /** Conflict policy. Defaults to `\"overwrite\"`. */\n conflictPolicy?: SyncConflictPolicy;\n /** Whether to plan upload/download steps for directories. Defaults to `false`. */\n includeDirectoryActions?: boolean;\n /** Whether the plan is informational only. Defaults to `true`. */\n dryRun?: boolean;\n /** Clock used for deterministic tests. Defaults to `new Date()`. */\n now?: () => Date;\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Builds a {@link TransferPlan} that reconciles two remote subtrees.\n *\n * Plan steps are derived from a {@link RemoteTreeDiff}; the function does not perform\n * any I/O. Direction, delete policy, and conflict policy control which entries\n * become executable transfers and which become `skip` steps.\n *\n * @param options - Inputs and policies that shape the plan.\n * @returns Transfer plan ready for `createTransferJobsFromPlan` or queue execution.\n * @throws {@link ConfigurationError} When `conflictPolicy: \"error\"` encounters a conflict.\n *\n * @example Mirror SFTP → S3 with deletes\n * ```ts\n * import {\n * createSyncPlan,\n * diffRemoteTrees,\n * summarizeTransferPlan,\n * } from \"@zero-transfer/sdk\";\n *\n * const diff = await diffRemoteTrees(\n * srcSession.fs, \"/dist\",\n * dstSession.fs, \"/releases/current\",\n * );\n *\n * const plan = createSyncPlan({\n * id: \"release-mirror\",\n * diff,\n * source: { provider: \"sftp\", rootPath: \"/dist\" },\n * destination: { provider: \"s3\", rootPath: \"/releases/current\" },\n * deletePolicy: \"mirror\",\n * conflictPolicy: \"overwrite\",\n * });\n *\n * console.table(summarizeTransferPlan(plan));\n * ```\n */\nexport function createSyncPlan(options: CreateSyncPlanOptions): TransferPlan {\n const direction: SyncDirection = options.direction ?? \"source-to-destination\";\n const deletePolicy: SyncDeletePolicy = options.deletePolicy ?? \"never\";\n const conflictPolicy: SyncConflictPolicy = options.conflictPolicy ?? \"overwrite\";\n const includeDirectoryActions = options.includeDirectoryActions ?? false;\n const sourceRoot = normalizeRemotePath(options.source.rootPath);\n const destinationRoot = normalizeRemotePath(options.destination.rootPath);\n const warnings: string[] = [];\n const steps: TransferPlanStep[] = [];\n\n for (const entry of options.diff.entries) {\n const context: PlanEntryContext = {\n conflictPolicy,\n deletePolicy,\n destinationRoot,\n direction,\n entry,\n includeDirectoryActions,\n sourceRoot,\n warnings,\n };\n if (options.source.provider !== undefined) context.sourceProvider = options.source.provider;\n if (options.destination.provider !== undefined) {\n context.destinationProvider = options.destination.provider;\n }\n const step = planEntry(context);\n\n if (step !== undefined) steps.push(step);\n }\n\n const planInput: Parameters<typeof createTransferPlan>[0] = {\n id: options.id,\n steps,\n warnings,\n };\n if (options.dryRun !== undefined) planInput.dryRun = options.dryRun;\n if (options.now !== undefined) planInput.now = options.now;\n if (options.metadata !== undefined) planInput.metadata = options.metadata;\n\n return createTransferPlan(planInput);\n}\n\ninterface PlanEntryContext {\n conflictPolicy: SyncConflictPolicy;\n deletePolicy: SyncDeletePolicy;\n destinationProvider?: ProviderId;\n destinationRoot: string;\n direction: SyncDirection;\n entry: RemoteTreeDiffEntry;\n includeDirectoryActions: boolean;\n sourceProvider?: ProviderId;\n sourceRoot: string;\n warnings: string[];\n}\n\nfunction planEntry(context: PlanEntryContext): TransferPlanStep | undefined {\n const { entry } = context;\n const isDirectory = isDirectoryEntry(entry);\n\n if (isDirectory && !context.includeDirectoryActions) {\n return undefined;\n }\n\n switch (entry.status) {\n case \"added\":\n return planAdded(context);\n case \"removed\":\n return planRemoved(context);\n case \"modified\":\n return planModified(context);\n case \"unchanged\":\n return planUnchanged(context);\n default:\n // Unreachable when callers pass a normalized RemoteTreeDiff.\n return undefined;\n }\n}\n\nfunction planAdded(context: PlanEntryContext): TransferPlanStep {\n if (context.direction === \"source-to-destination\") {\n return createCopyStep(context, \"source\", \"destination\", expectedBytesFor(context.entry));\n }\n\n // Direction is destination-to-source: source-only entries should be deleted.\n if (context.deletePolicy === \"never\") {\n return createSkipStep(context, \"Source-only entry preserved by delete policy\");\n }\n\n return createDeleteStep(context, \"source\");\n}\n\nfunction planRemoved(context: PlanEntryContext): TransferPlanStep {\n if (context.direction === \"destination-to-source\") {\n return createCopyStep(context, \"destination\", \"source\", expectedBytesFor(context.entry));\n }\n\n // Direction is source-to-destination: destination-only entries.\n if (context.deletePolicy === \"never\") {\n return createSkipStep(context, \"Destination-only entry preserved by delete policy\");\n }\n\n if (context.deletePolicy === \"replace-only\") {\n return createSkipStep(\n context,\n \"Destination-only entry preserved (no source replacement available)\",\n );\n }\n\n return createDeleteStep(context, \"destination\");\n}\n\nfunction planModified(context: PlanEntryContext): TransferPlanStep {\n switch (context.conflictPolicy) {\n case \"overwrite\":\n return createCopyStep(context, \"source\", \"destination\", expectedBytesFor(context.entry), {\n destructive: true,\n });\n case \"prefer-destination\":\n return createCopyStep(context, \"destination\", \"source\", expectedBytesFor(context.entry), {\n destructive: true,\n });\n case \"skip\":\n return createSkipStep(context, `Conflict skipped: ${context.entry.reasons.join(\",\")}`);\n case \"error\":\n throw new ConfigurationError({\n details: {\n path: context.entry.path,\n reasons: context.entry.reasons,\n },\n message: `Sync plan conflict at ${context.entry.path} with reasons: ${context.entry.reasons.join(\", \")}`,\n retryable: false,\n });\n default:\n return createSkipStep(context, \"Conflict skipped\");\n }\n}\n\nfunction planUnchanged(context: PlanEntryContext): TransferPlanStep {\n return createSkipStep(context, \"Entry already in sync\");\n}\n\nfunction createCopyStep(\n context: PlanEntryContext,\n fromSide: \"source\" | \"destination\",\n toSide: \"source\" | \"destination\",\n expectedBytes: number | undefined,\n overrides: Partial<TransferPlanStep> = {},\n): TransferPlanStep {\n const step: TransferPlanStep = {\n action: \"copy\",\n id: makeStepId(context.entry, `copy-${fromSide}-to-${toSide}`),\n reason: describeReasons(context.entry, `Copy ${fromSide} to ${toSide}`),\n };\n\n step.source = endpointFor(context, fromSide);\n step.destination = endpointFor(context, toSide);\n if (expectedBytes !== undefined) step.expectedBytes = expectedBytes;\n if (overrides.destructive === true) step.destructive = true;\n if (overrides.metadata !== undefined) step.metadata = { ...overrides.metadata };\n\n return step;\n}\n\nfunction createDeleteStep(\n context: PlanEntryContext,\n side: \"source\" | \"destination\",\n): TransferPlanStep {\n return {\n action: \"delete\",\n destination: endpointFor(context, side),\n destructive: true,\n id: makeStepId(context.entry, `delete-${side}`),\n reason: `Delete ${side} entry not present on the other side`,\n };\n}\n\nfunction createSkipStep(context: PlanEntryContext, reason: string): TransferPlanStep {\n return {\n action: \"skip\",\n id: makeStepId(context.entry, \"skip\"),\n reason,\n source: endpointFor(context, \"source\"),\n destination: endpointFor(context, \"destination\"),\n };\n}\n\nfunction endpointFor(\n context: PlanEntryContext,\n side: \"source\" | \"destination\",\n): NonNullable<TransferPlanStep[\"source\"]> {\n const root = side === \"source\" ? context.sourceRoot : context.destinationRoot;\n const provider = side === \"source\" ? context.sourceProvider : context.destinationProvider;\n const endpoint: NonNullable<TransferPlanStep[\"source\"]> = {\n path: joinRootAndRelative(root, context.entry.path),\n };\n if (provider !== undefined) endpoint.provider = provider;\n return endpoint;\n}\n\nfunction joinRootAndRelative(rootPath: string, relativePath: string): string {\n if (rootPath === \"/\") return relativePath;\n if (relativePath === \"/\") return rootPath;\n return joinRemotePath(rootPath, relativePath);\n}\n\nfunction makeStepId(entry: RemoteTreeDiffEntry, suffix: string): string {\n return `${entry.path}#${suffix}`;\n}\n\nfunction describeReasons(entry: RemoteTreeDiffEntry, prefix: string): string {\n if (entry.reasons.length === 0) return prefix;\n return `${prefix} (${entry.reasons.join(\",\")})`;\n}\n\nfunction expectedBytesFor(entry: RemoteTreeDiffEntry): number | undefined {\n return entry.source?.size ?? entry.destination?.size;\n}\n\nfunction isDirectoryEntry(entry: RemoteTreeDiffEntry): boolean {\n return entry.source?.type === \"directory\" || entry.destination?.type === \"directory\";\n}\n","/**\n * Atomic deploy planning helpers.\n *\n * Produces a structured plan that stages a release under `<liveRoot>/<releasesDir>/<releaseId>`,\n * activates it via rename or symlink swap, and prunes older releases beyond a retain count.\n *\n * The plan is provider-neutral and execution-free: callers wire the upload {@link TransferPlan}\n * through the transfer engine and execute the activate/prune steps using their provider's\n * filesystem mutation primitives (rename, symlink, delete).\n *\n * @module sync/createAtomicDeployPlan\n */\nimport type { ProviderId } from \"../core/ProviderId\";\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { TransferPlan } from \"../transfers/TransferPlan\";\nimport { joinRemotePath, normalizeRemotePath } from \"../utils/path\";\nimport { createSyncPlan, type SyncEndpointInput } from \"./createSyncPlan\";\nimport type { RemoteTreeDiff } from \"./diffRemoteTrees\";\n\n/** Activation strategy used to swap a staged release into place. */\nexport type AtomicDeployStrategy =\n /** Rename `<liveRoot>` aside, then rename the staging path to `<liveRoot>`. */\n | \"rename\"\n /** Update a symlink at `<liveRoot>` to point at the staging path. */\n | \"symlink\";\n\n/** Operation kind for an activation step. */\nexport type AtomicDeployActivateOperation = \"rename\" | \"symlink\" | \"delete\";\n\n/** Kind of activation step described by the plan. */\nexport interface AtomicDeployActivateStep {\n /** Stable identifier within the activation list. */\n id: string;\n /** Operation the step would perform. */\n operation: AtomicDeployActivateOperation;\n /** Source path the operation reads or moves from. */\n fromPath?: string;\n /** Destination path the operation writes to. */\n toPath: string;\n /** Provider identifier that owns the affected paths when known. */\n provider?: ProviderId;\n /** Whether the step replaces or removes data. */\n destructive?: boolean;\n /** Human-readable description for previews and logs. */\n reason: string;\n}\n\n/** Pruning step describing an old release directory marked for deletion. */\nexport interface AtomicDeployPruneStep {\n /** Stable identifier within the prune list. */\n id: string;\n /** Absolute release directory path to delete. */\n path: string;\n /** Provider identifier that owns the path when known. */\n provider?: ProviderId;\n /** Reason the release was selected for pruning. */\n reason: string;\n}\n\n/** Result returned by {@link createAtomicDeployPlan}. */\nexport interface AtomicDeployPlan {\n /** Stable plan identifier. */\n id: string;\n /** Release identifier embedded into the staging path. */\n releaseId: string;\n /** Activation strategy chosen for the swap. */\n strategy: AtomicDeployStrategy;\n /** Provider identifier for the live destination when known. */\n provider?: ProviderId;\n /** Live target path the release activates onto. */\n livePath: string;\n /** Staging directory the upload populates. */\n stagingPath: string;\n /** Releases root directory under which staging and prior releases live. */\n releasesRoot: string;\n /** Optional backup path used by the rename strategy. */\n backupPath?: string;\n /** Upload plan that populates the staging directory. */\n uploadPlan: TransferPlan;\n /** Activation steps that swap staging into the live path. */\n activate: AtomicDeployActivateStep[];\n /** Prune steps that remove older releases beyond {@link retain}. */\n prune: AtomicDeployPruneStep[];\n /** Number of releases to retain (including the new release). */\n retain: number;\n /** Time the plan was created. */\n createdAt: Date;\n /** Non-fatal plan warnings. */\n warnings: string[];\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\n/** Options accepted by {@link createAtomicDeployPlan}. */\nexport interface CreateAtomicDeployPlanOptions {\n /** Stable plan identifier. */\n id: string;\n /** Diff describing source vs. staging contents (typically diffed against an empty staging directory). */\n diff: RemoteTreeDiff;\n /** Source-side endpoint feeding the release. */\n source: SyncEndpointInput;\n /** Live destination endpoint the release activates onto. */\n destination: SyncEndpointInput;\n /** Activation strategy. Defaults to `\"rename\"`. */\n strategy?: AtomicDeployStrategy;\n /** Release identifier. Defaults to a timestamp derived from {@link now}. */\n releaseId?: string;\n /** Releases directory name under the destination root. Defaults to `\".releases\"`. */\n releasesDirectory?: string;\n /** Number of releases to retain after the new release, including the new one. Defaults to `3`. */\n retain?: number;\n /** Existing release directory paths under the releases root that may be pruned. */\n existingReleases?: string[];\n /** Whether the plan is informational only. Defaults to `true`. */\n dryRun?: boolean;\n /** Clock used for deterministic tests. Defaults to `new Date()`. */\n now?: () => Date;\n /** Caller-defined metadata retained for diagnostics. */\n metadata?: Record<string, unknown>;\n}\n\nconst DEFAULT_RELEASES_DIRECTORY = \".releases\";\nconst DEFAULT_RETAIN = 3;\n\n/**\n * Builds an {@link AtomicDeployPlan} that stages a release, swaps it live, and prunes old releases.\n *\n * The plan describes a blue/green-style deploy:\n * 1. Upload to a timestamped staging directory under `<destination>/.releases/`.\n * 2. Atomically swap the `current` symlink/rename to point at the new release.\n * 3. Optionally prune old releases beyond `retain`.\n *\n * No I/O is performed - the host executes the plan steps. Pair with\n * {@link createTransferPlan} or {@link createTransferJobsFromPlan} to execute.\n *\n * @param options - Inputs and policies that shape the deploy.\n * @returns Structured deploy plan ready for execution by the calling host.\n * @throws {@link ConfigurationError} When `retain` is less than `1` or the destination root is empty.\n *\n * @example Plan a release with rollback path\n * ```ts\n * import { createAtomicDeployPlan } from \"@zero-transfer/sdk\";\n *\n * const plan = createAtomicDeployPlan({\n * id: \"web-2026-04-28\",\n * source: { rootPath: \"./dist\" },\n * destination: {\n * profile: { host: \"web1.example.com\", provider: \"sftp\", username: \"deploy\" },\n * rootPath: \"/srv/www\",\n * },\n * retain: 5,\n * existingReleases: [\n * \"/srv/www/.releases/2026-04-21T00-00-00Z\",\n * \"/srv/www/.releases/2026-04-14T00-00-00Z\",\n * ],\n * });\n *\n * console.log(plan.swap); // staging → current rename\n * console.log(plan.prune); // releases scheduled for removal\n * ```\n */\nexport function createAtomicDeployPlan(options: CreateAtomicDeployPlanOptions): AtomicDeployPlan {\n const retain = options.retain ?? DEFAULT_RETAIN;\n if (retain < 1) {\n throw new ConfigurationError({\n details: { retain },\n message: \"Atomic deploy retain count must be at least 1\",\n retryable: false,\n });\n }\n\n const livePath = normalizeRemotePath(options.destination.rootPath);\n if (livePath === \"/\") {\n throw new ConfigurationError({\n message: \"Atomic deploy destination rootPath must not be the filesystem root\",\n retryable: false,\n });\n }\n\n const strategy: AtomicDeployStrategy = options.strategy ?? \"rename\";\n const now = options.now?.() ?? new Date();\n const releaseId = options.releaseId ?? defaultReleaseId(now);\n const releasesRoot = joinRemotePath(\n livePath,\n options.releasesDirectory ?? DEFAULT_RELEASES_DIRECTORY,\n );\n const stagingPath = joinRemotePath(releasesRoot, releaseId);\n const backupPath =\n strategy === \"rename\" ? joinRemotePath(releasesRoot, `${releaseId}.previous`) : undefined;\n const provider = options.destination.provider ?? options.source.provider;\n const warnings: string[] = [];\n\n const uploadPlan = createSyncPlan({\n conflictPolicy: \"overwrite\",\n deletePolicy: \"never\",\n destination: {\n ...(options.destination.provider !== undefined\n ? { provider: options.destination.provider }\n : {}),\n rootPath: stagingPath,\n },\n diff: options.diff,\n direction: \"source-to-destination\",\n dryRun: options.dryRun ?? true,\n id: `${options.id}/upload`,\n includeDirectoryActions: false,\n ...(options.now !== undefined ? { now: options.now } : {}),\n source: options.source,\n });\n\n const activate = buildActivateSteps({\n backupPath,\n livePath,\n planId: options.id,\n provider,\n stagingPath,\n strategy,\n });\n\n const prune = buildPruneSteps({\n existingReleases: options.existingReleases ?? [],\n planId: options.id,\n provider,\n releaseId,\n releasesRoot,\n retain,\n });\n\n const plan: AtomicDeployPlan = {\n activate,\n createdAt: now,\n id: options.id,\n livePath,\n prune,\n releaseId,\n releasesRoot,\n retain,\n stagingPath,\n strategy,\n uploadPlan,\n warnings,\n };\n if (provider !== undefined) plan.provider = provider;\n if (backupPath !== undefined) plan.backupPath = backupPath;\n if (options.metadata !== undefined) plan.metadata = { ...options.metadata };\n return plan;\n}\n\ninterface BuildActivateContext {\n backupPath: string | undefined;\n livePath: string;\n planId: string;\n provider: ProviderId | undefined;\n stagingPath: string;\n strategy: AtomicDeployStrategy;\n}\n\nfunction buildActivateSteps(context: BuildActivateContext): AtomicDeployActivateStep[] {\n if (context.strategy === \"symlink\") {\n const step: AtomicDeployActivateStep = {\n destructive: true,\n fromPath: context.stagingPath,\n id: `${context.planId}/activate/symlink`,\n operation: \"symlink\",\n reason: \"Update live symlink to point at the new release\",\n toPath: context.livePath,\n };\n if (context.provider !== undefined) step.provider = context.provider;\n return [step];\n }\n\n const steps: AtomicDeployActivateStep[] = [];\n if (context.backupPath !== undefined) {\n const backup: AtomicDeployActivateStep = {\n destructive: true,\n fromPath: context.livePath,\n id: `${context.planId}/activate/backup`,\n operation: \"rename\",\n reason: \"Rename current live path aside as a release backup\",\n toPath: context.backupPath,\n };\n if (context.provider !== undefined) backup.provider = context.provider;\n steps.push(backup);\n }\n\n const promote: AtomicDeployActivateStep = {\n destructive: true,\n fromPath: context.stagingPath,\n id: `${context.planId}/activate/promote`,\n operation: \"rename\",\n reason: \"Promote the staged release to the live path\",\n toPath: context.livePath,\n };\n if (context.provider !== undefined) promote.provider = context.provider;\n steps.push(promote);\n return steps;\n}\n\ninterface BuildPruneContext {\n existingReleases: string[];\n planId: string;\n provider: ProviderId | undefined;\n releaseId: string;\n releasesRoot: string;\n retain: number;\n}\n\nfunction buildPruneSteps(context: BuildPruneContext): AtomicDeployPruneStep[] {\n if (context.existingReleases.length === 0) return [];\n\n const normalizedRoot = normalizeRemotePath(context.releasesRoot);\n const newReleasePath = joinRemotePath(normalizedRoot, context.releaseId);\n const candidates = [...new Set(context.existingReleases.map((path) => normalizeRemotePath(path)))]\n .filter((path) => path !== newReleasePath)\n .sort();\n\n const releasesToRetain = Math.max(0, context.retain - 1);\n if (candidates.length <= releasesToRetain) return [];\n\n const toPrune = candidates.slice(0, candidates.length - releasesToRetain);\n return toPrune.map((path, index) => {\n const step: AtomicDeployPruneStep = {\n id: `${context.planId}/prune/${index}`,\n path,\n reason: \"Older release exceeds retain window\",\n };\n if (context.provider !== undefined) step.provider = context.provider;\n return step;\n });\n}\n\nfunction defaultReleaseId(now: Date): string {\n // ISO timestamp with characters safe for filesystem path segments (no `:` or `.`).\n return now.toISOString().replace(/[:.]/g, \"-\");\n}\n","/**\n * Recursive remote-tree traversal helpers.\n *\n * @module sync/walkRemoteTree\n */\nimport { AbortError } from \"../errors/ZeroTransferError\";\nimport type { RemoteFileSystem } from \"../providers/RemoteFileSystem\";\nimport type { RemoteEntry } from \"../types/public\";\nimport { joinRemotePath, normalizeRemotePath } from \"../utils/path\";\n\n/** Filter callback applied to each visited entry. Returning `false` skips the entry. */\nexport type RemoteTreeFilter = (entry: RemoteEntry) => boolean;\n\n/** Options accepted by {@link walkRemoteTree}. */\nexport interface WalkRemoteTreeOptions {\n /** Whether to descend into subdirectories. Defaults to `true`. */\n recursive?: boolean;\n /** Maximum traversal depth. `0` walks only the root listing. Unbounded by default. */\n maxDepth?: number;\n /** Whether to include directory entries in the output. Defaults to `true`. */\n includeDirectories?: boolean;\n /** Whether to include file entries in the output. Defaults to `true`. */\n includeFiles?: boolean;\n /** Whether to follow symlinks during traversal. Defaults to `false`. */\n followSymlinks?: boolean;\n /** Optional filter applied before yielding and before descending into directories. */\n filter?: RemoteTreeFilter;\n /** Optional abort signal that interrupts traversal between listings. */\n signal?: AbortSignal;\n}\n\n/** Walk record yielded by {@link walkRemoteTree}. */\nexport interface RemoteTreeEntry {\n /** Visited remote entry. */\n entry: RemoteEntry;\n /** Zero-based depth relative to the traversal root. */\n depth: number;\n /** Normalized parent directory path. */\n parentPath: string;\n}\n\n/**\n * Walks a remote file system depth-first, yielding entries in a stable order.\n *\n * Listings are sorted by entry path within each directory so output is deterministic\n * across providers. Errors thrown by `fs.list()` propagate; callers can supply a\n * filter to skip directories that should not be traversed.\n *\n * @param fs - Remote file system used for listings.\n * @param rootPath - Root directory to walk.\n * @param options - Optional traversal controls.\n * @returns Async generator emitting {@link RemoteTreeEntry} records.\n * @throws {@link AbortError} When the supplied abort signal is cancelled mid-walk.\n */\nexport async function* walkRemoteTree(\n fs: RemoteFileSystem,\n rootPath: string,\n options: WalkRemoteTreeOptions = {},\n): AsyncGenerator<RemoteTreeEntry> {\n const recursive = options.recursive ?? true;\n const includeDirectories = options.includeDirectories ?? true;\n const includeFiles = options.includeFiles ?? true;\n const followSymlinks = options.followSymlinks ?? false;\n const root = normalizeRemotePath(rootPath);\n const normalized: NormalizedWalkOptions = {\n followSymlinks,\n includeDirectories,\n includeFiles,\n recursive,\n };\n if (options.maxDepth !== undefined) normalized.maxDepth = options.maxDepth;\n if (options.filter !== undefined) normalized.filter = options.filter;\n if (options.signal !== undefined) normalized.signal = options.signal;\n\n yield* walkDirectory(fs, root, 0, normalized);\n}\n\ninterface NormalizedWalkOptions {\n recursive: boolean;\n includeDirectories: boolean;\n includeFiles: boolean;\n followSymlinks: boolean;\n maxDepth?: number;\n filter?: RemoteTreeFilter;\n signal?: AbortSignal;\n}\n\nasync function* walkDirectory(\n fs: RemoteFileSystem,\n path: string,\n depth: number,\n options: NormalizedWalkOptions,\n): AsyncGenerator<RemoteTreeEntry> {\n throwIfAborted(options.signal);\n const entries = await fs.list(path);\n const sorted = [...entries].sort(compareEntries);\n\n for (const entry of sorted) {\n if (options.filter !== undefined && !options.filter(entry)) continue;\n\n if (matchesEntryKind(entry, options.includeDirectories, options.includeFiles)) {\n yield { depth, entry, parentPath: path };\n }\n\n if (\n options.recursive &&\n canDescendInto(entry, options.followSymlinks) &&\n (options.maxDepth === undefined || depth < options.maxDepth)\n ) {\n yield* walkDirectory(fs, ensureDescendPath(entry, path), depth + 1, options);\n }\n }\n}\n\nfunction matchesEntryKind(\n entry: RemoteEntry,\n includeDirectories: boolean,\n includeFiles: boolean,\n): boolean {\n if (entry.type === \"directory\") return includeDirectories;\n if (entry.type === \"file\") return includeFiles;\n return true;\n}\n\nfunction canDescendInto(entry: RemoteEntry, followSymlinks: boolean): boolean {\n if (entry.type === \"directory\") return true;\n return followSymlinks && entry.type === \"symlink\";\n}\n\nfunction ensureDescendPath(entry: RemoteEntry, parentPath: string): string {\n if (entry.path !== \"\" && entry.path !== entry.name) {\n return normalizeRemotePath(entry.path);\n }\n\n return joinRemotePath(parentPath, entry.name);\n}\n\nfunction compareEntries(left: RemoteEntry, right: RemoteEntry): number {\n if (left.path < right.path) return -1;\n if (left.path > right.path) return 1;\n return 0;\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted === true) {\n throw new AbortError({\n message: \"Remote tree walk aborted\",\n retryable: false,\n });\n }\n}\n","/**\n * Directory diffing primitives that compare two remote trees.\n *\n * @module sync/diffRemoteTrees\n */\nimport type { RemoteFileSystem } from \"../providers/RemoteFileSystem\";\nimport type { RemoteEntry } from \"../types/public\";\nimport { normalizeRemotePath } from \"../utils/path\";\nimport {\n walkRemoteTree,\n type RemoteTreeFilter,\n type WalkRemoteTreeOptions,\n} from \"./walkRemoteTree\";\n\n/** Outcome category for an entry across the two compared trees. */\nexport type RemoteTreeDiffStatus = \"added\" | \"removed\" | \"modified\" | \"unchanged\";\n\n/** Reason an entry is considered modified. */\nexport type RemoteTreeDiffReason = \"type\" | \"size\" | \"modifiedAt\" | \"checksum\";\n\n/** Single diff record produced by {@link diffRemoteTrees}. */\nexport interface RemoteTreeDiffEntry {\n /** Path relative to the traversal root, beginning with `/`. */\n path: string;\n /** Outcome category for this entry. */\n status: RemoteTreeDiffStatus;\n /** Reasons the entry is considered modified. Empty for unchanged/added/removed records. */\n reasons: RemoteTreeDiffReason[];\n /** Source-side entry, when present. */\n source?: RemoteEntry;\n /** Destination-side entry, when present. */\n destination?: RemoteEntry;\n}\n\n/** Compact summary of a diff result. */\nexport interface RemoteTreeDiffSummary {\n /** Number of entries present only on the source side. */\n added: number;\n /** Number of entries present only on the destination side. */\n removed: number;\n /** Number of entries present on both sides whose contents differ. */\n modified: number;\n /** Number of entries present on both sides with identical contents. */\n unchanged: number;\n /** Total entries inspected across both sides. */\n total: number;\n}\n\n/** Result returned by {@link diffRemoteTrees}. */\nexport interface RemoteTreeDiff {\n /** Diff records sorted by path. */\n entries: RemoteTreeDiffEntry[];\n /** Compact counts for the diff. */\n summary: RemoteTreeDiffSummary;\n}\n\n/** Options accepted by {@link diffRemoteTrees}. */\nexport interface DiffRemoteTreesOptions {\n /** Optional traversal controls applied to both sides. */\n walk?: Pick<\n WalkRemoteTreeOptions,\n \"filter\" | \"followSymlinks\" | \"includeDirectories\" | \"includeFiles\" | \"maxDepth\" | \"recursive\"\n >;\n /** Filter applied only to the source side. Overrides `walk.filter` when set. */\n sourceFilter?: RemoteTreeFilter;\n /** Filter applied only to the destination side. Overrides `walk.filter` when set. */\n destinationFilter?: RemoteTreeFilter;\n /** Whether unchanged entries are included in `entries`. Defaults to `false`. */\n includeUnchanged?: boolean;\n /** Tolerance in milliseconds when comparing modification timestamps. Defaults to `1000`. */\n modifiedAtToleranceMs?: number;\n /** Whether modification timestamps participate in the comparison. Defaults to `true`. */\n compareModifiedAt?: boolean;\n /** Whether sizes participate in the comparison. Defaults to `true`. */\n compareSize?: boolean;\n /** Whether to require matching `uniqueId` checksums when both entries expose one. Defaults to `false`. */\n compareUniqueId?: boolean;\n /** Optional abort signal threaded through both walks. */\n signal?: AbortSignal;\n}\n\n/**\n * Compares two remote subtrees and produces an entry-level diff.\n *\n * Source and destination paths are walked independently; entries are then aligned by\n * the relative path from each tree root. Directory equality is structural - directories\n * are equal when their relative paths match and the entry types agree.\n *\n * @param source - Source-side remote file system.\n * @param sourcePath - Source-side root path being compared.\n * @param destination - Destination-side remote file system.\n * @param destinationPath - Destination-side root path being compared.\n * @param options - Optional comparison controls.\n * @returns Diff result containing entries and a summary.\n *\n * @example Diff two SFTP subtrees and feed the result into createSyncPlan\n * ```ts\n * import { createSyncPlan, diffRemoteTrees } from \"@zero-transfer/sdk\";\n *\n * const diff = await diffRemoteTrees(\n * srcSession.fs, \"/exports\",\n * dstSession.fs, \"/exports\",\n * { compareUniqueId: true },\n * );\n *\n * console.log(diff.summary); // { added, removed, changed, unchanged }\n *\n * const plan = createSyncPlan({\n * id: \"exports-sync\",\n * diff,\n * source: { provider: \"sftp\", rootPath: \"/exports\" },\n * destination: { provider: \"sftp\", rootPath: \"/exports\" },\n * });\n * ```\n */\nexport async function diffRemoteTrees(\n source: RemoteFileSystem,\n sourcePath: string,\n destination: RemoteFileSystem,\n destinationPath: string,\n options: DiffRemoteTreesOptions = {},\n): Promise<RemoteTreeDiff> {\n const includeUnchanged = options.includeUnchanged ?? false;\n const sourceRoot = normalizeRemotePath(sourcePath);\n const destinationRoot = normalizeRemotePath(destinationPath);\n const sourceWalk = createWalkOptions(options, options.sourceFilter);\n const destinationWalk = createWalkOptions(options, options.destinationFilter);\n\n const [sourceEntries, destinationEntries] = await Promise.all([\n collectEntries(source, sourceRoot, sourceWalk),\n collectEntries(destination, destinationRoot, destinationWalk),\n ]);\n\n const aligned = alignEntries(sourceEntries, destinationEntries);\n const entries: RemoteTreeDiffEntry[] = [];\n const summary: RemoteTreeDiffSummary = {\n added: 0,\n modified: 0,\n removed: 0,\n total: 0,\n unchanged: 0,\n };\n\n for (const { path, source: sourceEntry, destination: destinationEntry } of aligned) {\n summary.total += 1;\n const reasons: RemoteTreeDiffReason[] = [];\n let status: RemoteTreeDiffStatus;\n\n if (sourceEntry !== undefined && destinationEntry === undefined) {\n status = \"added\";\n summary.added += 1;\n } else if (sourceEntry === undefined && destinationEntry !== undefined) {\n status = \"removed\";\n summary.removed += 1;\n } else if (sourceEntry !== undefined && destinationEntry !== undefined) {\n const computedReasons = compareEntries(sourceEntry, destinationEntry, options);\n\n if (computedReasons.length === 0) {\n status = \"unchanged\";\n summary.unchanged += 1;\n } else {\n status = \"modified\";\n reasons.push(...computedReasons);\n summary.modified += 1;\n }\n } else {\n // Both entries undefined cannot happen because alignEntries only emits aligned pairs.\n continue;\n }\n\n if (status === \"unchanged\" && !includeUnchanged) continue;\n\n const record: RemoteTreeDiffEntry = { path, reasons, status };\n if (sourceEntry !== undefined) record.source = sourceEntry;\n if (destinationEntry !== undefined) record.destination = destinationEntry;\n entries.push(record);\n }\n\n entries.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));\n\n return { entries, summary };\n}\n\nfunction createWalkOptions(\n options: DiffRemoteTreesOptions,\n filter: RemoteTreeFilter | undefined,\n): WalkRemoteTreeOptions {\n const walk = options.walk ?? {};\n const merged: WalkRemoteTreeOptions = {};\n\n if (walk.recursive !== undefined) merged.recursive = walk.recursive;\n if (walk.maxDepth !== undefined) merged.maxDepth = walk.maxDepth;\n if (walk.includeDirectories !== undefined) merged.includeDirectories = walk.includeDirectories;\n if (walk.includeFiles !== undefined) merged.includeFiles = walk.includeFiles;\n if (walk.followSymlinks !== undefined) merged.followSymlinks = walk.followSymlinks;\n const resolvedFilter = filter ?? walk.filter;\n if (resolvedFilter !== undefined) merged.filter = resolvedFilter;\n if (options.signal !== undefined) merged.signal = options.signal;\n\n return merged;\n}\n\ninterface CollectedEntry {\n relativePath: string;\n entry: RemoteEntry;\n}\n\nasync function collectEntries(\n fs: RemoteFileSystem,\n rootPath: string,\n walkOptions: WalkRemoteTreeOptions,\n): Promise<Map<string, RemoteEntry>> {\n const map = new Map<string, RemoteEntry>();\n\n for await (const record of walkRemoteTree(fs, rootPath, walkOptions)) {\n const collected = toCollectedEntry(record.entry, rootPath);\n if (collected !== undefined) map.set(collected.relativePath, collected.entry);\n }\n\n return map;\n}\n\nfunction toCollectedEntry(entry: RemoteEntry, rootPath: string): CollectedEntry | undefined {\n const root = normalizeRemotePath(rootPath);\n const path = normalizeRemotePath(entry.path);\n\n if (path === root) return undefined;\n if (root === \"/\") return { entry, relativePath: path };\n if (path.startsWith(`${root}/`)) {\n return { entry, relativePath: path.slice(root.length) };\n }\n\n return undefined;\n}\n\ninterface AlignedPair {\n path: string;\n source?: RemoteEntry;\n destination?: RemoteEntry;\n}\n\nfunction alignEntries(\n sourceEntries: Map<string, RemoteEntry>,\n destinationEntries: Map<string, RemoteEntry>,\n): AlignedPair[] {\n const paths = new Set<string>([...sourceEntries.keys(), ...destinationEntries.keys()]);\n const aligned: AlignedPair[] = [];\n\n for (const path of paths) {\n const pair: AlignedPair = { path };\n const source = sourceEntries.get(path);\n const destination = destinationEntries.get(path);\n\n if (source !== undefined) pair.source = source;\n if (destination !== undefined) pair.destination = destination;\n aligned.push(pair);\n }\n\n return aligned;\n}\n\nfunction compareEntries(\n source: RemoteEntry,\n destination: RemoteEntry,\n options: DiffRemoteTreesOptions,\n): RemoteTreeDiffReason[] {\n const reasons: RemoteTreeDiffReason[] = [];\n const compareSize = options.compareSize ?? true;\n const compareModifiedAt = options.compareModifiedAt ?? true;\n const compareUniqueId = options.compareUniqueId ?? false;\n const tolerance = options.modifiedAtToleranceMs ?? 1000;\n\n if (source.type !== destination.type) {\n reasons.push(\"type\");\n }\n\n if (compareSize && isSizeRelevant(source, destination) && source.size !== destination.size) {\n reasons.push(\"size\");\n }\n\n if (compareModifiedAt && isModifiedAtDifferent(source, destination, tolerance)) {\n reasons.push(\"modifiedAt\");\n }\n\n if (\n compareUniqueId &&\n source.uniqueId !== undefined &&\n destination.uniqueId !== undefined &&\n source.uniqueId !== destination.uniqueId\n ) {\n reasons.push(\"checksum\");\n }\n\n return reasons;\n}\n\nfunction isSizeRelevant(source: RemoteEntry, destination: RemoteEntry): boolean {\n if (source.type !== \"file\" || destination.type !== \"file\") return false;\n return source.size !== undefined && destination.size !== undefined;\n}\n\nfunction isModifiedAtDifferent(\n source: RemoteEntry,\n destination: RemoteEntry,\n toleranceMs: number,\n): boolean {\n if (source.modifiedAt === undefined || destination.modifiedAt === undefined) return false;\n const delta = Math.abs(source.modifiedAt.getTime() - destination.modifiedAt.getTime());\n return delta > toleranceMs;\n}\n","/**\n * Remote manifest read/write/compare helpers.\n *\n * A manifest is a serializable snapshot of a remote subtree produced by walking\n * the live tree once and persisting the result. Manifests can be diffed against\n * each other to detect drift without re-listing both sides.\n *\n * @module sync/manifest\n */\nimport { ConfigurationError } from \"../errors/ZeroTransferError\";\nimport type { ProviderId } from \"../core/ProviderId\";\nimport type { RemoteFileSystem } from \"../providers/RemoteFileSystem\";\nimport type { RemoteEntry, RemoteEntryType } from \"../types/public\";\nimport { normalizeRemotePath } from \"../utils/path\";\nimport type {\n RemoteTreeDiff,\n RemoteTreeDiffEntry,\n RemoteTreeDiffReason,\n RemoteTreeDiffStatus,\n RemoteTreeDiffSummary,\n} from \"./diffRemoteTrees\";\nimport {\n walkRemoteTree,\n type RemoteTreeFilter,\n type WalkRemoteTreeOptions,\n} from \"./walkRemoteTree\";\n\n/** Schema version for the manifest payload. Bumped on incompatible format changes. */\nexport const REMOTE_MANIFEST_FORMAT_VERSION = 1;\n\n/** Manifest entry recorded for each visited remote node. */\nexport interface RemoteManifestEntry {\n /** Path relative to {@link RemoteManifest.root}, beginning with `/`. */\n path: string;\n /** Entry kind. */\n type: RemoteEntryType;\n /** Entry size in bytes when known. */\n size?: number;\n /** Last modification time as an ISO 8601 timestamp when known. */\n modifiedAt?: string;\n /** Protocol-specific stable identity when available. */\n uniqueId?: string;\n /** Target path for symbolic links when known. */\n symlinkTarget?: string;\n}\n\n/** Persisted snapshot of a remote subtree. */\nexport interface RemoteManifest {\n /** Schema version. Must equal {@link REMOTE_MANIFEST_FORMAT_VERSION}. */\n formatVersion: number;\n /** ISO 8601 timestamp recording when the manifest was generated. */\n generatedAt: string;\n /** Normalized absolute root path the manifest snapshot is anchored to. */\n root: string;\n /** Optional provider identifier the snapshot was captured from. */\n provider?: ProviderId;\n /** Manifest entries sorted by path. */\n entries: RemoteManifestEntry[];\n}\n\n/** Options accepted by {@link createRemoteManifest}. */\nexport interface CreateRemoteManifestOptions {\n /** Optional traversal controls forwarded to {@link walkRemoteTree}. */\n walk?: Pick<\n WalkRemoteTreeOptions,\n \"filter\" | \"followSymlinks\" | \"includeDirectories\" | \"includeFiles\" | \"maxDepth\" | \"recursive\"\n >;\n /** Filter applied during traversal. Overrides `walk.filter` when provided. */\n filter?: RemoteTreeFilter;\n /** Provider identifier embedded into the manifest header. */\n provider?: ProviderId;\n /** Clock used to stamp `generatedAt`. Defaults to `Date.now`. */\n now?: () => Date;\n /** Optional abort signal threaded through the walk. */\n signal?: AbortSignal;\n}\n\n/** Options accepted by {@link compareRemoteManifests}. */\nexport interface CompareRemoteManifestsOptions {\n /** Whether unchanged entries are included in the result. Defaults to `false`. */\n includeUnchanged?: boolean;\n /** Tolerance in milliseconds applied to `modifiedAt` comparisons. Defaults to `1000`. */\n modifiedAtToleranceMs?: number;\n /** Whether modification timestamps participate in the comparison. Defaults to `true`. */\n compareModifiedAt?: boolean;\n /** Whether sizes participate in the comparison. Defaults to `true`. */\n compareSize?: boolean;\n /** Whether to require matching `uniqueId` checksums when both entries expose one. Defaults to `false`. */\n compareUniqueId?: boolean;\n}\n\n/**\n * Walks a remote subtree and produces a serializable manifest snapshot.\n *\n * @param fs - Remote file system to capture.\n * @param rootPath - Root path the manifest is anchored to.\n * @param options - Optional capture controls.\n * @returns Manifest snapshot suitable for serialization or comparison.\n */\nexport async function createRemoteManifest(\n fs: RemoteFileSystem,\n rootPath: string,\n options: CreateRemoteManifestOptions = {},\n): Promise<RemoteManifest> {\n const root = normalizeRemotePath(rootPath);\n const walkOptions: WalkRemoteTreeOptions = { ...(options.walk ?? {}) };\n const resolvedFilter = options.filter ?? options.walk?.filter;\n if (resolvedFilter !== undefined) walkOptions.filter = resolvedFilter;\n if (options.signal !== undefined) walkOptions.signal = options.signal;\n\n const entries: RemoteManifestEntry[] = [];\n\n for await (const record of walkRemoteTree(fs, root, walkOptions)) {\n const relativePath = relativeFromRoot(record.entry.path, root);\n if (relativePath === undefined) continue;\n entries.push(toManifestEntry(record.entry, relativePath));\n }\n\n entries.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));\n\n const generatedAt = (options.now?.() ?? new Date()).toISOString();\n const manifest: RemoteManifest = {\n entries,\n formatVersion: REMOTE_MANIFEST_FORMAT_VERSION,\n generatedAt,\n root,\n };\n if (options.provider !== undefined) manifest.provider = options.provider;\n return manifest;\n}\n\n/**\n * Serializes a manifest to a JSON string suitable for persistence.\n *\n * @param manifest - Manifest snapshot to serialize.\n * @param indent - Optional indentation passed to `JSON.stringify`. Defaults to `2`.\n * @returns Stable JSON representation of the manifest.\n */\nexport function serializeRemoteManifest(manifest: RemoteManifest, indent: number = 2): string {\n return JSON.stringify(manifest, undefined, indent);\n}\n\n/**\n * Parses a JSON-encoded manifest, validating the schema version and entry shape.\n *\n * @param text - JSON payload produced by {@link serializeRemoteManifest}.\n * @returns Parsed manifest snapshot.\n * @throws {@link ConfigurationError} When the payload is invalid or has an unsupported version.\n */\nexport function parseRemoteManifest(text: string): RemoteManifest {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n throw new ConfigurationError({\n cause: error,\n message: \"Failed to parse remote manifest payload as JSON\",\n retryable: false,\n });\n }\n\n if (parsed === null || typeof parsed !== \"object\") {\n throw new ConfigurationError({\n message: \"Remote manifest payload must be a JSON object\",\n retryable: false,\n });\n }\n\n const candidate = parsed as Partial<RemoteManifest> & Record<string, unknown>;\n if (candidate.formatVersion !== REMOTE_MANIFEST_FORMAT_VERSION) {\n throw new ConfigurationError({\n details: {\n expected: REMOTE_MANIFEST_FORMAT_VERSION,\n received: candidate.formatVersion,\n },\n message: `Unsupported remote manifest formatVersion: ${String(candidate.formatVersion)}`,\n retryable: false,\n });\n }\n\n if (typeof candidate.root !== \"string\" || candidate.root.length === 0) {\n throw new ConfigurationError({\n message: \"Remote manifest root must be a non-empty string\",\n retryable: false,\n });\n }\n\n if (typeof candidate.generatedAt !== \"string\") {\n throw new ConfigurationError({\n message: \"Remote manifest generatedAt must be an ISO timestamp string\",\n retryable: false,\n });\n }\n\n if (!Array.isArray(candidate.entries)) {\n throw new ConfigurationError({\n message: \"Remote manifest entries must be an array\",\n retryable: false,\n });\n }\n\n const entries = candidate.entries.map((entry, index) => normalizeManifestEntry(entry, index));\n const manifest: RemoteManifest = {\n entries,\n formatVersion: REMOTE_MANIFEST_FORMAT_VERSION,\n generatedAt: candidate.generatedAt,\n root: normalizeRemotePath(candidate.root),\n };\n if (typeof candidate.provider === \"string\") manifest.provider = candidate.provider;\n return manifest;\n}\n\n/**\n * Compares two manifests and produces an entry-level diff.\n *\n * The comparison is performed on the relative-path keys recorded inside each manifest;\n * the absolute roots may differ between snapshots (e.g. captured against `/site` on the\n * source and `/var/www/site` on the destination).\n *\n * @param source - Source-side manifest snapshot.\n * @param destination - Destination-side manifest snapshot.\n * @param options - Optional comparison controls.\n * @returns Diff result mirroring {@link RemoteTreeDiff}.\n */\nexport function compareRemoteManifests(\n source: RemoteManifest,\n destination: RemoteManifest,\n options: CompareRemoteManifestsOptions = {},\n): RemoteTreeDiff {\n const includeUnchanged = options.includeUnchanged ?? false;\n const sourceMap = indexEntries(source);\n const destinationMap = indexEntries(destination);\n const paths = new Set<string>([...sourceMap.keys(), ...destinationMap.keys()]);\n\n const entries: RemoteTreeDiffEntry[] = [];\n const summary: RemoteTreeDiffSummary = {\n added: 0,\n modified: 0,\n removed: 0,\n total: 0,\n unchanged: 0,\n };\n\n for (const path of paths) {\n summary.total += 1;\n const sourceEntry = sourceMap.get(path);\n const destinationEntry = destinationMap.get(path);\n const reasons: RemoteTreeDiffReason[] = [];\n let status: RemoteTreeDiffStatus;\n\n if (sourceEntry !== undefined && destinationEntry === undefined) {\n status = \"added\";\n summary.added += 1;\n } else if (sourceEntry === undefined && destinationEntry !== undefined) {\n status = \"removed\";\n summary.removed += 1;\n } else if (sourceEntry !== undefined && destinationEntry !== undefined) {\n const computed = compareManifestEntries(sourceEntry, destinationEntry, options);\n if (computed.length === 0) {\n status = \"unchanged\";\n summary.unchanged += 1;\n } else {\n status = \"modified\";\n reasons.push(...computed);\n summary.modified += 1;\n }\n } else {\n continue;\n }\n\n if (status === \"unchanged\" && !includeUnchanged) continue;\n\n const record: RemoteTreeDiffEntry = { path, reasons, status };\n if (sourceEntry !== undefined) {\n record.source = manifestEntryToRemote(sourceEntry, source.root);\n }\n if (destinationEntry !== undefined) {\n record.destination = manifestEntryToRemote(destinationEntry, destination.root);\n }\n entries.push(record);\n }\n\n entries.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));\n return { entries, summary };\n}\n\nfunction relativeFromRoot(entryPath: string, root: string): string | undefined {\n const path = normalizeRemotePath(entryPath);\n if (path === root) return undefined;\n if (root === \"/\") return path;\n if (path.startsWith(`${root}/`)) return path.slice(root.length);\n return undefined;\n}\n\nfunction toManifestEntry(entry: RemoteEntry, relativePath: string): RemoteManifestEntry {\n const manifestEntry: RemoteManifestEntry = {\n path: relativePath,\n type: entry.type,\n };\n if (entry.size !== undefined) manifestEntry.size = entry.size;\n if (entry.modifiedAt !== undefined) manifestEntry.modifiedAt = entry.modifiedAt.toISOString();\n if (entry.uniqueId !== undefined) manifestEntry.uniqueId = entry.uniqueId;\n if (entry.symlinkTarget !== undefined) manifestEntry.symlinkTarget = entry.symlinkTarget;\n return manifestEntry;\n}\n\nfunction normalizeManifestEntry(value: unknown, index: number): RemoteManifestEntry {\n if (value === null || typeof value !== \"object\") {\n throw new ConfigurationError({\n details: { index },\n message: `Remote manifest entry at index ${index} must be an object`,\n retryable: false,\n });\n }\n\n const candidate = value as Partial<RemoteManifestEntry> & Record<string, unknown>;\n if (typeof candidate.path !== \"string\" || candidate.path.length === 0) {\n throw new ConfigurationError({\n details: { index },\n message: `Remote manifest entry at index ${index} must have a non-empty path`,\n retryable: false,\n });\n }\n if (!isRemoteEntryType(candidate.type)) {\n throw new ConfigurationError({\n details: { index, received: candidate.type },\n message: `Remote manifest entry at index ${index} has an invalid type`,\n retryable: false,\n });\n }\n\n const entry: RemoteManifestEntry = {\n path: candidate.path,\n type: candidate.type,\n };\n if (typeof candidate.size === \"number\") entry.size = candidate.size;\n if (typeof candidate.modifiedAt === \"string\") entry.modifiedAt = candidate.modifiedAt;\n if (typeof candidate.uniqueId === \"string\") entry.uniqueId = candidate.uniqueId;\n if (typeof candidate.symlinkTarget === \"string\") entry.symlinkTarget = candidate.symlinkTarget;\n return entry;\n}\n\nfunction isRemoteEntryType(value: unknown): value is RemoteEntryType {\n return value === \"file\" || value === \"directory\" || value === \"symlink\" || value === \"unknown\";\n}\n\nfunction indexEntries(manifest: RemoteManifest): Map<string, RemoteManifestEntry> {\n const map = new Map<string, RemoteManifestEntry>();\n for (const entry of manifest.entries) map.set(entry.path, entry);\n return map;\n}\n\nfunction manifestEntryToRemote(entry: RemoteManifestEntry, root: string): RemoteEntry {\n const absolutePath = root === \"/\" ? entry.path : `${root}${entry.path}`;\n const remote: RemoteEntry = {\n name: deriveName(entry.path),\n path: absolutePath,\n type: entry.type,\n };\n if (entry.size !== undefined) remote.size = entry.size;\n if (entry.modifiedAt !== undefined) {\n const parsed = new Date(entry.modifiedAt);\n if (!Number.isNaN(parsed.getTime())) remote.modifiedAt = parsed;\n }\n if (entry.uniqueId !== undefined) remote.uniqueId = entry.uniqueId;\n if (entry.symlinkTarget !== undefined) remote.symlinkTarget = entry.symlinkTarget;\n return remote;\n}\n\nfunction deriveName(path: string): string {\n const segments = path.split(\"/\").filter(Boolean);\n return segments.length === 0 ? \"/\" : (segments[segments.length - 1] ?? \"/\");\n}\n\nfunction compareManifestEntries(\n source: RemoteManifestEntry,\n destination: RemoteManifestEntry,\n options: CompareRemoteManifestsOptions,\n): RemoteTreeDiffReason[] {\n const reasons: RemoteTreeDiffReason[] = [];\n const compareSize = options.compareSize ?? true;\n const compareModifiedAt = options.compareModifiedAt ?? true;\n const compareUniqueId = options.compareUniqueId ?? false;\n const tolerance = options.modifiedAtToleranceMs ?? 1000;\n\n if (source.type !== destination.type) reasons.push(\"type\");\n\n if (\n compareSize &&\n source.type === \"file\" &&\n destination.type === \"file\" &&\n source.size !== undefined &&\n destination.size !== undefined &&\n source.size !== destination.size\n ) {\n reasons.push(\"size\");\n }\n\n if (compareModifiedAt && isModifiedAtDifferent(source, destination, tolerance)) {\n reasons.push(\"modifiedAt\");\n }\n\n if (\n compareUniqueId &&\n source.uniqueId !== undefined &&\n destination.uniqueId !== undefined &&\n source.uniqueId !== destination.uniqueId\n ) {\n reasons.push(\"checksum\");\n }\n\n return reasons;\n}\n\nfunction isModifiedAtDifferent(\n source: RemoteManifestEntry,\n destination: RemoteManifestEntry,\n toleranceMs: number,\n): boolean {\n if (source.modifiedAt === undefined || destination.modifiedAt === undefined) return false;\n const sourceTime = Date.parse(source.modifiedAt);\n const destinationTime = Date.parse(destination.modifiedAt);\n if (Number.isNaN(sourceTime) || Number.isNaN(destinationTime)) return false;\n return Math.abs(sourceTime - destinationTime) > toleranceMs;\n}\n","/**\n * @file `isMainModule` - small helper for the rare case a script needs to\n * branch on whether it is the process entry point.\n *\n * Most code does not need this. Examples and CLIs should just put their work\n * at the top level of an ES module - top-level `await` is allowed, and any\n * thrown error propagates up so Node prints it and exits non-zero. No guard,\n * no wrapper, no `import.meta.url` plumbing required.\n *\n * If you do need the boolean (e.g. a file that is both a library and a CLI),\n * call `isMainModule(import.meta.url)`.\n */\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Returns `true` when the file containing `import.meta.url` is the entry point\n * of the current Node.js process. Returns `false` outside Node.\n */\nexport function isMainModule(importMetaUrl: string): boolean {\n if (typeof process === \"undefined\" || !process.argv || process.argv.length < 2) {\n return false;\n }\n try {\n return process.argv[1] === fileURLToPath(importMetaUrl);\n } catch {\n return false;\n }\n}\n","import { Buffer } from \"node:buffer\";\nimport type { Socket } from \"node:net\";\nimport { ConnectionError, ProtocolError, TimeoutError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader } from \"../binary/SshDataReader\";\nimport { SshDataWriter } from \"../binary/SshDataWriter\";\nimport type { SshAlgorithmPreferences } from \"./SshAlgorithmNegotiation\";\nimport { SshTransportHandshake, type SshTransportHandshakeResult } from \"./SshTransportHandshake\";\nimport type {\n SshTransportPacketProtector,\n SshTransportPacketUnprotector,\n} from \"./SshTransportProtection\";\nimport { createSshTransportProtectionContext } from \"./SshTransportProtection\";\n\n/** Standard SSH disconnect reason codes (RFC 4253 §11.1). */\nexport const SshDisconnectReason = {\n HOST_NOT_ALLOWED_TO_CONNECT: 1,\n PROTOCOL_ERROR: 2,\n KEY_EXCHANGE_FAILED: 3,\n MAC_ERROR: 5,\n COMPRESSION_ERROR: 6,\n SERVICE_NOT_AVAILABLE: 7,\n PROTOCOL_VERSION_NOT_SUPPORTED: 8,\n HOST_KEY_NOT_VERIFIABLE: 9,\n CONNECTION_LOST: 10,\n BY_APPLICATION: 11,\n TOO_MANY_CONNECTIONS: 12,\n AUTH_CANCELLED_BY_USER: 13,\n NO_MORE_AUTH_METHODS: 14,\n ILLEGAL_USER_NAME: 15,\n} as const;\n\nexport type SshDisconnectReason = (typeof SshDisconnectReason)[keyof typeof SshDisconnectReason];\n\nconst MSG_DISCONNECT = 1;\nconst MSG_IGNORE = 2;\nconst MSG_DEBUG = 4;\n\nexport interface SshTransportConnectionOptions {\n /** AbortSignal that cancels the in-flight `connect()` call and tears down the socket. */\n abortSignal?: AbortSignal;\n /** Algorithm preference overrides. Defaults to the library defaults. */\n algorithms?: SshAlgorithmPreferences;\n /** SSH software version string embedded in the identification line. */\n clientSoftwareVersion?: string;\n /**\n * Hard cap (milliseconds) on the SSH identification + key exchange + first\n * NEWKEYS handshake. If exceeded the socket is destroyed and `connect()`\n * rejects with a `TimeoutError`. Has no effect once `connect()` resolves.\n */\n handshakeTimeoutMs?: number;\n /**\n * If set, sends a `SSH_MSG_IGNORE` packet every `keepaliveIntervalMs`\n * milliseconds while the transport is connected and idle. This prevents\n * stateful NAT / firewall devices from dropping long-lived idle sessions\n * (e.g. between batches in a transfer queue). The timer is reset on every\n * outbound payload, so active transfers do not generate extra traffic.\n */\n keepaliveIntervalMs?: number;\n /**\n * Synchronous host-key policy hook invoked after the signature on the SSH\n * exchange hash is verified. Throw to reject the server's identity.\n */\n verifyHostKey?: (input: {\n hostKeyBlob: Buffer;\n hostKeySha256: Buffer;\n algorithmName: string;\n }) => void;\n}\n\ntype InboundQueueEntry =\n | { type: \"payload\"; payload: Buffer }\n | { type: \"error\"; error: Error }\n | { type: \"end\" };\n\n/**\n * Live SSH transport connection over a TCP socket.\n *\n * Runs the SSH identification exchange and key exchange handshake on the supplied socket,\n * then provides an encrypted packet send/receive interface for higher-level SSH layers\n * (authentication, connection, SFTP subsystem).\n *\n * Usage:\n * ```ts\n * const conn = new SshTransportConnection();\n * const result = await conn.connect(socket); // runs handshake\n * conn.sendPayload(payload); // post-NEWKEYS send\n * for await (const payload of conn.receivePayloads()) { ... }\n * conn.disconnect();\n * ```\n */\nexport class SshTransportConnection {\n private connected = false;\n private disposed = false;\n private protector: SshTransportPacketProtector | undefined;\n private unprotector: SshTransportPacketUnprotector | undefined;\n private socket: Socket | undefined;\n private keepaliveTimer: ReturnType<typeof setInterval> | undefined;\n\n private readonly inboundQueue: InboundQueueEntry[] = [];\n /**\n * FIFO of waiters when the queue is empty. Multiple iterators may suspend on\n * the same transport (auth session, channel setup, connection-manager pump);\n * each receives exactly one entry in arrival order. A single-slot field would\n * lose wakeups when a second consumer suspends before the first is resolved.\n */\n private readonly waitingConsumers: Array<(entry: InboundQueueEntry) => void> = [];\n\n constructor(private readonly options: SshTransportConnectionOptions = {}) {}\n\n /**\n * Runs the SSH handshake on a TCP-connected socket.\n * Resolves when NEWKEYS completes and the transport is ready for encrypted messages.\n * Rejects on socket error, abort, or protocol failure.\n */\n connect(socket: Socket): Promise<SshTransportHandshakeResult> {\n if (this.connected || this.socket !== undefined) {\n throw new ProtocolError({\n message: \"SshTransportConnection.connect() called more than once\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n this.socket = socket;\n\n const handshake = new SshTransportHandshake({\n ...(this.options.algorithms === undefined ? {} : { algorithms: this.options.algorithms }),\n ...(this.options.clientSoftwareVersion === undefined\n ? {}\n : { clientSoftwareVersion: this.options.clientSoftwareVersion }),\n ...(this.options.verifyHostKey === undefined\n ? {}\n : { verifyHostKey: this.options.verifyHostKey }),\n });\n\n return new Promise<SshTransportHandshakeResult>((resolve, reject) => {\n const { abortSignal, handshakeTimeoutMs } = this.options;\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n\n // Declare all handlers before any early-return path so const bindings are\n // never in the temporal dead zone when cleanup() is called.\n const onError = (err: Error): void => {\n cleanup();\n reject(\n new ConnectionError({\n message: `SSH socket error during handshake: ${err.message}`,\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n };\n\n const onClose = (): void => {\n cleanup();\n reject(\n new ConnectionError({\n message: \"SSH socket closed before handshake completed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n };\n\n const onAbort = (): void => {\n cleanup();\n socket.destroy();\n reject(\n new ConnectionError({\n message: \"SSH connection aborted before handshake completed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n };\n\n const onTimeout = (): void => {\n cleanup();\n socket.destroy();\n reject(\n new TimeoutError({\n details: { handshakeTimeoutMs },\n message: `SSH handshake did not complete within ${handshakeTimeoutMs}ms`,\n protocol: \"sftp\",\n retryable: true,\n }),\n );\n };\n\n function cleanup(): void {\n if (timeoutHandle !== undefined) {\n clearTimeout(timeoutHandle);\n timeoutHandle = undefined;\n }\n abortSignal?.removeEventListener(\"abort\", onAbort);\n socket.off(\"error\", onError);\n socket.off(\"close\", onClose);\n }\n\n // If the signal is already aborted, reject immediately before registering\n // any listeners (nothing to clean up yet in that case).\n if (abortSignal?.aborted) {\n socket.destroy();\n reject(\n new ConnectionError({\n message: \"SSH connection aborted before handshake completed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n return;\n }\n\n abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n socket.on(\"error\", onError);\n socket.on(\"close\", onClose);\n\n if (handshakeTimeoutMs !== undefined && handshakeTimeoutMs > 0) {\n timeoutHandle = setTimeout(onTimeout, handshakeTimeoutMs);\n }\n\n const handshakeDataHandler = (chunk: Buffer): void => {\n let handshakeResult: SshTransportHandshakeResult | undefined;\n try {\n const { outbound, result } = handshake.pushServerBytes(chunk);\n for (const outbuf of outbound) {\n socket.write(outbuf);\n }\n handshakeResult = result;\n } catch (err) {\n cleanup();\n socket.off(\"data\", handshakeDataHandler);\n socket.destroy();\n reject(\n err instanceof Error\n ? err\n : new ProtocolError({\n message: \"SSH handshake failed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n return;\n }\n\n if (handshakeResult !== undefined) {\n cleanup();\n socket.off(\"data\", handshakeDataHandler);\n\n let protection;\n try {\n protection = createSshTransportProtectionContext({\n keys: {\n clientToServer: handshakeResult.keyExchange.transportKeys.clientToServer,\n serverToClient: handshakeResult.keyExchange.transportKeys.serverToClient,\n },\n negotiatedAlgorithms: handshakeResult.negotiatedAlgorithms,\n // RFC 4253 §6.4: sequence numbers are never reset across NEWKEYS;\n // they continue counting from the unencrypted handshake packets.\n initialInboundSequence: handshakeResult.inboundPacketCount,\n initialOutboundSequence: handshakeResult.outboundPacketCount,\n });\n } catch (err) {\n socket.destroy();\n reject(\n err instanceof Error\n ? err\n : new ProtocolError({\n message: \"SSH transport protection context creation failed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n return;\n }\n\n this.protector = protection.outbound;\n this.unprotector = protection.inbound;\n this.connected = true;\n\n socket.on(\"data\", this.onEncryptedData.bind(this));\n socket.on(\"error\", this.onSocketError.bind(this));\n socket.on(\"close\", this.onSocketClose.bind(this));\n\n this.startKeepalive();\n\n // Feed any bytes that arrived after NEWKEYS in the same TCP segment.\n const leftover = handshake.takeRemainingBytes();\n if (leftover.length > 0) {\n this.onEncryptedData(leftover);\n }\n\n resolve(handshakeResult);\n }\n };\n\n // Send the initial client identification line, then listen for server bytes.\n socket.write(handshake.createInitialClientBytes());\n socket.on(\"data\", handshakeDataHandler);\n });\n }\n\n /**\n * Sends an SSH payload over the encrypted transport.\n * The payload must start with the SSH message type byte.\n */\n sendPayload(payload: Buffer | Uint8Array): void {\n this.assertConnected();\n const frame = this.protector!.protectPayload(Buffer.from(payload));\n this.socket!.write(frame);\n // Suppress an imminent keepalive ping after real outbound traffic.\n this.resetKeepaliveTimer();\n }\n\n /**\n * Async generator that yields inbound SSH payloads (post-NEWKEYS).\n *\n * Transparent handling:\n * - SSH_MSG_IGNORE (2) and SSH_MSG_DEBUG (4) are silently dropped.\n * - SSH_MSG_DISCONNECT (1) from the server throws a `ConnectionError`.\n * - Socket error or close terminates the generator.\n */\n async *receivePayloads(): AsyncGenerator<Buffer> {\n this.assertConnected();\n while (true) {\n const entry = await this.dequeuePayload();\n if (entry.type === \"end\") return;\n if (entry.type === \"error\") throw entry.error;\n yield entry.payload;\n }\n }\n\n /**\n * Sends SSH_MSG_DISCONNECT and ends the socket.\n * Safe to call multiple times; subsequent calls are no-ops.\n */\n disconnect(\n reason: SshDisconnectReason = SshDisconnectReason.BY_APPLICATION,\n description = \"\",\n ): void {\n if (this.disposed || this.socket === undefined) return;\n this.disposed = true;\n\n this.stopKeepalive();\n\n if (this.connected && this.protector !== undefined) {\n try {\n const payload = new SshDataWriter()\n .writeByte(MSG_DISCONNECT)\n .writeUint32(reason)\n .writeString(description, \"utf8\")\n .writeString(\"\", \"utf8\") // language tag (RFC 4253 §11.1)\n .toBuffer();\n this.socket.write(this.protector.protectPayload(payload));\n } catch {\n // best-effort: socket may already be closing\n }\n }\n\n this.socket.end();\n this.enqueueEntry({ type: \"end\" });\n }\n\n isConnected(): boolean {\n return this.connected && !this.disposed;\n }\n\n private onEncryptedData(chunk: Buffer): void {\n try {\n const payloads = this.unprotector!.pushBytes(chunk);\n for (const payload of payloads) {\n const msgType = payload[0];\n if (msgType === MSG_IGNORE || msgType === MSG_DEBUG) continue;\n if (msgType === MSG_DISCONNECT) {\n this.enqueueEntry({ type: \"error\", error: parseDisconnectPayload(payload) });\n this.socket?.destroy();\n return;\n }\n this.enqueueEntry({ type: \"payload\", payload });\n }\n } catch (err) {\n this.enqueueEntry({\n type: \"error\",\n error:\n err instanceof Error\n ? err\n : new ProtocolError({\n message: \"SSH encrypted data processing error\",\n protocol: \"sftp\",\n retryable: false,\n }),\n });\n this.socket?.destroy();\n }\n }\n\n private onSocketError(err: Error): void {\n this.stopKeepalive();\n if (!this.disposed) {\n this.enqueueEntry({\n type: \"error\",\n error: new ConnectionError({\n message: `SSH socket error: ${err.message}`,\n protocol: \"sftp\",\n retryable: false,\n }),\n });\n }\n }\n\n private onSocketClose(): void {\n this.stopKeepalive();\n if (!this.disposed) {\n this.enqueueEntry({ type: \"end\" });\n }\n }\n\n private enqueueEntry(entry: InboundQueueEntry): void {\n if (this.waitingConsumers.length > 0) {\n const resolve = this.waitingConsumers.shift()!;\n resolve(entry);\n } else {\n this.inboundQueue.push(entry);\n }\n }\n\n private dequeuePayload(): Promise<InboundQueueEntry> {\n if (this.inboundQueue.length > 0) {\n return Promise.resolve(this.inboundQueue.shift()!);\n }\n return new Promise((resolve) => {\n this.waitingConsumers.push(resolve);\n });\n }\n\n private assertConnected(): void {\n if (!this.connected) {\n throw new ProtocolError({\n message: \"SshTransportConnection is not yet connected - call connect() first\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n }\n\n private startKeepalive(): void {\n const intervalMs = this.options.keepaliveIntervalMs;\n if (intervalMs === undefined || intervalMs <= 0) return;\n this.keepaliveTimer = setInterval(() => this.sendKeepalivePing(), intervalMs);\n // Don't keep the Node event loop alive solely for keepalives - when the\n // process is otherwise idle the consumer should be free to exit.\n this.keepaliveTimer.unref?.();\n }\n\n private stopKeepalive(): void {\n if (this.keepaliveTimer !== undefined) {\n clearInterval(this.keepaliveTimer);\n this.keepaliveTimer = undefined;\n }\n }\n\n private resetKeepaliveTimer(): void {\n if (this.keepaliveTimer === undefined) return;\n this.stopKeepalive();\n this.startKeepalive();\n }\n\n private sendKeepalivePing(): void {\n if (!this.connected || this.disposed || this.protector === undefined) return;\n try {\n // SSH_MSG_IGNORE: a benign packet the server discards, sufficient to keep\n // stateful intermediaries (NAT, firewalls) from idling out the TCP flow.\n // Body is a single empty SSH string per RFC 4253 §11.2.\n const payload = new SshDataWriter().writeByte(MSG_IGNORE).writeString(\"\", \"utf8\").toBuffer();\n this.socket!.write(this.protector.protectPayload(payload));\n } catch {\n // Best-effort: a write failure here will surface via the socket error\n // handler; keepalive should never throw to the caller.\n }\n }\n}\n\nfunction parseDisconnectPayload(payload: Buffer): ConnectionError {\n try {\n const reader = new SshDataReader(payload.subarray(1)); // skip message type byte\n const reasonCode = reader.readUint32();\n const description = reader.readString().toString(\"utf8\");\n return new ConnectionError({\n details: { reasonCode },\n message: `SSH_MSG_DISCONNECT: ${description.length > 0 ? description : \"connection closed by server\"} (code ${reasonCode})`,\n protocol: \"sftp\",\n retryable: false,\n });\n } catch {\n return new ConnectionError({\n message: \"SSH_MSG_DISCONNECT received from server\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n","import { Buffer } from \"node:buffer\";\nimport { ParseError } from \"../../../errors/ZeroTransferError\";\n\n/**\n * Stateful SSH primitive decoder that reads sequential values from a packet payload.\n */\nexport class SshDataReader {\n private offset = 0;\n\n constructor(private readonly source: Uint8Array) {}\n\n get remaining(): number {\n return this.source.length - this.offset;\n }\n\n hasMore(): boolean {\n return this.remaining > 0;\n }\n\n readByte(): number {\n this.ensureAvailable(1, \"byte\");\n const value = this.source[this.offset]!;\n this.offset += 1;\n return value;\n }\n\n readBoolean(): boolean {\n return this.readByte() !== 0;\n }\n\n readBytes(length: number): Buffer {\n this.ensureAvailable(length, \"bytes\");\n const data = this.source.subarray(this.offset, this.offset + length);\n this.offset += length;\n return Buffer.from(data);\n }\n\n readUint32(): number {\n this.ensureAvailable(4, \"uint32\");\n const buffer = Buffer.from(this.source);\n const value = buffer.readUInt32BE(this.offset);\n this.offset += 4;\n return value;\n }\n\n readUint64(): bigint {\n this.ensureAvailable(8, \"uint64\");\n const buffer = Buffer.from(this.source);\n const value = buffer.readBigUInt64BE(this.offset);\n this.offset += 8;\n return value;\n }\n\n readString(): Buffer {\n const length = this.readUint32();\n this.ensureAvailable(length, \"string\");\n const data = this.source.subarray(this.offset, this.offset + length);\n this.offset += length;\n return Buffer.from(data);\n }\n\n readUtf8String(): string {\n return this.readString().toString(\"utf8\");\n }\n\n readNameList(): string[] {\n const value = this.readString().toString(\"ascii\");\n\n if (value.length === 0) {\n return [];\n }\n\n return value.split(\",\").filter((item) => item.length > 0);\n }\n\n /**\n * Reads an SSH `mpint` value (RFC 4251 §5): a length-prefixed two's-complement\n * big-endian integer. Returns the raw magnitude bytes (non-negative integers\n * may have a leading 0x00 byte preserved by the caller as needed).\n */\n readMpint(): Buffer {\n return this.readString();\n }\n\n assertFinished(): void {\n if (this.remaining !== 0) {\n throw new ParseError({\n details: { remaining: this.remaining },\n message: \"Unexpected trailing SSH packet bytes\",\n retryable: false,\n });\n }\n }\n\n private ensureAvailable(bytes: number, type: string): void {\n if (this.remaining >= bytes) {\n return;\n }\n\n throw new ParseError({\n details: {\n available: this.remaining,\n needed: bytes,\n },\n message: `Unexpected end of SSH packet while reading ${type}`,\n retryable: false,\n });\n }\n}\n","import { Buffer } from \"node:buffer\";\nimport { ConfigurationError } from \"../../../errors/ZeroTransferError\";\n\nconst MAX_UINT32 = 0xffff_ffff;\nconst MAX_UINT64 = (1n << 64n) - 1n;\n\n/**\n * Minimal SSH primitive encoder for transport and authentication packets.\n */\nexport class SshDataWriter {\n private readonly chunks: Buffer[] = [];\n private length = 0;\n\n writeByte(value: number): this {\n this.assertByte(value, \"byte\");\n const chunk = Buffer.alloc(1);\n chunk.writeUInt8(value, 0);\n return this.push(chunk);\n }\n\n writeBoolean(value: boolean): this {\n return this.writeByte(value ? 1 : 0);\n }\n\n writeBytes(value: Uint8Array): this {\n return this.push(Buffer.from(value));\n }\n\n writeUint32(value: number): this {\n if (!Number.isInteger(value) || value < 0 || value > MAX_UINT32) {\n throw new ConfigurationError({\n details: { value },\n message: \"SSH uint32 values must be integers in the range 0..2^32-1\",\n retryable: false,\n });\n }\n\n const chunk = Buffer.alloc(4);\n chunk.writeUInt32BE(value, 0);\n return this.push(chunk);\n }\n\n writeUint64(value: bigint): this {\n if (value < 0n || value > MAX_UINT64) {\n throw new ConfigurationError({\n details: { value: value.toString() },\n message: \"SSH uint64 values must be in the range 0..2^64-1\",\n retryable: false,\n });\n }\n\n const chunk = Buffer.alloc(8);\n chunk.writeBigUInt64BE(value, 0);\n return this.push(chunk);\n }\n\n writeString(value: string | Uint8Array, encoding: BufferEncoding = \"utf8\"): this {\n const payload = typeof value === \"string\" ? Buffer.from(value, encoding) : Buffer.from(value);\n this.writeUint32(payload.length);\n return this.push(payload);\n }\n\n writeMpint(value: Uint8Array): this {\n const normalized = normalizePositiveMpint(value);\n this.writeUint32(normalized.length);\n return this.push(normalized);\n }\n\n writeNameList(values: readonly string[]): this {\n for (const name of values) {\n if (name.includes(\",\")) {\n throw new ConfigurationError({\n details: { name },\n message: \"SSH name-list entries cannot contain commas\",\n retryable: false,\n });\n }\n }\n\n return this.writeString(values.join(\",\"), \"ascii\");\n }\n\n toBuffer(): Buffer {\n return Buffer.concat(this.chunks, this.length);\n }\n\n private push(chunk: Buffer): this {\n this.chunks.push(chunk);\n this.length += chunk.length;\n return this;\n }\n\n private assertByte(value: number, label: string): void {\n if (!Number.isInteger(value) || value < 0 || value > 0xff) {\n throw new ConfigurationError({\n details: { value },\n message: `SSH ${label} values must be integers in the range 0..255`,\n retryable: false,\n });\n }\n }\n}\n\nfunction normalizePositiveMpint(value: Uint8Array): Buffer {\n const input = Buffer.from(value);\n\n let offset = 0;\n while (offset < input.length && input[offset] === 0x00) {\n offset += 1;\n }\n\n if (offset >= input.length) {\n return Buffer.alloc(0);\n }\n\n const stripped = input.subarray(offset);\n if ((stripped[0]! & 0x80) === 0x80) {\n return Buffer.concat([Buffer.from([0x00]), stripped]);\n }\n\n return stripped;\n}\n","import { Buffer } from \"node:buffer\";\nimport { ParseError, ProtocolError } from \"../../../errors/ZeroTransferError\";\nimport type { NegotiatedSshAlgorithms, SshAlgorithmPreferences } from \"./SshAlgorithmNegotiation\";\nimport {\n DEFAULT_SSH_ALGORITHM_PREFERENCES,\n negotiateSshAlgorithms,\n} from \"./SshAlgorithmNegotiation\";\nimport {\n buildSshIdentificationLine,\n parseSshIdentificationLine,\n type SshIdentification,\n} from \"./SshIdentification\";\nimport {\n decodeSshKexInitMessage,\n encodeSshKexInitMessage,\n type SshKexInitMessage,\n} from \"./SshKexInit\";\nimport {\n createCurve25519Ephemeral,\n decodeSshKexEcdhReplyMessage,\n encodeSshKexEcdhInitMessage,\n} from \"./SshKexCurve25519\";\nimport { deriveSshSessionKeys, type SshDerivedSessionKeys } from \"./SshKeyDerivation\";\nimport { decodeSshNewKeysMessage, encodeSshNewKeysMessage } from \"./SshNewKeys\";\nimport { SshTransportPacketFramer, encodeSshTransportPacket } from \"./SshTransportPacket\";\nimport { verifySshHostKeySignature } from \"./SshHostKeyVerification\";\n\n/** Initial client-side handshake state before key exchange math starts. */\nexport interface SshTransportHandshakeResult {\n keyExchange: {\n algorithm: string;\n clientKexInitPayload: Buffer;\n clientPublicKey: Buffer;\n exchangeHash: Buffer;\n serverHostKey: Buffer;\n serverKexInitPayload: Buffer;\n serverPublicKey: Buffer;\n serverSignature: Buffer;\n sessionId: Buffer;\n sharedSecret: Buffer;\n transportKeys: {\n clientToServer: SshDerivedSessionKeys[\"clientToServer\"];\n serverToClient: SshDerivedSessionKeys[\"serverToClient\"];\n };\n };\n negotiatedAlgorithms: NegotiatedSshAlgorithms;\n serverIdentification: SshIdentification;\n serverKexInit: SshKexInitMessage;\n /**\n * Number of unencrypted packets the client sent during the handshake (KEXINIT,\n * KEX_ECDH_INIT, NEWKEYS). Per RFC 4253 §6.4, packet sequence numbers are never\n * reset across NEWKEYS, so this value seeds the outbound protector.\n */\n outboundPacketCount: number;\n /**\n * Number of unencrypted packets the client received from the server during the\n * handshake (server KEXINIT, KEX_ECDH_REPLY, NEWKEYS). Seeds the inbound unprotector.\n */\n inboundPacketCount: number;\n}\n\ntype HandshakePhase =\n | \"awaiting-server-identification\"\n | \"awaiting-server-kexinit\"\n | \"awaiting-server-kexreply\"\n | \"awaiting-server-newkeys\"\n | \"complete\";\n\n/**\n * Client-side SSH handshake coordinator for version exchange and KEXINIT negotiation.\n */\nexport class SshTransportHandshake {\n private readonly clientAlgorithms: SshAlgorithmPreferences;\n private readonly clientIdentificationLine: string;\n private readonly clientKexInitPayload: Buffer;\n private readonly identificationLines: string[] = [];\n private readonly packetFramer = new SshTransportPacketFramer();\n private readonly pendingIdentification = new SshIdentificationAccumulator();\n private phase: HandshakePhase = \"awaiting-server-identification\";\n private inboundPacketCount = 0;\n private outboundPacketCount = 0;\n private pendingCurve25519:\n | {\n deriveSharedSecret: (serverPublicKey: Uint8Array) => Buffer;\n publicKey: Buffer;\n }\n | undefined;\n private pendingKeyExchange:\n | {\n clientIdentification: string;\n algorithm: string;\n clientKexInitPayload: Buffer;\n clientPublicKey: Buffer;\n serverHostKey: Buffer;\n serverIdentification: string;\n serverKexInitPayload: Buffer;\n serverPublicKey: Buffer;\n serverSignature: Buffer;\n sharedSecret: Buffer;\n negotiatedAlgorithms: NegotiatedSshAlgorithms;\n }\n | undefined;\n private serverIdentification: SshIdentification | undefined;\n\n constructor(\n private readonly options: {\n algorithms?: SshAlgorithmPreferences;\n clientComments?: string;\n clientSoftwareVersion?: string;\n kexCookie?: Uint8Array;\n /**\n * Verifies the server's host key after the signature check passes.\n * Receives the SSH wire-format host key blob and its SHA-256 digest.\n * Throwing rejects the handshake; resolving accepts it.\n *\n * If omitted, the host key is accepted as long as its signature over the\n * exchange hash verifies. Callers SHOULD supply this hook in production\n * to enforce known_hosts or pinned-fingerprint policies.\n */\n verifyHostKey?: (input: {\n hostKeyBlob: Buffer;\n hostKeySha256: Buffer;\n algorithmName: string;\n }) => void | Promise<void>;\n } = {},\n ) {\n this.clientAlgorithms = options.algorithms ?? DEFAULT_SSH_ALGORITHM_PREFERENCES;\n this.clientIdentificationLine = buildSshIdentificationLine({\n ...(options.clientComments === undefined ? {} : { comments: options.clientComments }),\n softwareVersion: options.clientSoftwareVersion ?? \"ZeroTransfer_Dev\",\n });\n this.clientKexInitPayload = encodeSshKexInitMessage({\n algorithms: this.clientAlgorithms,\n ...(options.kexCookie === undefined ? {} : { cookie: options.kexCookie }),\n });\n }\n\n /** Creates the first outbound bytes (client identification line). */\n createInitialClientBytes(): Buffer {\n return Buffer.from(`${this.clientIdentificationLine}\\r\\n`, \"ascii\");\n }\n\n /**\n * Feeds raw server bytes into the handshake state machine.\n */\n pushServerBytes(chunk: Uint8Array): {\n outbound: Buffer[];\n result?: SshTransportHandshakeResult;\n } {\n const outbound: Buffer[] = [];\n\n if (this.phase === \"awaiting-server-identification\") {\n const scan = this.pendingIdentification.push(chunk);\n for (const banner of scan.bannerLines) {\n this.identificationLines.push(banner);\n }\n\n if (scan.identLine !== undefined) {\n this.serverIdentification = parseSshIdentificationLine(scan.identLine);\n this.phase = \"awaiting-server-kexinit\";\n outbound.push(encodeSshTransportPacket(this.clientKexInitPayload));\n this.outboundPacketCount += 1;\n\n if (scan.remainder.length > 0) {\n return this.pushServerBytesWithPhase(outbound, scan.remainder);\n }\n }\n\n return { outbound };\n }\n\n return this.pushServerBytesWithPhase(outbound, Buffer.from(chunk));\n }\n\n getServerBannerLines(): readonly string[] {\n return this.identificationLines;\n }\n\n isComplete(): boolean {\n return this.phase === \"complete\";\n }\n\n /**\n * Returns any bytes received after the last complete handshake packet and clears the buffer.\n * Call this once after `pushServerBytes` returns a result to drain bytes that belong to the\n * post-NEWKEYS encrypted phase but arrived in the same TCP segment as NEWKEYS.\n */\n takeRemainingBytes(): Buffer {\n return this.packetFramer.takeRemainingBytes();\n }\n\n private pushServerBytesWithPhase(\n outbound: Buffer[],\n chunk: Uint8Array,\n ): {\n outbound: Buffer[];\n result?: SshTransportHandshakeResult;\n } {\n if (this.phase === \"awaiting-server-identification\") {\n return { outbound };\n }\n\n for (const packet of this.packetFramer.push(chunk)) {\n const messageType = packet.payload[0];\n this.inboundPacketCount += 1;\n\n if (this.phase === \"awaiting-server-kexinit\") {\n if (messageType !== 20) {\n throw new ProtocolError({\n details: { messageType },\n message: \"Expected SSH_MSG_KEXINIT from server during initial handshake\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const serverKexInit = decodeSshKexInitMessage(packet.payload);\n const negotiatedAlgorithms = negotiateSshAlgorithms(this.clientAlgorithms, serverKexInit);\n\n if (\n negotiatedAlgorithms.kexAlgorithm !== \"curve25519-sha256\" &&\n negotiatedAlgorithms.kexAlgorithm !== \"curve25519-sha256@libssh.org\"\n ) {\n throw new ProtocolError({\n details: { kexAlgorithm: negotiatedAlgorithms.kexAlgorithm },\n message: \"Native SSH transport currently supports only Curve25519 key exchange\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n this.pendingCurve25519 = createCurve25519Ephemeral();\n this.phase = \"awaiting-server-kexreply\";\n outbound.push(\n encodeSshTransportPacket(encodeSshKexEcdhInitMessage(this.pendingCurve25519.publicKey)),\n );\n this.outboundPacketCount += 1;\n\n // Preserve KEXINIT artifacts required for exchange hash in the next wave.\n this.pendingKeyExchange = {\n clientIdentification: this.clientIdentificationLine,\n algorithm: negotiatedAlgorithms.kexAlgorithm,\n clientKexInitPayload: this.clientKexInitPayload,\n clientPublicKey: this.pendingCurve25519.publicKey,\n negotiatedAlgorithms,\n serverHostKey: Buffer.alloc(0),\n serverIdentification: (this.serverIdentification ?? missingServerIdentificationError())\n .raw,\n serverKexInitPayload: Buffer.from(packet.payload),\n serverPublicKey: Buffer.alloc(0),\n serverSignature: Buffer.alloc(0),\n sharedSecret: Buffer.alloc(0),\n };\n\n continue;\n }\n\n if (this.phase === \"awaiting-server-kexreply\") {\n if (messageType !== 31) {\n throw new ProtocolError({\n details: { messageType },\n message: \"Expected SSH_MSG_KEX_ECDH_REPLY from server\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n if (this.pendingCurve25519 === undefined || this.pendingKeyExchange === undefined) {\n throw new ProtocolError({\n message:\n \"Curve25519 client key state missing while processing server key exchange reply\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const reply = decodeSshKexEcdhReplyMessage(packet.payload);\n const sharedSecret = this.pendingCurve25519.deriveSharedSecret(reply.serverPublicKey);\n\n this.pendingKeyExchange = {\n ...this.pendingKeyExchange,\n serverHostKey: reply.hostKey,\n serverPublicKey: reply.serverPublicKey,\n serverSignature: reply.signature,\n sharedSecret,\n };\n\n this.phase = \"awaiting-server-newkeys\";\n outbound.push(encodeSshTransportPacket(encodeSshNewKeysMessage()));\n this.outboundPacketCount += 1;\n continue;\n }\n\n if (this.phase === \"awaiting-server-newkeys\") {\n decodeSshNewKeysMessage(packet.payload);\n\n const keyExchange = this.pendingKeyExchange ?? missingPendingKeyExchangeError();\n const derivedKeys = deriveSshSessionKeys({\n clientIdentification: keyExchange.clientIdentification,\n clientKexInitPayload: keyExchange.clientKexInitPayload,\n clientPublicKey: keyExchange.clientPublicKey,\n kexAlgorithm: keyExchange.algorithm,\n negotiatedAlgorithms: keyExchange.negotiatedAlgorithms,\n serverHostKey: keyExchange.serverHostKey,\n serverIdentification: keyExchange.serverIdentification,\n serverKexInitPayload: keyExchange.serverKexInitPayload,\n serverPublicKey: keyExchange.serverPublicKey,\n sharedSecret: keyExchange.sharedSecret,\n });\n\n // RFC 4253 §8: the client MUST verify the host key signature over the\n // exchange hash before transitioning to the encrypted phase. Without\n // this check the entire transport is open to a man-in-the-middle.\n const hostKeyVerification = verifySshHostKeySignature({\n exchangeHash: derivedKeys.exchangeHash,\n hostKeyBlob: keyExchange.serverHostKey,\n signatureBlob: keyExchange.serverSignature,\n });\n\n // Optional caller-supplied policy gate (known_hosts, pinned fingerprint, …).\n const verifyHook = this.options.verifyHostKey;\n if (verifyHook !== undefined) {\n // The hook may throw to reject; we surface that as a ProtocolError below.\n // Promise-returning hooks are not awaited inside this synchronous\n // state machine - callers requiring async policy must perform it\n // before initiating connect().\n const maybe = verifyHook({\n algorithmName: hostKeyVerification.algorithmName,\n hostKeyBlob: keyExchange.serverHostKey,\n hostKeySha256: hostKeyVerification.hostKeySha256,\n });\n if (maybe instanceof Promise) {\n throw new ProtocolError({\n message:\n \"verifyHostKey must be synchronous; perform any async lookups before calling connect()\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n }\n\n const serverKexInit = decodeSshKexInitMessage(keyExchange.serverKexInitPayload);\n const result: SshTransportHandshakeResult = {\n keyExchange: {\n algorithm: keyExchange.algorithm,\n clientKexInitPayload: keyExchange.clientKexInitPayload,\n clientPublicKey: keyExchange.clientPublicKey,\n exchangeHash: derivedKeys.exchangeHash,\n serverHostKey: keyExchange.serverHostKey,\n serverKexInitPayload: keyExchange.serverKexInitPayload,\n serverPublicKey: keyExchange.serverPublicKey,\n serverSignature: keyExchange.serverSignature,\n sessionId: derivedKeys.sessionId,\n sharedSecret: keyExchange.sharedSecret,\n transportKeys: {\n clientToServer: derivedKeys.clientToServer,\n serverToClient: derivedKeys.serverToClient,\n },\n },\n negotiatedAlgorithms: keyExchange.negotiatedAlgorithms,\n serverIdentification: this.serverIdentification ?? missingServerIdentificationError(),\n serverKexInit,\n inboundPacketCount: this.inboundPacketCount,\n outboundPacketCount: this.outboundPacketCount,\n };\n\n this.phase = \"complete\";\n this.pendingCurve25519 = undefined;\n this.pendingKeyExchange = undefined;\n return { outbound, result };\n }\n\n throw new ProtocolError({\n details: { phase: this.phase },\n message: \"SSH transport handshake received unexpected packets after completion\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n return { outbound };\n }\n}\n\n/** Longest accepted identification/banner line; matches OpenSSH's 8 KiB cap. */\nconst MAX_IDENTIFICATION_LINE_BYTES = 8192;\n/** Most pre-identification banner lines accepted; matches OpenSSH's 1024-line cap. */\nconst MAX_PRE_IDENTIFICATION_LINES = 1024;\n\nclass SshIdentificationAccumulator {\n private pending = Buffer.alloc(0);\n private bannerLineCount = 0;\n\n push(chunk: Uint8Array): { bannerLines: string[]; identLine?: string; remainder: Buffer } {\n this.pending = Buffer.concat([this.pending, Buffer.from(chunk)]);\n const bannerLines: string[] = [];\n\n while (true) {\n const lfIndex = this.pending.indexOf(0x0a);\n if (lfIndex < 0) {\n if (this.pending.length > MAX_IDENTIFICATION_LINE_BYTES) {\n throw new ProtocolError({\n details: { limitBytes: MAX_IDENTIFICATION_LINE_BYTES },\n message: \"SSH identification line exceeds the maximum accepted length\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n break;\n }\n if (lfIndex > MAX_IDENTIFICATION_LINE_BYTES) {\n throw new ProtocolError({\n details: { limitBytes: MAX_IDENTIFICATION_LINE_BYTES },\n message: \"SSH identification line exceeds the maximum accepted length\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n // Capture the line as text (safe: identification exchange is ASCII-only).\n const lineText = trimLineEndings(this.pending.subarray(0, lfIndex + 1).toString(\"ascii\"));\n\n // Capture everything AFTER the \\n as raw binary before any string conversion.\n const remainder = Buffer.from(this.pending.subarray(lfIndex + 1));\n this.pending = remainder;\n\n if (lineText.startsWith(\"SSH-\")) {\n // Found the identification line. Everything in pending is binary packet data.\n this.pending = Buffer.alloc(0);\n return { bannerLines, identLine: lineText, remainder };\n }\n\n this.bannerLineCount += 1;\n if (this.bannerLineCount > MAX_PRE_IDENTIFICATION_LINES) {\n throw new ProtocolError({\n details: { limitLines: MAX_PRE_IDENTIFICATION_LINES },\n message: \"SSH server sent too many pre-identification banner lines\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n bannerLines.push(lineText);\n }\n\n return { bannerLines, remainder: Buffer.alloc(0) };\n }\n}\n\nfunction trimLineEndings(value: string): string {\n if (value.endsWith(\"\\r\\n\")) {\n return value.slice(0, -2);\n }\n\n if (value.endsWith(\"\\n\")) {\n return value.slice(0, -1);\n }\n\n return value;\n}\n\nfunction missingServerIdentificationError(): never {\n throw new ParseError({\n message: \"Missing server SSH identification while negotiating KEXINIT\",\n protocol: \"sftp\",\n retryable: false,\n });\n}\n\nfunction missingPendingKeyExchangeError(): never {\n throw new ProtocolError({\n message: \"SSH transport key exchange state was not initialized\",\n protocol: \"sftp\",\n retryable: false,\n });\n}\n","import { UnsupportedFeatureError } from \"../../../errors/ZeroTransferError\";\n\n/** Algorithm lists exchanged during SSH KEXINIT negotiation. */\nexport interface SshAlgorithmPreferences {\n compressionClientToServer: readonly string[];\n compressionServerToClient: readonly string[];\n encryptionClientToServer: readonly string[];\n encryptionServerToClient: readonly string[];\n kexAlgorithms: readonly string[];\n languagesClientToServer: readonly string[];\n languagesServerToClient: readonly string[];\n macClientToServer: readonly string[];\n macServerToClient: readonly string[];\n serverHostKeyAlgorithms: readonly string[];\n}\n\n/** Selected algorithms after intersecting client preferences with server capabilities. */\nexport interface NegotiatedSshAlgorithms {\n compressionClientToServer: string;\n compressionServerToClient: string;\n encryptionClientToServer: string;\n encryptionServerToClient: string;\n kexAlgorithm: string;\n languageClientToServer?: string;\n languageServerToClient?: string;\n macClientToServer: string;\n macServerToClient: string;\n serverHostKeyAlgorithm: string;\n}\n\n/**\n * Baseline algorithm order for the initial native SSH transport implementation.\n */\nexport const DEFAULT_SSH_ALGORITHM_PREFERENCES: Readonly<SshAlgorithmPreferences> = {\n compressionClientToServer: [\"none\"],\n compressionServerToClient: [\"none\"],\n encryptionClientToServer: [\n \"chacha20-poly1305@openssh.com\",\n \"aes256-gcm@openssh.com\",\n \"aes128-gcm@openssh.com\",\n \"aes256-ctr\",\n \"aes128-ctr\",\n ],\n encryptionServerToClient: [\n \"chacha20-poly1305@openssh.com\",\n \"aes256-gcm@openssh.com\",\n \"aes128-gcm@openssh.com\",\n \"aes256-ctr\",\n \"aes128-ctr\",\n ],\n kexAlgorithms: [\"curve25519-sha256\", \"curve25519-sha256@libssh.org\"],\n languagesClientToServer: [],\n languagesServerToClient: [],\n macClientToServer: [\"hmac-sha2-512\", \"hmac-sha2-256\"],\n macServerToClient: [\"hmac-sha2-512\", \"hmac-sha2-256\"],\n serverHostKeyAlgorithms: [\n \"ssh-ed25519\",\n \"ecdsa-sha2-nistp256\",\n \"ecdsa-sha2-nistp384\",\n \"ecdsa-sha2-nistp521\",\n \"rsa-sha2-512\",\n \"rsa-sha2-256\",\n ],\n};\n\n/**\n * Intersects client and server algorithm lists using SSH's client-priority selection model.\n */\nexport function negotiateSshAlgorithms(\n client: SshAlgorithmPreferences,\n server: SshAlgorithmPreferences,\n): NegotiatedSshAlgorithms {\n const languageClientToServer = chooseLanguage(\n \"languages client->server\",\n client.languagesClientToServer,\n server.languagesClientToServer,\n );\n const languageServerToClient = chooseLanguage(\n \"languages server->client\",\n client.languagesServerToClient,\n server.languagesServerToClient,\n );\n\n return {\n compressionClientToServer: chooseRequired(\n \"compression client->server\",\n client.compressionClientToServer,\n server.compressionClientToServer,\n ),\n compressionServerToClient: chooseRequired(\n \"compression server->client\",\n client.compressionServerToClient,\n server.compressionServerToClient,\n ),\n encryptionClientToServer: chooseRequired(\n \"encryption client->server\",\n client.encryptionClientToServer,\n server.encryptionClientToServer,\n ),\n encryptionServerToClient: chooseRequired(\n \"encryption server->client\",\n client.encryptionServerToClient,\n server.encryptionServerToClient,\n ),\n kexAlgorithm: chooseRequired(\"kex\", client.kexAlgorithms, server.kexAlgorithms),\n ...(languageClientToServer === undefined ? {} : { languageClientToServer }),\n ...(languageServerToClient === undefined ? {} : { languageServerToClient }),\n macClientToServer: chooseRequired(\n \"mac client->server\",\n client.macClientToServer,\n server.macClientToServer,\n ),\n macServerToClient: chooseRequired(\n \"mac server->client\",\n client.macServerToClient,\n server.macServerToClient,\n ),\n serverHostKeyAlgorithm: chooseRequired(\n \"server host key\",\n client.serverHostKeyAlgorithms,\n server.serverHostKeyAlgorithms,\n ),\n };\n}\n\nfunction chooseRequired(\n label: string,\n preferred: readonly string[],\n supported: readonly string[],\n): string {\n const selected = preferred.find((candidate) => supported.includes(candidate));\n\n if (selected !== undefined) {\n return selected;\n }\n\n throw new UnsupportedFeatureError({\n details: {\n preferred,\n supported,\n },\n message: `Unable to negotiate SSH ${label} algorithm`,\n protocol: \"sftp\",\n retryable: false,\n });\n}\n\nfunction chooseLanguage(\n label: string,\n preferred: readonly string[],\n supported: readonly string[],\n): string | undefined {\n if (preferred.length === 0 || supported.length === 0) {\n return undefined;\n }\n\n return chooseRequired(label, preferred, supported);\n}\n","import { ParseError } from \"../../../errors/ZeroTransferError\";\n\nconst SSH_IDENT_PREFIX = \"SSH-\";\nconst SSH_PROTOCOL_VERSION = \"2.0\";\n\n/** Parsed SSH identification components from the RFC 4253 banner line. */\nexport interface SshIdentification {\n protocolVersion: string;\n softwareVersion: string;\n comments?: string;\n raw: string;\n}\n\n/**\n * Builds an SSH identification line without CRLF terminators.\n */\nexport function buildSshIdentificationLine(options: {\n softwareVersion: string;\n comments?: string;\n protocolVersion?: string;\n}): string {\n const protocolVersion = options.protocolVersion ?? SSH_PROTOCOL_VERSION;\n\n if (protocolVersion.trim().length === 0 || options.softwareVersion.trim().length === 0) {\n throw new ParseError({\n message: \"SSH identification protocol and software versions must be non-empty\",\n retryable: false,\n });\n }\n\n const base = `${SSH_IDENT_PREFIX}${protocolVersion}-${options.softwareVersion}`;\n if (options.comments === undefined || options.comments.length === 0) {\n return base;\n }\n\n return `${base} ${options.comments}`;\n}\n\n/**\n * Parses a single SSH identification line without the trailing CRLF.\n */\nexport function parseSshIdentificationLine(line: string): SshIdentification {\n if (!line.startsWith(SSH_IDENT_PREFIX)) {\n throw new ParseError({\n details: { line },\n message: \"SSH identification line must start with 'SSH-'\",\n retryable: false,\n });\n }\n\n const firstSpace = line.indexOf(\" \");\n const header = firstSpace === -1 ? line : line.slice(0, firstSpace);\n const comments = firstSpace === -1 ? undefined : line.slice(firstSpace + 1);\n const headerParts = header.split(\"-\");\n\n if (headerParts.length < 3) {\n throw new ParseError({\n details: { line },\n message: \"SSH identification line is malformed\",\n retryable: false,\n });\n }\n\n const protocolVersion = headerParts[1] ?? \"\";\n const softwareVersion = headerParts.slice(2).join(\"-\");\n\n if (protocolVersion.length === 0 || softwareVersion.length === 0) {\n throw new ParseError({\n details: { line },\n message: \"SSH identification line must include protocol and software versions\",\n retryable: false,\n });\n }\n\n return {\n protocolVersion,\n softwareVersion,\n raw: line,\n ...(comments === undefined || comments.length === 0 ? {} : { comments }),\n };\n}\n","import { Buffer } from \"node:buffer\";\nimport { randomBytes } from \"node:crypto\";\nimport { ConfigurationError, ParseError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader, SshDataWriter } from \"../binary\";\nimport type { SshAlgorithmPreferences } from \"./SshAlgorithmNegotiation\";\n\nconst SSH_MSG_KEXINIT = 20;\nconst KEXINIT_COOKIE_LENGTH = 16;\n\n/** Parsed SSH_MSG_KEXINIT payload. */\nexport interface SshKexInitMessage extends SshAlgorithmPreferences {\n cookie: Buffer;\n firstKexPacketFollows: boolean;\n messageType: number;\n reserved: number;\n}\n\n/**\n * Encodes SSH_MSG_KEXINIT payload bytes (starting with message number 20).\n */\nexport function encodeSshKexInitMessage(options: {\n algorithms: SshAlgorithmPreferences;\n cookie?: Uint8Array;\n firstKexPacketFollows?: boolean;\n}): Buffer {\n const cookie =\n options.cookie === undefined ? randomBytes(KEXINIT_COOKIE_LENGTH) : Buffer.from(options.cookie);\n\n if (cookie.length !== KEXINIT_COOKIE_LENGTH) {\n throw new ConfigurationError({\n details: { actualLength: cookie.length, expectedLength: KEXINIT_COOKIE_LENGTH },\n message: \"SSH KEXINIT cookie must be 16 bytes\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const writer = new SshDataWriter();\n writer.writeByte(SSH_MSG_KEXINIT);\n writer.writeBytes(cookie);\n writer.writeNameList(options.algorithms.kexAlgorithms);\n writer.writeNameList(options.algorithms.serverHostKeyAlgorithms);\n writer.writeNameList(options.algorithms.encryptionClientToServer);\n writer.writeNameList(options.algorithms.encryptionServerToClient);\n writer.writeNameList(options.algorithms.macClientToServer);\n writer.writeNameList(options.algorithms.macServerToClient);\n writer.writeNameList(options.algorithms.compressionClientToServer);\n writer.writeNameList(options.algorithms.compressionServerToClient);\n writer.writeNameList(options.algorithms.languagesClientToServer);\n writer.writeNameList(options.algorithms.languagesServerToClient);\n writer.writeBoolean(options.firstKexPacketFollows ?? false);\n writer.writeUint32(0);\n return writer.toBuffer();\n}\n\n/**\n * Decodes SSH_MSG_KEXINIT payload bytes into algorithm lists and flags.\n */\nexport function decodeSshKexInitMessage(payload: Uint8Array): SshKexInitMessage {\n const reader = new SshDataReader(payload);\n const messageType = reader.readByte();\n\n if (messageType !== SSH_MSG_KEXINIT) {\n throw new ParseError({\n details: { messageType },\n message: \"Expected SSH_MSG_KEXINIT payload\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const cookie = reader.readBytes(KEXINIT_COOKIE_LENGTH);\n const kexAlgorithms = reader.readNameList();\n const serverHostKeyAlgorithms = reader.readNameList();\n const encryptionClientToServer = reader.readNameList();\n const encryptionServerToClient = reader.readNameList();\n const macClientToServer = reader.readNameList();\n const macServerToClient = reader.readNameList();\n const compressionClientToServer = reader.readNameList();\n const compressionServerToClient = reader.readNameList();\n const languagesClientToServer = reader.readNameList();\n const languagesServerToClient = reader.readNameList();\n const firstKexPacketFollows = reader.readBoolean();\n const reserved = reader.readUint32();\n\n reader.assertFinished();\n\n return {\n compressionClientToServer,\n compressionServerToClient,\n cookie,\n encryptionClientToServer,\n encryptionServerToClient,\n firstKexPacketFollows,\n kexAlgorithms,\n languagesClientToServer,\n languagesServerToClient,\n macClientToServer,\n macServerToClient,\n messageType,\n reserved,\n serverHostKeyAlgorithms,\n };\n}\n","import { Buffer } from \"node:buffer\";\nimport { createPublicKey, diffieHellman, generateKeyPairSync, type KeyObject } from \"node:crypto\";\nimport { ConfigurationError, ParseError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader, SshDataWriter } from \"../binary\";\n\nconst SSH_MSG_KEX_ECDH_INIT = 30;\nconst SSH_MSG_KEX_ECDH_REPLY = 31;\nconst X25519_PUBLIC_KEY_LENGTH = 32;\n\n// DER SubjectPublicKeyInfo prefix for X25519 public keys (RFC 8410).\nconst X25519_SPKI_PREFIX = Buffer.from(\"302a300506032b656e032100\", \"hex\");\n\n/** Parsed SSH_MSG_KEX_ECDH_INIT payload. */\nexport interface SshKexEcdhInitMessage {\n clientPublicKey: Buffer;\n messageType: number;\n}\n\n/** Parsed SSH_MSG_KEX_ECDH_REPLY payload. */\nexport interface SshKexEcdhReplyMessage {\n hostKey: Buffer;\n messageType: number;\n serverPublicKey: Buffer;\n signature: Buffer;\n}\n\n/**\n * Generates a client Curve25519 ephemeral keypair with SSH wire-format helpers.\n */\nexport function createCurve25519Ephemeral(): {\n deriveSharedSecret: (serverPublicKey: Uint8Array) => Buffer;\n publicKey: Buffer;\n} {\n const { privateKey, publicKey } = generateKeyPairSync(\"x25519\");\n const encodedPublicKey = exportX25519PublicKeyRaw(publicKey);\n\n return {\n deriveSharedSecret: (serverPublicKey) => {\n const peer = importX25519PublicKeyRaw(serverPublicKey);\n return diffieHellman({ privateKey, publicKey: peer });\n },\n publicKey: encodedPublicKey,\n };\n}\n\n/**\n * Encodes SSH_MSG_KEX_ECDH_INIT payload bytes.\n */\nexport function encodeSshKexEcdhInitMessage(publicKey: Uint8Array): Buffer {\n const normalized = normalizeX25519PublicKey(publicKey, \"client\");\n return new SshDataWriter().writeByte(SSH_MSG_KEX_ECDH_INIT).writeString(normalized).toBuffer();\n}\n\n/**\n * Decodes SSH_MSG_KEX_ECDH_INIT payload bytes.\n */\nexport function decodeSshKexEcdhInitMessage(payload: Uint8Array): SshKexEcdhInitMessage {\n const reader = new SshDataReader(payload);\n const messageType = reader.readByte();\n\n if (messageType !== SSH_MSG_KEX_ECDH_INIT) {\n throw new ParseError({\n details: { messageType },\n message: \"Expected SSH_MSG_KEX_ECDH_INIT payload\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const clientPublicKey = normalizeX25519PublicKey(reader.readString(), \"client\");\n reader.assertFinished();\n return { clientPublicKey, messageType };\n}\n\n/**\n * Encodes SSH_MSG_KEX_ECDH_REPLY payload bytes.\n */\nexport function encodeSshKexEcdhReplyMessage(input: {\n hostKey: Uint8Array;\n serverPublicKey: Uint8Array;\n signature: Uint8Array;\n}): Buffer {\n const serverPublicKey = normalizeX25519PublicKey(input.serverPublicKey, \"server\");\n\n return new SshDataWriter()\n .writeByte(SSH_MSG_KEX_ECDH_REPLY)\n .writeString(input.hostKey)\n .writeString(serverPublicKey)\n .writeString(input.signature)\n .toBuffer();\n}\n\n/**\n * Decodes SSH_MSG_KEX_ECDH_REPLY payload bytes.\n */\nexport function decodeSshKexEcdhReplyMessage(payload: Uint8Array): SshKexEcdhReplyMessage {\n const reader = new SshDataReader(payload);\n const messageType = reader.readByte();\n\n if (messageType !== SSH_MSG_KEX_ECDH_REPLY) {\n throw new ParseError({\n details: { messageType },\n message: \"Expected SSH_MSG_KEX_ECDH_REPLY payload\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const hostKey = reader.readString();\n const serverPublicKey = normalizeX25519PublicKey(reader.readString(), \"server\");\n const signature = reader.readString();\n reader.assertFinished();\n\n return {\n hostKey,\n messageType,\n serverPublicKey,\n signature,\n };\n}\n\nfunction exportX25519PublicKeyRaw(publicKey: KeyObject): Buffer {\n const der = publicKey.export({ format: \"der\", type: \"spki\" });\n const raw = der.subarray(der.length - X25519_PUBLIC_KEY_LENGTH);\n return normalizeX25519PublicKey(raw, \"client\");\n}\n\nfunction importX25519PublicKeyRaw(raw: Uint8Array): KeyObject {\n const normalized = normalizeX25519PublicKey(raw, \"server\");\n const der = Buffer.concat([X25519_SPKI_PREFIX, normalized]);\n return createPublicKey({\n format: \"der\",\n key: der,\n type: \"spki\",\n });\n}\n\nfunction normalizeX25519PublicKey(value: Uint8Array, label: \"client\" | \"server\"): Buffer {\n const key = Buffer.from(value);\n if (key.length !== X25519_PUBLIC_KEY_LENGTH) {\n throw new ConfigurationError({\n details: { keyLength: key.length, label },\n message: `SSH ${label} Curve25519 public key must be 32 bytes`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n return key;\n}\n","import { Buffer } from \"node:buffer\";\nimport { createHash } from \"node:crypto\";\nimport { ProtocolError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataWriter } from \"../binary\";\nimport type { NegotiatedSshAlgorithms } from \"./SshAlgorithmNegotiation\";\n\n/** Directional key material used after SSH NEWKEYS. */\nexport interface SshTransportDirectionKeys {\n encryptionKey: Buffer;\n iv: Buffer;\n macKey: Buffer;\n}\n\n/** Session key bundle derived from K, H, and session id. */\nexport interface SshDerivedSessionKeys {\n clientToServer: SshTransportDirectionKeys;\n exchangeHash: Buffer;\n serverToClient: SshTransportDirectionKeys;\n sessionId: Buffer;\n}\n\n/** Input transcript used to compute SSH exchange hash for curve25519 KEX. */\nexport interface SshExchangeHashInput {\n clientIdentification: string;\n clientKexInitPayload: Uint8Array;\n clientPublicKey: Uint8Array;\n kexAlgorithm: string;\n negotiatedAlgorithms: NegotiatedSshAlgorithms;\n serverHostKey: Uint8Array;\n serverIdentification: string;\n serverKexInitPayload: Uint8Array;\n serverPublicKey: Uint8Array;\n sharedSecret: Uint8Array;\n}\n\n/**\n * Computes exchange hash and derives initial transport key material for the negotiated algorithms.\n */\nexport function deriveSshSessionKeys(input: SshExchangeHashInput): SshDerivedSessionKeys {\n const hashAlgorithm = resolveKexHashAlgorithm(input.kexAlgorithm);\n const exchangeHash = computeCurve25519ExchangeHash(input, hashAlgorithm);\n const sessionId = exchangeHash;\n\n const c2sEncryptionLength = resolveEncryptionKeyLength(\n input.negotiatedAlgorithms.encryptionClientToServer,\n );\n const s2cEncryptionLength = resolveEncryptionKeyLength(\n input.negotiatedAlgorithms.encryptionServerToClient,\n );\n const c2sIvLength = resolveIvLength(input.negotiatedAlgorithms.encryptionClientToServer);\n const s2cIvLength = resolveIvLength(input.negotiatedAlgorithms.encryptionServerToClient);\n const c2sMacLength = resolveMacKeyLength(\n input.negotiatedAlgorithms.encryptionClientToServer,\n input.negotiatedAlgorithms.macClientToServer,\n );\n const s2cMacLength = resolveMacKeyLength(\n input.negotiatedAlgorithms.encryptionServerToClient,\n input.negotiatedAlgorithms.macServerToClient,\n );\n\n const sharedSecret = Buffer.from(input.sharedSecret);\n\n return {\n clientToServer: {\n encryptionKey: deriveMaterial(\n sharedSecret,\n exchangeHash,\n sessionId,\n \"C\",\n c2sEncryptionLength,\n hashAlgorithm,\n ),\n iv: deriveMaterial(sharedSecret, exchangeHash, sessionId, \"A\", c2sIvLength, hashAlgorithm),\n macKey: deriveMaterial(\n sharedSecret,\n exchangeHash,\n sessionId,\n \"E\",\n c2sMacLength,\n hashAlgorithm,\n ),\n },\n exchangeHash,\n serverToClient: {\n encryptionKey: deriveMaterial(\n sharedSecret,\n exchangeHash,\n sessionId,\n \"D\",\n s2cEncryptionLength,\n hashAlgorithm,\n ),\n iv: deriveMaterial(sharedSecret, exchangeHash, sessionId, \"B\", s2cIvLength, hashAlgorithm),\n macKey: deriveMaterial(\n sharedSecret,\n exchangeHash,\n sessionId,\n \"F\",\n s2cMacLength,\n hashAlgorithm,\n ),\n },\n sessionId,\n };\n}\n\nfunction computeCurve25519ExchangeHash(\n input: SshExchangeHashInput,\n hashAlgorithm: \"sha256\",\n): Buffer {\n const transcript = new SshDataWriter()\n .writeString(input.clientIdentification, \"ascii\")\n .writeString(input.serverIdentification, \"ascii\")\n .writeString(input.clientKexInitPayload)\n .writeString(input.serverKexInitPayload)\n .writeString(input.serverHostKey)\n .writeString(input.clientPublicKey)\n .writeString(input.serverPublicKey)\n .writeMpint(input.sharedSecret)\n .toBuffer();\n\n return createHash(hashAlgorithm).update(transcript).digest();\n}\n\nfunction deriveMaterial(\n sharedSecret: Buffer,\n exchangeHash: Buffer,\n sessionId: Buffer,\n letter: string,\n length: number,\n hashAlgorithm: \"sha256\",\n): Buffer {\n if (length <= 0) {\n return Buffer.alloc(0);\n }\n\n const result: Buffer[] = [];\n\n const first = createHash(hashAlgorithm)\n .update(\n new SshDataWriter()\n .writeMpint(sharedSecret)\n .writeBytes(exchangeHash)\n .writeByte(letter.charCodeAt(0))\n .writeBytes(sessionId)\n .toBuffer(),\n )\n .digest();\n result.push(first);\n\n while (Buffer.concat(result).length < length) {\n const previous = Buffer.concat(result);\n const next = createHash(hashAlgorithm)\n .update(\n new SshDataWriter()\n .writeMpint(sharedSecret)\n .writeBytes(exchangeHash)\n .writeBytes(previous)\n .toBuffer(),\n )\n .digest();\n result.push(next);\n }\n\n return Buffer.concat(result).subarray(0, length);\n}\n\nfunction resolveKexHashAlgorithm(kexAlgorithm: string): \"sha256\" {\n if (kexAlgorithm === \"curve25519-sha256\" || kexAlgorithm === \"curve25519-sha256@libssh.org\") {\n return \"sha256\";\n }\n\n throw new ProtocolError({\n details: { kexAlgorithm },\n message: \"Unsupported key exchange hash algorithm\",\n protocol: \"sftp\",\n retryable: false,\n });\n}\n\nfunction resolveEncryptionKeyLength(algorithm: string): number {\n switch (algorithm) {\n case \"chacha20-poly1305@openssh.com\":\n return 64;\n case \"aes128-gcm@openssh.com\":\n case \"aes128-ctr\":\n return 16;\n case \"aes256-gcm@openssh.com\":\n case \"aes256-ctr\":\n return 32;\n default:\n throw new ProtocolError({\n details: { algorithm },\n message: \"Unsupported SSH encryption algorithm for key derivation\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveIvLength(algorithm: string): number {\n switch (algorithm) {\n case \"chacha20-poly1305@openssh.com\":\n return 0;\n case \"aes128-gcm@openssh.com\":\n case \"aes256-gcm@openssh.com\":\n return 12;\n case \"aes128-ctr\":\n case \"aes256-ctr\":\n return 16;\n default:\n throw new ProtocolError({\n details: { algorithm },\n message: \"Unsupported SSH encryption algorithm for IV derivation\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveMacKeyLength(encryptionAlgorithm: string, macAlgorithm: string): number {\n if (\n encryptionAlgorithm.endsWith(\"-gcm@openssh.com\") ||\n encryptionAlgorithm === \"chacha20-poly1305@openssh.com\"\n ) {\n return 0;\n }\n\n switch (macAlgorithm) {\n case \"hmac-sha2-256\":\n return 32;\n case \"hmac-sha2-512\":\n return 64;\n default:\n throw new ProtocolError({\n details: { macAlgorithm },\n message: \"Unsupported SSH MAC algorithm for key derivation\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n","import { ParseError } from \"../../../errors/ZeroTransferError\";\n\nexport const SSH_MSG_NEWKEYS = 21;\n\n/**\n * Encodes an SSH_MSG_NEWKEYS payload.\n */\nexport function encodeSshNewKeysMessage(): Buffer {\n return Buffer.from([SSH_MSG_NEWKEYS]);\n}\n\n/**\n * Validates and decodes an SSH_MSG_NEWKEYS payload.\n */\nexport function decodeSshNewKeysMessage(payload: Uint8Array): { messageType: number } {\n if (payload.length !== 1 || payload[0] !== SSH_MSG_NEWKEYS) {\n throw new ParseError({\n details: { length: payload.length, messageType: payload[0] },\n message: \"Expected SSH_MSG_NEWKEYS payload\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n return { messageType: SSH_MSG_NEWKEYS };\n}\n","import { Buffer } from \"node:buffer\";\nimport { randomBytes } from \"node:crypto\";\nimport { ConfigurationError, ParseError } from \"../../../errors/ZeroTransferError\";\n\nconst MIN_PADDING_LENGTH = 4;\nconst MIN_PACKET_LENGTH = 1 + MIN_PADDING_LENGTH;\n\n/**\n * Maximum accepted SSH `packet_length` before a peer is considered hostile or\n * broken. RFC 4253 only requires support for 35000-byte packets; this matches\n * OpenSSH's 256 KiB cap so the framers never buffer unbounded amounts of\n * network data on a forged length prefix.\n */\nexport const MAX_SSH_PACKET_LENGTH = 256 * 1024;\n\n/** Decoded SSH transport packet before decryption/MAC pipelines are applied. */\nexport interface SshTransportPacket {\n padding: Buffer;\n paddingLength: number;\n payload: Buffer;\n}\n\n/**\n * Encodes an SSH binary packet using RFC 4253 framing for the cleartext phase.\n */\nexport function encodeSshTransportPacket(\n payload: Uint8Array,\n options: {\n blockSize?: number;\n randomPadding?: boolean;\n } = {},\n): Buffer {\n const body = Buffer.from(payload);\n const blockSize = normalizeBlockSize(options.blockSize ?? 8);\n\n // packet_length covers padding_length + payload + padding, and packet_length+4\n // must align to the transport block size.\n let paddingLength = MIN_PADDING_LENGTH;\n while ((1 + body.length + paddingLength + 4) % blockSize !== 0) {\n paddingLength += 1;\n }\n\n const padding =\n options.randomPadding === false ? Buffer.alloc(paddingLength) : randomBytes(paddingLength);\n const packetLength = 1 + body.length + paddingLength;\n // Use Buffer.alloc (zero-init) for defense-in-depth: every byte of the frame\n // is overwritten below, but a zeroed buffer eliminates any chance of leaking\n // residual heap memory if a future code path mis-counts.\n const frame = Buffer.alloc(4 + packetLength);\n\n frame.writeUInt32BE(packetLength, 0);\n frame.writeUInt8(paddingLength, 4);\n body.copy(frame, 5);\n padding.copy(frame, 5 + body.length);\n\n return frame;\n}\n\n/**\n * Decodes a complete SSH transport frame into payload and padding metadata.\n */\nexport function decodeSshTransportPacket(frame: Uint8Array): SshTransportPacket {\n const bytes = Buffer.from(frame);\n if (bytes.length < 4 + MIN_PACKET_LENGTH) {\n throw new ParseError({\n details: { length: bytes.length },\n message: \"SSH transport frame is too short\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const packetLength = bytes.readUInt32BE(0);\n if (packetLength < MIN_PACKET_LENGTH) {\n throw new ParseError({\n details: { packetLength },\n message: \"SSH transport packet length is invalid\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const totalLength = 4 + packetLength;\n if (bytes.length !== totalLength) {\n throw new ParseError({\n details: { actualLength: bytes.length, expectedLength: totalLength },\n message: \"SSH transport packet length prefix does not match frame size\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const paddingLength = bytes.readUInt8(4);\n if (paddingLength < MIN_PADDING_LENGTH) {\n throw new ParseError({\n details: { paddingLength },\n message: \"SSH transport packet padding length is invalid\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const payloadLength = packetLength - 1 - paddingLength;\n if (payloadLength < 0) {\n throw new ParseError({\n details: { packetLength, paddingLength },\n message: \"SSH transport packet payload length is negative\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const payloadStart = 5;\n const payloadEnd = payloadStart + payloadLength;\n\n return {\n padding: bytes.subarray(payloadEnd, payloadEnd + paddingLength),\n paddingLength,\n payload: bytes.subarray(payloadStart, payloadEnd),\n };\n}\n\n/**\n * Streaming framer for SSH transport packets from arbitrary TCP chunk boundaries.\n */\nexport class SshTransportPacketFramer {\n private pending = Buffer.alloc(0);\n\n push(chunk: Uint8Array): SshTransportPacket[] {\n this.pending = Buffer.concat([this.pending, Buffer.from(chunk)]);\n const packets: SshTransportPacket[] = [];\n\n while (this.pending.length >= 4) {\n const packetLength = this.pending.readUInt32BE(0);\n if (packetLength > MAX_SSH_PACKET_LENGTH) {\n throw new ParseError({\n details: { maxPacketLength: MAX_SSH_PACKET_LENGTH, packetLength },\n message: \"SSH transport packet length exceeds the maximum accepted size\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const frameLength = 4 + packetLength;\n\n if (this.pending.length < frameLength) {\n break;\n }\n\n const frame = this.pending.subarray(0, frameLength);\n packets.push(decodeSshTransportPacket(frame));\n this.pending = this.pending.subarray(frameLength);\n }\n\n return packets;\n }\n\n getBufferedByteLength(): number {\n return this.pending.length;\n }\n\n /** Returns and clears any bytes buffered but not yet part of a complete packet. */\n takeRemainingBytes(): Buffer {\n const remaining = Buffer.from(this.pending);\n this.pending = Buffer.alloc(0);\n return remaining;\n }\n}\n\nfunction normalizeBlockSize(blockSize: number): number {\n if (!Number.isInteger(blockSize) || blockSize < 8 || blockSize > 255) {\n throw new ConfigurationError({\n details: { blockSize },\n message: \"SSH transport block size must be an integer between 8 and 255\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n return blockSize;\n}\n","/**\n * SSH server host key signature verification (RFC 4253 §6.6, §8).\n *\n * The KEX_ECDH_REPLY message carries:\n * - K_S: the server's public host key blob (algorithm-prefixed, SSH wire format)\n * - signature: H signed with the host private key\n *\n * The client MUST verify the signature against H using the algorithm advertised\n * by the K_S blob. Without this check, the server's identity is unauthenticated\n * and the entire transport is vulnerable to a man-in-the-middle attack.\n */\nimport { Buffer } from \"node:buffer\";\nimport { createHash, createPublicKey, verify as cryptoVerify, type KeyObject } from \"node:crypto\";\nimport { ProtocolError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader } from \"../binary/SshDataReader\";\n\nconst ED25519_RAW_KEY_LENGTH = 32;\n// DER SubjectPublicKeyInfo prefix for Ed25519 public keys (RFC 8410).\nconst ED25519_SPKI_PREFIX = Buffer.from(\"302a300506032b6570032100\", \"hex\");\n\n/**\n * Verifies the server's host key signature over the SSH exchange hash.\n *\n * @throws ProtocolError if the signature is invalid, the algorithm is unsupported,\n * or the host key blob is malformed.\n */\nexport function verifySshHostKeySignature(input: {\n exchangeHash: Uint8Array;\n hostKeyBlob: Uint8Array;\n signatureBlob: Uint8Array;\n}): { algorithmName: string; hostKeySha256: Buffer } {\n const { algorithmName, publicKey } = parseHostKey(input.hostKeyBlob);\n const { signatureAlgorithm, signatureBytes } = parseSignatureBlob(input.signatureBlob);\n\n if (!isCompatibleSignatureAlgorithm(algorithmName, signatureAlgorithm)) {\n throw new ProtocolError({\n details: { hostKeyAlgorithm: algorithmName, signatureAlgorithm },\n message: \"SSH host key signature algorithm does not match host key type\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const verified = verifySignature({\n data: Buffer.from(input.exchangeHash),\n publicKey,\n signature: Buffer.from(signatureBytes),\n signatureAlgorithm,\n });\n\n if (!verified) {\n throw new ProtocolError({\n details: { signatureAlgorithm },\n message: \"SSH host key signature verification failed\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const hostKeySha256 = createHash(\"sha256\").update(input.hostKeyBlob).digest();\n return { algorithmName, hostKeySha256 };\n}\n\ninterface ParsedHostKey {\n algorithmName: string;\n publicKey: KeyObject;\n}\n\nfunction parseHostKey(blob: Uint8Array): ParsedHostKey {\n const reader = new SshDataReader(blob);\n const algorithmName = reader.readString().toString(\"ascii\");\n\n switch (algorithmName) {\n case \"ssh-ed25519\": {\n const raw = reader.readString();\n reader.assertFinished();\n if (raw.length !== ED25519_RAW_KEY_LENGTH) {\n throw new ProtocolError({\n details: { actualLength: raw.length, expectedLength: ED25519_RAW_KEY_LENGTH },\n message: \"Ed25519 host key has invalid length\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const spki = Buffer.concat([ED25519_SPKI_PREFIX, raw]);\n return {\n algorithmName,\n publicKey: createPublicKey({ format: \"der\", key: spki, type: \"spki\" }),\n };\n }\n\n case \"rsa-sha2-256\":\n case \"rsa-sha2-512\":\n case \"ssh-rsa\": {\n // RSA public keys: mpint e, mpint n.\n const e = reader.readMpint();\n const n = reader.readMpint();\n reader.assertFinished();\n return {\n algorithmName,\n publicKey: rsaPublicKeyFromComponents(e, n),\n };\n }\n\n case \"ecdsa-sha2-nistp256\":\n case \"ecdsa-sha2-nistp384\":\n case \"ecdsa-sha2-nistp521\": {\n // RFC 5656 §3.1: string \"ecdsa-sha2-[identifier]\" || string identifier || string Q\n // where Q is the uncompressed point bytes.\n const curveIdentifier = reader.readString().toString(\"ascii\");\n const expectedIdentifier = algorithmName.slice(\"ecdsa-sha2-\".length);\n if (curveIdentifier !== expectedIdentifier) {\n throw new ProtocolError({\n details: { algorithmName, curveIdentifier },\n message: \"ECDSA host key curve identifier does not match algorithm\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const point = reader.readString();\n reader.assertFinished();\n return {\n algorithmName,\n publicKey: ecdsaPublicKeyFromPoint(curveIdentifier, point),\n };\n }\n\n default:\n throw new ProtocolError({\n details: { algorithmName },\n message: \"Unsupported SSH host key algorithm\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\ninterface ParsedSignatureBlob {\n signatureAlgorithm: string;\n signatureBytes: Buffer;\n}\n\nfunction parseSignatureBlob(blob: Uint8Array): ParsedSignatureBlob {\n const reader = new SshDataReader(blob);\n const signatureAlgorithm = reader.readString().toString(\"ascii\");\n const signatureBytes = reader.readString();\n // Some servers append nothing more; do not assertFinished to remain forgiving\n // of trailing bytes from extension formats.\n return { signatureAlgorithm, signatureBytes };\n}\n\nfunction isCompatibleSignatureAlgorithm(\n hostKeyAlgorithm: string,\n signatureAlgorithm: string,\n): boolean {\n if (hostKeyAlgorithm === signatureAlgorithm) return true;\n // RFC 8332: an \"ssh-rsa\" host key can sign with either rsa-sha2-256 or rsa-sha2-512.\n if (hostKeyAlgorithm === \"ssh-rsa\") {\n return signatureAlgorithm === \"rsa-sha2-256\" || signatureAlgorithm === \"rsa-sha2-512\";\n }\n return false;\n}\n\nfunction verifySignature(input: {\n data: Buffer;\n publicKey: KeyObject;\n signature: Buffer;\n signatureAlgorithm: string;\n}): boolean {\n switch (input.signatureAlgorithm) {\n case \"ssh-ed25519\":\n // Ed25519 signs over the raw data; Node's verify() with `null` algorithm.\n return cryptoVerify(null, input.data, input.publicKey, input.signature);\n\n case \"rsa-sha2-256\":\n return cryptoVerify(\"sha256\", input.data, input.publicKey, input.signature);\n\n case \"rsa-sha2-512\":\n return cryptoVerify(\"sha512\", input.data, input.publicKey, input.signature);\n\n case \"ecdsa-sha2-nistp256\":\n return cryptoVerify(\n \"sha256\",\n input.data,\n input.publicKey,\n sshEcdsaSignatureToDer(input.signature),\n );\n\n case \"ecdsa-sha2-nistp384\":\n return cryptoVerify(\n \"sha384\",\n input.data,\n input.publicKey,\n sshEcdsaSignatureToDer(input.signature),\n );\n\n case \"ecdsa-sha2-nistp521\":\n return cryptoVerify(\n \"sha512\",\n input.data,\n input.publicKey,\n sshEcdsaSignatureToDer(input.signature),\n );\n\n case \"ssh-rsa\":\n // Legacy SHA-1 RSA. Disabled by default for security; reject explicitly.\n throw new ProtocolError({\n message: \"Legacy ssh-rsa (SHA-1) host key signatures are not accepted\",\n protocol: \"sftp\",\n retryable: false,\n });\n\n default:\n throw new ProtocolError({\n details: { signatureAlgorithm: input.signatureAlgorithm },\n message: \"Unsupported SSH host key signature algorithm\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\n/**\n * Builds a Node KeyObject from RSA components (e, n) encoded as SSH mpints.\n * Uses ASN.1 DER SubjectPublicKeyInfo so that crypto.verify accepts the result.\n */\nfunction rsaPublicKeyFromComponents(e: Buffer, n: Buffer): KeyObject {\n const eDer = encodeAsn1Integer(e);\n const nDer = encodeAsn1Integer(n);\n const rsaPublicKeyDer = encodeAsn1Sequence(Buffer.concat([nDer, eDer]));\n // BIT STRING wrap: 0x03 LEN 0x00 (unused-bits) || rsaPublicKeyDer\n const bitStringContent = Buffer.concat([Buffer.from([0x00]), rsaPublicKeyDer]);\n const bitString = Buffer.concat([\n Buffer.from([0x03]),\n encodeAsn1Length(bitStringContent.length),\n bitStringContent,\n ]);\n // AlgorithmIdentifier for rsaEncryption: SEQUENCE { OID 1.2.840.113549.1.1.1, NULL }.\n const algoId = Buffer.from(\"300d06092a864886f70d010101 0500\".replace(/\\s+/g, \"\"), \"hex\");\n const spki = encodeAsn1Sequence(Buffer.concat([algoId, bitString]));\n return createPublicKey({ format: \"der\", key: spki, type: \"spki\" });\n}\n\nfunction encodeAsn1Integer(value: Buffer): Buffer {\n // Strip leading zero bytes but preserve a single zero if value is exactly 0.\n let body = value;\n while (body.length > 1 && body[0] === 0x00) body = body.subarray(1);\n // Prepend a 0x00 if the high bit is set so the integer remains positive.\n if (body.length > 0 && (body[0]! & 0x80) !== 0) {\n body = Buffer.concat([Buffer.from([0x00]), body]);\n }\n return Buffer.concat([Buffer.from([0x02]), encodeAsn1Length(body.length), body]);\n}\n\nfunction encodeAsn1Sequence(content: Buffer): Buffer {\n return Buffer.concat([Buffer.from([0x30]), encodeAsn1Length(content.length), content]);\n}\n\nfunction encodeAsn1Length(length: number): Buffer {\n if (length < 0x80) return Buffer.from([length]);\n const bytes: number[] = [];\n let n = length;\n while (n > 0) {\n bytes.unshift(n & 0xff);\n n >>>= 8;\n }\n return Buffer.from([0x80 | bytes.length, ...bytes]);\n}\n\n// -- ECDSA helpers -------------------------------------------------------------\n\n// Named-curve OIDs (RFC 5480).\nconst ECDSA_OID_BY_CURVE = {\n nistp256: \"06082a8648ce3d030107\", // secp256r1 / prime256v1\n nistp384: \"06052b81040022\", // secp384r1\n nistp521: \"06052b81040023\", // secp521r1\n} as const;\n\n// id-ecPublicKey: 1.2.840.10045.2.1\nconst ECDSA_ALGORITHM_OID_HEX = \"06072a8648ce3d0201\";\n\n/**\n * Builds a Node KeyObject from an SSH-encoded ECDSA point. The point is the\n * uncompressed SEC1 encoding (0x04 || X || Y) for nistp256/384/521.\n */\nfunction ecdsaPublicKeyFromPoint(curveIdentifier: string, point: Buffer): KeyObject {\n const oidHex = ECDSA_OID_BY_CURVE[curveIdentifier as keyof typeof ECDSA_OID_BY_CURVE];\n if (oidHex === undefined) {\n throw new ProtocolError({\n details: { curveIdentifier },\n message: \"Unsupported ECDSA curve\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n // AlgorithmIdentifier: SEQUENCE { id-ecPublicKey, namedCurve OID }\n const algoIdContent = Buffer.from(ECDSA_ALGORITHM_OID_HEX + oidHex, \"hex\");\n const algoId = encodeAsn1Sequence(algoIdContent);\n // BIT STRING wrap of the point bytes: 0x03 LEN 0x00 (unused-bits) || point\n const bitStringContent = Buffer.concat([Buffer.from([0x00]), point]);\n const bitString = Buffer.concat([\n Buffer.from([0x03]),\n encodeAsn1Length(bitStringContent.length),\n bitStringContent,\n ]);\n const spki = encodeAsn1Sequence(Buffer.concat([algoId, bitString]));\n return createPublicKey({ format: \"der\", key: spki, type: \"spki\" });\n}\n\n/**\n * Converts an SSH-format ECDSA signature blob (RFC 5656 §3.1.2:\n * `mpint r || mpint s`) into the ASN.1 DER `Ecdsa-Sig-Value` SEQUENCE that\n * `crypto.verify` expects.\n */\nfunction sshEcdsaSignatureToDer(sshSignature: Buffer): Buffer {\n const reader = new SshDataReader(sshSignature);\n const r = reader.readMpint();\n const s = reader.readMpint();\n // Trailing bytes are tolerated for the same forgiveness reasons as the outer\n // signature blob parser.\n const rDer = encodeAsn1Integer(r);\n const sDer = encodeAsn1Integer(s);\n return encodeAsn1Sequence(Buffer.concat([rDer, sDer]));\n}\n","import { Buffer } from \"node:buffer\";\nimport {\n createCipheriv,\n createDecipheriv,\n createHmac,\n timingSafeEqual,\n type Cipheriv,\n type Decipheriv,\n} from \"node:crypto\";\nimport { ProtocolError } from \"../../../errors/ZeroTransferError\";\nimport type { NegotiatedSshAlgorithms } from \"./SshAlgorithmNegotiation\";\nimport type { SshTransportDirectionKeys } from \"./SshKeyDerivation\";\nimport {\n decodeSshTransportPacket,\n encodeSshTransportPacket,\n MAX_SSH_PACKET_LENGTH,\n} from \"./SshTransportPacket\";\n\n/** Bidirectional packet protection pair for SSH transport after NEWKEYS. */\nexport interface SshTransportProtectionContext {\n inbound: SshTransportPacketUnprotector;\n outbound: SshTransportPacketProtector;\n}\n\n/**\n * Creates directional packet protectors for the currently negotiated transport algorithms.\n */\nexport function createSshTransportProtectionContext(input: {\n keys: {\n clientToServer: SshTransportDirectionKeys;\n serverToClient: SshTransportDirectionKeys;\n };\n negotiatedAlgorithms: NegotiatedSshAlgorithms;\n deterministicPadding?: boolean;\n initialInboundSequence?: number;\n initialOutboundSequence?: number;\n}): SshTransportProtectionContext {\n return {\n inbound: new SshTransportPacketUnprotector({\n encryptionAlgorithm: input.negotiatedAlgorithms.encryptionServerToClient,\n initialSequence: input.initialInboundSequence ?? 0,\n macAlgorithm: input.negotiatedAlgorithms.macServerToClient,\n keys: input.keys.serverToClient,\n }),\n outbound: new SshTransportPacketProtector({\n deterministicPadding: input.deterministicPadding ?? false,\n encryptionAlgorithm: input.negotiatedAlgorithms.encryptionClientToServer,\n initialSequence: input.initialOutboundSequence ?? 0,\n macAlgorithm: input.negotiatedAlgorithms.macClientToServer,\n keys: input.keys.clientToServer,\n }),\n };\n}\n\n/** Encrypts and authenticates outbound SSH transport packets. */\nexport class SshTransportPacketProtector {\n private readonly blockLength: number;\n private readonly cipher: Cipheriv | undefined;\n private readonly encryptionAlgorithm: string;\n private readonly macAlgorithm: string;\n private readonly macLength: number;\n private sequenceNumber: number;\n\n constructor(\n private readonly options: {\n deterministicPadding: boolean;\n encryptionAlgorithm: string;\n initialSequence: number;\n macAlgorithm: string;\n keys: SshTransportDirectionKeys;\n },\n ) {\n this.encryptionAlgorithm = options.encryptionAlgorithm;\n this.macAlgorithm = options.macAlgorithm;\n this.sequenceNumber = options.initialSequence >>> 0;\n this.blockLength = resolveBlockLength(options.encryptionAlgorithm);\n this.macLength = resolveMacLength(options.encryptionAlgorithm, options.macAlgorithm);\n this.cipher = createCipher(\n options.encryptionAlgorithm,\n options.keys.encryptionKey,\n options.keys.iv,\n );\n }\n\n getSequenceNumber(): number {\n return this.sequenceNumber;\n }\n\n protectPayload(payload: Uint8Array): Buffer {\n const clearPacket = encodeSshTransportPacket(payload, {\n blockSize: this.blockLength,\n randomPadding: !this.options.deterministicPadding,\n });\n const mac = computeMac(\n this.macAlgorithm,\n this.options.keys.macKey,\n this.sequenceNumber,\n clearPacket,\n this.macLength,\n );\n const encrypted = this.cipher === undefined ? clearPacket : this.cipher.update(clearPacket);\n\n this.sequenceNumber = (this.sequenceNumber + 1) >>> 0;\n return Buffer.concat([encrypted, mac]);\n }\n}\n\n/** Verifies and decrypts inbound SSH transport packets. */\nexport class SshTransportPacketUnprotector {\n private readonly blockLength: number;\n private readonly decipher: Decipheriv | undefined;\n private readonly encryptionAlgorithm: string;\n private readonly macAlgorithm: string;\n private readonly macLength: number;\n private sequenceNumber: number;\n\n // Streaming framing state for pushBytes()\n private framePartialDecrypted: Buffer | undefined;\n private framePendingRaw = Buffer.alloc(0);\n private frameRemainingNeeded: number | undefined;\n\n constructor(\n private readonly options: {\n encryptionAlgorithm: string;\n initialSequence: number;\n macAlgorithm: string;\n keys: SshTransportDirectionKeys;\n },\n ) {\n this.encryptionAlgorithm = options.encryptionAlgorithm;\n this.macAlgorithm = options.macAlgorithm;\n this.sequenceNumber = options.initialSequence >>> 0;\n this.blockLength = resolveBlockLength(options.encryptionAlgorithm);\n this.macLength = resolveMacLength(options.encryptionAlgorithm, options.macAlgorithm);\n this.decipher = createDecipher(\n options.encryptionAlgorithm,\n options.keys.encryptionKey,\n options.keys.iv,\n );\n }\n\n getSequenceNumber(): number {\n return this.sequenceNumber;\n }\n\n /**\n * Feeds raw encrypted bytes from the socket and returns any fully decoded payloads.\n * Maintains internal framing state across calls - pass each `data` event chunk directly.\n */\n pushBytes(chunk: Buffer): Buffer[] {\n this.framePendingRaw = Buffer.concat([this.framePendingRaw, chunk]);\n const results: Buffer[] = [];\n\n while (true) {\n if (this.framePartialDecrypted === undefined) {\n // Phase 1: buffer the first cipher block to read the encrypted packet_length.\n if (this.framePendingRaw.length < this.blockLength) break;\n const firstBlock = this.framePendingRaw.subarray(0, this.blockLength);\n this.framePendingRaw = Buffer.from(this.framePendingRaw.subarray(this.blockLength));\n this.framePartialDecrypted = this.decipher\n ? Buffer.from(this.decipher.update(firstBlock))\n : Buffer.from(firstBlock);\n const packetLength = this.framePartialDecrypted.readUInt32BE(0);\n if (packetLength > MAX_SSH_PACKET_LENGTH) {\n throw new ProtocolError({\n details: { maxPacketLength: MAX_SSH_PACKET_LENGTH, packetLength },\n message: \"SSH encrypted packet length exceeds the maximum accepted size\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n // Total encrypted bytes = 4 (length field) + packetLength.\n // Remaining raw after first block = (4 + packetLength - blockLength) + macLength.\n const remaining = 4 + packetLength - this.blockLength + this.macLength;\n if (remaining < 0) {\n throw new ProtocolError({\n details: { blockLength: this.blockLength, packetLength },\n message: \"SSH encrypted packet_length is smaller than one cipher block\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n this.frameRemainingNeeded = remaining;\n }\n\n const needed = this.frameRemainingNeeded!;\n if (this.framePendingRaw.length < needed) break;\n\n const encryptedRest = this.framePendingRaw.subarray(0, needed - this.macLength);\n const receivedMac = this.framePendingRaw.subarray(needed - this.macLength, needed);\n this.framePendingRaw = Buffer.from(this.framePendingRaw.subarray(needed));\n\n const decryptedRest =\n encryptedRest.length > 0\n ? this.decipher\n ? Buffer.from(this.decipher.update(encryptedRest))\n : Buffer.from(encryptedRest)\n : Buffer.alloc(0);\n\n const clearPacket = Buffer.concat([this.framePartialDecrypted, decryptedRest]);\n const expectedMac = computeMac(\n this.macAlgorithm,\n this.options.keys.macKey,\n this.sequenceNumber,\n clearPacket,\n this.macLength,\n );\n\n if (!timingSafeEqual(receivedMac, expectedMac)) {\n throw new ProtocolError({\n message: \"SSH packet MAC verification failed\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n this.sequenceNumber = (this.sequenceNumber + 1) >>> 0;\n results.push(decodeSshTransportPacket(clearPacket).payload);\n\n this.framePartialDecrypted = undefined;\n this.frameRemainingNeeded = undefined;\n }\n\n return results;\n }\n\n unprotectPayload(packet: Uint8Array): Buffer {\n const frame = Buffer.from(packet);\n if (frame.length < this.macLength) {\n throw new ProtocolError({\n details: { length: frame.length, macLength: this.macLength },\n message: \"SSH packet is shorter than its expected MAC length\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const macOffset = frame.length - this.macLength;\n const encryptedPacket = frame.subarray(0, macOffset);\n const receivedMac = frame.subarray(macOffset);\n const clearPacket =\n this.decipher === undefined ? encryptedPacket : this.decipher.update(encryptedPacket);\n const expectedMac = computeMac(\n this.macAlgorithm,\n this.options.keys.macKey,\n this.sequenceNumber,\n clearPacket,\n this.macLength,\n );\n\n if (!timingSafeEqual(receivedMac, expectedMac)) {\n throw new ProtocolError({\n message: \"SSH packet MAC verification failed\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n this.sequenceNumber = (this.sequenceNumber + 1) >>> 0;\n return decodeSshTransportPacket(clearPacket).payload;\n }\n}\n\nfunction createCipher(algorithm: string, key: Buffer, iv: Buffer): Cipheriv | undefined {\n if (algorithm === \"none\") {\n return undefined;\n }\n\n validateCipherMaterial(algorithm, key, iv);\n const cipher = createCipheriv(toOpenSslCipherName(algorithm), key, iv);\n cipher.setAutoPadding(false);\n return cipher;\n}\n\nfunction createDecipher(algorithm: string, key: Buffer, iv: Buffer): Decipheriv | undefined {\n if (algorithm === \"none\") {\n return undefined;\n }\n\n validateCipherMaterial(algorithm, key, iv);\n const decipher = createDecipheriv(toOpenSslCipherName(algorithm), key, iv);\n decipher.setAutoPadding(false);\n return decipher;\n}\n\nfunction toOpenSslCipherName(algorithm: string): string {\n switch (algorithm) {\n case \"aes128-ctr\":\n return \"aes-128-ctr\";\n case \"aes256-ctr\":\n return \"aes-256-ctr\";\n default:\n return algorithm;\n }\n}\n\nfunction validateCipherMaterial(algorithm: string, key: Buffer, iv: Buffer): void {\n const expectedKeyLength = resolveCipherKeyLength(algorithm);\n const expectedIvLength = resolveCipherIvLength(algorithm);\n\n if (key.length !== expectedKeyLength || iv.length !== expectedIvLength) {\n throw new ProtocolError({\n details: {\n algorithm,\n ivLength: iv.length,\n keyLength: key.length,\n },\n message: \"SSH cipher key material does not match algorithm requirements\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveCipherKeyLength(algorithm: string): number {\n switch (algorithm) {\n case \"aes128-ctr\":\n return 16;\n case \"aes256-ctr\":\n return 32;\n default:\n throw new ProtocolError({\n details: { algorithm },\n message: \"Unsupported SSH cipher algorithm for transport protection\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveCipherIvLength(algorithm: string): number {\n switch (algorithm) {\n case \"aes128-ctr\":\n case \"aes256-ctr\":\n return 16;\n default:\n throw new ProtocolError({\n details: { algorithm },\n message: \"Unsupported SSH cipher IV length for transport protection\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveBlockLength(algorithm: string): number {\n switch (algorithm) {\n case \"aes128-ctr\":\n case \"aes256-ctr\":\n return 16;\n case \"none\":\n return 8; // RFC 4253 §6.1: minimum block size for framing with no cipher\n default:\n throw new ProtocolError({\n details: { algorithm },\n message: \"Unsupported SSH cipher block length for transport protection\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction resolveMacLength(encryptionAlgorithm: string, macAlgorithm: string): number {\n if (encryptionAlgorithm === \"none\") {\n return 0;\n }\n\n switch (macAlgorithm) {\n case \"hmac-sha2-256\":\n return 32;\n case \"hmac-sha2-512\":\n return 64;\n default:\n throw new ProtocolError({\n details: { macAlgorithm },\n message: \"Unsupported SSH MAC algorithm for transport protection\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n}\n\nfunction computeMac(\n macAlgorithm: string,\n macKey: Buffer,\n sequence: number,\n packet: Buffer,\n macLength: number,\n): Buffer {\n if (macLength === 0) {\n return Buffer.alloc(0);\n }\n\n const hashName = macAlgorithm === \"hmac-sha2-512\" ? \"sha512\" : \"sha256\";\n // Defense-in-depth: zero-init this small buffer so any future change in MAC\n // input length cannot leak uninitialized memory into the HMAC tag.\n const sequenceBuffer = Buffer.alloc(4);\n sequenceBuffer.writeUInt32BE(sequence >>> 0, 0);\n\n return createHmac(hashName, macKey)\n .update(sequenceBuffer)\n .update(packet)\n .digest()\n .subarray(0, macLength);\n}\n","/**\n * SSH Authentication Protocol message codecs (RFC 4252).\n *\n * Covers:\n * - SSH_MSG_SERVICE_REQUEST / SSH_MSG_SERVICE_ACCEPT\n * - SSH_MSG_USERAUTH_REQUEST (none, password, publickey)\n * - SSH_MSG_USERAUTH_SUCCESS / SSH_MSG_USERAUTH_FAILURE\n * - SSH_MSG_USERAUTH_BANNER\n * - SSH_MSG_USERAUTH_PK_OK (publickey pre-auth query response)\n * - SSH_MSG_USERAUTH_INFO_REQUEST / SSH_MSG_USERAUTH_INFO_RESPONSE (keyboard-interactive, RFC 4256)\n */\nimport type { Buffer } from \"node:buffer\";\nimport { ParseError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader } from \"../binary/SshDataReader\";\nimport { SshDataWriter } from \"../binary/SshDataWriter\";\n\n// -- Message type constants --------------------------------------------------\n\nexport const SSH_MSG_SERVICE_REQUEST = 5;\nexport const SSH_MSG_SERVICE_ACCEPT = 6;\nexport const SSH_MSG_USERAUTH_REQUEST = 50;\nexport const SSH_MSG_USERAUTH_FAILURE = 51;\nexport const SSH_MSG_USERAUTH_SUCCESS = 52;\nexport const SSH_MSG_USERAUTH_BANNER = 53;\nexport const SSH_MSG_USERAUTH_PK_OK = 60;\nexport const SSH_MSG_USERAUTH_INFO_REQUEST = 60; // keyboard-interactive\nexport const SSH_MSG_USERAUTH_INFO_RESPONSE = 61; // keyboard-interactive\n\n// -- Service request / accept ------------------------------------------------\n\n/**\n * Encodes SSH_MSG_SERVICE_REQUEST payload (RFC 4253 §10).\n * The service name is always \"ssh-userauth\" before authentication.\n */\nexport function encodeSshServiceRequest(serviceName: string): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_SERVICE_REQUEST)\n .writeString(serviceName, \"utf8\")\n .toBuffer();\n}\n\n/**\n * Decodes SSH_MSG_SERVICE_ACCEPT payload.\n * Returns the echoed service name.\n */\nexport function decodeSshServiceAccept(payload: Uint8Array): { serviceName: string } {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_SERVICE_ACCEPT) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_SERVICE_ACCEPT\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n return { serviceName: reader.readString().toString(\"utf8\") };\n}\n\n// -- USERAUTH REQUEST ---------------------------------------------------------\n\n/** Common fields for all USERAUTH request methods. */\ninterface UserauthRequestBase {\n serviceName: string;\n username: string;\n}\n\n/** SSH_MSG_USERAUTH_REQUEST with method \"none\" - probes allowed methods. */\nexport function encodeUserauthRequestNone(args: UserauthRequestBase): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_USERAUTH_REQUEST)\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"none\", \"ascii\")\n .toBuffer();\n}\n\n/** SSH_MSG_USERAUTH_REQUEST with method \"password\". */\nexport function encodeUserauthRequestPassword(\n args: UserauthRequestBase & { password: string },\n): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_USERAUTH_REQUEST)\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"password\", \"ascii\")\n .writeBoolean(false) // change-password is not supported\n .writeString(args.password, \"utf8\")\n .toBuffer();\n}\n\n/**\n * SSH_MSG_USERAUTH_REQUEST with method \"publickey\" - pre-auth query.\n * Asks the server if it would accept a signature from this key, without providing one.\n */\nexport function encodeUserauthRequestPublickeyQuery(\n args: UserauthRequestBase & { algorithmName: string; publicKeyBlob: Uint8Array },\n): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_USERAUTH_REQUEST)\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"publickey\", \"ascii\")\n .writeBoolean(false)\n .writeString(args.algorithmName, \"ascii\")\n .writeString(args.publicKeyBlob)\n .toBuffer();\n}\n\n/**\n * SSH_MSG_USERAUTH_REQUEST with method \"publickey\" - actual signature.\n * sessionId is the exchange hash / session identifier from key exchange.\n */\nexport function encodeUserauthRequestPublickeySign(\n args: UserauthRequestBase & {\n algorithmName: string;\n publicKeyBlob: Uint8Array;\n signature: Uint8Array;\n },\n): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_USERAUTH_REQUEST)\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"publickey\", \"ascii\")\n .writeBoolean(true)\n .writeString(args.algorithmName, \"ascii\")\n .writeString(args.publicKeyBlob)\n .writeString(args.signature)\n .toBuffer();\n}\n\n/**\n * Builds the exact byte sequence that must be signed for publickey auth (RFC 4252 §7).\n * The signature covers: session_id || SSH_MSG_USERAUTH_REQUEST || fields.\n */\nexport function buildPublickeySignData(\n args: UserauthRequestBase & {\n algorithmName: string;\n publicKeyBlob: Uint8Array;\n sessionId: Uint8Array;\n },\n): Buffer {\n return new SshDataWriter()\n .writeString(args.sessionId) // length-prefixed session_id\n .writeByte(SSH_MSG_USERAUTH_REQUEST)\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"publickey\", \"ascii\")\n .writeBoolean(true)\n .writeString(args.algorithmName, \"ascii\")\n .writeString(args.publicKeyBlob)\n .toBuffer();\n}\n\n// -- USERAUTH FAILURE ---------------------------------------------------------\n\nexport interface SshUserauthFailure {\n allowedAuthentications: string[];\n partialSuccess: boolean;\n}\n\n/**\n * Decodes SSH_MSG_USERAUTH_FAILURE payload.\n */\nexport function decodeSshUserauthFailure(payload: Uint8Array): SshUserauthFailure {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_USERAUTH_FAILURE) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_USERAUTH_FAILURE\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const nameList = reader.readString().toString(\"ascii\");\n const allowedAuthentications = nameList.length === 0 ? [] : nameList.split(\",\");\n const partialSuccess = reader.readBoolean();\n return { allowedAuthentications, partialSuccess };\n}\n\n// -- USERAUTH BANNER ---------------------------------------------------------\n\nexport interface SshUserauthBanner {\n languageTag: string;\n message: string;\n}\n\nexport function decodeSshUserauthBanner(payload: Uint8Array): SshUserauthBanner {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_USERAUTH_BANNER) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_USERAUTH_BANNER\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const message = reader.readString().toString(\"utf8\");\n const languageTag = reader.readString().toString(\"ascii\");\n return { languageTag, message };\n}\n\n// -- USERAUTH_PK_OK -----------------------------------------------------------\n\nexport interface SshUserauthPkOk {\n algorithmName: string;\n publicKeyBlob: Buffer;\n}\n\nexport function decodeSshUserauthPkOk(payload: Uint8Array): SshUserauthPkOk {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_USERAUTH_PK_OK) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_USERAUTH_PK_OK\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n return {\n algorithmName: reader.readString().toString(\"ascii\"),\n publicKeyBlob: reader.readString(),\n };\n}\n\n// -- Keyboard-interactive (RFC 4256) -----------------------------------------\n\nexport interface SshUserauthInfoRequest {\n instruction: string;\n languageTag: string;\n name: string;\n prompts: Array<{ echo: boolean; prompt: string }>;\n}\n\nexport function decodeSshUserauthInfoRequest(payload: Uint8Array): SshUserauthInfoRequest {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_USERAUTH_INFO_REQUEST) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_USERAUTH_INFO_REQUEST\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const name = reader.readString().toString(\"utf8\");\n const instruction = reader.readString().toString(\"utf8\");\n const languageTag = reader.readString().toString(\"ascii\");\n const count = reader.readUint32();\n const prompts: Array<{ echo: boolean; prompt: string }> = [];\n for (let i = 0; i < count; i++) {\n const prompt = reader.readString().toString(\"utf8\");\n const echo = reader.readBoolean();\n prompts.push({ echo, prompt });\n }\n return { instruction, languageTag, name, prompts };\n}\n\nexport function encodeSshUserauthInfoResponse(responses: string[]): Buffer {\n const writer = new SshDataWriter()\n .writeByte(SSH_MSG_USERAUTH_INFO_RESPONSE)\n .writeUint32(responses.length);\n for (const r of responses) {\n writer.writeString(r, \"utf8\");\n }\n return writer.toBuffer();\n}\n","/**\n * SSH authentication session (RFC 4252).\n *\n * Drives service-request → USERAUTH exchange over an already-encrypted\n * SshTransportConnection. Supports:\n * - none (probes allowed methods, satisfies some servers)\n * - password\n * - publickey (query + sign; external signing callback)\n * - keyboard-interactive (caller supplies responses via callback)\n */\nimport type { Buffer } from \"node:buffer\";\nimport { AuthenticationError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataWriter } from \"../binary/SshDataWriter\";\nimport {\n SSH_MSG_USERAUTH_BANNER,\n SSH_MSG_USERAUTH_FAILURE,\n SSH_MSG_USERAUTH_INFO_REQUEST,\n SSH_MSG_USERAUTH_PK_OK,\n SSH_MSG_USERAUTH_SUCCESS,\n buildPublickeySignData,\n decodeSshServiceAccept,\n decodeSshUserauthBanner,\n decodeSshUserauthFailure,\n decodeSshUserauthInfoRequest,\n decodeSshUserauthPkOk,\n encodeUserauthRequestPassword,\n encodeUserauthRequestPublickeyQuery,\n encodeUserauthRequestPublickeySign,\n encodeSshServiceRequest,\n encodeSshUserauthInfoResponse,\n} from \"./SshAuthMessages\";\nimport type { SshTransportConnection } from \"../transport/SshTransportConnection\";\n\nconst SSH_USERAUTH_SERVICE = \"ssh-userauth\";\nconst SSH_CONNECTION_SERVICE = \"ssh-connection\";\n\n// -- Credential shapes --------------------------------------------------------\n\nexport interface SshPasswordCredential {\n type: \"password\";\n username: string;\n password: string;\n}\n\nexport interface SshPublickeyCredential {\n type: \"publickey\";\n username: string;\n algorithmName: string;\n /** Raw public key blob in SSH wire format (e.g. the bytes returned by ssh-keygen -e -f key.pub). */\n publicKeyBlob: Uint8Array;\n /**\n * Signs the challenge data. The data is already the complete sign-data per RFC 4252 §7.\n * Should return the signature blob (without algorithm prefix; caller adds wrapping).\n */\n sign: (data: Uint8Array) => Promise<Uint8Array> | Uint8Array;\n}\n\nexport interface SshKeyboardInteractiveCredential {\n type: \"keyboard-interactive\";\n username: string;\n /**\n * Called for each INFO_REQUEST round. Return one string per prompt in order.\n */\n respond: (\n name: string,\n instruction: string,\n prompts: Array<{ echo: boolean; prompt: string }>,\n ) => Promise<string[]> | string[];\n}\n\nexport type SshCredential =\n | SshPasswordCredential\n | SshPublickeyCredential\n | SshKeyboardInteractiveCredential;\n\nexport interface SshAuthOptions {\n credential: SshCredential;\n /** SSH session id (exchange hash) from key exchange - required for publickey signing. */\n sessionId: Uint8Array;\n /** Maximum number of USERAUTH_FAILURE retries before giving up. Defaults to 4. */\n maxAttempts?: number;\n}\n\nexport interface SshAuthResult {\n /** Banner lines received from the server during authentication. */\n bannerLines: string[];\n /** Auth method that succeeded. */\n method: string;\n}\n\n/**\n * Runs SSH user authentication over an encrypted transport connection.\n *\n * Call this after `SshTransportConnection.connect()` completes.\n * Returns a generator of inbound payloads for the upper (connection) layer to consume.\n * Resolves with an `SshAuthResult` on success; throws `AuthenticationError` on failure.\n */\nexport class SshAuthSession {\n constructor(private readonly transport: SshTransportConnection) {}\n\n async authenticate(options: SshAuthOptions): Promise<SshAuthResult> {\n const { credential, sessionId, maxAttempts = 4 } = options;\n const bannerLines: string[] = [];\n\n // 1. Request the ssh-userauth service.\n this.transport.sendPayload(encodeSshServiceRequest(SSH_USERAUTH_SERVICE));\n\n // Wait for SERVICE_ACCEPT.\n const serviceAcceptPayload = await this.nextPayload();\n decodeSshServiceAccept(serviceAcceptPayload);\n\n // 2. Run the auth exchange.\n let attempts = 0;\n\n while (attempts < maxAttempts) {\n attempts += 1;\n\n const method = credential.type;\n\n switch (credential.type) {\n case \"password\": {\n this.transport.sendPayload(\n encodeUserauthRequestPassword({\n password: credential.password,\n serviceName: SSH_CONNECTION_SERVICE,\n username: credential.username,\n }),\n );\n break;\n }\n\n case \"publickey\": {\n // Phase 1: query whether server accepts this key.\n this.transport.sendPayload(\n encodeUserauthRequestPublickeyQuery({\n algorithmName: credential.algorithmName,\n publicKeyBlob: credential.publicKeyBlob,\n serviceName: SSH_CONNECTION_SERVICE,\n username: credential.username,\n }),\n );\n\n const queryResponse = await this.nextPayloadSkippingBanners(bannerLines);\n const queryMsgType = queryResponse[0];\n\n if (queryMsgType === SSH_MSG_USERAUTH_FAILURE) {\n const failure = decodeSshUserauthFailure(queryResponse);\n throw new AuthenticationError({\n details: { allowed: failure.allowedAuthentications },\n message: `SSH server does not accept public key for user \"${credential.username}\"`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n if (queryMsgType !== SSH_MSG_USERAUTH_PK_OK) {\n throw new AuthenticationError({\n details: { msgType: queryMsgType },\n message: \"Unexpected server response to publickey query\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n decodeSshUserauthPkOk(queryResponse); // validates structure\n\n // Phase 2: sign and send.\n const signData = buildPublickeySignData({\n algorithmName: credential.algorithmName,\n publicKeyBlob: credential.publicKeyBlob,\n serviceName: SSH_CONNECTION_SERVICE,\n sessionId,\n username: credential.username,\n });\n\n const rawSignature = await credential.sign(signData);\n const signatureBlob = buildSignatureBlob(credential.algorithmName, rawSignature);\n\n this.transport.sendPayload(\n encodeUserauthRequestPublickeySign({\n algorithmName: credential.algorithmName,\n publicKeyBlob: credential.publicKeyBlob,\n serviceName: SSH_CONNECTION_SERVICE,\n signature: signatureBlob,\n username: credential.username,\n }),\n );\n break;\n }\n\n case \"keyboard-interactive\": {\n // RFC 4256 §3.1: send the keyboard-interactive USERAUTH_REQUEST\n // directly. The server then drives one or more INFO_REQUEST rounds.\n await this.runKeyboardInteractiveRounds(credential, bannerLines);\n const kiResult = await this.nextPayloadSkippingBanners(bannerLines);\n if (kiResult[0] === SSH_MSG_USERAUTH_SUCCESS) {\n return { bannerLines, method: \"keyboard-interactive\" };\n }\n if (kiResult[0] === SSH_MSG_USERAUTH_FAILURE) {\n throw new AuthenticationError({\n details: { allowed: decodeSshUserauthFailure(kiResult).allowedAuthentications },\n message: `SSH keyboard-interactive authentication failed for user \"${credential.username}\"`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n throw new AuthenticationError({\n details: { msgType: kiResult[0] },\n message: \"Unexpected message type after keyboard-interactive exchange\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n }\n\n const response = await this.nextPayloadSkippingBanners(bannerLines);\n const responseMsgType = response[0];\n\n if (responseMsgType === SSH_MSG_USERAUTH_SUCCESS) {\n return { bannerLines, method };\n }\n\n if (responseMsgType === SSH_MSG_USERAUTH_FAILURE) {\n const failure = decodeSshUserauthFailure(response);\n\n if (attempts >= maxAttempts || !failure.allowedAuthentications.includes(credential.type)) {\n throw new AuthenticationError({\n details: { allowed: failure.allowedAuthentications, attempts },\n message: `SSH authentication failed for user \"${credential.username}\" after ${attempts} attempt(s)`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n // Server rejected this attempt but allows retry - loop.\n continue;\n }\n\n throw new AuthenticationError({\n details: { msgType: responseMsgType },\n message: \"Unexpected message type during SSH authentication\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n throw new AuthenticationError({\n details: { maxAttempts },\n message: `SSH authentication exceeded maximum attempts (${maxAttempts})`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n // -- Private helpers ------------------------------------------------------\n\n private async runKeyboardInteractiveRounds(\n credential: SshKeyboardInteractiveCredential,\n bannerLines: string[],\n ): Promise<void> {\n // Send the keyboard-interactive auth request now that we know the server accepts it.\n this.transport.sendPayload(\n buildKiRequest({ serviceName: SSH_CONNECTION_SERVICE, username: credential.username }),\n );\n\n while (true) {\n const payload = await this.nextPayloadSkippingBanners(bannerLines);\n const msgType = payload[0];\n\n if (msgType === SSH_MSG_USERAUTH_INFO_REQUEST) {\n const infoReq = decodeSshUserauthInfoRequest(payload);\n let responses: string[];\n try {\n responses = await credential.respond(infoReq.name, infoReq.instruction, infoReq.prompts);\n } catch (cause) {\n throw new AuthenticationError({\n cause,\n message: `SSH keyboard-interactive callback failed for user \"${credential.username}\"`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n this.transport.sendPayload(encodeSshUserauthInfoResponse(responses));\n continue;\n }\n\n // Put the payload back in the caller's view by re-emitting - handled by returning.\n this.pendingPayload = payload;\n return;\n }\n }\n\n private pendingPayload: Buffer | undefined;\n\n private async nextPayload(): Promise<Buffer> {\n if (this.pendingPayload !== undefined) {\n const p = this.pendingPayload;\n this.pendingPayload = undefined;\n return p;\n }\n const result = await this.transport.receivePayloads().next();\n if (result.done === true) {\n throw new AuthenticationError({\n message: \"SSH connection closed during authentication\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n return result.value;\n }\n\n private async nextPayloadSkippingBanners(bannerLines: string[]): Promise<Buffer> {\n while (true) {\n const payload = await this.nextPayload();\n if (payload[0] === SSH_MSG_USERAUTH_BANNER) {\n bannerLines.push(decodeSshUserauthBanner(payload).message);\n continue;\n }\n return payload;\n }\n }\n}\n\n// -- Helpers ------------------------------------------------------------------\n\n/**\n * Wraps a raw signature value in an SSH \"sig\" blob:\n * string algorithm-name\n * string signature-bytes\n */\nfunction buildSignatureBlob(algorithmName: string, rawSignature: Uint8Array): Buffer {\n return new SshDataWriter()\n .writeString(algorithmName, \"ascii\")\n .writeString(rawSignature)\n .toBuffer();\n}\n\n/**\n * Encodes keyboard-interactive USERAUTH_REQUEST (RFC 4256 §3.1).\n */\nfunction buildKiRequest(args: { serviceName: string; username: string }): Buffer {\n return new SshDataWriter()\n .writeByte(50) // SSH_MSG_USERAUTH_REQUEST\n .writeString(args.username, \"utf8\")\n .writeString(args.serviceName, \"utf8\")\n .writeString(\"keyboard-interactive\", \"ascii\")\n .writeString(\"\", \"utf8\") // language tag (deprecated, empty)\n .writeString(\"\", \"utf8\") // submethods (empty = server chooses)\n .toBuffer();\n}\n","/**\n * Builds an {@link SshPublickeyCredential} from a Node `KeyObject` private key.\n *\n * Supported algorithms:\n * - Ed25519 → signature algorithm `ssh-ed25519`\n * - RSA → signature algorithm `rsa-sha2-512` (preferred) or `rsa-sha2-256`\n *\n * Node 17+ accepts OpenSSH-format private keys (the `-----BEGIN OPENSSH PRIVATE KEY-----`\n * envelope) directly via `crypto.createPrivateKey`, so the caller can pass either\n * OpenSSH or PKCS#8 PEM material.\n *\n * Encrypted keys are supported by passing a `passphrase` to `createPrivateKey`\n * before calling this helper; this module does not perform decryption.\n */\nimport { Buffer } from \"node:buffer\";\nimport { createPublicKey, sign as cryptoSign, type KeyObject } from \"node:crypto\";\nimport { ConfigurationError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataWriter } from \"../binary/SshDataWriter\";\nimport type { SshPublickeyCredential } from \"./SshAuthSession\";\n\nconst ED25519_RAW_KEY_LENGTH = 32;\n// DER SubjectPublicKeyInfo prefix for Ed25519 public keys (RFC 8410).\nconst ED25519_SPKI_PREFIX_LENGTH = 12;\n\nexport interface BuildPublickeyCredentialOptions {\n /** Username to authenticate as. */\n username: string;\n /** Decoded private key (OpenSSH or PKCS8 PEM accepted by `crypto.createPrivateKey`). */\n privateKey: KeyObject;\n /**\n * For RSA keys, the SSH signature algorithm. Defaults to `rsa-sha2-512`.\n * Ignored for Ed25519 keys.\n */\n rsaSignatureAlgorithm?: \"rsa-sha2-256\" | \"rsa-sha2-512\";\n}\n\nexport function buildPublickeyCredential(\n options: BuildPublickeyCredentialOptions,\n): SshPublickeyCredential {\n const { privateKey, username } = options;\n const publicKey = createPublicKey(privateKey);\n\n switch (privateKey.asymmetricKeyType) {\n case \"ed25519\": {\n const spki = publicKey.export({ format: \"der\", type: \"spki\" });\n if (spki.length !== ED25519_SPKI_PREFIX_LENGTH + ED25519_RAW_KEY_LENGTH) {\n throw createInvalidKeyError(\"Ed25519 SPKI export has unexpected length\");\n }\n const raw = spki.subarray(ED25519_SPKI_PREFIX_LENGTH);\n const publicKeyBlob = new SshDataWriter()\n .writeString(\"ssh-ed25519\", \"ascii\")\n .writeString(raw)\n .toBuffer();\n return {\n algorithmName: \"ssh-ed25519\",\n publicKeyBlob,\n sign: (data: Uint8Array): Buffer => cryptoSign(null, Buffer.from(data), privateKey),\n type: \"publickey\",\n username,\n };\n }\n\n case \"rsa\": {\n const algorithmName = options.rsaSignatureAlgorithm ?? \"rsa-sha2-512\";\n const hash = algorithmName === \"rsa-sha2-256\" ? \"sha256\" : \"sha512\";\n const jwk = publicKey.export({ format: \"jwk\" });\n if (jwk.n === undefined || jwk.e === undefined) {\n throw createInvalidKeyError(\"RSA public key is missing modulus or exponent\");\n }\n // SSH wire format uses two's-complement mpints. base64url JWK fields are\n // unsigned big-endian, so prepend a 0x00 if the high bit is set.\n const n = base64UrlToMpint(jwk.n);\n const e = base64UrlToMpint(jwk.e);\n const publicKeyBlob = new SshDataWriter()\n .writeString(\"ssh-rsa\", \"ascii\")\n .writeMpint(e)\n .writeMpint(n)\n .toBuffer();\n return {\n algorithmName,\n publicKeyBlob,\n sign: (data: Uint8Array): Buffer => cryptoSign(hash, Buffer.from(data), privateKey),\n type: \"publickey\",\n username,\n };\n }\n\n default:\n throw createInvalidKeyError(\n `Unsupported SSH private key type: ${privateKey.asymmetricKeyType ?? \"unknown\"}`,\n );\n }\n}\n\nfunction base64UrlToMpint(value: string): Buffer {\n // base64url → base64\n const padded = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const buffer = Buffer.from(padded, \"base64\");\n // writeMpint will add the required leading 0x00 if the high bit is set.\n return buffer;\n}\n\nfunction createInvalidKeyError(message: string): ConfigurationError {\n return new ConfigurationError({\n message,\n protocol: \"sftp\",\n retryable: false,\n });\n}\n","/**\n * SSH Connection Protocol message codecs (RFC 4254).\n *\n * Covers:\n * - SSH_MSG_CHANNEL_OPEN / CHANNEL_OPEN_CONFIRMATION / CHANNEL_OPEN_FAILURE\n * - SSH_MSG_CHANNEL_REQUEST (exec, subsystem, pty-req, env, signal, exit-status)\n * - SSH_MSG_CHANNEL_SUCCESS / CHANNEL_FAILURE\n * - SSH_MSG_CHANNEL_DATA / CHANNEL_EXTENDED_DATA\n * - SSH_MSG_CHANNEL_WINDOW_ADJUST\n * - SSH_MSG_CHANNEL_EOF / CHANNEL_CLOSE\n */\nimport type { Buffer } from \"node:buffer\";\nimport { ParseError } from \"../../../errors/ZeroTransferError\";\nimport { SshDataReader } from \"../binary/SshDataReader\";\nimport { SshDataWriter } from \"../binary/SshDataWriter\";\n\n// -- Message type constants --------------------------------------------------\n\nexport const SSH_MSG_CHANNEL_OPEN = 90;\nexport const SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91;\nexport const SSH_MSG_CHANNEL_OPEN_FAILURE = 92;\nexport const SSH_MSG_CHANNEL_WINDOW_ADJUST = 93;\nexport const SSH_MSG_CHANNEL_DATA = 94;\nexport const SSH_MSG_CHANNEL_EXTENDED_DATA = 95;\nexport const SSH_MSG_CHANNEL_EOF = 96;\nexport const SSH_MSG_CHANNEL_CLOSE = 97;\nexport const SSH_MSG_CHANNEL_REQUEST = 98;\nexport const SSH_MSG_CHANNEL_SUCCESS = 99;\nexport const SSH_MSG_CHANNEL_FAILURE = 100;\n\n/** Channel open failure reason codes (RFC 4254 §5.1). */\nexport const SshChannelOpenFailureReason = {\n ADMINISTRATIVELY_PROHIBITED: 1,\n CONNECT_FAILED: 2,\n UNKNOWN_CHANNEL_TYPE: 3,\n RESOURCE_SHORTAGE: 4,\n} as const;\n\n// -- CHANNEL_OPEN -------------------------------------------------------------\n\nexport interface SshChannelOpenArgs {\n channelType: string;\n senderChannel: number;\n /** Initial local window size (bytes). */\n initialWindowSize: number;\n /** Maximum packet size the sender can accept. */\n maxPacketSize: number;\n}\n\nexport function encodeSshChannelOpen(args: SshChannelOpenArgs): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_OPEN)\n .writeString(args.channelType, \"ascii\")\n .writeUint32(args.senderChannel)\n .writeUint32(args.initialWindowSize)\n .writeUint32(args.maxPacketSize)\n .toBuffer();\n}\n\n// -- CHANNEL_OPEN_CONFIRMATION -------------------------------------------------\n\nexport interface SshChannelOpenConfirmation {\n recipientChannel: number;\n senderChannel: number;\n initialWindowSize: number;\n maxPacketSize: number;\n}\n\nexport function decodeSshChannelOpenConfirmation(payload: Uint8Array): SshChannelOpenConfirmation {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_OPEN_CONFIRMATION\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const recipientChannel = reader.readUint32();\n const senderChannel = reader.readUint32();\n const initialWindowSize = reader.readUint32();\n const maxPacketSize = reader.readUint32();\n return { initialWindowSize, maxPacketSize, recipientChannel, senderChannel };\n}\n\n// -- CHANNEL_OPEN_FAILURE ------------------------------------------------------\n\nexport interface SshChannelOpenFailure {\n recipientChannel: number;\n reasonCode: number;\n description: string;\n languageTag: string;\n}\n\nexport function decodeSshChannelOpenFailure(payload: Uint8Array): SshChannelOpenFailure {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_CHANNEL_OPEN_FAILURE) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_OPEN_FAILURE\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const recipientChannel = reader.readUint32();\n const reasonCode = reader.readUint32();\n const description = reader.readString().toString(\"utf8\");\n const languageTag = reader.readString().toString(\"ascii\");\n return { description, languageTag, reasonCode, recipientChannel };\n}\n\n// -- CHANNEL_REQUEST -----------------------------------------------------------\n\nexport function encodeSshChannelRequestSubsystem(args: {\n recipientChannel: number;\n subsystemName: string;\n wantReply: boolean;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_REQUEST)\n .writeUint32(args.recipientChannel)\n .writeString(\"subsystem\", \"ascii\")\n .writeBoolean(args.wantReply)\n .writeString(args.subsystemName, \"ascii\")\n .toBuffer();\n}\n\nexport function encodeSshChannelRequestExec(args: {\n recipientChannel: number;\n command: string;\n wantReply: boolean;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_REQUEST)\n .writeUint32(args.recipientChannel)\n .writeString(\"exec\", \"ascii\")\n .writeBoolean(args.wantReply)\n .writeString(args.command, \"utf8\")\n .toBuffer();\n}\n\nexport function encodeSshChannelRequestEnv(args: {\n recipientChannel: number;\n variableName: string;\n variableValue: string;\n wantReply: boolean;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_REQUEST)\n .writeUint32(args.recipientChannel)\n .writeString(\"env\", \"ascii\")\n .writeBoolean(args.wantReply)\n .writeString(args.variableName, \"utf8\")\n .writeString(args.variableValue, \"utf8\")\n .toBuffer();\n}\n\nexport function encodeSshChannelRequestSignal(args: {\n recipientChannel: number;\n signalName: string;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_REQUEST)\n .writeUint32(args.recipientChannel)\n .writeString(\"signal\", \"ascii\")\n .writeBoolean(false) // RFC 4254 §6.9 says wantReply MUST be false\n .writeString(args.signalName, \"ascii\")\n .toBuffer();\n}\n\n// -- CHANNEL_SUCCESS / CHANNEL_FAILURE -----------------------------------------\n\nexport function encodeSshChannelSuccess(recipientChannel: number): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_SUCCESS)\n .writeUint32(recipientChannel)\n .toBuffer();\n}\n\nexport function encodeSshChannelFailure(recipientChannel: number): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_FAILURE)\n .writeUint32(recipientChannel)\n .toBuffer();\n}\n\n// -- CHANNEL_DATA --------------------------------------------------------------\n\nexport function encodeSshChannelData(args: { recipientChannel: number; data: Uint8Array }): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_DATA)\n .writeUint32(args.recipientChannel)\n .writeString(args.data)\n .toBuffer();\n}\n\nexport interface SshChannelDataMessage {\n recipientChannel: number;\n data: Buffer;\n}\n\nexport function decodeSshChannelData(payload: Uint8Array): SshChannelDataMessage {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_CHANNEL_DATA) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_DATA\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const recipientChannel = reader.readUint32();\n const data = reader.readString();\n return { data, recipientChannel };\n}\n\n/** Standard extended data type codes. */\nexport const SSH_EXTENDED_DATA_STDERR = 1;\n\nexport function encodeSshChannelExtendedData(args: {\n recipientChannel: number;\n dataTypeCode: number;\n data: Uint8Array;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_EXTENDED_DATA)\n .writeUint32(args.recipientChannel)\n .writeUint32(args.dataTypeCode)\n .writeString(args.data)\n .toBuffer();\n}\n\nexport interface SshChannelExtendedDataMessage {\n recipientChannel: number;\n dataTypeCode: number;\n data: Buffer;\n}\n\nexport function decodeSshChannelExtendedData(payload: Uint8Array): SshChannelExtendedDataMessage {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_CHANNEL_EXTENDED_DATA) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_EXTENDED_DATA\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const recipientChannel = reader.readUint32();\n const dataTypeCode = reader.readUint32();\n const data = reader.readString();\n return { data, dataTypeCode, recipientChannel };\n}\n\n// -- CHANNEL_WINDOW_ADJUST -----------------------------------------------------\n\nexport function encodeSshChannelWindowAdjust(args: {\n recipientChannel: number;\n bytesToAdd: number;\n}): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_WINDOW_ADJUST)\n .writeUint32(args.recipientChannel)\n .writeUint32(args.bytesToAdd)\n .toBuffer();\n}\n\nexport interface SshChannelWindowAdjustMessage {\n recipientChannel: number;\n bytesToAdd: number;\n}\n\nexport function decodeSshChannelWindowAdjust(payload: Uint8Array): SshChannelWindowAdjustMessage {\n const reader = new SshDataReader(payload);\n const msgType = reader.readByte();\n if (msgType !== SSH_MSG_CHANNEL_WINDOW_ADJUST) {\n throw new ParseError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_WINDOW_ADJUST\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n const recipientChannel = reader.readUint32();\n const bytesToAdd = reader.readUint32();\n return { bytesToAdd, recipientChannel };\n}\n\n// -- CHANNEL_EOF / CHANNEL_CLOSE -----------------------------------------------\n\nexport function encodeSshChannelEof(recipientChannel: number): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_EOF)\n .writeUint32(recipientChannel)\n .toBuffer();\n}\n\nexport function encodeSshChannelClose(recipientChannel: number): Buffer {\n return new SshDataWriter()\n .writeByte(SSH_MSG_CHANNEL_CLOSE)\n .writeUint32(recipientChannel)\n .toBuffer();\n}\n","/**\n * SSH session channel (RFC 4254 §6).\n *\n * Manages a single \"session\" channel from the client side:\n * CHANNEL_OPEN → OPEN_CONFIRMATION → CHANNEL_REQUEST (subsystem/exec) →\n * bidirectional CHANNEL_DATA with window management → CHANNEL_EOF/CLOSE.\n *\n * Window management strategy:\n * - Local window starts at INITIAL_WINDOW_SIZE.\n * - When consumed bytes exceed WINDOW_REFILL_THRESHOLD, a WINDOW_ADJUST is sent.\n * - Outbound data respects the remote window; excess is queued and flushed\n * as the remote issues WINDOW_ADJUST messages.\n */\nimport { Buffer } from \"node:buffer\";\nimport { ConnectionError, ProtocolError } from \"../../../errors/ZeroTransferError\";\nimport {\n SSH_MSG_CHANNEL_CLOSE,\n SSH_MSG_CHANNEL_DATA,\n SSH_MSG_CHANNEL_EOF,\n SSH_MSG_CHANNEL_EXTENDED_DATA,\n SSH_MSG_CHANNEL_FAILURE,\n SSH_MSG_CHANNEL_OPEN_CONFIRMATION,\n SSH_MSG_CHANNEL_OPEN_FAILURE,\n SSH_MSG_CHANNEL_SUCCESS,\n SSH_MSG_CHANNEL_WINDOW_ADJUST,\n decodeSshChannelData,\n decodeSshChannelExtendedData,\n decodeSshChannelOpenConfirmation,\n decodeSshChannelOpenFailure,\n decodeSshChannelWindowAdjust,\n encodeSshChannelClose,\n encodeSshChannelData,\n encodeSshChannelEof,\n encodeSshChannelOpen,\n encodeSshChannelRequestExec,\n encodeSshChannelRequestSubsystem,\n encodeSshChannelWindowAdjust,\n} from \"./SshConnectionMessages\";\nimport type { SshTransportConnection } from \"../transport/SshTransportConnection\";\n\nconst INITIAL_WINDOW_SIZE = 256 * 1024; // 256 KiB\nconst MAX_PACKET_SIZE = 32 * 1024; // 32 KiB\nconst WINDOW_REFILL_THRESHOLD = 64 * 1024;\n\n// -- Channel state -------------------------------------------------------------\n\ntype ChannelPhase = \"opening\" | \"requesting\" | \"open\" | \"closing\" | \"closed\";\n\ntype InboundEntry =\n | { type: \"data\"; data: Buffer }\n | { type: \"eof\" }\n | { type: \"close\" }\n | { type: \"error\"; error: Error };\n\nexport interface SshSessionChannelOptions {\n /**\n * Local channel id allocated by the caller.\n * If omitted, defaults to 0 (single-channel use case).\n */\n localChannelId?: number;\n}\n\n/**\n * A single SSH session channel.\n * Not safe to share across concurrent callers; each SftpSession should own one.\n */\nexport class SshSessionChannel {\n private phase: ChannelPhase = \"opening\";\n\n /** Remote channel id assigned by the server in OPEN_CONFIRMATION. */\n private remoteChannelId = 0;\n /** Bytes the remote side can still receive before we must stop sending. */\n private remoteWindowRemaining = 0;\n /** Maximum packet data size the remote accepts. */\n private remoteMaxPacketSize = MAX_PACKET_SIZE;\n\n /** Local window: bytes we can still accept from remote. */\n private localWindowConsumed = 0;\n private localWindowSize = INITIAL_WINDOW_SIZE;\n\n /** Queue of inbound data for the `receiveData()` generator. */\n private readonly inboundQueue: InboundEntry[] = [];\n private waitingConsumer: (() => void) | undefined;\n\n /** Queue of outbound data waiting for remote window space. */\n private readonly outboundQueue: Buffer[] = [];\n /**\n * FIFO of waiters blocked on remote window credit. Each WINDOW_ADJUST wakes\n * exactly one waiter; concurrent senders must not lose wakeups.\n */\n private readonly outboundDrainedWaiters: Array<() => void> = [];\n /** Serializes sendData() calls so byte order on the wire matches call order. */\n private sendChain: Promise<void> = Promise.resolve();\n\n private readonly localChannelId: number;\n\n constructor(\n private readonly transport: SshTransportConnection,\n options: SshSessionChannelOptions = {},\n ) {\n this.localChannelId = options.localChannelId ?? 0;\n }\n\n // -- Lifecycle ---------------------------------------------------------------\n\n /**\n * Opens the channel and requests a subsystem.\n * Resolves once the server confirms both CHANNEL_OPEN and the subsystem request.\n */\n async openSubsystem(subsystemName: string): Promise<void> {\n await this.openChannel();\n await this.requestSubsystem(subsystemName);\n }\n\n /**\n * Opens the channel and executes a command.\n */\n async openExec(command: string): Promise<void> {\n await this.openChannel();\n await this.requestExec(command);\n }\n\n private async openChannel(): Promise<void> {\n this.transport.sendPayload(\n encodeSshChannelOpen({\n channelType: \"session\",\n initialWindowSize: INITIAL_WINDOW_SIZE,\n maxPacketSize: MAX_PACKET_SIZE,\n senderChannel: this.localChannelId,\n }),\n );\n\n const payload = await this.nextPayload();\n const msgType = payload[0];\n\n if (msgType === SSH_MSG_CHANNEL_OPEN_FAILURE) {\n const failure = decodeSshChannelOpenFailure(payload);\n throw new ConnectionError({\n details: { reason: failure.reasonCode, description: failure.description },\n message: `SSH channel open failed: ${failure.description}`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n if (msgType !== SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {\n throw new ProtocolError({\n details: { msgType },\n message: \"Expected SSH_MSG_CHANNEL_OPEN_CONFIRMATION\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n const confirmation = decodeSshChannelOpenConfirmation(payload);\n this.remoteChannelId = confirmation.senderChannel;\n this.remoteWindowRemaining = confirmation.initialWindowSize;\n this.remoteMaxPacketSize = confirmation.maxPacketSize;\n this.phase = \"requesting\";\n }\n\n private async requestSubsystem(subsystemName: string): Promise<void> {\n this.transport.sendPayload(\n encodeSshChannelRequestSubsystem({\n recipientChannel: this.remoteChannelId,\n subsystemName,\n wantReply: true,\n }),\n );\n await this.awaitChannelRequestReply(\"subsystem\");\n }\n\n private async requestExec(command: string): Promise<void> {\n this.transport.sendPayload(\n encodeSshChannelRequestExec({\n command,\n recipientChannel: this.remoteChannelId,\n wantReply: true,\n }),\n );\n await this.awaitChannelRequestReply(\"exec\");\n }\n\n private async awaitChannelRequestReply(requestType: string): Promise<void> {\n const payload = await this.nextPayload();\n const msgType = payload[0];\n\n if (msgType === SSH_MSG_CHANNEL_SUCCESS) {\n this.phase = \"open\";\n return;\n }\n\n if (msgType === SSH_MSG_CHANNEL_FAILURE) {\n throw new ConnectionError({\n details: { requestType },\n message: `SSH channel request \"${requestType}\" was rejected by the server`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n throw new ProtocolError({\n details: { msgType },\n message: `Unexpected response to channel request \"${requestType}\"`,\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n // -- Send --------------------------------------------------------------------\n\n /**\n * Sends data on the channel. Respects the remote window; if there is no space,\n * splits the data and queues the remainder for when WINDOW_ADJUST arrives.\n *\n * Concurrent calls are serialized so wire byte order matches call order.\n */\n sendData(data: Uint8Array): Promise<void> {\n const next = this.sendChain.then(() => this.sendDataLocked(data));\n // Keep the chain alive even if a single send rejects, so subsequent sends\n // are not blocked on a poisoned promise.\n this.sendChain = next.catch(() => undefined);\n return next;\n }\n\n private async sendDataLocked(data: Uint8Array): Promise<void> {\n if (this.phase !== \"open\") {\n throw new ProtocolError({\n message: \"Cannot send data on a channel that is not open\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n\n let offset = 0;\n while (offset < data.length) {\n if (this.remoteWindowRemaining <= 0) {\n // Backpressure: wait for remote to issue WINDOW_ADJUST.\n await new Promise<void>((resolve) => {\n this.outboundDrainedWaiters.push(resolve);\n });\n continue;\n }\n\n const chunkSize = Math.min(\n data.length - offset,\n this.remoteWindowRemaining,\n this.remoteMaxPacketSize,\n );\n const chunk = Buffer.from(data.subarray(offset, offset + chunkSize));\n this.transport.sendPayload(\n encodeSshChannelData({ data: chunk, recipientChannel: this.remoteChannelId }),\n );\n this.remoteWindowRemaining -= chunkSize;\n offset += chunkSize;\n }\n }\n\n // -- Receive -----------------------------------------------------------------\n\n /**\n * Async generator that yields raw data buffers from the channel.\n * Returns (done) when the channel receives EOF or CLOSE.\n */\n async *receiveData(): AsyncGenerator<Buffer, void, undefined> {\n while (true) {\n const entry = await this.dequeueInbound();\n if (entry.type === \"error\") throw entry.error;\n if (entry.type === \"eof\" || entry.type === \"close\") return;\n yield entry.data;\n }\n }\n\n // -- Close -------------------------------------------------------------------\n\n /**\n * Sends EOF and CLOSE. Should be called when the client is done sending.\n */\n close(): void {\n if (this.phase === \"closed\" || this.phase === \"closing\") return;\n this.phase = \"closing\";\n this.transport.sendPayload(encodeSshChannelEof(this.remoteChannelId));\n this.transport.sendPayload(encodeSshChannelClose(this.remoteChannelId));\n }\n\n // -- Dispatch (called by SshConnectionManager) -----------------------------\n\n /**\n * Feed an inbound transport payload to this channel.\n * Called by the channel multiplexer (`SshConnectionManager`).\n */\n dispatch(payload: Buffer): void {\n const msgType = payload[0];\n\n switch (msgType) {\n case SSH_MSG_CHANNEL_DATA: {\n const msg = decodeSshChannelData(payload);\n this.consumeLocalWindow(msg.data.length);\n this.enqueueInbound({ type: \"data\", data: msg.data });\n break;\n }\n\n case SSH_MSG_CHANNEL_EXTENDED_DATA: {\n // Consume window credit; we discard STDERR data (SFTP doesn't use it).\n const msg = decodeSshChannelExtendedData(payload);\n this.consumeLocalWindow(msg.data.length);\n break;\n }\n\n case SSH_MSG_CHANNEL_WINDOW_ADJUST: {\n const msg = decodeSshChannelWindowAdjust(payload);\n this.remoteWindowRemaining += msg.bytesToAdd;\n // Wake all waiters; sendDataLocked re-checks the window in its loop.\n const waiters = this.outboundDrainedWaiters.splice(0);\n for (const cb of waiters) cb();\n break;\n }\n\n case SSH_MSG_CHANNEL_EOF: {\n this.enqueueInbound({ type: \"eof\" });\n break;\n }\n\n case SSH_MSG_CHANNEL_CLOSE: {\n this.phase = \"closed\";\n this.enqueueInbound({ type: \"close\" });\n // Wake any waiters blocked on remote window credit so they can observe\n // the channel is no longer open and reject.\n const waiters = this.outboundDrainedWaiters.splice(0);\n for (const cb of waiters) cb();\n break;\n }\n\n default:\n // Unknown or ignored channel message types.\n break;\n }\n }\n\n dispatchError(error: Error): void {\n this.enqueueInbound({ type: \"error\", error });\n // Unblock any senders so they observe the failure rather than hanging.\n const waiters = this.outboundDrainedWaiters.splice(0);\n for (const cb of waiters) cb();\n }\n\n // -- Private helpers ------------------------------------------------------\n\n private consumeLocalWindow(bytes: number): void {\n this.localWindowConsumed += bytes;\n if (this.localWindowConsumed >= WINDOW_REFILL_THRESHOLD) {\n const bytesToAdd = this.localWindowConsumed;\n this.localWindowConsumed = 0;\n this.transport.sendPayload(\n encodeSshChannelWindowAdjust({\n bytesToAdd,\n recipientChannel: this.remoteChannelId,\n }),\n );\n }\n }\n\n private enqueueInbound(entry: InboundEntry): void {\n this.inboundQueue.push(entry);\n if (this.waitingConsumer !== undefined) {\n const cb = this.waitingConsumer;\n this.waitingConsumer = undefined;\n cb();\n }\n }\n\n private dequeueInbound(): Promise<InboundEntry> {\n if (this.inboundQueue.length > 0) {\n return Promise.resolve(this.inboundQueue.shift()!);\n }\n return new Promise<InboundEntry>((resolve) => {\n this.waitingConsumer = () => {\n resolve(this.inboundQueue.shift()!);\n };\n });\n }\n\n /** Pull the next payload from the transport (used during channel setup only). */\n private async nextPayload(): Promise<Buffer> {\n const result = await this.transport.receivePayloads().next();\n if (result.done === true) {\n throw new ConnectionError({\n message: \"SSH connection closed during channel setup\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n return result.value;\n }\n}\n","/**\n * SSH connection protocol manager (RFC 4254).\n *\n * Drives the transport-level `receivePayloads()` generator and dispatches each\n * payload to the right `SshSessionChannel` by recipient channel id.\n *\n * Lifecycle:\n * 1. Create after auth succeeds.\n * 2. Call `openSubsystemChannel(\"sftp\")` or `openExecChannel(cmd)` to get a channel.\n * 3. Drive the pump: `start()` returns a Promise that resolves when the transport\n * closes cleanly or rejects on a fatal error.\n */\nimport type { Buffer } from \"node:buffer\";\nimport { ConnectionError } from \"../../../errors/ZeroTransferError\";\nimport {\n SSH_MSG_CHANNEL_CLOSE,\n SSH_MSG_CHANNEL_DATA,\n SSH_MSG_CHANNEL_EXTENDED_DATA,\n SSH_MSG_CHANNEL_EOF,\n SSH_MSG_CHANNEL_FAILURE,\n SSH_MSG_CHANNEL_OPEN_CONFIRMATION,\n SSH_MSG_CHANNEL_OPEN_FAILURE,\n SSH_MSG_CHANNEL_REQUEST,\n SSH_MSG_CHANNEL_SUCCESS,\n SSH_MSG_CHANNEL_WINDOW_ADJUST,\n} from \"./SshConnectionMessages\";\nimport { SshSessionChannel } from \"./SshSessionChannel\";\nimport type { SshTransportConnection } from \"../transport/SshTransportConnection\";\n\n/** Channel messages that carry a recipient-channel id at byte offset 1 (uint32 BE). */\nconst CHANNEL_MSG_TYPES = new Set([\n SSH_MSG_CHANNEL_OPEN_CONFIRMATION,\n SSH_MSG_CHANNEL_OPEN_FAILURE,\n SSH_MSG_CHANNEL_WINDOW_ADJUST,\n SSH_MSG_CHANNEL_DATA,\n SSH_MSG_CHANNEL_EXTENDED_DATA,\n SSH_MSG_CHANNEL_EOF,\n SSH_MSG_CHANNEL_CLOSE,\n SSH_MSG_CHANNEL_REQUEST,\n SSH_MSG_CHANNEL_SUCCESS,\n SSH_MSG_CHANNEL_FAILURE,\n]);\n\nexport class SshConnectionManager {\n private readonly channels = new Map<number, SshSessionChannel>();\n private nextLocalId = 0;\n private pumpPromise: Promise<void> | undefined;\n private pumpResolve: (() => void) | undefined;\n private pumpReject: ((e: Error) => void) | undefined;\n\n /** Payloads that arrived before any channel registered (buffered for the first channel). */\n private readonly pendingSetupPayloads: Buffer[] = [];\n private setupPayloadConsumer: ((payload: Buffer) => void) | undefined;\n\n constructor(private readonly transport: SshTransportConnection) {}\n\n // -- Setup-phase payload delivery (for channel open/request handshakes) -----\n\n /**\n * Delivers the next connection-layer payload to callers during channel setup.\n * Called by `SshSessionChannel` during `openChannel()` / `requestSubsystem()`.\n *\n * Channel setup happens sequentially before `start()` begins pumping, so we\n * pull directly from the transport iterator here.\n */\n async nextSetupPayload(): Promise<Buffer> {\n // If there are buffered payloads from before, drain them first.\n if (this.pendingSetupPayloads.length > 0) {\n return this.pendingSetupPayloads.shift()!;\n }\n\n const result = await this.transport.receivePayloads().next();\n if (result.done === true) {\n throw new ConnectionError({\n message: \"SSH connection closed during channel setup\",\n protocol: \"sftp\",\n retryable: false,\n });\n }\n return result.value;\n }\n\n // -- Channel factory -------------------------------------------------------\n\n /**\n * Opens a session channel and starts the SFTP subsystem on it.\n * Must be called before `start()`.\n */\n async openSubsystemChannel(subsystemName: string): Promise<SshSessionChannel> {\n const localId = this.nextLocalId++;\n const channel = new SshSessionChannel(this.transport, { localChannelId: localId });\n this.channels.set(localId, channel);\n\n // Temporarily replace the channel's transport.receivePayloads with our setup pump.\n await this.runChannelSetup(channel, () => channel.openSubsystem(subsystemName));\n return channel;\n }\n\n /**\n * Opens a session channel and runs the given command on it.\n * Must be called before `start()`.\n */\n async openExecChannel(command: string): Promise<SshSessionChannel> {\n const localId = this.nextLocalId++;\n const channel = new SshSessionChannel(this.transport, { localChannelId: localId });\n this.channels.set(localId, channel);\n await this.runChannelSetup(channel, () => channel.openExec(command));\n return channel;\n }\n\n // -- Pump --------------------------------------------------------------------\n\n /**\n * Starts the main dispatch loop. Returns a Promise that resolves when the\n * connection closes cleanly, or rejects on a fatal transport error.\n *\n * Call this after all channels have been opened and the application is ready\n * to receive data.\n */\n start(): Promise<void> {\n if (this.pumpPromise !== undefined) return this.pumpPromise;\n\n this.pumpPromise = new Promise<void>((resolve, reject) => {\n this.pumpResolve = resolve;\n this.pumpReject = reject;\n void this.pump();\n });\n\n return this.pumpPromise;\n }\n\n // -- Private --------------------------------------------------------------\n\n /**\n * Runs channel setup (open + request) with a dedicated payload pump that\n * pulls from the transport iterator and dispatches non-channel-setup messages\n * to `pendingSetupPayloads` for later processing.\n */\n private async runChannelSetup(\n channel: SshSessionChannel,\n setup: () => Promise<void>,\n ): Promise<void> {\n // Intercept transport.receivePayloads to route through our setup-phase consumer.\n // We achieve this by temporarily wrapping the channel's nextPayload calls via\n // `nextSetupPayload`. SshSessionChannel's private `nextPayload()` already calls\n // `transport.receivePayloads().next()` - so we cannot intercept it without changing\n // the design. Instead, we create a shim transport that the channel talks to.\n await setup();\n }\n\n private async pump(): Promise<void> {\n try {\n for await (const payload of this.transport.receivePayloads()) {\n this.dispatch(payload);\n }\n // Generator exhausted cleanly.\n this.terminateChannels(\n new ConnectionError({\n message: \"SSH connection closed\",\n protocol: \"sftp\",\n retryable: false,\n }),\n );\n this.pumpResolve?.();\n } catch (err) {\n const error =\n err instanceof Error\n ? err\n : new ConnectionError({\n message: String(err),\n protocol: \"sftp\",\n retryable: false,\n });\n this.terminateChannels(error);\n this.pumpReject?.(error);\n }\n }\n\n private dispatch(payload: Buffer): void {\n const msgType = payload[0];\n if (msgType === undefined) return;\n\n if (CHANNEL_MSG_TYPES.has(msgType)) {\n // All channel messages carry recipient channel id at bytes 1-4.\n const recipientChannel = payload.readUInt32BE(1);\n const channel = this.channels.get(recipientChannel);\n if (channel !== undefined) {\n channel.dispatch(payload);\n }\n // Unknown channel ids are silently ignored (server may send late CLOSE).\n }\n // Global connection-layer messages (SSH_MSG_REQUEST_SUCCESS/FAILURE, etc.) are\n // silently dropped here. Extend as needed.\n }\n\n private terminateChannels(error: Error): void {\n for (const channel of this.channels.values()) {\n channel.dispatchError(error);\n }\n }\n}\n","/**\n * @file `runSshCommand` - high-level helper that opens an SSH connection,\n * authenticates, runs a single command on an `exec` channel, captures stdout,\n * and tears the connection down. Eliminates the manual TCP socket / transport\n * / auth / channel choreography for the common one-shot use case.\n */\nimport { connect, type Socket } from \"node:net\";\n\nimport { SshAuthSession, type SshCredential } from \"./auth/SshAuthSession\";\nimport { SshConnectionManager } from \"./connection/SshConnectionManager\";\nimport {\n SshTransportConnection,\n type SshTransportConnectionOptions,\n} from \"./transport/SshTransportConnection\";\n\n/**\n * Options for {@link runSshCommand}.\n */\nexport interface RunSshCommandOptions {\n /** Hostname or IP of the SSH server. */\n host: string;\n /** TCP port. Defaults to `22`. */\n port?: number;\n /** Command to execute on the remote shell. */\n command: string;\n /**\n * Authentication credential. Use one of:\n *\n * - `{ type: \"password\", username, password }`\n * - `{ type: \"publickey\", username, algorithmName, publicKeyBlob, sign }`\n * (build one from a private-key file with `buildPublickeyCredential`)\n * - `{ type: \"keyboard-interactive\", username, respond }`\n */\n auth: SshCredential;\n /**\n * Forwarded to {@link SshTransportConnection}; covers host-key pinning,\n * algorithm overrides, and handshake timeout. The default\n * `handshakeTimeoutMs` is 10 seconds.\n */\n transport?: SshTransportConnectionOptions;\n /** TCP connect timeout in milliseconds. Defaults to 10 000. */\n connectTimeoutMs?: number;\n /** Maximum total bytes captured from stdout. Defaults to 16 MiB. */\n maxOutputBytes?: number;\n}\n\n/**\n * Result of {@link runSshCommand}. The full captured stdout is provided as\n * both a `Buffer` (for binary output) and as a UTF-8 decoded `string`.\n *\n * Note: stderr (CHANNEL_EXTENDED_DATA) and exit-status are not currently\n * surfaced - drop down to {@link SshConnectionManager}/{@link SshSessionChannel}\n * directly if you need them.\n */\nexport interface RunSshCommandResult {\n /** Captured stdout as raw bytes. */\n stdout: Buffer;\n /** Captured stdout decoded as UTF-8. */\n stdoutText: string;\n /** Bytes received before the channel closed. */\n bytesReceived: number;\n}\n\nconst DEFAULT_PORT = 22;\nconst DEFAULT_CONNECT_TIMEOUT_MS = 10_000;\nconst DEFAULT_HANDSHAKE_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_OUTPUT_BYTES = 16 * 1024 * 1024;\n\n/**\n * Connects, authenticates, runs `command` on a fresh exec channel, drains\n * stdout, and disconnects. The TCP socket, transport, auth session, and\n * channel are all owned by this helper and torn down before it returns.\n *\n * @example Run uname -a with a password credential\n * ```ts\n * import { runSshCommand } from \"@zero-transfer/ssh\";\n *\n * const { stdoutText } = await runSshCommand({\n * host: \"ssh.example.com\",\n * auth: { type: \"password\", username: \"deploy\", password: process.env.SSH_PASSWORD! },\n * command: \"uname -a\",\n * });\n * console.log(stdoutText);\n * ```\n */\nexport async function runSshCommand(options: RunSshCommandOptions): Promise<RunSshCommandResult> {\n const {\n host,\n port = DEFAULT_PORT,\n command,\n auth,\n transport: transportOptions,\n connectTimeoutMs = DEFAULT_CONNECT_TIMEOUT_MS,\n maxOutputBytes = DEFAULT_MAX_OUTPUT_BYTES,\n } = options;\n\n const socket = await openTcpSocket(host, port, connectTimeoutMs);\n const transport = new SshTransportConnection({\n handshakeTimeoutMs: DEFAULT_HANDSHAKE_TIMEOUT_MS,\n ...transportOptions,\n });\n\n try {\n const handshake = await transport.connect(socket);\n\n const authSession = new SshAuthSession(transport);\n await authSession.authenticate({\n credential: auth,\n sessionId: handshake.keyExchange.sessionId,\n });\n\n const conn = new SshConnectionManager(transport);\n const channel = await conn.openExecChannel(command);\n\n const pump = conn.start();\n pump.catch(() => {\n // Errors surface through the receiveData() iterator below.\n });\n\n const chunks: Buffer[] = [];\n let bytesReceived = 0;\n try {\n for await (const chunk of channel.receiveData()) {\n bytesReceived += chunk.length;\n if (bytesReceived > maxOutputBytes) {\n throw new Error(\n `runSshCommand: stdout exceeded ${maxOutputBytes} bytes (set maxOutputBytes to allow more)`,\n );\n }\n chunks.push(chunk);\n }\n } finally {\n channel.close();\n }\n\n const stdout = Buffer.concat(chunks);\n return {\n stdout,\n stdoutText: stdout.toString(\"utf8\"),\n bytesReceived,\n };\n } finally {\n transport.disconnect();\n }\n}\n\n/**\n * Opens a TCP socket with a timeout, returning it in the connected state.\n * @internal\n */\nfunction openTcpSocket(host: string, port: number, timeoutMs: number): Promise<Socket> {\n return new Promise<Socket>((resolve, reject) => {\n const socket = connect({ host, port });\n const timer = setTimeout(() => {\n socket.destroy();\n reject(\n new Error(`runSshCommand: TCP connect to ${host}:${port} timed out after ${timeoutMs}ms`),\n );\n }, timeoutMs);\n socket.once(\"connect\", () => {\n clearTimeout(timer);\n resolve(socket);\n });\n socket.once(\"error\", (error) => {\n clearTimeout(timer);\n reject(error);\n });\n });\n}\n"],"mappings":";AASA,SAAS,oBAAoB;;;ACAtB,IAAM,WAAW;AAExB,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,kBAAkB;AAQjB,SAAS,eAAe,KAAsB;AACnD,SAAO,sBAAsB,KAAK,IAAI,QAAQ,SAAS,EAAE,CAAC;AAC5D;AAQO,SAAS,cAAc,SAAyB;AACrD,SAAO,QAAQ,QAAQ,wBAAwB,CAAC,YAAY,gBAAwB;AAClF,WAAO,GAAG,YAAY,YAAY,CAAC,IAAI,QAAQ;AAAA,EACjD,CAAC;AACH;AAQO,SAAS,YAAY,OAAyB;AACnD,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,cAAc,KAAK;AAAA,EAC5B;AAEA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC;AAAA,EAC9C;AAEA,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,WAAO,aAAa,KAAgC;AAAA,EACtD;AAEA,SAAO;AACT;AAQO,SAAS,aAAa,OAAyD;AACpF,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AAC1C,UAAI,eAAe,GAAG,GAAG;AACvB,eAAO,CAAC,KAAK,QAAQ;AAAA,MACvB;AAEA,UAAI,gBAAgB,KAAK,GAAG,KAAK,OAAO,UAAU,UAAU;AAC1D,eAAO,CAAC,KAAK,oBAAoB,KAAK,CAAC;AAAA,MACzC;AAEA,aAAO,CAAC,KAAK,YAAY,KAAK,CAAC;AAAA,IACjC,CAAC;AAAA,EACH;AACF;AAeO,SAAS,oBAAoB,KAA2B;AAC7D,MAAI;AACJ,MAAI;AACF,aAAS,OAAO,QAAQ,WAAW,IAAI,IAAI,GAAG,IAAI;AAAA,EACpD,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,OAAO,KAAK,SAAS,IAAI,GAAG,OAAO,QAAQ,KAAK,OAAO,IAAI,KAAK,OAAO;AACtF,QAAM,QAAQ,OAAO,OAAO,SAAS,IAAI,IAAI,QAAQ,KAAK;AAC1D,SAAO,GAAG,MAAM,GAAG,OAAO,QAAQ,GAAG,KAAK;AAC5C;AAaO,SAAS,sBAAsB,OAAyC;AAC7E,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,UAAM,YAAY;AAClB,QAAI,OAAO,UAAU,WAAW,YAAY;AAC1C,aAAO,aAAa,UAAU,OAAO,CAAC;AAAA,IACxC;AAAA,EACF;AAEA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,aAAa,EAAE,SAAS,MAAM,SAAS,MAAM,MAAM,KAAK,CAAC;AAAA,EAClE;AAEA,SAAO,EAAE,SAAS,YAAY,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK,CAAC,EAAE;AACnF;;;AChFO,IAAM,oBAAN,cAAgC,MAAM;AAAA;AAAA,EAElC;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,YAAY,SAAmC;AAC7C,UAAM,QAAQ,SAAS,QAAQ,UAAU,SAAY,SAAY,EAAE,OAAO,QAAQ,MAAM,CAAC;AACzF,SAAK,OAAO,WAAW;AACvB,SAAK,OAAO,QAAQ;AACpB,SAAK,YAAY,QAAQ;AAEzB,QAAI,QAAQ,aAAa,OAAW,MAAK,WAAW,QAAQ;AAC5D,QAAI,QAAQ,SAAS,OAAW,MAAK,OAAO,QAAQ;AACpD,QAAI,QAAQ,YAAY,OAAW,MAAK,UAAU,QAAQ;AAC1D,QAAI,QAAQ,YAAY,OAAW,MAAK,UAAU,QAAQ;AAC1D,QAAI,QAAQ,aAAa,OAAW,MAAK,WAAW,QAAQ;AAC5D,QAAI,QAAQ,SAAS,OAAW,MAAK,OAAO,QAAQ;AACpD,QAAI,QAAQ,YAAY,OAAW,MAAK,UAAU,QAAQ;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,SAAkC;AAChC,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,UAAU,KAAK;AAAA,MACf,MAAM,KAAK;AAAA,MACX,SAAS,KAAK,YAAY,SAAY,SAAY,cAAc,KAAK,OAAO;AAAA,MAC5E,SAAS,KAAK;AAAA,MACd,UAAU,KAAK;AAAA,MACf,MAAM,KAAK;AAAA,MACX,WAAW,KAAK;AAAA,MAChB,SAAS,KAAK,YAAY,SAAY,SAAY,aAAa,KAAK,OAAO;AAAA,IAC7E;AAAA,EACF;AACF;AASA,SAAS,gBAAgB,SAAkC,MAAwC;AACjG,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM,QAAQ,QAAQ;AAAA,EACxB;AACF;AAGO,IAAM,kBAAN,cAA8B,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMrD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,gCAAgC,CAAC;AAAA,EAClE;AACF;AAGO,IAAM,sBAAN,cAAkC,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,oCAAoC,CAAC;AAAA,EACtE;AACF;AAGO,IAAM,qBAAN,cAAiC,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMxD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,mCAAmC,CAAC;AAAA,EACrE;AACF;AAGO,IAAM,oBAAN,cAAgC,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,8BAA8B,CAAC;AAAA,EAChE;AACF;AAGO,IAAM,yBAAN,cAAqC,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM5D,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,mCAAmC,CAAC;AAAA,EACrE;AACF;AAGO,IAAM,wBAAN,cAAoC,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM3D,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,iCAAiC,CAAC;AAAA,EACnE;AACF;AAGO,IAAM,eAAN,cAA2B,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,uBAAuB,CAAC;AAAA,EACzD;AACF;AAGO,IAAM,aAAN,cAAyB,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,uBAAuB,CAAC;AAAA,EACzD;AACF;AAGO,IAAM,gBAAN,cAA4B,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMnD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,8BAA8B,CAAC;AAAA,EAChE;AACF;AAGO,IAAM,aAAN,cAAyB,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,2BAA2B,CAAC;AAAA,EAC7D;AACF;AAGO,IAAM,gBAAN,cAA4B,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMnD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,8BAA8B,CAAC;AAAA,EAChE;AACF;AAGO,IAAM,oBAAN,cAAgC,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,kCAAkC,CAAC;AAAA,EACpE;AACF;AAGO,IAAM,0BAAN,cAAsC,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM7D,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,mCAAmC,CAAC;AAAA,EACrE;AACF;AAGO,IAAM,qBAAN,cAAiC,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMxD,YAAY,SAAkC;AAC5C,UAAM,gBAAgB,SAAS,mCAAmC,CAAC;AAAA,EACrE;AACF;;;AC9NO,IAAM,aAA2C;AAAA,EACtD,QAAQ;AAAA,EAAC;AAAA,EACT,QAAQ;AAAA,EAAC;AAAA,EACT,OAAO;AAAA,EAAC;AAAA,EACR,OAAO;AAAA,EAAC;AAAA,EACR,QAAQ;AAAA,EAAC;AACX;AAUO,SAAS,QAAQ,QAA4B,OAAiB,QAA8B;AACjG,QAAM,SAAS,OAAO,KAAK;AAE3B,MAAI,WAAW,QAAW;AACxB;AAAA,EACF;AAEA,QAAM,YAAuB;AAAA,IAC3B,GAAG;AAAA,IACH;AAAA,EACF;AAEA,SAAO,WAAW,UAAU,OAAO;AACrC;;;ACpGA,SAAS,UAAAA,eAAc;;;ACEhB,IAAM,uBAAuB,CAAC,OAAO,QAAQ,MAAM;AAqCnD,SAAS,oBACd,YACiC;AACjC,SACE,OAAO,eAAe,YAAY,qBAAqB,SAAS,UAA+B;AAEnG;AAQO,SAAS,kBAAkB,WAAsD;AACtF,SAAO,UAAU,YAAY,UAAU;AACzC;;;ADjDA,IAAM,eAAe,oBAAI,IAAI,CAAC,SAAS,WAAW,WAAW,SAAS,CAAC;AAEvE,IAAM,gCAAgC;AAEtC,IAAM,4BAA4B;AAS3B,SAAS,0BAA0B,SAA+C;AACvF,MAAI,kBAAkB,OAAO,MAAM,QAAW;AAC5C,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,KAAK,KAAK,EAAE,WAAW,GAAG;AACpC,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,SAAS,UAAa,CAAC,YAAY,QAAQ,IAAI,GAAG;AAC5D,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,MAAM,QAAQ,KAAK;AAAA,MAC9B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,cAAc,UAAa,CAAC,uBAAuB,QAAQ,SAAS,GAAG;AACjF,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,WAAW,QAAQ,UAAU;AAAA,MACxC,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,QAAQ,QAAW;AAC7B,uBAAmB,QAAQ,GAAG;AAAA,EAChC;AAEA,MAAI,QAAQ,QAAQ,QAAW;AAC7B,uBAAmB,QAAQ,GAAG;AAAA,EAChC;AAEA,SAAO;AACT;AAQA,SAAS,mBAAmB,SAA2B;AACrD,8BAA4B,QAAQ,mBAAmB;AAEvD,MAAI,QAAQ,eAAe,QAAW;AACpC,0BAAsB,QAAQ,UAAU;AAAA,EAC1C;AAEA,MAAI,QAAQ,UAAU,QAAW;AAC/B,2BAAuB,QAAQ,KAAK;AAAA,EACtC;AAEA,MACE,QAAQ,wBAAwB,UAChC,OAAO,QAAQ,wBAAwB,YACvC;AACA,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,qBAAqB,OAAO,QAAQ,oBAAoB;AAAA,MACnE,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,kBAAkB,UAAa,OAAO,QAAQ,kBAAkB,YAAY;AACtF,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,eAAe,OAAO,QAAQ,cAAc;AAAA,MACvD,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACF;AAQA,SAAS,sBAAsB,OAAuC;AACpE,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG;AACvE,UAAM,yBAAyB,KAAK;AAAA,EACtC;AAEA,QAAM,aAAa;AAEnB,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,SAAS,QAAW;AACtB;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,UAAI,CAAC,sBAAsB,IAAI,GAAG;AAChC,cAAM,yBAAyB,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC;AAAA,MACjD;AAEA;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,GAAG;AACpE,YAAM,yBAAyB,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC;AAAA,IACjD;AAEA,UAAM,iBAAiB;AAEvB,eAAW,CAAC,WAAW,aAAa,KAAK,OAAO,QAAQ,cAAc,GAAG;AACvE,UAAI,CAAC,CAAC,UAAU,WAAW,QAAQ,EAAE,SAAS,SAAS,GAAG;AACxD,cAAM,yBAAyB,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC;AAAA,MACjD;AAEA,UACE,OAAO,kBAAkB,aACxB,CAAC,MAAM,QAAQ,aAAa,KAAK,CAAC,sBAAsB,aAAa,IACtE;AACA,cAAM,yBAAyB,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,sBAAsB,OAAqC;AAClE,SAAO,MAAM,SAAS,KAAK,MAAM,MAAM,CAAC,SAAS,OAAO,SAAS,YAAY,KAAK,SAAS,CAAC;AAC9F;AAQA,SAAS,uBAAuB,OAAkC;AAChE,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI,MAAM,KAAK,EAAE,SAAS,GAAG;AAC3B;AAAA,IACF;AAAA,EACF,WACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAAsC,kBAAkB,cAChE,OAAQ,MAA6B,SAAS,YAC9C;AACA;AAAA,EACF;AAEA,QAAM,IAAI,mBAAmB;AAAA,IAC3B,SAAS,EAAE,OAAO,OAAO,MAAM;AAAA,IAC/B,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACH;AAQA,SAAS,mBAAmB,SAA2B;AACrD,MAAI,QAAQ,eAAe,UAAa,QAAQ,WAAW,KAAK,EAAE,WAAW,GAAG;AAC9E,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,uBAAuB,UAAa,OAAO,QAAQ,uBAAuB,WAAW;AAC/F,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,oBAAoB,QAAQ,mBAAmB;AAAA,MAC1D,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,qBAAmB,QAAQ,YAAY,YAAY;AACnD,qBAAmB,QAAQ,YAAY,YAAY;AACnD,+BAA6B,QAAQ,oBAAoB;AAC3D;AAQA,SAAS,6BAA6B,OAAiD;AACrF,MAAI,UAAU,QAAW;AACvB;AAAA,EACF;AAEA,QAAM,eAAe,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAE1D,MAAI,aAAa,WAAW,GAAG;AAC7B,UAAM,6BAA6B,KAAK;AAAA,EAC1C;AAEA,aAAW,eAAe,cAAc;AACtC,QAAI,OAAO,gBAAgB,YAAY,CAAC,oBAAoB,WAAW,GAAG;AACxE,YAAM,6BAA6B,KAAK;AAAA,IAC1C;AAAA,EACF;AACF;AAQA,SAAS,4BAA4B,OAAgD;AACnF,MAAI,UAAU,QAAW;AACvB;AAAA,EACF;AAEA,QAAM,eAAe,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAE1D,MAAI,aAAa,WAAW,GAAG;AAC7B,UAAM,yBAAyB,KAAK;AAAA,EACtC;AAEA,aAAW,eAAe,cAAc;AACtC,QAAI,OAAO,gBAAgB,YAAY,CAAC,8BAA8B,WAAW,GAAG;AAClF,YAAM,yBAAyB,KAAK;AAAA,IACtC;AAAA,EACF;AACF;AAQA,SAAS,oBAAoB,OAAwB;AACnD,QAAM,aAAa,MAAM,KAAK,EAAE,QAAQ,MAAM,EAAE;AAChD,SAAO,WAAW,WAAW,iCAAiC,eAAe,KAAK,UAAU;AAC9F;AAQA,SAAS,8BAA8B,OAAwB;AAC7D,QAAM,UAAU,MAAM,KAAK;AAE3B,MAAI,oBAAoB,OAAO,GAAG;AAChC,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,QAAQ,WAAW,SAAS,IAAI,QAAQ,MAAM,UAAU,MAAM,IAAI;AAC/E,QAAM,SAAS,UAAU,IAAI;AAE7B,MAAI,CAAC,uBAAuB,KAAK,MAAM,GAAG;AACxC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAOC,QAAO,KAAK,QAAQ,QAAQ,EAAE,eAAe;AAAA,EACtD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,UAAU,OAAuB;AACxC,QAAM,YAAY,MAAM,SAAS;AAEjC,SAAO,cAAc,IAAI,QAAQ,GAAG,KAAK,GAAG,IAAI,OAAO,IAAI,SAAS,CAAC;AACvE;AAQA,SAAS,6BAA6B,OAAoC;AACxE,SAAO,IAAI,mBAAmB;AAAA,IAC5B,SAAS,EAAE,sBAAsB,MAAM;AAAA,IACvC,SACE;AAAA,IACF,WAAW;AAAA,EACb,CAAC;AACH;AAQA,SAAS,yBAAyB,OAAoC;AACpE,SAAO,IAAI,mBAAmB;AAAA,IAC5B,SAAS,EAAE,qBAAqB,MAAM;AAAA,IACtC,SACE;AAAA,IACF,WAAW;AAAA,EACb,CAAC;AACH;AAQA,SAAS,yBAAyB,OAAoC;AACpE,SAAO,IAAI,mBAAmB;AAAA,IAC5B,SAAS,EAAE,YAAY,MAAM;AAAA,IAC7B,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACH;AASA,SAAS,mBAAmB,OAAiC,OAAqB;AAChF,MAAI,UAAU,QAAW;AACvB;AAAA,EACF;AAEA,MAAI,CAAC,aAAa,IAAI,KAAK,GAAG;AAC5B,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,CAAC,KAAK,GAAG,MAAM;AAAA,MAC1B,SAAS,0BAA0B,KAAK;AAAA,MACxC,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACF;AAEA,SAAS,YAAY,OAAwB;AAC3C,SAAO,OAAO,UAAU,KAAK,KAAK,SAAS,KAAK,SAAS;AAC3D;AAEA,SAAS,uBAAuB,OAAwB;AACtD,SAAO,OAAO,SAAS,KAAK,KAAK,QAAQ;AAC3C;;;AExWO,IAAM,mBAAN,MAAuB;AAAA,EACX,YAAY,oBAAI,IAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOlE,YAAY,YAAuC,CAAC,GAAG;AACrD,eAAW,YAAY,WAAW;AAChC,WAAK,SAAS,QAAQ;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,SAAS,UAAiC;AACxC,QAAI,KAAK,UAAU,IAAI,SAAS,EAAE,GAAG;AACnC,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,EAAE,UAAU,SAAS,GAAG;AAAA,QACjC,SAAS,aAAa,SAAS,EAAE;AAAA,QACjC,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,SAAK,UAAU,IAAI,SAAS,IAAI,QAAQ;AACxC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,YAAiC;AAC1C,WAAO,KAAK,UAAU,OAAO,UAAU;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,YAAiC;AACnC,WAAO,KAAK,UAAU,IAAI,UAAU;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,YAAqD;AACvD,WAAO,KAAK,UAAU,IAAI,UAAU;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,QAAQ,YAAyC;AAC/C,UAAM,WAAW,KAAK,IAAI,UAAU;AAEpC,QAAI,aAAa,QAAW;AAC1B,YAAM,IAAI,wBAAwB;AAAA,QAChC,SAAS,EAAE,UAAU,WAAW;AAAA,QAChC,SAAS,aAAa,UAAU;AAAA,QAChC,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,YAAmD;AACjE,WAAO,KAAK,IAAI,UAAU,GAAG;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,oBAAoB,YAAuC;AACzD,WAAO,KAAK,QAAQ,UAAU,EAAE;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAA0B;AACxB,WAAO,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAoC;AAClC,WAAO,KAAK,KAAK,EAAE,IAAI,CAAC,aAAa,SAAS,YAAY;AAAA,EAC5D;AACF;;;AC/DO,IAAM,iBAAN,MAAqB;AAAA;AAAA,EAEjB;AAAA;AAAA,EAGA;AAAA,EAEQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,YAAY,UAAiC,CAAC,GAAG;AAC/C,SAAK,WAAW,QAAQ,YAAY,IAAI,iBAAiB;AACzD,SAAK,SAAS,QAAQ,UAAU;AAChC,QAAI,QAAQ,aAAa,QAAW;AAClC,WAAK,WAAW,EAAE,GAAG,QAAQ,SAAS;AAAA,IACxC;AAEA,eAAW,YAAY,QAAQ,aAAa,CAAC,GAAG;AAC9C,WAAK,SAAS,SAAS,QAAQ;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiB,UAAiC;AAChD,SAAK,SAAS,SAAS,QAAQ;AAC/B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,YAAiC;AAC3C,WAAO,KAAK,SAAS,IAAI,UAAU;AAAA,EACrC;AAAA,EAMA,gBAAgB,YAA0D;AACxE,QAAI,eAAe,QAAW;AAC5B,aAAO,KAAK,SAAS,iBAAiB;AAAA,IACxC;AAEA,WAAO,KAAK,SAAS,oBAAoB,UAAU;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QAAQ,SAAsD;AAClE,UAAM,eAAe,0BAA0B,OAAO;AACtD,UAAM,aAAa,kBAAkB,YAAY;AAEjD,QAAI,eAAe,QAAW;AAC5B,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS;AAAA,QACT,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,kBAAkB,KAAK,SAAS,QAAQ,UAAU;AACxD,UAAM,WAAW,gBAAgB,OAAO;AACxC,UAAM,oBAAuC;AAAA,MAC3C,GAAG;AAAA,MACH,UAAU;AAAA,IACZ;AAEA,QAAI,kBAAkB,aAAa,UAAa,oBAAoB,UAAU,GAAG;AAC/E,wBAAkB,WAAW;AAAA,IAC/B;AAEA,YAAQ,KAAK,QAAQ,QAAQ,uBAAuB,mBAAmB,UAAU,CAAC;AAElF,WAAO,SAAS,QAAQ,iBAAiB;AAAA,EAC3C;AACF;AAEA,SAAS,uBACP,SACA,YACgB;AAChB,QAAM,SAAyB;AAAA,IAC7B,WAAW;AAAA,IACX,MAAM,QAAQ;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AAEA,MAAI,oBAAoB,UAAU,GAAG;AACnC,WAAO,WAAW;AAAA,EACpB;AAEA,SAAO;AACT;;;AC9HO,SAAS,qBAAqB,UAAiC,CAAC,GAAmB;AACxF,SAAO,IAAI,eAAe,OAAO;AACnC;;;ARIO,IAAM,eAAN,MAAM,sBAAqB,aAAa;AAAA;AAAA,EAE7C,OAAgB,uBAAuB;AAAA;AAAA,EAG9B;AAAA,EAEQ;AAAA,EACA;AAAA,EACT,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOpB,YAAY,UAA+B,CAAC,GAAG;AAC7C,UAAM;AACN,SAAK,WAAW,QAAQ,YAAY;AACpC,SAAK,SAAS,QAAQ,UAAU;AAChC,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,UAA+B,CAAC,GAAiB;AAC7D,WAAO,IAAI,cAAa,OAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,aAAa,QACX,SACA,UAA+B,CAAC,GACT;AACvB,UAAM,gBAAqC,EAAE,GAAG,QAAQ;AAExD,QAAI,QAAQ,WAAW,QAAW;AAChC,oBAAc,SAAS,QAAQ;AAAA,IACjC;AAEA,QAAI,QAAQ,aAAa,QAAW;AAClC,oBAAc,WAAW,QAAQ;AAAA,IACnC,WAAW,oBAAoB,QAAQ,QAAQ,GAAG;AAChD,oBAAc,WAAW,QAAQ;AAAA,IACnC;AAEA,UAAM,SAAS,IAAI,cAAa,aAAa;AAC7C,UAAM,OAAO,QAAQ,OAAO;AAC5B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QAAQ,SAA2C;AACvD,UAAM,UAAU,KAAK,eAAe;AACpC,UAAM,WACJ,QAAQ,aACP,oBAAoB,QAAQ,QAAQ,IAAI,QAAQ,WAAW,KAAK;AACnE,YAAQ,KAAK,QAAQ,QAAQ;AAAA,MAC3B,WAAW;AAAA,MACX,MAAM,QAAQ;AAAA,MACd,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AACD,UAAM,QAAQ,QAAQ;AAAA,MACpB,GAAG;AAAA,MACH;AAAA,IACF,CAAC;AACD,SAAK,YAAY;AACjB,SAAK,KAAK,WAAW;AAAA,MACnB,MAAM,QAAQ;AAAA,MACd;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAA4B;AAChC,QAAI,KAAK,YAAY,UAAa,KAAK,WAAW;AAChD,YAAM,KAAK,QAAQ,WAAW;AAAA,IAChC;AAEA,SAAK,YAAY;AACjB,SAAK,KAAK,YAAY;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,kBAA4C;AAC1C,WAAO;AAAA,MACL,cAAc,KAAK,YAAY;AAAA,MAC/B,UAAU,KAAK;AAAA,IACjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,KAAKC,OAAc,SAA+C;AACtE,WAAO,KAAK,eAAe,EAAE,KAAKA,OAAM,OAAO;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,KAAKA,OAAc,SAA4C;AACnE,WAAO,KAAK,eAAe,EAAE,KAAKA,OAAM,OAAO;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,iBAAoC;AAC1C,QAAI,KAAK,YAAY,QAAW;AAC9B,YAAM,IAAI,wBAAwB;AAAA,QAChC,SAAS,OAAO,KAAK,SAAS,YAAY,CAAC;AAAA,QAC3C,UAAU,KAAK;AAAA,QACf,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,WAAO,KAAK;AAAA,EACd;AACF;;;ASzNA,SAAS,YAAY,WAAW,mBAAmB;;;ACoC5C,SAAS,wBACd,OACA,UAAoC,CAAC,GACN;AAC/B,MAAI,UAAU,OAAW,QAAO;AAEhC,QAAM,iBAAiB,cAAc,MAAM,cAAc;AACzD,QAAM,aAAa,eAAe,MAAM,YAAY,cAAc;AAClE,QAAM,MAAM,QAAQ,OAAO,KAAK;AAChC,QAAM,QAAQ,QAAQ,SAAS;AAE/B,MAAI,SAAS;AACb,MAAI,eAAe,IAAI;AAEvB,WAAS,SAAe;AACtB,UAAM,UAAU,IAAI;AACpB,UAAM,YAAY,KAAK,IAAI,GAAG,UAAU,YAAY;AAEpD,QAAI,YAAY,GAAG;AACjB,eAAS,KAAK,IAAI,YAAY,SAAU,YAAY,MAAQ,cAAc;AAC1E,qBAAe;AAAA,IACjB;AAAA,EACF;AAEA,iBAAe,QAAQ,OAAe,QAAqC;AACzE,QAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GAAG;AACxC,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,EAAE,MAAM;AAAA,QACjB,SAAS;AAAA,QACT,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,QAAI,UAAU,EAAG;AAEjB,QAAI,YAAY;AAEhB,WAAO,YAAY,GAAG;AACpB,qBAAe,MAAM;AACrB,aAAO;AAEP,UAAI,UAAU,WAAW;AACvB,kBAAU;AACV;AAAA,MACF;AAEA,UAAI,UAAU,YAAY;AAGxB,cAAM,UAAU;AAChB,iBAAS;AACT,qBAAa;AACb,cAAMC,UAAS,KAAK,KAAM,KAAK,IAAI,WAAW,UAAU,IAAI,iBAAkB,GAAI;AAClF,cAAM,MAAMA,SAAQ,MAAM;AAC1B;AAAA,MACF;AAEA,YAAM,UAAU,KAAK,IAAI,WAAW,UAAU,IAAI;AAClD,YAAM,SAAS,KAAK,IAAI,GAAG,KAAK,KAAM,UAAU,iBAAkB,GAAI,CAAC;AACvE,YAAM,MAAM,QAAQ,MAAM;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO,EAAE,YAAY,gBAAgB,QAAQ;AAC/C;AAaO,SAAS,qBACd,QACA,UACA,QAC2B;AAC3B,MAAI,aAAa,OAAW,QAAO;AAEnC,SAAO;AAAA,IACL,CAAC,OAAO,aAAa,GAAG,mBAAmB;AACzC,uBAAiB,SAAS,QAAQ;AAChC,uBAAe,MAAM;AACrB,YAAI,MAAM,aAAa,GAAG;AACxB,gBAAM,SAAS,QAAQ,MAAM,YAAY,MAAM;AAAA,QACjD;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,cAAc,OAAuB;AAC5C,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG;AACzC,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,gBAAgB,MAAM;AAAA,MACjC,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,OAA2B,gBAAgC;AACjF,MAAI,UAAU,OAAW,QAAO;AAEhC,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG;AACzC,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,YAAY,MAAM;AAAA,MAC7B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,QAAuC;AAC7D,MAAI,QAAQ,YAAY,MAAM;AAC5B,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACF;AAEA,SAAS,aAAa,SAAiB,QAAqC;AAC1E,MAAI,WAAW,EAAG,QAAO,QAAQ,QAAQ;AAEzC,SAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,UAAM,QAAQ,WAAW,MAAM;AAC7B,cAAQ;AACR,cAAQ;AAAA,IACV,GAAG,OAAO;AAEV,UAAM,UAAU,MAAM;AACpB,cAAQ;AACR;AAAA,QACE,IAAI,WAAW;AAAA,UACb,SAAS;AAAA,UACT,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAEA,aAAS,UAAgB;AACvB,mBAAa,KAAK;AAClB,cAAQ,oBAAoB,SAAS,OAAO;AAAA,IAC9C;AAEA,QAAI,WAAW,QAAW;AACxB,UAAI,OAAO,SAAS;AAClB,gBAAQ;AACR;AAAA,MACF;AACA,aAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,IAC1D;AAAA,EACF,CAAC;AACH;;;ACnJO,SAAS,+BACd,SACkB;AAClB,SAAO,OAAO,YAAY;AACxB,UAAM,EAAE,IAAI,IAAI;AAEhB,QAAI,CAAC,qBAAqB,IAAI,SAAS,GAAG;AACxC,YAAM,IAAI,wBAAwB;AAAA,QAChC,SAAS,EAAE,OAAO,IAAI,IAAI,WAAW,IAAI,UAAU;AAAA,QACnD,SAAS,qEAAqE,IAAI,SAAS;AAAA,QAC3F,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,SAAS,gBAAgB,KAAK,QAAQ;AAC5C,UAAM,cAAc,gBAAgB,KAAK,aAAa;AACtD,UAAM,gBAAgB,QAAQ,eAAe,EAAE,UAAU,QAAQ,KAAK,MAAM,SAAS,CAAC;AACtF,UAAM,qBAAqB,QAAQ,eAAe;AAAA,MAChD,UAAU;AAAA,MACV;AAAA,MACA,MAAM;AAAA,IACR,CAAC;AACD,UAAM,kBAAkB,0BAA0B,eAAe,QAAQ,UAAU,GAAG;AACtF,UAAM,uBAAuB;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,YAAQ,eAAe;AACvB,UAAM,aAAa,MAAM,gBAAgB,KAAK,kBAAkB,SAAS,MAAM,CAAC;AAChF,YAAQ,eAAe;AACvB,UAAM,sBAAsB,uBAAuB,YAAY,SAAS,QAAQ,QAAQ;AACxF,UAAM,cAAc,MAAM,qBAAqB;AAAA,MAC7C,mBAAmB,SAAS,aAAa,mBAAmB;AAAA,IAC9D;AAEA,WAAO,4BAA4B,YAAY,aAAa,GAAG;AAAA,EACjE;AACF;AAEA,SAAS,uBACP,YACA,SACA,SAC4B;AAC5B,QAAM,WAAW,wBAAwB,QAAQ,gBAAgB,OAAO;AAExE,MAAI,aAAa,OAAW,QAAO;AAEnC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS,qBAAqB,WAAW,SAAS,UAAU,QAAQ,MAAM;AAAA,EAC5E;AACF;AAEA,SAAS,qBAAqB,WAAuC;AACnE,SAAO,cAAc,UAAU,cAAc,cAAc,cAAc;AAC3E;AAEA,SAAS,gBAAgB,KAAkB,MAAsD;AAC/F,QAAM,WAAW,SAAS,WAAW,IAAI,SAAS,IAAI;AAEtD,MAAI,aAAa,QAAW;AAC1B,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,OAAO,IAAI,IAAI,WAAW,IAAI,WAAW,KAAK;AAAA,MACzD,SAAS,2BAA2B,IAAI,cAAc,IAAI,EAAE;AAAA,MAC5D,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,0BACP,SACA,UACA,MACA,KAC4B;AAC5B,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI,wBAAwB;AAAA,MAChC,SAAS,EAAE,UAAU,cAAc,QAAQ,GAAG,OAAO,IAAI,IAAI,WAAW,IAAI,WAAW,KAAK;AAAA,MAC5F,SAAS,oCAAoC,IAAI,cAAc,SAAS,IAAI;AAAA,MAC5E,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,cAAc,QAAW;AACnC,UAAM,IAAI,wBAAwB;AAAA,MAChC,SAAS;AAAA,QACP,UAAU,cAAc,QAAQ;AAAA,QAChC,OAAO,IAAI;AAAA,QACX,WAAW,IAAI;AAAA,QACf,UAAU,QAAQ;AAAA,QAClB;AAAA,MACF;AAAA,MACA,SAAS,yDAAyD,QAAQ,QAAQ;AAAA,MAClF,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO,QAAQ;AACjB;AAEA,SAAS,kBACP,SACA,UAC6B;AAC7B,QAAM,UAAuC;AAAA,IAC3C,SAAS,QAAQ;AAAA,IACjB,UAAU,cAAc,QAAQ;AAAA,IAChC,KAAK,QAAQ;AAAA,IACb,gBAAgB,CAAC,kBAAkB,eACjC,QAAQ,eAAe,kBAAkB,UAAU;AAAA,IACrD,gBAAgB,MAAM,QAAQ,eAAe;AAAA,EAC/C;AAEA,MAAI,QAAQ,WAAW,OAAW,SAAQ,SAAS,QAAQ;AAC3D,MAAI,QAAQ,mBAAmB,QAAW;AACxC,YAAQ,iBAAiB,EAAE,GAAG,QAAQ,eAAe;AAAA,EACvD;AAEA,SAAO;AACT;AAEA,SAAS,mBACP,SACA,UACA,YAC8B;AAC9B,QAAM,UAAwC;AAAA,IAC5C,SAAS,QAAQ;AAAA,IACjB,SAAS,WAAW;AAAA,IACpB,UAAU,cAAc,QAAQ;AAAA,IAChC,KAAK,QAAQ;AAAA,IACb,gBAAgB,CAAC,kBAAkBC,gBACjC,QAAQ,eAAe,kBAAkBA,WAAU;AAAA,IACrD,gBAAgB,MAAM,QAAQ,eAAe;AAAA,EAC/C;AACA,QAAM,aAAa,WAAW,cAAc,QAAQ,IAAI;AAExD,MAAI,QAAQ,WAAW,OAAW,SAAQ,SAAS,QAAQ;AAC3D,MAAI,QAAQ,mBAAmB,QAAW;AACxC,YAAQ,iBAAiB,EAAE,GAAG,QAAQ,eAAe;AAAA,EACvD;AACA,MAAI,eAAe,OAAW,SAAQ,aAAa;AACnD,MAAI,QAAQ,IAAI,YAAY,KAAM,SAAQ,SAAS,WAAW,aAAa;AAC3E,MAAI,WAAW,iBAAiB,QAAW;AACzC,YAAQ,eAAe,kBAAkB,WAAW,YAAY;AAAA,EAClE;AAEA,SAAO;AACT;AAEA,SAAS,4BACP,YACA,aACA,KACyB;AACzB,QAAM,SAAkC;AAAA,IACtC,kBAAkB,YAAY;AAAA,EAChC;AACA,QAAM,aAAa,YAAY,cAAc,WAAW,cAAc,IAAI;AAC1E,QAAM,WAAW,CAAC,GAAI,WAAW,YAAY,CAAC,GAAI,GAAI,YAAY,YAAY,CAAC,CAAE;AAEjF,MAAI,eAAe,OAAW,QAAO,aAAa;AAClD,MAAI,YAAY,YAAY,OAAW,QAAO,UAAU,YAAY;AACpE,MAAI,YAAY,aAAa,OAAW,QAAO,WAAW,YAAY;AACtE,MAAI,YAAY,aAAa,OAAW,QAAO,WAAW,YAAY;AAAA,WAC7D,WAAW,aAAa,OAAW,QAAO,WAAW,WAAW;AACzE,MAAI,YAAY,iBAAiB,QAAW;AAC1C,WAAO,eAAe,kBAAkB,YAAY,YAAY;AAAA,EAClE,WAAW,WAAW,iBAAiB,QAAW;AAChD,WAAO,eAAe,kBAAkB,WAAW,YAAY;AAAA,EACjE;AACA,MAAI,SAAS,SAAS,EAAG,QAAO,WAAW;AAE3C,SAAO;AACT;AAEA,SAAS,cAAc,UAA8C;AACnE,QAAM,QAA0B,EAAE,MAAM,SAAS,KAAK;AAEtD,MAAI,SAAS,aAAa,OAAW,OAAM,WAAW,SAAS;AAE/D,SAAO;AACT;AAEA,SAAS,kBAAkB,cAAsE;AAC/F,QAAM,QAAoC,EAAE,UAAU,aAAa,SAAS;AAE5E,MAAI,aAAa,WAAW,OAAW,OAAM,SAAS,aAAa;AACnE,MAAI,aAAa,aAAa,OAAW,OAAM,WAAW,aAAa;AACvE,MAAI,aAAa,qBAAqB,QAAW;AAC/C,UAAM,mBAAmB,aAAa;AAAA,EACxC;AACA,MAAI,aAAa,mBAAmB,OAAW,OAAM,iBAAiB,aAAa;AACnF,MAAI,aAAa,YAAY,OAAW,OAAM,UAAU,EAAE,GAAG,aAAa,QAAQ;AAElF,SAAO;AACT;;;ACpNO,SAAS,qBAAqB,OAA4C;AAC/E,QAAM,aAAa,KAAK,IAAI,GAAG,MAAM,YAAY,QAAQ,IAAI,MAAM,UAAU,QAAQ,CAAC;AACtF,QAAM,SAAyB;AAAA,IAC7B,iBAAiB,MAAM;AAAA,IACvB,kBAAkB,MAAM;AAAA,IACxB,WAAW,MAAM;AAAA,IACjB,aAAa,MAAM;AAAA,IACnB;AAAA,IACA,uBAAuB,wBAAwB,MAAM,kBAAkB,UAAU;AAAA,IACjF,SAAS,MAAM,WAAW;AAAA,IAC1B,UAAU,MAAM,YAAY;AAAA,EAC9B;AAEA,MAAI,MAAM,eAAe,OAAW,QAAO,aAAa,MAAM;AAC9D,MAAI,MAAM,aAAa,OAAW,QAAO,WAAW,MAAM;AAE1D,SAAO;AACT;AAQO,SAAS,oBAAoB,OAAkD;AACpF,QAAM,MAAM,MAAM,OAAO,oBAAI,KAAK;AAClC,QAAM,YAAY,KAAK,IAAI,GAAG,IAAI,QAAQ,IAAI,MAAM,UAAU,QAAQ,CAAC;AACvE,QAAM,QAA+B;AAAA,IACnC,YAAY,MAAM;AAAA,IAClB,kBAAkB,MAAM;AAAA,IACxB,WAAW,MAAM;AAAA,IACjB;AAAA,IACA,gBAAgB,wBAAwB,MAAM,kBAAkB,SAAS;AAAA,EAC3E;AAEA,MAAI,MAAM,eAAe,QAAW;AAClC,UAAM,aAAa,MAAM;AACzB,UAAM,UAAU,MAAM,aAAa,IAAK,MAAM,mBAAmB,MAAM,aAAc,MAAM;AAAA,EAC7F;AAEA,SAAO;AACT;AASA,SAAS,wBAAwB,OAAe,YAA4B;AAC1E,MAAI,cAAc,GAAG;AACnB,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,aAAa;AAC/B;;;AC+BO,IAAM,iBAAN,MAAqB;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,YAAY,UAAiC,CAAC,GAAG;AAC/C,SAAK,MAAM,QAAQ,QAAQ,MAAM,oBAAI,KAAK;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,QACJ,KACA,UACA,UAAwC,CAAC,GACf;AAC1B,UAAM,cAAc,qBAAqB,QAAQ,OAAO,WAAW;AACnE,UAAM,WAA8B,CAAC;AACrC,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,aAAa,iBAAiB,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACxE,QAAI,yBAAyB;AAE7B,QAAI;AACF,eAAS,gBAAgB,GAAG,iBAAiB,aAAa,iBAAiB,GAAG;AAC5E,aAAK,eAAe,WAAW,QAAQ,GAAG;AAE1C,cAAM,mBAAmB,KAAK,IAAI;AAClC,cAAM,eAAe;AAAA,UACnB,WAAW;AAAA,UACX,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,QACF;AACA,cAAM,UAAU,KAAK;AAAA,UACnB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa;AAAA,UACb,CAAC,qBAAqB;AACpB,qCAAyB;AAAA,UAC3B;AAAA,UACA,aAAa;AAAA,QACf;AAEA,YAAI;AACF,gBAAM,SAAS,MAAM,YAAY,UAAU,SAAS,aAAa,QAAQ,GAAG;AAC5E,kBAAQ,eAAe;AACvB,mCAAyB,OAAO;AAEhC,gBAAM,cAAc,KAAK,IAAI;AAC7B,mBAAS;AAAA,YACP,cAAc,eAAe,kBAAkB,aAAa,OAAO,gBAAgB;AAAA,UACrF;AAEA,iBAAO,cAAc,KAAK,QAAQ,UAAU,WAAW,WAAW;AAAA,QACpE,SAAS,OAAO;AACd,gBAAM,cAAc,KAAK,IAAI;AAC7B,gBAAM,UAAU;AAAA,YACd;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,eAAe,KAAK;AAAA,UACtB;AACA,mBAAS,KAAK,OAAO;AAKrB,cAAI,iBAAiB,cAAc,WAAW,QAAQ,YAAY,MAAM;AACtE,kBAAM;AAAA,UACR;AAEA,gBAAM,aAAyC;AAAA,YAC7C,SAAS;AAAA,YACT,WAAW,KAAK,IAAI,GAAG,YAAY,QAAQ,IAAI,UAAU,QAAQ,CAAC;AAAA,YAClE;AAAA,YACA;AAAA,UACF;AACA,gBAAM,cACJ,gBAAgB,gBACf,QAAQ,OAAO,cAAc,UAAU,KAAK,YAAY,KAAK;AAEhE,cAAI,aAAa;AACf,oBAAQ,OAAO,UAAU,UAAU;AACnC,kBAAM,UAAU,iBAAiB,QAAQ,OAAO,aAAa,UAAU,CAAC;AACxE,gBAAI,UAAU,GAAG;AACf,oBAAM,eAAe,SAAS,WAAW,QAAQ,GAAG;AAAA,YACtD;AACA;AAAA,UACF;AAEA,gBAAM,sBAAsB,KAAK,OAAO,QAAQ;AAAA,QAClD,UAAE;AACA,uBAAa,QAAQ;AAAA,QACvB;AAAA,MACF;AAEA,YAAM,sBAAsB,KAAK,QAAW,QAAQ;AAAA,IACtD,UAAE;AACA,iBAAW,QAAQ;AAAA,IACrB;AAAA,EACF;AAAA,EAEQ,uBACN,KACA,SACA,WACA,SACA,QACA,wBACA,gBAC0B;AAC1B,UAAM,UAAoC;AAAA,MACxC;AAAA,MACA;AAAA,MACA,gBAAgB,CAAC,kBAAkB,eAAe;AAChD,aAAK,eAAe,QAAQ,GAAG;AAC/B,uBAAe;AACf,+BAAuB,gBAAgB;AACvC,cAAM,gBAAgB;AAAA,UACpB;AAAA,UACA,KAAK,KAAK,IAAI;AAAA,UACd;AAAA,UACA,YAAY,IAAI;AAAA,QAClB;AACA,cAAM,qBAAqB,cAAc,IAAI;AAC7C,cAAM,QAAQ;AAAA,UACZ,uBAAuB,SACnB,gBACA,EAAE,GAAG,eAAe,YAAY,mBAAmB;AAAA,QACzD;AACA,gBAAQ,aAAa,KAAK;AAC1B,eAAO;AAAA,MACT;AAAA,MACA,gBAAgB,MAAM,KAAK,eAAe,QAAQ,GAAG;AAAA,IACvD;AAEA,QAAI,WAAW,QAAW;AACxB,cAAQ,SAAS;AAAA,IACnB;AAEA,QAAI,QAAQ,mBAAmB,QAAW;AACxC,cAAQ,iBAAiB,EAAE,GAAG,QAAQ,eAAe;AAAA,IACvD;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,eAAe,QAAiC,KAAwB;AAC9E,QAAI,QAAQ,YAAY,MAAM;AAC5B,UAAI,OAAO,kBAAkB,mBAAmB;AAC9C,cAAM,OAAO;AAAA,MACf;AAEA,YAAM,IAAI,WAAW;AAAA,QACnB,SAAS,EAAE,OAAO,IAAI,IAAI,WAAW,IAAI,UAAU;AAAA,QACnD,SAAS,yBAAyB,IAAI,EAAE;AAAA,QACxC,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAOA,SAAS,iBACP,cACA,SACA,KACY;AACZ,QAAM,YAAY,mBAAmB,SAAS,SAAS;AAEvD,MAAI,iBAAiB,UAAa,cAAc,QAAW;AACzD,WAAO,EAAE,SAAS,MAAM,OAAU;AAAA,EACpC;AAEA,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,kBAAkB,MAAY,WAAW,MAAM,cAAc,MAAM;AACzE,QAAM,gBACJ,cAAc,SACV,SACA,WAAW,MAAM;AACf,eAAW;AAAA,MACT,IAAI,aAAa;AAAA,QACf,SAAS,EAAE,OAAO,IAAI,IAAI,WAAW,IAAI,WAAW,UAAU;AAAA,QAC9D,SAAS,gCAAgC,SAAS,OAAO,IAAI,EAAE;AAAA,QAC/D,WAAW,SAAS,aAAa;AAAA,MACnC,CAAC;AAAA,IACH;AAAA,EACF,GAAG,SAAS;AAElB,MAAI,cAAc,YAAY,MAAM;AAClC,oBAAgB;AAAA,EAClB,OAAO;AACL,kBAAc,iBAAiB,SAAS,iBAAiB,EAAE,MAAM,KAAK,CAAC;AAAA,EACzE;AAEA,SAAO;AAAA,IACL,SAAS,MAAM;AACb,UAAI,kBAAkB,QAAW;AAC/B,qBAAa,aAAa;AAAA,MAC5B;AACA,oBAAc,oBAAoB,SAAS,eAAe;AAAA,IAC5D;AAAA,IACA,QAAQ,WAAW;AAAA,EACrB;AACF;AAiBA,SAAS,mBACP,cACA,SACA,KACA,SACc;AACd,QAAM,mBAAmB,mBAAmB,SAAS,gBAAgB;AACrE,QAAM,iBAAiB,mBAAmB,SAAS,cAAc;AAEjE,MAAI,qBAAqB,UAAa,mBAAmB,QAAW;AAClE,UAAM,QAAsB;AAAA,MAC1B,SAAS,MAAM;AAAA,MACf,gBAAgB,MAAM;AAAA,IACxB;AACA,QAAI,iBAAiB,OAAW,OAAM,SAAS;AAC/C,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,YAAY,SAAS,aAAa;AACxC,QAAM,kBAAkB,MAAY,WAAW,MAAM,cAAc,MAAM;AAEzE,MAAI,cAAc,YAAY,MAAM;AAClC,oBAAgB;AAAA,EAClB,OAAO;AACL,kBAAc,iBAAiB,SAAS,iBAAiB,EAAE,MAAM,KAAK,CAAC;AAAA,EACzE;AAEA,QAAM,eACJ,qBAAqB,SACjB,SACA,WAAW,MAAM;AACf,eAAW;AAAA,MACT,IAAI,aAAa;AAAA,QACf,SAAS,EAAE,SAAS,kBAAkB,OAAO,IAAI,IAAI,WAAW,IAAI,UAAU;AAAA,QAC9E,SAAS,oBAAoB,OAAO,OAAO,CAAC,oBAAoB,OAAO,gBAAgB,CAAC,OAAO,IAAI,EAAE;AAAA,QACrG;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,GAAG,gBAAgB;AAEzB,MAAI;AACJ,QAAM,mBAAmB,MAAY;AACnC,QAAI,mBAAmB,UAAa,WAAW,OAAO,QAAS;AAC/D,QAAI,eAAe,OAAW,cAAa,UAAU;AACrD,iBAAa,WAAW,MAAM;AAC5B,iBAAW;AAAA,QACT,IAAI,aAAa;AAAA,UACf,SAAS,EAAE,SAAS,OAAO,IAAI,IAAI,WAAW,IAAI,WAAW,eAAe;AAAA,UAC5E,SACE,oBAAoB,OAAO,OAAO,CAAC,6BACf,OAAO,cAAc,CAAC,QAAQ,IAAI,EAAE;AAAA,UAC1D;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,GAAG,cAAc;AAAA,EACnB;AACA,mBAAiB;AAEjB,SAAO;AAAA,IACL,SAAS,MAAM;AACb,UAAI,iBAAiB,OAAW,cAAa,YAAY;AACzD,UAAI,eAAe,OAAW,cAAa,UAAU;AACrD,oBAAc,oBAAoB,SAAS,eAAe;AAAA,IAC5D;AAAA,IACA,gBAAgB;AAAA,IAChB,QAAQ,WAAW;AAAA,EACrB;AACF;AAGA,SAAS,eACP,SACA,QACA,KACe;AACf,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,WAAW,QAAW;AACxB,iBAAW,SAAS,OAAO;AAC3B;AAAA,IACF;AAEA,QAAI,OAAO,SAAS;AAClB,aAAO,eAAe,QAAQ,GAAG,CAAC;AAClC;AAAA,IACF;AAEA,UAAM,cAAc,MAAY;AAC9B,mBAAa,KAAK;AAClB,aAAO,eAAe,QAAQ,GAAG,CAAC;AAAA,IACpC;AACA,UAAM,QAAQ,WAAW,MAAM;AAC7B,aAAO,oBAAoB,SAAS,WAAW;AAC/C,cAAQ;AAAA,IACV,GAAG,OAAO;AACV,WAAO,iBAAiB,SAAS,aAAa,EAAE,MAAM,KAAK,CAAC;AAAA,EAC9D,CAAC;AACH;AAGA,SAAS,eAAe,QAAqB,KAAqC;AAChF,MAAI,OAAO,kBAAkB,mBAAmB;AAC9C,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO,IAAI,WAAW;AAAA,IACpB,SAAS,EAAE,OAAO,IAAI,IAAI,WAAW,IAAI,UAAU;AAAA,IACnD,SAAS,yBAAyB,IAAI,EAAE;AAAA,IACxC,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,iBAAiB,OAAmC;AAC3D,MAAI,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG;AAChE,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,MAAM,KAAK;AACzB;AAEA,SAAS,mBAAmB,OAA+C;AACzE,MAAI,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG;AAChE,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,MAAM,KAAK;AACzB;AAEA,eAAe,YACb,UACA,SACA,QACA,KACkC;AAClC,MAAI,WAAW,QAAW;AACxB,WAAO,SAAS,OAAO;AAAA,EACzB;AAEA,SAAO,QAAQ,KAAK,CAAC,SAAS,OAAO,GAAG,kBAAkB,QAAQ,GAAG,CAAC,CAAC;AACzE;AAEA,SAAS,kBACP,QACA,KACkC;AAClC,SAAO,IAAI,QAAQ,CAAC,GAAG,WAAW;AAChC,UAAM,cAAc,MAAY;AAC9B,UAAI,OAAO,kBAAkB,mBAAmB;AAC9C,eAAO,OAAO,MAAM;AACpB;AAAA,MACF;AAEA;AAAA,QACE,IAAI,WAAW;AAAA,UACb,SAAS,EAAE,OAAO,IAAI,IAAI,WAAW,IAAI,UAAU;AAAA,UACnD,SAAS,yBAAyB,IAAI,EAAE;AAAA,UACxC,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAEA,QAAI,OAAO,SAAS;AAClB,kBAAY;AACZ;AAAA,IACF;AAEA,WAAO,iBAAiB,SAAS,aAAa,EAAE,MAAM,KAAK,CAAC;AAAA,EAC9D,CAAC;AACH;AAEA,SAAS,qBAAqB,OAAmC;AAC/D,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC;AACtC;AAEA,SAAS,cACP,SACA,WACA,aACA,kBACA,OACiB;AACjB,QAAM,SAA0B;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,KAAK,IAAI,GAAG,YAAY,QAAQ,IAAI,UAAU,QAAQ,CAAC;AAAA,IACnE;AAAA,EACF;AAEA,MAAI,UAAU,QAAW;AACvB,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO;AACT;AAEA,SAAS,cACP,KACA,QACA,UACA,WACA,aACiB;AACjB,QAAM,aAAa,KAAK,IAAI,GAAG,YAAY,QAAQ,IAAI,UAAU,QAAQ,CAAC;AAC1E,QAAM,eAAe,4BAA4B,MAAM;AACvD,QAAM,UAA2B;AAAA,IAC/B;AAAA,IACA,uBAAuBC,yBAAwB,OAAO,kBAAkB,UAAU;AAAA,IAClF,kBAAkB,OAAO;AAAA,IACzB;AAAA,IACA;AAAA,IACA,OAAO,IAAI;AAAA,IACX,WAAW,IAAI;AAAA,IACf,SAAS,OAAO,WAAW,IAAI,WAAW;AAAA,IAC1C;AAAA,IACA,YAAY,IAAI;AAAA,IAChB,UAAU,cAAc,YAAY,OAAO,YAAY;AAAA,IACvD,UAAU,CAAC,GAAI,OAAO,YAAY,CAAC,CAAE;AAAA,EACvC;AAEA,MAAI,IAAI,WAAW,OAAW,SAAQ,SAAS,EAAE,GAAG,IAAI,OAAO;AAC/D,MAAI,IAAI,gBAAgB,OAAW,SAAQ,cAAc,EAAE,GAAG,IAAI,YAAY;AAC9E,MAAI,OAAO,eAAe,OAAW,SAAQ,aAAa,OAAO;AAAA,WACxD,IAAI,eAAe,OAAW,SAAQ,aAAa,IAAI;AAChE,MAAI,OAAO,aAAa,OAAW,SAAQ,WAAW,OAAO;AAAA,WACpD,cAAc,aAAa,OAAW,SAAQ,WAAW,aAAa;AAC/E,MAAI,iBAAiB,OAAW,SAAQ,eAAe;AACvD,MAAI,IAAI,aAAa,OAAW,SAAQ,WAAW,EAAE,GAAG,IAAI,SAAS;AAErE,SAAO;AACT;AAEA,SAAS,4BACP,QACwC;AACxC,QAAM,eAAe,OAAO;AAE5B,MAAI,iBAAiB,QAAW;AAC9B,UAAMC,cAAyC,EAAE,UAAU,aAAa,SAAS;AAEjF,QAAI,aAAa,WAAW,OAAW,CAAAA,YAAW,SAAS,aAAa;AACxE,QAAI,aAAa,aAAa,OAAW,CAAAA,YAAW,WAAW,aAAa;AAC5E,QAAI,aAAa,qBAAqB,QAAW;AAC/C,MAAAA,YAAW,mBAAmB,aAAa;AAAA,IAC7C;AACA,QAAI,aAAa,mBAAmB;AAClC,MAAAA,YAAW,iBAAiB,aAAa;AAC3C,QAAI,aAAa,YAAY,OAAW,CAAAA,YAAW,UAAU,EAAE,GAAG,aAAa,QAAQ;AAEvF,WAAOA;AAAA,EACT;AAEA,MAAI,OAAO,aAAa,UAAa,OAAO,aAAa,QAAW;AAClE,WAAO;AAAA,EACT;AAEA,QAAM,aAAyC,EAAE,UAAU,OAAO,YAAY,MAAM;AAEpF,MAAI,OAAO,aAAa,QAAW;AACjC,eAAW,WAAW,OAAO;AAAA,EAC/B;AAEA,SAAO;AACT;AAEA,SAAS,sBACP,KACA,OACA,UACe;AACf,SAAO,IAAI,cAAc;AAAA,IACvB,OAAO;AAAA,IACP,SAAS;AAAA,MACP;AAAA,MACA,OAAO,IAAI;AAAA,MACX,WAAW,IAAI;AAAA,IACjB;AAAA,IACA,SAAS,wBAAwB,IAAI,EAAE;AAAA,IACvC,WAAW,YAAY,KAAK;AAAA,EAC9B,CAAC;AACH;AAEA,SAAS,eAAe,OAAsC;AAC5D,MAAI,iBAAiB,mBAAmB;AACtC,WAAO;AAAA,MACL,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,MAAM,MAAM;AAAA,MACZ,WAAW,MAAM;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,iBAAiB,OAAO;AAC1B,WAAO;AAAA,MACL,SAAS,MAAM;AAAA,MACf,MAAM,MAAM;AAAA,IACd;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS,OAAO,KAAK;AAAA,IACrB,MAAM;AAAA,EACR;AACF;AAEA,SAAS,YAAY,OAAyB;AAC5C,SAAO,iBAAiB,qBAAqB,MAAM;AACrD;AAEA,SAASD,yBAAwB,OAAe,YAA4B;AAC1E,MAAI,cAAc,GAAG;AACnB,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,aAAa;AAC/B;;;ACxlBA,eAAsB,SAAS,SAAoD;AACjF,QAAM,EAAE,QAAQ,MAAM,IAAI;AAE1B,MAAI,MAAM,YAAY,OAAO;AAC3B,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,SAAS,MAAM,GAAG;AAAA,MAC7B,SAAS,cAAc,MAAM,EAAE;AAAA,MAC/B,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,MAAM,OAAO,QAAQ,MAAM,OAAO,OAAO;AAE/D,MAAI;AACJ,MAAI;AACF,yBAAqB,MAAM,OAAO,QAAQ,MAAM,YAAY,OAAO;AACnE,UAAM,SAAS,QAAQ,UAAU,IAAI,eAAe;AACpD,UAAM,MAAM,eAAe,OAAO,eAAe,oBAAoB,OAAO;AAC5E,UAAM,WAAW,oBAAI,IAA6B;AAAA,MAChD,CAAC,UAAU,aAAa;AAAA,MACxB,CAAC,eAAe,kBAAkB;AAAA,IACpC,CAAC;AACD,UAAM,WAAW,+BAA+B;AAAA,MAC9C,gBAAgB,CAAC,EAAE,KAAK,MAAM,SAAS,IAAI,IAAI;AAAA,IACjD,CAAC;AAED,WAAO,MAAM,OAAO,QAAQ,KAAK,UAAU,oBAAoB,SAAS,MAAM,CAAC;AAAA,EACjF,UAAE;AACA,QAAI,uBAAuB,QAAW;AACpC,YAAM,mBAAmB,WAAW;AAAA,IACtC;AACA,UAAM,cAAc,WAAW;AAAA,EACjC;AACF;AAEA,SAAS,eACP,OACA,eACA,oBACA,SACa;AACb,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,SAA2B;AAAA,IAC/B,MAAM,MAAM,OAAO;AAAA,IACnB,UAAU,cAAc;AAAA,EAC1B;AACA,QAAM,cAAgC;AAAA,IACpC,MAAM,MAAM,YAAY;AAAA,IACxB,UAAU,mBAAmB;AAAA,EAC/B;AAEA,QAAM,eAAwC,EAAE,SAAS,MAAM,GAAG;AAClE,MAAI,MAAM,SAAS,OAAW,cAAa,WAAW,IAAI,MAAM;AAChE,MAAI,MAAM,aAAa,OAAW,QAAO,OAAO,cAAc,MAAM,QAAQ;AAC5E,MAAI,QAAQ,aAAa,OAAW,QAAO,OAAO,cAAc,QAAQ,QAAQ;AAEhF,QAAM,MAAmB;AAAA,IACvB;AAAA,IACA,IAAI,QAAQ,SAAS,aAAa,OAAO,QAAQ,GAAG;AAAA,IACpD;AAAA,IACA;AAAA,EACF;AAEA,MAAI,OAAO,KAAK,YAAY,EAAE,SAAS,GAAG;AACxC,QAAI,WAAW;AAAA,EACjB;AAEA,SAAO;AACT;AAEA,SAAS,aAAa,OAAiB,KAAuC;AAC5E,QAAM,aAAa,MAAM,KAAK,oBAAI,KAAK,GAAG,QAAQ;AAClD,SAAO,SAAS,MAAM,EAAE,IAAI,UAAU,SAAS,EAAE,CAAC;AACpD;AAEA,SAAS,oBACP,SACA,QAC8B;AAC9B,QAAM,UAAwC,CAAC;AAC/C,QAAM,QAAQ,QAAQ,SAAS,OAAO,UAAU;AAChD,QAAM,UAAU,QAAQ,WAAW,OAAO,UAAU;AACpD,MAAI,QAAQ,WAAW,OAAW,SAAQ,SAAS,QAAQ;AAC3D,MAAI,UAAU,OAAW,SAAQ,QAAQ;AACzC,MAAI,QAAQ,eAAe,OAAW,SAAQ,aAAa,QAAQ;AACnE,MAAI,YAAY,OAAW,SAAQ,UAAU;AAC7C,MAAI,QAAQ,mBAAmB,OAAW,SAAQ,iBAAiB,QAAQ;AAC3E,SAAO;AACT;;;ALzJA,IAAM,gBAAmC,EAAE,MAAM,SAAS,UAAU,QAAQ;AA+CrE,SAAS,WAAW,SAAsD;AAC/E,QAAM,EAAE,QAAQ,aAAa,WAAW,SAAS,WAAW,GAAG,KAAK,IAAI;AACxE,QAAM,QAAQ,WAAW;AAAA,IACvB,aAAa,EAAE,MAAM,YAAY,MAAM,SAAS,YAAY,QAAQ;AAAA,IACpE,IAAI,WAAW,UAAU,mBAAmB,WAAW,YAAY,IAAI,CAAC;AAAA,IACxE,MAAM;AAAA,IACN,WAAW;AAAA,IACX,QAAQ,EAAE,MAAM,aAAa,SAAS,GAAG,SAAS,cAAc;AAAA,EAClE,CAAC;AACD,SAAO,SAAS,EAAE,QAAQ,OAAO,GAAG,KAAK,CAAC;AAC5C;AA6CO,SAAS,aAAa,SAAwD;AACnF,QAAM,EAAE,QAAQ,WAAW,SAAS,WAAW,QAAQ,GAAG,KAAK,IAAI;AACnE,QAAM,QAAQ,WAAW;AAAA,IACvB,aAAa,EAAE,MAAM,aAAa,SAAS,GAAG,SAAS,cAAc;AAAA,IACrE,IAAI,WAAW,YAAY,mBAAmB,OAAO,MAAM,SAAS,CAAC;AAAA,IACrE,MAAM;AAAA,IACN,WAAW;AAAA,IACX,QAAQ,EAAE,MAAM,OAAO,MAAM,SAAS,OAAO,QAAQ;AAAA,EACvD,CAAC;AACD,SAAO,SAAS,EAAE,QAAQ,OAAO,GAAG,KAAK,CAAC;AAC5C;AAgDO,SAAS,YAAY,SAAuD;AACjF,QAAM,EAAE,QAAQ,aAAa,SAAS,WAAW,QAAQ,GAAG,KAAK,IAAI;AACrE,QAAM,QAAQ,WAAW;AAAA,IACvB,aAAa,EAAE,MAAM,YAAY,MAAM,SAAS,YAAY,QAAQ;AAAA,IACpE,IAAI,WAAW,QAAQ,mBAAmB,OAAO,MAAM,YAAY,IAAI,CAAC;AAAA,IACxE,MAAM;AAAA,IACN,WAAW;AAAA,IACX,QAAQ,EAAE,MAAM,OAAO,MAAM,SAAS,OAAO,QAAQ;AAAA,EACvD,CAAC;AACD,SAAO,SAAS,EAAE,QAAQ,OAAO,GAAG,KAAK,CAAC;AAC5C;AAUA,SAAS,WAAW,OAAkC;AACpD,QAAM,QAAkB;AAAA,IACtB,aAAa,MAAM;AAAA,IACnB,IAAI,MAAM;AAAA,IACV,WAAW,MAAM;AAAA,IACjB,QAAQ,MAAM;AAAA,EAChB;AACA,MAAI,MAAM,SAAS,OAAW,OAAM,OAAO,MAAM;AACjD,SAAO;AACT;AAEA,SAAS,aAAa,WAA2B;AAC/C,SAAO,WAAW,SAAS,IAAI,YAAY,YAAY,SAAS;AAClE;AAEA,SAAS,mBAAmB,QAAgB,aAA6B;AACvE,SAAO,GAAG,MAAM,KAAK,WAAW;AAClC;;;AMnOA,SAAS,UAAAE,eAAc;AACvB,SAAS,gBAAgB;AA6DzB,eAAsB,cACpB,QACA,UAAgC,CAAC,GACX;AACtB,MAAI,cAAc,MAAM,GAAG;AACzB,WAAO,iBAAiB,MAAM;AAAA,EAChC;AAEA,MAAI,OAAO,WAAW,YAAY;AAChC,WAAO,iBAAiB,MAAM,OAAO,CAAC;AAAA,EACxC;AAEA,MAAI,oBAAoB,MAAM,GAAG;AAC/B,WAAO,iBAAiB,OAAO,KAAK;AAAA,EACtC;AAEA,MAAI,kBAAkB,MAAM,GAAG;AAC7B,UAAM,SAAS,QAAQ,OAAO,QAAQ,KAAK,OAAO,GAAG;AAErD,QAAI,UAAU,QAAW;AACvB,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,OAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,wBAAwB,MAAM,GAAG;AACnC,UAAM,SAAS,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS;AAE3D,QAAI,UAAU,QAAW;AACvB,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,OAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAOC,QAAO,KAAK,OAAO,QAAQ;AAAA,EACpC;AAEA,MAAI,mBAAmB,MAAM,GAAG;AAC9B,UAAM,aAAa,QAAQ,YAAY;AACvC,UAAM,QAAQ,MAAM,WAAW,OAAO,IAAI;AAE1C,QAAI,OAAO,aAAa,UAAU;AAChC,aAAOA,QAAO,KAAK,KAAK;AAAA,IAC1B;AAEA,WAAO,MAAM,SAAS,OAAO,YAAY,MAAM;AAAA,EACjD;AAEA,QAAM,+BAA+B,6BAA6B,UAAU,SAAS;AACvF;AAQO,SAAS,mBAAmB,QAA6C;AAC9E,MAAI,cAAc,MAAM,KAAK,OAAO,WAAW,YAAY;AACzD,WAAO;AAAA,EACT;AAEA,MAAI,oBAAoB,MAAM,EAAG,QAAO,EAAE,OAAO,SAAS;AAC1D,MAAI,kBAAkB,MAAM,EAAG,QAAO,EAAE,KAAK,SAAS;AACtD,MAAI,wBAAwB,MAAM,EAAG,QAAO,EAAE,WAAW,SAAS;AAClE,MAAI,mBAAmB,MAAM,EAAG,QAAO,EAAE,UAAU,OAAO,UAAU,MAAM,SAAS;AAEnF,SAAO;AACT;AAEA,SAAS,cAAc,OAAsC;AAC3D,SAAO,OAAO,UAAU,YAAYA,QAAO,SAAS,KAAK;AAC3D;AAEA,SAAS,oBAAoB,OAA4C;AACvE,SAAO,SAAS,KAAK,KAAK,WAAW,SAAS,cAAc,MAAM,KAAK;AACzE;AAEA,SAAS,kBAAkB,OAA0C;AACnE,SAAO,SAAS,KAAK,KAAK,OAAO,MAAM,QAAQ;AACjD;AAEA,SAAS,wBAAwB,OAAgD;AAC/E,SAAO,SAAS,KAAK,KAAK,OAAO,MAAM,cAAc;AACvD;AAEA,SAAS,mBAAmB,OAA2C;AACrE,SAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AAClD;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,iBAAiB,OAAiC;AACzD,SAAOA,QAAO,SAAS,KAAK,IAAIA,QAAO,KAAK,KAAK,IAAI;AACvD;AAEA,SAAS,+BACP,SACA,YACA,YACoB;AACpB,SAAO,IAAI,mBAAmB;AAAA,IAC5B,SAAS,EAAE,YAAY,WAAW;AAAA,IAClC;AAAA,IACA,WAAW;AAAA,EACb,CAAC;AACH;;;ACvKO,SAAS,wBAAwB,SAAqD;AAC3F,QAAM,EAAE,QAAQ,UAAU,QAAQ,KAAK,KAAK,UAAU,GAAG,KAAK,IAAI;AAClE,QAAM,WAAW,aAAa,IAAI;AAElC,MAAI,aAAa,OAAW,UAAS,WAAW,mBAAmB,QAAQ;AAC3E,MAAI,aAAa,OAAW,UAAS,WAAW,mBAAmB,QAAQ;AAC3E,MAAI,QAAQ,OAAW,UAAS,MAAM,iBAAiB,GAAG;AAC1D,MAAI,QAAQ,OAAW,UAAS,MAAM,iBAAiB,GAAG;AAC1D,MAAI,WAAW,OAAW,UAAS,SAAS;AAC5C,MAAI,WAAW,OAAW,UAAS,SAAS;AAE5C,SAAO;AACT;AAQA,SAAS,iBAAiB,SAA8C;AACtE,QAAM,EAAE,OAAO,qBAAqB,YAAY,YAAY,YAAY,eAAe,GAAG,KAAK,IAC7F;AACF,QAAM,WAAW,aAAa,IAAI;AAElC,MAAI,UAAU,OAAW,UAAS,QAAQ;AAC1C,MAAI,eAAe,OAAW,UAAS,aAAa,mBAAmB,UAAU;AACjF,MAAI,eAAe,OAAW,UAAS,aAAa,mBAAmB,UAAU;AACjF,MAAI,eAAe,OAAW,UAAS,aAAa,0BAA0B,UAAU;AACxF,MAAI,wBAAwB,OAAW,UAAS,sBAAsB;AACtE,MAAI,kBAAkB,OAAW,UAAS,gBAAgB;AAE1D,SAAO;AACT;AAQA,SAAS,0BAA0B,QAAwD;AACzF,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,OAAO,IAAI,CAAC,SAAS,mBAAmB,IAAI,CAAC;AAAA,EACtD;AAEA,SAAO,mBAAmB,MAAM;AAClC;AAQA,SAAS,iBAAiB,SAA8C;AACtE,QAAM,EAAE,IAAI,MAAM,qBAAqB,KAAK,YAAY,KAAK,GAAG,KAAK,IAAI;AACzE,QAAM,WAAW,aAAa,IAAI;AAElC,MAAI,OAAO,OAAW,UAAS,KAAK,sBAAsB,EAAE;AAC5D,MAAI,SAAS,OAAW,UAAS,OAAO,mBAAmB,IAAI;AAC/D,MAAI,QAAQ,OAAW,UAAS,MAAM,mBAAmB,GAAG;AAC5D,MAAI,eAAe,OAAW,UAAS,aAAa,mBAAmB,UAAU;AACjF,MAAI,QAAQ,OAAW,UAAS,MAAM,mBAAmB,GAAG;AAC5D,MAAI,wBAAwB,OAAW,UAAS,sBAAsB;AAEtE,SAAO;AACT;AAQA,SAAS,sBAAsB,QAAkC;AAC/D,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,OAAO,IAAI,CAAC,SAAS,mBAAmB,IAAI,CAAC;AAAA,EACtD;AAEA,SAAO,mBAAmB,MAAM;AAClC;;;ACzDO,SAAS,2BAA2B,QAA2C;AACpF,QAAM,eAAe,OAAO,gBAAgB;AAC5C,SAAO;AAAA,IACL,WAAW,aAAa,IAAI,CAAC,WAAW,EAAE,cAAc,OAAO,IAAI,MAAM,SAAS,EAAE;AAAA,EACtF;AACF;AAkFA,eAAsB,yBACpB,SACsC;AACtC,QAAM,MAAM,QAAQ,QAAQ,MAAM,YAAY,IAAI;AAClD,QAAM,YAAY,QAAQ,cAAc;AACxC,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,aAAa,KAAK,IAAI,GAAG,QAAQ,cAAc,CAAC;AACtD,QAAM,kBAAkB,wBAAwB,QAAQ,OAAO;AAE/D,QAAM,SAAsC;AAAA,IAC1C,MAAM,QAAQ,QAAQ;AAAA,IACtB,IAAI;AAAA,IACJ;AAAA,IACA,SAAS,CAAC;AAAA,EACZ;AAEA,QAAM,eAAe,IAAI;AACzB,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,OAAO,QAAQ,QAAQ,OAAO;AAC5D,WAAO,QAAQ,YAAY,IAAI,IAAI;AACnC,WAAO,WAAW,QAAQ;AAC1B,WAAO,eAAe,QAAQ;AAC9B,QAAI;AACF,UAAI,WAAW;AACb,cAAM,YAAY,IAAI;AACtB,cAAM,UAAU,MAAM,QAAQ,GAAG,KAAK,QAAQ;AAC9C,eAAO,QAAQ,SAAS,IAAI,IAAI;AAChC,eAAO,SAAS,QAAQ,MAAM,GAAG,UAAU;AAAA,MAC7C;AACA,aAAO,KAAK;AAAA,IACd,UAAE;AACA,YAAM,kBAAkB,IAAI;AAC5B,YAAM,QAAQ,WAAW;AACzB,aAAO,QAAQ,eAAe,IAAI,IAAI;AAAA,IACxC;AAAA,EACF,SAAS,OAAO;AACd,WAAO,QAAQ,yBAAyB,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,OAIhC;AACA,MAAI,iBAAiB,OAAO;AAC1B,UAAM,UAA6D,EAAE,SAAS,MAAM,QAAQ;AAC5F,QAAI,MAAM,SAAS,QAAS,SAAQ,OAAO,MAAM;AACjD,UAAM,OAAQ,MAA6B;AAC3C,QAAI,OAAO,SAAS,SAAU,SAAQ,OAAO;AAC7C,WAAO;AAAA,EACT;AACA,SAAO,EAAE,SAAS,OAAO,KAAK,EAAE;AAClC;;;AChFA,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AASzB,SAAS,2BACd,OACA,UAAiC,CAAC,GACZ;AACtB,QAAM,gBAAgB,KAAK,IAAI,GAAG,QAAQ,iBAAiB,wBAAwB;AACnF,QAAM,gBAAgB,KAAK,IAAI,GAAG,QAAQ,iBAAiB,uBAAuB;AAClF,QAAM,QAAQ,QAAQ,SAAS;AAE/B,QAAM,QAAuB;AAAA,IAC3B,SAAS;AAAA,IACT,MAAM,oBAAI,IAAI;AAAA,EAChB;AAEA,QAAM,UAAU,CAAC,KAAa,SAA0B,YAAoC;AAC1F,QAAI,WAAW,MAAM,SAAS;AAC5B,aAAO,iBAAiB,OAAO;AAAA,IACjC;AAEA,QAAI,SAAS,MAAM,KAAK,IAAI,GAAG;AAC/B,QAAI,WAAW,QAAW;AACxB,eAAS,CAAC;AACV,YAAM,KAAK,IAAI,KAAK,MAAM;AAAA,IAC5B;AAEA,UAAM,QAAmB,EAAE,QAAQ;AACnC,QAAI,gBAAgB,GAAG;AACrB,YAAM,YAAY,WAAW,MAAM;AACjC,mBAAW,OAAO,KAAK,KAAK;AAAA,MAC9B,GAAG,aAAa;AAGhB,YAAM,QAAQ,MAAM;AACpB,UAAI,UAAU,UAAa,OAAO,MAAM,UAAU,YAAY;AAC5D,cAAM,MAAM;AAAA,MACd;AAAA,IACF;AAEA,WAAO,KAAK,KAAK;AAGjB,WAAO,OAAO,SAAS,eAAe;AACpC,YAAM,UAAU,OAAO,MAAM;AAC7B,UAAI,YAAY,QAAW;AACzB,wBAAgB,OAAO;AACvB,aAAK,iBAAiB,QAAQ,OAAO;AAAA,MACvC;AAAA,IACF;AACA,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAEA,QAAM,UAAU,OACd,YACuD;AACvD,UAAM,MAAM,MAAM,OAAO;AACzB,UAAM,SAAS,MAAM,KAAK,IAAI,GAAG;AACjC,QAAI,WAAW,UAAa,OAAO,SAAS,GAAG;AAC7C,YAAM,QAAQ,OAAO,IAAI;AACzB,UAAI,UAAU,QAAW;AACvB,wBAAgB,KAAK;AACrB,YAAI,OAAO,WAAW,EAAG,OAAM,KAAK,OAAO,GAAG;AAC9C,eAAO,EAAE,KAAK,SAAS,MAAM,QAAQ;AAAA,MACvC;AAAA,IACF;AACA,UAAM,UAAU,MAAM,MAAM,QAAQ,OAAO;AAC3C,WAAO,EAAE,KAAK,QAAQ;AAAA,EACxB;AAEA,SAAO;AAAA,IACL,SAAS,OAAO,YAAY;AAC1B,YAAM,EAAE,KAAK,QAAQ,IAAI,MAAM,QAAQ,OAAO;AAC9C,aAAO,kBAAkB,SAAS,KAAK,OAAO;AAAA,IAChD;AAAA,IACA,WAAW,YAAY;AACrB,YAAM,UAAU;AAChB,YAAM,UAAuB,CAAC;AAC9B,iBAAW,UAAU,MAAM,KAAK,OAAO,GAAG;AACxC,mBAAW,SAAS,QAAQ;AAC1B,0BAAgB,KAAK;AACrB,kBAAQ,KAAK,KAAK;AAAA,QACpB;AAAA,MACF;AACA,YAAM,KAAK,MAAM;AACjB,YAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,UAAU,iBAAiB,MAAM,OAAO,CAAC,CAAC;AAAA,IAC3E;AAAA,IACA,kBAAkB,CAAC,eAA6D;AAC9E,UAAI,eAAe,OAAW,QAAO,MAAM,gBAAgB;AAC3D,aAAO,MAAM,gBAAgB,UAAU;AAAA,IACzC;AAAA,IACA,aAAa,CAAC,eAAe,MAAM,YAAY,UAAU;AAAA,IACzD,UAAU,MAAM;AACd,UAAI,QAAQ;AACZ,iBAAW,UAAU,MAAM,KAAK,OAAO,EAAG,UAAS,OAAO;AAC1D,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAGA,SAAS,aAAa,SAAoC;AACxD,QAAM,WAAW,QAAQ,YAAY,QAAQ,YAAY;AACzD,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,WAAW,OAAO,QAAQ,aAAa,WAAW,QAAQ,WAAW;AAC3E,SAAO,GAAG,QAAQ,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,QAAQ;AACxD;AAEA,SAAS,WAAW,OAAsB,KAAa,OAAwB;AAC7E,QAAM,SAAS,MAAM,KAAK,IAAI,GAAG;AACjC,MAAI,WAAW,OAAW;AAC1B,QAAM,QAAQ,OAAO,QAAQ,KAAK;AAClC,MAAI,QAAQ,EAAG;AACf,SAAO,OAAO,OAAO,CAAC;AACtB,MAAI,OAAO,WAAW,EAAG,OAAM,KAAK,OAAO,GAAG;AAC9C,kBAAgB,KAAK;AACrB,OAAK,iBAAiB,MAAM,OAAO;AACrC;AAEA,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,MAAM,cAAc,QAAW;AACjC,iBAAa,MAAM,SAAS;AAC5B,WAAO,MAAM;AAAA,EACf;AACF;AAEA,eAAe,iBAAiB,SAAyC;AACvE,MAAI;AACF,UAAM,QAAQ,WAAW;AAAA,EAC3B,QAAQ;AAAA,EAER;AACF;AAGA,SAAS,gBAAgB,OAAyB;AAChD,SACE,iBAAiB,mBACjB,iBAAiB,gBACjB,iBAAiB;AAErB;AAQA,SAAS,kBACP,SACA,KACA,SACiB;AACjB,MAAI,UAAU;AACd,MAAI,WAAW;AAEf,QAAM,QAAQ,CAAI,OAAqC;AACrD,QAAI;AACJ,QAAI;AACF,gBAAU,GAAG;AAAA,IACf,SAAS,OAAO;AACd,UAAI,gBAAgB,KAAK,EAAG,WAAU;AACtC,aAAO,QAAQ,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACjF;AACA,WAAO,QAAQ,MAAM,CAAC,UAAmB;AACvC,UAAI,gBAAgB,KAAK,EAAG,WAAU;AACtC,YAAM;AAAA,IACR,CAAC;AAAA,EACH;AAEA,QAAM,KAAK,OAAO,QAAQ,IAAI,KAAK;AACnC,QAAM,YACJ,QAAQ,cAAc,SAAY,SAAY,cAAc,QAAQ,WAAW,KAAK;AAEtF,QAAM,UAA2B;AAAA,IAC/B,cAAc,QAAQ;AAAA,IACtB,YAAY,YAAY;AACtB,UAAI,SAAU;AACd,iBAAW;AACX,YAAM,QAAQ,KAAK,SAAS,OAAO;AAAA,IACrC;AAAA,IACA;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,EACjD;AAEA,MAAI,OAAO,QAAQ,QAAQ,YAAY;AACrC,UAAM,QAAQ,QAAQ,IAAI,KAAK,OAAO;AACtC,YAAQ,MAAM,MAAM,MAAM;AAAA,EAC5B;AAEA,SAAO;AACT;AAEA,SAAS,OACP,IACA,OACkB;AAClB,QAAM,UAA4B;AAAA,IAChC,MAAM,CAACC,OAAM,YACX,MAAM,MAAO,YAAY,SAAY,GAAG,KAAKA,OAAM,OAAO,IAAI,GAAG,KAAKA,KAAI,CAAE;AAAA,IAC9E,MAAM,CAACA,OAAM,YACX,MAAM,MAAO,YAAY,SAAY,GAAG,KAAKA,OAAM,OAAO,IAAI,GAAG,KAAKA,KAAI,CAAE;AAAA,EAChF;AACA,MAAI,OAAO,GAAG,WAAW,YAAY;AACnC,UAAM,SAAS,GAAG,OAAO,KAAK,EAAE;AAChC,YAAQ,SAAS,CAACA,OAAM,YACtB,MAAM,MAAO,YAAY,SAAY,OAAOA,OAAM,OAAO,IAAI,OAAOA,KAAI,CAAE;AAAA,EAC9E;AACA,MAAI,OAAO,GAAG,WAAW,YAAY;AACnC,UAAMC,UAAS,GAAG,OAAO,KAAK,EAAE;AAChC,YAAQ,SAAS,CAAC,MAAM,IAAI,YAC1B,MAAM,MAAO,YAAY,SAAYA,QAAO,MAAM,IAAI,OAAO,IAAIA,QAAO,MAAM,EAAE,CAAE;AAAA,EACtF;AACA,MAAI,OAAO,GAAG,UAAU,YAAY;AAClC,UAAMC,SAAQ,GAAG,MAAM,KAAK,EAAE;AAC9B,YAAQ,QAAQ,CAACF,OAAM,YACrB,MAAM,MAAO,YAAY,SAAYE,OAAMF,OAAM,OAAO,IAAIE,OAAMF,KAAI,CAAE;AAAA,EAC5E;AACA,MAAI,OAAO,GAAG,UAAU,YAAY;AAClC,UAAM,QAAQ,GAAG,MAAM,KAAK,EAAE;AAC9B,YAAQ,QAAQ,CAACA,OAAM,YACrB,MAAM,MAAO,YAAY,SAAY,MAAMA,OAAM,OAAO,IAAI,MAAMA,KAAI,CAAE;AAAA,EAC5E;AACA,SAAO;AACT;AAEA,SAAS,cACP,WACA,OAC4B;AAC5B,SAAO;AAAA,IACL,MAAM,CAAC,YAAY,MAAM,MAAM,QAAQ,QAAQ,UAAU,KAAK,OAAO,CAAC,CAAC;AAAA,IACvE,OAAO,CAAC,YAAY,MAAM,MAAM,QAAQ,QAAQ,UAAU,MAAM,OAAO,CAAC,CAAC;AAAA,EAC3E;AACF;;;ACnVA,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,OAAO,UAAU;;;ACNjB,IAAM,8BAA8B;AAc7B,SAAS,sBAAsB,OAAe,QAAQ,QAAgB;AAC3E,MAAI,4BAA4B,KAAK,KAAK,GAAG;AAC3C,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,cAAc,KAAK;AAAA,MAC5B,WAAW;AAAA,MACX,SAAS;AAAA,QACP;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AASO,SAAS,oBAAoB,OAAuB;AACzD,wBAAsB,KAAK;AAE3B,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,QAAMG,cAAa,MAAM,WAAW,GAAG;AACvC,QAAM,WAAqB,CAAC;AAE5B,aAAW,WAAW,MAAM,MAAM,QAAQ,GAAG;AAC3C,QAAI,QAAQ,WAAW,KAAK,YAAY,KAAK;AAC3C;AAAA,IACF;AAEA,QAAI,YAAY,MAAM;AACpB,UAAI,SAAS,SAAS,KAAK,SAAS,SAAS,SAAS,CAAC,MAAM,MAAM;AACjE,iBAAS,IAAI;AAAA,MACf,WAAW,CAACA,aAAY;AACtB,iBAAS,KAAK,OAAO;AAAA,MACvB;AACA;AAAA,IACF;AAEA,aAAS,KAAK,OAAO;AAAA,EACvB;AAEA,QAAM,aAAa,SAAS,KAAK,GAAG;AAEpC,MAAIA,aAAY;AACd,WAAO,WAAW,SAAS,IAAI,IAAI,UAAU,KAAK;AAAA,EACpD;AAEA,SAAO,WAAW,SAAS,IAAI,aAAa;AAC9C;AASO,SAAS,kBAAkB,UAA4B;AAC5D,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,SAAO,oBAAoB,SAAS,KAAK,GAAG,CAAC;AAC/C;AASO,SAAS,mBAAmB,OAAuB;AACxD,QAAM,aAAa,oBAAoB,KAAK;AAC5C,QAAM,QAAQ,WAAW,MAAM,GAAG,EAAE,OAAO,OAAO;AAClD,SAAO,MAAM,MAAM,SAAS,CAAC,KAAK;AACpC;;;AD3DA,IAAM,oBAAoB;AAE1B,IAAM,8BAA6C;AAAA,EACjD,UAAU;AAAA,EACV,gBAAgB,CAAC,WAAW;AAAA,EAC5B,MAAM;AAAA,EACN,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,UAAU,CAAC;AAAA,EACX,cAAc;AAAA,EACd,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU,CAAC,cAAc,aAAa,cAAc,eAAe,iBAAiB,UAAU;AAAA,EAC9F,gBAAgB;AAAA,EAChB,OAAO,CAAC,8DAA8D;AACxE;AA8BO,SAAS,2BAA2B,UAAgC,CAAC,GAAoB;AAC9F,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,cAAc;AAAA,IACd,QAAQ,MAAM,IAAI,cAAc,QAAQ,QAAQ;AAAA,EAClD;AACF;AAEA,IAAM,gBAAN,MAAgD;AAAA,EAI9C,YAA6B,oBAAwC;AAAxC;AAAA,EAAyC;AAAA,EAAzC;AAAA,EAHpB,KAAK;AAAA,EACL,eAAe;AAAA,EAIxB,QAAQ,SAAsD;AAC5D,WAAO,QAAQ,QAAQ,EAAE,KAAK,MAAM;AAClC,YAAM,WAAW,KAAK,QAAQ,KAAK,sBAAsB,QAAQ,IAAI;AACrE,aAAO,IAAI,qBAAqB,QAAQ;AAAA,IAC1C,CAAC;AAAA,EACH;AACF;AAEA,IAAM,uBAAN,MAAsD;AAAA,EAC3C,WAAW;AAAA,EACX,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EAET,YAAY,UAAkB;AAC5B,SAAK,KAAK,IAAI,gBAAgB,QAAQ;AACtC,SAAK,YAAY,IAAI,wBAAwB,QAAQ;AAAA,EACvD;AAAA,EAEA,aAA4B;AAC1B,WAAO,QAAQ,QAAQ;AAAA,EACzB;AACF;AAEA,IAAM,0BAAN,MAAoE;AAAA,EAClE,YAA6B,UAAkB;AAAlB;AAAA,EAAmB;AAAA,EAAnB;AAAA,EAE7B,MAAM,KAAK,SAA2E;AACpF,YAAQ,eAAe;AACvB,UAAM,aAAa,2BAA2B,QAAQ,SAAS,IAAI;AACnE,UAAM,QAAQ,MAAM,eAAe,KAAK,UAAU,UAAU;AAE5D,QAAI,MAAM,SAAS,QAAQ;AACzB,YAAM,wBAAwB,YAAY,sCAAsC,UAAU,EAAE;AAAA,IAC9F;AAEA,UAAM,QAAQ,iBAAiB,MAAM,QAAQ,GAAG,QAAQ,KAAK;AAC7D,UAAM,SAAqC;AAAA,MACzC,SAAS,sBAAsB,iBAAiB,KAAK,UAAU,UAAU,GAAG,KAAK;AAAA,MACjF,YAAY,MAAM;AAAA,IACpB;AAEA,QAAI,MAAM,SAAS,GAAG;AACpB,aAAO,YAAY,MAAM;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MAAM,SAA6E;AACvF,YAAQ,eAAe;AACvB,UAAM,aAAa,2BAA2B,QAAQ,SAAS,IAAI;AACnE,UAAM,YAAY,iBAAiB,KAAK,UAAU,UAAU;AAC5D,UAAM,UAAU,MAAM,uBAAuB,OAAO;AACpD,UAAM,SAAS,2BAA2B,QAAQ,QAAQ,UAAU,UAAU;AAE9E,UAAM,2BAA2B,WAAW,UAAU;AACtD,UAAM,kBAAkB,WAAW,YAAY,SAAS,MAAM;AAE9D,UAAM,OAAO,MAAM,eAAe,KAAK,UAAU,UAAU;AAC3D,UAAM,SAAsC;AAAA,MAC1C,kBAAkB,QAAQ;AAAA,MAC1B,SAAS,WAAW,UAAa,SAAS;AAAA,MAC1C,UAAU,QAAQ,cAAc,YAAY;AAAA,IAC9C;AAEA,QAAI,KAAK,SAAS,QAAW;AAC3B,aAAO,aAAa,KAAK;AAAA,IAC3B;AAEA,QAAI,QAAQ,iBAAiB,QAAW;AACtC,aAAO,eAAeC,mBAAkB,QAAQ,YAAY;AAAA,IAC9D;AAEA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,kBAAN,MAAkD;AAAA,EAChD,YAA6B,UAAkB;AAAlB;AAAA,EAAmB;AAAA,EAAnB;AAAA,EAE7B,MAAM,KAAKC,OAAsC;AAC/C,UAAM,aAAa,2BAA2BA,KAAI;AAClD,UAAM,YAAY,MAAM,KAAK,KAAK,UAAU;AAE5C,QAAI,UAAU,SAAS,aAAa;AAClC,YAAM;AAAA,QACJ;AAAA,QACA,2CAA2C,UAAU;AAAA,MACvD;AAAA,IACF;AAEA,UAAM,YAAY,iBAAiB,KAAK,UAAU,UAAU;AAC5D,UAAM,QAAQ,MAAM,mBAAmB,WAAW,UAAU;AAC5D,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,MAAM,IAAI,CAAC,SAAS,eAAe,KAAK,UAAU,eAAe,YAAY,IAAI,CAAC,CAAC;AAAA,IACrF;AAEA,WAAO,QAAQ,KAAK,cAAc;AAAA,EACpC;AAAA,EAEA,MAAM,KAAKA,OAAmC;AAC5C,WAAO,eAAe,KAAK,UAAU,2BAA2BA,KAAI,CAAC;AAAA,EACvE;AAAA,EAEA,MAAM,OAAO,QAAgB,UAAyB,CAAC,GAAkB;AACvE,UAAM,aAAa,2BAA2B,MAAM;AACpD,UAAM,YAAY,iBAAiB,KAAK,UAAU,UAAU;AAC5D,QAAI;AACF,YAAM,OAAO,SAAS;AAAA,IACxB,SAAS,OAAO;AACd,UAAI,QAAQ,iBAAiB,YAAY,OAAO,QAAQ,EAAG;AAC3D,UAAI,YAAY,OAAO,QAAQ,GAAG;AAChC,cAAM,wBAAwB,YAAY,yBAAyB,UAAU,EAAE;AAAA,MACjF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,MAAc,IAA2B;AACpD,UAAM,aAAa,2BAA2B,IAAI;AAClD,UAAM,WAAW,2BAA2B,EAAE;AAC9C,UAAM,YAAY,iBAAiB,KAAK,UAAU,UAAU;AAC5D,UAAM,UAAU,iBAAiB,KAAK,UAAU,QAAQ;AACxD,QAAI;AACF,YAAM,OAAO,WAAW,OAAO;AAAA,IACjC,SAAS,OAAO;AACd,UAAI,YAAY,OAAO,QAAQ,GAAG;AAChC,cAAM,wBAAwB,YAAY,yBAAyB,UAAU,EAAE;AAAA,MACjF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,MAAM,QAAgB,UAAwB,CAAC,GAAkB;AACrE,UAAM,aAAa,2BAA2B,MAAM;AACpD,UAAM,YAAY,iBAAiB,KAAK,UAAU,UAAU;AAC5D,UAAM,MAAM,WAAW,EAAE,WAAW,QAAQ,cAAc,KAAK,CAAC;AAAA,EAClE;AAAA,EAEA,MAAM,MAAM,QAAgB,UAAwB,CAAC,GAAkB;AACrE,UAAM,aAAa,2BAA2B,MAAM;AACpD,UAAM,YAAY,iBAAiB,KAAK,UAAU,UAAU;AAC5D,QAAI;AACF,YAAM,GAAG,WAAW,EAAE,WAAW,QAAQ,cAAc,MAAM,OAAO,MAAM,CAAC;AAAA,IAC7E,SAAS,OAAO;AACd,UAAI,YAAY,OAAO,QAAQ,GAAG;AAChC,YAAI,QAAQ,cAAe;AAC3B,cAAM,wBAAwB,YAAY,yBAAyB,UAAU,EAAE;AAAA,MACjF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,SAAS,YAAY,OAAgB,MAAuB;AAC1D,SACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACT,MAA6B,SAAS;AAE3C;AAOA,SAAS,iBACP,MACA,OACmB;AACnB,MAAI,UAAU,QAAW;AACvB,WAAO,EAAE,QAAQ,MAAM,QAAQ,EAAE;AAAA,EACnC;AAEA,QAAM,kBAAkB,mBAAmB,MAAM,QAAQ,UAAU,GAAG;AACtE,QAAM,kBACJ,MAAM,WAAW,SACb,OAAO,KAAK,IAAI,iBAAiB,IAAI,IACrC,mBAAmB,MAAM,QAAQ,UAAU,GAAG;AACpD,QAAM,SAAS,KAAK,IAAI,iBAAiB,IAAI;AAC7C,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,iBAAiB,OAAO,MAAM,CAAC;AAEnE,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAEA,gBAAgB,sBACd,WACA,OAC4B;AAC5B,MAAI,MAAM,UAAU,GAAG;AACrB;AAAA,EACF;AAEA,QAAM,SAAS,iBAAiB,WAAW;AAAA,IACzC,KAAK,MAAM,SAAS,MAAM,SAAS;AAAA,IACnC,OAAO,MAAM;AAAA,EACf,CAAC;AAED,mBAAiB,SAAS,QAAQ;AAChC,UAAM,IAAI,WAAW,KAAK;AAAA,EAC5B;AACF;AAEA,eAAe,uBAAuB,SAA4D;AAChG,QAAM,SAAuB,CAAC;AAC9B,MAAI,aAAa;AAEjB,mBAAiB,SAAS,QAAQ,SAAS;AACzC,YAAQ,eAAe;AACvB,UAAM,cAAc,IAAI,WAAW,KAAK;AACxC,WAAO,KAAK,WAAW;AACvB,kBAAc,YAAY;AAC1B,YAAQ,eAAe,YAAY,QAAQ,UAAU;AAAA,EACvD;AAEA,SAAO,aAAa,QAAQ,UAAU;AACxC;AAEA,SAAS,aAAa,QAAsB,YAAgC;AAC1E,QAAM,UAAU,IAAI,WAAW,UAAU;AACzC,MAAI,SAAS;AAEb,aAAW,SAAS,QAAQ;AAC1B,YAAQ,IAAI,OAAO,MAAM;AACzB,cAAU,MAAM;AAAA,EAClB;AAEA,SAAO;AACT;AAEA,eAAe,2BAA2B,WAAmB,YAAmC;AAC9F,MAAI;AACF,UAAM,MAAM,KAAK,QAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AAAA,EAC1D,SAAS,OAAO;AACd,UAAM,wBAAwB,OAAO,UAAU;AAAA,EACjD;AACF;AAEA,eAAe,kBACb,WACA,YACA,SACA,QACe;AACf,MAAI;AACF,QAAI,WAAW,QAAW;AACxB,YAAM,UAAU,WAAW,OAAO;AAClC;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,4BAA4B,SAAS;AAE1D,QAAI;AACF,YAAM,OAAO,MAAM,SAAS,GAAG,QAAQ,YAAY,MAAM;AAAA,IAC3D,UAAE;AACA,YAAM,OAAO,MAAM;AAAA,IACrB;AAAA,EACF,SAAS,OAAO;AACd,UAAM,wBAAwB,OAAO,UAAU;AAAA,EACjD;AACF;AAEA,eAAe,4BAA4B,WAAmB;AAC5D,MAAI;AACF,WAAO,MAAM,KAAK,WAAW,IAAI;AAAA,EACnC,SAAS,OAAO;AACd,QAAI,aAAa,KAAK,MAAM,UAAU;AACpC,aAAO,KAAK,WAAW,IAAI;AAAA,IAC7B;AAEA,UAAM;AAAA,EACR;AACF;AAEA,SAAS,2BACP,OACA,OACA,YACoB;AACpB,SAAO,UAAU,SAAY,SAAY,mBAAmB,OAAO,OAAO,UAAU;AACtF;AAEA,SAAS,mBAAmB,OAAe,OAAe,YAA4B;AACpF,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GAAG;AACxC,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,OAAO,UAAU,kBAAkB;AAAA,MAC9C,SAAS,kBAAkB,KAAK;AAAA,MAChC,MAAM;AAAA,MACN,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO,KAAK,MAAM,KAAK;AACzB;AAEA,SAASD,mBAAkB,cAAsE;AAC/F,QAAM,QAAoC,EAAE,UAAU,aAAa,SAAS;AAE5E,MAAI,aAAa,WAAW,OAAW,OAAM,SAAS,aAAa;AACnE,MAAI,aAAa,aAAa,OAAW,OAAM,WAAW,aAAa;AACvE,MAAI,aAAa,qBAAqB,QAAW;AAC/C,UAAM,mBAAmB,aAAa;AAAA,EACxC;AACA,MAAI,aAAa,mBAAmB,OAAW,OAAM,iBAAiB,aAAa;AACnF,MAAI,aAAa,YAAY,OAAW,OAAM,UAAU,EAAE,GAAG,aAAa,QAAQ;AAElF,SAAO;AACT;AAEA,eAAe,mBAAmB,WAAmB,YAAuC;AAC1F,MAAI;AACF,WAAO,MAAM,QAAQ,SAAS;AAAA,EAChC,SAAS,OAAO;AACd,UAAM,wBAAwB,OAAO,UAAU;AAAA,EACjD;AACF;AAEA,eAAe,eAAe,UAAkB,YAAyC;AACvF,QAAM,YAAY,iBAAiB,UAAU,UAAU;AACvD,MAAI;AAEJ,MAAI;AACF,YAAQ,MAAM,MAAM,SAAS;AAAA,EAC/B,SAAS,OAAO;AACd,UAAM,wBAAwB,OAAO,UAAU;AAAA,EACjD;AAEA,QAAM,QAAqB;AAAA,IACzB,YAAY,UAAU,MAAM,KAAK;AAAA,IACjC,WAAW,UAAU,MAAM,SAAS;AAAA,IACpC,YAAY,UAAU,MAAM,KAAK;AAAA,IACjC,MAAM,mBAAmB,UAAU;AAAA,IACnC,MAAM;AAAA,IACN,aAAa,EAAE,KAAK,WAAW,MAAM,IAAI,EAAE;AAAA,IAC3C,MAAM,MAAM;AAAA,IACZ,MAAM,kBAAkB,KAAK;AAAA,IAC7B,UAAU,GAAG,MAAM,GAAG,IAAI,MAAM,GAAG;AAAA,EACrC;AAEA,MAAI,MAAM,SAAS,WAAW;AAC5B,UAAM,gBAAgB,MAAM,kBAAkB,SAAS;AAEvD,QAAI,kBAAkB,QAAW;AAC/B,YAAM,gBAAgB;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ;AAAA,EACV;AACF;AAEA,eAAe,kBAAkB,WAAgD;AAC/E,MAAI;AACF,WAAO,MAAM,SAAS,SAAS;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,2BAA2B,OAAuB;AACzD,QAAM,aAAa,oBAAoB,KAAK;AAE5C,MAAI,eAAe,QAAQ,WAAW,WAAW,KAAK,GAAG;AACvD,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,UAAU,kBAAkB;AAAA,MACvC,SAAS,oDAAoD,UAAU;AAAA,MACvE,MAAM;AAAA,MACN,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,eAAe,OAAO,eAAe,KAAK;AAC5C,WAAO;AAAA,EACT;AAEA,SAAO,WAAW,WAAW,GAAG,IAAI,aAAa,IAAI,UAAU;AACjE;AAEA,SAAS,iBAAiB,UAAkB,YAA4B;AACtE,QAAM,uBAAuB,2BAA2B,UAAU;AAKlE,QAAM,mBAAmB,KAAK,QAAQ,QAAQ;AAC9C,QAAM,oBAAoB,KAAK,QAAQ,qBAAqB,MAAM,GAAG,EAAE,KAAK,KAAK,GAAG,CAAC;AACrF,MACE,sBAAsB,oBACtB,kBAAkB,WAAW,mBAAmB,KAAK,GAAG,GACxD;AACA,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,yBAAyB,MAAM,MAAM,qBAAqB,MAAM,CAAC;AACtF,QAAM,eAAe,KAAK,QAAQ,UAAU,aAAa,MAAM,GAAG,EAAE,KAAK,KAAK,GAAG,CAAC;AAClF,QAAM,iBAAiB,KAAK,SAAS,UAAU,YAAY;AAE3D,MACE,mBAAmB,MAClB,CAAC,eAAe,WAAW,IAAI,KAAK,CAAC,KAAK,WAAW,cAAc,GACpE;AACA,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,mBAAmB;AAAA,IAC3B,SAAS,EAAE,UAAU,mBAAmB,SAAS;AAAA,IACjD,SAAS,oDAAoD,oBAAoB;AAAA,IACjF,MAAM;AAAA,IACN,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,kBAAkB,OAA+B;AACxD,MAAI,MAAM,OAAO,EAAG,QAAO;AAC3B,MAAI,MAAM,YAAY,EAAG,QAAO;AAChC,MAAI,MAAM,eAAe,EAAG,QAAO;AACnC,SAAO;AACT;AAEA,SAAS,WAAW,MAAsB;AACxC,UAAQ,OAAO,KAAO,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AACnD;AAEA,SAAS,UAAU,OAAmB;AACpC,SAAO,IAAI,KAAK,MAAM,QAAQ,CAAC;AACjC;AAEA,SAAS,eAAe,MAAmB,OAA4B;AACrE,SAAO,KAAK,KAAK,cAAc,MAAM,IAAI;AAC3C;AAEA,SAAS,wBAAwB,OAAgB,YAA2B;AAC1E,QAAM,OAAO,aAAa,KAAK;AAE/B,MAAI,SAAS,YAAY,SAAS,WAAW;AAC3C,WAAO,wBAAwB,YAAY,kCAAkC,UAAU,EAAE;AAAA,EAC3F;AAEA,MAAI,SAAS,YAAY,SAAS,SAAS;AACzC,WAAO,IAAI,sBAAsB;AAAA,MAC/B,OAAO;AAAA,MACP,SAAS,EAAE,UAAU,kBAAkB;AAAA,MACvC,SAAS,qCAAqC,UAAU;AAAA,MACxD,MAAM;AAAA,MACN,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO,IAAI,mBAAmB;AAAA,IAC5B,OAAO;AAAA,IACP,SAAS,EAAE,MAAM,UAAU,kBAAkB;AAAA,IAC7C,SAAS,+CAA+C,UAAU;AAAA,IAClE,MAAM;AAAA,IACN,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,wBAAwBC,OAAc,SAAoC;AACjF,SAAO,IAAI,kBAAkB;AAAA,IAC3B,SAAS,EAAE,UAAU,kBAAkB;AAAA,IACvC;AAAA,IACA,MAAAA;AAAA,IACA,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,aAAa,OAAoC;AACxD,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,QAC5D,OAAQ,MAA6B,IAAI,IACzC;AACN;;;AExkBA,SAAS,UAAAC,eAAc;AAyBvB,IAAM,qBAAqB;AAE3B,IAAM,+BAA8C;AAAA,EAClD,UAAU;AAAA,EACV,gBAAgB,CAAC,WAAW;AAAA,EAC5B,MAAM;AAAA,EACN,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,UAAU,CAAC;AAAA,EACX,cAAc;AAAA,EACd,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,EAChB,OAAO,CAAC,6EAA6E;AACvF;AA2CO,SAAS,4BAA4B,UAAiC,CAAC,GAAoB;AAChG,QAAM,QAAQ,kBAAkB,QAAQ,WAAW,CAAC,CAAC;AAErD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,cAAc;AAAA,IACd,QAAQ,MAAM,IAAI,eAAe,KAAK;AAAA,EACxC;AACF;AAEA,IAAM,iBAAN,MAAiD;AAAA,EAI/C,YAA6B,OAA4B;AAA5B;AAAA,EAA6B;AAAA,EAA7B;AAAA,EAHpB,KAAK;AAAA,EACL,eAAe;AAAA,EAIxB,UAAoC;AAClC,WAAO,QAAQ,QAAQ,IAAI,sBAAsB,KAAK,KAAK,CAAC;AAAA,EAC9D;AACF;AAEA,IAAM,wBAAN,MAAuD;AAAA,EAC5C,WAAW;AAAA,EACX,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EAET,YAAY,OAA4B;AACtC,SAAK,KAAK,IAAI,iBAAiB,KAAK;AACpC,SAAK,YAAY,IAAI,yBAAyB,KAAK;AAAA,EACrD;AAAA,EAEA,aAA4B;AAC1B,WAAO,QAAQ,QAAQ;AAAA,EACzB;AACF;AAOA,IAAM,mBAAN,MAAmD;AAAA,EACjD,YAA6B,OAA4B;AAA5B;AAAA,EAA6B;AAAA,EAA7B;AAAA,EAE7B,KAAKC,OAAsC;AACzC,WAAO,QAAQ,QAAQ,EAAE,KAAK,MAAM;AAClC,YAAM,iBAAiB,oBAAoBA,KAAI;AAC/C,YAAM,YAAY,KAAK,aAAa,cAAc;AAElD,UAAI,UAAU,SAAS,aAAa;AAClC,cAAMC;AAAA,UACJ;AAAA,UACA,mCAAmC,cAAc;AAAA,QACnD;AAAA,MACF;AAEA,aAAO,CAAC,GAAG,KAAK,MAAM,QAAQ,OAAO,CAAC,EACnC;AAAA,QACC,CAAC,UAAU,MAAM,SAAS,kBAAkB,cAAc,MAAM,IAAI,MAAM;AAAA,MAC5E,EACC,IAAI,gBAAgB,EACpB,KAAKC,eAAc;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEA,KAAKF,OAAmC;AACtC,WAAO,QAAQ,QAAQ,EAAE;AAAA,MAAK,MAC5B,gBAAgB,KAAK,aAAa,oBAAoBA,KAAI,CAAC,CAAC;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,OAAOA,OAAc,UAAyB,CAAC,GAAkB;AAC/D,WAAO,QAAQ,QAAQ,EAAE,KAAK,MAAM;AAClC,YAAM,aAAa,oBAAoBA,KAAI;AAC3C,YAAM,QAAQ,KAAK,MAAM,QAAQ,IAAI,UAAU;AAC/C,UAAI,UAAU,QAAW;AACvB,YAAI,QAAQ,cAAe;AAC3B,cAAMC,yBAAwB,YAAY,0BAA0B,UAAU,EAAE;AAAA,MAClF;AACA,UAAI,MAAM,SAAS,aAAa;AAC9B,cAAMA;AAAA,UACJ;AAAA,UACA,0CAA0C,UAAU;AAAA,QACtD;AAAA,MACF;AACA,WAAK,MAAM,QAAQ,OAAO,UAAU;AACpC,WAAK,MAAM,QAAQ,OAAO,UAAU;AAAA,IACtC,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,MAAc,IAA2B;AAC9C,WAAO,QAAQ,QAAQ,EAAE,KAAK,MAAM;AAClC,YAAM,WAAW,oBAAoB,IAAI;AACzC,YAAM,SAAS,oBAAoB,EAAE;AACrC,YAAM,QAAQ,KAAK,MAAM,QAAQ,IAAI,QAAQ;AAC7C,UAAI,UAAU,QAAW;AACvB,cAAMA,yBAAwB,UAAU,0BAA0B,QAAQ,EAAE;AAAA,MAC9E;AACA,8BAAwB,KAAK,MAAM,SAAS,MAAM;AAClD,YAAM,QAAoB,EAAE,GAAG,OAAO,MAAM,QAAQ,MAAM,mBAAmB,MAAM,EAAE;AACrF,WAAK,MAAM,QAAQ,OAAO,QAAQ;AAClC,WAAK,MAAM,QAAQ,IAAI,QAAQ,KAAK;AACpC,YAAM,UAAU,KAAK,MAAM,QAAQ,IAAI,QAAQ;AAC/C,UAAI,YAAY,QAAW;AACzB,aAAK,MAAM,QAAQ,OAAO,QAAQ;AAClC,aAAK,MAAM,QAAQ,IAAI,QAAQ,OAAO;AAAA,MACxC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAMD,OAAc,UAAwB,CAAC,GAAkB;AAC7D,WAAO,QAAQ,QAAQ,EAAE,KAAK,MAAM;AAClC,YAAM,aAAa,oBAAoBA,KAAI;AAC3C,YAAM,WAAW,KAAK,MAAM,QAAQ,IAAI,UAAU;AAClD,UAAI,aAAa,QAAW;AAC1B,YAAI,SAAS,SAAS,eAAe,QAAQ,UAAW;AACxD,cAAM,0BAA0B,YAAY,+BAA+B,UAAU,EAAE;AAAA,MACzF;AACA,UAAI,QAAQ,WAAW;AACrB,gCAAwB,KAAK,MAAM,SAAS,UAAU;AAAA,MACxD,OAAO;AACL,cAAM,SAAS,cAAc,UAAU;AACvC,YAAI,WAAW,UAAa,CAAC,KAAK,MAAM,QAAQ,IAAI,MAAM,GAAG;AAC3D,gBAAMC,yBAAwB,QAAQ,4BAA4B,MAAM,EAAE;AAAA,QAC5E;AAAA,MACF;AACA,WAAK,MAAM,QAAQ,IAAI,YAAY,qBAAqB,UAAU,CAAC;AAAA,IACrE,CAAC;AAAA,EACH;AAAA,EAEA,MAAMD,OAAc,UAAwB,CAAC,GAAkB;AAC7D,WAAO,QAAQ,QAAQ,EAAE,KAAK,MAAM;AAClC,YAAM,aAAa,oBAAoBA,KAAI;AAC3C,YAAM,QAAQ,KAAK,MAAM,QAAQ,IAAI,UAAU;AAC/C,UAAI,UAAU,QAAW;AACvB,YAAI,QAAQ,cAAe;AAC3B,cAAMC,yBAAwB,YAAY,0BAA0B,UAAU,EAAE;AAAA,MAClF;AACA,UAAI,MAAM,SAAS,aAAa;AAC9B,cAAMA,yBAAwB,YAAY,mCAAmC,UAAU,EAAE;AAAA,MAC3F;AACA,YAAM,WAAW,CAAC,GAAG,KAAK,MAAM,QAAQ,OAAO,CAAC,EAAE;AAAA,QAChD,CAAC,UAAU,MAAM,SAAS,cAAc,cAAc,MAAM,IAAI,MAAM;AAAA,MACxE;AACA,UAAI,SAAS,SAAS,KAAK,CAAC,QAAQ,WAAW;AAC7C,cAAM,0BAA0B,YAAY,+BAA+B,UAAU,EAAE;AAAA,MACzF;AACA,YAAM,QAAQ,CAAC,GAAG,QAAQ;AAC1B,aAAO,MAAM,SAAS,GAAG;AACvB,cAAM,OAAO,MAAM,IAAI;AACvB,YAAI,CAAC,KAAM;AACX,YAAI,KAAK,SAAS,aAAa;AAC7B,qBAAW,SAAS,KAAK,MAAM,QAAQ,OAAO,GAAG;AAC/C,gBAAI,MAAM,SAAS,KAAK,QAAQ,cAAc,MAAM,IAAI,MAAM,KAAK,MAAM;AACvE,oBAAM,KAAK,KAAK;AAAA,YAClB;AAAA,UACF;AAAA,QACF;AACA,aAAK,MAAM,QAAQ,OAAO,KAAK,IAAI;AACnC,aAAK,MAAM,QAAQ,OAAO,KAAK,IAAI;AAAA,MACrC;AACA,WAAK,MAAM,QAAQ,OAAO,UAAU;AAAA,IACtC,CAAC;AAAA,EACH;AAAA,EAEQ,aAAaD,OAA0B;AAC7C,UAAM,QAAQ,KAAK,MAAM,QAAQ,IAAIA,KAAI;AAEzC,QAAI,UAAU,QAAW;AACvB,YAAMC,yBAAwBD,OAAM,0BAA0BA,KAAI,EAAE;AAAA,IACtE;AAEA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,2BAAN,MAAqE;AAAA,EACnE,YAA6B,OAA4B;AAA5B;AAAA,EAA6B;AAAA,EAA7B;AAAA,EAE7B,KAAK,SAA2E;AAC9E,WAAO,QAAQ,QAAQ,EAAE,KAAK,MAAM;AAClC,cAAQ,eAAe;AACvB,YAAMA,QAAO,oBAAoB,QAAQ,SAAS,IAAI;AACtD,YAAM,QAAQ,iBAAiB,KAAK,OAAOA,KAAI;AAC/C,YAAM,UAAU,KAAK,MAAM,QAAQ,IAAIA,KAAI,KAAK,IAAI,WAAW,MAAM,QAAQ,CAAC;AAC9E,YAAM,QAAQ,iBAAiB,QAAQ,YAAY,QAAQ,KAAK;AAChE,YAAM,QAAQ,QAAQ,MAAM,MAAM,QAAQ,MAAM,SAAS,MAAM,MAAM;AACrE,YAAM,SAAqC;AAAA,QACzC,SAAS,0BAA0B,KAAK;AAAA,QACxC,YAAY,MAAM;AAAA,MACpB;AAEA,UAAI,MAAM,SAAS,GAAG;AACpB,eAAO,YAAY,MAAM;AAAA,MAC3B;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAM,SAA6E;AACvF,YAAQ,eAAe;AACvB,UAAMA,QAAO,oBAAoB,QAAQ,SAAS,IAAI;AACtD,UAAM,WAAW,KAAK,MAAM,QAAQ,IAAIA,KAAI;AAE5C,QAAI,UAAU,SAAS,aAAa;AAClC,YAAM,0BAA0BA,OAAM,+BAA+BA,KAAI,EAAE;AAAA,IAC7E;AAEA,UAAM,iBAAiB,MAAMG,wBAAuB,OAAO;AAC3D,UAAM,SAASC,4BAA2B,QAAQ,QAAQ,QAAQ;AAClE,UAAM,kBAAkB,KAAK,MAAM,QAAQ,IAAIJ,KAAI,KAAK,IAAI,WAAW,CAAC;AACxE,UAAM,UACJ,WAAW,SACP,iBACA,qBAAqB,iBAAiB,gBAAgB,MAAM;AAElE,4BAAwB,KAAK,MAAM,SAASA,KAAI;AAChD,SAAK,MAAM,QAAQ,IAAIA,OAAM,uBAAuBA,OAAM,QAAQ,UAAU,CAAC;AAC7E,SAAK,MAAM,QAAQ,IAAIA,OAAM,OAAO;AAEpC,UAAM,SAAsC;AAAA,MAC1C,kBAAkB,eAAe;AAAA,MACjC,SAAS,WAAW,UAAa,SAAS;AAAA,MAC1C,YAAY,QAAQ;AAAA,MACpB,UAAU,QAAQ,cAAc,YAAY;AAAA,IAC9C;AAEA,QAAI,QAAQ,iBAAiB,QAAW;AACtC,aAAO,eAAeK,mBAAkB,QAAQ,YAAY;AAAA,IAC9D;AAEA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,kBAAkB,SAA6D;AACtF,QAAM,QAA6B;AAAA,IACjC,SAAS,oBAAI,IAAI;AAAA,IACjB,SAAS,oBAAI,IAAI,CAAC,CAAC,KAAK,qBAAqB,GAAG,CAAC,CAAC,CAAC;AAAA,EACrD;AAEA,aAAW,SAAS,SAAS;AAC3B,UAAM,QAAQ,kBAAkB,KAAK;AACrC,UAAM,UAAU,oBAAoB,OAAO,KAAK;AAEhD,QAAI,MAAM,SAAS,OAAO,MAAM,SAAS,aAAa;AACpD,YAAM,0BAA0B,MAAM,MAAM,0CAA0C;AAAA,IACxF;AAEA,4BAAwB,MAAM,SAAS,MAAM,IAAI;AACjD,UAAM,QAAQ,IAAI,MAAM,MAAM,KAAK;AAEnC,QAAI,YAAY,QAAW;AACzB,YAAM,QAAQ,IAAI,MAAM,MAAM,OAAO;AAAA,IACvC;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,kBAAkB,OAAwC;AACjE,QAAML,QAAO,oBAAoB,MAAM,IAAI;AAC3C,QAAM,QAAqB;AAAA,IACzB,MAAM,MAAM,QAAQ,mBAAmBA,KAAI;AAAA,IAC3C,MAAAA;AAAA,IACA,MAAM,MAAM;AAAA,EACd;AAEA,0BAAwB,OAAO,KAAK;AAEpC,QAAM,UAAU,uBAAuB,MAAM,OAAO;AAEpD,MAAI,YAAY,QAAW;AACzB,UAAM,OAAO,QAAQ;AAAA,EACvB;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ;AAAA,EACV;AACF;AAEA,SAAS,oBACP,OACA,OACwB;AACxB,QAAM,UAAU,uBAAuB,MAAM,OAAO;AAEpD,MAAI,YAAY,QAAW;AACzB,QAAI,MAAM,SAAS,QAAQ;AACzB,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,2CAA2C,MAAM,IAAI;AAAA,MACvD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,SAAS,QAAQ;AACzB,WAAO,IAAI,WAAW,MAAM,QAAQ,CAAC;AAAA,EACvC;AAEA,SAAO;AACT;AAEA,SAAS,uBAAuB,SAAkE;AAChG,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,EACT;AAEA,SAAO,OAAO,YAAY,WAAWM,QAAO,KAAK,OAAO,IAAI,IAAI,WAAW,OAAO;AACpF;AAEA,SAAS,uBAAuBN,OAAc,MAA0B;AACtE,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,YAAY,oBAAI,KAAK;AAAA,IACrB,MAAM,mBAAmBA,KAAI;AAAA,IAC7B,MAAAA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,EACR;AACF;AAEA,SAAS,qBAAqBA,OAA0B;AACtD,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,MAAM,mBAAmBA,KAAI;AAAA,IAC7B,MAAAA;AAAA,IACA,MAAM;AAAA,EACR;AACF;AAEA,SAAS,wBAAwB,OAAgCA,OAAoB;AACnF,aAAW,cAAc,iBAAiBA,KAAI,GAAG;AAC/C,UAAM,SAAS,MAAM,IAAI,UAAU;AAEnC,QAAI,WAAW,UAAa,OAAO,SAAS,aAAa;AACvD,YAAM;AAAA,QACJ;AAAA,QACA,6CAA6C,UAAU;AAAA,MACzD;AAAA,IACF;AAEA,QAAI,WAAW,QAAW;AACxB,YAAM,IAAI,YAAY,qBAAqB,UAAU,CAAC;AAAA,IACxD;AAAA,EACF;AACF;AAEA,SAAS,oBAAoBA,OAAsB;AACjD,QAAM,aAAa,oBAAoBA,KAAI;AAE3C,MAAI,eAAe,OAAO,eAAe,KAAK;AAC5C,WAAO;AAAA,EACT;AAEA,SAAO,WAAW,WAAW,GAAG,IAAI,aAAa,IAAI,UAAU;AACjE;AAEA,SAAS,iBAAiBA,OAAwB;AAChD,QAAM,YAAsB,CAAC;AAC7B,MAAI,aAAa,cAAcA,KAAI;AAEnC,SAAO,eAAe,UAAa,eAAe,KAAK;AACrD,cAAU,QAAQ,UAAU;AAC5B,iBAAa,cAAc,UAAU;AAAA,EACvC;AAEA,SAAO;AACT;AAEA,SAAS,cAAcA,OAAkC;AACvD,MAAIA,UAAS,KAAK;AAChB,WAAO;AAAA,EACT;AAEA,QAAM,YAAYA,MAAK,YAAY,GAAG;AACtC,SAAO,aAAa,IAAI,MAAMA,MAAK,MAAM,GAAG,SAAS;AACvD;AAEA,SAAS,iBAAiB,OAA4BA,OAA0B;AAC9E,QAAM,QAAQ,MAAM,QAAQ,IAAIA,KAAI;AAEpC,MAAI,UAAU,QAAW;AACvB,UAAMC,yBAAwBD,OAAM,0BAA0BA,KAAI,EAAE;AAAA,EACtE;AAEA,MAAI,MAAM,SAAS,QAAQ;AACzB,UAAMC,yBAAwBD,OAAM,8BAA8BA,KAAI,EAAE;AAAA,EAC1E;AAEA,SAAO;AACT;AAEA,SAAS,iBACP,MACA,OACoC;AACpC,MAAI,UAAU,QAAW;AACvB,WAAO,EAAE,QAAQ,MAAM,QAAQ,EAAE;AAAA,EACnC;AAEA,QAAM,kBAAkBO,oBAAmB,MAAM,QAAQ,QAAQ;AACjE,QAAM,kBACJ,MAAM,WAAW,SACb,OAAO,KAAK,IAAI,iBAAiB,IAAI,IACrCA,oBAAmB,MAAM,QAAQ,QAAQ;AAC/C,QAAM,SAAS,KAAK,IAAI,iBAAiB,IAAI;AAC7C,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,iBAAiB,OAAO,MAAM,CAAC;AAEnE,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAEA,eAAeJ,wBAAuB,SAA4D;AAChG,QAAM,SAAuB,CAAC;AAC9B,MAAI,aAAa;AAEjB,mBAAiB,SAAS,QAAQ,SAAS;AACzC,YAAQ,eAAe;AACvB,UAAM,cAAc,IAAI,WAAW,KAAK;AACxC,WAAO,KAAK,WAAW;AACvB,kBAAc,YAAY;AAC1B,YAAQ,eAAe,YAAY,QAAQ,UAAU;AAAA,EACvD;AAEA,SAAOK,cAAa,QAAQ,UAAU;AACxC;AAEA,SAASA,cAAa,QAAsB,YAAgC;AAC1E,QAAM,UAAU,IAAI,WAAW,UAAU;AACzC,MAAI,SAAS;AAEb,aAAW,SAAS,QAAQ;AAC1B,YAAQ,IAAI,OAAO,MAAM;AACzB,cAAU,MAAM;AAAA,EAClB;AAEA,SAAO;AACT;AAEA,SAAS,qBACP,iBACA,gBACA,QACY;AACZ,QAAM,UAAU,IAAI;AAAA,IAClB,KAAK,IAAI,gBAAgB,YAAY,SAAS,eAAe,UAAU;AAAA,EACzE;AACA,UAAQ,IAAI,eAAe;AAC3B,UAAQ,IAAI,gBAAgB,MAAM;AAClC,SAAO;AACT;AAEA,gBAAgB,0BAA0B,SAAiD;AACzF,QAAM,QAAQ,QAAQ;AACtB,QAAM,IAAI,WAAW,OAAO;AAC9B;AAEA,SAASJ,4BAA2B,OAA2B,OAAmC;AAChG,SAAO,UAAU,SAAY,SAAYG,oBAAmB,OAAO,KAAK;AAC1E;AAEA,SAASA,oBAAmB,OAAe,OAAuB;AAChE,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GAAG;AACxC,UAAM,0BAA0B,KAAK,mBAAmB,KAAK,gCAAgC;AAAA,EAC/F;AAEA,SAAO,KAAK,MAAM,KAAK;AACzB;AAEA,SAASF,mBAAkB,cAAsE;AAC/F,QAAM,QAAoC,EAAE,UAAU,aAAa,SAAS;AAE5E,MAAI,aAAa,WAAW,OAAW,OAAM,SAAS,aAAa;AACnE,MAAI,aAAa,aAAa,OAAW,OAAM,WAAW,aAAa;AACvE,MAAI,aAAa,qBAAqB,QAAW;AAC/C,UAAM,mBAAmB,aAAa;AAAA,EACxC;AACA,MAAI,aAAa,mBAAmB,OAAW,OAAM,iBAAiB,aAAa;AACnF,MAAI,aAAa,YAAY,OAAW,OAAM,UAAU,EAAE,GAAG,aAAa,QAAQ;AAElF,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAiC;AACzD,QAAM,QAAqB;AAAA,IACzB,MAAM,MAAM;AAAA,IACZ,MAAM,MAAM;AAAA,IACZ,MAAM,MAAM;AAAA,EACd;AAEA,0BAAwB,OAAO,KAAK;AACpC,SAAO;AACT;AAEA,SAAS,gBAAgB,OAA+B;AACtD,SAAO;AAAA,IACL,GAAG,iBAAiB,KAAK;AAAA,IACzB,QAAQ;AAAA,EACV;AACF;AAEA,SAAS,wBAAwB,QAAqB,QAAoC;AACxF,MAAI,OAAO,SAAS,OAAW,QAAO,OAAO,OAAO;AACpD,MAAI,OAAO,eAAe,OAAW,QAAO,aAAaI,WAAU,OAAO,UAAU;AACpF,MAAI,OAAO,cAAc,OAAW,QAAO,YAAYA,WAAU,OAAO,SAAS;AACjF,MAAI,OAAO,eAAe,OAAW,QAAO,aAAaA,WAAU,OAAO,UAAU;AACpF,MAAI,OAAO,gBAAgB,OAAW,QAAO,cAAc,iBAAiB,OAAO,WAAW;AAC9F,MAAI,OAAO,UAAU,OAAW,QAAO,QAAQ,OAAO;AACtD,MAAI,OAAO,UAAU,OAAW,QAAO,QAAQ,OAAO;AACtD,MAAI,OAAO,kBAAkB,OAAW,QAAO,gBAAgB,OAAO;AACtE,MAAI,OAAO,aAAa,OAAW,QAAO,WAAW,OAAO;AAC5D,MAAI,OAAO,QAAQ,OAAW,QAAO,MAAM,OAAO;AACpD;AAEA,SAASA,WAAU,OAAmB;AACpC,SAAO,IAAI,KAAK,MAAM,QAAQ,CAAC;AACjC;AAEA,SAAS,iBAAiB,aAAmD;AAC3E,SAAO,EAAE,GAAG,YAAY;AAC1B;AAEA,SAASP,gBAAe,MAAmB,OAA4B;AACrE,SAAO,KAAK,KAAK,cAAc,MAAM,IAAI;AAC3C;AAEA,SAASD,yBAAwBD,OAAc,SAAoC;AACjF,SAAO,IAAI,kBAAkB;AAAA,IAC3B,SAAS,EAAE,UAAU,mBAAmB;AAAA,IACxC;AAAA,IACA,MAAAA;AAAA,IACA,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,0BAA0BA,OAAc,SAAqC;AACpF,SAAO,IAAI,mBAAmB;AAAA,IAC5B,SAAS,EAAE,UAAU,mBAAmB;AAAA,IACxC;AAAA,IACA,MAAAA;AAAA,IACA,WAAW;AAAA,EACb,CAAC;AACH;;;AC9kBA,eAAsB,gCACpB,SACA,UAAgC,CAAC,GACG;AACpC,QAAM,EAAE,UAAU,KAAK,KAAK,UAAU,GAAG,KAAK,IAAI;AAClD,QAAM,WAAsC,EAAE,GAAG,KAAK;AAEtD,MAAI,aAAa,QAAW;AAC1B,aAAS,WAAW,MAAM,cAAc,UAAU,OAAO;AAAA,EAC3D;AAEA,MAAI,aAAa,QAAW;AAC1B,aAAS,WAAW,MAAM,cAAc,UAAU,OAAO;AAAA,EAC3D;AAEA,MAAI,QAAQ,QAAW;AACrB,aAAS,MAAM,MAAM,kBAAkB,KAAK,OAAO;AAAA,EACrD;AAEA,MAAI,QAAQ,QAAW;AACrB,aAAS,MAAM,MAAM,kBAAkB,KAAK,OAAO;AAAA,EACrD;AAEA,SAAO;AACT;AASA,eAAe,kBACb,SACA,SAC6B;AAC7B,QAAM,EAAE,YAAY,YAAY,YAAY,GAAG,KAAK,IAAI;AACxD,QAAM,WAA+B,EAAE,GAAG,KAAK;AAE/C,MAAI,eAAe,OAAW,UAAS,aAAa,MAAM,cAAc,YAAY,OAAO;AAC3F,MAAI,eAAe,OAAW,UAAS,aAAa,MAAM,cAAc,YAAY,OAAO;AAC3F,MAAI,eAAe;AACjB,aAAS,aAAa,MAAM,wBAAwB,YAAY,OAAO;AAEzE,SAAO;AACT;AASA,eAAe,wBACb,QACA,SACsC;AACtC,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,QAAQ,IAAI,OAAO,IAAI,CAAC,SAAS,cAAc,MAAM,OAAO,CAAC,CAAC;AAAA,EACvE;AAEA,SAAO,cAAc,QAAQ,OAAO;AACtC;AASA,eAAe,kBACb,SACA,SAC6B;AAC7B,QAAM,EAAE,IAAI,MAAM,KAAK,YAAY,KAAK,GAAG,KAAK,IAAI;AACpD,QAAM,WAA+B,EAAE,GAAG,KAAK;AAE/C,MAAI,OAAO,OAAW,UAAS,KAAK,MAAM,uBAAuB,IAAI,OAAO;AAC5E,MAAI,SAAS,OAAW,UAAS,OAAO,MAAM,cAAc,MAAM,OAAO;AACzE,MAAI,QAAQ,OAAW,UAAS,MAAM,MAAM,cAAc,KAAK,OAAO;AACtE,MAAI,eAAe,OAAW,UAAS,aAAa,MAAM,cAAc,YAAY,OAAO;AAC3F,MAAI,QAAQ,OAAW,UAAS,MAAM,MAAM,cAAc,KAAK,OAAO;AAEtE,SAAO;AACT;AASA,eAAe,uBACb,QACA,SACsC;AACtC,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,QAAQ,IAAI,OAAO,IAAI,CAAC,SAAS,cAAc,MAAM,OAAO,CAAC,CAAC;AAAA,EACvE;AAEA,SAAO,cAAc,QAAQ,OAAO;AACtC;;;AC/FO,SAAS,6BACd,SACA,UAAyC,CAAC,GAC1B;AAChB,MAAI,OAAO,YAAY,YAAY;AACjC,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,MAAM,QAAQ,QAAQ,MAAM,KAAK,IAAI;AAC3C,MAAI,SAAS,GAAG;AACd,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI;AACJ,MAAI;AAEJ,QAAM,QAAQ,YAAkC;AAC9C,UAAM,SAAS,MAAM,QAAQ;AAC7B,QAAI,OAAO,OAAO,gBAAgB,YAAY,OAAO,gBAAgB,IAAI;AACvE,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS;AAAA,QACT,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,QAAI;AACJ,QAAI,OAAO,cAAc,QAAW;AAClC,YAAM,KAAK,OAAO,UAAU,QAAQ;AACpC,UAAI,OAAO,SAAS,EAAE,EAAG,eAAc;AAAA,IACzC,WAAW,OAAO,OAAO,qBAAqB,UAAU;AACtD,UAAI,CAAC,OAAO,SAAS,OAAO,gBAAgB,KAAK,OAAO,oBAAoB,GAAG;AAC7E,cAAM,IAAI,mBAAmB;AAAA,UAC3B,SAAS;AAAA,UACT,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AACA,oBAAc,IAAI,IAAI,OAAO,mBAAmB;AAAA,IAClD;AACA,UAAM,SAAsB,EAAE,aAAa,OAAO,aAAa,YAAY;AAC3E,YAAQ;AACR,WAAO;AAAA,EACT;AAEA,SAAO,YAAY;AACjB,UAAM,UAAU;AAChB,QAAI,YAAY,UAAa,QAAQ,SAAS,QAAQ,GAAG,GAAG;AAC1D,aAAO,QAAQ;AAAA,IACjB;AACA,QAAI,YAAY,QAAW;AACzB,gBAAU,MAAM,EAAE,QAAQ,MAAM;AAC9B,kBAAU;AAAA,MACZ,CAAC;AAAA,IACH;AACA,UAAM,YAAY,MAAM;AACxB,WAAO,UAAU;AAAA,EACnB;AACF;AAEA,SAAS,QAAQ,OAAoB,QAAgB,KAA4B;AAC/E,MAAI,MAAM,gBAAgB,OAAW,QAAO;AAC5C,SAAO,MAAM,cAAc,SAAS,IAAI;AAC1C;;;ACnIA,SAAS,UAAAU,eAAc;AACvB,SAAS,kBAAkB;AAgCpB,SAAS,gBAAgB,MAAiC;AAC/D,QAAM,UAA6B,CAAC;AACpC,QAAM,QAAQ,KAAK,MAAM,OAAO;AAChC,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,YAAY,MAAM,QAAQ,WAAW,GAAG,EAAG;AAC/C,UAAM,QAAQ,oBAAoB,IAAI;AACtC,QAAI,UAAU,OAAW,SAAQ,KAAK,KAAK;AAAA,EAC7C;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,MAA2C;AACtE,QAAM,SAAS,KAAK,KAAK,EAAE,MAAM,KAAK;AACtC,MAAI,OAAO,SAAS,EAAG,QAAO;AAC9B,MAAI,QAAQ;AACZ,MAAI;AACJ,QAAMC,SAAQ,OAAO,KAAK;AAC1B,MAAIA,WAAU,qBAAqBA,WAAU,YAAY;AACvD,aAASA,WAAU,oBAAoB,mBAAmB;AAC1D,aAAS;AAAA,EACX;AACA,QAAM,YAAY,OAAO,KAAK;AAC9B,QAAM,UAAU,OAAO,QAAQ,CAAC;AAChC,QAAM,YAAY,OAAO,QAAQ,CAAC;AAClC,MAAI,cAAc,UAAa,YAAY,UAAa,cAAc,OAAW,QAAO;AACxF,QAAM,gBAAgB,OAAO,MAAM,QAAQ,CAAC;AAC5C,QAAM,UAAU,cAAc,SAAS,IAAI,cAAc,KAAK,GAAG,IAAI;AAErE,MAAI,eAAkC,CAAC;AACvC,MAAI;AACJ,MAAI;AACJ,MAAI,UAAU,WAAW,KAAK,GAAG;AAC/B,UAAM,QAAQ,UAAU,MAAM,GAAG;AACjC,QAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,iBAAa,MAAM,CAAC;AACpB,iBAAa,MAAM,CAAC;AAAA,EACtB,OAAO;AACL,mBAAe,UAAU,MAAM,GAAG,EAAE,OAAO,CAAC,UAAU,UAAU,EAAE;AAAA,EACpE;AAEA,QAAM,QAAyB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK;AAAA,EACP;AACA,MAAI,WAAW,OAAW,OAAM,SAAS;AACzC,MAAI,YAAY,OAAW,OAAM,UAAU;AAC3C,MAAI,eAAe,OAAW,OAAM,aAAa;AACjD,MAAI,eAAe,OAAW,OAAM,aAAa;AACjD,SAAO;AACT;AAGA,IAAM,mBAAmB;AAWlB,SAAS,qBACd,OACA,MACA,OAAe,kBACN;AACT,MAAI,MAAM,eAAe,UAAa,MAAM,eAAe,QAAW;AACpE,WAAO,mBAAmB,MAAM,YAAY,MAAM,YAAY,MAAM,IAAI;AAAA,EAC1E;AACA,MAAI,UAAU;AACd,aAAW,WAAW,MAAM,cAAc;AACxC,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,YAAM,UAAU,QAAQ,MAAM,CAAC;AAC/B,UAAI,oBAAoB,SAAS,MAAM,IAAI,EAAG,QAAO;AACrD;AAAA,IACF;AACA,QAAI,oBAAoB,SAAS,MAAM,IAAI,EAAG,WAAU;AAAA,EAC1D;AACA,SAAO;AACT;AAUO,SAAS,gBACd,SACA,MACA,OAAe,kBACI;AACnB,SAAO,QAAQ,OAAO,CAAC,UAAU,qBAAqB,OAAO,MAAM,IAAI,CAAC;AAC1E;AAEA,SAAS,oBAAoB,SAAiB,MAAc,MAAuB;AACjF,QAAM,YAAY,QAAQ,MAAM,kBAAkB;AAClD,MAAI,WAAW;AACb,UAAM,CAAC,EAAE,aAAa,QAAQ,IAAI;AAClC,QAAI,gBAAgB,UAAa,aAAa,OAAW,QAAO;AAChE,UAAM,eAAe,OAAO,SAAS,UAAU,EAAE;AACjD,QAAI,OAAO,MAAM,YAAY,KAAK,iBAAiB,KAAM,QAAO;AAChE,WAAO,UAAU,aAAa,IAAI;AAAA,EACpC;AACA,SAAO,SAAS,oBAAoB,UAAU,SAAS,IAAI;AAC7D;AAEA,SAAS,UAAU,SAAiB,OAAwB;AAC1D,QAAM,QAAQ,IAAI;AAAA,IAChB,IAAI,QACD,QAAQ,kBAAkB,MAAM,EAChC,QAAQ,OAAO,IAAI,EACnB,QAAQ,OAAO,GAAG,CAAC;AAAA,IACtB;AAAA,EACF;AACA,SAAO,MAAM,KAAK,KAAK;AACzB;AAEA,SAAS,mBAAmB,MAAc,MAAc,MAAc,MAAuB;AAC3F,QAAM,aAAaD,QAAO,KAAK,MAAM,QAAQ;AAC7C,MAAI,WAAW,WAAW,EAAG,QAAO;AACpC,QAAM,aAAa,SAAS,mBAAmB,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,IAAI,IAAI;AAC1F,aAAW,aAAa,YAAY;AAClC,UAAM,WAAW,WAAW,QAAQ,UAAU,EAAE,OAAO,SAAS,EAAE,OAAO,QAAQ;AACjF,QAAI,aAAa,KAAM,QAAO;AAAA,EAChC;AACA,SAAO;AACT;;;AChJO,SAAS,mBAAmB,MAAoC;AACrE,QAAM,UAAgC,CAAC;AACvC,MAAI;AACJ,MAAI,WAAW;AACf,QAAM,QAAQ,KAAK,MAAM,OAAO;AAChC,aAAW,WAAW,OAAO;AAC3B,UAAM,OAAO,QAAQ,QAAQ,QAAQ,EAAE,EAAE,KAAK;AAC9C,QAAI,SAAS,GAAI;AACjB,UAAM,QAAQ,KAAK,MAAM,wCAAwC;AACjE,QAAI,CAAC,MAAO;AACZ,UAAM,CAAC,EAAE,YAAY,QAAQ,IAAI;AACjC,QAAI,eAAe,UAAa,aAAa,OAAW;AACxD,UAAM,UAAU,WAAW,YAAY;AACvC,UAAM,QAAQ,SAAS,KAAK;AAC5B,QAAI,YAAY,QAAQ;AACtB,UAAI,YAAY,OAAW,SAAQ,KAAK,OAAO;AAC/C,gBAAU,EAAE,SAAS,CAAC,GAAG,UAAU,eAAe,KAAK,EAAE;AACzD,iBAAW;AACX;AAAA,IACF;AACA,QAAI,YAAY,SAAS;AACvB,UAAI,YAAY,OAAW,SAAQ,KAAK,OAAO;AAC/C,gBAAU;AACV,iBAAW;AACX;AAAA,IACF;AACA,QAAI,YAAY,YAAY,OAAW;AACvC,UAAM,SAAS,eAAe,KAAK;AACnC,UAAM,WAAW,QAAQ,QAAQ,OAAO;AACxC,QAAI,aAAa,QAAW;AAC1B,cAAQ,QAAQ,OAAO,IAAI,CAAC,GAAG,MAAM;AAAA,IACvC,OAAO;AACL,eAAS,KAAK,GAAG,MAAM;AAAA,IACzB;AAAA,EACF;AACA,MAAI,YAAY,OAAW,SAAQ,KAAK,OAAO;AAC/C,SAAO;AACT;AAEA,SAAS,eAAe,OAAyB;AAC/C,MAAI,UAAU,GAAI,QAAO,CAAC;AAC1B,QAAM,SAAmB,CAAC;AAC1B,QAAM,QAAQ;AACd,MAAI;AACJ,UAAQ,QAAQ,MAAM,KAAK,KAAK,OAAO,MAAM;AAC3C,WAAO,KAAK,MAAM,CAAC,KAAK,MAAM,CAAC,KAAK,EAAE;AAAA,EACxC;AACA,SAAO;AACT;AAsBO,SAAS,mBACd,SACA,OACqB;AACrB,QAAM,SAAmC,CAAC;AAC1C,QAAM,UAAgC,CAAC;AACvC,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,kBAAkB,OAAO,KAAK,EAAG;AACtC,YAAQ,KAAK,KAAK;AAClB,eAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,MAAM,OAAO,GAAG;AACzD,UAAI,OAAO,GAAG,MAAM,OAAW,QAAO,GAAG,IAAI,CAAC,GAAG,MAAM;AAAA,IACzD;AAAA,EACF;AACA,SAAO,EAAE,OAAO,SAAS,SAAS,OAAO;AAC3C;AAEA,SAAS,kBAAkB,OAA2B,OAAwB;AAC5E,MAAI,UAAU;AACd,aAAW,WAAW,MAAM,UAAU;AACpC,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,UAAIE,WAAU,QAAQ,MAAM,CAAC,GAAG,KAAK,EAAG,QAAO;AAC/C;AAAA,IACF;AACA,QAAIA,WAAU,SAAS,KAAK,EAAG,WAAU;AAAA,EAC3C;AACA,SAAO;AACT;AAEA,SAASA,WAAU,SAAiB,OAAwB;AAC1D,QAAM,QAAQ,IAAI;AAAA,IAChB,IAAI,QACD,QAAQ,kBAAkB,MAAM,EAChC,QAAQ,OAAO,IAAI,EACnB,QAAQ,OAAO,GAAG,CAAC;AAAA,IACtB;AAAA,EACF;AACA,SAAO,MAAM,KAAK,KAAK;AACzB;AA+BO,SAAS,oBACd,SAC2B;AAC3B,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,UACJ,QAAQ,YAAY,QAAQ,SAAS,SAAY,mBAAmB,QAAQ,IAAI,IAAI;AACtF,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI,mBAAmB;AAAA,MAC3B,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,WAAW,mBAAmB,SAAS,KAAK;AAClD,QAAM,aAAa,SAAS;AAE5B,QAAM,OAAO,MAAM,YAAY,UAAU,KAAK;AAC9C,QAAM,WAAW,MAAM,YAAY,MAAM;AACzC,QAAM,OAAO,aAAa,SAAY,QAAQ,QAAQ,IAAI;AAC1D,QAAM,OAAO,MAAM,YAAY,MAAM;AACrC,QAAM,gBAAgB,WAAW,cAAc,KAAK,CAAC;AACrD,QAAM,kBAAkB,WAAW,oBAAoB,KAAK,CAAC;AAC7D,QAAM,qBAAqB,MAAM,YAAY,gBAAgB;AAC7D,QAAM,YAAY,MAAM,YAAY,WAAW;AAC/C,QAAM,MAAM,WAAW,eAAe,KAAK,CAAC;AAC5C,QAAM,UAAU,WAAW,SAAS,KAAK,CAAC;AAC1C,QAAM,OAAO,WAAW,MAAM,KAAK,CAAC;AACpC,QAAM,gBAAgB,WAAW,mBAAmB,KAAK,CAAC;AAE1D,QAAM,UAA6B,EAAE,MAAM,UAAU,OAAO;AAC5D,MAAI,SAAS,OAAW,SAAQ,OAAO;AACvC,MAAI,SAAS,OAAW,SAAQ,WAAW,EAAE,OAAO,KAAK;AACzD,MAAI,uBAAuB,QAAW;AACpC,UAAM,UAAU,QAAQ,kBAAkB;AAC1C,QAAI,YAAY,OAAW,SAAQ,YAAY,UAAU;AAAA,EAC3D;AAEA,QAAM,MAA6C,CAAC;AACpD,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,WAAW,cAAc,CAAC;AAChC,QAAI,aAAa,OAAW,KAAI,aAAa,EAAE,MAAM,WAAW,QAAQ,EAAE;AAAA,EAC5E;AACA,MAAI,gBAAgB,SAAS,GAAG;AAC9B,QAAI,aAAa,gBAAgB,IAAI,CAACC,WAAU,EAAE,MAAM,WAAWA,KAAI,EAAE,EAAE;AAAA,EAC7E;AACA,QAAM,aAAuC,CAAC;AAC9C,MAAI,IAAI,SAAS,EAAG,YAAW,KAAK,IAAI,iBAAiB,GAAG;AAC5D,MAAI,QAAQ,SAAS,EAAG,YAAW,QAAQ,IAAI,iBAAiB,OAAO;AACvE,MAAI,KAAK,SAAS,EAAG,YAAW,MAAM,IAAI,iBAAiB,IAAI;AAC/D,MAAI,cAAc,SAAS,EAAG,YAAW,eAAe,IAAI,iBAAiB,aAAa;AAC1F,MAAI,OAAO,KAAK,UAAU,EAAE,SAAS,GAAG;AACtC,QAAI,aAAa;AAAA,EACnB;AACA,MAAI,OAAO,KAAK,GAAG,EAAE,SAAS,EAAG,SAAQ,MAAM;AAE/C,QAAM,SAAoC;AAAA,IACxC,eAAe,cAAc,IAAI,UAAU;AAAA,IAC3C;AAAA,IACA;AAAA,EACF;AACA,MAAI,cAAc,OAAW,QAAO,YAAY;AAChD,SAAO;AACT;AAEA,SAAS,MACP,SACA,KACoB;AACpB,QAAM,SAAS,QAAQ,GAAG;AAC1B,SAAO,WAAW,UAAa,OAAO,SAAS,IAAI,OAAO,CAAC,IAAI;AACjE;AAEA,SAAS,QAAQ,MAAkC;AACjD,QAAM,QAAQ,OAAO,SAAS,MAAM,EAAE;AACtC,SAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;AAC1C;AAEA,SAAS,WAAWA,OAAsB;AACxC,MAAI,CAACA,MAAK,WAAW,GAAG,EAAG,QAAOA;AAClC,QAAM,OAAO,QAAQ,IAAI,MAAM,KAAK,QAAQ,IAAI,aAAa;AAC7D,MAAI,SAAS,OAAW,QAAOA;AAC/B,MAAIA,UAAS,IAAK,QAAO;AACzB,MAAIA,MAAK,WAAW,IAAI,KAAKA,MAAK,WAAW,KAAK,EAAG,QAAO,GAAG,IAAI,GAAGA,MAAK,MAAM,CAAC,CAAC;AACnF,SAAOA;AACT;AAEA,SAAS,iBAAiB,QAAqC;AAC7D,QAAM,MAAgB,CAAC;AACvB,aAAW,SAAS,QAAQ;AAC1B,eAAW,QAAQ,MAAM,MAAM,GAAG,GAAG;AACnC,YAAM,UAAU,KAAK,KAAK;AAC1B,UAAI,YAAY,GAAI,KAAI,KAAK,OAAO;AAAA,IACtC;AAAA,EACF;AACA,SAAO;AACT;;;ACrNO,SAAS,qBAAqB,KAAyC;AAC5E,QAAM,SAAS,YAAY,GAAG;AAC9B,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,mBAAmB;AAAA,MAC3B,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,QAAyB,CAAC;AAChC,QAAM,UAA4E,CAAC;AACnF,QAAM,cAAwB,CAAC;AAC/B,QAAM,oBAA+B,CAAC;AACtC,MAAI,WAAW;AACf,MAAI,eAAuC,CAAC;AAC5C,MAAI;AACJ,MAAI,oBAAoB;AAExB,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,QAAQ;AACzB,UAAI,MAAM,SAAS,UAAU;AAC3B,oBAAY,KAAK,EAAE;AACnB,0BAAkB,KAAK,IAAI;AAC3B;AAAA,MACF;AACA,UAAI,MAAM,SAAS,UAAU;AAC3B,mBAAW;AACX,uBAAe,CAAC;AAChB;AAAA,MACF;AACA,kBAAY,MAAM;AAClB,UAAI,MAAM,SAAS,UAAU,CAAC,YAAY,kBAAkB,SAAS,GAAG;AACtE,4BAAoB;AAAA,MACtB;AACA;AAAA,IACF;AACA,QAAI,MAAM,SAAS,QAAQ;AACzB,UAAI,mBAAmB;AACrB,cAAM,MAAM,YAAY,SAAS;AACjC,YAAI,OAAO,EAAG,aAAY,GAAG,IAAI,MAAM,KAAK,KAAK;AACjD,4BAAoB;AACpB;AAAA,MACF;AACA,UAAI,YAAY,cAAc,QAAW;AACvC,qBAAa,SAAS,KAAK,aAAa,SAAS,KAAK,MAAM,MAAM;AAAA,MACpE;AACA;AAAA,IACF;AACA,QAAI,MAAM,SAAS,SAAS;AAC1B,UAAI,MAAM,SAAS,UAAU;AAC3B,oBAAY,IAAI;AAChB,0BAAkB,IAAI;AACtB;AAAA,MACF;AACA,UAAI,MAAM,SAAS,UAAU;AAC3B,cAAM,SAAS,YAAY,OAAO,CAAC,YAAY,YAAY,EAAE;AAC7D,cAAM,SAAS,oBAAoB,YAAY;AAC/C,YAAI,OAAO,SAAS,QAAQ;AAC1B,gBAAM,KAAK,EAAE,GAAG,OAAO,MAAM,OAAO,CAAC;AAAA,QACvC,OAAO;AACL,kBAAQ,KAAK;AAAA,YACX;AAAA,YACA,MAAM,OAAO;AAAA,YACb,GAAI,OAAO,aAAa,SAAY,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,UACvE,CAAC;AAAA,QACH;AACA,mBAAW;AACX,uBAAe,CAAC;AAChB,oBAAY;AACZ;AAAA,MACF;AACA,UAAI,cAAc,MAAM,KAAM,aAAY;AAAA,IAC5C;AAAA,EACF;AACA,SAAO,EAAE,OAAO,QAAQ;AAC1B;AAaA,SAAS,oBAAoB,QAAyD;AACpF,QAAM,QAAQ,OAAO,MAAM,KAAK,OAAO,MAAM,KAAK,YAAY,KAAK;AACnE,QAAM,QAAQ,OAAO,MAAM,KAAK,IAAI,KAAK;AACzC,MAAI,SAAS,GAAI,QAAO,EAAE,MAAM,WAAW,KAAK;AAChD,QAAM,eAAe,OAAO,UAAU;AACtC,QAAM,WAAW,iBAAiB,SAAY,OAAO,SAAS,aAAa,KAAK,GAAG,EAAE,IAAI;AACzF,QAAM,SAAS,qBAAqB,QAAQ;AAC5C,MAAI,WAAW,QAAW;AACxB,WAAO,OAAO,SAAS,QAAQ,IAC3B,EAAE,MAAM,WAAW,MAAM,SAAS,IAClC,EAAE,MAAM,WAAW,KAAK;AAAA,EAC9B;AACA,QAAM,UAA6B,EAAE,MAAM,UAAU,OAAO,SAAS;AACrE,MAAI,OAAO,WAAW,OAAW,SAAQ,SAAS,OAAO;AACzD,QAAM,WAAW,OAAO,MAAM;AAC9B,MAAI,aAAa,QAAW;AAC1B,UAAM,OAAO,OAAO,SAAS,SAAS,KAAK,GAAG,EAAE;AAChD,QAAI,OAAO,SAAS,IAAI,EAAG,SAAQ,OAAO;AAAA,EAC5C;AACA,QAAM,OAAO,OAAO,MAAM,GAAG,KAAK;AAClC,MAAI,SAAS,UAAa,SAAS,GAAI,SAAQ,WAAW,EAAE,OAAO,KAAK;AAExE,QAAM,UAAU,OAAO,MAAM;AAC7B,QAAM,oBAAoB,YAAY,UAAa,YAAY;AAE/D,QAAM,OAAsC,EAAE,mBAAmB,MAAM,QAAQ;AAC/E,QAAM,YAAY,OAAO,WAAW;AACpC,MAAI,cAAc,QAAW;AAC3B,UAAM,YAAY,OAAO,SAAS,UAAU,KAAK,GAAG,EAAE;AACtD,QAAI,OAAO,SAAS,SAAS,EAAG,MAAK,YAAY;AAAA,EACnD;AACA,SAAO,EAAE,MAAM,QAAQ,KAAK;AAC9B;AAEA,SAAS,qBACP,MACwF;AACxF,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,EAAE,UAAU,MAAM;AAAA,IAC3B,KAAK;AACH,aAAO,EAAE,UAAU,OAAO;AAAA,IAC5B,KAAK;AACH,aAAO,EAAE,UAAU,QAAQ,QAAQ,KAAK;AAAA,IAC1C,KAAK;AACH,aAAO,EAAE,UAAU,QAAQ,QAAQ,KAAK;AAAA,IAC1C,KAAK;AACH,aAAO,EAAE,UAAU,OAAO,QAAQ,MAAM;AAAA,IAC1C;AACE,aAAO;AAAA,EACX;AACF;AAkBA,SAAS,YAAY,KAAyB;AAC5C,QAAM,SAAqB,CAAC;AAC5B,MAAI,QAAQ;AACZ,QAAM,SAAS,IAAI;AACnB,SAAO,QAAQ,QAAQ;AACrB,UAAM,KAAK,IAAI,QAAQ,KAAK,KAAK;AACjC,QAAI,OAAO,IAAI;AACb,YAAM,OAAO,IAAI,MAAM,KAAK;AAC5B,UAAI,KAAK,KAAK,MAAM,GAAI,QAAO,KAAK,EAAE,MAAM,QAAQ,MAAM,eAAe,IAAI,EAAE,CAAC;AAChF;AAAA,IACF;AACA,QAAI,KAAK,OAAO;AACd,YAAM,OAAO,IAAI,MAAM,OAAO,EAAE;AAChC,UAAI,KAAK,KAAK,MAAM,GAAI,QAAO,KAAK,EAAE,MAAM,QAAQ,MAAM,eAAe,IAAI,EAAE,CAAC;AAAA,IAClF;AACA,QAAI,IAAI,WAAW,QAAQ,EAAE,GAAG;AAC9B,YAAM,MAAM,IAAI,QAAQ,OAAO,KAAK,CAAC;AACrC,cAAQ,QAAQ,KAAK,SAAS,MAAM;AACpC;AAAA,IACF;AACA,QAAI,IAAI,WAAW,aAAa,EAAE,GAAG;AACnC,YAAM,MAAM,IAAI,QAAQ,OAAO,KAAK,CAAC;AACrC,YAAM,WAAW,QAAQ,KAAK,SAAS;AACvC,aAAO,KAAK,EAAE,MAAM,QAAQ,MAAM,IAAI,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;AAC/D,cAAQ,QAAQ,KAAK,SAAS,MAAM;AACpC;AAAA,IACF;AACA,QAAI,IAAI,KAAK,CAAC,MAAM,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK;AAC9C,YAAMC,MAAK,IAAI,QAAQ,KAAK,KAAK,CAAC;AAClC,cAAQA,QAAO,KAAK,SAASA,MAAK;AAClC;AAAA,IACF;AACA,UAAM,KAAK,IAAI,QAAQ,KAAK,KAAK,CAAC;AAClC,QAAI,OAAO,GAAI;AACf,UAAM,UAAU,IAAI,MAAM,KAAK,GAAG,EAAE;AACpC,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,aAAO,KAAK,EAAE,MAAM,SAAS,MAAM,QAAQ,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;AAAA,IAC9D,OAAO;AACL,YAAM,cAAc,QAAQ,SAAS,GAAG;AACxC,YAAM,OAAO,cAAc,QAAQ,MAAM,GAAG,EAAE,IAAI;AAClD,YAAM,EAAE,MAAM,WAAW,IAAI,aAAa,KAAK,KAAK,CAAC;AACrD,aAAO,KAAK,EAAE,YAAY,MAAM,QAAQ,MAAM,YAAY,CAAC;AAC3D,UAAI,YAAa,QAAO,KAAK,EAAE,MAAM,SAAS,KAAK,CAAC;AAAA,IACtD;AACA,YAAQ,KAAK;AAAA,EACf;AACA,SAAO;AACT;AAEA,SAAS,aAAa,MAAoE;AACxF,QAAM,QAAQ,KAAK,MAAM,+BAA+B;AACxD,MAAI,CAAC,MAAO,QAAO,EAAE,YAAY,CAAC,GAAG,MAAM,KAAK;AAChD,QAAM,OAAO,MAAM,CAAC,KAAK;AACzB,QAAM,OAAO,MAAM,CAAC,KAAK;AACzB,QAAM,aAAqC,CAAC;AAC5C,QAAM,YAAY;AAClB,MAAI;AACJ,UAAQ,YAAY,UAAU,KAAK,IAAI,OAAO,MAAM;AAClD,UAAM,MAAM,UAAU,CAAC;AACvB,UAAM,QAAQ,UAAU,CAAC,KAAK,UAAU,CAAC,KAAK;AAC9C,QAAI,QAAQ,OAAW,YAAW,GAAG,IAAI,eAAe,KAAK;AAAA,EAC/D;AACA,SAAO,EAAE,YAAY,KAAK;AAC5B;AAEA,SAAS,eAAe,MAAsB;AAC5C,SAAO,KACJ,QAAQ,SAAS,GAAG,EACpB,QAAQ,SAAS,GAAG,EACpB,QAAQ,WAAW,GAAG,EACtB,QAAQ,WAAW,GAAG,EACtB,QAAQ,UAAU,GAAG;AAC1B;;;AC7OO,SAAS,qBAAqB,KAAyC;AAC5E,QAAM,WAAW,SAAS,GAAG;AAC7B,QAAM,kBAAkB,SAAS,OAAO,CAAC,YAAY,QAAQ,KAAK,WAAW,YAAY,CAAC;AAC1F,MAAI,gBAAgB,WAAW,GAAG;AAChC,UAAM,IAAI,mBAAmB;AAAA,MAC3B,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,WAA4B,CAAC;AACnC,QAAM,UAA8E,CAAC;AACrF,aAAW,WAAW,iBAAiB;AACrC,UAAM,cAAc,kBAAkB,QAAQ,KAAK,MAAM,aAAa,MAAM,CAAC;AAC7E,UAAM,WAAW,YAAY,MAAM,GAAG,EAAE,OAAO,CAAC,YAAY,YAAY,EAAE;AAC1E,UAAM,OAAO,SAAS,SAAS,SAAS,CAAC,KAAK;AAC9C,UAAM,SAAS,SAAS,MAAM,GAAG,EAAE;AACnC,UAAM,QAAQ,oBAAoB,MAAM,QAAQ,MAAM;AACtD,QAAI,MAAM,SAAS,WAAW;AAC5B,eAAS,KAAK,EAAE,GAAG,MAAM,SAAS,OAAO,CAAC;AAAA,IAC5C,OAAO;AACL,cAAQ,KAAK;AAAA,QACX;AAAA,QACA;AAAA,QACA,GAAI,MAAM,eAAe,SAAY,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;AAAA,MAC3E,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,EAAE,UAAU,QAAQ;AAC7B;AAWA,SAAS,oBACP,MACA,QAC+B;AAC/B,QAAM,OAAO,OAAO,UAAU,GAAG,KAAK;AACtC,MAAI,SAAS,UAAa,SAAS,GAAI,QAAO,EAAE,MAAM,UAAU;AAChE,QAAM,iBAAiB,OAAO,YAAY;AAC1C,QAAM,aAAa,mBAAmB,SAAY,OAAO,SAAS,gBAAgB,EAAE,IAAI;AACxF,QAAM,WAAW,OAAO,MAAM;AAC9B,QAAM,OAAO,aAAa,SAAY,OAAO,SAAS,UAAU,EAAE,IAAI;AACtE,QAAM,SAAS,kBAAkB,YAAY,IAAI;AACjD,MAAI,WAAW,QAAW;AACxB,WAAO,OAAO,SAAS,UAAU,IAAI,EAAE,YAAY,MAAM,UAAU,IAAI,EAAE,MAAM,UAAU;AAAA,EAC3F;AAEA,QAAM,UAA6B,EAAE,MAAM,UAAU,OAAO,SAAS;AACrE,MAAI,OAAO,WAAW,OAAW,SAAQ,SAAS,OAAO;AACzD,QAAM,WAAW,OAAO,YAAY;AACpC,MAAI,aAAa,QAAW;AAC1B,UAAM,OAAO,OAAO,SAAS,UAAU,EAAE;AACzC,QAAI,OAAO,SAAS,IAAI,EAAG,SAAQ,OAAO;AAAA,EAC5C;AACA,QAAM,OAAO,OAAO,UAAU,GAAG,KAAK;AACtC,MAAI,SAAS,UAAa,SAAS,GAAI,SAAQ,WAAW,EAAE,OAAO,KAAK;AAExE,MAAI,OAAO,aAAa,QAAQ;AAC9B,UAAM,MAA6C,CAAC;AACpD,UAAM,UAAU,OAAO,eAAe,GAAG,KAAK;AAC9C,QAAI,YAAY,UAAa,YAAY,GAAI,KAAI,aAAa,EAAE,MAAM,QAAQ;AAC9E,QAAI,OAAO,KAAK,GAAG,EAAE,SAAS,EAAG,SAAQ,MAAM;AAAA,EACjD;AAEA,QAAM,UAAyC,EAAE,MAAM,QAAQ;AAC/D,MAAI,OAAO,SAAS,UAAU,EAAG,SAAQ,aAAa;AACtD,MAAI,OAAO,SAAS,IAAI,KAAK,SAAS,EAAG,SAAQ,OAAO;AACxD,SAAO,EAAE,MAAM,WAAW,QAAQ;AACpC;AAEA,SAAS,kBACP,YACA,MACwF;AACxF,UAAQ,YAAY;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,EAAE,UAAU,OAAO;AAAA,IAC5B,KAAK;AACH,aAAO,SAAS,IAAI,EAAE,UAAU,MAAM,IAAI,EAAE,UAAU,QAAQ,QAAQ,SAAS,EAAE;AAAA,IACnF;AACE,aAAO;AAAA,EACX;AACF;AAOA,SAAS,SAAS,MAA4B;AAC5C,QAAM,WAAyB,CAAC;AAChC,MAAI;AACJ,QAAM,QAAQ,KAAK,MAAM,OAAO;AAChC,aAAW,WAAW,OAAO;AAC3B,UAAM,OAAO,QAAQ,QAAQ,eAAe,EAAE,EAAE,KAAK;AACrD,QAAI,SAAS,GAAI;AACjB,UAAM,eAAe,KAAK,MAAM,YAAY;AAC5C,QAAI,gBAAgB,aAAa,CAAC,MAAM,QAAW;AACjD,gBAAU,EAAE,MAAM,aAAa,CAAC,GAAG,QAAQ,CAAC,EAAE;AAC9C,eAAS,KAAK,OAAO;AACrB;AAAA,IACF;AACA,QAAI,YAAY,OAAW;AAC3B,UAAM,KAAK,KAAK,QAAQ,GAAG;AAC3B,QAAI,OAAO,GAAI;AACf,UAAM,MAAM,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK;AACnC,UAAM,QAAQ,KAAK,MAAM,KAAK,CAAC,EAAE,KAAK;AACtC,QAAI,QAAQ,GAAI,SAAQ,OAAO,GAAG,IAAI;AAAA,EACxC;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,MAAsB;AAE/C,MAAI;AACF,WAAO,mBAAmB,IAAI;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC5HO,SAAS,kBAAkB,OAA8C;AAC9E,QAAM,UAAmC;AAAA,IACvC,SAAS,MAAM;AAAA,IACf,SAAS,MAAM;AAAA,IACf,UAAU,MAAM,YAAY;AAAA,IAC5B,WAAW;AAAA,EACb;AAEA,MAAI,MAAM,YAAY,OAAW,SAAQ,UAAU,MAAM;AACzD,MAAI,MAAM,SAAS,OAAW,SAAQ,OAAO,MAAM;AACnD,MAAI,MAAM,UAAU,OAAW,SAAQ,QAAQ,MAAM;AAErD,MAAI,MAAM,YAAY,KAAK;AACzB,WAAO,IAAI,oBAAoB,OAAO;AAAA,EACxC;AAEA,MAAI,MAAM,YAAY,KAAK;AACzB,WAAO,IAAI,gBAAgB;AAAA,MACzB,GAAG;AAAA,MACH,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,MAAM,YAAY,KAAK;AACzB,WAAO,UAAU,OAAO;AAAA,EAC1B;AAEA,MAAI,CAAC,KAAK,KAAK,GAAG,EAAE,SAAS,MAAM,OAAO,GAAG;AAC3C,WAAO,IAAI,cAAc;AAAA,MACvB,GAAG;AAAA,MACH,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,MAAM,WAAW,OAAO,MAAM,UAAU,KAAK;AAC/C,WAAO,IAAI,gBAAgB;AAAA,MACzB,GAAG;AAAA,MACH,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO,IAAI,cAAc,OAAO;AAClC;AAQA,SAAS,UAAU,SAAqD;AACtE,QAAM,eAAe,QAAQ,QAAQ,YAAY;AAEjD,MAAI,aAAa,SAAS,SAAS,KAAK,aAAa,SAAS,QAAQ,GAAG;AACvE,WAAO,IAAI,uBAAuB,OAAO;AAAA,EAC3C;AAEA,MACE,aAAa,SAAS,WAAW,KACjC,aAAa,SAAS,SAAS,KAC/B,aAAa,SAAS,aAAa,GACnC;AACA,WAAO,IAAI,kBAAkB,OAAO;AAAA,EACtC;AAEA,SAAO,IAAI,sBAAsB,OAAO;AAC1C;;;ACnFA,IAAM,uBAAuB;AAC7B,IAAM,wBAAwB;AAC9B,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;AAgDxB,SAAS,yBACd,UAAqC,CAAC,GACjB;AACrB,QAAM,cAAc,yBAAyB,QAAQ,aAAa,oBAAoB;AACtF,QAAM,cAAc,qBAAqB,QAAQ,aAAa,qBAAqB;AACnF,QAAM,aAAa,qBAAqB,QAAQ,YAAY,oBAAoB;AAChF,QAAM,eAAe,qBAAqB,QAAQ,cAAc,sBAAsB;AACtF,QAAM,SAAS,QAAQ,UAAU,KAAK;AAEtC,SAAO;AAAA,IACL,WAAW,OAA2C;AACpD,YAAM,eAAe,iBAAiB,MAAM,KAAK;AACjD,UAAI,iBAAiB,QAAW;AAC9B,eAAO;AAAA,MACT;AAEA,YAAM,gBAAgB,cAAc,MAAM,MAAM,UAAU;AAC1D,YAAM,WAAW,KAAK,IAAI,YAAY,aAAa;AACnD,aAAO,KAAK,MAAM,OAAO,IAAI,QAAQ;AAAA,IACvC;AAAA,IACA;AAAA,IACA,YAAY,OAA4C;AACtD,UAAI,EAAE,MAAM,iBAAiB,sBAAsB,CAAC,MAAM,MAAM,WAAW;AACzE,eAAO;AAAA,MACT;AAEA,UAAI,MAAM,aAAa,cAAc;AACnC,eAAO;AAAA,MACT;AAEA,YAAM,eAAe,iBAAiB,MAAM,KAAK;AACjD,UAAI,iBAAiB,UAAa,MAAM,YAAY,eAAe,cAAc;AAC/E,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAGA,SAAS,iBAAiB,OAAoC;AAC5D,MAAI,EAAE,iBAAiB,mBAAoB,QAAO;AAClD,QAAM,QAAQ,MAAM,UAAU,cAAc;AAC5C,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,EAAG,QAAO;AAC9E,SAAO,KAAK,MAAM,KAAK;AACzB;AAEA,SAAS,yBAAyB,OAA2B,UAA0B;AACrF,MAAI,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GAAG;AAC/D,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,MAAM,KAAK;AACzB;AAEA,SAAS,qBAAqB,OAA2B,UAA0B;AACjF,MAAI,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GAAG;AAC/D,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,MAAM,KAAK;AACzB;;;ACxCO,SAAS,mBAAmB,OAAwC;AACzE,QAAM,OAAqB;AAAA,IACzB,WAAW,MAAM,MAAM,KAAK,oBAAI,KAAK;AAAA,IACrC,QAAQ,MAAM,UAAU;AAAA,IACxB,IAAI,MAAM;AAAA,IACV,OAAO,MAAM,MAAM,IAAI,aAAa;AAAA,IACpC,UAAU,CAAC,GAAI,MAAM,YAAY,CAAC,CAAE;AAAA,EACtC;AAEA,MAAI,MAAM,aAAa,QAAW;AAChC,SAAK,WAAW,EAAE,GAAG,MAAM,SAAS;AAAA,EACtC;AAEA,SAAO;AACT;AAmBO,SAAS,sBAAsB,MAAyC;AAC7E,QAAM,UAAkC,CAAC;AACzC,MAAI,mBAAmB;AACvB,MAAI,kBAAkB;AACtB,MAAI,eAAe;AACnB,MAAI,qBAAqB;AAEzB,aAAW,QAAQ,KAAK,OAAO;AAC7B,YAAQ,KAAK,MAAM,KAAK,QAAQ,KAAK,MAAM,KAAK,KAAK;AACrD,wBAAoB,KAAK,gBAAgB,OAAO,IAAI;AACpD,oBAAgB,KAAK,WAAW,SAAS,IAAI;AAC7C,uBAAmB,KAAK,WAAW,SAAS,IAAI;AAChD,0BAAsB,KAAK,iBAAiB;AAAA,EAC9C;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,KAAK,MAAM;AAAA,EACzB;AACF;AAGO,SAAS,2BAA2B,MAAmC;AAC5E,SAAO,KAAK,MAAM,QAAQ,CAAC,SAAS;AAClC,QAAI,KAAK,WAAW,QAAQ;AAC1B,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,MAAmB;AAAA,MACvB,IAAI,GAAG,KAAK,EAAE,IAAI,KAAK,EAAE;AAAA,MACzB,WAAW,KAAK;AAAA,IAClB;AAEA,QAAI,KAAK,WAAW,OAAW,KAAI,SAASC,eAAc,KAAK,MAAM;AACrE,QAAI,KAAK,gBAAgB,OAAW,KAAI,cAAcA,eAAc,KAAK,WAAW;AACpF,QAAI,KAAK,kBAAkB,OAAW,KAAI,aAAa,KAAK;AAC5D,QAAI,KAAK,aAAa,OAAW,KAAI,WAAW,EAAE,GAAG,KAAK,SAAS;AAEnE,WAAO,CAAC,GAAG;AAAA,EACb,CAAC;AACH;AAEA,SAAS,cAAc,MAA0C;AAC/D,QAAM,QAA0B;AAAA,IAC9B,QAAQ,KAAK;AAAA,IACb,IAAI,KAAK;AAAA,EACX;AAEA,MAAI,KAAK,WAAW,OAAW,OAAM,SAASA,eAAc,KAAK,MAAM;AACvE,MAAI,KAAK,gBAAgB,OAAW,OAAM,cAAcA,eAAc,KAAK,WAAW;AACtF,MAAI,KAAK,kBAAkB,OAAW,OAAM,gBAAgB,KAAK;AACjE,MAAI,KAAK,gBAAgB,OAAW,OAAM,cAAc,KAAK;AAC7D,MAAI,KAAK,WAAW,OAAW,OAAM,SAAS,KAAK;AACnD,MAAI,KAAK,aAAa,OAAW,OAAM,WAAW,EAAE,GAAG,KAAK,SAAS;AAErE,SAAO;AACT;AAEA,SAASA,eAAc,UAA8C;AACnE,QAAM,QAA0B,EAAE,MAAM,SAAS,KAAK;AAEtD,MAAI,SAAS,aAAa,QAAW;AACnC,UAAM,WAAW,SAAS;AAAA,EAC5B;AAEA,SAAO;AACT;;;AC5DO,IAAM,gBAAN,MAAoB;AAAA,EACR;AAAA,EACA,QAAqC,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA,EACA,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,YAAY,UAAgC,CAAC,GAAG;AAC9C,SAAK,SAAS,QAAQ,UAAU,IAAI,eAAe;AACnD,SAAK,cAAc,qBAAqB,QAAQ,WAAW;AAC3D,SAAK,kBAAkB,QAAQ;AAC/B,SAAK,kBAAkB,QAAQ;AAC/B,SAAK,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,UAAU;AACxD,SAAK,UAAU,QAAQ,WAAW,QAAQ,QAAQ,UAAU;AAC5D,SAAK,iBAAiB,QAAQ;AAC9B,SAAK,aAAa,QAAQ;AAC1B,SAAK,YAAY,QAAQ;AACzB,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA;AAAA,EAGA,IAAI,KAAkB,UAAgD;AACpE,QAAI,KAAK,MAAM,KAAK,CAACC,UAASA,MAAK,OAAO,IAAI,EAAE,GAAG;AACjD,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,EAAE,OAAO,IAAI,GAAG;AAAA,QACzB,SAAS,wCAAwC,IAAI,EAAE;AAAA,QACvD,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,OAAkC;AAAA,MACtC,YAAY,IAAI,gBAAgB;AAAA,MAChC,IAAI,IAAI;AAAA,MACR,KAAK,iBAAiB,GAAG;AAAA,MACzB,QAAQ;AAAA,IACV;AAEA,QAAI,aAAa,QAAW;AAC1B,WAAK,WAAW;AAAA,IAClB;AAEA,SAAK,MAAM,KAAK,IAAI;AACpB,WAAO,aAAa,IAAI;AAAA,EAC1B;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGA,SAAe;AACb,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGA,eAAe,aAA2B;AACxC,SAAK,cAAc,qBAAqB,WAAW;AAAA,EACrD;AAAA;AAAA,EAGA,OAAO,OAAwB;AAC7B,UAAM,OAAO,KAAK,MAAM,KAAK,CAAC,cAAc,UAAU,OAAO,KAAK;AAElE,QACE,SAAS,UACT,KAAK,WAAW,eAChB,KAAK,WAAW,YAChB,KAAK,WAAW,YAChB;AACA,aAAO;AAAA,IACT;AAEA,SAAK,WAAW,MAAM;AAEtB,QAAI,KAAK,WAAW,UAAU;AAC5B,WAAK,SAAS;AAAA,IAChB;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,IAAI,OAA8C;AAChD,UAAM,OAAO,KAAK,MAAM,KAAK,CAAC,cAAc,UAAU,OAAO,KAAK;AAClE,WAAO,SAAS,SAAY,SAAY,aAAa,IAAI;AAAA,EAC3D;AAAA;AAAA,EAGA,OAA4B;AAC1B,WAAO,KAAK,MAAM,IAAI,YAAY;AAAA,EACpC;AAAA;AAAA,EAGA,MAAM,IAAI,UAAmC,CAAC,GAAkC;AAC9E,UAAM,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,aAAa,KAAK,uBAAuB,CAAC,CAAC;AACzF,UAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,YAAY,GAAG,MAAM,KAAK,UAAU,OAAO,CAAC;AAEjF,UAAM,QAAQ,IAAI,OAAO;AACzB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA,EAGA,YAAkC;AAChC,UAAM,cAAc,KAAK,MAAM,IAAI,YAAY;AAE/C,WAAO;AAAA,MACL,UAAU,YAAY,OAAO,CAAC,SAAS,KAAK,WAAW,UAAU,EAAE;AAAA,MACnE,WAAW,YAAY,OAAO,CAAC,SAAS,KAAK,WAAW,WAAW,EAAE;AAAA,MACrE,QAAQ,YAAY,OAAO,CAAC,SAAS,KAAK,WAAW,QAAQ,EAAE;AAAA,MAC/D,UAAU,YAAY,OAAO,CAAC,SAAS,KAAK,WAAW,QAAQ;AAAA,MAC/D,QAAQ,YAAY,OAAO,CAAC,SAAS,KAAK,WAAW,QAAQ,EAAE;AAAA,MAC/D,UAAU,YACP;AAAA,QACC,CAAC,SACC,KAAK,YAAY;AAAA,MACrB,EACC,IAAI,CAAC,SAAS,KAAK,OAAO;AAAA,MAC7B,SAAS,YAAY,OAAO,CAAC,SAAS,KAAK,WAAW,SAAS,EAAE;AAAA,MACjE,OAAO,YAAY;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAc,UAAU,SAAiD;AACvE,eAAS;AACP,YAAM,OAAO,KAAK,eAAe;AAEjC,UAAI,SAAS,QAAW;AACtB;AAAA,MACF;AAEA,YAAM,KAAK,QAAQ,MAAM,OAAO;AAAA,IAClC;AAAA,EACF;AAAA,EAEQ,iBAAwD;AAC9D,QAAI,KAAK,QAAQ;AACf,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,KAAK,MAAM,KAAK,CAAC,cAAc,UAAU,WAAW,QAAQ;AAEzE,QAAI,SAAS,QAAW;AACtB,WAAK,SAAS,KAAK,WAAW,OAAO,UAAU,aAAa;AAAA,IAC9D;AAEA,WAAO,MAAM,WAAW,YAAY,OAAO;AAAA,EAC7C;AAAA,EAEA,MAAc,QACZ,MACA,SACe;AACf,UAAM,gBAAgB,qBAAqB,QAAQ,QAAQ,KAAK,UAAU;AAE1E,QAAI;AACF,YAAM,iBAA+C;AAAA,QACnD,QAAQ,KAAK,WAAW;AAAA,MAC1B;AACA,YAAM,aAAa,QAAQ,cAAc,KAAK;AAC9C,YAAM,QAAQ,QAAQ,SAAS,KAAK;AACpC,YAAM,UAAU,QAAQ,WAAW,KAAK;AACxC,YAAM,iBAAiB,QAAQ,kBAAkB,KAAK;AAEtD,UAAI,eAAe,QAAW;AAC5B,uBAAe,aAAa;AAAA,MAC9B;AAEA,UAAI,UAAU,QAAW;AACvB,uBAAe,QAAQ;AAAA,MACzB;AAEA,UAAI,YAAY,QAAW;AACzB,uBAAe,UAAU;AAAA,MAC3B;AAEA,UAAI,mBAAmB,QAAW;AAChC,uBAAe,iBAAiB;AAAA,MAClC;AAEA,YAAM,UAAU,MAAM,KAAK,OAAO;AAAA,QAChC,KAAK;AAAA,QACL,KAAK,gBAAgB,IAAI;AAAA,QACzB;AAAA,MACF;AAEA,WAAK,UAAU;AACf,WAAK,SAAS;AACd,WAAK,YAAY,OAAO;AAAA,IAC1B,SAAS,OAAO;AACd,WAAK,QAAQ;AACb,WAAK,SAAS,KAAK,WAAW,OAAO,UAAU,aAAa;AAE5D,UAAI,KAAK,WAAW,UAAU;AAC5B,aAAK,UAAU,aAAa,IAAI,GAAG,KAAK;AAAA,MAC1C;AAAA,IACF,UAAE;AACA,oBAAc,QAAQ;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,gBAAgB,MAAmD;AACzE,UAAM,WAAW,KAAK,YAAY,KAAK,mBAAmB,KAAK,kBAAkB,KAAK,GAAG;AAEzF,QAAI,aAAa,QAAW;AAC1B,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG;AAAA,QAC9B,SAAS,uCAAuC,KAAK,IAAI,EAAE;AAAA,QAC3D,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,yBAAiC;AACvC,WAAO,KAAK,MAAM,OAAO,CAAC,SAAS,KAAK,WAAW,YAAY,CAAC,KAAK,WAAW,OAAO,OAAO,EAC3F;AAAA,EACL;AACF;AAEA,SAAS,qBAAqB,OAAmC;AAC/D,MAAI,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,GAAG;AAClD,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC;AACtC;AAEA,SAAS,qBACP,QACA,QACqB;AACrB,MAAI,WAAW,QAAW;AACxB,WAAO,EAAE,SAAS,MAAM,OAAU;AAAA,EACpC;AAEA,QAAM,QAAQ,MAAY,OAAO,MAAM;AAEvC,MAAI,OAAO,SAAS;AAClB,UAAM;AACN,WAAO,EAAE,SAAS,MAAM,OAAU;AAAA,EACpC;AAEA,SAAO,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;AAEtD,SAAO;AAAA,IACL,SAAS,MAAM,OAAO,oBAAoB,SAAS,KAAK;AAAA,EAC1D;AACF;AAEA,SAAS,aAAa,MAAoD;AACxE,QAAM,WAA8B;AAAA,IAClC,IAAI,KAAK;AAAA,IACT,KAAK,iBAAiB,KAAK,GAAG;AAAA,IAC9B,QAAQ,KAAK;AAAA,EACf;AAEA,MAAI,KAAK,YAAY,OAAW,UAAS,UAAU,KAAK;AACxD,MAAI,KAAK,UAAU,OAAW,UAAS,QAAQ,KAAK;AAEpD,SAAO;AACT;AAEA,SAAS,iBAAiB,KAA+B;AACvD,QAAM,QAAqB;AAAA,IACzB,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,EACjB;AAEA,MAAI,IAAI,WAAW,OAAW,OAAM,SAAS,EAAE,GAAG,IAAI,OAAO;AAC7D,MAAI,IAAI,gBAAgB,OAAW,OAAM,cAAc,EAAE,GAAG,IAAI,YAAY;AAC5E,MAAI,IAAI,eAAe,OAAW,OAAM,aAAa,IAAI;AACzD,MAAI,IAAI,YAAY,OAAW,OAAM,UAAU,IAAI;AACnD,MAAI,IAAI,aAAa,OAAW,OAAM,WAAW,EAAE,GAAG,IAAI,SAAS;AAEnE,SAAO;AACT;;;AC7VO,SAAS,iBAAiB,OAAuB;AACtD,QAAM,aAAa,oBAAoB,KAAK;AAC5C,MAAI,eAAe,IAAK,QAAO;AAC/B,QAAM,QAAQ,WAAW,MAAM,GAAG,EAAE,OAAO,OAAO;AAClD,QAAM,IAAI;AACV,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO,IAAI,MAAM,KAAK,GAAG,CAAC;AAC5B;AAQO,SAAS,uBAAuB,OAAmC;AACxE,QAAM,aAAa,oBAAoB,KAAK;AAC5C,QAAM,SAA6B,CAAC,EAAE,MAAM,KAAK,MAAM,IAAI,CAAC;AAC5D,MAAI,eAAe,IAAK,QAAO;AAE/B,QAAM,QAAQ,WAAW,MAAM,GAAG,EAAE,OAAO,OAAO;AAClD,MAAI,SAAS;AACb,aAAW,QAAQ,OAAO;AACxB,cAAU,IAAI,IAAI;AAClB,WAAO,KAAK,EAAE,MAAM,MAAM,MAAM,OAAO,CAAC;AAAA,EAC1C;AACA,SAAO;AACT;AAWO,SAAS,kBACd,SACA,MAA0B,QAC1B,QAA8B,OACf;AACf,QAAM,YAAY,UAAU,QAAQ,IAAI;AACxC,SAAO,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,MAAM,UAAU;AACxC,QAAI,QAAQ,QAAQ;AAClB,YAAM,YAAY,KAAK,SAAS;AAChC,YAAM,aAAa,MAAM,SAAS;AAClC,UAAI,cAAc,WAAY,QAAO,YAAY,KAAK;AAAA,IACxD;AAEA,UAAM,WAAW,oBAAoB,MAAM,OAAO,GAAG;AACrD,QAAI,aAAa,EAAG,QAAO,WAAW;AACtC,WAAO,aAAa,MAAM,KAAK;AAAA,EACjC,CAAC;AACH;AASO,SAAS,oBACd,SACA,UAAkE,CAAC,GACpD;AACf,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,SAAS,QAAQ;AACvB,SAAO,QAAQ,OAAO,CAAC,UAAU;AAC/B,QAAI,CAAC,cAAc,MAAM,KAAK,WAAW,GAAG,EAAG,QAAO;AACtD,QAAI,WAAW,UAAa,CAAC,OAAO,KAAK,EAAG,QAAO;AACnD,WAAO;AAAA,EACT,CAAC;AACH;AAYO,SAAS,oBAAoB,SAAoD;AACtF,QAAM,EAAE,GAAG,IAAI;AACf,MAAI,cAAc,oBAAoB,QAAQ,eAAe,GAAG;AAChE,MAAI,gBAA+B,CAAC;AACpC,MAAI,UAA8B,QAAQ,WAAW;AACrD,MAAI,YAAkC,QAAQ,aAAa;AAC3D,MAAI,aAAa,QAAQ,cAAc;AACvC,QAAM,SAAS,QAAQ;AAEvB,iBAAe,cAA8C;AAC3D,UAAM,MAAM,MAAM,GAAG,KAAK,WAAW;AACrC,UAAM,YAAY,eAAe,GAAG;AACpC,oBAAgB;AAChB,WAAO,SAAS;AAAA,EAClB;AAEA,WAAS,eAAe,KAA4C;AAClE,UAAM,gBAAuE,EAAE,WAAW;AAC1F,QAAI,WAAW,OAAW,eAAc,SAAS;AACjD,UAAM,WAAW,oBAAoB,KAAK,aAAa;AACvD,WAAO,kBAAkB,UAAU,SAAS,SAAS;AAAA,EACvD;AAEA,WAAS,WAAkC;AACzC,WAAO;AAAA,MACL,aAAa,uBAAuB,WAAW;AAAA,MAC/C,SAAS,CAAC,GAAG,aAAa;AAAA,MAC1B,MAAM;AAAA,IACR;AAAA,EACF;AAEA,iBAAe,SAAS,QAAgD;AACtE,kBAAc,cAAc,aAAa,MAAM;AAC/C,WAAO,YAAY;AAAA,EACrB;AAEA,iBAAeC,MAAK,OAAoD;AACtE,QAAI,MAAM,SAAS,aAAa;AAC9B,YAAM,IAAI,UAAU,oCAAoC,MAAM,IAAI,YAAY,MAAM,IAAI,GAAG;AAAA,IAC7F;AACA,WAAO,SAAS,MAAM,IAAI;AAAA,EAC5B;AAEA,SAAO;AAAA,IACL,aAAa,MAAM,uBAAuB,WAAW;AAAA,IACrD,IAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAAA,IACA;AAAA,IACA,MAAAA;AAAA,IACA,IAAI,OAAO;AACT,aAAO;AAAA,IACT;AAAA,IACA,SAAS;AAAA,IACT,cAAc,OAAgB;AAC5B,mBAAa;AAAA,IACf;AAAA,IACA,QAAQ,KAAyB,QAA8B,WAAW;AACxE,gBAAU;AACV,kBAAY;AAAA,IACd;AAAA,IACA,IAAI,MAAM,SAAS,iBAAiB,WAAW,CAAC;AAAA,EAClD;AACF;AAEA,SAAS,cAAc,aAAqB,QAAwB;AAClE,MAAI,OAAO,WAAW,GAAG,EAAG,QAAO,oBAAoB,MAAM;AAC7D,MAAI,WAAW,MAAM,WAAW,IAAK,QAAO;AAC5C,MAAI,WAAW,KAAM,QAAO,iBAAiB,WAAW;AACxD,QAAM,OAAO,gBAAgB,MAAM,KAAK;AACxC,SAAO,oBAAoB,GAAG,IAAI,IAAI,MAAM,EAAE;AAChD;AAEA,SAAS,oBACP,MACA,OACA,KACQ;AACR,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,cAAQ,KAAK,QAAQ,MAAM,MAAM,QAAQ;AAAA,IAC3C,KAAK,cAAc;AACjB,YAAM,WAAW,KAAK,YAAY,QAAQ,KAAK;AAC/C,YAAM,YAAY,MAAM,YAAY,QAAQ,KAAK;AACjD,aAAO,WAAW;AAAA,IACpB;AAAA,IACA,KAAK;AACH,aAAO,KAAK,KAAK,cAAc,MAAM,IAAI;AAAA,IAC3C,KAAK;AAAA,IACL;AACE,aAAO,aAAa,MAAM,KAAK;AAAA,EACnC;AACF;AAEA,SAAS,aAAa,MAAmB,OAA4B;AACnE,SAAO,KAAK,KAAK,cAAc,MAAM,MAAM,QAAW,EAAE,SAAS,MAAM,aAAa,OAAO,CAAC;AAC9F;;;AC/JO,SAAS,eAAe,SAA8C;AAC3E,QAAM,YAA2B,QAAQ,aAAa;AACtD,QAAM,eAAiC,QAAQ,gBAAgB;AAC/D,QAAM,iBAAqC,QAAQ,kBAAkB;AACrE,QAAM,0BAA0B,QAAQ,2BAA2B;AACnE,QAAM,aAAa,oBAAoB,QAAQ,OAAO,QAAQ;AAC9D,QAAM,kBAAkB,oBAAoB,QAAQ,YAAY,QAAQ;AACxE,QAAM,WAAqB,CAAC;AAC5B,QAAM,QAA4B,CAAC;AAEnC,aAAW,SAAS,QAAQ,KAAK,SAAS;AACxC,UAAM,UAA4B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,QAAQ,OAAO,aAAa,OAAW,SAAQ,iBAAiB,QAAQ,OAAO;AACnF,QAAI,QAAQ,YAAY,aAAa,QAAW;AAC9C,cAAQ,sBAAsB,QAAQ,YAAY;AAAA,IACpD;AACA,UAAM,OAAO,UAAU,OAAO;AAE9B,QAAI,SAAS,OAAW,OAAM,KAAK,IAAI;AAAA,EACzC;AAEA,QAAM,YAAsD;AAAA,IAC1D,IAAI,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,EACF;AACA,MAAI,QAAQ,WAAW,OAAW,WAAU,SAAS,QAAQ;AAC7D,MAAI,QAAQ,QAAQ,OAAW,WAAU,MAAM,QAAQ;AACvD,MAAI,QAAQ,aAAa,OAAW,WAAU,WAAW,QAAQ;AAEjE,SAAO,mBAAmB,SAAS;AACrC;AAeA,SAAS,UAAU,SAAyD;AAC1E,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,cAAc,iBAAiB,KAAK;AAE1C,MAAI,eAAe,CAAC,QAAQ,yBAAyB;AACnD,WAAO;AAAA,EACT;AAEA,UAAQ,MAAM,QAAQ;AAAA,IACpB,KAAK;AACH,aAAO,UAAU,OAAO;AAAA,IAC1B,KAAK;AACH,aAAO,YAAY,OAAO;AAAA,IAC5B,KAAK;AACH,aAAO,aAAa,OAAO;AAAA,IAC7B,KAAK;AACH,aAAO,cAAc,OAAO;AAAA,IAC9B;AAEE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,UAAU,SAA6C;AAC9D,MAAI,QAAQ,cAAc,yBAAyB;AACjD,WAAO,eAAe,SAAS,UAAU,eAAe,iBAAiB,QAAQ,KAAK,CAAC;AAAA,EACzF;AAGA,MAAI,QAAQ,iBAAiB,SAAS;AACpC,WAAO,eAAe,SAAS,8CAA8C;AAAA,EAC/E;AAEA,SAAO,iBAAiB,SAAS,QAAQ;AAC3C;AAEA,SAAS,YAAY,SAA6C;AAChE,MAAI,QAAQ,cAAc,yBAAyB;AACjD,WAAO,eAAe,SAAS,eAAe,UAAU,iBAAiB,QAAQ,KAAK,CAAC;AAAA,EACzF;AAGA,MAAI,QAAQ,iBAAiB,SAAS;AACpC,WAAO,eAAe,SAAS,mDAAmD;AAAA,EACpF;AAEA,MAAI,QAAQ,iBAAiB,gBAAgB;AAC3C,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,iBAAiB,SAAS,aAAa;AAChD;AAEA,SAAS,aAAa,SAA6C;AACjE,UAAQ,QAAQ,gBAAgB;AAAA,IAC9B,KAAK;AACH,aAAO,eAAe,SAAS,UAAU,eAAe,iBAAiB,QAAQ,KAAK,GAAG;AAAA,QACvF,aAAa;AAAA,MACf,CAAC;AAAA,IACH,KAAK;AACH,aAAO,eAAe,SAAS,eAAe,UAAU,iBAAiB,QAAQ,KAAK,GAAG;AAAA,QACvF,aAAa;AAAA,MACf,CAAC;AAAA,IACH,KAAK;AACH,aAAO,eAAe,SAAS,qBAAqB,QAAQ,MAAM,QAAQ,KAAK,GAAG,CAAC,EAAE;AAAA,IACvF,KAAK;AACH,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS;AAAA,UACP,MAAM,QAAQ,MAAM;AAAA,UACpB,SAAS,QAAQ,MAAM;AAAA,QACzB;AAAA,QACA,SAAS,yBAAyB,QAAQ,MAAM,IAAI,kBAAkB,QAAQ,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,QACtG,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACE,aAAO,eAAe,SAAS,kBAAkB;AAAA,EACrD;AACF;AAEA,SAAS,cAAc,SAA6C;AAClE,SAAO,eAAe,SAAS,uBAAuB;AACxD;AAEA,SAAS,eACP,SACA,UACA,QACA,eACA,YAAuC,CAAC,GACtB;AAClB,QAAM,OAAyB;AAAA,IAC7B,QAAQ;AAAA,IACR,IAAI,WAAW,QAAQ,OAAO,QAAQ,QAAQ,OAAO,MAAM,EAAE;AAAA,IAC7D,QAAQ,gBAAgB,QAAQ,OAAO,QAAQ,QAAQ,OAAO,MAAM,EAAE;AAAA,EACxE;AAEA,OAAK,SAAS,YAAY,SAAS,QAAQ;AAC3C,OAAK,cAAc,YAAY,SAAS,MAAM;AAC9C,MAAI,kBAAkB,OAAW,MAAK,gBAAgB;AACtD,MAAI,UAAU,gBAAgB,KAAM,MAAK,cAAc;AACvD,MAAI,UAAU,aAAa,OAAW,MAAK,WAAW,EAAE,GAAG,UAAU,SAAS;AAE9E,SAAO;AACT;AAEA,SAAS,iBACP,SACA,MACkB;AAClB,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,aAAa,YAAY,SAAS,IAAI;AAAA,IACtC,aAAa;AAAA,IACb,IAAI,WAAW,QAAQ,OAAO,UAAU,IAAI,EAAE;AAAA,IAC9C,QAAQ,UAAU,IAAI;AAAA,EACxB;AACF;AAEA,SAAS,eAAe,SAA2B,QAAkC;AACnF,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,IAAI,WAAW,QAAQ,OAAO,MAAM;AAAA,IACpC;AAAA,IACA,QAAQ,YAAY,SAAS,QAAQ;AAAA,IACrC,aAAa,YAAY,SAAS,aAAa;AAAA,EACjD;AACF;AAEA,SAAS,YACP,SACA,MACyC;AACzC,QAAM,OAAO,SAAS,WAAW,QAAQ,aAAa,QAAQ;AAC9D,QAAM,WAAW,SAAS,WAAW,QAAQ,iBAAiB,QAAQ;AACtE,QAAM,WAAoD;AAAA,IACxD,MAAM,oBAAoB,MAAM,QAAQ,MAAM,IAAI;AAAA,EACpD;AACA,MAAI,aAAa,OAAW,UAAS,WAAW;AAChD,SAAO;AACT;AAEA,SAAS,oBAAoB,UAAkB,cAA8B;AAC3E,MAAI,aAAa,IAAK,QAAO;AAC7B,MAAI,iBAAiB,IAAK,QAAO;AACjC,SAAO,eAAe,UAAU,YAAY;AAC9C;AAEA,SAAS,WAAW,OAA4B,QAAwB;AACtE,SAAO,GAAG,MAAM,IAAI,IAAI,MAAM;AAChC;AAEA,SAAS,gBAAgB,OAA4B,QAAwB;AAC3E,MAAI,MAAM,QAAQ,WAAW,EAAG,QAAO;AACvC,SAAO,GAAG,MAAM,KAAK,MAAM,QAAQ,KAAK,GAAG,CAAC;AAC9C;AAEA,SAAS,iBAAiB,OAAgD;AACxE,SAAO,MAAM,QAAQ,QAAQ,MAAM,aAAa;AAClD;AAEA,SAAS,iBAAiB,OAAqC;AAC7D,SAAO,MAAM,QAAQ,SAAS,eAAe,MAAM,aAAa,SAAS;AAC3E;;;AC/MA,IAAM,6BAA6B;AACnC,IAAM,iBAAiB;AAuChB,SAAS,uBAAuB,SAA0D;AAC/F,QAAM,SAAS,QAAQ,UAAU;AACjC,MAAI,SAAS,GAAG;AACd,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,OAAO;AAAA,MAClB,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,oBAAoB,QAAQ,YAAY,QAAQ;AACjE,MAAI,aAAa,KAAK;AACpB,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,WAAiC,QAAQ,YAAY;AAC3D,QAAM,MAAM,QAAQ,MAAM,KAAK,oBAAI,KAAK;AACxC,QAAM,YAAY,QAAQ,aAAa,iBAAiB,GAAG;AAC3D,QAAM,eAAe;AAAA,IACnB;AAAA,IACA,QAAQ,qBAAqB;AAAA,EAC/B;AACA,QAAM,cAAc,eAAe,cAAc,SAAS;AAC1D,QAAM,aACJ,aAAa,WAAW,eAAe,cAAc,GAAG,SAAS,WAAW,IAAI;AAClF,QAAM,WAAW,QAAQ,YAAY,YAAY,QAAQ,OAAO;AAChE,QAAM,WAAqB,CAAC;AAE5B,QAAM,aAAa,eAAe;AAAA,IAChC,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,aAAa;AAAA,MACX,GAAI,QAAQ,YAAY,aAAa,SACjC,EAAE,UAAU,QAAQ,YAAY,SAAS,IACzC,CAAC;AAAA,MACL,UAAU;AAAA,IACZ;AAAA,IACA,MAAM,QAAQ;AAAA,IACd,WAAW;AAAA,IACX,QAAQ,QAAQ,UAAU;AAAA,IAC1B,IAAI,GAAG,QAAQ,EAAE;AAAA,IACjB,yBAAyB;AAAA,IACzB,GAAI,QAAQ,QAAQ,SAAY,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;AAAA,IACxD,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAED,QAAM,WAAW,mBAAmB;AAAA,IAClC;AAAA,IACA;AAAA,IACA,QAAQ,QAAQ;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,QAAQ,gBAAgB;AAAA,IAC5B,kBAAkB,QAAQ,oBAAoB,CAAC;AAAA,IAC/C,QAAQ,QAAQ;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,OAAyB;AAAA,IAC7B;AAAA,IACA,WAAW;AAAA,IACX,IAAI,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,aAAa,OAAW,MAAK,WAAW;AAC5C,MAAI,eAAe,OAAW,MAAK,aAAa;AAChD,MAAI,QAAQ,aAAa,OAAW,MAAK,WAAW,EAAE,GAAG,QAAQ,SAAS;AAC1E,SAAO;AACT;AAWA,SAAS,mBAAmB,SAA2D;AACrF,MAAI,QAAQ,aAAa,WAAW;AAClC,UAAM,OAAiC;AAAA,MACrC,aAAa;AAAA,MACb,UAAU,QAAQ;AAAA,MAClB,IAAI,GAAG,QAAQ,MAAM;AAAA,MACrB,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,QAAQ,QAAQ;AAAA,IAClB;AACA,QAAI,QAAQ,aAAa,OAAW,MAAK,WAAW,QAAQ;AAC5D,WAAO,CAAC,IAAI;AAAA,EACd;AAEA,QAAM,QAAoC,CAAC;AAC3C,MAAI,QAAQ,eAAe,QAAW;AACpC,UAAM,SAAmC;AAAA,MACvC,aAAa;AAAA,MACb,UAAU,QAAQ;AAAA,MAClB,IAAI,GAAG,QAAQ,MAAM;AAAA,MACrB,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,QAAQ,QAAQ;AAAA,IAClB;AACA,QAAI,QAAQ,aAAa,OAAW,QAAO,WAAW,QAAQ;AAC9D,UAAM,KAAK,MAAM;AAAA,EACnB;AAEA,QAAM,UAAoC;AAAA,IACxC,aAAa;AAAA,IACb,UAAU,QAAQ;AAAA,IAClB,IAAI,GAAG,QAAQ,MAAM;AAAA,IACrB,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,QAAQ,QAAQ;AAAA,EAClB;AACA,MAAI,QAAQ,aAAa,OAAW,SAAQ,WAAW,QAAQ;AAC/D,QAAM,KAAK,OAAO;AAClB,SAAO;AACT;AAWA,SAAS,gBAAgB,SAAqD;AAC5E,MAAI,QAAQ,iBAAiB,WAAW,EAAG,QAAO,CAAC;AAEnD,QAAM,iBAAiB,oBAAoB,QAAQ,YAAY;AAC/D,QAAM,iBAAiB,eAAe,gBAAgB,QAAQ,SAAS;AACvE,QAAM,aAAa,CAAC,GAAG,IAAI,IAAI,QAAQ,iBAAiB,IAAI,CAACC,UAAS,oBAAoBA,KAAI,CAAC,CAAC,CAAC,EAC9F,OAAO,CAACA,UAASA,UAAS,cAAc,EACxC,KAAK;AAER,QAAM,mBAAmB,KAAK,IAAI,GAAG,QAAQ,SAAS,CAAC;AACvD,MAAI,WAAW,UAAU,iBAAkB,QAAO,CAAC;AAEnD,QAAM,UAAU,WAAW,MAAM,GAAG,WAAW,SAAS,gBAAgB;AACxE,SAAO,QAAQ,IAAI,CAACA,OAAM,UAAU;AAClC,UAAM,OAA8B;AAAA,MAClC,IAAI,GAAG,QAAQ,MAAM,UAAU,KAAK;AAAA,MACpC,MAAAA;AAAA,MACA,QAAQ;AAAA,IACV;AACA,QAAI,QAAQ,aAAa,OAAW,MAAK,WAAW,QAAQ;AAC5D,WAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,iBAAiB,KAAmB;AAE3C,SAAO,IAAI,YAAY,EAAE,QAAQ,SAAS,GAAG;AAC/C;;;ACxRA,gBAAuB,eACrB,IACA,UACA,UAAiC,CAAC,GACD;AACjC,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,qBAAqB,QAAQ,sBAAsB;AACzD,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAM,iBAAiB,QAAQ,kBAAkB;AACjD,QAAM,OAAO,oBAAoB,QAAQ;AACzC,QAAM,aAAoC;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,QAAQ,aAAa,OAAW,YAAW,WAAW,QAAQ;AAClE,MAAI,QAAQ,WAAW,OAAW,YAAW,SAAS,QAAQ;AAC9D,MAAI,QAAQ,WAAW,OAAW,YAAW,SAAS,QAAQ;AAE9D,SAAO,cAAc,IAAI,MAAM,GAAG,UAAU;AAC9C;AAYA,gBAAgB,cACd,IACAC,OACA,OACA,SACiC;AACjC,EAAAC,gBAAe,QAAQ,MAAM;AAC7B,QAAM,UAAU,MAAM,GAAG,KAAKD,KAAI;AAClC,QAAM,SAAS,CAAC,GAAG,OAAO,EAAE,KAAKE,eAAc;AAE/C,aAAW,SAAS,QAAQ;AAC1B,QAAI,QAAQ,WAAW,UAAa,CAAC,QAAQ,OAAO,KAAK,EAAG;AAE5D,QAAI,iBAAiB,OAAO,QAAQ,oBAAoB,QAAQ,YAAY,GAAG;AAC7E,YAAM,EAAE,OAAO,OAAO,YAAYF,MAAK;AAAA,IACzC;AAEA,QACE,QAAQ,aACR,eAAe,OAAO,QAAQ,cAAc,MAC3C,QAAQ,aAAa,UAAa,QAAQ,QAAQ,WACnD;AACA,aAAO,cAAc,IAAI,kBAAkB,OAAOA,KAAI,GAAG,QAAQ,GAAG,OAAO;AAAA,IAC7E;AAAA,EACF;AACF;AAEA,SAAS,iBACP,OACA,oBACA,cACS;AACT,MAAI,MAAM,SAAS,YAAa,QAAO;AACvC,MAAI,MAAM,SAAS,OAAQ,QAAO;AAClC,SAAO;AACT;AAEA,SAAS,eAAe,OAAoB,gBAAkC;AAC5E,MAAI,MAAM,SAAS,YAAa,QAAO;AACvC,SAAO,kBAAkB,MAAM,SAAS;AAC1C;AAEA,SAAS,kBAAkB,OAAoB,YAA4B;AACzE,MAAI,MAAM,SAAS,MAAM,MAAM,SAAS,MAAM,MAAM;AAClD,WAAO,oBAAoB,MAAM,IAAI;AAAA,EACvC;AAEA,SAAO,eAAe,YAAY,MAAM,IAAI;AAC9C;AAEA,SAASE,gBAAe,MAAmB,OAA4B;AACrE,MAAI,KAAK,OAAO,MAAM,KAAM,QAAO;AACnC,MAAI,KAAK,OAAO,MAAM,KAAM,QAAO;AACnC,SAAO;AACT;AAEA,SAASD,gBAAe,QAAuC;AAC7D,MAAI,QAAQ,YAAY,MAAM;AAC5B,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACF;;;ACnCA,eAAsB,gBACpB,QACA,YACA,aACA,iBACA,UAAkC,CAAC,GACV;AACzB,QAAM,mBAAmB,QAAQ,oBAAoB;AACrD,QAAM,aAAa,oBAAoB,UAAU;AACjD,QAAM,kBAAkB,oBAAoB,eAAe;AAC3D,QAAM,aAAa,kBAAkB,SAAS,QAAQ,YAAY;AAClE,QAAM,kBAAkB,kBAAkB,SAAS,QAAQ,iBAAiB;AAE5E,QAAM,CAAC,eAAe,kBAAkB,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC5D,eAAe,QAAQ,YAAY,UAAU;AAAA,IAC7C,eAAe,aAAa,iBAAiB,eAAe;AAAA,EAC9D,CAAC;AAED,QAAM,UAAU,aAAa,eAAe,kBAAkB;AAC9D,QAAM,UAAiC,CAAC;AACxC,QAAM,UAAiC;AAAA,IACrC,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW;AAAA,EACb;AAEA,aAAW,EAAE,MAAAE,OAAM,QAAQ,aAAa,aAAa,iBAAiB,KAAK,SAAS;AAClF,YAAQ,SAAS;AACjB,UAAM,UAAkC,CAAC;AACzC,QAAI;AAEJ,QAAI,gBAAgB,UAAa,qBAAqB,QAAW;AAC/D,eAAS;AACT,cAAQ,SAAS;AAAA,IACnB,WAAW,gBAAgB,UAAa,qBAAqB,QAAW;AACtE,eAAS;AACT,cAAQ,WAAW;AAAA,IACrB,WAAW,gBAAgB,UAAa,qBAAqB,QAAW;AACtE,YAAM,kBAAkBC,gBAAe,aAAa,kBAAkB,OAAO;AAE7E,UAAI,gBAAgB,WAAW,GAAG;AAChC,iBAAS;AACT,gBAAQ,aAAa;AAAA,MACvB,OAAO;AACL,iBAAS;AACT,gBAAQ,KAAK,GAAG,eAAe;AAC/B,gBAAQ,YAAY;AAAA,MACtB;AAAA,IACF,OAAO;AAEL;AAAA,IACF;AAEA,QAAI,WAAW,eAAe,CAAC,iBAAkB;AAEjD,UAAM,SAA8B,EAAE,MAAAD,OAAM,SAAS,OAAO;AAC5D,QAAI,gBAAgB,OAAW,QAAO,SAAS;AAC/C,QAAI,qBAAqB,OAAW,QAAO,cAAc;AACzD,YAAQ,KAAK,MAAM;AAAA,EACrB;AAEA,UAAQ,KAAK,CAAC,MAAM,UAAW,KAAK,OAAO,MAAM,OAAO,KAAK,KAAK,OAAO,MAAM,OAAO,IAAI,CAAE;AAE5F,SAAO,EAAE,SAAS,QAAQ;AAC5B;AAEA,SAAS,kBACP,SACA,QACuB;AACvB,QAAM,OAAO,QAAQ,QAAQ,CAAC;AAC9B,QAAM,SAAgC,CAAC;AAEvC,MAAI,KAAK,cAAc,OAAW,QAAO,YAAY,KAAK;AAC1D,MAAI,KAAK,aAAa,OAAW,QAAO,WAAW,KAAK;AACxD,MAAI,KAAK,uBAAuB,OAAW,QAAO,qBAAqB,KAAK;AAC5E,MAAI,KAAK,iBAAiB,OAAW,QAAO,eAAe,KAAK;AAChE,MAAI,KAAK,mBAAmB,OAAW,QAAO,iBAAiB,KAAK;AACpE,QAAM,iBAAiB,UAAU,KAAK;AACtC,MAAI,mBAAmB,OAAW,QAAO,SAAS;AAClD,MAAI,QAAQ,WAAW,OAAW,QAAO,SAAS,QAAQ;AAE1D,SAAO;AACT;AAOA,eAAe,eACb,IACA,UACA,aACmC;AACnC,QAAM,MAAM,oBAAI,IAAyB;AAEzC,mBAAiB,UAAU,eAAe,IAAI,UAAU,WAAW,GAAG;AACpE,UAAM,YAAY,iBAAiB,OAAO,OAAO,QAAQ;AACzD,QAAI,cAAc,OAAW,KAAI,IAAI,UAAU,cAAc,UAAU,KAAK;AAAA,EAC9E;AAEA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAoB,UAA8C;AAC1F,QAAM,OAAO,oBAAoB,QAAQ;AACzC,QAAMA,QAAO,oBAAoB,MAAM,IAAI;AAE3C,MAAIA,UAAS,KAAM,QAAO;AAC1B,MAAI,SAAS,IAAK,QAAO,EAAE,OAAO,cAAcA,MAAK;AACrD,MAAIA,MAAK,WAAW,GAAG,IAAI,GAAG,GAAG;AAC/B,WAAO,EAAE,OAAO,cAAcA,MAAK,MAAM,KAAK,MAAM,EAAE;AAAA,EACxD;AAEA,SAAO;AACT;AAQA,SAAS,aACP,eACA,oBACe;AACf,QAAM,QAAQ,oBAAI,IAAY,CAAC,GAAG,cAAc,KAAK,GAAG,GAAG,mBAAmB,KAAK,CAAC,CAAC;AACrF,QAAM,UAAyB,CAAC;AAEhC,aAAWA,SAAQ,OAAO;AACxB,UAAM,OAAoB,EAAE,MAAAA,MAAK;AACjC,UAAM,SAAS,cAAc,IAAIA,KAAI;AACrC,UAAM,cAAc,mBAAmB,IAAIA,KAAI;AAE/C,QAAI,WAAW,OAAW,MAAK,SAAS;AACxC,QAAI,gBAAgB,OAAW,MAAK,cAAc;AAClD,YAAQ,KAAK,IAAI;AAAA,EACnB;AAEA,SAAO;AACT;AAEA,SAASC,gBACP,QACA,aACA,SACwB;AACxB,QAAM,UAAkC,CAAC;AACzC,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,oBAAoB,QAAQ,qBAAqB;AACvD,QAAM,kBAAkB,QAAQ,mBAAmB;AACnD,QAAM,YAAY,QAAQ,yBAAyB;AAEnD,MAAI,OAAO,SAAS,YAAY,MAAM;AACpC,YAAQ,KAAK,MAAM;AAAA,EACrB;AAEA,MAAI,eAAe,eAAe,QAAQ,WAAW,KAAK,OAAO,SAAS,YAAY,MAAM;AAC1F,YAAQ,KAAK,MAAM;AAAA,EACrB;AAEA,MAAI,qBAAqB,sBAAsB,QAAQ,aAAa,SAAS,GAAG;AAC9E,YAAQ,KAAK,YAAY;AAAA,EAC3B;AAEA,MACE,mBACA,OAAO,aAAa,UACpB,YAAY,aAAa,UACzB,OAAO,aAAa,YAAY,UAChC;AACA,YAAQ,KAAK,UAAU;AAAA,EACzB;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,QAAqB,aAAmC;AAC9E,MAAI,OAAO,SAAS,UAAU,YAAY,SAAS,OAAQ,QAAO;AAClE,SAAO,OAAO,SAAS,UAAa,YAAY,SAAS;AAC3D;AAEA,SAAS,sBACP,QACA,aACA,aACS;AACT,MAAI,OAAO,eAAe,UAAa,YAAY,eAAe,OAAW,QAAO;AACpF,QAAM,QAAQ,KAAK,IAAI,OAAO,WAAW,QAAQ,IAAI,YAAY,WAAW,QAAQ,CAAC;AACrF,SAAO,QAAQ;AACjB;;;ACzRO,IAAM,iCAAiC;AAuE9C,eAAsB,qBACpB,IACA,UACA,UAAuC,CAAC,GACf;AACzB,QAAM,OAAO,oBAAoB,QAAQ;AACzC,QAAM,cAAqC,EAAE,GAAI,QAAQ,QAAQ,CAAC,EAAG;AACrE,QAAM,iBAAiB,QAAQ,UAAU,QAAQ,MAAM;AACvD,MAAI,mBAAmB,OAAW,aAAY,SAAS;AACvD,MAAI,QAAQ,WAAW,OAAW,aAAY,SAAS,QAAQ;AAE/D,QAAM,UAAiC,CAAC;AAExC,mBAAiB,UAAU,eAAe,IAAI,MAAM,WAAW,GAAG;AAChE,UAAM,eAAe,iBAAiB,OAAO,MAAM,MAAM,IAAI;AAC7D,QAAI,iBAAiB,OAAW;AAChC,YAAQ,KAAK,gBAAgB,OAAO,OAAO,YAAY,CAAC;AAAA,EAC1D;AAEA,UAAQ,KAAK,CAAC,MAAM,UAAW,KAAK,OAAO,MAAM,OAAO,KAAK,KAAK,OAAO,MAAM,OAAO,IAAI,CAAE;AAE5F,QAAM,eAAe,QAAQ,MAAM,KAAK,oBAAI,KAAK,GAAG,YAAY;AAChE,QAAM,WAA2B;AAAA,IAC/B;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA;AAAA,EACF;AACA,MAAI,QAAQ,aAAa,OAAW,UAAS,WAAW,QAAQ;AAChE,SAAO;AACT;AASO,SAAS,wBAAwB,UAA0B,SAAiB,GAAW;AAC5F,SAAO,KAAK,UAAU,UAAU,QAAW,MAAM;AACnD;AASO,SAAS,oBAAoB,MAA8B;AAChE,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,SAAS,OAAO;AACd,UAAM,IAAI,mBAAmB;AAAA,MAC3B,OAAO;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;AACjD,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,YAAY;AAClB,MAAI,UAAU,kBAAkB,gCAAgC;AAC9D,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,QACP,UAAU;AAAA,QACV,UAAU,UAAU;AAAA,MACtB;AAAA,MACA,SAAS,8CAA8C,OAAO,UAAU,aAAa,CAAC;AAAA,MACtF,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,UAAU,SAAS,YAAY,UAAU,KAAK,WAAW,GAAG;AACrE,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,UAAU,gBAAgB,UAAU;AAC7C,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,MAAM,QAAQ,UAAU,OAAO,GAAG;AACrC,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,UAAU,QAAQ,IAAI,CAAC,OAAO,UAAU,uBAAuB,OAAO,KAAK,CAAC;AAC5F,QAAM,WAA2B;AAAA,IAC/B;AAAA,IACA,eAAe;AAAA,IACf,aAAa,UAAU;AAAA,IACvB,MAAM,oBAAoB,UAAU,IAAI;AAAA,EAC1C;AACA,MAAI,OAAO,UAAU,aAAa,SAAU,UAAS,WAAW,UAAU;AAC1E,SAAO;AACT;AAcO,SAAS,uBACd,QACA,aACA,UAAyC,CAAC,GAC1B;AAChB,QAAM,mBAAmB,QAAQ,oBAAoB;AACrD,QAAM,YAAY,aAAa,MAAM;AACrC,QAAM,iBAAiB,aAAa,WAAW;AAC/C,QAAM,QAAQ,oBAAI,IAAY,CAAC,GAAG,UAAU,KAAK,GAAG,GAAG,eAAe,KAAK,CAAC,CAAC;AAE7E,QAAM,UAAiC,CAAC;AACxC,QAAM,UAAiC;AAAA,IACrC,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW;AAAA,EACb;AAEA,aAAWC,SAAQ,OAAO;AACxB,YAAQ,SAAS;AACjB,UAAM,cAAc,UAAU,IAAIA,KAAI;AACtC,UAAM,mBAAmB,eAAe,IAAIA,KAAI;AAChD,UAAM,UAAkC,CAAC;AACzC,QAAI;AAEJ,QAAI,gBAAgB,UAAa,qBAAqB,QAAW;AAC/D,eAAS;AACT,cAAQ,SAAS;AAAA,IACnB,WAAW,gBAAgB,UAAa,qBAAqB,QAAW;AACtE,eAAS;AACT,cAAQ,WAAW;AAAA,IACrB,WAAW,gBAAgB,UAAa,qBAAqB,QAAW;AACtE,YAAM,WAAW,uBAAuB,aAAa,kBAAkB,OAAO;AAC9E,UAAI,SAAS,WAAW,GAAG;AACzB,iBAAS;AACT,gBAAQ,aAAa;AAAA,MACvB,OAAO;AACL,iBAAS;AACT,gBAAQ,KAAK,GAAG,QAAQ;AACxB,gBAAQ,YAAY;AAAA,MACtB;AAAA,IACF,OAAO;AACL;AAAA,IACF;AAEA,QAAI,WAAW,eAAe,CAAC,iBAAkB;AAEjD,UAAM,SAA8B,EAAE,MAAAA,OAAM,SAAS,OAAO;AAC5D,QAAI,gBAAgB,QAAW;AAC7B,aAAO,SAAS,sBAAsB,aAAa,OAAO,IAAI;AAAA,IAChE;AACA,QAAI,qBAAqB,QAAW;AAClC,aAAO,cAAc,sBAAsB,kBAAkB,YAAY,IAAI;AAAA,IAC/E;AACA,YAAQ,KAAK,MAAM;AAAA,EACrB;AAEA,UAAQ,KAAK,CAAC,MAAM,UAAW,KAAK,OAAO,MAAM,OAAO,KAAK,KAAK,OAAO,MAAM,OAAO,IAAI,CAAE;AAC5F,SAAO,EAAE,SAAS,QAAQ;AAC5B;AAEA,SAAS,iBAAiB,WAAmB,MAAkC;AAC7E,QAAMA,QAAO,oBAAoB,SAAS;AAC1C,MAAIA,UAAS,KAAM,QAAO;AAC1B,MAAI,SAAS,IAAK,QAAOA;AACzB,MAAIA,MAAK,WAAW,GAAG,IAAI,GAAG,EAAG,QAAOA,MAAK,MAAM,KAAK,MAAM;AAC9D,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAoB,cAA2C;AACtF,QAAM,gBAAqC;AAAA,IACzC,MAAM;AAAA,IACN,MAAM,MAAM;AAAA,EACd;AACA,MAAI,MAAM,SAAS,OAAW,eAAc,OAAO,MAAM;AACzD,MAAI,MAAM,eAAe,OAAW,eAAc,aAAa,MAAM,WAAW,YAAY;AAC5F,MAAI,MAAM,aAAa,OAAW,eAAc,WAAW,MAAM;AACjE,MAAI,MAAM,kBAAkB,OAAW,eAAc,gBAAgB,MAAM;AAC3E,SAAO;AACT;AAEA,SAAS,uBAAuB,OAAgB,OAAoC;AAClF,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,MAAM;AAAA,MACjB,SAAS,kCAAkC,KAAK;AAAA,MAChD,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,YAAY;AAClB,MAAI,OAAO,UAAU,SAAS,YAAY,UAAU,KAAK,WAAW,GAAG;AACrE,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,MAAM;AAAA,MACjB,SAAS,kCAAkC,KAAK;AAAA,MAChD,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,MAAI,CAAC,kBAAkB,UAAU,IAAI,GAAG;AACtC,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,OAAO,UAAU,UAAU,KAAK;AAAA,MAC3C,SAAS,kCAAkC,KAAK;AAAA,MAChD,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,QAA6B;AAAA,IACjC,MAAM,UAAU;AAAA,IAChB,MAAM,UAAU;AAAA,EAClB;AACA,MAAI,OAAO,UAAU,SAAS,SAAU,OAAM,OAAO,UAAU;AAC/D,MAAI,OAAO,UAAU,eAAe,SAAU,OAAM,aAAa,UAAU;AAC3E,MAAI,OAAO,UAAU,aAAa,SAAU,OAAM,WAAW,UAAU;AACvE,MAAI,OAAO,UAAU,kBAAkB,SAAU,OAAM,gBAAgB,UAAU;AACjF,SAAO;AACT;AAEA,SAAS,kBAAkB,OAA0C;AACnE,SAAO,UAAU,UAAU,UAAU,eAAe,UAAU,aAAa,UAAU;AACvF;AAEA,SAAS,aAAa,UAA4D;AAChF,QAAM,MAAM,oBAAI,IAAiC;AACjD,aAAW,SAAS,SAAS,QAAS,KAAI,IAAI,MAAM,MAAM,KAAK;AAC/D,SAAO;AACT;AAEA,SAAS,sBAAsB,OAA4B,MAA2B;AACpF,QAAMC,gBAAe,SAAS,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,MAAM,IAAI;AACrE,QAAM,SAAsB;AAAA,IAC1B,MAAM,WAAW,MAAM,IAAI;AAAA,IAC3B,MAAMA;AAAA,IACN,MAAM,MAAM;AAAA,EACd;AACA,MAAI,MAAM,SAAS,OAAW,QAAO,OAAO,MAAM;AAClD,MAAI,MAAM,eAAe,QAAW;AAClC,UAAM,SAAS,IAAI,KAAK,MAAM,UAAU;AACxC,QAAI,CAAC,OAAO,MAAM,OAAO,QAAQ,CAAC,EAAG,QAAO,aAAa;AAAA,EAC3D;AACA,MAAI,MAAM,aAAa,OAAW,QAAO,WAAW,MAAM;AAC1D,MAAI,MAAM,kBAAkB,OAAW,QAAO,gBAAgB,MAAM;AACpE,SAAO;AACT;AAEA,SAAS,WAAWD,OAAsB;AACxC,QAAM,WAAWA,MAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/C,SAAO,SAAS,WAAW,IAAI,MAAO,SAAS,SAAS,SAAS,CAAC,KAAK;AACzE;AAEA,SAAS,uBACP,QACA,aACA,SACwB;AACxB,QAAM,UAAkC,CAAC;AACzC,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,oBAAoB,QAAQ,qBAAqB;AACvD,QAAM,kBAAkB,QAAQ,mBAAmB;AACnD,QAAM,YAAY,QAAQ,yBAAyB;AAEnD,MAAI,OAAO,SAAS,YAAY,KAAM,SAAQ,KAAK,MAAM;AAEzD,MACE,eACA,OAAO,SAAS,UAChB,YAAY,SAAS,UACrB,OAAO,SAAS,UAChB,YAAY,SAAS,UACrB,OAAO,SAAS,YAAY,MAC5B;AACA,YAAQ,KAAK,MAAM;AAAA,EACrB;AAEA,MAAI,qBAAqBE,uBAAsB,QAAQ,aAAa,SAAS,GAAG;AAC9E,YAAQ,KAAK,YAAY;AAAA,EAC3B;AAEA,MACE,mBACA,OAAO,aAAa,UACpB,YAAY,aAAa,UACzB,OAAO,aAAa,YAAY,UAChC;AACA,YAAQ,KAAK,UAAU;AAAA,EACzB;AAEA,SAAO;AACT;AAEA,SAASA,uBACP,QACA,aACA,aACS;AACT,MAAI,OAAO,eAAe,UAAa,YAAY,eAAe,OAAW,QAAO;AACpF,QAAM,aAAa,KAAK,MAAM,OAAO,UAAU;AAC/C,QAAM,kBAAkB,KAAK,MAAM,YAAY,UAAU;AACzD,MAAI,OAAO,MAAM,UAAU,KAAK,OAAO,MAAM,eAAe,EAAG,QAAO;AACtE,SAAO,KAAK,IAAI,aAAa,eAAe,IAAI;AAClD;;;AC5ZA,SAAS,qBAAqB;AAMvB,SAAS,aAAa,eAAgC;AAC3D,MAAI,OAAO,YAAY,eAAe,CAAC,QAAQ,QAAQ,QAAQ,KAAK,SAAS,GAAG;AAC9E,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,QAAQ,KAAK,CAAC,MAAM,cAAc,aAAa;AAAA,EACxD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC3BA,SAAS,UAAAC,gBAAc;;;ACAvB,SAAS,UAAAC,eAAc;AAMhB,IAAM,gBAAN,MAAoB;AAAA,EAGzB,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAArB;AAAA,EAFrB,SAAS;AAAA,EAIjB,IAAI,YAAoB;AACtB,WAAO,KAAK,OAAO,SAAS,KAAK;AAAA,EACnC;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA,EAEA,WAAmB;AACjB,SAAK,gBAAgB,GAAG,MAAM;AAC9B,UAAM,QAAQ,KAAK,OAAO,KAAK,MAAM;AACrC,SAAK,UAAU;AACf,WAAO;AAAA,EACT;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK,SAAS,MAAM;AAAA,EAC7B;AAAA,EAEA,UAAU,QAAwB;AAChC,SAAK,gBAAgB,QAAQ,OAAO;AACpC,UAAM,OAAO,KAAK,OAAO,SAAS,KAAK,QAAQ,KAAK,SAAS,MAAM;AACnE,SAAK,UAAU;AACf,WAAOC,QAAO,KAAK,IAAI;AAAA,EACzB;AAAA,EAEA,aAAqB;AACnB,SAAK,gBAAgB,GAAG,QAAQ;AAChC,UAAM,SAASA,QAAO,KAAK,KAAK,MAAM;AACtC,UAAM,QAAQ,OAAO,aAAa,KAAK,MAAM;AAC7C,SAAK,UAAU;AACf,WAAO;AAAA,EACT;AAAA,EAEA,aAAqB;AACnB,SAAK,gBAAgB,GAAG,QAAQ;AAChC,UAAM,SAASA,QAAO,KAAK,KAAK,MAAM;AACtC,UAAM,QAAQ,OAAO,gBAAgB,KAAK,MAAM;AAChD,SAAK,UAAU;AACf,WAAO;AAAA,EACT;AAAA,EAEA,aAAqB;AACnB,UAAM,SAAS,KAAK,WAAW;AAC/B,SAAK,gBAAgB,QAAQ,QAAQ;AACrC,UAAM,OAAO,KAAK,OAAO,SAAS,KAAK,QAAQ,KAAK,SAAS,MAAM;AACnE,SAAK,UAAU;AACf,WAAOA,QAAO,KAAK,IAAI;AAAA,EACzB;AAAA,EAEA,iBAAyB;AACvB,WAAO,KAAK,WAAW,EAAE,SAAS,MAAM;AAAA,EAC1C;AAAA,EAEA,eAAyB;AACvB,UAAM,QAAQ,KAAK,WAAW,EAAE,SAAS,OAAO;AAEhD,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO,CAAC;AAAA,IACV;AAEA,WAAO,MAAM,MAAM,GAAG,EAAE,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAoB;AAClB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA,EAEA,iBAAuB;AACrB,QAAI,KAAK,cAAc,GAAG;AACxB,YAAM,IAAI,WAAW;AAAA,QACnB,SAAS,EAAE,WAAW,KAAK,UAAU;AAAA,QACrC,SAAS;AAAA,QACT,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,gBAAgB,OAAe,MAAoB;AACzD,QAAI,KAAK,aAAa,OAAO;AAC3B;AAAA,IACF;AAEA,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS;AAAA,QACP,WAAW,KAAK;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,MACA,SAAS,8CAA8C,IAAI;AAAA,MAC3D,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACF;;;AC5GA,SAAS,UAAAC,eAAc;AAGvB,IAAM,aAAa;AACnB,IAAM,cAAc,MAAM,OAAO;AAK1B,IAAM,gBAAN,MAAoB;AAAA,EACR,SAAmB,CAAC;AAAA,EAC7B,SAAS;AAAA,EAEjB,UAAU,OAAqB;AAC7B,SAAK,WAAW,OAAO,MAAM;AAC7B,UAAM,QAAQC,QAAO,MAAM,CAAC;AAC5B,UAAM,WAAW,OAAO,CAAC;AACzB,WAAO,KAAK,KAAK,KAAK;AAAA,EACxB;AAAA,EAEA,aAAa,OAAsB;AACjC,WAAO,KAAK,UAAU,QAAQ,IAAI,CAAC;AAAA,EACrC;AAAA,EAEA,WAAW,OAAyB;AAClC,WAAO,KAAK,KAAKA,QAAO,KAAK,KAAK,CAAC;AAAA,EACrC;AAAA,EAEA,YAAY,OAAqB;AAC/B,QAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,YAAY;AAC/D,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,EAAE,MAAM;AAAA,QACjB,SAAS;AAAA,QACT,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,QAAQA,QAAO,MAAM,CAAC;AAC5B,UAAM,cAAc,OAAO,CAAC;AAC5B,WAAO,KAAK,KAAK,KAAK;AAAA,EACxB;AAAA,EAEA,YAAY,OAAqB;AAC/B,QAAI,QAAQ,MAAM,QAAQ,YAAY;AACpC,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,EAAE,OAAO,MAAM,SAAS,EAAE;AAAA,QACnC,SAAS;AAAA,QACT,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,QAAQA,QAAO,MAAM,CAAC;AAC5B,UAAM,iBAAiB,OAAO,CAAC;AAC/B,WAAO,KAAK,KAAK,KAAK;AAAA,EACxB;AAAA,EAEA,YAAY,OAA4B,WAA2B,QAAc;AAC/E,UAAM,UAAU,OAAO,UAAU,WAAWA,QAAO,KAAK,OAAO,QAAQ,IAAIA,QAAO,KAAK,KAAK;AAC5F,SAAK,YAAY,QAAQ,MAAM;AAC/B,WAAO,KAAK,KAAK,OAAO;AAAA,EAC1B;AAAA,EAEA,WAAW,OAAyB;AAClC,UAAM,aAAa,uBAAuB,KAAK;AAC/C,SAAK,YAAY,WAAW,MAAM;AAClC,WAAO,KAAK,KAAK,UAAU;AAAA,EAC7B;AAAA,EAEA,cAAc,QAAiC;AAC7C,eAAW,QAAQ,QAAQ;AACzB,UAAI,KAAK,SAAS,GAAG,GAAG;AACtB,cAAM,IAAI,mBAAmB;AAAA,UAC3B,SAAS,EAAE,KAAK;AAAA,UAChB,SAAS;AAAA,UACT,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,KAAK,YAAY,OAAO,KAAK,GAAG,GAAG,OAAO;AAAA,EACnD;AAAA,EAEA,WAAmB;AACjB,WAAOA,QAAO,OAAO,KAAK,QAAQ,KAAK,MAAM;AAAA,EAC/C;AAAA,EAEQ,KAAK,OAAqB;AAChC,SAAK,OAAO,KAAK,KAAK;AACtB,SAAK,UAAU,MAAM;AACrB,WAAO;AAAA,EACT;AAAA,EAEQ,WAAW,OAAe,OAAqB;AACrD,QAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,KAAM;AACzD,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,EAAE,MAAM;AAAA,QACjB,SAAS,OAAO,KAAK;AAAA,QACrB,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,SAAS,uBAAuB,OAA2B;AACzD,QAAM,QAAQA,QAAO,KAAK,KAAK;AAE/B,MAAI,SAAS;AACb,SAAO,SAAS,MAAM,UAAU,MAAM,MAAM,MAAM,GAAM;AACtD,cAAU;AAAA,EACZ;AAEA,MAAI,UAAU,MAAM,QAAQ;AAC1B,WAAOA,QAAO,MAAM,CAAC;AAAA,EACvB;AAEA,QAAM,WAAW,MAAM,SAAS,MAAM;AACtC,OAAK,SAAS,CAAC,IAAK,SAAU,KAAM;AAClC,WAAOA,QAAO,OAAO,CAACA,QAAO,KAAK,CAAC,CAAI,CAAC,GAAG,QAAQ,CAAC;AAAA,EACtD;AAEA,SAAO;AACT;;;ACzHA,SAAS,UAAAC,gBAAc;;;ACiChB,IAAM,oCAAuE;AAAA,EAClF,2BAA2B,CAAC,MAAM;AAAA,EAClC,2BAA2B,CAAC,MAAM;AAAA,EAClC,0BAA0B;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,0BAA0B;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe,CAAC,qBAAqB,8BAA8B;AAAA,EACnE,yBAAyB,CAAC;AAAA,EAC1B,yBAAyB,CAAC;AAAA,EAC1B,mBAAmB,CAAC,iBAAiB,eAAe;AAAA,EACpD,mBAAmB,CAAC,iBAAiB,eAAe;AAAA,EACpD,yBAAyB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAKO,SAAS,uBACd,QACA,QACyB;AACzB,QAAM,yBAAyB;AAAA,IAC7B;AAAA,IACA,OAAO;AAAA,IACP,OAAO;AAAA,EACT;AACA,QAAM,yBAAyB;AAAA,IAC7B;AAAA,IACA,OAAO;AAAA,IACP,OAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,2BAA2B;AAAA,MACzB;AAAA,MACA,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA,2BAA2B;AAAA,MACzB;AAAA,MACA,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA,0BAA0B;AAAA,MACxB;AAAA,MACA,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA,0BAA0B;AAAA,MACxB;AAAA,MACA,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA,cAAc,eAAe,OAAO,OAAO,eAAe,OAAO,aAAa;AAAA,IAC9E,GAAI,2BAA2B,SAAY,CAAC,IAAI,EAAE,uBAAuB;AAAA,IACzE,GAAI,2BAA2B,SAAY,CAAC,IAAI,EAAE,uBAAuB;AAAA,IACzE,mBAAmB;AAAA,MACjB;AAAA,MACA,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA,mBAAmB;AAAA,MACjB;AAAA,MACA,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA,wBAAwB;AAAA,MACtB;AAAA,MACA,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,eACP,OACA,WACA,WACQ;AACR,QAAM,WAAW,UAAU,KAAK,CAAC,cAAc,UAAU,SAAS,SAAS,CAAC;AAE5E,MAAI,aAAa,QAAW;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,wBAAwB;AAAA,IAChC,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,IACA,SAAS,2BAA2B,KAAK;AAAA,IACzC,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,eACP,OACA,WACA,WACoB;AACpB,MAAI,UAAU,WAAW,KAAK,UAAU,WAAW,GAAG;AACpD,WAAO;AAAA,EACT;AAEA,SAAO,eAAe,OAAO,WAAW,SAAS;AACnD;;;AC3JA,IAAM,mBAAmB;AACzB,IAAM,uBAAuB;AAatB,SAAS,2BAA2B,SAIhC;AACT,QAAM,kBAAkB,QAAQ,mBAAmB;AAEnD,MAAI,gBAAgB,KAAK,EAAE,WAAW,KAAK,QAAQ,gBAAgB,KAAK,EAAE,WAAW,GAAG;AACtF,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,OAAO,GAAG,gBAAgB,GAAG,eAAe,IAAI,QAAQ,eAAe;AAC7E,MAAI,QAAQ,aAAa,UAAa,QAAQ,SAAS,WAAW,GAAG;AACnE,WAAO;AAAA,EACT;AAEA,SAAO,GAAG,IAAI,IAAI,QAAQ,QAAQ;AACpC;AAKO,SAAS,2BAA2B,MAAiC;AAC1E,MAAI,CAAC,KAAK,WAAW,gBAAgB,GAAG;AACtC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,KAAK;AAAA,MAChB,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,QAAM,SAAS,eAAe,KAAK,OAAO,KAAK,MAAM,GAAG,UAAU;AAClE,QAAM,WAAW,eAAe,KAAK,SAAY,KAAK,MAAM,aAAa,CAAC;AAC1E,QAAM,cAAc,OAAO,MAAM,GAAG;AAEpC,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,KAAK;AAAA,MAChB,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,kBAAkB,YAAY,CAAC,KAAK;AAC1C,QAAM,kBAAkB,YAAY,MAAM,CAAC,EAAE,KAAK,GAAG;AAErD,MAAI,gBAAgB,WAAW,KAAK,gBAAgB,WAAW,GAAG;AAChE,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,KAAK;AAAA,MAChB,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL,GAAI,aAAa,UAAa,SAAS,WAAW,IAAI,CAAC,IAAI,EAAE,SAAS;AAAA,EACxE;AACF;;;AChFA,SAAS,UAAAC,eAAc;AACvB,SAAS,mBAAmB;AAK5B,IAAM,kBAAkB;AACxB,IAAM,wBAAwB;AAavB,SAAS,wBAAwB,SAI7B;AACT,QAAM,SACJ,QAAQ,WAAW,SAAY,YAAY,qBAAqB,IAAIC,QAAO,KAAK,QAAQ,MAAM;AAEhG,MAAI,OAAO,WAAW,uBAAuB;AAC3C,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,cAAc,OAAO,QAAQ,gBAAgB,sBAAsB;AAAA,MAC9E,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,IAAI,cAAc;AACjC,SAAO,UAAU,eAAe;AAChC,SAAO,WAAW,MAAM;AACxB,SAAO,cAAc,QAAQ,WAAW,aAAa;AACrD,SAAO,cAAc,QAAQ,WAAW,uBAAuB;AAC/D,SAAO,cAAc,QAAQ,WAAW,wBAAwB;AAChE,SAAO,cAAc,QAAQ,WAAW,wBAAwB;AAChE,SAAO,cAAc,QAAQ,WAAW,iBAAiB;AACzD,SAAO,cAAc,QAAQ,WAAW,iBAAiB;AACzD,SAAO,cAAc,QAAQ,WAAW,yBAAyB;AACjE,SAAO,cAAc,QAAQ,WAAW,yBAAyB;AACjE,SAAO,cAAc,QAAQ,WAAW,uBAAuB;AAC/D,SAAO,cAAc,QAAQ,WAAW,uBAAuB;AAC/D,SAAO,aAAa,QAAQ,yBAAyB,KAAK;AAC1D,SAAO,YAAY,CAAC;AACpB,SAAO,OAAO,SAAS;AACzB;AAKO,SAAS,wBAAwB,SAAwC;AAC9E,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,cAAc,OAAO,SAAS;AAEpC,MAAI,gBAAgB,iBAAiB;AACnC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,YAAY;AAAA,MACvB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,OAAO,UAAU,qBAAqB;AACrD,QAAM,gBAAgB,OAAO,aAAa;AAC1C,QAAM,0BAA0B,OAAO,aAAa;AACpD,QAAM,2BAA2B,OAAO,aAAa;AACrD,QAAM,2BAA2B,OAAO,aAAa;AACrD,QAAM,oBAAoB,OAAO,aAAa;AAC9C,QAAM,oBAAoB,OAAO,aAAa;AAC9C,QAAM,4BAA4B,OAAO,aAAa;AACtD,QAAM,4BAA4B,OAAO,aAAa;AACtD,QAAM,0BAA0B,OAAO,aAAa;AACpD,QAAM,0BAA0B,OAAO,aAAa;AACpD,QAAM,wBAAwB,OAAO,YAAY;AACjD,QAAM,WAAW,OAAO,WAAW;AAEnC,SAAO,eAAe;AAEtB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACvGA,SAAS,UAAAC,eAAc;AACvB,SAAS,iBAAiB,eAAe,2BAA2C;AAIpF,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,2BAA2B;AAGjC,IAAM,qBAAqBC,QAAO,KAAK,4BAA4B,KAAK;AAmBjE,SAAS,4BAGd;AACA,QAAM,EAAE,YAAY,UAAU,IAAI,oBAAoB,QAAQ;AAC9D,QAAM,mBAAmB,yBAAyB,SAAS;AAE3D,SAAO;AAAA,IACL,oBAAoB,CAAC,oBAAoB;AACvC,YAAM,OAAO,yBAAyB,eAAe;AACrD,aAAO,cAAc,EAAE,YAAY,WAAW,KAAK,CAAC;AAAA,IACtD;AAAA,IACA,WAAW;AAAA,EACb;AACF;AAKO,SAAS,4BAA4B,WAA+B;AACzE,QAAM,aAAa,yBAAyB,WAAW,QAAQ;AAC/D,SAAO,IAAI,cAAc,EAAE,UAAU,qBAAqB,EAAE,YAAY,UAAU,EAAE,SAAS;AAC/F;AA4CO,SAAS,6BAA6B,SAA6C;AACxF,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,cAAc,OAAO,SAAS;AAEpC,MAAI,gBAAgB,wBAAwB;AAC1C,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,YAAY;AAAA,MACvB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,OAAO,WAAW;AAClC,QAAM,kBAAkB,yBAAyB,OAAO,WAAW,GAAG,QAAQ;AAC9E,QAAM,YAAY,OAAO,WAAW;AACpC,SAAO,eAAe;AAEtB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,yBAAyB,WAA8B;AAC9D,QAAM,MAAM,UAAU,OAAO,EAAE,QAAQ,OAAO,MAAM,OAAO,CAAC;AAC5D,QAAM,MAAM,IAAI,SAAS,IAAI,SAAS,wBAAwB;AAC9D,SAAO,yBAAyB,KAAK,QAAQ;AAC/C;AAEA,SAAS,yBAAyB,KAA4B;AAC5D,QAAM,aAAa,yBAAyB,KAAK,QAAQ;AACzD,QAAM,MAAMC,QAAO,OAAO,CAAC,oBAAoB,UAAU,CAAC;AAC1D,SAAO,gBAAgB;AAAA,IACrB,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,MAAM;AAAA,EACR,CAAC;AACH;AAEA,SAAS,yBAAyB,OAAmB,OAAoC;AACvF,QAAM,MAAMA,QAAO,KAAK,KAAK;AAC7B,MAAI,IAAI,WAAW,0BAA0B;AAC3C,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,WAAW,IAAI,QAAQ,MAAM;AAAA,MACxC,SAAS,OAAO,KAAK;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACrJA,SAAS,UAAAC,gBAAc;AACvB,SAAS,kBAAkB;AAqCpB,SAAS,qBAAqB,OAAoD;AACvF,QAAM,gBAAgB,wBAAwB,MAAM,YAAY;AAChE,QAAM,eAAe,8BAA8B,OAAO,aAAa;AACvE,QAAM,YAAY;AAElB,QAAM,sBAAsB;AAAA,IAC1B,MAAM,qBAAqB;AAAA,EAC7B;AACA,QAAM,sBAAsB;AAAA,IAC1B,MAAM,qBAAqB;AAAA,EAC7B;AACA,QAAM,cAAc,gBAAgB,MAAM,qBAAqB,wBAAwB;AACvF,QAAM,cAAc,gBAAgB,MAAM,qBAAqB,wBAAwB;AACvF,QAAM,eAAe;AAAA,IACnB,MAAM,qBAAqB;AAAA,IAC3B,MAAM,qBAAqB;AAAA,EAC7B;AACA,QAAM,eAAe;AAAA,IACnB,MAAM,qBAAqB;AAAA,IAC3B,MAAM,qBAAqB;AAAA,EAC7B;AAEA,QAAM,eAAeC,SAAO,KAAK,MAAM,YAAY;AAEnD,SAAO;AAAA,IACL,gBAAgB;AAAA,MACd,eAAe;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,IAAI,eAAe,cAAc,cAAc,WAAW,KAAK,aAAa,aAAa;AAAA,MACzF,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,MACd,eAAe;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,IAAI,eAAe,cAAc,cAAc,WAAW,KAAK,aAAa,aAAa;AAAA,MACzF,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,8BACP,OACA,eACQ;AACR,QAAM,aAAa,IAAI,cAAc,EAClC,YAAY,MAAM,sBAAsB,OAAO,EAC/C,YAAY,MAAM,sBAAsB,OAAO,EAC/C,YAAY,MAAM,oBAAoB,EACtC,YAAY,MAAM,oBAAoB,EACtC,YAAY,MAAM,aAAa,EAC/B,YAAY,MAAM,eAAe,EACjC,YAAY,MAAM,eAAe,EACjC,WAAW,MAAM,YAAY,EAC7B,SAAS;AAEZ,SAAO,WAAW,aAAa,EAAE,OAAO,UAAU,EAAE,OAAO;AAC7D;AAEA,SAAS,eACP,cACA,cACA,WACA,QACA,QACA,eACQ;AACR,MAAI,UAAU,GAAG;AACf,WAAOA,SAAO,MAAM,CAAC;AAAA,EACvB;AAEA,QAAM,SAAmB,CAAC;AAE1B,QAAMC,SAAQ,WAAW,aAAa,EACnC;AAAA,IACC,IAAI,cAAc,EACf,WAAW,YAAY,EACvB,WAAW,YAAY,EACvB,UAAU,OAAO,WAAW,CAAC,CAAC,EAC9B,WAAW,SAAS,EACpB,SAAS;AAAA,EACd,EACC,OAAO;AACV,SAAO,KAAKA,MAAK;AAEjB,SAAOD,SAAO,OAAO,MAAM,EAAE,SAAS,QAAQ;AAC5C,UAAM,WAAWA,SAAO,OAAO,MAAM;AACrC,UAAM,OAAO,WAAW,aAAa,EAClC;AAAA,MACC,IAAI,cAAc,EACf,WAAW,YAAY,EACvB,WAAW,YAAY,EACvB,WAAW,QAAQ,EACnB,SAAS;AAAA,IACd,EACC,OAAO;AACV,WAAO,KAAK,IAAI;AAAA,EAClB;AAEA,SAAOA,SAAO,OAAO,MAAM,EAAE,SAAS,GAAG,MAAM;AACjD;AAEA,SAAS,wBAAwB,cAAgC;AAC/D,MAAI,iBAAiB,uBAAuB,iBAAiB,gCAAgC;AAC3F,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,cAAc;AAAA,IACtB,SAAS,EAAE,aAAa;AAAA,IACxB,SAAS;AAAA,IACT,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,2BAA2B,WAA2B;AAC7D,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,UAAU;AAAA,QACrB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,EACL;AACF;AAEA,SAAS,gBAAgB,WAA2B;AAClD,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,UAAU;AAAA,QACrB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,EACL;AACF;AAEA,SAAS,oBAAoB,qBAA6B,cAA8B;AACtF,MACE,oBAAoB,SAAS,kBAAkB,KAC/C,wBAAwB,iCACxB;AACA,WAAO;AAAA,EACT;AAEA,UAAQ,cAAc;AAAA,IACpB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,aAAa;AAAA,QACxB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,EACL;AACF;;;AC/OO,IAAM,kBAAkB;AAKxB,SAAS,0BAAkC;AAChD,SAAO,OAAO,KAAK,CAAC,eAAe,CAAC;AACtC;AAKO,SAAS,wBAAwB,SAA8C;AACpF,MAAI,QAAQ,WAAW,KAAK,QAAQ,CAAC,MAAM,iBAAiB;AAC1D,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ,QAAQ,QAAQ,aAAa,QAAQ,CAAC,EAAE;AAAA,MAC3D,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,aAAa,gBAAgB;AACxC;;;ACzBA,SAAS,UAAAE,gBAAc;AACvB,SAAS,eAAAC,oBAAmB;AAG5B,IAAM,qBAAqB;AAC3B,IAAM,oBAAoB,IAAI;AAQvB,IAAM,wBAAwB,MAAM;AAYpC,SAAS,yBACd,SACA,UAGI,CAAC,GACG;AACR,QAAM,OAAOC,SAAO,KAAK,OAAO;AAChC,QAAM,YAAY,mBAAmB,QAAQ,aAAa,CAAC;AAI3D,MAAI,gBAAgB;AACpB,UAAQ,IAAI,KAAK,SAAS,gBAAgB,KAAK,cAAc,GAAG;AAC9D,qBAAiB;AAAA,EACnB;AAEA,QAAM,UACJ,QAAQ,kBAAkB,QAAQA,SAAO,MAAM,aAAa,IAAIC,aAAY,aAAa;AAC3F,QAAM,eAAe,IAAI,KAAK,SAAS;AAIvC,QAAM,QAAQD,SAAO,MAAM,IAAI,YAAY;AAE3C,QAAM,cAAc,cAAc,CAAC;AACnC,QAAM,WAAW,eAAe,CAAC;AACjC,OAAK,KAAK,OAAO,CAAC;AAClB,UAAQ,KAAK,OAAO,IAAI,KAAK,MAAM;AAEnC,SAAO;AACT;AAKO,SAAS,yBAAyB,OAAuC;AAC9E,QAAM,QAAQA,SAAO,KAAK,KAAK;AAC/B,MAAI,MAAM,SAAS,IAAI,mBAAmB;AACxC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ,MAAM,OAAO;AAAA,MAChC,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,eAAe,MAAM,aAAa,CAAC;AACzC,MAAI,eAAe,mBAAmB;AACpC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,aAAa;AAAA,MACxB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,IAAI;AACxB,MAAI,MAAM,WAAW,aAAa;AAChC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,cAAc,MAAM,QAAQ,gBAAgB,YAAY;AAAA,MACnE,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,MAAM,UAAU,CAAC;AACvC,MAAI,gBAAgB,oBAAoB;AACtC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,cAAc;AAAA,MACzB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,eAAe,IAAI;AACzC,MAAI,gBAAgB,GAAG;AACrB,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,cAAc,cAAc;AAAA,MACvC,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,eAAe;AACrB,QAAM,aAAa,eAAe;AAElC,SAAO;AAAA,IACL,SAAS,MAAM,SAAS,YAAY,aAAa,aAAa;AAAA,IAC9D;AAAA,IACA,SAAS,MAAM,SAAS,cAAc,UAAU;AAAA,EAClD;AACF;AAKO,IAAM,2BAAN,MAA+B;AAAA,EAC5B,UAAUA,SAAO,MAAM,CAAC;AAAA,EAEhC,KAAK,OAAyC;AAC5C,SAAK,UAAUA,SAAO,OAAO,CAAC,KAAK,SAASA,SAAO,KAAK,KAAK,CAAC,CAAC;AAC/D,UAAM,UAAgC,CAAC;AAEvC,WAAO,KAAK,QAAQ,UAAU,GAAG;AAC/B,YAAM,eAAe,KAAK,QAAQ,aAAa,CAAC;AAChD,UAAI,eAAe,uBAAuB;AACxC,cAAM,IAAI,WAAW;AAAA,UACnB,SAAS,EAAE,iBAAiB,uBAAuB,aAAa;AAAA,UAChE,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AACA,YAAM,cAAc,IAAI;AAExB,UAAI,KAAK,QAAQ,SAAS,aAAa;AACrC;AAAA,MACF;AAEA,YAAM,QAAQ,KAAK,QAAQ,SAAS,GAAG,WAAW;AAClD,cAAQ,KAAK,yBAAyB,KAAK,CAAC;AAC5C,WAAK,UAAU,KAAK,QAAQ,SAAS,WAAW;AAAA,IAClD;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,wBAAgC;AAC9B,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA,EAGA,qBAA6B;AAC3B,UAAM,YAAYA,SAAO,KAAK,KAAK,OAAO;AAC1C,SAAK,UAAUA,SAAO,MAAM,CAAC;AAC7B,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,WAA2B;AACrD,MAAI,CAAC,OAAO,UAAU,SAAS,KAAK,YAAY,KAAK,YAAY,KAAK;AACpE,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,EAAE,UAAU;AAAA,MACrB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACxKA,SAAS,UAAAE,gBAAc;AACvB,SAAS,cAAAC,aAAY,mBAAAC,kBAAiB,UAAU,oBAAoC;AAIpF,IAAM,yBAAyB;AAE/B,IAAM,sBAAsBC,SAAO,KAAK,4BAA4B,KAAK;AAQlE,SAAS,0BAA0B,OAIW;AACnD,QAAM,EAAE,eAAe,UAAU,IAAI,aAAa,MAAM,WAAW;AACnE,QAAM,EAAE,oBAAoB,eAAe,IAAI,mBAAmB,MAAM,aAAa;AAErF,MAAI,CAAC,+BAA+B,eAAe,kBAAkB,GAAG;AACtE,UAAM,IAAI,cAAc;AAAA,MACtB,SAAS,EAAE,kBAAkB,eAAe,mBAAmB;AAAA,MAC/D,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,gBAAgB;AAAA,IAC/B,MAAMA,SAAO,KAAK,MAAM,YAAY;AAAA,IACpC;AAAA,IACA,WAAWA,SAAO,KAAK,cAAc;AAAA,IACrC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,cAAc;AAAA,MACtB,SAAS,EAAE,mBAAmB;AAAA,MAC9B,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgBC,YAAW,QAAQ,EAAE,OAAO,MAAM,WAAW,EAAE,OAAO;AAC5E,SAAO,EAAE,eAAe,cAAc;AACxC;AAOA,SAAS,aAAa,MAAiC;AACrD,QAAM,SAAS,IAAI,cAAc,IAAI;AACrC,QAAM,gBAAgB,OAAO,WAAW,EAAE,SAAS,OAAO;AAE1D,UAAQ,eAAe;AAAA,IACrB,KAAK,eAAe;AAClB,YAAM,MAAM,OAAO,WAAW;AAC9B,aAAO,eAAe;AACtB,UAAI,IAAI,WAAW,wBAAwB;AACzC,cAAM,IAAI,cAAc;AAAA,UACtB,SAAS,EAAE,cAAc,IAAI,QAAQ,gBAAgB,uBAAuB;AAAA,UAC5E,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AACA,YAAM,OAAOD,SAAO,OAAO,CAAC,qBAAqB,GAAG,CAAC;AACrD,aAAO;AAAA,QACL;AAAA,QACA,WAAWE,iBAAgB,EAAE,QAAQ,OAAO,KAAK,MAAM,MAAM,OAAO,CAAC;AAAA,MACvE;AAAA,IACF;AAAA,IAEA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,WAAW;AAEd,YAAM,IAAI,OAAO,UAAU;AAC3B,YAAM,IAAI,OAAO,UAAU;AAC3B,aAAO,eAAe;AACtB,aAAO;AAAA,QACL;AAAA,QACA,WAAW,2BAA2B,GAAG,CAAC;AAAA,MAC5C;AAAA,IACF;AAAA,IAEA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,uBAAuB;AAG1B,YAAM,kBAAkB,OAAO,WAAW,EAAE,SAAS,OAAO;AAC5D,YAAM,qBAAqB,cAAc,MAAM,cAAc,MAAM;AACnE,UAAI,oBAAoB,oBAAoB;AAC1C,cAAM,IAAI,cAAc;AAAA,UACtB,SAAS,EAAE,eAAe,gBAAgB;AAAA,UAC1C,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AACA,YAAM,QAAQ,OAAO,WAAW;AAChC,aAAO,eAAe;AACtB,aAAO;AAAA,QACL;AAAA,QACA,WAAW,wBAAwB,iBAAiB,KAAK;AAAA,MAC3D;AAAA,IACF;AAAA,IAEA;AACE,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,cAAc;AAAA,QACzB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,EACL;AACF;AAOA,SAAS,mBAAmB,MAAuC;AACjE,QAAM,SAAS,IAAI,cAAc,IAAI;AACrC,QAAM,qBAAqB,OAAO,WAAW,EAAE,SAAS,OAAO;AAC/D,QAAM,iBAAiB,OAAO,WAAW;AAGzC,SAAO,EAAE,oBAAoB,eAAe;AAC9C;AAEA,SAAS,+BACP,kBACA,oBACS;AACT,MAAI,qBAAqB,mBAAoB,QAAO;AAEpD,MAAI,qBAAqB,WAAW;AAClC,WAAO,uBAAuB,kBAAkB,uBAAuB;AAAA,EACzE;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAKb;AACV,UAAQ,MAAM,oBAAoB;AAAA,IAChC,KAAK;AAEH,aAAO,aAAa,MAAM,MAAM,MAAM,MAAM,WAAW,MAAM,SAAS;AAAA,IAExE,KAAK;AACH,aAAO,aAAa,UAAU,MAAM,MAAM,MAAM,WAAW,MAAM,SAAS;AAAA,IAE5E,KAAK;AACH,aAAO,aAAa,UAAU,MAAM,MAAM,MAAM,WAAW,MAAM,SAAS;AAAA,IAE5E,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA,MAAM;AAAA,QACN,MAAM;AAAA,QACN,uBAAuB,MAAM,SAAS;AAAA,MACxC;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA,MAAM;AAAA,QACN,MAAM;AAAA,QACN,uBAAuB,MAAM,SAAS;AAAA,MACxC;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA,MAAM;AAAA,QACN,MAAM;AAAA,QACN,uBAAuB,MAAM,SAAS;AAAA,MACxC;AAAA,IAEF,KAAK;AAEH,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IAEH;AACE,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,oBAAoB,MAAM,mBAAmB;AAAA,QACxD,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,EACL;AACF;AAMA,SAAS,2BAA2B,GAAW,GAAsB;AACnE,QAAM,OAAO,kBAAkB,CAAC;AAChC,QAAM,OAAO,kBAAkB,CAAC;AAChC,QAAM,kBAAkB,mBAAmBF,SAAO,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;AAEtE,QAAM,mBAAmBA,SAAO,OAAO,CAACA,SAAO,KAAK,CAAC,CAAI,CAAC,GAAG,eAAe,CAAC;AAC7E,QAAM,YAAYA,SAAO,OAAO;AAAA,IAC9BA,SAAO,KAAK,CAAC,CAAI,CAAC;AAAA,IAClB,iBAAiB,iBAAiB,MAAM;AAAA,IACxC;AAAA,EACF,CAAC;AAED,QAAM,SAASA,SAAO,KAAK,kCAAkC,QAAQ,QAAQ,EAAE,GAAG,KAAK;AACvF,QAAM,OAAO,mBAAmBA,SAAO,OAAO,CAAC,QAAQ,SAAS,CAAC,CAAC;AAClE,SAAOE,iBAAgB,EAAE,QAAQ,OAAO,KAAK,MAAM,MAAM,OAAO,CAAC;AACnE;AAEA,SAAS,kBAAkB,OAAuB;AAEhD,MAAI,OAAO;AACX,SAAO,KAAK,SAAS,KAAK,KAAK,CAAC,MAAM,EAAM,QAAO,KAAK,SAAS,CAAC;AAElE,MAAI,KAAK,SAAS,MAAM,KAAK,CAAC,IAAK,SAAU,GAAG;AAC9C,WAAOF,SAAO,OAAO,CAACA,SAAO,KAAK,CAAC,CAAI,CAAC,GAAG,IAAI,CAAC;AAAA,EAClD;AACA,SAAOA,SAAO,OAAO,CAACA,SAAO,KAAK,CAAC,CAAI,CAAC,GAAG,iBAAiB,KAAK,MAAM,GAAG,IAAI,CAAC;AACjF;AAEA,SAAS,mBAAmB,SAAyB;AACnD,SAAOA,SAAO,OAAO,CAACA,SAAO,KAAK,CAAC,EAAI,CAAC,GAAG,iBAAiB,QAAQ,MAAM,GAAG,OAAO,CAAC;AACvF;AAEA,SAAS,iBAAiB,QAAwB;AAChD,MAAI,SAAS,IAAM,QAAOA,SAAO,KAAK,CAAC,MAAM,CAAC;AAC9C,QAAM,QAAkB,CAAC;AACzB,MAAI,IAAI;AACR,SAAO,IAAI,GAAG;AACZ,UAAM,QAAQ,IAAI,GAAI;AACtB,WAAO;AAAA,EACT;AACA,SAAOA,SAAO,KAAK,CAAC,MAAO,MAAM,QAAQ,GAAG,KAAK,CAAC;AACpD;AAKA,IAAM,qBAAqB;AAAA,EACzB,UAAU;AAAA;AAAA,EACV,UAAU;AAAA;AAAA,EACV,UAAU;AAAA;AACZ;AAGA,IAAM,0BAA0B;AAMhC,SAAS,wBAAwB,iBAAyB,OAA0B;AAClF,QAAM,SAAS,mBAAmB,eAAkD;AACpF,MAAI,WAAW,QAAW;AACxB,UAAM,IAAI,cAAc;AAAA,MACtB,SAAS,EAAE,gBAAgB;AAAA,MAC3B,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgBA,SAAO,KAAK,0BAA0B,QAAQ,KAAK;AACzE,QAAM,SAAS,mBAAmB,aAAa;AAE/C,QAAM,mBAAmBA,SAAO,OAAO,CAACA,SAAO,KAAK,CAAC,CAAI,CAAC,GAAG,KAAK,CAAC;AACnE,QAAM,YAAYA,SAAO,OAAO;AAAA,IAC9BA,SAAO,KAAK,CAAC,CAAI,CAAC;AAAA,IAClB,iBAAiB,iBAAiB,MAAM;AAAA,IACxC;AAAA,EACF,CAAC;AACD,QAAM,OAAO,mBAAmBA,SAAO,OAAO,CAAC,QAAQ,SAAS,CAAC,CAAC;AAClE,SAAOE,iBAAgB,EAAE,QAAQ,OAAO,KAAK,MAAM,MAAM,OAAO,CAAC;AACnE;AAOA,SAAS,uBAAuB,cAA8B;AAC5D,QAAM,SAAS,IAAI,cAAc,YAAY;AAC7C,QAAM,IAAI,OAAO,UAAU;AAC3B,QAAM,IAAI,OAAO,UAAU;AAG3B,QAAM,OAAO,kBAAkB,CAAC;AAChC,QAAM,OAAO,kBAAkB,CAAC;AAChC,SAAO,mBAAmBF,SAAO,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;AACvD;;;AR5PO,IAAM,wBAAN,MAA4B;AAAA,EAiCjC,YACmB,UAmBb,CAAC,GACL;AApBiB;AAqBjB,SAAK,mBAAmB,QAAQ,cAAc;AAC9C,SAAK,2BAA2B,2BAA2B;AAAA,MACzD,GAAI,QAAQ,mBAAmB,SAAY,CAAC,IAAI,EAAE,UAAU,QAAQ,eAAe;AAAA,MACnF,iBAAiB,QAAQ,yBAAyB;AAAA,IACpD,CAAC;AACD,SAAK,uBAAuB,wBAAwB;AAAA,MAClD,YAAY,KAAK;AAAA,MACjB,GAAI,QAAQ,cAAc,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,UAAU;AAAA,IACzE,CAAC;AAAA,EACH;AAAA,EA9BmB;AAAA,EAjCF;AAAA,EACA;AAAA,EACA;AAAA,EACA,sBAAgC,CAAC;AAAA,EACjC,eAAe,IAAI,yBAAyB;AAAA,EAC5C,wBAAwB,IAAI,6BAA6B;AAAA,EAClE,QAAwB;AAAA,EACxB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB;AAAA,EAMA;AAAA,EAeA;AAAA;AAAA,EAoCR,2BAAmC;AACjC,WAAOG,SAAO,KAAK,GAAG,KAAK,wBAAwB;AAAA,GAAQ,OAAO;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,OAGd;AACA,UAAM,WAAqB,CAAC;AAE5B,QAAI,KAAK,UAAU,kCAAkC;AACnD,YAAM,OAAO,KAAK,sBAAsB,KAAK,KAAK;AAClD,iBAAW,UAAU,KAAK,aAAa;AACrC,aAAK,oBAAoB,KAAK,MAAM;AAAA,MACtC;AAEA,UAAI,KAAK,cAAc,QAAW;AAChC,aAAK,uBAAuB,2BAA2B,KAAK,SAAS;AACrE,aAAK,QAAQ;AACb,iBAAS,KAAK,yBAAyB,KAAK,oBAAoB,CAAC;AACjE,aAAK,uBAAuB;AAE5B,YAAI,KAAK,UAAU,SAAS,GAAG;AAC7B,iBAAO,KAAK,yBAAyB,UAAU,KAAK,SAAS;AAAA,QAC/D;AAAA,MACF;AAEA,aAAO,EAAE,SAAS;AAAA,IACpB;AAEA,WAAO,KAAK,yBAAyB,UAAUA,SAAO,KAAK,KAAK,CAAC;AAAA,EACnE;AAAA,EAEA,uBAA0C;AACxC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,aAAsB;AACpB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,qBAA6B;AAC3B,WAAO,KAAK,aAAa,mBAAmB;AAAA,EAC9C;AAAA,EAEQ,yBACN,UACA,OAIA;AACA,QAAI,KAAK,UAAU,kCAAkC;AACnD,aAAO,EAAE,SAAS;AAAA,IACpB;AAEA,eAAW,UAAU,KAAK,aAAa,KAAK,KAAK,GAAG;AAClD,YAAM,cAAc,OAAO,QAAQ,CAAC;AACpC,WAAK,sBAAsB;AAE3B,UAAI,KAAK,UAAU,2BAA2B;AAC5C,YAAI,gBAAgB,IAAI;AACtB,gBAAM,IAAI,cAAc;AAAA,YACtB,SAAS,EAAE,YAAY;AAAA,YACvB,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAEA,cAAM,gBAAgB,wBAAwB,OAAO,OAAO;AAC5D,cAAM,uBAAuB,uBAAuB,KAAK,kBAAkB,aAAa;AAExF,YACE,qBAAqB,iBAAiB,uBACtC,qBAAqB,iBAAiB,gCACtC;AACA,gBAAM,IAAI,cAAc;AAAA,YACtB,SAAS,EAAE,cAAc,qBAAqB,aAAa;AAAA,YAC3D,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAEA,aAAK,oBAAoB,0BAA0B;AACnD,aAAK,QAAQ;AACb,iBAAS;AAAA,UACP,yBAAyB,4BAA4B,KAAK,kBAAkB,SAAS,CAAC;AAAA,QACxF;AACA,aAAK,uBAAuB;AAG5B,aAAK,qBAAqB;AAAA,UACxB,sBAAsB,KAAK;AAAA,UAC3B,WAAW,qBAAqB;AAAA,UAChC,sBAAsB,KAAK;AAAA,UAC3B,iBAAiB,KAAK,kBAAkB;AAAA,UACxC;AAAA,UACA,eAAeA,SAAO,MAAM,CAAC;AAAA,UAC7B,uBAAuB,KAAK,wBAAwB,iCAAiC,GAClF;AAAA,UACH,sBAAsBA,SAAO,KAAK,OAAO,OAAO;AAAA,UAChD,iBAAiBA,SAAO,MAAM,CAAC;AAAA,UAC/B,iBAAiBA,SAAO,MAAM,CAAC;AAAA,UAC/B,cAAcA,SAAO,MAAM,CAAC;AAAA,QAC9B;AAEA;AAAA,MACF;AAEA,UAAI,KAAK,UAAU,4BAA4B;AAC7C,YAAI,gBAAgB,IAAI;AACtB,gBAAM,IAAI,cAAc;AAAA,YACtB,SAAS,EAAE,YAAY;AAAA,YACvB,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAEA,YAAI,KAAK,sBAAsB,UAAa,KAAK,uBAAuB,QAAW;AACjF,gBAAM,IAAI,cAAc;AAAA,YACtB,SACE;AAAA,YACF,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAEA,cAAM,QAAQ,6BAA6B,OAAO,OAAO;AACzD,cAAM,eAAe,KAAK,kBAAkB,mBAAmB,MAAM,eAAe;AAEpF,aAAK,qBAAqB;AAAA,UACxB,GAAG,KAAK;AAAA,UACR,eAAe,MAAM;AAAA,UACrB,iBAAiB,MAAM;AAAA,UACvB,iBAAiB,MAAM;AAAA,UACvB;AAAA,QACF;AAEA,aAAK,QAAQ;AACb,iBAAS,KAAK,yBAAyB,wBAAwB,CAAC,CAAC;AACjE,aAAK,uBAAuB;AAC5B;AAAA,MACF;AAEA,UAAI,KAAK,UAAU,2BAA2B;AAC5C,gCAAwB,OAAO,OAAO;AAEtC,cAAM,cAAc,KAAK,sBAAsB,+BAA+B;AAC9E,cAAM,cAAc,qBAAqB;AAAA,UACvC,sBAAsB,YAAY;AAAA,UAClC,sBAAsB,YAAY;AAAA,UAClC,iBAAiB,YAAY;AAAA,UAC7B,cAAc,YAAY;AAAA,UAC1B,sBAAsB,YAAY;AAAA,UAClC,eAAe,YAAY;AAAA,UAC3B,sBAAsB,YAAY;AAAA,UAClC,sBAAsB,YAAY;AAAA,UAClC,iBAAiB,YAAY;AAAA,UAC7B,cAAc,YAAY;AAAA,QAC5B,CAAC;AAKD,cAAM,sBAAsB,0BAA0B;AAAA,UACpD,cAAc,YAAY;AAAA,UAC1B,aAAa,YAAY;AAAA,UACzB,eAAe,YAAY;AAAA,QAC7B,CAAC;AAGD,cAAM,aAAa,KAAK,QAAQ;AAChC,YAAI,eAAe,QAAW;AAK5B,gBAAM,QAAQ,WAAW;AAAA,YACvB,eAAe,oBAAoB;AAAA,YACnC,aAAa,YAAY;AAAA,YACzB,eAAe,oBAAoB;AAAA,UACrC,CAAC;AACD,cAAI,iBAAiB,SAAS;AAC5B,kBAAM,IAAI,cAAc;AAAA,cACtB,SACE;AAAA,cACF,UAAU;AAAA,cACV,WAAW;AAAA,YACb,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM,gBAAgB,wBAAwB,YAAY,oBAAoB;AAC9E,cAAM,SAAsC;AAAA,UAC1C,aAAa;AAAA,YACX,WAAW,YAAY;AAAA,YACvB,sBAAsB,YAAY;AAAA,YAClC,iBAAiB,YAAY;AAAA,YAC7B,cAAc,YAAY;AAAA,YAC1B,eAAe,YAAY;AAAA,YAC3B,sBAAsB,YAAY;AAAA,YAClC,iBAAiB,YAAY;AAAA,YAC7B,iBAAiB,YAAY;AAAA,YAC7B,WAAW,YAAY;AAAA,YACvB,cAAc,YAAY;AAAA,YAC1B,eAAe;AAAA,cACb,gBAAgB,YAAY;AAAA,cAC5B,gBAAgB,YAAY;AAAA,YAC9B;AAAA,UACF;AAAA,UACA,sBAAsB,YAAY;AAAA,UAClC,sBAAsB,KAAK,wBAAwB,iCAAiC;AAAA,UACpF;AAAA,UACA,oBAAoB,KAAK;AAAA,UACzB,qBAAqB,KAAK;AAAA,QAC5B;AAEA,aAAK,QAAQ;AACb,aAAK,oBAAoB;AACzB,aAAK,qBAAqB;AAC1B,eAAO,EAAE,UAAU,OAAO;AAAA,MAC5B;AAEA,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,OAAO,KAAK,MAAM;AAAA,QAC7B,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,WAAO,EAAE,SAAS;AAAA,EACpB;AACF;AAGA,IAAM,gCAAgC;AAEtC,IAAM,+BAA+B;AAErC,IAAM,+BAAN,MAAmC;AAAA,EACzB,UAAUA,SAAO,MAAM,CAAC;AAAA,EACxB,kBAAkB;AAAA,EAE1B,KAAK,OAAqF;AACxF,SAAK,UAAUA,SAAO,OAAO,CAAC,KAAK,SAASA,SAAO,KAAK,KAAK,CAAC,CAAC;AAC/D,UAAM,cAAwB,CAAC;AAE/B,WAAO,MAAM;AACX,YAAM,UAAU,KAAK,QAAQ,QAAQ,EAAI;AACzC,UAAI,UAAU,GAAG;AACf,YAAI,KAAK,QAAQ,SAAS,+BAA+B;AACvD,gBAAM,IAAI,cAAc;AAAA,YACtB,SAAS,EAAE,YAAY,8BAA8B;AAAA,YACrD,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AACA;AAAA,MACF;AACA,UAAI,UAAU,+BAA+B;AAC3C,cAAM,IAAI,cAAc;AAAA,UACtB,SAAS,EAAE,YAAY,8BAA8B;AAAA,UACrD,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAGA,YAAM,WAAW,gBAAgB,KAAK,QAAQ,SAAS,GAAG,UAAU,CAAC,EAAE,SAAS,OAAO,CAAC;AAGxF,YAAM,YAAYA,SAAO,KAAK,KAAK,QAAQ,SAAS,UAAU,CAAC,CAAC;AAChE,WAAK,UAAU;AAEf,UAAI,SAAS,WAAW,MAAM,GAAG;AAE/B,aAAK,UAAUA,SAAO,MAAM,CAAC;AAC7B,eAAO,EAAE,aAAa,WAAW,UAAU,UAAU;AAAA,MACvD;AAEA,WAAK,mBAAmB;AACxB,UAAI,KAAK,kBAAkB,8BAA8B;AACvD,cAAM,IAAI,cAAc;AAAA,UACtB,SAAS,EAAE,YAAY,6BAA6B;AAAA,UACpD,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AACA,kBAAY,KAAK,QAAQ;AAAA,IAC3B;AAEA,WAAO,EAAE,aAAa,WAAWA,SAAO,MAAM,CAAC,EAAE;AAAA,EACnD;AACF;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,MAAI,MAAM,SAAS,MAAM,GAAG;AAC1B,WAAO,MAAM,MAAM,GAAG,EAAE;AAAA,EAC1B;AAEA,MAAI,MAAM,SAAS,IAAI,GAAG;AACxB,WAAO,MAAM,MAAM,GAAG,EAAE;AAAA,EAC1B;AAEA,SAAO;AACT;AAEA,SAAS,mCAA0C;AACjD,QAAM,IAAI,WAAW;AAAA,IACnB,SAAS;AAAA,IACT,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,iCAAwC;AAC/C,QAAM,IAAI,cAAc;AAAA,IACtB,SAAS;AAAA,IACT,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AACH;;;AS1dA,SAAS,UAAAC,gBAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,OAGK;AAmBA,SAAS,oCAAoC,OASlB;AAChC,SAAO;AAAA,IACL,SAAS,IAAI,8BAA8B;AAAA,MACzC,qBAAqB,MAAM,qBAAqB;AAAA,MAChD,iBAAiB,MAAM,0BAA0B;AAAA,MACjD,cAAc,MAAM,qBAAqB;AAAA,MACzC,MAAM,MAAM,KAAK;AAAA,IACnB,CAAC;AAAA,IACD,UAAU,IAAI,4BAA4B;AAAA,MACxC,sBAAsB,MAAM,wBAAwB;AAAA,MACpD,qBAAqB,MAAM,qBAAqB;AAAA,MAChD,iBAAiB,MAAM,2BAA2B;AAAA,MAClD,cAAc,MAAM,qBAAqB;AAAA,MACzC,MAAM,MAAM,KAAK;AAAA,IACnB,CAAC;AAAA,EACH;AACF;AAGO,IAAM,8BAAN,MAAkC;AAAA,EAQvC,YACmB,SAOjB;AAPiB;AAQjB,SAAK,sBAAsB,QAAQ;AACnC,SAAK,eAAe,QAAQ;AAC5B,SAAK,iBAAiB,QAAQ,oBAAoB;AAClD,SAAK,cAAc,mBAAmB,QAAQ,mBAAmB;AACjE,SAAK,YAAY,iBAAiB,QAAQ,qBAAqB,QAAQ,YAAY;AACnF,SAAK,SAAS;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAAA,EAlBmB;AAAA,EARF;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA,EAuBR,oBAA4B;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,eAAe,SAA6B;AAC1C,UAAM,cAAc,yBAAyB,SAAS;AAAA,MACpD,WAAW,KAAK;AAAA,MAChB,eAAe,CAAC,KAAK,QAAQ;AAAA,IAC/B,CAAC;AACD,UAAM,MAAM;AAAA,MACV,KAAK;AAAA,MACL,KAAK,QAAQ,KAAK;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,IACP;AACA,UAAM,YAAY,KAAK,WAAW,SAAY,cAAc,KAAK,OAAO,OAAO,WAAW;AAE1F,SAAK,iBAAkB,KAAK,iBAAiB,MAAO;AACpD,WAAOC,SAAO,OAAO,CAAC,WAAW,GAAG,CAAC;AAAA,EACvC;AACF;AAGO,IAAM,gCAAN,MAAoC;AAAA,EAazC,YACmB,SAMjB;AANiB;AAOjB,SAAK,sBAAsB,QAAQ;AACnC,SAAK,eAAe,QAAQ;AAC5B,SAAK,iBAAiB,QAAQ,oBAAoB;AAClD,SAAK,cAAc,mBAAmB,QAAQ,mBAAmB;AACjE,SAAK,YAAY,iBAAiB,QAAQ,qBAAqB,QAAQ,YAAY;AACnF,SAAK,WAAW;AAAA,MACd,QAAQ;AAAA,MACR,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAAA,EAjBmB;AAAA,EAbF;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA;AAAA,EAGA;AAAA,EACA,kBAAkBA,SAAO,MAAM,CAAC;AAAA,EAChC;AAAA,EAsBR,oBAA4B;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,OAAyB;AACjC,SAAK,kBAAkBA,SAAO,OAAO,CAAC,KAAK,iBAAiB,KAAK,CAAC;AAClE,UAAM,UAAoB,CAAC;AAE3B,WAAO,MAAM;AACX,UAAI,KAAK,0BAA0B,QAAW;AAE5C,YAAI,KAAK,gBAAgB,SAAS,KAAK,YAAa;AACpD,cAAM,aAAa,KAAK,gBAAgB,SAAS,GAAG,KAAK,WAAW;AACpE,aAAK,kBAAkBA,SAAO,KAAK,KAAK,gBAAgB,SAAS,KAAK,WAAW,CAAC;AAClF,aAAK,wBAAwB,KAAK,WAC9BA,SAAO,KAAK,KAAK,SAAS,OAAO,UAAU,CAAC,IAC5CA,SAAO,KAAK,UAAU;AAC1B,cAAM,eAAe,KAAK,sBAAsB,aAAa,CAAC;AAC9D,YAAI,eAAe,uBAAuB;AACxC,gBAAM,IAAI,cAAc;AAAA,YACtB,SAAS,EAAE,iBAAiB,uBAAuB,aAAa;AAAA,YAChE,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAGA,cAAM,YAAY,IAAI,eAAe,KAAK,cAAc,KAAK;AAC7D,YAAI,YAAY,GAAG;AACjB,gBAAM,IAAI,cAAc;AAAA,YACtB,SAAS,EAAE,aAAa,KAAK,aAAa,aAAa;AAAA,YACvD,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AACA,aAAK,uBAAuB;AAAA,MAC9B;AAEA,YAAM,SAAS,KAAK;AACpB,UAAI,KAAK,gBAAgB,SAAS,OAAQ;AAE1C,YAAM,gBAAgB,KAAK,gBAAgB,SAAS,GAAG,SAAS,KAAK,SAAS;AAC9E,YAAM,cAAc,KAAK,gBAAgB,SAAS,SAAS,KAAK,WAAW,MAAM;AACjF,WAAK,kBAAkBA,SAAO,KAAK,KAAK,gBAAgB,SAAS,MAAM,CAAC;AAExE,YAAM,gBACJ,cAAc,SAAS,IACnB,KAAK,WACHA,SAAO,KAAK,KAAK,SAAS,OAAO,aAAa,CAAC,IAC/CA,SAAO,KAAK,aAAa,IAC3BA,SAAO,MAAM,CAAC;AAEpB,YAAM,cAAcA,SAAO,OAAO,CAAC,KAAK,uBAAuB,aAAa,CAAC;AAC7E,YAAM,cAAc;AAAA,QAClB,KAAK;AAAA,QACL,KAAK,QAAQ,KAAK;AAAA,QAClB,KAAK;AAAA,QACL;AAAA,QACA,KAAK;AAAA,MACP;AAEA,UAAI,CAAC,gBAAgB,aAAa,WAAW,GAAG;AAC9C,cAAM,IAAI,cAAc;AAAA,UACtB,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAEA,WAAK,iBAAkB,KAAK,iBAAiB,MAAO;AACpD,cAAQ,KAAK,yBAAyB,WAAW,EAAE,OAAO;AAE1D,WAAK,wBAAwB;AAC7B,WAAK,uBAAuB;AAAA,IAC9B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,iBAAiB,QAA4B;AAC3C,UAAM,QAAQA,SAAO,KAAK,MAAM;AAChC,QAAI,MAAM,SAAS,KAAK,WAAW;AACjC,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,QAAQ,MAAM,QAAQ,WAAW,KAAK,UAAU;AAAA,QAC3D,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,YAAY,MAAM,SAAS,KAAK;AACtC,UAAM,kBAAkB,MAAM,SAAS,GAAG,SAAS;AACnD,UAAM,cAAc,MAAM,SAAS,SAAS;AAC5C,UAAM,cACJ,KAAK,aAAa,SAAY,kBAAkB,KAAK,SAAS,OAAO,eAAe;AACtF,UAAM,cAAc;AAAA,MAClB,KAAK;AAAA,MACL,KAAK,QAAQ,KAAK;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,IACP;AAEA,QAAI,CAAC,gBAAgB,aAAa,WAAW,GAAG;AAC9C,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,SAAK,iBAAkB,KAAK,iBAAiB,MAAO;AACpD,WAAO,yBAAyB,WAAW,EAAE;AAAA,EAC/C;AACF;AAEA,SAAS,aAAa,WAAmB,KAAa,IAAkC;AACtF,MAAI,cAAc,QAAQ;AACxB,WAAO;AAAA,EACT;AAEA,yBAAuB,WAAW,KAAK,EAAE;AACzC,QAAM,SAAS,eAAe,oBAAoB,SAAS,GAAG,KAAK,EAAE;AACrE,SAAO,eAAe,KAAK;AAC3B,SAAO;AACT;AAEA,SAAS,eAAe,WAAmB,KAAa,IAAoC;AAC1F,MAAI,cAAc,QAAQ;AACxB,WAAO;AAAA,EACT;AAEA,yBAAuB,WAAW,KAAK,EAAE;AACzC,QAAM,WAAW,iBAAiB,oBAAoB,SAAS,GAAG,KAAK,EAAE;AACzE,WAAS,eAAe,KAAK;AAC7B,SAAO;AACT;AAEA,SAAS,oBAAoB,WAA2B;AACtD,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,uBAAuB,WAAmB,KAAa,IAAkB;AAChF,QAAM,oBAAoB,uBAAuB,SAAS;AAC1D,QAAM,mBAAmB,sBAAsB,SAAS;AAExD,MAAI,IAAI,WAAW,qBAAqB,GAAG,WAAW,kBAAkB;AACtE,UAAM,IAAI,cAAc;AAAA,MACtB,SAAS;AAAA,QACP;AAAA,QACA,UAAU,GAAG;AAAA,QACb,WAAW,IAAI;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACF;AAEA,SAAS,uBAAuB,WAA2B;AACzD,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,UAAU;AAAA,QACrB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,EACL;AACF;AAEA,SAAS,sBAAsB,WAA2B;AACxD,UAAQ,WAAW;AAAA,IACjB,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,UAAU;AAAA,QACrB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,EACL;AACF;AAEA,SAAS,mBAAmB,WAA2B;AACrD,UAAQ,WAAW;AAAA,IACjB,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA;AAAA,IACT;AACE,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,UAAU;AAAA,QACrB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,EACL;AACF;AAEA,SAAS,iBAAiB,qBAA6B,cAA8B;AACnF,MAAI,wBAAwB,QAAQ;AAClC,WAAO;AAAA,EACT;AAEA,UAAQ,cAAc;AAAA,IACpB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,aAAa;AAAA,QACxB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,EACL;AACF;AAEA,SAAS,WACP,cACA,QACA,UACA,QACA,WACQ;AACR,MAAI,cAAc,GAAG;AACnB,WAAOA,SAAO,MAAM,CAAC;AAAA,EACvB;AAEA,QAAM,WAAW,iBAAiB,kBAAkB,WAAW;AAG/D,QAAM,iBAAiBA,SAAO,MAAM,CAAC;AACrC,iBAAe,cAAc,aAAa,GAAG,CAAC;AAE9C,SAAOC,YAAW,UAAU,MAAM,EAC/B,OAAO,cAAc,EACrB,OAAO,MAAM,EACb,OAAO,EACP,SAAS,GAAG,SAAS;AAC1B;;;AZtYO,IAAM,sBAAsB;AAAA,EACjC,6BAA6B;AAAA,EAC7B,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,WAAW;AAAA,EACX,mBAAmB;AAAA,EACnB,uBAAuB;AAAA,EACvB,gCAAgC;AAAA,EAChC,yBAAyB;AAAA,EACzB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,wBAAwB;AAAA,EACxB,sBAAsB;AAAA,EACtB,mBAAmB;AACrB;AAIA,IAAM,iBAAiB;AACvB,IAAM,aAAa;AACnB,IAAM,YAAY;AAuDX,IAAM,yBAAN,MAA6B;AAAA,EAiBlC,YAA6B,UAAyC,CAAC,GAAG;AAA7C;AAAA,EAA8C;AAAA,EAA9C;AAAA,EAhBrB,YAAY;AAAA,EACZ,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAES,eAAoC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrC,mBAA8D,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShF,QAAQ,QAAsD;AAC5D,QAAI,KAAK,aAAa,KAAK,WAAW,QAAW;AAC/C,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,SAAK,SAAS;AAEd,UAAM,YAAY,IAAI,sBAAsB;AAAA,MAC1C,GAAI,KAAK,QAAQ,eAAe,SAAY,CAAC,IAAI,EAAE,YAAY,KAAK,QAAQ,WAAW;AAAA,MACvF,GAAI,KAAK,QAAQ,0BAA0B,SACvC,CAAC,IACD,EAAE,uBAAuB,KAAK,QAAQ,sBAAsB;AAAA,MAChE,GAAI,KAAK,QAAQ,kBAAkB,SAC/B,CAAC,IACD,EAAE,eAAe,KAAK,QAAQ,cAAc;AAAA,IAClD,CAAC;AAED,WAAO,IAAI,QAAqC,CAAC,SAAS,WAAW;AACnE,YAAM,EAAE,aAAa,mBAAmB,IAAI,KAAK;AACjD,UAAI;AAIJ,YAAM,UAAU,CAAC,QAAqB;AACpC,gBAAQ;AACR;AAAA,UACE,IAAI,gBAAgB;AAAA,YAClB,SAAS,sCAAsC,IAAI,OAAO;AAAA,YAC1D,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF;AAEA,YAAM,UAAU,MAAY;AAC1B,gBAAQ;AACR;AAAA,UACE,IAAI,gBAAgB;AAAA,YAClB,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF;AAEA,YAAM,UAAU,MAAY;AAC1B,gBAAQ;AACR,eAAO,QAAQ;AACf;AAAA,UACE,IAAI,gBAAgB;AAAA,YAClB,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF;AAEA,YAAM,YAAY,MAAY;AAC5B,gBAAQ;AACR,eAAO,QAAQ;AACf;AAAA,UACE,IAAI,aAAa;AAAA,YACf,SAAS,EAAE,mBAAmB;AAAA,YAC9B,SAAS,yCAAyC,kBAAkB;AAAA,YACpE,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF;AAEA,eAAS,UAAgB;AACvB,YAAI,kBAAkB,QAAW;AAC/B,uBAAa,aAAa;AAC1B,0BAAgB;AAAA,QAClB;AACA,qBAAa,oBAAoB,SAAS,OAAO;AACjD,eAAO,IAAI,SAAS,OAAO;AAC3B,eAAO,IAAI,SAAS,OAAO;AAAA,MAC7B;AAIA,UAAI,aAAa,SAAS;AACxB,eAAO,QAAQ;AACf;AAAA,UACE,IAAI,gBAAgB;AAAA,YAClB,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAEA,mBAAa,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAC9D,aAAO,GAAG,SAAS,OAAO;AAC1B,aAAO,GAAG,SAAS,OAAO;AAE1B,UAAI,uBAAuB,UAAa,qBAAqB,GAAG;AAC9D,wBAAgB,WAAW,WAAW,kBAAkB;AAAA,MAC1D;AAEA,YAAM,uBAAuB,CAAC,UAAwB;AACpD,YAAI;AACJ,YAAI;AACF,gBAAM,EAAE,UAAU,OAAO,IAAI,UAAU,gBAAgB,KAAK;AAC5D,qBAAW,UAAU,UAAU;AAC7B,mBAAO,MAAM,MAAM;AAAA,UACrB;AACA,4BAAkB;AAAA,QACpB,SAAS,KAAK;AACZ,kBAAQ;AACR,iBAAO,IAAI,QAAQ,oBAAoB;AACvC,iBAAO,QAAQ;AACf;AAAA,YACE,eAAe,QACX,MACA,IAAI,cAAc;AAAA,cAChB,SAAS;AAAA,cACT,UAAU;AAAA,cACV,WAAW;AAAA,YACb,CAAC;AAAA,UACP;AACA;AAAA,QACF;AAEA,YAAI,oBAAoB,QAAW;AACjC,kBAAQ;AACR,iBAAO,IAAI,QAAQ,oBAAoB;AAEvC,cAAI;AACJ,cAAI;AACF,yBAAa,oCAAoC;AAAA,cAC/C,MAAM;AAAA,gBACJ,gBAAgB,gBAAgB,YAAY,cAAc;AAAA,gBAC1D,gBAAgB,gBAAgB,YAAY,cAAc;AAAA,cAC5D;AAAA,cACA,sBAAsB,gBAAgB;AAAA;AAAA;AAAA,cAGtC,wBAAwB,gBAAgB;AAAA,cACxC,yBAAyB,gBAAgB;AAAA,YAC3C,CAAC;AAAA,UACH,SAAS,KAAK;AACZ,mBAAO,QAAQ;AACf;AAAA,cACE,eAAe,QACX,MACA,IAAI,cAAc;AAAA,gBAChB,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,WAAW;AAAA,cACb,CAAC;AAAA,YACP;AACA;AAAA,UACF;AAEA,eAAK,YAAY,WAAW;AAC5B,eAAK,cAAc,WAAW;AAC9B,eAAK,YAAY;AAEjB,iBAAO,GAAG,QAAQ,KAAK,gBAAgB,KAAK,IAAI,CAAC;AACjD,iBAAO,GAAG,SAAS,KAAK,cAAc,KAAK,IAAI,CAAC;AAChD,iBAAO,GAAG,SAAS,KAAK,cAAc,KAAK,IAAI,CAAC;AAEhD,eAAK,eAAe;AAGpB,gBAAM,WAAW,UAAU,mBAAmB;AAC9C,cAAI,SAAS,SAAS,GAAG;AACvB,iBAAK,gBAAgB,QAAQ;AAAA,UAC/B;AAEA,kBAAQ,eAAe;AAAA,QACzB;AAAA,MACF;AAGA,aAAO,MAAM,UAAU,yBAAyB,CAAC;AACjD,aAAO,GAAG,QAAQ,oBAAoB;AAAA,IACxC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,SAAoC;AAC9C,SAAK,gBAAgB;AACrB,UAAM,QAAQ,KAAK,UAAW,eAAeC,SAAO,KAAK,OAAO,CAAC;AACjE,SAAK,OAAQ,MAAM,KAAK;AAExB,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAO,kBAA0C;AAC/C,SAAK,gBAAgB;AACrB,WAAO,MAAM;AACX,YAAM,QAAQ,MAAM,KAAK,eAAe;AACxC,UAAI,MAAM,SAAS,MAAO;AAC1B,UAAI,MAAM,SAAS,QAAS,OAAM,MAAM;AACxC,YAAM,MAAM;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WACE,SAA8B,oBAAoB,gBAClD,cAAc,IACR;AACN,QAAI,KAAK,YAAY,KAAK,WAAW,OAAW;AAChD,SAAK,WAAW;AAEhB,SAAK,cAAc;AAEnB,QAAI,KAAK,aAAa,KAAK,cAAc,QAAW;AAClD,UAAI;AACF,cAAM,UAAU,IAAI,cAAc,EAC/B,UAAU,cAAc,EACxB,YAAY,MAAM,EAClB,YAAY,aAAa,MAAM,EAC/B,YAAY,IAAI,MAAM,EACtB,SAAS;AACZ,aAAK,OAAO,MAAM,KAAK,UAAU,eAAe,OAAO,CAAC;AAAA,MAC1D,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,SAAK,OAAO,IAAI;AAChB,SAAK,aAAa,EAAE,MAAM,MAAM,CAAC;AAAA,EACnC;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK,aAAa,CAAC,KAAK;AAAA,EACjC;AAAA,EAEQ,gBAAgB,OAAqB;AAC3C,QAAI;AACF,YAAM,WAAW,KAAK,YAAa,UAAU,KAAK;AAClD,iBAAW,WAAW,UAAU;AAC9B,cAAM,UAAU,QAAQ,CAAC;AACzB,YAAI,YAAY,cAAc,YAAY,UAAW;AACrD,YAAI,YAAY,gBAAgB;AAC9B,eAAK,aAAa,EAAE,MAAM,SAAS,OAAO,uBAAuB,OAAO,EAAE,CAAC;AAC3E,eAAK,QAAQ,QAAQ;AACrB;AAAA,QACF;AACA,aAAK,aAAa,EAAE,MAAM,WAAW,QAAQ,CAAC;AAAA,MAChD;AAAA,IACF,SAAS,KAAK;AACZ,WAAK,aAAa;AAAA,QAChB,MAAM;AAAA,QACN,OACE,eAAe,QACX,MACA,IAAI,cAAc;AAAA,UAChB,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAW;AAAA,QACb,CAAC;AAAA,MACT,CAAC;AACD,WAAK,QAAQ,QAAQ;AAAA,IACvB;AAAA,EACF;AAAA,EAEQ,cAAc,KAAkB;AACtC,SAAK,cAAc;AACnB,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK,aAAa;AAAA,QAChB,MAAM;AAAA,QACN,OAAO,IAAI,gBAAgB;AAAA,UACzB,SAAS,qBAAqB,IAAI,OAAO;AAAA,UACzC,UAAU;AAAA,UACV,WAAW;AAAA,QACb,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,gBAAsB;AAC5B,SAAK,cAAc;AACnB,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK,aAAa,EAAE,MAAM,MAAM,CAAC;AAAA,IACnC;AAAA,EACF;AAAA,EAEQ,aAAa,OAAgC;AACnD,QAAI,KAAK,iBAAiB,SAAS,GAAG;AACpC,YAAM,UAAU,KAAK,iBAAiB,MAAM;AAC5C,cAAQ,KAAK;AAAA,IACf,OAAO;AACL,WAAK,aAAa,KAAK,KAAK;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,iBAA6C;AACnD,QAAI,KAAK,aAAa,SAAS,GAAG;AAChC,aAAO,QAAQ,QAAQ,KAAK,aAAa,MAAM,CAAE;AAAA,IACnD;AACA,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,WAAK,iBAAiB,KAAK,OAAO;AAAA,IACpC,CAAC;AAAA,EACH;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,iBAAuB;AAC7B,UAAM,aAAa,KAAK,QAAQ;AAChC,QAAI,eAAe,UAAa,cAAc,EAAG;AACjD,SAAK,iBAAiB,YAAY,MAAM,KAAK,kBAAkB,GAAG,UAAU;AAG5E,SAAK,eAAe,QAAQ;AAAA,EAC9B;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,mBAAmB,QAAW;AACrC,oBAAc,KAAK,cAAc;AACjC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,sBAA4B;AAClC,QAAI,KAAK,mBAAmB,OAAW;AACvC,SAAK,cAAc;AACnB,SAAK,eAAe;AAAA,EACtB;AAAA,EAEQ,oBAA0B;AAChC,QAAI,CAAC,KAAK,aAAa,KAAK,YAAY,KAAK,cAAc,OAAW;AACtE,QAAI;AAIF,YAAM,UAAU,IAAI,cAAc,EAAE,UAAU,UAAU,EAAE,YAAY,IAAI,MAAM,EAAE,SAAS;AAC3F,WAAK,OAAQ,MAAM,KAAK,UAAU,eAAe,OAAO,CAAC;AAAA,IAC3D,QAAQ;AAAA,IAGR;AAAA,EACF;AACF;AAEA,SAAS,uBAAuB,SAAkC;AAChE,MAAI;AACF,UAAM,SAAS,IAAI,cAAc,QAAQ,SAAS,CAAC,CAAC;AACpD,UAAM,aAAa,OAAO,WAAW;AACrC,UAAM,cAAc,OAAO,WAAW,EAAE,SAAS,MAAM;AACvD,WAAO,IAAI,gBAAgB;AAAA,MACzB,SAAS,EAAE,WAAW;AAAA,MACtB,SAAS,uBAAuB,YAAY,SAAS,IAAI,cAAc,6BAA6B,UAAU,UAAU;AAAA,MACxH,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,IAAI,gBAAgB;AAAA,MACzB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACF;;;AajeO,IAAM,0BAA0B;AAChC,IAAM,yBAAyB;AAC/B,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,yBAAyB;AAC/B,IAAM,gCAAgC;AACtC,IAAM,iCAAiC;AAQvC,SAAS,wBAAwB,aAA6B;AACnE,SAAO,IAAI,cAAc,EACtB,UAAU,uBAAuB,EACjC,YAAY,aAAa,MAAM,EAC/B,SAAS;AACd;AAMO,SAAS,uBAAuB,SAA8C;AACnF,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,YAAY,wBAAwB;AACtC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,SAAO,EAAE,aAAa,OAAO,WAAW,EAAE,SAAS,MAAM,EAAE;AAC7D;AAqBO,SAAS,8BACd,MACQ;AACR,SAAO,IAAI,cAAc,EACtB,UAAU,wBAAwB,EAClC,YAAY,KAAK,UAAU,MAAM,EACjC,YAAY,KAAK,aAAa,MAAM,EACpC,YAAY,YAAY,OAAO,EAC/B,aAAa,KAAK,EAClB,YAAY,KAAK,UAAU,MAAM,EACjC,SAAS;AACd;AAMO,SAAS,oCACd,MACQ;AACR,SAAO,IAAI,cAAc,EACtB,UAAU,wBAAwB,EAClC,YAAY,KAAK,UAAU,MAAM,EACjC,YAAY,KAAK,aAAa,MAAM,EACpC,YAAY,aAAa,OAAO,EAChC,aAAa,KAAK,EAClB,YAAY,KAAK,eAAe,OAAO,EACvC,YAAY,KAAK,aAAa,EAC9B,SAAS;AACd;AAMO,SAAS,mCACd,MAKQ;AACR,SAAO,IAAI,cAAc,EACtB,UAAU,wBAAwB,EAClC,YAAY,KAAK,UAAU,MAAM,EACjC,YAAY,KAAK,aAAa,MAAM,EACpC,YAAY,aAAa,OAAO,EAChC,aAAa,IAAI,EACjB,YAAY,KAAK,eAAe,OAAO,EACvC,YAAY,KAAK,aAAa,EAC9B,YAAY,KAAK,SAAS,EAC1B,SAAS;AACd;AAMO,SAAS,uBACd,MAKQ;AACR,SAAO,IAAI,cAAc,EACtB,YAAY,KAAK,SAAS,EAC1B,UAAU,wBAAwB,EAClC,YAAY,KAAK,UAAU,MAAM,EACjC,YAAY,KAAK,aAAa,MAAM,EACpC,YAAY,aAAa,OAAO,EAChC,aAAa,IAAI,EACjB,YAAY,KAAK,eAAe,OAAO,EACvC,YAAY,KAAK,aAAa,EAC9B,SAAS;AACd;AAYO,SAAS,yBAAyB,SAAyC;AAChF,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,YAAY,0BAA0B;AACxC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,WAAW,OAAO,WAAW,EAAE,SAAS,OAAO;AACrD,QAAM,yBAAyB,SAAS,WAAW,IAAI,CAAC,IAAI,SAAS,MAAM,GAAG;AAC9E,QAAM,iBAAiB,OAAO,YAAY;AAC1C,SAAO,EAAE,wBAAwB,eAAe;AAClD;AASO,SAAS,wBAAwB,SAAwC;AAC9E,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,YAAY,yBAAyB;AACvC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,UAAU,OAAO,WAAW,EAAE,SAAS,MAAM;AACnD,QAAM,cAAc,OAAO,WAAW,EAAE,SAAS,OAAO;AACxD,SAAO,EAAE,aAAa,QAAQ;AAChC;AASO,SAAS,sBAAsB,SAAsC;AAC1E,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,YAAY,wBAAwB;AACtC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,SAAO;AAAA,IACL,eAAe,OAAO,WAAW,EAAE,SAAS,OAAO;AAAA,IACnD,eAAe,OAAO,WAAW;AAAA,EACnC;AACF;AAWO,SAAS,6BAA6B,SAA6C;AACxF,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,YAAY,+BAA+B;AAC7C,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,OAAO,OAAO,WAAW,EAAE,SAAS,MAAM;AAChD,QAAM,cAAc,OAAO,WAAW,EAAE,SAAS,MAAM;AACvD,QAAM,cAAc,OAAO,WAAW,EAAE,SAAS,OAAO;AACxD,QAAM,QAAQ,OAAO,WAAW;AAChC,QAAM,UAAoD,CAAC;AAC3D,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,UAAM,SAAS,OAAO,WAAW,EAAE,SAAS,MAAM;AAClD,UAAM,OAAO,OAAO,YAAY;AAChC,YAAQ,KAAK,EAAE,MAAM,OAAO,CAAC;AAAA,EAC/B;AACA,SAAO,EAAE,aAAa,aAAa,MAAM,QAAQ;AACnD;AAEO,SAAS,8BAA8B,WAA6B;AACzE,QAAM,SAAS,IAAI,cAAc,EAC9B,UAAU,8BAA8B,EACxC,YAAY,UAAU,MAAM;AAC/B,aAAW,KAAK,WAAW;AACzB,WAAO,YAAY,GAAG,MAAM;AAAA,EAC9B;AACA,SAAO,OAAO,SAAS;AACzB;;;AC7OA,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;AA+DxB,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YAA6B,WAAmC;AAAnC;AAAA,EAAoC;AAAA,EAApC;AAAA,EAE7B,MAAM,aAAa,SAAiD;AAClE,UAAM,EAAE,YAAY,WAAW,cAAc,EAAE,IAAI;AACnD,UAAM,cAAwB,CAAC;AAG/B,SAAK,UAAU,YAAY,wBAAwB,oBAAoB,CAAC;AAGxE,UAAM,uBAAuB,MAAM,KAAK,YAAY;AACpD,2BAAuB,oBAAoB;AAG3C,QAAI,WAAW;AAEf,WAAO,WAAW,aAAa;AAC7B,kBAAY;AAEZ,YAAM,SAAS,WAAW;AAE1B,cAAQ,WAAW,MAAM;AAAA,QACvB,KAAK,YAAY;AACf,eAAK,UAAU;AAAA,YACb,8BAA8B;AAAA,cAC5B,UAAU,WAAW;AAAA,cACrB,aAAa;AAAA,cACb,UAAU,WAAW;AAAA,YACvB,CAAC;AAAA,UACH;AACA;AAAA,QACF;AAAA,QAEA,KAAK,aAAa;AAEhB,eAAK,UAAU;AAAA,YACb,oCAAoC;AAAA,cAClC,eAAe,WAAW;AAAA,cAC1B,eAAe,WAAW;AAAA,cAC1B,aAAa;AAAA,cACb,UAAU,WAAW;AAAA,YACvB,CAAC;AAAA,UACH;AAEA,gBAAM,gBAAgB,MAAM,KAAK,2BAA2B,WAAW;AACvE,gBAAM,eAAe,cAAc,CAAC;AAEpC,cAAI,iBAAiB,0BAA0B;AAC7C,kBAAM,UAAU,yBAAyB,aAAa;AACtD,kBAAM,IAAI,oBAAoB;AAAA,cAC5B,SAAS,EAAE,SAAS,QAAQ,uBAAuB;AAAA,cACnD,SAAS,mDAAmD,WAAW,QAAQ;AAAA,cAC/E,UAAU;AAAA,cACV,WAAW;AAAA,YACb,CAAC;AAAA,UACH;AAEA,cAAI,iBAAiB,wBAAwB;AAC3C,kBAAM,IAAI,oBAAoB;AAAA,cAC5B,SAAS,EAAE,SAAS,aAAa;AAAA,cACjC,SAAS;AAAA,cACT,UAAU;AAAA,cACV,WAAW;AAAA,YACb,CAAC;AAAA,UACH;AAEA,gCAAsB,aAAa;AAGnC,gBAAM,WAAW,uBAAuB;AAAA,YACtC,eAAe,WAAW;AAAA,YAC1B,eAAe,WAAW;AAAA,YAC1B,aAAa;AAAA,YACb;AAAA,YACA,UAAU,WAAW;AAAA,UACvB,CAAC;AAED,gBAAM,eAAe,MAAM,WAAW,KAAK,QAAQ;AACnD,gBAAM,gBAAgB,mBAAmB,WAAW,eAAe,YAAY;AAE/E,eAAK,UAAU;AAAA,YACb,mCAAmC;AAAA,cACjC,eAAe,WAAW;AAAA,cAC1B,eAAe,WAAW;AAAA,cAC1B,aAAa;AAAA,cACb,WAAW;AAAA,cACX,UAAU,WAAW;AAAA,YACvB,CAAC;AAAA,UACH;AACA;AAAA,QACF;AAAA,QAEA,KAAK,wBAAwB;AAG3B,gBAAM,KAAK,6BAA6B,YAAY,WAAW;AAC/D,gBAAM,WAAW,MAAM,KAAK,2BAA2B,WAAW;AAClE,cAAI,SAAS,CAAC,MAAM,0BAA0B;AAC5C,mBAAO,EAAE,aAAa,QAAQ,uBAAuB;AAAA,UACvD;AACA,cAAI,SAAS,CAAC,MAAM,0BAA0B;AAC5C,kBAAM,IAAI,oBAAoB;AAAA,cAC5B,SAAS,EAAE,SAAS,yBAAyB,QAAQ,EAAE,uBAAuB;AAAA,cAC9E,SAAS,4DAA4D,WAAW,QAAQ;AAAA,cACxF,UAAU;AAAA,cACV,WAAW;AAAA,YACb,CAAC;AAAA,UACH;AACA,gBAAM,IAAI,oBAAoB;AAAA,YAC5B,SAAS,EAAE,SAAS,SAAS,CAAC,EAAE;AAAA,YAChC,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF;AAEA,YAAM,WAAW,MAAM,KAAK,2BAA2B,WAAW;AAClE,YAAM,kBAAkB,SAAS,CAAC;AAElC,UAAI,oBAAoB,0BAA0B;AAChD,eAAO,EAAE,aAAa,OAAO;AAAA,MAC/B;AAEA,UAAI,oBAAoB,0BAA0B;AAChD,cAAM,UAAU,yBAAyB,QAAQ;AAEjD,YAAI,YAAY,eAAe,CAAC,QAAQ,uBAAuB,SAAS,WAAW,IAAI,GAAG;AACxF,gBAAM,IAAI,oBAAoB;AAAA,YAC5B,SAAS,EAAE,SAAS,QAAQ,wBAAwB,SAAS;AAAA,YAC7D,SAAS,uCAAuC,WAAW,QAAQ,WAAW,QAAQ;AAAA,YACtF,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAGA;AAAA,MACF;AAEA,YAAM,IAAI,oBAAoB;AAAA,QAC5B,SAAS,EAAE,SAAS,gBAAgB;AAAA,QACpC,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,IAAI,oBAAoB;AAAA,MAC5B,SAAS,EAAE,YAAY;AAAA,MACvB,SAAS,iDAAiD,WAAW;AAAA,MACrE,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,MAAc,6BACZ,YACA,aACe;AAEf,SAAK,UAAU;AAAA,MACb,eAAe,EAAE,aAAa,wBAAwB,UAAU,WAAW,SAAS,CAAC;AAAA,IACvF;AAEA,WAAO,MAAM;AACX,YAAM,UAAU,MAAM,KAAK,2BAA2B,WAAW;AACjE,YAAM,UAAU,QAAQ,CAAC;AAEzB,UAAI,YAAY,+BAA+B;AAC7C,cAAM,UAAU,6BAA6B,OAAO;AACpD,YAAI;AACJ,YAAI;AACF,sBAAY,MAAM,WAAW,QAAQ,QAAQ,MAAM,QAAQ,aAAa,QAAQ,OAAO;AAAA,QACzF,SAAS,OAAO;AACd,gBAAM,IAAI,oBAAoB;AAAA,YAC5B;AAAA,YACA,SAAS,sDAAsD,WAAW,QAAQ;AAAA,YAClF,UAAU;AAAA,YACV,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AACA,aAAK,UAAU,YAAY,8BAA8B,SAAS,CAAC;AACnE;AAAA,MACF;AAGA,WAAK,iBAAiB;AACtB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ;AAAA,EAER,MAAc,cAA+B;AAC3C,QAAI,KAAK,mBAAmB,QAAW;AACrC,YAAM,IAAI,KAAK;AACf,WAAK,iBAAiB;AACtB,aAAO;AAAA,IACT;AACA,UAAM,SAAS,MAAM,KAAK,UAAU,gBAAgB,EAAE,KAAK;AAC3D,QAAI,OAAO,SAAS,MAAM;AACxB,YAAM,IAAI,oBAAoB;AAAA,QAC5B,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAc,2BAA2B,aAAwC;AAC/E,WAAO,MAAM;AACX,YAAM,UAAU,MAAM,KAAK,YAAY;AACvC,UAAI,QAAQ,CAAC,MAAM,yBAAyB;AAC1C,oBAAY,KAAK,wBAAwB,OAAO,EAAE,OAAO;AACzD;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AASA,SAAS,mBAAmB,eAAuB,cAAkC;AACnF,SAAO,IAAI,cAAc,EACtB,YAAY,eAAe,OAAO,EAClC,YAAY,YAAY,EACxB,SAAS;AACd;AAKA,SAAS,eAAe,MAAyD;AAC/E,SAAO,IAAI,cAAc,EACtB,UAAU,EAAE,EACZ,YAAY,KAAK,UAAU,MAAM,EACjC,YAAY,KAAK,aAAa,MAAM,EACpC,YAAY,wBAAwB,OAAO,EAC3C,YAAY,IAAI,MAAM,EACtB,YAAY,IAAI,MAAM,EACtB,SAAS;AACd;;;AC/UA,SAAS,UAAAC,gBAAc;AACvB,SAAS,mBAAAC,kBAAiB,QAAQ,kBAAkC;AAKpE,IAAMC,0BAAyB;AAE/B,IAAM,6BAA6B;AAc5B,SAAS,yBACd,SACwB;AACxB,QAAM,EAAE,YAAY,SAAS,IAAI;AACjC,QAAM,YAAYC,iBAAgB,UAAU;AAE5C,UAAQ,WAAW,mBAAmB;AAAA,IACpC,KAAK,WAAW;AACd,YAAM,OAAO,UAAU,OAAO,EAAE,QAAQ,OAAO,MAAM,OAAO,CAAC;AAC7D,UAAI,KAAK,WAAW,6BAA6BD,yBAAwB;AACvE,cAAM,sBAAsB,2CAA2C;AAAA,MACzE;AACA,YAAM,MAAM,KAAK,SAAS,0BAA0B;AACpD,YAAM,gBAAgB,IAAI,cAAc,EACrC,YAAY,eAAe,OAAO,EAClC,YAAY,GAAG,EACf,SAAS;AACZ,aAAO;AAAA,QACL,eAAe;AAAA,QACf;AAAA,QACA,MAAM,CAAC,SAA6B,WAAW,MAAME,SAAO,KAAK,IAAI,GAAG,UAAU;AAAA,QAClF,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,OAAO;AACV,YAAM,gBAAgB,QAAQ,yBAAyB;AACvD,YAAM,OAAO,kBAAkB,iBAAiB,WAAW;AAC3D,YAAM,MAAM,UAAU,OAAO,EAAE,QAAQ,MAAM,CAAC;AAC9C,UAAI,IAAI,MAAM,UAAa,IAAI,MAAM,QAAW;AAC9C,cAAM,sBAAsB,+CAA+C;AAAA,MAC7E;AAGA,YAAM,IAAI,iBAAiB,IAAI,CAAC;AAChC,YAAM,IAAI,iBAAiB,IAAI,CAAC;AAChC,YAAM,gBAAgB,IAAI,cAAc,EACrC,YAAY,WAAW,OAAO,EAC9B,WAAW,CAAC,EACZ,WAAW,CAAC,EACZ,SAAS;AACZ,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,MAAM,CAAC,SAA6B,WAAW,MAAMA,SAAO,KAAK,IAAI,GAAG,UAAU;AAAA,QAClF,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,IAEA;AACE,YAAM;AAAA,QACJ,qCAAqC,WAAW,qBAAqB,SAAS;AAAA,MAChF;AAAA,EACJ;AACF;AAEA,SAAS,iBAAiB,OAAuB;AAE/C,QAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AACzD,QAAM,SAASA,SAAO,KAAK,QAAQ,QAAQ;AAE3C,SAAO;AACT;AAEA,SAAS,sBAAsB,SAAqC;AAClE,SAAO,IAAI,mBAAmB;AAAA,IAC5B;AAAA,IACA,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AACH;;;AC1FO,IAAM,uBAAuB;AAC7B,IAAM,oCAAoC;AAC1C,IAAM,+BAA+B;AACrC,IAAM,gCAAgC;AACtC,IAAM,uBAAuB;AAC7B,IAAM,gCAAgC;AACtC,IAAM,sBAAsB;AAC5B,IAAM,wBAAwB;AAC9B,IAAM,0BAA0B;AAChC,IAAM,0BAA0B;AAChC,IAAM,0BAA0B;AAqBhC,SAAS,qBAAqB,MAAkC;AACrE,SAAO,IAAI,cAAc,EACtB,UAAU,oBAAoB,EAC9B,YAAY,KAAK,aAAa,OAAO,EACrC,YAAY,KAAK,aAAa,EAC9B,YAAY,KAAK,iBAAiB,EAClC,YAAY,KAAK,aAAa,EAC9B,SAAS;AACd;AAWO,SAAS,iCAAiC,SAAiD;AAChG,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,YAAY,mCAAmC;AACjD,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,mBAAmB,OAAO,WAAW;AAC3C,QAAM,gBAAgB,OAAO,WAAW;AACxC,QAAM,oBAAoB,OAAO,WAAW;AAC5C,QAAM,gBAAgB,OAAO,WAAW;AACxC,SAAO,EAAE,mBAAmB,eAAe,kBAAkB,cAAc;AAC7E;AAWO,SAAS,4BAA4B,SAA4C;AACtF,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,YAAY,8BAA8B;AAC5C,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,mBAAmB,OAAO,WAAW;AAC3C,QAAM,aAAa,OAAO,WAAW;AACrC,QAAM,cAAc,OAAO,WAAW,EAAE,SAAS,MAAM;AACvD,QAAM,cAAc,OAAO,WAAW,EAAE,SAAS,OAAO;AACxD,SAAO,EAAE,aAAa,aAAa,YAAY,iBAAiB;AAClE;AAIO,SAAS,iCAAiC,MAItC;AACT,SAAO,IAAI,cAAc,EACtB,UAAU,uBAAuB,EACjC,YAAY,KAAK,gBAAgB,EACjC,YAAY,aAAa,OAAO,EAChC,aAAa,KAAK,SAAS,EAC3B,YAAY,KAAK,eAAe,OAAO,EACvC,SAAS;AACd;AAEO,SAAS,4BAA4B,MAIjC;AACT,SAAO,IAAI,cAAc,EACtB,UAAU,uBAAuB,EACjC,YAAY,KAAK,gBAAgB,EACjC,YAAY,QAAQ,OAAO,EAC3B,aAAa,KAAK,SAAS,EAC3B,YAAY,KAAK,SAAS,MAAM,EAChC,SAAS;AACd;AAiDO,SAAS,qBAAqB,MAA8D;AACjG,SAAO,IAAI,cAAc,EACtB,UAAU,oBAAoB,EAC9B,YAAY,KAAK,gBAAgB,EACjC,YAAY,KAAK,IAAI,EACrB,SAAS;AACd;AAOO,SAAS,qBAAqB,SAA4C;AAC/E,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,YAAY,sBAAsB;AACpC,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,mBAAmB,OAAO,WAAW;AAC3C,QAAM,OAAO,OAAO,WAAW;AAC/B,SAAO,EAAE,MAAM,iBAAiB;AAClC;AAwBO,SAAS,6BAA6B,SAAoD;AAC/F,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,YAAY,+BAA+B;AAC7C,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,mBAAmB,OAAO,WAAW;AAC3C,QAAM,eAAe,OAAO,WAAW;AACvC,QAAM,OAAO,OAAO,WAAW;AAC/B,SAAO,EAAE,MAAM,cAAc,iBAAiB;AAChD;AAIO,SAAS,6BAA6B,MAGlC;AACT,SAAO,IAAI,cAAc,EACtB,UAAU,6BAA6B,EACvC,YAAY,KAAK,gBAAgB,EACjC,YAAY,KAAK,UAAU,EAC3B,SAAS;AACd;AAOO,SAAS,6BAA6B,SAAoD;AAC/F,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,YAAY,+BAA+B;AAC7C,UAAM,IAAI,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,QAAM,mBAAmB,OAAO,WAAW;AAC3C,QAAM,aAAa,OAAO,WAAW;AACrC,SAAO,EAAE,YAAY,iBAAiB;AACxC;AAIO,SAAS,oBAAoB,kBAAkC;AACpE,SAAO,IAAI,cAAc,EACtB,UAAU,mBAAmB,EAC7B,YAAY,gBAAgB,EAC5B,SAAS;AACd;AAEO,SAAS,sBAAsB,kBAAkC;AACtE,SAAO,IAAI,cAAc,EACtB,UAAU,qBAAqB,EAC/B,YAAY,gBAAgB,EAC5B,SAAS;AACd;;;ACrSA,SAAS,UAAAC,gBAAc;AA2BvB,IAAM,sBAAsB,MAAM;AAClC,IAAM,kBAAkB,KAAK;AAC7B,IAAM,0BAA0B,KAAK;AAwB9B,IAAM,oBAAN,MAAwB;AAAA,EA8B7B,YACmB,WACjB,UAAoC,CAAC,GACrC;AAFiB;AAGjB,SAAK,iBAAiB,QAAQ,kBAAkB;AAAA,EAClD;AAAA,EAJmB;AAAA,EA9BX,QAAsB;AAAA;AAAA,EAGtB,kBAAkB;AAAA;AAAA,EAElB,wBAAwB;AAAA;AAAA,EAExB,sBAAsB;AAAA;AAAA,EAGtB,sBAAsB;AAAA,EACtB,kBAAkB;AAAA;AAAA,EAGT,eAA+B,CAAC;AAAA,EACzC;AAAA;AAAA,EAGS,gBAA0B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAK3B,yBAA4C,CAAC;AAAA;AAAA,EAEtD,YAA2B,QAAQ,QAAQ;AAAA,EAElC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAejB,MAAM,cAAc,eAAsC;AACxD,UAAM,KAAK,YAAY;AACvB,UAAM,KAAK,iBAAiB,aAAa;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,SAAgC;AAC7C,UAAM,KAAK,YAAY;AACvB,UAAM,KAAK,YAAY,OAAO;AAAA,EAChC;AAAA,EAEA,MAAc,cAA6B;AACzC,SAAK,UAAU;AAAA,MACb,qBAAqB;AAAA,QACnB,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,eAAe;AAAA,QACf,eAAe,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AAEA,UAAM,UAAU,MAAM,KAAK,YAAY;AACvC,UAAM,UAAU,QAAQ,CAAC;AAEzB,QAAI,YAAY,8BAA8B;AAC5C,YAAM,UAAU,4BAA4B,OAAO;AACnD,YAAM,IAAI,gBAAgB;AAAA,QACxB,SAAS,EAAE,QAAQ,QAAQ,YAAY,aAAa,QAAQ,YAAY;AAAA,QACxE,SAAS,4BAA4B,QAAQ,WAAW;AAAA,QACxD,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,QAAI,YAAY,mCAAmC;AACjD,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS,EAAE,QAAQ;AAAA,QACnB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,eAAe,iCAAiC,OAAO;AAC7D,SAAK,kBAAkB,aAAa;AACpC,SAAK,wBAAwB,aAAa;AAC1C,SAAK,sBAAsB,aAAa;AACxC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAc,iBAAiB,eAAsC;AACnE,SAAK,UAAU;AAAA,MACb,iCAAiC;AAAA,QAC/B,kBAAkB,KAAK;AAAA,QACvB;AAAA,QACA,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,UAAM,KAAK,yBAAyB,WAAW;AAAA,EACjD;AAAA,EAEA,MAAc,YAAY,SAAgC;AACxD,SAAK,UAAU;AAAA,MACb,4BAA4B;AAAA,QAC1B;AAAA,QACA,kBAAkB,KAAK;AAAA,QACvB,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,UAAM,KAAK,yBAAyB,MAAM;AAAA,EAC5C;AAAA,EAEA,MAAc,yBAAyB,aAAoC;AACzE,UAAM,UAAU,MAAM,KAAK,YAAY;AACvC,UAAM,UAAU,QAAQ,CAAC;AAEzB,QAAI,YAAY,yBAAyB;AACvC,WAAK,QAAQ;AACb;AAAA,IACF;AAEA,QAAI,YAAY,yBAAyB;AACvC,YAAM,IAAI,gBAAgB;AAAA,QACxB,SAAS,EAAE,YAAY;AAAA,QACvB,SAAS,wBAAwB,WAAW;AAAA,QAC5C,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,IAAI,cAAc;AAAA,MACtB,SAAS,EAAE,QAAQ;AAAA,MACnB,SAAS,2CAA2C,WAAW;AAAA,MAC/D,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,SAAS,MAAiC;AACxC,UAAM,OAAO,KAAK,UAAU,KAAK,MAAM,KAAK,eAAe,IAAI,CAAC;AAGhE,SAAK,YAAY,KAAK,MAAM,MAAM,MAAS;AAC3C,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,eAAe,MAAiC;AAC5D,QAAI,KAAK,UAAU,QAAQ;AACzB,YAAM,IAAI,cAAc;AAAA,QACtB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,QAAI,SAAS;AACb,WAAO,SAAS,KAAK,QAAQ;AAC3B,UAAI,KAAK,yBAAyB,GAAG;AAEnC,cAAM,IAAI,QAAc,CAAC,YAAY;AACnC,eAAK,uBAAuB,KAAK,OAAO;AAAA,QAC1C,CAAC;AACD;AAAA,MACF;AAEA,YAAM,YAAY,KAAK;AAAA,QACrB,KAAK,SAAS;AAAA,QACd,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AACA,YAAM,QAAQC,SAAO,KAAK,KAAK,SAAS,QAAQ,SAAS,SAAS,CAAC;AACnE,WAAK,UAAU;AAAA,QACb,qBAAqB,EAAE,MAAM,OAAO,kBAAkB,KAAK,gBAAgB,CAAC;AAAA,MAC9E;AACA,WAAK,yBAAyB;AAC9B,gBAAU;AAAA,IACZ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,cAAuD;AAC5D,WAAO,MAAM;AACX,YAAM,QAAQ,MAAM,KAAK,eAAe;AACxC,UAAI,MAAM,SAAS,QAAS,OAAM,MAAM;AACxC,UAAI,MAAM,SAAS,SAAS,MAAM,SAAS,QAAS;AACpD,YAAM,MAAM;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAc;AACZ,QAAI,KAAK,UAAU,YAAY,KAAK,UAAU,UAAW;AACzD,SAAK,QAAQ;AACb,SAAK,UAAU,YAAY,oBAAoB,KAAK,eAAe,CAAC;AACpE,SAAK,UAAU,YAAY,sBAAsB,KAAK,eAAe,CAAC;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,SAAuB;AAC9B,UAAM,UAAU,QAAQ,CAAC;AAEzB,YAAQ,SAAS;AAAA,MACf,KAAK,sBAAsB;AACzB,cAAM,MAAM,qBAAqB,OAAO;AACxC,aAAK,mBAAmB,IAAI,KAAK,MAAM;AACvC,aAAK,eAAe,EAAE,MAAM,QAAQ,MAAM,IAAI,KAAK,CAAC;AACpD;AAAA,MACF;AAAA,MAEA,KAAK,+BAA+B;AAElC,cAAM,MAAM,6BAA6B,OAAO;AAChD,aAAK,mBAAmB,IAAI,KAAK,MAAM;AACvC;AAAA,MACF;AAAA,MAEA,KAAK,+BAA+B;AAClC,cAAM,MAAM,6BAA6B,OAAO;AAChD,aAAK,yBAAyB,IAAI;AAElC,cAAM,UAAU,KAAK,uBAAuB,OAAO,CAAC;AACpD,mBAAW,MAAM,QAAS,IAAG;AAC7B;AAAA,MACF;AAAA,MAEA,KAAK,qBAAqB;AACxB,aAAK,eAAe,EAAE,MAAM,MAAM,CAAC;AACnC;AAAA,MACF;AAAA,MAEA,KAAK,uBAAuB;AAC1B,aAAK,QAAQ;AACb,aAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAGrC,cAAM,UAAU,KAAK,uBAAuB,OAAO,CAAC;AACpD,mBAAW,MAAM,QAAS,IAAG;AAC7B;AAAA,MACF;AAAA,MAEA;AAEE;AAAA,IACJ;AAAA,EACF;AAAA,EAEA,cAAc,OAAoB;AAChC,SAAK,eAAe,EAAE,MAAM,SAAS,MAAM,CAAC;AAE5C,UAAM,UAAU,KAAK,uBAAuB,OAAO,CAAC;AACpD,eAAW,MAAM,QAAS,IAAG;AAAA,EAC/B;AAAA;AAAA,EAIQ,mBAAmB,OAAqB;AAC9C,SAAK,uBAAuB;AAC5B,QAAI,KAAK,uBAAuB,yBAAyB;AACvD,YAAM,aAAa,KAAK;AACxB,WAAK,sBAAsB;AAC3B,WAAK,UAAU;AAAA,QACb,6BAA6B;AAAA,UAC3B;AAAA,UACA,kBAAkB,KAAK;AAAA,QACzB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,eAAe,OAA2B;AAChD,SAAK,aAAa,KAAK,KAAK;AAC5B,QAAI,KAAK,oBAAoB,QAAW;AACtC,YAAM,KAAK,KAAK;AAChB,WAAK,kBAAkB;AACvB,SAAG;AAAA,IACL;AAAA,EACF;AAAA,EAEQ,iBAAwC;AAC9C,QAAI,KAAK,aAAa,SAAS,GAAG;AAChC,aAAO,QAAQ,QAAQ,KAAK,aAAa,MAAM,CAAE;AAAA,IACnD;AACA,WAAO,IAAI,QAAsB,CAAC,YAAY;AAC5C,WAAK,kBAAkB,MAAM;AAC3B,gBAAQ,KAAK,aAAa,MAAM,CAAE;AAAA,MACpC;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAc,cAA+B;AAC3C,UAAM,SAAS,MAAM,KAAK,UAAU,gBAAgB,EAAE,KAAK;AAC3D,QAAI,OAAO,SAAS,MAAM;AACxB,YAAM,IAAI,gBAAgB;AAAA,QACxB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,WAAO,OAAO;AAAA,EAChB;AACF;;;AC5WA,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,uBAAN,MAA2B;AAAA,EAWhC,YAA6B,WAAmC;AAAnC;AAAA,EAAoC;AAAA,EAApC;AAAA,EAVZ,WAAW,oBAAI,IAA+B;AAAA,EACvD,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGS,uBAAiC,CAAC;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaR,MAAM,mBAAoC;AAExC,QAAI,KAAK,qBAAqB,SAAS,GAAG;AACxC,aAAO,KAAK,qBAAqB,MAAM;AAAA,IACzC;AAEA,UAAM,SAAS,MAAM,KAAK,UAAU,gBAAgB,EAAE,KAAK;AAC3D,QAAI,OAAO,SAAS,MAAM;AACxB,YAAM,IAAI,gBAAgB;AAAA,QACxB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,qBAAqB,eAAmD;AAC5E,UAAM,UAAU,KAAK;AACrB,UAAM,UAAU,IAAI,kBAAkB,KAAK,WAAW,EAAE,gBAAgB,QAAQ,CAAC;AACjF,SAAK,SAAS,IAAI,SAAS,OAAO;AAGlC,UAAM,KAAK,gBAAgB,SAAS,MAAM,QAAQ,cAAc,aAAa,CAAC;AAC9E,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,SAA6C;AACjE,UAAM,UAAU,KAAK;AACrB,UAAM,UAAU,IAAI,kBAAkB,KAAK,WAAW,EAAE,gBAAgB,QAAQ,CAAC;AACjF,SAAK,SAAS,IAAI,SAAS,OAAO;AAClC,UAAM,KAAK,gBAAgB,SAAS,MAAM,QAAQ,SAAS,OAAO,CAAC;AACnE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,QAAuB;AACrB,QAAI,KAAK,gBAAgB,OAAW,QAAO,KAAK;AAEhD,SAAK,cAAc,IAAI,QAAc,CAAC,SAAS,WAAW;AACxD,WAAK,cAAc;AACnB,WAAK,aAAa;AAClB,WAAK,KAAK,KAAK;AAAA,IACjB,CAAC;AAED,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,gBACZ,SACA,OACe;AAMf,UAAM,MAAM;AAAA,EACd;AAAA,EAEA,MAAc,OAAsB;AAClC,QAAI;AACF,uBAAiB,WAAW,KAAK,UAAU,gBAAgB,GAAG;AAC5D,aAAK,SAAS,OAAO;AAAA,MACvB;AAEA,WAAK;AAAA,QACH,IAAI,gBAAgB;AAAA,UAClB,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AACA,WAAK,cAAc;AAAA,IACrB,SAAS,KAAK;AACZ,YAAM,QACJ,eAAe,QACX,MACA,IAAI,gBAAgB;AAAA,QAClB,SAAS,OAAO,GAAG;AAAA,QACnB,UAAU;AAAA,QACV,WAAW;AAAA,MACb,CAAC;AACP,WAAK,kBAAkB,KAAK;AAC5B,WAAK,aAAa,KAAK;AAAA,IACzB;AAAA,EACF;AAAA,EAEQ,SAAS,SAAuB;AACtC,UAAM,UAAU,QAAQ,CAAC;AACzB,QAAI,YAAY,OAAW;AAE3B,QAAI,kBAAkB,IAAI,OAAO,GAAG;AAElC,YAAM,mBAAmB,QAAQ,aAAa,CAAC;AAC/C,YAAM,UAAU,KAAK,SAAS,IAAI,gBAAgB;AAClD,UAAI,YAAY,QAAW;AACzB,gBAAQ,SAAS,OAAO;AAAA,MAC1B;AAAA,IAEF;AAAA,EAGF;AAAA,EAEQ,kBAAkB,OAAoB;AAC5C,eAAW,WAAW,KAAK,SAAS,OAAO,GAAG;AAC5C,cAAQ,cAAc,KAAK;AAAA,IAC7B;AAAA,EACF;AACF;;;AClMA,SAAS,eAA4B;AAyDrC,IAAM,eAAe;AACrB,IAAM,6BAA6B;AACnC,IAAM,+BAA+B;AACrC,IAAM,2BAA2B,KAAK,OAAO;AAmB7C,eAAsB,cAAc,SAA6D;AAC/F,QAAM;AAAA,IACJ;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,EACnB,IAAI;AAEJ,QAAM,SAAS,MAAM,cAAc,MAAM,MAAM,gBAAgB;AAC/D,QAAM,YAAY,IAAI,uBAAuB;AAAA,IAC3C,oBAAoB;AAAA,IACpB,GAAG;AAAA,EACL,CAAC;AAED,MAAI;AACF,UAAM,YAAY,MAAM,UAAU,QAAQ,MAAM;AAEhD,UAAM,cAAc,IAAI,eAAe,SAAS;AAChD,UAAM,YAAY,aAAa;AAAA,MAC7B,YAAY;AAAA,MACZ,WAAW,UAAU,YAAY;AAAA,IACnC,CAAC;AAED,UAAM,OAAO,IAAI,qBAAqB,SAAS;AAC/C,UAAM,UAAU,MAAM,KAAK,gBAAgB,OAAO;AAElD,UAAM,OAAO,KAAK,MAAM;AACxB,SAAK,MAAM,MAAM;AAAA,IAEjB,CAAC;AAED,UAAM,SAAmB,CAAC;AAC1B,QAAI,gBAAgB;AACpB,QAAI;AACF,uBAAiB,SAAS,QAAQ,YAAY,GAAG;AAC/C,yBAAiB,MAAM;AACvB,YAAI,gBAAgB,gBAAgB;AAClC,gBAAM,IAAI;AAAA,YACR,kCAAkC,cAAc;AAAA,UAClD;AAAA,QACF;AACA,eAAO,KAAK,KAAK;AAAA,MACnB;AAAA,IACF,UAAE;AACA,cAAQ,MAAM;AAAA,IAChB;AAEA,UAAM,SAAS,OAAO,OAAO,MAAM;AACnC,WAAO;AAAA,MACL;AAAA,MACA,YAAY,OAAO,SAAS,MAAM;AAAA,MAClC;AAAA,IACF;AAAA,EACF,UAAE;AACA,cAAU,WAAW;AAAA,EACvB;AACF;AAMA,SAAS,cAAc,MAAc,MAAc,WAAoC;AACrF,SAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,UAAM,SAAS,QAAQ,EAAE,MAAM,KAAK,CAAC;AACrC,UAAM,QAAQ,WAAW,MAAM;AAC7B,aAAO,QAAQ;AACf;AAAA,QACE,IAAI,MAAM,iCAAiC,IAAI,IAAI,IAAI,oBAAoB,SAAS,IAAI;AAAA,MAC1F;AAAA,IACF,GAAG,SAAS;AACZ,WAAO,KAAK,WAAW,MAAM;AAC3B,mBAAa,KAAK;AAClB,cAAQ,MAAM;AAAA,IAChB,CAAC;AACD,WAAO,KAAK,SAAS,CAAC,UAAU;AAC9B,mBAAa,KAAK;AAClB,aAAO,KAAK;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AACH;","names":["Buffer","Buffer","path","waitMs","totalBytes","calculateBytesPerSecond","normalized","Buffer","Buffer","path","rename","mkdir","isAbsolute","cloneVerification","path","Buffer","path","createPathNotFoundError","compareEntries","collectTransferContent","normalizeOptionalByteCount","cloneVerification","Buffer","normalizeByteCount","concatChunks","cloneDate","Buffer","first","globMatch","path","gt","cloneEndpoint","item","open","path","path","throwIfAborted","compareEntries","path","compareEntries","path","absolutePath","isModifiedAtDifferent","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","Buffer","first","Buffer","randomBytes","Buffer","randomBytes","Buffer","createHash","createPublicKey","Buffer","createHash","createPublicKey","Buffer","Buffer","createHmac","Buffer","createHmac","Buffer","Buffer","createPublicKey","ED25519_RAW_KEY_LENGTH","createPublicKey","Buffer","Buffer","Buffer"]}
|