UNPKG

sb-mig

Version:

CLI to rule the world. (and handle stuff related to Storyblok CMS)

186 lines (185 loc) 7.35 kB
import Logger from "../../utils/logger.js"; import { getAllItemsWithPagination } from "../utils/request.js"; import { createDatasourceEntries, getDatasourceEntries, } from "./datasource-entries.js"; import { formatDatasourceApiError } from "./error-formatting.js"; // GET export const getAllDatasources = (config) => { const { sbApi, spaceId } = config; Logger.log("Trying to get all Datasources."); return getAllItemsWithPagination({ // @ts-ignore apiFn: ({ per_page, page }) => { return sbApi .get(`spaces/${spaceId}/datasources/`) .then((res) => { if (res.total) { Logger.log(`Amount of datasources: ${res.total}`); } return res; }) .catch((err) => { if (err.response.status === 404) { Logger.error(`There is no datasources in your Storyblok ${spaceId} space.`); return true; } else { Logger.error(err); return false; } }); }, params: { spaceId, }, itemsKey: "datasources", }); }; export const getDatasource = (args, config) => { const { datasourceName } = args; Logger.log(`Trying to get '${datasourceName}' datasource.`); return getAllDatasources(config) .then((res) => { if (res) { return res.filter((datasource) => datasource.name === datasourceName); } else { return []; } }) .then((res) => { if (Array.isArray(res) && res.length === 0) { Logger.warning(`There is no datasource named '${datasourceName}'`); return false; } return res; }) .catch((err) => Logger.error(err)); }; // POST export const createDatasource = (args, config) => { const { datasource } = args; const { sbApi, spaceId } = config; const finalDatasource = { name: datasource.name, slug: datasource.slug, dimensions: [...datasource.dimensions], dimensions_attributes: [...datasource.dimensions], }; return sbApi .post(`spaces/${spaceId}/datasources/`, { datasource: finalDatasource, }) .then(({ data }) => { Logger.success(`Datasource '${data.datasource.name}' with id '${data.datasource.id}' created.`); return { data, datasource_entries: datasource.datasource_entries, }; }) .catch((err) => Logger.error(`Unable to create datasource '${datasource.name}' with slug '${datasource.slug}'. ${formatDatasourceApiError(err)}`)); }; export const updateDatasource = (args, config) => { const { datasource, datasourceToBeUpdated } = args; const { sbApi, spaceId } = config; const dimensionsToCreate = datasource.dimensions.filter((dimension) => { const isDimensionInRemoteDatasource = datasourceToBeUpdated.dimensions.find((d) => dimension.name === d.name); return !isDimensionInRemoteDatasource; }); return sbApi .put(`spaces/${spaceId}/datasources/${datasourceToBeUpdated.id}`, { datasource: { id: datasourceToBeUpdated.id, name: datasource.name, slug: datasource.slug, dimensions: [ ...datasourceToBeUpdated.dimensions, ...dimensionsToCreate, ], dimensions_attributes: [ ...datasourceToBeUpdated.dimensions, ...dimensionsToCreate, ], }, }) .then(({ data }) => { Logger.success(`Datasource '${data.datasource.name}' with id '${data.datasource.id}' created.`); return { data, datasource_entries: datasource.datasource_entries, }; }) .catch((err) => Logger.error(`Unable to update datasource '${datasource.name}' with id '${datasourceToBeUpdated.id}'. ${formatDatasourceApiError(err)}`)); }; // File-based sync wrapper lives in `datasources.sync.ts` to keep this module CJS-safe. export const syncDatasourcesData = async ({ datasources, dryRun }, config) => { const result = { created: [], updated: [], skipped: [], errors: [], }; if (dryRun) { Logger.warning("[dry-run] Datasource sync will only read remote data and report planned changes."); } const remoteDatasourcesRaw = await getAllDatasources(config); const remoteDatasources = Array.isArray(remoteDatasourcesRaw) ? remoteDatasourcesRaw : []; for (const datasource of datasources) { const name = String(datasource?.name ?? "unknown"); if (!datasource || typeof datasource !== "object" || !datasource.name) { result.skipped.push(name); continue; } try { const datasourceToBeUpdated = remoteDatasources.find((remoteDatasource) => datasource.name === remoteDatasource.name); if (dryRun) { if (datasourceToBeUpdated) { result.updated.push(name); Logger.warning(`[dry-run] Would update datasource '${name}'.`); const remoteDatasourceEntries = await getDatasourceEntries({ datasourceName: name, }, config); await createDatasourceEntries({ data: { datasource: datasourceToBeUpdated }, datasource_entries: datasource.datasource_entries ?? [], remoteDatasourceEntries, dryRun, }, config); } else { const entriesCount = Array.isArray(datasource.datasource_entries) ? datasource.datasource_entries.length : 0; result.created.push(name); Logger.warning(`[dry-run] Would create datasource '${name}'.`); if (entriesCount > 0) { Logger.warning(`[dry-run] Would create ${entriesCount} datasource entries for '${name}' after datasource creation.`); } } continue; } const opResult = datasourceToBeUpdated ? await updateDatasource({ datasource, datasourceToBeUpdated }, config) : await createDatasource({ datasource }, config); if (datasourceToBeUpdated) result.updated.push(name); else result.created.push(name); if (opResult?.data?.datasource && opResult?.datasource_entries) { const remoteDatasourceEntries = await getDatasourceEntries({ datasourceName: opResult.data.datasource.name, }, config); await createDatasourceEntries({ data: opResult.data, datasource_entries: opResult.datasource_entries, remoteDatasourceEntries, }, config); } } catch (e) { result.errors.push({ name, message: String(e) }); } } return result; };