@strapi/cloud-cli 0.0.0-experimental.f77206734629a2b88793a7a8abca40388843c656 → 0.0.0-next.b11829e6c6aacb45bc1ec2f341609d04d88080d2

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
@@ -1,11 +1,12 @@
1
1
  import crypto$1 from "crypto";
2
- import * as fs from "fs";
3
- import fs__default from "fs";
2
+ import fse from "fs-extra";
4
3
  import * as path from "path";
5
4
  import path__default from "path";
5
+ import chalk from "chalk";
6
6
  import axios, { AxiosError } from "axios";
7
7
  import * as crypto from "node:crypto";
8
8
  import { env } from "@strapi/utils";
9
+ import * as fs from "fs";
9
10
  import * as tar from "tar";
10
11
  import { minimatch } from "minimatch";
11
12
  import inquirer from "inquirer";
@@ -14,7 +15,6 @@ import os from "os";
14
15
  import XDGAppPaths from "xdg-app-paths";
15
16
  import jwksClient from "jwks-rsa";
16
17
  import jwt from "jsonwebtoken";
17
- import chalk from "chalk";
18
18
  import stringify from "fast-safe-stringify";
19
19
  import ora from "ora";
20
20
  import * as cliProgress from "cli-progress";
@@ -23,7 +23,8 @@ import fs$1 from "fs/promises";
23
23
  import pkgUp from "pkg-up";
24
24
  import * as yup from "yup";
25
25
  const apiConfig = {
26
- apiBaseUrl: env("STRAPI_CLI_CLOUD_API", "https://cli.cloud.strapi.io")
26
+ apiBaseUrl: env("STRAPI_CLI_CLOUD_API", "https://cloud-cli-api.strapi.io"),
27
+ dashboardBaseUrl: env("STRAPI_CLI_CLOUD_DASHBOARD", "https://cloud.strapi.io")
27
28
  };
