@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.
Files changed (142) hide show
  1. package/README.md +47 -178
  2. package/dist/index.d.ts +11 -4
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +11 -4
  5. package/dist/src/concurrency/AsyncChannel.d.ts +9 -0
  6. package/dist/src/concurrency/AsyncChannel.d.ts.map +1 -0
  7. package/dist/src/concurrency/AsyncChannel.js +48 -0
  8. package/dist/src/{ConcurrencyLimiter.d.ts → concurrency/ConcurrencyLimiter.d.ts} +1 -12
  9. package/dist/src/concurrency/ConcurrencyLimiter.d.ts.map +1 -0
  10. package/dist/src/concurrency/ConcurrencyLimiter.js +64 -0
  11. package/dist/src/concurrency/mapAsyncIterableConcurrently.d.ts +13 -0
  12. package/dist/src/concurrency/mapAsyncIterableConcurrently.d.ts.map +1 -0
  13. package/dist/src/concurrency/mapAsyncIterableConcurrently.js +61 -0
  14. package/dist/src/decorators/locallyCached.d.ts +9 -10
  15. package/dist/src/decorators/locallyCached.d.ts.map +1 -1
  16. package/dist/src/decorators/locallyCached.js +23 -16
  17. package/dist/src/decorators/seekable.d.ts +4 -4
  18. package/dist/src/decorators/seekable.d.ts.map +1 -1
  19. package/dist/src/decorators/seekable.js +2 -2
  20. package/dist/src/registry/ProviderRegistry.d.ts +52 -0
  21. package/dist/src/registry/ProviderRegistry.d.ts.map +1 -0
  22. package/dist/src/registry/ProviderRegistry.js +148 -0
  23. package/dist/src/registry/detectProtocol.d.ts +8 -0
  24. package/dist/src/registry/detectProtocol.d.ts.map +1 -0
  25. package/dist/src/registry/detectProtocol.js +15 -0
  26. package/dist/src/registry/negotiateTransfer.d.ts +29 -0
  27. package/dist/src/registry/negotiateTransfer.d.ts.map +1 -0
  28. package/dist/src/registry/negotiateTransfer.js +69 -0
  29. package/dist/src/retry/RetryOptions.d.ts +19 -0
  30. package/dist/src/retry/RetryOptions.d.ts.map +1 -0
  31. package/dist/src/retry/RetryOptions.js +9 -0
  32. package/dist/src/{withRetry.d.ts → retry/withRetry.d.ts} +1 -5
  33. package/dist/src/retry/withRetry.d.ts.map +1 -0
  34. package/dist/src/{withRetry.js → retry/withRetry.js} +2 -5
  35. package/dist/src/transfer/EntryContext.d.ts +16 -0
  36. package/dist/src/transfer/EntryContext.d.ts.map +1 -0
  37. package/dist/src/transfer/EntryContext.js +1 -0
  38. package/dist/src/transfer/TransferOptions.d.ts +45 -0
  39. package/dist/src/transfer/TransferOptions.d.ts.map +1 -0
  40. package/dist/src/transfer/TransferOptions.js +1 -0
  41. package/dist/src/transfer/TransferResult.d.ts +9 -0
  42. package/dist/src/transfer/TransferResult.d.ts.map +1 -0
  43. package/dist/src/transfer/TransferResult.js +1 -0
  44. package/dist/src/transfer/aggregateResults.d.ts +4 -0
  45. package/dist/src/transfer/aggregateResults.d.ts.map +1 -0
  46. package/dist/src/transfer/aggregateResults.js +9 -0
  47. package/dist/src/transfer/copyMove.d.ts +23 -0
  48. package/dist/src/transfer/copyMove.d.ts.map +1 -0
  49. package/dist/src/transfer/copyMove.js +68 -0
  50. package/dist/src/transfer/leaseTransfer.d.ts +14 -0
  51. package/dist/src/transfer/leaseTransfer.d.ts.map +1 -0
  52. package/dist/src/transfer/leaseTransfer.js +74 -0
  53. package/dist/src/transfer/multipartTransfer.d.ts +23 -0
  54. package/dist/src/transfer/multipartTransfer.d.ts.map +1 -0
  55. package/dist/src/transfer/multipartTransfer.js +94 -0
  56. package/dist/src/transfer/negotiatePartSize.d.ts +10 -0
  57. package/dist/src/transfer/negotiatePartSize.d.ts.map +1 -0
  58. package/dist/src/transfer/negotiatePartSize.js +27 -0
  59. package/dist/src/transfer/patternTransfer.d.ts +12 -0
  60. package/dist/src/transfer/patternTransfer.d.ts.map +1 -0
  61. package/dist/src/transfer/patternTransfer.js +61 -0
  62. package/dist/src/transfer/rangeReadableMultipartReader.d.ts +8 -0
  63. package/dist/src/transfer/rangeReadableMultipartReader.d.ts.map +1 -0
  64. package/dist/src/transfer/rangeReadableMultipartReader.js +19 -0
  65. package/dist/src/transfer/recursiveTransfer.d.ts +13 -0
  66. package/dist/src/transfer/recursiveTransfer.d.ts.map +1 -0
  67. package/dist/src/transfer/recursiveTransfer.js +112 -0
  68. package/dist/src/transfer/streamTransfer.d.ts +32 -0
  69. package/dist/src/transfer/streamTransfer.d.ts.map +1 -0
  70. package/dist/src/transfer/streamTransfer.js +186 -0
  71. package/dist/src/transfer/transferEntry.d.ts +25 -0
  72. package/dist/src/transfer/transferEntry.d.ts.map +1 -0
  73. package/dist/src/transfer/transferEntry.js +136 -0
  74. package/dist/src/util/abort.d.ts +12 -0
  75. package/dist/src/util/abort.d.ts.map +1 -0
  76. package/dist/src/util/abort.js +39 -0
  77. package/dist/src/util/applyPayloadConverter.d.ts +9 -0
  78. package/dist/src/util/applyPayloadConverter.d.ts.map +1 -0
  79. package/dist/src/util/applyPayloadConverter.js +26 -0
  80. package/dist/src/util/describePath.d.ts +6 -0
  81. package/dist/src/util/describePath.d.ts.map +1 -0
  82. package/dist/src/util/describePath.js +9 -0
  83. package/dist/src/util/globToRegex.d.ts +8 -0
  84. package/dist/src/util/globToRegex.d.ts.map +1 -0
  85. package/dist/src/util/globToRegex.js +35 -0
  86. package/dist/src/util/itemLength.d.ts +4 -0
  87. package/dist/src/util/itemLength.d.ts.map +1 -0
  88. package/dist/src/util/itemLength.js +5 -0
  89. package/dist/src/util/keys.d.ts +8 -0
  90. package/dist/src/util/keys.d.ts.map +1 -0
  91. package/dist/src/util/keys.js +19 -0
  92. package/dist/src/util/withParentOperationId.d.ts +4 -0
  93. package/dist/src/util/withParentOperationId.d.ts.map +1 -0
  94. package/dist/src/util/withParentOperationId.js +12 -0
  95. package/index.ts +11 -4
  96. package/package.json +6 -5
  97. package/src/concurrency/AsyncChannel.ts +52 -0
  98. package/src/concurrency/ConcurrencyLimiter.ts +72 -0
  99. package/src/concurrency/mapAsyncIterableConcurrently.ts +66 -0
  100. package/src/decorators/locallyCached.ts +30 -22
  101. package/src/decorators/seekable.ts +7 -7
  102. package/src/registry/ProviderRegistry.ts +241 -0
  103. package/src/registry/detectProtocol.ts +16 -0
  104. package/src/registry/negotiateTransfer.ts +121 -0
  105. package/src/retry/RetryOptions.ts +26 -0
  106. package/src/{withRetry.ts → retry/withRetry.ts} +2 -12
  107. package/src/transfer/EntryContext.ts +17 -0
  108. package/src/transfer/TransferOptions.ts +45 -0
  109. package/src/transfer/TransferResult.ts +8 -0
  110. package/src/transfer/aggregateResults.ts +15 -0
  111. package/src/transfer/copyMove.ts +113 -0
  112. package/src/transfer/leaseTransfer.ts +93 -0
  113. package/src/transfer/multipartTransfer.ts +119 -0
  114. package/src/transfer/negotiatePartSize.ts +40 -0
  115. package/src/transfer/patternTransfer.ts +84 -0
  116. package/src/transfer/rangeReadableMultipartReader.ts +30 -0
  117. package/src/transfer/recursiveTransfer.ts +147 -0
  118. package/src/transfer/streamTransfer.ts +214 -0
  119. package/src/transfer/transferEntry.ts +185 -0
  120. package/src/util/abort.ts +42 -0
  121. package/src/util/applyPayloadConverter.ts +37 -0
  122. package/src/util/describePath.ts +12 -0
  123. package/src/util/globToRegex.ts +32 -0
  124. package/src/util/itemLength.ts +6 -0
  125. package/src/util/keys.ts +21 -0
  126. package/src/util/withParentOperationId.ts +17 -0
  127. package/dist/src/ConcurrencyLimiter.d.ts.map +0 -1
  128. package/dist/src/ConcurrencyLimiter.js +0 -161
  129. package/dist/src/ProviderRegistry.d.ts +0 -14
  130. package/dist/src/ProviderRegistry.d.ts.map +0 -1
  131. package/dist/src/ProviderRegistry.js +0 -22
  132. package/dist/src/chunkLength.d.ts +0 -3
  133. package/dist/src/chunkLength.d.ts.map +0 -1
  134. package/dist/src/chunkLength.js +0 -4
  135. package/dist/src/copyMove.d.ts +0 -46
  136. package/dist/src/copyMove.d.ts.map +0 -1
  137. package/dist/src/copyMove.js +0 -280
  138. package/dist/src/withRetry.d.ts.map +0 -1
  139. package/src/ConcurrencyLimiter.ts +0 -178
  140. package/src/ProviderRegistry.ts +0 -32
  141. package/src/chunkLength.ts +0 -5
  142. 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,SAAS,EAET,aAAa,EACb,QAAQ,EACR,YAAY,EACb,MAAM,0CAA0C,CAAC;AAElD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,SAAS,EAC1C,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,GACzC,YAAY,CAAC,CAAC,CAAC,GAAG,QAAQ,CAiC5B"}
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 {@link RangeReadable} (arbitrary
3
- * byte-range reads) with a {@link Seekable} capability: a single logical
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
- export interface RetryOptions {
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
- function defaultBackoffMs(attempt) {
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 new Promise((resolve) => setTimeout(resolve, backoffMs(attempt)));
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"}