@ethersphere/bee-js 11.0.0 → 11.1.1

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.
@@ -17,6 +17,10 @@ async function streamDirectory(_bee, _dir, _postageBatchId, _onUploadProgress, _
17
17
  throw new Error('Streaming directories is not supported in browsers!');
18
18
  }
19
19
  async function streamFiles(bee, files, postageBatchId, onUploadProgress, options, requestOptions) {
20
+ const signal = requestOptions?.signal;
21
+ if (signal?.aborted) {
22
+ throw new Error('Request aborted');
23
+ }
20
24
  const queue = new cafe_utility_1.AsyncQueue(64, 64);
21
25
  let total = 0;
22
26
  let processed = 0;
@@ -26,12 +30,26 @@ async function streamFiles(bee, files, postageBatchId, onUploadProgress, options
26
30
  postageBatchId = new typed_bytes_1.BatchId(postageBatchId);
27
31
  async function onChunk(chunk) {
28
32
  await queue.enqueue(async () => {
29
- await bee.uploadChunk(postageBatchId, chunk.build(), options, requestOptions);
30
- onUploadProgress?.({ total, processed: ++processed });
33
+ if (signal?.aborted) {
34
+ return;
35
+ }
36
+ try {
37
+ await bee.uploadChunk(postageBatchId, chunk.build(), options, requestOptions);
38
+ onUploadProgress?.({ total, processed: ++processed });
39
+ }
40
+ catch (err) {
41
+ if (signal?.aborted) {
42
+ return;
43
+ }
44
+ throw err;
45
+ }
31
46
  });
32
47
  }
33
48
  const mantaray = new manifest_1.MantarayNode();
34
49
  for (const file of files) {
50
+ if (signal?.aborted) {
51
+ throw new Error('Request aborted');
52
+ }
35
53
  const rootChunk = await new Promise((resolve, reject) => {
36
54
  const tree = new cafe_utility_1.MerkleTree(onChunk);
37
55
  let offset = 0;
@@ -40,6 +58,10 @@ async function streamFiles(bee, files, postageBatchId, onUploadProgress, options
40
58
  reject(reader.error);
41
59
  };
42
60
  const readNextChunk = async () => {
61
+ if (signal?.aborted) {
62
+ reject(new Error('Request aborted'));
63
+ return;
64
+ }
43
65
  if (offset >= file.size) {
44
66
  const rootChunk = await tree.finalize();
45
67
  resolve(rootChunk);
@@ -74,6 +96,9 @@ async function streamFiles(bee, files, postageBatchId, onUploadProgress, options
74
96
  });
75
97
  }
76
98
  }
99
+ if (signal?.aborted) {
100
+ throw new Error('Request aborted');
101
+ }
77
102
  return mantaray.saveRecursively(bee, postageBatchId, options, requestOptions);
78
103
  }
79
104
  function maybeEnrichMime(mime) {
@@ -15,6 +15,7 @@ const MAX_FAILED_ATTEMPTS = 100000;
15
15
  const DELAY_FAST = 200;
16
16
  const DELAY_SLOW = 1000;
17
17
  const DELAY_THRESHOLD = cafe_utility_1.Dates.minutes(1) / DELAY_FAST;
18
+ const ABORT_ERROR_MESSAGE = 'Request aborted';
18
19
  exports.DEFAULT_HTTP_CONFIG = {
19
20
  headers: {
20
21
  accept: 'application/json, text/plain, */*',
@@ -22,6 +23,11 @@ exports.DEFAULT_HTTP_CONFIG = {
22
23
  maxBodyLength: Infinity,
23
24
  maxContentLength: Infinity,
24
25
  };
26
+ function throwIfAborted(signal, config, responseData, responseStatus) {
27
+ if (signal?.aborted) {
28
+ throw new index_1.BeeResponseError(config.method || 'get', config.url || '<unknown>', ABORT_ERROR_MESSAGE, responseData, responseStatus, 'ERR_CANCELED');
29
+ }
30
+ }
25
31
  /**
26
32
  * Main function to make HTTP requests.
27
33
  * @param options User defined settings
@@ -29,9 +35,11 @@ exports.DEFAULT_HTTP_CONFIG = {
29
35
  */
30
36
  async function http(options, config) {
31
37
  const requestConfig = cafe_utility_1.Objects.deepMerge3(exports.DEFAULT_HTTP_CONFIG, config, options);
32
- if (requestConfig.data && typeof Buffer !== 'undefined' && Buffer.isBuffer(requestConfig.data)) {
33
- requestConfig.data = requestConfig.data.buffer.slice(requestConfig.data.byteOffset, requestConfig.data.byteOffset + requestConfig.data.byteLength);
38
+ if (options.signal) {
39
+ requestConfig.signal = options.signal;
40
+ throwIfAborted(options.signal, config);
34
41
  }
42
+ maybeReplaceBodyBuffers(requestConfig);
35
43
  if (requestConfig.params) {
36
44
  const keys = Object.keys(requestConfig.params);
37
45
  for (const key of keys) {
@@ -43,6 +51,7 @@ async function http(options, config) {
43
51
  }
44
52
  let failedAttempts = 0;
45
53
  while (failedAttempts < MAX_FAILED_ATTEMPTS) {
54
+ throwIfAborted(options.signal, config);
46
55
  try {
47
56
  debug(`${requestConfig.method || 'get'} ${cafe_utility_1.Strings.joinUrl([
48
57
  requestConfig.baseURL,
@@ -54,12 +63,15 @@ async function http(options, config) {
54
63
  }
55
64
  catch (e) {
56
65
  if (e instanceof AxiosError) {
66
+ if (e.code === 'ERR_CANCELED') {
67
+ throwIfAborted({ aborted: true }, config, e.response?.data, e.response?.status);
68
+ }
57
69
  if (e.code === 'ECONNABORTED' && options.endlesslyRetry) {
58
70
  failedAttempts++;
59
71
  await cafe_utility_1.System.sleepMillis(failedAttempts < DELAY_THRESHOLD ? DELAY_FAST : DELAY_SLOW);
60
72
  }
61
73
  else {
62
- throw new index_1.BeeResponseError(config.method || 'get', config.url || '<unknown>', e.message, e.response?.data, e.response?.status, e.code);
74
+ throw new index_1.BeeResponseError(config.method || 'get', config.url || '<unknown>', e.message, e.response?.data, e.response?.status, e.response?.statusText);
63
75
  }
64
76
  }
65
77
  else {
@@ -79,3 +91,11 @@ function maybeRunOnRequestHook(options, requestConfig) {
79
91
  });
80
92
  }
81
93
  }
94
+ function maybeReplaceBodyBuffers(config) {
95
+ if (config.data && config.data instanceof Uint8Array) {
96
+ config.data = config.data.buffer.slice(config.data.byteOffset, config.data.byteOffset + config.data.byteLength);
97
+ }
98
+ if (config.data && typeof Buffer !== 'undefined' && Buffer.isBuffer(config.data)) {
99
+ config.data = config.data.buffer.slice(config.data.byteOffset, config.data.byteOffset + config.data.byteLength);
100
+ }
101
+ }
@@ -74,6 +74,7 @@ function prepareBeeRequestOptions(value) {
74
74
  httpAgent: object.httpAgent,
75
75
  httpsAgent: object.httpsAgent,
76
76
  endlesslyRetry: cafe_utility_1.Types.asOptional(x => cafe_utility_1.Types.asBoolean(x, { name: 'endlesslyRetry' }), object.endlesslyRetry),
77
+ signal: object.signal,
77
78
  };
78
79
  }
79
80
  function prepareDownloadOptions(value) {