@zero-transfer/s3 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1643,6 +1643,65 @@ interface RunConnectionDiagnosticsOptions {
1643
1643
  */
1644
1644
  declare function runConnectionDiagnostics(options: RunConnectionDiagnosticsOptions): Promise<ConnectionDiagnosticsResult>;
1645
1645
 
1646
+ /** Options for {@link createPooledTransferClient}. */
1647
+ interface ConnectionPoolOptions {
1648
+ /**
1649
+ * Maximum number of *idle* sessions retained per pool key.
1650
+ *
1651
+ * Active leases are not counted against this limit — the cap only applies
1652
+ * to sessions waiting in the pool. When more than `maxIdlePerKey` sessions
1653
+ * become idle simultaneously, the oldest ones are disconnected. Defaults
1654
+ * to `4`.
1655
+ */
1656
+ maxIdlePerKey?: number;
1657
+ /**
1658
+ * How long an idle session may sit unused before it is automatically
1659
+ * disconnected. Defaults to `60_000` ms. Set to `0` to disable the timer
1660
+ * (idle sessions persist until `drainPool()` is called).
1661
+ */
1662
+ idleTimeoutMs?: number;
1663
+ /**
1664
+ * Custom pool key derivation. Receives the resolved
1665
+ * {@link ConnectionProfile} (after TransferClient validation) and must
1666
+ * return a string. Sessions with matching keys are pooled together; never
1667
+ * include secrets in the key.
1668
+ *
1669
+ * The default derives the key from `provider`, `host`, `port`, and
1670
+ * `username`.
1671
+ */
1672
+ keyOf?: (profile: ConnectionProfile) => string;
1673
+ }
1674
+ /**
1675
+ * Pool-aware {@link TransferClient} returned by
1676
+ * {@link createPooledTransferClient}.
1677
+ */
1678
+ interface PooledTransferClient {
1679
+ /** Opens (or leases) a pooled provider session. */
1680
+ connect(profile: ConnectionProfile): Promise<TransferSession>;
1681
+ /** Inspects the registered providers (delegated to the underlying client). */
1682
+ hasProvider(providerId: ProviderId): boolean;
1683
+ /** Returns the registered capability snapshots (delegated). */
1684
+ getCapabilities(): CapabilitySet[];
1685
+ /** Returns a specific capability snapshot (delegated). */
1686
+ getCapabilities(providerId: ProviderId): CapabilitySet;
1687
+ /**
1688
+ * Disconnects every idle session and prevents further pooling. After
1689
+ * `drainPool()` resolves, subsequent `connect()` calls still work but
1690
+ * always create fresh sessions (and never return them to the pool).
1691
+ */
1692
+ drainPool(): Promise<void>;
1693
+ /** Returns the number of idle sessions currently held in the pool. */
1694
+ poolSize(): number;
1695
+ }
1696
+ /**
1697
+ * Wraps a {@link TransferClient} with connection pooling.
1698
+ *
1699
+ * @param inner - Underlying client used to create real provider sessions.
1700
+ * @param options - Pool sizing, eviction, and key-derivation overrides.
1701
+ * @returns A {@link PooledTransferClient} that reuses idle sessions.
1702
+ */
1703
+ declare function createPooledTransferClient(inner: TransferClient, options?: ConnectionPoolOptions): PooledTransferClient;
1704
+
1646
1705
  /** Options used to create a local file-system provider factory. */
1647
1706
  interface LocalProviderOptions {
1648
1707
  /** Root directory exposed as `/`. When omitted, `profile.host` is treated as the root path. */
@@ -3194,7 +3253,14 @@ interface S3ProviderOptions {
3194
3253
  }
3195
3254
  /** Multipart upload tuning for the S3 provider. */
3196
3255
  interface S3MultipartOptions {
3197
- /** Enable multipart upload. Defaults to `false`. */
3256
+ /**
3257
+ * Enable multipart upload. **Defaults to `true`** so large objects stream
3258
+ * in fixed-size parts instead of being buffered in memory before a single
3259
+ * `PUT`. Payloads at or below {@link S3MultipartOptions.thresholdBytes}
3260
+ * still fall back to a single-shot `PUT` automatically. Set to `false` to
3261
+ * force the legacy single-shot behaviour (e.g. when targeting an
3262
+ * S3-compatible endpoint that does not support `CreateMultipartUpload`).
3263
+ */
3198
3264
  enabled?: boolean;
3199
3265
  /** Object size threshold in bytes above which multipart is used. Defaults to 8 MiB. */
3200
3266
  thresholdBytes?: number;
@@ -3240,6 +3306,41 @@ interface S3MultipartResumeStore {
3240
3306
  }
3241
3307
  /** Creates an in-memory {@link S3MultipartResumeStore}. */
3242
3308
  declare function createMemoryS3MultipartResumeStore(): S3MultipartResumeStore;
3309
+ /** Options for {@link createFileSystemS3MultipartResumeStore}. */
3310
+ interface FileSystemS3MultipartResumeStoreOptions {
3311
+ /**
3312
+ * Directory under which checkpoint JSON files are written. Created
3313
+ * recursively if it does not exist. Each upload occupies a single file
3314
+ * named after a SHA-256 hash of the resume key, so the directory is safe
3315
+ * to share across many concurrent uploads.
3316
+ */
3317
+ directory: string;
3318
+ }
3319
+ /**
3320
+ * File-system backed {@link S3MultipartResumeStore} that survives process
3321
+ * restarts. Each in-flight multipart upload is checkpointed to a single
3322
+ * JSON file in `options.directory` after every part. On retry the upload
3323
+ * reuses the stored `uploadId` and skips parts that S3 has already
3324
+ * accepted.
3325
+ *
3326
+ * The implementation writes atomically (`<file>.tmp` then `rename`) so a
3327
+ * crash mid-write cannot leave a corrupt checkpoint.
3328
+ *
3329
+ * @example
3330
+ * ```ts
3331
+ * import { createFileSystemS3MultipartResumeStore, createS3ProviderFactory }
3332
+ * from "@zero-transfer/sdk";
3333
+ *
3334
+ * const resumeStore = createFileSystemS3MultipartResumeStore({
3335
+ * directory: "./.zt-s3-resume",
3336
+ * });
3337
+ *
3338
+ * const factory = createS3ProviderFactory({
3339
+ * multipart: { enabled: true, resumeStore },
3340
+ * });
3341
+ * ```
3342
+ */
3343
+ declare function createFileSystemS3MultipartResumeStore(options: FileSystemS3MultipartResumeStoreOptions): S3MultipartResumeStore;
3243
3344
  /**
3244
3345
  * Creates an S3-compatible provider factory.
3245
3346
  *
@@ -3277,4 +3378,4 @@ declare function createMemoryS3MultipartResumeStore(): S3MultipartResumeStore;
3277
3378
  */
3278
3379
  declare function createS3ProviderFactory(options?: S3ProviderOptions): ProviderFactory;
3279
3380
 
3280
- export { AbortError, type AtomicDeployActivateOperation, type AtomicDeployActivateStep, type AtomicDeployPlan, type AtomicDeployPruneStep, type AtomicDeployStrategy, type AuthenticationCapability, AuthenticationError, AuthorizationError, type BandwidthSleep, type BandwidthThrottle, type BandwidthThrottleOptions, type Base64EnvSecretSource, type BuiltInProviderId, CLASSIC_PROVIDER_IDS, type CapabilitySet, type ChecksumCapability, type ClassicProviderId, type ClientDiagnostics, type CompareRemoteManifestsOptions, ConfigurationError, type ConnectionDiagnosticTimings, type ConnectionDiagnosticsResult, ConnectionError, type ConnectionProfile, type CopyBetweenOptions, type CreateAtomicDeployPlanOptions, type CreateRemoteBrowserOptions, type CreateRemoteManifestOptions, type CreateSyncPlanOptions, type DiffRemoteTreesOptions, type DownloadFileOptions, type EnvSecretSource, type FileSecretSource, type FileZillaSite, type FriendlyTransferOptions, type FtpReplyErrorInput, type ImportFileZillaSitesResult, type ImportOpenSshConfigOptions, type ImportOpenSshConfigResult, type ImportWinScpSessionsResult, type KnownHostsEntry, type KnownHostsMarker, type ListOptions, type LocalProviderOptions, type LogLevel, type LogRecord, type LogRecordInput, type LoggerMethod, type MemoryProviderEntry, type MemoryProviderOptions, type MetadataCapability, type MkdirOptions, type OAuthAccessToken, type OAuthRefreshCallback, type OAuthTokenSecretSourceOptions, type OpenSshConfigEntry, ParseError, PathAlreadyExistsError, PathNotFoundError, PermissionDeniedError, type ProgressEventInput, ProtocolError, type AuthenticationCapability as ProviderAuthenticationCapability, type CapabilitySet as ProviderCapabilities, type ChecksumCapability as ProviderChecksumCapability, type ProviderFactory, type ProviderId, type MetadataCapability as ProviderMetadataCapability, ProviderRegistry, type ProviderSelection, type ProviderTransferEndpointRole, type ProviderTransferExecutorOptions, type ProviderTransferOperations, type ProviderTransferReadRequest, type ProviderTransferReadResult, type ProviderTransferRequest, type ProviderTransferSessionResolver, type ProviderTransferSessionResolverInput, type ProviderTransferWriteRequest, type ProviderTransferWriteResult, REDACTED, REMOTE_MANIFEST_FORMAT_VERSION, type RemoteBreadcrumb, type RemoteBrowser, type RemoteBrowserFilter, type RemoteBrowserSnapshot, type RemoteEntry, type RemoteEntrySortKey, type RemoteEntrySortOrder, type RemoteEntryType, type RemoteFileAdapter, type RemoteFileEndpoint, type RemoteFileSystem, type RemoteManifest, type RemoteManifestEntry, type RemotePermissions, type RemoteProtocol, type RemoteStat, type RemoteTreeDiff, type RemoteTreeDiffEntry, type RemoteTreeDiffReason, type RemoteTreeDiffStatus, type RemoteTreeDiffSummary, type RemoteTreeEntry, type RemoteTreeFilter, type RemoveOptions, type RenameOptions, type ResolveSecretOptions, type ResolvedConnectionProfile, type ResolvedOpenSshHost, type ResolvedSshProfile, type ResolvedTlsProfile, type RmdirOptions, type RunConnectionDiagnosticsOptions, type S3MultipartCheckpoint, type S3MultipartOptions, type S3MultipartPart, type S3MultipartResumeKey, type S3MultipartResumeStore, type S3ProviderOptions, type SecretProvider, type SecretSource, type SecretValue, type SpecializedErrorDetails, type SshAgentSource, type SshAlgorithms, type SshKeyboardInteractiveChallenge, type SshKeyboardInteractiveHandler, type SshKeyboardInteractivePrompt, type SshKnownHostsSource, type SshProfile, type SshSocketFactory, type SshSocketFactoryContext, type StatOptions, type SyncConflictPolicy, type SyncDeletePolicy, type SyncDirection, type SyncEndpointInput, TimeoutError, type TlsProfile, type TlsSecretSource, type TransferAttempt, type TransferAttemptError, type TransferBandwidthLimit, type TransferByteRange, TransferClient, type TransferClientOptions, type TransferDataChunk, type TransferDataSource, type TransferEndpoint, TransferEngine, type TransferEngineExecuteOptions, type TransferEngineOptions, TransferError, type TransferExecutionContext, type TransferExecutionResult, type TransferExecutor, type TransferJob, type TransferOperation, type TransferPlan, type TransferPlanAction, type TransferPlanInput, type TransferPlanStep, type TransferPlanSummary, type TransferProgressEvent, type TransferProvider, TransferQueue, type TransferQueueExecutorResolver, type TransferQueueItem, type TransferQueueItemStatus, type TransferQueueOptions, type TransferQueueRunOptions, type TransferQueueSummary, type TransferReceipt, type TransferResult, type TransferResultInput, type TransferRetryDecisionInput, type TransferRetryPolicy, type TransferSession, type TransferTimeoutPolicy, type TransferVerificationResult, UnsupportedFeatureError, type UploadFileOptions, type ValueSecretSource, VerificationError, type WalkRemoteTreeOptions, type WinScpSession, ZeroTransfer, type ZeroTransferCapabilities, ZeroTransferError, type ZeroTransferErrorDetails, type ZeroTransferLogger, type ZeroTransferOptions, assertSafeFtpArgument, basenameRemotePath, buildRemoteBreadcrumbs, compareRemoteManifests, copyBetween, createAtomicDeployPlan, createBandwidthThrottle, createLocalProviderFactory, createMemoryProviderFactory, createMemoryS3MultipartResumeStore, createOAuthTokenSecretSource, createProgressEvent, createProviderTransferExecutor, createRemoteBrowser, createRemoteManifest, createS3ProviderFactory, createSyncPlan, createTransferClient, createTransferJobsFromPlan, createTransferPlan, createTransferResult, diffRemoteTrees, downloadFile, emitLog, errorFromFtpReply, filterRemoteEntries, importFileZillaSites, importOpenSshConfig, importWinScpSessions, isClassicProviderId, isSensitiveKey, joinRemotePath, matchKnownHosts, matchKnownHostsEntry, noopLogger, normalizeRemotePath, parentRemotePath, parseKnownHosts, parseOpenSshConfig, parseRemoteManifest, redactCommand, redactConnectionProfile, redactObject, redactSecretSource, redactValue, resolveConnectionProfileSecrets, resolveOpenSshHost, resolveProviderId, resolveSecret, runConnectionDiagnostics, serializeRemoteManifest, sortRemoteEntries, summarizeClientDiagnostics, summarizeTransferPlan, throttleByteIterable, uploadFile, validateConnectionProfile, walkRemoteTree };
3381
+ export { AbortError, type AtomicDeployActivateOperation, type AtomicDeployActivateStep, type AtomicDeployPlan, type AtomicDeployPruneStep, type AtomicDeployStrategy, type AuthenticationCapability, AuthenticationError, AuthorizationError, type BandwidthSleep, type BandwidthThrottle, type BandwidthThrottleOptions, type Base64EnvSecretSource, type BuiltInProviderId, CLASSIC_PROVIDER_IDS, type CapabilitySet, type ChecksumCapability, type ClassicProviderId, type ClientDiagnostics, type CompareRemoteManifestsOptions, ConfigurationError, type ConnectionDiagnosticTimings, type ConnectionDiagnosticsResult, ConnectionError, type ConnectionPoolOptions, type ConnectionProfile, type CopyBetweenOptions, type CreateAtomicDeployPlanOptions, type CreateRemoteBrowserOptions, type CreateRemoteManifestOptions, type CreateSyncPlanOptions, type DiffRemoteTreesOptions, type DownloadFileOptions, type EnvSecretSource, type FileSecretSource, type FileSystemS3MultipartResumeStoreOptions, type FileZillaSite, type FriendlyTransferOptions, type FtpReplyErrorInput, type ImportFileZillaSitesResult, type ImportOpenSshConfigOptions, type ImportOpenSshConfigResult, type ImportWinScpSessionsResult, type KnownHostsEntry, type KnownHostsMarker, type ListOptions, type LocalProviderOptions, type LogLevel, type LogRecord, type LogRecordInput, type LoggerMethod, type MemoryProviderEntry, type MemoryProviderOptions, type MetadataCapability, type MkdirOptions, type OAuthAccessToken, type OAuthRefreshCallback, type OAuthTokenSecretSourceOptions, type OpenSshConfigEntry, ParseError, PathAlreadyExistsError, PathNotFoundError, PermissionDeniedError, type PooledTransferClient, type ProgressEventInput, ProtocolError, type AuthenticationCapability as ProviderAuthenticationCapability, type CapabilitySet as ProviderCapabilities, type ChecksumCapability as ProviderChecksumCapability, type ProviderFactory, type ProviderId, type MetadataCapability as ProviderMetadataCapability, ProviderRegistry, type ProviderSelection, type ProviderTransferEndpointRole, type ProviderTransferExecutorOptions, type ProviderTransferOperations, type ProviderTransferReadRequest, type ProviderTransferReadResult, type ProviderTransferRequest, type ProviderTransferSessionResolver, type ProviderTransferSessionResolverInput, type ProviderTransferWriteRequest, type ProviderTransferWriteResult, REDACTED, REMOTE_MANIFEST_FORMAT_VERSION, type RemoteBreadcrumb, type RemoteBrowser, type RemoteBrowserFilter, type RemoteBrowserSnapshot, type RemoteEntry, type RemoteEntrySortKey, type RemoteEntrySortOrder, type RemoteEntryType, type RemoteFileAdapter, type RemoteFileEndpoint, type RemoteFileSystem, type RemoteManifest, type RemoteManifestEntry, type RemotePermissions, type RemoteProtocol, type RemoteStat, type RemoteTreeDiff, type RemoteTreeDiffEntry, type RemoteTreeDiffReason, type RemoteTreeDiffStatus, type RemoteTreeDiffSummary, type RemoteTreeEntry, type RemoteTreeFilter, type RemoveOptions, type RenameOptions, type ResolveSecretOptions, type ResolvedConnectionProfile, type ResolvedOpenSshHost, type ResolvedSshProfile, type ResolvedTlsProfile, type RmdirOptions, type RunConnectionDiagnosticsOptions, type S3MultipartCheckpoint, type S3MultipartOptions, type S3MultipartPart, type S3MultipartResumeKey, type S3MultipartResumeStore, type S3ProviderOptions, type SecretProvider, type SecretSource, type SecretValue, type SpecializedErrorDetails, type SshAgentSource, type SshAlgorithms, type SshKeyboardInteractiveChallenge, type SshKeyboardInteractiveHandler, type SshKeyboardInteractivePrompt, type SshKnownHostsSource, type SshProfile, type SshSocketFactory, type SshSocketFactoryContext, type StatOptions, type SyncConflictPolicy, type SyncDeletePolicy, type SyncDirection, type SyncEndpointInput, TimeoutError, type TlsProfile, type TlsSecretSource, type TransferAttempt, type TransferAttemptError, type TransferBandwidthLimit, type TransferByteRange, TransferClient, type TransferClientOptions, type TransferDataChunk, type TransferDataSource, type TransferEndpoint, TransferEngine, type TransferEngineExecuteOptions, type TransferEngineOptions, TransferError, type TransferExecutionContext, type TransferExecutionResult, type TransferExecutor, type TransferJob, type TransferOperation, type TransferPlan, type TransferPlanAction, type TransferPlanInput, type TransferPlanStep, type TransferPlanSummary, type TransferProgressEvent, type TransferProvider, TransferQueue, type TransferQueueExecutorResolver, type TransferQueueItem, type TransferQueueItemStatus, type TransferQueueOptions, type TransferQueueRunOptions, type TransferQueueSummary, type TransferReceipt, type TransferResult, type TransferResultInput, type TransferRetryDecisionInput, type TransferRetryPolicy, type TransferSession, type TransferTimeoutPolicy, type TransferVerificationResult, UnsupportedFeatureError, type UploadFileOptions, type ValueSecretSource, VerificationError, type WalkRemoteTreeOptions, type WinScpSession, ZeroTransfer, type ZeroTransferCapabilities, ZeroTransferError, type ZeroTransferErrorDetails, type ZeroTransferLogger, type ZeroTransferOptions, assertSafeFtpArgument, basenameRemotePath, buildRemoteBreadcrumbs, compareRemoteManifests, copyBetween, createAtomicDeployPlan, createBandwidthThrottle, createFileSystemS3MultipartResumeStore, createLocalProviderFactory, createMemoryProviderFactory, createMemoryS3MultipartResumeStore, createOAuthTokenSecretSource, createPooledTransferClient, createProgressEvent, createProviderTransferExecutor, createRemoteBrowser, createRemoteManifest, createS3ProviderFactory, createSyncPlan, createTransferClient, createTransferJobsFromPlan, createTransferPlan, createTransferResult, diffRemoteTrees, downloadFile, emitLog, errorFromFtpReply, filterRemoteEntries, importFileZillaSites, importOpenSshConfig, importWinScpSessions, isClassicProviderId, isSensitiveKey, joinRemotePath, matchKnownHosts, matchKnownHostsEntry, noopLogger, normalizeRemotePath, parentRemotePath, parseKnownHosts, parseOpenSshConfig, parseRemoteManifest, redactCommand, redactConnectionProfile, redactObject, redactSecretSource, redactValue, resolveConnectionProfileSecrets, resolveOpenSshHost, resolveProviderId, resolveSecret, runConnectionDiagnostics, serializeRemoteManifest, sortRemoteEntries, summarizeClientDiagnostics, summarizeTransferPlan, throttleByteIterable, uploadFile, validateConnectionProfile, walkRemoteTree };
package/dist/index.d.ts CHANGED
@@ -1643,6 +1643,65 @@ interface RunConnectionDiagnosticsOptions {
1643
1643
  */
1644
1644
  declare function runConnectionDiagnostics(options: RunConnectionDiagnosticsOptions): Promise<ConnectionDiagnosticsResult>;
1645
1645
 
1646
+ /** Options for {@link createPooledTransferClient}. */
1647
+ interface ConnectionPoolOptions {
1648
+ /**
1649
+ * Maximum number of *idle* sessions retained per pool key.
1650
+ *
1651
+ * Active leases are not counted against this limit — the cap only applies
1652
+ * to sessions waiting in the pool. When more than `maxIdlePerKey` sessions
1653
+ * become idle simultaneously, the oldest ones are disconnected. Defaults
1654
+ * to `4`.
1655
+ */
1656
+ maxIdlePerKey?: number;
1657
+ /**
1658
+ * How long an idle session may sit unused before it is automatically
1659
+ * disconnected. Defaults to `60_000` ms. Set to `0` to disable the timer
1660
+ * (idle sessions persist until `drainPool()` is called).
1661
+ */
1662
+ idleTimeoutMs?: number;
1663
+ /**
1664
+ * Custom pool key derivation. Receives the resolved
1665
+ * {@link ConnectionProfile} (after TransferClient validation) and must
1666
+ * return a string. Sessions with matching keys are pooled together; never
1667
+ * include secrets in the key.
1668
+ *
1669
+ * The default derives the key from `provider`, `host`, `port`, and
1670
+ * `username`.
1671
+ */
1672
+ keyOf?: (profile: ConnectionProfile) => string;
1673
+ }
1674
+ /**
1675
+ * Pool-aware {@link TransferClient} returned by
1676
+ * {@link createPooledTransferClient}.
1677
+ */
1678
+ interface PooledTransferClient {
1679
+ /** Opens (or leases) a pooled provider session. */
1680
+ connect(profile: ConnectionProfile): Promise<TransferSession>;
1681
+ /** Inspects the registered providers (delegated to the underlying client). */
1682
+ hasProvider(providerId: ProviderId): boolean;
1683
+ /** Returns the registered capability snapshots (delegated). */
1684
+ getCapabilities(): CapabilitySet[];
1685
+ /** Returns a specific capability snapshot (delegated). */
1686
+ getCapabilities(providerId: ProviderId): CapabilitySet;
1687
+ /**
1688
+ * Disconnects every idle session and prevents further pooling. After
1689
+ * `drainPool()` resolves, subsequent `connect()` calls still work but
1690
+ * always create fresh sessions (and never return them to the pool).
1691
+ */
1692
+ drainPool(): Promise<void>;
1693
+ /** Returns the number of idle sessions currently held in the pool. */
1694
+ poolSize(): number;
1695
+ }
1696
+ /**
1697
+ * Wraps a {@link TransferClient} with connection pooling.
1698
+ *
1699
+ * @param inner - Underlying client used to create real provider sessions.
1700
+ * @param options - Pool sizing, eviction, and key-derivation overrides.
1701
+ * @returns A {@link PooledTransferClient} that reuses idle sessions.
1702
+ */
1703
+ declare function createPooledTransferClient(inner: TransferClient, options?: ConnectionPoolOptions): PooledTransferClient;
1704
+
1646
1705
  /** Options used to create a local file-system provider factory. */
1647
1706
  interface LocalProviderOptions {
1648
1707
  /** Root directory exposed as `/`. When omitted, `profile.host` is treated as the root path. */
@@ -3194,7 +3253,14 @@ interface S3ProviderOptions {
3194
3253
  }
3195
3254
  /** Multipart upload tuning for the S3 provider. */
3196
3255
  interface S3MultipartOptions {
3197
- /** Enable multipart upload. Defaults to `false`. */
3256
+ /**
3257
+ * Enable multipart upload. **Defaults to `true`** so large objects stream
3258
+ * in fixed-size parts instead of being buffered in memory before a single
3259
+ * `PUT`. Payloads at or below {@link S3MultipartOptions.thresholdBytes}
3260
+ * still fall back to a single-shot `PUT` automatically. Set to `false` to
3261
+ * force the legacy single-shot behaviour (e.g. when targeting an
3262
+ * S3-compatible endpoint that does not support `CreateMultipartUpload`).
3263
+ */
3198
3264
  enabled?: boolean;
3199
3265
  /** Object size threshold in bytes above which multipart is used. Defaults to 8 MiB. */
3200
3266
  thresholdBytes?: number;
@@ -3240,6 +3306,41 @@ interface S3MultipartResumeStore {
3240
3306
  }
3241
3307
  /** Creates an in-memory {@link S3MultipartResumeStore}. */
3242
3308
  declare function createMemoryS3MultipartResumeStore(): S3MultipartResumeStore;
3309
+ /** Options for {@link createFileSystemS3MultipartResumeStore}. */
3310
+ interface FileSystemS3MultipartResumeStoreOptions {
3311
+ /**
3312
+ * Directory under which checkpoint JSON files are written. Created
3313
+ * recursively if it does not exist. Each upload occupies a single file
3314
+ * named after a SHA-256 hash of the resume key, so the directory is safe
3315
+ * to share across many concurrent uploads.
3316
+ */
3317
+ directory: string;
3318
+ }
3319
+ /**
3320
+ * File-system backed {@link S3MultipartResumeStore} that survives process
3321
+ * restarts. Each in-flight multipart upload is checkpointed to a single
3322
+ * JSON file in `options.directory` after every part. On retry the upload
3323
+ * reuses the stored `uploadId` and skips parts that S3 has already
3324
+ * accepted.
3325
+ *
3326
+ * The implementation writes atomically (`<file>.tmp` then `rename`) so a
3327
+ * crash mid-write cannot leave a corrupt checkpoint.
3328
+ *
3329
+ * @example
3330
+ * ```ts
3331
+ * import { createFileSystemS3MultipartResumeStore, createS3ProviderFactory }
3332
+ * from "@zero-transfer/sdk";
3333
+ *
3334
+ * const resumeStore = createFileSystemS3MultipartResumeStore({
3335
+ * directory: "./.zt-s3-resume",
3336
+ * });
3337
+ *
3338
+ * const factory = createS3ProviderFactory({
3339
+ * multipart: { enabled: true, resumeStore },
3340
+ * });
3341
+ * ```
3342
+ */
3343
+ declare function createFileSystemS3MultipartResumeStore(options: FileSystemS3MultipartResumeStoreOptions): S3MultipartResumeStore;
3243
3344
  /**
3244
3345
  * Creates an S3-compatible provider factory.
3245
3346
  *
@@ -3277,4 +3378,4 @@ declare function createMemoryS3MultipartResumeStore(): S3MultipartResumeStore;
3277
3378
  */
3278
3379
  declare function createS3ProviderFactory(options?: S3ProviderOptions): ProviderFactory;
3279
3380
 
3280
- export { AbortError, type AtomicDeployActivateOperation, type AtomicDeployActivateStep, type AtomicDeployPlan, type AtomicDeployPruneStep, type AtomicDeployStrategy, type AuthenticationCapability, AuthenticationError, AuthorizationError, type BandwidthSleep, type BandwidthThrottle, type BandwidthThrottleOptions, type Base64EnvSecretSource, type BuiltInProviderId, CLASSIC_PROVIDER_IDS, type CapabilitySet, type ChecksumCapability, type ClassicProviderId, type ClientDiagnostics, type CompareRemoteManifestsOptions, ConfigurationError, type ConnectionDiagnosticTimings, type ConnectionDiagnosticsResult, ConnectionError, type ConnectionProfile, type CopyBetweenOptions, type CreateAtomicDeployPlanOptions, type CreateRemoteBrowserOptions, type CreateRemoteManifestOptions, type CreateSyncPlanOptions, type DiffRemoteTreesOptions, type DownloadFileOptions, type EnvSecretSource, type FileSecretSource, type FileZillaSite, type FriendlyTransferOptions, type FtpReplyErrorInput, type ImportFileZillaSitesResult, type ImportOpenSshConfigOptions, type ImportOpenSshConfigResult, type ImportWinScpSessionsResult, type KnownHostsEntry, type KnownHostsMarker, type ListOptions, type LocalProviderOptions, type LogLevel, type LogRecord, type LogRecordInput, type LoggerMethod, type MemoryProviderEntry, type MemoryProviderOptions, type MetadataCapability, type MkdirOptions, type OAuthAccessToken, type OAuthRefreshCallback, type OAuthTokenSecretSourceOptions, type OpenSshConfigEntry, ParseError, PathAlreadyExistsError, PathNotFoundError, PermissionDeniedError, type ProgressEventInput, ProtocolError, type AuthenticationCapability as ProviderAuthenticationCapability, type CapabilitySet as ProviderCapabilities, type ChecksumCapability as ProviderChecksumCapability, type ProviderFactory, type ProviderId, type MetadataCapability as ProviderMetadataCapability, ProviderRegistry, type ProviderSelection, type ProviderTransferEndpointRole, type ProviderTransferExecutorOptions, type ProviderTransferOperations, type ProviderTransferReadRequest, type ProviderTransferReadResult, type ProviderTransferRequest, type ProviderTransferSessionResolver, type ProviderTransferSessionResolverInput, type ProviderTransferWriteRequest, type ProviderTransferWriteResult, REDACTED, REMOTE_MANIFEST_FORMAT_VERSION, type RemoteBreadcrumb, type RemoteBrowser, type RemoteBrowserFilter, type RemoteBrowserSnapshot, type RemoteEntry, type RemoteEntrySortKey, type RemoteEntrySortOrder, type RemoteEntryType, type RemoteFileAdapter, type RemoteFileEndpoint, type RemoteFileSystem, type RemoteManifest, type RemoteManifestEntry, type RemotePermissions, type RemoteProtocol, type RemoteStat, type RemoteTreeDiff, type RemoteTreeDiffEntry, type RemoteTreeDiffReason, type RemoteTreeDiffStatus, type RemoteTreeDiffSummary, type RemoteTreeEntry, type RemoteTreeFilter, type RemoveOptions, type RenameOptions, type ResolveSecretOptions, type ResolvedConnectionProfile, type ResolvedOpenSshHost, type ResolvedSshProfile, type ResolvedTlsProfile, type RmdirOptions, type RunConnectionDiagnosticsOptions, type S3MultipartCheckpoint, type S3MultipartOptions, type S3MultipartPart, type S3MultipartResumeKey, type S3MultipartResumeStore, type S3ProviderOptions, type SecretProvider, type SecretSource, type SecretValue, type SpecializedErrorDetails, type SshAgentSource, type SshAlgorithms, type SshKeyboardInteractiveChallenge, type SshKeyboardInteractiveHandler, type SshKeyboardInteractivePrompt, type SshKnownHostsSource, type SshProfile, type SshSocketFactory, type SshSocketFactoryContext, type StatOptions, type SyncConflictPolicy, type SyncDeletePolicy, type SyncDirection, type SyncEndpointInput, TimeoutError, type TlsProfile, type TlsSecretSource, type TransferAttempt, type TransferAttemptError, type TransferBandwidthLimit, type TransferByteRange, TransferClient, type TransferClientOptions, type TransferDataChunk, type TransferDataSource, type TransferEndpoint, TransferEngine, type TransferEngineExecuteOptions, type TransferEngineOptions, TransferError, type TransferExecutionContext, type TransferExecutionResult, type TransferExecutor, type TransferJob, type TransferOperation, type TransferPlan, type TransferPlanAction, type TransferPlanInput, type TransferPlanStep, type TransferPlanSummary, type TransferProgressEvent, type TransferProvider, TransferQueue, type TransferQueueExecutorResolver, type TransferQueueItem, type TransferQueueItemStatus, type TransferQueueOptions, type TransferQueueRunOptions, type TransferQueueSummary, type TransferReceipt, type TransferResult, type TransferResultInput, type TransferRetryDecisionInput, type TransferRetryPolicy, type TransferSession, type TransferTimeoutPolicy, type TransferVerificationResult, UnsupportedFeatureError, type UploadFileOptions, type ValueSecretSource, VerificationError, type WalkRemoteTreeOptions, type WinScpSession, ZeroTransfer, type ZeroTransferCapabilities, ZeroTransferError, type ZeroTransferErrorDetails, type ZeroTransferLogger, type ZeroTransferOptions, assertSafeFtpArgument, basenameRemotePath, buildRemoteBreadcrumbs, compareRemoteManifests, copyBetween, createAtomicDeployPlan, createBandwidthThrottle, createLocalProviderFactory, createMemoryProviderFactory, createMemoryS3MultipartResumeStore, createOAuthTokenSecretSource, createProgressEvent, createProviderTransferExecutor, createRemoteBrowser, createRemoteManifest, createS3ProviderFactory, createSyncPlan, createTransferClient, createTransferJobsFromPlan, createTransferPlan, createTransferResult, diffRemoteTrees, downloadFile, emitLog, errorFromFtpReply, filterRemoteEntries, importFileZillaSites, importOpenSshConfig, importWinScpSessions, isClassicProviderId, isSensitiveKey, joinRemotePath, matchKnownHosts, matchKnownHostsEntry, noopLogger, normalizeRemotePath, parentRemotePath, parseKnownHosts, parseOpenSshConfig, parseRemoteManifest, redactCommand, redactConnectionProfile, redactObject, redactSecretSource, redactValue, resolveConnectionProfileSecrets, resolveOpenSshHost, resolveProviderId, resolveSecret, runConnectionDiagnostics, serializeRemoteManifest, sortRemoteEntries, summarizeClientDiagnostics, summarizeTransferPlan, throttleByteIterable, uploadFile, validateConnectionProfile, walkRemoteTree };
3381
+ export { AbortError, type AtomicDeployActivateOperation, type AtomicDeployActivateStep, type AtomicDeployPlan, type AtomicDeployPruneStep, type AtomicDeployStrategy, type AuthenticationCapability, AuthenticationError, AuthorizationError, type BandwidthSleep, type BandwidthThrottle, type BandwidthThrottleOptions, type Base64EnvSecretSource, type BuiltInProviderId, CLASSIC_PROVIDER_IDS, type CapabilitySet, type ChecksumCapability, type ClassicProviderId, type ClientDiagnostics, type CompareRemoteManifestsOptions, ConfigurationError, type ConnectionDiagnosticTimings, type ConnectionDiagnosticsResult, ConnectionError, type ConnectionPoolOptions, type ConnectionProfile, type CopyBetweenOptions, type CreateAtomicDeployPlanOptions, type CreateRemoteBrowserOptions, type CreateRemoteManifestOptions, type CreateSyncPlanOptions, type DiffRemoteTreesOptions, type DownloadFileOptions, type EnvSecretSource, type FileSecretSource, type FileSystemS3MultipartResumeStoreOptions, type FileZillaSite, type FriendlyTransferOptions, type FtpReplyErrorInput, type ImportFileZillaSitesResult, type ImportOpenSshConfigOptions, type ImportOpenSshConfigResult, type ImportWinScpSessionsResult, type KnownHostsEntry, type KnownHostsMarker, type ListOptions, type LocalProviderOptions, type LogLevel, type LogRecord, type LogRecordInput, type LoggerMethod, type MemoryProviderEntry, type MemoryProviderOptions, type MetadataCapability, type MkdirOptions, type OAuthAccessToken, type OAuthRefreshCallback, type OAuthTokenSecretSourceOptions, type OpenSshConfigEntry, ParseError, PathAlreadyExistsError, PathNotFoundError, PermissionDeniedError, type PooledTransferClient, type ProgressEventInput, ProtocolError, type AuthenticationCapability as ProviderAuthenticationCapability, type CapabilitySet as ProviderCapabilities, type ChecksumCapability as ProviderChecksumCapability, type ProviderFactory, type ProviderId, type MetadataCapability as ProviderMetadataCapability, ProviderRegistry, type ProviderSelection, type ProviderTransferEndpointRole, type ProviderTransferExecutorOptions, type ProviderTransferOperations, type ProviderTransferReadRequest, type ProviderTransferReadResult, type ProviderTransferRequest, type ProviderTransferSessionResolver, type ProviderTransferSessionResolverInput, type ProviderTransferWriteRequest, type ProviderTransferWriteResult, REDACTED, REMOTE_MANIFEST_FORMAT_VERSION, type RemoteBreadcrumb, type RemoteBrowser, type RemoteBrowserFilter, type RemoteBrowserSnapshot, type RemoteEntry, type RemoteEntrySortKey, type RemoteEntrySortOrder, type RemoteEntryType, type RemoteFileAdapter, type RemoteFileEndpoint, type RemoteFileSystem, type RemoteManifest, type RemoteManifestEntry, type RemotePermissions, type RemoteProtocol, type RemoteStat, type RemoteTreeDiff, type RemoteTreeDiffEntry, type RemoteTreeDiffReason, type RemoteTreeDiffStatus, type RemoteTreeDiffSummary, type RemoteTreeEntry, type RemoteTreeFilter, type RemoveOptions, type RenameOptions, type ResolveSecretOptions, type ResolvedConnectionProfile, type ResolvedOpenSshHost, type ResolvedSshProfile, type ResolvedTlsProfile, type RmdirOptions, type RunConnectionDiagnosticsOptions, type S3MultipartCheckpoint, type S3MultipartOptions, type S3MultipartPart, type S3MultipartResumeKey, type S3MultipartResumeStore, type S3ProviderOptions, type SecretProvider, type SecretSource, type SecretValue, type SpecializedErrorDetails, type SshAgentSource, type SshAlgorithms, type SshKeyboardInteractiveChallenge, type SshKeyboardInteractiveHandler, type SshKeyboardInteractivePrompt, type SshKnownHostsSource, type SshProfile, type SshSocketFactory, type SshSocketFactoryContext, type StatOptions, type SyncConflictPolicy, type SyncDeletePolicy, type SyncDirection, type SyncEndpointInput, TimeoutError, type TlsProfile, type TlsSecretSource, type TransferAttempt, type TransferAttemptError, type TransferBandwidthLimit, type TransferByteRange, TransferClient, type TransferClientOptions, type TransferDataChunk, type TransferDataSource, type TransferEndpoint, TransferEngine, type TransferEngineExecuteOptions, type TransferEngineOptions, TransferError, type TransferExecutionContext, type TransferExecutionResult, type TransferExecutor, type TransferJob, type TransferOperation, type TransferPlan, type TransferPlanAction, type TransferPlanInput, type TransferPlanStep, type TransferPlanSummary, type TransferProgressEvent, type TransferProvider, TransferQueue, type TransferQueueExecutorResolver, type TransferQueueItem, type TransferQueueItemStatus, type TransferQueueOptions, type TransferQueueRunOptions, type TransferQueueSummary, type TransferReceipt, type TransferResult, type TransferResultInput, type TransferRetryDecisionInput, type TransferRetryPolicy, type TransferSession, type TransferTimeoutPolicy, type TransferVerificationResult, UnsupportedFeatureError, type UploadFileOptions, type ValueSecretSource, VerificationError, type WalkRemoteTreeOptions, type WinScpSession, ZeroTransfer, type ZeroTransferCapabilities, ZeroTransferError, type ZeroTransferErrorDetails, type ZeroTransferLogger, type ZeroTransferOptions, assertSafeFtpArgument, basenameRemotePath, buildRemoteBreadcrumbs, compareRemoteManifests, copyBetween, createAtomicDeployPlan, createBandwidthThrottle, createFileSystemS3MultipartResumeStore, createLocalProviderFactory, createMemoryProviderFactory, createMemoryS3MultipartResumeStore, createOAuthTokenSecretSource, createPooledTransferClient, createProgressEvent, createProviderTransferExecutor, createRemoteBrowser, createRemoteManifest, createS3ProviderFactory, createSyncPlan, createTransferClient, createTransferJobsFromPlan, createTransferPlan, createTransferResult, diffRemoteTrees, downloadFile, emitLog, errorFromFtpReply, filterRemoteEntries, importFileZillaSites, importOpenSshConfig, importWinScpSessions, isClassicProviderId, isSensitiveKey, joinRemotePath, matchKnownHosts, matchKnownHostsEntry, noopLogger, normalizeRemotePath, parentRemotePath, parseKnownHosts, parseOpenSshConfig, parseRemoteManifest, redactCommand, redactConnectionProfile, redactObject, redactSecretSource, redactValue, resolveConnectionProfileSecrets, resolveOpenSshHost, resolveProviderId, resolveSecret, runConnectionDiagnostics, serializeRemoteManifest, sortRemoteEntries, summarizeClientDiagnostics, summarizeTransferPlan, throttleByteIterable, uploadFile, validateConnectionProfile, walkRemoteTree };
package/dist/index.mjs CHANGED
@@ -1767,6 +1767,186 @@ function summarizeDiagnosticError(error) {
1767
1767
  return { message: String(error) };
1768
1768
  }
1769
1769
 
1770
+ // src/core/ConnectionPool.ts
1771
+ var DEFAULT_MAX_IDLE_PER_KEY = 4;
1772
+ var DEFAULT_IDLE_TIMEOUT_MS = 6e4;
1773
+ function createPooledTransferClient(inner, options = {}) {
1774
+ const maxIdlePerKey = Math.max(1, options.maxIdlePerKey ?? DEFAULT_MAX_IDLE_PER_KEY);
1775
+ const idleTimeoutMs = Math.max(0, options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS);
1776
+ const keyOf = options.keyOf ?? defaultKeyOf;
1777
+ const state = {
1778
+ drained: false,
1779
+ idle: /* @__PURE__ */ new Map()
1780
+ };
1781
+ const release = (key, session, tainted) => {
1782
+ if (tainted || state.drained) {
1783
+ return safelyDisconnect(session);
1784
+ }
1785
+ let bucket = state.idle.get(key);
1786
+ if (bucket === void 0) {
1787
+ bucket = [];
1788
+ state.idle.set(key, bucket);
1789
+ }
1790
+ const entry = { session };
1791
+ if (idleTimeoutMs > 0) {
1792
+ entry.idleTimer = setTimeout(() => {
1793
+ evictEntry(state, key, entry);
1794
+ }, idleTimeoutMs);
1795
+ const timer = entry.idleTimer;
1796
+ if (timer !== void 0 && typeof timer.unref === "function") {
1797
+ timer.unref();
1798
+ }
1799
+ }
1800
+ bucket.push(entry);
1801
+ while (bucket.length > maxIdlePerKey) {
1802
+ const dropped = bucket.shift();
1803
+ if (dropped !== void 0) {
1804
+ clearEntryTimer(dropped);
1805
+ void safelyDisconnect(dropped.session);
1806
+ }
1807
+ }
1808
+ return Promise.resolve();
1809
+ };
1810
+ const acquire = async (profile) => {
1811
+ const key = keyOf(profile);
1812
+ const bucket = state.idle.get(key);
1813
+ if (bucket !== void 0 && bucket.length > 0) {
1814
+ const entry = bucket.pop();
1815
+ if (entry !== void 0) {
1816
+ clearEntryTimer(entry);
1817
+ if (bucket.length === 0) state.idle.delete(key);
1818
+ return { key, session: entry.session };
1819
+ }
1820
+ }
1821
+ const session = await inner.connect(profile);
1822
+ return { key, session };
1823
+ };
1824
+ return {
1825
+ connect: async (profile) => {
1826
+ const { key, session } = await acquire(profile);
1827
+ return wrapPooledSession(session, key, release);
1828
+ },
1829
+ drainPool: async () => {
1830
+ state.drained = true;
1831
+ const entries = [];
1832
+ for (const bucket of state.idle.values()) {
1833
+ for (const entry of bucket) {
1834
+ clearEntryTimer(entry);
1835
+ entries.push(entry);
1836
+ }
1837
+ }
1838
+ state.idle.clear();
1839
+ await Promise.all(entries.map((entry) => safelyDisconnect(entry.session)));
1840
+ },
1841
+ getCapabilities: ((providerId) => {
1842
+ if (providerId === void 0) return inner.getCapabilities();
1843
+ return inner.getCapabilities(providerId);
1844
+ }),
1845
+ hasProvider: (providerId) => inner.hasProvider(providerId),
1846
+ poolSize: () => {
1847
+ let total = 0;
1848
+ for (const bucket of state.idle.values()) total += bucket.length;
1849
+ return total;
1850
+ }
1851
+ };
1852
+ }
1853
+ function defaultKeyOf(profile) {
1854
+ const provider = profile.provider ?? profile.protocol ?? "unknown";
1855
+ const host = profile.host ?? "";
1856
+ const port = profile.port ?? "";
1857
+ const username = typeof profile.username === "string" ? profile.username : "";
1858
+ return `${provider}|${host}|${String(port)}|${username}`;
1859
+ }
1860
+ function evictEntry(state, key, entry) {
1861
+ const bucket = state.idle.get(key);
1862
+ if (bucket === void 0) return;
1863
+ const index = bucket.indexOf(entry);
1864
+ if (index < 0) return;
1865
+ bucket.splice(index, 1);
1866
+ if (bucket.length === 0) state.idle.delete(key);
1867
+ clearEntryTimer(entry);
1868
+ void safelyDisconnect(entry.session);
1869
+ }
1870
+ function clearEntryTimer(entry) {
1871
+ if (entry.idleTimer !== void 0) {
1872
+ clearTimeout(entry.idleTimer);
1873
+ delete entry.idleTimer;
1874
+ }
1875
+ }
1876
+ async function safelyDisconnect(session) {
1877
+ try {
1878
+ await session.disconnect();
1879
+ } catch {
1880
+ }
1881
+ }
1882
+ function isTaintingError(error) {
1883
+ return error instanceof ConnectionError || error instanceof TimeoutError || error instanceof ProtocolError;
1884
+ }
1885
+ function wrapPooledSession(session, key, release) {
1886
+ let tainted = false;
1887
+ let released = false;
1888
+ const guard = (fn) => {
1889
+ let promise;
1890
+ try {
1891
+ promise = fn();
1892
+ } catch (error) {
1893
+ if (isTaintingError(error)) tainted = true;
1894
+ return Promise.reject(error instanceof Error ? error : new Error(String(error)));
1895
+ }
1896
+ return promise.catch((error) => {
1897
+ if (isTaintingError(error)) tainted = true;
1898
+ throw error;
1899
+ });
1900
+ };
1901
+ const fs = wrapFs(session.fs, guard);
1902
+ const transfers = session.transfers === void 0 ? void 0 : wrapTransfers(session.transfers, guard);
1903
+ const wrapped = {
1904
+ capabilities: session.capabilities,
1905
+ disconnect: async () => {
1906
+ if (released) return;
1907
+ released = true;
1908
+ await release(key, session, tainted);
1909
+ },
1910
+ fs,
1911
+ provider: session.provider,
1912
+ ...transfers !== void 0 ? { transfers } : {}
1913
+ };
1914
+ if (typeof session.raw === "function") {
1915
+ const rawFn = session.raw.bind(session);
1916
+ wrapped.raw = () => rawFn();
1917
+ }
1918
+ return wrapped;
1919
+ }
1920
+ function wrapFs(fs, guard) {
1921
+ const wrapped = {
1922
+ list: (path2, options) => guard(() => options !== void 0 ? fs.list(path2, options) : fs.list(path2)),
1923
+ stat: (path2, options) => guard(() => options !== void 0 ? fs.stat(path2, options) : fs.stat(path2))
1924
+ };
1925
+ if (typeof fs.remove === "function") {
1926
+ const remove = fs.remove.bind(fs);
1927
+ wrapped.remove = (path2, options) => guard(() => options !== void 0 ? remove(path2, options) : remove(path2));
1928
+ }
1929
+ if (typeof fs.rename === "function") {
1930
+ const rename2 = fs.rename.bind(fs);
1931
+ wrapped.rename = (from, to, options) => guard(() => options !== void 0 ? rename2(from, to, options) : rename2(from, to));
1932
+ }
1933
+ if (typeof fs.mkdir === "function") {
1934
+ const mkdir2 = fs.mkdir.bind(fs);
1935
+ wrapped.mkdir = (path2, options) => guard(() => options !== void 0 ? mkdir2(path2, options) : mkdir2(path2));
1936
+ }
1937
+ if (typeof fs.rmdir === "function") {
1938
+ const rmdir = fs.rmdir.bind(fs);
1939
+ wrapped.rmdir = (path2, options) => guard(() => options !== void 0 ? rmdir(path2, options) : rmdir(path2));
1940
+ }
1941
+ return wrapped;
1942
+ }
1943
+ function wrapTransfers(transfers, guard) {
1944
+ return {
1945
+ read: (request) => guard(() => Promise.resolve(transfers.read(request))),
1946
+ write: (request) => guard(() => Promise.resolve(transfers.write(request)))
1947
+ };
1948
+ }
1949
+
1770
1950
  // src/providers/local/LocalProvider.ts
1771
1951
  import { createReadStream } from "fs";
1772
1952
  import {
@@ -4605,6 +4785,17 @@ function isModifiedAtDifferent2(source, destination, toleranceMs) {
4605
4785
  return Math.abs(sourceTime - destinationTime) > toleranceMs;
4606
4786
  }
4607
4787
 
4788
+ // src/providers/web/S3Provider.ts
4789
+ import { createHash as createHash2 } from "crypto";
4790
+ import {
4791
+ mkdir as fsMkdir,
4792
+ readFile as fsReadFile,
4793
+ rename as fsRename,
4794
+ unlink as fsUnlink,
4795
+ writeFile as fsWriteFile
4796
+ } from "fs/promises";
4797
+ import { join as joinPath } from "path";
4798
+
4608
4799
  // src/providers/web/awsSigv4.ts
4609
4800
  import { createHash, createHmac as createHmac2 } from "crypto";
4610
4801
  function signSigV4(input) {
@@ -4775,6 +4966,48 @@ function createMemoryS3MultipartResumeStore() {
4775
4966
  }
4776
4967
  };
4777
4968
  }
4969
+ function createFileSystemS3MultipartResumeStore(options) {
4970
+ const directory = options.directory;
4971
+ if (typeof directory !== "string" || directory.length === 0) {
4972
+ throw new ConfigurationError({
4973
+ message: "createFileSystemS3MultipartResumeStore requires a non-empty directory option",
4974
+ retryable: false
4975
+ });
4976
+ }
4977
+ const fileFor = (key) => {
4978
+ const hash = createHash2("sha256").update(`${key.bucket}\0${key.jobId}\0${key.path}`).digest("hex");
4979
+ return joinPath(directory, `${hash}.json`);
4980
+ };
4981
+ return {
4982
+ async clear(key) {
4983
+ try {
4984
+ await fsUnlink(fileFor(key));
4985
+ } catch (error) {
4986
+ if (error.code !== "ENOENT") throw error;
4987
+ }
4988
+ },
4989
+ async load(key) {
4990
+ try {
4991
+ const text = await fsReadFile(fileFor(key), "utf8");
4992
+ const parsed = JSON.parse(text);
4993
+ if (typeof parsed !== "object" || parsed === null || typeof parsed.uploadId !== "string" || !Array.isArray(parsed.parts)) {
4994
+ return void 0;
4995
+ }
4996
+ return parsed;
4997
+ } catch (error) {
4998
+ if (error.code === "ENOENT") return void 0;
4999
+ throw error;
5000
+ }
5001
+ },
5002
+ async save(key, checkpoint) {
5003
+ await fsMkdir(directory, { recursive: true });
5004
+ const target = fileFor(key);
5005
+ const tmp = `${target}.${String(process.pid)}.${String(Date.now())}.tmp`;
5006
+ await fsWriteFile(tmp, JSON.stringify(checkpoint), { encoding: "utf8", mode: 384 });
5007
+ await fsRename(tmp, target);
5008
+ }
5009
+ };
5010
+ }
4778
5011
  var DEFAULT_MULTIPART_PART_SIZE = 8 * 1024 * 1024;
4779
5012
  var DEFAULT_MULTIPART_THRESHOLD = 8 * 1024 * 1024;
4780
5013
  var S3_CHECKSUM_CAPABILITIES = ["etag"];
@@ -4802,7 +5035,7 @@ function createS3ProviderFactory(options = {}) {
4802
5035
  retryable: false
4803
5036
  });
4804
5037
  }
4805
- const multipartEnabled = options.multipart?.enabled ?? false;
5038
+ const multipartEnabled = options.multipart?.enabled ?? true;
4806
5039
  const multipart = {
4807
5040
  enabled: multipartEnabled,
4808
5041
  partSizeBytes: options.multipart?.partSizeBytes ?? DEFAULT_MULTIPART_PART_SIZE,
@@ -4819,9 +5052,11 @@ function createS3ProviderFactory(options = {}) {
4819
5052
  maxConcurrency: 16,
4820
5053
  metadata: ["modifiedAt", "mimeType", "uniqueId"],
4821
5054
  notes: multipartEnabled ? [
4822
- `S3 multipart upload enabled (partSize=${String(multipart.partSizeBytes)}B, threshold=${String(multipart.thresholdBytes)}B).`
5055
+ `S3 multipart upload enabled by default (partSize=${String(multipart.partSizeBytes)}B, threshold=${String(multipart.thresholdBytes)}B).`,
5056
+ "Payloads at or below the threshold automatically fall back to single-shot PUT.",
5057
+ "Pass `multipart: { enabled: false }` to force the legacy single-shot behaviour."
4823
5058
  ] : [
4824
- "S3 provider performs single-shot PUT uploads; pass multipart.enabled to stream large objects."
5059
+ "S3 provider performs single-shot PUT uploads; entire object is buffered in memory before transmission."
4825
5060
  ],
4826
5061
  provider: id,
4827
5062
  readStream: true,
@@ -5427,10 +5662,12 @@ export {
5427
5662
  copyBetween,
5428
5663
  createAtomicDeployPlan,
5429
5664
  createBandwidthThrottle,
5665
+ createFileSystemS3MultipartResumeStore,
5430
5666
  createLocalProviderFactory,
5431
5667
  createMemoryProviderFactory,
5432
5668
  createMemoryS3MultipartResumeStore,
5433
5669
  createOAuthTokenSecretSource,
5670
+ createPooledTransferClient,
5434
5671
  createProgressEvent,
5435
5672
  createProviderTransferExecutor,
5436
5673
  createRemoteBrowser,