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

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/LICENSE CHANGED
@@ -1,21 +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.
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 CHANGED
@@ -1,158 +1,110 @@
1
1
  <p align="center">
2
- <img src="assets/zero-transfer-logo.svg" alt="ZeroTransfer file transfer SDK for Node.js" width="720">
2
+ <img src="https://tonywied17.github.io/zero-transfer/assets/zero-transfer-logo.svg" alt="ZeroTransfer file transfer SDK for Node.js" width="720">
3
3
  </p>
4
4
 
5
- # ZeroTransfer
5
+ <h1 align="center">ZeroTransfer</h1>
6
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";
7
+ <p align="center">
8
+ <strong>One TypeScript SDK for moving files across every storage system you actually use.</strong><br/>
9
+ FTP · FTPS · SFTP · HTTP(S) · WebDAV · S3-compatible · Azure Blob · GCS · Google Drive · Dropbox · OneDrive · Local
10
+ </p>
59
11
 
60
- const client = createTransferClient();
61
- const capabilities = client.getCapabilities();
62
- ```
12
+ <p align="center">
13
+ <a href="https://www.npmjs.com/package/@zero-transfer/sdk"><img src="https://img.shields.io/npm/v/@zero-transfer/sdk.svg?style=for-the-badge&labelColor=0d1117&color=00b4d8&logo=npm&logoColor=white&label=%40zero-transfer%2Fsdk" alt="npm version"></a>
14
+ <a href="https://www.npmjs.com/package/@zero-transfer/sdk"><img src="https://img.shields.io/npm/dm/@zero-transfer/sdk.svg?style=for-the-badge&labelColor=0d1117&color=00b4d8&logo=npm&logoColor=white" alt="npm downloads"></a>
15
+ <a href="https://github.com/tonywied17/zero-transfer/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/tonywied17/zero-transfer/ci.yml?branch=main&style=for-the-badge&labelColor=0d1117&logo=githubactions&logoColor=white&label=CI" alt="CI"></a>
16
+ <a href="https://github.com/tonywied17/zero-transfer/actions/workflows/ci.yml"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Ftonywied17.github.io%2Fzero-transfer%2Fbadges%2Ftests.json&style=for-the-badge&labelColor=0d1117&logo=vitest&logoColor=white" alt="Tests"></a>
17
+ <a href="https://github.com/tonywied17/zero-transfer/actions/workflows/ci.yml"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Ftonywied17.github.io%2Fzero-transfer%2Fbadges%2Fcoverage.json&style=for-the-badge&labelColor=0d1117&logo=vitest&logoColor=white" alt="Coverage"></a>
18
+ <a href="https://tonywied17.github.io/zero-transfer/"><img src="https://img.shields.io/badge/docs-typedoc-00b4d8?style=for-the-badge&labelColor=0d1117&logo=readthedocs&logoColor=white" alt="Docs"></a>
19
+ <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-00b4d8?style=for-the-badge&labelColor=0d1117" alt="License"></a>
20
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D20-339933?style=for-the-badge&labelColor=0d1117&logo=nodedotjs&logoColor=white" alt="Node.js"></a>
21
+ </p>
63
22
 
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.
23
+ ZeroTransfer is a unified, TypeScript-first file transfer SDK for Node.js. One typed API speaks to every backend you actually deploy against classic protocols, web endpoints, object storage, cloud drives, and local disks with streaming, resume, verification, dry-run plans, MFT-style scheduling, audit logs, and webhook delivery built in.
65
24
 
66
25
  ```ts
67
- import { createFtpProviderFactory, createTransferClient } from "@zero-transfer/sdk";
26
+ import { createS3ProviderFactory, createTransferClient, uploadFile } from "@zero-transfer/sdk";
68
27
 
69
28
  const client = createTransferClient({
70
- providers: [createFtpProviderFactory()],
29
+ providers: [createS3ProviderFactory({ region: "us-east-1" })],
71
30
  });
72
31
 
