@flowscripter/pluggable-io-framework 1.2.6 → 2.0.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 +47 -178
- package/dist/index.d.ts +11 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -4
- package/dist/src/concurrency/AsyncChannel.d.ts +9 -0
- package/dist/src/concurrency/AsyncChannel.d.ts.map +1 -0
- package/dist/src/concurrency/AsyncChannel.js +48 -0
- package/dist/src/{ConcurrencyLimiter.d.ts → concurrency/ConcurrencyLimiter.d.ts} +1 -12
- package/dist/src/concurrency/ConcurrencyLimiter.d.ts.map +1 -0
- package/dist/src/concurrency/ConcurrencyLimiter.js +64 -0
- package/dist/src/concurrency/mapAsyncIterableConcurrently.d.ts +13 -0
- package/dist/src/concurrency/mapAsyncIterableConcurrently.d.ts.map +1 -0
- package/dist/src/concurrency/mapAsyncIterableConcurrently.js +61 -0
- package/dist/src/decorators/locallyCached.d.ts +9 -10
- package/dist/src/decorators/locallyCached.d.ts.map +1 -1
- package/dist/src/decorators/locallyCached.js +23 -16
- package/dist/src/decorators/seekable.d.ts +4 -4
- package/dist/src/decorators/seekable.d.ts.map +1 -1
- package/dist/src/decorators/seekable.js +2 -2
- package/dist/src/registry/ProviderRegistry.d.ts +52 -0
- package/dist/src/registry/ProviderRegistry.d.ts.map +1 -0
- package/dist/src/registry/ProviderRegistry.js +148 -0
- package/dist/src/registry/detectProtocol.d.ts +8 -0
- package/dist/src/registry/detectProtocol.d.ts.map +1 -0
- package/dist/src/registry/detectProtocol.js +15 -0
- package/dist/src/registry/negotiateTransfer.d.ts +29 -0
- package/dist/src/registry/negotiateTransfer.d.ts.map +1 -0
- package/dist/src/registry/negotiateTransfer.js +69 -0
- package/dist/src/retry/RetryOptions.d.ts +19 -0
- package/dist/src/retry/RetryOptions.d.ts.map +1 -0
- package/dist/src/retry/RetryOptions.js +9 -0
- package/dist/src/{withRetry.d.ts → retry/withRetry.d.ts} +1 -5
- package/dist/src/retry/withRetry.d.ts.map +1 -0
- package/dist/src/{withRetry.js → retry/withRetry.js} +2 -5
- package/dist/src/transfer/EntryContext.d.ts +16 -0
- package/dist/src/transfer/EntryContext.d.ts.map +1 -0
- package/dist/src/transfer/EntryContext.js +1 -0
- package/dist/src/transfer/TransferOptions.d.ts +45 -0
- package/dist/src/transfer/TransferOptions.d.ts.map +1 -0
- package/dist/src/transfer/TransferOptions.js +1 -0
- package/dist/src/transfer/TransferResult.d.ts +9 -0
- package/dist/src/transfer/TransferResult.d.ts.map +1 -0
- package/dist/src/transfer/TransferResult.js +1 -0
- package/dist/src/transfer/aggregateResults.d.ts +4 -0
- package/dist/src/transfer/aggregateResults.d.ts.map +1 -0
- package/dist/src/transfer/aggregateResults.js +9 -0
- package/dist/src/transfer/copyMove.d.ts +23 -0
- package/dist/src/transfer/copyMove.d.ts.map +1 -0
- package/dist/src/transfer/copyMove.js +68 -0
- package/dist/src/transfer/leaseTransfer.d.ts +14 -0
- package/dist/src/transfer/leaseTransfer.d.ts.map +1 -0
- package/dist/src/transfer/leaseTransfer.js +74 -0
- package/dist/src/transfer/multipartTransfer.d.ts +23 -0
- package/dist/src/transfer/multipartTransfer.d.ts.map +1 -0
- package/dist/src/transfer/multipartTransfer.js +94 -0
- package/dist/src/transfer/negotiatePartSize.d.ts +10 -0
- package/dist/src/transfer/negotiatePartSize.d.ts.map +1 -0
- package/dist/src/transfer/negotiatePartSize.js +27 -0
- package/dist/src/transfer/patternTransfer.d.ts +12 -0
- package/dist/src/transfer/patternTransfer.d.ts.map +1 -0
- package/dist/src/transfer/patternTransfer.js +61 -0
- package/dist/src/transfer/rangeReadableMultipartReader.d.ts +8 -0
- package/dist/src/transfer/rangeReadableMultipartReader.d.ts.map +1 -0
- package/dist/src/transfer/rangeReadableMultipartReader.js +19 -0
- package/dist/src/transfer/recursiveTransfer.d.ts +13 -0
- package/dist/src/transfer/recursiveTransfer.d.ts.map +1 -0
- package/dist/src/transfer/recursiveTransfer.js +112 -0
- package/dist/src/transfer/streamTransfer.d.ts +32 -0
- package/dist/src/transfer/streamTransfer.d.ts.map +1 -0
- package/dist/src/transfer/streamTransfer.js +186 -0
- package/dist/src/transfer/transferEntry.d.ts +25 -0
- package/dist/src/transfer/transferEntry.d.ts.map +1 -0
- package/dist/src/transfer/transferEntry.js +136 -0
- package/dist/src/util/abort.d.ts +12 -0
- package/dist/src/util/abort.d.ts.map +1 -0
- package/dist/src/util/abort.js +39 -0
- package/dist/src/util/applyPayloadConverter.d.ts +9 -0
- package/dist/src/util/applyPayloadConverter.d.ts.map +1 -0
- package/dist/src/util/applyPayloadConverter.js +26 -0
- package/dist/src/util/describePath.d.ts +6 -0
- package/dist/src/util/describePath.d.ts.map +1 -0
- package/dist/src/util/describePath.js +9 -0
- package/dist/src/util/globToRegex.d.ts +8 -0
- package/dist/src/util/globToRegex.d.ts.map +1 -0
- package/dist/src/util/globToRegex.js +35 -0
- package/dist/src/util/itemLength.d.ts +4 -0
- package/dist/src/util/itemLength.d.ts.map +1 -0
- package/dist/src/util/itemLength.js +5 -0
- package/dist/src/util/keys.d.ts +8 -0
- package/dist/src/util/keys.d.ts.map +1 -0
- package/dist/src/util/keys.js +19 -0
- package/dist/src/util/withParentOperationId.d.ts +4 -0
- package/dist/src/util/withParentOperationId.d.ts.map +1 -0
- package/dist/src/util/withParentOperationId.js +12 -0
- package/index.ts +11 -4
- package/package.json +6 -5
- package/src/concurrency/AsyncChannel.ts +52 -0
- package/src/concurrency/ConcurrencyLimiter.ts +72 -0
- package/src/concurrency/mapAsyncIterableConcurrently.ts +66 -0
- package/src/decorators/locallyCached.ts +30 -22
- package/src/decorators/seekable.ts +7 -7
- package/src/registry/ProviderRegistry.ts +241 -0
- package/src/registry/detectProtocol.ts +16 -0
- package/src/registry/negotiateTransfer.ts +121 -0
- package/src/retry/RetryOptions.ts +26 -0
- package/src/{withRetry.ts → retry/withRetry.ts} +2 -12
- package/src/transfer/EntryContext.ts +17 -0
- package/src/transfer/TransferOptions.ts +45 -0
- package/src/transfer/TransferResult.ts +8 -0
- package/src/transfer/aggregateResults.ts +15 -0
- package/src/transfer/copyMove.ts +113 -0
- package/src/transfer/leaseTransfer.ts +93 -0
- package/src/transfer/multipartTransfer.ts +119 -0
- package/src/transfer/negotiatePartSize.ts +40 -0
- package/src/transfer/patternTransfer.ts +84 -0
- package/src/transfer/rangeReadableMultipartReader.ts +30 -0
- package/src/transfer/recursiveTransfer.ts +147 -0
- package/src/transfer/streamTransfer.ts +214 -0
- package/src/transfer/transferEntry.ts +185 -0
- package/src/util/abort.ts +42 -0
- package/src/util/applyPayloadConverter.ts +37 -0
- package/src/util/describePath.ts +12 -0
- package/src/util/globToRegex.ts +32 -0
- package/src/util/itemLength.ts +6 -0
- package/src/util/keys.ts +21 -0
- package/src/util/withParentOperationId.ts +17 -0
- package/dist/src/ConcurrencyLimiter.d.ts.map +0 -1
- package/dist/src/ConcurrencyLimiter.js +0 -161
- package/dist/src/ProviderRegistry.d.ts +0 -14
- package/dist/src/ProviderRegistry.d.ts.map +0 -1
- package/dist/src/ProviderRegistry.js +0 -22
- package/dist/src/chunkLength.d.ts +0 -3
- package/dist/src/chunkLength.d.ts.map +0 -1
- package/dist/src/chunkLength.js +0 -4
- package/dist/src/copyMove.d.ts +0 -46
- package/dist/src/copyMove.d.ts.map +0 -1
- package/dist/src/copyMove.js +0 -280
- package/dist/src/withRetry.d.ts.map +0 -1
- package/src/ConcurrencyLimiter.ts +0 -178
- package/src/ProviderRegistry.ts +0 -32
- package/src/chunkLength.ts +0 -5
- package/src/copyMove.ts +0 -458
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seekable.d.ts","sourceRoot":"","sources":["../../../src/decorators/seekable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,
|
|
1
|
+
{"version":3,"file":"seekable.d.ts","sourceRoot":"","sources":["../../../src/decorators/seekable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAEX,aAAa,EACb,QAAQ,EACR,YAAY,EACb,MAAM,0CAA0C,CAAC;AAElD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,WAAW,EAC5C,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,GACzC,YAAY,CAAC,CAAC,CAAC,GAAG,QAAQ,CAiC5B"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Wraps a handle that already supports
|
|
3
|
-
* byte-range reads) with a
|
|
2
|
+
* Wraps a handle that already supports `RangeReadable` (arbitrary
|
|
3
|
+
* byte-range reads) with a `Seekable` capability: a single logical
|
|
4
4
|
* stream whose read position can be jumped via `seek(offset)`, rather than
|
|
5
5
|
* requiring the caller to open a fresh stream per range.
|
|
6
6
|
*
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { PluginManager } from "@flowscripter/dynamic-plugin-framework";
|
|
2
|
+
import { type IOProvider, type IOProviderFactory, type LocationTarget, PayloadKind, type PayloadConverter, type ProviderResolver } from "@flowscripter/pluggable-io-framework-api";
|
|
3
|
+
import type { TransferOptions } from "../transfer/TransferOptions.ts";
|
|
4
|
+
/** Nested provider resolutions allowed before resolution fails. */
|
|
5
|
+
export declare const MAX_RESOLUTION_DEPTH = 4;
|
|
6
|
+
export interface ResolvedProvider {
|
|
7
|
+
readonly provider: IOProvider;
|
|
8
|
+
readonly target: LocationTarget;
|
|
9
|
+
}
|
|
10
|
+
export interface TransferProviders {
|
|
11
|
+
readonly source: ResolvedProvider;
|
|
12
|
+
readonly dest: ResolvedProvider;
|
|
13
|
+
/**
|
|
14
|
+
* The negotiated `converter`, `path` and `writePayloadTypes`, to pass to
|
|
15
|
+
* `copy`/`move` as is or spread together with caller options.
|
|
16
|
+
*/
|
|
17
|
+
readonly options: TransferOptions;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Discovers provider factories and payload converters through a
|
|
21
|
+
* `dynamic-plugin-framework` `PluginManager`, keyed by protocol and
|
|
22
|
+
* payload kind, and creates providers for location strings. It is also the
|
|
23
|
+
* `ProviderResolver` handed to every provider it creates.
|
|
24
|
+
*/
|
|
25
|
+
export declare class ProviderRegistry implements ProviderResolver {
|
|
26
|
+
#private;
|
|
27
|
+
private readonly pluginManager;
|
|
28
|
+
constructor(pluginManager: PluginManager);
|
|
29
|
+
/**
|
|
30
|
+
* Instantiates every registered factory and converter once. Fails, naming
|
|
31
|
+
* both factories, if two share a (protocol, kind) pair or if factories for
|
|
32
|
+
* the same protocol have different top-level location fields.
|
|
33
|
+
*/
|
|
34
|
+
discover(): Promise<void>;
|
|
35
|
+
getProtocols(): string[];
|
|
36
|
+
getKinds(protocol: string): PayloadKind[];
|
|
37
|
+
/** The factory for `protocol` and `kind`; without `kind`, the `js` one, else the only one. */
|
|
38
|
+
getFactory(protocol: string, kind?: PayloadKind): IOProviderFactory | undefined;
|
|
39
|
+
getConverters(): readonly PayloadConverter[];
|
|
40
|
+
createProviderForLocation(location: string, options?: {
|
|
41
|
+
kind?: PayloadKind;
|
|
42
|
+
domain?: string;
|
|
43
|
+
}): Promise<ResolvedProvider>;
|
|
44
|
+
/**
|
|
45
|
+
* Creates providers for both sides of a transfer, negotiating a common
|
|
46
|
+
* (kind, domain) and payload type, or a converter.
|
|
47
|
+
*/
|
|
48
|
+
createProvidersForTransfer(source: string, dest: string, options?: {
|
|
49
|
+
kind?: PayloadKind;
|
|
50
|
+
}): Promise<TransferProviders>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=ProviderRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProviderRegistry.d.ts","sourceRoot":"","sources":["../../../src/registry/ProviderRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,WAAW,EACX,KAAK,gBAAgB,EAIrB,KAAK,gBAAgB,EACtB,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAItE,mEAAmE;AACnE,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;CACnC;AAOD;;;;;GAKG;AACH,qBAAa,gBAAiB,YAAW,gBAAgB;;IAIpC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAAjD,YAAoC,aAAa,EAAE,aAAa,EAAI;IAEpE;;;;OAIG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAqCrC;IAEM,YAAY,IAAI,MAAM,EAAE,CAE9B;IAEM,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAE/C;IAED,8FAA8F;IACvF,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,iBAAiB,GAAG,SAAS,CAKrF;IAEM,aAAa,IAAI,SAAS,gBAAgB,EAAE,CAElD;IAEM,yBAAyB,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,WAAW,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAChD,OAAO,CAAC,gBAAgB,CAAC,CAE3B;IAED;;;OAGG;IACU,0BAA0B,CACrC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,WAAW,CAAA;KAAE,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAwC5B;CAqEF"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { BYTES_PAYLOAD_TYPE, PayloadKind, PermanentIOError, PLUGGABLE_IO_FRAMEWORK_PAYLOAD_CONVERTER_EXTENSION_POINT, PLUGGABLE_IO_FRAMEWORK_PROVIDER_FACTORY_EXTENSION_POINT, } from "@flowscripter/pluggable-io-framework-api";
|
|
2
|
+
import { detectProtocol } from "./detectProtocol.js";
|
|
3
|
+
import { DEFAULT_NATIVE_DOMAINS, negotiateTransfer } from "./negotiateTransfer.js";
|
|
4
|
+
/** Nested provider resolutions allowed before resolution fails. */
|
|
5
|
+
export const MAX_RESOLUTION_DEPTH = 4;
|
|
6
|
+
function locationFieldNames(factory) {
|
|
7
|
+
const shape = factory.locationSchema.shape;
|
|
8
|
+
return Object.keys(shape ?? {}).sort();
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Discovers provider factories and payload converters through a
|
|
12
|
+
* `dynamic-plugin-framework` `PluginManager`, keyed by protocol and
|
|
13
|
+
* payload kind, and creates providers for location strings. It is also the
|
|
14
|
+
* `ProviderResolver` handed to every provider it creates.
|
|
15
|
+
*/
|
|
16
|
+
export class ProviderRegistry {
|
|
17
|
+
pluginManager;
|
|
18
|
+
#factories = new Map();
|
|
19
|
+
#converters = [];
|
|
20
|
+
constructor(pluginManager) {
|
|
21
|
+
this.pluginManager = pluginManager;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Instantiates every registered factory and converter once. Fails, naming
|
|
25
|
+
* both factories, if two share a (protocol, kind) pair or if factories for
|
|
26
|
+
* the same protocol have different top-level location fields.
|
|
27
|
+
*/
|
|
28
|
+
async discover() {
|
|
29
|
+
const factories = new Map();
|
|
30
|
+
const handles = new Map();
|
|
31
|
+
for (const extension of await this.#extensions(PLUGGABLE_IO_FRAMEWORK_PROVIDER_FACTORY_EXTENSION_POINT)) {
|
|
32
|
+
const factory = (await this.pluginManager.instantiate(extension.extensionHandle));
|
|
33
|
+
handles.set(factory, extension.extensionHandle);
|
|
34
|
+
const byKind = factories.get(factory.protocol) ?? new Map();
|
|
35
|
+
const clash = byKind.get(factory.kind);
|
|
36
|
+
if (clash) {
|
|
37
|
+
throw new Error(`Factories "${handles.get(clash)}" and "${extension.extensionHandle}" both provide protocol "${factory.protocol}" with payload kind "${factory.kind}"`);
|
|
38
|
+
}
|
|
39
|
+
for (const other of byKind.values()) {
|
|
40
|
+
if (locationFieldNames(other).join() !== locationFieldNames(factory).join()) {
|
|
41
|
+
throw new Error(`Factories "${handles.get(other)}" and "${extension.extensionHandle}" for protocol "${factory.protocol}" have different location fields`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
byKind.set(factory.kind, factory);
|
|
45
|
+
factories.set(factory.protocol, byKind);
|
|
46
|
+
}
|
|
47
|
+
const converters = [];
|
|
48
|
+
for (const extension of await this.#extensions(PLUGGABLE_IO_FRAMEWORK_PAYLOAD_CONVERTER_EXTENSION_POINT)) {
|
|
49
|
+
converters.push((await this.pluginManager.instantiate(extension.extensionHandle)));
|
|
50
|
+
}
|
|
51
|
+
this.#factories = factories;
|
|
52
|
+
this.#converters = converters;
|
|
53
|
+
}
|
|
54
|
+
getProtocols() {
|
|
55
|
+
return [...this.#factories.keys()].sort();
|
|
56
|
+
}
|
|
57
|
+
getKinds(protocol) {
|
|
58
|
+
return [...(this.#factories.get(protocol)?.keys() ?? [])].sort();
|
|
59
|
+
}
|
|
60
|
+
/** The factory for `protocol` and `kind`; without `kind`, the `js` one, else the only one. */
|
|
61
|
+
getFactory(protocol, kind) {
|
|
62
|
+
const byKind = this.#factories.get(protocol);
|
|
63
|
+
if (!byKind)
|
|
64
|
+
return undefined;
|
|
65
|
+
if (kind !== undefined)
|
|
66
|
+
return byKind.get(kind);
|
|
67
|
+
return byKind.get(PayloadKind.Js) ?? byKind.values().next().value;
|
|
68
|
+
}
|
|
69
|
+
getConverters() {
|
|
70
|
+
return this.#converters;
|
|
71
|
+
}
|
|
72
|
+
createProviderForLocation(location, options) {
|
|
73
|
+
return this.#resolve(location, options, 0);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Creates providers for both sides of a transfer, negotiating a common
|
|
77
|
+
* (kind, domain) and payload type, or a converter.
|
|
78
|
+
*/
|
|
79
|
+
async createProvidersForTransfer(source, dest, options) {
|
|
80
|
+
const sourceProtocol = detectProtocol(source);
|
|
81
|
+
const destProtocol = detectProtocol(dest);
|
|
82
|
+
const sourceFactories = this.#factoriesFor(sourceProtocol, options?.kind);
|
|
83
|
+
const destFactories = this.#factoriesFor(destProtocol, options?.kind);
|
|
84
|
+
const negotiation = negotiateTransfer(sourceProtocol, sourceFactories, destProtocol, destFactories, this.#converters, options?.kind);
|
|
85
|
+
const sourceResolved = await this.#instantiate(negotiation.source.factory, source, negotiation.source.domain, 0);
|
|
86
|
+
let destResolved;
|
|
87
|
+
try {
|
|
88
|
+
destResolved = await this.#instantiate(negotiation.dest.factory, dest, negotiation.dest.domain, 0);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
await sourceResolved.provider[Symbol.asyncDispose]();
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
source: sourceResolved,
|
|
96
|
+
dest: destResolved,
|
|
97
|
+
options: {
|
|
98
|
+
converter: negotiation.converter,
|
|
99
|
+
path: negotiation.path,
|
|
100
|
+
writePayloadTypes: negotiation.dest.factory.writePayloadTypes ?? [BYTES_PAYLOAD_TYPE],
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
#extensions(extensionPoint) {
|
|
105
|
+
return this.pluginManager
|
|
106
|
+
.registerExtensions(extensionPoint)
|
|
107
|
+
.then(() => this.pluginManager.getRegisteredExtensions(extensionPoint));
|
|
108
|
+
}
|
|
109
|
+
#factoriesFor(protocol, kind) {
|
|
110
|
+
const byKind = this.#factories.get(protocol);
|
|
111
|
+
if (!byKind) {
|
|
112
|
+
throw new Error(`No provider for protocol "${protocol}" (available: ${this.getProtocols().join(", ")})`);
|
|
113
|
+
}
|
|
114
|
+
if (kind !== undefined && !byKind.has(kind)) {
|
|
115
|
+
throw new Error(`No provider for protocol "${protocol}" with payload kind "${kind}" (available: ${this.getKinds(protocol).join(", ")})`);
|
|
116
|
+
}
|
|
117
|
+
return [...byKind.values()];
|
|
118
|
+
}
|
|
119
|
+
async #resolve(location, options, depth) {
|
|
120
|
+
if (depth > MAX_RESOLUTION_DEPTH) {
|
|
121
|
+
throw new PermanentIOError("provider resolution too deep");
|
|
122
|
+
}
|
|
123
|
+
const protocol = detectProtocol(location);
|
|
124
|
+
this.#factoriesFor(protocol, options?.kind);
|
|
125
|
+
const factory = this.getFactory(protocol, options?.kind);
|
|
126
|
+
let domain;
|
|
127
|
+
if (factory.kind === PayloadKind.Native) {
|
|
128
|
+
const domains = factory.domains ?? DEFAULT_NATIVE_DOMAINS;
|
|
129
|
+
domain = options?.domain ?? domains[0];
|
|
130
|
+
if (domain === undefined || !domains.includes(domain)) {
|
|
131
|
+
throw new Error(`No provider for protocol "${protocol}" supports domain "${domain}" (available: ${domains.join(", ")})`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return this.#instantiate(factory, location, domain, depth);
|
|
135
|
+
}
|
|
136
|
+
async #instantiate(factory, location, domain, depth) {
|
|
137
|
+
const parsed = factory.locationSchema.parse(factory.parseLocationString(location));
|
|
138
|
+
const { config, target } = factory.toProviderInputs(parsed);
|
|
139
|
+
const resolver = {
|
|
140
|
+
createProviderForLocation: (inner, opts) => this.#resolve(inner, { kind: opts?.kind ?? factory.kind, domain: opts?.domain ?? domain }, depth + 1),
|
|
141
|
+
};
|
|
142
|
+
const provider = await factory.createProvider(factory.configSchema.parse(config), {
|
|
143
|
+
domain,
|
|
144
|
+
resolver,
|
|
145
|
+
});
|
|
146
|
+
return { provider, target };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the protocol of a location string: its URI scheme, lower-cased,
|
|
3
|
+
* or `"file"` when there is none. A scheme must be at least two characters,
|
|
4
|
+
* so a Windows drive letter (`C:\foo`) is not read as one. For a composite
|
|
5
|
+
* scheme the protocol is the part before the first `+`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function detectProtocol(input: string): string;
|
|
8
|
+
//# sourceMappingURL=detectProtocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectProtocol.d.ts","sourceRoot":"","sources":["../../../src/registry/detectProtocol.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOpD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const SCHEME = /^([a-z][a-z0-9+.-]+):/i;
|
|
2
|
+
/**
|
|
3
|
+
* Returns the protocol of a location string: its URI scheme, lower-cased,
|
|
4
|
+
* or `"file"` when there is none. A scheme must be at least two characters,
|
|
5
|
+
* so a Windows drive letter (`C:\foo`) is not read as one. For a composite
|
|
6
|
+
* scheme the protocol is the part before the first `+`.
|
|
7
|
+
*/
|
|
8
|
+
export function detectProtocol(input) {
|
|
9
|
+
const match = SCHEME.exec(input);
|
|
10
|
+
if (!match) {
|
|
11
|
+
return "file";
|
|
12
|
+
}
|
|
13
|
+
const scheme = match[1].toLowerCase();
|
|
14
|
+
return scheme.split("+")[0];
|
|
15
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type IOProviderFactory, type PayloadConverter, PayloadKind } from "@flowscripter/pluggable-io-framework-api";
|
|
2
|
+
/** One (factory, kind, domain) choice for one side of a transfer. */
|
|
3
|
+
export interface Endpoint {
|
|
4
|
+
readonly factory: IOProviderFactory;
|
|
5
|
+
readonly kind: PayloadKind;
|
|
6
|
+
readonly domain?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface Negotiation {
|
|
9
|
+
readonly source: Endpoint;
|
|
10
|
+
readonly dest: Endpoint;
|
|
11
|
+
readonly converter?: PayloadConverter;
|
|
12
|
+
readonly path: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const DEFAULT_NATIVE_DOMAINS: readonly string[];
|
|
15
|
+
/** Every (kind, domain) a factory offers, in its preference order. */
|
|
16
|
+
export declare function endpointsOf(factory: IOProviderFactory): Endpoint[];
|
|
17
|
+
/**
|
|
18
|
+
* Chooses the (kind, domain) for each side of a transfer between factories
|
|
19
|
+
* of two protocols, considering only pairs that share an exact payload type:
|
|
20
|
+
* 1. a common (kind, domain), preferring `js`, then the source factory's
|
|
21
|
+
* domain order;
|
|
22
|
+
* 2. otherwise the cheapest single converter from a source pair to a
|
|
23
|
+
* destination pair;
|
|
24
|
+
* 3. otherwise an error listing what each side supports.
|
|
25
|
+
* An explicit `kind` restricts both sides to it, and allows only converters
|
|
26
|
+
* that keep it.
|
|
27
|
+
*/
|
|
28
|
+
export declare function negotiateTransfer(sourceProtocol: string, sourceFactories: readonly IOProviderFactory[], destProtocol: string, destFactories: readonly IOProviderFactory[], converters: readonly PayloadConverter[], kind?: PayloadKind): Negotiation;
|
|
29
|
+
//# sourceMappingURL=negotiateTransfer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"negotiateTransfer.d.ts","sourceRoot":"","sources":["../../../src/registry/negotiateTransfer.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,WAAW,EACZ,MAAM,0CAA0C,CAAC;AAGlD,qEAAqE;AACrE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAAa,CAAC;AAElE,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,OAAO,EAAE,iBAAiB,GAAG,QAAQ,EAAE,CASlE;AAqBD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,SAAS,iBAAiB,EAAE,EAC7C,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,SAAS,iBAAiB,EAAE,EAC3C,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,IAAI,CAAC,EAAE,WAAW,GACjB,WAAW,CA+Cb"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { BYTES_PAYLOAD_TYPE, PayloadKind, } from "@flowscripter/pluggable-io-framework-api";
|
|
2
|
+
import { describeConverter, describeKind } from "../util/describePath.js";
|
|
3
|
+
export const DEFAULT_NATIVE_DOMAINS = ["host"];
|
|
4
|
+
/** Every (kind, domain) a factory offers, in its preference order. */
|
|
5
|
+
export function endpointsOf(factory) {
|
|
6
|
+
if (factory.kind === PayloadKind.Js) {
|
|
7
|
+
return [{ factory, kind: factory.kind }];
|
|
8
|
+
}
|
|
9
|
+
return (factory.domains ?? DEFAULT_NATIVE_DOMAINS).map((domain) => ({
|
|
10
|
+
factory,
|
|
11
|
+
kind: factory.kind,
|
|
12
|
+
domain,
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
function sharesPayloadType(source, dest) {
|
|
16
|
+
const reads = source.factory.readPayloadTypes ?? [BYTES_PAYLOAD_TYPE];
|
|
17
|
+
const writes = dest.factory.writePayloadTypes ?? [BYTES_PAYLOAD_TYPE];
|
|
18
|
+
return reads.some((payloadType) => writes.includes(payloadType));
|
|
19
|
+
}
|
|
20
|
+
function matches(end, endpoint) {
|
|
21
|
+
return end.kind === endpoint.kind && (end.domain === undefined || end.domain === endpoint.domain);
|
|
22
|
+
}
|
|
23
|
+
function kindOrder(kind) {
|
|
24
|
+
return kind === PayloadKind.Js ? 0 : 1;
|
|
25
|
+
}
|
|
26
|
+
function describeSide(protocol, endpoints) {
|
|
27
|
+
const kinds = endpoints.map((endpoint) => describeKind(endpoint.kind, endpoint.domain));
|
|
28
|
+
return `"${protocol}" supports [${kinds.join(", ")}]`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Chooses the (kind, domain) for each side of a transfer between factories
|
|
32
|
+
* of two protocols, considering only pairs that share an exact payload type:
|
|
33
|
+
* 1. a common (kind, domain), preferring `js`, then the source factory's
|
|
34
|
+
* domain order;
|
|
35
|
+
* 2. otherwise the cheapest single converter from a source pair to a
|
|
36
|
+
* destination pair;
|
|
37
|
+
* 3. otherwise an error listing what each side supports.
|
|
38
|
+
* An explicit `kind` restricts both sides to it, and allows only converters
|
|
39
|
+
* that keep it.
|
|
40
|
+
*/
|
|
41
|
+
export function negotiateTransfer(sourceProtocol, sourceFactories, destProtocol, destFactories, converters, kind) {
|
|
42
|
+
const restrict = (factories) => factories
|
|
43
|
+
.filter((factory) => kind === undefined || factory.kind === kind)
|
|
44
|
+
.flatMap(endpointsOf)
|
|
45
|
+
.sort((a, b) => kindOrder(a.kind) - kindOrder(b.kind));
|
|
46
|
+
const sources = restrict(sourceFactories);
|
|
47
|
+
const dests = restrict(destFactories);
|
|
48
|
+
const describe = (source, dest, converter) => `${sourceProtocol}/${describeKind(source.kind, source.domain)} -> ${destProtocol}/${describeKind(dest.kind, dest.domain)}${converter ? describeConverter(converter) : ""}`;
|
|
49
|
+
const pairs = sources.flatMap((source) => dests.filter((dest) => sharesPayloadType(source, dest)).map((dest) => ({ source, dest })));
|
|
50
|
+
if (pairs.length === 0 && sources.length > 0 && dests.length > 0) {
|
|
51
|
+
const reads = sourceFactories.flatMap((f) => f.readPayloadTypes ?? [BYTES_PAYLOAD_TYPE]);
|
|
52
|
+
const writes = destFactories.flatMap((f) => f.writePayloadTypes ?? [BYTES_PAYLOAD_TYPE]);
|
|
53
|
+
throw new Error(`No common payload type: "${sourceProtocol}" reads [${[...new Set(reads)].join(", ")}], "${destProtocol}" writes [${[...new Set(writes)].join(", ")}]`);
|
|
54
|
+
}
|
|
55
|
+
const common = pairs.find(({ source, dest }) => source.kind === dest.kind && source.domain === dest.domain);
|
|
56
|
+
if (common) {
|
|
57
|
+
return { ...common, path: describe(common.source, common.dest) };
|
|
58
|
+
}
|
|
59
|
+
const usable = converters
|
|
60
|
+
.filter((converter) => kind === undefined || (converter.from.kind === kind && converter.to.kind === kind))
|
|
61
|
+
.toSorted((a, b) => a.cost - b.cost);
|
|
62
|
+
for (const converter of usable) {
|
|
63
|
+
const pair = pairs.find(({ source, dest }) => matches(converter.from, source) && matches(converter.to, dest));
|
|
64
|
+
if (pair) {
|
|
65
|
+
return { ...pair, converter, path: describe(pair.source, pair.dest, converter) };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw new Error(`No common payload kind/domain and no registered converter between ${describeSide(sourceProtocol, sources)} and ${describeSide(destProtocol, dests)}`);
|
|
69
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface RetryOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Maximum retries after a `TransientIOError`. For an unbounded source this
|
|
4
|
+
* counts consecutive failures and resets once an item arrives.
|
|
5
|
+
*/
|
|
6
|
+
readonly maxRetries: number;
|
|
7
|
+
/** Delay in ms before the given retry attempt (1-based). Defaults to `min(200 * 2^attempt, 5000)`. */
|
|
8
|
+
readonly backoffMs?: (attempt: number) => number;
|
|
9
|
+
/**
|
|
10
|
+
* Unbounded sources only: what to do when the source fails and has to be
|
|
11
|
+
* reconnected, leaving a gap. Defaults to `"continue"`.
|
|
12
|
+
*/
|
|
13
|
+
readonly onGap?: "continue" | "fail";
|
|
14
|
+
}
|
|
15
|
+
export declare const DEFAULT_RETRY: RetryOptions;
|
|
16
|
+
export declare function defaultBackoffMs(attempt: number): number;
|
|
17
|
+
/** Waits for the backoff delay before retry `attempt`. */
|
|
18
|
+
export declare function backoff(options: RetryOptions, attempt: number): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=RetryOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RetryOptions.d.ts","sourceRoot":"","sources":["../../../src/retry/RetryOptions.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,sGAAsG;IACtG,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CACtC;AAED,eAAO,MAAM,aAAa,EAAE,YAAgC,CAAC;AAE7D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,0DAA0D;AAC1D,wBAAgB,OAAO,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG7E"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const DEFAULT_RETRY = { maxRetries: 3 };
|
|
2
|
+
export function defaultBackoffMs(attempt) {
|
|
3
|
+
return Math.min(200 * 2 ** attempt, 5000);
|
|
4
|
+
}
|
|
5
|
+
/** Waits for the backoff delay before retry `attempt`. */
|
|
6
|
+
export function backoff(options, attempt) {
|
|
7
|
+
const delay = (options.backoffMs ?? defaultBackoffMs)(attempt);
|
|
8
|
+
return new Promise((resolve) => setTimeout(resolve, delay));
|
|
9
|
+
}
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
readonly maxRetries: number;
|
|
3
|
-
/** Delay in ms before the given retry attempt (1-based). Defaults to `min(200 * 2^attempt, 5000)`. */
|
|
4
|
-
readonly backoffMs?: (attempt: number) => number;
|
|
5
|
-
}
|
|
1
|
+
import { type RetryOptions } from "./RetryOptions.ts";
|
|
6
2
|
/**
|
|
7
3
|
* Runs `fn`, retrying only on `TransientIOError` up to `options.maxRetries`
|
|
8
4
|
* times with a delay between attempts. Any other error - including a plain
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withRetry.d.ts","sourceRoot":"","sources":["../../../src/retry/withRetry.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE/D;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAa1F"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { TransientIOError } from "@flowscripter/pluggable-io-framework-api";
|
|
2
|
-
|
|
3
|
-
return Math.min(200 * 2 ** attempt, 5000);
|
|
4
|
-
}
|
|
2
|
+
import { backoff } from "./RetryOptions.js";
|
|
5
3
|
/**
|
|
6
4
|
* Runs `fn`, retrying only on `TransientIOError` up to `options.maxRetries`
|
|
7
5
|
* times with a delay between attempts. Any other error - including a plain
|
|
@@ -9,7 +7,6 @@ function defaultBackoffMs(attempt) {
|
|
|
9
7
|
* rethrown immediately.
|
|
10
8
|
*/
|
|
11
9
|
export async function withRetry(fn, options) {
|
|
12
|
-
const backoffMs = options.backoffMs ?? defaultBackoffMs;
|
|
13
10
|
let attempt = 0;
|
|
14
11
|
for (;;) {
|
|
15
12
|
try {
|
|
@@ -20,7 +17,7 @@ export async function withRetry(fn, options) {
|
|
|
20
17
|
throw error;
|
|
21
18
|
}
|
|
22
19
|
attempt += 1;
|
|
23
|
-
await
|
|
20
|
+
await backoff(options, attempt);
|
|
24
21
|
}
|
|
25
22
|
}
|
|
26
23
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TelemetryHooks } from "@flowscripter/pluggable-io-framework-api";
|
|
2
|
+
import type { TransferOptions } from "./TransferOptions.ts";
|
|
3
|
+
/** Per-entry state shared by the transfer strategies. */
|
|
4
|
+
export interface EntryContext {
|
|
5
|
+
readonly operationId: string;
|
|
6
|
+
readonly hooks: TelemetryHooks;
|
|
7
|
+
readonly options: TransferOptions;
|
|
8
|
+
readonly type: "copy" | "move";
|
|
9
|
+
}
|
|
10
|
+
/** Bytes and items moved by one strategy run, and whether `stop` ended it. */
|
|
11
|
+
export interface EntryOutcome {
|
|
12
|
+
readonly bytes: number;
|
|
13
|
+
readonly items: number;
|
|
14
|
+
readonly stopped: boolean;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=EntryContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EntryContext.d.ts","sourceRoot":"","sources":["../../../src/transfer/EntryContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,yDAAyD;AACzD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CAChC;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { PayloadConverter, TelemetryHooks } from "@flowscripter/pluggable-io-framework-api";
|
|
2
|
+
import type { ConcurrencyLimiter } from "../concurrency/ConcurrencyLimiter.ts";
|
|
3
|
+
import type { RetryOptions } from "../retry/RetryOptions.ts";
|
|
4
|
+
export interface TransferOptions {
|
|
5
|
+
readonly telemetry?: TelemetryHooks;
|
|
6
|
+
/** Minimum entry size (bytes) before multipart transfer is attempted over plain streaming. */
|
|
7
|
+
readonly multipartThreshold?: number;
|
|
8
|
+
/**
|
|
9
|
+
* The payload converter chosen by negotiation, applied to every item.
|
|
10
|
+
* Without one, the source and sink must share a payload kind. Set by the
|
|
11
|
+
* options `createProvidersForTransfer` returns.
|
|
12
|
+
*/
|
|
13
|
+
readonly converter?: PayloadConverter;
|
|
14
|
+
/**
|
|
15
|
+
* The negotiated path description reported in {@link TransferResult.path}.
|
|
16
|
+
* Set by the options `createProvidersForTransfer` returns; without it the
|
|
17
|
+
* path is described from the provider kinds.
|
|
18
|
+
*/
|
|
19
|
+
readonly path?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Payload type IDs the sink's factory accepts, which an opened source
|
|
22
|
+
* handle's `payloadType` must be one of. Providers don't carry their
|
|
23
|
+
* factory's declarations, so `createProvidersForTransfer` returns them in
|
|
24
|
+
* its options. Defaults to `["bytes"]`.
|
|
25
|
+
*/
|
|
26
|
+
readonly writePayloadTypes?: readonly string[];
|
|
27
|
+
/**
|
|
28
|
+
* Bounds concurrent multipart parts and recursive/pattern entries.
|
|
29
|
+
* Defaults to the shared `defaultConcurrencyLimiter` - so two
|
|
30
|
+
* `copy()`/`move()` calls in the same process share one cap unless a
|
|
31
|
+
* caller passes its own isolated instance.
|
|
32
|
+
*/
|
|
33
|
+
readonly concurrencyLimiter?: ConcurrencyLimiter;
|
|
34
|
+
/** Retry policy for the non-direct transfer path. Defaults to `{ maxRetries: 3 }`. */
|
|
35
|
+
readonly retry?: RetryOptions;
|
|
36
|
+
/** Cancels the transfer: the source is cancelled, the sink aborted, and the transfer rejects with an `AbortError`. */
|
|
37
|
+
readonly signal?: AbortSignal;
|
|
38
|
+
/** Ends the transfer gracefully: the source is cancelled, the sink closed normally, and the result reports `stopped`. */
|
|
39
|
+
readonly stop?: AbortSignal;
|
|
40
|
+
/** When `false`, `directCopy`/`directMove` are never used. Defaults to `true`. */
|
|
41
|
+
readonly directTransfer?: boolean;
|
|
42
|
+
/** Maximum leases outstanding on the lease path, capped by the sink's `maxOutstanding`. Defaults to 2. */
|
|
43
|
+
readonly leaseDepth?: number;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=TransferOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TransferOptions.d.ts","sourceRoot":"","sources":["../../../src/transfer/TransferOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AACjG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC;IACpC,8FAA8F;IAC9F,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACjD,sFAAsF;IACtF,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,sHAAsH;IACtH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,yHAAyH;IACzH,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,0GAA0G;IAC1G,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface TransferResult {
|
|
2
|
+
/** Whether `stop` ended the transfer early (output is truncated for a bounded source). */
|
|
3
|
+
readonly stopped: boolean;
|
|
4
|
+
readonly bytes: number;
|
|
5
|
+
readonly items: number;
|
|
6
|
+
/** Human-readable description of the negotiated transfer path. */
|
|
7
|
+
readonly path: string;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=TransferResult.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TransferResult.d.ts","sourceRoot":"","sources":["../../../src/transfer/TransferResult.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,0FAA0F;IAC1F,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TransferResult } from "./TransferResult.ts";
|
|
2
|
+
/** Sums per-entry results; the aggregate is stopped if any entry was. */
|
|
3
|
+
export declare function aggregateResults(results: readonly TransferResult[], path: string, stopped: boolean): TransferResult;
|
|
4
|
+
//# sourceMappingURL=aggregateResults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregateResults.d.ts","sourceRoot":"","sources":["../../../src/transfer/aggregateResults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,yEAAyE;AACzE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,GACf,cAAc,CAOhB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Sums per-entry results; the aggregate is stopped if any entry was. */
|
|
2
|
+
export function aggregateResults(results, path, stopped) {
|
|
3
|
+
return {
|
|
4
|
+
stopped: stopped || results.some((result) => result.stopped),
|
|
5
|
+
bytes: results.reduce((total, result) => total + result.bytes, 0),
|
|
6
|
+
items: results.reduce((total, result) => total + result.items, 0),
|
|
7
|
+
path,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type IOProvider, type LocationTarget } from "@flowscripter/pluggable-io-framework-api";
|
|
2
|
+
import type { TransferOptions } from "./TransferOptions.ts";
|
|
3
|
+
import type { TransferResult } from "./TransferResult.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Copies `sourceTarget` on `source` to `destTarget` on `sink`:
|
|
6
|
+
* - entry -> entry writes exactly the destination key;
|
|
7
|
+
* - entry -> container writes `<container>/<source basename>`;
|
|
8
|
+
* - container -> container copies recursively with `cp -r` semantics;
|
|
9
|
+
* - pattern -> container copies each matching entry;
|
|
10
|
+
* - container or pattern -> entry, and any pattern destination, are rejected.
|
|
11
|
+
*
|
|
12
|
+
* Each entry uses `directCopy` when eligible (and `options.directTransfer`
|
|
13
|
+
* is not `false`), otherwise multipart, the lease path or plain streaming.
|
|
14
|
+
*/
|
|
15
|
+
export declare function copy(source: IOProvider, sourceTarget: LocationTarget, sink: IOProvider, destTarget: LocationTarget, options?: TransferOptions): Promise<TransferResult>;
|
|
16
|
+
/**
|
|
17
|
+
* Moves `sourceTarget` on `source` to `destTarget` on `sink`, with the same
|
|
18
|
+
* target rules as {@link copy}. Non-direct moves copy and then delete the
|
|
19
|
+
* source. Unbounded sources are rejected, and a stopped move never deletes
|
|
20
|
+
* its source.
|
|
21
|
+
*/
|
|
22
|
+
export declare function move(source: IOProvider, sourceTarget: LocationTarget, sink: IOProvider, destTarget: LocationTarget, options?: TransferOptions): Promise<TransferResult>;
|
|
23
|
+
//# sourceMappingURL=copyMove.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copyMove.d.ts","sourceRoot":"","sources":["../../../src/transfer/copyMove.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,cAAc,EAEpB,MAAM,0CAA0C,CAAC;AAKlD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAmE1D;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAClB,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,cAAc,EAC5B,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,cAAc,EAC1B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAEzB;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAClB,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,cAAc,EAC5B,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,cAAc,EAC1B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAEzB"}
|