libfw-client 0.1.3 → 0.1.4
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 +28 -6
- package/index.d.ts +23 -1
- package/index.js +22 -1
- package/package.json +1 -1
- package/pkg/libfw_client.d.ts +3 -2
- package/pkg/libfw_client.js +4 -3
- package/pkg/libfw_client_bg.wasm +0 -0
- package/pkg/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,11 @@ import { LibfwClient } from 'libfw-client';
|
|
|
11
11
|
const client = new LibfwClient({
|
|
12
12
|
baseUrl: '/api', // where libfw-server routes are mounted
|
|
13
13
|
concurrency: 4, // max parallel file transfers
|
|
14
|
+
uploadWindow: 8, // in-flight chunks per single file upload (raise to
|
|
15
|
+
// reduce upload stutter on high-latency links)
|
|
16
|
+
downloadWindow: 4, // in-flight byte-range GETs per single file download
|
|
17
|
+
// (tus-style parallel download: one file's throughput
|
|
18
|
+
// isn't bounded by a single connection's RTT)
|
|
14
19
|
compress: true, // zrip streaming compression
|
|
15
20
|
onEvent: (e) => console.log(e), // { type: 'progress', done, total }
|
|
16
21
|
});
|
|
@@ -38,14 +43,25 @@ client.cancel();
|
|
|
38
43
|
- `downloadFolder(token, dirPath?)` / `downloadFile(token, filePath)` — the
|
|
39
44
|
engine lists (for folders) and downloads each file with `Range`/`If-Range`
|
|
40
45
|
resume, decompresses the zrip stream, and pushes `Uint8Array` chunks to the
|
|
41
|
-
SDK.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
SDK. Large files use the **tus-style parallel path**: `downloadWindow`
|
|
47
|
+
concurrent byte-range GETs, reordered in memory so the SDK still receives
|
|
48
|
+
bytes strictly in order (append-mode `createWritable()`, no `.crswap`
|
|
49
|
+
churn), with per-chunk independent retries. With the File System Access API
|
|
50
|
+
the SDK streams them to disk via `fileHandle.createWritable()`; without it
|
|
51
|
+
(or with `downloadMode: 'browser'`) the SDK buffers the chunks and saves the
|
|
52
|
+
result through a traditional browser download — a single file as-is, a
|
|
53
|
+
folder packed into a `.zip`.
|
|
45
54
|
- `upload(token, files?)` — the engine slices each file into fixed-size
|
|
46
55
|
chunks, reads them via `readFile`, compresses each chunk into one zstd
|
|
47
|
-
frame, and POSTs them with `x-libfw-offset`
|
|
48
|
-
|
|
56
|
+
frame, and POSTs them with an absolute `x-libfw-offset` into a shared
|
|
57
|
+
per-session temp file. Up to `uploadWindow` chunks of one file are kept in
|
|
58
|
+
flight concurrently (independent of the cross-file `concurrency`), so a
|
|
59
|
+
high-latency link stays saturated. Uploads are **tus-style
|
|
60
|
+
verify-then-complete**: the server is the source of truth — the client
|
|
61
|
+
probes the byte ranges the server actually persisted and re-sends only the
|
|
62
|
+
still-missing blocks, filling gaps a lost response may have left (and
|
|
63
|
+
re-probing + refilling if a commit fails) before the final `x-libfw-final`
|
|
64
|
+
request merges the temp into place.
|
|
49
65
|
- Resume state (`etag`, `offset`, `size`) is persisted per path in
|
|
50
66
|
IndexedDB and re-validated on every retry.
|
|
51
67
|
- Pause/resume/cancel drive the WASM state machine
|
|
@@ -74,6 +90,12 @@ dist/libfw-client.umd.js UMD bundle (after build:umd)
|
|
|
74
90
|
## API
|
|
75
91
|
|
|
76
92
|
- `new LibfwClient(options?)`
|
|
93
|
+
- `downloadWindow: number` (default `4`) — in-flight byte-range GETs per
|
|
94
|
+
single file download; `1` disables parallelism.
|
|
95
|
+
- `downloadChunkSize: number` (default `262144`, 256 KiB) — byte range size
|
|
96
|
+
for parallel downloads; the engine reorders in-flight chunks in memory
|
|
97
|
+
(worst case ≈ `downloadWindow * downloadChunkSize` bytes) so the SDK
|
|
98
|
+
still receives data in order.
|
|
77
99
|
- `downloadMode: 'auto' | 'fs' | 'browser'` (default `'auto'`) — `'fs'`
|
|
78
100
|
streams downloads through the File System Access API; `'browser'` buffers
|
|
79
101
|
and triggers a traditional browser download (folders become `.zip`);
|
package/index.d.ts
CHANGED
|
@@ -52,8 +52,30 @@ export interface LibfwEvent {
|
|
|
52
52
|
export interface LibfwClientOptions {
|
|
53
53
|
/** Base URL the libfw server routes are mounted under. Default `''`. */
|
|
54
54
|
baseUrl?: string;
|
|
55
|
-
/** Max
|
|
55
|
+
/** Max concurrently-transferring files. Default `4`. */
|
|
56
56
|
concurrency?: number;
|
|
57
|
+
/**
|
|
58
|
+
* In-flight chunk window for a single file's upload, independent of
|
|
59
|
+
* `concurrency`. A higher value keeps high-latency links saturated and
|
|
60
|
+
* reduces upload stutter; keep it within your server's connection limit
|
|
61
|
+
* (~6 for HTTP/1.1). Default `8`.
|
|
62
|
+
*/
|
|
63
|
+
uploadWindow?: number;
|
|
64
|
+
/**
|
|
65
|
+
* In-flight byte-range window for a single file's download. Large files
|
|
66
|
+
* are fetched as `downloadWindow` concurrent `Range` GETs (tus-style
|
|
67
|
+
* parallel transfer), so a single file's throughput is bounded by
|
|
68
|
+
* bandwidth instead of one connection's `chunkSize / RTT` on high-latency
|
|
69
|
+
* links. `1` disables parallelism. Default `4`.
|
|
70
|
+
*/
|
|
71
|
+
downloadWindow?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Byte range size for parallel downloads. Smaller than the upload chunk
|
|
74
|
+
* on purpose: the engine reorders in-flight chunks in memory (worst case
|
|
75
|
+
* ≈ `downloadWindow * downloadChunkSize` bytes) so the SDK still receives
|
|
76
|
+
* data strictly in order. Default `262144` (256 KiB).
|
|
77
|
+
*/
|
|
78
|
+
downloadChunkSize?: number;
|
|
57
79
|
/** Negotiate zrip compression. Default `true`. */
|
|
58
80
|
compress?: boolean;
|
|
59
81
|
/** Upload chunk size in bytes. Default 2 MiB. */
|
package/index.js
CHANGED
|
@@ -188,7 +188,22 @@ export class LibfwClient {
|
|
|
188
188
|
/**
|
|
189
189
|
* @param {object} [options]
|
|
190
190
|
* @param {string} [options.baseUrl=''] base URL the server routes are mounted under
|
|
191
|
-
* @param {number} [options.concurrency=4] max
|
|
191
|
+
* @param {number} [options.concurrency=4] max concurrently-transferring files
|
|
192
|
+
* @param {number} [options.uploadWindow=8] in-flight chunk window for a
|
|
193
|
+
* single file's upload; independent of `concurrency`, keeps a
|
|
194
|
+
* high-latency link saturated (raise it to reduce upload stutter;
|
|
195
|
+
* keep within your server's connection limit, ~6 for HTTP/1.1)
|
|
196
|
+
* @param {number} [options.downloadWindow=4] in-flight byte-range window
|
|
197
|
+
* for a single file's download. Large files are fetched as
|
|
198
|
+
* `downloadWindow` concurrent `Range` GETs (tus-style parallel
|
|
199
|
+
* transfer), so a single file's throughput is bounded by bandwidth
|
|
200
|
+
* instead of one connection's `chunkSize / RTT` on high-latency
|
|
201
|
+
* links. `1` disables parallelism (sequential downloads).
|
|
202
|
+
* @param {number} [options.downloadChunkSize=262144] byte range size for
|
|
203
|
+
* parallel downloads (256 KiB default). Smaller than the upload
|
|
204
|
+
* chunk on purpose: the engine reorders in-flight chunks in memory
|
|
205
|
+
* (worst case ≈ `downloadWindow * downloadChunkSize` bytes) so the
|
|
206
|
+
* SDK still receives data strictly in order.
|
|
192
207
|
* @param {boolean} [options.compress=true] negotiate zrip compression
|
|
193
208
|
* @param {number} [options.chunkSize=2097152] upload chunk size in bytes
|
|
194
209
|
* @param {number} [options.maxRetries=3] retries per chunk/file before failing
|
|
@@ -216,6 +231,9 @@ export class LibfwClient {
|
|
|
216
231
|
this._options = {
|
|
217
232
|
baseUrl: '',
|
|
218
233
|
concurrency: 4,
|
|
234
|
+
uploadWindow: 8,
|
|
235
|
+
downloadWindow: 4,
|
|
236
|
+
downloadChunkSize: 256 * 1024,
|
|
219
237
|
compress: true,
|
|
220
238
|
chunkSize: 2 * 1024 * 1024,
|
|
221
239
|
maxRetries: 3,
|
|
@@ -272,6 +290,9 @@ export class LibfwClient {
|
|
|
272
290
|
await this._initPromise;
|
|
273
291
|
const engine = new WasmEngine({
|
|
274
292
|
concurrency: this._options.concurrency,
|
|
293
|
+
uploadWindow: this._options.uploadWindow,
|
|
294
|
+
downloadWindow: this._options.downloadWindow,
|
|
295
|
+
downloadChunkSize: this._options.downloadChunkSize,
|
|
275
296
|
compress: this._options.compress,
|
|
276
297
|
chunkSize: this._options.chunkSize,
|
|
277
298
|
maxRetries: this._options.maxRetries,
|
package/package.json
CHANGED
package/pkg/libfw_client.d.ts
CHANGED
|
@@ -33,8 +33,9 @@ export class LibfwClient {
|
|
|
33
33
|
has_callbacks(): boolean;
|
|
34
34
|
/**
|
|
35
35
|
* Create an engine. `options` may include:
|
|
36
|
-
* `{ concurrency,
|
|
37
|
-
*
|
|
36
|
+
* `{ concurrency, uploadWindow, downloadWindow, downloadChunkSize,
|
|
37
|
+
* compress, chunkSize, maxRetries, baseRetryDelayMs, maxRetryDelayMs,
|
|
38
|
+
* timeoutMs }`.
|
|
38
39
|
*/
|
|
39
40
|
constructor(opts: any);
|
|
40
41
|
/**
|
package/pkg/libfw_client.js
CHANGED
|
@@ -76,8 +76,9 @@ export class LibfwClient {
|
|
|
76
76
|
}
|
|
77
77
|
/**
|
|
78
78
|
* Create an engine. `options` may include:
|
|
79
|
-
* `{ concurrency,
|
|
80
|
-
*
|
|
79
|
+
* `{ concurrency, uploadWindow, downloadWindow, downloadChunkSize,
|
|
80
|
+
* compress, chunkSize, maxRetries, baseRetryDelayMs, maxRetryDelayMs,
|
|
81
|
+
* timeoutMs }`.
|
|
81
82
|
* @param {any} opts
|
|
82
83
|
*/
|
|
83
84
|
constructor(opts) {
|
|
@@ -462,7 +463,7 @@ function __wbg_get_imports() {
|
|
|
462
463
|
return ret;
|
|
463
464
|
},
|
|
464
465
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
465
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx:
|
|
466
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 145, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
466
467
|
const ret = makeMutClosure(arg0, arg1, wasm_bindgen_1e05ddb24c0b7df4___convert__closures_____invoke___wasm_bindgen_1e05ddb24c0b7df4___JsValue__core_9b3796e30d99ddb7___result__Result_____wasm_bindgen_1e05ddb24c0b7df4___JsError___true_);
|
|
467
468
|
return ret;
|
|
468
469
|
},
|
package/pkg/libfw_client_bg.wasm
CHANGED
|
Binary file
|