@zero-transfer/google-drive 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 +283 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +228 -24
- package/dist/index.d.ts +228 -24
- package/dist/index.mjs +280 -79
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -60,6 +60,7 @@ __export(google_drive_exports, {
|
|
|
60
60
|
copyBetween: () => copyBetween,
|
|
61
61
|
createAtomicDeployPlan: () => createAtomicDeployPlan,
|
|
62
62
|
createBandwidthThrottle: () => createBandwidthThrottle,
|
|
63
|
+
createDefaultRetryPolicy: () => createDefaultRetryPolicy,
|
|
63
64
|
createGoogleDriveProviderFactory: () => createGoogleDriveProviderFactory,
|
|
64
65
|
createLocalProviderFactory: () => createLocalProviderFactory,
|
|
65
66
|
createMemoryProviderFactory: () => createMemoryProviderFactory,
|
|
@@ -96,8 +97,10 @@ __export(google_drive_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(google_drive_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
|
|
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
|
-
|
|
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,
|
|
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 ||
|
|
1391
|
+
if (error instanceof AbortError || abortScope.signal?.aborted === true) {
|
|
1310
1392
|
throw error;
|
|
1311
1393
|
}
|
|
1312
|
-
const retryInput = {
|
|
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 (
|
|
1794
|
+
if (retry !== void 0) execute.retry = retry;
|
|
1609
1795
|
if (options.onProgress !== void 0) execute.onProgress = options.onProgress;
|
|
1610
|
-
if (
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
3483
|
-
|
|
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,11 +5097,11 @@ function isMainModule(importMetaUrl) {
|
|
|
4906
5097
|
}
|
|
4907
5098
|
|
|
4908
5099
|
// src/providers/cloud/GoogleDriveProvider.ts
|
|
4909
|
-
var
|
|
5100
|
+
var import_node_buffer6 = require("buffer");
|
|
4910
5101
|
var import_node_crypto2 = require("crypto");
|
|
4911
5102
|
|
|
4912
5103
|
// src/providers/web/httpInternals.ts
|
|
4913
|
-
var
|
|
5104
|
+
var import_node_buffer5 = require("buffer");
|
|
4914
5105
|
function parseContentRangeTotal(value) {
|
|
4915
5106
|
const match = /\/(\d+)\s*$/.exec(value);
|
|
4916
5107
|
if (match === null) return void 0;
|
|
@@ -4940,9 +5131,19 @@ async function* webStreamToAsyncIterable(body) {
|
|
|
4940
5131
|
const reader = body.getReader();
|
|
4941
5132
|
try {
|
|
4942
5133
|
while (true) {
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
5134
|
+
let result;
|
|
5135
|
+
try {
|
|
5136
|
+
result = await reader.read();
|
|
5137
|
+
} catch (error) {
|
|
5138
|
+
if (error instanceof ZeroTransferError) throw error;
|
|
5139
|
+
throw new ConnectionError({
|
|
5140
|
+
cause: error,
|
|
5141
|
+
message: "HTTP response stream was interrupted before completion",
|
|
5142
|
+
retryable: true
|
|
5143
|
+
});
|
|
5144
|
+
}
|
|
5145
|
+
if (result.done) break;
|
|
5146
|
+
if (result.value !== void 0) yield result.value;
|
|
4946
5147
|
}
|
|
4947
5148
|
} finally {
|
|
4948
5149
|
reader.releaseLock();
|
|
@@ -4950,8 +5151,8 @@ async function* webStreamToAsyncIterable(body) {
|
|
|
4950
5151
|
}
|
|
4951
5152
|
function secretToString(value) {
|
|
4952
5153
|
if (typeof value === "string") return value;
|
|
4953
|
-
if (value instanceof Uint8Array ||
|
|
4954
|
-
return
|
|
5154
|
+
if (value instanceof Uint8Array || import_node_buffer5.Buffer.isBuffer(value)) {
|
|
5155
|
+
return import_node_buffer5.Buffer.from(value).toString("utf8");
|
|
4955
5156
|
}
|
|
4956
5157
|
return String(value);
|
|
4957
5158
|
}
|
|
@@ -5485,6 +5686,7 @@ function concatChunks3(chunks, totalSize) {
|
|
|
5485
5686
|
copyBetween,
|
|
5486
5687
|
createAtomicDeployPlan,
|
|
5487
5688
|
createBandwidthThrottle,
|
|
5689
|
+
createDefaultRetryPolicy,
|
|
5488
5690
|
createGoogleDriveProviderFactory,
|
|
5489
5691
|
createLocalProviderFactory,
|
|
5490
5692
|
createMemoryProviderFactory,
|
|
@@ -5521,8 +5723,10 @@ function concatChunks3(chunks, totalSize) {
|
|
|
5521
5723
|
parseRemoteManifest,
|
|
5522
5724
|
redactCommand,
|
|
5523
5725
|
redactConnectionProfile,
|
|
5726
|
+
redactErrorForLogging,
|
|
5524
5727
|
redactObject,
|
|
5525
5728
|
redactSecretSource,
|
|
5729
|
+
redactUrlForLogging,
|
|
5526
5730
|
redactValue,
|
|
5527
5731
|
resolveConnectionProfileSecrets,
|
|
5528
5732
|
resolveOpenSshHost,
|