@strapi/data-transfer 4.25.17 → 4.25.19

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 (40) hide show
  1. package/dist/commands/data-transfer.d.ts +1 -1
  2. package/dist/commands/data-transfer.d.ts.map +1 -1
  3. package/dist/commands/export/action.d.ts +1 -0
  4. package/dist/commands/export/action.d.ts.map +1 -1
  5. package/dist/commands/export/command.d.ts.map +1 -1
  6. package/dist/commands/import/action.d.ts +1 -0
  7. package/dist/commands/import/action.d.ts.map +1 -1
  8. package/dist/commands/import/command.d.ts.map +1 -1
  9. package/dist/commands/transfer/action.d.ts +1 -0
  10. package/dist/commands/transfer/action.d.ts.map +1 -1
  11. package/dist/commands/transfer/command.d.ts.map +1 -1
  12. package/dist/engine/index.d.ts +1 -1
  13. package/dist/engine/index.d.ts.map +1 -1
  14. package/dist/errors/constants.d.ts +1 -1
  15. package/dist/errors/constants.d.ts.map +1 -1
  16. package/dist/file/providers/destination/index.d.ts +2 -1
  17. package/dist/file/providers/destination/index.d.ts.map +1 -1
  18. package/dist/file/providers/source/index.d.ts.map +1 -1
  19. package/dist/index.js +272 -39
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +273 -40
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/strapi/providers/local-destination/index.d.ts +2 -1
  24. package/dist/strapi/providers/local-destination/index.d.ts.map +1 -1
  25. package/dist/strapi/providers/local-source/index.d.ts +3 -1
  26. package/dist/strapi/providers/local-source/index.d.ts.map +1 -1
  27. package/dist/strapi/providers/remote-destination/index.d.ts +2 -1
  28. package/dist/strapi/providers/remote-destination/index.d.ts.map +1 -1
  29. package/dist/strapi/providers/remote-source/index.d.ts.map +1 -1
  30. package/dist/strapi/providers/utils.d.ts +3 -2
  31. package/dist/strapi/providers/utils.d.ts.map +1 -1
  32. package/dist/strapi/remote/handlers/abstract.d.ts +4 -0
  33. package/dist/strapi/remote/handlers/abstract.d.ts.map +1 -1
  34. package/dist/strapi/remote/handlers/pull.d.ts.map +1 -1
  35. package/dist/strapi/remote/handlers/push.d.ts.map +1 -1
  36. package/dist/strapi/remote/handlers/utils.d.ts.map +1 -1
  37. package/dist/{engine → utils}/diagnostic.d.ts +1 -0
  38. package/dist/utils/diagnostic.d.ts.map +1 -0
  39. package/package.json +6 -6
  40. package/dist/engine/diagnostic.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -612,7 +612,7 @@ class TransferEngine {
612
612
  reportInfo(message, params) {
613
613
  this.diagnostics.report({
614
614
  kind: "info",
615
- details: { createdAt: /* @__PURE__ */ new Date(), message, params }
615
+ details: { createdAt: /* @__PURE__ */ new Date(), message, params, origin: "engine" }
616
616
  });
617
617
  }
618
618
  /**
@@ -904,8 +904,8 @@ ${formattedDiffs}`,
904
904
  */
905
905
  async bootstrap() {
906
906
  const results = await Promise.allSettled([
907
- this.sourceProvider.bootstrap?.(),
908
- this.destinationProvider.bootstrap?.()
907
+ this.sourceProvider.bootstrap?.(this.diagnostics),
908
+ this.destinationProvider.bootstrap?.(this.diagnostics)
909
909
  ]);
910
910
  results.forEach((result) => {
911
911
  if (result.status === "rejected") {
@@ -1896,6 +1896,7 @@ class LocalStrapiDestinationProvider {
1896
1896
  transaction;
1897
1897
  uploadsBackupDirectoryName;
1898
1898
  onWarning;
1899
+ #diagnostics;
1899
1900
  /**
1900
1901
  * The entities mapper is used to map old entities to their new IDs
1901
1902
  */
@@ -1905,7 +1906,8 @@ class LocalStrapiDestinationProvider {
1905
1906
  this.#entitiesMapper = {};
1906
1907
  this.uploadsBackupDirectoryName = `uploads_backup_${Date.now()}`;
1907
1908
  }
1908
- async bootstrap() {
1909
+ async bootstrap(diagnostics) {
1910
+ this.#diagnostics = diagnostics;
1909
1911
  this.#validateOptions();
1910
1912
  this.strapi = await this.options.getStrapi();
1911
1913
  if (!this.strapi) {
@@ -1922,6 +1924,16 @@ class LocalStrapiDestinationProvider {
1922
1924
  const excluded = this.options.restore?.entities?.exclude && this.options.restore?.entities.exclude.includes(type);
1923
1925
  return !excluded && !notIncluded;
1924
1926
  };
1927
+ #reportInfo(message) {
1928
+ this.#diagnostics?.report({
1929
+ details: {
1930
+ createdAt: /* @__PURE__ */ new Date(),
1931
+ message,
1932
+ origin: "local-destination-provider"
1933
+ },
1934
+ kind: "info"
1935
+ });
1936
+ }
1925
1937
  async close() {
1926
1938
  const { autoDestroy } = this.options;
1927
1939
  this.transaction?.end();
@@ -1930,6 +1942,7 @@ class LocalStrapiDestinationProvider {
1930
1942
  }
1931
1943
  }
1932
1944
  #validateOptions() {
1945
+ this.#reportInfo("validating options");
1933
1946
  if (!VALID_CONFLICT_STRATEGIES.includes(this.options.strategy)) {
1934
1947
  throw new ProviderValidationError(`Invalid strategy ${this.options.strategy}`, {
1935
1948
  check: "strategy",
@@ -1946,10 +1959,12 @@ class LocalStrapiDestinationProvider {
1946
1959
  if (!this.options.restore) {
1947
1960
  throw new ProviderValidationError("Missing restore options");
1948
1961
  }
1962
+ this.#reportInfo("deleting record");
1949
1963
  return deleteRecords(this.strapi, this.options.restore);
1950
1964
  }
1951
1965
  async #deleteAllAssets(trx) {
1952
1966
  assertValidStrapi(this.strapi);
1967
+ this.#reportInfo("deleting all assets");
1953
1968
  if (!this.#areAssetsIncluded()) {
1954
1969
  return;
1955
1970
  }
@@ -1962,9 +1977,12 @@ class LocalStrapiDestinationProvider {
1962
1977
  }
1963
1978
  }
1964
1979
  }
1980
+ this.#reportInfo("deleted all assets");
1965
1981
  }
1966
1982
  async rollback() {
1983
+ this.#reportInfo("Rolling back transaction");
1967
1984
  await this.transaction?.rollback();
1985
+ this.#reportInfo("Rolled back transaction");
1968
1986
  }
1969
1987
  async beforeTransfer() {
1970
1988
  if (!this.strapi) {
@@ -1983,6 +2001,7 @@ class LocalStrapiDestinationProvider {
1983
2001
  });
1984
2002
  }
1985
2003
  getMetadata() {
2004
+ this.#reportInfo("getting metadata");
1986
2005
  assertValidStrapi(this.strapi, "Not able to get Schemas");
1987
2006
  const strapiVersion = this.strapi.config.get("info.strapi");
1988
2007
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -1994,6 +2013,7 @@ class LocalStrapiDestinationProvider {
1994
2013
  };
1995
2014
  }
1996
2015
  getSchemas() {
2016
+ this.#reportInfo("getting schema");
1997
2017
  assertValidStrapi(this.strapi, "Not able to get Schemas");
1998
2018
  const schemas = {
1999
2019
  ...this.strapi.contentTypes,
@@ -2003,6 +2023,7 @@ class LocalStrapiDestinationProvider {
2003
2023
  }
2004
2024
  createEntitiesWriteStream() {
2005
2025
  assertValidStrapi(this.strapi, "Not able to import entities");
2026
+ this.#reportInfo("creating entities stream");
2006
2027
  const { strategy } = this.options;
2007
2028
  const updateMappingTable = (type, oldID, newID) => {
2008
2029
  if (!this.#entitiesMapper[type]) {
@@ -2029,6 +2050,7 @@ class LocalStrapiDestinationProvider {
2029
2050
  return;
2030
2051
  }
2031
2052
  if (this.strapi.config.get("plugin.upload").provider === "local") {
2053
+ this.#reportInfo("creating assets backup directory");
2032
2054
  const assetsDirectory = path__default.default.join(this.strapi.dirs.static.public, "uploads");
2033
2055
  const backupDirectory = path__default.default.join(
2034
2056
  this.strapi.dirs.static.public,
@@ -2044,6 +2066,7 @@ class LocalStrapiDestinationProvider {
2044
2066
  await fse__namespace.move(assetsDirectory, backupDirectory);
2045
2067
  await fse__namespace.mkdir(assetsDirectory);
2046
2068
  await fse__namespace.outputFile(path__default.default.join(assetsDirectory, ".gitkeep"), "");
2069
+ this.#reportInfo(`created assets backup directory ${backupDirectory}`);
2047
2070
  } catch (err) {
2048
2071
  throw new ProviderTransferError(
2049
2072
  "The backup folder for the assets could not be created inside the public folder. Please ensure Strapi has write permissions on the public directory",
@@ -2061,17 +2084,20 @@ class LocalStrapiDestinationProvider {
2061
2084
  return;
2062
2085
  }
2063
2086
  if (this.strapi.config.get("plugin.upload").provider === "local") {
2087
+ this.#reportInfo("removing assets backup");
2064
2088
  assertValidStrapi(this.strapi);
2065
2089
  const backupDirectory = path__default.default.join(
2066
2090
  this.strapi.dirs.static.public,
2067
2091
  this.uploadsBackupDirectoryName
2068
2092
  );
2069
2093
  await fse__namespace.rm(backupDirectory, { recursive: true, force: true });
2094
+ this.#reportInfo("successfully removed assets backup");
2070
2095
  }
2071
2096
  }
2072
2097
  // TODO: Move this logic to the restore strategy
2073
2098
  async createAssetsWriteStream() {
2074
2099
  assertValidStrapi(this.strapi, "Not able to stream Assets");
2100
+ this.#reportInfo("creating assets write stream");
2075
2101
  if (!this.#areAssetsIncluded()) {
2076
2102
  throw new ProviderTransferError(
2077
2103
  "Attempting to transfer assets when `assets` is not set in restore options"
@@ -2166,6 +2192,7 @@ class LocalStrapiDestinationProvider {
2166
2192
  }
2167
2193
  async createConfigurationWriteStream() {
2168
2194
  assertValidStrapi(this.strapi, "Not able to stream Configurations");
2195
+ this.#reportInfo("creating configuration write stream");
2169
2196
  const { strategy } = this.options;
2170
2197
  if (strategy === "restore") {
2171
2198
  return createConfigurationWriteStream(this.strapi, this.transaction);
@@ -2177,6 +2204,7 @@ class LocalStrapiDestinationProvider {
2177
2204
  });
2178
2205
  }
2179
2206
  async createLinksWriteStream() {
2207
+ this.#reportInfo("creating links write stream");
2180
2208
  if (!this.strapi) {
2181
2209
  throw new Error("Not able to stream links. Strapi instance not found");
2182
2210
  }
@@ -2377,12 +2405,24 @@ class LocalStrapiSourceProvider {
2377
2405
  type = "source";
2378
2406
  options;
2379
2407
  strapi;
2408
+ #diagnostics;
2380
2409
  constructor(options) {
2381
2410
  this.options = options;
2382
2411
  }
2383
- async bootstrap() {
2412
+ async bootstrap(diagnostics) {
2413
+ this.#diagnostics = diagnostics;
2384
2414
  this.strapi = await this.options.getStrapi();
2385
2415
  }
2416
+ #reportInfo(message) {
2417
+ this.#diagnostics?.report({
2418
+ details: {
2419
+ createdAt: /* @__PURE__ */ new Date(),
2420
+ message,
2421
+ origin: "local-source-provider"
2422
+ },
2423
+ kind: "info"
2424
+ });
2425
+ }
2386
2426
  async close() {
2387
2427
  const { autoDestroy } = this.options;
2388
2428
  if (autoDestroy === void 0 || autoDestroy === true) {
@@ -2390,6 +2430,7 @@ class LocalStrapiSourceProvider {
2390
2430
  }
2391
2431
  }
2392
2432
  getMetadata() {
2433
+ this.#reportInfo("getting metadata");
2393
2434
  const strapiVersion = strapi.config.get("info.strapi");
2394
2435
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
2395
2436
  return {
@@ -2401,6 +2442,7 @@ class LocalStrapiSourceProvider {
2401
2442
  }
2402
2443
  async createEntitiesReadStream() {
2403
2444
  assertValidStrapi(this.strapi, "Not able to stream entities");
2445
+ this.#reportInfo("creating entities read stream");
2404
2446
  return streamChain.chain([
2405
2447
  // Entities stream
2406
2448
  createEntitiesStream(this.strapi),
@@ -2410,14 +2452,17 @@ class LocalStrapiSourceProvider {
2410
2452
  }
2411
2453
  createLinksReadStream() {
2412
2454
  assertValidStrapi(this.strapi, "Not able to stream links");
2455
+ this.#reportInfo("creating links read stream");
2413
2456
  return createLinksStream(this.strapi);
2414
2457
  }
2415
2458
  createConfigurationReadStream() {
2416
2459
  assertValidStrapi(this.strapi, "Not able to stream configuration");
2460
+ this.#reportInfo("creating configuration read stream");
2417
2461
  return createConfigurationStream(this.strapi);
2418
2462
  }
2419
2463
  getSchemas() {
2420
2464
  assertValidStrapi(this.strapi, "Not able to get Schemas");
2465
+ this.#reportInfo("getting schemas");
2421
2466
  const schemas = {
2422
2467
  ...this.strapi.contentTypes,
2423
2468
  ...this.strapi.components
@@ -2429,13 +2474,14 @@ class LocalStrapiSourceProvider {
2429
2474
  }
2430
2475
  createAssetsReadStream() {
2431
2476
  assertValidStrapi(this.strapi, "Not able to stream assets");
2477
+ this.#reportInfo("creating assets read stream");
2432
2478
  return createAssetsStream(this.strapi);
2433
2479
  }
2434
2480
  }
2435
2481
  const createDispatcher = (ws2, retryMessageOptions = {
2436
2482
  retryMessageMaxRetries: 5,
2437
2483
  retryMessageTimeout: 3e4
2438
- }) => {
2484
+ }, reportInfo) => {
2439
2485
  const state = {};
2440
2486
  const dispatch = async (message, options = {}) => {
2441
2487
  if (!ws2) {
@@ -2448,6 +2494,16 @@ const createDispatcher = (ws2, retryMessageOptions = {
2448
2494
  if (options.attachTransfer) {
2449
2495
  Object.assign(payload, { transferID: state.transfer?.id });
2450
2496
  }
2497
+ if (message.type === "command") {
2498
+ reportInfo?.(
2499
+ `dispatching message command:${message.command} uuid:${uuid} sent:${numberOfTimesMessageWasSent}`
2500
+ );
2501
+ } else if (message.type === "transfer") {
2502
+ const messageToSend = message;
2503
+ reportInfo?.(
2504
+ `dispatching message action:${messageToSend.action} ${messageToSend.kind === "step" ? `step:${messageToSend.step}` : ""} uuid:${uuid} sent:${numberOfTimesMessageWasSent}`
2505
+ );
2506
+ }
2451
2507
  const stringifiedPayload = JSON.stringify(payload);
2452
2508
  ws2.send(stringifiedPayload, (error) => {
2453
2509
  if (error) {
@@ -2470,6 +2526,16 @@ const createDispatcher = (ws2, retryMessageOptions = {
2470
2526
  const interval = setInterval(sendPeriodically, retryMessageTimeout);
2471
2527
  const onResponse = (raw) => {
2472
2528
  const response = JSON.parse(raw.toString());
2529
+ if (message.type === "command") {
2530
+ reportInfo?.(
2531
+ `received response to message command: ${message.command} uuid: ${uuid} sent: ${numberOfTimesMessageWasSent}`
2532
+ );
2533
+ } else if (message.type === "transfer") {
2534
+ const messageToSend = message;
2535
+ reportInfo?.(
2536
+ `received response to message action:${messageToSend.action} ${messageToSend.kind === "step" ? `step:${messageToSend.step}` : ""} uuid:${uuid} sent:${numberOfTimesMessageWasSent}`
2537
+ );
2538
+ }
2473
2539
  if (response.uuid === uuid) {
2474
2540
  clearInterval(interval);
2475
2541
  if (response.error) {
@@ -2526,7 +2592,7 @@ const createDispatcher = (ws2, retryMessageOptions = {
2526
2592
  dispatchTransferStep
2527
2593
  };
2528
2594
  };
2529
- const connectToWebsocket = (address, options) => {
2595
+ const connectToWebsocket = (address, options, diagnostics) => {
2530
2596
  return new Promise((resolve, reject2) => {
2531
2597
  const server = new ws.WebSocket(address, options);
2532
2598
  server.once("open", () => {
@@ -2560,6 +2626,14 @@ const connectToWebsocket = (address, options) => {
2560
2626
  )
2561
2627
  );
2562
2628
  });
2629
+ server.on("message", (raw) => {
2630
+ const response = JSON.parse(raw.toString());
2631
+ if (response.diagnostic) {
2632
+ diagnostics?.report({
2633
+ ...response.diagnostic
2634
+ });
2635
+ }
2636
+ });
2563
2637
  server.once("error", (err) => {
2564
2638
  reject2(
2565
2639
  new ProviderTransferError(err.message, {
@@ -2600,6 +2674,7 @@ class RemoteStrapiDestinationProvider {
2600
2674
  ws;
2601
2675
  dispatcher;
2602
2676
  transferID;
2677
+ #diagnostics;
2603
2678
  constructor(options) {
2604
2679
  this.options = options;
2605
2680
  this.ws = null;
@@ -2698,7 +2773,18 @@ class RemoteStrapiDestinationProvider {
2698
2773
  }
2699
2774
  });
2700
2775
  }
2701
- async bootstrap() {
2776
+ #reportInfo(message) {
2777
+ this.#diagnostics?.report({
2778
+ details: {
2779
+ createdAt: /* @__PURE__ */ new Date(),
2780
+ message,
2781
+ origin: "remote-destination-provider"
2782
+ },
2783
+ kind: "info"
2784
+ });
2785
+ }
2786
+ async bootstrap(diagnostics) {
2787
+ this.#diagnostics = diagnostics;
2702
2788
  const { url, auth } = this.options;
2703
2789
  const validProtocols = ["https:", "http:"];
2704
2790
  let ws2;
@@ -2715,6 +2801,7 @@ class RemoteStrapiDestinationProvider {
2715
2801
  const wsUrl = `${wsProtocol}//${url.host}${trimTrailingSlash(
2716
2802
  url.pathname
2717
2803
  )}${TRANSFER_PATH}/push`;
2804
+ this.#reportInfo("establishing websocket connection");
2718
2805
  if (!auth) {
2719
2806
  ws2 = await connectToWebsocket(wsUrl);
2720
2807
  } else if (auth.type === "token") {
@@ -2728,10 +2815,19 @@ class RemoteStrapiDestinationProvider {
2728
2815
  }
2729
2816
  });
2730
2817
  }
2818
+ this.#reportInfo("established websocket connection");
2731
2819
  this.ws = ws2;
2732
2820
  const { retryMessageOptions } = this.options;
2733
- this.dispatcher = createDispatcher(this.ws, retryMessageOptions);
2821
+ this.#reportInfo("creating dispatcher");
2822
+ this.dispatcher = createDispatcher(
2823
+ this.ws,
2824
+ retryMessageOptions,
2825
+ (message) => this.#reportInfo(message)
2826
+ );
2827
+ this.#reportInfo("created dispatcher");
2828
+ this.#reportInfo("initialize transfer");
2734
2829
  this.transferID = await this.initTransfer();
2830
+ this.#reportInfo(`initialized transfer ${this.transferID}`);
2735
2831
  this.dispatcher.setTransferProperties({ id: this.transferID, kind: "push" });
2736
2832
  await this.dispatcher.dispatchTransferAction("bootstrap");
2737
2833
  }
@@ -2852,6 +2948,7 @@ class RemoteStrapiSourceProvider {
2852
2948
  options;
2853
2949
  ws;
2854
2950
  dispatcher;
2951
+ #diagnostics;
2855
2952
  constructor(options) {
2856
2953
  this.options = options;
2857
2954
  this.ws = null;
@@ -3040,6 +3137,16 @@ class RemoteStrapiSourceProvider {
3040
3137
  }
3041
3138
  return res.transferID;
3042
3139
  }
3140
+ #reportInfo(message) {
3141
+ this.#diagnostics?.report({
3142
+ details: {
3143
+ createdAt: /* @__PURE__ */ new Date(),
3144
+ message,
3145
+ origin: "remote-source-provider"
3146
+ },
3147
+ kind: "info"
3148
+ });
3149
+ }
3043
3150
  async bootstrap() {
3044
3151
  const { url, auth } = this.options;
3045
3152
  let ws2;
@@ -3048,6 +3155,7 @@ class RemoteStrapiSourceProvider {
3048
3155
  const wsUrl = `${wsProtocol}//${url.host}${trimTrailingSlash(
3049
3156
  url.pathname
3050
3157
  )}${TRANSFER_PATH}/pull`;
3158
+ this.#reportInfo("establishing websocket connection");
3051
3159
  if (!auth) {
3052
3160
  ws2 = await connectToWebsocket(wsUrl);
3053
3161
  } else if (auth.type === "token") {
@@ -3061,10 +3169,19 @@ class RemoteStrapiSourceProvider {
3061
3169
  }
3062
3170
  });
3063
3171
  }
3172
+ this.#reportInfo("established websocket connection");
3064
3173
  this.ws = ws2;
3065
3174
  const { retryMessageOptions } = this.options;
3066
- this.dispatcher = createDispatcher(this.ws, retryMessageOptions);
3175
+ this.#reportInfo("creating dispatcher");
3176
+ this.dispatcher = createDispatcher(
3177
+ this.ws,
3178
+ retryMessageOptions,
3179
+ (message) => this.#reportInfo(message)
3180
+ );
3181
+ this.#reportInfo("creating dispatcher");
3182
+ this.#reportInfo("initialize transfer");
3067
3183
  const transferID = await this.initTransfer();
3184
+ this.#reportInfo(`initialized transfer ${transferID}`);
3068
3185
  this.dispatcher.setTransferProperties({ id: transferID, kind: "pull" });
3069
3186
  await this.dispatcher.dispatchTransferAction("bootstrap");
3070
3187
  }
@@ -3296,6 +3413,7 @@ const handlerControllerFactory = (implementation) => (options) => {
3296
3413
  const cb = (ws2) => {
3297
3414
  const state = { id: void 0 };
3298
3415
  const messageUUIDs = /* @__PURE__ */ new Set();
3416
+ const diagnostics = createDiagnosticReporter();
3299
3417
  const cannotRespondHandler = (err) => {
3300
3418
  strapi?.log?.error(
3301
3419
  "[Data transfer] Cannot send error response to client, closing connection"
@@ -3329,6 +3447,9 @@ const handlerControllerFactory = (implementation) => (options) => {
3329
3447
  set response(response) {
3330
3448
  state.response = response;
3331
3449
  },
3450
+ get diagnostics() {
3451
+ return diagnostics;
3452
+ },
3332
3453
  addUUID(uuid) {
3333
3454
  messageUUIDs.add(uuid);
3334
3455
  },
@@ -3444,6 +3565,10 @@ const handlerControllerFactory = (implementation) => (options) => {
3444
3565
  onError() {
3445
3566
  },
3446
3567
  onClose() {
3568
+ },
3569
+ onInfo() {
3570
+ },
3571
+ onWarning() {
3447
3572
  }
3448
3573
  };
3449
3574
  const handler = Object.assign(Object.create(prototype), implementation(prototype));
@@ -3476,6 +3601,14 @@ const handlerControllerFactory = (implementation) => (options) => {
3476
3601
  cannotRespondHandler(err);
3477
3602
  }
3478
3603
  });
3604
+ diagnostics.onDiagnostic((diagnostic) => {
3605
+ const uuid = crypto.randomUUID();
3606
+ const payload = JSON.stringify({
3607
+ diagnostic,
3608
+ uuid
3609
+ });
3610
+ handler.send(payload);
3611
+ });
3479
3612
  };
3480
3613
  try {
3481
3614
  handleWSUpgrade(wss, ctx, cb);
@@ -3511,6 +3644,26 @@ const createPushController = handlerControllerFactory((proto) => ({
3511
3644
  verifyAuth() {
3512
3645
  return proto.verifyAuth.call(this, TRANSFER_KIND$1);
3513
3646
  },
3647
+ onInfo(message) {
3648
+ this.diagnostics?.report({
3649
+ details: {
3650
+ message,
3651
+ origin: "push-handler",
3652
+ createdAt: /* @__PURE__ */ new Date()
3653
+ },
3654
+ kind: "info"
3655
+ });
3656
+ },
3657
+ onWarning(message) {
3658
+ this.diagnostics?.report({
3659
+ details: {
3660
+ message,
3661
+ createdAt: /* @__PURE__ */ new Date(),
3662
+ origin: "push-handler"
3663
+ },
3664
+ kind: "warning"
3665
+ });
3666
+ },
3514
3667
  cleanup() {
3515
3668
  proto.cleanup.call(this);
3516
3669
  this.streams = {};
@@ -3587,6 +3740,7 @@ const createPushController = handlerControllerFactory((proto) => ({
3587
3740
  proto.addUUID(uuid);
3588
3741
  if (type === "command") {
3589
3742
  const { command: command2 } = msg;
3743
+ this.onInfo(`received command:${command2} uuid:${uuid}`);
3590
3744
  await this.executeAndRespond(uuid, () => {
3591
3745
  this.assertValidTransferCommand(command2);
3592
3746
  if (command2 === "status") {
@@ -3595,6 +3749,7 @@ const createPushController = handlerControllerFactory((proto) => ({
3595
3749
  return this[command2](msg.params);
3596
3750
  });
3597
3751
  } else if (type === "transfer") {
3752
+ this.onInfo(`received transfer action:${msg.action} step:${msg.kind} uuid:${uuid}`);
3598
3753
  await this.executeAndRespond(uuid, async () => {
3599
3754
  await this.verifyAuth();
3600
3755
  this.assertValidTransfer();
@@ -3689,6 +3844,9 @@ const createPushController = handlerControllerFactory((proto) => ({
3689
3844
  }
3690
3845
  this.flow?.set(step);
3691
3846
  }
3847
+ if (action2 === "bootstrap") {
3848
+ return this.provider?.[action2](this.diagnostics);
3849
+ }
3692
3850
  return this.provider?.[action2]();
3693
3851
  },
3694
3852
  async streamAsset(payload) {
@@ -3746,6 +3904,7 @@ const createPushController = handlerControllerFactory((proto) => ({
3746
3904
  getStrapi: () => strapi
3747
3905
  });
3748
3906
  this.provider.onWarning = (message) => {
3907
+ this.onWarning(message);
3749
3908
  strapi.log.warn(message);
3750
3909
  };
3751
3910
  return { transferID: this.transferID };
@@ -3786,6 +3945,26 @@ const createPullController = handlerControllerFactory((proto) => ({
3786
3945
  this.streams = {};
3787
3946
  delete this.provider;
3788
3947
  },
3948
+ onInfo(message) {
3949
+ this.diagnostics?.report({
3950
+ details: {
3951
+ message,
3952
+ origin: "pull-handler",
3953
+ createdAt: /* @__PURE__ */ new Date()
3954
+ },
3955
+ kind: "info"
3956
+ });
3957
+ },
3958
+ onWarning(message) {
3959
+ this.diagnostics?.report({
3960
+ details: {
3961
+ message,
3962
+ createdAt: /* @__PURE__ */ new Date(),
3963
+ origin: "pull-handler"
3964
+ },
3965
+ kind: "warning"
3966
+ });
3967
+ },
3789
3968
  assertValidTransferAction(action2) {
3790
3969
  const validActions = VALID_TRANSFER_ACTIONS;
3791
3970
  if (validActions.includes(action2)) {
@@ -3815,6 +3994,7 @@ const createPullController = handlerControllerFactory((proto) => ({
3815
3994
  proto.addUUID(uuid);
3816
3995
  if (type === "command") {
3817
3996
  const { command: command2 } = msg;
3997
+ this.onInfo(`received command:${command2} uuid:${uuid}`);
3818
3998
  await this.executeAndRespond(uuid, () => {
3819
3999
  this.assertValidTransferCommand(command2);
3820
4000
  if (command2 === "status") {
@@ -3823,6 +4003,7 @@ const createPullController = handlerControllerFactory((proto) => ({
3823
4003
  return this[command2](msg.params);
3824
4004
  });
3825
4005
  } else if (type === "transfer") {
4006
+ this.onInfo(`received transfer action:${msg.action} step:${msg.kind} uuid:${uuid}`);
3826
4007
  await this.executeAndRespond(uuid, async () => {
3827
4008
  await this.verifyAuth();
3828
4009
  this.assertValidTransfer();
@@ -3844,6 +4025,9 @@ const createPullController = handlerControllerFactory((proto) => ({
3844
4025
  async onTransferAction(msg) {
3845
4026
  const { action: action2 } = msg;
3846
4027
  this.assertValidTransferAction(action2);
4028
+ if (action2 === "bootstrap") {
4029
+ return this.provider?.[action2](this.diagnostics);
4030
+ }
3847
4031
  return this.provider?.[action2]();
3848
4032
  },
3849
4033
  async flush(stage, id) {
@@ -4042,6 +4226,7 @@ class LocalFileSourceProvider {
4042
4226
  name = "source::local-file";
4043
4227
  options;
4044
4228
  #metadata;
4229
+ #diagnostics;
4045
4230
  constructor(options) {
4046
4231
  this.options = options;
4047
4232
  const { encryption } = this.options;
@@ -4049,6 +4234,16 @@ class LocalFileSourceProvider {
4049
4234
  throw new Error("Missing encryption key");
4050
4235
  }
4051
4236
  }
4237
+ #reportInfo(message) {
4238
+ this.#diagnostics?.report({
4239
+ details: {
4240
+ createdAt: /* @__PURE__ */ new Date(),
4241
+ message,
4242
+ origin: "file-source-provider"
4243
+ },
4244
+ kind: "info"
4245
+ });
4246
+ }
4052
4247
  /**
4053
4248
  * Pre flight checks regarding the provided options, making sure that the file can be opened (decrypted, decompressed), etc.
4054
4249
  */
@@ -4077,12 +4272,14 @@ class LocalFileSourceProvider {
4077
4272
  return this.#parseJSONFile(backupStream, path2);
4078
4273
  }
4079
4274
  async getMetadata() {
4275
+ this.#reportInfo("getting metadata");
4080
4276
  if (!this.#metadata) {
4081
4277
  await this.#loadMetadata();
4082
4278
  }
4083
4279
  return this.#metadata ?? null;
4084
4280
  }
4085
4281
  async getSchemas() {
4282
+ this.#reportInfo("getting schemas");
4086
4283
  const schemas = await collect(this.createSchemasReadStream());
4087
4284
  if (fp.isEmpty(schemas)) {
4088
4285
  throw new ProviderInitializationError("Could not load schemas from Strapi data file.");
@@ -4090,21 +4287,26 @@ class LocalFileSourceProvider {
4090
4287
  return fp.keyBy("uid", schemas);
4091
4288
  }
4092
4289
  createEntitiesReadStream() {
4290
+ this.#reportInfo("creating entities read stream");
4093
4291
  return this.#streamJsonlDirectory("entities");
4094
4292
  }
4095
4293
  createSchemasReadStream() {
4294
+ this.#reportInfo("creating schemas read stream");
4096
4295
  return this.#streamJsonlDirectory("schemas");
4097
4296
  }
4098
4297
  createLinksReadStream() {
4298
+ this.#reportInfo("creating links read stream");
4099
4299
  return this.#streamJsonlDirectory("links");
4100
4300
  }
4101
4301
  createConfigurationReadStream() {
4302
+ this.#reportInfo("creating configuration read stream");
4102
4303
  return this.#streamJsonlDirectory("configuration");
4103
4304
  }
4104
4305
  createAssetsReadStream() {
4105
4306
  const inStream = this.#getBackupStream();
4106
4307
  const outStream = new stream$1.PassThrough({ objectMode: true });
4107
4308
  const loadAssetMetadata = this.#loadAssetMetadata.bind(this);
4309
+ this.#reportInfo("creating assets read stream");
4108
4310
  stream$1.pipeline(
4109
4311
  [
4110
4312
  inStream,
@@ -4305,9 +4507,20 @@ class LocalFileDestinationProvider {
4305
4507
  results = {};
4306
4508
  #providersMetadata = {};
4307
4509
  #archive = {};
4510
+ #diagnostics;
4308
4511
  constructor(options) {
4309
4512
  this.options = options;
4310
4513
  }
4514
+ #reportInfo(message) {
4515
+ this.#diagnostics?.report({
4516
+ details: {
4517
+ createdAt: /* @__PURE__ */ new Date(),
4518
+ message,
4519
+ origin: "file-destination-provider"
4520
+ },
4521
+ kind: "info"
4522
+ });
4523
+ }
4311
4524
  get #archivePath() {
4312
4525
  const { encryption, compression, file: file2 } = this.options;
4313
4526
  let filePath = `${file2.path}.tar`;
@@ -4324,9 +4537,11 @@ class LocalFileDestinationProvider {
4324
4537
  return this;
4325
4538
  }
4326
4539
  createGzip() {
4540
+ this.#reportInfo("creating gzip");
4327
4541
  return zip__default.default.createGzip();
4328
4542
  }
4329
- bootstrap() {
4543
+ bootstrap(diagnostics) {
4544
+ this.#diagnostics = diagnostics;
4330
4545
  const { compression, encryption } = this.options;
4331
4546
  if (encryption.enabled && !encryption.key) {
4332
4547
  throw new Error("Can't encrypt without a key");
@@ -4365,6 +4580,7 @@ class LocalFileDestinationProvider {
4365
4580
  }
4366
4581
  }
4367
4582
  async rollback() {
4583
+ this.#reportInfo("rolling back");
4368
4584
  await this.close();
4369
4585
  await fse.rm(this.#archivePath, { force: true });
4370
4586
  }
@@ -4372,6 +4588,7 @@ class LocalFileDestinationProvider {
4372
4588
  return null;
4373
4589
  }
4374
4590
  async #writeMetadata() {
4591
+ this.#reportInfo("writing metadata");
4375
4592
  const metadata = this.#providersMetadata.source;
4376
4593
  if (metadata) {
4377
4594
  await new Promise((resolve) => {
@@ -4392,6 +4609,7 @@ class LocalFileDestinationProvider {
4392
4609
  if (!this.#archive.stream) {
4393
4610
  throw new Error("Archive stream is unavailable");
4394
4611
  }
4612
+ this.#reportInfo("creating schemas write stream");
4395
4613
  const filePathFactory = createFilePathFactory("schemas");
4396
4614
  const entryStream = createTarEntryStream(
4397
4615
  this.#archive.stream,
@@ -4404,6 +4622,7 @@ class LocalFileDestinationProvider {
4404
4622
  if (!this.#archive.stream) {
4405
4623
  throw new Error("Archive stream is unavailable");
4406
4624
  }
4625
+ this.#reportInfo("creating entities write stream");
4407
4626
  const filePathFactory = createFilePathFactory("entities");
4408
4627
  const entryStream = createTarEntryStream(
4409
4628
  this.#archive.stream,
@@ -4416,6 +4635,7 @@ class LocalFileDestinationProvider {
4416
4635
  if (!this.#archive.stream) {
4417
4636
  throw new Error("Archive stream is unavailable");
4418
4637
  }
4638
+ this.#reportInfo("creating links write stream");
4419
4639
  const filePathFactory = createFilePathFactory("links");
4420
4640
  const entryStream = createTarEntryStream(
4421
4641
  this.#archive.stream,
@@ -4428,6 +4648,7 @@ class LocalFileDestinationProvider {
4428
4648
  if (!this.#archive.stream) {
4429
4649
  throw new Error("Archive stream is unavailable");
4430
4650
  }
4651
+ this.#reportInfo("creating configuration write stream");
4431
4652
  const filePathFactory = createFilePathFactory("configuration");
4432
4653
  const entryStream = createTarEntryStream(
4433
4654
  this.#archive.stream,
@@ -4441,6 +4662,7 @@ class LocalFileDestinationProvider {
4441
4662
  if (!archiveStream) {
4442
4663
  throw new Error("Archive stream is unavailable");
4443
4664
  }
4665
+ this.#reportInfo("creating assets write stream");
4444
4666
  return new stream$1.Writable({
4445
4667
  objectMode: true,
4446
4668
  write(data, _encoding, callback) {
@@ -4776,30 +4998,41 @@ const errorColors = {
4776
4998
  error: chalk__default.default.red,
4777
4999
  silly: chalk__default.default.yellow
4778
5000
  };
4779
- const formatDiagnostic = (operation) => ({ details, kind }) => {
4780
- const logger$1 = logger.createLogger(
4781
- logger.configs.createOutputFileConfiguration(`${operation}_error_log_${Date.now()}.log`)
4782
- );
4783
- try {
4784
- if (kind === "error") {
4785
- const { message, severity = "fatal" } = details;
4786
- const colorizeError = errorColors[severity];
4787
- const errorMessage = colorizeError(`[${severity.toUpperCase()}] ${message}`);
4788
- logger$1.error(errorMessage);
4789
- }
4790
- if (kind === "info") {
4791
- const { message, params } = details;
4792
- const msg = `${message}
4793
- ${params ? JSON.stringify(params, null, 2) : ""}`;
4794
- logger$1.info(msg);
5001
+ const formatDiagnostic = (operation, info) => {
5002
+ let logger$1;
5003
+ const getLogger = () => {
5004
+ if (!logger$1) {
5005
+ logger$1 = logger.createLogger(
5006
+ logger.configs.createOutputFileConfiguration(`${operation}_${Date.now()}.log`, {
5007
+ level: "info",
5008
+ format: logger.formats?.detailedLogs
5009
+ })
5010
+ );
4795
5011
  }
4796
- if (kind === "warning") {
4797
- const { origin: origin2, message } = details;
4798
- logger$1.warn(`(${origin2 ?? "transfer"}) ${message}`);
5012
+ return logger$1;
5013
+ };
5014
+ return ({ details, kind }) => {
5015
+ try {
5016
+ if (kind === "error") {
5017
+ const { message, severity = "fatal" } = details;
5018
+ const colorizeError = errorColors[severity];
5019
+ const errorMessage = colorizeError(`[${severity.toUpperCase()}] ${message}`);
5020
+ getLogger().error(errorMessage);
5021
+ }
5022
+ if (kind === "info" && info) {
5023
+ const { message, params, origin: origin2 } = details;
5024
+ const msg = `[${origin2 ?? "transfer"}] ${message}
5025
+ ${params ? JSON.stringify(params, null, 2) : ""}`;
5026
+ getLogger().info(msg);
5027
+ }
5028
+ if (kind === "warning") {
5029
+ const { origin: origin2, message } = details;
5030
+ getLogger().warn(`(${origin2 ?? "transfer"}) ${message}`);
5031
+ }
5032
+ } catch (err) {
5033
+ getLogger().error(err);
4799
5034
  }
4800
- } catch (err) {
4801
- logger$1.error(err);
4802
- }
5035
+ };
4803
5036
  };
4804
5037
  const loadersFactory = (defaultLoaders = {}) => {
4805
5038
  const loaders = defaultLoaders;
@@ -4981,7 +5214,7 @@ const action$2 = async (opts) => {
4981
5214
  ]
4982
5215
  }
4983
5216
  });
4984
- engine.diagnostics.onDiagnostic(formatDiagnostic("export"));
5217
+ engine.diagnostics.onDiagnostic(formatDiagnostic("export", opts.verbose));
4985
5218
  const progress = engine.progress.stream;
4986
5219
  const { updateLoader } = loadersFactory();
4987
5220
  progress.on(`stage::start`, ({ stage, data }) => {
@@ -5053,7 +5286,7 @@ const command$2 = ({ command: command2 }) => {
5053
5286
  )
5054
5287
  ).addOption(
5055
5288
  new commander.Option("--no-compress", "Disables gzip compression of output file").default(true)
5056
- ).addOption(
5289
+ ).addOption(new commander.Option("--verbose", "Enable verbose logs")).addOption(
5057
5290
  new commander.Option(
5058
5291
  "-k, --key <string>",
5059
5292
  "Provide encryption key in command instead of using the prompt"
@@ -5109,7 +5342,7 @@ const action$1 = async (opts) => {
5109
5342
  destination.onWarning = (message) => console.warn(`
5110
5343
  ${chalk__default.default.yellow("warn")}: ${message}`);
5111
5344
  const engine2 = createTransferEngine$1(source, destination, engineOptions);
5112
- engine2.diagnostics.onDiagnostic(formatDiagnostic("import"));
5345
+ engine2.diagnostics.onDiagnostic(formatDiagnostic("import", opts.verbose));
5113
5346
  const progress = engine2.progress.stream;
5114
5347
  const { updateLoader } = loadersFactory();
5115
5348
  engine2.onSchemaDiff(getDiffHandler(engine2, { force: opts.force, action: "import" }));
@@ -5167,7 +5400,7 @@ const command$1 = ({ command: command2 }) => {
5167
5400
  "-k, --key <string>",
5168
5401
  "Provide encryption key in command instead of using the prompt"
5169
5402
  )
5170
- ).addOption(forceOption).addOption(excludeOption).addOption(onlyOption).addOption(throttleOption).hook("preAction", validateExcludeOnly).hook("preAction", async (thisCommand) => {
5403
+ ).addOption(new commander.Option("--verbose", "Enable verbose logs")).addOption(forceOption).addOption(excludeOption).addOption(onlyOption).addOption(throttleOption).hook("preAction", validateExcludeOnly).hook("preAction", async (thisCommand) => {
5171
5404
  const opts = thisCommand.opts();
5172
5405
  const ext = path__default.default.extname(String(opts.file));
5173
5406
  if (ext === ".enc") {
@@ -5297,7 +5530,7 @@ const action = async (opts) => {
5297
5530
  ]
5298
5531
  }
5299
5532
  });
5300
- engine.diagnostics.onDiagnostic(formatDiagnostic("transfer"));
5533
+ engine.diagnostics.onDiagnostic(formatDiagnostic("transfer", opts.verbose));
5301
5534
  const progress = engine.progress.stream;
5302
5535
  const { updateLoader } = loadersFactory();
5303
5536
  engine.onSchemaDiff(getDiffHandler(engine, { force: opts.force, action: "transfer" }));
@@ -5349,7 +5582,7 @@ const command = ({ command: command2 }) => {
5349
5582
  "--to <destinationURL>",
5350
5583
  `URL of the remote Strapi instance to send data to`
5351
5584
  ).argParser(parseURL)
5352
- ).addOption(new commander.Option("--to-token <token>", `Transfer token for the remote Strapi destination`)).addOption(forceOption).addOption(excludeOption).addOption(onlyOption).addOption(throttleOption).hook("preAction", validateExcludeOnly).hook(
5585
+ ).addOption(new commander.Option("--to-token <token>", `Transfer token for the remote Strapi destination`)).addOption(new commander.Option("--verbose", "Enable verbose logs")).addOption(forceOption).addOption(excludeOption).addOption(onlyOption).addOption(throttleOption).hook("preAction", validateExcludeOnly).hook(
5353
5586
  "preAction",
5354
5587
  ifOptions(
5355
5588
  (opts) => !(opts.from || opts.to) || opts.from && opts.to,