@zero-transfer/sftp 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/dist/index.cjs CHANGED
@@ -60,16 +60,16 @@ __export(sftp_exports, {
60
60
  copyBetween: () => copyBetween,
61
61
  createAtomicDeployPlan: () => createAtomicDeployPlan,
62
62
  createBandwidthThrottle: () => createBandwidthThrottle,
63
+ createDefaultRetryPolicy: () => createDefaultRetryPolicy,
63
64
  createLocalProviderFactory: () => createLocalProviderFactory,
64
65
  createMemoryProviderFactory: () => createMemoryProviderFactory,
65
- createNativeSftpProviderFactory: () => createNativeSftpProviderFactory,
66
66
  createOAuthTokenSecretSource: () => createOAuthTokenSecretSource,
67
67
  createPooledTransferClient: () => createPooledTransferClient,
68
68
  createProgressEvent: () => createProgressEvent,
69
69
  createProviderTransferExecutor: () => createProviderTransferExecutor,
70
70
  createRemoteBrowser: () => createRemoteBrowser,
71
71
  createRemoteManifest: () => createRemoteManifest,
72
- createSftpProviderFactory: () => createNativeSftpProviderFactory,
72
+ createSftpProviderFactory: () => createSftpProviderFactory,
73
73
  createSyncPlan: () => createSyncPlan,
74
74
  createTransferClient: () => createTransferClient,
75
75
  createTransferJobsFromPlan: () => createTransferJobsFromPlan,
@@ -97,8 +97,10 @@ __export(sftp_exports, {
97
97
  parseRemoteManifest: () => parseRemoteManifest,
98
98
  redactCommand: () => redactCommand,
99
99
  redactConnectionProfile: () => redactConnectionProfile,
100
+ redactErrorForLogging: () => redactErrorForLogging,
100
101
  redactObject: () => redactObject,
101
102
  redactSecretSource: () => redactSecretSource,
103
+ redactUrlForLogging: () => redactUrlForLogging,
102
104
  redactValue: () => redactValue,
103
105
  resolveConnectionProfileSecrets: () => resolveConnectionProfileSecrets,
104
106
  resolveOpenSshHost: () => resolveOpenSshHost,
@@ -119,6 +121,68 @@ module.exports = __toCommonJS(sftp_exports);
119
121
  // src/client/ZeroTransfer.ts
120
122
  var import_node_events = require("events");
121
123
 
124
+ // src/logging/redaction.ts
125
+ var REDACTED = "[REDACTED]";
126
+ var SENSITIVE_KEY_PATTERN = /(?:password|passphrase|privatekey|token|secret|username|user)$/i;
127
+ var SECRET_COMMAND_PATTERN = /^(PASS|USER|ACCT)\s+(.+)$/i;
128
+ var URL_KEY_PATTERN = /(?:url|uri|href)$/i;
129
+ function isSensitiveKey(key) {
130
+ return SENSITIVE_KEY_PATTERN.test(key.replace(/[_-]/g, ""));
131
+ }
132
+ function redactCommand(command) {
133
+ return command.replace(SECRET_COMMAND_PATTERN, (_fullMatch, commandName) => {
134
+ return `${commandName.toUpperCase()} ${REDACTED}`;
135
+ });
136
+ }
137
+ function redactValue(value) {
138
+ if (typeof value === "string") {
139
+ return redactCommand(value);
140
+ }
141
+ if (Array.isArray(value)) {
142
+ return value.map((item) => redactValue(item));
143
+ }
144
+ if (value !== null && typeof value === "object") {
145
+ return redactObject(value);
146
+ }
147
+ return value;
148
+ }
149
+ function redactObject(input) {
150
+ return Object.fromEntries(
151
+ Object.entries(input).map(([key, value]) => {
152
+ if (isSensitiveKey(key)) {
153
+ return [key, REDACTED];
154
+ }
155
+ if (URL_KEY_PATTERN.test(key) && typeof value === "string") {
156
+ return [key, redactUrlForLogging(value)];
157
+ }
158
+ return [key, redactValue(value)];
159
+ })
160
+ );
161
+ }
162
+ function redactUrlForLogging(url) {
163
+ let parsed;
164
+ try {
165
+ parsed = typeof url === "string" ? new URL(url) : url;
166
+ } catch {
167
+ return REDACTED;
168
+ }
169
+ const origin = parsed.host.length > 0 ? `${parsed.protocol}//${parsed.host}` : parsed.protocol;
170
+ const query = parsed.search.length > 0 ? `?${REDACTED}` : "";
171
+ return `${origin}${parsed.pathname}${query}`;
172
+ }
173
+ function redactErrorForLogging(error) {
174
+ if (error !== null && typeof error === "object") {
175
+ const candidate = error;
176
+ if (typeof candidate.toJSON === "function") {
177
+ return redactObject(candidate.toJSON());
178
+ }
179
+ }
180
+ if (error instanceof Error) {
181
+ return redactObject({ message: error.message, name: error.name });
182
+ }
183
+ return { message: redactValue(typeof error === "string" ? error : String(error)) };
184
+ }
185
+
122
186
  // src/errors/ZeroTransferError.ts
123
187
  var ZeroTransferError = class extends Error {
124
188
  /** Stable machine-readable error code. */
@@ -160,6 +224,11 @@ var ZeroTransferError = class extends Error {
160
224
  /**
161
225
  * Serializes the error into a plain object suitable for logs or API responses.
162
226
  *
227
+ * `details` and `command` are passed through secret redaction so serialized
228
+ * errors never leak credentials, signed URLs, or raw protocol commands. The
229
+ * live {@link ZeroTransferError.details | details} property stays unredacted
230
+ * for programmatic consumers.
231
+ *
163
232
  * @returns A JSON-safe object containing public structured error fields.
164
233
  */
165
234
  toJSON() {
@@ -169,12 +238,12 @@ var ZeroTransferError = class extends Error {
169
238
  message: this.message,
170
239
  protocol: this.protocol,
171
240
  host: this.host,
172
- command: this.command,
241
+ command: this.command === void 0 ? void 0 : redactCommand(this.command),
173
242
  ftpCode: this.ftpCode,
174
243
  sftpCode: this.sftpCode,
175
244
  path: this.path,
176
245
  retryable: this.retryable,
177
- details: this.details
246
+ details: this.details === void 0 ? void 0 : redactObject(this.details)
178
247
  };
179
248
  }
180
249
  };
@@ -697,15 +766,20 @@ var ProviderRegistry = class {
697
766
  var TransferClient = class {
698
767
  /** Provider registry used by this client. */
699
768
  registry;
769
+ /** Execution defaults applied when call sites omit their own values. */
770
+ defaults;
700
771
  logger;
701
772
  /**
702
773
  * Creates a transfer client without opening any provider connections.
703
774
  *
704
- * @param options - Optional registry, provider factories, and logger.
775
+ * @param options - Optional registry, provider factories, logger, and execution defaults.
705
776
  */
706
777
  constructor(options = {}) {
707
778
  this.registry = options.registry ?? new ProviderRegistry();
708
779
  this.logger = options.logger ?? noopLogger;
780
+ if (options.defaults !== void 0) {
781
+ this.defaults = { ...options.defaults };
782
+ }
709
783
  for (const provider of options.providers ?? []) {
710
784
  this.registry.register(provider);
711
785
  }
@@ -1278,18 +1352,25 @@ var TransferEngine = class {
1278
1352
  for (let attemptNumber = 1; attemptNumber <= maxAttempts; attemptNumber += 1) {
1279
1353
  this.throwIfAborted(abortScope.signal, job);
1280
1354
  const attemptStartedAt = this.now();
1355
+ const attemptScope = createAttemptScope(
1356
+ abortScope.signal,
1357
+ options.timeout,
1358
+ job,
1359
+ attemptNumber
1360
+ );
1281
1361
  const context = this.createExecutionContext(
1282
1362
  job,
1283
1363
  attemptNumber,
1284
1364
  attemptStartedAt,
1285
1365
  options,
1286
- abortScope.signal,
1366
+ attemptScope.signal,
1287
1367
  (bytesTransferred) => {
1288
1368
  latestBytesTransferred = bytesTransferred;
1289
- }
1369
+ },
1370
+ attemptScope.notifyProgress
1290
1371
  );
1291
1372
  try {
1292
- const result = await runExecutor(executor, context, abortScope.signal, job);
1373
+ const result = await runExecutor(executor, context, attemptScope.signal, job);
1293
1374
  context.throwIfAborted();
1294
1375
  latestBytesTransferred = result.bytesTransferred;
1295
1376
  const completedAt = this.now();
@@ -1307,16 +1388,27 @@ var TransferEngine = class {
1307
1388
  summarizeError(error)
1308
1389
  );
1309
1390
  attempts.push(attempt);
1310
- if (error instanceof AbortError || error instanceof TimeoutError) {
1391
+ if (error instanceof AbortError || abortScope.signal?.aborted === true) {
1311
1392
  throw error;
1312
1393
  }
1313
- const retryInput = { attempt: attemptNumber, error, job };
1394
+ const retryInput = {
1395
+ attempt: attemptNumber,
1396
+ elapsedMs: Math.max(0, completedAt.getTime() - startedAt.getTime()),
1397
+ error,
1398
+ job
1399
+ };
1314
1400
  const shouldRetry = attemptNumber < maxAttempts && (options.retry?.shouldRetry?.(retryInput) ?? isRetryable(error));
1315
1401
  if (shouldRetry) {
1316
1402
  options.retry?.onRetry?.(retryInput);
1403
+ const delayMs = normalizeDelayMs(options.retry?.getDelayMs?.(retryInput));
1404
+ if (delayMs > 0) {
1405
+ await sleepWithAbort(delayMs, abortScope.signal, job);
1406
+ }
1317
1407
  continue;
1318
1408
  }
1319
1409
  throw createTransferFailure(job, error, attempts);
1410
+ } finally {
1411
+ attemptScope.dispose();
1320
1412
  }
1321
1413
  }
1322
1414
  throw createTransferFailure(job, void 0, attempts);
@@ -1324,12 +1416,13 @@ var TransferEngine = class {
1324
1416
  abortScope.dispose();
1325
1417
  }
1326
1418
  }
1327
- createExecutionContext(job, attempt, startedAt, options, signal, updateBytesTransferred) {
1419
+ createExecutionContext(job, attempt, startedAt, options, signal, updateBytesTransferred, notifyProgress) {
1328
1420
  const context = {
1329
1421
  attempt,
1330
1422
  job,
1331
1423
  reportProgress: (bytesTransferred, totalBytes) => {
1332
1424
  this.throwIfAborted(signal, job);
1425
+ notifyProgress();
1333
1426
  updateBytesTransferred(bytesTransferred);
1334
1427
  const progressInput = {
1335
1428
  bytesTransferred,
@@ -1398,6 +1491,96 @@ function createAbortScope(parentSignal, timeout, job) {
1398
1491
  signal: controller.signal
1399
1492
  };
1400
1493
  }
1494
+ function createAttemptScope(parentSignal, timeout, job, attempt) {
1495
+ const attemptTimeoutMs = normalizeTimeoutMs(timeout?.attemptTimeoutMs);
1496
+ const stallTimeoutMs = normalizeTimeoutMs(timeout?.stallTimeoutMs);
1497
+ if (attemptTimeoutMs === void 0 && stallTimeoutMs === void 0) {
1498
+ const scope = {
1499
+ dispose: () => void 0,
1500
+ notifyProgress: () => void 0
1501
+ };
1502
+ if (parentSignal !== void 0) scope.signal = parentSignal;
1503
+ return scope;
1504
+ }
1505
+ const controller = new AbortController();
1506
+ const retryable = timeout?.retryable ?? true;
1507
+ const abortFromParent = () => controller.abort(parentSignal?.reason);
1508
+ if (parentSignal?.aborted === true) {
1509
+ abortFromParent();
1510
+ } else {
1511
+ parentSignal?.addEventListener("abort", abortFromParent, { once: true });
1512
+ }
1513
+ const attemptTimer = attemptTimeoutMs === void 0 ? void 0 : setTimeout(() => {
1514
+ controller.abort(
1515
+ new TimeoutError({
1516
+ details: { attempt, attemptTimeoutMs, jobId: job.id, operation: job.operation },
1517
+ message: `Transfer attempt ${String(attempt)} timed out after ${String(attemptTimeoutMs)}ms: ${job.id}`,
1518
+ retryable
1519
+ })
1520
+ );
1521
+ }, attemptTimeoutMs);
1522
+ let stallTimer;
1523
+ const armStallWatchdog = () => {
1524
+ if (stallTimeoutMs === void 0 || controller.signal.aborted) return;
1525
+ if (stallTimer !== void 0) clearTimeout(stallTimer);
1526
+ stallTimer = setTimeout(() => {
1527
+ controller.abort(
1528
+ new TimeoutError({
1529
+ details: { attempt, jobId: job.id, operation: job.operation, stallTimeoutMs },
1530
+ message: `Transfer attempt ${String(attempt)} stalled (no progress for ${String(stallTimeoutMs)}ms): ${job.id}`,
1531
+ retryable
1532
+ })
1533
+ );
1534
+ }, stallTimeoutMs);
1535
+ };
1536
+ armStallWatchdog();
1537
+ return {
1538
+ dispose: () => {
1539
+ if (attemptTimer !== void 0) clearTimeout(attemptTimer);
1540
+ if (stallTimer !== void 0) clearTimeout(stallTimer);
1541
+ parentSignal?.removeEventListener("abort", abortFromParent);
1542
+ },
1543
+ notifyProgress: armStallWatchdog,
1544
+ signal: controller.signal
1545
+ };
1546
+ }
1547
+ function sleepWithAbort(delayMs, signal, job) {
1548
+ return new Promise((resolve, reject) => {
1549
+ if (signal === void 0) {
1550
+ setTimeout(resolve, delayMs);
1551
+ return;
1552
+ }
1553
+ if (signal.aborted) {
1554
+ reject(toAbortFailure(signal, job));
1555
+ return;
1556
+ }
1557
+ const rejectAbort = () => {
1558
+ clearTimeout(timer);
1559
+ reject(toAbortFailure(signal, job));
1560
+ };
1561
+ const timer = setTimeout(() => {
1562
+ signal.removeEventListener("abort", rejectAbort);
1563
+ resolve();
1564
+ }, delayMs);
1565
+ signal.addEventListener("abort", rejectAbort, { once: true });
1566
+ });
1567
+ }
1568
+ function toAbortFailure(signal, job) {
1569
+ if (signal.reason instanceof ZeroTransferError) {
1570
+ return signal.reason;
1571
+ }
1572
+ return new AbortError({
1573
+ details: { jobId: job.id, operation: job.operation },
1574
+ message: `Transfer job aborted: ${job.id}`,
1575
+ retryable: false
1576
+ });
1577
+ }
1578
+ function normalizeDelayMs(value) {
1579
+ if (value === void 0 || !Number.isFinite(value) || value <= 0) {
1580
+ return 0;
1581
+ }
1582
+ return Math.floor(value);
1583
+ }
1401
1584
  function normalizeTimeoutMs(value) {
1402
1585
  if (value === void 0 || !Number.isFinite(value) || value <= 0) {
1403
1586
  return void 0;
@@ -1566,7 +1749,7 @@ async function runRoute(options) {
1566
1749
  const executor = createProviderTransferExecutor({
1567
1750
  resolveSession: ({ role }) => sessions.get(role)
1568
1751
  });
1569
- return await engine.execute(job, executor, buildExecuteOptions(options));
1752
+ return await engine.execute(job, executor, buildExecuteOptions(options, client));
1570
1753
  } finally {
1571
1754
  if (destinationSession !== void 0) {
1572
1755
  await destinationSession.disconnect();
@@ -1603,12 +1786,14 @@ function defaultJobId(route, now) {
1603
1786
  const timestamp = (now?.() ?? /* @__PURE__ */ new Date()).getTime();
1604
1787
  return `route:${route.id}:${timestamp.toString(36)}`;
1605
1788
  }
1606
- function buildExecuteOptions(options) {
1789
+ function buildExecuteOptions(options, client) {
1607
1790
  const execute = {};
1791
+ const retry = options.retry ?? client.defaults?.retry;
1792
+ const timeout = options.timeout ?? client.defaults?.timeout;
1608
1793
  if (options.signal !== void 0) execute.signal = options.signal;
1609
- if (options.retry !== void 0) execute.retry = options.retry;
1794
+ if (retry !== void 0) execute.retry = retry;
1610
1795
  if (options.onProgress !== void 0) execute.onProgress = options.onProgress;
1611
- if (options.timeout !== void 0) execute.timeout = options.timeout;
1796
+ if (timeout !== void 0) execute.timeout = timeout;
1612
1797
  if (options.bandwidthLimit !== void 0) execute.bandwidthLimit = options.bandwidthLimit;
1613
1798
  return execute;
1614
1799
  }
@@ -1665,41 +1850,6 @@ function defaultRouteSuffix(source, destination) {
1665
1850
  return `${source}->${destination}`;
1666
1851
  }
1667
1852
 
1668
- // src/logging/redaction.ts
1669
- var REDACTED = "[REDACTED]";
1670
- var SENSITIVE_KEY_PATTERN = /(?:password|passphrase|privatekey|token|secret|username|user)$/i;
1671
- var SECRET_COMMAND_PATTERN = /^(PASS|USER|ACCT)\s+(.+)$/i;
1672
- function isSensitiveKey(key) {
1673
- return SENSITIVE_KEY_PATTERN.test(key.replace(/[_-]/g, ""));
1674
- }
1675
- function redactCommand(command) {
1676
- return command.replace(SECRET_COMMAND_PATTERN, (_fullMatch, commandName) => {
1677
- return `${commandName.toUpperCase()} ${REDACTED}`;
1678
- });
1679
- }
1680
- function redactValue(value) {
1681
- if (typeof value === "string") {
1682
- return redactCommand(value);
1683
- }
1684
- if (Array.isArray(value)) {
1685
- return value.map((item) => redactValue(item));
1686
- }
1687
- if (value !== null && typeof value === "object") {
1688
- return redactObject(value);
1689
- }
1690
- return value;
1691
- }
1692
- function redactObject(input) {
1693
- return Object.fromEntries(
1694
- Object.entries(input).map(([key, value]) => {
1695
- if (isSensitiveKey(key)) {
1696
- return [key, REDACTED];
1697
- }
1698
- return [key, redactValue(value)];
1699
- })
1700
- );
1701
- }
1702
-
1703
1853
  // src/profiles/SecretSource.ts
1704
1854
  var import_node_buffer2 = require("buffer");
1705
1855
  var import_promises = require("fs/promises");
@@ -2071,11 +2221,11 @@ var import_promises2 = require("fs/promises");
2071
2221
  var import_node_path2 = __toESM(require("path"));
2072
2222
 
2073
2223
  // src/utils/path.ts
2074
- var UNSAFE_FTP_ARGUMENT_PATTERN = /[\r\n]/;
2224
+ var UNSAFE_FTP_ARGUMENT_PATTERN = /[\r\n\0]/;
2075
2225
  function assertSafeFtpArgument(value, label = "path") {
2076
2226
  if (UNSAFE_FTP_ARGUMENT_PATTERN.test(value)) {
2077
2227
  throw new ConfigurationError({
2078
- message: `Unsafe FTP ${label}: CR and LF characters are not allowed`,
2228
+ message: `Unsafe FTP ${label}: CR, LF, and NUL characters are not allowed`,
2079
2229
  retryable: false,
2080
2230
  details: {
2081
2231
  label
@@ -3377,7 +3527,6 @@ function expandAlgorithms(values) {
3377
3527
  }
3378
3528
 
3379
3529
  // src/profiles/importers/FileZillaImporter.ts
3380
- var import_node_buffer5 = require("buffer");
3381
3530
  function importFileZillaSites(xml) {
3382
3531
  const events = tokenizeXml(xml);
3383
3532
  if (events.length === 0) {
@@ -3393,7 +3542,6 @@ function importFileZillaSites(xml) {
3393
3542
  const folderNamePending = [];
3394
3543
  let inServer = false;
3395
3544
  let serverFields = {};
3396
- let serverPasswordEncoding;
3397
3545
  let activeTag;
3398
3546
  let captureFolderName = false;
3399
3547
  for (const event of events) {
@@ -3406,13 +3554,9 @@ function importFileZillaSites(xml) {
3406
3554
  if (event.name === "Server") {
3407
3555
  inServer = true;
3408
3556
  serverFields = {};
3409
- serverPasswordEncoding = void 0;
3410
3557
  continue;
3411
3558
  }
3412
3559
  activeTag = event.name;
3413
- if (event.name === "Pass" && inServer) {
3414
- serverPasswordEncoding = event.attributes["encoding"];
3415
- }
3416
3560
  if (event.name === "Name" && !inServer && folderNamePending.length > 0) {
3417
3561
  captureFolderName = true;
3418
3562
  }
@@ -3438,7 +3582,7 @@ function importFileZillaSites(xml) {
3438
3582
  }
3439
3583
  if (event.name === "Server") {
3440
3584
  const folder = folderStack.filter((segment) => segment !== "");
3441
- const result = buildSiteFromFields(serverFields, serverPasswordEncoding);
3585
+ const result = buildSiteFromFields(serverFields);
3442
3586
  if (result.kind === "site") {
3443
3587
  sites.push({ ...result.site, folder });
3444
3588
  } else {
@@ -3450,7 +3594,6 @@ function importFileZillaSites(xml) {
3450
3594
  }
3451
3595
  inServer = false;
3452
3596
  serverFields = {};
3453
- serverPasswordEncoding = void 0;
3454
3597
  activeTag = void 0;
3455
3598
  continue;
3456
3599
  }
@@ -3459,7 +3602,7 @@ function importFileZillaSites(xml) {
3459
3602
  }
3460
3603
  return { sites, skipped };
3461
3604
  }
3462
- function buildSiteFromFields(fields, passwordEncoding) {
3605
+ function buildSiteFromFields(fields) {
3463
3606
  const name = (fields["Name"] ?? fields["Host"] ?? "Untitled").trim();
3464
3607
  const host = (fields["Host"] ?? "").trim();
3465
3608
  if (host === "") return { kind: "skipped", name };
@@ -3478,18 +3621,9 @@ function buildSiteFromFields(fields, passwordEncoding) {
3478
3621
  }
3479
3622
  const user = fields["User"]?.trim();
3480
3623
  if (user !== void 0 && user !== "") profile.username = { value: user };
3481
- let password;
3482
3624
  const rawPass = fields["Pass"];
3483
- if (rawPass !== void 0 && rawPass !== "") {
3484
- if (passwordEncoding === "base64") {
3485
- password = import_node_buffer5.Buffer.from(rawPass, "base64").toString("utf8");
3486
- } else {
3487
- password = rawPass;
3488
- }
3489
- if (password !== void 0 && password !== "") profile.password = { value: password };
3490
- }
3491
- const site = { name, profile };
3492
- if (password !== void 0) site.password = password;
3625
+ const hasStoredPassword = rawPass !== void 0 && rawPass !== "";
3626
+ const site = { hasStoredPassword, name, profile };
3493
3627
  const logonText = fields["Logontype"];
3494
3628
  if (logonText !== void 0) {
3495
3629
  const logonType = Number.parseInt(logonText.trim(), 10);
@@ -3732,6 +3866,62 @@ function mapFtp550(details) {
3732
3866
  return new PermissionDeniedError(details);
3733
3867
  }
3734
3868
 
3869
+ // src/transfers/createDefaultRetryPolicy.ts
3870
+ var DEFAULT_MAX_ATTEMPTS = 4;
3871
+ var DEFAULT_BASE_DELAY_MS = 250;
3872
+ var DEFAULT_MAX_DELAY_MS = 3e4;
3873
+ var DEFAULT_MAX_ELAPSED_MS = 3e5;
3874
+ function createDefaultRetryPolicy(options = {}) {
3875
+ const maxAttempts = normalizePositiveInteger(options.maxAttempts, DEFAULT_MAX_ATTEMPTS);
3876
+ const baseDelayMs = normalizeNonNegative(options.baseDelayMs, DEFAULT_BASE_DELAY_MS);
3877
+ const maxDelayMs = normalizeNonNegative(options.maxDelayMs, DEFAULT_MAX_DELAY_MS);
3878
+ const maxElapsedMs = normalizeNonNegative(options.maxElapsedMs, DEFAULT_MAX_ELAPSED_MS);
3879
+ const random = options.random ?? Math.random;
3880
+ return {
3881
+ getDelayMs(input) {
3882
+ const retryAfterMs = readRetryAfterMs(input.error);
3883
+ if (retryAfterMs !== void 0) {
3884
+ return retryAfterMs;
3885
+ }
3886
+ const exponentialMs = baseDelayMs * 2 ** (input.attempt - 1);
3887
+ const cappedMs = Math.min(maxDelayMs, exponentialMs);
3888
+ return Math.floor(random() * cappedMs);
3889
+ },
3890
+ maxAttempts,
3891
+ shouldRetry(input) {
3892
+ if (!(input.error instanceof ZeroTransferError) || !input.error.retryable) {
3893
+ return false;
3894
+ }
3895
+ if (input.elapsedMs >= maxElapsedMs) {
3896
+ return false;
3897
+ }
3898
+ const retryAfterMs = readRetryAfterMs(input.error);
3899
+ if (retryAfterMs !== void 0 && input.elapsedMs + retryAfterMs > maxElapsedMs) {
3900
+ return false;
3901
+ }
3902
+ return true;
3903
+ }
3904
+ };
3905
+ }
3906
+ function readRetryAfterMs(error) {
3907
+ if (!(error instanceof ZeroTransferError)) return void 0;
3908
+ const value = error.details?.["retryAfterMs"];
3909
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return void 0;
3910
+ return Math.floor(value);
3911
+ }
3912
+ function normalizePositiveInteger(value, fallback) {
3913
+ if (value === void 0 || !Number.isFinite(value) || value < 1) {
3914
+ return fallback;
3915
+ }
3916
+ return Math.floor(value);
3917
+ }
3918
+ function normalizeNonNegative(value, fallback) {
3919
+ if (value === void 0 || !Number.isFinite(value) || value < 0) {
3920
+ return fallback;
3921
+ }
3922
+ return Math.floor(value);
3923
+ }
3924
+
3735
3925
  // src/transfers/TransferPlan.ts
3736
3926
  function createTransferPlan(input) {
3737
3927
  const plan = {
@@ -3829,8 +4019,8 @@ var TransferQueue = class {
3829
4019
  this.concurrency = normalizeConcurrency(options.concurrency);
3830
4020
  this.defaultExecutor = options.executor;
3831
4021
  this.resolveExecutor = options.resolveExecutor;
3832
- this.retry = options.retry;
3833
- this.timeout = options.timeout;
4022
+ this.retry = options.retry ?? options.client?.defaults?.retry;
4023
+ this.timeout = options.timeout ?? options.client?.defaults?.timeout;
3834
4024
  this.bandwidthLimit = options.bandwidthLimit;
3835
4025
  this.onProgress = options.onProgress;
3836
4026
  this.onReceipt = options.onReceipt;
@@ -4907,12 +5097,12 @@ function isMainModule(importMetaUrl) {
4907
5097
  }
4908
5098
 
4909
5099
  // src/providers/native/sftp/NativeSftpProvider.ts
4910
- var import_node_buffer20 = require("buffer");
5100
+ var import_node_buffer19 = require("buffer");
4911
5101
  var import_node_crypto9 = require("crypto");
4912
5102
  var import_node_net = require("net");
4913
5103
 
4914
5104
  // src/protocols/ssh/binary/SshDataWriter.ts
4915
- var import_node_buffer6 = require("buffer");
5105
+ var import_node_buffer5 = require("buffer");
4916
5106
  var MAX_UINT32 = 4294967295;
4917
5107
  var MAX_UINT64 = (1n << 64n) - 1n;
4918
5108
  var SshDataWriter = class {
@@ -4920,7 +5110,7 @@ var SshDataWriter = class {
4920
5110
  length = 0;
4921
5111
  writeByte(value) {
4922
5112
  this.assertByte(value, "byte");
4923
- const chunk = import_node_buffer6.Buffer.alloc(1);
5113
+ const chunk = import_node_buffer5.Buffer.alloc(1);
4924
5114
  chunk.writeUInt8(value, 0);
4925
5115
  return this.push(chunk);
4926
5116
  }
@@ -4928,7 +5118,7 @@ var SshDataWriter = class {
4928
5118
  return this.writeByte(value ? 1 : 0);
4929
5119
  }
4930
5120
  writeBytes(value) {
4931
- return this.push(import_node_buffer6.Buffer.from(value));
5121
+ return this.push(import_node_buffer5.Buffer.from(value));
4932
5122
  }
4933
5123
  writeUint32(value) {
4934
5124
  if (!Number.isInteger(value) || value < 0 || value > MAX_UINT32) {
@@ -4938,7 +5128,7 @@ var SshDataWriter = class {
4938
5128
  retryable: false
4939
5129
  });
4940
5130
  }
4941
- const chunk = import_node_buffer6.Buffer.alloc(4);
5131
+ const chunk = import_node_buffer5.Buffer.alloc(4);
4942
5132
  chunk.writeUInt32BE(value, 0);
4943
5133
  return this.push(chunk);
4944
5134
  }
@@ -4950,12 +5140,12 @@ var SshDataWriter = class {
4950
5140
  retryable: false
4951
5141
  });
4952
5142
  }
4953
- const chunk = import_node_buffer6.Buffer.alloc(8);
5143
+ const chunk = import_node_buffer5.Buffer.alloc(8);
4954
5144
  chunk.writeBigUInt64BE(value, 0);
4955
5145
  return this.push(chunk);
4956
5146
  }
4957
5147
  writeString(value, encoding = "utf8") {
4958
- const payload = typeof value === "string" ? import_node_buffer6.Buffer.from(value, encoding) : import_node_buffer6.Buffer.from(value);
5148
+ const payload = typeof value === "string" ? import_node_buffer5.Buffer.from(value, encoding) : import_node_buffer5.Buffer.from(value);
4959
5149
  this.writeUint32(payload.length);
4960
5150
  return this.push(payload);
4961
5151
  }
@@ -4977,7 +5167,7 @@ var SshDataWriter = class {
4977
5167
  return this.writeString(values.join(","), "ascii");
4978
5168
  }
4979
5169
  toBuffer() {
4980
- return import_node_buffer6.Buffer.concat(this.chunks, this.length);
5170
+ return import_node_buffer5.Buffer.concat(this.chunks, this.length);
4981
5171
  }
4982
5172
  push(chunk) {
4983
5173
  this.chunks.push(chunk);
@@ -4995,23 +5185,23 @@ var SshDataWriter = class {
4995
5185
  }
4996
5186
  };
4997
5187
  function normalizePositiveMpint(value) {
4998
- const input = import_node_buffer6.Buffer.from(value);
5188
+ const input = import_node_buffer5.Buffer.from(value);
4999
5189
  let offset = 0;
5000
5190
  while (offset < input.length && input[offset] === 0) {
5001
5191
  offset += 1;
5002
5192
  }
5003
5193
  if (offset >= input.length) {
5004
- return import_node_buffer6.Buffer.alloc(0);
5194
+ return import_node_buffer5.Buffer.alloc(0);
5005
5195
  }
5006
5196
  const stripped = input.subarray(offset);
5007
5197
  if ((stripped[0] & 128) === 128) {
5008
- return import_node_buffer6.Buffer.concat([import_node_buffer6.Buffer.from([0]), stripped]);
5198
+ return import_node_buffer5.Buffer.concat([import_node_buffer5.Buffer.from([0]), stripped]);
5009
5199
  }
5010
5200
  return stripped;
5011
5201
  }
5012
5202
 
5013
5203
  // src/protocols/ssh/binary/SshDataReader.ts
5014
- var import_node_buffer7 = require("buffer");
5204
+ var import_node_buffer6 = require("buffer");
5015
5205
  var SshDataReader = class {
5016
5206
  constructor(source) {
5017
5207
  this.source = source;
@@ -5037,18 +5227,18 @@ var SshDataReader = class {
5037
5227
  this.ensureAvailable(length, "bytes");
5038
5228
  const data = this.source.subarray(this.offset, this.offset + length);
5039
5229
  this.offset += length;
5040
- return import_node_buffer7.Buffer.from(data);
5230
+ return import_node_buffer6.Buffer.from(data);
5041
5231
  }
5042
5232
  readUint32() {
5043
5233
  this.ensureAvailable(4, "uint32");
5044
- const buffer = import_node_buffer7.Buffer.from(this.source);
5234
+ const buffer = import_node_buffer6.Buffer.from(this.source);
5045
5235
  const value = buffer.readUInt32BE(this.offset);
5046
5236
  this.offset += 4;
5047
5237
  return value;
5048
5238
  }
5049
5239
  readUint64() {
5050
5240
  this.ensureAvailable(8, "uint64");
5051
- const buffer = import_node_buffer7.Buffer.from(this.source);
5241
+ const buffer = import_node_buffer6.Buffer.from(this.source);
5052
5242
  const value = buffer.readBigUInt64BE(this.offset);
5053
5243
  this.offset += 8;
5054
5244
  return value;
@@ -5058,7 +5248,7 @@ var SshDataReader = class {
5058
5248
  this.ensureAvailable(length, "string");
5059
5249
  const data = this.source.subarray(this.offset, this.offset + length);
5060
5250
  this.offset += length;
5061
- return import_node_buffer7.Buffer.from(data);
5251
+ return import_node_buffer6.Buffer.from(data);
5062
5252
  }
5063
5253
  readUtf8String() {
5064
5254
  return this.readString().toString("utf8");
@@ -5413,7 +5603,7 @@ function buildKiRequest(args) {
5413
5603
  }
5414
5604
 
5415
5605
  // src/protocols/ssh/auth/SshPublickeyCredentialBuilder.ts
5416
- var import_node_buffer8 = require("buffer");
5606
+ var import_node_buffer7 = require("buffer");
5417
5607
  var import_node_crypto2 = require("crypto");
5418
5608
  var ED25519_RAW_KEY_LENGTH = 32;
5419
5609
  var ED25519_SPKI_PREFIX_LENGTH = 12;
@@ -5431,7 +5621,7 @@ function buildPublickeyCredential(options) {
5431
5621
  return {
5432
5622
  algorithmName: "ssh-ed25519",
5433
5623
  publicKeyBlob,
5434
- sign: (data) => (0, import_node_crypto2.sign)(null, import_node_buffer8.Buffer.from(data), privateKey),
5624
+ sign: (data) => (0, import_node_crypto2.sign)(null, import_node_buffer7.Buffer.from(data), privateKey),
5435
5625
  type: "publickey",
5436
5626
  username
5437
5627
  };
@@ -5449,7 +5639,7 @@ function buildPublickeyCredential(options) {
5449
5639
  return {
5450
5640
  algorithmName,
5451
5641
  publicKeyBlob,
5452
- sign: (data) => (0, import_node_crypto2.sign)(hash, import_node_buffer8.Buffer.from(data), privateKey),
5642
+ sign: (data) => (0, import_node_crypto2.sign)(hash, import_node_buffer7.Buffer.from(data), privateKey),
5453
5643
  type: "publickey",
5454
5644
  username
5455
5645
  };
@@ -5462,7 +5652,7 @@ function buildPublickeyCredential(options) {
5462
5652
  }
5463
5653
  function base64UrlToMpint(value) {
5464
5654
  const padded = value.replace(/-/g, "+").replace(/_/g, "/");
5465
- const buffer = import_node_buffer8.Buffer.from(padded, "base64");
5655
+ const buffer = import_node_buffer7.Buffer.from(padded, "base64");
5466
5656
  return buffer;
5467
5657
  }
5468
5658
  function createInvalidKeyError(message) {
@@ -5588,7 +5778,7 @@ function encodeSshChannelClose(recipientChannel) {
5588
5778
  }
5589
5779
 
5590
5780
  // src/protocols/ssh/connection/SshSessionChannel.ts
5591
- var import_node_buffer9 = require("buffer");
5781
+ var import_node_buffer8 = require("buffer");
5592
5782
  var INITIAL_WINDOW_SIZE = 256 * 1024;
5593
5783
  var MAX_PACKET_SIZE = 32 * 1024;
5594
5784
  var WINDOW_REFILL_THRESHOLD = 64 * 1024;
@@ -5746,7 +5936,7 @@ var SshSessionChannel = class {
5746
5936
  this.remoteWindowRemaining,
5747
5937
  this.remoteMaxPacketSize
5748
5938
  );
5749
- const chunk = import_node_buffer9.Buffer.from(data.subarray(offset, offset + chunkSize));
5939
+ const chunk = import_node_buffer8.Buffer.from(data.subarray(offset, offset + chunkSize));
5750
5940
  this.transport.sendPayload(
5751
5941
  encodeSshChannelData({ data: chunk, recipientChannel: this.remoteChannelId })
5752
5942
  );
@@ -6008,10 +6198,10 @@ var SshConnectionManager = class {
6008
6198
  };
6009
6199
 
6010
6200
  // src/protocols/ssh/transport/SshTransportConnection.ts
6011
- var import_node_buffer17 = require("buffer");
6201
+ var import_node_buffer16 = require("buffer");
6012
6202
 
6013
6203
  // src/protocols/ssh/transport/SshTransportHandshake.ts
6014
- var import_node_buffer15 = require("buffer");
6204
+ var import_node_buffer14 = require("buffer");
6015
6205
 
6016
6206
  // src/protocols/ssh/transport/SshAlgorithmNegotiation.ts
6017
6207
  var DEFAULT_SSH_ALGORITHM_PREFERENCES = {
@@ -6173,12 +6363,12 @@ function parseSshIdentificationLine(line) {
6173
6363
  }
6174
6364
 
6175
6365
  // src/protocols/ssh/transport/SshKexInit.ts
6176
- var import_node_buffer10 = require("buffer");
6366
+ var import_node_buffer9 = require("buffer");
6177
6367
  var import_node_crypto3 = require("crypto");
6178
6368
  var SSH_MSG_KEXINIT = 20;
6179
6369
  var KEXINIT_COOKIE_LENGTH = 16;
6180
6370
  function encodeSshKexInitMessage(options) {
6181
- const cookie = options.cookie === void 0 ? (0, import_node_crypto3.randomBytes)(KEXINIT_COOKIE_LENGTH) : import_node_buffer10.Buffer.from(options.cookie);
6371
+ const cookie = options.cookie === void 0 ? (0, import_node_crypto3.randomBytes)(KEXINIT_COOKIE_LENGTH) : import_node_buffer9.Buffer.from(options.cookie);
6182
6372
  if (cookie.length !== KEXINIT_COOKIE_LENGTH) {
6183
6373
  throw new ConfigurationError({
6184
6374
  details: { actualLength: cookie.length, expectedLength: KEXINIT_COOKIE_LENGTH },
@@ -6248,12 +6438,12 @@ function decodeSshKexInitMessage(payload) {
6248
6438
  }
6249
6439
 
6250
6440
  // src/protocols/ssh/transport/SshKexCurve25519.ts
6251
- var import_node_buffer11 = require("buffer");
6441
+ var import_node_buffer10 = require("buffer");
6252
6442
  var import_node_crypto4 = require("crypto");
6253
6443
  var SSH_MSG_KEX_ECDH_INIT = 30;
6254
6444
  var SSH_MSG_KEX_ECDH_REPLY = 31;
6255
6445
  var X25519_PUBLIC_KEY_LENGTH = 32;
6256
- var X25519_SPKI_PREFIX = import_node_buffer11.Buffer.from("302a300506032b656e032100", "hex");
6446
+ var X25519_SPKI_PREFIX = import_node_buffer10.Buffer.from("302a300506032b656e032100", "hex");
6257
6447
  function createCurve25519Ephemeral() {
6258
6448
  const { privateKey, publicKey } = (0, import_node_crypto4.generateKeyPairSync)("x25519");
6259
6449
  const encodedPublicKey = exportX25519PublicKeyRaw(publicKey);
@@ -6298,7 +6488,7 @@ function exportX25519PublicKeyRaw(publicKey) {
6298
6488
  }
6299
6489
  function importX25519PublicKeyRaw(raw) {
6300
6490
  const normalized = normalizeX25519PublicKey(raw, "server");
6301
- const der = import_node_buffer11.Buffer.concat([X25519_SPKI_PREFIX, normalized]);
6491
+ const der = import_node_buffer10.Buffer.concat([X25519_SPKI_PREFIX, normalized]);
6302
6492
  return (0, import_node_crypto4.createPublicKey)({
6303
6493
  format: "der",
6304
6494
  key: der,
@@ -6306,7 +6496,7 @@ function importX25519PublicKeyRaw(raw) {
6306
6496
  });
6307
6497
  }
6308
6498
  function normalizeX25519PublicKey(value, label) {
6309
- const key = import_node_buffer11.Buffer.from(value);
6499
+ const key = import_node_buffer10.Buffer.from(value);
6310
6500
  if (key.length !== X25519_PUBLIC_KEY_LENGTH) {
6311
6501
  throw new ConfigurationError({
6312
6502
  details: { keyLength: key.length, label },
@@ -6319,7 +6509,7 @@ function normalizeX25519PublicKey(value, label) {
6319
6509
  }
6320
6510
 
6321
6511
  // src/protocols/ssh/transport/SshKeyDerivation.ts
6322
- var import_node_buffer12 = require("buffer");
6512
+ var import_node_buffer11 = require("buffer");
6323
6513
  var import_node_crypto5 = require("crypto");
6324
6514
  function deriveSshSessionKeys(input) {
6325
6515
  const hashAlgorithm = resolveKexHashAlgorithm(input.kexAlgorithm);
@@ -6341,7 +6531,7 @@ function deriveSshSessionKeys(input) {
6341
6531
  input.negotiatedAlgorithms.encryptionServerToClient,
6342
6532
  input.negotiatedAlgorithms.macServerToClient
6343
6533
  );
6344
- const sharedSecret = import_node_buffer12.Buffer.from(input.sharedSecret);
6534
+ const sharedSecret = import_node_buffer11.Buffer.from(input.sharedSecret);
6345
6535
  return {
6346
6536
  clientToServer: {
6347
6537
  encryptionKey: deriveMaterial(
@@ -6391,21 +6581,21 @@ function computeCurve25519ExchangeHash(input, hashAlgorithm) {
6391
6581
  }
6392
6582
  function deriveMaterial(sharedSecret, exchangeHash, sessionId, letter, length, hashAlgorithm) {
6393
6583
  if (length <= 0) {
6394
- return import_node_buffer12.Buffer.alloc(0);
6584
+ return import_node_buffer11.Buffer.alloc(0);
6395
6585
  }
6396
6586
  const result = [];
6397
6587
  const first2 = (0, import_node_crypto5.createHash)(hashAlgorithm).update(
6398
6588
  new SshDataWriter().writeMpint(sharedSecret).writeBytes(exchangeHash).writeByte(letter.charCodeAt(0)).writeBytes(sessionId).toBuffer()
6399
6589
  ).digest();
6400
6590
  result.push(first2);
6401
- while (import_node_buffer12.Buffer.concat(result).length < length) {
6402
- const previous = import_node_buffer12.Buffer.concat(result);
6591
+ while (import_node_buffer11.Buffer.concat(result).length < length) {
6592
+ const previous = import_node_buffer11.Buffer.concat(result);
6403
6593
  const next = (0, import_node_crypto5.createHash)(hashAlgorithm).update(
6404
6594
  new SshDataWriter().writeMpint(sharedSecret).writeBytes(exchangeHash).writeBytes(previous).toBuffer()
6405
6595
  ).digest();
6406
6596
  result.push(next);
6407
6597
  }
6408
- return import_node_buffer12.Buffer.concat(result).subarray(0, length);
6598
+ return import_node_buffer11.Buffer.concat(result).subarray(0, length);
6409
6599
  }
6410
6600
  function resolveKexHashAlgorithm(kexAlgorithm) {
6411
6601
  if (kexAlgorithm === "curve25519-sha256" || kexAlgorithm === "curve25519-sha256@libssh.org") {
@@ -6493,20 +6683,21 @@ function decodeSshNewKeysMessage(payload) {
6493
6683
  }
6494
6684
 
6495
6685
  // src/protocols/ssh/transport/SshTransportPacket.ts
6496
- var import_node_buffer13 = require("buffer");
6686
+ var import_node_buffer12 = require("buffer");
6497
6687
  var import_node_crypto6 = require("crypto");
6498
6688
  var MIN_PADDING_LENGTH = 4;
6499
6689
  var MIN_PACKET_LENGTH = 1 + MIN_PADDING_LENGTH;
6690
+ var MAX_SSH_PACKET_LENGTH = 256 * 1024;
6500
6691
  function encodeSshTransportPacket(payload, options = {}) {
6501
- const body = import_node_buffer13.Buffer.from(payload);
6692
+ const body = import_node_buffer12.Buffer.from(payload);
6502
6693
  const blockSize = normalizeBlockSize(options.blockSize ?? 8);
6503
6694
  let paddingLength = MIN_PADDING_LENGTH;
6504
6695
  while ((1 + body.length + paddingLength + 4) % blockSize !== 0) {
6505
6696
  paddingLength += 1;
6506
6697
  }
6507
- const padding = options.randomPadding === false ? import_node_buffer13.Buffer.alloc(paddingLength) : (0, import_node_crypto6.randomBytes)(paddingLength);
6698
+ const padding = options.randomPadding === false ? import_node_buffer12.Buffer.alloc(paddingLength) : (0, import_node_crypto6.randomBytes)(paddingLength);
6508
6699
  const packetLength = 1 + body.length + paddingLength;
6509
- const frame = import_node_buffer13.Buffer.alloc(4 + packetLength);
6700
+ const frame = import_node_buffer12.Buffer.alloc(4 + packetLength);
6510
6701
  frame.writeUInt32BE(packetLength, 0);
6511
6702
  frame.writeUInt8(paddingLength, 4);
6512
6703
  body.copy(frame, 5);
@@ -6514,7 +6705,7 @@ function encodeSshTransportPacket(payload, options = {}) {
6514
6705
  return frame;
6515
6706
  }
6516
6707
  function decodeSshTransportPacket(frame) {
6517
- const bytes = import_node_buffer13.Buffer.from(frame);
6708
+ const bytes = import_node_buffer12.Buffer.from(frame);
6518
6709
  if (bytes.length < 4 + MIN_PACKET_LENGTH) {
6519
6710
  throw new ParseError({
6520
6711
  details: { length: bytes.length },
@@ -6568,12 +6759,20 @@ function decodeSshTransportPacket(frame) {
6568
6759
  };
6569
6760
  }
6570
6761
  var SshTransportPacketFramer = class {
6571
- pending = import_node_buffer13.Buffer.alloc(0);
6762
+ pending = import_node_buffer12.Buffer.alloc(0);
6572
6763
  push(chunk) {
6573
- this.pending = import_node_buffer13.Buffer.concat([this.pending, import_node_buffer13.Buffer.from(chunk)]);
6764
+ this.pending = import_node_buffer12.Buffer.concat([this.pending, import_node_buffer12.Buffer.from(chunk)]);
6574
6765
  const packets = [];
6575
6766
  while (this.pending.length >= 4) {
6576
6767
  const packetLength = this.pending.readUInt32BE(0);
6768
+ if (packetLength > MAX_SSH_PACKET_LENGTH) {
6769
+ throw new ParseError({
6770
+ details: { maxPacketLength: MAX_SSH_PACKET_LENGTH, packetLength },
6771
+ message: "SSH transport packet length exceeds the maximum accepted size",
6772
+ protocol: "sftp",
6773
+ retryable: false
6774
+ });
6775
+ }
6577
6776
  const frameLength = 4 + packetLength;
6578
6777
  if (this.pending.length < frameLength) {
6579
6778
  break;
@@ -6589,8 +6788,8 @@ var SshTransportPacketFramer = class {
6589
6788
  }
6590
6789
  /** Returns and clears any bytes buffered but not yet part of a complete packet. */
6591
6790
  takeRemainingBytes() {
6592
- const remaining = import_node_buffer13.Buffer.from(this.pending);
6593
- this.pending = import_node_buffer13.Buffer.alloc(0);
6791
+ const remaining = import_node_buffer12.Buffer.from(this.pending);
6792
+ this.pending = import_node_buffer12.Buffer.alloc(0);
6594
6793
  return remaining;
6595
6794
  }
6596
6795
  };
@@ -6607,10 +6806,10 @@ function normalizeBlockSize(blockSize) {
6607
6806
  }
6608
6807
 
6609
6808
  // src/protocols/ssh/transport/SshHostKeyVerification.ts
6610
- var import_node_buffer14 = require("buffer");
6809
+ var import_node_buffer13 = require("buffer");
6611
6810
  var import_node_crypto7 = require("crypto");
6612
6811
  var ED25519_RAW_KEY_LENGTH2 = 32;
6613
- var ED25519_SPKI_PREFIX = import_node_buffer14.Buffer.from("302a300506032b6570032100", "hex");
6812
+ var ED25519_SPKI_PREFIX = import_node_buffer13.Buffer.from("302a300506032b6570032100", "hex");
6614
6813
  function verifySshHostKeySignature(input) {
6615
6814
  const { algorithmName, publicKey } = parseHostKey(input.hostKeyBlob);
6616
6815
  const { signatureAlgorithm, signatureBytes } = parseSignatureBlob(input.signatureBlob);
@@ -6623,9 +6822,9 @@ function verifySshHostKeySignature(input) {
6623
6822
  });
6624
6823
  }
6625
6824
  const verified = verifySignature({
6626
- data: import_node_buffer14.Buffer.from(input.exchangeHash),
6825
+ data: import_node_buffer13.Buffer.from(input.exchangeHash),
6627
6826
  publicKey,
6628
- signature: import_node_buffer14.Buffer.from(signatureBytes),
6827
+ signature: import_node_buffer13.Buffer.from(signatureBytes),
6629
6828
  signatureAlgorithm
6630
6829
  });
6631
6830
  if (!verified) {
@@ -6654,7 +6853,7 @@ function parseHostKey(blob) {
6654
6853
  retryable: false
6655
6854
  });
6656
6855
  }
6657
- const spki = import_node_buffer14.Buffer.concat([ED25519_SPKI_PREFIX, raw]);
6856
+ const spki = import_node_buffer13.Buffer.concat([ED25519_SPKI_PREFIX, raw]);
6658
6857
  return {
6659
6858
  algorithmName,
6660
6859
  publicKey: (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" })
@@ -6760,37 +6959,37 @@ function verifySignature(input) {
6760
6959
  function rsaPublicKeyFromComponents(e, n) {
6761
6960
  const eDer = encodeAsn1Integer(e);
6762
6961
  const nDer = encodeAsn1Integer(n);
6763
- const rsaPublicKeyDer = encodeAsn1Sequence(import_node_buffer14.Buffer.concat([nDer, eDer]));
6764
- const bitStringContent = import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([0]), rsaPublicKeyDer]);
6765
- const bitString = import_node_buffer14.Buffer.concat([
6766
- import_node_buffer14.Buffer.from([3]),
6962
+ const rsaPublicKeyDer = encodeAsn1Sequence(import_node_buffer13.Buffer.concat([nDer, eDer]));
6963
+ const bitStringContent = import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from([0]), rsaPublicKeyDer]);
6964
+ const bitString = import_node_buffer13.Buffer.concat([
6965
+ import_node_buffer13.Buffer.from([3]),
6767
6966
  encodeAsn1Length(bitStringContent.length),
6768
6967
  bitStringContent
6769
6968
  ]);
6770
- const algoId = import_node_buffer14.Buffer.from("300d06092a864886f70d010101 0500".replace(/\s+/g, ""), "hex");
6771
- const spki = encodeAsn1Sequence(import_node_buffer14.Buffer.concat([algoId, bitString]));
6969
+ const algoId = import_node_buffer13.Buffer.from("300d06092a864886f70d010101 0500".replace(/\s+/g, ""), "hex");
6970
+ const spki = encodeAsn1Sequence(import_node_buffer13.Buffer.concat([algoId, bitString]));
6772
6971
  return (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" });
6773
6972
  }
6774
6973
  function encodeAsn1Integer(value) {
6775
6974
  let body = value;
6776
6975
  while (body.length > 1 && body[0] === 0) body = body.subarray(1);
6777
6976
  if (body.length > 0 && (body[0] & 128) !== 0) {
6778
- body = import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([0]), body]);
6977
+ body = import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from([0]), body]);
6779
6978
  }
6780
- return import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([2]), encodeAsn1Length(body.length), body]);
6979
+ return import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from([2]), encodeAsn1Length(body.length), body]);
6781
6980
  }
6782
6981
  function encodeAsn1Sequence(content) {
6783
- return import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([48]), encodeAsn1Length(content.length), content]);
6982
+ return import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from([48]), encodeAsn1Length(content.length), content]);
6784
6983
  }
6785
6984
  function encodeAsn1Length(length) {
6786
- if (length < 128) return import_node_buffer14.Buffer.from([length]);
6985
+ if (length < 128) return import_node_buffer13.Buffer.from([length]);
6787
6986
  const bytes = [];
6788
6987
  let n = length;
6789
6988
  while (n > 0) {
6790
6989
  bytes.unshift(n & 255);
6791
6990
  n >>>= 8;
6792
6991
  }
6793
- return import_node_buffer14.Buffer.from([128 | bytes.length, ...bytes]);
6992
+ return import_node_buffer13.Buffer.from([128 | bytes.length, ...bytes]);
6794
6993
  }
6795
6994
  var ECDSA_OID_BY_CURVE = {
6796
6995
  nistp256: "06082a8648ce3d030107",
@@ -6811,15 +7010,15 @@ function ecdsaPublicKeyFromPoint(curveIdentifier, point) {
6811
7010
  retryable: false
6812
7011
  });
6813
7012
  }
6814
- const algoIdContent = import_node_buffer14.Buffer.from(ECDSA_ALGORITHM_OID_HEX + oidHex, "hex");
7013
+ const algoIdContent = import_node_buffer13.Buffer.from(ECDSA_ALGORITHM_OID_HEX + oidHex, "hex");
6815
7014
  const algoId = encodeAsn1Sequence(algoIdContent);
6816
- const bitStringContent = import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([0]), point]);
6817
- const bitString = import_node_buffer14.Buffer.concat([
6818
- import_node_buffer14.Buffer.from([3]),
7015
+ const bitStringContent = import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from([0]), point]);
7016
+ const bitString = import_node_buffer13.Buffer.concat([
7017
+ import_node_buffer13.Buffer.from([3]),
6819
7018
  encodeAsn1Length(bitStringContent.length),
6820
7019
  bitStringContent
6821
7020
  ]);
6822
- const spki = encodeAsn1Sequence(import_node_buffer14.Buffer.concat([algoId, bitString]));
7021
+ const spki = encodeAsn1Sequence(import_node_buffer13.Buffer.concat([algoId, bitString]));
6823
7022
  return (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" });
6824
7023
  }
6825
7024
  function sshEcdsaSignatureToDer(sshSignature) {
@@ -6828,7 +7027,7 @@ function sshEcdsaSignatureToDer(sshSignature) {
6828
7027
  const s = reader.readMpint();
6829
7028
  const rDer = encodeAsn1Integer(r);
6830
7029
  const sDer = encodeAsn1Integer(s);
6831
- return encodeAsn1Sequence(import_node_buffer14.Buffer.concat([rDer, sDer]));
7030
+ return encodeAsn1Sequence(import_node_buffer13.Buffer.concat([rDer, sDer]));
6832
7031
  }
6833
7032
 
6834
7033
  // src/protocols/ssh/transport/SshTransportHandshake.ts
@@ -6860,7 +7059,7 @@ var SshTransportHandshake = class {
6860
7059
  serverIdentification;
6861
7060
  /** Creates the first outbound bytes (client identification line). */
6862
7061
  createInitialClientBytes() {
6863
- return import_node_buffer15.Buffer.from(`${this.clientIdentificationLine}\r
7062
+ return import_node_buffer14.Buffer.from(`${this.clientIdentificationLine}\r
6864
7063
  `, "ascii");
6865
7064
  }
6866
7065
  /**
@@ -6884,7 +7083,7 @@ var SshTransportHandshake = class {
6884
7083
  }
6885
7084
  return { outbound };
6886
7085
  }
6887
- return this.pushServerBytesWithPhase(outbound, import_node_buffer15.Buffer.from(chunk));
7086
+ return this.pushServerBytesWithPhase(outbound, import_node_buffer14.Buffer.from(chunk));
6888
7087
  }
6889
7088
  getServerBannerLines() {
6890
7089
  return this.identificationLines;
@@ -6938,12 +7137,12 @@ var SshTransportHandshake = class {
6938
7137
  clientKexInitPayload: this.clientKexInitPayload,
6939
7138
  clientPublicKey: this.pendingCurve25519.publicKey,
6940
7139
  negotiatedAlgorithms,
6941
- serverHostKey: import_node_buffer15.Buffer.alloc(0),
7140
+ serverHostKey: import_node_buffer14.Buffer.alloc(0),
6942
7141
  serverIdentification: (this.serverIdentification ?? missingServerIdentificationError()).raw,
6943
- serverKexInitPayload: import_node_buffer15.Buffer.from(packet.payload),
6944
- serverPublicKey: import_node_buffer15.Buffer.alloc(0),
6945
- serverSignature: import_node_buffer15.Buffer.alloc(0),
6946
- sharedSecret: import_node_buffer15.Buffer.alloc(0)
7142
+ serverKexInitPayload: import_node_buffer14.Buffer.from(packet.payload),
7143
+ serverPublicKey: import_node_buffer14.Buffer.alloc(0),
7144
+ serverSignature: import_node_buffer14.Buffer.alloc(0),
7145
+ sharedSecret: import_node_buffer14.Buffer.alloc(0)
6947
7146
  };
6948
7147
  continue;
6949
7148
  }
@@ -7051,24 +7250,54 @@ var SshTransportHandshake = class {
7051
7250
  return { outbound };
7052
7251
  }
7053
7252
  };
7253
+ var MAX_IDENTIFICATION_LINE_BYTES = 8192;
7254
+ var MAX_PRE_IDENTIFICATION_LINES = 1024;
7054
7255
  var SshIdentificationAccumulator = class {
7055
- pending = import_node_buffer15.Buffer.alloc(0);
7256
+ pending = import_node_buffer14.Buffer.alloc(0);
7257
+ bannerLineCount = 0;
7056
7258
  push(chunk) {
7057
- this.pending = import_node_buffer15.Buffer.concat([this.pending, import_node_buffer15.Buffer.from(chunk)]);
7259
+ this.pending = import_node_buffer14.Buffer.concat([this.pending, import_node_buffer14.Buffer.from(chunk)]);
7058
7260
  const bannerLines = [];
7059
7261
  while (true) {
7060
7262
  const lfIndex = this.pending.indexOf(10);
7061
- if (lfIndex < 0) break;
7263
+ if (lfIndex < 0) {
7264
+ if (this.pending.length > MAX_IDENTIFICATION_LINE_BYTES) {
7265
+ throw new ProtocolError({
7266
+ details: { limitBytes: MAX_IDENTIFICATION_LINE_BYTES },
7267
+ message: "SSH identification line exceeds the maximum accepted length",
7268
+ protocol: "sftp",
7269
+ retryable: false
7270
+ });
7271
+ }
7272
+ break;
7273
+ }
7274
+ if (lfIndex > MAX_IDENTIFICATION_LINE_BYTES) {
7275
+ throw new ProtocolError({
7276
+ details: { limitBytes: MAX_IDENTIFICATION_LINE_BYTES },
7277
+ message: "SSH identification line exceeds the maximum accepted length",
7278
+ protocol: "sftp",
7279
+ retryable: false
7280
+ });
7281
+ }
7062
7282
  const lineText = trimLineEndings(this.pending.subarray(0, lfIndex + 1).toString("ascii"));
7063
- const remainder = import_node_buffer15.Buffer.from(this.pending.subarray(lfIndex + 1));
7283
+ const remainder = import_node_buffer14.Buffer.from(this.pending.subarray(lfIndex + 1));
7064
7284
  this.pending = remainder;
7065
7285
  if (lineText.startsWith("SSH-")) {
7066
- this.pending = import_node_buffer15.Buffer.alloc(0);
7286
+ this.pending = import_node_buffer14.Buffer.alloc(0);
7067
7287
  return { bannerLines, identLine: lineText, remainder };
7068
7288
  }
7289
+ this.bannerLineCount += 1;
7290
+ if (this.bannerLineCount > MAX_PRE_IDENTIFICATION_LINES) {
7291
+ throw new ProtocolError({
7292
+ details: { limitLines: MAX_PRE_IDENTIFICATION_LINES },
7293
+ message: "SSH server sent too many pre-identification banner lines",
7294
+ protocol: "sftp",
7295
+ retryable: false
7296
+ });
7297
+ }
7069
7298
  bannerLines.push(lineText);
7070
7299
  }
7071
- return { bannerLines, remainder: import_node_buffer15.Buffer.alloc(0) };
7300
+ return { bannerLines, remainder: import_node_buffer14.Buffer.alloc(0) };
7072
7301
  }
7073
7302
  };
7074
7303
  function trimLineEndings(value) {
@@ -7096,7 +7325,7 @@ function missingPendingKeyExchangeError() {
7096
7325
  }
7097
7326
 
7098
7327
  // src/protocols/ssh/transport/SshTransportProtection.ts
7099
- var import_node_buffer16 = require("buffer");
7328
+ var import_node_buffer15 = require("buffer");
7100
7329
  var import_node_crypto8 = require("crypto");
7101
7330
  function createSshTransportProtectionContext(input) {
7102
7331
  return {
@@ -7153,7 +7382,7 @@ var SshTransportPacketProtector = class {
7153
7382
  );
7154
7383
  const encrypted = this.cipher === void 0 ? clearPacket : this.cipher.update(clearPacket);
7155
7384
  this.sequenceNumber = this.sequenceNumber + 1 >>> 0;
7156
- return import_node_buffer16.Buffer.concat([encrypted, mac]);
7385
+ return import_node_buffer15.Buffer.concat([encrypted, mac]);
7157
7386
  }
7158
7387
  };
7159
7388
  var SshTransportPacketUnprotector = class {
@@ -7179,7 +7408,7 @@ var SshTransportPacketUnprotector = class {
7179
7408
  sequenceNumber;
7180
7409
  // Streaming framing state for pushBytes()
7181
7410
  framePartialDecrypted;
7182
- framePendingRaw = import_node_buffer16.Buffer.alloc(0);
7411
+ framePendingRaw = import_node_buffer15.Buffer.alloc(0);
7183
7412
  frameRemainingNeeded;
7184
7413
  getSequenceNumber() {
7185
7414
  return this.sequenceNumber;
@@ -7189,15 +7418,23 @@ var SshTransportPacketUnprotector = class {
7189
7418
  * Maintains internal framing state across calls - pass each `data` event chunk directly.
7190
7419
  */
7191
7420
  pushBytes(chunk) {
7192
- this.framePendingRaw = import_node_buffer16.Buffer.concat([this.framePendingRaw, chunk]);
7421
+ this.framePendingRaw = import_node_buffer15.Buffer.concat([this.framePendingRaw, chunk]);
7193
7422
  const results = [];
7194
7423
  while (true) {
7195
7424
  if (this.framePartialDecrypted === void 0) {
7196
7425
  if (this.framePendingRaw.length < this.blockLength) break;
7197
7426
  const firstBlock = this.framePendingRaw.subarray(0, this.blockLength);
7198
- this.framePendingRaw = import_node_buffer16.Buffer.from(this.framePendingRaw.subarray(this.blockLength));
7199
- this.framePartialDecrypted = this.decipher ? import_node_buffer16.Buffer.from(this.decipher.update(firstBlock)) : import_node_buffer16.Buffer.from(firstBlock);
7427
+ this.framePendingRaw = import_node_buffer15.Buffer.from(this.framePendingRaw.subarray(this.blockLength));
7428
+ this.framePartialDecrypted = this.decipher ? import_node_buffer15.Buffer.from(this.decipher.update(firstBlock)) : import_node_buffer15.Buffer.from(firstBlock);
7200
7429
  const packetLength = this.framePartialDecrypted.readUInt32BE(0);
7430
+ if (packetLength > MAX_SSH_PACKET_LENGTH) {
7431
+ throw new ProtocolError({
7432
+ details: { maxPacketLength: MAX_SSH_PACKET_LENGTH, packetLength },
7433
+ message: "SSH encrypted packet length exceeds the maximum accepted size",
7434
+ protocol: "sftp",
7435
+ retryable: false
7436
+ });
7437
+ }
7201
7438
  const remaining = 4 + packetLength - this.blockLength + this.macLength;
7202
7439
  if (remaining < 0) {
7203
7440
  throw new ProtocolError({
@@ -7213,9 +7450,9 @@ var SshTransportPacketUnprotector = class {
7213
7450
  if (this.framePendingRaw.length < needed) break;
7214
7451
  const encryptedRest = this.framePendingRaw.subarray(0, needed - this.macLength);
7215
7452
  const receivedMac = this.framePendingRaw.subarray(needed - this.macLength, needed);
7216
- this.framePendingRaw = import_node_buffer16.Buffer.from(this.framePendingRaw.subarray(needed));
7217
- const decryptedRest = encryptedRest.length > 0 ? this.decipher ? import_node_buffer16.Buffer.from(this.decipher.update(encryptedRest)) : import_node_buffer16.Buffer.from(encryptedRest) : import_node_buffer16.Buffer.alloc(0);
7218
- const clearPacket = import_node_buffer16.Buffer.concat([this.framePartialDecrypted, decryptedRest]);
7453
+ this.framePendingRaw = import_node_buffer15.Buffer.from(this.framePendingRaw.subarray(needed));
7454
+ const decryptedRest = encryptedRest.length > 0 ? this.decipher ? import_node_buffer15.Buffer.from(this.decipher.update(encryptedRest)) : import_node_buffer15.Buffer.from(encryptedRest) : import_node_buffer15.Buffer.alloc(0);
7455
+ const clearPacket = import_node_buffer15.Buffer.concat([this.framePartialDecrypted, decryptedRest]);
7219
7456
  const expectedMac = computeMac(
7220
7457
  this.macAlgorithm,
7221
7458
  this.options.keys.macKey,
@@ -7238,7 +7475,7 @@ var SshTransportPacketUnprotector = class {
7238
7475
  return results;
7239
7476
  }
7240
7477
  unprotectPayload(packet) {
7241
- const frame = import_node_buffer16.Buffer.from(packet);
7478
+ const frame = import_node_buffer15.Buffer.from(packet);
7242
7479
  if (frame.length < this.macLength) {
7243
7480
  throw new ProtocolError({
7244
7481
  details: { length: frame.length, macLength: this.macLength },
@@ -7379,10 +7616,10 @@ function resolveMacLength(encryptionAlgorithm, macAlgorithm) {
7379
7616
  }
7380
7617
  function computeMac(macAlgorithm, macKey, sequence, packet, macLength) {
7381
7618
  if (macLength === 0) {
7382
- return import_node_buffer16.Buffer.alloc(0);
7619
+ return import_node_buffer15.Buffer.alloc(0);
7383
7620
  }
7384
7621
  const hashName = macAlgorithm === "hmac-sha2-512" ? "sha512" : "sha256";
7385
- const sequenceBuffer = import_node_buffer16.Buffer.alloc(4);
7622
+ const sequenceBuffer = import_node_buffer15.Buffer.alloc(4);
7386
7623
  sequenceBuffer.writeUInt32BE(sequence >>> 0, 0);
7387
7624
  return (0, import_node_crypto8.createHmac)(hashName, macKey).update(sequenceBuffer).update(packet).digest().subarray(0, macLength);
7388
7625
  }
@@ -7589,7 +7826,7 @@ var SshTransportConnection = class {
7589
7826
  */
7590
7827
  sendPayload(payload) {
7591
7828
  this.assertConnected();
7592
- const frame = this.protector.protectPayload(import_node_buffer17.Buffer.from(payload));
7829
+ const frame = this.protector.protectPayload(import_node_buffer16.Buffer.from(payload));
7593
7830
  this.socket.write(frame);
7594
7831
  this.resetKeepaliveTimer();
7595
7832
  }
@@ -7747,7 +7984,7 @@ function parseDisconnectPayload(payload) {
7747
7984
  }
7748
7985
 
7749
7986
  // src/protocols/sftp/v3/SftpSession.ts
7750
- var import_node_buffer19 = require("buffer");
7987
+ var import_node_buffer18 = require("buffer");
7751
7988
 
7752
7989
  // src/protocols/sftp/v3/SftpAttributes.ts
7753
7990
  var SFTP_ATTR_FLAG = {
@@ -7820,7 +8057,8 @@ function decodeSftpAttributesFromReader(reader) {
7820
8057
  }
7821
8058
 
7822
8059
  // src/protocols/sftp/v3/SftpPacket.ts
7823
- var import_node_buffer18 = require("buffer");
8060
+ var import_node_buffer17 = require("buffer");
8061
+ var MAX_SFTP_PACKET_LENGTH = 256 * 1024;
7824
8062
  var SFTP_PACKET_TYPE = {
7825
8063
  ATTRS: 105,
7826
8064
  CLOSE: 4,
@@ -7851,7 +8089,7 @@ var SFTP_PACKET_TYPE = {
7851
8089
  WRITE: 6
7852
8090
  };
7853
8091
  function decodeSftpPacket(frame) {
7854
- const bytes = import_node_buffer18.Buffer.from(frame);
8092
+ const bytes = import_node_buffer17.Buffer.from(frame);
7855
8093
  if (bytes.length < 5) {
7856
8094
  throw new ParseError({
7857
8095
  details: { length: bytes.length },
@@ -7874,12 +8112,19 @@ function decodeSftpPacket(frame) {
7874
8112
  };
7875
8113
  }
7876
8114
  var SftpPacketFramer = class {
7877
- pending = import_node_buffer18.Buffer.alloc(0);
8115
+ pending = import_node_buffer17.Buffer.alloc(0);
7878
8116
  push(chunk) {
7879
- this.pending = import_node_buffer18.Buffer.concat([this.pending, import_node_buffer18.Buffer.from(chunk)]);
8117
+ this.pending = import_node_buffer17.Buffer.concat([this.pending, import_node_buffer17.Buffer.from(chunk)]);
7880
8118
  const packets = [];
7881
8119
  while (this.pending.length >= 4) {
7882
8120
  const bodyLength = this.pending.readUInt32BE(0);
8121
+ if (bodyLength > MAX_SFTP_PACKET_LENGTH) {
8122
+ throw new ParseError({
8123
+ details: { bodyLength, maxPacketLength: MAX_SFTP_PACKET_LENGTH },
8124
+ message: "SFTP packet length exceeds the maximum accepted size",
8125
+ retryable: false
8126
+ });
8127
+ }
7883
8128
  const frameLength = 4 + bodyLength;
7884
8129
  if (this.pending.length < frameLength) {
7885
8130
  break;
@@ -8334,7 +8579,7 @@ var SftpSession = class {
8334
8579
  * serializes concurrent calls so byte ordering is preserved.
8335
8580
  */
8336
8581
  sendRaw(encodedMessage, requestId) {
8337
- const frame = import_node_buffer19.Buffer.alloc(4 + encodedMessage.length);
8582
+ const frame = import_node_buffer18.Buffer.alloc(4 + encodedMessage.length);
8338
8583
  frame.writeUInt32BE(encodedMessage.length, 0);
8339
8584
  encodedMessage.copy(frame, 4);
8340
8585
  this.channel.sendData(frame).catch((err) => {
@@ -8481,7 +8726,7 @@ function buildNativeSftpCapabilities(maxConcurrency) {
8481
8726
  var NATIVE_SFTP_PROVIDER_CAPABILITIES = buildNativeSftpCapabilities(
8482
8727
  NATIVE_SFTP_DEFAULT_MAX_CONCURRENCY
8483
8728
  );
8484
- function createNativeSftpProviderFactory(options = {}) {
8729
+ function createSftpProviderFactory(options = {}) {
8485
8730
  validateNativeSftpOptions(options);
8486
8731
  const capabilities = buildNativeSftpCapabilities(
8487
8732
  options.maxConcurrency ?? NATIVE_SFTP_DEFAULT_MAX_CONCURRENCY
@@ -8877,9 +9122,9 @@ function buildNativePublickeyCredential(profile, username) {
8877
9122
  const passphrase = profile.ssh?.passphrase;
8878
9123
  try {
8879
9124
  const privateKey = (0, import_node_crypto9.createPrivateKey)({
8880
- key: import_node_buffer20.Buffer.isBuffer(keyMaterial) ? keyMaterial : keyMaterial,
9125
+ key: import_node_buffer19.Buffer.isBuffer(keyMaterial) ? keyMaterial : keyMaterial,
8881
9126
  ...passphrase === void 0 ? {} : {
8882
- passphrase: import_node_buffer20.Buffer.isBuffer(passphrase) ? passphrase : passphrase
9127
+ passphrase: import_node_buffer19.Buffer.isBuffer(passphrase) ? passphrase : passphrase
8883
9128
  }
8884
9129
  });
8885
9130
  return buildPublickeyCredential({ privateKey, username });
@@ -9006,12 +9251,12 @@ function normalizeNativeHostKeyPins(value) {
9006
9251
  const trimmed = pin.trim();
9007
9252
  const hex = trimmed.replace(/:/g, "");
9008
9253
  if (hex.length === 64 && /^[a-f0-9]+$/i.test(hex)) {
9009
- normalized.add(import_node_buffer20.Buffer.from(hex, "hex").toString("base64").replace(/=+$/g, ""));
9254
+ normalized.add(import_node_buffer19.Buffer.from(hex, "hex").toString("base64").replace(/=+$/g, ""));
9010
9255
  continue;
9011
9256
  }
9012
9257
  const bare = trimmed.startsWith("SHA256:") ? trimmed.slice("SHA256:".length) : trimmed;
9013
9258
  const padded = bare.length % 4 === 0 ? bare : `${bare}${"=".repeat(4 - bare.length % 4)}`;
9014
- normalized.add(import_node_buffer20.Buffer.from(padded, "base64").toString("base64").replace(/=+$/g, ""));
9259
+ normalized.add(import_node_buffer19.Buffer.from(padded, "base64").toString("base64").replace(/=+$/g, ""));
9015
9260
  }
9016
9261
  return normalized;
9017
9262
  }
@@ -9021,7 +9266,7 @@ function parseNativeKnownHosts(source) {
9021
9266
  const entries = [];
9022
9267
  let sawNonEmpty = false;
9023
9268
  for (const value of sources) {
9024
- const text = import_node_buffer20.Buffer.isBuffer(value) ? value.toString("utf8") : String(value);
9269
+ const text = import_node_buffer19.Buffer.isBuffer(value) ? value.toString("utf8") : String(value);
9025
9270
  if (text.length === 0) continue;
9026
9271
  sawNonEmpty = true;
9027
9272
  entries.push(...parseKnownHosts(text));
@@ -9094,7 +9339,7 @@ function requireNativeSftpUsername(profile) {
9094
9339
  }
9095
9340
  function resolveNativeSftpTextSecret(value) {
9096
9341
  if (value === void 0) return void 0;
9097
- const text = import_node_buffer20.Buffer.isBuffer(value) ? value.toString("utf8") : value;
9342
+ const text = import_node_buffer19.Buffer.isBuffer(value) ? value.toString("utf8") : value;
9098
9343
  if (text.length === 0) return void 0;
9099
9344
  return text;
9100
9345
  }
@@ -9169,9 +9414,9 @@ function validateNativeSftpOptions(options) {
9169
9414
  copyBetween,
9170
9415
  createAtomicDeployPlan,
9171
9416
  createBandwidthThrottle,
9417
+ createDefaultRetryPolicy,
9172
9418
  createLocalProviderFactory,
9173
9419
  createMemoryProviderFactory,
9174
- createNativeSftpProviderFactory,
9175
9420
  createOAuthTokenSecretSource,
9176
9421
  createPooledTransferClient,
9177
9422
  createProgressEvent,
@@ -9206,8 +9451,10 @@ function validateNativeSftpOptions(options) {
9206
9451
  parseRemoteManifest,
9207
9452
  redactCommand,
9208
9453
  redactConnectionProfile,
9454
+ redactErrorForLogging,
9209
9455
  redactObject,
9210
9456
  redactSecretSource,
9457
+ redactUrlForLogging,
9211
9458
  redactValue,
9212
9459
  resolveConnectionProfileSecrets,
9213
9460
  resolveOpenSshHost,