@localazy/strapi-plugin 1.3.0 → 1.6.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.
- package/README.md +30 -0
- package/dist/_chunks/{FetchIdentity-BJGoZPpM.mjs → FetchIdentity-Bm7bc5bS.mjs} +36 -44
- package/dist/_chunks/{FetchIdentity-CtBRO-Cn.js → FetchIdentity-CcEjakiz.js} +25 -33
- package/dist/_chunks/{LanguagesSelector-DJxgCwgM.mjs → LanguagesSelector-B1rwN7-Y.mjs} +4 -3
- package/dist/_chunks/{LanguagesSelector-CNaKrS-m.js → LanguagesSelector-DejYCwBl.js} +4 -3
- package/dist/_chunks/{LocalazyApp-CJRpsTKr.mjs → LocalazyApp-C4kbsnQh.mjs} +148 -35
- package/dist/_chunks/{LocalazyApp-B1qCCEPe.js → LocalazyApp-jPO7Yr1S.js} +154 -41
- package/dist/_chunks/{LocalazyContentTransferSetup-CLAWn95U.mjs → LocalazyContentTransferSetup-C1wDD9hA.mjs} +58 -22
- package/dist/_chunks/{LocalazyContentTransferSetup-CCxiLHdG.js → LocalazyContentTransferSetup-DZh4ZdSi.js} +63 -27
- package/dist/_chunks/{LocalazyGlobalSettings-BJ5qfFfK.js → LocalazyGlobalSettings-D76it6rn.js} +57 -26
- package/dist/_chunks/{LocalazyGlobalSettings-Z-4Ykc_J.mjs → LocalazyGlobalSettings-DOW5rjLn.mjs} +56 -25
- package/dist/_chunks/{LocalazyPanel-CL_mzzfD.mjs → LocalazyPanel-C_Z4W49T.mjs} +12 -6
- package/dist/_chunks/{LocalazyPanel-DE3TtHOQ.js → LocalazyPanel-D2LQpqii.js} +14 -8
- package/dist/_chunks/{LocalazyStatusColumn-R5n6q_cx.mjs → LocalazyStatusColumn-C_ZCd_s7.mjs} +10 -4
- package/dist/_chunks/{LocalazyStatusColumn-BMLcklG-.js → LocalazyStatusColumn-Dy6N4_X6.js} +10 -4
- package/dist/_chunks/{RequireLocalazyAuth-WKKFdQlR.js → RequireLocalazyAuth-BVwF0bRC.js} +31 -4
- package/dist/_chunks/{RequireLocalazyAuth-Dzsu6UNS.mjs → RequireLocalazyAuth-DNhTZZ_6.mjs} +32 -5
- package/dist/_chunks/{entry-exclusion-service-DxqTlZFR.mjs → entry-exclusion-service-CF_yNCly.mjs} +1 -1
- package/dist/_chunks/{entry-exclusion-service-CggmAKxq.js → entry-exclusion-service-CH3ZoJQN.js} +1 -1
- package/dist/_chunks/{has-model-changed-FMGVcFHU.mjs → has-model-changed-CVJEuGxM.mjs} +2 -2
- package/dist/_chunks/{has-model-changed-BR53L6pA.js → has-model-changed-DdYbyv0v.js} +2 -2
- package/dist/_chunks/{i18n-QelOdIB2.mjs → i18n-76ox2llT.mjs} +9 -2
- package/dist/_chunks/{i18n-CAsbU4pi.js → i18n-C5ucROBh.js} +9 -2
- package/dist/_chunks/{index-BmxGKspv.js → index-CEGaWWh3.js} +33 -11
- package/dist/_chunks/{index-BK7lmZSN.js → index-CTkxoioB.js} +1 -0
- package/dist/_chunks/{index-toauQlIK.mjs → index-DP2ugzc_.mjs} +34 -12
- package/dist/_chunks/{index-CHjIMO9T.mjs → index-shryj0jT.mjs} +19 -18
- package/dist/_chunks/{strapi-api-base-CT9lknwW.js → strapi-api-base-CCUuu7EY.js} +1 -1
- package/dist/_chunks/{strapi-api-base-BflplVsH.mjs → strapi-api-base-IiMEtDoH.mjs} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/components/LocalazyStatusColumn.d.ts +1 -1
- package/dist/admin/src/constants/permissions.d.ts +29 -0
- package/dist/admin/src/modules/@common/components/LanguagesSelector.d.ts +1 -0
- package/dist/admin/src/modules/activity-logs/locale/en.d.ts +4 -0
- package/dist/admin/src/modules/activity-logs/services/debug-bundle-service.d.ts +10 -0
- package/dist/admin/src/modules/login/locale/en.d.ts +1 -0
- package/dist/admin/src/modules/plugin-settings/components/Tree.d.ts +1 -0
- package/dist/admin/src/modules/plugin-settings/components/TreeItem.d.ts +1 -0
- package/dist/admin/src/modules/plugin-settings/components/WebhookSetup.d.ts +4 -1
- package/dist/admin/src/modules/plugin-settings/locale/en.d.ts +2 -0
- package/dist/admin/src/modules/plugin-settings/services/plugin-settings-service.d.ts +4 -0
- package/dist/server/index.js +665 -38
- package/dist/server/index.mjs +665 -39
- package/dist/server/src/bootstrap.d.ts +1 -1
- package/dist/server/src/constants/permissions.d.ts +38 -0
- package/dist/server/src/controllers/debug-bundle-controller.d.ts +7 -0
- package/dist/server/src/controllers/index.d.ts +6 -0
- package/dist/server/src/controllers/plugin-settings-controller.d.ts +1 -0
- package/dist/server/src/core/index.d.ts +5 -1
- package/dist/server/src/db/model/activity-logs.d.ts +10 -0
- package/dist/server/src/index.d.ts +64 -8
- package/dist/server/src/routes/activity-logs-routes.d.ts +20 -3
- package/dist/server/src/routes/debug-bundle-routes.d.ts +14 -0
- package/dist/server/src/routes/entry-exclusion-routes.d.ts +20 -3
- package/dist/server/src/routes/index.d.ts +52 -6
- package/dist/server/src/routes/localazy-auth-routes.d.ts +6 -1
- package/dist/server/src/routes/localazy-project-routes.d.ts +20 -3
- package/dist/server/src/routes/localazy-transfer-routes.d.ts +6 -1
- package/dist/server/src/routes/localazy-user-routes.d.ts +20 -3
- package/dist/server/src/routes/plugin-settings-routes.d.ts +20 -3
- package/dist/server/src/routes/strapi-routes.d.ts +20 -3
- package/dist/server/src/services/activity-logs-service.d.ts +3 -1
- package/dist/server/src/services/index.d.ts +5 -1
- package/dist/server/src/services/localazy-transfer-download-service.d.ts +2 -1
- package/dist/server/src/services/plugin-settings-service.d.ts +4 -0
- package/dist/server/src/utils/build-debug-bundle.d.ts +68 -0
- package/dist/server/src/utils/sanitize-debug-bundle.d.ts +25 -0
- package/package.json +2 -1
package/dist/server/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import require$$0$4 from "http";
|
|
2
|
-
import require$$1$4 from "fs";
|
|
2
|
+
import require$$1$4, { promises } from "fs";
|
|
3
3
|
import require$$1$1 from "zlib";
|
|
4
4
|
import require$$1 from "path";
|
|
5
5
|
import require$$4 from "stream";
|
|
@@ -9,6 +9,7 @@ import require$$0$2 from "crypto";
|
|
|
9
9
|
import require$$0$3 from "events";
|
|
10
10
|
import require$$2 from "timers";
|
|
11
11
|
import require$$8, { WebSocketServer } from "ws";
|
|
12
|
+
import JSZip from "jszip";
|
|
12
13
|
var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
|
|
13
14
|
function getDefaultExportFromCjs(x2) {
|
|
14
15
|
return x2 && x2.__esModule && Object.prototype.hasOwnProperty.call(x2, "default") ? x2["default"] : x2;
|
|
@@ -20519,7 +20520,7 @@ var distExports = dist$1.exports;
|
|
|
20519
20520
|
const io = /* @__PURE__ */ getDefaultExportFromCjs(distExports);
|
|
20520
20521
|
const { Server: Server2, Namespace, Socket: Socket3 } = io;
|
|
20521
20522
|
const name = "@localazy/strapi-plugin";
|
|
20522
|
-
const version = "1.
|
|
20523
|
+
const version = "1.6.0";
|
|
20523
20524
|
const description = "The official Strapi Plugin by Localazy.";
|
|
20524
20525
|
const keywords = [
|
|
20525
20526
|
"strapi",
|
|
@@ -20589,6 +20590,7 @@ const scripts = {
|
|
|
20589
20590
|
prepare: "husky || true"
|
|
20590
20591
|
};
|
|
20591
20592
|
const dependencies = {
|
|
20593
|
+
jszip: "^3.10.1",
|
|
20592
20594
|
shelljs: "^0.8.5",
|
|
20593
20595
|
ws: "^8.18.0"
|
|
20594
20596
|
};
|
|
@@ -20702,7 +20704,60 @@ const _package$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
|
|
|
20702
20704
|
version
|
|
20703
20705
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
20704
20706
|
const PLUGIN_NAME = strapi$1.name;
|
|
20705
|
-
const
|
|
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);
|
|
20706
20761
|
if (strapi2.plugin(PLUGIN_NAME)?.config("enableSocketIO", true)) {
|
|
20707
20762
|
process.nextTick(async () => {
|
|
20708
20763
|
const io2 = new Server2(strapi2.server.httpServer, {
|
|
@@ -24285,6 +24340,9 @@ const PluginSettingsController = ({ strapi: _strapi }) => ({
|
|
|
24285
24340
|
async updatePluginSettings(ctx) {
|
|
24286
24341
|
ctx.body = await getPluginSettingsService().updatePluginSettings(ctx.request.body);
|
|
24287
24342
|
},
|
|
24343
|
+
async updatePluginSettingsUiPrefs(ctx) {
|
|
24344
|
+
ctx.body = await getPluginSettingsService().updatePluginSettingsUiPrefs(ctx.request.body);
|
|
24345
|
+
},
|
|
24288
24346
|
async getSyncCursor(ctx) {
|
|
24289
24347
|
ctx.body = await getPluginSettingsService().getSyncCursor();
|
|
24290
24348
|
}
|
|
@@ -24384,6 +24442,8 @@ const LocalazyTransferController = ({ strapi: strapi2 }) => ({
|
|
|
24384
24442
|
try {
|
|
24385
24443
|
const LocalazyTransferDownloadService2 = getLocalazyTransferDownloadService();
|
|
24386
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;
|
|
24387
24447
|
const requestInitiatorHelper = new RequestInitiatorHelper(strapi2);
|
|
24388
24448
|
if (requestInitiatorHelper.isInitiatedByLocalazyWebhook()) {
|
|
24389
24449
|
const pluginSettingsServiceHelper = new PluginSettingsServiceHelper();
|
|
@@ -24393,7 +24453,8 @@ const LocalazyTransferController = ({ strapi: strapi2 }) => ({
|
|
|
24393
24453
|
setTimeout(
|
|
24394
24454
|
() => LocalazyTransferDownloadService2.download({
|
|
24395
24455
|
notificationService: JobNotificationService$1,
|
|
24396
|
-
fullSync
|
|
24456
|
+
fullSync,
|
|
24457
|
+
requestedUiLanguages
|
|
24397
24458
|
}),
|
|
24398
24459
|
1e3
|
|
24399
24460
|
);
|
|
@@ -24488,6 +24549,413 @@ const ActivityLogsController = ({ strapi: _strapi }) => ({
|
|
|
24488
24549
|
ctx.body = { success: true };
|
|
24489
24550
|
}
|
|
24490
24551
|
});
|
|
24552
|
+
const URL_SECRET_KEYS = ["token", "secret", "signature", "key", "apikey", "api_key"];
|
|
24553
|
+
const DEBUG_BUNDLE_ENV_ALLOWLIST = [
|
|
24554
|
+
"STRAPI_ADMIN_LOCALAZY_ENV",
|
|
24555
|
+
"STRAPI_ADMIN_BACKEND_URL",
|
|
24556
|
+
"NODE_ENV",
|
|
24557
|
+
"STRAPI_TELEMETRY_DISABLED"
|
|
24558
|
+
];
|
|
24559
|
+
const redactIdentity = (identity2) => {
|
|
24560
|
+
if (!identity2) return null;
|
|
24561
|
+
return {
|
|
24562
|
+
userId: identity2.user?.id ?? "",
|
|
24563
|
+
name: identity2.user?.name ?? "",
|
|
24564
|
+
scope: identity2.scope ?? "",
|
|
24565
|
+
hasAccessToken: Boolean(identity2.accessToken)
|
|
24566
|
+
};
|
|
24567
|
+
};
|
|
24568
|
+
const scrubUrlSecrets = (input) => {
|
|
24569
|
+
if (typeof input !== "string") return input;
|
|
24570
|
+
if (!/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(input) && !input.includes("?")) return input;
|
|
24571
|
+
try {
|
|
24572
|
+
const url2 = new URL(input);
|
|
24573
|
+
let mutated = false;
|
|
24574
|
+
for (const k2 of [...url2.searchParams.keys()]) {
|
|
24575
|
+
if (URL_SECRET_KEYS.includes(k2.toLowerCase())) {
|
|
24576
|
+
url2.searchParams.delete(k2);
|
|
24577
|
+
mutated = true;
|
|
24578
|
+
}
|
|
24579
|
+
}
|
|
24580
|
+
return mutated ? url2.toString() : input;
|
|
24581
|
+
} catch {
|
|
24582
|
+
return input;
|
|
24583
|
+
}
|
|
24584
|
+
};
|
|
24585
|
+
const pickEnvAllowlist = (env) => {
|
|
24586
|
+
const out = {};
|
|
24587
|
+
for (const key of DEBUG_BUNDLE_ENV_ALLOWLIST) {
|
|
24588
|
+
const raw = env[key];
|
|
24589
|
+
const present = raw !== void 0;
|
|
24590
|
+
out[key] = {
|
|
24591
|
+
present,
|
|
24592
|
+
value: present ? raw : null
|
|
24593
|
+
};
|
|
24594
|
+
}
|
|
24595
|
+
return out;
|
|
24596
|
+
};
|
|
24597
|
+
const serializeContentTypeSchema = (contentType) => {
|
|
24598
|
+
if (!contentType || typeof contentType !== "object") return null;
|
|
24599
|
+
const ct = contentType;
|
|
24600
|
+
return {
|
|
24601
|
+
kind: ct.kind,
|
|
24602
|
+
collectionName: ct.collectionName,
|
|
24603
|
+
info: ct.info,
|
|
24604
|
+
options: ct.options,
|
|
24605
|
+
pluginOptions: ct.pluginOptions,
|
|
24606
|
+
attributes: ct.attributes
|
|
24607
|
+
};
|
|
24608
|
+
};
|
|
24609
|
+
const DOCUMENT_INTERNAL_FIELDS = ["createdBy", "updatedBy"];
|
|
24610
|
+
const stripDocumentInternals = (doc) => {
|
|
24611
|
+
if (!doc || typeof doc !== "object") return doc;
|
|
24612
|
+
const clone = { ...doc };
|
|
24613
|
+
for (const field of DOCUMENT_INTERNAL_FIELDS) {
|
|
24614
|
+
delete clone[field];
|
|
24615
|
+
}
|
|
24616
|
+
return clone;
|
|
24617
|
+
};
|
|
24618
|
+
class SessionNotFoundError extends Error {
|
|
24619
|
+
constructor(sessionId) {
|
|
24620
|
+
super(`Session ${sessionId} not found`);
|
|
24621
|
+
this.name = "SessionNotFoundError";
|
|
24622
|
+
}
|
|
24623
|
+
}
|
|
24624
|
+
const DEBUG_BUNDLE_SCHEMA_VERSION = 1;
|
|
24625
|
+
const CAPS = {
|
|
24626
|
+
perEntryBytes: 1 * 1024 * 1024,
|
|
24627
|
+
// 1 MB
|
|
24628
|
+
totalEntries: 100,
|
|
24629
|
+
errorLogBytes: 2 * 1024 * 1024,
|
|
24630
|
+
// 2 MB
|
|
24631
|
+
consoleErrorsLines: 200,
|
|
24632
|
+
browserPayloadBytes: 64 * 1024
|
|
24633
|
+
// 64 KB
|
|
24634
|
+
};
|
|
24635
|
+
const selectAttemptedEntries = (attempted) => {
|
|
24636
|
+
const failedByKey = /* @__PURE__ */ new Map();
|
|
24637
|
+
const successByKey = /* @__PURE__ */ new Map();
|
|
24638
|
+
for (const record of attempted) {
|
|
24639
|
+
const key = `${record.uid}|${record.documentId}|${record.locale}`;
|
|
24640
|
+
const selected = {
|
|
24641
|
+
uid: record.uid,
|
|
24642
|
+
documentId: record.documentId,
|
|
24643
|
+
locale: record.locale,
|
|
24644
|
+
status: record.status,
|
|
24645
|
+
attemptedAt: record.attemptedAt
|
|
24646
|
+
};
|
|
24647
|
+
if (record.status === "failed") {
|
|
24648
|
+
successByKey.delete(key);
|
|
24649
|
+
if (!failedByKey.has(key)) failedByKey.set(key, selected);
|
|
24650
|
+
} else if (!failedByKey.has(key) && !successByKey.has(key)) {
|
|
24651
|
+
successByKey.set(key, selected);
|
|
24652
|
+
}
|
|
24653
|
+
}
|
|
24654
|
+
return [...failedByKey.values(), ...successByKey.values()];
|
|
24655
|
+
};
|
|
24656
|
+
const formatTimestampForFilename = (ms2) => new Date(ms2).toISOString().replace(/[:.]/g, "-");
|
|
24657
|
+
const safeUidForPath = (uid) => uid.replace(/::/g, "--").replace(/\./g, "-");
|
|
24658
|
+
const decodeBrowserPayload = (encoded) => {
|
|
24659
|
+
const markers = [];
|
|
24660
|
+
if (!encoded) return { payload: null, truncationMarkers: markers };
|
|
24661
|
+
try {
|
|
24662
|
+
const raw = Buffer.from(encoded, "base64").toString("utf8");
|
|
24663
|
+
const rawBytes = Buffer.byteLength(raw, "utf8");
|
|
24664
|
+
if (rawBytes > CAPS.browserPayloadBytes) {
|
|
24665
|
+
markers.push({ kind: "browser-payload-truncated", originalSizeBytes: rawBytes });
|
|
24666
|
+
return { payload: null, truncationMarkers: markers };
|
|
24667
|
+
}
|
|
24668
|
+
const parsed = JSON.parse(raw);
|
|
24669
|
+
if (parsed && Array.isArray(parsed.consoleErrors) && parsed.consoleErrors.length > CAPS.consoleErrorsLines) {
|
|
24670
|
+
markers.push({ kind: "console-errors-truncated", originalCount: parsed.consoleErrors.length });
|
|
24671
|
+
parsed.consoleErrors = parsed.consoleErrors.slice(0, CAPS.consoleErrorsLines);
|
|
24672
|
+
}
|
|
24673
|
+
return { payload: parsed, truncationMarkers: markers };
|
|
24674
|
+
} catch {
|
|
24675
|
+
return { payload: null, truncationMarkers: markers };
|
|
24676
|
+
}
|
|
24677
|
+
};
|
|
24678
|
+
const deepScrubUrls = (value) => {
|
|
24679
|
+
if (value == null) return value;
|
|
24680
|
+
if (typeof value === "string") return scrubUrlSecrets(value);
|
|
24681
|
+
if (Array.isArray(value)) return value.map(deepScrubUrls);
|
|
24682
|
+
if (typeof value === "object") {
|
|
24683
|
+
const out = {};
|
|
24684
|
+
for (const [k2, v2] of Object.entries(value)) {
|
|
24685
|
+
out[k2] = deepScrubUrls(v2);
|
|
24686
|
+
}
|
|
24687
|
+
return out;
|
|
24688
|
+
}
|
|
24689
|
+
return value;
|
|
24690
|
+
};
|
|
24691
|
+
const sanitizePluginSettings = (settings) => {
|
|
24692
|
+
const cloned = JSON.parse(JSON.stringify(settings ?? {}));
|
|
24693
|
+
if (cloned.webhookConfig?.url) {
|
|
24694
|
+
cloned.webhookConfig.url = scrubUrlSecrets(cloned.webhookConfig.url);
|
|
24695
|
+
}
|
|
24696
|
+
return cloned;
|
|
24697
|
+
};
|
|
24698
|
+
const sanitizeSession = (session) => {
|
|
24699
|
+
const cloned = JSON.parse(JSON.stringify(session));
|
|
24700
|
+
for (const entry of cloned.entries ?? []) {
|
|
24701
|
+
if (entry.data !== void 0) {
|
|
24702
|
+
entry.data = deepScrubUrls(entry.data);
|
|
24703
|
+
}
|
|
24704
|
+
}
|
|
24705
|
+
return cloned;
|
|
24706
|
+
};
|
|
24707
|
+
const buildErrorLog = (session) => {
|
|
24708
|
+
const lines = [];
|
|
24709
|
+
for (const entry of session.entries ?? []) {
|
|
24710
|
+
const ts = Number.isFinite(entry.timestamp) ? new Date(entry.timestamp).toISOString() : "unknown";
|
|
24711
|
+
lines.push(`${ts} ${entry.message}`);
|
|
24712
|
+
}
|
|
24713
|
+
if (session.status === "failed" && session.summary) {
|
|
24714
|
+
lines.push(`ERROR: ${session.summary}`);
|
|
24715
|
+
}
|
|
24716
|
+
const full = lines.join("\n");
|
|
24717
|
+
const fullBytes = Buffer.byteLength(full, "utf8");
|
|
24718
|
+
if (fullBytes <= CAPS.errorLogBytes) {
|
|
24719
|
+
return { text: full, markers: [] };
|
|
24720
|
+
}
|
|
24721
|
+
const truncated = Buffer.from(full, "utf8").subarray(fullBytes - CAPS.errorLogBytes).toString("utf8");
|
|
24722
|
+
return {
|
|
24723
|
+
text: `...[truncated, kept last ${CAPS.errorLogBytes} bytes]
|
|
24724
|
+
${truncated}`,
|
|
24725
|
+
markers: [{ kind: "error-log-truncated", originalSizeBytes: fullBytes }]
|
|
24726
|
+
};
|
|
24727
|
+
};
|
|
24728
|
+
const readHostPackages = async (strapi2) => {
|
|
24729
|
+
const appRoot = strapi2?.dirs?.app?.root ?? process.cwd();
|
|
24730
|
+
if (!appRoot) return { data: null, reason: "host-app-root-unknown" };
|
|
24731
|
+
try {
|
|
24732
|
+
const raw = await promises.readFile(require$$1.join(appRoot, "package.json"), "utf8");
|
|
24733
|
+
const parsed = JSON.parse(raw);
|
|
24734
|
+
return {
|
|
24735
|
+
data: {
|
|
24736
|
+
name: parsed.name,
|
|
24737
|
+
version: parsed.version,
|
|
24738
|
+
dependencies: parsed.dependencies ?? {},
|
|
24739
|
+
devDependencies: parsed.devDependencies ?? {}
|
|
24740
|
+
}
|
|
24741
|
+
};
|
|
24742
|
+
} catch (err) {
|
|
24743
|
+
return { data: null, reason: err instanceof Error ? err.message : String(err) };
|
|
24744
|
+
}
|
|
24745
|
+
};
|
|
24746
|
+
const buildReadme = ({
|
|
24747
|
+
sessionShortId,
|
|
24748
|
+
sessionId,
|
|
24749
|
+
schemaVersion,
|
|
24750
|
+
hostPackagesSkipped
|
|
24751
|
+
}) => {
|
|
24752
|
+
const lines = [];
|
|
24753
|
+
lines.push(`# Localazy Strapi Plugin — Troubleshooting Bundle`);
|
|
24754
|
+
lines.push("");
|
|
24755
|
+
lines.push(`Generated: ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
24756
|
+
lines.push(`Session id: ${sessionId}`);
|
|
24757
|
+
lines.push(`Schema version: ${schemaVersion}`);
|
|
24758
|
+
lines.push("");
|
|
24759
|
+
lines.push("## Contents");
|
|
24760
|
+
lines.push("");
|
|
24761
|
+
lines.push("- `meta.json` — schema version, session metadata.");
|
|
24762
|
+
lines.push("- `versions.json` — plugin version, Strapi version, Node version, platform/arch.");
|
|
24763
|
+
lines.push("- `env.json` — allow-listed environment variables only.");
|
|
24764
|
+
lines.push("- `browser.json` — user agent, language, viewport, console errors (from the admin UI).");
|
|
24765
|
+
lines.push("- `session.json` — full activity-log session record (URLs scrubbed of secret query keys).");
|
|
24766
|
+
lines.push("- `error.log` — chronological text log of session entries.");
|
|
24767
|
+
lines.push("- `plugin-settings.json` — full plugin settings (webhook URL secrets scrubbed).");
|
|
24768
|
+
lines.push("- `content-transfer-setup.json` — content-transfer setup record.");
|
|
24769
|
+
if (hostPackagesSkipped) {
|
|
24770
|
+
lines.push("- `host-packages.json` — NOT INCLUDED (could not be read; see `bundle-truncated.json`).");
|
|
24771
|
+
} else {
|
|
24772
|
+
lines.push("- `host-packages.json` — host project's package.json (deps + devDeps only).");
|
|
24773
|
+
}
|
|
24774
|
+
lines.push("- `content-types/` — schema.json per touched content-type UID.");
|
|
24775
|
+
lines.push("- `entries/<uid>/<documentId>--<locale>.json` — per-entry payload from `strapi.documents().findOne()`.");
|
|
24776
|
+
lines.push("- `bundle-truncated.json` — present only if any per-section cap was exceeded.");
|
|
24777
|
+
lines.push("");
|
|
24778
|
+
lines.push("## Reproducing locally");
|
|
24779
|
+
lines.push("");
|
|
24780
|
+
lines.push("1. `unzip` the bundle.");
|
|
24781
|
+
lines.push("2. Recreate the content types from `content-types/*.schema.json` in your Strapi project.");
|
|
24782
|
+
lines.push("3. Import the entries via the Document Service using `entries/<uid>/*.json`.");
|
|
24783
|
+
lines.push("4. Apply `plugin-settings.json` and `content-transfer-setup.json` via the plugin admin UI.");
|
|
24784
|
+
lines.push("5. Trigger the same upload/download/webhook with the same locale set.");
|
|
24785
|
+
lines.push("6. Compare the failure against `error.log` and `session.json`.");
|
|
24786
|
+
lines.push("");
|
|
24787
|
+
lines.push(`Bundle short id: ${sessionShortId}`);
|
|
24788
|
+
return lines.join("\n");
|
|
24789
|
+
};
|
|
24790
|
+
const buildDebugBundle = async ({
|
|
24791
|
+
strapi: strapi2,
|
|
24792
|
+
sessionId,
|
|
24793
|
+
browserPayloadEncoded
|
|
24794
|
+
}) => {
|
|
24795
|
+
const zip = new JSZip();
|
|
24796
|
+
const truncationMarkers = [];
|
|
24797
|
+
const pluginName = "localazy";
|
|
24798
|
+
const activityLogsService = strapi2.plugin(pluginName).service("ActivityLogsService");
|
|
24799
|
+
const pluginSettingsService = strapi2.plugin(pluginName).service("PluginSettingsService");
|
|
24800
|
+
const strapiService = strapi2.plugin(pluginName).service("StrapiService");
|
|
24801
|
+
const localazyUserService = strapi2.plugin(pluginName).service("LocalazyUserService");
|
|
24802
|
+
const session = await activityLogsService.getSession(sessionId);
|
|
24803
|
+
if (!session) {
|
|
24804
|
+
throw new SessionNotFoundError(sessionId);
|
|
24805
|
+
}
|
|
24806
|
+
const sessionShortId = session.id.slice(0, 8);
|
|
24807
|
+
const pluginSettingsRaw = await pluginSettingsService.getPluginSettings();
|
|
24808
|
+
const contentTransferSetup = await pluginSettingsService.getContentTransferSetup();
|
|
24809
|
+
const identity2 = await localazyUserService.getUser();
|
|
24810
|
+
const redactedIdentity = redactIdentity(identity2);
|
|
24811
|
+
const pluginVersion = await strapiService.getPluginVersion();
|
|
24812
|
+
const strapiVersion = strapiService.getStrapiVersion();
|
|
24813
|
+
zip.file(
|
|
24814
|
+
"meta.json",
|
|
24815
|
+
JSON.stringify(
|
|
24816
|
+
{
|
|
24817
|
+
schemaVersion: DEBUG_BUNDLE_SCHEMA_VERSION,
|
|
24818
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24819
|
+
sessionId: session.id,
|
|
24820
|
+
sessionShortId,
|
|
24821
|
+
eventType: session.eventType,
|
|
24822
|
+
status: session.status,
|
|
24823
|
+
startedAt: session.startedAt,
|
|
24824
|
+
finishedAt: session.finishedAt ?? null,
|
|
24825
|
+
initiatedBy: session.initiatedBy,
|
|
24826
|
+
identity: redactedIdentity
|
|
24827
|
+
},
|
|
24828
|
+
null,
|
|
24829
|
+
2
|
|
24830
|
+
)
|
|
24831
|
+
);
|
|
24832
|
+
zip.file(
|
|
24833
|
+
"versions.json",
|
|
24834
|
+
JSON.stringify(
|
|
24835
|
+
{
|
|
24836
|
+
plugin: { name: "@localazy/strapi-plugin", version: pluginVersion },
|
|
24837
|
+
strapi: { version: strapiVersion },
|
|
24838
|
+
node: process.version,
|
|
24839
|
+
platform: process.platform,
|
|
24840
|
+
arch: process.arch
|
|
24841
|
+
},
|
|
24842
|
+
null,
|
|
24843
|
+
2
|
|
24844
|
+
)
|
|
24845
|
+
);
|
|
24846
|
+
const envSnapshot = pickEnvAllowlist(process.env);
|
|
24847
|
+
zip.file(
|
|
24848
|
+
"env.json",
|
|
24849
|
+
JSON.stringify(
|
|
24850
|
+
{
|
|
24851
|
+
allowlist: [...DEBUG_BUNDLE_ENV_ALLOWLIST],
|
|
24852
|
+
values: envSnapshot
|
|
24853
|
+
},
|
|
24854
|
+
null,
|
|
24855
|
+
2
|
|
24856
|
+
)
|
|
24857
|
+
);
|
|
24858
|
+
const { payload: browserPayload, truncationMarkers: browserMarkers } = decodeBrowserPayload(browserPayloadEncoded);
|
|
24859
|
+
truncationMarkers.push(...browserMarkers);
|
|
24860
|
+
zip.file("browser.json", JSON.stringify(browserPayload ? browserPayload : { captured: false }, null, 2));
|
|
24861
|
+
zip.file("session.json", JSON.stringify(sanitizeSession(session), null, 2));
|
|
24862
|
+
const { text: errorLogText, markers: errorLogMarkers } = buildErrorLog(session);
|
|
24863
|
+
truncationMarkers.push(...errorLogMarkers);
|
|
24864
|
+
zip.file("error.log", errorLogText);
|
|
24865
|
+
zip.file("plugin-settings.json", JSON.stringify(sanitizePluginSettings(pluginSettingsRaw), null, 2));
|
|
24866
|
+
zip.file("content-transfer-setup.json", JSON.stringify(contentTransferSetup, null, 2));
|
|
24867
|
+
const hostPackages = await readHostPackages(strapi2);
|
|
24868
|
+
if (hostPackages.data) {
|
|
24869
|
+
zip.file("host-packages.json", JSON.stringify(hostPackages.data, null, 2));
|
|
24870
|
+
}
|
|
24871
|
+
if (session.attemptedEntries === void 0) {
|
|
24872
|
+
truncationMarkers.push({ kind: "attempted-entries-missing-legacy-session" });
|
|
24873
|
+
}
|
|
24874
|
+
const selected = selectAttemptedEntries(session.attemptedEntries ?? []);
|
|
24875
|
+
const kept = selected.slice(0, CAPS.totalEntries);
|
|
24876
|
+
const skipped = selected.slice(CAPS.totalEntries);
|
|
24877
|
+
if (skipped.length > 0) {
|
|
24878
|
+
truncationMarkers.push({
|
|
24879
|
+
kind: "entries-skipped",
|
|
24880
|
+
tuples: skipped.map(({ uid, documentId, locale }) => ({ uid, documentId, locale }))
|
|
24881
|
+
});
|
|
24882
|
+
}
|
|
24883
|
+
const uniqueUids = [...new Set(kept.map((t3) => t3.uid))];
|
|
24884
|
+
for (const uid of uniqueUids) {
|
|
24885
|
+
const schema = serializeContentTypeSchema(strapi2.contentTypes?.[uid]);
|
|
24886
|
+
if (schema) {
|
|
24887
|
+
zip.file(`content-types/${safeUidForPath(uid)}.schema.json`, JSON.stringify(schema, null, 2));
|
|
24888
|
+
}
|
|
24889
|
+
}
|
|
24890
|
+
for (const tuple of kept) {
|
|
24891
|
+
let documentJson = null;
|
|
24892
|
+
try {
|
|
24893
|
+
const doc = await strapi2.documents(tuple.uid).findOne({ documentId: tuple.documentId, locale: tuple.locale, populate: "*" });
|
|
24894
|
+
documentJson = doc ? stripDocumentInternals(doc) : { __not_found: true, attemptedAt: tuple.attemptedAt };
|
|
24895
|
+
} catch (err) {
|
|
24896
|
+
documentJson = { __error: err instanceof Error ? err.message : String(err) };
|
|
24897
|
+
}
|
|
24898
|
+
const serialised = JSON.stringify(documentJson, null, 2);
|
|
24899
|
+
const sizeBytes = Buffer.byteLength(serialised, "utf8");
|
|
24900
|
+
let body;
|
|
24901
|
+
if (sizeBytes > CAPS.perEntryBytes) {
|
|
24902
|
+
truncationMarkers.push({
|
|
24903
|
+
kind: "entry-too-large",
|
|
24904
|
+
uid: tuple.uid,
|
|
24905
|
+
documentId: tuple.documentId,
|
|
24906
|
+
locale: tuple.locale,
|
|
24907
|
+
originalSizeBytes: sizeBytes
|
|
24908
|
+
});
|
|
24909
|
+
body = JSON.stringify({ __truncated: true, originalSizeBytes: sizeBytes }, null, 2);
|
|
24910
|
+
} else {
|
|
24911
|
+
body = serialised;
|
|
24912
|
+
}
|
|
24913
|
+
const safeDocId = tuple.documentId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
24914
|
+
zip.file(`entries/${safeUidForPath(tuple.uid)}/${safeDocId}--${tuple.locale}.json`, body);
|
|
24915
|
+
}
|
|
24916
|
+
zip.file(
|
|
24917
|
+
"README.md",
|
|
24918
|
+
buildReadme({
|
|
24919
|
+
sessionShortId,
|
|
24920
|
+
sessionId: session.id,
|
|
24921
|
+
schemaVersion: DEBUG_BUNDLE_SCHEMA_VERSION,
|
|
24922
|
+
hostPackagesSkipped: !hostPackages.data
|
|
24923
|
+
})
|
|
24924
|
+
);
|
|
24925
|
+
if (truncationMarkers.length > 0 || !hostPackages.data) {
|
|
24926
|
+
const marker = {
|
|
24927
|
+
schemaVersion: DEBUG_BUNDLE_SCHEMA_VERSION,
|
|
24928
|
+
markers: truncationMarkers,
|
|
24929
|
+
hostPackagesSkipped: hostPackages.data ? null : hostPackages.reason ?? "unknown"
|
|
24930
|
+
};
|
|
24931
|
+
zip.file("bundle-truncated.json", JSON.stringify(marker, null, 2));
|
|
24932
|
+
}
|
|
24933
|
+
const zipBuffer = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
|
|
24934
|
+
const filename = `localazy-debug-bundle-${sessionShortId}-${formatTimestampForFilename(Date.now())}.zip`;
|
|
24935
|
+
return { zipBuffer, filename };
|
|
24936
|
+
};
|
|
24937
|
+
const DebugBundleController = ({ strapi: strapi2 }) => ({
|
|
24938
|
+
async getBundle(ctx) {
|
|
24939
|
+
const { sessionId } = ctx.params;
|
|
24940
|
+
const browserPayloadEncoded = typeof ctx.query.browser === "string" ? ctx.query.browser : null;
|
|
24941
|
+
try {
|
|
24942
|
+
const { zipBuffer, filename } = await buildDebugBundle({
|
|
24943
|
+
strapi: strapi2,
|
|
24944
|
+
sessionId,
|
|
24945
|
+
browserPayloadEncoded
|
|
24946
|
+
});
|
|
24947
|
+
ctx.type = "application/zip";
|
|
24948
|
+
ctx.set("Content-Disposition", `attachment; filename="${filename}"`);
|
|
24949
|
+
ctx.body = zipBuffer;
|
|
24950
|
+
} catch (err) {
|
|
24951
|
+
if (err instanceof SessionNotFoundError) {
|
|
24952
|
+
return ctx.notFound("Session not found");
|
|
24953
|
+
}
|
|
24954
|
+
strapi2.log.error(`[localazy] failed to build debug bundle: ${err instanceof Error ? err.message : err}`);
|
|
24955
|
+
throw err;
|
|
24956
|
+
}
|
|
24957
|
+
}
|
|
24958
|
+
});
|
|
24491
24959
|
const controllers = {
|
|
24492
24960
|
LocalazyUserController,
|
|
24493
24961
|
LocalazyAuthController,
|
|
@@ -24496,7 +24964,8 @@ const controllers = {
|
|
|
24496
24964
|
PluginSettingsController,
|
|
24497
24965
|
LocalazyTransferController,
|
|
24498
24966
|
EntryExclusionController,
|
|
24499
|
-
ActivityLogsController
|
|
24967
|
+
ActivityLogsController,
|
|
24968
|
+
DebugBundleController
|
|
24500
24969
|
};
|
|
24501
24970
|
const verifyWebhook = (config2, { strapi: strapi2 }) => {
|
|
24502
24971
|
return async (ctx, next) => {
|
|
@@ -24554,13 +25023,17 @@ const middlewares = {
|
|
|
24554
25023
|
};
|
|
24555
25024
|
const policies = {};
|
|
24556
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
|
+
];
|
|
24557
25030
|
const LocalazyUserRoutes = [
|
|
24558
25031
|
{
|
|
24559
25032
|
method: "GET",
|
|
24560
25033
|
path: `${ROUTE_PREFIX$8}`,
|
|
24561
25034
|
handler: "LocalazyUserController.getUser",
|
|
24562
25035
|
config: {
|
|
24563
|
-
policies:
|
|
25036
|
+
policies: readPolicy$6
|
|
24564
25037
|
}
|
|
24565
25038
|
},
|
|
24566
25039
|
{
|
|
@@ -24568,7 +25041,7 @@ const LocalazyUserRoutes = [
|
|
|
24568
25041
|
path: `${ROUTE_PREFIX$8}`,
|
|
24569
25042
|
handler: "LocalazyUserController.updateUser",
|
|
24570
25043
|
config: {
|
|
24571
|
-
policies:
|
|
25044
|
+
policies: settingsUpdatePolicy$4
|
|
24572
25045
|
}
|
|
24573
25046
|
},
|
|
24574
25047
|
{
|
|
@@ -24576,18 +25049,21 @@ const LocalazyUserRoutes = [
|
|
|
24576
25049
|
path: `${ROUTE_PREFIX$8}`,
|
|
24577
25050
|
handler: "LocalazyUserController.deleteUser",
|
|
24578
25051
|
config: {
|
|
24579
|
-
policies:
|
|
25052
|
+
policies: settingsUpdatePolicy$4
|
|
24580
25053
|
}
|
|
24581
25054
|
}
|
|
24582
25055
|
];
|
|
24583
25056
|
const ROUTE_PREFIX$7 = "/auth";
|
|
25057
|
+
const settingsUpdatePolicy$3 = [
|
|
25058
|
+
{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.SETTINGS_UPDATE] } }
|
|
25059
|
+
];
|
|
24584
25060
|
const LocalazyAuthRoutes = [
|
|
24585
25061
|
{
|
|
24586
25062
|
method: "GET",
|
|
24587
25063
|
path: `${ROUTE_PREFIX$7}/generate-keys`,
|
|
24588
25064
|
handler: "LocalazyAuthController.generateKeys",
|
|
24589
25065
|
config: {
|
|
24590
|
-
policies:
|
|
25066
|
+
policies: settingsUpdatePolicy$3
|
|
24591
25067
|
}
|
|
24592
25068
|
},
|
|
24593
25069
|
{
|
|
@@ -24595,18 +25071,26 @@ const LocalazyAuthRoutes = [
|
|
|
24595
25071
|
path: `${ROUTE_PREFIX$7}/continuous-poll`,
|
|
24596
25072
|
handler: "LocalazyAuthController.continuousPoll",
|
|
24597
25073
|
config: {
|
|
24598
|
-
policies:
|
|
25074
|
+
policies: settingsUpdatePolicy$3
|
|
24599
25075
|
}
|
|
24600
25076
|
}
|
|
24601
25077
|
];
|
|
24602
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
|
+
];
|
|
24603
25083
|
const PluginSettingsRoutes = [
|
|
24604
25084
|
{
|
|
24605
25085
|
method: "GET",
|
|
24606
25086
|
path: `${ROUTE_PREFIX$6}/content-transfer-setup`,
|
|
24607
25087
|
handler: "PluginSettingsController.getContentTransferSetup",
|
|
24608
25088
|
config: {
|
|
24609
|
-
|
|
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
|
|
24610
25094
|
}
|
|
24611
25095
|
},
|
|
24612
25096
|
{
|
|
@@ -24614,7 +25098,7 @@ const PluginSettingsRoutes = [
|
|
|
24614
25098
|
path: `${ROUTE_PREFIX$6}/content-transfer-setup`,
|
|
24615
25099
|
handler: "PluginSettingsController.updateContentTransferSetup",
|
|
24616
25100
|
config: {
|
|
24617
|
-
policies:
|
|
25101
|
+
policies: settingsUpdatePolicy$2
|
|
24618
25102
|
}
|
|
24619
25103
|
},
|
|
24620
25104
|
{
|
|
@@ -24622,7 +25106,7 @@ const PluginSettingsRoutes = [
|
|
|
24622
25106
|
path: `${ROUTE_PREFIX$6}/plugin-settings`,
|
|
24623
25107
|
handler: "PluginSettingsController.getPluginSettings",
|
|
24624
25108
|
config: {
|
|
24625
|
-
policies:
|
|
25109
|
+
policies: readPolicy$5
|
|
24626
25110
|
}
|
|
24627
25111
|
},
|
|
24628
25112
|
{
|
|
@@ -24630,7 +25114,20 @@ const PluginSettingsRoutes = [
|
|
|
24630
25114
|
path: `${ROUTE_PREFIX$6}/plugin-settings`,
|
|
24631
25115
|
handler: "PluginSettingsController.updatePluginSettings",
|
|
24632
25116
|
config: {
|
|
24633
|
-
|
|
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
|
|
24634
25131
|
}
|
|
24635
25132
|
},
|
|
24636
25133
|
{
|
|
@@ -24638,18 +25135,22 @@ const PluginSettingsRoutes = [
|
|
|
24638
25135
|
path: `${ROUTE_PREFIX$6}/sync-cursor`,
|
|
24639
25136
|
handler: "PluginSettingsController.getSyncCursor",
|
|
24640
25137
|
config: {
|
|
24641
|
-
policies:
|
|
25138
|
+
policies: readPolicy$5
|
|
24642
25139
|
}
|
|
24643
25140
|
}
|
|
24644
25141
|
];
|
|
24645
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
|
+
];
|
|
24646
25147
|
const StrapiRoutes = [
|
|
24647
25148
|
{
|
|
24648
25149
|
method: "GET",
|
|
24649
25150
|
path: `${ROUTE_PREFIX$5}/models`,
|
|
24650
25151
|
handler: "StrapiController.getModels",
|
|
24651
25152
|
config: {
|
|
24652
|
-
policies:
|
|
25153
|
+
policies: readPolicy$4
|
|
24653
25154
|
}
|
|
24654
25155
|
},
|
|
24655
25156
|
{
|
|
@@ -24657,7 +25158,7 @@ const StrapiRoutes = [
|
|
|
24657
25158
|
path: `${ROUTE_PREFIX$5}/localizable-models`,
|
|
24658
25159
|
handler: "StrapiController.getLocalizableModels",
|
|
24659
25160
|
config: {
|
|
24660
|
-
policies:
|
|
25161
|
+
policies: readPolicy$4
|
|
24661
25162
|
}
|
|
24662
25163
|
},
|
|
24663
25164
|
{
|
|
@@ -24665,7 +25166,7 @@ const StrapiRoutes = [
|
|
|
24665
25166
|
path: `${ROUTE_PREFIX$5}/lifecycle/localazy-webhooks`,
|
|
24666
25167
|
handler: "StrapiController.postLifecycleLocalazyWebhooks",
|
|
24667
25168
|
config: {
|
|
24668
|
-
policies:
|
|
25169
|
+
policies: settingsUpdatePolicy$1
|
|
24669
25170
|
}
|
|
24670
25171
|
},
|
|
24671
25172
|
{
|
|
@@ -24673,18 +25174,19 @@ const StrapiRoutes = [
|
|
|
24673
25174
|
path: `${ROUTE_PREFIX$5}/version`,
|
|
24674
25175
|
handler: "StrapiController.getPluginVersion",
|
|
24675
25176
|
config: {
|
|
24676
|
-
policies:
|
|
25177
|
+
policies: readPolicy$4
|
|
24677
25178
|
}
|
|
24678
25179
|
}
|
|
24679
25180
|
];
|
|
24680
25181
|
const ROUTE_PREFIX$4 = "/transfer";
|
|
25182
|
+
const transferPolicy$2 = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.TRANSFER] } }];
|
|
24681
25183
|
const LocalazyTransferRoutes = [
|
|
24682
25184
|
{
|
|
24683
25185
|
method: "POST",
|
|
24684
25186
|
path: `${ROUTE_PREFIX$4}/upload`,
|
|
24685
25187
|
handler: "LocalazyTransferController.upload",
|
|
24686
25188
|
config: {
|
|
24687
|
-
policies:
|
|
25189
|
+
policies: transferPolicy$2
|
|
24688
25190
|
}
|
|
24689
25191
|
},
|
|
24690
25192
|
{
|
|
@@ -24692,18 +25194,22 @@ const LocalazyTransferRoutes = [
|
|
|
24692
25194
|
path: `${ROUTE_PREFIX$4}/download`,
|
|
24693
25195
|
handler: "LocalazyTransferController.download",
|
|
24694
25196
|
config: {
|
|
24695
|
-
policies:
|
|
25197
|
+
policies: transferPolicy$2
|
|
24696
25198
|
}
|
|
24697
25199
|
}
|
|
24698
25200
|
];
|
|
24699
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
|
+
];
|
|
24700
25206
|
const LocalazyProjectRoutes = [
|
|
24701
25207
|
{
|
|
24702
25208
|
method: "GET",
|
|
24703
25209
|
path: `${ROUTE_PREFIX$3}`,
|
|
24704
25210
|
handler: "LocalazyProjectController.getConnectedProject",
|
|
24705
25211
|
config: {
|
|
24706
|
-
policies:
|
|
25212
|
+
policies: readPolicy$3
|
|
24707
25213
|
}
|
|
24708
25214
|
},
|
|
24709
25215
|
{
|
|
@@ -24711,7 +25217,7 @@ const LocalazyProjectRoutes = [
|
|
|
24711
25217
|
path: `${ROUTE_PREFIX$3}/webhooks`,
|
|
24712
25218
|
handler: "LocalazyProjectController.getWebhookStatus",
|
|
24713
25219
|
config: {
|
|
24714
|
-
policies:
|
|
25220
|
+
policies: readPolicy$3
|
|
24715
25221
|
}
|
|
24716
25222
|
},
|
|
24717
25223
|
{
|
|
@@ -24719,7 +25225,7 @@ const LocalazyProjectRoutes = [
|
|
|
24719
25225
|
path: `${ROUTE_PREFIX$3}/webhooks/setup`,
|
|
24720
25226
|
handler: "LocalazyProjectController.setupWebhook",
|
|
24721
25227
|
config: {
|
|
24722
|
-
policies:
|
|
25228
|
+
policies: settingsUpdatePolicy
|
|
24723
25229
|
}
|
|
24724
25230
|
},
|
|
24725
25231
|
{
|
|
@@ -24727,7 +25233,7 @@ const LocalazyProjectRoutes = [
|
|
|
24727
25233
|
path: `${ROUTE_PREFIX$3}/strapi-url`,
|
|
24728
25234
|
handler: "LocalazyProjectController.getStrapiUrl",
|
|
24729
25235
|
config: {
|
|
24730
|
-
policies:
|
|
25236
|
+
policies: readPolicy$3
|
|
24731
25237
|
}
|
|
24732
25238
|
}
|
|
24733
25239
|
];
|
|
@@ -24746,13 +25252,15 @@ const LocalazyPublicTransferRoutes = [
|
|
|
24746
25252
|
}
|
|
24747
25253
|
];
|
|
24748
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] } }];
|
|
24749
25257
|
const EntryExclusionRoutes = [
|
|
24750
25258
|
{
|
|
24751
25259
|
method: "GET",
|
|
24752
25260
|
path: `${ROUTE_PREFIX$1}/:contentType/:documentId`,
|
|
24753
25261
|
handler: "EntryExclusionController.getEntryExclusion",
|
|
24754
25262
|
config: {
|
|
24755
|
-
policies:
|
|
25263
|
+
policies: readPolicy$2
|
|
24756
25264
|
}
|
|
24757
25265
|
},
|
|
24758
25266
|
{
|
|
@@ -24760,7 +25268,7 @@ const EntryExclusionRoutes = [
|
|
|
24760
25268
|
path: `${ROUTE_PREFIX$1}/:contentType/:documentId`,
|
|
24761
25269
|
handler: "EntryExclusionController.setEntryExclusion",
|
|
24762
25270
|
config: {
|
|
24763
|
-
policies:
|
|
25271
|
+
policies: transferPolicy$1
|
|
24764
25272
|
}
|
|
24765
25273
|
},
|
|
24766
25274
|
{
|
|
@@ -24768,18 +25276,20 @@ const EntryExclusionRoutes = [
|
|
|
24768
25276
|
path: `${ROUTE_PREFIX$1}/:contentType`,
|
|
24769
25277
|
handler: "EntryExclusionController.getContentTypeExclusions",
|
|
24770
25278
|
config: {
|
|
24771
|
-
policies:
|
|
25279
|
+
policies: readPolicy$2
|
|
24772
25280
|
}
|
|
24773
25281
|
}
|
|
24774
25282
|
];
|
|
24775
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] } }];
|
|
24776
25286
|
const ActivityLogsRoutes = [
|
|
24777
25287
|
{
|
|
24778
25288
|
method: "GET",
|
|
24779
25289
|
path: `${ROUTE_PREFIX}`,
|
|
24780
25290
|
handler: "ActivityLogsController.getSessions",
|
|
24781
25291
|
config: {
|
|
24782
|
-
policies:
|
|
25292
|
+
policies: readPolicy$1
|
|
24783
25293
|
}
|
|
24784
25294
|
},
|
|
24785
25295
|
{
|
|
@@ -24787,7 +25297,7 @@ const ActivityLogsRoutes = [
|
|
|
24787
25297
|
path: `${ROUTE_PREFIX}/export`,
|
|
24788
25298
|
handler: "ActivityLogsController.exportSessions",
|
|
24789
25299
|
config: {
|
|
24790
|
-
policies:
|
|
25300
|
+
policies: readPolicy$1
|
|
24791
25301
|
}
|
|
24792
25302
|
},
|
|
24793
25303
|
{
|
|
@@ -24795,7 +25305,7 @@ const ActivityLogsRoutes = [
|
|
|
24795
25305
|
path: `${ROUTE_PREFIX}/:sessionId`,
|
|
24796
25306
|
handler: "ActivityLogsController.getSession",
|
|
24797
25307
|
config: {
|
|
24798
|
-
policies:
|
|
25308
|
+
policies: readPolicy$1
|
|
24799
25309
|
}
|
|
24800
25310
|
},
|
|
24801
25311
|
{
|
|
@@ -24803,13 +25313,28 @@ const ActivityLogsRoutes = [
|
|
|
24803
25313
|
path: `${ROUTE_PREFIX}`,
|
|
24804
25314
|
handler: "ActivityLogsController.clearSessions",
|
|
24805
25315
|
config: {
|
|
24806
|
-
policies:
|
|
25316
|
+
policies: transferPolicy
|
|
24807
25317
|
}
|
|
24808
25318
|
}
|
|
24809
25319
|
];
|
|
25320
|
+
const readPolicy = [{ name: "admin::hasPermissions", config: { actions: [PERMISSION_UIDS.READ] } }];
|
|
25321
|
+
const DebugBundleRoutes = [
|
|
25322
|
+
{
|
|
25323
|
+
method: "GET",
|
|
25324
|
+
path: "/activity-logs/:sessionId/bundle",
|
|
25325
|
+
handler: "DebugBundleController.getBundle",
|
|
25326
|
+
config: {
|
|
25327
|
+
policies: readPolicy
|
|
25328
|
+
}
|
|
25329
|
+
}
|
|
25330
|
+
];
|
|
25331
|
+
const withoutAdminPolicies = (routes2) => routes2.map((route) => ({
|
|
25332
|
+
...route,
|
|
25333
|
+
config: { ...route.config, policies: [] }
|
|
25334
|
+
}));
|
|
24810
25335
|
const routes = {
|
|
24811
25336
|
"content-api": {
|
|
24812
|
-
routes:
|
|
25337
|
+
routes: withoutAdminPolicies(StrapiRoutes)
|
|
24813
25338
|
},
|
|
24814
25339
|
admin: {
|
|
24815
25340
|
type: "admin",
|
|
@@ -24821,7 +25346,8 @@ const routes = {
|
|
|
24821
25346
|
...LocalazyTransferRoutes,
|
|
24822
25347
|
...LocalazyProjectRoutes,
|
|
24823
25348
|
...EntryExclusionRoutes,
|
|
24824
|
-
...ActivityLogsRoutes
|
|
25349
|
+
...ActivityLogsRoutes,
|
|
25350
|
+
...DebugBundleRoutes
|
|
24825
25351
|
]
|
|
24826
25352
|
},
|
|
24827
25353
|
LocalazyPublicTransferRoutes: {
|
|
@@ -25020,6 +25546,7 @@ const KEY$1 = "sync-cursor";
|
|
|
25020
25546
|
const emptySyncCursor = {
|
|
25021
25547
|
processedKeys: {}
|
|
25022
25548
|
};
|
|
25549
|
+
const UI_PREF_FIELDS = ["defaultRoute", "activityLogsSort"];
|
|
25023
25550
|
const PluginSettingsService = ({ strapi: strapi2 }) => ({
|
|
25024
25551
|
async getContentTransferSetup() {
|
|
25025
25552
|
const pluginStore = getStrapiStore(strapi2);
|
|
@@ -25056,6 +25583,20 @@ const PluginSettingsService = ({ strapi: strapi2 }) => ({
|
|
|
25056
25583
|
});
|
|
25057
25584
|
return newSettings;
|
|
25058
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
|
+
},
|
|
25059
25600
|
async getSyncCursor() {
|
|
25060
25601
|
const pluginStore = getStrapiStore(strapi2);
|
|
25061
25602
|
const cursor = await pluginStore.get({ key: KEY$1 });
|
|
@@ -25100,6 +25641,8 @@ const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
|
|
|
25100
25641
|
const { setup: setup2 } = contentTransferSetup;
|
|
25101
25642
|
const collectionsNames = getCollectionsNames(setup2);
|
|
25102
25643
|
const models = await StrapiService2.getModels();
|
|
25644
|
+
const strapiDefaultLocaleCode = await StrapiI18nService2.getDefaultLocaleCode();
|
|
25645
|
+
const attemptedTuples = [];
|
|
25103
25646
|
let pickedFlattenStrapiContent = {};
|
|
25104
25647
|
for (const collectionName of collectionsNames) {
|
|
25105
25648
|
const currentModel = models.find((model) => model.collectionName === collectionName);
|
|
@@ -25162,6 +25705,15 @@ const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
|
|
|
25162
25705
|
});
|
|
25163
25706
|
await activityLogsService.addEntry(sessionId, message);
|
|
25164
25707
|
strapi2.log.info(message);
|
|
25708
|
+
if (strapiDefaultLocaleCode) {
|
|
25709
|
+
for (const entry of entries) {
|
|
25710
|
+
attemptedTuples.push({
|
|
25711
|
+
uid: modelUid,
|
|
25712
|
+
documentId: entry.documentId,
|
|
25713
|
+
locale: strapiDefaultLocaleCode
|
|
25714
|
+
});
|
|
25715
|
+
}
|
|
25716
|
+
}
|
|
25165
25717
|
entries = omitDeep(entries, ["locale", "createdAt", "updatedAt", "publishedAt"]);
|
|
25166
25718
|
entries.forEach((entry) => {
|
|
25167
25719
|
const flatten = flattenObject({
|
|
@@ -25179,7 +25731,6 @@ const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
|
|
|
25179
25731
|
...characterLimitsMetadata
|
|
25180
25732
|
};
|
|
25181
25733
|
}
|
|
25182
|
-
const strapiDefaultLocaleCode = await StrapiI18nService2.getDefaultLocaleCode();
|
|
25183
25734
|
const localazyLocaleCode = strapiDefaultLocaleCode ? isoStrapiToLocalazy(strapiDefaultLocaleCode) : config.default.LOCALAZY_DEFAULT_LOCALE;
|
|
25184
25735
|
const importFile = LocalazyUploadService2.createImportFileRepresentation(
|
|
25185
25736
|
localazyLocaleCode,
|
|
@@ -25201,6 +25752,10 @@ const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
|
|
|
25201
25752
|
await activityLogsService.addEntry(sessionId, "Uploading collections to Localazy...");
|
|
25202
25753
|
try {
|
|
25203
25754
|
await LocalazyUploadService2.upload(importFile, uploadConfig);
|
|
25755
|
+
await activityLogsService.recordAttemptedEntries(
|
|
25756
|
+
sessionId,
|
|
25757
|
+
attemptedTuples.map((t3) => ({ ...t3, status: "success" }))
|
|
25758
|
+
);
|
|
25204
25759
|
} catch (error) {
|
|
25205
25760
|
success = false;
|
|
25206
25761
|
const errorMessage = `Upload to Localazy failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
@@ -25210,6 +25765,10 @@ const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
|
|
|
25210
25765
|
message: errorMessage
|
|
25211
25766
|
});
|
|
25212
25767
|
await activityLogsService.addEntry(sessionId, errorMessage);
|
|
25768
|
+
await activityLogsService.recordAttemptedEntries(
|
|
25769
|
+
sessionId,
|
|
25770
|
+
attemptedTuples.map((t3) => ({ ...t3, status: "failed", errorMessage }))
|
|
25771
|
+
);
|
|
25213
25772
|
await activityLogsService.finishSession(sessionId, "failed", errorMessage);
|
|
25214
25773
|
console.timeEnd("upload");
|
|
25215
25774
|
return;
|
|
@@ -25614,7 +26173,7 @@ const shouldSetDownloadedProperty = (modelContentTransferSetup, parsedKeyRest) =
|
|
|
25614
26173
|
return "no";
|
|
25615
26174
|
}
|
|
25616
26175
|
};
|
|
25617
|
-
const getFilteredLanguagesCodesForDownload = async (languagesCodes) => {
|
|
26176
|
+
const getFilteredLanguagesCodesForDownload = async (languagesCodes, requestedUiLanguages) => {
|
|
25618
26177
|
const pluginSettingsServiceHelper = new PluginSettingsServiceHelper();
|
|
25619
26178
|
const requestInitiatorHelper = new RequestInitiatorHelper(strapi);
|
|
25620
26179
|
await pluginSettingsServiceHelper.setup();
|
|
@@ -25622,7 +26181,7 @@ const getFilteredLanguagesCodesForDownload = async (languagesCodes) => {
|
|
|
25622
26181
|
if (requestInitiatorHelper.isInitiatedByLocalazyWebhook()) {
|
|
25623
26182
|
localLanguagesCodes = pluginSettingsServiceHelper.getWebhookLanguagesCodes();
|
|
25624
26183
|
} else if (requestInitiatorHelper.isInitiatedByLocalazyPluginUI()) {
|
|
25625
|
-
localLanguagesCodes = pluginSettingsServiceHelper.getUiLanguagesCodes();
|
|
26184
|
+
localLanguagesCodes = requestedUiLanguages ?? pluginSettingsServiceHelper.getUiLanguagesCodes();
|
|
25626
26185
|
} else {
|
|
25627
26186
|
strapi.log.warn("Called by an unknown initiator.");
|
|
25628
26187
|
return languagesCodes;
|
|
@@ -25635,7 +26194,8 @@ const getFilteredLanguagesCodesForDownload = async (languagesCodes) => {
|
|
|
25635
26194
|
const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
|
|
25636
26195
|
async download({
|
|
25637
26196
|
notificationService,
|
|
25638
|
-
fullSync = false
|
|
26197
|
+
fullSync = false,
|
|
26198
|
+
requestedUiLanguages
|
|
25639
26199
|
}) {
|
|
25640
26200
|
console.time("download");
|
|
25641
26201
|
const syncMode = fullSync ? "Full sync" : "Incremental sync";
|
|
@@ -25715,7 +26275,7 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
|
|
|
25715
26275
|
return;
|
|
25716
26276
|
}
|
|
25717
26277
|
let languagesCodes = projectLanguagesWithoutSourceLanguage.map((language3) => language3.code);
|
|
25718
|
-
languagesCodes = await getFilteredLanguagesCodesForDownload(languagesCodes);
|
|
26278
|
+
languagesCodes = await getFilteredLanguagesCodesForDownload(languagesCodes, requestedUiLanguages);
|
|
25719
26279
|
const strapiUnsupportedLanguages = [];
|
|
25720
26280
|
const strapiLocales = await StrapiI18nService2.getLocales();
|
|
25721
26281
|
for (const isoLocalazy of languagesCodes) {
|
|
@@ -25934,6 +26494,12 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
|
|
|
25934
26494
|
message
|
|
25935
26495
|
});
|
|
25936
26496
|
await activityLogsService.addEntry(sessionId, message);
|
|
26497
|
+
await activityLogsService.recordAttemptedEntry(sessionId, {
|
|
26498
|
+
uid,
|
|
26499
|
+
documentId,
|
|
26500
|
+
locale: isoStrapi,
|
|
26501
|
+
status: "success"
|
|
26502
|
+
});
|
|
25937
26503
|
await markKeysProcessed(sourceKeys);
|
|
25938
26504
|
} catch (e2) {
|
|
25939
26505
|
success = false;
|
|
@@ -25950,6 +26516,13 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
|
|
|
25950
26516
|
sessionId,
|
|
25951
26517
|
`Failed to create ${uid} [${documentId}] in ${isoStrapi}: ${e2.message}`
|
|
25952
26518
|
);
|
|
26519
|
+
await activityLogsService.recordAttemptedEntry(sessionId, {
|
|
26520
|
+
uid,
|
|
26521
|
+
documentId,
|
|
26522
|
+
locale: isoStrapi,
|
|
26523
|
+
status: "failed",
|
|
26524
|
+
errorMessage: e2.message
|
|
26525
|
+
});
|
|
25953
26526
|
}
|
|
25954
26527
|
} else {
|
|
25955
26528
|
try {
|
|
@@ -25968,6 +26541,12 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
|
|
|
25968
26541
|
message
|
|
25969
26542
|
});
|
|
25970
26543
|
await activityLogsService.addEntry(sessionId, message);
|
|
26544
|
+
await activityLogsService.recordAttemptedEntry(sessionId, {
|
|
26545
|
+
uid,
|
|
26546
|
+
documentId,
|
|
26547
|
+
locale: isoStrapi,
|
|
26548
|
+
status: "success"
|
|
26549
|
+
});
|
|
25971
26550
|
await markKeysProcessed(sourceKeys);
|
|
25972
26551
|
} catch (e2) {
|
|
25973
26552
|
success = false;
|
|
@@ -25984,6 +26563,13 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
|
|
|
25984
26563
|
sessionId,
|
|
25985
26564
|
`Failed to update ${uid} [${documentId}] in ${isoStrapi}: ${e2.message}`
|
|
25986
26565
|
);
|
|
26566
|
+
await activityLogsService.recordAttemptedEntry(sessionId, {
|
|
26567
|
+
uid,
|
|
26568
|
+
documentId,
|
|
26569
|
+
locale: isoStrapi,
|
|
26570
|
+
status: "failed",
|
|
26571
|
+
errorMessage: e2.message
|
|
26572
|
+
});
|
|
25987
26573
|
}
|
|
25988
26574
|
}
|
|
25989
26575
|
} catch (e2) {
|
|
@@ -25996,6 +26582,13 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
|
|
|
25996
26582
|
sessionId,
|
|
25997
26583
|
`Error processing ${uid} [${documentId}] in ${isoStrapi}: ${e2.message}`
|
|
25998
26584
|
);
|
|
26585
|
+
await activityLogsService.recordAttemptedEntry(sessionId, {
|
|
26586
|
+
uid,
|
|
26587
|
+
documentId,
|
|
26588
|
+
locale: isoStrapi,
|
|
26589
|
+
status: "failed",
|
|
26590
|
+
errorMessage: e2.message
|
|
26591
|
+
});
|
|
25999
26592
|
}
|
|
26000
26593
|
}
|
|
26001
26594
|
}
|
|
@@ -26746,6 +27339,7 @@ const emptyActivityLogs = {
|
|
|
26746
27339
|
sessions: []
|
|
26747
27340
|
};
|
|
26748
27341
|
const ONE_YEAR_MS = 365 * 24 * 60 * 60 * 1e3;
|
|
27342
|
+
const ATTEMPTED_ENTRIES_CAP = 5e3;
|
|
26749
27343
|
let writeLock = Promise.resolve();
|
|
26750
27344
|
const withLock = async (fn) => {
|
|
26751
27345
|
let release;
|
|
@@ -26810,6 +27404,38 @@ const ActivityLogsService = ({ strapi: strapi2 }) => ({
|
|
|
26810
27404
|
await this.saveActivityLogs(logs);
|
|
26811
27405
|
});
|
|
26812
27406
|
},
|
|
27407
|
+
async recordAttemptedEntry(sessionId, entry) {
|
|
27408
|
+
return this.recordAttemptedEntries(sessionId, [entry]);
|
|
27409
|
+
},
|
|
27410
|
+
async recordAttemptedEntries(sessionId, entries) {
|
|
27411
|
+
if (!entries.length) {
|
|
27412
|
+
return;
|
|
27413
|
+
}
|
|
27414
|
+
return withLock(async () => {
|
|
27415
|
+
const logs = await this.getActivityLogs();
|
|
27416
|
+
const session = logs.sessions.find((s2) => s2.id === sessionId);
|
|
27417
|
+
if (!session) {
|
|
27418
|
+
return;
|
|
27419
|
+
}
|
|
27420
|
+
if (!session.attemptedEntries) {
|
|
27421
|
+
session.attemptedEntries = [];
|
|
27422
|
+
}
|
|
27423
|
+
const now = Date.now();
|
|
27424
|
+
const wasAtCap = session.attemptedEntries.length >= ATTEMPTED_ENTRIES_CAP;
|
|
27425
|
+
const remaining = Math.max(0, ATTEMPTED_ENTRIES_CAP - session.attemptedEntries.length);
|
|
27426
|
+
const accepted = entries.slice(0, remaining);
|
|
27427
|
+
const dropped = entries.length - accepted.length;
|
|
27428
|
+
for (const entry of accepted) {
|
|
27429
|
+
session.attemptedEntries.push({ ...entry, attemptedAt: now });
|
|
27430
|
+
}
|
|
27431
|
+
if (dropped > 0 && !wasAtCap) {
|
|
27432
|
+
strapi2.log.warn(
|
|
27433
|
+
`[localazy] attemptedEntries cap (${ATTEMPTED_ENTRIES_CAP}) reached for session ${sessionId}; ${dropped} record(s) dropped.`
|
|
27434
|
+
);
|
|
27435
|
+
}
|
|
27436
|
+
await this.saveActivityLogs(logs);
|
|
27437
|
+
});
|
|
27438
|
+
},
|
|
26813
27439
|
async finishSession(sessionId, status, summary) {
|
|
26814
27440
|
return withLock(async () => {
|
|
26815
27441
|
const logs = await this.getActivityLogs();
|