UNPKG

@itxch/contentful-import

Version:

This tool allows you to import JSON dump exported by contentful-export

315 lines (314 loc) 11.2 kB
import Listr from "listr"; import verboseRenderer from "listr-verbose-renderer"; import { logEmitter } from "contentful-batch-libs/dist/logging.js"; import { wrapTask } from "contentful-batch-libs/dist/listr.js"; import { getAssetStreamForURL, processAssets } from "./assets.js"; import { createLocales, createEntities, createEntries } from "./creation.js"; import { publishEntities as publishEntities$1, archiveEntities as archiveEntities$1 } from "./publishing.js"; import { ContentfulEntityError } from "../../utils/errors.js"; const DEFAULT_CONTENT_STRUCTURE = { entries: [], assets: [], contentTypes: [], tags: [], locales: [], webhooks: [], editorInterfaces: [] }; function pushToSpace({ sourceData, destinationData = {}, client, spaceId, environmentId, contentModelOnly, skipContentModel, skipContentUpdates, skipLocales, skipContentPublishing, timeout, retryLimit, listrOptions, uploadAssets, skipAssetUpdates, assetsDirectory, requestQueue }) { sourceData = { ...DEFAULT_CONTENT_STRUCTURE, ...sourceData }; destinationData = { ...DEFAULT_CONTENT_STRUCTURE, ...destinationData }; listrOptions = listrOptions || { renderer: verboseRenderer }; const destinationDataById = {}; for (const [entityType, entities] of Object.entries(destinationData)) { const entitiesById = /* @__PURE__ */ new Map(); for (const entity of entities) { entitiesById.set(entity.sys.id, entity); } destinationDataById[entityType] = entitiesById; } return new Listr([ { title: "Connecting to space", task: wrapTask(async (ctx) => { const space = await client.getSpace(spaceId); const environment = await space.getEnvironment(environmentId); ctx.space = space; ctx.environment = environment; }) }, { title: "Importing Locales", task: wrapTask(async (ctx) => { if (!destinationDataById.locales) { return; } const locales = await createLocales({ context: { target: ctx.environment, type: "Locale" }, entities: sourceData.locales, destinationEntitiesById: destinationDataById.locales, requestQueue }); ctx.data.locales = locales; }), skip: () => skipContentModel || skipLocales }, { title: "Importing Content Types", task: wrapTask(async (ctx) => { if (!destinationDataById.contentTypes) { return; } const contentTypes = await createEntities({ context: { target: ctx.environment, type: "ContentType" }, entities: sourceData.contentTypes, destinationEntitiesById: destinationDataById.contentTypes, skipUpdates: false, requestQueue }); ctx.data.contentTypes = contentTypes; }), skip: () => skipContentModel }, { title: "Publishing Content Types", task: wrapTask(async (ctx) => { const publishedContentTypes = await publishEntities({ entities: ctx.data.contentTypes, sourceEntities: sourceData.contentTypes, requestQueue }); ctx.data.contentTypes = publishedContentTypes; }), skip: () => skipContentModel }, { title: "Importing Tags", task: wrapTask(async (ctx) => { if (sourceData.tags && destinationDataById.tags) { const tags = await createEntities({ context: { target: ctx.environment, type: "Tag" }, entities: sourceData.tags, destinationEntitiesById: destinationDataById.tags, skipUpdates: false, requestQueue }); ctx.data.tags = tags; } }), // we remove `tags` from destination data if an error was thrown trying to access them // this means the user doesn't have access to this feature, skip importing tags skip: () => !destinationDataById.tags }, { title: "Importing Editor Interfaces", task: wrapTask(async (ctx) => { const allEditorInterfacesBeingFetched = ctx.data.contentTypes.map(async (contentType) => { if (!sourceData.editorInterfaces) { return; } const editorInterface = sourceData.editorInterfaces.find((editorInterface2) => { return editorInterface2.sys.contentType.sys.id === contentType.sys.id; }); if (!editorInterface) { return; } try { const ctEditorInterface = await requestQueue.add(() => ctx.environment.getEditorInterfaceForContentType(contentType.sys.id)); logEmitter.emit("info", `Fetched editor interface for ${contentType.name}`); ctEditorInterface.controls = editorInterface.controls; ctEditorInterface.groupControls = editorInterface.groupControls; ctEditorInterface.editorLayout = editorInterface.editorLayout; ctEditorInterface.sidebar = editorInterface.sidebar; ctEditorInterface.editors = editorInterface.editors; const updatedEditorInterface = await requestQueue.add(() => ctEditorInterface.update()); return updatedEditorInterface; } catch (err) { if (err instanceof ContentfulEntityError) { err.entity = editorInterface; } throw err; } }); const allEditorInterfaces = await Promise.all(allEditorInterfacesBeingFetched); const editorInterfaces = allEditorInterfaces.filter((editorInterface) => editorInterface); ctx.data.editorInterfaces = editorInterfaces; }), skip: (ctx) => skipContentModel || ctx.data.contentTypes.length === 0 }, { title: "Uploading Assets", task: wrapTask(async (ctx) => { const allPendingUploads = []; for (const asset of sourceData.assets) { for (const file of Object.values(asset.transformed.fields.file)) { allPendingUploads.push(requestQueue.add(async () => { try { logEmitter.emit("info", `Uploading Asset file ${file.upload}`); const assetStream = await getAssetStreamForURL(file.upload, assetsDirectory); const upload = await ctx.environment.createUpload({ fileName: asset.transformed.sys.id, file: assetStream }); delete file.upload; file.uploadFrom = { sys: { type: "Link", linkType: "Upload", id: upload.sys.id } }; return upload; } catch (err) { logEmitter.emit("error", err); } })); } } const uploads = await Promise.all(allPendingUploads); ctx.data.uploadedAssetFiles = uploads; }), skip: () => !uploadAssets || !sourceData.assets.length }, { title: "Importing Assets", task: wrapTask(async (ctx) => { if (!destinationDataById.assets) { return; } const assetsToProcess = await createEntities({ context: { target: ctx.environment, type: "Asset" }, entities: sourceData.assets, destinationEntitiesById: destinationDataById.assets, skipUpdates: skipAssetUpdates, requestQueue }); const processedAssets = await processAssets({ assets: assetsToProcess, timeout, retryLimit, requestQueue }); ctx.data.assets = processedAssets; }), skip: () => contentModelOnly }, { title: "Publishing Assets", task: wrapTask(async (ctx) => { const publishedAssets = await publishEntities({ entities: ctx.data.assets, sourceEntities: sourceData.assets, requestQueue }); ctx.data.publishedAssets = publishedAssets; }), skip: () => contentModelOnly || skipContentPublishing }, { title: "Archiving Assets", task: wrapTask(async (ctx) => { const archivedAssets = await archiveEntities({ entities: ctx.data.assets, sourceEntities: sourceData.assets, requestQueue }); ctx.data.archivedAssets = archivedAssets; }), skip: () => contentModelOnly || skipContentPublishing }, { title: "Importing Content Entries", task: wrapTask(async (ctx) => { const entries = await createEntries({ context: { target: ctx.environment, skipContentModel }, entities: sourceData.entries, destinationEntitiesById: destinationDataById.entries, skipUpdates: skipContentUpdates, requestQueue }); ctx.data.entries = entries; }), skip: () => contentModelOnly }, { title: "Publishing Content Entries", task: wrapTask(async (ctx) => { const publishedEntries = await publishEntities({ entities: ctx.data.entries, sourceEntities: sourceData.entries, requestQueue }); ctx.data.publishedEntries = publishedEntries; }), skip: () => contentModelOnly || skipContentPublishing }, { title: "Archiving Entries", task: wrapTask(async (ctx) => { const archivedEntries = await archiveEntities({ entities: ctx.data.entries, sourceEntities: sourceData.entries, requestQueue }); ctx.data.archivedEntries = archivedEntries; }), skip: () => contentModelOnly || skipContentPublishing }, { title: "Creating Web Hooks", task: wrapTask(async (ctx) => { if (!sourceData.webhooks || !destinationDataById.webhooks) { return; } const webhooks = await createEntities({ context: { target: ctx.space, type: "Webhook" }, entities: sourceData.webhooks, destinationEntitiesById: destinationDataById.webhooks, requestQueue }); ctx.data.webhooks = webhooks; }), skip: () => contentModelOnly || environmentId !== "master" && "Webhooks can only be imported in master environment" } ], listrOptions); } function archiveEntities({ entities, sourceEntities, requestQueue }) { const entityIdsToArchive = sourceEntities.filter(({ original }) => original.sys.archivedVersion).map(({ original }) => original.sys.id); const entitiesToArchive = entities.filter((entity) => entityIdsToArchive.indexOf(entity.sys.id) !== -1); return archiveEntities$1({ entities: entitiesToArchive, requestQueue }); } function publishEntities({ entities, sourceEntities, requestQueue }) { const entityIdsToPublish = sourceEntities.filter(({ original }) => original.sys.publishedVersion).map(({ original }) => original.sys.id); const entitiesToPublish = entities.filter((entity) => entityIdsToPublish.indexOf(entity.sys.id) !== -1); return publishEntities$1({ entities: entitiesToPublish, requestQueue }); } export { pushToSpace as default };