@localazy/strapi-plugin 1.4.0 → 1.7.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 (64) hide show
  1. package/README.md +30 -0
  2. package/dist/_chunks/{FetchIdentity-BpFOT163.js → FetchIdentity-D89DgpbN.js} +24 -32
  3. package/dist/_chunks/{FetchIdentity-Cor4ooZv.mjs → FetchIdentity-DkHj24S5.mjs} +36 -44
  4. package/dist/_chunks/{LanguagesSelector-CC1ecWnc.js → LanguagesSelector-638KGQYw.js} +3 -2
  5. package/dist/_chunks/{LanguagesSelector-BbrMKwQY.mjs → LanguagesSelector-CR_7I2R1.mjs} +4 -3
  6. package/dist/_chunks/{LocalazyApp-D0JGRQeF.js → LocalazyApp-Benn8pkA.js} +75 -39
  7. package/dist/_chunks/{LocalazyApp-DpFR8p10.mjs → LocalazyApp-DM3zg5E4.mjs} +70 -34
  8. package/dist/_chunks/{LocalazyContentTransferSetup-Dael1Q4w.mjs → LocalazyContentTransferSetup-BA_rtSBM.mjs} +58 -22
  9. package/dist/_chunks/{LocalazyContentTransferSetup-Cr7D-BUi.js → LocalazyContentTransferSetup-CWchyGdD.js} +62 -26
  10. package/dist/_chunks/{LocalazyGlobalSettings-D3nG4zl7.js → LocalazyGlobalSettings-88jqQbD4.js} +56 -25
  11. package/dist/_chunks/{LocalazyGlobalSettings-DzBI5M-K.mjs → LocalazyGlobalSettings-BWF0s9tM.mjs} +56 -25
  12. package/dist/_chunks/{LocalazyPanel-W6j8N1WC.mjs → LocalazyPanel-4HRa1jNl.mjs} +12 -6
  13. package/dist/_chunks/{LocalazyPanel-KQPLxTDz.js → LocalazyPanel-D0w9JSIS.js} +14 -8
  14. package/dist/_chunks/{LocalazyStatusColumn-B7Q_U2Lu.js → LocalazyStatusColumn-BR3f8rKp.js} +10 -4
  15. package/dist/_chunks/{LocalazyStatusColumn-CrhsCjgp.mjs → LocalazyStatusColumn-D4-rZZUK.mjs} +10 -4
  16. package/dist/_chunks/{RequireLocalazyAuth-D3GeZPDh.js → RequireLocalazyAuth-C442750b.js} +30 -3
  17. package/dist/_chunks/{RequireLocalazyAuth-BwoGRfJq.mjs → RequireLocalazyAuth-DbNjEOq-.mjs} +32 -5
  18. package/dist/_chunks/{entry-exclusion-service-D7gaRHPE.mjs → entry-exclusion-service-Bd3mUDde.mjs} +1 -1
  19. package/dist/_chunks/{entry-exclusion-service-Bwruvyce.js → entry-exclusion-service-CAIcybXX.js} +1 -1
  20. package/dist/_chunks/{has-model-changed-Dp2Vkwjw.mjs → has-model-changed-BNs3d9q5.mjs} +4 -3
  21. package/dist/_chunks/{has-model-changed-5IV9WI_-.js → has-model-changed-BrDeyHFt.js} +4 -3
  22. package/dist/_chunks/{i18n-o24yXf-j.mjs → i18n-76ox2llT.mjs} +4 -1
  23. package/dist/_chunks/{i18n-C_5tJvr0.js → i18n-C5ucROBh.js} +4 -1
  24. package/dist/_chunks/{index-C9hN3KbD.mjs → index-C9Px4v-A.mjs} +34 -12
  25. package/dist/_chunks/{index-jAg6jjCu.js → index-DwFm1TyM.js} +33 -11
  26. package/dist/_chunks/{index-BjL9XpRh.mjs → index-shryj0jT.mjs} +16 -16
  27. package/dist/_chunks/{strapi-api-base-IG3Pe5Sg.js → strapi-api-base-BWZYbxxj.js} +1 -1
  28. package/dist/_chunks/{strapi-api-base-CAzGcwF6.mjs → strapi-api-base-lPo7wq6I.mjs} +1 -1
  29. package/dist/admin/index.js +1 -1
  30. package/dist/admin/index.mjs +1 -1
  31. package/dist/admin/src/components/LocalazyStatusColumn.d.ts +1 -1
  32. package/dist/admin/src/constants/permissions.d.ts +29 -0
  33. package/dist/admin/src/modules/@common/components/LanguagesSelector.d.ts +1 -0
  34. package/dist/admin/src/modules/@common/models/supported-content-type-fields.d.ts +1 -1
  35. package/dist/admin/src/modules/login/locale/en.d.ts +1 -0
  36. package/dist/admin/src/modules/plugin-settings/components/Tree.d.ts +1 -0
  37. package/dist/admin/src/modules/plugin-settings/components/TreeItem.d.ts +1 -0
  38. package/dist/admin/src/modules/plugin-settings/components/WebhookSetup.d.ts +4 -1
  39. package/dist/admin/src/modules/plugin-settings/locale/en.d.ts +2 -0
  40. package/dist/admin/src/modules/plugin-settings/services/plugin-settings-service.d.ts +4 -0
  41. package/dist/server/index.js +422 -213
  42. package/dist/server/index.mjs +422 -213
  43. package/dist/server/src/bootstrap.d.ts +1 -1
  44. package/dist/server/src/constants/permissions.d.ts +38 -0
  45. package/dist/server/src/controllers/index.d.ts +1 -0
  46. package/dist/server/src/controllers/plugin-settings-controller.d.ts +1 -0
  47. package/dist/server/src/core/index.d.ts +3 -1
  48. package/dist/server/src/index.d.ts +57 -8
  49. package/dist/server/src/routes/activity-logs-routes.d.ts +20 -3
  50. package/dist/server/src/routes/debug-bundle-routes.d.ts +6 -1
  51. package/dist/server/src/routes/entry-exclusion-routes.d.ts +20 -3
  52. package/dist/server/src/routes/index.d.ts +52 -6
  53. package/dist/server/src/routes/localazy-auth-routes.d.ts +6 -1
  54. package/dist/server/src/routes/localazy-project-routes.d.ts +20 -3
  55. package/dist/server/src/routes/localazy-transfer-routes.d.ts +6 -1
  56. package/dist/server/src/routes/localazy-user-routes.d.ts +20 -3
  57. package/dist/server/src/routes/plugin-settings-routes.d.ts +20 -3
  58. package/dist/server/src/routes/strapi-routes.d.ts +20 -3
  59. package/dist/server/src/services/index.d.ts +3 -1
  60. package/dist/server/src/services/localazy-transfer-download-service.d.ts +2 -1
  61. package/dist/server/src/services/plugin-settings-service.d.ts +4 -0
  62. package/dist/server/src/utils/blocks-to-translatable.d.ts +34 -0
  63. package/dist/server/src/utils/model-utils.d.ts +2 -1
  64. package/package.json +1 -1