73
- const session = await client.connect({
74
- provider: "ftp",
75
- host: "ftp.example.com",
76
- username: { env: "FTP_USERNAME" },
77
- password: { env: "FTP_PASSWORD" },
32
+ // One call, any provider you registered above.
33
+ await uploadFile({
34
+ client,
35
+ localPath: "./dist/app.tar.gz",
36
+ destination: {
37
+ path: "/lake/bronze/app.tar.gz",
38
+ profile: {
39
+ provider: "s3",
40
+ host: "data-lake-bronze",
41
+ username: { env: "AWS_ACCESS_KEY_ID" },
42
+ password: { env: "AWS_SECRET_ACCESS_KEY" },
43
+ },
44
+ },
78
45
  });
79
-
80
- const releases = await session.fs.list("/releases");
81
- const artifact = await session.fs.stat("/releases/app.zip");
82
- await session.disconnect();
83
46
  ```
84
47
 
85
- Explicit FTPS can use the same provider-neutral session API with TLS settings on the connection profile:
48
+ ---
86
49
 
87
- ```ts
88
- import { createFtpsProviderFactory, createTransferClient } from "@zero-transfer/sdk";
50
+ ## Why ZeroTransfer
89
51
 
90
- const client = createTransferClient({
91
- providers: [createFtpsProviderFactory()],
92
- });
52
+ - **One API, every provider.** Replace bespoke FTP, SFTP, S3, and cloud-drive code with a single `TransferClient` and provider-neutral sessions.
53
+ - **TypeScript-first.** Strict types, exact optional properties, exhaustive capability discovery, and typed errors for every protocol failure mode.
54
+ - **Streaming + resume.** Backpressure via `stream.pipeline`, byte-range downloads, multipart uploads, and cross-process resume stores for object storage.
55
+ - **Dry-run-first sync.** Diff remote trees, generate `TransferPlan`s, and review every step before any byte moves.
56
+ - **MFT batteries.** Routes, cron + interval schedules, audit logs, HMAC-signed webhooks, retention policies, and approval gates that block on human sign-off.
57
+ - **Security by default.** Profile redaction in every log, host-key pinning, certificate fingerprint pinning, OAuth refresh, and SecretSource adapters for vaults / env / files / commands.
58
+ - **Observable.** Structured logger, redaction-safe diagnostics, immutable transfer receipts, and per-attempt history for compliance.
93
59
 
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
- });
60
+ ## Install
104
61
 
105
- const releases = await session.fs.list("/releases");
106
- await session.disconnect();
62
+ ```bash
63
+ # Batteries-included SDK (every provider):
64
+ npm install @zero-transfer/sdk
65
+
66
+ # Or pick a scoped slice (today these re-export the full SDK; future releases will narrow):
67
+ npm install @zero-transfer/sftp
68
+ npm install @zero-transfer/s3
69
+ npm install @zero-transfer/mft
107
70
  ```
108
71
 
109
- For deterministic contract and unit tests, the SDK exports a fixture-backed memory provider factory:
72
+ Requires Node.js **>=20**.
110
73
 
