@zero-transfer/sftp 0.4.7 → 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,6 +60,7 @@ __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
66
  createOAuthTokenSecretSource: () => createOAuthTokenSecretSource,
@@ -96,8 +97,10 @@ __export(sftp_exports, {
96
97
  parseRemoteManifest: () => parseRemoteManifest,
97
98
  redactCommand: () => redactCommand,
98
99
  redactConnectionProfile: () => redactConnectionProfile,
100
+ redactErrorForLogging: () => redactErrorForLogging,
99
101
  redactObject: () => redactObject,
100
102
  redactSecretSource: () => redactSecretSource,
103
+ redactUrlForLogging: () => redactUrlForLogging,
101
104
  redactValue: () => redactValue,
102
105
  resolveConnectionProfileSecrets: () => resolveConnectionProfileSecrets,
103
106
  resolveOpenSshHost: () => resolveOpenSshHost,
@@ -118,6 +121,68 @@ module.exports = __toCommonJS(sftp_exports);
118
121
  // src/client/ZeroTransfer.ts
119
122
  var import_node_events = require("events");
120
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
+
121
186
  // src/errors/ZeroTransferError.ts
122
187
  var ZeroTransferError = class extends Error {
123
188
  /** Stable machine-readable error code. */
@@ -159,6 +224,11 @@ var ZeroTransferError = class extends Error {
159
224
  /**
160
225
  * Serializes the error into a plain object suitable for logs or API responses.
161
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
+ *
162
232
  * @returns A JSON-safe object containing public structured error fields.
163
233
  */
164
234
  toJSON() {
@@ -168,12 +238,12 @@ var ZeroTransferError = class extends Error {
168
238
  message: this.message,
169
239
  protocol: this.protocol,
170
240
  host: this.host,
171
- command: this.command,
241
+ command: this.command === void 0 ? void 0 : redactCommand(this.command),
172
242
  ftpCode: this.ftpCode,
173
243
  sftpCode: this.sftpCode,
174
244
  path: this.path,
175
245
  retryable: this.retryable,
176
- details: this.details
246
+ details: this.details === void 0 ? void 0 : redactObject(this.details)
177
247
  };
178
248
  }
179
249
  };
@@ -696,15 +766,20 @@ var ProviderRegistry = class {
696
766
  var TransferClient = class {
697
767
  /** Provider registry used by this client. */
698
768
  registry;
769
+ /** Execution defaults applied when call sites omit their own values. */
770
+ defaults;
699
771
  logger;
700
772
  /**
701
773
  * Creates a transfer client without opening any provider connections.
702
774
  *
703
- * @param options - Optional registry, provider factories, and logger.
775
+ * @param options - Optional registry, provider factories, logger, and execution defaults.
704
776
  */
705
777
  constructor(options = {}) {
706
778
  this.registry = options.registry ?? new ProviderRegistry();
707
779
  this.logger = options.logger ?? noopLogger;
780
+ if (options.defaults !== void 0) {
781
+ this.defaults = { ...options.defaults };
782
+ }
708
783
  for (const provider of options.providers ?? []) {
709
784
  this.registry.register(provider);
710
785
  }
@@ -1277,18 +1352,25 @@ var TransferEngine = class {
1277
1352
  for (let attemptNumber = 1; attemptNumber <= maxAttempts; attemptNumber += 1) {
1278
1353
  this.throwIfAborted(abortScope.signal, job);
1279
1354
  const attemptStartedAt = this.now();
1355
+ const attemptScope = createAttemptScope(
1356
+ abortScope.signal,
1357
+ options.timeout,
1358
+ job,
1359
+ attemptNumber
1360
+ );
1280
1361
  const context = this.createExecutionContext(
1281
1362
  job,
1282
1363
  attemptNumber,
1283
1364
  attemptStartedAt,
1284
1365
  options,
1285
- abortScope.signal,
1366
+ attemptScope.signal,
1286
1367
  (bytesTransferred) => {
1287
1368
  latestBytesTransferred = bytesTransferred;
1288
- }
1369
+ },
1370
+ attemptScope.notifyProgress
1289
1371
  );
1290
1372
  try {
1291
- const result = await runExecutor(executor, context, abortScope.signal, job);
1373
+ const result = await runExecutor(executor, context, attemptScope.signal, job);
1292
1374
  context.throwIfAborted();
1293
1375
  latestBytesTransferred = result.bytesTransferred;
1294
1376
  const completedAt = this.now();
@@ -1306,16 +1388,27 @@ var TransferEngine = class {
1306
1388
  summarizeError(error)
1307
1389
  );
1308
1390
  attempts.push(attempt);
1309
- if (error instanceof AbortError || error instanceof TimeoutError) {
1391
+ if (error instanceof AbortError || abortScope.signal?.aborted === true) {
1310
1392
  throw error;
1311
1393
  }
1312
- 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
+ };
1313
1400
  const shouldRetry = attemptNumber < maxAttempts && (options.retry?.shouldRetry?.(retryInput) ?? isRetryable(error));
1314
1401
  if (shouldRetry) {
1315
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
+ }
1316
1407
  continue;
1317
1408
  }
1318
1409
  throw createTransferFailure(job, error, attempts);
1410
+ } finally {
1411
+ attemptScope.dispose();
1319
1412
  }
1320
1413
  }
1321
1414
  throw createTransferFailure(job, void 0, attempts);
@@ -1323,12 +1416,13 @@ var TransferEngine = class {
1323
1416
  abortScope.dispose();
1324
1417
  }
1325
1418
  }
1326
- createExecutionContext(job, attempt, startedAt, options, signal, updateBytesTransferred) {
1419
+ createExecutionContext(job, attempt, startedAt, options, signal, updateBytesTransferred, notifyProgress) {
1327
1420
  const context = {
1328
1421
  attempt,
1329
1422
  job,
1330
1423
  reportProgress: (bytesTransferred, totalBytes) => {
1331
1424
  this.throwIfAborted(signal, job);
1425
+ notifyProgress();
1332
1426
  updateBytesTransferred(bytesTransferred);
1333
1427
  const progressInput = {
1334
1428
  bytesTransferred,
@@ -1397,6 +1491,96 @@ function createAbortScope(parentSignal, timeout, job) {
1397
1491
  signal: controller.signal
1398
1492
  };
1399
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
+ }
1400
1584
  function normalizeTimeoutMs(value) {
1401
1585
  if (value === void 0 || !Number.isFinite(value) || value <= 0) {
1402
1586
  return void 0;
@@ -1565,7 +1749,7 @@ async function runRoute(options) {
1565
1749
  const executor = createProviderTransferExecutor({
1566
1750
  resolveSession: ({ role }) => sessions.get(role)
1567
1751
  });
1568
- return await engine.execute(job, executor, buildExecuteOptions(options));
1752
+ return await engine.execute(job, executor, buildExecuteOptions(options, client));
1569
1753
  } finally {
1570
1754
  if (destinationSession !== void 0) {
1571
1755
  await destinationSession.disconnect();
@@ -1602,12 +1786,14 @@ function defaultJobId(route, now) {
1602
1786
  const timestamp = (now?.() ?? /* @__PURE__ */ new Date()).getTime();
1603
1787
  return `route:${route.id}:${timestamp.toString(36)}`;
1604
1788
  }
1605
- function buildExecuteOptions(options) {
1789
+ function buildExecuteOptions(options, client) {
1606
1790
  const execute = {};
1791
+ const retry = options.retry ?? client.defaults?.retry;
1792
+ const timeout = options.timeout ?? client.defaults?.timeout;
1607
1793
  if (options.signal !== void 0) execute.signal = options.signal;
1608
- if (options.retry !== void 0) execute.retry = options.retry;
1794
+ if (retry !== void 0) execute.retry = retry;
1609
1795
  if (options.onProgress !== void 0) execute.onProgress = options.onProgress;
1610
- if (options.timeout !== void 0) execute.timeout = options.timeout;
1796
+ if (timeout !== void 0) execute.timeout = timeout;
1611
1797
  if (options.bandwidthLimit !== void 0) execute.bandwidthLimit = options.bandwidthLimit;
1612
1798
  return execute;
1613
1799
  }
@@ -1664,41 +1850,6 @@ function defaultRouteSuffix(source, destination) {
1664
1850
  return `${source}->${destination}`;
1665
1851
  }
1666
1852
 
1667
- // src/logging/redaction.ts
1668
- var REDACTED = "[REDACTED]";
1669
- var SENSITIVE_KEY_PATTERN = /(?:password|passphrase|privatekey|token|secret|username|user)$/i;
1670
- var SECRET_COMMAND_PATTERN = /^(PASS|USER|ACCT)\s+(.+)$/i;
1671
- function isSensitiveKey(key) {
1672
- return SENSITIVE_KEY_PATTERN.test(key.replace(/[_-]/g, ""));
1673
- }
1674
- function redactCommand(command) {
1675
- return command.replace(SECRET_COMMAND_PATTERN, (_fullMatch, commandName) => {
1676
- return `${commandName.toUpperCase()} ${REDACTED}`;
1677
- });
1678
- }
1679
- function redactValue(value) {
1680
- if (typeof value === "string") {
1681
- return redactCommand(value);
1682
- }
1683
- if (Array.isArray(value)) {
1684
- return value.map((item) => redactValue(item));
1685
- }
1686
- if (value !== null && typeof value === "object") {
1687
- return redactObject(value);
1688
- }
1689
- return value;
1690
- }
1691
- function redactObject(input) {
1692
- return Object.fromEntries(
1693
- Object.entries(input).map(([key, value]) => {
1694
- if (isSensitiveKey(key)) {
1695
- return [key, REDACTED];
1696
- }
1697
- return [key, redactValue(value)];
1698
- })
1699
- );
1700
- }
1701
-
1702
1853
  // src/profiles/SecretSource.ts
1703
1854
  var import_node_buffer2 = require("buffer");
1704
1855
  var import_promises = require("fs/promises");
@@ -2070,11 +2221,11 @@ var import_promises2 = require("fs/promises");
2070
2221
  var import_node_path2 = __toESM(require("path"));
2071
2222
 
2072
2223
  // src/utils/path.ts
2073
- var UNSAFE_FTP_ARGUMENT_PATTERN = /[\r\n]/;
2224
+ var UNSAFE_FTP_ARGUMENT_PATTERN = /[\r\n\0]/;
2074
2225
  function assertSafeFtpArgument(value, label = "path") {
2075
2226
  if (UNSAFE_FTP_ARGUMENT_PATTERN.test(value)) {
2076
2227
  throw new ConfigurationError({
2077
- message: `Unsafe FTP ${label}: CR and LF characters are not allowed`,
2228
+ message: `Unsafe FTP ${label}: CR, LF, and NUL characters are not allowed`,
2078
2229
  retryable: false,
2079
2230
  details: {
2080
2231
  label
@@ -3376,7 +3527,6 @@ function expandAlgorithms(values) {
3376
3527
  }
3377
3528
 
3378
3529
  // src/profiles/importers/FileZillaImporter.ts
3379
- var import_node_buffer5 = require("buffer");
3380
3530
  function importFileZillaSites(xml) {
3381
3531
  const events = tokenizeXml(xml);
3382
3532
  if (events.length === 0) {
@@ -3392,7 +3542,6 @@ function importFileZillaSites(xml) {
3392
3542
  const folderNamePending = [];
3393
3543
  let inServer = false;
3394
3544
  let serverFields = {};
3395
- let serverPasswordEncoding;
3396
3545
  let activeTag;
3397
3546
  let captureFolderName = false;
3398
3547
  for (const event of events) {
@@ -3405,13 +3554,9 @@ function importFileZillaSites(xml) {
3405
3554
  if (event.name === "Server") {
3406
3555
  inServer = true;
3407
3556
  serverFields = {};
3408
- serverPasswordEncoding = void 0;
3409
3557
  continue;
3410
3558
  }
3411
3559
  activeTag = event.name;
3412
- if (event.name === "Pass" && inServer) {
3413
- serverPasswordEncoding = event.attributes["encoding"];
3414
- }
3415
3560
  if (event.name === "Name" && !inServer && folderNamePending.length > 0) {
3416
3561
  captureFolderName = true;
3417
3562
  }
@@ -3437,7 +3582,7 @@ function importFileZillaSites(xml) {
3437
3582
  }
3438
3583
  if (event.name === "Server") {
3439
3584
  const folder = folderStack.filter((segment) => segment !== "");
3440
- const result = buildSiteFromFields(serverFields, serverPasswordEncoding);
3585
+ const result = buildSiteFromFields(serverFields);
3441
3586
  if (result.kind === "site") {
3442
3587
  sites.push({ ...result.site, folder });
3443
3588
  } else {
@@ -3449,7 +3594,6 @@ function importFileZillaSites(xml) {
3449
3594
  }
3450
3595
  inServer = false;
3451
3596
  serverFields = {};
3452
- serverPasswordEncoding = void 0;
3453
3597
  activeTag = void 0;
3454
3598
  continue;
3455
3599
  }
@@ -3458,7 +3602,7 @@ function importFileZillaSites(xml) {
3458
3602
  }
3459
3603
  return { sites, skipped };
3460
3604
  }
3461
- function buildSiteFromFields(fields, passwordEncoding) {
3605
+ function buildSiteFromFields(fields) {
3462
3606
  const name = (fields["Name"] ?? fields["Host"] ?? "Untitled").trim();
3463
3607
  const host = (fields["Host"] ?? "").trim();
3464
3608
  if (host === "") return { kind: "skipped", name };
@@ -3477,18 +3621,9 @@ function buildSiteFromFields(fields, passwordEncoding) {
3477
3621
  }
3478
3622
  const user = fields["User"]?.trim();
3479
3623
  if (user !== void 0 && user !== "") profile.username = { value: user };
3480
- let password;
3481
3624
  const rawPass = fields["Pass"];
3482
- if (rawPass !== void 0 && rawPass !== "") {
3483
- if (passwordEncoding === "base64") {
3484
- password = import_node_buffer5.Buffer.from(rawPass, "base64").toString("utf8");
3485
- } else {
3486
- password = rawPass;
3487
- }
3488
- if (password !== void 0 && password !== "") profile.password = { value: password };
3489
- }
3490
- const site = { name, profile };
3491
- if (password !== void 0) site.password = password;
3625
+ const hasStoredPassword = rawPass !== void 0 && rawPass !== "";
3626
+ const site = { hasStoredPassword, name, profile };
3492
3627
  const logonText = fields["Logontype"];
3493
3628
  if (logonText !== void 0) {
3494
3629
  const logonType = Number.parseInt(logonText.trim(), 10);
@@ -3731,6 +3866,62 @@ function mapFtp550(details) {
3731
3866
  return new PermissionDeniedError(details);
3732
3867
  }
3733
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
+
3734
3925
  // src/transfers/TransferPlan.ts
3735
3926
  function createTransferPlan(input) {
3736
3927
  const plan = {
@@ -3828,8 +4019,8 @@ var TransferQueue = class {
3828
4019
  this.concurrency = normalizeConcurrency(options.concurrency);
3829
4020
  this.defaultExecutor = options.executor;
3830
4021
  this.resolveExecutor = options.resolveExecutor;
3831
- this.retry = options.retry;
3832
- this.timeout = options.timeout;
4022
+ this.retry = options.retry ?? options.client?.defaults?.retry;
4023
+ this.timeout = options.timeout ?? options.client?.defaults?.timeout;
3833
4024
  this.bandwidthLimit = options.bandwidthLimit;
3834
4025
  this.onProgress = options.onProgress;
3835
4026
  this.onReceipt = options.onReceipt;
@@ -4906,12 +5097,12 @@ function isMainModule(importMetaUrl) {
4906
5097
  }
4907
5098
 
4908
5099
  // src/providers/native/sftp/NativeSftpProvider.ts
4909
- var import_node_buffer20 = require("buffer");
5100
+ var import_node_buffer19 = require("buffer");
4910
5101
  var import_node_crypto9 = require("crypto");
4911
5102
  var import_node_net = require("net");
4912
5103
 
4913
5104
  // src/protocols/ssh/binary/SshDataWriter.ts
4914
- var import_node_buffer6 = require("buffer");
5105
+ var import_node_buffer5 = require("buffer");
4915
5106
  var MAX_UINT32 = 4294967295;
4916
5107
  var MAX_UINT64 = (1n << 64n) - 1n;
4917
5108
  var SshDataWriter = class {
@@ -4919,7 +5110,7 @@ var SshDataWriter = class {
4919
5110
  length = 0;
4920
5111
  writeByte(value) {
4921
5112
  this.assertByte(value, "byte");
4922
- const chunk = import_node_buffer6.Buffer.alloc(1);
5113
+ const chunk = import_node_buffer5.Buffer.alloc(1);
4923
5114
  chunk.writeUInt8(value, 0);
4924
5115
  return this.push(chunk);
4925
5116
  }
@@ -4927,7 +5118,7 @@ var SshDataWriter = class {
4927
5118
  return this.writeByte(value ? 1 : 0);
4928
5119
  }
4929
5120
  writeBytes(value) {
4930
- return this.push(import_node_buffer6.Buffer.from(value));
5121
+ return this.push(import_node_buffer5.Buffer.from(value));
4931
5122
  }
4932
5123
  writeUint32(value) {
4933
5124
  if (!Number.isInteger(value) || value < 0 || value > MAX_UINT32) {
@@ -4937,7 +5128,7 @@ var SshDataWriter = class {
4937
5128
  retryable: false
4938
5129
  });
4939
5130
  }
4940
- const chunk = import_node_buffer6.Buffer.alloc(4);
5131
+ const chunk = import_node_buffer5.Buffer.alloc(4);
4941
5132
  chunk.writeUInt32BE(value, 0);
4942
5133
  return this.push(chunk);
4943
5134
  }
@@ -4949,12 +5140,12 @@ var SshDataWriter = class {
4949
5140
  retryable: false
4950
5141
  });
4951
5142
  }
4952
- const chunk = import_node_buffer6.Buffer.alloc(8);
5143
+ const chunk = import_node_buffer5.Buffer.alloc(8);
4953
5144
  chunk.writeBigUInt64BE(value, 0);
4954
5145
  return this.push(chunk);
4955
5146
  }
4956
5147
  writeString(value, encoding = "utf8") {
4957
- 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);
4958
5149
  this.writeUint32(payload.length);
4959
5150
  return this.push(payload);
4960
5151
  }
@@ -4976,7 +5167,7 @@ var SshDataWriter = class {
4976
5167
  return this.writeString(values.join(","), "ascii");
4977
5168
  }
4978
5169
  toBuffer() {
4979
- return import_node_buffer6.Buffer.concat(this.chunks, this.length);
5170
+ return import_node_buffer5.Buffer.concat(this.chunks, this.length);
4980
5171
  }
4981
5172
  push(chunk) {
4982
5173
  this.chunks.push(chunk);
@@ -4994,23 +5185,23 @@ var SshDataWriter = class {
4994
5185
  }
4995
5186
  };
4996
5187
  function normalizePositiveMpint(value) {
4997
- const input = import_node_buffer6.Buffer.from(value);
5188
+ const input = import_node_buffer5.Buffer.from(value);
4998
5189
  let offset = 0;
4999
5190
  while (offset < input.length && input[offset] === 0) {
5000
5191
  offset += 1;
5001
5192
  }
5002
5193
  if (offset >= input.length) {
5003
- return import_node_buffer6.Buffer.alloc(0);
5194
+ return import_node_buffer5.Buffer.alloc(0);
5004
5195
  }
5005
5196
  const stripped = input.subarray(offset);
5006
5197
  if ((stripped[0] & 128) === 128) {
5007
- 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]);
5008
5199
  }
5009
5200
  return stripped;
5010
5201
  }
5011
5202
 
5012
5203
  // src/protocols/ssh/binary/SshDataReader.ts
5013
- var import_node_buffer7 = require("buffer");
5204
+ var import_node_buffer6 = require("buffer");
5014
5205
  var SshDataReader = class {
5015
5206
  constructor(source) {
5016
5207
  this.source = source;
@@ -5036,18 +5227,18 @@ var SshDataReader = class {
5036
5227
  this.ensureAvailable(length, "bytes");
5037
5228
  const data = this.source.subarray(this.offset, this.offset + length);
5038
5229
  this.offset += length;
5039
- return import_node_buffer7.Buffer.from(data);
5230
+ return import_node_buffer6.Buffer.from(data);
5040
5231
  }
5041
5232
  readUint32() {
5042
5233
  this.ensureAvailable(4, "uint32");
5043
- const buffer = import_node_buffer7.Buffer.from(this.source);
5234
+ const buffer = import_node_buffer6.Buffer.from(this.source);
5044
5235
  const value = buffer.readUInt32BE(this.offset);
5045
5236
  this.offset += 4;
5046
5237
  return value;
5047
5238
  }
5048
5239
  readUint64() {
5049
5240
  this.ensureAvailable(8, "uint64");
5050
- const buffer = import_node_buffer7.Buffer.from(this.source);
5241
+ const buffer = import_node_buffer6.Buffer.from(this.source);
5051
5242
  const value = buffer.readBigUInt64BE(this.offset);
5052
5243
  this.offset += 8;
5053
5244
  return value;
@@ -5057,7 +5248,7 @@ var SshDataReader = class {
5057
5248
  this.ensureAvailable(length, "string");
5058
5249
  const data = this.source.subarray(this.offset, this.offset + length);
5059
5250
  this.offset += length;
5060
- return import_node_buffer7.Buffer.from(data);
5251
+ return import_node_buffer6.Buffer.from(data);
5061
5252
  }
5062
5253
  readUtf8String() {
5063
5254
  return this.readString().toString("utf8");
@@ -5412,7 +5603,7 @@ function buildKiRequest(args) {
5412
5603
  }
5413
5604
 
5414
5605
  // src/protocols/ssh/auth/SshPublickeyCredentialBuilder.ts
5415
- var import_node_buffer8 = require("buffer");
5606
+ var import_node_buffer7 = require("buffer");
5416
5607
  var import_node_crypto2 = require("crypto");
5417
5608
  var ED25519_RAW_KEY_LENGTH = 32;
5418
5609
  var ED25519_SPKI_PREFIX_LENGTH = 12;
@@ -5430,7 +5621,7 @@ function buildPublickeyCredential(options) {
5430
5621
  return {
5431
5622
  algorithmName: "ssh-ed25519",
5432
5623
  publicKeyBlob,
5433
- 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),
5434
5625
  type: "publickey",
5435
5626
  username
5436
5627
  };
@@ -5448,7 +5639,7 @@ function buildPublickeyCredential(options) {
5448
5639
  return {
5449
5640
  algorithmName,
5450
5641
  publicKeyBlob,
5451
- 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),
5452
5643
  type: "publickey",
5453
5644
  username
5454
5645
  };
@@ -5461,7 +5652,7 @@ function buildPublickeyCredential(options) {
5461
5652
  }
5462
5653
  function base64UrlToMpint(value) {
5463
5654
  const padded = value.replace(/-/g, "+").replace(/_/g, "/");
5464
- const buffer = import_node_buffer8.Buffer.from(padded, "base64");
5655
+ const buffer = import_node_buffer7.Buffer.from(padded, "base64");
5465
5656
  return buffer;
5466
5657
  }
5467
5658
  function createInvalidKeyError(message) {
@@ -5587,7 +5778,7 @@ function encodeSshChannelClose(recipientChannel) {
5587
5778
  }
5588
5779
 
5589
5780
  // src/protocols/ssh/connection/SshSessionChannel.ts
5590
- var import_node_buffer9 = require("buffer");
5781
+ var import_node_buffer8 = require("buffer");
5591
5782
  var INITIAL_WINDOW_SIZE = 256 * 1024;
5592
5783
  var MAX_PACKET_SIZE = 32 * 1024;
5593
5784
  var WINDOW_REFILL_THRESHOLD = 64 * 1024;
@@ -5745,7 +5936,7 @@ var SshSessionChannel = class {
5745
5936
  this.remoteWindowRemaining,
5746
5937
  this.remoteMaxPacketSize
5747
5938
  );
5748
- 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));
5749
5940
  this.transport.sendPayload(
5750
5941
  encodeSshChannelData({ data: chunk, recipientChannel: this.remoteChannelId })
5751
5942
  );
@@ -6007,10 +6198,10 @@ var SshConnectionManager = class {
6007
6198
  };
6008
6199
 
6009
6200
  // src/protocols/ssh/transport/SshTransportConnection.ts
6010
- var import_node_buffer17 = require("buffer");
6201
+ var import_node_buffer16 = require("buffer");
6011
6202
 
6012
6203
  // src/protocols/ssh/transport/SshTransportHandshake.ts
6013
- var import_node_buffer15 = require("buffer");
6204
+ var import_node_buffer14 = require("buffer");
6014
6205
 
6015
6206
  // src/protocols/ssh/transport/SshAlgorithmNegotiation.ts
6016
6207
  var DEFAULT_SSH_ALGORITHM_PREFERENCES = {
@@ -6172,12 +6363,12 @@ function parseSshIdentificationLine(line) {
6172
6363
  }
6173
6364
 
6174
6365
  // src/protocols/ssh/transport/SshKexInit.ts
6175
- var import_node_buffer10 = require("buffer");
6366
+ var import_node_buffer9 = require("buffer");
6176
6367
  var import_node_crypto3 = require("crypto");
6177
6368
  var SSH_MSG_KEXINIT = 20;
6178
6369
  var KEXINIT_COOKIE_LENGTH = 16;
6179
6370
  function encodeSshKexInitMessage(options) {
6180
- 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);
6181
6372
  if (cookie.length !== KEXINIT_COOKIE_LENGTH) {
6182
6373
  throw new ConfigurationError({
6183
6374
  details: { actualLength: cookie.length, expectedLength: KEXINIT_COOKIE_LENGTH },
@@ -6247,12 +6438,12 @@ function decodeSshKexInitMessage(payload) {
6247
6438
  }
6248
6439
 
6249
6440
  // src/protocols/ssh/transport/SshKexCurve25519.ts
6250
- var import_node_buffer11 = require("buffer");
6441
+ var import_node_buffer10 = require("buffer");
6251
6442
  var import_node_crypto4 = require("crypto");
6252
6443
  var SSH_MSG_KEX_ECDH_INIT = 30;
6253
6444
  var SSH_MSG_KEX_ECDH_REPLY = 31;
6254
6445
  var X25519_PUBLIC_KEY_LENGTH = 32;
6255
- var X25519_SPKI_PREFIX = import_node_buffer11.Buffer.from("302a300506032b656e032100", "hex");
6446
+ var X25519_SPKI_PREFIX = import_node_buffer10.Buffer.from("302a300506032b656e032100", "hex");
6256
6447
  function createCurve25519Ephemeral() {
6257
6448
  const { privateKey, publicKey } = (0, import_node_crypto4.generateKeyPairSync)("x25519");
6258
6449
  const encodedPublicKey = exportX25519PublicKeyRaw(publicKey);
@@ -6297,7 +6488,7 @@ function exportX25519PublicKeyRaw(publicKey) {
6297
6488
  }
6298
6489
  function importX25519PublicKeyRaw(raw) {
6299
6490
  const normalized = normalizeX25519PublicKey(raw, "server");
6300
- const der = import_node_buffer11.Buffer.concat([X25519_SPKI_PREFIX, normalized]);
6491
+ const der = import_node_buffer10.Buffer.concat([X25519_SPKI_PREFIX, normalized]);
6301
6492
  return (0, import_node_crypto4.createPublicKey)({
6302
6493
  format: "der",
6303
6494
  key: der,
@@ -6305,7 +6496,7 @@ function importX25519PublicKeyRaw(raw) {
6305
6496
  });
6306
6497
  }
6307
6498
  function normalizeX25519PublicKey(value, label) {
6308
- const key = import_node_buffer11.Buffer.from(value);
6499
+ const key = import_node_buffer10.Buffer.from(value);
6309
6500
  if (key.length !== X25519_PUBLIC_KEY_LENGTH) {
6310
6501
  throw new ConfigurationError({
6311
6502
  details: { keyLength: key.length, label },
@@ -6318,7 +6509,7 @@ function normalizeX25519PublicKey(value, label) {
6318
6509
  }
6319
6510
 
6320
6511
  // src/protocols/ssh/transport/SshKeyDerivation.ts
6321
- var import_node_buffer12 = require("buffer");
6512
+ var import_node_buffer11 = require("buffer");
6322
6513
  var import_node_crypto5 = require("crypto");
6323
6514
  function deriveSshSessionKeys(input) {
6324
6515
  const hashAlgorithm = resolveKexHashAlgorithm(input.kexAlgorithm);
@@ -6340,7 +6531,7 @@ function deriveSshSessionKeys(input) {
6340
6531
  input.negotiatedAlgorithms.encryptionServerToClient,
6341
6532
  input.negotiatedAlgorithms.macServerToClient
6342
6533
  );
6343
- const sharedSecret = import_node_buffer12.Buffer.from(input.sharedSecret);
6534
+ const sharedSecret = import_node_buffer11.Buffer.from(input.sharedSecret);
6344
6535
  return {
6345
6536
  clientToServer: {
6346
6537
  encryptionKey: deriveMaterial(
@@ -6390,21 +6581,21 @@ function computeCurve25519ExchangeHash(input, hashAlgorithm) {
6390
6581
  }
6391
6582
  function deriveMaterial(sharedSecret, exchangeHash, sessionId, letter, length, hashAlgorithm) {
6392
6583
  if (length <= 0) {
6393
- return import_node_buffer12.Buffer.alloc(0);
6584
+ return import_node_buffer11.Buffer.alloc(0);
6394
6585
  }
6395
6586
  const result = [];
6396
6587
  const first2 = (0, import_node_crypto5.createHash)(hashAlgorithm).update(
6397
6588
  new SshDataWriter().writeMpint(sharedSecret).writeBytes(exchangeHash).writeByte(letter.charCodeAt(0)).writeBytes(sessionId).toBuffer()
6398
6589
  ).digest();
6399
6590
  result.push(first2);
6400
- while (import_node_buffer12.Buffer.concat(result).length < length) {
6401
- 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);
6402
6593
  const next = (0, import_node_crypto5.createHash)(hashAlgorithm).update(
6403
6594
  new SshDataWriter().writeMpint(sharedSecret).writeBytes(exchangeHash).writeBytes(previous).toBuffer()
6404
6595
  ).digest();
6405
6596
  result.push(next);
6406
6597
  }
6407
- return import_node_buffer12.Buffer.concat(result).subarray(0, length);
6598
+ return import_node_buffer11.Buffer.concat(result).subarray(0, length);
6408
6599
  }
6409
6600
  function resolveKexHashAlgorithm(kexAlgorithm) {
6410
6601
  if (kexAlgorithm === "curve25519-sha256" || kexAlgorithm === "curve25519-sha256@libssh.org") {
@@ -6492,20 +6683,21 @@ function decodeSshNewKeysMessage(payload) {
6492
6683
  }
6493
6684
 
6494
6685
  // src/protocols/ssh/transport/SshTransportPacket.ts
6495
- var import_node_buffer13 = require("buffer");
6686
+ var import_node_buffer12 = require("buffer");
6496
6687
  var import_node_crypto6 = require("crypto");
6497
6688
  var MIN_PADDING_LENGTH = 4;
6498
6689
  var MIN_PACKET_LENGTH = 1 + MIN_PADDING_LENGTH;
6690
+ var MAX_SSH_PACKET_LENGTH = 256 * 1024;
6499
6691
  function encodeSshTransportPacket(payload, options = {}) {
6500
- const body = import_node_buffer13.Buffer.from(payload);
6692
+ const body = import_node_buffer12.Buffer.from(payload);
6501
6693
  const blockSize = normalizeBlockSize(options.blockSize ?? 8);
6502
6694
  let paddingLength = MIN_PADDING_LENGTH;
6503
6695
  while ((1 + body.length + paddingLength + 4) % blockSize !== 0) {
6504
6696
  paddingLength += 1;
6505
6697
  }
6506
- 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);
6507
6699
  const packetLength = 1 + body.length + paddingLength;
6508
- const frame = import_node_buffer13.Buffer.alloc(4 + packetLength);
6700
+ const frame = import_node_buffer12.Buffer.alloc(4 + packetLength);
6509
6701
  frame.writeUInt32BE(packetLength, 0);
6510
6702
  frame.writeUInt8(paddingLength, 4);
6511
6703
  body.copy(frame, 5);
@@ -6513,7 +6705,7 @@ function encodeSshTransportPacket(payload, options = {}) {
6513
6705
  return frame;
6514
6706
  }
6515
6707
  function decodeSshTransportPacket(frame) {
6516
- const bytes = import_node_buffer13.Buffer.from(frame);
6708
+ const bytes = import_node_buffer12.Buffer.from(frame);
6517
6709
  if (bytes.length < 4 + MIN_PACKET_LENGTH) {
6518
6710
  throw new ParseError({
6519
6711
  details: { length: bytes.length },
@@ -6567,12 +6759,20 @@ function decodeSshTransportPacket(frame) {
6567
6759
  };
6568
6760
  }
6569
6761
  var SshTransportPacketFramer = class {
6570
- pending = import_node_buffer13.Buffer.alloc(0);
6762
+ pending = import_node_buffer12.Buffer.alloc(0);
6571
6763
  push(chunk) {
6572
- 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)]);
6573
6765
  const packets = [];
6574
6766
  while (this.pending.length >= 4) {
6575
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
+ }
6576
6776
  const frameLength = 4 + packetLength;
6577
6777
  if (this.pending.length < frameLength) {
6578
6778
  break;
@@ -6588,8 +6788,8 @@ var SshTransportPacketFramer = class {
6588
6788
  }
6589
6789
  /** Returns and clears any bytes buffered but not yet part of a complete packet. */
6590
6790
  takeRemainingBytes() {
6591
- const remaining = import_node_buffer13.Buffer.from(this.pending);
6592
- 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);
6593
6793
  return remaining;
6594
6794
  }
6595
6795
  };
@@ -6606,10 +6806,10 @@ function normalizeBlockSize(blockSize) {
6606
6806
  }
6607
6807
 
6608
6808
  // src/protocols/ssh/transport/SshHostKeyVerification.ts
6609
- var import_node_buffer14 = require("buffer");
6809
+ var import_node_buffer13 = require("buffer");
6610
6810
  var import_node_crypto7 = require("crypto");
6611
6811
  var ED25519_RAW_KEY_LENGTH2 = 32;
6612
- var ED25519_SPKI_PREFIX = import_node_buffer14.Buffer.from("302a300506032b6570032100", "hex");
6812
+ var ED25519_SPKI_PREFIX = import_node_buffer13.Buffer.from("302a300506032b6570032100", "hex");
6613
6813
  function verifySshHostKeySignature(input) {
6614
6814
  const { algorithmName, publicKey } = parseHostKey(input.hostKeyBlob);
6615
6815
  const { signatureAlgorithm, signatureBytes } = parseSignatureBlob(input.signatureBlob);
@@ -6622,9 +6822,9 @@ function verifySshHostKeySignature(input) {
6622
6822
  });
6623
6823
  }
6624
6824
  const verified = verifySignature({
6625
- data: import_node_buffer14.Buffer.from(input.exchangeHash),
6825
+ data: import_node_buffer13.Buffer.from(input.exchangeHash),
6626
6826
  publicKey,
6627
- signature: import_node_buffer14.Buffer.from(signatureBytes),
6827
+ signature: import_node_buffer13.Buffer.from(signatureBytes),
6628
6828
  signatureAlgorithm
6629
6829
  });
6630
6830
  if (!verified) {
@@ -6653,7 +6853,7 @@ function parseHostKey(blob) {
6653
6853
  retryable: false
6654
6854
  });
6655
6855
  }
6656
- const spki = import_node_buffer14.Buffer.concat([ED25519_SPKI_PREFIX, raw]);
6856
+ const spki = import_node_buffer13.Buffer.concat([ED25519_SPKI_PREFIX, raw]);
6657
6857
  return {
6658
6858
  algorithmName,
6659
6859
  publicKey: (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" })
@@ -6759,37 +6959,37 @@ function verifySignature(input) {
6759
6959
  function rsaPublicKeyFromComponents(e, n) {
6760
6960
  const eDer = encodeAsn1Integer(e);
6761
6961
  const nDer = encodeAsn1Integer(n);
6762
- const rsaPublicKeyDer = encodeAsn1Sequence(import_node_buffer14.Buffer.concat([nDer, eDer]));
6763
- const bitStringContent = import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([0]), rsaPublicKeyDer]);
6764
- const bitString = import_node_buffer14.Buffer.concat([
6765
- 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]),
6766
6966
  encodeAsn1Length(bitStringContent.length),
6767
6967
  bitStringContent
6768
6968
  ]);
6769
- const algoId = import_node_buffer14.Buffer.from("300d06092a864886f70d010101 0500".replace(/\s+/g, ""), "hex");
6770
- 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]));
6771
6971
  return (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" });
6772
6972
  }
6773
6973
  function encodeAsn1Integer(value) {
6774
6974
  let body = value;
6775
6975
  while (body.length > 1 && body[0] === 0) body = body.subarray(1);
6776
6976
  if (body.length > 0 && (body[0] & 128) !== 0) {
6777
- 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]);
6778
6978
  }
6779
- 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]);
6780
6980
  }
6781
6981
  function encodeAsn1Sequence(content) {
6782
- 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]);
6783
6983
  }
6784
6984
  function encodeAsn1Length(length) {
6785
- if (length < 128) return import_node_buffer14.Buffer.from([length]);
6985
+ if (length < 128) return import_node_buffer13.Buffer.from([length]);
6786
6986
  const bytes = [];
6787
6987
  let n = length;
6788
6988
  while (n > 0) {
6789
6989
  bytes.unshift(n & 255);
6790
6990
  n >>>= 8;
6791
6991
  }
6792
- return import_node_buffer14.Buffer.from([128 | bytes.length, ...bytes]);
6992
+ return import_node_buffer13.Buffer.from([128 | bytes.length, ...bytes]);
6793
6993
  }
6794
6994
  var ECDSA_OID_BY_CURVE = {
6795
6995
  nistp256: "06082a8648ce3d030107",
@@ -6810,15 +7010,15 @@ function ecdsaPublicKeyFromPoint(curveIdentifier, point) {
6810
7010
  retryable: false
6811
7011
  });
6812
7012
  }
6813
- 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");
6814
7014
  const algoId = encodeAsn1Sequence(algoIdContent);
6815
- const bitStringContent = import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([0]), point]);
6816
- const bitString = import_node_buffer14.Buffer.concat([
6817
- 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]),
6818
7018
  encodeAsn1Length(bitStringContent.length),
6819
7019
  bitStringContent
6820
7020
  ]);
6821
- const spki = encodeAsn1Sequence(import_node_buffer14.Buffer.concat([algoId, bitString]));
7021
+ const spki = encodeAsn1Sequence(import_node_buffer13.Buffer.concat([algoId, bitString]));
6822
7022
  return (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" });
6823
7023
  }
6824
7024
  function sshEcdsaSignatureToDer(sshSignature) {
@@ -6827,7 +7027,7 @@ function sshEcdsaSignatureToDer(sshSignature) {
6827
7027
  const s = reader.readMpint();
6828
7028
  const rDer = encodeAsn1Integer(r);
6829
7029
  const sDer = encodeAsn1Integer(s);
6830
- return encodeAsn1Sequence(import_node_buffer14.Buffer.concat([rDer, sDer]));
7030
+ return encodeAsn1Sequence(import_node_buffer13.Buffer.concat([rDer, sDer]));
6831
7031
  }
6832
7032
 
6833
7033
  // src/protocols/ssh/transport/SshTransportHandshake.ts
@@ -6859,7 +7059,7 @@ var SshTransportHandshake = class {
6859
7059
  serverIdentification;
6860
7060
  /** Creates the first outbound bytes (client identification line). */
6861
7061
  createInitialClientBytes() {
6862
- return import_node_buffer15.Buffer.from(`${this.clientIdentificationLine}\r
7062
+ return import_node_buffer14.Buffer.from(`${this.clientIdentificationLine}\r
6863
7063
  `, "ascii");
6864
7064
  }
6865
7065
  /**
@@ -6883,7 +7083,7 @@ var SshTransportHandshake = class {
6883
7083
  }
6884
7084
  return { outbound };
6885
7085
  }
6886
- return this.pushServerBytesWithPhase(outbound, import_node_buffer15.Buffer.from(chunk));
7086
+ return this.pushServerBytesWithPhase(outbound, import_node_buffer14.Buffer.from(chunk));
6887
7087
  }
6888
7088
  getServerBannerLines() {
6889
7089
  return this.identificationLines;
@@ -6937,12 +7137,12 @@ var SshTransportHandshake = class {
6937
7137
  clientKexInitPayload: this.clientKexInitPayload,
6938
7138
  clientPublicKey: this.pendingCurve25519.publicKey,
6939
7139
  negotiatedAlgorithms,
6940
- serverHostKey: import_node_buffer15.Buffer.alloc(0),
7140
+ serverHostKey: import_node_buffer14.Buffer.alloc(0),
6941
7141
  serverIdentification: (this.serverIdentification ?? missingServerIdentificationError()).raw,
6942
- serverKexInitPayload: import_node_buffer15.Buffer.from(packet.payload),
6943
- serverPublicKey: import_node_buffer15.Buffer.alloc(0),
6944
- serverSignature: import_node_buffer15.Buffer.alloc(0),
6945
- 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)
6946
7146
  };
6947
7147
  continue;
6948
7148
  }
@@ -7050,24 +7250,54 @@ var SshTransportHandshake = class {
7050
7250
  return { outbound };
7051
7251
  }
7052
7252
  };
7253
+ var MAX_IDENTIFICATION_LINE_BYTES = 8192;
7254
+ var MAX_PRE_IDENTIFICATION_LINES = 1024;
7053
7255
  var SshIdentificationAccumulator = class {
7054
- pending = import_node_buffer15.Buffer.alloc(0);
7256
+ pending = import_node_buffer14.Buffer.alloc(0);
7257
+ bannerLineCount = 0;
7055
7258
  push(chunk) {
7056
- 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)]);
7057
7260
  const bannerLines = [];
7058
7261
  while (true) {
7059
7262
  const lfIndex = this.pending.indexOf(10);
7060
- 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
+ }
7061
7282
  const lineText = trimLineEndings(this.pending.subarray(0, lfIndex + 1).toString("ascii"));
7062
- 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));
7063
7284
  this.pending = remainder;
7064
7285
  if (lineText.startsWith("SSH-")) {
7065
- this.pending = import_node_buffer15.Buffer.alloc(0);
7286
+ this.pending = import_node_buffer14.Buffer.alloc(0);
7066
7287
  return { bannerLines, identLine: lineText, remainder };
7067
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
+ }
7068
7298
  bannerLines.push(lineText);
7069
7299
  }
7070
- return { bannerLines, remainder: import_node_buffer15.Buffer.alloc(0) };
7300
+ return { bannerLines, remainder: import_node_buffer14.Buffer.alloc(0) };
7071
7301
  }
7072
7302
  };
7073
7303
  function trimLineEndings(value) {
@@ -7095,7 +7325,7 @@ function missingPendingKeyExchangeError() {
7095
7325
  }
7096
7326
 
7097
7327
  // src/protocols/ssh/transport/SshTransportProtection.ts
7098
- var import_node_buffer16 = require("buffer");
7328
+ var import_node_buffer15 = require("buffer");
7099
7329
  var import_node_crypto8 = require("crypto");
7100
7330
  function createSshTransportProtectionContext(input) {
7101
7331
  return {
@@ -7152,7 +7382,7 @@ var SshTransportPacketProtector = class {
7152
7382
  );
7153
7383
  const encrypted = this.cipher === void 0 ? clearPacket : this.cipher.update(clearPacket);
7154
7384
  this.sequenceNumber = this.sequenceNumber + 1 >>> 0;
7155
- return import_node_buffer16.Buffer.concat([encrypted, mac]);
7385
+ return import_node_buffer15.Buffer.concat([encrypted, mac]);
7156
7386
  }
7157
7387
  };
7158
7388
  var SshTransportPacketUnprotector = class {
@@ -7178,7 +7408,7 @@ var SshTransportPacketUnprotector = class {
7178
7408
  sequenceNumber;
7179
7409
  // Streaming framing state for pushBytes()
7180
7410
  framePartialDecrypted;
7181
- framePendingRaw = import_node_buffer16.Buffer.alloc(0);
7411
+ framePendingRaw = import_node_buffer15.Buffer.alloc(0);
7182
7412
  frameRemainingNeeded;
7183
7413
  getSequenceNumber() {
7184
7414
  return this.sequenceNumber;
@@ -7188,15 +7418,23 @@ var SshTransportPacketUnprotector = class {
7188
7418
  * Maintains internal framing state across calls - pass each `data` event chunk directly.
7189
7419
  */
7190
7420
  pushBytes(chunk) {
7191
- this.framePendingRaw = import_node_buffer16.Buffer.concat([this.framePendingRaw, chunk]);
7421
+ this.framePendingRaw = import_node_buffer15.Buffer.concat([this.framePendingRaw, chunk]);
7192
7422
  const results = [];
7193
7423
  while (true) {
7194
7424
  if (this.framePartialDecrypted === void 0) {
7195
7425
  if (this.framePendingRaw.length < this.blockLength) break;
7196
7426
  const firstBlock = this.framePendingRaw.subarray(0, this.blockLength);
7197
- this.framePendingRaw = import_node_buffer16.Buffer.from(this.framePendingRaw.subarray(this.blockLength));
7198
- 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);
7199
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
+ }
7200
7438
  const remaining = 4 + packetLength - this.blockLength + this.macLength;
7201
7439
  if (remaining < 0) {
7202
7440
  throw new ProtocolError({
@@ -7212,9 +7450,9 @@ var SshTransportPacketUnprotector = class {
7212
7450
  if (this.framePendingRaw.length < needed) break;
7213
7451
  const encryptedRest = this.framePendingRaw.subarray(0, needed - this.macLength);
7214
7452
  const receivedMac = this.framePendingRaw.subarray(needed - this.macLength, needed);
7215
- this.framePendingRaw = import_node_buffer16.Buffer.from(this.framePendingRaw.subarray(needed));
7216
- 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);
7217
- 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]);
7218
7456
  const expectedMac = computeMac(
7219
7457
  this.macAlgorithm,
7220
7458
  this.options.keys.macKey,
@@ -7237,7 +7475,7 @@ var SshTransportPacketUnprotector = class {
7237
7475
  return results;
7238
7476
  }
7239
7477
  unprotectPayload(packet) {
7240
- const frame = import_node_buffer16.Buffer.from(packet);
7478
+ const frame = import_node_buffer15.Buffer.from(packet);
7241
7479
  if (frame.length < this.macLength) {
7242
7480
  throw new ProtocolError({
7243
7481
  details: { length: frame.length, macLength: this.macLength },
@@ -7378,10 +7616,10 @@ function resolveMacLength(encryptionAlgorithm, macAlgorithm) {
7378
7616
  }
7379
7617
  function computeMac(macAlgorithm, macKey, sequence, packet, macLength) {
7380
7618
  if (macLength === 0) {
7381
- return import_node_buffer16.Buffer.alloc(0);
7619
+ return import_node_buffer15.Buffer.alloc(0);
7382
7620
  }
7383
7621
  const hashName = macAlgorithm === "hmac-sha2-512" ? "sha512" : "sha256";
7384
- const sequenceBuffer = import_node_buffer16.Buffer.alloc(4);
7622
+ const sequenceBuffer = import_node_buffer15.Buffer.alloc(4);
7385
7623
  sequenceBuffer.writeUInt32BE(sequence >>> 0, 0);
7386
7624
  return (0, import_node_crypto8.createHmac)(hashName, macKey).update(sequenceBuffer).update(packet).digest().subarray(0, macLength);
7387
7625
  }
@@ -7588,7 +7826,7 @@ var SshTransportConnection = class {
7588
7826
  */
7589
7827
  sendPayload(payload) {
7590
7828
  this.assertConnected();
7591
- const frame = this.protector.protectPayload(import_node_buffer17.Buffer.from(payload));
7829
+ const frame = this.protector.protectPayload(import_node_buffer16.Buffer.from(payload));
7592
7830
  this.socket.write(frame);
7593
7831
  this.resetKeepaliveTimer();
7594
7832
  }
@@ -7746,7 +7984,7 @@ function parseDisconnectPayload(payload) {
7746
7984
  }
7747
7985
 
7748
7986
  // src/protocols/sftp/v3/SftpSession.ts
7749
- var import_node_buffer19 = require("buffer");
7987
+ var import_node_buffer18 = require("buffer");
7750
7988
 
7751
7989
  // src/protocols/sftp/v3/SftpAttributes.ts
7752
7990
  var SFTP_ATTR_FLAG = {
@@ -7819,7 +8057,8 @@ function decodeSftpAttributesFromReader(reader) {
7819
8057
  }
7820
8058
 
7821
8059
  // src/protocols/sftp/v3/SftpPacket.ts
7822
- var import_node_buffer18 = require("buffer");
8060
+ var import_node_buffer17 = require("buffer");
8061
+ var MAX_SFTP_PACKET_LENGTH = 256 * 1024;
7823
8062
  var SFTP_PACKET_TYPE = {
7824
8063
  ATTRS: 105,
7825
8064
  CLOSE: 4,
@@ -7850,7 +8089,7 @@ var SFTP_PACKET_TYPE = {
7850
8089
  WRITE: 6
7851
8090
  };
7852
8091
  function decodeSftpPacket(frame) {
7853
- const bytes = import_node_buffer18.Buffer.from(frame);
8092
+ const bytes = import_node_buffer17.Buffer.from(frame);
7854
8093
  if (bytes.length < 5) {
7855
8094
  throw new ParseError({
7856
8095
  details: { length: bytes.length },
@@ -7873,12 +8112,19 @@ function decodeSftpPacket(frame) {
7873
8112
  };
7874
8113
  }
7875
8114
  var SftpPacketFramer = class {
7876
- pending = import_node_buffer18.Buffer.alloc(0);
8115
+ pending = import_node_buffer17.Buffer.alloc(0);
7877
8116
  push(chunk) {
7878
- 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)]);
7879
8118
  const packets = [];
7880
8119
  while (this.pending.length >= 4) {
7881
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
+ }
7882
8128
  const frameLength = 4 + bodyLength;
7883
8129
  if (this.pending.length < frameLength) {
7884
8130
  break;
@@ -8333,7 +8579,7 @@ var SftpSession = class {
8333
8579
  * serializes concurrent calls so byte ordering is preserved.
8334
8580
  */
8335
8581
  sendRaw(encodedMessage, requestId) {
8336
- const frame = import_node_buffer19.Buffer.alloc(4 + encodedMessage.length);
8582
+ const frame = import_node_buffer18.Buffer.alloc(4 + encodedMessage.length);
8337
8583
  frame.writeUInt32BE(encodedMessage.length, 0);
8338
8584
  encodedMessage.copy(frame, 4);
8339
8585
  this.channel.sendData(frame).catch((err) => {
@@ -8876,9 +9122,9 @@ function buildNativePublickeyCredential(profile, username) {
8876
9122
  const passphrase = profile.ssh?.passphrase;
8877
9123
  try {
8878
9124
  const privateKey = (0, import_node_crypto9.createPrivateKey)({
8879
- key: import_node_buffer20.Buffer.isBuffer(keyMaterial) ? keyMaterial : keyMaterial,
9125
+ key: import_node_buffer19.Buffer.isBuffer(keyMaterial) ? keyMaterial : keyMaterial,
8880
9126
  ...passphrase === void 0 ? {} : {
8881
- passphrase: import_node_buffer20.Buffer.isBuffer(passphrase) ? passphrase : passphrase
9127
+ passphrase: import_node_buffer19.Buffer.isBuffer(passphrase) ? passphrase : passphrase
8882
9128
  }
8883
9129
  });
8884
9130
  return buildPublickeyCredential({ privateKey, username });
@@ -9005,12 +9251,12 @@ function normalizeNativeHostKeyPins(value) {
9005
9251
  const trimmed = pin.trim();
9006
9252
  const hex = trimmed.replace(/:/g, "");
9007
9253
  if (hex.length === 64 && /^[a-f0-9]+$/i.test(hex)) {
9008
- 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, ""));
9009
9255
  continue;
9010
9256
  }
9011
9257
  const bare = trimmed.startsWith("SHA256:") ? trimmed.slice("SHA256:".length) : trimmed;
9012
9258
  const padded = bare.length % 4 === 0 ? bare : `${bare}${"=".repeat(4 - bare.length % 4)}`;
9013
- 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, ""));
9014
9260
  }
9015
9261
  return normalized;
9016
9262
  }
@@ -9020,7 +9266,7 @@ function parseNativeKnownHosts(source) {
9020
9266
  const entries = [];
9021
9267
  let sawNonEmpty = false;
9022
9268
  for (const value of sources) {
9023
- 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);
9024
9270
  if (text.length === 0) continue;
9025
9271
  sawNonEmpty = true;
9026
9272
  entries.push(...parseKnownHosts(text));
@@ -9093,7 +9339,7 @@ function requireNativeSftpUsername(profile) {
9093
9339
  }
9094
9340
  function resolveNativeSftpTextSecret(value) {
9095
9341
  if (value === void 0) return void 0;
9096
- 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;
9097
9343
  if (text.length === 0) return void 0;
9098
9344
  return text;
9099
9345
  }
@@ -9168,6 +9414,7 @@ function validateNativeSftpOptions(options) {
9168
9414
  copyBetween,
9169
9415
  createAtomicDeployPlan,
9170
9416
  createBandwidthThrottle,
9417
+ createDefaultRetryPolicy,
9171
9418
  createLocalProviderFactory,
9172
9419
  createMemoryProviderFactory,
9173
9420
  createOAuthTokenSecretSource,
@@ -9204,8 +9451,10 @@ function validateNativeSftpOptions(options) {
9204
9451
  parseRemoteManifest,
9205
9452
  redactCommand,
9206
9453
  redactConnectionProfile,
9454
+ redactErrorForLogging,
9207
9455
  redactObject,
9208
9456
  redactSecretSource,
9457
+ redactUrlForLogging,
9209
9458
  redactValue,
9210
9459
  resolveConnectionProfileSecrets,
9211
9460
  resolveOpenSshHost,