@@ -20534,7 +20534,7 @@ var distExports = dist$1.exports;
20534
20534
  const io = /* @__PURE__ */ getDefaultExportFromCjs(distExports);
20535
20535
  const { Server: Server2, Namespace, Socket: Socket3 } = io;
20536
20536
  const name = "@localazy/strapi-plugin";
20537
- const version = "1.4.0";
20537
+ const version = "1.7.0";
20538
20538
  const description = "The official Strapi Plugin by Localazy.";
20539
20539
  const keywords = [
20540
20540
  "strapi",
@@ -20718,7 +20718,60 @@ const _package$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
20718
20718
  version
20719
20719
  }, Symbol.toStringTag, { value: "Module" }));
20720
20720
  const PLUGIN_NAME = strapi$1.name;
20721
- const bootstrap = ({ strapi: strapi2 }) => {
20721
+ const PERMISSION_UIDS = {
20722
+ READ: `plugin::${PLUGIN_NAME}.read`,
20723
+ TRANSFER: `plugin::${PLUGIN_NAME}.transfer`,
20724
+ SETTINGS_UPDATE: `plugin::${PLUGIN_NAME}.settings.update`
20725
+ };
20726
+ const LOCALAZY_RBAC_ACTIONS = [
20727
+ {
20728
+ section: "plugins",
20729
+ subCategory: "General",
20730
+ pluginName: PLUGIN_NAME,
20731
+ displayName: "Read",
20732
+ uid: "read"
20733
+ },
20734
+ {
20735
+ section: "plugins",
20736
+ subCategory: "General",
20737
+ pluginName: PLUGIN_NAME,
20738
+ displayName: "Transfer",
20739
+ uid: "transfer"
20740
+ },
20741
+ {
20742
+ section: "plugins",
20743
+ subCategory: "Settings",
20744
+ pluginName: PLUGIN_NAME,
20745
+ displayName: "Read settings",
20746
+ uid: "settings.read"
20747
+ },
20748
+ {
20749
+ section: "plugins",
20750
+ subCategory: "Settings",
20751
+ pluginName: PLUGIN_NAME,
20752
+ displayName: "Update settings",
20753
+ uid: "settings.update"
20754
+ }
20755
+ ];
20756
+ const registerRbacActions = async (strapi2) => {
20757
+ try {
20758
+ const permissionService = strapi2.service("admin::permission");
20759
+ const actionProvider = permissionService?.actionProvider;
20760
+ if (!actionProvider?.registerMany) {
20761
+ strapi2.log.warn(
20762
+ `[${PLUGIN_NAME}] admin::permission.actionProvider unavailable — skipping RBAC action registration`
20763
+ );
20764
+ return;
20765
+ }
20766
+ await actionProvider.registerMany(LOCALAZY_RBAC_ACTIONS);
20767
+ } catch (error) {
20768
+ strapi2.log.error(
20769
+ `[${PLUGIN_NAME}] Failed to register RBAC actions — plugin permissions will not appear in role editor: ${error instanceof Error ? error.message : String(error)}`
20770
+ );
20771
+ }
20772
+ };
20773
+ const bootstrap = async ({ strapi: strapi2 }) => {
20774
+ await registerRbacActions(strapi2);
20722
20775
  if (strapi2.plugin(PLUGIN_NAME)?.config("enableSocketIO", true)) {
20723
20776
  process.nextTick(async () => {
20724
20777
  const io2 = new Server2(strapi2.server.httpServer, {
@@ -24301,6 +24354,9 @@ const PluginSettingsController = ({ strapi: _strapi }) => ({
24301
24354
  async updatePluginSettings(ctx) {
24302
24355
  ctx.body = await getPluginSettingsService().updatePluginSettings(ctx.request.body);
24303
24356
  },
24357
+ async updatePluginSettingsUiPrefs(ctx) {
24358
+ ctx.body = await getPluginSettingsService().updatePluginSettingsUiPrefs(ctx.request.body);
24359
+ },
24304
24360
  async getSyncCursor(ctx) {
24305
24361
  ctx.body = await getPluginSettingsService().getSyncCursor();
24306
24362
  }
@@ -24400,6 +24456,8 @@ const LocalazyTransferController = ({ strapi: strapi2 }) => ({
24400
24456
  try {
24401
24457
  const LocalazyTransferDownloadService2 = getLocalazyTransferDownloadService();
24402
24458
  let fullSync = ctx.request.body?.fullSync === true;
24459
+ const rawUiLanguages = ctx.request.body?.uiLanguages;
24460
+ const requestedUiLanguages = Array.isArray(rawUiLanguages) && rawUiLanguages.every((code) => typeof code === "string") ? rawUiLanguages : void 0;
24403
24461
  const requestInitiatorHelper = new RequestInitiatorHelper(strapi2);
24404
24462
  if (requestInitiatorHelper.isInitiatedByLocalazyWebhook()) {
24405
24463
  const pluginSettingsServiceHelper = new PluginSettingsServiceHelper();
@@ -24409,7 +24467,8 @@ const LocalazyTransferController = ({ strapi: strapi2 }) => ({
24409
24467
  setTimeout(
24410
24468
  () => LocalazyTransferDownloadService2.download({
24411
24469
  notificationService: JobNotificationService$1,
24412
- fullSync
24470
+ fullSync,
24471
+ requestedUiLanguages
24413
24472
  }),
24414
24473
  1e3
24415
24474
  );
@@ -24978,13 +25037,17 @@ const middlewares = {
24978
25037
  };
24979
25038
  const policies = {};
24980
25039
  const ROUTE_PREFIX$8 = "/user";
25040
+ const readPolicy$6 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25041
+ const settingsUpdatePolicy$4 = [
25042
+ { name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
25043
+ ];
24981
25044
  const LocalazyUserRoutes = [
24982
25045
  {
24983
25046
  method: "GET",
24984
25047
  path: `${ROUTE_PREFIX$8}`,
24985
25048
  handler: "LocalazyUserController.getUser",
24986
25049
  config: {
24987
- policies: []
25050
+ policies: readPolicy$6
24988
25051
  }
24989
25052
  },
24990
25053
  {
@@ -24992,7 +25055,7 @@ const LocalazyUserRoutes = [
24992
25055
  path: `${ROUTE_PREFIX$8}`,
24993
25056
  handler: "LocalazyUserController.updateUser",
24994
25057
  config: {
24995
- policies: []
25058
+ policies: settingsUpdatePolicy$4
24996
25059
  }
24997
25060
  },
24998
25061
  {
@@ -25000,18 +25063,21 @@ const LocalazyUserRoutes = [
25000
25063
  path: `${ROUTE_PREFIX$8}`,
25001
25064
  handler: "LocalazyUserController.deleteUser",
25002
25065
  config: {
25003
- policies: []
25066
+ policies: settingsUpdatePolicy$4
25004
25067
  }
25005
25068
  }
25006
25069
  ];
25007
25070
  const ROUTE_PREFIX$7 = "/auth";
25071
+ const settingsUpdatePolicy$3 = [
25072
+ { name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
25073
+ ];
25008
25074
  const LocalazyAuthRoutes = [
25009
25075
  {
25010
25076
  method: "GET",
25011
25077
  path: `${ROUTE_PREFIX$7}/generate-keys`,
25012
25078
  handler: "LocalazyAuthController.generateKeys",
25013
25079
  config: {
25014
- policies: []
25080
+ policies: settingsUpdatePolicy$3
25015
25081
  }
25016
25082
  },
25017
25083
  {
@@ -25019,18 +25085,26 @@ const LocalazyAuthRoutes = [
25019
25085
  path: `${ROUTE_PREFIX$7}/continuous-poll`,
25020
25086
  handler: "LocalazyAuthController.continuousPoll",
25021
25087
  config: {
25022
- policies: []
25088
+ policies: settingsUpdatePolicy$3
25023
25089
  }
25024
25090
  }
25025
25091
  ];
25026
25092
  const ROUTE_PREFIX$6 = "/plugin-settings";
25093
+ const readPolicy$5 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25094
+ const settingsUpdatePolicy$2 = [
25095
+ { name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
25096
+ ];
25027
25097
  const PluginSettingsRoutes = [
25028
25098
  {
25029
25099
  method: "GET",
25030
25100
  path: `${ROUTE_PREFIX$6}/content-transfer-setup`,
25031
25101
  handler: "PluginSettingsController.getContentTransferSetup",
25032
25102
  config: {
25033
- policies: []
25103
+ // Upload/Download pages call this to detect "model changed" before
25104
+ // transferring. Gating on `settings.read` would lock transfer-only
25105
+ // roles out of the transfer pages, so the read is open to any plugin
25106
+ // user. The destructive PUT below stays on `settings.update`.
25107
+ policies: readPolicy$5
25034
25108
  }
25035
25109
  },
25036
25110
  {
@@ -25038,7 +25112,7 @@ const PluginSettingsRoutes = [
25038
25112
  path: `${ROUTE_PREFIX$6}/content-transfer-setup`,
25039
25113
  handler: "PluginSettingsController.updateContentTransferSetup",
25040
25114
  config: {
25041
- policies: []
25115
+ policies: settingsUpdatePolicy$2
25042
25116
  }
25043
25117
  },
25044
25118
  {
@@ -25046,7 +25120,7 @@ const PluginSettingsRoutes = [
25046
25120
  path: `${ROUTE_PREFIX$6}/plugin-settings`,
25047
25121
  handler: "PluginSettingsController.getPluginSettings",
25048
25122
  config: {
25049
- policies: []
25123
+ policies: readPolicy$5
25050
25124
  }
25051
25125
  },
25052
25126
  {
@@ -25054,7 +25128,20 @@ const PluginSettingsRoutes = [
25054
25128
  path: `${ROUTE_PREFIX$6}/plugin-settings`,
25055
25129
  handler: "PluginSettingsController.updatePluginSettings",
25056
25130
  config: {
25057
- policies: []
25131
+ // Persists destructive Global Settings (webhookConfig, download.*, upload.*).
25132
+ // UI-pref-only writes use `PUT /plugin-settings/ui-prefs` (read-gated) below.
25133
+ policies: settingsUpdatePolicy$2
25134
+ }
25135
+ },
25136
+ {
25137
+ method: "PUT",
25138
+ path: `${ROUTE_PREFIX$6}/ui-prefs`,
25139
+ handler: "PluginSettingsController.updatePluginSettingsUiPrefs",
25140
+ config: {
25141
+ // Per-user UI state (last visited route, sort prefs). Service-side filters
25142
+ // the body to a fixed allowlist so a `read`-only caller cannot reach the
25143
+ // destructive fields that share the same plugin-settings store.
25144
+ policies: readPolicy$5
25058
25145
  }
25059
25146
  },
25060
25147
  {
@@ -25062,18 +25149,22 @@ const PluginSettingsRoutes = [
25062
25149
  path: `${ROUTE_PREFIX$6}/sync-cursor`,
25063
25150
  handler: "PluginSettingsController.getSyncCursor",
25064
25151
  config: {
25065
- policies: []
25152
+ policies: readPolicy$5
25066
25153
  }
25067
25154
  }
25068
25155
  ];
25069
25156
  const ROUTE_PREFIX$5 = "/strapi";
25157
+ const readPolicy$4 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25158
+ const settingsUpdatePolicy$1 = [
25159
+ { name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
25160
+ ];
25070
25161
  const StrapiRoutes = [
25071
25162
  {
25072
25163
  method: "GET",
25073
25164
  path: `${ROUTE_PREFIX$5}/models`,
25074
25165
  handler: "StrapiController.getModels",
25075
25166
  config: {
25076
- policies: []
25167
+ policies: readPolicy$4
25077
25168
  }
25078
25169
  },
25079
25170
  {
@@ -25081,7 +25172,7 @@ const StrapiRoutes = [
25081
25172
  path: `${ROUTE_PREFIX$5}/localizable-models`,
25082
25173
  handler: "StrapiController.getLocalizableModels",
25083
25174
  config: {
25084
- policies: []
25175
+ policies: readPolicy$4
25085
25176
  }
25086
25177
  },
25087
25178
  {
@@ -25089,7 +25180,7 @@ const StrapiRoutes = [
25089
25180
  path: `${ROUTE_PREFIX$5}/lifecycle/localazy-webhooks`,
25090
25181
  handler: "StrapiController.postLifecycleLocalazyWebhooks",
25091
25182
  config: {
25092
- policies: []
25183
+ policies: settingsUpdatePolicy$1
25093
25184
  }
25094
25185
  },
25095
25186
  {
@@ -25097,18 +25188,19 @@ const StrapiRoutes = [
25097
25188
  path: `${ROUTE_PREFIX$5}/version`,
25098
25189
  handler: "StrapiController.getPluginVersion",
25099
25190
  config: {
25100
- policies: []
25191
+ policies: readPolicy$4
25101
25192
  }
25102
25193
  }
25103
25194
  ];
25104
25195
  const ROUTE_PREFIX$4 = "/transfer";
25196
+ const transferPolicy$2 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.TRANSFER] } }];
25105
25197
  const LocalazyTransferRoutes = [
25106
25198
  {
25107
25199
  method: "POST",
25108
25200
  path: `${ROUTE_PREFIX$4}/upload`,
25109
25201
  handler: "LocalazyTransferController.upload",
25110
25202
  config: {
25111
- policies: []
25203
+ policies: transferPolicy$2
25112
25204
  }
25113
25205
  },
25114
25206
  {
@@ -25116,18 +25208,22 @@ const LocalazyTransferRoutes = [
25116
25208
  path: `${ROUTE_PREFIX$4}/download`,
25117
25209
  handler: "LocalazyTransferController.download",
25118
25210
  config: {
25119
- policies: []
25211
+ policies: transferPolicy$2
25120
25212
  }
25121
25213
  }
25122
25214
  ];
25123
25215
  const ROUTE_PREFIX$3 = "/project";
25216
+ const readPolicy$3 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25217
+ const settingsUpdatePolicy = [
25218
+ { name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
25219
+ ];
25124
25220
  const LocalazyProjectRoutes = [
25125
25221
  {
25126
25222
  method: "GET",
25127
25223
  path: `${ROUTE_PREFIX$3}`,
25128
25224
  handler: "LocalazyProjectController.getConnectedProject",
25129
25225
  config: {
25130
- policies: []
25226
+ policies: readPolicy$3
25131
25227
  }
25132
25228
  },
25133
25229
  {
@@ -25135,7 +25231,7 @@ const LocalazyProjectRoutes = [
25135
25231
  path: `${ROUTE_PREFIX$3}/webhooks`,
25136
25232
  handler: "LocalazyProjectController.getWebhookStatus",
25137
25233
  config: {
25138
- policies: []
25234
+ policies: readPolicy$3
25139
25235
  }
25140
25236
  },
25141
25237
  {
@@ -25143,7 +25239,7 @@ const LocalazyProjectRoutes = [
25143
25239
  path: `${ROUTE_PREFIX$3}/webhooks/setup`,
25144
25240
  handler: "LocalazyProjectController.setupWebhook",
25145
25241
  config: {
25146
- policies: []
25242
+ policies: settingsUpdatePolicy
25147
25243
  }
25148
25244
  },
25149
25245
  {
@@ -25151,7 +25247,7 @@ const LocalazyProjectRoutes = [
25151
25247
  path: `${ROUTE_PREFIX$3}/strapi-url`,
25152
25248
  handler: "LocalazyProjectController.getStrapiUrl",
25153
25249
  config: {
25154
- policies: []
25250
+ policies: readPolicy$3
25155
25251
  }
25156
25252
  }
25157
25253
  ];
@@ -25170,13 +25266,15 @@ const LocalazyPublicTransferRoutes = [
25170
25266
  }
25171
25267
  ];
25172
25268
  const ROUTE_PREFIX$1 = "/entry-exclusion";
25269
+ const readPolicy$2 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25270
+ const transferPolicy$1 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.TRANSFER] } }];
25173
25271
  const EntryExclusionRoutes = [
25174
25272
  {
25175
25273
  method: "GET",
25176
25274
  path: `${ROUTE_PREFIX$1}/:contentType/:documentId`,
25177
25275
  handler: "EntryExclusionController.getEntryExclusion",
25178
25276
  config: {
25179
- policies: []
25277
+ policies: readPolicy$2
25180
25278
  }
25181
25279
  },
25182
25280
  {
@@ -25184,7 +25282,7 @@ const EntryExclusionRoutes = [
25184
25282
  path: `${ROUTE_PREFIX$1}/:contentType/:documentId`,
25185
25283
  handler: "EntryExclusionController.setEntryExclusion",
25186
25284
  config: {
25187
- policies: []
25285
+ policies: transferPolicy$1
25188
25286
  }
25189
25287
  },
25190
25288
  {
@@ -25192,18 +25290,20 @@ const EntryExclusionRoutes = [
25192
25290
  path: `${ROUTE_PREFIX$1}/:contentType`,
25193
25291
  handler: "EntryExclusionController.getContentTypeExclusions",
25194
25292
  config: {
25195
- policies: []
25293
+ policies: readPolicy$2
25196
25294
  }
25197
25295
  }
25198
25296
  ];
25199
25297
  const ROUTE_PREFIX = "/activity-logs";
25298
+ const readPolicy$1 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25299
+ const transferPolicy = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.TRANSFER] } }];
25200
25300
  const ActivityLogsRoutes = [
25201
25301
  {
25202
25302
  method: "GET",
25203
25303
  path: `${ROUTE_PREFIX}`,
25204
25304
  handler: "ActivityLogsController.getSessions",
25205
25305
  config: {
25206
- policies: []
25306
+ policies: readPolicy$1
25207
25307
  }
25208
25308
  },
25209
25309
  {
@@ -25211,7 +25311,7 @@ const ActivityLogsRoutes = [
25211
25311
  path: `${ROUTE_PREFIX}/export`,
25212
25312
  handler: "ActivityLogsController.exportSessions",
25213
25313
  config: {
25214
- policies: []
25314
+ policies: readPolicy$1
25215
25315
  }
25216
25316
  },
25217
25317
  {
@@ -25219,7 +25319,7 @@ const ActivityLogsRoutes = [
25219
25319
  path: `${ROUTE_PREFIX}/:sessionId`,
25220
25320
  handler: "ActivityLogsController.getSession",
25221
25321
  config: {
25222
- policies: []
25322
+ policies: readPolicy$1
25223
25323
  }
25224
25324
  },
25225
25325
  {
@@ -25227,23 +25327,28 @@ const ActivityLogsRoutes = [
25227
25327
  path: `${ROUTE_PREFIX}`,
25228
25328
  handler: "ActivityLogsController.clearSessions",
25229
25329
  config: {
25230
- policies: []
25330
+ policies: transferPolicy
25231
25331
  }
25232
25332
  }
25233
25333
  ];
25334
+ const readPolicy = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25234
25335
  const DebugBundleRoutes = [
25235
25336
  {
25236
25337
  method: "GET",
25237
25338
  path: "/activity-logs/:sessionId/bundle",
25238
25339
  handler: "DebugBundleController.getBundle",
25239
25340
  config: {
25240
- policies: []
25341
+ policies: readPolicy
25241
25342
  }
25242
25343
  }
25243
25344
  ];
25345
+ const withoutAdminPolicies = (routes2) => routes2.map((route) => ({
25346
+ ...route,
25347
+ config: { ...route.config, policies: [] }
25348
+ }));
25244
25349
  const routes = {
25245
25350
  "content-api": {
25246
- routes: [...StrapiRoutes]
25351
+ routes: withoutAdminPolicies(StrapiRoutes)
25247
25352
  },
25248
25353
  admin: {
25249
25354
  type: "admin",
@@ -25455,6 +25560,7 @@ const KEY$1 = "sync-cursor";
25455
25560
  const emptySyncCursor = {
25456
25561
  processedKeys: {}
25457
25562
  };
25563
+ const UI_PREF_FIELDS = ["defaultRoute", "activityLogsSort"];
25458
25564
  const PluginSettingsService = ({ strapi: strapi2 }) => ({
25459
25565
  async getContentTransferSetup() {
25460
25566
  const pluginStore = getStrapiStore(strapi2);
@@ -25491,6 +25597,20 @@ const PluginSettingsService = ({ strapi: strapi2 }) => ({
25491
25597
  });
25492
25598
  return newSettings;
25493
25599
  },
25600
+ // Counterpart to `updatePluginSettings` for the `read`-gated UI-prefs route.
25601
+ // Drops any field outside `UI_PREF_FIELDS` server-side so a `read`-only caller
25602
+ // cannot reach `webhookConfig` / `download.*` / `upload.*` via the merge.
25603
+ async updatePluginSettingsUiPrefs(prefs) {
25604
+ const sanitized = {};
25605
+ if (prefs && typeof prefs === "object") {
25606
+ for (const field of UI_PREF_FIELDS) {
25607
+ if (field in prefs) {
25608
+ sanitized[field] = prefs[field];
25609
+ }
25610
+ }
25611
+ }
25612
+ return this.updatePluginSettings(sanitized);
25613
+ },
25494
25614
  async getSyncCursor() {
25495
25615
  const pluginStore = getStrapiStore(strapi2);
25496
25616
  const cursor = await pluginStore.get({ key: KEY$1 });
@@ -25505,182 +25625,6 @@ const PluginSettingsService = ({ strapi: strapi2 }) => ({
25505
25625
  return cursor;
25506
25626
  }
25507
25627
  });
25508
- const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
25509
- async upload({ notificationService }) {
25510
- console.time("upload");
25511
- await notificationService.emit(EventType.UPLOAD, {
25512
- message: "Upload started"
25513
- });
25514
- const activityLogsService = getActivityLogsService();
25515
- const sessionId = await activityLogsService.startSession("upload", "Strapi User");
25516
- await activityLogsService.addEntry(sessionId, "Upload started");
25517
- let success = true;
25518
- const StrapiService2 = getStrapiService();
25519
- const StrapiI18nService2 = getStrapiI18nService();
25520
- const LocalazyUploadService2 = getLocalazyUploadService();
25521
- const EntryExclusionService2 = getEntryExclusionService();
25522
- const contentTransferSetup = await getPluginSettingsService().getContentTransferSetup();
25523
- if (!contentTransferSetup.has_setup) {
25524
- const message = "Content transfer setup is not set up.";
25525
- success = false;
25526
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25527
- success,
25528
- message
25529
- });
25530
- await activityLogsService.addEntry(sessionId, message);
25531
- await activityLogsService.finishSession(sessionId, "failed", message);
25532
- strapi2.log.info(message);
25533
- return;
25534
- }
25535
- const { setup: setup2 } = contentTransferSetup;
25536
- const collectionsNames = getCollectionsNames(setup2);
25537
- const models = await StrapiService2.getModels();
25538
- const strapiDefaultLocaleCode = await StrapiI18nService2.getDefaultLocaleCode();
25539
- const attemptedTuples = [];
25540
- let pickedFlattenStrapiContent = {};
25541
- for (const collectionName of collectionsNames) {
25542
- const currentModel = models.find((model) => model.collectionName === collectionName);
25543
- const modelUid = currentModel.uid;
25544
- if (!currentModel) {
25545
- strapi2.log.warn(`Model with uid ${modelUid} is not found.`);
25546
- continue;
25547
- }
25548
- const transferSetupModel = findSetupModelByCollectionName(setup2, collectionName);
25549
- if (!isCollectionTransferEnabled(setup2, collectionName)) {
25550
- const message2 = `Collection ${collectionName} transfer is disabled.`;
25551
- await notificationService.emit(EventType.UPLOAD, {
25552
- message: message2
25553
- });
25554
- await activityLogsService.addEntry(sessionId, message2);
25555
- strapi2.log.info(message2);
25556
- continue;
25557
- }
25558
- const currentTransferSetupModel = transferSetupModel[collectionName];
25559
- const pickPaths = getPickPathsWithComponents(currentTransferSetupModel);
25560
- if (!pickPaths.length) {
25561
- const message2 = `No fields for collection ${collectionName} transfer are enabled.`;
25562
- await notificationService.emit(EventType.UPLOAD, {
25563
- message: message2
25564
- });
25565
- await activityLogsService.addEntry(sessionId, message2);
25566
- strapi2.log.warn(message2);
25567
- continue;
25568
- }
25569
- const pickPathsWithUid = pickPaths.map((pickPath) => `${modelUid}.${pickPath}`);
25570
- let entries = await strapi2.documents(modelUid).findMany({
25571
- locUploadPLevel: 6,
25572
- status: "draft"
25573
- });
25574
- if (!entries.length) {
25575
- strapi2.log.info(`No entries found for model ${modelUid}`);
25576
- continue;
25577
- }
25578
- const excludedEntries = await EntryExclusionService2.getContentTypeExclusions(modelUid);
25579
- const filteredEntries = [];
25580
- for (const entry of entries) {
25581
- const isExcluded = excludedEntries.includes(entry.documentId);
25582
- if (!isExcluded) {
25583
- filteredEntries.push(entry);
25584
- }
25585
- }
25586
- entries = filteredEntries;
25587
- if (!entries.length) {
25588
- const message2 = `All entries for model ${collectionName} are excluded from translation`;
25589
- await notificationService.emit(EventType.UPLOAD, {
25590
- message: message2
25591
- });
25592
- await activityLogsService.addEntry(sessionId, message2);
25593
- strapi2.log.info(message2);
25594
- continue;
25595
- }
25596
- const message = `Excluding ${excludedEntries.length} entries for model ${collectionName} from upload. Entries to translate: ${entries.length}.`;
25597
- await notificationService.emit(EventType.UPLOAD, {
25598
- message
25599
- });
25600
- await activityLogsService.addEntry(sessionId, message);
25601
- strapi2.log.info(message);
25602
- if (strapiDefaultLocaleCode) {
25603
- for (const entry of entries) {
25604
- attemptedTuples.push({
25605
- uid: modelUid,
25606
- documentId: entry.documentId,
25607
- locale: strapiDefaultLocaleCode
25608
- });
25609
- }
25610
- }
25611
- entries = omitDeep(entries, ["locale", "createdAt", "updatedAt", "publishedAt"]);
25612
- entries.forEach((entry) => {
25613
- const flatten = flattenObject({
25614
- [modelUid]: entry
25615
- });
25616
- const pickedFlatten = pickEntries(flatten, pickPathsWithUid);
25617
- pickedFlattenStrapiContent = {
25618
- ...pickedFlattenStrapiContent,
25619
- ...pickedFlatten
25620
- };
25621
- });
25622
- const characterLimitsMetadata = getCharacterLimitsMetadata(pickedFlattenStrapiContent, modelUid);
25623
- pickedFlattenStrapiContent = {
25624
- ...pickedFlattenStrapiContent,
25625
- ...characterLimitsMetadata
25626
- };
25627
- }
25628
- const localazyLocaleCode = strapiDefaultLocaleCode ? isoStrapiToLocalazy(strapiDefaultLocaleCode) : config.default.LOCALAZY_DEFAULT_LOCALE;
25629
- const importFile = LocalazyUploadService2.createImportFileRepresentation(
25630
- localazyLocaleCode,
25631
- pickedFlattenStrapiContent
25632
- );
25633
- const uploadConfig = {
25634
- contentOptions: {
25635
- type: config.default.LOCALAZY_DEFAULT_FILE_EXTENSION
25636
- },
25637
- i18nOptions: { deprecate: "file" },
25638
- fileOptions: {
25639
- name: config.default.LOCALAZY_DEFAULT_FILE_NAME,
25640
- path: config.default.LOCALAZY_DEFAULT_FILE_PATH
25641
- }
25642
- };
25643
- await notificationService.emit(EventType.UPLOAD, {
25644
- message: "Uploading collections to Localazy..."
25645
- });
25646
- await activityLogsService.addEntry(sessionId, "Uploading collections to Localazy...");
25647
- try {
25648
- await LocalazyUploadService2.upload(importFile, uploadConfig);
25649
- await activityLogsService.recordAttemptedEntries(
25650
- sessionId,
25651
- attemptedTuples.map((t3) => ({ ...t3, status: "success" }))
25652
- );
25653
- } catch (error) {
25654
- success = false;
25655
- const errorMessage = `Upload to Localazy failed: ${error instanceof Error ? error.message : String(error)}`;
25656
- strapi2.log.error(errorMessage);
25657
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25658
- success,
25659
- message: errorMessage
25660
- });
25661
- await activityLogsService.addEntry(sessionId, errorMessage);
25662
- await activityLogsService.recordAttemptedEntries(
25663
- sessionId,
25664
- attemptedTuples.map((t3) => ({ ...t3, status: "failed", errorMessage }))
25665
- );
25666
- await activityLogsService.finishSession(sessionId, "failed", errorMessage);
25667
- console.timeEnd("upload");
25668
- return;
25669
- }
25670
- strapi2.log.info("Upload finished in");
25671
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25672
- success,
25673
- message: "Upload finished"
25674
- });
25675
- await activityLogsService.addEntry(sessionId, "Upload finished");
25676
- await activityLogsService.finishSession(
25677
- sessionId,
25678
- success ? "completed" : "failed",
25679
- success ? "Upload completed successfully" : "Upload finished with errors"
25680
- );
25681
- console.timeEnd("upload");
25682
- }
25683
- });
25684
25628
  var symbolTag$2 = "[object Symbol]";
25685
25629
  function isSymbol(value) {
25686
25630
  return typeof value == "symbol" || isObjectLike(value) && baseGetTag(value) == symbolTag$2;
@@ -25995,6 +25939,263 @@ function baseSet(object, path, value, customizer) {
25995
25939
  function set(object, path, value) {
25996
25940
  return object == null ? object : baseSet(object, path, value);
25997
25941
  }
25942
+ const BLOCKS_ATTRIBUTE_TYPE = "blocks";
25943
+ const projectBlocksFields = (entry, model, getModel) => {
25944
+ const cloned = cloneDeep(entry);
25945
+ walkAndProject(cloned, model, getModel);
25946
+ return cloned;
25947
+ };
25948
+ const walkAndProject = (value, model, getModel) => {
25949
+ if (!value || !model?.attributes) {
25950
+ return;
25951
+ }
25952
+ for (const [attributeName, attribute] of Object.entries(model.attributes)) {
25953
+ const fieldValue = value[attributeName];
25954
+ if (fieldValue === void 0 || fieldValue === null) {
25955
+ continue;
25956
+ }
25957
+ if (attribute.type === BLOCKS_ATTRIBUTE_TYPE) {
25958
+ value[attributeName] = projectBlocksValue(fieldValue);
25959
+ } else if (attribute.type === "component") {
25960
+ const componentModel = getModel(attribute.component);
25961
+ if (attribute.repeatable && Array.isArray(fieldValue)) {
25962
+ fieldValue.forEach((item) => walkAndProject(item, componentModel, getModel));
25963
+ } else if (isPlainObject(fieldValue)) {
25964
+ walkAndProject(fieldValue, componentModel, getModel);
25965
+ }
25966
+ } else if (attribute.type === "dynamiczone" && Array.isArray(fieldValue)) {
25967
+ fieldValue.forEach((item) => {
25968
+ if (item?.__component) {
25969
+ walkAndProject(item, getModel(item.__component), getModel);
25970
+ }
25971
+ });
25972
+ }
25973
+ }
25974
+ };
25975
+ const projectBlocksValue = (nodes) => {
25976
+ if (!Array.isArray(nodes)) {
25977
+ return nodes;
25978
+ }
25979
+ return nodes.map(projectNode);
25980
+ };
25981
+ const projectNode = (node) => {
25982
+ if (!isPlainObject(node)) {
25983
+ return {};
25984
+ }
25985
+ const projected = {};
25986
+ if (typeof node.text === "string") {
25987
+ projected.text = node.text;
25988
+ }
25989
+ if (Array.isArray(node.children)) {
25990
+ projected.children = node.children.map(projectNode);
25991
+ }
25992
+ return projected;
25993
+ };
25994
+ const overlayBlocksTranslation = (sourceAst, translated) => {
25995
+ if (!Array.isArray(sourceAst)) {
25996
+ return void 0;
25997
+ }
25998
+ return sourceAst.map((node, index2) => overlayNode(node, get(translated, [String(index2)])));
25999
+ };
26000
+ const overlayNode = (node, translatedNode) => {
26001
+ if (!isPlainObject(node)) {
26002
+ return cloneDeep(node);
26003
+ }
26004
+ if (typeof node.text === "string") {
26005
+ const translatedText = isPlainObject(translatedNode) ? translatedNode.text : void 0;
26006
+ return typeof translatedText === "string" ? { ...node, text: translatedText } : cloneDeep(node);
26007
+ }
26008
+ if (Array.isArray(node.children)) {
26009
+ return {
26010
+ ...node,
26011
+ children: node.children.map(
26012
+ (child, index2) => overlayNode(child, translatedNode ? get(translatedNode, ["children", String(index2)]) : void 0)
26013
+ )
26014
+ };
26015
+ }
26016
+ return cloneDeep(node);
26017
+ };
26018
+ const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
26019
+ async upload({ notificationService }) {
26020
+ console.time("upload");
26021
+ await notificationService.emit(EventType.UPLOAD, {
26022
+ message: "Upload started"
26023
+ });
26024
+ const activityLogsService = getActivityLogsService();
26025
+ const sessionId = await activityLogsService.startSession("upload", "Strapi User");
26026
+ await activityLogsService.addEntry(sessionId, "Upload started");
26027
+ let success = true;
26028
+ const StrapiService2 = getStrapiService();
26029
+ const StrapiI18nService2 = getStrapiI18nService();
26030
+ const LocalazyUploadService2 = getLocalazyUploadService();
26031
+ const EntryExclusionService2 = getEntryExclusionService();
26032
+ const contentTransferSetup = await getPluginSettingsService().getContentTransferSetup();
26033
+ if (!contentTransferSetup.has_setup) {
26034
+ const message = "Content transfer setup is not set up.";
26035
+ success = false;
26036
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26037
+ success,
26038
+ message
26039
+ });
26040
+ await activityLogsService.addEntry(sessionId, message);
26041
+ await activityLogsService.finishSession(sessionId, "failed", message);
26042
+ strapi2.log.info(message);
26043
+ return;
26044
+ }
26045
+ const { setup: setup2 } = contentTransferSetup;
26046
+ const collectionsNames = getCollectionsNames(setup2);
26047
+ const models = await StrapiService2.getModels();
26048
+ const strapiDefaultLocaleCode = await StrapiI18nService2.getDefaultLocaleCode();
26049
+ const attemptedTuples = [];
26050
+ let pickedFlattenStrapiContent = {};
26051
+ for (const collectionName of collectionsNames) {
26052
+ const currentModel = models.find((model) => model.collectionName === collectionName);
26053
+ const modelUid = currentModel.uid;
26054
+ if (!currentModel) {
26055
+ strapi2.log.warn(`Model with uid ${modelUid} is not found.`);
26056
+ continue;
26057
+ }
26058
+ const transferSetupModel = findSetupModelByCollectionName(setup2, collectionName);
26059
+ if (!isCollectionTransferEnabled(setup2, collectionName)) {
26060
+ const message2 = `Collection ${collectionName} transfer is disabled.`;
26061
+ await notificationService.emit(EventType.UPLOAD, {
26062
+ message: message2
26063
+ });
26064
+ await activityLogsService.addEntry(sessionId, message2);
26065
+ strapi2.log.info(message2);
26066
+ continue;
26067
+ }
26068
+ const currentTransferSetupModel = transferSetupModel[collectionName];
26069
+ const pickPaths = getPickPathsWithComponents(currentTransferSetupModel);
26070
+ if (!pickPaths.length) {
26071
+ const message2 = `No fields for collection ${collectionName} transfer are enabled.`;
26072
+ await notificationService.emit(EventType.UPLOAD, {
26073
+ message: message2
26074
+ });
26075
+ await activityLogsService.addEntry(sessionId, message2);
26076
+ strapi2.log.warn(message2);
26077
+ continue;
26078
+ }
26079
+ const pickPathsWithUid = pickPaths.map((pickPath) => `${modelUid}.${pickPath}`);
26080
+ let entries = await strapi2.documents(modelUid).findMany({
26081
+ locUploadPLevel: 6,
26082
+ status: "draft"
26083
+ });
26084
+ if (!entries.length) {
26085
+ strapi2.log.info(`No entries found for model ${modelUid}`);
26086
+ continue;
26087
+ }
26088
+ const excludedEntries = await EntryExclusionService2.getContentTypeExclusions(modelUid);
26089
+ const filteredEntries = [];
26090
+ for (const entry of entries) {
26091
+ const isExcluded = excludedEntries.includes(entry.documentId);
26092
+ if (!isExcluded) {
26093
+ filteredEntries.push(entry);
26094
+ }
26095
+ }
26096
+ entries = filteredEntries;
26097
+ if (!entries.length) {
26098
+ const message2 = `All entries for model ${collectionName} are excluded from translation`;
26099
+ await notificationService.emit(EventType.UPLOAD, {
26100
+ message: message2
26101
+ });
26102
+ await activityLogsService.addEntry(sessionId, message2);
26103
+ strapi2.log.info(message2);
26104
+ continue;
26105
+ }
26106
+ const message = `Excluding ${excludedEntries.length} entries for model ${collectionName} from upload. Entries to translate: ${entries.length}.`;
26107
+ await notificationService.emit(EventType.UPLOAD, {
26108
+ message
26109
+ });
26110
+ await activityLogsService.addEntry(sessionId, message);
26111
+ strapi2.log.info(message);
26112
+ if (strapiDefaultLocaleCode) {
26113
+ for (const entry of entries) {
26114
+ attemptedTuples.push({
26115
+ uid: modelUid,
26116
+ documentId: entry.documentId,
26117
+ locale: strapiDefaultLocaleCode
26118
+ });
26119
+ }
26120
+ }
26121
+ entries = omitDeep(entries, ["locale", "createdAt", "updatedAt", "publishedAt"]);
26122
+ entries.forEach((entry) => {
26123
+ const projectedEntry = projectBlocksFields(
26124
+ entry,
26125
+ strapi2.getModel(modelUid),
26126
+ (uid) => strapi2.getModel(uid)
26127
+ );
26128
+ const flatten = flattenObject({
26129
+ [modelUid]: projectedEntry
26130
+ });
26131
+ const pickedFlatten = pickEntries(flatten, pickPathsWithUid);
26132
+ pickedFlattenStrapiContent = {
26133
+ ...pickedFlattenStrapiContent,
26134
+ ...pickedFlatten
26135
+ };
26136
+ });
26137
+ const characterLimitsMetadata = getCharacterLimitsMetadata(pickedFlattenStrapiContent, modelUid);
26138
+ pickedFlattenStrapiContent = {
26139
+ ...pickedFlattenStrapiContent,
26140
+ ...characterLimitsMetadata
26141
+ };
26142
+ }
26143
+ const localazyLocaleCode = strapiDefaultLocaleCode ? isoStrapiToLocalazy(strapiDefaultLocaleCode) : config.default.LOCALAZY_DEFAULT_LOCALE;
26144
+ const importFile = LocalazyUploadService2.createImportFileRepresentation(
26145
+ localazyLocaleCode,
26146
+ pickedFlattenStrapiContent
26147
+ );
26148
+ const uploadConfig = {
26149
+ contentOptions: {
26150
+ type: config.default.LOCALAZY_DEFAULT_FILE_EXTENSION
26151
+ },
26152
+ i18nOptions: { deprecate: "file" },
26153
+ fileOptions: {
26154
+ name: config.default.LOCALAZY_DEFAULT_FILE_NAME,
26155
+ path: config.default.LOCALAZY_DEFAULT_FILE_PATH
26156
+ }
26157
+ };
26158
+ await notificationService.emit(EventType.UPLOAD, {
26159
+ message: "Uploading collections to Localazy..."
26160
+ });
26161
+ await activityLogsService.addEntry(sessionId, "Uploading collections to Localazy...");
26162
+ try {
26163
+ await LocalazyUploadService2.upload(importFile, uploadConfig);
26164
+ await activityLogsService.recordAttemptedEntries(
26165
+ sessionId,
26166
+ attemptedTuples.map((t3) => ({ ...t3, status: "success" }))
26167
+ );
26168
+ } catch (error) {
26169
+ success = false;
26170
+ const errorMessage = `Upload to Localazy failed: ${error instanceof Error ? error.message : String(error)}`;
26171
+ strapi2.log.error(errorMessage);
26172
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26173
+ success,
26174
+ message: errorMessage
26175
+ });
26176
+ await activityLogsService.addEntry(sessionId, errorMessage);
26177
+ await activityLogsService.recordAttemptedEntries(
26178
+ sessionId,
26179
+ attemptedTuples.map((t3) => ({ ...t3, status: "failed", errorMessage }))
26180
+ );
26181
+ await activityLogsService.finishSession(sessionId, "failed", errorMessage);
26182
+ console.timeEnd("upload");
26183
+ return;
26184
+ }
26185
+ strapi2.log.info("Upload finished in");
26186
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26187
+ success,
26188
+ message: "Upload finished"
26189
+ });
26190
+ await activityLogsService.addEntry(sessionId, "Upload finished");
26191
+ await activityLogsService.finishSession(
26192
+ sessionId,
26193
+ success ? "completed" : "failed",
26194
+ success ? "Upload completed successfully" : "Upload finished with errors"
26195
+ );
26196
+ console.timeEnd("upload");
26197
+ }
26198
+ });
25998
26199
  const hasDynamicZoneKeySegment = (parsedKey) => {
25999
26200
  return parsedKey.some((segment) => segment.includes(";"));
26000
26201
  };
@@ -26067,7 +26268,7 @@ const shouldSetDownloadedProperty = (modelContentTransferSetup, parsedKeyRest) =
26067
26268
  return "no";
26068
26269
  }
26069
26270
  };
26070
- const getFilteredLanguagesCodesForDownload = async (languagesCodes) => {
26271
+ const getFilteredLanguagesCodesForDownload = async (languagesCodes, requestedUiLanguages) => {
26071
26272
  const pluginSettingsServiceHelper = new PluginSettingsServiceHelper();
26072
26273
  const requestInitiatorHelper = new RequestInitiatorHelper(strapi);
26073
26274
  await pluginSettingsServiceHelper.setup();
@@ -26075,7 +26276,7 @@ const getFilteredLanguagesCodesForDownload = async (languagesCodes) => {
26075
26276
  if (requestInitiatorHelper.isInitiatedByLocalazyWebhook()) {
26076
26277
  localLanguagesCodes = pluginSettingsServiceHelper.getWebhookLanguagesCodes();
26077
26278
  } else if (requestInitiatorHelper.isInitiatedByLocalazyPluginUI()) {
26078
- localLanguagesCodes = pluginSettingsServiceHelper.getUiLanguagesCodes();
26279
+ localLanguagesCodes = requestedUiLanguages ?? pluginSettingsServiceHelper.getUiLanguagesCodes();
26079
26280
  } else {
26080
26281
  strapi.log.warn("Called by an unknown initiator.");
26081
26282
  return languagesCodes;
@@ -26088,7 +26289,8 @@ const getFilteredLanguagesCodesForDownload = async (languagesCodes) => {
26088
26289
  const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
26089
26290
  async download({
26090
26291
  notificationService,
26091
- fullSync = false
26292
+ fullSync = false,
26293
+ requestedUiLanguages
26092
26294
  }) {
26093
26295
  console.time("download");
26094
26296
  const syncMode = fullSync ? "Full sync" : "Incremental sync";
@@ -26168,7 +26370,7 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
26168
26370
  return;
26169
26371
  }
26170
26372
  let languagesCodes = projectLanguagesWithoutSourceLanguage.map((language3) => language3.code);
26171
- languagesCodes = await getFilteredLanguagesCodesForDownload(languagesCodes);
26373
+ languagesCodes = await getFilteredLanguagesCodesForDownload(languagesCodes, requestedUiLanguages);
26172
26374
  const strapiUnsupportedLanguages = [];
26173
26375
  const strapiLocales = await StrapiI18nService2.getLocales();
26174
26376
  for (const isoLocalazy of languagesCodes) {
@@ -26681,6 +26883,9 @@ const isRepeatable = (attributeObj) => {
26681
26883
  const isRelation = (attributeObj) => {
26682
26884
  return attributeObj.type === "relation" && attributeObj.target !== "plugin::upload.file";
26683
26885
  };
26886
+ const isBlocks = (attributeObj) => {
26887
+ return attributeObj.type === BLOCKS_ATTRIBUTE_TYPE;
26888
+ };
26684
26889
  const findModel = (models, uid) => {
26685
26890
  const model = models.find((model2) => model2.uid === uid);
26686
26891
  return model;
@@ -26824,7 +27029,11 @@ const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry
26824
27029
  newPrefixBase = `${dzParamKey}.${baseEntryDZIndex}`;
26825
27030
  newPrefix = `${newPrefixBase}.${objectKey}`;
26826
27031
  }
26827
- set(createEntry, newPrefix, value);
27032
+ const valueToSet = isBlocks(attribute) ? overlayBlocksTranslation(get(baseEntry, newPrefix), value) : value;
27033
+ if (valueToSet === void 0) {
27034
+ return;
27035
+ }
27036
+ set(createEntry, newPrefix, valueToSet);
26828
27037
  if (component) {
26829
27038
  const componentKeyToSet = `${newPrefixBase}.__component`;
26830
27039
  set(createEntry, componentKeyToSet, component);