@zero-transfer/sdk 0.1.0-alpha.0 → 0.1.2

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.mjs CHANGED
@@ -2440,6 +2440,74 @@ var FtpFileSystem = class {
2440
2440
  path: remotePath
2441
2441
  };
2442
2442
  }
2443
+ async remove(path2, options = {}) {
2444
+ const remotePath = normalizeFtpPath(path2);
2445
+ const response = await this.control.sendCommand(`DELE ${remotePath}`);
2446
+ if (response.completion) return;
2447
+ if (response.code === 550 && options.ignoreMissing) return;
2448
+ assertPathCommandSucceeded(response, "DELE", remotePath, this.control.providerId);
2449
+ }
2450
+ async rename(from, to) {
2451
+ const fromPath = normalizeFtpPath(from);
2452
+ const toPath = normalizeFtpPath(to);
2453
+ const rnfr = await this.control.sendCommand(`RNFR ${fromPath}`);
2454
+ if (!rnfr.intermediate && !rnfr.completion) {
2455
+ assertPathCommandSucceeded(rnfr, "RNFR", fromPath, this.control.providerId);
2456
+ }
2457
+ await expectCompletion(this.control, `RNTO ${toPath}`, toPath);
2458
+ }
2459
+ async mkdir(path2, options = {}) {
2460
+ const remotePath = normalizeFtpPath(path2);
2461
+ if (!options.recursive) {
2462
+ await expectCompletion(this.control, `MKD ${remotePath}`, remotePath);
2463
+ return;
2464
+ }
2465
+ const segments = remotePath.split("/").filter((s) => s.length > 0);
2466
+ let current = "";
2467
+ for (const segment of segments) {
2468
+ current = `${current}/${segment}`;
2469
+ const response = await this.control.sendCommand(`MKD ${current}`);
2470
+ if (response.completion) continue;
2471
+ if (response.code === 550) continue;
2472
+ assertPathCommandSucceeded(response, "MKD", current, this.control.providerId);
2473
+ }
2474
+ }
2475
+ async rmdir(path2, options = {}) {
2476
+ const remotePath = normalizeFtpPath(path2);
2477
+ if (options.recursive) {
2478
+ await this.removeDirectoryRecursive(remotePath);
2479
+ return;
2480
+ }
2481
+ const response = await this.control.sendCommand(`RMD ${remotePath}`);
2482
+ if (response.completion) return;
2483
+ if (response.code === 550 && options.ignoreMissing) return;
2484
+ assertPathCommandSucceeded(response, "RMD", remotePath, this.control.providerId);
2485
+ }
2486
+ async removeDirectoryRecursive(remotePath) {
2487
+ let entries;
2488
+ try {
2489
+ entries = await readDirectoryEntries(this.control, remotePath);
2490
+ } catch (error) {
2491
+ if (error instanceof PathNotFoundError) return;
2492
+ throw error;
2493
+ }
2494
+ for (const entry of entries) {
2495
+ if (entry.name === "." || entry.name === "..") continue;
2496
+ const childPath = entry.path.startsWith("/") ? entry.path : normalizeFtpPath(`${remotePath.replace(/\/+$/, "")}/${entry.name}`);
2497
+ if (entry.type === "directory") {
2498
+ await this.removeDirectoryRecursive(childPath);
2499
+ } else {
2500
+ const del = await this.control.sendCommand(`DELE ${childPath}`);
2501
+ if (!del.completion && del.code !== 550) {
2502
+ assertPathCommandSucceeded(del, "DELE", childPath, this.control.providerId);
2503
+ }
2504
+ }
2505
+ }
2506
+ const response = await this.control.sendCommand(`RMD ${remotePath}`);
2507
+ if (response.completion) return;
2508
+ if (response.code === 550) return;
2509
+ assertPathCommandSucceeded(response, "RMD", remotePath, this.control.providerId);
2510
+ }
2443
2511
  };
