@zero-transfer/sdk 0.4.0 → 0.4.6

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/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
  <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>
19
19
  </p>
20
20
 
21
- 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.
21
+ 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.
22
22
 
23
23
  ```ts
24
24
  import { createS3ProviderFactory, createTransferClient, uploadFile } from "@zero-transfer/sdk";
@@ -71,7 +71,7 @@ Requires Node.js **>=20**.
71
71
 
72
72
  ## Scoped packages
73
73
 
74
- 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 publish 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.
74
+ ZeroTransfer publishes 14 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 13 are **narrowly scoped** packages that publish 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.
75
75
 
76
76
  | Package | Summary | Docs |
77
77
  | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | ----------------------------------------- |
@@ -81,6 +81,7 @@ ZeroTransfer publishes 13 scoped packages under the [`@zero-transfer`](https://w
81
81
  | [`@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) |
82
82
  | [`@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) |
83
83
  | [`@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) |
84
+ | [`@zero-transfer/ssh`](https://www.npmjs.com/package/@zero-transfer/ssh) | Standalone SSH 2.0 transport, auth, and channel primitives (exec/subsystem). | [Scope page](docs/scopes/ssh.md) |
84
85
  | [`@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) |
85
86
  | [`@zero-transfer/webdav`](https://www.npmjs.com/package/@zero-transfer/webdav) | WebDAV with PROPFIND listings and ranged downloads. | [Scope page](docs/scopes/webdav.md) |
86
87
  | [`@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) |
@@ -120,7 +121,17 @@ await session.disconnect();
120
121
  ### 2. Move a file with one call
121
122
 
122
123
  ```ts
123
- import { uploadFile } from "@zero-transfer/sdk";
124
+ import { uploadFile, type ConnectionProfile } from "@zero-transfer/sdk";
125
+
126
+ const sftpProfile: ConnectionProfile = {
127
+ host: "files.example.com",
128
+ provider: "sftp",
129
+ username: { env: "ZT_USER" },
130
+ ssh: {
131
+ privateKey: { path: "./keys/id_ed25519" },
132
+ pinnedHostKeySha256: "SHA256:base64-encoded-host-key-digest",
133
+ },
134
+ };
124
135
 
125
136
  await uploadFile({
126
137
  client,
@@ -130,6 +141,8 @@ await uploadFile({
130
141
  });
131
142
  ```
132
143
 
144
+ > The `profile` shape is the same provider-neutral [`ConnectionProfile`](docs/api-md/interfaces/ConnectionProfile.md) used by `client.connect()`. See **[Connection profiles](#connection-profiles)** below for the full field reference and security guidance.
145
+
133
146
  ### 3. Plan a sync without touching bytes
134
147
 
135
148
  ```ts
@@ -174,25 +187,133 @@ const scheduler = new MftScheduler({
174
187
  scheduler.start();
175
188
  ```
176
189
 
190
+ ## Connection profiles
191
+
192
+ Every operation that touches a remote system takes a [`ConnectionProfile`](docs/api-md/interfaces/ConnectionProfile.md). Profiles are provider-neutral data - you build one once and pass it to `client.connect()`, `uploadFile()`, `downloadFile()`, `copyBetween()`, MFT routes, and diagnostics. The same shape works for every provider; only the optional auth blocks (`ssh`, `tls`, `oauth`, `s3`, …) change.
193
+
194
+ ### Required fields
195
+
196
+ | Field | Type | Notes |
197
+ | ---------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
198
+ | `host` | `string` | Remote hostname / IP / bucket / drive identifier (provider-specific). Always required. |
199
+ | `provider` | [`ProviderId`](docs/api-md/type-aliases/ProviderId.md) | One of `"ftp"`, `"ftps"`, `"sftp"`, `"http"`, `"https"`, `"webdav"`, `"s3"`, `"azure-blob"`, `"gcs"`, `"google-drive"`, `"dropbox"`, `"one-drive"`, `"local"`, `"memory"`, or any custom id you registered. |
200
+
201
+ ### Optional top-level fields
202
+
203
+ | Field | Type | Notes |
204
+ | ----------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------- |
205
+ | `port` | `number` | Provider applies a sensible default when omitted. |
206
+ | `username` | [`SecretSource`](docs/api-md/type-aliases/SecretSource.md) | String, `{ env }`, `{ path }`, `{ base64Env }`, `{ value }`, or callback. |
207
+ | `password` | [`SecretSource`](docs/api-md/type-aliases/SecretSource.md) | Same shapes as `username`. Used as bearer token for cloud providers. |
208
+ | `secure` | `boolean` | Request encrypted transport when the protocol allows opt-in TLS. |
209
+ | `tls` | [`TlsProfile`](docs/api-md/interfaces/TlsProfile.md) | CA bundle, mTLS cert/key, fingerprint pinning, min/max TLS version. |
210
+ | `ssh` | [`SshProfile`](docs/api-md/interfaces/SshProfile.md) | Private key, passphrase, `known_hosts`, host-key pin, agent, algorithms. |
211
+ | `timeoutMs` | `number` | Connection / operation timeout. |
212
+ | `signal` | `AbortSignal` | Cancels connection setup and long-running operations. |
213
+ | `logger` | [`ZeroTransferLogger`](docs/api-md/interfaces/ZeroTransferLogger.md) | Per-profile structured logger override (still redaction-safe). |
214
+
215
+ ### Secret-bearing fields use `SecretSource`
216
+
217
+ Every credential field (`username`, `password`, `tls.ca`, `tls.key`, `ssh.privateKey`, `ssh.knownHosts`, `ssh.passphrase`, …) accepts a [`SecretSource`](docs/api-md/type-aliases/SecretSource.md). Inline strings work for prototypes, but production code should pull from the environment, a file, or a callback so secrets stay out of source control and out of process memory dumps.
218
+
219
+ ```ts
220
+ // Inline string - fine for tests, avoid in production.
221
+ password: "hunter2";
222
+
223
+ // Read from an environment variable.
224
+ password: {
225
+ env: "SFTP_PASSWORD";
226
+ }
227
+
228
+ // Read from a file (e.g. a Docker / Kubernetes secret mount).
229
+ privateKey: {
230
+ path: "/run/secrets/sftp_id_ed25519";
231
+ }
232
+
233
+ // Read base64-encoded binary from an environment variable.
234
+ ca: {
235
+ base64Env: "FTPS_CA_BUNDLE_B64";
236
+ }
237
+
238
+ // Pull from your vault / credential broker on demand.
239
+ password: async () => await vault.read("kv/sftp/deploy");
240
+ ```
241
+
242
+ Profiles are run through [`redactConnectionProfile()`](docs/api-md/functions/redactConnectionProfile.md) before any log line is emitted, so secret values never appear in logs, audit entries, or diagnostics.
243
+
244
+ ### Worked examples
245
+
246
+ ```ts
247
+ // SFTP with public-key auth + host-key pin (production-hardened)
248
+ const sftpProfile: ConnectionProfile = {
249
+ host: "sftp.example.com",
250
+ provider: "sftp",
251
+ username: "deploy",
252
+ ssh: {
253
+ privateKey: { path: "./keys/id_ed25519" },
254
+ pinnedHostKeySha256: "SHA256:abc123basesixfourpinFromKnownHosts=",
255
+ },
256
+ };
257
+
258
+ // FTPS with mTLS + private CA bundle
259
+ const ftpsProfile: ConnectionProfile = {
260
+ host: "ftps.internal.example",
261
+ provider: "ftps",
262
+ username: "audit",
263
+ tls: {
264
+ ca: { path: "./certs/ca-bundle.pem" },
265
+ cert: { path: "./certs/client.crt" },
266
+ key: { path: "./certs/client.key" },
267
+ pinnedFingerprint256:
268
+ "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99",
269
+ },
270
+ };
271
+
272
+ // S3-compatible bucket
273
+ const s3Profile: ConnectionProfile = {
274
+ host: "data-lake-bronze",
275
+ provider: "s3",
276
+ username: { env: "AWS_ACCESS_KEY_ID" },
277
+ password: { env: "AWS_SECRET_ACCESS_KEY" },
278
+ };
279
+
280
+ // Cloud drive (OAuth bearer token in `password`)
281
+ const dropboxProfile: ConnectionProfile = {
282
+ host: "",
283
+ provider: "dropbox",
284
+ password: { env: "DROPBOX_ACCESS_TOKEN" },
285
+ };
286
+ ```
287
+
288
+ ### Security guidance
289
+
290
+ - **Pin host keys for SSH/SFTP.** Without `ssh.knownHosts` or `ssh.pinnedHostKeySha256` the SSH session accepts any key the server presents - a MITM risk.
291
+ - **Pin TLS fingerprints when you control the server.** `tls.pinnedFingerprint256` is defence-in-depth on top of `rejectUnauthorized: true` and a CA bundle.
292
+ - **Never set `tls.rejectUnauthorized: false` in production.** Pair self-signed servers with `tls.ca` instead.
293
+ - **Prefer `{ env }`, `{ path }`, or callback secrets** over inline strings or hard-coded values.
294
+ - See [`examples/sftp-private-key.ts`](examples/sftp-private-key.ts), [`examples/ftps-client-certificate.ts`](examples/ftps-client-certificate.ts), and [`examples/profile-from-env.ts`](examples/profile-from-env.ts) for end-to-end hardened profile builds.
295
+
296
+ Full per-field reference: [`ConnectionProfile`](docs/api-md/interfaces/ConnectionProfile.md), [`SshProfile`](docs/api-md/interfaces/SshProfile.md), [`TlsProfile`](docs/api-md/interfaces/TlsProfile.md), [`SecretSource`](docs/api-md/type-aliases/SecretSource.md).
297
+
177
298
  ## Capability matrix
178
299
 
179
300
  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).
180
301
 
181
302
  | Provider | Streaming | Resume | Server-side copy | Multipart upload | Checksum exposed |
182
303
  | ------------- | :-------: | :------------------------------: | :--------------: | :--------------: | :----------------------: |
183
- | FTP | ✅ | ⬆/⬇ via REST | | | |
184
- | FTPS | ✅ | ⬆/⬇ via REST | | | |
185
- | SFTP | ✅ | ⬆/⬇ | rename | | |
186
- | HTTP(S) | ✅ (read) | ⬇ via Range | | | ETag |
187
- | WebDAV | ✅ | ⬇ via Range | COPY | | ETag |
304
+ | FTP | ✅ | ⬆/⬇ via REST | - | - | - |
305
+ | FTPS | ✅ | ⬆/⬇ via REST | - | - | - |
306
+ | SFTP | ✅ | ⬆/⬇ | rename | - | - |
307
+ | HTTP(S) | ✅ (read) | ⬇ via Range | - | - | ETag |
308
+ | WebDAV | ✅ | ⬇ via Range | COPY | - | ETag |
188
309
  | S3-compatible | ✅ | ⬆ via multipart resume / ⬇ Range | CopyObject | ✅ | SHA-256 / md5 |
189
- | Azure Blob | ✅ | ⬇ via Range | | (planned) | md5 |
190
- | GCS | ✅ | ⬇ via Range | | (planned) | crc32c / md5 |
191
- | Google Drive | ✅ | ⬇ via Range | | | md5 |
192
- | Dropbox | ✅ | ⬇ via Range | | | content_hash |
193
- | OneDrive | ✅ | ⬇ via Range | | (planned) | sha256 / sha1 / quickXor |
194
- | Local | ✅ | ⬆/⬇ | | | |
195
- | Memory | ✅ | ⬆/⬇ | | | |
310
+ | Azure Blob | ✅ | ⬇ via Range | - || md5 |
311
+ | GCS | ✅ | ⬇ via Range | - || crc32c / md5 |
312
+ | Google Drive | ✅ | ⬇ via Range | - | - | md5 |
313
+ | Dropbox | ✅ | ⬇ via Range | - | - | content_hash |
314
+ | OneDrive | ✅ | ⬇ via Range | - || sha256 / sha1 / quickXor |
315
+ | Local | ✅ | ⬆/⬇ | - | - | - |
316
+ | Memory | ✅ | ⬆/⬇ | - | - | - |
196
317
 
197
318
  ## Examples
198
319
 
@@ -202,10 +323,14 @@ Real-world examples live in [`examples/`](https://github.com/tonywied17/zero-tra
202
323
  | --------------------------------------------------------------------------- | ----------------------------------------------------------------- |
203
324
  | [`local-copy-file.ts`](examples/local-copy-file.ts) | Zero-config local-to-local copy via `copyBetween`. |
204
325
  | [`ftp-basic.ts`](examples/ftp-basic.ts) | Plain FTP upload + download round-trip with username/password. |
326
+ | [`ftp-directory-ops.ts`](examples/ftp-directory-ops.ts) | FTP `session.fs`: list, stat, mkdir, rename, remove, rmdir. |
205
327
  | [`ftps-basic.ts`](examples/ftps-basic.ts) | FTPS with username/password over a public-CA endpoint. |
206
328
  | [`ftps-client-certificate.ts`](examples/ftps-client-certificate.ts) | FTPS hardened: mTLS + private CA bundle + fingerprint pinning. |
329
+ | [`ftps-directory-ops.ts`](examples/ftps-directory-ops.ts) | FTPS `session.fs`: list, stat, mkdir, rename, remove, rmdir. |
207
330
  | [`sftp-basic.ts`](examples/sftp-basic.ts) | Minimal SFTP with username/password (no host-key pinning). |
208
331
  | [`sftp-private-key.ts`](examples/sftp-private-key.ts) | SFTP hardened: private-key auth + pinned host-key SHA-256. |
332
+ | [`sftp-directory-ops.ts`](examples/sftp-directory-ops.ts) | SFTP `session.fs`: list, stat, mkdir, rename, remove, rmdir. |
333
+ | [`ssh-exec-command.ts`](examples/ssh-exec-command.ts) | Standalone SSH stack: handshake, auth, run a remote command. |
209
334
  | [`s3-compatible-upload.ts`](examples/s3-compatible-upload.ts) | S3 multipart upload with cross-process resume store. |
210
335
  | [`webdav-sync.ts`](examples/webdav-sync.ts) | WebDAV diff + sync plan with deterministic ordering. |
211
336
  | [`signed-url-download.ts`](examples/signed-url-download.ts) | HTTPS signed-URL download with progress reporting. |
@@ -220,10 +345,10 @@ Real-world examples live in [`examples/`](https://github.com/tonywied17/zero-tra
220
345
 
221
346
  ## Documentation
222
347
 
223
- - [Full API reference (HTML)](https://tonywied17.github.io/zero-transfer/) TypeDoc HTML site, deployed from `main` on every push.
224
- - [Full API reference (Markdown)](docs/api-md/README.md) every public symbol with parameter / property / type tables.
225
- - [Per-scope pages](docs/scopes/README.md) one page per `@zero-transfer/*` package.
226
- - [Examples directory](https://github.com/tonywied17/zero-transfer/tree/main/examples) runnable real-world flows.
348
+ - [Full API reference (HTML)](https://tonywied17.github.io/zero-transfer/) - TypeDoc HTML site, deployed from `main` on every push.
349
+ - [Full API reference (Markdown)](docs/api-md/README.md) - every public symbol with parameter / property / type tables.
350
+ - [Per-scope pages](docs/scopes/README.md) - one page per `@zero-transfer/*` package.
351
+ - [Examples directory](https://github.com/tonywied17/zero-transfer/tree/main/examples) - runnable real-world flows.
227
352
 
228
353
  Regenerate everything locally:
229
354
 
@@ -233,7 +358,7 @@ npm run docs:all # HTML + Markdown api refs + per-scope pages + per-package
233
358
 
234
359
  ## Project status
235
360
 
236
- 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.
361
+ 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. Multipart / resumable upload sessions are now wired up across S3, Azure Blob, GCS, and OneDrive. Phase work in progress: broader real-server compatibility coverage and the push to higher coverage targets.
237
362
 
238
363
  ## Contributing
239
364
 
@@ -245,7 +370,7 @@ npm run ci # lint, format check, typecheck, tests with coverage, build,
245
370
  npm run test:watch # iterate
246
371
  ```
247
372
 
248
- 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.
373
+ 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.
249
374
 
250
375
  ## License
251
376