@flowscripter/pluggable-io-framework 1.1.5 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/src/ConcurrencyLimiter.d.ts +33 -0
- package/dist/src/ConcurrencyLimiter.d.ts.map +1 -0
- package/dist/src/ConcurrencyLimiter.js +161 -0
- package/dist/src/copyMove.d.ts +25 -8
- package/dist/src/copyMove.d.ts.map +1 -1
- package/dist/src/copyMove.js +233 -58
- package/dist/src/withRetry.d.ts +13 -0
- package/dist/src/withRetry.d.ts.map +1 -0
- package/dist/src/withRetry.js +26 -0
- package/index.ts +2 -0
- package/package.json +2 -2
- package/src/ConcurrencyLimiter.ts +178 -0
- package/src/copyMove.ts +347 -79
- package/src/withRetry.ts +33 -0
package/README.md
CHANGED
|
@@ -22,8 +22,20 @@
|
|
|
22
22
|
bucket).
|
|
23
23
|
- Otherwise transfers via multipart (when both sides support it and file
|
|
24
24
|
size crosses a configurable threshold) or plain streaming.
|
|
25
|
+
- Multipart part size is negotiated between source and sink via
|
|
26
|
+
`getPartSizeConstraints` (e.g. reconciling S3's minimum part size and
|
|
27
|
+
10000-part cap on both ends) - see [Part-size negotiation](#part-size-negotiation).
|
|
28
|
+
- A folder `sourcePath` recurses: a folder-aware `directCopy`/`directMove`
|
|
29
|
+
when the source declares `supportsRecursiveDirectTransfer`, otherwise a
|
|
30
|
+
concurrency-bounded listing-driven transfer following `cp -r` target
|
|
31
|
+
semantics - see [Recursive copy/move](#recursive-copymove).
|
|
32
|
+
- Concurrent multipart parts and recursive entries are bounded by a shared
|
|
33
|
+
`ConcurrencyLimiter` - see [Concurrency](#concurrency).
|
|
34
|
+
- The non-direct transfer path is retried on `TransientIOError` - see
|
|
35
|
+
[Retries](#retries).
|
|
25
36
|
- Reports progress via a global `TelemetryHooks` callback, tagged with a
|
|
26
|
-
per-operation correlation id
|
|
37
|
+
per-operation correlation id; multipart parts and recursive entries
|
|
38
|
+
report their own child stream tagged with `parentOperationId`.
|
|
27
39
|
- Stream decorators:
|
|
28
40
|
- `seekable` wraps a handle that supports `RangeReadable` with a single
|
|
29
41
|
logical stream whose read position can be jumped via `seek(offset)`,
|
|
@@ -69,6 +81,61 @@ The following example project is available:
|
|
|
69
81
|
- [flowscripter-io-cli](https://github.com/flowscripter/flowscripter-io-cli) is
|
|
70
82
|
an example CLI application based on this framework.
|
|
71
83
|
|
|
84
|
+
## Part-size negotiation
|
|
85
|
+
|
|
86
|
+
Before a multipart transfer, `copy()`/`move()` call `getPartSizeConstraints(totalSize)`
|
|
87
|
+
on both `source` and `sink` (when implemented - a missing implementation is
|
|
88
|
+
treated as unconstrained) and reconcile the two into a single part size:
|
|
89
|
+
the larger of the two minimums, clamped to the smaller of the two maximums,
|
|
90
|
+
bumped up if needed so the total number of parts never exceeds the smaller
|
|
91
|
+
of the two `maxParts` (e.g. S3's 10000-part cap on a very large file). If
|
|
92
|
+
the reconciled bounds are mutually infeasible, the transfer falls back to
|
|
93
|
+
plain streaming rather than failing.
|
|
94
|
+
|
|
95
|
+
## Recursive copy/move
|
|
96
|
+
|
|
97
|
+
When `sourcePath` is a folder, `copy()`/`move()` follow `cp -r`/`mv`
|
|
98
|
+
semantics for the destination: a `destPath` that doesn't exist becomes the
|
|
99
|
+
copy itself; an existing folder gets the source nested inside it as
|
|
100
|
+
`destPath/<source-basename>`; an existing file is rejected.
|
|
101
|
+
|
|
102
|
+
If the source provider declares `supportsRecursiveDirectTransfer: true` and
|
|
103
|
+
is direct-transfer-eligible with the sink, the whole folder is handed to a
|
|
104
|
+
single `directCopy`/`directMove` call. Otherwise the folder is listed
|
|
105
|
+
(`source.list(path, { recursive: true })`) and each entry is transferred
|
|
106
|
+
individually - folders via the optional `createFolder` capability (so empty
|
|
107
|
+
folders are preserved), files via the normal single-file path (which may
|
|
108
|
+
still resolve to a per-file `directCopy`/`directMove`). For a recursive
|
|
109
|
+
move without any direct-transfer capability, every entry is copied first;
|
|
110
|
+
the source folder is deleted as a single recursive `delete()` call only
|
|
111
|
+
after every entry has succeeded.
|
|
112
|
+
|
|
113
|
+
## Concurrency
|
|
114
|
+
|
|
115
|
+
Multipart parts and recursive-copy/move entries are bounded by a
|
|
116
|
+
`ConcurrencyLimiter` (`TransferOptions.concurrencyLimiter`), defaulting to
|
|
117
|
+
the exported `defaultConcurrencyLimiter` singleton - so two `copy()`/`move()`
|
|
118
|
+
calls in the same process share one cap unless a caller passes its own
|
|
119
|
+
isolated instance:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { defaultConcurrencyLimiter } from "@flowscripter/pluggable-io-framework";
|
|
123
|
+
|
|
124
|
+
defaultConcurrencyLimiter.setMaxConcurrency(8);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Retries
|
|
128
|
+
|
|
129
|
+
The non-direct transfer path (plain streaming, multipart, and the
|
|
130
|
+
copy-then-delete in a non-direct `move()`) is retried via `TransferOptions.retry`
|
|
131
|
+
(`{ maxRetries, backoffMs? }`, defaulting to `{ maxRetries: 3 }`) whenever a
|
|
132
|
+
provider throws `TransientIOError` from `pluggable-io-framework-api`. Any
|
|
133
|
+
other error - including a plain, unwrapped `Error` - is treated as
|
|
134
|
+
non-retryable. Direct provider calls (`directCopy`/`directMove`) are never
|
|
135
|
+
retried by the framework, since backends like the AWS SDK already retry
|
|
136
|
+
internally. The underlying `withRetry` utility is exported standalone for
|
|
137
|
+
other call sites.
|
|
138
|
+
|
|
72
139
|
## Development
|
|
73
140
|
|
|
74
141
|
Install dependencies:
|
|
@@ -114,12 +181,18 @@ sequenceDiagram
|
|
|
114
181
|
ProviderRegistry-->>Host: IOProvider
|
|
115
182
|
|
|
116
183
|
Host->>Source: copy(source, path, sink, path)
|
|
117
|
-
alt
|
|
184
|
+
alt path is a folder
|
|
185
|
+
alt supportsRecursiveDirectTransfer
|
|
186
|
+
Source->>Sink: directCopy(folderPath, folderPath)
|
|
187
|
+
else
|
|
188
|
+
Source-->>Sink: list + transfer entries (bounded by ConcurrencyLimiter)
|
|
189
|
+
end
|
|
190
|
+
else canDirectTransfer
|
|
118
191
|
Source->>Sink: directCopy(path, path)
|
|
119
|
-
else multipart eligible
|
|
120
|
-
Source-->>Sink: transfer Parts concurrently
|
|
192
|
+
else multipart eligible (negotiated part size)
|
|
193
|
+
Source-->>Sink: transfer Parts concurrently (bounded, retried on TransientIOError)
|
|
121
194
|
else
|
|
122
|
-
Source-->>Sink: stream ChunkRefs
|
|
195
|
+
Source-->>Sink: stream ChunkRefs (retried on TransientIOError)
|
|
123
196
|
end
|
|
124
197
|
```
|
|
125
198
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
export * from "./src/ConcurrencyLimiter.ts";
|
|
1
2
|
export * from "./src/ProviderRegistry.ts";
|
|
2
3
|
export * from "./src/copyMove.ts";
|
|
3
4
|
export * from "./src/decorators/locallyCached.ts";
|
|
4
5
|
export * from "./src/decorators/seekable.ts";
|
|
6
|
+
export * from "./src/withRetry.ts";
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A semaphore bounding how many `run()` callbacks execute at once. A single
|
|
3
|
+
* shared instance (see {@link defaultConcurrencyLimiter}) enforces its cap
|
|
4
|
+
* *globally* across concurrently invoked `copy()`/`move()` calls, not just
|
|
5
|
+
* within one call - two folder copies started at the same time and sharing
|
|
6
|
+
* a limiter will never together exceed its `maxConcurrency`.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ConcurrencyLimiter {
|
|
9
|
+
#private;
|
|
10
|
+
constructor(maxConcurrency: number);
|
|
11
|
+
get maxConcurrency(): number;
|
|
12
|
+
setMaxConcurrency(maxConcurrency: number): void;
|
|
13
|
+
run<T>(fn: () => Promise<T>): Promise<T>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Process-wide default limiter, used by `copy()`/`move()` whenever
|
|
17
|
+
* `TransferOptions.concurrencyLimiter` is omitted - so any two calls in the
|
|
18
|
+
* same process share one cap unless a caller explicitly opts out with its
|
|
19
|
+
* own instance (e.g. for test isolation).
|
|
20
|
+
*/
|
|
21
|
+
export declare const defaultConcurrencyLimiter: ConcurrencyLimiter;
|
|
22
|
+
/**
|
|
23
|
+
* Pulls items from `source` and runs `fn` on each, bounded by `limiter`:
|
|
24
|
+
* exactly `limiter.maxConcurrency` worker loops each pull-then-process one
|
|
25
|
+
* item at a time through `limiter.run`, so at most that many items are ever
|
|
26
|
+
* pulled/in-flight at once (important for sources like a multipart reader
|
|
27
|
+
* where pulling an item eagerly opens a file/network handle). Results are
|
|
28
|
+
* yielded in completion order, not source order. If `fn` throws, no new
|
|
29
|
+
* items are pulled but already-in-flight ones are allowed to finish before
|
|
30
|
+
* the error is rethrown from the returned iterable.
|
|
31
|
+
*/
|
|
32
|
+
export declare function mapAsyncIterableConcurrently<T, R>(source: AsyncIterable<T>, fn: (item: T) => Promise<R>, limiter: ConcurrencyLimiter): AsyncIterable<R>;
|
|
33
|
+
//# sourceMappingURL=ConcurrencyLimiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConcurrencyLimiter.d.ts","sourceRoot":"","sources":["../../src/ConcurrencyLimiter.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,qBAAa,kBAAkB;;IAK7B,YAAmB,cAAc,EAAE,MAAM,EAGxC;IAED,IAAW,cAAc,IAAI,MAAM,CAElC;IAEM,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAIrD;IAEY,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAQpD;CA0BF;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,oBAAkD,CAAC;AAuDzF;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,CAAC,EAC/C,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EACxB,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAC3B,OAAO,EAAE,kBAAkB,GAC1B,aAAa,CAAC,CAAC,CAAC,CAqClB"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
const DEFAULT_MAX_CONCURRENCY = 4;
|
|
2
|
+
/**
|
|
3
|
+
* A semaphore bounding how many `run()` callbacks execute at once. A single
|
|
4
|
+
* shared instance (see {@link defaultConcurrencyLimiter}) enforces its cap
|
|
5
|
+
* *globally* across concurrently invoked `copy()`/`move()` calls, not just
|
|
6
|
+
* within one call - two folder copies started at the same time and sharing
|
|
7
|
+
* a limiter will never together exceed its `maxConcurrency`.
|
|
8
|
+
*/
|
|
9
|
+
export class ConcurrencyLimiter {
|
|
10
|
+
#maxConcurrency;
|
|
11
|
+
#active = 0;
|
|
12
|
+
#queue = [];
|
|
13
|
+
constructor(maxConcurrency) {
|
|
14
|
+
ConcurrencyLimiter.#validate(maxConcurrency);
|
|
15
|
+
this.#maxConcurrency = maxConcurrency;
|
|
16
|
+
}
|
|
17
|
+
get maxConcurrency() {
|
|
18
|
+
return this.#maxConcurrency;
|
|
19
|
+
}
|
|
20
|
+
setMaxConcurrency(maxConcurrency) {
|
|
21
|
+
ConcurrencyLimiter.#validate(maxConcurrency);
|
|
22
|
+
this.#maxConcurrency = maxConcurrency;
|
|
23
|
+
this.#drain();
|
|
24
|
+
}
|
|
25
|
+
async run(fn) {
|
|
26
|
+
await this.#acquire();
|
|
27
|
+
try {
|
|
28
|
+
return await fn();
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
this.#active -= 1;
|
|
32
|
+
this.#drain();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
#acquire() {
|
|
36
|
+
if (this.#active < this.#maxConcurrency) {
|
|
37
|
+
this.#active += 1;
|
|
38
|
+
return Promise.resolve();
|
|
39
|
+
}
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
this.#queue.push(() => {
|
|
42
|
+
this.#active += 1;
|
|
43
|
+
resolve();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
#drain() {
|
|
48
|
+
while (this.#active < this.#maxConcurrency && this.#queue.length > 0) {
|
|
49
|
+
this.#queue.shift()?.();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
static #validate(maxConcurrency) {
|
|
53
|
+
if (!Number.isInteger(maxConcurrency) || maxConcurrency < 1) {
|
|
54
|
+
throw new Error(`maxConcurrency must be a positive integer, got ${maxConcurrency}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Process-wide default limiter, used by `copy()`/`move()` whenever
|
|
60
|
+
* `TransferOptions.concurrencyLimiter` is omitted - so any two calls in the
|
|
61
|
+
* same process share one cap unless a caller explicitly opts out with its
|
|
62
|
+
* own instance (e.g. for test isolation).
|
|
63
|
+
*/
|
|
64
|
+
export const defaultConcurrencyLimiter = new ConcurrencyLimiter(DEFAULT_MAX_CONCURRENCY);
|
|
65
|
+
/** Minimal single-consumer async FIFO queue backing {@link mapAsyncIterableConcurrently}. */
|
|
66
|
+
class AsyncChannel {
|
|
67
|
+
#items = [];
|
|
68
|
+
#waiters = [];
|
|
69
|
+
#closed = false;
|
|
70
|
+
#hasError = false;
|
|
71
|
+
#error;
|
|
72
|
+
push(item) {
|
|
73
|
+
const waiter = this.#waiters.shift();
|
|
74
|
+
if (waiter) {
|
|
75
|
+
waiter.resolve({ value: item, done: false });
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
this.#items.push(item);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
close() {
|
|
82
|
+
this.#closed = true;
|
|
83
|
+
for (const waiter of this.#waiters.splice(0)) {
|
|
84
|
+
if (this.#hasError) {
|
|
85
|
+
waiter.reject(this.#error);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
waiter.resolve({ value: undefined, done: true });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
fail(error) {
|
|
93
|
+
this.#hasError = true;
|
|
94
|
+
this.#error = error;
|
|
95
|
+
this.close();
|
|
96
|
+
}
|
|
97
|
+
async #next() {
|
|
98
|
+
if (this.#items.length > 0) {
|
|
99
|
+
return { value: this.#items.shift(), done: false };
|
|
100
|
+
}
|
|
101
|
+
if (this.#closed) {
|
|
102
|
+
if (this.#hasError) {
|
|
103
|
+
throw this.#error;
|
|
104
|
+
}
|
|
105
|
+
return { value: undefined, done: true };
|
|
106
|
+
}
|
|
107
|
+
return new Promise((resolve, reject) => this.#waiters.push({ resolve, reject }));
|
|
108
|
+
}
|
|
109
|
+
[Symbol.asyncIterator]() {
|
|
110
|
+
return { next: () => this.#next() };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Pulls items from `source` and runs `fn` on each, bounded by `limiter`:
|
|
115
|
+
* exactly `limiter.maxConcurrency` worker loops each pull-then-process one
|
|
116
|
+
* item at a time through `limiter.run`, so at most that many items are ever
|
|
117
|
+
* pulled/in-flight at once (important for sources like a multipart reader
|
|
118
|
+
* where pulling an item eagerly opens a file/network handle). Results are
|
|
119
|
+
* yielded in completion order, not source order. If `fn` throws, no new
|
|
120
|
+
* items are pulled but already-in-flight ones are allowed to finish before
|
|
121
|
+
* the error is rethrown from the returned iterable.
|
|
122
|
+
*/
|
|
123
|
+
export function mapAsyncIterableConcurrently(source, fn, limiter) {
|
|
124
|
+
const channel = new AsyncChannel();
|
|
125
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
126
|
+
let stopped = false;
|
|
127
|
+
let firstError;
|
|
128
|
+
let errorRecorded = false;
|
|
129
|
+
async function worker() {
|
|
130
|
+
for (;;) {
|
|
131
|
+
if (stopped)
|
|
132
|
+
return;
|
|
133
|
+
const { done, value } = await iterator.next();
|
|
134
|
+
if (done)
|
|
135
|
+
return;
|
|
136
|
+
try {
|
|
137
|
+
const result = await limiter.run(() => fn(value));
|
|
138
|
+
channel.push(result);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
stopped = true;
|
|
142
|
+
if (!errorRecorded) {
|
|
143
|
+
errorRecorded = true;
|
|
144
|
+
firstError = error;
|
|
145
|
+
}
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
void (async () => {
|
|
151
|
+
const workerCount = Math.max(1, limiter.maxConcurrency);
|
|
152
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
153
|
+
if (errorRecorded) {
|
|
154
|
+
channel.fail(firstError);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
channel.close();
|
|
158
|
+
}
|
|
159
|
+
})();
|
|
160
|
+
return channel;
|
|
161
|
+
}
|
package/dist/src/copyMove.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type ChunkConverter, type IOProvider, type TelemetryHooks } from "@flowscripter/pluggable-io-framework-api";
|
|
2
|
+
import { type ConcurrencyLimiter } from "./ConcurrencyLimiter.ts";
|
|
3
|
+
import { type RetryOptions } from "./withRetry.ts";
|
|
2
4
|
export interface TransferOptions {
|
|
3
5
|
readonly telemetry?: TelemetryHooks;
|
|
4
6
|
/** Minimum file size (bytes) before multipart transfer is attempted over plain streaming. */
|
|
@@ -10,20 +12,35 @@ export interface TransferOptions {
|
|
|
10
12
|
* FFI-capable converter supplied by a runtime-specific package.
|
|
11
13
|
*/
|
|
12
14
|
readonly chunkConverter?: ChunkConverter;
|
|
15
|
+
/**
|
|
16
|
+
* Bounds concurrent multipart parts and recursive-copy/move entries.
|
|
17
|
+
* Defaults to the shared {@link defaultConcurrencyLimiter} - so two
|
|
18
|
+
* `copy()`/`move()` calls in the same process share one cap unless a
|
|
19
|
+
* caller passes its own isolated instance.
|
|
20
|
+
*/
|
|
21
|
+
readonly concurrencyLimiter?: ConcurrencyLimiter;
|
|
22
|
+
/** Retry policy for the non-direct transfer path. Defaults to `{ maxRetries: 3 }`. */
|
|
23
|
+
readonly retry?: RetryOptions;
|
|
13
24
|
}
|
|
14
25
|
/**
|
|
15
|
-
* Copies `sourcePath` on `source` to `destPath` on `sink`.
|
|
26
|
+
* Copies `sourcePath` on `source` to `destPath` on `sink`. When `sourcePath`
|
|
27
|
+
* is a folder, recurses: uses a folder-aware `directCopy` when the source
|
|
28
|
+
* declares `supportsRecursiveDirectTransfer`, otherwise lists the folder and
|
|
29
|
+
* transfers each entry (bounded by `options.concurrencyLimiter`), following
|
|
30
|
+
* `cp -r` target semantics (see {@link resolveRecursiveDestRoot}).
|
|
16
31
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* multipart transfer (when both sides support it
|
|
20
|
-
* `options.multipartThreshold
|
|
32
|
+
* For a single file: uses `source.directCopy` when
|
|
33
|
+
* `source.canDirectTransfer?.(sink)` reports eligibility. Otherwise falls
|
|
34
|
+
* back to multipart transfer (when both sides support it, size crosses
|
|
35
|
+
* `options.multipartThreshold`, and part-size negotiation succeeds) or plain
|
|
36
|
+
* streaming - retried per `options.retry` on `TransientIOError`.
|
|
21
37
|
*/
|
|
22
38
|
export declare function copy(source: IOProvider, sourcePath: string, sink: IOProvider, destPath: string, options?: TransferOptions): Promise<void>;
|
|
23
39
|
/**
|
|
24
|
-
* Moves `sourcePath` on `source` to `destPath` on `sink`.
|
|
25
|
-
*
|
|
26
|
-
* followed by deleting the
|
|
40
|
+
* Moves `sourcePath` on `source` to `destPath` on `sink`. Folder handling
|
|
41
|
+
* mirrors {@link copy}. For a single file, uses `source.directMove` when
|
|
42
|
+
* eligible, otherwise performs a {@link copy} followed by deleting the
|
|
43
|
+
* source item (each retried independently per `options.retry`).
|
|
27
44
|
*/
|
|
28
45
|
export declare function move(source: IOProvider, sourcePath: string, sink: IOProvider, destPath: string, options?: TransferOptions): Promise<void>;
|
|
29
46
|
//# sourceMappingURL=copyMove.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copyMove.d.ts","sourceRoot":"","sources":["../../src/copyMove.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,cAAc,EAEnB,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"copyMove.d.ts","sourceRoot":"","sources":["../../src/copyMove.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,cAAc,EAEnB,KAAK,UAAU,EAIf,KAAK,cAAc,EACpB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EACL,KAAK,kBAAkB,EAGxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC;IACpC,6FAA6F;IAC7F,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACjD,sFAAsF;IACtF,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;CAC/B;AA+WD;;;;;;;;;;;;GAYG;AACH,wBAAsB,IAAI,CACxB,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;;;GAKG;AACH,wBAAsB,IAAI,CACxB,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAOf"}
|