2444
2512
  var FtpControlConnection = class _FtpControlConnection {
2445
2513
  /**
@@ -3473,7 +3541,8 @@ function normalizeFeatureLines(input) {
3473
3541
  // src/providers/classic/sftp/SftpProvider.ts
3474
3542
  import { Buffer as Buffer5 } from "buffer";
3475
3543
  import { createHash, createHmac, timingSafeEqual } from "crypto";
3476
- import { Client, utils } from "ssh2";
3544
+ import ssh2 from "ssh2";
3545
+ var { Client: SshClientCtor, utils } = ssh2;
3477
3546
  var SFTP_PROVIDER_ID = "sftp";
3478
3547
  var SFTP_DEFAULT_PORT = 22;
3479
3548
  var SFTP_PROVIDER_CAPABILITIES = {
@@ -3631,9 +3700,104 @@ var SftpFileSystem = class {
3631
3700
  throw mapSftpError(error, { command: "LSTAT", path: remotePath });
3632
3701
  }
3633
3702
  }
3703
+ async remove(path2, options = {}) {
3704
+ throwIfAborted2(options.signal, path2, "remove");
3705
+ const remotePath = normalizeSftpPath(path2);
3706
+ try {
3707
+ await sftpUnlink(this.sftp, remotePath);
3708
+ } catch (error) {
3709
+ const mapped = mapSftpError(error, { command: "REMOVE", path: remotePath });
3710
+ if (options.ignoreMissing && mapped instanceof PathNotFoundError) return;
3711
+ throw mapped;
3712
+ }
3713
+ }
3714
+ async rename(from, to, options = {}) {
3715
+ throwIfAborted2(options.signal, from, "rename");
3716
+ const fromPath = normalizeSftpPath(from);
3717
+ const toPath = normalizeSftpPath(to);
3718
+ try {
3719
+ await sftpRename(this.sftp, fromPath, toPath);
3720
+ } catch (error) {
3721
+ throw mapSftpError(error, { command: "RENAME", path: fromPath });
3722
+ }
3723
+ }
3724
+ async mkdir(path2, options = {}) {
3725
+ throwIfAborted2(options.signal, path2, "mkdir");
3726
+ const remotePath = normalizeSftpPath(path2);
3727
+ if (!options.recursive) {
3728
+ try {
3729
+ await sftpMkdir(this.sftp, remotePath);
3730
+ } catch (error) {
3731
+ throw mapSftpError(error, { command: "MKDIR", path: remotePath });
3732
+ }
3733
+ return;
3734
+ }
3735
+ const segments = remotePath.split("/").filter((s) => s.length > 0);
3736
+ let current = "";
3737
+ for (const segment of segments) {
3738
+ current = `${current}/${segment}`;
3739
+ try {
3740
+ await sftpMkdir(this.sftp, current);
3741
+ } catch (error) {
3742
+ try {
3743
+ const stats = await readSftpStats(this.sftp, current);
3744
+ if (stats.isDirectory()) continue;
3745
+ } catch {
3746
+ }
3747
+ throw mapSftpError(error, { command: "MKDIR", path: current });
3748
+ }
3749
+ }
3750
+ }
3751
+ async rmdir(path2, options = {}) {
3752
+ throwIfAborted2(options.signal, path2, "rmdir");
3753
+ const remotePath = normalizeSftpPath(path2);
3754
+ if (options.recursive) {
3755
+ await this.removeDirectoryRecursive(remotePath);
3756
+ return;
3757
+ }
3758
+ try {
3759
+ await sftpRmdir(this.sftp, remotePath);
3760
+ } catch (error) {
3761
+ const mapped = mapSftpError(error, { command: "RMDIR", path: remotePath });
3762
+ if (options.ignoreMissing && mapped instanceof PathNotFoundError) return;
3763
+ throw mapped;
3764
+ }
3765
+ }
3766
+ async removeDirectoryRecursive(remotePath) {
3767
+ let entries;
3768
+ try {
3769
+ entries = await readSftpDirectory(this.sftp, remotePath);
3770
+ } catch (error) {
3771
+ const mapped = mapSftpError(error, { command: "READDIR", path: remotePath });
3772
+ if (mapped instanceof PathNotFoundError) return;
3773
+ throw mapped;
3774
+ }
3775
+ for (const entry of entries) {
3776
+ if (entry.filename === "." || entry.filename === "..") continue;
3777
+ const childPath = `${remotePath.replace(/\/+$/, "")}/${entry.filename}`.replace(/\/+/g, "/");
3778
+ const isDir = entry.attrs.isDirectory();
3779
+ try {
3780
+ if (isDir) {
3781
+ await this.removeDirectoryRecursive(childPath);
3782
+ } else {
3783
+ await sftpUnlink(this.sftp, childPath);
3784
+ }
3785
+ } catch (error) {
3786
+ throw mapSftpError(error, {
3787
+ command: isDir ? "RMDIR" : "REMOVE",
3788
+ path: childPath
3789
+ });
3790
+ }
3791
+ }
3792
+ try {
3793
+ await sftpRmdir(this.sftp, remotePath);
3794
+ } catch (error) {
3795
+ throw mapSftpError(error, { command: "RMDIR", path: remotePath });
3796
+ }
3797
+ }
3634
3798
  };
3635
3799
  async function connectSshClient(profile, options, username, authentication) {
3636
- const client = new Client();
3800
+ const client = new SshClientCtor();
3637
3801
  let config;
3638
3802
  try {
3639
3803
  config = await createConnectConfig(profile, options, username, authentication);
@@ -4022,6 +4186,50 @@ function readSftpStats(sftp, path2) {
4022
4186
  });
4023
4187
  });
4024
4188
  }
4189
+ function sftpUnlink(sftp, path2) {
4190
+ return new Promise((resolve, reject) => {
4191
+ sftp.unlink(path2, (error) => {
4192
+ if (error !== void 0 && error !== null) {
4193
+ reject(error);
4194
+ return;
4195
+ }
4196
+ resolve();
4197
+ });
4198
+ });
4199
+ }
4200
+ function sftpRename(sftp, from, to) {
4201
+ return new Promise((resolve, reject) => {
4202
+ sftp.rename(from, to, (error) => {
4203
+ if (error !== void 0 && error !== null) {
4204
+ reject(error);
4205
+ return;
4206
+ }
4207
+ resolve();
4208
+ });
4209
+ });
4210
+ }
4211
+ function sftpMkdir(sftp, path2) {
4212
+ return new Promise((resolve, reject) => {
4213
+ sftp.mkdir(path2, (error) => {
4214
+ if (error !== void 0 && error !== null) {
4215
+ reject(error);
4216
+ return;
4217
+ }
4218
+ resolve();
4219
+ });
4220
+ });
4221
+ }
4222
+ function sftpRmdir(sftp, path2) {
4223
+ return new Promise((resolve, reject) => {
4224
+ sftp.rmdir(path2, (error) => {
4225
+ if (error !== void 0 && error !== null) {
4226
+ reject(error);
4227
+ return;
4228
+ }
4229
+ resolve();
4230
+ });
4231
+ });
4232
+ }
4025
4233
  async function* createSftpReadSource(sftp, path2, range, request) {
4026
4234
  if (range.length <= 0) {
4027
4235
  return;
@@ -4349,7 +4557,8 @@ function noop() {
4349
4557
 
4350
4558
  // src/providers/classic/sftp/jumpHost.ts
4351
4559
  import { Buffer as Buffer6 } from "buffer";
4352
- import { Client as SshClient } from "ssh2";
4560
+ import ssh22 from "ssh2";
4561
+ var { Client: SshClientCtor2 } = ssh22;
4353
4562
  function createSftpJumpHostSocketFactory(options) {
4354
4563
  if (options.bastion === void 0 && options.buildBastion === void 0) {
4355
4564
  throw new ConfigurationError({
@@ -4370,7 +4579,7 @@ function createSftpJumpHostSocketFactory(options) {
4370
4579
  }
4371
4580
  function openJumpHostChannel(options) {
4372
4581
  const { bastionConfig, context } = options;
4373
- const client = options.createClient ? options.createClient() : new SshClient();
4582
+ const client = options.createClient ? options.createClient() : new SshClientCtor2();
4374
4583
  if (context.signal?.aborted === true) {
4375
4584
  return Promise.reject(
4376
4585
  new AbortError({
@@ -6730,7 +6939,17 @@ async function collectChunks5(source) {
6730
6939
 
6731
6940
  // src/providers/local/LocalProvider.ts
6732
6941
  import { createReadStream } from "fs";
6733
- import { lstat, mkdir, open, readdir, readlink, writeFile } from "fs/promises";
6942
+ import {
6943
+ lstat,
6944
+ mkdir,
6945
+ open,
6946
+ readdir,
6947
+ readlink,
6948
+ rename,
6949
+ rm,
6950
+ unlink,
6951
+ writeFile
6952
+ } from "fs/promises";
6734
6953
  import path from "path";
6735
6954
  var LOCAL_PROVIDER_ID = "local";
6736
6955
  var LOCAL_PROVIDER_CAPABILITIES = {
@@ -6856,7 +7075,55 @@ var LocalFileSystem = class {
6856
7075
  async stat(path2) {
6857
7076
  return readLocalEntry(this.rootPath, normalizeLocalProviderPath(path2));
6858
7077
  }
7078
+ async remove(remote, options = {}) {
7079
+ const remotePath = normalizeLocalProviderPath(remote);
7080
+ const localPath = resolveLocalPath(this.rootPath, remotePath);
7081
+ try {
7082
+ await unlink(localPath);
7083
+ } catch (error) {
7084
+ if (options.ignoreMissing && isNodeErrno(error, "ENOENT")) return;
7085
+ if (isNodeErrno(error, "ENOENT")) {
7086
+ throw createPathNotFoundError(remotePath, `Local path not found: ${remotePath}`);
7087
+ }
7088
+ throw error;
7089
+ }
7090
+ }
7091
+ async rename(from, to) {
7092
+ const fromRemote = normalizeLocalProviderPath(from);
7093
+ const toRemote = normalizeLocalProviderPath(to);
7094
+ const fromLocal = resolveLocalPath(this.rootPath, fromRemote);
7095
+ const toLocal = resolveLocalPath(this.rootPath, toRemote);
7096
+ try {
7097
+ await rename(fromLocal, toLocal);
7098
+ } catch (error) {
7099
+ if (isNodeErrno(error, "ENOENT")) {
7100
+ throw createPathNotFoundError(fromRemote, `Local path not found: ${fromRemote}`);
7101
+ }
7102
+ throw error;
7103
+ }
7104
+ }
7105
+ async mkdir(remote, options = {}) {
7106
+ const remotePath = normalizeLocalProviderPath(remote);
7107
+ const localPath = resolveLocalPath(this.rootPath, remotePath);
7108
+ await mkdir(localPath, { recursive: options.recursive === true });
7109
+ }
7110
+ async rmdir(remote, options = {}) {
7111
+ const remotePath = normalizeLocalProviderPath(remote);
7112
+ const localPath = resolveLocalPath(this.rootPath, remotePath);
7113
+ try {
7114
+ await rm(localPath, { recursive: options.recursive === true, force: false });
7115
+ } catch (error) {
7116
+ if (isNodeErrno(error, "ENOENT")) {
7117
+ if (options.ignoreMissing) return;
7118
+ throw createPathNotFoundError(remotePath, `Local path not found: ${remotePath}`);
7119
+ }
7120
+ throw error;
7121
+ }
7122
+ }
6859
7123
  };
7124
+ function isNodeErrno(error, code) {
7125
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
7126
+ }
6860
7127
  function resolveReadRange2(size, range) {
6861
7128
  if (range === void 0) {
6862
7129
  return { length: size, offset: 0 };
@@ -7019,6 +7286,11 @@ function normalizeLocalProviderPath(input) {
7019
7286
  }
7020
7287
  function resolveLocalPath(rootPath, remotePath) {
7021
7288
  const normalizedRemotePath = normalizeLocalProviderPath(remotePath);
7289
+ const resolvedRootPath = path.resolve(rootPath);
7290
+ const candidateAbsolute = path.resolve(normalizedRemotePath.split("/").join(path.sep));
7291
+ if (candidateAbsolute === resolvedRootPath || candidateAbsolute.startsWith(resolvedRootPath + path.sep)) {
7292
+ return candidateAbsolute;
7293
+ }
7022
7294
  const relativePath = normalizedRemotePath === "/" ? "." : normalizedRemotePath.slice(1);
7023
7295
  const resolvedPath = path.resolve(rootPath, relativePath.split("/").join(path.sep));
7024
7296
  const relativeToRoot = path.relative(rootPath, resolvedPath);
@@ -7170,6 +7442,96 @@ var MemoryFileSystem = class {
7170
7442
  () => cloneRemoteStat(this.requireEntry(normalizeMemoryPath(path2)))
7171
7443
  );
7172
7444
  }
7445
+ remove(path2, options = {}) {
7446
+ return Promise.resolve().then(() => {
7447
+ const normalized = normalizeMemoryPath(path2);
7448
+ const entry = this.state.entries.get(normalized);
7449
+ if (entry === void 0) {
7450
+ if (options.ignoreMissing) return;
7451
+ throw createPathNotFoundError2(normalized, `Memory path not found: ${normalized}`);
7452
+ }
7453
+ if (entry.type === "directory") {
7454
+ throw createPathNotFoundError2(
7455
+ normalized,
7456
+ `Memory path is a directory; use rmdir: ${normalized}`
7457
+ );
7458
+ }
7459
+ this.state.entries.delete(normalized);
7460
+ this.state.content.delete(normalized);
7461
+ });
7462
+ }
7463
+ rename(from, to) {
7464
+ return Promise.resolve().then(() => {
7465
+ const fromPath = normalizeMemoryPath(from);
7466
+ const toPath = normalizeMemoryPath(to);
7467
+ const entry = this.state.entries.get(fromPath);
7468
+ if (entry === void 0) {
7469
+ throw createPathNotFoundError2(fromPath, `Memory path not found: ${fromPath}`);
7470
+ }
7471
+ ensureParentDirectories(this.state.entries, toPath);
7472
+ const moved = { ...entry, path: toPath, name: basenameRemotePath(toPath) };
7473
+ this.state.entries.delete(fromPath);
7474
+ this.state.entries.set(toPath, moved);
7475
+ const content = this.state.content.get(fromPath);
7476
+ if (content !== void 0) {
7477
+ this.state.content.delete(fromPath);
7478
+ this.state.content.set(toPath, content);
7479
+ }
7480
+ });
7481
+ }
7482
+ mkdir(path2, options = {}) {
7483
+ return Promise.resolve().then(() => {
7484
+ const normalized = normalizeMemoryPath(path2);
7485
+ const existing = this.state.entries.get(normalized);
7486
+ if (existing !== void 0) {
7487
+ if (existing.type === "directory" && options.recursive) return;
7488
+ throw createInvalidFixtureError(normalized, `Memory path already exists: ${normalized}`);
7489
+ }
7490
+ if (options.recursive) {
7491
+ ensureParentDirectories(this.state.entries, normalized);
7492
+ } else {
7493
+ const parent = getParentPath2(normalized);
7494
+ if (parent !== void 0 && !this.state.entries.has(parent)) {
7495
+ throw createPathNotFoundError2(parent, `Memory parent not found: ${parent}`);
7496
+ }
7497
+ }
7498
+ this.state.entries.set(normalized, createDirectoryEntry(normalized));
7499
+ });
7500
+ }
7501
+ rmdir(path2, options = {}) {
7502
+ return Promise.resolve().then(() => {
7503
+ const normalized = normalizeMemoryPath(path2);
7504
+ const entry = this.state.entries.get(normalized);
7505
+ if (entry === void 0) {
7506
+ if (options.ignoreMissing) return;
7507
+ throw createPathNotFoundError2(normalized, `Memory path not found: ${normalized}`);
7508
+ }
7509
+ if (entry.type !== "directory") {
7510
+ throw createPathNotFoundError2(normalized, `Memory path is not a directory: ${normalized}`);
7511
+ }
7512
+ const children = [...this.state.entries.values()].filter(
7513
+ (child) => child.path !== normalized && getParentPath2(child.path) === normalized
7514
+ );
7515
+ if (children.length > 0 && !options.recursive) {
7516
+ throw createInvalidFixtureError(normalized, `Memory directory not empty: ${normalized}`);
7517
+ }
7518
+ const stack = [...children];
7519
+ while (stack.length > 0) {
7520
+ const next = stack.pop();
7521
+ if (!next) continue;
7522
+ if (next.type === "directory") {
7523
+ for (const grand of this.state.entries.values()) {
7524
+ if (grand.path !== next.path && getParentPath2(grand.path) === next.path) {
7525
+ stack.push(grand);
7526
+ }
7527
+ }
7528
+ }
7529
+ this.state.entries.delete(next.path);
7530
+ this.state.content.delete(next.path);
7531
+ }
7532
+ this.state.entries.delete(normalized);
7533
+ });
7534
+ }
7173
7535
  requireEntry(path2) {
7174
7536
  const entry = this.state.entries.get(path2);
7175
7537
  if (entry === void 0) {