28
29
  const IGNORED_PATTERNS = [
29
30
  "**/.git/**",
@@ -78,7 +79,7 @@ const readGitignore = (folderPath) => {
78
79
  if (!fs.existsSync(gitignorePath))
79
80
  return [];
80
81
  const gitignoreContent = fs.readFileSync(gitignorePath, "utf8");
81
- return gitignoreContent.split("\n").filter((line) => Boolean(line.trim()) && !line.startsWith("#"));
82
+ return gitignoreContent.split(/\r?\n/).filter((line) => Boolean(line.trim()) && !line.startsWith("#"));
82
83
  };
83
84
  const compressFilesToTar = async (storagePath, folderToCompress, filename) => {
84
85
  const ignorePatterns = readGitignore(folderToCompress);
@@ -93,48 +94,45 @@ const compressFilesToTar = async (storagePath, folderToCompress, filename) => {
93
94
  };
94
95
  const APP_FOLDER_NAME = "com.strapi.cli";
95
96
  const CONFIG_FILENAME = "config.json";
96
- function checkDirectoryExists(directoryPath) {
97
+ async function checkDirectoryExists(directoryPath) {
97
98
  try {
98
- return fs__default.lstatSync(directoryPath).isDirectory();
99
+ const fsStat = await fse.lstat(directoryPath);
100
+ return fsStat.isDirectory();
99
101
  } catch (e) {
100
102
  return false;
101
103
  }
102
104
  }
103
- function getTmpStoragePath() {
105
+ async function getTmpStoragePath() {
104
106
  const storagePath = path__default.join(os.tmpdir(), APP_FOLDER_NAME);
105
- if (!checkDirectoryExists(storagePath)) {
106
- fs__default.mkdirSync(storagePath, { recursive: true });
107
- }
107
+ await fse.ensureDir(storagePath);
108
108
  return storagePath;
109
109
  }
110
- function getConfigPath() {
110
+ async function getConfigPath() {
111
111
  const configDirs = XDGAppPaths(APP_FOLDER_NAME).configDirs();
112
112
  const configPath = configDirs.find(checkDirectoryExists);
113
113
  if (!configPath) {
114
- fs__default.mkdirSync(configDirs[0], { recursive: true });
114
+ await fse.ensureDir(configDirs[0]);
115
115
  return configDirs[0];
116
116
  }
117
117
  return configPath;
118
118
  }
119
- function getLocalConfig() {
120
- const configPath = getConfigPath();
119
+ async function getLocalConfig() {
120
+ const configPath = await getConfigPath();
121
121
  const configFilePath = path__default.join(configPath, CONFIG_FILENAME);
122
- if (!fs__default.existsSync(configFilePath)) {
123
- return {};
124
- }
122
+ await fse.ensureFile(configFilePath);
125
123
  try {
126
- return JSON.parse(fs__default.readFileSync(configFilePath, "utf8"));
124
+ return await fse.readJSON(configFilePath, { encoding: "utf8", throws: true });
127
125
  } catch (e) {
128
126
  return {};
129
127
  }
130
128
  }
131
- function saveLocalConfig(data) {
132
- const configPath = getConfigPath();
129
+ async function saveLocalConfig(data) {
130
+ const configPath = await getConfigPath();
133
131
  const configFilePath = path__default.join(configPath, CONFIG_FILENAME);
134
- fs__default.writeFileSync(configFilePath, JSON.stringify(data), { encoding: "utf8", mode: 384 });
132
+ await fse.writeJson(configFilePath, data, { encoding: "utf8", spaces: 2, mode: 384 });
135
133
  }
136
134
  const name = "@strapi/cloud-cli";
137
- const version = "4.24.3";
135
+ const version = "4.25.0";
138
136
  const description = "Commands to interact with the Strapi Cloud";
139
137
  const keywords = [
140
138
  "strapi",
@@ -178,13 +176,14 @@ const scripts = {
178
176
  watch: "pack-up watch"
179
177
  };
180
178
  const dependencies = {
181
- "@strapi/utils": "4.24.3",
179
+ "@strapi/utils": "4.25.0",
182
180
  axios: "1.6.0",
183
181
  chalk: "4.1.2",
184
182
  "cli-progress": "3.12.0",
185
183
  commander: "8.3.0",
186
184
  eventsource: "2.0.2",
187
185
  "fast-safe-stringify": "2.1.1",
186
+ "fs-extra": "10.0.0",
188
187
  inquirer: "8.2.5",
189
188
  jsonwebtoken: "9.0.0",
190
189
  "jwks-rsa": "3.1.0",
@@ -202,8 +201,8 @@ const devDependencies = {
202
201
  "@types/cli-progress": "3.11.5",
203
202
  "@types/eventsource": "1.1.15",
204
203
  "@types/lodash": "^4.14.191",
205
- "eslint-config-custom": "4.24.3",
206
- tsconfig: "4.24.3"
204
+ "eslint-config-custom": "4.25.0",
205
+ tsconfig: "4.25.0"
207
206
  };
208
207
  const engines = {
209
208
  node: ">=18.0.0 <=20.x.x",
@@ -232,8 +231,8 @@ const packageJson = {
232
231
  engines
233
232
  };
234
233
  const VERSION = "v1";
235
- function cloudApiFactory(token) {
236
- const localConfig = getLocalConfig();
234
+ async function cloudApiFactory(token) {
235
+ const localConfig = await getLocalConfig();
237
236
  const customHeaders = {
238
237
  "x-device-id": localConfig.deviceId,
239
238
  "x-app-version": packageJson.version,
@@ -256,7 +255,7 @@ function cloudApiFactory(token) {
256
255
  deploy({ filePath, project }, { onUploadProgress }) {
257
256
  return axiosCloudAPI.post(
258
257
  `/deploy/${project.name}`,
259
- { file: fs.createReadStream(filePath) },
258
+ { file: fse.createReadStream(filePath) },
260
259
  {
261
260
  headers: {
262
261
  "Content-Type": "multipart/form-data"
@@ -300,53 +299,48 @@ function cloudApiFactory(token) {
300
299
  };
301
300
  }
302
301
  const LOCAL_SAVE_FILENAME = ".strapi-cloud.json";
303
- function save(data, { directoryPath } = {}) {
304
- const storedData = { ...retrieve(), ...data };
302
+ async function save(data, { directoryPath } = {}) {
303
+ const alreadyInFileData = await retrieve({ directoryPath });
304
+ const storedData = { ...alreadyInFileData, ...data };
305
305
  const pathToFile = path__default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
306
- if (!fs__default.existsSync(path__default.dirname(pathToFile))) {
307
- fs__default.mkdirSync(path__default.dirname(pathToFile), { recursive: true });
308
- }
309
- fs__default.writeFileSync(pathToFile, JSON.stringify(storedData), "utf8");
306
+ await fse.ensureDir(path__default.dirname(pathToFile));
307
+ await fse.writeJson(pathToFile, storedData, { encoding: "utf8" });
310
308
  }
311
- function retrieve({ directoryPath } = {}) {
309
+ async function retrieve({
310
+ directoryPath
311
+ } = {}) {
312
312
  const pathToFile = path__default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
313
- if (!fs__default.existsSync(pathToFile)) {
313
+ const pathExists = await fse.pathExists(pathToFile);
314
+ if (!pathExists) {
314
315
  return {};
315
316
  }
316
- return JSON.parse(fs__default.readFileSync(pathToFile, "utf8"));
317
- }
318
- function erase({ directoryPath } = {}) {
319
- const pathToFile = path__default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
320
- if (fs__default.existsSync(pathToFile)) {
321
- fs__default.unlinkSync(pathToFile);
322
- }
317
+ return fse.readJSON(pathToFile, { encoding: "utf8" });
323
318
  }
324
319
  const strapiInfoSave = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
325
320
  __proto__: null,
326
321
  LOCAL_SAVE_FILENAME,
327
- erase,
328
322
  retrieve,
329
323
  save
330
324
  }, Symbol.toStringTag, { value: "Module" }));
331
- const cloudApiService = cloudApiFactory();
332
325
  let cliConfig;
333
- function tokenServiceFactory({ logger }) {
334
- function saveToken(str) {
335
- const appConfig = getLocalConfig();
326
+ async function tokenServiceFactory({ logger }) {
327
+ const cloudApiService = await cloudApiFactory();
328
+ async function saveToken(str) {
329
+ const appConfig = await getLocalConfig();
336
330
  if (!appConfig) {
337
331
  logger.error("There was a problem saving your token. Please try again.");
338
332
  return;
339
333
  }
340
334
  appConfig.token = str;
341
335
  try {
342
- saveLocalConfig(appConfig);
343
- } catch (error) {
344
- logger.debug(error);
336
+ await saveLocalConfig(appConfig);
337
+ } catch (e) {
338
+ logger.debug(e);
345
339
  logger.error("There was a problem saving your token. Please try again.");
346
340
  }
347
341
  }
348
342
  async function retrieveToken() {
349
- const appConfig = getLocalConfig();
343
+ const appConfig = await getLocalConfig();
350
344
  if (appConfig.token) {
351
345
  if (await isTokenValid(appConfig.token)) {
352
346
  return appConfig.token;
@@ -359,9 +353,9 @@ function tokenServiceFactory({ logger }) {
359
353
  jwksUri: jwksUrl
360
354
  });
361
355
  const getKey = (header, callback) => {
362
- client.getSigningKey(header.kid, (err, key) => {
363
- if (err) {
364
- callback(err);
356
+ client.getSigningKey(header.kid, (e, key) => {
357
+ if (e) {
358
+ callback(e);
365
359
  } else if (key) {
366
360
  const publicKey = "publicKey" in key ? key.publicKey : key.rsaPublicKey;
367
361
  callback(null, publicKey);
@@ -399,24 +393,25 @@ function tokenServiceFactory({ logger }) {
399
393
  return true;
400
394
  }
401
395
  return false;
402
- } catch (error) {
403
- logger.debug(error);
396
+ } catch (e) {
397
+ logger.debug(e);
404
398
  return false;
405
399
  }
406
400
  }
407
- function eraseToken() {
408
- const appConfig = getLocalConfig();
401
+ async function eraseToken() {
402
+ const appConfig = await getLocalConfig();
409
403
  if (!appConfig) {
410
404
  return;
411
405
  }
412
406
  delete appConfig.token;
413
407
  try {
414
- saveLocalConfig(appConfig);
415
- } catch (error) {
416
- logger.debug(error);
408
+ await saveLocalConfig(appConfig);
409
+ } catch (e) {
410
+ logger.debug(e);
417
411
  logger.error(
418
412
  "There was an issue removing your login information. Please try logging out again."
419
413
  );
414
+ throw e;
420
415
  }
421
416
  }
422
417
  async function getValidToken() {
@@ -561,29 +556,36 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
561
556
  local: strapiInfoSave,
562
557
  tokenServiceFactory
563
558
  }, Symbol.toStringTag, { value: "Module" }));
564
- function handleError(ctx, error) {
565
- const tokenService = tokenServiceFactory(ctx);
559
+ async function handleError(ctx, error) {
560
+ const tokenService = await tokenServiceFactory(ctx);
566
561
  const { logger } = ctx;
567
562
  logger.debug(error);
568
563
  if (error instanceof AxiosError) {
564
+ const errorMessage = typeof error.response?.data === "string" ? error.response.data : null;
569
565
  switch (error.response?.status) {
570
566
  case 401:
571
567
  logger.error("Your session has expired. Please log in again.");
572
- tokenService.eraseToken();
568
+ await tokenService.eraseToken();
573
569
  return;
574
570
  case 403:
575
571
  logger.error(
576
- error.response.data || "You do not have permission to create a project. Please contact support for assistance."
572
+ errorMessage || "You do not have permission to create a project. Please contact support for assistance."
577
573
  );
578
574
  return;
579
575
  case 400:
580
- logger.error("Invalid input. Please check your inputs and try again.");
576
+ logger.error(errorMessage || "Invalid input. Please check your inputs and try again.");
581
577
  return;
582
578
  case 503:
583
579
  logger.error(
584
580
  "Strapi Cloud project creation is currently unavailable. Please try again later."
585
581
  );
586
582
  return;
583
+ default:
584
+ if (errorMessage) {
585
+ logger.error(errorMessage);
586
+ return;
587
+ }
588
+ break;
587
589
  }
588
590
  }
589
591
  logger.error(
@@ -592,12 +594,12 @@ function handleError(ctx, error) {
592
594
  }
593
595
  const action$3 = async (ctx) => {
594
596
  const { logger } = ctx;
595
- const { getValidToken } = tokenServiceFactory(ctx);
597
+ const { getValidToken } = await tokenServiceFactory(ctx);
596
598
  const token = await getValidToken();
597
599
  if (!token) {
598
600
  return;
599
601
  }
600
- const cloudApi = cloudApiFactory(token);
602
+ const cloudApi = await cloudApiFactory(token);
601
603
  const { data: config } = await cloudApi.config();
602
604
  const { questions, defaults: defaultValues } = config.projectCreation;
603
605
  const projectAnswersDefaulted = defaults(defaultValues);
@@ -606,12 +608,12 @@ const action$3 = async (ctx) => {
606
608
  const spinner = logger.spinner("Setting up your project...").start();
607
609
  try {
608
610
  const { data } = await cloudApi.createProject(projectInput);
609
- save({ project: data });
611
+ await save({ project: data });
610
612
  spinner.succeed("Project created successfully!");
611
613
  return data;
612
614
  } catch (e) {
613
615
  spinner.fail("Failed to create project on Strapi Cloud.");
614
- handleError(ctx, e);
616
+ await handleError(ctx, e);
615
617
  }
616
618
  };
617
619
  function notificationServiceFactory({ logger }) {
@@ -739,9 +741,9 @@ const buildLogsServiceFactory = ({ logger }) => {
739
741
  };
740
742
  };
741
743
  async function upload(ctx, project, token, maxProjectFileSize) {
742
- const cloudApi = cloudApiFactory(token);
744
+ const cloudApi = await cloudApiFactory(token);
743
745
  try {
744
- const storagePath = getTmpStoragePath();
746
+ const storagePath = await getTmpStoragePath();
745
747
  const projectFolder = path__default.resolve(process.cwd());
746
748
  const packageJson2 = await loadPkg(ctx);
747
749
  if (!packageJson2) {
@@ -772,11 +774,18 @@ async function upload(ctx, project, token, maxProjectFileSize) {
772
774
  process.exit(1);
773
775
  }
774
776
  const tarFilePath = path__default.resolve(storagePath, compressedFilename);
775
- const fileStats = fs__default.statSync(tarFilePath);
777
+ const fileStats = await fse.stat(tarFilePath);
776
778
  if (fileStats.size > maxProjectFileSize) {
777
- return ctx.logger.log(
779
+ ctx.logger.log(
778
780
  "Unable to proceed: Your project is too big to be transferred, please use a git repo instead."
779
781
  );
782
+ try {
783
+ await fse.remove(tarFilePath);
784
+ } catch (e) {
785
+ ctx.logger.log("Unable to remove file: ", tarFilePath);
786
+ ctx.logger.debug(e);
787
+ }
788
+ return;
780
789
  }
781
790
  ctx.logger.info("🚀 Uploading project...");
782
791
  const progressBar = ctx.logger.progressBar(100, "Upload Progress");
@@ -810,7 +819,7 @@ async function upload(ctx, project, token, maxProjectFileSize) {
810
819
  }
811
820
  ctx.logger.debug(e);
812
821
  } finally {
813
- fs__default.rmSync(tarFilePath, { force: true });
822
+ await fse.remove(tarFilePath);
814
823
  }
815
824
  process.exit(0);
816
825
  } catch (e) {
@@ -820,7 +829,7 @@ async function upload(ctx, project, token, maxProjectFileSize) {
820
829
  }
821
830
  }
822
831
  async function getProject(ctx) {
823
- const { project } = retrieve();
832
+ const { project } = await retrieve();
824
833
  if (!project) {
825
834
  try {
826
835
  return await action$3(ctx);
@@ -833,7 +842,8 @@ async function getProject(ctx) {
833
842
  return project;
834
843
  }
835
844
  const action$2 = async (ctx) => {
836
- const { getValidToken } = tokenServiceFactory(ctx);
845
+ const { getValidToken } = await tokenServiceFactory(ctx);
846
+ const cloudApiService = await cloudApiFactory();
837
847
  const token = await getValidToken();
838
848
  if (!token) {
839
849
  return;
@@ -842,10 +852,14 @@ const action$2 = async (ctx) => {
842
852
  if (!project) {
843
853
  return;
844
854
  }
855
+ try {
856
+ await cloudApiService.track("willDeployWithCLI", { projectInternalName: project.name });
857
+ } catch (e) {
858
+ ctx.logger.debug("Failed to track willDeploy", e);
859
+ }
845
860
  const notificationService = notificationServiceFactory(ctx);
846
861
  const buildLogsService = buildLogsServiceFactory(ctx);
847
- const cloudApiService2 = cloudApiFactory();
848
- const { data: cliConfig2 } = await cloudApiService2.config();
862
+ const { data: cliConfig2 } = await cloudApiService.config();
849
863
  let maxSize = parseInt(cliConfig2.maxProjectFileSize, 10);
850
864
  if (Number.isNaN(maxSize)) {
851
865
  ctx.logger.debug(
@@ -854,9 +868,18 @@ const action$2 = async (ctx) => {
854
868
  maxSize = 1e8;
855
869
  }
856
870
  const buildId = await upload(ctx, project, token, maxSize);
871
+ if (!buildId) {
872
+ return;
873
+ }
857
874
  try {
858
875
  notificationService(`${apiConfig.apiBaseUrl}/notifications`, token, cliConfig2);
859
876
  await buildLogsService(`${apiConfig.apiBaseUrl}/v1/logs/${buildId}`, token, cliConfig2);
877
+ ctx.logger.log(
878
+ "Visit the following URL for deployment logs. Your deployment will be available here shortly."
879
+ );
880
+ ctx.logger.log(
881
+ chalk.underline(`${apiConfig.dashboardBaseUrl}/projects/${project.name}/deployments`)
882
+ );
860
883
  } catch (e) {
861
884
  if (e instanceof Error) {
862
885
  ctx.logger.error(e.message);
@@ -893,7 +916,7 @@ const runAction = (name2, action2) => (...args) => {
893
916
  });
894
917
  };
895
918
  const command$3 = ({ command: command2, ctx }) => {
896
- return 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));
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));
897
920
  };
898
921
  const deployProject = {
899
922
  name: "deploy-project",
@@ -904,12 +927,12 @@ const deployProject = {
904
927
  const openModule = import("open");
905
928
  const action$1 = async (ctx) => {
906
929
  const { logger } = ctx;
907
- const tokenService = tokenServiceFactory(ctx);
930
+ const tokenService = await tokenServiceFactory(ctx);
908
931
  const existingToken = await tokenService.retrieveToken();
909
- const cloudApiService2 = cloudApiFactory(existingToken || void 0);
932
+ const cloudApiService = await cloudApiFactory(existingToken || void 0);
910
933
  const trackFailedLogin = async () => {
911
934
  try {
912
- await cloudApiService2.track("didNotLogin", { loginMethod: "cli" });
935
+ await cloudApiService.track("didNotLogin", { loginMethod: "cli" });
913
936
  } catch (e) {
914
937
  logger.debug("Failed to track failed login", e);
915
938
  }
@@ -918,14 +941,18 @@ const action$1 = async (ctx) => {
918
941
  const isTokenValid = await tokenService.isTokenValid(existingToken);
919
942
  if (isTokenValid) {
920
943
  try {
921
- const userInfo = await cloudApiService2.getUserInfo();
944
+ const userInfo = await cloudApiService.getUserInfo();
922
945
  const { email } = userInfo.data.data;
923
946
  if (email) {
924
947
  logger.log(`You are already logged into your account (${email}).`);
925
948
  } else {
926
949
  logger.log("You are already logged in.");
927
950
  }
928
- return;
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;
929
956
  } catch (e) {
930
957
  logger.debug("Failed to fetch user info", e);
931
958
  }
@@ -934,15 +961,15 @@ const action$1 = async (ctx) => {
934
961
  let cliConfig2;
935
962
  try {
936
963
  logger.info("🔌 Connecting to the Strapi Cloud API...");
937
- const config = await cloudApiService2.config();
964
+ const config = await cloudApiService.config();
938
965
  cliConfig2 = config.data;
939
966
  } catch (e) {
940
967
  logger.error("🥲 Oops! Something went wrong while logging you in. Please try again.");
941
968
  logger.debug(e);
942
- return;
969
+ return false;
943
970
  }
944
971
  try {
945
- await cloudApiService2.track("willLoginAttempt", {});
972
+ await cloudApiService.track("willLoginAttempt", {});
946
973
  } catch (e) {
947
974
  logger.debug("Failed to track login attempt", e);
948
975
  }
@@ -1001,9 +1028,9 @@ const action$1 = async (ctx) => {
1001
1028
  spinnerFail();
1002
1029
  throw new Error("Unable to proceed: Token validation failed");
1003
1030
  }
1004
- const cloudApiService22 = cloudApiFactory(authTokenData.access_token);
1005
1031
  logger.debug("🔍 Fetching user information...");
1006
- await cloudApiService22.getUserInfo();
1032
+ const cloudApiServiceWithToken = await cloudApiFactory(authTokenData.access_token);
1033
+ await cloudApiServiceWithToken.getUserInfo();
1007
1034
  logger.debug("🔍 User information fetched successfully!");
1008
1035
  try {
1009
1036
  logger.debug("📝 Saving login information...");
@@ -1016,7 +1043,7 @@ const action$1 = async (ctx) => {
1016
1043
  );
1017
1044
  logger.debug(e);
1018
1045
  spinnerFail();
1019
- return;
1046
+ return false;
1020
1047
  }
1021
1048
  }
1022
1049
  } catch (e) {
@@ -1026,13 +1053,13 @@ const action$1 = async (ctx) => {
1026
1053
  );
1027
1054
  spinnerFail();
1028
1055
  await trackFailedLogin();
1029
- return;
1056
+ return false;
1030
1057
  }
1031
1058
  if (e.response?.data.error && !["authorization_pending", "slow_down"].includes(e.response.data.error)) {
1032
1059
  logger.debug(e);
1033
1060
  spinnerFail();
1034
1061
  await trackFailedLogin();
1035
- return;
1062
+ return false;
1036
1063
  }
1037
1064
  await new Promise((resolve) => {
1038
1065
  setTimeout(resolve, deviceAuthResponse.data.interval * 1e3);
@@ -1041,16 +1068,21 @@ const action$1 = async (ctx) => {
1041
1068
  }
1042
1069
  spinner.succeed("Authentication successful!");
1043
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`));
1044
1075
  try {
1045
- await cloudApiService2.track("didLogin", { loginMethod: "cli" });
1076
+ await cloudApiService.track("didLogin", { loginMethod: "cli" });
1046
1077
  } catch (e) {
1047
1078
  logger.debug("Failed to track login", e);
1048
1079
  }
1049
1080
  };
1050
1081
  await authenticate();
1082
+ return isAuthenticated;
1051
1083
  };
1052
1084
  const command$2 = ({ command: command2, ctx }) => {
1053
- return command2.command("cloud:login").alias("login").description("Strapi Cloud Login").addHelpText(
1085
+ command2.command("cloud:login").alias("login").description("Strapi Cloud Login").addHelpText(
1054
1086
  "after",
1055
1087
  "\nAfter running this command, you will be prompted to enter your authentication information."
1056
1088
  ).option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("login", action$1)(ctx));
@@ -1063,13 +1095,13 @@ const login = {
1063
1095
  };
1064
1096
  const action = async (ctx) => {
1065
1097
  const { logger } = ctx;
1066
- const { retrieveToken, eraseToken } = tokenServiceFactory(ctx);
1098
+ const { retrieveToken, eraseToken } = await tokenServiceFactory(ctx);
1067
1099
  const token = await retrieveToken();
1068
1100
  if (!token) {
1069
1101
  logger.log("You're already logged out.");
1070
1102
  return;
1071
1103
  }
1072
- const cloudApiService2 = cloudApiFactory(token);
1104
+ const cloudApiService = await cloudApiFactory(token);
1073
1105
  try {
1074
1106
  await eraseToken();
1075
1107
  logger.log(
@@ -1080,13 +1112,13 @@ const action = async (ctx) => {
1080
1112
  logger.debug(e);
1081
1113
  }
1082
1114
  try {
1083
- await cloudApiService2.track("didLogout", { loginMethod: "cli" });
1115
+ await cloudApiService.track("didLogout", { loginMethod: "cli" });
1084
1116
  } catch (e) {
1085
1117
  logger.debug("Failed to track logout event", e);
1086
1118
  }
1087
1119
  };
1088
1120
  const command$1 = ({ command: command2, ctx }) => {
1089
- return command2.command("cloud:logout").alias("logout").description("Strapi Cloud Logout").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("logout", action)(ctx));
1121
+ command2.command("cloud:logout").alias("logout").description("Strapi Cloud Logout").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("logout", action)(ctx));
1090
1122
  };
1091
1123
  const logout = {
1092
1124
  name: "logout",
@@ -1095,7 +1127,7 @@ const logout = {
1095
1127
  command: command$1
1096
1128
  };
1097
1129
  const command = ({ command: command2, ctx }) => {
1098
- return 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));
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));
1099
1131
  };
1100
1132
  const createProject = {
1101
1133
  name: "create-project",
@@ -1111,25 +1143,25 @@ const cli = {
1111
1143
  };
1112
1144
  const cloudCommands = [deployProject, login, logout];
1113
1145
  async function initCloudCLIConfig() {
1114
- const localConfig = getLocalConfig();
1146
+ const localConfig = await getLocalConfig();
1115
1147
  if (!localConfig.deviceId) {
1116
1148
  localConfig.deviceId = crypto$1.randomUUID();
1117
1149
  }
1118
- saveLocalConfig(localConfig);
1150
+ await saveLocalConfig(localConfig);
1119
1151
  }
1120
- function buildStrapiCloudCommands({
1152
+ async function buildStrapiCloudCommands({
1121
1153
  command: command2,
1122
1154
  ctx,
1123
1155
  argv
1124
1156
  }) {
1125
- initCloudCLIConfig();
1126
- cloudCommands.forEach((cloudCommand) => {
1157
+ await initCloudCLIConfig();
1158
+ for (const cloudCommand of cloudCommands) {
1127
1159
  try {
1128
- cloudCommand.command({ command: command2, ctx, argv });
1160
+ await cloudCommand.command({ command: command2, ctx, argv });
1129
1161
  } catch (e) {
1130
1162
  console.error(`Failed to load command ${cloudCommand.name}`, e);
1131
1163
  }
1132
- });
1164
+ }
1133
1165
  }
1134
1166
  export {
1135
1167
  buildStrapiCloudCommands,