storyblok 4.12.1 → 4.13.0
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 +185 -108
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1862,23 +1862,117 @@ function session() {
|
|
|
1862
1862
|
return sessionInstance;
|
|
1863
1863
|
}
|
|
1864
1864
|
|
|
1865
|
+
async function performInteractiveLogin(options) {
|
|
1866
|
+
const { verbose = false, preSelectedRegion, showWelcomeMessage = true } = options || {};
|
|
1867
|
+
const spinner = new Spinner({
|
|
1868
|
+
verbose: !isVitest
|
|
1869
|
+
});
|
|
1870
|
+
try {
|
|
1871
|
+
const strategy = await select({
|
|
1872
|
+
message: "How would you like to login?",
|
|
1873
|
+
choices: [
|
|
1874
|
+
{
|
|
1875
|
+
name: "With email",
|
|
1876
|
+
value: "login-with-email",
|
|
1877
|
+
short: "Email"
|
|
1878
|
+
},
|
|
1879
|
+
{
|
|
1880
|
+
name: "With Token (Personal Access Token \u2013 works also for SSO accounts)",
|
|
1881
|
+
value: "login-with-token",
|
|
1882
|
+
short: "Token"
|
|
1883
|
+
}
|
|
1884
|
+
]
|
|
1885
|
+
});
|
|
1886
|
+
let userToken;
|
|
1887
|
+
let userRegion;
|
|
1888
|
+
if (strategy === "login-with-token") {
|
|
1889
|
+
konsola.info([
|
|
1890
|
+
"\u{1F511} You can use a Personal Access Token to log in.",
|
|
1891
|
+
"This works for all accounts, including SSO accounts.",
|
|
1892
|
+
`Generate one in your Storyblok account settings: ${chalk.underline.blue("https://app.storyblok.com/#/me/account?tab=token")}`
|
|
1893
|
+
].join("\n"));
|
|
1894
|
+
userToken = await password({
|
|
1895
|
+
message: "Please enter your Personal Access Token:",
|
|
1896
|
+
validate: (value) => {
|
|
1897
|
+
return value.length > 0;
|
|
1898
|
+
}
|
|
1899
|
+
});
|
|
1900
|
+
userRegion = preSelectedRegion || await select({
|
|
1901
|
+
message: "Please select the region you would like to work in:",
|
|
1902
|
+
choices: Object.values(regions).map((region) => ({
|
|
1903
|
+
name: regionNames[region],
|
|
1904
|
+
value: region
|
|
1905
|
+
})),
|
|
1906
|
+
default: regions.EU
|
|
1907
|
+
});
|
|
1908
|
+
spinner.start(`Logging in with token`);
|
|
1909
|
+
const user = await loginWithToken(userToken, userRegion);
|
|
1910
|
+
spinner.succeed();
|
|
1911
|
+
if (user) {
|
|
1912
|
+
const { updateSession, persistCredentials } = session();
|
|
1913
|
+
updateSession(user.email, userToken, userRegion);
|
|
1914
|
+
await persistCredentials(userRegion);
|
|
1915
|
+
if (showWelcomeMessage) {
|
|
1916
|
+
konsola.ok(`Successfully logged in to region ${chalk.hex(colorPalette.PRIMARY)(`${regionNames[userRegion]} (${userRegion})`)}. Welcome ${chalk.hex(colorPalette.PRIMARY)(user.friendly_name)}.`, true);
|
|
1917
|
+
}
|
|
1918
|
+
return { token: userToken, region: userRegion };
|
|
1919
|
+
}
|
|
1920
|
+
} else {
|
|
1921
|
+
const userEmail = await input({
|
|
1922
|
+
message: "Please enter your email address:",
|
|
1923
|
+
required: true,
|
|
1924
|
+
validate: (value) => {
|
|
1925
|
+
const emailRegex = /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/;
|
|
1926
|
+
return emailRegex.test(value);
|
|
1927
|
+
}
|
|
1928
|
+
});
|
|
1929
|
+
const userPassword = await password({
|
|
1930
|
+
message: "Please enter your password:"
|
|
1931
|
+
});
|
|
1932
|
+
userRegion = preSelectedRegion || await select({
|
|
1933
|
+
message: "Please select the region you would like to work in:",
|
|
1934
|
+
choices: Object.values(regions).map((region) => ({
|
|
1935
|
+
name: regionNames[region],
|
|
1936
|
+
value: region
|
|
1937
|
+
})),
|
|
1938
|
+
default: regions.EU
|
|
1939
|
+
});
|
|
1940
|
+
spinner.start(`Logging in with email`);
|
|
1941
|
+
spinner.succeed();
|
|
1942
|
+
const response = await loginWithEmailAndPassword(userEmail, userPassword, userRegion);
|
|
1943
|
+
if (response?.otp_required) {
|
|
1944
|
+
const otp = await input({
|
|
1945
|
+
message: "Add the code from your Authenticator app, or the one we sent to your e-mail / phone:",
|
|
1946
|
+
required: true
|
|
1947
|
+
});
|
|
1948
|
+
const otpResponse = await loginWithOtp(userEmail, userPassword, otp, userRegion);
|
|
1949
|
+
if (otpResponse?.access_token) {
|
|
1950
|
+
userToken = otpResponse.access_token;
|
|
1951
|
+
}
|
|
1952
|
+
} else if (response?.access_token) {
|
|
1953
|
+
userToken = response.access_token;
|
|
1954
|
+
}
|
|
1955
|
+
if (userToken) {
|
|
1956
|
+
const { updateSession, persistCredentials } = session();
|
|
1957
|
+
updateSession(userEmail, userToken, userRegion);
|
|
1958
|
+
await persistCredentials(userRegion);
|
|
1959
|
+
if (showWelcomeMessage) {
|
|
1960
|
+
konsola.ok(`Successfully logged in to region ${chalk.hex(colorPalette.PRIMARY)(`${regionNames[userRegion]} (${userRegion})`)}. Welcome ${chalk.hex(colorPalette.PRIMARY)(userEmail)}.`, true);
|
|
1961
|
+
}
|
|
1962
|
+
return { token: userToken, region: userRegion };
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
return null;
|
|
1966
|
+
} catch (error) {
|
|
1967
|
+
spinner.failed();
|
|
1968
|
+
konsola.br();
|
|
1969
|
+
handleError(error, verbose);
|
|
1970
|
+
return null;
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1865
1974
|
const program$h = getProgram();
|
|
1866
1975
|
const allRegionsText = Object.values(regions).join(",");
|
|
1867
|
-
const loginStrategy = {
|
|
1868
|
-
message: "How would you like to login?",
|
|
1869
|
-
choices: [
|
|
1870
|
-
{
|
|
1871
|
-
name: "With email",
|
|
1872
|
-
value: "login-with-email",
|
|
1873
|
-
short: "Email"
|
|
1874
|
-
},
|
|
1875
|
-
{
|
|
1876
|
-
name: "With Token (Personal Access Token \u2013 works also for SSO accounts)",
|
|
1877
|
-
value: "login-with-token",
|
|
1878
|
-
short: "Token"
|
|
1879
|
-
}
|
|
1880
|
-
]
|
|
1881
|
-
};
|
|
1882
1976
|
program$h.command(commands.LOGIN).description("Login to the Storyblok CLI").option("-t, --token <token>", "Token to login directly without questions, like for CI environments").option(
|
|
1883
1977
|
"-r, --region <region>",
|
|
1884
1978
|
`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}.`
|
|
@@ -1926,85 +2020,16 @@ program$h.command(commands.LOGIN).description("Login to the Storyblok CLI").opti
|
|
|
1926
2020
|
handleError(error, verbose);
|
|
1927
2021
|
}
|
|
1928
2022
|
} else {
|
|
1929
|
-
const spinner = new Spinner({
|
|
1930
|
-
verbose: !isVitest
|
|
1931
|
-
});
|
|
1932
2023
|
try {
|
|
1933
|
-
const
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
const userToken = await password({
|
|
1941
|
-
message: "Please enter your Personal Access Token:",
|
|
1942
|
-
validate: (value) => {
|
|
1943
|
-
return value.length > 0;
|
|
1944
|
-
}
|
|
1945
|
-
});
|
|
1946
|
-
let userRegion = region;
|
|
1947
|
-
if (!userRegion) {
|
|
1948
|
-
userRegion = await select({
|
|
1949
|
-
message: "Please select the region you would like to work in:",
|
|
1950
|
-
choices: Object.values(regions).map((region2) => ({
|
|
1951
|
-
name: regionNames[region2],
|
|
1952
|
-
value: region2
|
|
1953
|
-
})),
|
|
1954
|
-
default: regions.EU
|
|
1955
|
-
});
|
|
1956
|
-
}
|
|
1957
|
-
spinner.start(`Logging in with token`);
|
|
1958
|
-
const user = await loginWithToken(userToken, userRegion);
|
|
1959
|
-
spinner.succeed();
|
|
1960
|
-
if (user) {
|
|
1961
|
-
updateSession(user.email, userToken, userRegion);
|
|
1962
|
-
await persistCredentials(userRegion);
|
|
1963
|
-
konsola.ok(`Successfully logged in to region ${chalk.hex(colorPalette.PRIMARY)(`${regionNames[userRegion]} (${userRegion})`)}. Welcome ${chalk.hex(colorPalette.PRIMARY)(user.friendly_name)}.`, true);
|
|
1964
|
-
}
|
|
1965
|
-
} else {
|
|
1966
|
-
const userEmail = await input({
|
|
1967
|
-
message: "Please enter your email address:",
|
|
1968
|
-
required: true,
|
|
1969
|
-
validate: (value) => {
|
|
1970
|
-
const emailRegex = /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/;
|
|
1971
|
-
return emailRegex.test(value);
|
|
1972
|
-
}
|
|
1973
|
-
});
|
|
1974
|
-
const userPassword = await password({
|
|
1975
|
-
message: "Please enter your password:"
|
|
1976
|
-
});
|
|
1977
|
-
let userRegion = region;
|
|
1978
|
-
if (!userRegion) {
|
|
1979
|
-
userRegion = await select({
|
|
1980
|
-
message: "Please select the region you would like to work in:",
|
|
1981
|
-
choices: Object.values(regions).map((region2) => ({
|
|
1982
|
-
name: regionNames[region2],
|
|
1983
|
-
value: region2
|
|
1984
|
-
})),
|
|
1985
|
-
default: regions.EU
|
|
1986
|
-
});
|
|
1987
|
-
}
|
|
1988
|
-
spinner.start(`Logging in with email`);
|
|
1989
|
-
spinner.succeed();
|
|
1990
|
-
const response = await loginWithEmailAndPassword(userEmail, userPassword, userRegion);
|
|
1991
|
-
if (response?.otp_required) {
|
|
1992
|
-
const otp = await input({
|
|
1993
|
-
message: "Add the code from your Authenticator app, or the one we sent to your e-mail / phone:",
|
|
1994
|
-
required: true
|
|
1995
|
-
});
|
|
1996
|
-
const otpResponse = await loginWithOtp(userEmail, userPassword, otp, userRegion);
|
|
1997
|
-
if (otpResponse?.access_token) {
|
|
1998
|
-
updateSession(userEmail, otpResponse?.access_token, userRegion);
|
|
1999
|
-
}
|
|
2000
|
-
} else if (response?.access_token) {
|
|
2001
|
-
updateSession(userEmail, response.access_token, userRegion);
|
|
2002
|
-
}
|
|
2003
|
-
await persistCredentials(region);
|
|
2004
|
-
konsola.ok(`Successfully logged in to region ${chalk.hex(colorPalette.PRIMARY)(`${regionNames[userRegion]} (${userRegion})`)}. Welcome ${chalk.hex(colorPalette.PRIMARY)(userEmail)}.`, true);
|
|
2024
|
+
const result = await performInteractiveLogin({
|
|
2025
|
+
verbose,
|
|
2026
|
+
preSelectedRegion: region,
|
|
2027
|
+
showWelcomeMessage: true
|
|
2028
|
+
});
|
|
2029
|
+
if (!result) {
|
|
2030
|
+
konsola.warn("Login cancelled or failed.");
|
|
2005
2031
|
}
|
|
2006
2032
|
} catch (error) {
|
|
2007
|
-
spinner.failed();
|
|
2008
2033
|
konsola.br();
|
|
2009
2034
|
handleError(error, verbose);
|
|
2010
2035
|
}
|
|
@@ -6257,6 +6282,24 @@ function showNextSteps(technologyTemplate, finalProjectPath) {
|
|
|
6257
6282
|
`);
|
|
6258
6283
|
konsola.info(`Or check the dedicated guide at: ${chalk.hex(colorPalette.PRIMARY)(`https://www.storyblok.com/docs/guides/${technologyTemplate}`)}`);
|
|
6259
6284
|
}
|
|
6285
|
+
async function promptForLogin(verbose) {
|
|
6286
|
+
try {
|
|
6287
|
+
konsola.br();
|
|
6288
|
+
const shouldLogin = await confirm({
|
|
6289
|
+
message: "Would you like to login now?",
|
|
6290
|
+
default: true
|
|
6291
|
+
});
|
|
6292
|
+
if (!shouldLogin) {
|
|
6293
|
+
konsola.warn('Login cancelled. You can login later using the "storyblok login" command.');
|
|
6294
|
+
return null;
|
|
6295
|
+
}
|
|
6296
|
+
return await performInteractiveLogin({ verbose, showWelcomeMessage: true });
|
|
6297
|
+
} catch (error) {
|
|
6298
|
+
konsola.br();
|
|
6299
|
+
handleError(error, verbose);
|
|
6300
|
+
return null;
|
|
6301
|
+
}
|
|
6302
|
+
}
|
|
6260
6303
|
const program$3 = getProgram();
|
|
6261
6304
|
program$3.command(`${commands.CREATE} [project-path]`).alias("c").description(`Scaffold a new project using Storyblok`).option("-t, --template <template>", "technology starter template").option("-b, --blueprint <blueprint>", "[DEPRECATED] use --template instead").option("--skip-space", "skip space creation").option("--token <token>", "Storyblok access token (skip space creation and use this token)").option(
|
|
6262
6305
|
"-r, --region <region>",
|
|
@@ -6278,20 +6321,38 @@ program$3.command(`${commands.CREATE} [project-path]`).alias("c").description(`S
|
|
|
6278
6321
|
}
|
|
6279
6322
|
const { state, initializeSession } = session();
|
|
6280
6323
|
await initializeSession();
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6324
|
+
let password;
|
|
6325
|
+
let region;
|
|
6326
|
+
if (state.region) {
|
|
6327
|
+
region = state.region;
|
|
6328
|
+
}
|
|
6329
|
+
if (!token && !options.skipSpace) {
|
|
6330
|
+
if (!requireAuthentication(state, verbose)) {
|
|
6331
|
+
const loginResult = await promptForLogin(verbose);
|
|
6332
|
+
if (!loginResult) {
|
|
6333
|
+
return;
|
|
6334
|
+
}
|
|
6335
|
+
await initializeSession();
|
|
6336
|
+
}
|
|
6337
|
+
const authenticatedState = state;
|
|
6338
|
+
password = authenticatedState.password;
|
|
6339
|
+
region = authenticatedState.region;
|
|
6340
|
+
if (options.region && options.region !== region) {
|
|
6341
|
+
handleError(new CommandError(`Cannot create space in region "${options.region}". Your account is configured for region "${region}". Space creation must use your account's region.`));
|
|
6342
|
+
return;
|
|
6343
|
+
}
|
|
6344
|
+
mapiClient({
|
|
6345
|
+
token: {
|
|
6346
|
+
accessToken: password
|
|
6347
|
+
},
|
|
6348
|
+
region
|
|
6349
|
+
});
|
|
6350
|
+
} else if (state.isLoggedIn && state.password) {
|
|
6351
|
+
password = state.password;
|
|
6352
|
+
if (state.region) {
|
|
6353
|
+
region = state.region;
|
|
6354
|
+
}
|
|
6288
6355
|
}
|
|
6289
|
-
mapiClient({
|
|
6290
|
-
token: {
|
|
6291
|
-
accessToken: password
|
|
6292
|
-
},
|
|
6293
|
-
region
|
|
6294
|
-
});
|
|
6295
6356
|
const spinnerBlueprints = new Spinner({
|
|
6296
6357
|
verbose: !isVitest
|
|
6297
6358
|
});
|
|
@@ -6374,10 +6435,26 @@ program$3.command(`${commands.CREATE} [project-path]`).alias("c").description(`S
|
|
|
6374
6435
|
throw new Error("User data is undefined");
|
|
6375
6436
|
}
|
|
6376
6437
|
userData = user;
|
|
6377
|
-
} catch
|
|
6378
|
-
konsola.error("Failed to fetch user info.
|
|
6379
|
-
|
|
6380
|
-
|
|
6438
|
+
} catch {
|
|
6439
|
+
konsola.error("Failed to fetch user info. Your session may have expired.");
|
|
6440
|
+
const loginResult = await promptForLogin(verbose);
|
|
6441
|
+
if (!loginResult) {
|
|
6442
|
+
konsola.br();
|
|
6443
|
+
return;
|
|
6444
|
+
}
|
|
6445
|
+
await initializeSession();
|
|
6446
|
+
const { password: newPassword, region: newRegion } = session().state;
|
|
6447
|
+
try {
|
|
6448
|
+
const user = await getUser(newPassword, newRegion);
|
|
6449
|
+
if (!user) {
|
|
6450
|
+
throw new Error("User data is undefined");
|
|
6451
|
+
}
|
|
6452
|
+
userData = user;
|
|
6453
|
+
} catch (retryError) {
|
|
6454
|
+
konsola.error("Failed to fetch user info after login.", retryError);
|
|
6455
|
+
konsola.br();
|
|
6456
|
+
return;
|
|
6457
|
+
}
|
|
6381
6458
|
}
|
|
6382
6459
|
const choices = [
|
|
6383
6460
|
{ name: "My personal account", value: "personal" }
|