@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
@@ -20520,7 +20520,7 @@ var distExports = dist$1.exports;
20520
20520
  const io = /* @__PURE__ */ getDefaultExportFromCjs(distExports);
20521
20521
  const { Server: Server2, Namespace, Socket: Socket3 } = io;
20522
20522
  const name = "@localazy/strapi-plugin";
20523
- const version = "1.4.0";
20523
+ const version = "1.7.0";
20524
20524
  const description = "The official Strapi Plugin by Localazy.";
20525
20525
  const keywords = [
20526
20526
  "strapi",
@@ -20704,7 +20704,60 @@ const _package$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
20704
20704
  version
20705
20705
  }, Symbol.toStringTag, { value: "Module" }));
20706
20706
  const PLUGIN_NAME = strapi$1.name;
20707
- const bootstrap = ({ strapi: strapi2 }) => {
20707
+ const PERMISSION_UIDS = {
20708
+ READ: `plugin::${PLUGIN_NAME}.read`,
20709
+ TRANSFER: `plugin::${PLUGIN_NAME}.transfer`,
20710
+ SETTINGS_UPDATE: `plugin::${PLUGIN_NAME}.settings.update`
20711
+ };
20712
+ const LOCALAZY_RBAC_ACTIONS = [
20713
+ {
20714
+ section: "plugins",
20715
+ subCategory: "General",
20716
+ pluginName: PLUGIN_NAME,
20717
+ displayName: "Read",
20718
+ uid: "read"
20719
+ },
20720
+ {
20721
+ section: "plugins",
20722
+ subCategory: "General",
20723
+ pluginName: PLUGIN_NAME,
20724
+ displayName: "Transfer",
20725
+ uid: "transfer"
20726
+ },
20727
+ {
20728
+ section: "plugins",
20729
+ subCategory: "Settings",
20730
+ pluginName: PLUGIN_NAME,
20731
+ displayName: "Read settings",
20732
+ uid: "settings.read"
20733
+ },
20734
+ {
20735
+ section: "plugins",
20736
+ subCategory: "Settings",
20737
+ pluginName: PLUGIN_NAME,
20738
+ displayName: "Update settings",
20739
+ uid: "settings.update"
20740
+ }
20741
+ ];
20742
+ const registerRbacActions = async (strapi2) => {
20743
+ try {
20744
+ const permissionService = strapi2.service("admin::permission");
20745
+ const actionProvider = permissionService?.actionProvider;
20746
+ if (!actionProvider?.registerMany) {
20747
+ strapi2.log.warn(
20748
+ `[${PLUGIN_NAME}] admin::permission.actionProvider unavailable — skipping RBAC action registration`
20749
+ );
20750
+ return;
20751
+ }
20752
+ await actionProvider.registerMany(LOCALAZY_RBAC_ACTIONS);
20753
+ } catch (error) {
20754
+ strapi2.log.error(
20755
+ `[${PLUGIN_NAME}] Failed to register RBAC actions — plugin permissions will not appear in role editor: ${error instanceof Error ? error.message : String(error)}`
20756
+ );
20757
+ }
20758
+ };
20759
+ const bootstrap = async ({ strapi: strapi2 }) => {
20760
+ await registerRbacActions(strapi2);
20708
20761
  if (strapi2.plugin(PLUGIN_NAME)?.config("enableSocketIO", true)) {
20709
20762
  process.nextTick(async () => {
20710
20763
  const io2 = new Server2(strapi2.server.httpServer, {
@@ -24287,6 +24340,9 @@ const PluginSettingsController = ({ strapi: _strapi }) => ({
24287
24340
  async updatePluginSettings(ctx) {
24288
24341
  ctx.body = await getPluginSettingsService().updatePluginSettings(ctx.request.body);
24289
24342
  },
24343
+ async updatePluginSettingsUiPrefs(ctx) {
24344
+ ctx.body = await getPluginSettingsService().updatePluginSettingsUiPrefs(ctx.request.body);
24345
+ },
24290
24346
  async getSyncCursor(ctx) {
24291
24347
  ctx.body = await getPluginSettingsService().getSyncCursor();
24292
24348
  }
@@ -24386,6 +24442,8 @@ const LocalazyTransferController = ({ strapi: strapi2 }) => ({
24386
24442
  try {
24387
24443
  const LocalazyTransferDownloadService2 = getLocalazyTransferDownloadService();
24388
24444
  let fullSync = ctx.request.body?.fullSync === true;
24445
+ const rawUiLanguages = ctx.request.body?.uiLanguages;
24446
+ const requestedUiLanguages = Array.isArray(rawUiLanguages) && rawUiLanguages.every((code) => typeof code === "string") ? rawUiLanguages : void 0;
24389
24447
  const requestInitiatorHelper = new RequestInitiatorHelper(strapi2);
24390
24448
  if (requestInitiatorHelper.isInitiatedByLocalazyWebhook()) {
24391
24449
  const pluginSettingsServiceHelper = new PluginSettingsServiceHelper();
@@ -24395,7 +24453,8 @@ const LocalazyTransferController = ({ strapi: strapi2 }) => ({
24395
24453
  setTimeout(
24396
24454
  () => LocalazyTransferDownloadService2.download({
24397
24455
  notificationService: JobNotificationService$1,
24398
- fullSync
24456
+ fullSync,
24457
+ requestedUiLanguages
24399
24458
  }),
24400
24459
  1e3
24401
24460
  );
@@ -24964,13 +25023,17 @@ const middlewares = {
24964
25023
  };
24965
25024
  const policies = {};
24966
25025
  const ROUTE_PREFIX$8 = "/user";
25026
+ const readPolicy$6 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25027
+ const settingsUpdatePolicy$4 = [
25028
+ { name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
25029
+ ];
24967
25030
  const LocalazyUserRoutes = [
24968
25031
  {
24969
25032
  method: "GET",
24970
25033
  path: `${ROUTE_PREFIX$8}`,
24971
25034
  handler: "LocalazyUserController.getUser",
24972
25035
  config: {
24973
- policies: []
25036
+ policies: readPolicy$6
24974
25037
  }
24975
25038
  },
24976
25039
  {
@@ -24978,7 +25041,7 @@ const LocalazyUserRoutes = [
24978
25041
  path: `${ROUTE_PREFIX$8}`,
24979
25042
  handler: "LocalazyUserController.updateUser",
24980
25043
  config: {
24981
- policies: []
25044
+ policies: settingsUpdatePolicy$4
24982
25045
  }
24983
25046
  },
24984
25047
  {
@@ -24986,18 +25049,21 @@ const LocalazyUserRoutes = [
24986
25049
  path: `${ROUTE_PREFIX$8}`,
24987
25050
  handler: "LocalazyUserController.deleteUser",
24988
25051
  config: {
24989
- policies: []
25052
+ policies: settingsUpdatePolicy$4
24990
25053
  }
24991
25054
  }
24992
25055
  ];
24993
25056
  const ROUTE_PREFIX$7 = "/auth";
25057
+ const settingsUpdatePolicy$3 = [
25058
+ { name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
25059
+ ];
24994
25060
  const LocalazyAuthRoutes = [
24995
25061
  {
24996
25062
  method: "GET",
24997
25063
  path: `${ROUTE_PREFIX$7}/generate-keys`,
24998
25064
  handler: "LocalazyAuthController.generateKeys",
24999
25065
  config: {
25000
- policies: []
25066
+ policies: settingsUpdatePolicy$3
25001
25067
  }
25002
25068
  },
25003
25069
  {
@@ -25005,18 +25071,26 @@ const LocalazyAuthRoutes = [
25005
25071
  path: `${ROUTE_PREFIX$7}/continuous-poll`,
25006
25072
  handler: "LocalazyAuthController.continuousPoll",
25007
25073
  config: {
25008
- policies: []
25074
+ policies: settingsUpdatePolicy$3
25009
25075
  }
25010
25076
  }
25011
25077
  ];
25012
25078
  const ROUTE_PREFIX$6 = "/plugin-settings";
25079
+ const readPolicy$5 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25080
+ const settingsUpdatePolicy$2 = [
25081
+ { name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
25082
+ ];
25013
25083
  const PluginSettingsRoutes = [
25014
25084
  {
25015
25085
  method: "GET",
25016
25086
  path: `${ROUTE_PREFIX$6}/content-transfer-setup`,
25017
25087
  handler: "PluginSettingsController.getContentTransferSetup",
25018
25088
  config: {
25019
- policies: []
25089
+ // Upload/Download pages call this to detect "model changed" before
25090
+ // transferring. Gating on `settings.read` would lock transfer-only
25091
+ // roles out of the transfer pages, so the read is open to any plugin
25092
+ // user. The destructive PUT below stays on `settings.update`.
25093
+ policies: readPolicy$5
25020
25094
  }
25021
25095
  },
25022
25096
  {
@@ -25024,7 +25098,7 @@ const PluginSettingsRoutes = [
25024
25098
  path: `${ROUTE_PREFIX$6}/content-transfer-setup`,
25025
25099
  handler: "PluginSettingsController.updateContentTransferSetup",
25026
25100
  config: {
25027
- policies: []
25101
+ policies: settingsUpdatePolicy$2
25028
25102
  }
25029
25103
  },
25030
25104
  {
@@ -25032,7 +25106,7 @@ const PluginSettingsRoutes = [
25032
25106
  path: `${ROUTE_PREFIX$6}/plugin-settings`,
25033
25107
  handler: "PluginSettingsController.getPluginSettings",
25034
25108
  config: {
25035
- policies: []
25109
+ policies: readPolicy$5
25036
25110
  }
25037
25111
  },
25038
25112
  {
@@ -25040,7 +25114,20 @@ const PluginSettingsRoutes = [
25040
25114
  path: `${ROUTE_PREFIX$6}/plugin-settings`,
25041
25115
  handler: "PluginSettingsController.updatePluginSettings",
25042
25116
  config: {
25043
- policies: []
25117
+ // Persists destructive Global Settings (webhookConfig, download.*, upload.*).
25118
+ // UI-pref-only writes use `PUT /plugin-settings/ui-prefs` (read-gated) below.
25119
+ policies: settingsUpdatePolicy$2
25120
+ }
25121
+ },
25122
+ {
25123
+ method: "PUT",
25124
+ path: `${ROUTE_PREFIX$6}/ui-prefs`,
25125
+ handler: "PluginSettingsController.updatePluginSettingsUiPrefs",
25126
+ config: {
25127
+ // Per-user UI state (last visited route, sort prefs). Service-side filters
25128
+ // the body to a fixed allowlist so a `read`-only caller cannot reach the
25129
+ // destructive fields that share the same plugin-settings store.
25130
+ policies: readPolicy$5
25044
25131
  }
25045
25132
  },
25046
25133
  {
@@ -25048,18 +25135,22 @@ const PluginSettingsRoutes = [
25048
25135
  path: `${ROUTE_PREFIX$6}/sync-cursor`,
25049
25136
  handler: "PluginSettingsController.getSyncCursor",
25050
25137
  config: {
25051
- policies: []
25138
+ policies: readPolicy$5
25052
25139
  }
25053
25140
  }
25054
25141
  ];
25055
25142
  const ROUTE_PREFIX$5 = "/strapi";
25143
+ const readPolicy$4 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25144
+ const settingsUpdatePolicy$1 = [
25145
+ { name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
25146
+ ];
25056
25147
  const StrapiRoutes = [
25057
25148
  {
25058
25149
  method: "GET",
25059
25150
  path: `${ROUTE_PREFIX$5}/models`,
25060
25151
  handler: "StrapiController.getModels",
25061
25152
  config: {
25062
- policies: []
25153
+ policies: readPolicy$4
25063
25154
  }
25064
25155
  },
25065
25156
  {
@@ -25067,7 +25158,7 @@ const StrapiRoutes = [
25067
25158
  path: `${ROUTE_PREFIX$5}/localizable-models`,
25068
25159
  handler: "StrapiController.getLocalizableModels",
25069
25160
  config: {
25070
- policies: []
25161
+ policies: readPolicy$4
25071
25162
  }
25072
25163
  },
25073
25164
  {
@@ -25075,7 +25166,7 @@ const StrapiRoutes = [
25075
25166
  path: `${ROUTE_PREFIX$5}/lifecycle/localazy-webhooks`,
25076
25167
  handler: "StrapiController.postLifecycleLocalazyWebhooks",
25077
25168
  config: {
25078
- policies: []
25169
+ policies: settingsUpdatePolicy$1
25079
25170
  }
25080
25171
  },
25081
25172
  {
@@ -25083,18 +25174,19 @@ const StrapiRoutes = [
25083
25174
  path: `${ROUTE_PREFIX$5}/version`,
25084
25175
  handler: "StrapiController.getPluginVersion",
25085
25176
  config: {
25086
- policies: []
25177
+ policies: readPolicy$4
25087
25178
  }
25088
25179
  }
25089
25180
  ];
25090
25181
  const ROUTE_PREFIX$4 = "/transfer";
25182
+ const transferPolicy$2 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.TRANSFER] } }];
25091
25183
  const LocalazyTransferRoutes = [
25092
25184
  {
25093
25185
  method: "POST",
25094
25186
  path: `${ROUTE_PREFIX$4}/upload`,
25095
25187
  handler: "LocalazyTransferController.upload",
25096
25188
  config: {
25097
- policies: []
25189
+ policies: transferPolicy$2
25098
25190
  }
25099
25191
  },
25100
25192
  {
@@ -25102,18 +25194,22 @@ const LocalazyTransferRoutes = [
25102
25194
  path: `${ROUTE_PREFIX$4}/download`,
25103
25195
  handler: "LocalazyTransferController.download",
25104
25196
  config: {
25105
- policies: []
25197
+ policies: transferPolicy$2
25106
25198
  }
25107
25199
  }
25108
25200
  ];
25109
25201
  const ROUTE_PREFIX$3 = "/project";
25202
+ const readPolicy$3 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25203
+ const settingsUpdatePolicy = [
25204
+ { name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
25205
+ ];
25110
25206
  const LocalazyProjectRoutes = [
25111
25207
  {
25112
25208
  method: "GET",
25113
25209
  path: `${ROUTE_PREFIX$3}`,
25114
25210
  handler: "LocalazyProjectController.getConnectedProject",
25115
25211
  config: {
25116
- policies: []
25212
+ policies: readPolicy$3
25117
25213
  }
25118
25214
  },
25119
25215
  {
@@ -25121,7 +25217,7 @@ const LocalazyProjectRoutes = [
25121
25217
  path: `${ROUTE_PREFIX$3}/webhooks`,
25122
25218
  handler: "LocalazyProjectController.getWebhookStatus",
25123
25219
  config: {
25124
- policies: []
25220
+ policies: readPolicy$3
25125
25221
  }
25126
25222
  },
25127
25223
  {
@@ -25129,7 +25225,7 @@ const LocalazyProjectRoutes = [
25129
25225
  path: `${ROUTE_PREFIX$3}/webhooks/setup`,
25130
25226
  handler: "LocalazyProjectController.setupWebhook",
25131
25227
  config: {
25132
- policies: []
25228
+ policies: settingsUpdatePolicy
25133
25229
  }
25134
25230
  },
25135
25231
  {
@@ -25137,7 +25233,7 @@ const LocalazyProjectRoutes = [
25137
25233
  path: `${ROUTE_PREFIX$3}/strapi-url`,
25138
25234
  handler: "LocalazyProjectController.getStrapiUrl",
25139
25235
  config: {
25140
- policies: []
25236
+ policies: readPolicy$3
25141
25237
  }
25142
25238
  }
25143
25239
  ];
@@ -25156,13 +25252,15 @@ const LocalazyPublicTransferRoutes = [
25156
25252
  }
25157
25253
  ];
25158
25254
  const ROUTE_PREFIX$1 = "/entry-exclusion";
25255
+ const readPolicy$2 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25256
+ const transferPolicy$1 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.TRANSFER] } }];
25159
25257
  const EntryExclusionRoutes = [
25160
25258
  {
25161
25259
  method: "GET",
25162
25260
  path: `${ROUTE_PREFIX$1}/:contentType/:documentId`,
25163
25261
  handler: "EntryExclusionController.getEntryExclusion",
25164
25262
  config: {
25165
- policies: []
25263
+ policies: readPolicy$2
25166
25264
  }
25167
25265
  },
25168
25266
  {
@@ -25170,7 +25268,7 @@ const EntryExclusionRoutes = [
25170
25268
  path: `${ROUTE_PREFIX$1}/:contentType/:documentId`,
25171
25269
  handler: "EntryExclusionController.setEntryExclusion",
25172
25270
  config: {
25173
- policies: []
25271
+ policies: transferPolicy$1
25174
25272
  }
25175
25273
  },
25176
25274
  {
@@ -25178,18 +25276,20 @@ const EntryExclusionRoutes = [
25178
25276
  path: `${ROUTE_PREFIX$1}/:contentType`,
25179
25277
  handler: "EntryExclusionController.getContentTypeExclusions",
25180
25278
  config: {
25181
- policies: []
25279
+ policies: readPolicy$2
25182
25280
  }
25183
25281
  }
25184
25282
  ];
25185
25283
  const ROUTE_PREFIX = "/activity-logs";
25284
+ const readPolicy$1 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25285
+ const transferPolicy = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.TRANSFER] } }];
25186
25286
  const ActivityLogsRoutes = [
25187
25287
  {
25188
25288
  method: "GET",
25189
25289
  path: `${ROUTE_PREFIX}`,
25190
25290
  handler: "ActivityLogsController.getSessions",
25191
25291
  config: {
25192
- policies: []
25292
+ policies: readPolicy$1
25193
25293
  }
25194
25294
  },
25195
25295
  {
@@ -25197,7 +25297,7 @@ const ActivityLogsRoutes = [
25197
25297
  path: `${ROUTE_PREFIX}/export`,
25198
25298
  handler: "ActivityLogsController.exportSessions",
25199
25299
  config: {
25200
- policies: []
25300
+ policies: readPolicy$1
25201
25301
  }
25202
25302
  },
25203
25303
  {
@@ -25205,7 +25305,7 @@ const ActivityLogsRoutes = [
25205
25305
  path: `${ROUTE_PREFIX}/:sessionId`,
25206
25306
  handler: "ActivityLogsController.getSession",
25207
25307
  config: {
25208
- policies: []
25308
+ policies: readPolicy$1
25209
25309
  }
25210
25310
  },
25211
25311
  {
@@ -25213,23 +25313,28 @@ const ActivityLogsRoutes = [
25213
25313
  path: `${ROUTE_PREFIX}`,
25214
25314
  handler: "ActivityLogsController.clearSessions",
25215
25315
  config: {
25216
- policies: []
25316
+ policies: transferPolicy
25217
25317
  }
25218
25318
  }
25219
25319
  ];
25320
+ const readPolicy = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
25220
25321
  const DebugBundleRoutes = [
25221
25322
  {
25222
25323
  method: "GET",
25223
25324
  path: "/activity-logs/:sessionId/bundle",
25224
25325
  handler: "DebugBundleController.getBundle",
25225
25326
  config: {
25226
- policies: []
25327
+ policies: readPolicy
25227
25328
  }
25228
25329
  }
25229
25330
  ];
25331
+ const withoutAdminPolicies = (routes2) => routes2.map((route) => ({
25332
+ ...route,
25333
+ config: { ...route.config, policies: [] }
25334
+ }));
25230
25335
  const routes = {
25231
25336
  "content-api": {
25232
- routes: [...StrapiRoutes]
25337
+ routes: withoutAdminPolicies(StrapiRoutes)
25233
25338
  },
25234
25339
  admin: {
25235
25340
  type: "admin",
@@ -25441,6 +25546,7 @@ const KEY$1 = "sync-cursor";
25441
25546
  const emptySyncCursor = {
25442
25547
  processedKeys: {}
25443
25548
  };
25549
+ const UI_PREF_FIELDS = ["defaultRoute", "activityLogsSort"];
25444
25550
  const PluginSettingsService = ({ strapi: strapi2 }) => ({
25445
25551
  async getContentTransferSetup() {
25446
25552
  const pluginStore = getStrapiStore(strapi2);
@@ -25477,6 +25583,20 @@ const PluginSettingsService = ({ strapi: strapi2 }) => ({
25477
25583
  });
25478
25584
  return newSettings;
25479
25585
  },
25586
+ // Counterpart to `updatePluginSettings` for the `read`-gated UI-prefs route.
25587
+ // Drops any field outside `UI_PREF_FIELDS` server-side so a `read`-only caller
25588
+ // cannot reach `webhookConfig` / `download.*` / `upload.*` via the merge.
25589
+ async updatePluginSettingsUiPrefs(prefs) {
25590
+ const sanitized = {};
25591
+ if (prefs && typeof prefs === "object") {
25592
+ for (const field of UI_PREF_FIELDS) {
25593
+ if (field in prefs) {
25594
+ sanitized[field] = prefs[field];
25595
+ }
25596
+ }
25597
+ }
25598
+ return this.updatePluginSettings(sanitized);
25599
+ },
25480
25600
  async getSyncCursor() {
25481
25601
  const pluginStore = getStrapiStore(strapi2);
25482
25602
  const cursor = await pluginStore.get({ key: KEY$1 });
@@ -25491,182 +25611,6 @@ const PluginSettingsService = ({ strapi: strapi2 }) => ({
25491
25611
  return cursor;
25492
25612
  }
25493
25613
  });
25494
- const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
25495
- async upload({ notificationService }) {
25496
- console.time("upload");
25497
- await notificationService.emit(EventType.UPLOAD, {
25498
- message: "Upload started"
25499
- });
25500
- const activityLogsService = getActivityLogsService();
25501
- const sessionId = await activityLogsService.startSession("upload", "Strapi User");
25502
- await activityLogsService.addEntry(sessionId, "Upload started");
25503
- let success = true;
25504
- const StrapiService2 = getStrapiService();
25505
- const StrapiI18nService2 = getStrapiI18nService();
25506
- const LocalazyUploadService2 = getLocalazyUploadService();
25507
- const EntryExclusionService2 = getEntryExclusionService();
25508
- const contentTransferSetup = await getPluginSettingsService().getContentTransferSetup();
25509
- if (!contentTransferSetup.has_setup) {
25510
- const message = "Content transfer setup is not set up.";
25511
- success = false;
25512
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25513
- success,
25514
- message
25515
- });
25516
- await activityLogsService.addEntry(sessionId, message);
25517
- await activityLogsService.finishSession(sessionId, "failed", message);
25518
- strapi2.log.info(message);
25519
- return;
25520
- }
25521
- const { setup: setup2 } = contentTransferSetup;
25522
- const collectionsNames = getCollectionsNames(setup2);
25523
- const models = await StrapiService2.getModels();
25524
- const strapiDefaultLocaleCode = await StrapiI18nService2.getDefaultLocaleCode();
25525
- const attemptedTuples = [];
25526
- let pickedFlattenStrapiContent = {};
25527
- for (const collectionName of collectionsNames) {
25528
- const currentModel = models.find((model) => model.collectionName === collectionName);
25529
- const modelUid = currentModel.uid;
25530
- if (!currentModel) {
25531
- strapi2.log.warn(`Model with uid ${modelUid} is not found.`);
25532
- continue;
25533
- }
25534
- const transferSetupModel = findSetupModelByCollectionName(setup2, collectionName);
25535
- if (!isCollectionTransferEnabled(setup2, collectionName)) {
25536
- const message2 = `Collection ${collectionName} transfer is disabled.`;
25537
- await notificationService.emit(EventType.UPLOAD, {
25538
- message: message2
25539
- });
25540
- await activityLogsService.addEntry(sessionId, message2);
25541
- strapi2.log.info(message2);
25542
- continue;
25543
- }
25544
- const currentTransferSetupModel = transferSetupModel[collectionName];
25545
- const pickPaths = getPickPathsWithComponents(currentTransferSetupModel);
25546
- if (!pickPaths.length) {
25547
- const message2 = `No fields for collection ${collectionName} transfer are enabled.`;
25548
- await notificationService.emit(EventType.UPLOAD, {
25549
- message: message2
25550
- });
25551
- await activityLogsService.addEntry(sessionId, message2);
25552
- strapi2.log.warn(message2);
25553
- continue;
25554
- }
25555
- const pickPathsWithUid = pickPaths.map((pickPath) => `${modelUid}.${pickPath}`);
25556
- let entries = await strapi2.documents(modelUid).findMany({
25557
- locUploadPLevel: 6,
25558
- status: "draft"
25559
- });
25560
- if (!entries.length) {
25561
- strapi2.log.info(`No entries found for model ${modelUid}`);
25562
- continue;
25563
- }
25564
- const excludedEntries = await EntryExclusionService2.getContentTypeExclusions(modelUid);
25565
- const filteredEntries = [];
25566
- for (const entry of entries) {
25567
- const isExcluded = excludedEntries.includes(entry.documentId);
25568
- if (!isExcluded) {
25569
- filteredEntries.push(entry);
25570
- }
25571
- }
25572
- entries = filteredEntries;
25573
- if (!entries.length) {
25574
- const message2 = `All entries for model ${collectionName} are excluded from translation`;
25575
- await notificationService.emit(EventType.UPLOAD, {
25576
- message: message2
25577
- });
25578
- await activityLogsService.addEntry(sessionId, message2);
25579
- strapi2.log.info(message2);
25580
- continue;
25581
- }
25582
- const message = `Excluding ${excludedEntries.length} entries for model ${collectionName} from upload. Entries to translate: ${entries.length}.`;
25583
- await notificationService.emit(EventType.UPLOAD, {
25584
- message
25585
- });
25586
- await activityLogsService.addEntry(sessionId, message);
25587
- strapi2.log.info(message);
25588
- if (strapiDefaultLocaleCode) {
25589
- for (const entry of entries) {
25590
- attemptedTuples.push({
25591
- uid: modelUid,
25592
- documentId: entry.documentId,
25593
- locale: strapiDefaultLocaleCode
25594
- });
25595
- }
25596
- }
25597
- entries = omitDeep(entries, ["locale", "createdAt", "updatedAt", "publishedAt"]);
25598
- entries.forEach((entry) => {
25599
- const flatten = flattenObject({
25600
- [modelUid]: entry
25601
- });
25602
- const pickedFlatten = pickEntries(flatten, pickPathsWithUid);
25603
- pickedFlattenStrapiContent = {
25604
- ...pickedFlattenStrapiContent,
25605
- ...pickedFlatten
25606
- };
25607
- });
25608
- const characterLimitsMetadata = getCharacterLimitsMetadata(pickedFlattenStrapiContent, modelUid);
25609
- pickedFlattenStrapiContent = {
25610
- ...pickedFlattenStrapiContent,
25611
- ...characterLimitsMetadata
25612
- };
25613
- }
25614
- const localazyLocaleCode = strapiDefaultLocaleCode ? isoStrapiToLocalazy(strapiDefaultLocaleCode) : config.default.LOCALAZY_DEFAULT_LOCALE;
25615
- const importFile = LocalazyUploadService2.createImportFileRepresentation(
25616
- localazyLocaleCode,
25617
- pickedFlattenStrapiContent
25618
- );
25619
- const uploadConfig = {
25620
- contentOptions: {
25621
- type: config.default.LOCALAZY_DEFAULT_FILE_EXTENSION
25622
- },
25623
- i18nOptions: { deprecate: "file" },
25624
- fileOptions: {
25625
- name: config.default.LOCALAZY_DEFAULT_FILE_NAME,
25626
- path: config.default.LOCALAZY_DEFAULT_FILE_PATH
25627
- }
25628
- };
25629
- await notificationService.emit(EventType.UPLOAD, {
25630
- message: "Uploading collections to Localazy..."
25631
- });
25632
- await activityLogsService.addEntry(sessionId, "Uploading collections to Localazy...");
25633
- try {
25634
- await LocalazyUploadService2.upload(importFile, uploadConfig);
25635
- await activityLogsService.recordAttemptedEntries(
25636
- sessionId,
25637
- attemptedTuples.map((t3) => ({ ...t3, status: "success" }))
25638
- );
25639
- } catch (error) {
25640
- success = false;
25641
- const errorMessage = `Upload to Localazy failed: ${error instanceof Error ? error.message : String(error)}`;
25642
- strapi2.log.error(errorMessage);
25643
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25644
- success,
25645
- message: errorMessage
25646
- });
25647
- await activityLogsService.addEntry(sessionId, errorMessage);
25648
- await activityLogsService.recordAttemptedEntries(
25649
- sessionId,
25650
- attemptedTuples.map((t3) => ({ ...t3, status: "failed", errorMessage }))
25651
- );
25652
- await activityLogsService.finishSession(sessionId, "failed", errorMessage);
25653
- console.timeEnd("upload");
25654
- return;
25655
- }
25656
- strapi2.log.info("Upload finished in");
25657
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25658
- success,
25659
- message: "Upload finished"
25660
- });
25661
- await activityLogsService.addEntry(sessionId, "Upload finished");
25662
- await activityLogsService.finishSession(
25663
- sessionId,
25664
- success ? "completed" : "failed",
25665
- success ? "Upload completed successfully" : "Upload finished with errors"
25666
- );
25667
- console.timeEnd("upload");
25668
- }
25669
- });
25670
25614
  var symbolTag$2 = "[object Symbol]";
25671
25615
  function isSymbol(value) {
25672
25616
  return typeof value == "symbol" || isObjectLike(value) && baseGetTag(value) == symbolTag$2;
@@ -25981,6 +25925,263 @@ function baseSet(object, path, value, customizer) {
25981
25925
  function set(object, path, value) {
25982
25926
  return object == null ? object : baseSet(object, path, value);
25983
25927
  }
25928
+ const BLOCKS_ATTRIBUTE_TYPE = "blocks";
25929
+ const projectBlocksFields = (entry, model, getModel) => {
25930
+ const cloned = cloneDeep(entry);
25931
+ walkAndProject(cloned, model, getModel);
25932
+ return cloned;
25933
+ };
25934
+ const walkAndProject = (value, model, getModel) => {
25935
+ if (!value || !model?.attributes) {
25936
+ return;
25937
+ }
25938
+ for (const [attributeName, attribute] of Object.entries(model.attributes)) {
25939
+ const fieldValue = value[attributeName];
25940
+ if (fieldValue === void 0 || fieldValue === null) {
25941
+ continue;
25942
+ }
25943
+ if (attribute.type === BLOCKS_ATTRIBUTE_TYPE) {
25944
+ value[attributeName] = projectBlocksValue(fieldValue);
25945
+ } else if (attribute.type === "component") {
25946
+ const componentModel = getModel(attribute.component);
25947
+ if (attribute.repeatable && Array.isArray(fieldValue)) {
25948
+ fieldValue.forEach((item) => walkAndProject(item, componentModel, getModel));
25949
+ } else if (isPlainObject(fieldValue)) {
25950
+ walkAndProject(fieldValue, componentModel, getModel);
25951
+ }
25952
+ } else if (attribute.type === "dynamiczone" && Array.isArray(fieldValue)) {
25953
+ fieldValue.forEach((item) => {
25954
+ if (item?.__component) {
25955
+ walkAndProject(item, getModel(item.__component), getModel);
25956
+ }
25957
+ });
25958
+ }
25959
+ }
25960
+ };
25961
+ const projectBlocksValue = (nodes) => {
25962
+ if (!Array.isArray(nodes)) {
25963
+ return nodes;
25964
+ }
25965
+ return nodes.map(projectNode);
25966
+ };
25967
+ const projectNode = (node) => {
25968
+ if (!isPlainObject(node)) {
25969
+ return {};
25970
+ }
25971
+ const projected = {};
25972
+ if (typeof node.text === "string") {
25973
+ projected.text = node.text;
25974
+ }
25975
+ if (Array.isArray(node.children)) {
25976
+ projected.children = node.children.map(projectNode);
25977
+ }
25978
+ return projected;
25979
+ };
25980
+ const overlayBlocksTranslation = (sourceAst, translated) => {
25981
+ if (!Array.isArray(sourceAst)) {
25982
+ return void 0;
25983
+ }
25984
+ return sourceAst.map((node, index2) => overlayNode(node, get(translated, [String(index2)])));
25985
+ };
25986
+ const overlayNode = (node, translatedNode) => {
25987
+ if (!isPlainObject(node)) {
25988
+ return cloneDeep(node);
25989
+ }
25990
+ if (typeof node.text === "string") {
25991
+ const translatedText = isPlainObject(translatedNode) ? translatedNode.text : void 0;
25992
+ return typeof translatedText === "string" ? { ...node, text: translatedText } : cloneDeep(node);
25993
+ }
25994
+ if (Array.isArray(node.children)) {
25995
+ return {
25996
+ ...node,
25997
+ children: node.children.map(
25998
+ (child, index2) => overlayNode(child, translatedNode ? get(translatedNode, ["children", String(index2)]) : void 0)
25999
+ )
26000
+ };
26001
+ }
26002
+ return cloneDeep(node);
26003
+ };
26004
+ const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
26005
+ async upload({ notificationService }) {
26006
+ console.time("upload");
26007
+ await notificationService.emit(EventType.UPLOAD, {
26008
+ message: "Upload started"
26009
+ });
26010
+ const activityLogsService = getActivityLogsService();
26011
+ const sessionId = await activityLogsService.startSession("upload", "Strapi User");
26012
+ await activityLogsService.addEntry(sessionId, "Upload started");
26013
+ let success = true;
26014
+ const StrapiService2 = getStrapiService();
26015
+ const StrapiI18nService2 = getStrapiI18nService();
26016
+ const LocalazyUploadService2 = getLocalazyUploadService();
26017
+ const EntryExclusionService2 = getEntryExclusionService();
26018
+ const contentTransferSetup = await getPluginSettingsService().getContentTransferSetup();
26019
+ if (!contentTransferSetup.has_setup) {
26020
+ const message = "Content transfer setup is not set up.";
26021
+ success = false;
26022
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26023
+ success,
26024
+ message
26025
+ });
26026
+ await activityLogsService.addEntry(sessionId, message);
26027
+ await activityLogsService.finishSession(sessionId, "failed", message);
26028
+ strapi2.log.info(message);
26029
+ return;
26030
+ }
26031
+ const { setup: setup2 } = contentTransferSetup;
26032
+ const collectionsNames = getCollectionsNames(setup2);
26033
+ const models = await StrapiService2.getModels();
26034
+ const strapiDefaultLocaleCode = await StrapiI18nService2.getDefaultLocaleCode();
26035
+ const attemptedTuples = [];
26036
+ let pickedFlattenStrapiContent = {};
26037
+ for (const collectionName of collectionsNames) {
26038
+ const currentModel = models.find((model) => model.collectionName === collectionName);
26039
+ const modelUid = currentModel.uid;
26040
+ if (!currentModel) {
26041
+ strapi2.log.warn(`Model with uid ${modelUid} is not found.`);
26042
+ continue;
26043
+ }
26044
+ const transferSetupModel = findSetupModelByCollectionName(setup2, collectionName);
26045
+ if (!isCollectionTransferEnabled(setup2, collectionName)) {
26046
+ const message2 = `Collection ${collectionName} transfer is disabled.`;
26047
+ await notificationService.emit(EventType.UPLOAD, {
26048
+ message: message2
26049
+ });
26050
+ await activityLogsService.addEntry(sessionId, message2);
26051
+ strapi2.log.info(message2);
26052
+ continue;
26053
+ }
26054
+ const currentTransferSetupModel = transferSetupModel[collectionName];
26055
+ const pickPaths = getPickPathsWithComponents(currentTransferSetupModel);
26056
+ if (!pickPaths.length) {
26057
+ const message2 = `No fields for collection ${collectionName} transfer are enabled.`;
26058
+ await notificationService.emit(EventType.UPLOAD, {
26059
+ message: message2
26060
+ });
26061
+ await activityLogsService.addEntry(sessionId, message2);
26062
+ strapi2.log.warn(message2);
26063
+ continue;
26064
+ }
26065
+ const pickPathsWithUid = pickPaths.map((pickPath) => `${modelUid}.${pickPath}`);
26066
+ let entries = await strapi2.documents(modelUid).findMany({
26067
+ locUploadPLevel: 6,
26068
+ status: "draft"
26069
+ });
26070
+ if (!entries.length) {
26071
+ strapi2.log.info(`No entries found for model ${modelUid}`);
26072
+ continue;
26073
+ }
26074
+ const excludedEntries = await EntryExclusionService2.getContentTypeExclusions(modelUid);
26075
+ const filteredEntries = [];
26076
+ for (const entry of entries) {
26077
+ const isExcluded = excludedEntries.includes(entry.documentId);
26078
+ if (!isExcluded) {
26079
+ filteredEntries.push(entry);
26080
+ }
26081
+ }
26082
+ entries = filteredEntries;
26083
+ if (!entries.length) {
26084
+ const message2 = `All entries for model ${collectionName} are excluded from translation`;
26085
+ await notificationService.emit(EventType.UPLOAD, {
26086
+ message: message2
26087
+ });
26088
+ await activityLogsService.addEntry(sessionId, message2);
26089
+ strapi2.log.info(message2);
26090
+ continue;
26091
+ }
26092
+ const message = `Excluding ${excludedEntries.length} entries for model ${collectionName} from upload. Entries to translate: ${entries.length}.`;
26093
+ await notificationService.emit(EventType.UPLOAD, {
26094
+ message
26095
+ });
26096
+ await activityLogsService.addEntry(sessionId, message);
26097
+ strapi2.log.info(message);
26098
+ if (strapiDefaultLocaleCode) {
26099
+ for (const entry of entries) {
26100
+ attemptedTuples.push({
26101
+ uid: modelUid,
26102
+ documentId: entry.documentId,
26103
+ locale: strapiDefaultLocaleCode
26104
+ });
26105
+ }
26106
+ }
26107
+ entries = omitDeep(entries, ["locale", "createdAt", "updatedAt", "publishedAt"]);
26108
+ entries.forEach((entry) => {
26109
+ const projectedEntry = projectBlocksFields(
26110
+ entry,
26111
+ strapi2.getModel(modelUid),
26112
+ (uid) => strapi2.getModel(uid)
26113
+ );
26114
+ const flatten = flattenObject({
26115
+ [modelUid]: projectedEntry
26116
+ });
26117
+ const pickedFlatten = pickEntries(flatten, pickPathsWithUid);
26118
+ pickedFlattenStrapiContent = {
26119
+ ...pickedFlattenStrapiContent,
26120
+ ...pickedFlatten
26121
+ };
26122
+ });
26123
+ const characterLimitsMetadata = getCharacterLimitsMetadata(pickedFlattenStrapiContent, modelUid);
26124
+ pickedFlattenStrapiContent = {
26125
+ ...pickedFlattenStrapiContent,
26126
+ ...characterLimitsMetadata
26127
+ };
26128
+ }
26129
+ const localazyLocaleCode = strapiDefaultLocaleCode ? isoStrapiToLocalazy(strapiDefaultLocaleCode) : config.default.LOCALAZY_DEFAULT_LOCALE;
26130
+ const importFile = LocalazyUploadService2.createImportFileRepresentation(
26131
+ localazyLocaleCode,
26132
+ pickedFlattenStrapiContent
26133
+ );
26134
+ const uploadConfig = {
26135
+ contentOptions: {
26136
+ type: config.default.LOCALAZY_DEFAULT_FILE_EXTENSION
26137
+ },
26138
+ i18nOptions: { deprecate: "file" },
26139
+ fileOptions: {
26140
+ name: config.default.LOCALAZY_DEFAULT_FILE_NAME,
26141
+ path: config.default.LOCALAZY_DEFAULT_FILE_PATH
26142
+ }
26143
+ };
26144
+ await notificationService.emit(EventType.UPLOAD, {
26145
+ message: "Uploading collections to Localazy..."
26146
+ });
26147
+ await activityLogsService.addEntry(sessionId, "Uploading collections to Localazy...");
26148
+ try {
26149
+ await LocalazyUploadService2.upload(importFile, uploadConfig);
26150
+ await activityLogsService.recordAttemptedEntries(
26151
+ sessionId,
26152
+ attemptedTuples.map((t3) => ({ ...t3, status: "success" }))
26153
+ );
26154
+ } catch (error) {
26155
+ success = false;
26156
+ const errorMessage = `Upload to Localazy failed: ${error instanceof Error ? error.message : String(error)}`;
26157
+ strapi2.log.error(errorMessage);
26158
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26159
+ success,
26160
+ message: errorMessage
26161
+ });
26162
+ await activityLogsService.addEntry(sessionId, errorMessage);
26163
+ await activityLogsService.recordAttemptedEntries(
26164
+ sessionId,
26165
+ attemptedTuples.map((t3) => ({ ...t3, status: "failed", errorMessage }))
26166
+ );
26167
+ await activityLogsService.finishSession(sessionId, "failed", errorMessage);
26168
+ console.timeEnd("upload");
26169
+ return;
26170
+ }
26171
+ strapi2.log.info("Upload finished in");
26172
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26173
+ success,
26174
+ message: "Upload finished"
26175
+ });
26176
+ await activityLogsService.addEntry(sessionId, "Upload finished");
26177
+ await activityLogsService.finishSession(
26178
+ sessionId,
26179
+ success ? "completed" : "failed",
26180
+ success ? "Upload completed successfully" : "Upload finished with errors"
26181
+ );
26182
+ console.timeEnd("upload");
26183
+ }
26184
+ });
25984
26185
  const hasDynamicZoneKeySegment = (parsedKey) => {
25985
26186
  return parsedKey.some((segment) => segment.includes(";"));
25986
26187
  };
@@ -26053,7 +26254,7 @@ const shouldSetDownloadedProperty = (modelContentTransferSetup, parsedKeyRest) =
26053
26254
  return "no";
26054
26255
  }
26055
26256
  };
26056
- const getFilteredLanguagesCodesForDownload = async (languagesCodes) => {
26257
+ const getFilteredLanguagesCodesForDownload = async (languagesCodes, requestedUiLanguages) => {
26057
26258
  const pluginSettingsServiceHelper = new PluginSettingsServiceHelper();
26058
26259
  const requestInitiatorHelper = new RequestInitiatorHelper(strapi);
26059
26260
  await pluginSettingsServiceHelper.setup();
@@ -26061,7 +26262,7 @@ const getFilteredLanguagesCodesForDownload = async (languagesCodes) => {
26061
26262
  if (requestInitiatorHelper.isInitiatedByLocalazyWebhook()) {
26062
26263
  localLanguagesCodes = pluginSettingsServiceHelper.getWebhookLanguagesCodes();
26063
26264
  } else if (requestInitiatorHelper.isInitiatedByLocalazyPluginUI()) {
26064
- localLanguagesCodes = pluginSettingsServiceHelper.getUiLanguagesCodes();
26265
+ localLanguagesCodes = requestedUiLanguages ?? pluginSettingsServiceHelper.getUiLanguagesCodes();
26065
26266
  } else {
26066
26267
  strapi.log.warn("Called by an unknown initiator.");
26067
26268
  return languagesCodes;
@@ -26074,7 +26275,8 @@ const getFilteredLanguagesCodesForDownload = async (languagesCodes) => {
26074
26275
  const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
26075
26276
  async download({
26076
26277
  notificationService,
26077
- fullSync = false
26278
+ fullSync = false,
26279
+ requestedUiLanguages
26078
26280
  }) {
26079
26281
  console.time("download");
26080
26282
  const syncMode = fullSync ? "Full sync" : "Incremental sync";
@@ -26154,7 +26356,7 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
26154
26356
  return;
26155
26357
  }
26156
26358
  let languagesCodes = projectLanguagesWithoutSourceLanguage.map((language3) => language3.code);
26157
- languagesCodes = await getFilteredLanguagesCodesForDownload(languagesCodes);
26359
+ languagesCodes = await getFilteredLanguagesCodesForDownload(languagesCodes, requestedUiLanguages);
26158
26360
  const strapiUnsupportedLanguages = [];
26159
26361
  const strapiLocales = await StrapiI18nService2.getLocales();
26160
26362
  for (const isoLocalazy of languagesCodes) {
@@ -26667,6 +26869,9 @@ const isRepeatable = (attributeObj) => {
26667
26869
  const isRelation = (attributeObj) => {
26668
26870
  return attributeObj.type === "relation" && attributeObj.target !== "plugin::upload.file";
26669
26871
  };
26872
+ const isBlocks = (attributeObj) => {
26873
+ return attributeObj.type === BLOCKS_ATTRIBUTE_TYPE;
26874
+ };
26670
26875
  const findModel = (models, uid) => {
26671
26876
  const model = models.find((model2) => model2.uid === uid);
26672
26877
  return model;
@@ -26810,7 +27015,11 @@ const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry
26810
27015
  newPrefixBase = `${dzParamKey}.${baseEntryDZIndex}`;
26811
27016
  newPrefix = `${newPrefixBase}.${objectKey}`;
26812
27017
  }
26813
- set(createEntry, newPrefix, value);
27018
+ const valueToSet = isBlocks(attribute) ? overlayBlocksTranslation(get(baseEntry, newPrefix), value) : value;
27019
+ if (valueToSet === void 0) {
27020
+ return;
27021
+ }
27022
+ set(createEntry, newPrefix, valueToSet);
26814
27023
  if (component) {
26815
27024
  const componentKeyToSet = `${newPrefixBase}.__component`;
26816
27025
  set(createEntry, componentKeyToSet, component);