From 8e750a8abd3c402f941bf6e939ea3915fd8c9f7a Mon Sep 17 00:00:00 2001 From: chetan-contentstack Date: Wed, 1 Apr 2026 12:12:42 +0530 Subject: [PATCH 1/6] Implement extractEntries functionality for WordPress migration; update contentMapper and WordPress services to utilize new entry extraction logic, enhance error handling in parse utilities, and adjust API routes for improved response management. --- api/src/services/contentMapper.service.ts | 4 +- api/src/services/wordpress.service.ts | 19 ++- upload-api/migration-wordpress/index.js | 4 +- upload-api/migration-wordpress/index.ts | 10 +- .../libs/extractEntries.js | 116 +++++++++++++++++ .../libs/extractEntries.ts | 122 ++++++++++++++++++ .../migration-wordpress/utils/parseUtil.js | 21 ++- .../migration-wordpress/utils/parseUtil.ts | 20 ++- upload-api/src/config/index.json | 16 +-- upload-api/src/controllers/wordpress/index.ts | 42 +++--- upload-api/src/routes/index.ts | 7 +- 11 files changed, 328 insertions(+), 53 deletions(-) create mode 100644 upload-api/migration-wordpress/libs/extractEntries.js create mode 100644 upload-api/migration-wordpress/libs/extractEntries.ts diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index c9db93b49..a4fd55f06 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -208,10 +208,10 @@ const putTestData = async (req: Request) => { existingEntry.otherCmsEntryUid === newEntry.otherCmsEntryUid && existingEntry.contentTypeId === newEntry.contentTypeId ); }); - // console.info("newEntries", newEntries); + // Append only truly new entries; avoid re-adding the same batch twice. data.entry_mapper = [ + ...existingEntries, ...nonExistingEntries, - ...entries, ]; }); diff --git a/api/src/services/wordpress.service.ts b/api/src/services/wordpress.service.ts index bead1c375..38429e6b1 100644 --- a/api/src/services/wordpress.service.ts +++ b/api/src/services/wordpress.service.ts @@ -484,6 +484,9 @@ async function saveEntry(fields: any, entry: any, file_path: string, assetData const $ = cheerio.load(xmlData, { xmlMode: true }); const items = $('item'); const entryData: Record = {}; + const fieldList = Array.isArray(fields) ? fields : []; + const hasField = (uid: string) => + fieldList.some((field: any) => field?.uid === uid); try { if(entry ){ @@ -549,16 +552,20 @@ async function saveEntry(fields: any, entry: any, file_path: string, assetData // Pass individual content to createSchema entryData[uid] = await createSchema(fields, blocksJson, item?.title, uid, assetData); const categoryReference = extractCategoryReference(item?.['category']); - if (categoryReference?.length > 0) { - entryData[uid]['taxonomies'] = taxonomies; + if (hasField("taxonomies") && categoryReference?.length > 0) { + entryData[uid]["taxonomies"] = taxonomies; } const termsReference = extractTermsReference(item?.['category']); - if(termsReference?.length > 0) { - entryData[uid]['terms'] = terms; + if (hasField("terms") && termsReference?.length > 0) { + entryData[uid]["terms"] = terms; + } + entryData[uid]["tags"] = tags?.map((tag: any) => tag?.text) || []; + if (hasField("author")) { + entryData[uid]["author"] = + authorData?.filter((author: any) => author?.uid) || []; } - entryData[uid]['tags'] = tags?.map((tag: any) => tag?.text); - entryData[uid]['author'] = authorData; entryData[uid]['locale'] = locale; + entryData[uid]["publish_details"] = []; diff --git a/upload-api/migration-wordpress/index.js b/upload-api/migration-wordpress/index.js index 3598f8da8..1ec09f431 100644 --- a/upload-api/migration-wordpress/index.js +++ b/upload-api/migration-wordpress/index.js @@ -3,9 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.extractLocale = exports.extractContentTypes = void 0; +exports.extractEntries = exports.extractLocale = exports.extractContentTypes = void 0; const contentTypes_1 = __importDefault(require("./libs/contentTypes")); exports.extractContentTypes = contentTypes_1.default; //import contentTypeMaker from './libs/contentTypeMapper'; const extractLocale_1 = __importDefault(require("./libs/extractLocale")); exports.extractLocale = extractLocale_1.default; +const extractEntries_1 = __importDefault(require('./libs/extractEntries')); +exports.extractEntries = extractEntries_1.default; diff --git a/upload-api/migration-wordpress/index.ts b/upload-api/migration-wordpress/index.ts index d41b8bf32..67c48bb1d 100644 --- a/upload-api/migration-wordpress/index.ts +++ b/upload-api/migration-wordpress/index.ts @@ -1,9 +1,11 @@ import extractContentTypes from './libs/contentTypes'; //import contentTypeMaker from './libs/contentTypeMapper'; import extractLocale from './libs/extractLocale'; +import extractEntries from './libs/extractEntries'; export { - extractContentTypes, - //contentTypeMaker, - extractLocale -} \ No newline at end of file + extractContentTypes, + //contentTypeMaker, + extractLocale, + extractEntries +}; \ No newline at end of file diff --git a/upload-api/migration-wordpress/libs/extractEntries.js b/upload-api/migration-wordpress/libs/extractEntries.js new file mode 100644 index 000000000..db893a5fc --- /dev/null +++ b/upload-api/migration-wordpress/libs/extractEntries.js @@ -0,0 +1,116 @@ +"use strict"; +const fs = require("fs"); +const path = require("path"); +const config = require("../config/index.json"); + +const contentTypesConfig = config.modules.contentTypes; +const contentTypeFolderPath = path.resolve(config.data, contentTypesConfig.dirName); +const EXCLUDED_POST_TYPES = new Set(["attachment", "wp_global_styles", "wp_navigation"]); + +const normalizeArray = (value) => { + if (!value) return []; + return Array.isArray(value) ? value : [value]; +}; + +const idCorrector = (id) => { + const normalized = id && id.replace(/[-{}]/g, ""); + return normalized ? normalized.toLowerCase() : id; +}; + +const getEntryName = (item) => { + if (typeof item?.title === "string" && item.title.trim()) return item.title.trim(); + if (item?.title?.text) return String(item.title.text).trim(); + if (typeof item?.["wp:post_name"] === "string" && item["wp:post_name"].trim()) { + return item["wp:post_name"].trim(); + } + return "Untitled Entry"; +}; + +const getSourceEntryUid = (item) => { + const candidate = + item?.["wp:post_id"] ?? + item?.guid?.text ?? + item?.guid ?? + item?.link ?? + getEntryName(item); + return idCorrector(String(candidate || "")); +}; + +const getEntryLanguage = (item, channelLanguage) => { + const postMeta = normalizeArray(item?.["wp:postmeta"]); + const languageMeta = postMeta.find((meta) => { + const key = String(meta?.["wp:meta_key"] || "").toLowerCase(); + return key === "language" || key === "_language" || key === "locale" || key === "_locale"; + }); + + const metaLanguage = languageMeta?.["wp:meta_value"]; + if (typeof metaLanguage === "string" && metaLanguage.trim()) { + return metaLanguage.trim(); + } + + if (typeof channelLanguage === "string" && channelLanguage.trim()) { + return channelLanguage.trim(); + } + + return "en-us"; +}; + +const extractEntries = async (filePath, contentTypeData = []) => { + try { + const rawData = await fs.promises.readFile(filePath, "utf8"); + const jsonData = JSON.parse(rawData); + const items = normalizeArray(jsonData?.rss?.channel?.item); + const channelLanguage = jsonData?.rss?.channel?.language; + + const groupedByType = items.reduce((acc, item) => { + const postType = item?.["wp:post_type"] || "unknown"; + if (EXCLUDED_POST_TYPES.has(postType)) return acc; + if (!acc[postType]) acc[postType] = []; + acc[postType].push(item); + return acc; + }, {}); + + const updatedTypes = contentTypeData.map((ct) => ({ ...ct })); + + for (const [type, entries] of Object.entries(groupedByType)) { + const entryMapping = normalizeArray(entries) + .map((item) => { + const otherCmsEntryUid = getSourceEntryUid(item); + if (!otherCmsEntryUid) return null; + return { + contentTypeUid: type, + entryName: getEntryName(item), + otherCmsEntryUid, + otherCmsCTName: type, + language: getEntryLanguage(item, channelLanguage), + isUpdate: false + }; + }) + .filter(Boolean); + + const contentTypeFilePath = path.join(contentTypeFolderPath, `${type.toLowerCase()}.json`); + if (fs.existsSync(contentTypeFilePath)) { + const ctFile = JSON.parse(await fs.promises.readFile(contentTypeFilePath, "utf8")); + ctFile.entryMapping = entryMapping; + await fs.promises.writeFile(contentTypeFilePath, JSON.stringify(ctFile, null, 4), "utf8"); + } + + const index = updatedTypes.findIndex( + (ct) => + ct?.otherCmsUid?.toLowerCase?.() === type.toLowerCase() || + ct?.contentstackUid?.toLowerCase?.() === type.toLowerCase() + ); + if (index >= 0) { + updatedTypes[index] = { ...updatedTypes[index], entryMapping }; + } + } + + return updatedTypes; + } catch (error) { + console.error("Error while extracting WordPress entries:", error?.message || error); + return contentTypeData; + } +}; + +module.exports = extractEntries; +module.exports.default = extractEntries; diff --git a/upload-api/migration-wordpress/libs/extractEntries.ts b/upload-api/migration-wordpress/libs/extractEntries.ts new file mode 100644 index 000000000..3079455fe --- /dev/null +++ b/upload-api/migration-wordpress/libs/extractEntries.ts @@ -0,0 +1,122 @@ +import fs from 'fs'; +import path from 'path'; +import config from '../config/index.json'; + +const { contentTypes: contentTypesConfig } = config.modules; +const contentTypeFolderPath = path.resolve(config.data, contentTypesConfig.dirName); + +const EXCLUDED_POST_TYPES = new Set(['attachment', 'wp_global_styles', 'wp_navigation']); + +const normalizeArray = (value: T | T[] | undefined): T[] => { + if (!value) return []; + return Array.isArray(value) ? value : [value]; +}; + +const idCorrector = (id: string) => { + const normalized = id?.replace?.(/[-{}]/g, ''); + return normalized ? normalized.toLowerCase() : id; +}; + +const getEntryName = (item: any): string => { + if (typeof item?.title === 'string' && item.title.trim()) { + return item.title.trim(); + } + if (item?.title?.text) { + return String(item.title.text).trim(); + } + if (typeof item?.['wp:post_name'] === 'string' && item['wp:post_name'].trim()) { + return item['wp:post_name'].trim(); + } + return 'Untitled Entry'; +}; + +const getSourceEntryUid = (item: any): string => { + const candidate = + item?.['wp:post_id'] ?? + item?.guid?.text ?? + item?.guid ?? + item?.link ?? + getEntryName(item); + return idCorrector(String(candidate || '')); +}; + +const getEntryLanguage = (item: any, channelLanguage?: string): string => { + const postMeta = normalizeArray(item?.['wp:postmeta']); + const languageMeta = postMeta.find((meta: any) => { + const key = String(meta?.['wp:meta_key'] || '').toLowerCase(); + return key === 'language' || key === '_language' || key === 'locale' || key === '_locale'; + }); + + const metaLanguage = languageMeta?.['wp:meta_value']; + if (typeof metaLanguage === 'string' && metaLanguage.trim()) { + return metaLanguage.trim(); + } + + if (typeof channelLanguage === 'string' && channelLanguage.trim()) { + return channelLanguage.trim(); + } + + return 'en-us'; +}; + +const extractEntries = async (filePath: string, contentTypeData: any[] = []) => { + try { + const rawData = await fs.promises.readFile(filePath, 'utf8'); + const jsonData = JSON.parse(rawData); + const items = normalizeArray(jsonData?.rss?.channel?.item); + const channelLanguage = jsonData?.rss?.channel?.language; + + const groupedByType = items.reduce((acc: Record, item: any) => { + const postType = item?.['wp:post_type'] || 'unknown'; + if (EXCLUDED_POST_TYPES.has(postType)) return acc; + if (!acc[postType]) acc[postType] = []; + acc[postType].push(item); + return acc; + }, {}); + + const updatedTypes = contentTypeData.map((ct) => ({ ...ct })); + + for (const [type, entries] of Object.entries(groupedByType)) { + const entryMapping = normalizeArray(entries) + .map((item: any) => { + const otherCmsEntryUid = getSourceEntryUid(item); + if (!otherCmsEntryUid) return null; + return { + contentTypeUid: type, + entryName: getEntryName(item), + otherCmsEntryUid, + otherCmsCTName: type, + language: getEntryLanguage(item, channelLanguage), + isUpdate: false + }; + }) + .filter(Boolean); + + const contentTypeFilePath = path.join(contentTypeFolderPath, `${type.toLowerCase()}.json`); + if (fs.existsSync(contentTypeFilePath)) { + const ctFile = JSON.parse(await fs.promises.readFile(contentTypeFilePath, 'utf8')); + ctFile.entryMapping = entryMapping; + await fs.promises.writeFile(contentTypeFilePath, JSON.stringify(ctFile, null, 4), 'utf8'); + } + + const index = updatedTypes.findIndex( + (ct: any) => + ct?.otherCmsUid?.toLowerCase?.() === type.toLowerCase() || + ct?.contentstackUid?.toLowerCase?.() === type.toLowerCase() + ); + if (index >= 0) { + updatedTypes[index] = { + ...updatedTypes[index], + entryMapping + }; + } + } + + return updatedTypes; + } catch (error: any) { + console.error('Error while extracting WordPress entries:', error?.message || error); + return contentTypeData; + } +}; + +export default extractEntries; diff --git a/upload-api/migration-wordpress/utils/parseUtil.js b/upload-api/migration-wordpress/utils/parseUtil.js index ac5a2f9d2..3389bc729 100644 --- a/upload-api/migration-wordpress/utils/parseUtil.js +++ b/upload-api/migration-wordpress/utils/parseUtil.js @@ -88,10 +88,23 @@ const setupWordPressBlocks = (rawContent) => __awaiter(void 0, void 0, void 0, f // Now import WordPress packages after setting up globals const wpBlocks = yield Promise.resolve().then(() => __importStar(require('@wordpress/blocks'))); const { parse } = yield Promise.resolve().then(() => __importStar(require('@wordpress/blocks'))); - const { registerCoreBlocks } = yield Promise.resolve().then(() => __importStar(require('@wordpress/block-library'))); (_a = wpBlocks.__unstableSetDebugLevel) === null || _a === void 0 ? void 0 : _a.call(wpBlocks, 'none'); - registerCoreBlocks(); - const blocks = parse(rawContent); - return blocks; + try { + const { registerCoreBlocks } = yield Promise.resolve().then(() => __importStar(require('@wordpress/block-library'))); + registerCoreBlocks(); + } + catch (error) { + // Some environments cannot fully initialize Gutenberg internals (e.g. getSettings). + // Continue with parser-only mode so mapper generation does not fail. + console.warn('WordPress core blocks registration failed, using parser-only mode:', (error === null || error === void 0 ? void 0 : error.message) || error); + } + try { + const blocks = parse(rawContent); + return Array.isArray(blocks) ? blocks : []; + } + catch (error) { + console.warn('WordPress block parsing failed, returning empty blocks:', (error === null || error === void 0 ? void 0 : error.message) || error); + return []; + } }); exports.setupWordPressBlocks = setupWordPressBlocks; diff --git a/upload-api/migration-wordpress/utils/parseUtil.ts b/upload-api/migration-wordpress/utils/parseUtil.ts index d899a95bb..7f6058445 100644 --- a/upload-api/migration-wordpress/utils/parseUtil.ts +++ b/upload-api/migration-wordpress/utils/parseUtil.ts @@ -45,13 +45,25 @@ if (!global.navigator || typeof global.navigator === 'object') { } export const setupWordPressBlocks = async (rawContent: any) => { - // Now import WordPress packages after setting up globals const wpBlocks: any = await import('@wordpress/blocks'); const { parse } = await import('@wordpress/blocks'); - const { registerCoreBlocks } = await import('@wordpress/block-library'); wpBlocks.__unstableSetDebugLevel?.('none'); - registerCoreBlocks(); + + try { + const { registerCoreBlocks } = await import('@wordpress/block-library'); + registerCoreBlocks(); + } catch (error: any) { + // Some environments cannot fully initialize Gutenberg internals (e.g. getSettings). + // Continue with parser-only mode so mapper generation does not fail. + console.warn('WordPress core blocks registration failed, using parser-only mode:', error?.message || error); + } + + try { const blocks = parse(rawContent); - return blocks; + return Array.isArray(blocks) ? blocks : []; + } catch (error: any) { + console.warn('WordPress block parsing failed, returning empty blocks:', error?.message || error); + return []; + } } \ No newline at end of file diff --git a/upload-api/src/config/index.json b/upload-api/src/config/index.json index def7147fa..65d245605 100644 --- a/upload-api/src/config/index.json +++ b/upload-api/src/config/index.json @@ -4,7 +4,7 @@ "optionLimit": 100 } }, - "cmsType": "cmsType", + "cmsType": "wordpress", "isLocalPath": true, "awsData": { "awsRegion": "us-east-2", @@ -15,15 +15,15 @@ "bucketKey": "" }, "mysql": { - "host": "host_name", - "user": "user_name", + "host": "localhost", + "user": "root", "password": "", - "database": "database_name", - "port": "port_number" + "database": "", + "port": "3306" }, "assetsConfig": { - "base_url": "drupal_assets_base_url", - "public_path": "drupal_assets_public_path" + "base_url": "https://www.rice.edu/", + "public_path": "sites/g/files/bxs2566/files" }, - "localPath": "" + "localPath": "/Users/chetan.narkhede/Desktop/migration-v2/sitetitle.xml" } \ No newline at end of file diff --git a/upload-api/src/controllers/wordpress/index.ts b/upload-api/src/controllers/wordpress/index.ts index 269c0b1c5..9b5d46d31 100644 --- a/upload-api/src/controllers/wordpress/index.ts +++ b/upload-api/src/controllers/wordpress/index.ts @@ -2,27 +2,29 @@ import axios from "axios"; import logger from "../../utils/logger"; import { HTTP_CODES, HTTP_TEXTS, MIGRATION_DATA_CONFIG } from "../../constants"; // eslint-disable-next-line @typescript-eslint/no-var-requires -import { extractContentTypes, extractLocale } from 'migration-wordpress'; -import { deleteFolderSync } from "../../helper"; -import path from "path"; +import { extractContentTypes, extractEntries, extractLocale } from 'migration-wordpress'; +import { deleteFolderSync } from '../../helper'; +import path from 'path'; -const createWordpressMapper = async (filePath: string = "", projectId: string | string[], app_token: string | string[], affix: string | string[], config: any) => { +const createWordpressMapper = async (filePath: string = '',projectId: string | string[],app_token: string | string[],affix: string | string[],config: any +) => { try { const localeData = await extractLocale(filePath); - const contentTypeData : any = await extractContentTypes(affix as string, filePath, config); + const extractedContentTypes: any = await extractContentTypes(affix as string, filePath, config); + const contentTypeData: any = await extractEntries(filePath, extractedContentTypes); //const contentTypeData = await contentTypeMaker(affix, filePath) - - if(contentTypeData){ + + if (contentTypeData) { const fieldMapping: any = { contentTypes: [], extractPath: filePath }; contentTypeData.forEach((contentType: any) => { const jsonfileContent = contentType; - jsonfileContent.type = "content_type"; + jsonfileContent.type = 'content_type'; fieldMapping?.contentTypes?.push(jsonfileContent); - }) - + }); + const config = { method: 'post', maxBodyLength: Infinity, @@ -31,9 +33,9 @@ const createWordpressMapper = async (filePath: string = "", projectId: string | app_token, 'Content-Type': 'application/json' }, - data: JSON.stringify(fieldMapping), + data: JSON.stringify(fieldMapping) }; - const {data} = await axios.request(config); + const { data } = await axios.request(config); if (data?.data?.content_mapper?.length) { deleteFolderSync(path.join(process.cwd(), MIGRATION_DATA_CONFIG.DATA)); logger.info('Validation success:', { @@ -51,26 +53,26 @@ const createWordpressMapper = async (filePath: string = "", projectId: string | 'Content-Type': 'application/json' }, data: { - locale:Array.from(localeData) - }, + locale: Array.from(localeData) + } }; - const mapRes = await axios.request(mapperConfig) - if(mapRes?.status==200){ + const mapRes = await axios.request(mapperConfig); + if (mapRes?.status == 200) { logger.info('Legacy CMS', { status: HTTP_CODES?.OK, - message: HTTP_TEXTS?.LOCALE_SAVED, + message: HTTP_TEXTS?.LOCALE_SAVED }); } } } catch (err: any) { - console.error("🚀 ~ createWordpressMapper ~ err:", err?.response?.data ?? err) + console.error('🚀 ~ createWordpressMapper ~ err:', err?.response?.data ?? err); logger.warn('Validation error:', { status: HTTP_CODES?.UNAUTHORIZED, - message: HTTP_TEXTS?.VALIDATION_ERROR, + message: HTTP_TEXTS?.VALIDATION_ERROR }); } -} +}; export default createWordpressMapper; \ No newline at end of file diff --git a/upload-api/src/routes/index.ts b/upload-api/src/routes/index.ts index a91025c8c..c1f417021 100644 --- a/upload-api/src/routes/index.ts +++ b/upload-api/src/routes/index.ts @@ -233,10 +233,6 @@ router.get( } const data = await handleFileProcessing(fileExt, xmlData, cmsType || '', name); - if (!res.headersSent) { - res.status(data?.status || 200).json(data); - } - res.status(data?.status || 200).json(data); if (data?.status === 200) { // Sanitize the filename before constructing path const safeName = sanitizeFilename(name); @@ -249,6 +245,9 @@ router.get( console.error('Path traversal attempt detected'); } } + if (!res.headersSent) { + return res.status(data?.status || 200).json(data); + } } catch (error: any) { console.error('Error processing XML stream:', error); if (!res.headersSent) { From 7425777666e804fec11b594dc27c0a2c934ce9ed Mon Sep 17 00:00:00 2001 From: chetan-contentstack Date: Mon, 6 Apr 2026 12:28:14 +0530 Subject: [PATCH 2/6] Refactor extractEntries logic to improve null safety and consistency; update string handling and error logging for better readability and maintainability. --- .../libs/extractEntries.js | 50 +++++++++---------- .../libs/extractEntries.ts | 14 ++---- 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/upload-api/migration-wordpress/libs/extractEntries.js b/upload-api/migration-wordpress/libs/extractEntries.js index db893a5fc..d58fb5638 100644 --- a/upload-api/migration-wordpress/libs/extractEntries.js +++ b/upload-api/migration-wordpress/libs/extractEntries.js @@ -3,9 +3,9 @@ const fs = require("fs"); const path = require("path"); const config = require("../config/index.json"); -const contentTypesConfig = config.modules.contentTypes; -const contentTypeFolderPath = path.resolve(config.data, contentTypesConfig.dirName); -const EXCLUDED_POST_TYPES = new Set(["attachment", "wp_global_styles", "wp_navigation"]); +const { contentTypes: contentTypesConfig } = config?.modules ?? {}; +const contentTypeFolderPath = path.resolve(config?.data, contentTypesConfig?.dirName); +const EXCLUDED_POST_TYPES = new Set(['attachment', 'wp_global_styles', 'wp_navigation']); const normalizeArray = (value) => { if (!value) return []; @@ -13,57 +13,53 @@ const normalizeArray = (value) => { }; const idCorrector = (id) => { - const normalized = id && id.replace(/[-{}]/g, ""); + const normalized = id?.replace(/[-{}]/g, ''); return normalized ? normalized.toLowerCase() : id; }; const getEntryName = (item) => { - if (typeof item?.title === "string" && item.title.trim()) return item.title.trim(); + if (typeof item?.title === 'string' && item.title.trim()) return item.title.trim(); if (item?.title?.text) return String(item.title.text).trim(); - if (typeof item?.["wp:post_name"] === "string" && item["wp:post_name"].trim()) { - return item["wp:post_name"].trim(); + if (typeof item?.['wp:post_name'] === 'string' && item['wp:post_name'].trim()) { + return item['wp:post_name'].trim(); } - return "Untitled Entry"; + return 'Untitled Entry'; }; const getSourceEntryUid = (item) => { const candidate = - item?.["wp:post_id"] ?? - item?.guid?.text ?? - item?.guid ?? - item?.link ?? - getEntryName(item); - return idCorrector(String(candidate || "")); + item?.['wp:post_id'] ?? item?.guid?.text ?? item?.guid ?? item?.link ?? getEntryName(item); + return idCorrector(String(candidate || '')); }; const getEntryLanguage = (item, channelLanguage) => { - const postMeta = normalizeArray(item?.["wp:postmeta"]); + const postMeta = normalizeArray(item?.['wp:postmeta']); const languageMeta = postMeta.find((meta) => { - const key = String(meta?.["wp:meta_key"] || "").toLowerCase(); - return key === "language" || key === "_language" || key === "locale" || key === "_locale"; + const key = String(meta?.['wp:meta_key'] || '').toLowerCase(); + return key === 'language' || key === '_language' || key === 'locale' || key === '_locale'; }); - const metaLanguage = languageMeta?.["wp:meta_value"]; - if (typeof metaLanguage === "string" && metaLanguage.trim()) { + const metaLanguage = languageMeta?.['wp:meta_value']; + if (typeof metaLanguage === 'string' && metaLanguage.trim()) { return metaLanguage.trim(); } - if (typeof channelLanguage === "string" && channelLanguage.trim()) { + if (typeof channelLanguage === 'string' && channelLanguage.trim()) { return channelLanguage.trim(); } - return "en-us"; + return 'en-us'; }; const extractEntries = async (filePath, contentTypeData = []) => { try { - const rawData = await fs.promises.readFile(filePath, "utf8"); + const rawData = await fs.promises.readFile(filePath, 'utf8'); const jsonData = JSON.parse(rawData); const items = normalizeArray(jsonData?.rss?.channel?.item); const channelLanguage = jsonData?.rss?.channel?.language; - const groupedByType = items.reduce((acc, item) => { - const postType = item?.["wp:post_type"] || "unknown"; + const groupedByType = items?.reduce((acc, item) => { + const postType = item?.['wp:post_type'] || 'unknown'; if (EXCLUDED_POST_TYPES.has(postType)) return acc; if (!acc[postType]) acc[postType] = []; acc[postType].push(item); @@ -90,9 +86,9 @@ const extractEntries = async (filePath, contentTypeData = []) => { const contentTypeFilePath = path.join(contentTypeFolderPath, `${type.toLowerCase()}.json`); if (fs.existsSync(contentTypeFilePath)) { - const ctFile = JSON.parse(await fs.promises.readFile(contentTypeFilePath, "utf8")); + const ctFile = JSON.parse(await fs.promises.readFile(contentTypeFilePath, 'utf8')); ctFile.entryMapping = entryMapping; - await fs.promises.writeFile(contentTypeFilePath, JSON.stringify(ctFile, null, 4), "utf8"); + await fs.promises.writeFile(contentTypeFilePath, JSON.stringify(ctFile, null, 4), 'utf8'); } const index = updatedTypes.findIndex( @@ -107,7 +103,7 @@ const extractEntries = async (filePath, contentTypeData = []) => { return updatedTypes; } catch (error) { - console.error("Error while extracting WordPress entries:", error?.message || error); + console.error('Error while extracting WordPress entries:', error?.message || error); return contentTypeData; } }; diff --git a/upload-api/migration-wordpress/libs/extractEntries.ts b/upload-api/migration-wordpress/libs/extractEntries.ts index 3079455fe..176466d7a 100644 --- a/upload-api/migration-wordpress/libs/extractEntries.ts +++ b/upload-api/migration-wordpress/libs/extractEntries.ts @@ -2,8 +2,8 @@ import fs from 'fs'; import path from 'path'; import config from '../config/index.json'; -const { contentTypes: contentTypesConfig } = config.modules; -const contentTypeFolderPath = path.resolve(config.data, contentTypesConfig.dirName); +const { contentTypes: contentTypesConfig } = config?.modules; +const contentTypeFolderPath = path.resolve(config?.data, contentTypesConfig?.dirName); const EXCLUDED_POST_TYPES = new Set(['attachment', 'wp_global_styles', 'wp_navigation']); @@ -13,7 +13,7 @@ const normalizeArray = (value: T | T[] | undefined): T[] => { }; const idCorrector = (id: string) => { - const normalized = id?.replace?.(/[-{}]/g, ''); + const normalized = id?.replace(/[-{}]/g, ''); return normalized ? normalized.toLowerCase() : id; }; @@ -32,11 +32,7 @@ const getEntryName = (item: any): string => { const getSourceEntryUid = (item: any): string => { const candidate = - item?.['wp:post_id'] ?? - item?.guid?.text ?? - item?.guid ?? - item?.link ?? - getEntryName(item); + item?.['wp:post_id'] ?? item?.guid?.text ?? item?.guid ?? item?.link ?? getEntryName(item); return idCorrector(String(candidate || '')); }; @@ -66,7 +62,7 @@ const extractEntries = async (filePath: string, contentTypeData: any[] = []) => const items = normalizeArray(jsonData?.rss?.channel?.item); const channelLanguage = jsonData?.rss?.channel?.language; - const groupedByType = items.reduce((acc: Record, item: any) => { + const groupedByType = items?.reduce((acc: Record, item: any) => { const postType = item?.['wp:post_type'] || 'unknown'; if (EXCLUDED_POST_TYPES.has(postType)) return acc; if (!acc[postType]) acc[postType] = []; From 4dceab4ccbf59de278c6b4a078c5c8f19b44be49 Mon Sep 17 00:00:00 2001 From: chetan-contentstack Date: Mon, 6 Apr 2026 12:29:48 +0530 Subject: [PATCH 3/6] Enhance null safety in extractEntries by adding optional chaining to contentTypeData mapping. --- upload-api/migration-wordpress/libs/extractEntries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upload-api/migration-wordpress/libs/extractEntries.ts b/upload-api/migration-wordpress/libs/extractEntries.ts index 176466d7a..cfa7c6282 100644 --- a/upload-api/migration-wordpress/libs/extractEntries.ts +++ b/upload-api/migration-wordpress/libs/extractEntries.ts @@ -70,7 +70,7 @@ const extractEntries = async (filePath: string, contentTypeData: any[] = []) => return acc; }, {}); - const updatedTypes = contentTypeData.map((ct) => ({ ...ct })); + const updatedTypes = contentTypeData?.map((ct) => ({ ...ct })); for (const [type, entries] of Object.entries(groupedByType)) { const entryMapping = normalizeArray(entries) From 988e8154982f374cbf7697109c04d6863000893c Mon Sep 17 00:00:00 2001 From: chetan-contentstack Date: Mon, 6 Apr 2026 14:11:19 +0530 Subject: [PATCH 4/6] Update saveEntry function to enhance field UID matching logic for improved data handling. --- api/src/services/wordpress.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/src/services/wordpress.service.ts b/api/src/services/wordpress.service.ts index 38429e6b1..bf5b7c2ec 100644 --- a/api/src/services/wordpress.service.ts +++ b/api/src/services/wordpress.service.ts @@ -486,7 +486,9 @@ async function saveEntry(fields: any, entry: any, file_path: string, assetData const entryData: Record = {}; const fieldList = Array.isArray(fields) ? fields : []; const hasField = (uid: string) => - fieldList.some((field: any) => field?.uid === uid); + fieldList.some( + (field: any) => field?.contentstackFieldUid === uid || field?.uid === uid + ); try { if(entry ){ From f4f58a9f5fc8c0406cf25cc7b0a7ee23bd3ea037 Mon Sep 17 00:00:00 2001 From: chetan-contentstack Date: Mon, 6 Apr 2026 14:37:25 +0530 Subject: [PATCH 5/6] Update lodash and jsdom versions in package.json and package-lock.json; upgrade multer in upload-api and fix migration-wordpress package name. --- api/package-lock.json | 16 +- api/package.json | 2 +- upload-api/migration-wordpress/package.json | 2 +- upload-api/package-lock.json | 612 +++++++++----------- upload-api/package.json | 6 +- 5 files changed, 297 insertions(+), 341 deletions(-) diff --git a/api/package-lock.json b/api/package-lock.json index a641fdb2d..f4f5f95ed 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -30,7 +30,7 @@ "html-to-json-parser": "^2.0.1", "jsdom": "^24.1.0", "jsonwebtoken": "^9.0.3", - "lodash": "^4.17.21", + "lodash": "^4.18.1", "lowdb": "^7.0.1", "mkdirp": "^3.0.1", "mysql2": "^3.16.2", @@ -9782,6 +9782,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { @@ -10302,9 +10303,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.clonedeep": { @@ -13750,6 +13751,12 @@ "node": ">=0.10.0" } }, + "node_modules/omit-deep-lodash/node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -16108,6 +16115,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, "license": "MIT" }, "node_modules/thirty-two": { diff --git a/api/package.json b/api/package.json index 52ee2246c..a533d36a2 100644 --- a/api/package.json +++ b/api/package.json @@ -46,7 +46,7 @@ "html-to-json-parser": "^2.0.1", "jsdom": "^24.1.0", "jsonwebtoken": "^9.0.3", - "lodash": "^4.17.21", + "lodash": "^4.18.1", "lowdb": "^7.0.1", "mkdirp": "^3.0.1", "mysql2": "^3.16.2", diff --git a/upload-api/migration-wordpress/package.json b/upload-api/migration-wordpress/package.json index af0722115..6b80628f0 100644 --- a/upload-api/migration-wordpress/package.json +++ b/upload-api/migration-wordpress/package.json @@ -1,5 +1,5 @@ { - "name": "migration-v2-wordpress", + "name": "migration-wordpress", "version": "1.0.0", "description": "", "main": "build/index.js", diff --git a/upload-api/package-lock.json b/upload-api/package-lock.json index d535109cd..071f8c19a 100644 --- a/upload-api/package-lock.json +++ b/upload-api/package-lock.json @@ -24,9 +24,9 @@ "fs-readdir-recursive": "^1.1.0", "generate-schema": "^2.6.0", "helmet": "^7.1.0", - "jsdom": "^19.0.0", + "jsdom": "^23.0.0", "jszip": "^3.10.1", - "lodash": "^4.17.21", + "lodash": "^4.18.1", "lodash.isempty": "^4.4.0", "migration-aem": "file:migration-aem", "migration-contentful": "file:migration-contentful", @@ -34,7 +34,7 @@ "migration-sitecore": "file:migration-sitecore", "migration-wordpress": "file:migration-wordpress", "mkdirp": "^1.0.4", - "multer": "^2.0.1", + "multer": "^2.1.1", "mysql2": "^3.16.2", "php-serialize": "^5.1.3", "prettier": "^3.3.3", @@ -83,7 +83,6 @@ "migration-drupal": {}, "migration-sitecore": {}, "migration-wordpress": { - "name": "migration-v2-wordpress", "version": "1.0.0", "license": "ISC" }, @@ -128,6 +127,36 @@ "react-dom": "^17.0.0 || ^18.0.0" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-2.0.2.tgz", + "integrity": "sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ==", + "license": "MIT", + "dependencies": { + "bidi-js": "^1.0.3", + "css-tree": "^2.3.1", + "is-potential-custom-element-name": "^1.0.1" + } + }, "node_modules/@aws-crypto/crc32": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", @@ -1331,6 +1360,116 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@dabh/diagnostics": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz", @@ -2675,15 +2814,6 @@ "integrity": "sha512-RwARl+hFwhzy0tg9atWcchLFvoQiOh4rrP7uG2N5E4W80BPCUX0ElcUR9St43fxB9EfjsW2df9Qp+UsTbvQDjA==", "license": "MIT" }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", @@ -4440,13 +4570,6 @@ "npm": ">=8.19.2" } }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "license": "BSD-3-Clause" - }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -4472,28 +4595,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "license": "MIT", - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -4503,25 +4604,13 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", - "dependencies": { - "debug": "4" - }, "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/ajv": { @@ -4813,6 +4902,15 @@ ], "license": "MIT" }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -4958,12 +5056,6 @@ "wcwidth": "^1.0.1" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "license": "BSD-2-Clause" - }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -5748,6 +5840,19 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/css-what": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", @@ -5760,28 +5865,23 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "license": "MIT" - }, "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", "license": "MIT", "dependencies": { - "cssom": "~0.3.6" + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", "license": "MIT" }, "node_modules/csstype": { @@ -5824,39 +5924,16 @@ "license": "MIT" }, "node_modules/data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "license": "MIT", - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/data-urls/node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/data-urls/node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "license": "MIT", "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/data-view-buffer": { @@ -6107,19 +6184,6 @@ ], "license": "BSD-2-Clause" }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "deprecated": "Use your platform's native DOMException instead", - "license": "MIT", - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", @@ -6494,37 +6558,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/eslint": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.0.tgz", @@ -6762,19 +6795,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/esquery": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", @@ -7682,28 +7702,15 @@ "license": "MIT" }, "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "license": "MIT", - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-encoding-sniffer/node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "license": "MIT", "dependencies": { - "iconv-lite": "0.6.3" + "whatwg-encoding": "^3.1.1" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/htmlparser2": { @@ -7758,30 +7765,29 @@ } }, "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { - "agent-base": "6", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/husky": { @@ -8995,44 +9001,38 @@ } }, "node_modules/jsdom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", - "integrity": "sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==", - "license": "MIT", - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.5.0", - "acorn-globals": "^6.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.1", - "decimal.js": "^10.3.1", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.2.0.tgz", + "integrity": "sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==", + "license": "MIT", + "dependencies": { + "@asamuzakjp/dom-selector": "^2.0.1", + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^3.0.0", + "tough-cookie": "^4.1.3", + "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^10.0.0", - "ws": "^8.2.3", - "xml-name-validator": "^4.0.0" + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.16.0", + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "peerDependencies": { - "canvas": "^2.5.0" + "canvas": "^2.11.2" }, "peerDependenciesMeta": { "canvas": { @@ -9040,34 +9040,6 @@ } } }, - "node_modules/jsdom/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "license": "MIT" - }, - "node_modules/jsdom/node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", - "license": "MIT", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/jsdom/node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -9214,9 +9186,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.isempty": { @@ -9326,6 +9298,12 @@ "node": ">= 0.4" } }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "license": "CC0-1.0" + }, "node_modules/media-typer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", @@ -9422,15 +9400,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/minipass": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", @@ -9515,21 +9484,22 @@ "license": "MIT" }, "node_modules/multer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", - "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz", + "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", "license": "MIT", "dependencies": { "append-field": "^1.0.0", "busboy": "^1.6.0", "concat-stream": "^2.0.0", - "mkdirp": "^0.5.6", - "object-assign": "^4.1.1", - "type-is": "^1.6.18", - "xtend": "^4.0.2" + "type-is": "^1.6.18" }, "engines": { "node": ">= 10.16.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/multer/node_modules/media-typer": { @@ -9562,18 +9532,6 @@ "node": ">= 0.6" } }, - "node_modules/multer/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/multer/node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -9778,12 +9736,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/nwsapi": { - "version": "2.2.23", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", - "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", - "license": "MIT" - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -10844,6 +10796,12 @@ "url": "https://opencollective.com/express" } }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "license": "MIT" + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -10999,15 +10957,15 @@ } }, "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "license": "ISC", "dependencies": { "xmlchars": "^2.2.0" }, "engines": { - "node": ">=10" + "node": ">=v12.22.7" } }, "node_modules/scheduler": { @@ -11439,6 +11397,15 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", @@ -11836,15 +11803,15 @@ } }, "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", "license": "MIT", "dependencies": { - "punycode": "^2.1.1" + "punycode": "^2.3.1" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/traverse": { @@ -12370,26 +12337,16 @@ "node": ">= 0.8" } }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", - "license": "MIT", - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, "node_modules/w3c-xmlserializer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", - "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "license": "MIT", "dependencies": { - "xml-name-validator": "^4.0.0" + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/wcwidth": { @@ -12433,16 +12390,16 @@ } }, "node_modules/whatwg-url": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", - "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "license": "MIT", "dependencies": { - "tr46": "^3.0.0", + "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/which": { @@ -12702,12 +12659,12 @@ } }, "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/xml2js": { @@ -12738,15 +12695,6 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "license": "MIT" }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", diff --git a/upload-api/package.json b/upload-api/package.json index c64a0dcfd..4900dd303 100644 --- a/upload-api/package.json +++ b/upload-api/package.json @@ -54,9 +54,9 @@ "fs-readdir-recursive": "^1.1.0", "generate-schema": "^2.6.0", "helmet": "^7.1.0", - "jsdom": "^19.0.0", + "jsdom": "^23.0.0", "jszip": "^3.10.1", - "lodash": "^4.17.21", + "lodash": "^4.18.1", "lodash.isempty": "^4.4.0", "migration-aem": "file:migration-aem", "migration-contentful": "file:migration-contentful", @@ -64,7 +64,7 @@ "migration-sitecore": "file:migration-sitecore", "migration-wordpress": "file:migration-wordpress", "mkdirp": "^1.0.4", - "multer": "^2.0.1", + "multer": "^2.1.1", "mysql2": "^3.16.2", "php-serialize": "^5.1.3", "prettier": "^3.3.3", From d8cb5e59aa7fafd601fcfb7fe653cac9c4e316c5 Mon Sep 17 00:00:00 2001 From: chetan-contentstack Date: Tue, 7 Apr 2026 15:47:55 +0530 Subject: [PATCH 6/6] fix(extractEntries): align source entry UID generation with WordPress API standards and ensure consistency in otherCmsEntryUid formatting --- .../migration-wordpress/libs/extractEntries.js | 9 +++++++-- .../migration-wordpress/libs/extractEntries.ts | 12 ++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/upload-api/migration-wordpress/libs/extractEntries.js b/upload-api/migration-wordpress/libs/extractEntries.js index d58fb5638..ba41383e4 100644 --- a/upload-api/migration-wordpress/libs/extractEntries.js +++ b/upload-api/migration-wordpress/libs/extractEntries.js @@ -26,9 +26,14 @@ const getEntryName = (item) => { return 'Untitled Entry'; }; +/** Align with api wordpress.service entry uid: idCorrector(`posts_${wp:post_id}`). */ const getSourceEntryUid = (item) => { + const postId = item?.['wp:post_id']; + if (postId != null && String(postId).trim() !== '') { + return idCorrector(`posts_${postId}`); + } const candidate = - item?.['wp:post_id'] ?? item?.guid?.text ?? item?.guid ?? item?.link ?? getEntryName(item); + item?.guid?.text ?? item?.guid ?? item?.link ?? getEntryName(item); return idCorrector(String(candidate || '')); }; @@ -76,7 +81,7 @@ const extractEntries = async (filePath, contentTypeData = []) => { return { contentTypeUid: type, entryName: getEntryName(item), - otherCmsEntryUid, + otherCmsEntryUid: `posts_${otherCmsEntryUid}`, otherCmsCTName: type, language: getEntryLanguage(item, channelLanguage), isUpdate: false diff --git a/upload-api/migration-wordpress/libs/extractEntries.ts b/upload-api/migration-wordpress/libs/extractEntries.ts index cfa7c6282..2bbd075ae 100644 --- a/upload-api/migration-wordpress/libs/extractEntries.ts +++ b/upload-api/migration-wordpress/libs/extractEntries.ts @@ -30,9 +30,17 @@ const getEntryName = (item: any): string => { return 'Untitled Entry'; }; +/** + * Must match api WordPress entry keys: idCorrector(`posts_${wp:post_id}`) in wordpress.service.ts. + * Raw post id only caused otherCmsEntryUid to diverge from uid-map / entry JSON keys → entry mapper showed "-". + */ const getSourceEntryUid = (item: any): string => { + const postId = item?.['wp:post_id']; + if (postId != null && String(postId).trim() !== '') { + return idCorrector(`posts_${postId}`); + } const candidate = - item?.['wp:post_id'] ?? item?.guid?.text ?? item?.guid ?? item?.link ?? getEntryName(item); + item?.guid?.text ?? item?.guid ?? item?.link ?? getEntryName(item); return idCorrector(String(candidate || '')); }; @@ -80,7 +88,7 @@ const extractEntries = async (filePath: string, contentTypeData: any[] = []) => return { contentTypeUid: type, entryName: getEntryName(item), - otherCmsEntryUid, + otherCmsEntryUid: `posts_${otherCmsEntryUid}`, otherCmsCTName: type, language: getEntryLanguage(item, channelLanguage), isUpdate: false