@strapi/data-transfer 4.25.10 → 4.25.12

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