@strapi/data-transfer 5.0.0-rc.2 → 5.0.0-rc.21

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/dist/index.js CHANGED
@@ -2578,6 +2578,17 @@ const connectToWebsocket = (address, options) => {
2578
2578
  const trimTrailingSlash = (input) => {
2579
2579
  return input.replace(/\/$/, "");
2580
2580
  };
2581
+ const wait = (ms) => {
2582
+ return new Promise((resolve) => {
2583
+ setTimeout(resolve, ms);
2584
+ });
2585
+ };
2586
+ const waitUntil = async (test, interval) => {
2587
+ while (!test()) {
2588
+ await wait(interval);
2589
+ }
2590
+ return Promise.resolve();
2591
+ };
2581
2592
  const TRANSFER_PATH = "/transfer/runner";
2582
2593
  const TRANSFER_METHODS = ["push", "pull"];
2583
2594
  const constants = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -2903,32 +2914,105 @@ class RemoteStrapiSourceProvider {
2903
2914
  });
2904
2915
  };
2905
2916
  async createAssetsReadStream() {
2906
- const assets = {};
2907
2917
  const stream2 = await this.#createStageReadStream("assets");
2908
2918
  const pass = new stream$1.PassThrough({ objectMode: true });
2919
+ const assets = {};
2909
2920
  stream2.on("data", async (payload) => {
2910
2921
  for (const item of payload) {
2911
- const { action } = item;
2922
+ const { action, assetID } = item;
2912
2923
  if (action === "start") {
2913
- assets[item.assetID] = { ...item.data, stream: new stream$1.PassThrough() };
2914
- await this.writeAsync(pass, assets[item.assetID]);
2924
+ if (assets[assetID]) {
2925
+ continue;
2926
+ }
2927
+ assets[assetID] = {
2928
+ ...item.data,
2929
+ stream: new stream$1.PassThrough(),
2930
+ status: "idle",
2931
+ queue: []
2932
+ };
2933
+ await this.writeAsync(pass, assets[assetID]);
2915
2934
  } else if (action === "stream") {
2916
- const rawBuffer = item.data;
2917
- const chunk = Buffer.from(rawBuffer.data);
2918
- await this.writeAsync(assets[item.assetID].stream, chunk);
2935
+ if (!assets[assetID]) {
2936
+ continue;
2937
+ }
2938
+ switch (assets[assetID].status) {
2939
+ case "idle":
2940
+ await writeAssetChunk(assetID, item.data);
2941
+ break;
2942
+ case "busy":
2943
+ assets[assetID].queue.push(item);
2944
+ break;
2945
+ }
2919
2946
  } else if (action === "end") {
2920
- await new Promise((resolve, reject2) => {
2921
- const { stream: assetStream } = assets[item.assetID];
2922
- assetStream.on("close", () => {
2923
- delete assets[item.assetID];
2924
- resolve();
2925
- }).on("error", reject2).end();
2926
- });
2947
+ if (!assets[assetID]) {
2948
+ continue;
2949
+ }
2950
+ switch (assets[assetID].status) {
2951
+ case "idle":
2952
+ case "errored":
2953
+ await closeAssetStream(assetID);
2954
+ break;
2955
+ case "busy":
2956
+ await Promise.race([
2957
+ // Either: wait for the asset to be ready to be closed
2958
+ waitUntil(() => assets[assetID].status !== "busy", 100),
2959
+ // Or: if the last chunks are still not processed after ten seconds
2960
+ wait(1e4)
2961
+ ]);
2962
+ await closeAssetStream(assetID);
2963
+ break;
2964
+ }
2927
2965
  }
2928
2966
  }
2929
2967
  }).on("close", () => {
2930
2968
  pass.end();
2931
2969
  });
2970
+ const writeAssetChunk = async (id, data) => {
2971
+ if (!assets[id]) {
2972
+ throw new Error(`Failed to write asset chunk for "${id}". Asset not found.`);
2973
+ }
2974
+ const { status: currentStatus } = assets[id];
2975
+ if (currentStatus !== "idle") {
2976
+ throw new Error(
2977
+ `Failed to write asset chunk for "${id}". The asset is currently "${currentStatus}"`
2978
+ );
2979
+ }
2980
+ const nextItemInQueue = () => assets[id].queue.shift();
2981
+ try {
2982
+ assets[id].status = "busy";
2983
+ await unsafe_writeAssetChunk(id, data);
2984
+ let item = nextItemInQueue();
2985
+ while (item) {
2986
+ await unsafe_writeAssetChunk(id, item.data);
2987
+ item = nextItemInQueue();
2988
+ }
2989
+ assets[id].status = "idle";
2990
+ } catch {
2991
+ assets[id].status = "errored";
2992
+ }
2993
+ };
2994
+ const unsafe_writeAssetChunk = async (id, data) => {
2995
+ const asset = assets[id];
2996
+ if (!asset) {
2997
+ throw new Error(`Failed to write asset chunk for "${id}". Asset not found.`);
2998
+ }
2999
+ const rawBuffer = data;
3000
+ const chunk = Buffer.from(rawBuffer.data);
3001
+ await this.writeAsync(asset.stream, chunk);
3002
+ };
3003
+ const closeAssetStream = async (id) => {
3004
+ if (!assets[id]) {
3005
+ throw new Error(`Failed to close asset "${id}". Asset not found.`);
3006
+ }
3007
+ assets[id].status = "closed";
3008
+ await new Promise((resolve, reject2) => {
3009
+ const { stream: stream22 } = assets[id];
3010
+ stream22.on("close", () => {
3011
+ delete assets[id];
3012
+ resolve();
3013
+ }).on("error", reject2).end();
3014
+ });
3015
+ };
2932
3016
  return pass;
2933
3017
  }
2934
3018
  createConfigurationReadStream() {