storyblok 4.0.0-beta.3 → 4.0.0-beta.5
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 +386 -202
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/index.mjs
CHANGED
|
@@ -9,6 +9,8 @@ import { Spinner } from '@topcli/spinner';
|
|
|
9
9
|
import { select, password, input } from '@inquirer/prompts';
|
|
10
10
|
import { mkdir, writeFile, readFile as readFile$1, access, readdir } from 'node:fs/promises';
|
|
11
11
|
import { join, parse, resolve } from 'node:path';
|
|
12
|
+
import { exec } from 'node:child_process';
|
|
13
|
+
import { promisify } from 'node:util';
|
|
12
14
|
import { hash } from 'ohash';
|
|
13
15
|
import { compile } from 'json-schema-to-typescript';
|
|
14
16
|
import { readFileSync } from 'node:fs';
|
|
@@ -16,6 +18,7 @@ import { readFileSync } from 'node:fs';
|
|
|
16
18
|
const commands = {
|
|
17
19
|
LOGIN: "login",
|
|
18
20
|
LOGOUT: "logout",
|
|
21
|
+
SIGNUP: "signup",
|
|
19
22
|
USER: "user",
|
|
20
23
|
COMPONENTS: "Components",
|
|
21
24
|
LANGUAGES: "languages",
|
|
@@ -26,6 +29,7 @@ const colorPalette = {
|
|
|
26
29
|
PRIMARY: "#8d60ff",
|
|
27
30
|
LOGIN: "#dad4ff",
|
|
28
31
|
LOGOUT: "#6d6d6d",
|
|
32
|
+
SIGNUP: "#b6ff6d",
|
|
29
33
|
USER: "#71d300",
|
|
30
34
|
COMPONENTS: "#a185ff",
|
|
31
35
|
LANGUAGES: "#f5c003",
|
|
@@ -107,7 +111,11 @@ async function customFetch(url, options = {}) {
|
|
|
107
111
|
data
|
|
108
112
|
});
|
|
109
113
|
}
|
|
110
|
-
return
|
|
114
|
+
return {
|
|
115
|
+
...data,
|
|
116
|
+
perPage: Number(response.headers.get("Per-Page")),
|
|
117
|
+
total: Number(response.headers.get("Total"))
|
|
118
|
+
};
|
|
111
119
|
} catch (error) {
|
|
112
120
|
if (error instanceof FetchError) {
|
|
113
121
|
throw error;
|
|
@@ -315,6 +323,22 @@ class FileSystemError extends Error {
|
|
|
315
323
|
}
|
|
316
324
|
}
|
|
317
325
|
|
|
326
|
+
function handleVerboseError(error) {
|
|
327
|
+
if (error instanceof CommandError || error instanceof APIError || error instanceof FileSystemError) {
|
|
328
|
+
const errorDetails = "getInfo" in error ? error.getInfo() : {};
|
|
329
|
+
if (error instanceof CommandError) {
|
|
330
|
+
konsola.error(`Command Error: ${error.getInfo().message}`, errorDetails);
|
|
331
|
+
} else if (error instanceof APIError) {
|
|
332
|
+
konsola.error(`API Error: ${error.getInfo().cause}`, errorDetails);
|
|
333
|
+
} else if (error instanceof FileSystemError) {
|
|
334
|
+
konsola.error(`File System Error: ${error.getInfo().cause}`, errorDetails);
|
|
335
|
+
} else {
|
|
336
|
+
konsola.error(`Unexpected Error: ${error}`, errorDetails);
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
konsola.error(`Unexpected Error`, error);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
318
342
|
function handleError(error, verbose = false) {
|
|
319
343
|
if (error instanceof APIError || error instanceof FileSystemError) {
|
|
320
344
|
const messageStack = error.messageStack;
|
|
@@ -329,17 +353,8 @@ function handleError(error, verbose = false) {
|
|
|
329
353
|
header: true
|
|
330
354
|
});
|
|
331
355
|
}
|
|
332
|
-
if (verbose
|
|
333
|
-
|
|
334
|
-
if (error instanceof CommandError) {
|
|
335
|
-
konsola.error(`Command Error: ${error.getInfo().message}`, errorDetails);
|
|
336
|
-
} else if (error instanceof APIError) {
|
|
337
|
-
konsola.error(`API Error: ${error.getInfo().cause}`, errorDetails);
|
|
338
|
-
} else if (error instanceof FileSystemError) {
|
|
339
|
-
konsola.error(`File System Error: ${error.getInfo().cause}`, errorDetails);
|
|
340
|
-
} else {
|
|
341
|
-
konsola.error(`Unexpected Error: ${error}`, errorDetails);
|
|
342
|
-
}
|
|
356
|
+
if (verbose) {
|
|
357
|
+
handleVerboseError(error);
|
|
343
358
|
} else {
|
|
344
359
|
konsola.br();
|
|
345
360
|
konsola.info("For more information about the error, run the command with the `--verbose` flag");
|
|
@@ -349,6 +364,17 @@ function handleError(error, verbose = false) {
|
|
|
349
364
|
}
|
|
350
365
|
}
|
|
351
366
|
|
|
367
|
+
function requireAuthentication(state, verbose = false) {
|
|
368
|
+
if (!state.isLoggedIn || !state.password || !state.region) {
|
|
369
|
+
handleError(
|
|
370
|
+
new CommandError(`You are currently not logged in. Please run ${chalk.hex(colorPalette.PRIMARY)("storyblok login")} to authenticate, or ${chalk.hex(colorPalette.PRIMARY)("storyblok signup")} to sign up.`),
|
|
371
|
+
verbose
|
|
372
|
+
);
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
|
|
352
378
|
const toPascalCase = (str) => {
|
|
353
379
|
return str.replace(/(?:^|_)(\w)/g, (_, char) => char.toUpperCase());
|
|
354
380
|
};
|
|
@@ -688,7 +714,7 @@ function session() {
|
|
|
688
714
|
return sessionInstance;
|
|
689
715
|
}
|
|
690
716
|
|
|
691
|
-
const program$
|
|
717
|
+
const program$e = getProgram();
|
|
692
718
|
const allRegionsText = Object.values(regions).join(",");
|
|
693
719
|
const loginStrategy = {
|
|
694
720
|
message: "How would you like to login?",
|
|
@@ -705,12 +731,12 @@ const loginStrategy = {
|
|
|
705
731
|
}
|
|
706
732
|
]
|
|
707
733
|
};
|
|
708
|
-
program$
|
|
734
|
+
program$e.command(commands.LOGIN).description("Login to the Storyblok CLI").option("-t, --token <token>", "Token to login directly without questions, like for CI environments").option(
|
|
709
735
|
"-r, --region <region>",
|
|
710
736
|
`The region you would like to work in. Please keep in mind that the region must match the region of your space. This region flag will be used for the other cli's commands. You can use the values: ${allRegionsText}.`
|
|
711
737
|
).action(async (options) => {
|
|
712
738
|
konsola.title(` ${commands.LOGIN} `, colorPalette.LOGIN);
|
|
713
|
-
const verbose = program$
|
|
739
|
+
const verbose = program$e.opts().verbose;
|
|
714
740
|
const { token, region } = options;
|
|
715
741
|
const { state, updateSession, persistCredentials, initializeSession } = session();
|
|
716
742
|
await initializeSession();
|
|
@@ -818,10 +844,10 @@ program$d.command(commands.LOGIN).description("Login to the Storyblok CLI").opti
|
|
|
818
844
|
konsola.br();
|
|
819
845
|
});
|
|
820
846
|
|
|
821
|
-
const program$
|
|
822
|
-
program$
|
|
847
|
+
const program$d = getProgram();
|
|
848
|
+
program$d.command(commands.LOGOUT).description("Logout from the Storyblok CLI").action(async () => {
|
|
823
849
|
konsola.title(` ${commands.LOGOUT} `, colorPalette.LOGOUT);
|
|
824
|
-
const verbose = program$
|
|
850
|
+
const verbose = program$d.opts().verbose;
|
|
825
851
|
try {
|
|
826
852
|
const { state, initializeSession } = session();
|
|
827
853
|
await initializeSession();
|
|
@@ -839,6 +865,61 @@ program$c.command(commands.LOGOUT).description("Logout from the Storyblok CLI").
|
|
|
839
865
|
konsola.br();
|
|
840
866
|
});
|
|
841
867
|
|
|
868
|
+
const execAsync = promisify(exec);
|
|
869
|
+
function buildSignupUrl() {
|
|
870
|
+
const baseUrl = "https://app.storyblok.com";
|
|
871
|
+
const utmParams = new URLSearchParams({
|
|
872
|
+
utm_source: "storyblok-cli",
|
|
873
|
+
utm_medium: "cli",
|
|
874
|
+
utm_campaign: "signup"
|
|
875
|
+
});
|
|
876
|
+
return `${baseUrl}/#/signup?${utmParams.toString()}`;
|
|
877
|
+
}
|
|
878
|
+
async function openSignupInBrowser(url) {
|
|
879
|
+
let command;
|
|
880
|
+
switch (process.platform) {
|
|
881
|
+
case "darwin":
|
|
882
|
+
command = `open "${url}"`;
|
|
883
|
+
break;
|
|
884
|
+
case "win32":
|
|
885
|
+
command = `start "" "${url}"`;
|
|
886
|
+
break;
|
|
887
|
+
default:
|
|
888
|
+
command = `xdg-open "${url}"`;
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
try {
|
|
892
|
+
await execAsync(command);
|
|
893
|
+
} catch (error) {
|
|
894
|
+
throw new Error(`Failed to open browser: ${error}`);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
const program$c = getProgram();
|
|
899
|
+
program$c.command(commands.SIGNUP).description("Sign up for Storyblok").action(async () => {
|
|
900
|
+
konsola.title(` ${commands.SIGNUP} `, colorPalette.SIGNUP);
|
|
901
|
+
const verbose = program$c.opts().verbose;
|
|
902
|
+
const { state, initializeSession } = session();
|
|
903
|
+
await initializeSession();
|
|
904
|
+
if (state.isLoggedIn && !state.envLogin) {
|
|
905
|
+
konsola.ok(`You are already logged in. If you want to signup with a different account, please logout first.`);
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
try {
|
|
909
|
+
const signupUrl = buildSignupUrl();
|
|
910
|
+
konsola.info(`Opening Storyblok signup page...`);
|
|
911
|
+
konsola.info(`URL: ${chalk.dim(signupUrl)}`);
|
|
912
|
+
await openSignupInBrowser(signupUrl);
|
|
913
|
+
konsola.ok(`Browser opened! Please complete the signup process.`);
|
|
914
|
+
konsola.br();
|
|
915
|
+
konsola.info(`Once you've completed signup, run ${chalk.hex(colorPalette.PRIMARY)("storyblok login")} to authenticate with the CLI.`);
|
|
916
|
+
} catch (error) {
|
|
917
|
+
konsola.br();
|
|
918
|
+
handleError(error, verbose);
|
|
919
|
+
}
|
|
920
|
+
konsola.br();
|
|
921
|
+
});
|
|
922
|
+
|
|
842
923
|
const getUser = async (token, region) => {
|
|
843
924
|
try {
|
|
844
925
|
const url = getStoryblokUrl(region);
|
|
@@ -868,8 +949,7 @@ program$b.command(commands.USER).description("Get the current user").action(asyn
|
|
|
868
949
|
konsola.title(` ${commands.USER} `, colorPalette.USER);
|
|
869
950
|
const { state, initializeSession } = session();
|
|
870
951
|
await initializeSession();
|
|
871
|
-
if (!state
|
|
872
|
-
handleError(new CommandError(`You are currently not logged in. Please login first to get your user info.`));
|
|
952
|
+
if (!requireAuthentication(state)) {
|
|
873
953
|
return;
|
|
874
954
|
}
|
|
875
955
|
const spinner = new Spinner({
|
|
@@ -893,67 +973,174 @@ program$b.command(commands.USER).description("Get the current user").action(asyn
|
|
|
893
973
|
const program$a = getProgram();
|
|
894
974
|
const componentsCommand = program$a.command("components").alias("comp").description(`Manage your space's block schema`).option("-s, --space <space>", "space ID").option("-p, --path <path>", "path to save the file. Default is .storyblok/components");
|
|
895
975
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
976
|
+
let instance = null;
|
|
977
|
+
const createMapiClient = (options) => {
|
|
978
|
+
const baseHeaders = {
|
|
979
|
+
"Content-Type": "application/json",
|
|
980
|
+
"Authorization": options.token
|
|
981
|
+
};
|
|
982
|
+
const state = {
|
|
983
|
+
uuid: `mapi-client-${Math.random().toString(36).substring(2, 15)}`,
|
|
984
|
+
baseHeaders,
|
|
985
|
+
url: options.url || getStoryblokUrl(options.region),
|
|
986
|
+
maxRetries: options.maxRetries ?? 6,
|
|
987
|
+
baseDelay: options.baseDelay ?? 500,
|
|
988
|
+
freeze: false
|
|
989
|
+
};
|
|
990
|
+
const request = async (path, fetchOptions, attempt = 0, isRateLimitOwner = false) => {
|
|
991
|
+
if (state.freeze && !isRateLimitOwner) {
|
|
992
|
+
if (options?.verbose) {
|
|
993
|
+
console.log(`\u23F3 ${path} - Waiting for rate limit to be resolved`);
|
|
994
|
+
}
|
|
995
|
+
await new Promise((resolve) => {
|
|
996
|
+
const checkFreeze = setInterval(() => {
|
|
997
|
+
if (!state.freeze) {
|
|
998
|
+
clearInterval(checkFreeze);
|
|
999
|
+
resolve();
|
|
1000
|
+
}
|
|
1001
|
+
}, 50);
|
|
1002
|
+
});
|
|
1003
|
+
await delay(100 + Math.random() * 400);
|
|
1004
|
+
return request(path, fetchOptions, attempt);
|
|
1005
|
+
}
|
|
1006
|
+
try {
|
|
1007
|
+
if (options?.verbose) {
|
|
1008
|
+
console.log(`${state.url}/${path} - Attempt ${attempt}`);
|
|
902
1009
|
}
|
|
903
|
-
|
|
904
|
-
|
|
1010
|
+
const res = await fetch(`${state.url}/${path}`, {
|
|
1011
|
+
headers: {
|
|
1012
|
+
...state.baseHeaders,
|
|
1013
|
+
...fetchOptions?.headers
|
|
1014
|
+
},
|
|
1015
|
+
...fetchOptions
|
|
1016
|
+
});
|
|
1017
|
+
let data;
|
|
1018
|
+
try {
|
|
1019
|
+
data = await res.json();
|
|
1020
|
+
} catch {
|
|
1021
|
+
throw new FetchError("Non-JSON response", {
|
|
1022
|
+
status: res.status,
|
|
1023
|
+
statusText: res.statusText,
|
|
1024
|
+
data: null
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
if (res.ok) {
|
|
1028
|
+
if (options?.verbose) {
|
|
1029
|
+
console.log(`\u2705 ${path}`);
|
|
1030
|
+
}
|
|
1031
|
+
return {
|
|
1032
|
+
data,
|
|
1033
|
+
attempt
|
|
1034
|
+
};
|
|
1035
|
+
} else {
|
|
1036
|
+
throw new FetchError("Request failed", {
|
|
1037
|
+
status: res.status,
|
|
1038
|
+
statusText: res.statusText,
|
|
1039
|
+
data
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
if (error instanceof FetchError) {
|
|
1044
|
+
if (error.response.status === 429 && attempt < state.maxRetries) {
|
|
1045
|
+
if (options?.verbose) {
|
|
1046
|
+
console.log(`\u274C ${path} - Rate limit exceeded`);
|
|
1047
|
+
}
|
|
1048
|
+
let isOwner = isRateLimitOwner;
|
|
1049
|
+
if (!state.freeze) {
|
|
1050
|
+
state.freeze = true;
|
|
1051
|
+
isOwner = true;
|
|
1052
|
+
}
|
|
1053
|
+
const waitTime = state.baseDelay * 2 ** attempt + Math.random() * 100;
|
|
1054
|
+
await delay(waitTime);
|
|
1055
|
+
try {
|
|
1056
|
+
const result = await request(path, fetchOptions, attempt + 1, isOwner);
|
|
1057
|
+
return result;
|
|
1058
|
+
} finally {
|
|
1059
|
+
if (isOwner && state.freeze) {
|
|
1060
|
+
state.freeze = false;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
throw error;
|
|
1065
|
+
}
|
|
1066
|
+
if (state.freeze && isRateLimitOwner) {
|
|
1067
|
+
state.freeze = false;
|
|
1068
|
+
}
|
|
1069
|
+
throw new FetchError(error instanceof Error ? error.message : String(error), {
|
|
1070
|
+
status: 0,
|
|
1071
|
+
statusText: "Network Error",
|
|
1072
|
+
data: null
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
const get = async (path, fetchOptions) => {
|
|
1077
|
+
return request(path, fetchOptions);
|
|
1078
|
+
};
|
|
1079
|
+
const post = async (path, fetchOptions) => {
|
|
1080
|
+
return request(path, { ...fetchOptions, method: "POST" });
|
|
1081
|
+
};
|
|
1082
|
+
const put = async (path, fetchOptions) => {
|
|
1083
|
+
return request(path, { ...fetchOptions, method: "PUT" });
|
|
1084
|
+
};
|
|
1085
|
+
instance = {
|
|
1086
|
+
uuid: state.uuid,
|
|
1087
|
+
get,
|
|
1088
|
+
post,
|
|
1089
|
+
put,
|
|
1090
|
+
dispose: () => {
|
|
1091
|
+
instance = null;
|
|
1092
|
+
}
|
|
1093
|
+
};
|
|
1094
|
+
return instance;
|
|
1095
|
+
};
|
|
1096
|
+
function mapiClient(options) {
|
|
1097
|
+
if (!instance) {
|
|
1098
|
+
instance = createMapiClient(options ?? {});
|
|
1099
|
+
}
|
|
1100
|
+
return instance;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
const fetchComponents = async (space) => {
|
|
1104
|
+
try {
|
|
1105
|
+
const client = mapiClient();
|
|
1106
|
+
const { data } = await client.get(`spaces/${space}/components`, {});
|
|
1107
|
+
return data.components;
|
|
905
1108
|
} catch (error) {
|
|
906
1109
|
handleAPIError("pull_components", error);
|
|
907
1110
|
}
|
|
908
1111
|
};
|
|
909
|
-
const fetchComponent = async (space, componentName
|
|
1112
|
+
const fetchComponent = async (space, componentName) => {
|
|
910
1113
|
try {
|
|
911
|
-
const
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
Authorization: token
|
|
915
|
-
}
|
|
916
|
-
});
|
|
917
|
-
return response.components?.find((c) => c.name === componentName);
|
|
1114
|
+
const client = mapiClient();
|
|
1115
|
+
const { data } = await client.get(`spaces/${space}/components?search=${encodeURIComponent(componentName)}`, {});
|
|
1116
|
+
return data.components?.find((c) => c.name === componentName);
|
|
918
1117
|
} catch (error) {
|
|
919
1118
|
handleAPIError("pull_components", error, `Failed to fetch component ${componentName}`);
|
|
920
1119
|
}
|
|
921
1120
|
};
|
|
922
|
-
const fetchComponentGroups = async (space
|
|
1121
|
+
const fetchComponentGroups = async (space) => {
|
|
923
1122
|
try {
|
|
924
|
-
const
|
|
925
|
-
const
|
|
926
|
-
|
|
927
|
-
Authorization: token
|
|
928
|
-
}
|
|
929
|
-
});
|
|
930
|
-
return response.component_groups;
|
|
1123
|
+
const client = mapiClient();
|
|
1124
|
+
const { data } = await client.get(`spaces/${space}/component_groups`);
|
|
1125
|
+
return data.component_groups;
|
|
931
1126
|
} catch (error) {
|
|
932
1127
|
handleAPIError("pull_component_groups", error);
|
|
933
1128
|
}
|
|
934
1129
|
};
|
|
935
|
-
const fetchComponentPresets = async (space
|
|
1130
|
+
const fetchComponentPresets = async (space) => {
|
|
936
1131
|
try {
|
|
937
|
-
const
|
|
938
|
-
const
|
|
939
|
-
|
|
940
|
-
Authorization: token
|
|
941
|
-
}
|
|
942
|
-
});
|
|
943
|
-
return response.presets;
|
|
1132
|
+
const client = mapiClient();
|
|
1133
|
+
const { data } = await client.get(`spaces/${space}/presets`);
|
|
1134
|
+
return data.presets;
|
|
944
1135
|
} catch (error) {
|
|
945
1136
|
handleAPIError("pull_component_presets", error);
|
|
946
1137
|
}
|
|
947
1138
|
};
|
|
948
|
-
const fetchComponentInternalTags = async (space
|
|
1139
|
+
const fetchComponentInternalTags = async (space) => {
|
|
949
1140
|
try {
|
|
950
|
-
const
|
|
951
|
-
const
|
|
952
|
-
|
|
953
|
-
Authorization: token
|
|
954
|
-
}
|
|
955
|
-
});
|
|
956
|
-
return response.internal_tags.filter((tag) => tag.object_type === "component");
|
|
1141
|
+
const client = mapiClient();
|
|
1142
|
+
const { data } = await client.get(`spaces/${space}/internal_tags`, {});
|
|
1143
|
+
return data.internal_tags.filter((tag) => tag.object_type === "component");
|
|
957
1144
|
} catch (error) {
|
|
958
1145
|
handleAPIError("pull_component_internal_tags", error);
|
|
959
1146
|
}
|
|
@@ -998,187 +1185,157 @@ const saveComponentsToFiles = async (space, spaceData, options) => {
|
|
|
998
1185
|
}
|
|
999
1186
|
};
|
|
1000
1187
|
|
|
1001
|
-
const pushComponent = async (space, component
|
|
1188
|
+
const pushComponent = async (space, component) => {
|
|
1002
1189
|
try {
|
|
1003
|
-
const
|
|
1004
|
-
const
|
|
1005
|
-
method: "POST",
|
|
1006
|
-
headers: {
|
|
1007
|
-
Authorization: token
|
|
1008
|
-
},
|
|
1190
|
+
const client = mapiClient();
|
|
1191
|
+
const { data } = await client.post(`spaces/${space}/components`, {
|
|
1009
1192
|
body: JSON.stringify(component)
|
|
1010
1193
|
});
|
|
1011
|
-
return
|
|
1194
|
+
return data.component;
|
|
1012
1195
|
} catch (error) {
|
|
1013
1196
|
handleAPIError("push_component", error, `Failed to push component ${component.name}`);
|
|
1014
1197
|
}
|
|
1015
1198
|
};
|
|
1016
|
-
const updateComponent = async (space, componentId, component
|
|
1199
|
+
const updateComponent = async (space, componentId, component) => {
|
|
1017
1200
|
try {
|
|
1018
|
-
const
|
|
1019
|
-
const
|
|
1020
|
-
method: "PUT",
|
|
1021
|
-
headers: {
|
|
1022
|
-
Authorization: token
|
|
1023
|
-
},
|
|
1201
|
+
const client = mapiClient();
|
|
1202
|
+
const { data } = await client.put(`spaces/${space}/components/${componentId}`, {
|
|
1024
1203
|
body: JSON.stringify(component)
|
|
1025
1204
|
});
|
|
1026
|
-
return
|
|
1205
|
+
return data.component;
|
|
1027
1206
|
} catch (error) {
|
|
1028
1207
|
handleAPIError("update_component", error, `Failed to update component ${component.name}`);
|
|
1029
1208
|
}
|
|
1030
1209
|
};
|
|
1031
|
-
const upsertComponent = async (space, component
|
|
1210
|
+
const upsertComponent = async (space, component) => {
|
|
1032
1211
|
try {
|
|
1033
|
-
return await pushComponent(space, component
|
|
1212
|
+
return await pushComponent(space, component);
|
|
1034
1213
|
} catch (error) {
|
|
1035
1214
|
if (error instanceof APIError && error.code === 422) {
|
|
1036
1215
|
const responseData = error.response?.data;
|
|
1037
1216
|
if (responseData?.name?.[0] === "has already been taken") {
|
|
1038
|
-
const existingComponent = await fetchComponent(space, component.name
|
|
1217
|
+
const existingComponent = await fetchComponent(space, component.name);
|
|
1039
1218
|
if (existingComponent) {
|
|
1040
|
-
return await updateComponent(space, existingComponent.id, component
|
|
1219
|
+
return await updateComponent(space, existingComponent.id, component);
|
|
1041
1220
|
}
|
|
1042
1221
|
}
|
|
1043
1222
|
}
|
|
1044
1223
|
throw error;
|
|
1045
1224
|
}
|
|
1046
1225
|
};
|
|
1047
|
-
const pushComponentGroup = async (space, componentGroup
|
|
1226
|
+
const pushComponentGroup = async (space, componentGroup) => {
|
|
1048
1227
|
try {
|
|
1049
|
-
const
|
|
1050
|
-
const
|
|
1051
|
-
method: "POST",
|
|
1052
|
-
headers: {
|
|
1053
|
-
Authorization: token
|
|
1054
|
-
},
|
|
1228
|
+
const client = mapiClient();
|
|
1229
|
+
const { data } = await client.post(`spaces/${space}/component_groups`, {
|
|
1055
1230
|
body: JSON.stringify(componentGroup)
|
|
1056
1231
|
});
|
|
1057
|
-
return
|
|
1232
|
+
return data.component_group;
|
|
1058
1233
|
} catch (error) {
|
|
1059
1234
|
handleAPIError("push_component_group", error, `Failed to push component group ${componentGroup.name}`);
|
|
1060
1235
|
}
|
|
1061
1236
|
};
|
|
1062
|
-
const updateComponentGroup = async (space, groupId, componentGroup
|
|
1237
|
+
const updateComponentGroup = async (space, groupId, componentGroup) => {
|
|
1063
1238
|
try {
|
|
1064
|
-
const
|
|
1065
|
-
const
|
|
1066
|
-
method: "PUT",
|
|
1067
|
-
headers: {
|
|
1068
|
-
Authorization: token
|
|
1069
|
-
},
|
|
1239
|
+
const client = mapiClient();
|
|
1240
|
+
const { data } = await client.put(`spaces/${space}/component_groups/${groupId}`, {
|
|
1070
1241
|
body: JSON.stringify(componentGroup)
|
|
1071
1242
|
});
|
|
1072
|
-
return
|
|
1243
|
+
return data.component_group;
|
|
1073
1244
|
} catch (error) {
|
|
1074
1245
|
handleAPIError("update_component_group", error, `Failed to update component group ${componentGroup.name}`);
|
|
1075
1246
|
}
|
|
1076
1247
|
};
|
|
1077
|
-
const upsertComponentGroup = async (space, group
|
|
1248
|
+
const upsertComponentGroup = async (space, group) => {
|
|
1078
1249
|
try {
|
|
1079
|
-
return await pushComponentGroup(space, group
|
|
1250
|
+
return await pushComponentGroup(space, group);
|
|
1080
1251
|
} catch (error) {
|
|
1081
1252
|
if (error instanceof APIError && error.code === 422) {
|
|
1082
1253
|
const responseData = error.response?.data;
|
|
1083
1254
|
if (responseData?.name?.[0] === "has already been taken") {
|
|
1084
|
-
const existingGroups = await fetchComponentGroups(space
|
|
1255
|
+
const existingGroups = await fetchComponentGroups(space);
|
|
1085
1256
|
const existingGroup = existingGroups?.find((g) => g.name === group.name);
|
|
1086
1257
|
if (existingGroup) {
|
|
1087
|
-
return await updateComponentGroup(space, existingGroup.id, group
|
|
1258
|
+
return await updateComponentGroup(space, existingGroup.id, group);
|
|
1088
1259
|
}
|
|
1089
1260
|
}
|
|
1090
1261
|
}
|
|
1091
1262
|
throw error;
|
|
1092
1263
|
}
|
|
1093
1264
|
};
|
|
1094
|
-
const pushComponentPreset = async (space, componentPreset
|
|
1265
|
+
const pushComponentPreset = async (space, componentPreset) => {
|
|
1095
1266
|
try {
|
|
1096
|
-
const
|
|
1097
|
-
const
|
|
1098
|
-
method: "POST",
|
|
1099
|
-
headers: {
|
|
1100
|
-
Authorization: token
|
|
1101
|
-
},
|
|
1267
|
+
const client = mapiClient();
|
|
1268
|
+
const { data } = await client.post(`spaces/${space}/presets`, {
|
|
1102
1269
|
body: JSON.stringify(componentPreset)
|
|
1103
1270
|
});
|
|
1104
|
-
return
|
|
1271
|
+
return data.preset;
|
|
1105
1272
|
} catch (error) {
|
|
1106
1273
|
handleAPIError("push_component_preset", error, `Failed to push component preset ${componentPreset.preset.name}`);
|
|
1107
1274
|
}
|
|
1108
1275
|
};
|
|
1109
|
-
const updateComponentPreset = async (space, presetId, componentPreset
|
|
1276
|
+
const updateComponentPreset = async (space, presetId, componentPreset) => {
|
|
1110
1277
|
try {
|
|
1111
|
-
const
|
|
1112
|
-
const
|
|
1113
|
-
method: "PUT",
|
|
1114
|
-
headers: {
|
|
1115
|
-
Authorization: token
|
|
1116
|
-
},
|
|
1278
|
+
const client = mapiClient();
|
|
1279
|
+
const { data } = await client.put(`spaces/${space}/presets/${presetId}`, {
|
|
1117
1280
|
body: JSON.stringify(componentPreset)
|
|
1118
1281
|
});
|
|
1119
|
-
return
|
|
1282
|
+
return data.preset;
|
|
1120
1283
|
} catch (error) {
|
|
1121
1284
|
handleAPIError("update_component_preset", error, `Failed to update component preset ${componentPreset.preset.name}`);
|
|
1122
1285
|
}
|
|
1123
1286
|
};
|
|
1124
|
-
const upsertComponentPreset = async (space, preset
|
|
1287
|
+
const upsertComponentPreset = async (space, preset) => {
|
|
1125
1288
|
try {
|
|
1126
|
-
return await pushComponentPreset(space, { preset }
|
|
1289
|
+
return await pushComponentPreset(space, { preset });
|
|
1127
1290
|
} catch (error) {
|
|
1128
1291
|
if (error instanceof APIError && error.code === 422) {
|
|
1129
1292
|
const responseData = error.response?.data;
|
|
1130
1293
|
if (responseData?.name?.[0] === "has already been taken") {
|
|
1131
|
-
const existingPresets = await fetchComponentPresets(space
|
|
1294
|
+
const existingPresets = await fetchComponentPresets(space);
|
|
1132
1295
|
const existingPreset = existingPresets?.find((p) => p.name === preset.name && p.component_id === preset.component_id);
|
|
1133
1296
|
if (existingPreset) {
|
|
1134
|
-
return await updateComponentPreset(space, existingPreset.id, { preset }
|
|
1297
|
+
return await updateComponentPreset(space, existingPreset.id, { preset });
|
|
1135
1298
|
}
|
|
1136
1299
|
}
|
|
1137
1300
|
}
|
|
1138
1301
|
throw error;
|
|
1139
1302
|
}
|
|
1140
1303
|
};
|
|
1141
|
-
const pushComponentInternalTag = async (space, componentInternalTag
|
|
1304
|
+
const pushComponentInternalTag = async (space, componentInternalTag) => {
|
|
1142
1305
|
try {
|
|
1143
|
-
const
|
|
1144
|
-
const
|
|
1306
|
+
const client = mapiClient();
|
|
1307
|
+
const { data } = await client.post(`spaces/${space}/internal_tags`, {
|
|
1145
1308
|
method: "POST",
|
|
1146
|
-
headers: {
|
|
1147
|
-
Authorization: token
|
|
1148
|
-
},
|
|
1149
1309
|
body: JSON.stringify(componentInternalTag)
|
|
1150
1310
|
});
|
|
1151
|
-
return
|
|
1311
|
+
return data.internal_tag;
|
|
1152
1312
|
} catch (error) {
|
|
1153
1313
|
handleAPIError("push_component_internal_tag", error, `Failed to push component internal tag ${componentInternalTag.name}`);
|
|
1154
1314
|
}
|
|
1155
1315
|
};
|
|
1156
|
-
const updateComponentInternalTag = async (space, tagId, componentInternalTag
|
|
1316
|
+
const updateComponentInternalTag = async (space, tagId, componentInternalTag) => {
|
|
1157
1317
|
try {
|
|
1158
|
-
const
|
|
1159
|
-
const
|
|
1318
|
+
const client = mapiClient();
|
|
1319
|
+
const { data } = await client.put(`spaces/${space}/internal_tags/${tagId}`, {
|
|
1160
1320
|
method: "PUT",
|
|
1161
|
-
headers: {
|
|
1162
|
-
Authorization: token
|
|
1163
|
-
},
|
|
1164
1321
|
body: JSON.stringify(componentInternalTag)
|
|
1165
1322
|
});
|
|
1166
|
-
return
|
|
1323
|
+
return data.internal_tag;
|
|
1167
1324
|
} catch (error) {
|
|
1168
1325
|
handleAPIError("update_component_internal_tag", error, `Failed to update component internal tag ${componentInternalTag.name}`);
|
|
1169
1326
|
}
|
|
1170
1327
|
};
|
|
1171
|
-
const upsertComponentInternalTag = async (space, tag
|
|
1328
|
+
const upsertComponentInternalTag = async (space, tag) => {
|
|
1172
1329
|
try {
|
|
1173
|
-
return await pushComponentInternalTag(space, tag
|
|
1330
|
+
return await pushComponentInternalTag(space, tag);
|
|
1174
1331
|
} catch (error) {
|
|
1175
1332
|
if (error instanceof APIError && error.code === 422) {
|
|
1176
1333
|
const responseData = error.response?.data;
|
|
1177
1334
|
if (responseData?.name?.[0] === "has already been taken") {
|
|
1178
|
-
const existingTags = await fetchComponentInternalTags(space
|
|
1335
|
+
const existingTags = await fetchComponentInternalTags(space);
|
|
1179
1336
|
const existingTag = existingTags?.find((t) => t.name === tag.name);
|
|
1180
1337
|
if (existingTag) {
|
|
1181
|
-
return await updateComponentInternalTag(space, existingTag.id, tag
|
|
1338
|
+
return await updateComponentInternalTag(space, existingTag.id, tag);
|
|
1182
1339
|
}
|
|
1183
1340
|
}
|
|
1184
1341
|
}
|
|
@@ -1198,16 +1355,18 @@ async function readJsonFile(filePath) {
|
|
|
1198
1355
|
}
|
|
1199
1356
|
}
|
|
1200
1357
|
const readComponentsFiles = async (options) => {
|
|
1201
|
-
const { from, path, separateFiles = false, suffix } = options;
|
|
1358
|
+
const { from, path, separateFiles = false, suffix, space } = options;
|
|
1202
1359
|
const resolvedPath = resolvePath(path, `components/${from}`);
|
|
1203
1360
|
try {
|
|
1204
1361
|
await readdir(resolvedPath);
|
|
1205
1362
|
} catch (error) {
|
|
1206
|
-
const message = `No
|
|
1363
|
+
const message = `No local components found for space ${chalk.bold(from)}. To push components, you need to pull them first:
|
|
1207
1364
|
|
|
1208
|
-
|
|
1365
|
+
1. Pull the components from your source space:
|
|
1366
|
+
${chalk.cyan(`storyblok components pull --space ${from}`)}
|
|
1209
1367
|
|
|
1210
|
-
|
|
1368
|
+
2. Then try pushing again:
|
|
1369
|
+
${chalk.cyan(`storyblok components push --space ${space} --from ${from}`)}`;
|
|
1211
1370
|
throw new FileSystemError(
|
|
1212
1371
|
"file_not_found",
|
|
1213
1372
|
"read",
|
|
@@ -1307,8 +1466,7 @@ componentsCommand.command("pull [componentName]").option("-f, --filename <filena
|
|
|
1307
1466
|
const { separateFiles, suffix, filename = "components" } = options;
|
|
1308
1467
|
const { state, initializeSession } = session();
|
|
1309
1468
|
await initializeSession();
|
|
1310
|
-
if (!state
|
|
1311
|
-
handleError(new CommandError(`You are currently not logged in. Please login first to get your user info.`), verbose);
|
|
1469
|
+
if (!requireAuthentication(state, verbose)) {
|
|
1312
1470
|
return;
|
|
1313
1471
|
}
|
|
1314
1472
|
if (!space) {
|
|
@@ -1316,6 +1474,10 @@ componentsCommand.command("pull [componentName]").option("-f, --filename <filena
|
|
|
1316
1474
|
return;
|
|
1317
1475
|
}
|
|
1318
1476
|
const { password, region } = state;
|
|
1477
|
+
mapiClient({
|
|
1478
|
+
token: password,
|
|
1479
|
+
region
|
|
1480
|
+
});
|
|
1319
1481
|
const spinnerGroups = new Spinner({
|
|
1320
1482
|
verbose: !isVitest
|
|
1321
1483
|
});
|
|
@@ -1330,25 +1492,25 @@ componentsCommand.command("pull [componentName]").option("-f, --filename <filena
|
|
|
1330
1492
|
});
|
|
1331
1493
|
try {
|
|
1332
1494
|
spinnerGroups.start(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components groups")}`);
|
|
1333
|
-
const groups = await fetchComponentGroups(space
|
|
1495
|
+
const groups = await fetchComponentGroups(space);
|
|
1334
1496
|
spinnerGroups.succeed(`${chalk.hex(colorPalette.COMPONENTS)("Groups")} - Completed in ${spinnerGroups.elapsedTime.toFixed(2)}ms`);
|
|
1335
1497
|
spinnerPresets.start(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components presets")}`);
|
|
1336
|
-
const presets = await fetchComponentPresets(space
|
|
1498
|
+
const presets = await fetchComponentPresets(space);
|
|
1337
1499
|
spinnerPresets.succeed(`${chalk.hex(colorPalette.COMPONENTS)("Presets")} - Completed in ${spinnerPresets.elapsedTime.toFixed(2)}ms`);
|
|
1338
1500
|
spinnerInternalTags.start(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components internal tags")}`);
|
|
1339
|
-
const internalTags = await fetchComponentInternalTags(space
|
|
1501
|
+
const internalTags = await fetchComponentInternalTags(space);
|
|
1340
1502
|
spinnerInternalTags.succeed(`${chalk.hex(colorPalette.COMPONENTS)("Tags")} - Completed in ${spinnerInternalTags.elapsedTime.toFixed(2)}ms`);
|
|
1341
1503
|
let components;
|
|
1342
1504
|
spinnerComponents.start(`Fetching ${chalk.hex(colorPalette.COMPONENTS)("components")}`);
|
|
1343
1505
|
if (componentName) {
|
|
1344
|
-
const component = await fetchComponent(space, componentName
|
|
1506
|
+
const component = await fetchComponent(space, componentName);
|
|
1345
1507
|
if (!component) {
|
|
1346
1508
|
konsola.warn(`No component found with name "${componentName}"`);
|
|
1347
1509
|
return;
|
|
1348
1510
|
}
|
|
1349
1511
|
components = [component];
|
|
1350
1512
|
} else {
|
|
1351
|
-
components = await fetchComponents(space
|
|
1513
|
+
components = await fetchComponents(space);
|
|
1352
1514
|
if (!components || components.length === 0) {
|
|
1353
1515
|
konsola.warn(`No components found in the space ${space}`);
|
|
1354
1516
|
return;
|
|
@@ -1387,7 +1549,7 @@ componentsCommand.command("pull [componentName]").option("-f, --filename <filena
|
|
|
1387
1549
|
}
|
|
1388
1550
|
});
|
|
1389
1551
|
|
|
1390
|
-
function findRelatedResources(components, spaceData) {
|
|
1552
|
+
function findRelatedResources(components, spaceData, visitedComponents = /* @__PURE__ */ new Set()) {
|
|
1391
1553
|
const componentIds = new Set(components.map((c) => c.id));
|
|
1392
1554
|
const whitelistedComponentNames = /* @__PURE__ */ new Set();
|
|
1393
1555
|
const componentGroupUuids = /* @__PURE__ */ new Set();
|
|
@@ -1472,7 +1634,11 @@ function findRelatedResources(components, spaceData) {
|
|
|
1472
1634
|
whitelistedComponents: []
|
|
1473
1635
|
};
|
|
1474
1636
|
if (whitelistedComponents.length > 0) {
|
|
1475
|
-
|
|
1637
|
+
const newComponents = whitelistedComponents.filter((component) => !visitedComponents.has(component.name));
|
|
1638
|
+
if (newComponents.length > 0) {
|
|
1639
|
+
components.forEach((component) => visitedComponents.add(component.name));
|
|
1640
|
+
additionalResources = findRelatedResources(newComponents, spaceData, visitedComponents);
|
|
1641
|
+
}
|
|
1476
1642
|
}
|
|
1477
1643
|
const result = {
|
|
1478
1644
|
groups: Array.from(/* @__PURE__ */ new Set([...Array.from(relatedGroups), ...additionalResources.groups])),
|
|
@@ -1519,7 +1685,7 @@ function filterSpaceDataByComponent(spaceData, componentName) {
|
|
|
1519
1685
|
internalTags: relatedResources.internalTags
|
|
1520
1686
|
};
|
|
1521
1687
|
}
|
|
1522
|
-
async function handleTags(space,
|
|
1688
|
+
async function handleTags(space, spaceData, skipIds) {
|
|
1523
1689
|
const results = {
|
|
1524
1690
|
successful: [],
|
|
1525
1691
|
failed: [],
|
|
@@ -1532,7 +1698,7 @@ async function handleTags(space, password, region, spaceData, skipIds) {
|
|
|
1532
1698
|
});
|
|
1533
1699
|
consolidatedSpinner.start("Upserting tags...");
|
|
1534
1700
|
try {
|
|
1535
|
-
const updatedTag = await upsertComponentInternalTag(space, tag
|
|
1701
|
+
const updatedTag = await upsertComponentInternalTag(space, tag);
|
|
1536
1702
|
if (updatedTag) {
|
|
1537
1703
|
results.idMap.set(tag.id, updatedTag.id);
|
|
1538
1704
|
results.successful.push(tag.name);
|
|
@@ -1545,7 +1711,7 @@ async function handleTags(space, password, region, spaceData, skipIds) {
|
|
|
1545
1711
|
}));
|
|
1546
1712
|
return results;
|
|
1547
1713
|
}
|
|
1548
|
-
async function handleComponentGroups(space,
|
|
1714
|
+
async function handleComponentGroups(space, spaceData, skipUuids) {
|
|
1549
1715
|
const results = {
|
|
1550
1716
|
successful: [],
|
|
1551
1717
|
failed: [],
|
|
@@ -1562,7 +1728,7 @@ async function handleComponentGroups(space, password, region, spaceData, skipUui
|
|
|
1562
1728
|
});
|
|
1563
1729
|
spinner.start(`Upserting root group ${group.name}...`);
|
|
1564
1730
|
try {
|
|
1565
|
-
const updatedGroup = await upsertComponentGroup(space, group
|
|
1731
|
+
const updatedGroup = await upsertComponentGroup(space, group);
|
|
1566
1732
|
if (updatedGroup) {
|
|
1567
1733
|
results.uuidMap.set(group.uuid, updatedGroup.uuid);
|
|
1568
1734
|
results.idMap.set(group.id, updatedGroup.id);
|
|
@@ -1598,7 +1764,7 @@ async function handleComponentGroups(space, password, region, spaceData, skipUui
|
|
|
1598
1764
|
parent_uuid: newParentUuid,
|
|
1599
1765
|
parent_id: newParentId
|
|
1600
1766
|
};
|
|
1601
|
-
const updatedGroup = await upsertComponentGroup(space, groupToUpdate
|
|
1767
|
+
const updatedGroup = await upsertComponentGroup(space, groupToUpdate);
|
|
1602
1768
|
if (updatedGroup) {
|
|
1603
1769
|
results.uuidMap.set(group.uuid, updatedGroup.uuid);
|
|
1604
1770
|
results.idMap.set(group.id, updatedGroup.id);
|
|
@@ -1693,7 +1859,7 @@ function getGroupHierarchy(group, allGroups) {
|
|
|
1693
1859
|
}
|
|
1694
1860
|
return hierarchy;
|
|
1695
1861
|
}
|
|
1696
|
-
async function handleWhitelists(space,
|
|
1862
|
+
async function handleWhitelists(space, spaceData) {
|
|
1697
1863
|
const results = {
|
|
1698
1864
|
successful: [],
|
|
1699
1865
|
failed: [],
|
|
@@ -1723,7 +1889,7 @@ async function handleWhitelists(space, password, region, spaceData) {
|
|
|
1723
1889
|
verbose: !isVitest
|
|
1724
1890
|
});
|
|
1725
1891
|
spinner.start("Processing whitelist tags...");
|
|
1726
|
-
const tagResults = await handleTags(space,
|
|
1892
|
+
const tagResults = await handleTags(space, whitelistTags);
|
|
1727
1893
|
results.successful.push(...tagResults.successful);
|
|
1728
1894
|
results.failed.push(...tagResults.failed);
|
|
1729
1895
|
tagResults.idMap.forEach((newId, oldId) => {
|
|
@@ -1744,7 +1910,7 @@ async function handleWhitelists(space, password, region, spaceData) {
|
|
|
1744
1910
|
verbose: !isVitest
|
|
1745
1911
|
});
|
|
1746
1912
|
spinner.start("Processing whitelist groups...");
|
|
1747
|
-
const groupResults = await handleComponentGroups(space,
|
|
1913
|
+
const groupResults = await handleComponentGroups(space, whitelistGroups);
|
|
1748
1914
|
results.successful.push(...groupResults.successful);
|
|
1749
1915
|
results.failed.push(...groupResults.failed);
|
|
1750
1916
|
groupResults.uuidMap.forEach((newUuid, oldUuid) => {
|
|
@@ -1766,11 +1932,6 @@ async function handleWhitelists(space, password, region, spaceData) {
|
|
|
1766
1932
|
return;
|
|
1767
1933
|
}
|
|
1768
1934
|
if (visited.has(componentName)) {
|
|
1769
|
-
failedComponents.add(componentName);
|
|
1770
|
-
results.failed.push({
|
|
1771
|
-
name: componentName,
|
|
1772
|
-
error: new Error(`Circular dependency detected for component ${componentName}`)
|
|
1773
|
-
});
|
|
1774
1935
|
return;
|
|
1775
1936
|
}
|
|
1776
1937
|
visited.add(componentName);
|
|
@@ -1834,7 +1995,7 @@ async function handleWhitelists(space, password, region, spaceData) {
|
|
|
1834
1995
|
results.componentNameMap
|
|
1835
1996
|
);
|
|
1836
1997
|
}
|
|
1837
|
-
const updatedComponent = await upsertComponent(space, componentToUpdate
|
|
1998
|
+
const updatedComponent = await upsertComponent(space, componentToUpdate);
|
|
1838
1999
|
if (updatedComponent) {
|
|
1839
2000
|
results.successful.push(component.name);
|
|
1840
2001
|
results.componentNameMap.set(component.name, updatedComponent.name);
|
|
@@ -1858,8 +2019,6 @@ async function handleWhitelists(space, password, region, spaceData) {
|
|
|
1858
2019
|
async function handleComponents(options) {
|
|
1859
2020
|
const {
|
|
1860
2021
|
space,
|
|
1861
|
-
password,
|
|
1862
|
-
region,
|
|
1863
2022
|
spaceData: { components, internalTags, presets },
|
|
1864
2023
|
groupsUuidMap,
|
|
1865
2024
|
tagsIdMaps,
|
|
@@ -1938,7 +2097,7 @@ async function handleComponents(options) {
|
|
|
1938
2097
|
componentNameMap
|
|
1939
2098
|
);
|
|
1940
2099
|
}
|
|
1941
|
-
const updatedComponent = await upsertComponent(space, componentToUpdate
|
|
2100
|
+
const updatedComponent = await upsertComponent(space, componentToUpdate);
|
|
1942
2101
|
if (updatedComponent) {
|
|
1943
2102
|
results.successful.push(component.name);
|
|
1944
2103
|
results.componentIdMap.set(component.id, updatedComponent.id);
|
|
@@ -1972,7 +2131,7 @@ async function handleComponents(options) {
|
|
|
1972
2131
|
tagsIdMaps,
|
|
1973
2132
|
componentNameMap
|
|
1974
2133
|
);
|
|
1975
|
-
await upsertComponent(space, componentToUpdate
|
|
2134
|
+
await upsertComponent(space, componentToUpdate);
|
|
1976
2135
|
spinner.succeed(`Component whitelists-> ${chalk.hex(colorPalette.COMPONENTS)(component.name)} - Completed in ${spinner.elapsedTime.toFixed(2)}ms`);
|
|
1977
2136
|
} catch (error) {
|
|
1978
2137
|
spinner.failed(`Component whitelists-> ${chalk.hex(colorPalette.COMPONENTS)(component.name)} - Failed`);
|
|
@@ -1998,7 +2157,7 @@ async function handleComponents(options) {
|
|
|
1998
2157
|
preset: preset.preset,
|
|
1999
2158
|
component_id: newComponentId
|
|
2000
2159
|
};
|
|
2001
|
-
await upsertComponentPreset(space, presetToUpdate
|
|
2160
|
+
await upsertComponentPreset(space, presetToUpdate);
|
|
2002
2161
|
presetSpinner.succeed(`Preset-> ${chalk.hex(colorPalette.COMPONENTS)(preset.name)} - Completed in ${presetSpinner.elapsedTime.toFixed(2)}ms`);
|
|
2003
2162
|
} catch (error) {
|
|
2004
2163
|
presetSpinner.failed(`Preset-> ${chalk.hex(colorPalette.COMPONENTS)(preset.name)} - Failed`);
|
|
@@ -2018,8 +2177,7 @@ componentsCommand.command("push [componentName]").description(`Push your space's
|
|
|
2018
2177
|
const { from, filter } = options;
|
|
2019
2178
|
const { state, initializeSession } = session();
|
|
2020
2179
|
await initializeSession();
|
|
2021
|
-
if (!state
|
|
2022
|
-
handleError(new CommandError(`You are currently not logged in. Please login first to get your user info.`), verbose);
|
|
2180
|
+
if (!requireAuthentication(state, verbose)) {
|
|
2023
2181
|
return;
|
|
2024
2182
|
}
|
|
2025
2183
|
if (!space) {
|
|
@@ -2029,11 +2187,18 @@ componentsCommand.command("push [componentName]").description(`Push your space's
|
|
|
2029
2187
|
if (!from) {
|
|
2030
2188
|
options.from = space;
|
|
2031
2189
|
}
|
|
2190
|
+
konsola.info(`Attempting to push components ${chalk.bold("from")} space ${chalk.hex(colorPalette.COMPONENTS)(options.from)} ${chalk.bold("to")} ${chalk.hex(colorPalette.COMPONENTS)(space)}`);
|
|
2191
|
+
konsola.br();
|
|
2032
2192
|
const { password, region } = state;
|
|
2193
|
+
mapiClient({
|
|
2194
|
+
token: password,
|
|
2195
|
+
region
|
|
2196
|
+
});
|
|
2033
2197
|
try {
|
|
2034
2198
|
let spaceData = await readComponentsFiles({
|
|
2035
2199
|
...options,
|
|
2036
|
-
path
|
|
2200
|
+
path,
|
|
2201
|
+
space
|
|
2037
2202
|
});
|
|
2038
2203
|
if (componentName) {
|
|
2039
2204
|
spaceData = filterSpaceDataByComponent(spaceData, componentName);
|
|
@@ -2057,13 +2222,13 @@ componentsCommand.command("push [componentName]").description(`Push your space's
|
|
|
2057
2222
|
successful: [],
|
|
2058
2223
|
failed: []
|
|
2059
2224
|
};
|
|
2060
|
-
const whitelistResults = await handleWhitelists(space,
|
|
2225
|
+
const whitelistResults = await handleWhitelists(space, spaceData);
|
|
2061
2226
|
results.successful.push(...whitelistResults.successful);
|
|
2062
2227
|
results.failed.push(...whitelistResults.failed);
|
|
2063
|
-
const tagsResults = await handleTags(space,
|
|
2228
|
+
const tagsResults = await handleTags(space, spaceData.internalTags, whitelistResults.processedTagIds);
|
|
2064
2229
|
results.successful.push(...tagsResults.successful);
|
|
2065
2230
|
results.failed.push(...tagsResults.failed);
|
|
2066
|
-
const groupsResults = await handleComponentGroups(space,
|
|
2231
|
+
const groupsResults = await handleComponentGroups(space, spaceData.groups, whitelistResults.processedGroupUuids);
|
|
2067
2232
|
results.successful.push(...groupsResults.successful);
|
|
2068
2233
|
results.failed.push(...groupsResults.failed);
|
|
2069
2234
|
const remainingComponents = spaceData.components.filter(
|
|
@@ -2071,8 +2236,6 @@ componentsCommand.command("push [componentName]").description(`Push your space's
|
|
|
2071
2236
|
);
|
|
2072
2237
|
const componentsResults = await handleComponents({
|
|
2073
2238
|
space,
|
|
2074
|
-
password,
|
|
2075
|
-
region,
|
|
2076
2239
|
spaceData: {
|
|
2077
2240
|
...spaceData,
|
|
2078
2241
|
components: remainingComponents
|
|
@@ -2138,20 +2301,20 @@ languagesCommand.command("pull").description(`Download your space's languages sc
|
|
|
2138
2301
|
const { filename = "languages", suffix = options.space } = options;
|
|
2139
2302
|
const { state, initializeSession } = session();
|
|
2140
2303
|
await initializeSession();
|
|
2141
|
-
if (!state
|
|
2142
|
-
handleError(new CommandError(`You are currently not logged in. Please login first to get your user info.`), verbose);
|
|
2304
|
+
if (!requireAuthentication(state, verbose)) {
|
|
2143
2305
|
return;
|
|
2144
2306
|
}
|
|
2145
2307
|
if (!space) {
|
|
2146
2308
|
handleError(new CommandError(`Please provide the space as argument --space YOUR_SPACE_ID.`), verbose);
|
|
2147
2309
|
return;
|
|
2148
2310
|
}
|
|
2311
|
+
const { password, region } = state;
|
|
2149
2312
|
const spinner = new Spinner({
|
|
2150
2313
|
verbose: !isVitest
|
|
2151
2314
|
});
|
|
2152
2315
|
try {
|
|
2153
2316
|
spinner.start(`Fetching ${chalk.hex(colorPalette.LANGUAGES)("languages")}`);
|
|
2154
|
-
const internationalization = await fetchLanguages(space,
|
|
2317
|
+
const internationalization = await fetchLanguages(space, password, region);
|
|
2155
2318
|
if (!internationalization || internationalization.languages?.length === 0) {
|
|
2156
2319
|
spinner.failed();
|
|
2157
2320
|
konsola.warn(`No languages found in the space ${space}`, true);
|
|
@@ -2215,8 +2378,7 @@ migrationsCommand.command("generate [componentName]").description("Generate a mi
|
|
|
2215
2378
|
}
|
|
2216
2379
|
const { state, initializeSession } = session();
|
|
2217
2380
|
await initializeSession();
|
|
2218
|
-
if (!state
|
|
2219
|
-
handleError(new CommandError(`You are currently not logged in. Please login first to get your user info.`), verbose);
|
|
2381
|
+
if (!requireAuthentication(state, verbose)) {
|
|
2220
2382
|
return;
|
|
2221
2383
|
}
|
|
2222
2384
|
if (!space) {
|
|
@@ -2224,11 +2386,15 @@ migrationsCommand.command("generate [componentName]").description("Generate a mi
|
|
|
2224
2386
|
return;
|
|
2225
2387
|
}
|
|
2226
2388
|
const { password, region } = state;
|
|
2389
|
+
mapiClient({
|
|
2390
|
+
token: password,
|
|
2391
|
+
region
|
|
2392
|
+
});
|
|
2227
2393
|
const spinner = new Spinner({
|
|
2228
2394
|
verbose: !isVitest
|
|
2229
2395
|
}).start(`Generating migration for component ${componentName}...`);
|
|
2230
2396
|
try {
|
|
2231
|
-
const component = await fetchComponent(space, componentName
|
|
2397
|
+
const component = await fetchComponent(space, componentName);
|
|
2232
2398
|
if (!component) {
|
|
2233
2399
|
spinner.failed(`Failed to fetch component ${componentName}. Make sure the component exists in your space.`);
|
|
2234
2400
|
handleError(new CommandError(`No component found with name "${componentName}"`), verbose);
|
|
@@ -2248,16 +2414,28 @@ migrationsCommand.command("generate [componentName]").description("Generate a mi
|
|
|
2248
2414
|
const fetchStories = async (space, token, region, params) => {
|
|
2249
2415
|
try {
|
|
2250
2416
|
const url = getStoryblokUrl(region);
|
|
2251
|
-
const
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2417
|
+
const allStories = [];
|
|
2418
|
+
let currentPage = 1;
|
|
2419
|
+
let hasMorePages = true;
|
|
2420
|
+
while (hasMorePages) {
|
|
2421
|
+
const { filter_query, ...restParams } = params || {};
|
|
2422
|
+
const regularParams = new URLSearchParams({
|
|
2423
|
+
...objectToStringParams({ ...restParams, per_page: 100 }),
|
|
2424
|
+
...currentPage > 1 && { page: currentPage.toString() }
|
|
2425
|
+
}).toString();
|
|
2426
|
+
const queryString = filter_query ? `${regularParams ? `${regularParams}&` : ""}${filter_query}` : regularParams;
|
|
2427
|
+
const endpoint = `${url}/spaces/${space}/stories${queryString ? `?${queryString}` : ""}`;
|
|
2428
|
+
const response = await customFetch(endpoint, {
|
|
2429
|
+
headers: {
|
|
2430
|
+
Authorization: token
|
|
2431
|
+
}
|
|
2432
|
+
});
|
|
2433
|
+
allStories.push(...response.stories);
|
|
2434
|
+
const totalPages = Math.ceil(response.total / response.perPage);
|
|
2435
|
+
hasMorePages = currentPage < totalPages;
|
|
2436
|
+
currentPage++;
|
|
2437
|
+
}
|
|
2438
|
+
return allStories;
|
|
2261
2439
|
} catch (error) {
|
|
2262
2440
|
handleAPIError("pull_stories", error);
|
|
2263
2441
|
}
|
|
@@ -2615,8 +2793,7 @@ migrationsCommand.command("run [componentName]").description("Run migrations").o
|
|
|
2615
2793
|
const { space, path } = migrationsCommand.opts();
|
|
2616
2794
|
const { state, initializeSession } = session();
|
|
2617
2795
|
await initializeSession();
|
|
2618
|
-
if (!state
|
|
2619
|
-
handleError(new CommandError(`You are currently not logged in. Please login first to get your user info.`), verbose);
|
|
2796
|
+
if (!requireAuthentication(state, verbose)) {
|
|
2620
2797
|
return;
|
|
2621
2798
|
}
|
|
2622
2799
|
if (!space) {
|
|
@@ -2772,8 +2949,7 @@ migrationsCommand.command("rollback [migrationFile]").description("Rollback a mi
|
|
|
2772
2949
|
const { space, path } = migrationsCommand.opts();
|
|
2773
2950
|
const { state, initializeSession } = session();
|
|
2774
2951
|
await initializeSession();
|
|
2775
|
-
if (!state
|
|
2776
|
-
handleError(new CommandError(`You are currently not logged in. Please login first to get your user info.`), verbose);
|
|
2952
|
+
if (!requireAuthentication(state, verbose)) {
|
|
2777
2953
|
return;
|
|
2778
2954
|
}
|
|
2779
2955
|
if (!space) {
|
|
@@ -3386,7 +3562,7 @@ const loadCustomFieldsParser = async (path) => {
|
|
|
3386
3562
|
return customFieldsParser.default;
|
|
3387
3563
|
} catch (error) {
|
|
3388
3564
|
handleError(error);
|
|
3389
|
-
return
|
|
3565
|
+
return void 0;
|
|
3390
3566
|
}
|
|
3391
3567
|
};
|
|
3392
3568
|
async function loadCompilerOptions(path) {
|
|
@@ -3427,6 +3603,9 @@ const generateTypes = async (spaceData, options = {
|
|
|
3427
3603
|
if (property.type && Array.from(storyblokSchemas.keys()).includes(property.type)) {
|
|
3428
3604
|
storyblokPropertyTypes.add(property.type);
|
|
3429
3605
|
}
|
|
3606
|
+
if (property.tsType && property.tsType.includes(STORY_TYPE)) {
|
|
3607
|
+
storyblokPropertyTypes.add(STORY_TYPE);
|
|
3608
|
+
}
|
|
3430
3609
|
});
|
|
3431
3610
|
}
|
|
3432
3611
|
const componentSchema = {
|
|
@@ -3456,6 +3635,11 @@ const generateTypes = async (spaceData, options = {
|
|
|
3456
3635
|
});
|
|
3457
3636
|
}));
|
|
3458
3637
|
const imports = [];
|
|
3638
|
+
const needsISbStoryData = storyblokPropertyTypes.has(STORY_TYPE);
|
|
3639
|
+
if (needsISbStoryData) {
|
|
3640
|
+
imports.push(`import type { ${STORY_TYPE} } from '@storyblok/js';`);
|
|
3641
|
+
storyblokPropertyTypes.delete(STORY_TYPE);
|
|
3642
|
+
}
|
|
3459
3643
|
if (storyblokPropertyTypes.size > 0) {
|
|
3460
3644
|
const typeImports = Array.from(storyblokPropertyTypes).map((type) => {
|
|
3461
3645
|
const pascalType = toPascalCase(type);
|
|
@@ -3488,6 +3672,7 @@ const generateStoryblokTypes = async (options = {}) => {
|
|
|
3488
3672
|
const typeDefs = [
|
|
3489
3673
|
"// This file was generated by the Storyblok CLI.",
|
|
3490
3674
|
"// DO NOT MODIFY THIS FILE BY HAND.",
|
|
3675
|
+
`import type { ${STORY_TYPE} } from '@storyblok/js';`,
|
|
3491
3676
|
storyblokTypesContent
|
|
3492
3677
|
].join("\n");
|
|
3493
3678
|
const resolvedPath = path ? resolve(process.cwd(), path, "types") : resolvePath(path, "types");
|
|
@@ -3506,8 +3691,7 @@ typesCommand.command("generate").description("Generate types d.ts for your compo
|
|
|
3506
3691
|
const { space, path } = typesCommand.opts();
|
|
3507
3692
|
const { state, initializeSession } = session();
|
|
3508
3693
|
await initializeSession();
|
|
3509
|
-
if (!state
|
|
3510
|
-
handleError(new CommandError(`You are currently not logged in. Please login first to get your user info.`), verbose);
|
|
3694
|
+
if (!requireAuthentication(state, verbose)) {
|
|
3511
3695
|
return;
|
|
3512
3696
|
}
|
|
3513
3697
|
if (!space) {
|
|
@@ -3542,7 +3726,7 @@ typesCommand.command("generate").description("Generate types d.ts for your compo
|
|
|
3542
3726
|
}
|
|
3543
3727
|
});
|
|
3544
3728
|
|
|
3545
|
-
const version = "4.0.0-beta.
|
|
3729
|
+
const version = "4.0.0-beta.5";
|
|
3546
3730
|
const pkg = {
|
|
3547
3731
|
version: version};
|
|
3548
3732
|
|