@zero-transfer/sdk 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,177 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0-alpha.0] - 2026-04-27
4
+
5
+ ### Changed
6
+
7
+ - Prepared the package to publish under the `zero-transfer` npm organization as `@zero-transfer/sdk`.
8
+ - Updated repository metadata and documentation for the `tonywied17/zero-transfer` GitHub repository.
9
+ - Refreshed the animated ZeroTransfer logo and package tagline around a unified file-transfer SDK identity.
10
+ - Renamed package foundation from legacy FTP-first naming to `@zero-transfer/sdk`.
11
+ - Switched the package entry point to the new TypeScript `src/` rebuild output.
12
+ - Removed the old CommonJS FTP implementation after the TypeScript foundation became the package surface.
13
+ - Switched project licensing from ISC to MIT.
14
+
15
+ ### Added
16
+
17
+ - TypeScript, build, lint, format, typecheck, test, coverage, and package dry-run scripts.
18
+ - Initial parser-first test harness with 90% coverage gates.
19
+ - Verbose JSDoc comments for the TypeScript API foundation.
20
+ - Animated ZeroTransfer SVG logo assets for the repository README and package.
21
+ - npmjs-only publishing metadata with provenance enabled.
22
+ - CI, release, CodeQL, Dependabot, and integration-server scaffolding.
23
+
24
+ ## [2.3.0] - 2026-02-02
25
+
26
+ ### Added
27
+
28
+ - `uploadFile(localPath, remotePath, ensureDir)` - Upload local files from disk
29
+ - `downloadFile(remotePath, localPath)` - Download files directly to disk
30
+
31
+ ### Changed
32
+
33
+ - **Simplified `ensureDir()` API** - now auto-detects file paths (by extension) and creates parent directory
34
+ - No more confusing `ensureDir(path, true, true)` - just `ensureDir(path)` works for both files and directories
35
+ - Example: `ensureDir('/path/file.txt')` automatically creates `/path/` directory
36
+
37
+ ## [2.2.0] - 2026-02-02
38
+
39
+ ### Fixed
40
+
41
+ - **CRITICAL: Fixed 30-second timeout on all data transfers** - upload, download, list, downloadStream now complete instantly
42
+ - Commands with data connections no longer wait for 226 completion response, dramatically improving speed
43
+ - Download speed improved from 0.03 MB/s to 2.47 MB/s (80x faster!)
44
+ - Recursive directory deletion now blazing fast (sub-second instead of minutes)
45
+
46
+ ### Added
47
+
48
+ - `removeDir(path, recursive)` - Remove directories with optional recursive deletion
49
+ - `chmod(path, mode)` - Change file permissions (Unix/Linux servers)
50
+ - `listDetailed(path)` - Get parsed directory listings with permissions, owner, size, etc.
51
+ - `site(command)` - Execute server-specific SITE commands
52
+
53
+ ### Improved
54
+
55
+ - `listDetailed()` now filters out `.` and `..` entries automatically
56
+ - Better handling of unknown file types in recursive operations
57
+
58
+ ## [2.1.0] - 2026-02-02
59
+
60
+ ### Added
61
+
62
+ - `stat()` method returns detailed file/directory information: `{ exists, size, isFile, isDirectory }`
63
+
64
+ ### Changed
65
+
66
+ - **Simplified performance system** - removed over-engineered preset configuration
67
+ - TCP optimizations (TCP_NODELAY, keep-alive) now applied by default at socket creation
68
+ - `createOptimizedSocket()` replaces repeated `optimizeSocket()` calls for cleaner code
69
+ - Updated `exists()` to use new `stat()` method internally
70
+
71
+ ### Removed
72
+
73
+ - Performance presets (LOW_LATENCY, HIGH_THROUGHPUT, BALANCED) - unnecessary complexity
74
+ - `performancePreset` and `performance` constructor options
75
+ - `getOptimalChunkSize()` function - Node.js doesn't expose socket buffer controls
76
+
77
+ ## [2.0.0] - 2026-02-02
78
+
79
+ ### Breaking Changes
80
+
81
+ - Removed `ensureParentDir()` - use `ensureDir(path, true, true)` instead
82
+ - Removed `uploadFile()` - use `upload(data, path, true)` instead
83
+
84
+ ### Added
85
+
86
+ - **Performance optimization system** with TCP tuning (inspired by HFT practices)
87
+ - `downloadStream()` method for memory-efficient large file transfers
88
+ - `isConnected()` method to check connection and authentication status
89
+ - Parameter validation for `connect()`, `upload()`, and `download()`
90
+ - Connection state validation before upload/download operations
91
+ - Better error messages with file path context
92
+ - Data socket cleanup in connection close
93
+ - New `lib/performance.js` module for TCP optimization utilities
94
+
95
+ ### Improved
96
+
97
+ - **40-50% faster downloads** for small files with LOW_LATENCY preset
98
+ - **`exists()` now properly detects directories** (previously only detected files)
99
+ - All timeouts now respect `client.timeout` configuration (no more hardcoded values)
100
+ - Error messages include file paths for better debugging
101
+ - Connection cleanup includes data socket termination
102
+ - Code quality: added missing semicolons and consistent formatting
103
+ - All data connections now apply performance optimizations
104
+
105
+ ### Changed
106
+
107
+ - `upload()` now accepts optional `ensureDir` boolean parameter (default: false)
108
+ - `ensureDir()` now accepts optional `isFilePath` boolean parameter (default: false)
109
+ - Consolidated API reduces method count while maintaining functionality
110
+ - TCP sockets now optimized on connection for better performance
111
+
112
+ ## [1.2.1] - 2026-02-02
113
+
114
+ ### Changed
115
+
116
+ - Improved README documentation
117
+ - Better examples for `ensureDir()`, `ensureParentDir()`, and `uploadFile()`
118
+ - Added architecture section explaining modular structure
119
+ - Enhanced feature list highlighting directory management capabilities
120
+ - Reorganized API documentation for better clarity
121
+
122
+ ## [1.2.0] - 2026-02-02
123
+
124
+ ### Changed
125
+
126
+ - **Major refactoring**: Improved separation of concerns
127
+ - `index.js` now serves as simple entry point
128
+ - Implementation moved to organized `lib/` structure:
129
+ - `lib/FTPClient.js` - Main class definition
130
+ - `lib/connection.js` - Connection and authentication logic
131
+ - `lib/commands.js` - All FTP command implementations
132
+ - `lib/utils.js` - Helper functions
133
+ - Better code maintainability and readability
134
+ - No breaking changes - API remains identical
135
+
136
+ ## [1.1.0] - 2026-02-02
137
+
138
+ ### Added
139
+
140
+ - `ensureDir(dirPath, recursive)` - Ensure directory exists, creating parent directories if needed
141
+ - `ensureParentDir(filePath)` - Ensure parent directory exists for a file path
142
+ - `uploadFile(data, remotePath, ensureDir)` - Upload with automatic directory creation
143
+ - Utility library (`lib/utils.js`) for better code organization
144
+ - Helper functions for FTP command parsing and path manipulation
145
+
146
+ ### Changed
147
+
148
+ - Refactored internal code structure for better maintainability
149
+ - Improved path normalization across all directory operations
150
+ - Better error handling for directory creation
151
+
152
+ ### Improved
153
+
154
+ - Cleaner API for common operations
155
+ - Reduced boilerplate code needed for directory handling
156
+ - More consistent error messages
157
+
158
+ ## [1.0.1] - 2026-02-02
159
+
160
+ ### Fixed
161
+
162
+ - Updated repository URLs to correct GitHub location
163
+
164
+ ## [1.0.0] - 2026-02-02
165
+
166
+ ### Initial Release
167
+
168
+ - Zero dependencies FTP client using native Node.js TCP sockets
169
+ - Promise-based API with async/await support
170
+ - Passive mode (PASV) for data transfers
171
+ - Debug logging with configurable options
172
+ - Connection keep-alive and timeout configuration
173
+ - Upload/download files with Buffer support
174
+ - Directory operations (list, cd, mkdir, pwd)
175
+ - File operations (delete, rename, size, exists, modifiedTime)
176
+ - Connection statistics tracking
177
+ - Event-based architecture
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tony Wiedman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,285 @@
1
+ <p align="center">
2
+ <img src="assets/zero-transfer-logo.svg" alt="ZeroTransfer file transfer SDK for Node.js" width="720">
3
+ </p>
4
+
5
+ # ZeroTransfer
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@zero-transfer/sdk.svg)](https://www.npmjs.com/package/@zero-transfer/sdk)
8
+ [![npm downloads](https://img.shields.io/npm/dm/@zero-transfer/sdk.svg)](https://www.npmjs.com/package/@zero-transfer/sdk)
9
+ [![CI](https://github.com/tonywied17/zero-transfer/actions/workflows/ci.yml/badge.svg)](https://github.com/tonywied17/zero-transfer/actions/workflows/ci.yml)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
11
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org)
12
+
13
+ ZeroTransfer is a unified TypeScript-first Node.js SDK for moving files across classic protocols, web transfer endpoints, object storage, cloud drives, and future MFT-style workflows. The project is being rebuilt from the original FTP-first implementation into a safer, typed, observable transfer platform with parser-first tests, npmjs-only publishing, and generated API documentation in mind.
14
+
15
+ ## Status
16
+
17
+ This repository is in the ZeroTransfer alpha foundation phase. The old CommonJS package surface has been removed so the project can move forward around the TypeScript `src/` foundation and generated `dist/` output.
18
+
19
+ The current foundation includes:
20
+
21
+ - TypeScript source, declarations, and dual ESM/CJS package output.
22
+ - Vitest coverage gates at 90% across statements, branches, functions, and lines.
23
+ - ESLint, Prettier, typecheck, build, package dry-run, and CI scripts.
24
+ - Typed error classes, safe remote argument validation, structured logging redaction helpers, FTP parser tests, and an initial classic FTP provider contract slice.
25
+ - Provider-neutral core contracts, provider registry, `TransferClient`, `createTransferClient()`, provider capability discovery, deterministic memory and local providers with read/write transfer operations, an MLST/MLSD/EPSV/PASV-based FTP provider with streaming read/write transfer operations, profile secret utilities, transfer plans, transfer queue primitives, and the initial transfer engine.
26
+ - Verbose JSDoc across the public TypeScript API for future generated documentation.
27
+ - Initial GitHub Actions scaffolding for CI, CodeQL, and npmjs release provenance.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install @zero-transfer/sdk
33
+ ```
34
+
35
+ ## Intended API Direction
36
+
37
+ ```ts
38
+ import { ZeroTransfer } from "@zero-transfer/sdk";
39
+
40
+ const client = await ZeroTransfer.connect({
41
+ provider: "ftps",
42
+ host: "ftp.example.com",
43
+ username: "deploy",
44
+ password: { env: "FTP_PASSWORD" },
45
+ secure: true,
46
+ });
47
+
48
+ const entries = await client.list("/releases");
49
+ const artifact = await client.stat("/releases/app.zip");
50
+ await client.disconnect();
51
+ ```
52
+
53
+ `ZeroTransfer` is the facade for new provider-neutral code. Protocol-specific behavior lives behind providers and adapters rather than a protocol-named client class.
54
+
55
+ The first provider-neutral core path is also available for provider registration and capability discovery:
56
+
57
+ ```ts
58
+ import { createTransferClient } from "@zero-transfer/sdk";
59
+
60
+ const client = createTransferClient();
61
+ const capabilities = client.getCapabilities();
62
+ ```
63
+
64
+ Provider factories can be registered with `createTransferClient({ providers: [...] })`. Classic network providers are being added incrementally; the FTP provider supports login, `fs.stat()` through MLST, `fs.list()` through EPSV/PASV MLSD, streaming provider transfer reads/writes through EPSV/PASV `RETR`/`STOR` with REST offsets, and profile `timeoutMs` enforcement across control replies and passive transfers. The first FTPS slice supports explicit `AUTH TLS`, `PBSZ 0`, encrypted `PROT P` data channels, and TLS profile fields for CA bundles, client certificates, keys, PFX/P12 bundles, passphrases, SNI, TLS versions, and certificate validation controls. The SFTP provider supports password, private-key, agent, and keyboard-interactive authentication, SSH transport algorithm overrides, custom socket factories for proxy and tunnel integrations, provider transfer streams, and profile-level host-key verification with known_hosts content or pinned SHA-256 host-key fingerprints.
65
+
66
+ ```ts
67
+ import { createFtpProviderFactory, createTransferClient } from "@zero-transfer/sdk";
68
+
69
+ const client = createTransferClient({
70
+ providers: [createFtpProviderFactory()],
71
+ });
72
+
73
+ const session = await client.connect({
74
+ provider: "ftp",
75
+ host: "ftp.example.com",
76
+ username: { env: "FTP_USERNAME" },
77
+ password: { env: "FTP_PASSWORD" },
78
+ });
79
+
80
+ const releases = await session.fs.list("/releases");
81
+ const artifact = await session.fs.stat("/releases/app.zip");
82
+ await session.disconnect();
83
+ ```
84
+
85
+ Explicit FTPS can use the same provider-neutral session API with TLS settings on the connection profile:
86
+
87
+ ```ts
88
+ import { createFtpsProviderFactory, createTransferClient } from "@zero-transfer/sdk";
89
+
90
+ const client = createTransferClient({
91
+ providers: [createFtpsProviderFactory()],
92
+ });
93
+
94
+ const session = await client.connect({
95
+ provider: "ftps",
96
+ host: "ftp.example.com",
97
+ username: { env: "FTP_USERNAME" },
98
+ password: { env: "FTP_PASSWORD" },
99
+ tls: {
100
+ ca: { path: "./certs/private-ca.pem" },
101
+ servername: "ftp.example.com",
102
+ },
103
+ });
104
+
105
+ const releases = await session.fs.list("/releases");
106
+ await session.disconnect();
107
+ ```
108
+
109
+ For deterministic contract and unit tests, the SDK exports a fixture-backed memory provider factory:
110
+
111
+ ```ts
112
+ import { createMemoryProviderFactory, createTransferClient } from "@zero-transfer/sdk";
113
+
114
+ const client = createTransferClient({
115
+ providers: [
116
+ createMemoryProviderFactory({
117
+ entries: [{ path: "/fixtures/report.csv", type: "file", size: 24 }],
118
+ }),
119
+ ],
120
+ });
121
+
122
+ const session = await client.connect({ provider: "memory", host: "memory.local" });
123
+ const entries = await session.fs.list("/fixtures");
124
+ const report = await session.fs.stat("/fixtures/report.csv");
125
+ await session.disconnect();
126
+ ```
127
+
128
+ The memory provider is intentionally test-focused: it supports connection lifecycle, capability discovery, `fs.list()`, `fs.stat()`, typed missing-path errors, and deterministic in-memory transfer reads/writes over fixture state.
129
+
130
+ The local provider exposes a configured local root as `/` for local-only tests and early provider contract coverage:
131
+
132
+ ```ts
133
+ import { createLocalProviderFactory, createTransferClient } from "@zero-transfer/sdk";
134
+
135
+ const client = createTransferClient({
136
+ providers: [createLocalProviderFactory({ rootPath: process.cwd() })],
137
+ });
138
+
139
+ const session = await client.connect({ provider: "local", host: "local" });
140
+ const files = await session.fs.list("/");
141
+ await session.disconnect();
142
+ ```
143
+
144
+ The local provider also exposes provider transfer reads/writes under `session.transfers` for local-only workflow tests and early transfer-engine coverage.
145
+
146
+ Profile helpers are also available for validating connection profiles, resolving deferred secret sources, and redacting diagnostics:
147
+
148
+ ```ts
149
+ import {
150
+ redactConnectionProfile,
151
+ resolveConnectionProfileSecrets,
152
+ validateConnectionProfile,
153
+ } from "@zero-transfer/sdk";
154
+
155
+ const profile = validateConnectionProfile({
156
+ provider: "sftp",
157
+ host: "files.example.com",
158
+ username: { env: "ZT_USER" },
159
+ password: { env: "ZT_PASSWORD" },
160
+ ssh: {
161
+ knownHosts: { path: "./known_hosts" },
162
+ pinnedHostKeySha256: "SHA256:base64-encoded-host-key-digest",
163
+ },
164
+ });
165
+
166
+ const resolved = await resolveConnectionProfileSecrets(profile);
167
+ const safeForLogs = redactConnectionProfile(profile);
168
+ ```
169
+
170
+ Protocol adapters are intentionally being added incrementally. Early releases focus on the package foundation, deterministic tests, parser correctness, typed errors, logging, provider contracts, and transfer-service primitives while FTP is hardened, FTPS/SFTP support is ported in focused slices, and broader provider families are added.
171
+
172
+ The first transfer-engine foundation is available for adapters and higher-level workflows that need abort-aware execution, progress callbacks, retry hooks, timeout policy, bandwidth-limit handoff, verification details, and audit receipts around a concrete transfer operation:
173
+
174
+ ```ts
175
+ import { TransferEngine, type TransferJob } from "@zero-transfer/sdk";
176
+
177
+ const engine = new TransferEngine();
178
+ const job: TransferJob = {
179
+ id: "upload-1",
180
+ operation: "upload",
181
+ source: { provider: "local", path: "./dist/app.zip" },
182
+ destination: { provider: "memory", path: "/releases/app.zip" },
183
+ totalBytes: 1024,
184
+ };
185
+
186
+ const receipt = await engine.execute(
187
+ job,
188
+ (context) => {
189
+ context.reportProgress(1024);
190
+ return {
191
+ bytesTransferred: 1024,
192
+ verification: { method: "checksum", verified: true },
193
+ };
194
+ },
195
+ {
196
+ bandwidthLimit: { bytesPerSecond: 1024 * 1024 },
197
+ retry: { maxAttempts: 2 },
198
+ timeout: { timeoutMs: 30_000 },
199
+ },
200
+ );
201
+ ```
202
+
203
+ Provider sessions that can stream content expose `session.transfers.read()` and `session.transfers.write()`. The memory, local, and initial FTP providers implement that surface now, and the SDK exports `createProviderTransferExecutor()` to bridge provider operations into `TransferEngine` without hard-coding a concrete FTP, SFTP, or cloud implementation:
204
+
205
+ ```ts
206
+ import { createProviderTransferExecutor } from "@zero-transfer/sdk";
207
+
208
+ const executor = createProviderTransferExecutor({
209
+ resolveSession: ({ endpoint }) => connectedSessions.get(endpoint.provider ?? ""),
210
+ });
211
+
212
+ const receipt = await engine.execute(job, executor, {
213
+ retry: { maxAttempts: 2 },
214
+ });
215
+ ```
216
+
217
+ Dry-run transfer plans can be converted into executable jobs and drained through a minimal queue with concurrency, pause/resume, cancellation, progress, retries, receipts, and per-job failure tracking:
218
+
219
+ ```ts
220
+ import { TransferQueue, createTransferJobsFromPlan, createTransferPlan } from "@zero-transfer/sdk";
221
+
222
+ const plan = createTransferPlan({
223
+ id: "release-plan",
224
+ steps: [
225
+ {
226
+ id: "upload-app",
227
+ action: "upload",
228
+ source: { provider: "local", path: "./dist/app.zip" },
229
+ destination: { provider: "memory", path: "/releases/app.zip" },
230
+ expectedBytes: 1024,
231
+ },
232
+ ],
233
+ });
234
+
235
+ const queue = new TransferQueue({
236
+ concurrency: 2,
237
+ executor: (context) => {
238
+ const bytesTransferred = context.job.totalBytes ?? 0;
239
+ context.reportProgress(bytesTransferred);
240
+ return { bytesTransferred, verified: true };
241
+ },
242
+ });
243
+
244
+ for (const plannedJob of createTransferJobsFromPlan(plan)) {
245
+ queue.add(plannedJob);
246
+ }
247
+
248
+ const summary = await queue.run();
249
+ ```
250
+
251
+ ## Development
252
+
253
+ ```bash
254
+ npm install
255
+ npm run lint
256
+ npm run format:check
257
+ npm run typecheck
258
+ npm run test:coverage
259
+ npm run build
260
+ npm run pack:dry
261
+ ```
262
+
263
+ Use `npm run ci` to run the same local quality gate used by the CI workflow.
264
+
265
+ Docker-backed FTP integration coverage is opt-in because it pulls and runs a real `pure-ftpd`
266
+ container. With Docker running locally, use:
267
+
268
+ ```bash
269
+ npm run test:integration:ftp
270
+ ```
271
+
272
+ The script starts the FTP service from `test/servers/docker-compose.yml`, runs the provider
273
+ metadata and transfer round-trip coverage, and tears the container down afterward.
274
+
275
+ ## Publishing
276
+
277
+ ZeroTransfer publishes only to the public npm registry as `@zero-transfer/sdk`.
278
+
279
+ The `zero-transfer` npm organization owns the package scope. The first package is the batteries-included SDK at `@zero-transfer/sdk`; future monorepo packages can split provider-neutral contracts into `@zero-transfer/core` and adapters such as `@zero-transfer/ftp`, `@zero-transfer/sftp`, and `@zero-transfer/s3` when the contracts prove out.
280
+
281
+ Publishing is configured for npm provenance through GitHub Actions. For token-based test publishing, add the npm automation token as a repository secret named `NPM_TOKEN`; never commit npm tokens or place them in local config files. There is no GitHub Packages release target.
282
+
283
+ ## License
284
+
285
+ MIT License