storyblok 4.16.4 → 4.16.6
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/dist/index.mjs +91 -46
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -10,9 +10,9 @@ import { readPackageUp } from 'read-package-up';
|
|
|
10
10
|
import { Command } from 'commander';
|
|
11
11
|
import { MultiBar, Presets } from 'cli-progress';
|
|
12
12
|
import { Spinner } from '@topcli/spinner';
|
|
13
|
-
import fs, { mkdir, writeFile, readFile as readFile$1, appendFile,
|
|
13
|
+
import fs, { mkdir, writeFile, access, constants, readFile as readFile$1, appendFile, readdir, unlink } from 'node:fs/promises';
|
|
14
14
|
import filenamify from 'filenamify';
|
|
15
|
-
import { ManagementApiClient } from '@storyblok/management-api-client';
|
|
15
|
+
import { ManagementApiClient, normalizeAssetUrl } from '@storyblok/management-api-client';
|
|
16
16
|
import { RateLimit, Sema } from 'async-sema';
|
|
17
17
|
import { select, password, input, confirm } from '@inquirer/prompts';
|
|
18
18
|
import { exec, spawn } from 'node:child_process';
|
|
@@ -664,6 +664,7 @@ const API_ACTIONS = {
|
|
|
664
664
|
update_component_internal_tag: "Failed to update component internal tag",
|
|
665
665
|
update_component_group: "Failed to update component group",
|
|
666
666
|
update_component_preset: "Failed to update component preset",
|
|
667
|
+
delete_component_preset: "Failed to delete component preset",
|
|
667
668
|
pull_stories: "Failed to pull stories",
|
|
668
669
|
pull_story: "Failed to pull story",
|
|
669
670
|
create_story: "Failed to create story",
|
|
@@ -1357,6 +1358,15 @@ async function fileExists(path) {
|
|
|
1357
1358
|
return false;
|
|
1358
1359
|
}
|
|
1359
1360
|
}
|
|
1361
|
+
function consolidatedFilename(defaultFilename, suffix) {
|
|
1362
|
+
return suffix ? `${defaultFilename}.${suffix}.json` : `${defaultFilename}.json`;
|
|
1363
|
+
}
|
|
1364
|
+
async function shouldUseSeparateFiles(resolvedPath, defaultFilename, separateFiles, suffix) {
|
|
1365
|
+
if (separateFiles !== void 0) {
|
|
1366
|
+
return separateFiles;
|
|
1367
|
+
}
|
|
1368
|
+
return !await fileExists(join(resolvedPath, consolidatedFilename(defaultFilename, suffix)));
|
|
1369
|
+
}
|
|
1360
1370
|
|
|
1361
1371
|
const REPORT_STATUS = {
|
|
1362
1372
|
unfinished: "UNFINISHED",
|
|
@@ -2502,6 +2512,20 @@ const upsertComponentPreset = async (space, preset, existingId) => {
|
|
|
2502
2512
|
return await pushComponentPreset(space, preset);
|
|
2503
2513
|
}
|
|
2504
2514
|
};
|
|
2515
|
+
const deleteComponentPreset = async (space, presetId) => {
|
|
2516
|
+
try {
|
|
2517
|
+
const client = getMapiClient();
|
|
2518
|
+
await client.presets.delete({
|
|
2519
|
+
path: {
|
|
2520
|
+
space_id: Number(space),
|
|
2521
|
+
preset_id: presetId
|
|
2522
|
+
},
|
|
2523
|
+
throwOnError: true
|
|
2524
|
+
});
|
|
2525
|
+
} catch (error) {
|
|
2526
|
+
handleAPIError("delete_component_preset", error, `Failed to delete component preset ${presetId}`);
|
|
2527
|
+
}
|
|
2528
|
+
};
|
|
2505
2529
|
const pushComponentInternalTag = async (space, componentInternalTag) => {
|
|
2506
2530
|
try {
|
|
2507
2531
|
const client = getMapiClient();
|
|
@@ -2541,7 +2565,7 @@ const upsertComponentInternalTag = async (space, tag, existingId) => {
|
|
|
2541
2565
|
}
|
|
2542
2566
|
};
|
|
2543
2567
|
const readComponentsFiles = async (options) => {
|
|
2544
|
-
const { from, path, separateFiles
|
|
2568
|
+
const { from, path, separateFiles, suffix } = options;
|
|
2545
2569
|
const resolvedPath = resolvePath(path, `components/${from}`);
|
|
2546
2570
|
try {
|
|
2547
2571
|
await readdir(resolvedPath);
|
|
@@ -2560,7 +2584,7 @@ const readComponentsFiles = async (options) => {
|
|
|
2560
2584
|
message
|
|
2561
2585
|
);
|
|
2562
2586
|
}
|
|
2563
|
-
if (separateFiles) {
|
|
2587
|
+
if (await shouldUseSeparateFiles(resolvedPath, DEFAULT_COMPONENTS_FILENAME, separateFiles, suffix)) {
|
|
2564
2588
|
return await readSeparateFiles$1(resolvedPath, suffix);
|
|
2565
2589
|
}
|
|
2566
2590
|
return await readConsolidatedFiles$1(resolvedPath, suffix);
|
|
@@ -2646,7 +2670,9 @@ async function readConsolidatedFiles$1(resolvedPath, suffix) {
|
|
|
2646
2670
|
|
|
2647
2671
|
const pullCmd$4 = componentsCommand.command("pull [componentName]").option("-f, --filename <filename>", "custom name to be used in file(s) name instead of space id").option("--sf, --separate-files", "Argument to create a single file for each component").option("--su, --suffix <suffix>", "suffix to add to the file name (e.g. components.<suffix>.json)").option("-s, --space <space>", "space ID").option("-p, --path <path>", "path for file storage").description(`Download your space's components schema as json. Optionally specify a component name to pull a single component.`);
|
|
2648
2672
|
pullCmd$4.action(async (componentName, options, command) => {
|
|
2649
|
-
|
|
2673
|
+
const ui = getUI();
|
|
2674
|
+
const logger = getLogger();
|
|
2675
|
+
ui.title(`${commands.COMPONENTS}`, colorPalette.COMPONENTS, componentName ? `Pulling component ${componentName}...` : "Pulling components...");
|
|
2650
2676
|
const { space, path, verbose } = command.optsWithGlobals();
|
|
2651
2677
|
const {
|
|
2652
2678
|
separateFiles = false,
|
|
@@ -2663,41 +2689,30 @@ pullCmd$4.action(async (componentName, options, command) => {
|
|
|
2663
2689
|
handleError(new CommandError(`Please provide the space as argument --space YOUR_SPACE_ID.`), verbose);
|
|
2664
2690
|
return;
|
|
2665
2691
|
}
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
});
|
|
2669
|
-
const
|
|
2670
|
-
|
|
2671
|
-
});
|
|
2672
|
-
const spinnerInternalTags = new Spinner({
|
|
2673
|
-
verbose: !isVitest
|
|
2674
|
-
});
|
|
2675
|
-
const spinnerComponents = new Spinner({
|
|
2676
|
-
verbose: !isVitest
|
|
2677
|
-
});
|
|
2692
|
+
logger.info("Pulling components started", { space, componentName });
|
|
2693
|
+
const spinnerGroups = ui.createSpinner(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components groups")}`);
|
|
2694
|
+
const spinnerPresets = ui.createSpinner(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components presets")}`);
|
|
2695
|
+
const spinnerInternalTags = ui.createSpinner(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components internal tags")}`);
|
|
2696
|
+
const spinnerComponents = ui.createSpinner(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components")}`);
|
|
2678
2697
|
try {
|
|
2679
|
-
spinnerGroups.start(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components groups")}`);
|
|
2680
2698
|
const groups = await fetchComponentGroups(space);
|
|
2681
2699
|
spinnerGroups.succeed(`${chalk.hex(colorPalette.COMPONENTS)("Groups")} - Completed in ${spinnerGroups.elapsedTime.toFixed(2)}ms`);
|
|
2682
|
-
spinnerPresets.start(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components presets")}`);
|
|
2683
2700
|
const presets = await fetchComponentPresets(space);
|
|
2684
2701
|
spinnerPresets.succeed(`${chalk.hex(colorPalette.COMPONENTS)("Presets")} - Completed in ${spinnerPresets.elapsedTime.toFixed(2)}ms`);
|
|
2685
|
-
spinnerInternalTags.start(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components internal tags")}`);
|
|
2686
2702
|
const internalTags = await fetchComponentInternalTags(space);
|
|
2687
2703
|
spinnerInternalTags.succeed(`${chalk.hex(colorPalette.COMPONENTS)("Tags")} - Completed in ${spinnerInternalTags.elapsedTime.toFixed(2)}ms`);
|
|
2688
2704
|
let components;
|
|
2689
|
-
spinnerComponents.start(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components")}`);
|
|
2690
2705
|
if (componentName) {
|
|
2691
2706
|
const component = await fetchComponent(space, componentName);
|
|
2692
2707
|
if (!component) {
|
|
2693
|
-
|
|
2708
|
+
spinnerComponents.failed(`No component found with name "${componentName}"`);
|
|
2694
2709
|
return;
|
|
2695
2710
|
}
|
|
2696
2711
|
components = [component];
|
|
2697
2712
|
} else {
|
|
2698
2713
|
components = await fetchComponents(space);
|
|
2699
2714
|
if (!components || components.length === 0) {
|
|
2700
|
-
|
|
2715
|
+
spinnerComponents.failed(`No components found in the space ${space}`);
|
|
2701
2716
|
return;
|
|
2702
2717
|
}
|
|
2703
2718
|
}
|
|
@@ -2707,33 +2722,35 @@ pullCmd$4.action(async (componentName, options, command) => {
|
|
|
2707
2722
|
{ components, groups: groups || [], presets: presets || [], internalTags: internalTags || [], datasources: [] },
|
|
2708
2723
|
{ ...options, path, separateFiles: separateFiles || !!componentName }
|
|
2709
2724
|
);
|
|
2710
|
-
|
|
2725
|
+
ui.br();
|
|
2711
2726
|
if (separateFiles) {
|
|
2712
2727
|
if (filename && filename !== DEFAULT_COMPONENTS_FILENAME) {
|
|
2713
|
-
|
|
2728
|
+
ui.warn(`The --filename option is ignored when using --separate-files`);
|
|
2714
2729
|
}
|
|
2715
2730
|
const filePath = `${componentsOutputDir}/`;
|
|
2716
2731
|
const displayPath = path && isAbsolute(path) ? filePath : `${relative(process.cwd(), componentsOutputDir)}/`;
|
|
2717
|
-
|
|
2732
|
+
ui.ok(`Components downloaded successfully to ${chalk.hex(colorPalette.PRIMARY)(displayPath)}`);
|
|
2718
2733
|
} else if (componentName) {
|
|
2719
2734
|
const fileName = suffix ? `${actualFilename}.${suffix}.json` : `${componentName}.json`;
|
|
2720
2735
|
const filePath = join(componentsOutputDir, fileName);
|
|
2721
2736
|
const displayPath = path && isAbsolute(path) ? filePath : relative(process.cwd(), filePath);
|
|
2722
|
-
|
|
2737
|
+
ui.ok(`Component ${chalk.hex(colorPalette.PRIMARY)(componentName)} downloaded successfully in ${chalk.hex(colorPalette.PRIMARY)(displayPath)}`);
|
|
2723
2738
|
} else {
|
|
2724
2739
|
const fileName = suffix ? `${actualFilename}.${suffix}.json` : `${actualFilename}.json`;
|
|
2725
2740
|
const filePath = join(componentsOutputDir, fileName);
|
|
2726
2741
|
const displayPath = path && isAbsolute(path) ? filePath : relative(process.cwd(), filePath);
|
|
2727
|
-
|
|
2742
|
+
ui.ok(`Components downloaded successfully to ${chalk.hex(colorPalette.PRIMARY)(displayPath)}`);
|
|
2728
2743
|
}
|
|
2729
|
-
|
|
2744
|
+
ui.br();
|
|
2730
2745
|
} catch (error) {
|
|
2731
2746
|
spinnerGroups.failed(`Pulling ${chalk.hex(colorPalette.COMPONENTS)("Groups")} - Failed`);
|
|
2732
2747
|
spinnerPresets.failed(`Pulling ${chalk.hex(colorPalette.COMPONENTS)("Presets")} - Failed`);
|
|
2733
2748
|
spinnerInternalTags.failed(`Pulling ${chalk.hex(colorPalette.COMPONENTS)("Tags")} - Failed`);
|
|
2734
2749
|
spinnerComponents.failed(`Pulling ${chalk.hex(colorPalette.COMPONENTS)("Components")} - Failed`);
|
|
2735
|
-
|
|
2750
|
+
ui.br();
|
|
2736
2751
|
handleError(error, verbose);
|
|
2752
|
+
} finally {
|
|
2753
|
+
logger.info("Pulling components finished", { space, componentName });
|
|
2737
2754
|
}
|
|
2738
2755
|
});
|
|
2739
2756
|
|
|
@@ -3682,7 +3699,9 @@ async function pushWithDependencyGraph(space, spaceState, maxConcurrency = getAc
|
|
|
3682
3699
|
|
|
3683
3700
|
const pushCmd$3 = componentsCommand.command("push [componentName]").description(`Push your space's components schema as json`).option("-f, --from <from>", "source space id").option("--fi, --filter <filter>", "glob filter to apply to the components before pushing").option("--sf, --separate-files", "Read from separate files instead of consolidated files", false).option("--su, --suffix <suffix>", "Suffix to add to the component name").option("-s, --space <space>", "space ID").option("-p, --path <path>", "path for file storage");
|
|
3684
3701
|
pushCmd$3.action(async (componentName, options, command) => {
|
|
3685
|
-
|
|
3702
|
+
const ui = getUI();
|
|
3703
|
+
const logger = getLogger();
|
|
3704
|
+
ui.title(`${commands.COMPONENTS}`, colorPalette.COMPONENTS, componentName ? `Pushing component ${componentName}...` : "Pushing components...");
|
|
3686
3705
|
const { space, path, verbose } = command.optsWithGlobals();
|
|
3687
3706
|
const { filter } = options;
|
|
3688
3707
|
const fromSpace = options.from || space;
|
|
@@ -3694,8 +3713,9 @@ pushCmd$3.action(async (componentName, options, command) => {
|
|
|
3694
3713
|
handleError(new CommandError(`Please provide the target space as argument --space TARGET_SPACE_ID.`), verbose);
|
|
3695
3714
|
return;
|
|
3696
3715
|
}
|
|
3697
|
-
|
|
3698
|
-
|
|
3716
|
+
logger.info("Pushing components started", { space, fromSpace, componentName });
|
|
3717
|
+
ui.info(`Attempting to push components ${chalk.bold("from")} space ${chalk.hex(colorPalette.COMPONENTS)(fromSpace)} ${chalk.bold("to")} ${chalk.hex(colorPalette.COMPONENTS)(space)}`);
|
|
3718
|
+
ui.br();
|
|
3699
3719
|
let requestCount = 0;
|
|
3700
3720
|
const client = getMapiClient();
|
|
3701
3721
|
client.interceptors.request.use((config) => {
|
|
@@ -3765,24 +3785,45 @@ pushCmd$3.action(async (componentName, options, command) => {
|
|
|
3765
3785
|
handleError(new CommandError(`No components found matching pattern "${filter}".`), verbose);
|
|
3766
3786
|
return;
|
|
3767
3787
|
}
|
|
3768
|
-
|
|
3788
|
+
ui.info(`Filter applied: ${filter}`);
|
|
3769
3789
|
}
|
|
3770
3790
|
if (!spaceState.local.components.length) {
|
|
3771
|
-
|
|
3791
|
+
ui.warn("No components found. Please make sure you have pulled the components first.");
|
|
3772
3792
|
return;
|
|
3773
3793
|
}
|
|
3774
3794
|
const results = {
|
|
3775
3795
|
successful: [],
|
|
3776
3796
|
failed: []
|
|
3777
3797
|
};
|
|
3778
|
-
|
|
3798
|
+
const localComponentById = new Map(spaceState.local.components.map((c) => [c.id, c.name]));
|
|
3799
|
+
const localPresetKeys = /* @__PURE__ */ new Set();
|
|
3800
|
+
for (const preset of spaceState.local.presets) {
|
|
3801
|
+
const componentName2 = localComponentById.get(preset.component_id);
|
|
3802
|
+
if (componentName2) {
|
|
3803
|
+
localPresetKeys.add(`${componentName2}:${preset.name}`);
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
ui.info("Using graph-based dependency resolution");
|
|
3779
3807
|
const graphResults = await pushWithDependencyGraph(space, spaceState);
|
|
3780
3808
|
results.successful.push(...graphResults.successful);
|
|
3781
3809
|
results.failed.push(...graphResults.failed);
|
|
3810
|
+
const successfulNames = new Set(results.successful);
|
|
3811
|
+
for (const [compositeKey, targetPreset] of spaceState.target.presets) {
|
|
3812
|
+
const separatorIndex = compositeKey.indexOf(":");
|
|
3813
|
+
const componentName2 = compositeKey.substring(0, separatorIndex);
|
|
3814
|
+
if (successfulNames.has(componentName2) && !localPresetKeys.has(compositeKey)) {
|
|
3815
|
+
try {
|
|
3816
|
+
await deleteComponentPreset(space, targetPreset.id);
|
|
3817
|
+
ui.info(`Deleted stale preset: ${chalk.hex(colorPalette.PRESETS)(compositeKey)}`);
|
|
3818
|
+
} catch (error) {
|
|
3819
|
+
results.failed.push({ name: compositeKey, error });
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3782
3823
|
if (results.failed.length > 0) {
|
|
3783
3824
|
if (!verbose) {
|
|
3784
|
-
|
|
3785
|
-
|
|
3825
|
+
ui.br();
|
|
3826
|
+
ui.info("For more information about the error, run the command with the `--verbose` flag");
|
|
3786
3827
|
} else {
|
|
3787
3828
|
results.failed.forEach((failed) => {
|
|
3788
3829
|
handleError(failed.error, verbose);
|
|
@@ -3806,12 +3847,14 @@ pushCmd$3.action(async (componentName, options, command) => {
|
|
|
3806
3847
|
}
|
|
3807
3848
|
});
|
|
3808
3849
|
if (referencedDatasources.size > 0) {
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3850
|
+
ui.br();
|
|
3851
|
+
ui.info(`Components reference datasources: ${chalk.yellow(Array.from(referencedDatasources).join(", "))}`);
|
|
3852
|
+
ui.info(`To manage datasources, use: ${chalk.cyan("storyblok datasources push")}`);
|
|
3812
3853
|
}
|
|
3813
3854
|
} catch (error) {
|
|
3814
3855
|
handleError(error, verbose);
|
|
3856
|
+
} finally {
|
|
3857
|
+
logger.info("Pushing components finished", { space, fromSpace, componentName });
|
|
3815
3858
|
}
|
|
3816
3859
|
});
|
|
3817
3860
|
|
|
@@ -5947,7 +5990,7 @@ const deleteDatasourceEntry = async (spaceId, entryId) => {
|
|
|
5947
5990
|
}
|
|
5948
5991
|
};
|
|
5949
5992
|
const readDatasourcesFiles = async (options) => {
|
|
5950
|
-
const { from, path, separateFiles
|
|
5993
|
+
const { from, path, separateFiles, suffix } = options;
|
|
5951
5994
|
const resolvedPath = resolvePath(path, `datasources/${from}`);
|
|
5952
5995
|
try {
|
|
5953
5996
|
await readdir(resolvedPath);
|
|
@@ -5966,7 +6009,7 @@ const readDatasourcesFiles = async (options) => {
|
|
|
5966
6009
|
message
|
|
5967
6010
|
);
|
|
5968
6011
|
}
|
|
5969
|
-
if (separateFiles) {
|
|
6012
|
+
if (await shouldUseSeparateFiles(resolvedPath, DEFAULT_DATASOURCES_FILENAME, separateFiles, suffix)) {
|
|
5970
6013
|
return await readSeparateFiles(resolvedPath, suffix);
|
|
5971
6014
|
}
|
|
5972
6015
|
return await readConsolidatedFiles(resolvedPath, suffix);
|
|
@@ -6030,7 +6073,6 @@ generateCmd.action(async (options, command) => {
|
|
|
6030
6073
|
const componentsData = await readComponentsFiles({
|
|
6031
6074
|
from: space,
|
|
6032
6075
|
path,
|
|
6033
|
-
separateFiles,
|
|
6034
6076
|
suffix,
|
|
6035
6077
|
verbose
|
|
6036
6078
|
});
|
|
@@ -6039,7 +6081,6 @@ generateCmd.action(async (options, command) => {
|
|
|
6039
6081
|
dataSourceData = await readDatasourcesFiles({
|
|
6040
6082
|
from: space,
|
|
6041
6083
|
path,
|
|
6042
|
-
separateFiles,
|
|
6043
6084
|
suffix,
|
|
6044
6085
|
verbose
|
|
6045
6086
|
});
|
|
@@ -8074,9 +8115,13 @@ const bloksFieldRefMapper = (data, { schemas, maps, fieldRefMappers: fieldRefMap
|
|
|
8074
8115
|
};
|
|
8075
8116
|
const assetFieldRefMapper = (data, { maps }) => {
|
|
8076
8117
|
const mappedAsset = typeof data.id === "number" ? maps.assets?.get(data.id) : void 0;
|
|
8118
|
+
if (!mappedAsset) {
|
|
8119
|
+
return data;
|
|
8120
|
+
}
|
|
8077
8121
|
return {
|
|
8078
8122
|
...data,
|
|
8079
|
-
...mappedAsset
|
|
8123
|
+
...mappedAsset.new,
|
|
8124
|
+
filename: normalizeAssetUrl(mappedAsset.new.filename)
|
|
8080
8125
|
};
|
|
8081
8126
|
};
|
|
8082
8127
|
const multiassetFieldRefMapper = (data, options) => {
|