@strapi/cloud-cli 4.25.0 → 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/LICENSE +18 -3
- package/dist/index.js +256 -204
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +256 -204
- 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 +5 -5
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.
|
|
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.
|
|
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.
|
|
205
|
-
tsconfig: "4.
|
|
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
|
-
|
|
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
|
-
|
|
419
|
-
|
|
420
|
-
logger.log(
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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
|
-
|
|
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
|
-
|
|
775
|
+
async function createProject$1(ctx, cloudApi, projectInput) {
|
|
596
776
|
const { logger } = ctx;
|
|
597
|
-
const
|
|
598
|
-
|
|
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
|
-
|
|
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
|
-
|
|
616
|
-
|
|
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$
|
|
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$
|
|
1040
|
+
const action$1 = async (ctx) => {
|
|
845
1041
|
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
846
|
-
const
|
|
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$
|
|
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$
|
|
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",
|
|
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:
|
|
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$
|
|
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$
|
|
1187
|
+
action: action$2,
|
|
1136
1188
|
command
|
|
1137
1189
|
};
|
|
1138
1190
|
const cli = {
|