@zero-transfer/sdk 0.4.0 → 0.4.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/README.md +124 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +600 -13
- package/dist/index.d.ts +600 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
package/dist/index.d.ts
CHANGED
|
@@ -835,7 +835,41 @@ interface TransferEngineOptions {
|
|
|
835
835
|
/** Clock used for receipts and progress events. Defaults to `new Date()`. */
|
|
836
836
|
now?: () => Date;
|
|
837
837
|
}
|
|
838
|
-
/**
|
|
838
|
+
/**
|
|
839
|
+
* Executes transfer jobs and produces audit-friendly receipts.
|
|
840
|
+
*
|
|
841
|
+
* The engine is the lowest-level entry point in the transfer stack: it owns
|
|
842
|
+
* retry policy, attempt history, abort propagation, progress event
|
|
843
|
+
* normalization, and receipt construction. Most callers reach the engine
|
|
844
|
+
* indirectly through {@link runRoute}, {@link uploadFile}, {@link downloadFile},
|
|
845
|
+
* {@link copyBetween}, or {@link TransferQueue}; instantiate it directly when
|
|
846
|
+
* you need full control over execution semantics.
|
|
847
|
+
*
|
|
848
|
+
* @example Execute a single job with a custom executor
|
|
849
|
+
* ```ts
|
|
850
|
+
* import { TransferEngine, type TransferExecutor, type TransferJob } from "@zero-transfer/sdk";
|
|
851
|
+
*
|
|
852
|
+
* const engine = new TransferEngine();
|
|
853
|
+
*
|
|
854
|
+
* const executor: TransferExecutor = async ({ job, signal, onProgress }) => {
|
|
855
|
+
* onProgress?.({ jobId: job.id, bytesTransferred: 0 });
|
|
856
|
+
* // … perform the bytes here, honoring `signal` …
|
|
857
|
+
* return { jobId: job.id, bytesTransferred: 1234, completedAt: new Date() };
|
|
858
|
+
* };
|
|
859
|
+
*
|
|
860
|
+
* const job: TransferJob = {
|
|
861
|
+
* id: "manual-1",
|
|
862
|
+
* operation: "upload",
|
|
863
|
+
* source: { profile: localProfile, path: "./data.bin" },
|
|
864
|
+
* destination: { profile: s3Profile, path: "/data/data.bin" },
|
|
865
|
+
* };
|
|
866
|
+
*
|
|
867
|
+
* const receipt = await engine.execute(job, executor, {
|
|
868
|
+
* retry: { maxAttempts: 3, baseDelayMs: 250 },
|
|
869
|
+
* });
|
|
870
|
+
* console.log(receipt.attempts.length); // 1 on success
|
|
871
|
+
* ```
|
|
872
|
+
*/
|
|
839
873
|
declare class TransferEngine {
|
|
840
874
|
private readonly now;
|
|
841
875
|
/**
|
|
@@ -1418,9 +1452,41 @@ interface RunRouteOptions {
|
|
|
1418
1452
|
/**
|
|
1419
1453
|
* Executes an MFT route as a single transfer through the supplied client.
|
|
1420
1454
|
*
|
|
1455
|
+
* Connects the source and destination profiles, runs the route's transfer
|
|
1456
|
+
* through the engine, and returns the resulting receipt. The friendly helpers
|
|
1457
|
+
* {@link uploadFile}, {@link downloadFile}, and {@link copyBetween} synthesize
|
|
1458
|
+
* routes and delegate to this function, so behaviour around retry, abort,
|
|
1459
|
+
* progress, timeout, and bandwidth limits is identical.
|
|
1460
|
+
*
|
|
1421
1461
|
* @param options - Client, route, and optional engine/abort/retry hooks.
|
|
1422
1462
|
* @returns Receipt produced by the underlying transfer engine.
|
|
1423
1463
|
* @throws {@link ConfigurationError} When the route is disabled.
|
|
1464
|
+
*
|
|
1465
|
+
* @example Run a pre-built route with progress + retry
|
|
1466
|
+
* ```ts
|
|
1467
|
+
* import { createTransferClient, runRoute, type MftRoute } from "@zero-transfer/sdk";
|
|
1468
|
+
*
|
|
1469
|
+
* const route: MftRoute = {
|
|
1470
|
+
* id: "nightly-export",
|
|
1471
|
+
* operation: "copy",
|
|
1472
|
+
* source: {
|
|
1473
|
+
* path: "/exports/daily.csv",
|
|
1474
|
+
* profile: { host: "sftp.example.com", provider: "sftp", username: "etl" },
|
|
1475
|
+
* },
|
|
1476
|
+
* destination: {
|
|
1477
|
+
* path: "warehouse/daily.csv",
|
|
1478
|
+
* profile: { host: "warehouse", provider: "s3", s3: { region: "us-east-1" } },
|
|
1479
|
+
* },
|
|
1480
|
+
* };
|
|
1481
|
+
*
|
|
1482
|
+
* const receipt = await runRoute({
|
|
1483
|
+
* client,
|
|
1484
|
+
* route,
|
|
1485
|
+
* onProgress: (e) => console.log(`${e.bytesTransferred}/${e.totalBytes ?? "?"}`),
|
|
1486
|
+
* retry: { maxAttempts: 3, baseDelayMs: 500 },
|
|
1487
|
+
* });
|
|
1488
|
+
* console.log(`Job ${receipt.jobId} moved ${receipt.bytesTransferred} bytes…`);
|
|
1489
|
+
* ```
|
|
1424
1490
|
*/
|
|
1425
1491
|
declare function runRoute(options: RunRouteOptions): Promise<TransferReceipt>;
|
|
1426
1492
|
|
|
@@ -1594,8 +1660,20 @@ interface ClientDiagnostics {
|
|
|
1594
1660
|
/**
|
|
1595
1661
|
* Returns a redaction-safe snapshot of the providers registered with a client.
|
|
1596
1662
|
*
|
|
1663
|
+
* Use this when rendering a setup screen, generating a support bundle, or
|
|
1664
|
+
* asserting in tests that the expected provider factories were registered.
|
|
1665
|
+
*
|
|
1597
1666
|
* @param client - Transfer client to inspect.
|
|
1598
1667
|
* @returns Provider id and capability snapshot tuples.
|
|
1668
|
+
*
|
|
1669
|
+
* @example List registered providers
|
|
1670
|
+
* ```ts
|
|
1671
|
+
* import { summarizeClientDiagnostics } from "@zero-transfer/sdk";
|
|
1672
|
+
*
|
|
1673
|
+
* for (const { id, capabilities } of summarizeClientDiagnostics(client).providers) {
|
|
1674
|
+
* console.log(`${id}: streaming=${capabilities.readStream} resume=${capabilities.resumeDownload}`);
|
|
1675
|
+
* }
|
|
1676
|
+
* ```
|
|
1599
1677
|
*/
|
|
1600
1678
|
declare function summarizeClientDiagnostics(client: TransferClient): ClientDiagnostics;
|
|
1601
1679
|
/** Per-step duration measurements collected by {@link runConnectionDiagnostics}. */
|
|
@@ -1648,8 +1726,36 @@ interface RunConnectionDiagnosticsOptions {
|
|
|
1648
1726
|
/**
|
|
1649
1727
|
* Connects to a profile, captures capability and listing samples, and returns a redaction-safe report.
|
|
1650
1728
|
*
|
|
1729
|
+
* Useful for connectivity "ping" pages, smoke tests, and bug reports. Secrets
|
|
1730
|
+
* in the profile are redacted via {@link redactConnectionProfile} before being
|
|
1731
|
+
* returned. The session is always disconnected before the function returns,
|
|
1732
|
+
* including when probes throw.
|
|
1733
|
+
*
|
|
1651
1734
|
* @param options - Diagnostic probe options.
|
|
1652
1735
|
* @returns Diagnostic report including timings and any captured error.
|
|
1736
|
+
*
|
|
1737
|
+
* @example Probe an SFTP connection
|
|
1738
|
+
* ```ts
|
|
1739
|
+
* import { runConnectionDiagnostics } from "@zero-transfer/sdk";
|
|
1740
|
+
*
|
|
1741
|
+
* const report = await runConnectionDiagnostics({
|
|
1742
|
+
* client,
|
|
1743
|
+
* profile: {
|
|
1744
|
+
* host: "sftp.example.com",
|
|
1745
|
+
* provider: "sftp",
|
|
1746
|
+
* username: "deploy",
|
|
1747
|
+
* ssh: { privateKey: { path: "./keys/id_ed25519" } },
|
|
1748
|
+
* },
|
|
1749
|
+
* listPath: "/uploads",
|
|
1750
|
+
* });
|
|
1751
|
+
*
|
|
1752
|
+
* if (!report.ok) {
|
|
1753
|
+
* console.error("connection failed:", report.error);
|
|
1754
|
+
* } else {
|
|
1755
|
+
* console.log(`connect=${report.timings.connectMs}ms list=${report.timings.listMs}ms`);
|
|
1756
|
+
* console.log(report.sample); // up to 5 entries from /uploads
|
|
1757
|
+
* }
|
|
1758
|
+
* ```
|
|
1653
1759
|
*/
|
|
1654
1760
|
declare function runConnectionDiagnostics(options: RunConnectionDiagnosticsOptions): Promise<ConnectionDiagnosticsResult>;
|
|
1655
1761
|
|
|
@@ -1802,7 +1908,31 @@ interface DropboxProviderOptions {
|
|
|
1802
1908
|
*
|
|
1803
1909
|
* The bearer token is resolved per-connection from `profile.password`. The
|
|
1804
1910
|
* `profile.host` field is unused; Dropbox connections are identified solely by
|
|
1805
|
-
* their token.
|
|
1911
|
+
* their token. Uploads go to `/2/files/upload` (single-shot); resumable upload
|
|
1912
|
+
* sessions are not yet supported.
|
|
1913
|
+
*
|
|
1914
|
+
* @param options - Optional API base URL overrides and fetch implementation.
|
|
1915
|
+
* @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
|
|
1916
|
+
*
|
|
1917
|
+
* @example Upload a backup to Dropbox
|
|
1918
|
+
* ```ts
|
|
1919
|
+
* import { createDropboxProviderFactory, createTransferClient, uploadFile } from "@zero-transfer/sdk";
|
|
1920
|
+
*
|
|
1921
|
+
* const client = createTransferClient({ providers: [createDropboxProviderFactory()] });
|
|
1922
|
+
*
|
|
1923
|
+
* await uploadFile({
|
|
1924
|
+
* client,
|
|
1925
|
+
* localPath: "./backups/db.dump",
|
|
1926
|
+
* destination: {
|
|
1927
|
+
* path: "/Backups/2026-04-28/db.dump",
|
|
1928
|
+
* profile: {
|
|
1929
|
+
* host: "",
|
|
1930
|
+
* provider: "dropbox",
|
|
1931
|
+
* password: { env: "DROPBOX_ACCESS_TOKEN" },
|
|
1932
|
+
* },
|
|
1933
|
+
* },
|
|
1934
|
+
* });
|
|
1935
|
+
* ```
|
|
1806
1936
|
*/
|
|
1807
1937
|
declare function createDropboxProviderFactory(options?: DropboxProviderOptions): ProviderFactory;
|
|
1808
1938
|
|
|
@@ -1829,7 +1959,34 @@ interface GoogleDriveProviderOptions {
|
|
|
1829
1959
|
* Creates a Google Drive provider factory.
|
|
1830
1960
|
*
|
|
1831
1961
|
* The bearer token is resolved per-connection from `profile.password`
|
|
1832
|
-
* (typically an OAuth 2 access token). `profile.host` is unused.
|
|
1962
|
+
* (typically an OAuth 2 access token). `profile.host` is unused. Set
|
|
1963
|
+
* `rootFolderId` to scope the provider to a shared-drive subtree instead
|
|
1964
|
+
* of the authenticated user's My Drive root.
|
|
1965
|
+
*
|
|
1966
|
+
* @param options - Optional `rootFolderId`, `fetch`, and default headers.
|
|
1967
|
+
* @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
|
|
1968
|
+
*
|
|
1969
|
+
* @example Upload to a shared drive folder
|
|
1970
|
+
* ```ts
|
|
1971
|
+
* import { createGoogleDriveProviderFactory, createTransferClient, uploadFile } from "@zero-transfer/sdk";
|
|
1972
|
+
*
|
|
1973
|
+
* const client = createTransferClient({
|
|
1974
|
+
* providers: [createGoogleDriveProviderFactory({ rootFolderId: "0AB1cDeFG2HiJk" })],
|
|
1975
|
+
* });
|
|
1976
|
+
*
|
|
1977
|
+
* await uploadFile({
|
|
1978
|
+
* client,
|
|
1979
|
+
* localPath: "./contracts/2026-Q2.pdf",
|
|
1980
|
+
* destination: {
|
|
1981
|
+
* path: "/Contracts/2026-Q2.pdf",
|
|
1982
|
+
* profile: {
|
|
1983
|
+
* host: "",
|
|
1984
|
+
* provider: "google-drive",
|
|
1985
|
+
* password: { env: "GOOGLE_OAUTH_ACCESS_TOKEN" },
|
|
1986
|
+
* },
|
|
1987
|
+
* },
|
|
1988
|
+
* });
|
|
1989
|
+
* ```
|
|
1833
1990
|
*/
|
|
1834
1991
|
declare function createGoogleDriveProviderFactory(options?: GoogleDriveProviderOptions): ProviderFactory;
|
|
1835
1992
|
|
|
@@ -1852,7 +2009,40 @@ interface OneDriveProviderOptions {
|
|
|
1852
2009
|
* Creates a OneDrive/SharePoint provider factory backed by Microsoft Graph.
|
|
1853
2010
|
*
|
|
1854
2011
|
* The bearer token is resolved per-connection from `profile.password`.
|
|
1855
|
-
* `profile.host` is unused.
|
|
2012
|
+
* `profile.host` is unused. To target a SharePoint site or specific drive,
|
|
2013
|
+
* override `driveBaseUrl` with `https://graph.microsoft.com/v1.0/drives/{driveId}`.
|
|
2014
|
+
*
|
|
2015
|
+
* @param options - Optional `driveBaseUrl`, `fetch`, and default headers.
|
|
2016
|
+
* @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
|
|
2017
|
+
*
|
|
2018
|
+
* @example Upload to the authenticated user's OneDrive
|
|
2019
|
+
* ```ts
|
|
2020
|
+
* import { createOneDriveProviderFactory, createTransferClient, uploadFile } from "@zero-transfer/sdk";
|
|
2021
|
+
*
|
|
2022
|
+
* const client = createTransferClient({
|
|
2023
|
+
* providers: [createOneDriveProviderFactory()],
|
|
2024
|
+
* });
|
|
2025
|
+
*
|
|
2026
|
+
* await uploadFile({
|
|
2027
|
+
* client,
|
|
2028
|
+
* localPath: "./report.xlsx",
|
|
2029
|
+
* destination: {
|
|
2030
|
+
* path: "/Reports/Q2/report.xlsx",
|
|
2031
|
+
* profile: {
|
|
2032
|
+
* host: "",
|
|
2033
|
+
* provider: "one-drive",
|
|
2034
|
+
* password: { env: "GRAPH_ACCESS_TOKEN" },
|
|
2035
|
+
* },
|
|
2036
|
+
* },
|
|
2037
|
+
* });
|
|
2038
|
+
* ```
|
|
2039
|
+
*
|
|
2040
|
+
* @example Target a specific SharePoint drive
|
|
2041
|
+
* ```ts
|
|
2042
|
+
* createOneDriveProviderFactory({
|
|
2043
|
+
* driveBaseUrl: "https://graph.microsoft.com/v1.0/drives/b!abc123",
|
|
2044
|
+
* });
|
|
2045
|
+
* ```
|
|
1856
2046
|
*/
|
|
1857
2047
|
declare function createOneDriveProviderFactory(options?: OneDriveProviderOptions): ProviderFactory;
|
|
1858
2048
|
|
|
@@ -1879,7 +2069,48 @@ interface AzureBlobProviderOptions {
|
|
|
1879
2069
|
/** Default headers applied before bearer auth on every request. */
|
|
1880
2070
|
defaultHeaders?: Record<string, string>;
|
|
1881
2071
|
}
|
|
1882
|
-
/**
|
|
2072
|
+
/**
|
|
2073
|
+
* Creates an Azure Blob Storage provider factory.
|
|
2074
|
+
*
|
|
2075
|
+
* The container is fixed at factory construction time. Authenticate per-connection
|
|
2076
|
+
* with either a SAS token (configured at factory level via {@link AzureBlobProviderOptions.sasToken})
|
|
2077
|
+
* or an AAD bearer token resolved from `profile.password`. Override `endpoint` for
|
|
2078
|
+
* sovereign clouds or local Azurite testing.
|
|
2079
|
+
*
|
|
2080
|
+
* @param options - Container plus optional endpoint, SAS token, fetch override.
|
|
2081
|
+
* @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
|
|
2082
|
+
*
|
|
2083
|
+
* @example AAD-bearer upload
|
|
2084
|
+
* ```ts
|
|
2085
|
+
* import { createAzureBlobProviderFactory, createTransferClient, uploadFile } from "@zero-transfer/sdk";
|
|
2086
|
+
*
|
|
2087
|
+
* const client = createTransferClient({
|
|
2088
|
+
* providers: [createAzureBlobProviderFactory({ container: "snapshots" })],
|
|
2089
|
+
* });
|
|
2090
|
+
*
|
|
2091
|
+
* await uploadFile({
|
|
2092
|
+
* client,
|
|
2093
|
+
* localPath: "./snapshots/2026-04-28.tar.zst",
|
|
2094
|
+
* destination: {
|
|
2095
|
+
* path: "/2026/04/28/snapshot.tar.zst",
|
|
2096
|
+
* profile: {
|
|
2097
|
+
* host: "mystorageacct",
|
|
2098
|
+
* provider: "azure-blob",
|
|
2099
|
+
* password: { env: "AZURE_AAD_TOKEN" },
|
|
2100
|
+
* },
|
|
2101
|
+
* },
|
|
2102
|
+
* });
|
|
2103
|
+
* ```
|
|
2104
|
+
*
|
|
2105
|
+
* @example SAS-token + Azurite emulator
|
|
2106
|
+
* ```ts
|
|
2107
|
+
* createAzureBlobProviderFactory({
|
|
2108
|
+
* container: "devstoreaccount1",
|
|
2109
|
+
* endpoint: "http://127.0.0.1:10000/devstoreaccount1",
|
|
2110
|
+
* sasToken: "sv=2024-11-04&ss=b&srt=co&sp=rwdlac&se=...",
|
|
2111
|
+
* });
|
|
2112
|
+
* ```
|
|
2113
|
+
*/
|
|
1883
2114
|
declare function createAzureBlobProviderFactory(options: AzureBlobProviderOptions): ProviderFactory;
|
|
1884
2115
|
|
|
1885
2116
|
/** Options accepted by {@link createGcsProviderFactory}. */
|
|
@@ -1897,7 +2128,39 @@ interface GcsProviderOptions {
|
|
|
1897
2128
|
/** Default headers applied before bearer auth on every request. */
|
|
1898
2129
|
defaultHeaders?: Record<string, string>;
|
|
1899
2130
|
}
|
|
1900
|
-
/**
|
|
2131
|
+
/**
|
|
2132
|
+
* Creates a Google Cloud Storage provider factory.
|
|
2133
|
+
*
|
|
2134
|
+
* Authentication is per-connection: pass a Google OAuth 2 access token via
|
|
2135
|
+
* `profile.password`. `profile.host` is unused — the bucket is fixed at
|
|
2136
|
+
* factory construction time so a single client can target multiple buckets
|
|
2137
|
+
* by registering separate factories.
|
|
2138
|
+
*
|
|
2139
|
+
* @param options - Bucket plus optional fetch/transport overrides.
|
|
2140
|
+
* @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
|
|
2141
|
+
*
|
|
2142
|
+
* @example Bearer-token upload
|
|
2143
|
+
* ```ts
|
|
2144
|
+
* import { createGcsProviderFactory, createTransferClient, uploadFile } from "@zero-transfer/sdk";
|
|
2145
|
+
*
|
|
2146
|
+
* const client = createTransferClient({
|
|
2147
|
+
* providers: [createGcsProviderFactory({ bucket: "my-bucket" })],
|
|
2148
|
+
* });
|
|
2149
|
+
*
|
|
2150
|
+
* await uploadFile({
|
|
2151
|
+
* client,
|
|
2152
|
+
* localPath: "./build/app.tar.gz",
|
|
2153
|
+
* destination: {
|
|
2154
|
+
* path: "releases/2026.04/app.tar.gz",
|
|
2155
|
+
* profile: {
|
|
2156
|
+
* host: "my-bucket",
|
|
2157
|
+
* provider: "gcs",
|
|
2158
|
+
* password: { env: "GCP_OAUTH_ACCESS_TOKEN" },
|
|
2159
|
+
* },
|
|
2160
|
+
* },
|
|
2161
|
+
* });
|
|
2162
|
+
* ```
|
|
2163
|
+
*/
|
|
1901
2164
|
declare function createGcsProviderFactory(options: GcsProviderOptions): ProviderFactory;
|
|
1902
2165
|
|
|
1903
2166
|
/** Fixture entry used to seed a memory provider instance. */
|
|
@@ -1915,8 +2178,29 @@ interface MemoryProviderOptions {
|
|
|
1915
2178
|
/**
|
|
1916
2179
|
* Creates a provider factory backed by deterministic in-memory fixture entries.
|
|
1917
2180
|
*
|
|
2181
|
+
* Useful for tests and examples where you want a real `TransferSession` without
|
|
2182
|
+
* touching disk or the network. Entries are pre-seeded; mutations made through
|
|
2183
|
+
* the session are visible to subsequent operations on the same provider.
|
|
2184
|
+
*
|
|
1918
2185
|
* @param options - Optional fixture entries to expose through the memory provider.
|
|
1919
2186
|
* @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
|
|
2187
|
+
*
|
|
2188
|
+
* @example Seed entries and read them back
|
|
2189
|
+
* ```ts
|
|
2190
|
+
* import { createMemoryProviderFactory, createTransferClient } from "@zero-transfer/sdk";
|
|
2191
|
+
*
|
|
2192
|
+
* const client = createTransferClient({
|
|
2193
|
+
* providers: [createMemoryProviderFactory({
|
|
2194
|
+
* entries: [
|
|
2195
|
+
* { path: "/fixtures/hello.txt", content: "hello world" },
|
|
2196
|
+
* { path: "/fixtures/data.bin", content: new Uint8Array([1, 2, 3]) },
|
|
2197
|
+
* ],
|
|
2198
|
+
* })],
|
|
2199
|
+
* });
|
|
2200
|
+
*
|
|
2201
|
+
* const session = await client.connect({ host: "fixtures", provider: "memory" });
|
|
2202
|
+
* console.log(await session.fs.list("/fixtures"));
|
|
2203
|
+
* ```
|
|
1920
2204
|
*/
|
|
1921
2205
|
declare function createMemoryProviderFactory(options?: MemoryProviderOptions): ProviderFactory;
|
|
1922
2206
|
|
|
@@ -1936,8 +2220,45 @@ interface HttpProviderOptions {
|
|
|
1936
2220
|
/**
|
|
1937
2221
|
* Creates a provider factory backed by HTTP(S) GET/HEAD.
|
|
1938
2222
|
*
|
|
1939
|
-
*
|
|
2223
|
+
* Read-only by design — use it to fetch artifacts from public URLs, signed
|
|
2224
|
+
* URLs, or HTTP-only artifact servers. Range-based resume is supported when
|
|
2225
|
+
* the server advertises `Accept-Ranges: bytes`. To upload to an HTTP endpoint,
|
|
2226
|
+
* use the WebDAV provider, the S3 provider, or a cloud-specific provider.
|
|
2227
|
+
*
|
|
2228
|
+
* @param options - Optional id, base path, secure flag, fetch override.
|
|
1940
2229
|
* @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
|
|
2230
|
+
*
|
|
2231
|
+
* @example Download a public artifact
|
|
2232
|
+
* ```ts
|
|
2233
|
+
* import { createHttpProviderFactory, createTransferClient, downloadFile } from "@zero-transfer/sdk";
|
|
2234
|
+
*
|
|
2235
|
+
* const client = createTransferClient({ providers: [createHttpProviderFactory()] });
|
|
2236
|
+
*
|
|
2237
|
+
* await downloadFile({
|
|
2238
|
+
* client,
|
|
2239
|
+
* localPath: "./tmp/release.tar.gz",
|
|
2240
|
+
* source: {
|
|
2241
|
+
* path: "/releases/v1.0.0/release.tar.gz",
|
|
2242
|
+
* profile: { host: "downloads.example.com", provider: "http" },
|
|
2243
|
+
* },
|
|
2244
|
+
* });
|
|
2245
|
+
* ```
|
|
2246
|
+
*
|
|
2247
|
+
* @example Bearer-token-protected endpoint
|
|
2248
|
+
* ```ts
|
|
2249
|
+
* await downloadFile({
|
|
2250
|
+
* client,
|
|
2251
|
+
* localPath: "./reports/today.json",
|
|
2252
|
+
* source: {
|
|
2253
|
+
* path: "/reports/today.json",
|
|
2254
|
+
* profile: {
|
|
2255
|
+
* host: "api.example.com",
|
|
2256
|
+
* provider: "http",
|
|
2257
|
+
* password: { env: "REPORTS_TOKEN" },
|
|
2258
|
+
* },
|
|
2259
|
+
* },
|
|
2260
|
+
* });
|
|
2261
|
+
* ```
|
|
1941
2262
|
*/
|
|
1942
2263
|
declare function createHttpProviderFactory(options?: HttpProviderOptions): ProviderFactory;
|
|
1943
2264
|
|
|
@@ -1975,8 +2296,39 @@ interface WebDavProviderOptions {
|
|
|
1975
2296
|
/**
|
|
1976
2297
|
* Creates a WebDAV provider factory.
|
|
1977
2298
|
*
|
|
1978
|
-
*
|
|
2299
|
+
* Talks to any RFC 4918 server: Nextcloud, ownCloud, sabre/dav, Apache `mod_dav`,
|
|
2300
|
+
* IIS WebDAV, etc. PROPFIND drives directory listings, GET supports byte-range
|
|
2301
|
+
* resume on download, and PUT handles uploads. Server-side `COPY` is exposed via
|
|
2302
|
+
* the capability set. Authentication is per-connection from `profile.password`.
|
|
2303
|
+
*
|
|
2304
|
+
* @param options - Optional id, base path, secure flag, fetch, streaming policy.
|
|
1979
2305
|
* @returns Provider factory suitable for `createTransferClient({ providers: [...] })`.
|
|
2306
|
+
*
|
|
2307
|
+
* @example Upload to Nextcloud
|
|
2308
|
+
* ```ts
|
|
2309
|
+
* import { createTransferClient, createWebDavProviderFactory, uploadFile } from "@zero-transfer/sdk";
|
|
2310
|
+
*
|
|
2311
|
+
* const client = createTransferClient({
|
|
2312
|
+
* providers: [createWebDavProviderFactory({
|
|
2313
|
+
* secure: true,
|
|
2314
|
+
* basePath: "/remote.php/dav/files/alice",
|
|
2315
|
+
* })],
|
|
2316
|
+
* });
|
|
2317
|
+
*
|
|
2318
|
+
* await uploadFile({
|
|
2319
|
+
* client,
|
|
2320
|
+
* localPath: "./contracts/2026.pdf",
|
|
2321
|
+
* destination: {
|
|
2322
|
+
* path: "/Documents/Contracts/2026.pdf",
|
|
2323
|
+
* profile: {
|
|
2324
|
+
* host: "cloud.example.com",
|
|
2325
|
+
* provider: "webdav",
|
|
2326
|
+
* username: "alice",
|
|
2327
|
+
* password: { env: "NEXTCLOUD_APP_PASSWORD" },
|
|
2328
|
+
* },
|
|
2329
|
+
* },
|
|
2330
|
+
* });
|
|
2331
|
+
* ```
|
|
1980
2332
|
*/
|
|
1981
2333
|
declare function createWebDavProviderFactory(options?: WebDavProviderOptions): ProviderFactory;
|
|
1982
2334
|
|
|
@@ -3967,9 +4319,47 @@ interface TransferPlanSummary {
|
|
|
3967
4319
|
/** Counts grouped by action. */
|
|
3968
4320
|
actions: Record<string, number>;
|
|
3969
4321
|
}
|
|
3970
|
-
/**
|
|
4322
|
+
/**
|
|
4323
|
+
* Creates a transfer plan from dry-run planning input.
|
|
4324
|
+
*
|
|
4325
|
+
* Plans are immutable, structured descriptions of intended work. Pair with
|
|
4326
|
+
* {@link createSyncPlan} or {@link createAtomicDeployPlan} for end-to-end
|
|
4327
|
+
* planning, or build steps by hand when you need full control. Pass the plan
|
|
4328
|
+
* to {@link createTransferJobsFromPlan} to materialize executable jobs.
|
|
4329
|
+
*
|
|
4330
|
+
* @example Build a plan with two upload steps and inspect it
|
|
4331
|
+
* ```ts
|
|
4332
|
+
* import { createTransferPlan, summarizeTransferPlan } from "@zero-transfer/sdk";
|
|
4333
|
+
*
|
|
4334
|
+
* const plan = createTransferPlan({
|
|
4335
|
+
* id: "manual-batch",
|
|
4336
|
+
* steps: [
|
|
4337
|
+
* { action: "upload", source: "./a.bin", destination: "/lake/a.bin", expectedBytes: 1024 },
|
|
4338
|
+
* { action: "upload", source: "./b.bin", destination: "/lake/b.bin", expectedBytes: 2048 },
|
|
4339
|
+
* ],
|
|
4340
|
+
* });
|
|
4341
|
+
*
|
|
4342
|
+
* console.table(summarizeTransferPlan(plan));
|
|
4343
|
+
* ```
|
|
4344
|
+
*/
|
|
3971
4345
|
declare function createTransferPlan(input: TransferPlanInput): TransferPlan;
|
|
3972
|
-
/**
|
|
4346
|
+
/**
|
|
4347
|
+
* Summarizes a transfer plan for diagnostics, previews, and tests.
|
|
4348
|
+
*
|
|
4349
|
+
* Returns aggregate counts (total / executable / skipped / destructive),
|
|
4350
|
+
* total expected bytes, and a per-action histogram. Useful for printing a
|
|
4351
|
+
* one-line plan summary before executing or for asserting plan shape in
|
|
4352
|
+
* tests.
|
|
4353
|
+
*
|
|
4354
|
+
* @example Print a plan preview
|
|
4355
|
+
* ```ts
|
|
4356
|
+
* import { summarizeTransferPlan } from "@zero-transfer/sdk";
|
|
4357
|
+
*
|
|
4358
|
+
* const summary = summarizeTransferPlan(plan);
|
|
4359
|
+
* console.log(`${summary.executableSteps} steps, ${summary.totalExpectedBytes} bytes total`);
|
|
4360
|
+
* console.log("Actions:", summary.actions);
|
|
4361
|
+
* ```
|
|
4362
|
+
*/
|
|
3973
4363
|
declare function summarizeTransferPlan(plan: TransferPlan): TransferPlanSummary;
|
|
3974
4364
|
/** Converts executable plan steps into transfer jobs while preserving order. */
|
|
3975
4365
|
declare function createTransferJobsFromPlan(plan: TransferPlan): TransferJob[];
|
|
@@ -4046,7 +4436,41 @@ interface TransferQueueSummary {
|
|
|
4046
4436
|
/** Failed queue items in queue order. */
|
|
4047
4437
|
failures: TransferQueueItem[];
|
|
4048
4438
|
}
|
|
4049
|
-
/**
|
|
4439
|
+
/**
|
|
4440
|
+
* Minimal transfer queue with concurrency, pause/resume, cancellation, and drain summaries.
|
|
4441
|
+
*
|
|
4442
|
+
* Wrap a {@link TransferEngine} with a queue when you need to run many transfers
|
|
4443
|
+
* concurrently with bounded parallelism, observe per-job progress, or drive
|
|
4444
|
+
* a UI from a single source of truth. Items are FIFO; failures and successes
|
|
4445
|
+
* are surfaced via observers and in the final {@link TransferQueueSummary}.
|
|
4446
|
+
*
|
|
4447
|
+
* @example Run a batch of uploads with concurrency=4
|
|
4448
|
+
* ```ts
|
|
4449
|
+
* import {
|
|
4450
|
+
* TransferQueue,
|
|
4451
|
+
* createProviderTransferExecutor,
|
|
4452
|
+
* } from "@zero-transfer/sdk";
|
|
4453
|
+
*
|
|
4454
|
+
* const queue = new TransferQueue({
|
|
4455
|
+
* concurrency: 4,
|
|
4456
|
+
* executor: createProviderTransferExecutor({ client }),
|
|
4457
|
+
* onProgress: (e) => console.log(`${e.jobId}: ${e.bytesTransferred}`),
|
|
4458
|
+
* onError: (item, err) => console.error(`${item.job.id} failed`, err),
|
|
4459
|
+
* });
|
|
4460
|
+
*
|
|
4461
|
+
* for (const file of files) {
|
|
4462
|
+
* queue.enqueue({
|
|
4463
|
+
* id: file.name,
|
|
4464
|
+
* operation: "upload",
|
|
4465
|
+
* source: { profile: localProfile, path: file.path },
|
|
4466
|
+
* destination: { profile: s3Profile, path: `/lake/${file.name}` },
|
|
4467
|
+
* });
|
|
4468
|
+
* }
|
|
4469
|
+
*
|
|
4470
|
+
* const summary = await queue.drain();
|
|
4471
|
+
* console.log(`Completed ${summary.completed} / ${summary.total}`);
|
|
4472
|
+
* ```
|
|
4473
|
+
*/
|
|
4050
4474
|
declare class TransferQueue {
|
|
4051
4475
|
private readonly engine;
|
|
4052
4476
|
private readonly items;
|
|
@@ -4326,6 +4750,26 @@ interface DiffRemoteTreesOptions {
|
|
|
4326
4750
|
* @param destinationPath - Destination-side root path being compared.
|
|
4327
4751
|
* @param options - Optional comparison controls.
|
|
4328
4752
|
* @returns Diff result containing entries and a summary.
|
|
4753
|
+
*
|
|
4754
|
+
* @example Diff two SFTP subtrees and feed the result into createSyncPlan
|
|
4755
|
+
* ```ts
|
|
4756
|
+
* import { createSyncPlan, diffRemoteTrees } from "@zero-transfer/sdk";
|
|
4757
|
+
*
|
|
4758
|
+
* const diff = await diffRemoteTrees(
|
|
4759
|
+
* srcSession.fs, "/exports",
|
|
4760
|
+
* dstSession.fs, "/exports",
|
|
4761
|
+
* { compareUniqueId: true },
|
|
4762
|
+
* );
|
|
4763
|
+
*
|
|
4764
|
+
* console.log(diff.summary); // { added, removed, changed, unchanged }
|
|
4765
|
+
*
|
|
4766
|
+
* const plan = createSyncPlan({
|
|
4767
|
+
* id: "exports-sync",
|
|
4768
|
+
* diff,
|
|
4769
|
+
* source: { provider: "sftp", rootPath: "/exports" },
|
|
4770
|
+
* destination: { provider: "sftp", rootPath: "/exports" },
|
|
4771
|
+
* });
|
|
4772
|
+
* ```
|
|
4329
4773
|
*/
|
|
4330
4774
|
declare function diffRemoteTrees(source: RemoteFileSystem, sourcePath: string, destination: RemoteFileSystem, destinationPath: string, options?: DiffRemoteTreesOptions): Promise<RemoteTreeDiff>;
|
|
4331
4775
|
|
|
@@ -4397,6 +4841,31 @@ interface CreateSyncPlanOptions {
|
|
|
4397
4841
|
* @param options - Inputs and policies that shape the plan.
|
|
4398
4842
|
* @returns Transfer plan ready for `createTransferJobsFromPlan` or queue execution.
|
|
4399
4843
|
* @throws {@link ConfigurationError} When `conflictPolicy: "error"` encounters a conflict.
|
|
4844
|
+
*
|
|
4845
|
+
* @example Mirror SFTP → S3 with deletes
|
|
4846
|
+
* ```ts
|
|
4847
|
+
* import {
|
|
4848
|
+
* createSyncPlan,
|
|
4849
|
+
* diffRemoteTrees,
|
|
4850
|
+
* summarizeTransferPlan,
|
|
4851
|
+
* } from "@zero-transfer/sdk";
|
|
4852
|
+
*
|
|
4853
|
+
* const diff = await diffRemoteTrees(
|
|
4854
|
+
* srcSession.fs, "/dist",
|
|
4855
|
+
* dstSession.fs, "/releases/current",
|
|
4856
|
+
* );
|
|
4857
|
+
*
|
|
4858
|
+
* const plan = createSyncPlan({
|
|
4859
|
+
* id: "release-mirror",
|
|
4860
|
+
* diff,
|
|
4861
|
+
* source: { provider: "sftp", rootPath: "/dist" },
|
|
4862
|
+
* destination: { provider: "s3", rootPath: "/releases/current" },
|
|
4863
|
+
* deletePolicy: "mirror",
|
|
4864
|
+
* conflictPolicy: "overwrite",
|
|
4865
|
+
* });
|
|
4866
|
+
*
|
|
4867
|
+
* console.table(summarizeTransferPlan(plan));
|
|
4868
|
+
* ```
|
|
4400
4869
|
*/
|
|
4401
4870
|
declare function createSyncPlan(options: CreateSyncPlanOptions): TransferPlan;
|
|
4402
4871
|
|
|
@@ -4512,9 +4981,39 @@ interface CreateAtomicDeployPlanOptions {
|
|
|
4512
4981
|
/**
|
|
4513
4982
|
* Builds an {@link AtomicDeployPlan} that stages a release, swaps it live, and prunes old releases.
|
|
4514
4983
|
*
|
|
4984
|
+
* The plan describes a blue/green-style deploy:
|
|
4985
|
+
* 1. Upload to a timestamped staging directory under `<destination>/.releases/`.
|
|
4986
|
+
* 2. Atomically swap the `current` symlink/rename to point at the new release.
|
|
4987
|
+
* 3. Optionally prune old releases beyond `retain`.
|
|
4988
|
+
*
|
|
4989
|
+
* No I/O is performed — the host executes the plan steps. Pair with
|
|
4990
|
+
* {@link createTransferPlan} or {@link createTransferJobsFromPlan} to execute.
|
|
4991
|
+
*
|
|
4515
4992
|
* @param options - Inputs and policies that shape the deploy.
|
|
4516
4993
|
* @returns Structured deploy plan ready for execution by the calling host.
|
|
4517
4994
|
* @throws {@link ConfigurationError} When `retain` is less than `1` or the destination root is empty.
|
|
4995
|
+
*
|
|
4996
|
+
* @example Plan a release with rollback path
|
|
4997
|
+
* ```ts
|
|
4998
|
+
* import { createAtomicDeployPlan } from "@zero-transfer/sdk";
|
|
4999
|
+
*
|
|
5000
|
+
* const plan = createAtomicDeployPlan({
|
|
5001
|
+
* id: "web-2026-04-28",
|
|
5002
|
+
* source: { rootPath: "./dist" },
|
|
5003
|
+
* destination: {
|
|
5004
|
+
* profile: { host: "web1.example.com", provider: "sftp", username: "deploy" },
|
|
5005
|
+
* rootPath: "/srv/www",
|
|
5006
|
+
* },
|
|
5007
|
+
* retain: 5,
|
|
5008
|
+
* existingReleases: [
|
|
5009
|
+
* "/srv/www/.releases/2026-04-21T00-00-00Z",
|
|
5010
|
+
* "/srv/www/.releases/2026-04-14T00-00-00Z",
|
|
5011
|
+
* ],
|
|
5012
|
+
* });
|
|
5013
|
+
*
|
|
5014
|
+
* console.log(plan.swap); // staging → current rename
|
|
5015
|
+
* console.log(plan.prune); // releases scheduled for removal
|
|
5016
|
+
* ```
|
|
4518
5017
|
*/
|
|
4519
5018
|
declare function createAtomicDeployPlan(options: CreateAtomicDeployPlanOptions): AtomicDeployPlan;
|
|
4520
5019
|
|
|
@@ -5014,9 +5513,33 @@ interface CreateWebhookAuditLogOptions {
|
|
|
5014
5513
|
*
|
|
5015
5514
|
* Entries whose `type` is not in `target.types` are silently dropped. `list()`
|
|
5016
5515
|
* always returns an empty array because webhook deliveries are not buffered.
|
|
5516
|
+
* Payloads are HMAC-signed with `target.secret` (when provided) so receivers
|
|
5517
|
+
* can verify authenticity before acting on them.
|
|
5017
5518
|
*
|
|
5018
5519
|
* @param options - Webhook target plus optional retry/observer hooks.
|
|
5019
5520
|
* @returns An audit log that delivers each `record` call to the webhook.
|
|
5521
|
+
*
|
|
5522
|
+
* @example Compose a webhook log with an in-memory log for local replay
|
|
5523
|
+
* ```ts
|
|
5524
|
+
* import {
|
|
5525
|
+
* InMemoryAuditLog,
|
|
5526
|
+
* composeAuditLogs,
|
|
5527
|
+
* createWebhookAuditLog,
|
|
5528
|
+
* } from "@zero-transfer/sdk";
|
|
5529
|
+
*
|
|
5530
|
+
* const memory = new InMemoryAuditLog();
|
|
5531
|
+
* const webhook = createWebhookAuditLog({
|
|
5532
|
+
* target: {
|
|
5533
|
+
* url: "https://hooks.example.com/zt",
|
|
5534
|
+
* secret: { env: "ZT_WEBHOOK_SECRET" },
|
|
5535
|
+
* types: ["transfer.success", "transfer.failure"],
|
|
5536
|
+
* },
|
|
5537
|
+
* onDelivery: ({ result }) => console.log("delivered", result.statusCode),
|
|
5538
|
+
* });
|
|
5539
|
+
*
|
|
5540
|
+
* const audit = composeAuditLogs(memory, webhook);
|
|
5541
|
+
* await audit.record({ type: "transfer.success", receipt });
|
|
5542
|
+
* ```
|
|
5020
5543
|
*/
|
|
5021
5544
|
declare function createWebhookAuditLog(options: CreateWebhookAuditLogOptions): MftAuditLog;
|
|
5022
5545
|
|
|
@@ -5171,7 +5694,48 @@ interface MftSchedulerOptions {
|
|
|
5171
5694
|
/** Timer/clock injection used by tests. */
|
|
5172
5695
|
timer?: ScheduleTimerHooks;
|
|
5173
5696
|
}
|
|
5174
|
-
/**
|
|
5697
|
+
/**
|
|
5698
|
+
* Runs routes on configured schedules.
|
|
5699
|
+
*
|
|
5700
|
+
* Subscribes to a {@link ScheduleRegistry}, computes the next fire time for
|
|
5701
|
+
* each schedule (cron or interval), and dispatches the matching route through
|
|
5702
|
+
* a runner of your choice (`runRoute` by default, or a wrapped runner for
|
|
5703
|
+
* approvals / rate limiting / circuit breaking). Observers fire on each cycle
|
|
5704
|
+
* for telemetry. Tests can inject a deterministic timer via `timer`.
|
|
5705
|
+
*
|
|
5706
|
+
* @example Wire a cron schedule with audit + approval
|
|
5707
|
+
* ```ts
|
|
5708
|
+
* import {
|
|
5709
|
+
* ApprovalRegistry,
|
|
5710
|
+
* InMemoryAuditLog,
|
|
5711
|
+
* MftScheduler,
|
|
5712
|
+
* RouteRegistry,
|
|
5713
|
+
* ScheduleRegistry,
|
|
5714
|
+
* createApprovalGate,
|
|
5715
|
+
* runRoute,
|
|
5716
|
+
* } from "@zero-transfer/sdk";
|
|
5717
|
+
*
|
|
5718
|
+
* const audit = new InMemoryAuditLog();
|
|
5719
|
+
* const approvals = new ApprovalRegistry();
|
|
5720
|
+
*
|
|
5721
|
+
* const scheduler = new MftScheduler({
|
|
5722
|
+
* client,
|
|
5723
|
+
* routes: new RouteRegistry([route]),
|
|
5724
|
+
* schedules: new ScheduleRegistry([
|
|
5725
|
+
* { id: "nightly", routeId: route.id, cron: "0 2 * * *" },
|
|
5726
|
+
* ]),
|
|
5727
|
+
* runner: createApprovalGate({
|
|
5728
|
+
* registry: approvals,
|
|
5729
|
+
* approvalId: ({ route }) => `release:${route.id}`,
|
|
5730
|
+
* runner: ({ client: c, route: r, signal }) => runRoute({ client: c, route: r, signal }),
|
|
5731
|
+
* }),
|
|
5732
|
+
* onResult: ({ receipt }) => audit.record({ type: "transfer.success", receipt }),
|
|
5733
|
+
* onError: ({ error }) => audit.record({ type: "transfer.failure", error }),
|
|
5734
|
+
* });
|
|
5735
|
+
*
|
|
5736
|
+
* scheduler.start();
|
|
5737
|
+
* ```
|
|
5738
|
+
*/
|
|
5175
5739
|
declare class MftScheduler {
|
|
5176
5740
|
private readonly options;
|
|
5177
5741
|
private readonly now;
|
|
@@ -5315,10 +5879,33 @@ interface CreateApprovalGateOptions {
|
|
|
5315
5879
|
*
|
|
5316
5880
|
* The returned runner creates an approval request, waits for resolution, and
|
|
5317
5881
|
* dispatches the underlying runner only when the request is approved. Rejection
|
|
5318
|
-
* surfaces an {@link ApprovalRejectedError}.
|
|
5882
|
+
* surfaces an {@link ApprovalRejectedError}. Pair with {@link MftScheduler} to
|
|
5883
|
+
* implement two-person rules and human-in-the-loop release flows.
|
|
5319
5884
|
*
|
|
5320
5885
|
* @param options - Registry, downstream runner, approval-id derivation, hooks.
|
|
5321
5886
|
* @returns A {@link ScheduleRouteRunner} that gates execution behind approval.
|
|
5887
|
+
*
|
|
5888
|
+
* @example Two-person rule on a release route
|
|
5889
|
+
* ```ts
|
|
5890
|
+
* import {
|
|
5891
|
+
* ApprovalRegistry,
|
|
5892
|
+
* createApprovalGate,
|
|
5893
|
+
* runRoute,
|
|
5894
|
+
* } from "@zero-transfer/sdk";
|
|
5895
|
+
*
|
|
5896
|
+
* const approvals = new ApprovalRegistry();
|
|
5897
|
+
*
|
|
5898
|
+
* const gatedRunner = createApprovalGate({
|
|
5899
|
+
* registry: approvals,
|
|
5900
|
+
* approvalId: ({ route }) => `release:${route.id}:${Date.now()}`,
|
|
5901
|
+
* onRequested: (req) => notifyOnCallChannel(req),
|
|
5902
|
+
* runner: ({ client, route, signal }) => runRoute({ client, route, signal }),
|
|
5903
|
+
* });
|
|
5904
|
+
*
|
|
5905
|
+
* // Elsewhere, an authorized operator approves or rejects:
|
|
5906
|
+
* approvals.approve(approvalId, { actor: "alice@example.com" });
|
|
5907
|
+
* // approvals.reject(approvalId, { actor: "bob@example.com", reason: "hold release" });
|
|
5908
|
+
* ```
|
|
5322
5909
|
*/
|
|
5323
5910
|
declare function createApprovalGate(options: CreateApprovalGateOptions): ScheduleRouteRunner;
|
|
5324
5911
|
|