@strapi/cloud-cli 4.25.1 → 4.25.2

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 CHANGED
@@ -132,7 +132,7 @@ async function saveLocalConfig(data) {
132
132
  await fse.writeJson(configFilePath, data, { encoding: "utf8", spaces: 2, mode: 384 });
133
133
  }
134
134
  const name = "@strapi/cloud-cli";
135
- const version = "4.25.0";
135
+ const version = "4.25.1";
136
136
  const description = "Commands to interact with the Strapi Cloud";
137
137
  const keywords = [
138
138
  "strapi",
@@ -176,7 +176,7 @@ const scripts = {
176
176
  watch: "pack-up watch"
177
177
  };
178
178
  const dependencies = {
179
- "@strapi/utils": "4.25.0",
179
+ "@strapi/utils": "4.25.1",
180
180
  axios: "1.6.0",
181
181
  chalk: "4.1.2",
182
182
  "cli-progress": "3.12.0",
@@ -201,8 +201,8 @@ const devDependencies = {
201
201
  "@types/cli-progress": "3.11.5",
202
202
  "@types/eventsource": "1.1.15",
203
203
  "@types/lodash": "^4.14.191",
204
- "eslint-config-custom": "4.25.0",
205
- tsconfig: "4.25.0"
204
+ "eslint-config-custom": "4.25.1",
205
+ tsconfig: "4.25.1"
206
206
  };
207
207
  const engines = {
208
208
  node: ">=18.0.0 <=20.x.x",
@@ -231,7 +231,7 @@ const packageJson = {
231
231
  engines
232
232
  };
233
233
  const VERSION = "v1";
234
- async function cloudApiFactory(token) {
234
+ async function cloudApiFactory({ logger }, token) {
235
235
  const localConfig = await getLocalConfig();
236
236
  const customHeaders = {
237
237
  "x-device-id": localConfig.deviceId,
@@ -284,8 +284,19 @@ async function cloudApiFactory(token) {
284
284
  getUserInfo() {
285
285
  return axiosCloudAPI.get("/user");
286
286
  },
287
- config() {
288
- return axiosCloudAPI.get("/config");
287
+ async config() {
288
+ try {
289
+ const response = await axiosCloudAPI.get("/config");
290
+ if (response.status !== 200) {
291
+ throw new Error("Error fetching cloud CLI config from the server.");
292
+ }
293
+ return response;
294
+ } catch (error) {
295
+ logger.debug(
296
+ "🥲 Oops! Couldn't retrieve the cloud CLI config from the server. Please try again."
297
+ );
298
+ throw error;
299
+ }
289
300
  },
290
301
  listProjects() {
291
302
  return axiosCloudAPI.get("/projects");
@@ -324,7 +335,7 @@ const strapiInfoSave = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defi
324
335
  }, Symbol.toStringTag, { value: "Module" }));
325
336
  let cliConfig;
326
337
  async function tokenServiceFactory({ logger }) {
327
- const cloudApiService = await cloudApiFactory();
338
+ const cloudApiService = await cloudApiFactory({ logger });
328
339
  async function saveToken(str) {
329
340
  const appConfig = await getLocalConfig();
330
341
  if (!appConfig) {
@@ -373,14 +384,17 @@ async function tokenServiceFactory({ logger }) {
373
384
  "There seems to be a problem with your login information. Please try logging in again."
374
385
  );
375
386
  }
387
+ return Promise.reject(new Error("Invalid token"));
376
388
  }
377
389
  return new Promise((resolve, reject) => {
378
390
  jwt.verify(idToken, getKey, (err) => {
379
391
  if (err) {
380
392
  reject(err);
381
- } else {
382
- resolve();
383
393
  }
394
+ if (decodedToken.payload.exp < Math.floor(Date.now() / 1e3)) {
395
+ reject(new Error("Token is expired"));
396
+ }
397
+ resolve();
384
398
  });
385
399
  });
386
400
  }
@@ -414,15 +428,15 @@ async function tokenServiceFactory({ logger }) {
414
428
  throw e;
415
429
  }
416
430
  }
417
- async function getValidToken() {
418
- const token = await retrieveToken();
419
- if (!token) {
420
- logger.log("No token found. Please login first.");
421
- return null;
422
- }
423
- if (!await isTokenValid(token)) {
424
- logger.log("Unable to proceed: Token is expired or not valid. Please login again.");
425
- return null;
431
+ async function getValidToken(ctx, loginAction2) {
432
+ let token = await retrieveToken();
433
+ while (!token || !await isTokenValid(token)) {
434
+ logger.log(
435
+ token ? "Oops! Your token seems expired or invalid. Please login again." : "We couldn't find a valid token. You need to be logged in to use this feature."
436
+ );
437
+ if (!await loginAction2(ctx))
438
+ return null;
439
+ token = await retrieveToken();
426
440
  }
427
441
  return token;
428
442
  }
@@ -556,17 +570,183 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
556
570
  local: strapiInfoSave,
557
571
  tokenServiceFactory
558
572
  }, Symbol.toStringTag, { value: "Module" }));
559
- async function handleError(ctx, error) {
573
+ const openModule$1 = import("open");
574
+ async function promptLogin(ctx) {
575
+ const response = await inquirer.prompt([
576
+ {
577
+ type: "confirm",
578
+ name: "login",
579
+ message: "Would you like to login?"
580
+ }
581
+ ]);
582
+ if (response.login) {
583
+ const loginSuccessful = await loginAction(ctx);
584
+ return loginSuccessful;
585
+ }
586
+ return false;
587
+ }
588
+ async function loginAction(ctx) {
589
+ const { logger } = ctx;
560
590
  const tokenService = await tokenServiceFactory(ctx);
591
+ const existingToken = await tokenService.retrieveToken();
592
+ const cloudApiService = await cloudApiFactory(ctx, existingToken || void 0);
593
+ const trackFailedLogin = async () => {
594
+ try {
595
+ await cloudApiService.track("didNotLogin", { loginMethod: "cli" });
596
+ } catch (e) {
597
+ logger.debug("Failed to track failed login", e);
598
+ }
599
+ };
600
+ if (existingToken) {
601
+ const isTokenValid = await tokenService.isTokenValid(existingToken);
602
+ if (isTokenValid) {
603
+ try {
604
+ const userInfo = await cloudApiService.getUserInfo();
605
+ const { email } = userInfo.data.data;
606
+ if (email) {
607
+ logger.log(`You are already logged into your account (${email}).`);
608
+ } else {
609
+ logger.log("You are already logged in.");
610
+ }
611
+ logger.log(
612
+ "To access your dashboard, please copy and paste the following URL into your web browser:"
613
+ );
614
+ logger.log(chalk.underline(`${apiConfig.dashboardBaseUrl}/projects`));
615
+ return true;
616
+ } catch (e) {
617
+ logger.debug("Failed to fetch user info", e);
618
+ }
619
+ }
620
+ }
621
+ let cliConfig2;
622
+ try {
623
+ logger.info("🔌 Connecting to the Strapi Cloud API...");
624
+ const config = await cloudApiService.config();
625
+ cliConfig2 = config.data;
626
+ } catch (e) {
627
+ logger.error("🥲 Oops! Something went wrong while logging you in. Please try again.");
628
+ logger.debug(e);
629
+ return false;
630
+ }
631
+ try {
632
+ await cloudApiService.track("willLoginAttempt", {});
633
+ } catch (e) {
634
+ logger.debug("Failed to track login attempt", e);
635
+ }
636
+ logger.debug("🔐 Creating device authentication request...", {
637
+ client_id: cliConfig2.clientId,
638
+ scope: cliConfig2.scope,
639
+ audience: cliConfig2.audience
640
+ });
641
+ const deviceAuthResponse = await axios.post(cliConfig2.deviceCodeAuthUrl, {
642
+ client_id: cliConfig2.clientId,
643
+ scope: cliConfig2.scope,
644
+ audience: cliConfig2.audience
645
+ }).catch((e) => {
646
+ logger.error("There was an issue with the authentication process. Please try again.");
647
+ if (e.message) {
648
+ logger.debug(e.message, e);
649
+ } else {
650
+ logger.debug(e);
651
+ }
652
+ });
653
+ openModule$1.then((open) => {
654
+ open.default(deviceAuthResponse.data.verification_uri_complete).catch((e) => {
655
+ logger.error("We encountered an issue opening the browser. Please try again later.");
656
+ logger.debug(e.message, e);
657
+ });
658
+ });
659
+ logger.log("If a browser tab does not open automatically, please follow the next steps:");
660
+ logger.log(
661
+ `1. Open this url in your device: ${deviceAuthResponse.data.verification_uri_complete}`
662
+ );
663
+ logger.log(
664
+ `2. Enter the following code: ${deviceAuthResponse.data.user_code} and confirm to login.
665
+ `
666
+ );
667
+ const tokenPayload = {
668
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
669
+ device_code: deviceAuthResponse.data.device_code,
670
+ client_id: cliConfig2.clientId
671
+ };
672
+ let isAuthenticated = false;
673
+ const authenticate = async () => {
674
+ const spinner = logger.spinner("Waiting for authentication");
675
+ spinner.start();
676
+ const spinnerFail = () => spinner.fail("Authentication failed!");
677
+ while (!isAuthenticated) {
678
+ try {
679
+ const tokenResponse = await axios.post(cliConfig2.tokenUrl, tokenPayload);
680
+ const authTokenData = tokenResponse.data;
681
+ if (tokenResponse.status === 200) {
682
+ try {
683
+ logger.debug("🔐 Validating token...");
684
+ await tokenService.validateToken(authTokenData.id_token, cliConfig2.jwksUrl);
685
+ logger.debug("🔐 Token validation successful!");
686
+ } catch (e) {
687
+ logger.debug(e);
688
+ spinnerFail();
689
+ throw new Error("Unable to proceed: Token validation failed");
690
+ }
691
+ logger.debug("🔍 Fetching user information...");
692
+ const cloudApiServiceWithToken = await cloudApiFactory(ctx, authTokenData.access_token);
693
+ await cloudApiServiceWithToken.getUserInfo();
694
+ logger.debug("🔍 User information fetched successfully!");
695
+ try {
696
+ logger.debug("📝 Saving login information...");
697
+ await tokenService.saveToken(authTokenData.access_token);
698
+ logger.debug("📝 Login information saved successfully!");
699
+ isAuthenticated = true;
700
+ } catch (e) {
701
+ logger.error(
702
+ "There was a problem saving your login information. Please try logging in again."
703
+ );
704
+ logger.debug(e);
705
+ spinnerFail();
706
+ return false;
707
+ }
708
+ }
709
+ } catch (e) {
710
+ if (e.message === "Unable to proceed: Token validation failed") {
711
+ logger.error(
712
+ "There seems to be a problem with your login information. Please try logging in again."
713
+ );
714
+ spinnerFail();
715
+ await trackFailedLogin();
716
+ return false;
717
+ }
718
+ if (e.response?.data.error && !["authorization_pending", "slow_down"].includes(e.response.data.error)) {
719
+ logger.debug(e);
720
+ spinnerFail();
721
+ await trackFailedLogin();
722
+ return false;
723
+ }
724
+ await new Promise((resolve) => {
725
+ setTimeout(resolve, deviceAuthResponse.data.interval * 1e3);
726
+ });
727
+ }
728
+ }
729
+ spinner.succeed("Authentication successful!");
730
+ logger.log("You are now logged into Strapi Cloud.");
731
+ logger.log(
732
+ "To access your dashboard, please copy and paste the following URL into your web browser:"
733
+ );
734
+ logger.log(chalk.underline(`${apiConfig.dashboardBaseUrl}/projects`));
735
+ try {
736
+ await cloudApiService.track("didLogin", { loginMethod: "cli" });
737
+ } catch (e) {
738
+ logger.debug("Failed to track login", e);
739
+ }
740
+ };
741
+ await authenticate();
742
+ return isAuthenticated;
743
+ }
744
+ async function handleError(ctx, error) {
561
745
  const { logger } = ctx;
562
746
  logger.debug(error);
563
747
  if (error instanceof AxiosError) {
564
748
  const errorMessage = typeof error.response?.data === "string" ? error.response.data : null;
565
749
  switch (error.response?.status) {
566
- case 401:
567
- logger.error("Your session has expired. Please log in again.");
568
- await tokenService.eraseToken();
569
- return;
570
750
  case 403:
571
751
  logger.error(
572
752
  errorMessage || "You do not have permission to create a project. Please contact support for assistance."
@@ -592,28 +772,44 @@ async function handleError(ctx, error) {
592
772
  "We encountered an issue while creating your project. Please try again in a moment. If the problem persists, contact support for assistance."
593
773
  );
594
774
  }
595
- const action$3 = async (ctx) => {
775
+ async function createProject$1(ctx, cloudApi, projectInput) {
596
776
  const { logger } = ctx;
597
- const { getValidToken } = await tokenServiceFactory(ctx);
598
- const token = await getValidToken();
777
+ const spinner = logger.spinner("Setting up your project...").start();
778
+ try {
779
+ const { data } = await cloudApi.createProject(projectInput);
780
+ await save({ project: data });
781
+ spinner.succeed("Project created successfully!");
782
+ return data;
783
+ } catch (e) {
784
+ spinner.fail("An error occurred while creating the project on Strapi Cloud.");
785
+ throw e;
786
+ }
787
+ }
788
+ const action$2 = async (ctx) => {
789
+ const { logger } = ctx;
790
+ const { getValidToken, eraseToken } = await tokenServiceFactory(ctx);
791
+ const token = await getValidToken(ctx, promptLogin);
599
792
  if (!token) {
600
793
  return;
601
794
  }
602
- const cloudApi = await cloudApiFactory(token);
795
+ const cloudApi = await cloudApiFactory(ctx, token);
603
796
  const { data: config } = await cloudApi.config();
604
797
  const { questions, defaults: defaultValues } = config.projectCreation;
605
798
  const projectAnswersDefaulted = defaults(defaultValues);
606
799
  const projectAnswers = await inquirer.prompt(questions);
607
800
  const projectInput = projectAnswersDefaulted(projectAnswers);
608
- const spinner = logger.spinner("Setting up your project...").start();
609
801
  try {
610
- const { data } = await cloudApi.createProject(projectInput);
611
- await save({ project: data });
612
- spinner.succeed("Project created successfully!");
613
- return data;
802
+ return await createProject$1(ctx, cloudApi, projectInput);
614
803
  } catch (e) {
615
- spinner.fail("Failed to create project on Strapi Cloud.");
616
- await handleError(ctx, e);
804
+ if (e instanceof AxiosError && e.response?.status === 401) {
805
+ logger.warn("Oops! Your session has expired. Please log in again to retry.");
806
+ await eraseToken();
807
+ if (await promptLogin(ctx)) {
808
+ return await createProject$1(ctx, cloudApi, projectInput);
809
+ }
810
+ } else {
811
+ await handleError(ctx, e);
812
+ }
617
813
  }
618
814
  };
619
815
  function notificationServiceFactory({ logger }) {
@@ -741,7 +937,7 @@ const buildLogsServiceFactory = ({ logger }) => {
741
937
  };
742
938
  };
743
939
  async function upload(ctx, project, token, maxProjectFileSize) {
744
- const cloudApi = await cloudApiFactory(token);
940
+ const cloudApi = await cloudApiFactory(ctx, token);
745
941
  try {
746
942
  const storagePath = await getTmpStoragePath();
747
943
  const projectFolder = path__default.resolve(process.cwd());
@@ -832,7 +1028,7 @@ async function getProject(ctx) {
832
1028
  const { project } = await retrieve();
833
1029
  if (!project) {
834
1030
  try {
835
- return await action$3(ctx);
1031
+ return await action$2(ctx);
836
1032
  } catch (e) {
837
1033
  ctx.logger.error("An error occurred while deploying the project. Please try again later.");
838
1034
  ctx.logger.debug(e);
@@ -841,10 +1037,9 @@ async function getProject(ctx) {
841
1037
  }
842
1038
  return project;
843
1039
  }
844
- const action$2 = async (ctx) => {
1040
+ const action$1 = async (ctx) => {
845
1041
  const { getValidToken } = await tokenServiceFactory(ctx);
846
- const cloudApiService = await cloudApiFactory();
847
- const token = await getValidToken();
1042
+ const token = await getValidToken(ctx, promptLogin);
848
1043
  if (!token) {
849
1044
  return;
850
1045
  }
@@ -852,6 +1047,7 @@ const action$2 = async (ctx) => {
852
1047
  if (!project) {
853
1048
  return;
854
1049
  }
1050
+ const cloudApiService = await cloudApiFactory(ctx);
855
1051
  try {
856
1052
  await cloudApiService.track("willDeployWithCLI", { projectInternalName: project.name });
857
1053
  } catch (e) {
@@ -916,183 +1112,27 @@ const runAction = (name2, action2) => (...args) => {
916
1112
  });
917
1113
  };
918
1114
  const command$3 = ({ command: command2, ctx }) => {
919
- command2.command("cloud:deploy").alias("deploy").description("Deploy a Strapi Cloud project").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("deploy", action$2)(ctx));
1115
+ command2.command("cloud:deploy").alias("deploy").description("Deploy a Strapi Cloud project").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("deploy", action$1)(ctx));
920
1116
  };
921
1117
  const deployProject = {
922
1118
  name: "deploy-project",
923
1119
  description: "Deploy a Strapi Cloud project",
924
- action: action$2,
1120
+ action: action$1,
925
1121
  command: command$3
926
1122
  };
927
- const openModule = import("open");
928
- const action$1 = async (ctx) => {
929
- const { logger } = ctx;
930
- const tokenService = await tokenServiceFactory(ctx);
931
- const existingToken = await tokenService.retrieveToken();
932
- const cloudApiService = await cloudApiFactory(existingToken || void 0);
933
- const trackFailedLogin = async () => {
934
- try {
935
- await cloudApiService.track("didNotLogin", { loginMethod: "cli" });
936
- } catch (e) {
937
- logger.debug("Failed to track failed login", e);
938
- }
939
- };
940
- if (existingToken) {
941
- const isTokenValid = await tokenService.isTokenValid(existingToken);
942
- if (isTokenValid) {
943
- try {
944
- const userInfo = await cloudApiService.getUserInfo();
945
- const { email } = userInfo.data.data;
946
- if (email) {
947
- logger.log(`You are already logged into your account (${email}).`);
948
- } else {
949
- logger.log("You are already logged in.");
950
- }
951
- logger.log(
952
- "To access your dashboard, please copy and paste the following URL into your web browser:"
953
- );
954
- logger.log(chalk.underline(`${apiConfig.dashboardBaseUrl}/projects`));
955
- return true;
956
- } catch (e) {
957
- logger.debug("Failed to fetch user info", e);
958
- }
959
- }
960
- }
961
- let cliConfig2;
962
- try {
963
- logger.info("🔌 Connecting to the Strapi Cloud API...");
964
- const config = await cloudApiService.config();
965
- cliConfig2 = config.data;
966
- } catch (e) {
967
- logger.error("🥲 Oops! Something went wrong while logging you in. Please try again.");
968
- logger.debug(e);
969
- return false;
970
- }
971
- try {
972
- await cloudApiService.track("willLoginAttempt", {});
973
- } catch (e) {
974
- logger.debug("Failed to track login attempt", e);
975
- }
976
- logger.debug("🔐 Creating device authentication request...", {
977
- client_id: cliConfig2.clientId,
978
- scope: cliConfig2.scope,
979
- audience: cliConfig2.audience
980
- });
981
- const deviceAuthResponse = await axios.post(cliConfig2.deviceCodeAuthUrl, {
982
- client_id: cliConfig2.clientId,
983
- scope: cliConfig2.scope,
984
- audience: cliConfig2.audience
985
- }).catch((e) => {
986
- logger.error("There was an issue with the authentication process. Please try again.");
987
- if (e.message) {
988
- logger.debug(e.message, e);
989
- } else {
990
- logger.debug(e);
991
- }
992
- });
993
- openModule.then((open) => {
994
- open.default(deviceAuthResponse.data.verification_uri_complete).catch((e) => {
995
- logger.error("We encountered an issue opening the browser. Please try again later.");
996
- logger.debug(e.message, e);
997
- });
998
- });
999
- logger.log("If a browser tab does not open automatically, please follow the next steps:");
1000
- logger.log(
1001
- `1. Open this url in your device: ${deviceAuthResponse.data.verification_uri_complete}`
1002
- );
1003
- logger.log(
1004
- `2. Enter the following code: ${deviceAuthResponse.data.user_code} and confirm to login.
1005
- `
1006
- );
1007
- const tokenPayload = {
1008
- grant_type: "urn:ietf:params:oauth:grant-type:device_code",
1009
- device_code: deviceAuthResponse.data.device_code,
1010
- client_id: cliConfig2.clientId
1011
- };
1012
- let isAuthenticated = false;
1013
- const authenticate = async () => {
1014
- const spinner = logger.spinner("Waiting for authentication");
1015
- spinner.start();
1016
- const spinnerFail = () => spinner.fail("Authentication failed!");
1017
- while (!isAuthenticated) {
1018
- try {
1019
- const tokenResponse = await axios.post(cliConfig2.tokenUrl, tokenPayload);
1020
- const authTokenData = tokenResponse.data;
1021
- if (tokenResponse.status === 200) {
1022
- try {
1023
- logger.debug("🔐 Validating token...");
1024
- await tokenService.validateToken(authTokenData.id_token, cliConfig2.jwksUrl);
1025
- logger.debug("🔐 Token validation successful!");
1026
- } catch (e) {
1027
- logger.debug(e);
1028
- spinnerFail();
1029
- throw new Error("Unable to proceed: Token validation failed");
1030
- }
1031
- logger.debug("🔍 Fetching user information...");
1032
- const cloudApiServiceWithToken = await cloudApiFactory(authTokenData.access_token);
1033
- await cloudApiServiceWithToken.getUserInfo();
1034
- logger.debug("🔍 User information fetched successfully!");
1035
- try {
1036
- logger.debug("📝 Saving login information...");
1037
- await tokenService.saveToken(authTokenData.access_token);
1038
- logger.debug("📝 Login information saved successfully!");
1039
- isAuthenticated = true;
1040
- } catch (e) {
1041
- logger.error(
1042
- "There was a problem saving your login information. Please try logging in again."
1043
- );
1044
- logger.debug(e);
1045
- spinnerFail();
1046
- return false;
1047
- }
1048
- }
1049
- } catch (e) {
1050
- if (e.message === "Unable to proceed: Token validation failed") {
1051
- logger.error(
1052
- "There seems to be a problem with your login information. Please try logging in again."
1053
- );
1054
- spinnerFail();
1055
- await trackFailedLogin();
1056
- return false;
1057
- }
1058
- if (e.response?.data.error && !["authorization_pending", "slow_down"].includes(e.response.data.error)) {
1059
- logger.debug(e);
1060
- spinnerFail();
1061
- await trackFailedLogin();
1062
- return false;
1063
- }
1064
- await new Promise((resolve) => {
1065
- setTimeout(resolve, deviceAuthResponse.data.interval * 1e3);
1066
- });
1067
- }
1068
- }
1069
- spinner.succeed("Authentication successful!");
1070
- logger.log("You are now logged into Strapi Cloud.");
1071
- logger.log(
1072
- "To access your dashboard, please copy and paste the following URL into your web browser:"
1073
- );
1074
- logger.log(chalk.underline(`${apiConfig.dashboardBaseUrl}/projects`));
1075
- try {
1076
- await cloudApiService.track("didLogin", { loginMethod: "cli" });
1077
- } catch (e) {
1078
- logger.debug("Failed to track login", e);
1079
- }
1080
- };
1081
- await authenticate();
1082
- return isAuthenticated;
1083
- };
1084
1123
  const command$2 = ({ command: command2, ctx }) => {
1085
1124
  command2.command("cloud:login").alias("login").description("Strapi Cloud Login").addHelpText(
1086
1125
  "after",
1087
1126
  "\nAfter running this command, you will be prompted to enter your authentication information."
1088
- ).option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("login", action$1)(ctx));
1127
+ ).option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("login", loginAction)(ctx));
1089
1128
  };
1090
1129
  const login = {
1091
1130
  name: "login",
1092
1131
  description: "Strapi Cloud Login",
1093
- action: action$1,
1132
+ action: loginAction,
1094
1133
  command: command$2
1095
1134
  };
1135
+ const openModule = import("open");
1096
1136
  const action = async (ctx) => {
1097
1137
  const { logger } = ctx;
1098
1138
  const { retrieveToken, eraseToken } = await tokenServiceFactory(ctx);
@@ -1101,9 +1141,21 @@ const action = async (ctx) => {
1101
1141
  logger.log("You're already logged out.");
1102
1142
  return;
1103
1143
  }
1104
- const cloudApiService = await cloudApiFactory(token);
1144
+ const cloudApiService = await cloudApiFactory(ctx, token);
1145
+ const config = await cloudApiService.config();
1146
+ const cliConfig2 = config.data;
1105
1147
  try {
1106
1148
  await eraseToken();
1149
+ openModule.then((open) => {
1150
+ open.default(
1151
+ `${cliConfig2.baseUrl}/oidc/logout?client_id=${encodeURIComponent(
1152
+ cliConfig2.clientId
1153
+ )}&logout_hint=${encodeURIComponent(token)}
1154
+ `
1155
+ ).catch((e) => {
1156
+ logger.debug(e.message, e);
1157
+ });
1158
+ });
1107
1159
  logger.log(
1108
1160
  "🔌 You have been logged out from the CLI. If you are on a shared computer, please make sure to log out from the Strapi Cloud Dashboard as well."
1109
1161
  );
@@ -1127,12 +1179,12 @@ const logout = {
1127
1179
  command: command$1
1128
1180
  };
1129
1181
  const command = ({ command: command2, ctx }) => {
1130
- command2.command("cloud:create-project").description("Create a Strapi Cloud project").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("cloud:create-project", action$3)(ctx));
1182
+ command2.command("cloud:create-project").description("Create a Strapi Cloud project").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("cloud:create-project", action$2)(ctx));
1131
1183
  };
1132
1184
  const createProject = {
1133
1185
  name: "create-project",
1134
1186
  description: "Create a new project",
1135
- action: action$3,
1187
+ action: action$2,
1136
1188
  command
1137
1189
  };
1138
1190
  const cli = {