111
- ```ts
112
- import { createMemoryProviderFactory, createTransferClient } from "@zero-transfer/sdk";
74
+ ## Scoped packages
113
75
 
114
- const client = createTransferClient({
115
- providers: [
116
- createMemoryProviderFactory({
117
- entries: [{ path: "/fixtures/report.csv", type: "file", size: 24 }],
118
- }),
119
- ],
120
- });
76
+ ZeroTransfer publishes 13 scoped packages under the [`@zero-transfer`](https://www.npmjs.com/org/zero-transfer) npm organization. [`@zero-transfer/sdk`](https://www.npmjs.com/package/@zero-transfer/sdk) is the batteries-included distribution; the other 12 are **narrowly scoped** packages that re-export only the symbols listed in their [scope page](docs/scopes/README.md). Pick one to keep your dependency tree tight, or install the SDK if you want every provider in one go.
121
77
 
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
- ```
78
+ | Package | Summary | Docs |
79
+ | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | ----------------------------------------- |
80
+ | [`@zero-transfer/sdk`](https://www.npmjs.com/package/@zero-transfer/sdk) | Batteries-included distribution. Every provider, every helper. | [API reference](docs/api-md/README.md) |
81
+ | [`@zero-transfer/core`](https://www.npmjs.com/package/@zero-transfer/core) | Provider-neutral contracts, transfer engine, queue, profiles, errors. | [Scope page](docs/scopes/core.md) |
82
+ | [`@zero-transfer/classic`](https://www.npmjs.com/package/@zero-transfer/classic) | FTP + FTPS + SFTP in one install. | [Scope page](docs/scopes/classic.md) |
83
+ | [`@zero-transfer/ftp`](https://www.npmjs.com/package/@zero-transfer/ftp) | Classic FTP with EPSV/PASV streaming and REST resume. | [Scope page](docs/scopes/ftp.md) |
84
+ | [`@zero-transfer/ftps`](https://www.npmjs.com/package/@zero-transfer/ftps) | Explicit + implicit FTPS with full TLS profile support. | [Scope page](docs/scopes/ftps.md) |
85
+ | [`@zero-transfer/sftp`](https://www.npmjs.com/package/@zero-transfer/sftp) | SFTP with SSH key auth, known_hosts, and jump-host support. | [Scope page](docs/scopes/sftp.md) |
86
+ | [`@zero-transfer/http`](https://www.npmjs.com/package/@zero-transfer/http) | HTTP(S) and signed-URL provider with ranged downloads. | [Scope page](docs/scopes/http.md) |
87
+ | [`@zero-transfer/webdav`](https://www.npmjs.com/package/@zero-transfer/webdav) | WebDAV with PROPFIND listings and ranged downloads. | [Scope page](docs/scopes/webdav.md) |
88
+ | [`@zero-transfer/s3`](https://www.npmjs.com/package/@zero-transfer/s3) | S3-compatible storage with SigV4, multipart upload, and cross-process resume. | [Scope page](docs/scopes/s3.md) |
89
+ | [`@zero-transfer/google-drive`](https://www.npmjs.com/package/@zero-transfer/google-drive) | Google Drive with OAuth, folder paths, md5 checksums. | [Scope page](docs/scopes/google-drive.md) |
90
+ | [`@zero-transfer/dropbox`](https://www.npmjs.com/package/@zero-transfer/dropbox) | Dropbox with content-hash verification. | [Scope page](docs/scopes/dropbox.md) |
91
+ | [`@zero-transfer/azure-blob`](https://www.npmjs.com/package/@zero-transfer/azure-blob) | Azure Blob Storage with SAS or AAD bearer auth. | [Scope page](docs/scopes/azure-blob.md) |
92
+ | [`@zero-transfer/mft`](https://www.npmjs.com/package/@zero-transfer/mft) | Routes, schedules, audit logs, webhooks, approval gates. | [Scope page](docs/scopes/mft.md) |
93
+
94
+ The full per-scope index lives at [`docs/scopes/`](docs/scopes/README.md).
127
95
 
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.
96
+ ## Quick start
129
97
 
130
- The local provider exposes a configured local root as `/` for local-only tests and early provider contract coverage:
98
+ ### 1. Connect a provider-neutral client
131
99
 
132
100
  ```ts
133
- import { createLocalProviderFactory, createTransferClient } from "@zero-transfer/sdk";
101
+ import { createSftpProviderFactory, createTransferClient } from "@zero-transfer/sdk";
134
102
 
135
103
  const client = createTransferClient({
136
- providers: [createLocalProviderFactory({ rootPath: process.cwd() })],
104
+ providers: [createSftpProviderFactory()],
137
105
  });
138
106
 
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({
107
+ const session = await client.connect({
156
108
  provider: "sftp",
157
109
  host: "files.example.com",
158
110
  username: { env: "ZT_USER" },
@@ -163,123 +115,140 @@ const profile = validateConnectionProfile({
163
115
  },
164
116
  });
165
117
 
166
- const resolved = await resolveConnectionProfileSecrets(profile);
167
- const safeForLogs = redactConnectionProfile(profile);
118
+ const releases = await session.fs.list("/releases");
119
+ await session.disconnect();
168
120
  ```
169
121
 
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:
122
+ ### 2. Move a file with one call
173
123
 
174
124
  ```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
- );
125
+ import { uploadFile } from "@zero-transfer/sdk";
126
+
127
+ await uploadFile({
128
+ client,
129
+ localPath: "./dist/app.tar.gz",
130
+ destination: { path: "/releases/2026.04.28/app.tar.gz", profile: sftpProfile },
131
+ onProgress: (event) => console.log(`${event.bytesTransferred}/${event.totalBytes ?? "?"}`),
132
+ });
201
133
  ```
202
134
 
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:
135
+ ### 3. Plan a sync without touching bytes
204
136
 
205
137
  ```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 },
138
+ import { createSyncPlan, diffRemoteTrees, summarizeTransferPlan } from "@zero-transfer/sdk";
139
+
140
+ const diff = await diffRemoteTrees(srcSession.fs, "/dist", dstSession.fs, "/releases/current");
141
+ const plan = createSyncPlan({
142
+ id: "release-sync",
143
+ diff,
144
+ source: { provider: "sftp", rootPath: "/dist" },
145
+ destination: { provider: "s3", rootPath: "/releases/current" },
146
+ deletePolicy: "mirror",
214
147
  });
148
+ console.table(summarizeTransferPlan(plan));
215
149
  ```
216
150
 
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:
151
+ ### 4. Schedule it as an MFT route with audit + approval
218
152
 
219
153
  ```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
- });
154
+ import {
155
+ ApprovalRegistry,
156
+ MftScheduler,
157
+ RouteRegistry,
158
+ ScheduleRegistry,
159
+ createApprovalGate,
160
+ runRoute,
161
+ } from "@zero-transfer/sdk";
234
162
 
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
- },
163
+ const approvals = new ApprovalRegistry();
164
+ const scheduler = new MftScheduler({
165
+ client,
166
+ routes: new RouteRegistry([route]),
167
+ schedules: scheduleRegistry,
168
+ runner: createApprovalGate({
169
+ approvalId: ({ route }) => `release:${route.id}:${Date.now()}`,
170
+ registry: approvals,
171
+ runner: ({ client: c, route: r, signal }) => runRoute({ client: c, route: r, signal }),
172
+ }),
173
+ onResult: ({ receipt }) => console.log(`Released ${receipt.jobId}`),
242
174
  });
243
175
 
244
- for (const plannedJob of createTransferJobsFromPlan(plan)) {
245
- queue.add(plannedJob);
246
- }
247
-
248
- const summary = await queue.run();
176
+ scheduler.start();
249
177
  ```
250
178
 
251
- ## Development
179
+ ## Capability matrix
180
+
181
+ Every provider advertises its own [`CapabilitySet`](docs/api-md/interfaces/CapabilitySet.md). The full programmatic matrix is exposed via [`getBuiltinCapabilityMatrix()`](docs/api-md/functions/getBuiltinCapabilityMatrix.md) and renders to Markdown via [`formatCapabilityMatrixMarkdown()`](docs/api-md/functions/formatCapabilityMatrixMarkdown.md).
182
+
183
+ | Provider | Streaming | Resume | Server-side copy | Multipart upload | Checksum exposed |
184
+ | ------------- | :-------: | :------------------------------: | :--------------: | :--------------: | :----------------------: |
185
+ | FTP | ✅ | ⬆/⬇ via REST | — | — | — |
186
+ | FTPS | ✅ | ⬆/⬇ via REST | — | — | — |
187
+ | SFTP | ✅ | ⬆/⬇ | rename | — | — |
188
+ | HTTP(S) | ✅ (read) | ⬇ via Range | — | — | ETag |
189
+ | WebDAV | ✅ | ⬇ via Range | COPY | — | ETag |
190
+ | S3-compatible | ✅ | ⬆ via multipart resume / ⬇ Range | CopyObject | ✅ | SHA-256 / md5 |
191
+ | Azure Blob | ✅ | ⬇ via Range | — | (planned) | md5 |
192
+ | GCS | ✅ | ⬇ via Range | — | (planned) | crc32c / md5 |
193
+ | Google Drive | ✅ | ⬇ via Range | — | — | md5 |
194
+ | Dropbox | ✅ | ⬇ via Range | — | — | content_hash |
195
+ | OneDrive | ✅ | ⬇ via Range | — | (planned) | sha256 / sha1 / quickXor |
196
+ | Local | ✅ | ⬆/⬇ | — | — | — |
197
+ | Memory | ✅ | ⬆/⬇ | — | — | — |
198
+
199
+ ## Examples
200
+
201
+ Real-world examples live in [`examples/`](https://github.com/tonywied17/zero-transfer/tree/main/examples). Run them with `tsx examples/<file>`.
202
+
203
+ | Example | What it shows |
204
+ | --------------------------------------------------------------------------- | ----------------------------------------------------------------- |
205
+ | [`local-copy-file.ts`](examples/local-copy-file.ts) | Zero-config local-to-local copy via `copyBetween`. |
206
+ | [`ftp-basic.ts`](examples/ftp-basic.ts) | Plain FTP upload + download round-trip with username/password. |
207
+ | [`ftps-basic.ts`](examples/ftps-basic.ts) | FTPS with username/password over a public-CA endpoint. |
208
+ | [`ftps-client-certificate.ts`](examples/ftps-client-certificate.ts) | FTPS hardened: mTLS + private CA bundle + fingerprint pinning. |
209
+ | [`sftp-basic.ts`](examples/sftp-basic.ts) | Minimal SFTP with username/password (no host-key pinning). |
210
+ | [`sftp-private-key.ts`](examples/sftp-private-key.ts) | SFTP hardened: private-key auth + pinned host-key SHA-256. |
211
+ | [`s3-compatible-upload.ts`](examples/s3-compatible-upload.ts) | S3 multipart upload with cross-process resume store. |
212
+ | [`webdav-sync.ts`](examples/webdav-sync.ts) | WebDAV diff + sync plan with deterministic ordering. |
213
+ | [`signed-url-download.ts`](examples/signed-url-download.ts) | HTTPS signed-URL download with progress reporting. |
214
+ | [`transfer-queue.ts`](examples/transfer-queue.ts) | Concurrent transfers with `TransferQueue` + executor. |
215
+ | [`dry-run-sync.ts`](examples/dry-run-sync.ts) | Plan a sync, print a summary, never touch bytes. |
216
+ | [`mft-route.ts`](examples/mft-route.ts) | SFTP→S3 cron-scheduled MFT route with audit hooks. |
217
+ | [`profile-from-env.ts`](examples/profile-from-env.ts) | Build a `ConnectionProfile` from env / file / base64-env secrets. |
218
+ | [`diagnose-connection.ts`](examples/diagnose-connection.ts) | Provider summary + redaction-safe connection probe. |
219
+ | [`approval-gated-route.ts`](examples/approval-gated-route.ts) | Two-person rule: scheduled route blocks until approval lands. |
220
+ | [`multi-cloud-orchestration.ts`](examples/multi-cloud-orchestration.ts) | Fan-out SFTP → S3 + Azure + Local with webhook audit. |
221
+ | [`atomic-deploy-with-rollback.ts`](examples/atomic-deploy-with-rollback.ts) | Blue/green-style deploy plan with rollback path. |
222
+
223
+ ## Documentation
224
+
225
+ - [Full API reference (HTML)](https://tonywied17.github.io/zero-transfer/) — TypeDoc HTML site, deployed from `main` on every push.
226
+ - [Full API reference (Markdown)](docs/api-md/README.md) — every public symbol with parameter / property / type tables.
227
+ - [Per-scope pages](docs/scopes/README.md) — one page per `@zero-transfer/*` package.
228
+ - [Examples directory](https://github.com/tonywied17/zero-transfer/tree/main/examples) — runnable real-world flows.
229
+
230
+ Regenerate everything locally:
252
231
 
253
232
  ```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
233
+ npm run docs:all # HTML + Markdown api refs + per-scope pages + per-package READMEs
261
234
  ```
262
235
 
263
- Use `npm run ci` to run the same local quality gate used by the CI workflow.
236
+ ## Project status
237
+
238
+ ZeroTransfer is in **alpha** under the `alpha` npm dist-tag. The provider-neutral foundation, transfer engine, queue, sync planner, atomic deploy planner, MFT layer, friendly client surface, and diagnostics module are stable. Phase work in progress: resumable upload sessions for Azure / GCS / OneDrive, broader real-server compatibility coverage, and the push to higher coverage targets.
264
239
 
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:
240
+ ## Contributing
267
241
 
268
242
  ```bash
269
- npm run test:integration:ftp
243
+ git clone https://github.com/tonywied17/zero-transfer.git
244
+ cd zero-transfer
245
+ npm install
246
+ npm run ci # lint, format check, typecheck, tests with coverage, build, pack dry-run
247
+ npm run test:watch # iterate
270
248
  ```
271
249
 
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.
250
+ Issues and PRs welcome. Provider integration tests are gated behind opt-in env vars — see [`test/integration/`](https://github.com/tonywied17/zero-transfer/tree/main/test/integration) for the full list.
282
251
 
283
252
  ## License
284
253
 
285
- MIT License
254
+ MIT © [Tony Wiedman](https://github.com/tonywied17)