@strapi/cloud-cli 5.0.0-rc.0 → 5.0.0-rc.10
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.js +258 -206
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +258 -206
- package/dist/index.mjs.map +1 -1
- package/dist/src/create-project/action.d.ts +1 -1
- package/dist/src/create-project/action.d.ts.map +1 -1
- package/dist/src/deploy-project/action.d.ts.map +1 -1
- package/dist/src/login/action.d.ts +2 -2
- package/dist/src/login/action.d.ts.map +1 -1
- package/dist/src/logout/action.d.ts.map +1 -1
- package/dist/src/services/cli-api.d.ts +4 -2
- package/dist/src/services/cli-api.d.ts.map +1 -1
- package/dist/src/services/token.d.ts +1 -1
- package/dist/src/services/token.d.ts.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -195,7 +195,7 @@ async function saveLocalConfig(data) {
|
|
|
195
195
|
await fse__default.default.writeJson(configFilePath, data, { encoding: "utf8", spaces: 2, mode: 384 });
|
|
196
196
|
}
|
|
197
197
|
const name = "@strapi/cloud-cli";
|
|
198
|
-
const version = "5.0.0-
|
|
198
|
+
const version = "5.0.0-rc.9";
|
|
199
199
|
const description = "Commands to interact with the Strapi Cloud";
|
|
200
200
|
const keywords = [
|
|
201
201
|
"strapi",
|
|
@@ -239,14 +239,14 @@ const scripts = {
|
|
|
239
239
|
watch: "pack-up watch"
|
|
240
240
|
};
|
|
241
241
|
const dependencies = {
|
|
242
|
-
"@strapi/utils": "
|
|
243
|
-
axios: "1.6.
|
|
242
|
+
"@strapi/utils": "workspace:*",
|
|
243
|
+
axios: "1.6.8",
|
|
244
244
|
chalk: "4.1.2",
|
|
245
245
|
"cli-progress": "3.12.0",
|
|
246
246
|
commander: "8.3.0",
|
|
247
247
|
eventsource: "2.0.2",
|
|
248
248
|
"fast-safe-stringify": "2.1.1",
|
|
249
|
-
"fs-extra": "
|
|
249
|
+
"fs-extra": "11.2.0",
|
|
250
250
|
inquirer: "8.2.5",
|
|
251
251
|
jsonwebtoken: "9.0.0",
|
|
252
252
|
"jwks-rsa": "3.1.0",
|
|
@@ -264,8 +264,8 @@ const devDependencies = {
|
|
|
264
264
|
"@types/cli-progress": "3.11.5",
|
|
265
265
|
"@types/eventsource": "1.1.15",
|
|
266
266
|
"@types/lodash": "^4.14.191",
|
|
267
|
-
"eslint-config-custom": "
|
|
268
|
-
tsconfig: "
|
|
267
|
+
"eslint-config-custom": "workspace:*",
|
|
268
|
+
tsconfig: "workspace:*"
|
|
269
269
|
};
|
|
270
270
|
const engines = {
|
|
271
271
|
node: ">=18.0.0 <=20.x.x",
|
|
@@ -294,7 +294,7 @@ const packageJson = {
|
|
|
294
294
|
engines
|
|
295
295
|
};
|
|
296
296
|
const VERSION = "v1";
|
|
297
|
-
async function cloudApiFactory(token) {
|
|
297
|
+
async function cloudApiFactory({ logger }, token) {
|
|
298
298
|
const localConfig = await getLocalConfig();
|
|
299
299
|
const customHeaders = {
|
|
300
300
|
"x-device-id": localConfig.deviceId,
|
|
@@ -347,8 +347,19 @@ async function cloudApiFactory(token) {
|
|
|
347
347
|
getUserInfo() {
|
|
348
348
|
return axiosCloudAPI.get("/user");
|
|
349
349
|
},
|
|
350
|
-
config() {
|
|
351
|
-
|
|
350
|
+
async config() {
|
|
351
|
+
try {
|
|
352
|
+
const response = await axiosCloudAPI.get("/config");
|
|
353
|
+
if (response.status !== 200) {
|
|
354
|
+
throw new Error("Error fetching cloud CLI config from the server.");
|
|
355
|
+
}
|
|
356
|
+
return response;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
logger.debug(
|
|
359
|
+
"🥲 Oops! Couldn't retrieve the cloud CLI config from the server. Please try again."
|
|
360
|
+
);
|
|
361
|
+
throw error;
|
|
362
|
+
}
|
|
352
363
|
},
|
|
353
364
|
listProjects() {
|
|
354
365
|
return axiosCloudAPI.get("/projects");
|
|
@@ -387,7 +398,7 @@ const strapiInfoSave = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defi
|
|
|
387
398
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
388
399
|
let cliConfig;
|
|
389
400
|
async function tokenServiceFactory({ logger }) {
|
|
390
|
-
const cloudApiService = await cloudApiFactory();
|
|
401
|
+
const cloudApiService = await cloudApiFactory({ logger });
|
|
391
402
|
async function saveToken(str) {
|
|
392
403
|
const appConfig = await getLocalConfig();
|
|
393
404
|
if (!appConfig) {
|
|
@@ -436,14 +447,17 @@ async function tokenServiceFactory({ logger }) {
|
|
|
436
447
|
"There seems to be a problem with your login information. Please try logging in again."
|
|
437
448
|
);
|
|
438
449
|
}
|
|
450
|
+
return Promise.reject(new Error("Invalid token"));
|
|
439
451
|
}
|
|
440
452
|
return new Promise((resolve, reject) => {
|
|
441
453
|
jwt__default.default.verify(idToken, getKey, (err) => {
|
|
442
454
|
if (err) {
|
|
443
455
|
reject(err);
|
|
444
|
-
} else {
|
|
445
|
-
resolve();
|
|
446
456
|
}
|
|
457
|
+
if (decodedToken.payload.exp < Math.floor(Date.now() / 1e3)) {
|
|
458
|
+
reject(new Error("Token is expired"));
|
|
459
|
+
}
|
|
460
|
+
resolve();
|
|
447
461
|
});
|
|
448
462
|
});
|
|
449
463
|
}
|
|
@@ -477,15 +491,15 @@ async function tokenServiceFactory({ logger }) {
|
|
|
477
491
|
throw e;
|
|
478
492
|
}
|
|
479
493
|
}
|
|
480
|
-
async function getValidToken() {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
logger.log(
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
494
|
+
async function getValidToken(ctx, loginAction2) {
|
|
495
|
+
let token = await retrieveToken();
|
|
496
|
+
while (!token || !await isTokenValid(token)) {
|
|
497
|
+
logger.log(
|
|
498
|
+
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."
|
|
499
|
+
);
|
|
500
|
+
if (!await loginAction2(ctx))
|
|
501
|
+
return null;
|
|
502
|
+
token = await retrieveToken();
|
|
489
503
|
}
|
|
490
504
|
return token;
|
|
491
505
|
}
|
|
@@ -619,17 +633,183 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
|
|
|
619
633
|
local: strapiInfoSave,
|
|
620
634
|
tokenServiceFactory
|
|
621
635
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
622
|
-
|
|
636
|
+
const openModule$1 = import("open");
|
|
637
|
+
async function promptLogin(ctx) {
|
|
638
|
+
const response = await inquirer__default.default.prompt([
|
|
639
|
+
{
|
|
640
|
+
type: "confirm",
|
|
641
|
+
name: "login",
|
|
642
|
+
message: "Would you like to login?"
|
|
643
|
+
}
|
|
644
|
+
]);
|
|
645
|
+
if (response.login) {
|
|
646
|
+
const loginSuccessful = await loginAction(ctx);
|
|
647
|
+
return loginSuccessful;
|
|
648
|
+
}
|
|
649
|
+
return false;
|
|
650
|
+
}
|
|
651
|
+
async function loginAction(ctx) {
|
|
652
|
+
const { logger } = ctx;
|
|
623
653
|
const tokenService = await tokenServiceFactory(ctx);
|
|
654
|
+
const existingToken = await tokenService.retrieveToken();
|
|
655
|
+
const cloudApiService = await cloudApiFactory(ctx, existingToken || void 0);
|
|
656
|
+
const trackFailedLogin = async () => {
|
|
657
|
+
try {
|
|
658
|
+
await cloudApiService.track("didNotLogin", { loginMethod: "cli" });
|
|
659
|
+
} catch (e) {
|
|
660
|
+
logger.debug("Failed to track failed login", e);
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
if (existingToken) {
|
|
664
|
+
const isTokenValid = await tokenService.isTokenValid(existingToken);
|
|
665
|
+
if (isTokenValid) {
|
|
666
|
+
try {
|
|
667
|
+
const userInfo = await cloudApiService.getUserInfo();
|
|
668
|
+
const { email } = userInfo.data.data;
|
|
669
|
+
if (email) {
|
|
670
|
+
logger.log(`You are already logged into your account (${email}).`);
|
|
671
|
+
} else {
|
|
672
|
+
logger.log("You are already logged in.");
|
|
673
|
+
}
|
|
674
|
+
logger.log(
|
|
675
|
+
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
676
|
+
);
|
|
677
|
+
logger.log(chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
678
|
+
return true;
|
|
679
|
+
} catch (e) {
|
|
680
|
+
logger.debug("Failed to fetch user info", e);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
let cliConfig2;
|
|
685
|
+
try {
|
|
686
|
+
logger.info("🔌 Connecting to the Strapi Cloud API...");
|
|
687
|
+
const config = await cloudApiService.config();
|
|
688
|
+
cliConfig2 = config.data;
|
|
689
|
+
} catch (e) {
|
|
690
|
+
logger.error("🥲 Oops! Something went wrong while logging you in. Please try again.");
|
|
691
|
+
logger.debug(e);
|
|
692
|
+
return false;
|
|
693
|
+
}
|
|
694
|
+
try {
|
|
695
|
+
await cloudApiService.track("willLoginAttempt", {});
|
|
696
|
+
} catch (e) {
|
|
697
|
+
logger.debug("Failed to track login attempt", e);
|
|
698
|
+
}
|
|
699
|
+
logger.debug("🔐 Creating device authentication request...", {
|
|
700
|
+
client_id: cliConfig2.clientId,
|
|
701
|
+
scope: cliConfig2.scope,
|
|
702
|
+
audience: cliConfig2.audience
|
|
703
|
+
});
|
|
704
|
+
const deviceAuthResponse = await axios__default.default.post(cliConfig2.deviceCodeAuthUrl, {
|
|
705
|
+
client_id: cliConfig2.clientId,
|
|
706
|
+
scope: cliConfig2.scope,
|
|
707
|
+
audience: cliConfig2.audience
|
|
708
|
+
}).catch((e) => {
|
|
709
|
+
logger.error("There was an issue with the authentication process. Please try again.");
|
|
710
|
+
if (e.message) {
|
|
711
|
+
logger.debug(e.message, e);
|
|
712
|
+
} else {
|
|
713
|
+
logger.debug(e);
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
openModule$1.then((open) => {
|
|
717
|
+
open.default(deviceAuthResponse.data.verification_uri_complete).catch((e) => {
|
|
718
|
+
logger.error("We encountered an issue opening the browser. Please try again later.");
|
|
719
|
+
logger.debug(e.message, e);
|
|
720
|
+
});
|
|
721
|
+
});
|
|
722
|
+
logger.log("If a browser tab does not open automatically, please follow the next steps:");
|
|
723
|
+
logger.log(
|
|
724
|
+
`1. Open this url in your device: ${deviceAuthResponse.data.verification_uri_complete}`
|
|
725
|
+
);
|
|
726
|
+
logger.log(
|
|
727
|
+
`2. Enter the following code: ${deviceAuthResponse.data.user_code} and confirm to login.
|
|
728
|
+
`
|
|
729
|
+
);
|
|
730
|
+
const tokenPayload = {
|
|
731
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
732
|
+
device_code: deviceAuthResponse.data.device_code,
|
|
733
|
+
client_id: cliConfig2.clientId
|
|
734
|
+
};
|
|
735
|
+
let isAuthenticated = false;
|
|
736
|
+
const authenticate = async () => {
|
|
737
|
+
const spinner = logger.spinner("Waiting for authentication");
|
|
738
|
+
spinner.start();
|
|
739
|
+
const spinnerFail = () => spinner.fail("Authentication failed!");
|
|
740
|
+
while (!isAuthenticated) {
|
|
741
|
+
try {
|
|
742
|
+
const tokenResponse = await axios__default.default.post(cliConfig2.tokenUrl, tokenPayload);
|
|
743
|
+
const authTokenData = tokenResponse.data;
|
|
744
|
+
if (tokenResponse.status === 200) {
|
|
745
|
+
try {
|
|
746
|
+
logger.debug("🔐 Validating token...");
|
|
747
|
+
await tokenService.validateToken(authTokenData.id_token, cliConfig2.jwksUrl);
|
|
748
|
+
logger.debug("🔐 Token validation successful!");
|
|
749
|
+
} catch (e) {
|
|
750
|
+
logger.debug(e);
|
|
751
|
+
spinnerFail();
|
|
752
|
+
throw new Error("Unable to proceed: Token validation failed");
|
|
753
|
+
}
|
|
754
|
+
logger.debug("🔍 Fetching user information...");
|
|
755
|
+
const cloudApiServiceWithToken = await cloudApiFactory(ctx, authTokenData.access_token);
|
|
756
|
+
await cloudApiServiceWithToken.getUserInfo();
|
|
757
|
+
logger.debug("🔍 User information fetched successfully!");
|
|
758
|
+
try {
|
|
759
|
+
logger.debug("📝 Saving login information...");
|
|
760
|
+
await tokenService.saveToken(authTokenData.access_token);
|
|
761
|
+
logger.debug("📝 Login information saved successfully!");
|
|
762
|
+
isAuthenticated = true;
|
|
763
|
+
} catch (e) {
|
|
764
|
+
logger.error(
|
|
765
|
+
"There was a problem saving your login information. Please try logging in again."
|
|
766
|
+
);
|
|
767
|
+
logger.debug(e);
|
|
768
|
+
spinnerFail();
|
|
769
|
+
return false;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
} catch (e) {
|
|
773
|
+
if (e.message === "Unable to proceed: Token validation failed") {
|
|
774
|
+
logger.error(
|
|
775
|
+
"There seems to be a problem with your login information. Please try logging in again."
|
|
776
|
+
);
|
|
777
|
+
spinnerFail();
|
|
778
|
+
await trackFailedLogin();
|
|
779
|
+
return false;
|
|
780
|
+
}
|
|
781
|
+
if (e.response?.data.error && !["authorization_pending", "slow_down"].includes(e.response.data.error)) {
|
|
782
|
+
logger.debug(e);
|
|
783
|
+
spinnerFail();
|
|
784
|
+
await trackFailedLogin();
|
|
785
|
+
return false;
|
|
786
|
+
}
|
|
787
|
+
await new Promise((resolve) => {
|
|
788
|
+
setTimeout(resolve, deviceAuthResponse.data.interval * 1e3);
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
spinner.succeed("Authentication successful!");
|
|
793
|
+
logger.log("You are now logged into Strapi Cloud.");
|
|
794
|
+
logger.log(
|
|
795
|
+
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
796
|
+
);
|
|
797
|
+
logger.log(chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
798
|
+
try {
|
|
799
|
+
await cloudApiService.track("didLogin", { loginMethod: "cli" });
|
|
800
|
+
} catch (e) {
|
|
801
|
+
logger.debug("Failed to track login", e);
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
await authenticate();
|
|
805
|
+
return isAuthenticated;
|
|
806
|
+
}
|
|
807
|
+
async function handleError(ctx, error) {
|
|
624
808
|
const { logger } = ctx;
|
|
625
809
|
logger.debug(error);
|
|
626
810
|
if (error instanceof axios.AxiosError) {
|
|
627
811
|
const errorMessage = typeof error.response?.data === "string" ? error.response.data : null;
|
|
628
812
|
switch (error.response?.status) {
|
|
629
|
-
case 401:
|
|
630
|
-
logger.error("Your session has expired. Please log in again.");
|
|
631
|
-
await tokenService.eraseToken();
|
|
632
|
-
return;
|
|
633
813
|
case 403:
|
|
634
814
|
logger.error(
|
|
635
815
|
errorMessage || "You do not have permission to create a project. Please contact support for assistance."
|
|
@@ -655,28 +835,44 @@ async function handleError(ctx, error) {
|
|
|
655
835
|
"We encountered an issue while creating your project. Please try again in a moment. If the problem persists, contact support for assistance."
|
|
656
836
|
);
|
|
657
837
|
}
|
|
658
|
-
|
|
838
|
+
async function createProject$1(ctx, cloudApi, projectInput) {
|
|
659
839
|
const { logger } = ctx;
|
|
660
|
-
const
|
|
661
|
-
|
|
840
|
+
const spinner = logger.spinner("Setting up your project...").start();
|
|
841
|
+
try {
|
|
842
|
+
const { data } = await cloudApi.createProject(projectInput);
|
|
843
|
+
await save({ project: data });
|
|
844
|
+
spinner.succeed("Project created successfully!");
|
|
845
|
+
return data;
|
|
846
|
+
} catch (e) {
|
|
847
|
+
spinner.fail("An error occurred while creating the project on Strapi Cloud.");
|
|
848
|
+
throw e;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
const action$2 = async (ctx) => {
|
|
852
|
+
const { logger } = ctx;
|
|
853
|
+
const { getValidToken, eraseToken } = await tokenServiceFactory(ctx);
|
|
854
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
662
855
|
if (!token) {
|
|
663
856
|
return;
|
|
664
857
|
}
|
|
665
|
-
const cloudApi = await cloudApiFactory(token);
|
|
858
|
+
const cloudApi = await cloudApiFactory(ctx, token);
|
|
666
859
|
const { data: config } = await cloudApi.config();
|
|
667
860
|
const { questions, defaults: defaultValues } = config.projectCreation;
|
|
668
861
|
const projectAnswersDefaulted = fp.defaults(defaultValues);
|
|
669
862
|
const projectAnswers = await inquirer__default.default.prompt(questions);
|
|
670
863
|
const projectInput = projectAnswersDefaulted(projectAnswers);
|
|
671
|
-
const spinner = logger.spinner("Setting up your project...").start();
|
|
672
864
|
try {
|
|
673
|
-
|
|
674
|
-
await save({ project: data });
|
|
675
|
-
spinner.succeed("Project created successfully!");
|
|
676
|
-
return data;
|
|
865
|
+
return await createProject$1(ctx, cloudApi, projectInput);
|
|
677
866
|
} catch (e) {
|
|
678
|
-
|
|
679
|
-
|
|
867
|
+
if (e instanceof axios.AxiosError && e.response?.status === 401) {
|
|
868
|
+
logger.warn("Oops! Your session has expired. Please log in again to retry.");
|
|
869
|
+
await eraseToken();
|
|
870
|
+
if (await promptLogin(ctx)) {
|
|
871
|
+
return await createProject$1(ctx, cloudApi, projectInput);
|
|
872
|
+
}
|
|
873
|
+
} else {
|
|
874
|
+
await handleError(ctx, e);
|
|
875
|
+
}
|
|
680
876
|
}
|
|
681
877
|
};
|
|
682
878
|
function notificationServiceFactory({ logger }) {
|
|
@@ -807,7 +1003,7 @@ const buildLogsServiceFactory = ({ logger }) => {
|
|
|
807
1003
|
};
|
|
808
1004
|
};
|
|
809
1005
|
async function upload(ctx, project, token, maxProjectFileSize) {
|
|
810
|
-
const cloudApi = await cloudApiFactory(token);
|
|
1006
|
+
const cloudApi = await cloudApiFactory(ctx, token);
|
|
811
1007
|
try {
|
|
812
1008
|
const storagePath = await getTmpStoragePath();
|
|
813
1009
|
const projectFolder = path__namespace.default.resolve(process.cwd());
|
|
@@ -898,7 +1094,7 @@ async function getProject(ctx) {
|
|
|
898
1094
|
const { project } = await retrieve();
|
|
899
1095
|
if (!project) {
|
|
900
1096
|
try {
|
|
901
|
-
return await action$
|
|
1097
|
+
return await action$2(ctx);
|
|
902
1098
|
} catch (e) {
|
|
903
1099
|
ctx.logger.error("An error occurred while deploying the project. Please try again later.");
|
|
904
1100
|
ctx.logger.debug(e);
|
|
@@ -907,10 +1103,9 @@ async function getProject(ctx) {
|
|
|
907
1103
|
}
|
|
908
1104
|
return project;
|
|
909
1105
|
}
|
|
910
|
-
const action$
|
|
1106
|
+
const action$1 = async (ctx) => {
|
|
911
1107
|
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
912
|
-
const
|
|
913
|
-
const token = await getValidToken();
|
|
1108
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
914
1109
|
if (!token) {
|
|
915
1110
|
return;
|
|
916
1111
|
}
|
|
@@ -918,6 +1113,7 @@ const action$2 = async (ctx) => {
|
|
|
918
1113
|
if (!project) {
|
|
919
1114
|
return;
|
|
920
1115
|
}
|
|
1116
|
+
const cloudApiService = await cloudApiFactory(ctx);
|
|
921
1117
|
try {
|
|
922
1118
|
await cloudApiService.track("willDeployWithCLI", { projectInternalName: project.name });
|
|
923
1119
|
} catch (e) {
|
|
@@ -982,183 +1178,27 @@ const runAction = (name2, action2) => (...args) => {
|
|
|
982
1178
|
});
|
|
983
1179
|
};
|
|
984
1180
|
const command$3 = ({ ctx }) => {
|
|
985
|
-
return commander.createCommand("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$
|
|
1181
|
+
return commander.createCommand("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));
|
|
986
1182
|
};
|
|
987
1183
|
const deployProject = {
|
|
988
1184
|
name: "deploy-project",
|
|
989
1185
|
description: "Deploy a Strapi Cloud project",
|
|
990
|
-
action: action$
|
|
1186
|
+
action: action$1,
|
|
991
1187
|
command: command$3
|
|
992
1188
|
};
|
|
993
|
-
const openModule = import("open");
|
|
994
|
-
const action$1 = async (ctx) => {
|
|
995
|
-
const { logger } = ctx;
|
|
996
|
-
const tokenService = await tokenServiceFactory(ctx);
|
|
997
|
-
const existingToken = await tokenService.retrieveToken();
|
|
998
|
-
const cloudApiService = await cloudApiFactory(existingToken || void 0);
|
|
999
|
-
const trackFailedLogin = async () => {
|
|
1000
|
-
try {
|
|
1001
|
-
await cloudApiService.track("didNotLogin", { loginMethod: "cli" });
|
|
1002
|
-
} catch (e) {
|
|
1003
|
-
logger.debug("Failed to track failed login", e);
|
|
1004
|
-
}
|
|
1005
|
-
};
|
|
1006
|
-
if (existingToken) {
|
|
1007
|
-
const isTokenValid = await tokenService.isTokenValid(existingToken);
|
|
1008
|
-
if (isTokenValid) {
|
|
1009
|
-
try {
|
|
1010
|
-
const userInfo = await cloudApiService.getUserInfo();
|
|
1011
|
-
const { email } = userInfo.data.data;
|
|
1012
|
-
if (email) {
|
|
1013
|
-
logger.log(`You are already logged into your account (${email}).`);
|
|
1014
|
-
} else {
|
|
1015
|
-
logger.log("You are already logged in.");
|
|
1016
|
-
}
|
|
1017
|
-
logger.log(
|
|
1018
|
-
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
1019
|
-
);
|
|
1020
|
-
logger.log(chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
1021
|
-
return true;
|
|
1022
|
-
} catch (e) {
|
|
1023
|
-
logger.debug("Failed to fetch user info", e);
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
let cliConfig2;
|
|
1028
|
-
try {
|
|
1029
|
-
logger.info("🔌 Connecting to the Strapi Cloud API...");
|
|
1030
|
-
const config = await cloudApiService.config();
|
|
1031
|
-
cliConfig2 = config.data;
|
|
1032
|
-
} catch (e) {
|
|
1033
|
-
logger.error("🥲 Oops! Something went wrong while logging you in. Please try again.");
|
|
1034
|
-
logger.debug(e);
|
|
1035
|
-
return false;
|
|
1036
|
-
}
|
|
1037
|
-
try {
|
|
1038
|
-
await cloudApiService.track("willLoginAttempt", {});
|
|
1039
|
-
} catch (e) {
|
|
1040
|
-
logger.debug("Failed to track login attempt", e);
|
|
1041
|
-
}
|
|
1042
|
-
logger.debug("🔐 Creating device authentication request...", {
|
|
1043
|
-
client_id: cliConfig2.clientId,
|
|
1044
|
-
scope: cliConfig2.scope,
|
|
1045
|
-
audience: cliConfig2.audience
|
|
1046
|
-
});
|
|
1047
|
-
const deviceAuthResponse = await axios__default.default.post(cliConfig2.deviceCodeAuthUrl, {
|
|
1048
|
-
client_id: cliConfig2.clientId,
|
|
1049
|
-
scope: cliConfig2.scope,
|
|
1050
|
-
audience: cliConfig2.audience
|
|
1051
|
-
}).catch((e) => {
|
|
1052
|
-
logger.error("There was an issue with the authentication process. Please try again.");
|
|
1053
|
-
if (e.message) {
|
|
1054
|
-
logger.debug(e.message, e);
|
|
1055
|
-
} else {
|
|
1056
|
-
logger.debug(e);
|
|
1057
|
-
}
|
|
1058
|
-
});
|
|
1059
|
-
openModule.then((open) => {
|
|
1060
|
-
open.default(deviceAuthResponse.data.verification_uri_complete).catch((e) => {
|
|
1061
|
-
logger.error("We encountered an issue opening the browser. Please try again later.");
|
|
1062
|
-
logger.debug(e.message, e);
|
|
1063
|
-
});
|
|
1064
|
-
});
|
|
1065
|
-
logger.log("If a browser tab does not open automatically, please follow the next steps:");
|
|
1066
|
-
logger.log(
|
|
1067
|
-
`1. Open this url in your device: ${deviceAuthResponse.data.verification_uri_complete}`
|
|
1068
|
-
);
|
|
1069
|
-
logger.log(
|
|
1070
|
-
`2. Enter the following code: ${deviceAuthResponse.data.user_code} and confirm to login.
|
|
1071
|
-
`
|
|
1072
|
-
);
|
|
1073
|
-
const tokenPayload = {
|
|
1074
|
-
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
1075
|
-
device_code: deviceAuthResponse.data.device_code,
|
|
1076
|
-
client_id: cliConfig2.clientId
|
|
1077
|
-
};
|
|
1078
|
-
let isAuthenticated = false;
|
|
1079
|
-
const authenticate = async () => {
|
|
1080
|
-
const spinner = logger.spinner("Waiting for authentication");
|
|
1081
|
-
spinner.start();
|
|
1082
|
-
const spinnerFail = () => spinner.fail("Authentication failed!");
|
|
1083
|
-
while (!isAuthenticated) {
|
|
1084
|
-
try {
|
|
1085
|
-
const tokenResponse = await axios__default.default.post(cliConfig2.tokenUrl, tokenPayload);
|
|
1086
|
-
const authTokenData = tokenResponse.data;
|
|
1087
|
-
if (tokenResponse.status === 200) {
|
|
1088
|
-
try {
|
|
1089
|
-
logger.debug("🔐 Validating token...");
|
|
1090
|
-
await tokenService.validateToken(authTokenData.id_token, cliConfig2.jwksUrl);
|
|
1091
|
-
logger.debug("🔐 Token validation successful!");
|
|
1092
|
-
} catch (e) {
|
|
1093
|
-
logger.debug(e);
|
|
1094
|
-
spinnerFail();
|
|
1095
|
-
throw new Error("Unable to proceed: Token validation failed");
|
|
1096
|
-
}
|
|
1097
|
-
logger.debug("🔍 Fetching user information...");
|
|
1098
|
-
const cloudApiServiceWithToken = await cloudApiFactory(authTokenData.access_token);
|
|
1099
|
-
await cloudApiServiceWithToken.getUserInfo();
|
|
1100
|
-
logger.debug("🔍 User information fetched successfully!");
|
|
1101
|
-
try {
|
|
1102
|
-
logger.debug("📝 Saving login information...");
|
|
1103
|
-
await tokenService.saveToken(authTokenData.access_token);
|
|
1104
|
-
logger.debug("📝 Login information saved successfully!");
|
|
1105
|
-
isAuthenticated = true;
|
|
1106
|
-
} catch (e) {
|
|
1107
|
-
logger.error(
|
|
1108
|
-
"There was a problem saving your login information. Please try logging in again."
|
|
1109
|
-
);
|
|
1110
|
-
logger.debug(e);
|
|
1111
|
-
spinnerFail();
|
|
1112
|
-
return false;
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
} catch (e) {
|
|
1116
|
-
if (e.message === "Unable to proceed: Token validation failed") {
|
|
1117
|
-
logger.error(
|
|
1118
|
-
"There seems to be a problem with your login information. Please try logging in again."
|
|
1119
|
-
);
|
|
1120
|
-
spinnerFail();
|
|
1121
|
-
await trackFailedLogin();
|
|
1122
|
-
return false;
|
|
1123
|
-
}
|
|
1124
|
-
if (e.response?.data.error && !["authorization_pending", "slow_down"].includes(e.response.data.error)) {
|
|
1125
|
-
logger.debug(e);
|
|
1126
|
-
spinnerFail();
|
|
1127
|
-
await trackFailedLogin();
|
|
1128
|
-
return false;
|
|
1129
|
-
}
|
|
1130
|
-
await new Promise((resolve) => {
|
|
1131
|
-
setTimeout(resolve, deviceAuthResponse.data.interval * 1e3);
|
|
1132
|
-
});
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
spinner.succeed("Authentication successful!");
|
|
1136
|
-
logger.log("You are now logged into Strapi Cloud.");
|
|
1137
|
-
logger.log(
|
|
1138
|
-
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
1139
|
-
);
|
|
1140
|
-
logger.log(chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
1141
|
-
try {
|
|
1142
|
-
await cloudApiService.track("didLogin", { loginMethod: "cli" });
|
|
1143
|
-
} catch (e) {
|
|
1144
|
-
logger.debug("Failed to track login", e);
|
|
1145
|
-
}
|
|
1146
|
-
};
|
|
1147
|
-
await authenticate();
|
|
1148
|
-
return isAuthenticated;
|
|
1149
|
-
};
|
|
1150
1189
|
const command$2 = ({ ctx }) => {
|
|
1151
1190
|
return commander.createCommand("cloud:login").alias("login").description("Strapi Cloud Login").addHelpText(
|
|
1152
1191
|
"after",
|
|
1153
1192
|
"\nAfter running this command, you will be prompted to enter your authentication information."
|
|
1154
|
-
).option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("login",
|
|
1193
|
+
).option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("login", loginAction)(ctx));
|
|
1155
1194
|
};
|
|
1156
1195
|
const login = {
|
|
1157
1196
|
name: "login",
|
|
1158
1197
|
description: "Strapi Cloud Login",
|
|
1159
|
-
action:
|
|
1198
|
+
action: loginAction,
|
|
1160
1199
|
command: command$2
|
|
1161
1200
|
};
|
|
1201
|
+
const openModule = import("open");
|
|
1162
1202
|
const action = async (ctx) => {
|
|
1163
1203
|
const { logger } = ctx;
|
|
1164
1204
|
const { retrieveToken, eraseToken } = await tokenServiceFactory(ctx);
|
|
@@ -1167,9 +1207,21 @@ const action = async (ctx) => {
|
|
|
1167
1207
|
logger.log("You're already logged out.");
|
|
1168
1208
|
return;
|
|
1169
1209
|
}
|
|
1170
|
-
const cloudApiService = await cloudApiFactory(token);
|
|
1210
|
+
const cloudApiService = await cloudApiFactory(ctx, token);
|
|
1211
|
+
const config = await cloudApiService.config();
|
|
1212
|
+
const cliConfig2 = config.data;
|
|
1171
1213
|
try {
|
|
1172
1214
|
await eraseToken();
|
|
1215
|
+
openModule.then((open) => {
|
|
1216
|
+
open.default(
|
|
1217
|
+
`${cliConfig2.baseUrl}/oidc/logout?client_id=${encodeURIComponent(
|
|
1218
|
+
cliConfig2.clientId
|
|
1219
|
+
)}&logout_hint=${encodeURIComponent(token)}
|
|
1220
|
+
`
|
|
1221
|
+
).catch((e) => {
|
|
1222
|
+
logger.debug(e.message, e);
|
|
1223
|
+
});
|
|
1224
|
+
});
|
|
1173
1225
|
logger.log(
|
|
1174
1226
|
"🔌 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."
|
|
1175
1227
|
);
|
|
@@ -1193,12 +1245,12 @@ const logout = {
|
|
|
1193
1245
|
command: command$1
|
|
1194
1246
|
};
|
|
1195
1247
|
const command = ({ ctx }) => {
|
|
1196
|
-
return commander.createCommand("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$
|
|
1248
|
+
return commander.createCommand("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));
|
|
1197
1249
|
};
|
|
1198
1250
|
const createProject = {
|
|
1199
1251
|
name: "create-project",
|
|
1200
1252
|
description: "Create a new project",
|
|
1201
|
-
action: action$
|
|
1253
|
+
action: action$2,
|
|
1202
1254
|
command
|
|
1203
1255
|
};
|
|
1204
1256
|
const cli = {
|