@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/LICENSE
CHANGED
|
@@ -2,7 +2,21 @@ Copyright (c) 2015-present Strapi Solutions SAS
|
|
|
2
2
|
|
|
3
3
|
Portions of the Strapi software are licensed as follows:
|
|
4
4
|
|
|
5
|
-
* All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined
|
|
5
|
+
* All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined below.
|
|
6
|
+
|
|
7
|
+
Enterprise License
|
|
8
|
+
|
|
9
|
+
If you or the company you represent has entered into a written agreement referencing the Enterprise Edition of the Strapi source code available at
|
|
10
|
+
https://github.com/strapi/strapi, then such agreement applies to your use of the Enterprise Edition of the Strapi Software. If you or the company you
|
|
11
|
+
represent is using the Enterprise Edition of the Strapi Software in connection with a subscription to our cloud offering, then the agreement you have
|
|
12
|
+
agreed to with respect to our cloud offering and the licenses included in such agreement apply to your use of the Enterprise Edition of the Strapi Software.
|
|
13
|
+
Otherwise, the Strapi Enterprise Software License Agreement (found here https://strapi.io/enterprise-terms) applies to your use of the Enterprise Edition of the Strapi Software.
|
|
14
|
+
|
|
15
|
+
BY ACCESSING OR USING THE ENTERPRISE EDITION OF THE STRAPI SOFTWARE, YOU ARE AGREEING TO BE BOUND BY THE RELEVANT REFERENCED AGREEMENT.
|
|
16
|
+
IF YOU ARE NOT AUTHORIZED TO ACCEPT THESE TERMS ON BEHALF OF THE COMPANY YOU REPRESENT OR IF YOU DO NOT AGREE TO ALL OF THE RELEVANT TERMS AND CONDITIONS REFERENCED AND YOU
|
|
17
|
+
HAVE NOT OTHERWISE EXECUTED A WRITTEN AGREEMENT WITH STRAPI, YOU ARE NOT AUTHORIZED TO ACCESS OR USE OR ALLOW ANY USER TO ACCESS OR USE ANY PART OF
|
|
18
|
+
THE ENTERPRISE EDITION OF THE STRAPI SOFTWARE. YOUR ACCESS RIGHTS ARE CONDITIONAL ON YOUR CONSENT TO THE RELEVANT REFERENCED TERMS TO THE EXCLUSION OF ALL OTHER TERMS;
|
|
19
|
+
IF THE RELEVANT REFERENCED TERMS ARE CONSIDERED AN OFFER BY YOU, ACCEPTANCE IS EXPRESSLY LIMITED TO THE RELEVANT REFERENCED TERMS.
|
|
6
20
|
|
|
7
21
|
* All software outside of the above-mentioned directories or restrictions above is available under the "MIT Expat" license as set forth below.
|
|
8
22
|
|
|
@@ -18,5 +32,6 @@ furnished to do so, subject to the following conditions:
|
|
|
18
32
|
The above copyright notice and this permission notice shall be included in all
|
|
19
33
|
copies or substantial portions of the Software.
|
|
20
34
|
|
|
21
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
-
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
36
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
37
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/dist/index.js
CHANGED
|
@@ -194,7 +194,7 @@ async function saveLocalConfig(data) {
|
|
|
194
194
|
await fse__default.default.writeJson(configFilePath, data, { encoding: "utf8", spaces: 2, mode: 384 });
|
|
195
195
|
}
|
|
196
196
|
const name = "@strapi/cloud-cli";
|
|
197
|
-
const version = "4.
|
|
197
|
+
const version = "4.25.1";
|
|
198
198
|
const description = "Commands to interact with the Strapi Cloud";
|
|
199
199
|
const keywords = [
|
|
200
200
|
"strapi",
|
|
@@ -238,7 +238,7 @@ const scripts = {
|
|
|
238
238
|
watch: "pack-up watch"
|
|
239
239
|
};
|
|
240
240
|
const dependencies = {
|
|
241
|
-
"@strapi/utils": "4.
|
|
241
|
+
"@strapi/utils": "4.25.1",
|
|
242
242
|
axios: "1.6.0",
|
|
243
243
|
chalk: "4.1.2",
|
|
244
244
|
"cli-progress": "3.12.0",
|
|
@@ -263,8 +263,8 @@ const devDependencies = {
|
|
|
263
263
|
"@types/cli-progress": "3.11.5",
|
|
264
264
|
"@types/eventsource": "1.1.15",
|
|
265
265
|
"@types/lodash": "^4.14.191",
|
|
266
|
-
"eslint-config-custom": "4.
|
|
267
|
-
tsconfig: "4.
|
|
266
|
+
"eslint-config-custom": "4.25.1",
|
|
267
|
+
tsconfig: "4.25.1"
|
|
268
268
|
};
|
|
269
269
|
const engines = {
|
|
270
270
|
node: ">=18.0.0 <=20.x.x",
|
|
@@ -293,7 +293,7 @@ const packageJson = {
|
|
|
293
293
|
engines
|
|
294
294
|
};
|
|
295
295
|
const VERSION = "v1";
|
|
296
|
-
async function cloudApiFactory(token) {
|
|
296
|
+
async function cloudApiFactory({ logger }, token) {
|
|
297
297
|
const localConfig = await getLocalConfig();
|
|
298
298
|
const customHeaders = {
|
|
299
299
|
"x-device-id": localConfig.deviceId,
|
|
@@ -346,8 +346,19 @@ async function cloudApiFactory(token) {
|
|
|
346
346
|
getUserInfo() {
|
|
347
347
|
return axiosCloudAPI.get("/user");
|
|
348
348
|
},
|
|
349
|
-
config() {
|
|
350
|
-
|
|
349
|
+
async config() {
|
|
350
|
+
try {
|
|
351
|
+
const response = await axiosCloudAPI.get("/config");
|
|
352
|
+
if (response.status !== 200) {
|
|
353
|
+
throw new Error("Error fetching cloud CLI config from the server.");
|
|
354
|
+
}
|
|
355
|
+
return response;
|
|
356
|
+
} catch (error) {
|
|
357
|
+
logger.debug(
|
|
358
|
+
"🥲 Oops! Couldn't retrieve the cloud CLI config from the server. Please try again."
|
|
359
|
+
);
|
|
360
|
+
throw error;
|
|
361
|
+
}
|
|
351
362
|
},
|
|
352
363
|
listProjects() {
|
|
353
364
|
return axiosCloudAPI.get("/projects");
|
|
@@ -386,7 +397,7 @@ const strapiInfoSave = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defi
|
|
|
386
397
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
387
398
|
let cliConfig;
|
|
388
399
|
async function tokenServiceFactory({ logger }) {
|
|
389
|
-
const cloudApiService = await cloudApiFactory();
|
|
400
|
+
const cloudApiService = await cloudApiFactory({ logger });
|
|
390
401
|
async function saveToken(str) {
|
|
391
402
|
const appConfig = await getLocalConfig();
|
|
392
403
|
if (!appConfig) {
|
|
@@ -435,14 +446,17 @@ async function tokenServiceFactory({ logger }) {
|
|
|
435
446
|
"There seems to be a problem with your login information. Please try logging in again."
|
|
436
447
|
);
|
|
437
448
|
}
|
|
449
|
+
return Promise.reject(new Error("Invalid token"));
|
|
438
450
|
}
|
|
439
451
|
return new Promise((resolve, reject) => {
|
|
440
452
|
jwt__default.default.verify(idToken, getKey, (err) => {
|
|
441
453
|
if (err) {
|
|
442
454
|
reject(err);
|
|
443
|
-
} else {
|
|
444
|
-
resolve();
|
|
445
455
|
}
|
|
456
|
+
if (decodedToken.payload.exp < Math.floor(Date.now() / 1e3)) {
|
|
457
|
+
reject(new Error("Token is expired"));
|
|
458
|
+
}
|
|
459
|
+
resolve();
|
|
446
460
|
});
|
|
447
461
|
});
|
|
448
462
|
}
|
|
@@ -476,15 +490,15 @@ async function tokenServiceFactory({ logger }) {
|
|
|
476
490
|
throw e;
|
|
477
491
|
}
|
|
478
492
|
}
|
|
479
|
-
async function getValidToken() {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
logger.log(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
493
|
+
async function getValidToken(ctx, loginAction2) {
|
|
494
|
+
let token = await retrieveToken();
|
|
495
|
+
while (!token || !await isTokenValid(token)) {
|
|
496
|
+
logger.log(
|
|
497
|
+
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."
|
|
498
|
+
);
|
|
499
|
+
if (!await loginAction2(ctx))
|
|
500
|
+
return null;
|
|
501
|
+
token = await retrieveToken();
|
|
488
502
|
}
|
|
489
503
|
return token;
|
|
490
504
|
}
|
|
@@ -618,17 +632,183 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
|
|
|
618
632
|
local: strapiInfoSave,
|
|
619
633
|
tokenServiceFactory
|
|
620
634
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
621
|
-
|
|
635
|
+
const openModule$1 = import("open");
|
|
636
|
+
async function promptLogin(ctx) {
|
|
637
|
+
const response = await inquirer__default.default.prompt([
|
|
638
|
+
{
|
|
639
|
+
type: "confirm",
|
|
640
|
+
name: "login",
|
|
641
|
+
message: "Would you like to login?"
|
|
642
|
+
}
|
|
643
|
+
]);
|
|
644
|
+
if (response.login) {
|
|
645
|
+
const loginSuccessful = await loginAction(ctx);
|
|
646
|
+
return loginSuccessful;
|
|
647
|
+
}
|
|
648
|
+
return false;
|
|
649
|
+
}
|
|
650
|
+
async function loginAction(ctx) {
|
|
651
|
+
const { logger } = ctx;
|
|
622
652
|
const tokenService = await tokenServiceFactory(ctx);
|
|
653
|
+
const existingToken = await tokenService.retrieveToken();
|
|
654
|
+
const cloudApiService = await cloudApiFactory(ctx, existingToken || void 0);
|
|
655
|
+
const trackFailedLogin = async () => {
|
|
656
|
+
try {
|
|
657
|
+
await cloudApiService.track("didNotLogin", { loginMethod: "cli" });
|
|
658
|
+
} catch (e) {
|
|
659
|
+
logger.debug("Failed to track failed login", e);
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
if (existingToken) {
|
|
663
|
+
const isTokenValid = await tokenService.isTokenValid(existingToken);
|
|
664
|
+
if (isTokenValid) {
|
|
665
|
+
try {
|
|
666
|
+
const userInfo = await cloudApiService.getUserInfo();
|
|
667
|
+
const { email } = userInfo.data.data;
|
|
668
|
+
if (email) {
|
|
669
|
+
logger.log(`You are already logged into your account (${email}).`);
|
|
670
|
+
} else {
|
|
671
|
+
logger.log("You are already logged in.");
|
|
672
|
+
}
|
|
673
|
+
logger.log(
|
|
674
|
+
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
675
|
+
);
|
|
676
|
+
logger.log(chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
677
|
+
return true;
|
|
678
|
+
} catch (e) {
|
|
679
|
+
logger.debug("Failed to fetch user info", e);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
let cliConfig2;
|
|
684
|
+
try {
|
|
685
|
+
logger.info("🔌 Connecting to the Strapi Cloud API...");
|
|
686
|
+
const config = await cloudApiService.config();
|
|
687
|
+
cliConfig2 = config.data;
|
|
688
|
+
} catch (e) {
|
|
689
|
+
logger.error("🥲 Oops! Something went wrong while logging you in. Please try again.");
|
|
690
|
+
logger.debug(e);
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
try {
|
|
694
|
+
await cloudApiService.track("willLoginAttempt", {});
|
|
695
|
+
} catch (e) {
|
|
696
|
+
logger.debug("Failed to track login attempt", e);
|
|
697
|
+
}
|
|
698
|
+
logger.debug("🔐 Creating device authentication request...", {
|
|
699
|
+
client_id: cliConfig2.clientId,
|
|
700
|
+
scope: cliConfig2.scope,
|
|
701
|
+
audience: cliConfig2.audience
|
|
702
|
+
});
|
|
703
|
+
const deviceAuthResponse = await axios__default.default.post(cliConfig2.deviceCodeAuthUrl, {
|
|
704
|
+
client_id: cliConfig2.clientId,
|
|
705
|
+
scope: cliConfig2.scope,
|
|
706
|
+
audience: cliConfig2.audience
|
|
707
|
+
}).catch((e) => {
|
|
708
|
+
logger.error("There was an issue with the authentication process. Please try again.");
|
|
709
|
+
if (e.message) {
|
|
710
|
+
logger.debug(e.message, e);
|
|
711
|
+
} else {
|
|
712
|
+
logger.debug(e);
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
openModule$1.then((open) => {
|
|
716
|
+
open.default(deviceAuthResponse.data.verification_uri_complete).catch((e) => {
|
|
717
|
+
logger.error("We encountered an issue opening the browser. Please try again later.");
|
|
718
|
+
logger.debug(e.message, e);
|
|
719
|
+
});
|
|
720
|
+
});
|
|
721
|
+
logger.log("If a browser tab does not open automatically, please follow the next steps:");
|
|
722
|
+
logger.log(
|
|
723
|
+
`1. Open this url in your device: ${deviceAuthResponse.data.verification_uri_complete}`
|
|
724
|
+
);
|
|
725
|
+
logger.log(
|
|
726
|
+
`2. Enter the following code: ${deviceAuthResponse.data.user_code} and confirm to login.
|
|
727
|
+
`
|
|
728
|
+
);
|
|
729
|
+
const tokenPayload = {
|
|
730
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
731
|
+
device_code: deviceAuthResponse.data.device_code,
|
|
732
|
+
client_id: cliConfig2.clientId
|
|
733
|
+
};
|
|
734
|
+
let isAuthenticated = false;
|
|
735
|
+
const authenticate = async () => {
|
|
736
|
+
const spinner = logger.spinner("Waiting for authentication");
|
|
737
|
+
spinner.start();
|
|
738
|
+
const spinnerFail = () => spinner.fail("Authentication failed!");
|
|
739
|
+
while (!isAuthenticated) {
|
|
740
|
+
try {
|
|
741
|
+
const tokenResponse = await axios__default.default.post(cliConfig2.tokenUrl, tokenPayload);
|
|
742
|
+
const authTokenData = tokenResponse.data;
|
|
743
|
+
if (tokenResponse.status === 200) {
|
|
744
|
+
try {
|
|
745
|
+
logger.debug("🔐 Validating token...");
|
|
746
|
+
await tokenService.validateToken(authTokenData.id_token, cliConfig2.jwksUrl);
|
|
747
|
+
logger.debug("🔐 Token validation successful!");
|
|
748
|
+
} catch (e) {
|
|
749
|
+
logger.debug(e);
|
|
750
|
+
spinnerFail();
|
|
751
|
+
throw new Error("Unable to proceed: Token validation failed");
|
|
752
|
+
}
|
|
753
|
+
logger.debug("🔍 Fetching user information...");
|
|
754
|
+
const cloudApiServiceWithToken = await cloudApiFactory(ctx, authTokenData.access_token);
|
|
755
|
+
await cloudApiServiceWithToken.getUserInfo();
|
|
756
|
+
logger.debug("🔍 User information fetched successfully!");
|
|
757
|
+
try {
|
|
758
|
+
logger.debug("📝 Saving login information...");
|
|
759
|
+
await tokenService.saveToken(authTokenData.access_token);
|
|
760
|
+
logger.debug("📝 Login information saved successfully!");
|
|
761
|
+
isAuthenticated = true;
|
|
762
|
+
} catch (e) {
|
|
763
|
+
logger.error(
|
|
764
|
+
"There was a problem saving your login information. Please try logging in again."
|
|
765
|
+
);
|
|
766
|
+
logger.debug(e);
|
|
767
|
+
spinnerFail();
|
|
768
|
+
return false;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
} catch (e) {
|
|
772
|
+
if (e.message === "Unable to proceed: Token validation failed") {
|
|
773
|
+
logger.error(
|
|
774
|
+
"There seems to be a problem with your login information. Please try logging in again."
|
|
775
|
+
);
|
|
776
|
+
spinnerFail();
|
|
777
|
+
await trackFailedLogin();
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
if (e.response?.data.error && !["authorization_pending", "slow_down"].includes(e.response.data.error)) {
|
|
781
|
+
logger.debug(e);
|
|
782
|
+
spinnerFail();
|
|
783
|
+
await trackFailedLogin();
|
|
784
|
+
return false;
|
|
785
|
+
}
|
|
786
|
+
await new Promise((resolve) => {
|
|
787
|
+
setTimeout(resolve, deviceAuthResponse.data.interval * 1e3);
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
spinner.succeed("Authentication successful!");
|
|
792
|
+
logger.log("You are now logged into Strapi Cloud.");
|
|
793
|
+
logger.log(
|
|
794
|
+
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
795
|
+
);
|
|
796
|
+
logger.log(chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
797
|
+
try {
|
|
798
|
+
await cloudApiService.track("didLogin", { loginMethod: "cli" });
|
|
799
|
+
} catch (e) {
|
|
800
|
+
logger.debug("Failed to track login", e);
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
await authenticate();
|
|
804
|
+
return isAuthenticated;
|
|
805
|
+
}
|
|
806
|
+
async function handleError(ctx, error) {
|
|
623
807
|
const { logger } = ctx;
|
|
624
808
|
logger.debug(error);
|
|
625
809
|
if (error instanceof axios.AxiosError) {
|
|
626
810
|
const errorMessage = typeof error.response?.data === "string" ? error.response.data : null;
|
|
627
811
|
switch (error.response?.status) {
|
|
628
|
-
case 401:
|
|
629
|
-
logger.error("Your session has expired. Please log in again.");
|
|
630
|
-
await tokenService.eraseToken();
|
|
631
|
-
return;
|
|
632
812
|
case 403:
|
|
633
813
|
logger.error(
|
|
634
814
|
errorMessage || "You do not have permission to create a project. Please contact support for assistance."
|
|
@@ -654,28 +834,44 @@ async function handleError(ctx, error) {
|
|
|
654
834
|
"We encountered an issue while creating your project. Please try again in a moment. If the problem persists, contact support for assistance."
|
|
655
835
|
);
|
|
656
836
|
}
|
|
657
|
-
|
|
837
|
+
async function createProject$1(ctx, cloudApi, projectInput) {
|
|
658
838
|
const { logger } = ctx;
|
|
659
|
-
const
|
|
660
|
-
|
|
839
|
+
const spinner = logger.spinner("Setting up your project...").start();
|
|
840
|
+
try {
|
|
841
|
+
const { data } = await cloudApi.createProject(projectInput);
|
|
842
|
+
await save({ project: data });
|
|
843
|
+
spinner.succeed("Project created successfully!");
|
|
844
|
+
return data;
|
|
845
|
+
} catch (e) {
|
|
846
|
+
spinner.fail("An error occurred while creating the project on Strapi Cloud.");
|
|
847
|
+
throw e;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
const action$2 = async (ctx) => {
|
|
851
|
+
const { logger } = ctx;
|
|
852
|
+
const { getValidToken, eraseToken } = await tokenServiceFactory(ctx);
|
|
853
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
661
854
|
if (!token) {
|
|
662
855
|
return;
|
|
663
856
|
}
|
|
664
|
-
const cloudApi = await cloudApiFactory(token);
|
|
857
|
+
const cloudApi = await cloudApiFactory(ctx, token);
|
|
665
858
|
const { data: config } = await cloudApi.config();
|
|
666
859
|
const { questions, defaults: defaultValues } = config.projectCreation;
|
|
667
860
|
const projectAnswersDefaulted = fp.defaults(defaultValues);
|
|
668
861
|
const projectAnswers = await inquirer__default.default.prompt(questions);
|
|
669
862
|
const projectInput = projectAnswersDefaulted(projectAnswers);
|
|
670
|
-
const spinner = logger.spinner("Setting up your project...").start();
|
|
671
863
|
try {
|
|
672
|
-
|
|
673
|
-
await save({ project: data });
|
|
674
|
-
spinner.succeed("Project created successfully!");
|
|
675
|
-
return data;
|
|
864
|
+
return await createProject$1(ctx, cloudApi, projectInput);
|
|
676
865
|
} catch (e) {
|
|
677
|
-
|
|
678
|
-
|
|
866
|
+
if (e instanceof axios.AxiosError && e.response?.status === 401) {
|
|
867
|
+
logger.warn("Oops! Your session has expired. Please log in again to retry.");
|
|
868
|
+
await eraseToken();
|
|
869
|
+
if (await promptLogin(ctx)) {
|
|
870
|
+
return await createProject$1(ctx, cloudApi, projectInput);
|
|
871
|
+
}
|
|
872
|
+
} else {
|
|
873
|
+
await handleError(ctx, e);
|
|
874
|
+
}
|
|
679
875
|
}
|
|
680
876
|
};
|
|
681
877
|
function notificationServiceFactory({ logger }) {
|
|
@@ -803,7 +999,7 @@ const buildLogsServiceFactory = ({ logger }) => {
|
|
|
803
999
|
};
|
|
804
1000
|
};
|
|
805
1001
|
async function upload(ctx, project, token, maxProjectFileSize) {
|
|
806
|
-
const cloudApi = await cloudApiFactory(token);
|
|
1002
|
+
const cloudApi = await cloudApiFactory(ctx, token);
|
|
807
1003
|
try {
|
|
808
1004
|
const storagePath = await getTmpStoragePath();
|
|
809
1005
|
const projectFolder = path__namespace.default.resolve(process.cwd());
|
|
@@ -894,7 +1090,7 @@ async function getProject(ctx) {
|
|
|
894
1090
|
const { project } = await retrieve();
|
|
895
1091
|
if (!project) {
|
|
896
1092
|
try {
|
|
897
|
-
return await action$
|
|
1093
|
+
return await action$2(ctx);
|
|
898
1094
|
} catch (e) {
|
|
899
1095
|
ctx.logger.error("An error occurred while deploying the project. Please try again later.");
|
|
900
1096
|
ctx.logger.debug(e);
|
|
@@ -903,10 +1099,9 @@ async function getProject(ctx) {
|
|
|
903
1099
|
}
|
|
904
1100
|
return project;
|
|
905
1101
|
}
|
|
906
|
-
const action$
|
|
1102
|
+
const action$1 = async (ctx) => {
|
|
907
1103
|
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
908
|
-
const
|
|
909
|
-
const token = await getValidToken();
|
|
1104
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
910
1105
|
if (!token) {
|
|
911
1106
|
return;
|
|
912
1107
|
}
|
|
@@ -914,6 +1109,7 @@ const action$2 = async (ctx) => {
|
|
|
914
1109
|
if (!project) {
|
|
915
1110
|
return;
|
|
916
1111
|
}
|
|
1112
|
+
const cloudApiService = await cloudApiFactory(ctx);
|
|
917
1113
|
try {
|
|
918
1114
|
await cloudApiService.track("willDeployWithCLI", { projectInternalName: project.name });
|
|
919
1115
|
} catch (e) {
|
|
@@ -978,183 +1174,27 @@ const runAction = (name2, action2) => (...args) => {
|
|
|
978
1174
|
});
|
|
979
1175
|
};
|
|
980
1176
|
const command$3 = ({ command: command2, ctx }) => {
|
|
981
|
-
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$
|
|
1177
|
+
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));
|
|
982
1178
|
};
|
|
983
1179
|
const deployProject = {
|
|
984
1180
|
name: "deploy-project",
|
|
985
1181
|
description: "Deploy a Strapi Cloud project",
|
|
986
|
-
action: action$
|
|
1182
|
+
action: action$1,
|
|
987
1183
|
command: command$3
|
|
988
1184
|
};
|
|
989
|
-
const openModule = import("open");
|
|
990
|
-
const action$1 = async (ctx) => {
|
|
991
|
-
const { logger } = ctx;
|
|
992
|
-
const tokenService = await tokenServiceFactory(ctx);
|
|
993
|
-
const existingToken = await tokenService.retrieveToken();
|
|
994
|
-
const cloudApiService = await cloudApiFactory(existingToken || void 0);
|
|
995
|
-
const trackFailedLogin = async () => {
|
|
996
|
-
try {
|
|
997
|
-
await cloudApiService.track("didNotLogin", { loginMethod: "cli" });
|
|
998
|
-
} catch (e) {
|
|
999
|
-
logger.debug("Failed to track failed login", e);
|
|
1000
|
-
}
|
|
1001
|
-
};
|
|
1002
|
-
if (existingToken) {
|
|
1003
|
-
const isTokenValid = await tokenService.isTokenValid(existingToken);
|
|
1004
|
-
if (isTokenValid) {
|
|
1005
|
-
try {
|
|
1006
|
-
const userInfo = await cloudApiService.getUserInfo();
|
|
1007
|
-
const { email } = userInfo.data.data;
|
|
1008
|
-
if (email) {
|
|
1009
|
-
logger.log(`You are already logged into your account (${email}).`);
|
|
1010
|
-
} else {
|
|
1011
|
-
logger.log("You are already logged in.");
|
|
1012
|
-
}
|
|
1013
|
-
logger.log(
|
|
1014
|
-
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
1015
|
-
);
|
|
1016
|
-
logger.log(chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
1017
|
-
return true;
|
|
1018
|
-
} catch (e) {
|
|
1019
|
-
logger.debug("Failed to fetch user info", e);
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
let cliConfig2;
|
|
1024
|
-
try {
|
|
1025
|
-
logger.info("🔌 Connecting to the Strapi Cloud API...");
|
|
1026
|
-
const config = await cloudApiService.config();
|
|
1027
|
-
cliConfig2 = config.data;
|
|
1028
|
-
} catch (e) {
|
|
1029
|
-
logger.error("🥲 Oops! Something went wrong while logging you in. Please try again.");
|
|
1030
|
-
logger.debug(e);
|
|
1031
|
-
return false;
|
|
1032
|
-
}
|
|
1033
|
-
try {
|
|
1034
|
-
await cloudApiService.track("willLoginAttempt", {});
|
|
1035
|
-
} catch (e) {
|
|
1036
|
-
logger.debug("Failed to track login attempt", e);
|
|
1037
|
-
}
|
|
1038
|
-
logger.debug("🔐 Creating device authentication request...", {
|
|
1039
|
-
client_id: cliConfig2.clientId,
|
|
1040
|
-
scope: cliConfig2.scope,
|
|
1041
|
-
audience: cliConfig2.audience
|
|
1042
|
-
});
|
|
1043
|
-
const deviceAuthResponse = await axios__default.default.post(cliConfig2.deviceCodeAuthUrl, {
|
|
1044
|
-
client_id: cliConfig2.clientId,
|
|
1045
|
-
scope: cliConfig2.scope,
|
|
1046
|
-
audience: cliConfig2.audience
|
|
1047
|
-
}).catch((e) => {
|
|
1048
|
-
logger.error("There was an issue with the authentication process. Please try again.");
|
|
1049
|
-
if (e.message) {
|
|
1050
|
-
logger.debug(e.message, e);
|
|
1051
|
-
} else {
|
|
1052
|
-
logger.debug(e);
|
|
1053
|
-
}
|
|
1054
|
-
});
|
|
1055
|
-
openModule.then((open) => {
|
|
1056
|
-
open.default(deviceAuthResponse.data.verification_uri_complete).catch((e) => {
|
|
1057
|
-
logger.error("We encountered an issue opening the browser. Please try again later.");
|
|
1058
|
-
logger.debug(e.message, e);
|
|
1059
|
-
});
|
|
1060
|
-
});
|
|
1061
|
-
logger.log("If a browser tab does not open automatically, please follow the next steps:");
|
|
1062
|
-
logger.log(
|
|
1063
|
-
`1. Open this url in your device: ${deviceAuthResponse.data.verification_uri_complete}`
|
|
1064
|
-
);
|
|
1065
|
-
logger.log(
|
|
1066
|
-
`2. Enter the following code: ${deviceAuthResponse.data.user_code} and confirm to login.
|
|
1067
|
-
`
|
|
1068
|
-
);
|
|
1069
|
-
const tokenPayload = {
|
|
1070
|
-
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
1071
|
-
device_code: deviceAuthResponse.data.device_code,
|
|
1072
|
-
client_id: cliConfig2.clientId
|
|
1073
|
-
};
|
|
1074
|
-
let isAuthenticated = false;
|
|
1075
|
-
const authenticate = async () => {
|
|
1076
|
-
const spinner = logger.spinner("Waiting for authentication");
|
|
1077
|
-
spinner.start();
|
|
1078
|
-
const spinnerFail = () => spinner.fail("Authentication failed!");
|
|
1079
|
-
while (!isAuthenticated) {
|
|
1080
|
-
try {
|
|
1081
|
-
const tokenResponse = await axios__default.default.post(cliConfig2.tokenUrl, tokenPayload);
|
|
1082
|
-
const authTokenData = tokenResponse.data;
|
|
1083
|
-
if (tokenResponse.status === 200) {
|
|
1084
|
-
try {
|
|
1085
|
-
logger.debug("🔐 Validating token...");
|
|
1086
|
-
await tokenService.validateToken(authTokenData.id_token, cliConfig2.jwksUrl);
|
|
1087
|
-
logger.debug("🔐 Token validation successful!");
|
|
1088
|
-
} catch (e) {
|
|
1089
|
-
logger.debug(e);
|
|
1090
|
-
spinnerFail();
|
|
1091
|
-
throw new Error("Unable to proceed: Token validation failed");
|
|
1092
|
-
}
|
|
1093
|
-
logger.debug("🔍 Fetching user information...");
|
|
1094
|
-
const cloudApiServiceWithToken = await cloudApiFactory(authTokenData.access_token);
|
|
1095
|
-
await cloudApiServiceWithToken.getUserInfo();
|
|
1096
|
-
logger.debug("🔍 User information fetched successfully!");
|
|
1097
|
-
try {
|
|
1098
|
-
logger.debug("📝 Saving login information...");
|
|
1099
|
-
await tokenService.saveToken(authTokenData.access_token);
|
|
1100
|
-
logger.debug("📝 Login information saved successfully!");
|
|
1101
|
-
isAuthenticated = true;
|
|
1102
|
-
} catch (e) {
|
|
1103
|
-
logger.error(
|
|
1104
|
-
"There was a problem saving your login information. Please try logging in again."
|
|
1105
|
-
);
|
|
1106
|
-
logger.debug(e);
|
|
1107
|
-
spinnerFail();
|
|
1108
|
-
return false;
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
} catch (e) {
|
|
1112
|
-
if (e.message === "Unable to proceed: Token validation failed") {
|
|
1113
|
-
logger.error(
|
|
1114
|
-
"There seems to be a problem with your login information. Please try logging in again."
|
|
1115
|
-
);
|
|
1116
|
-
spinnerFail();
|
|
1117
|
-
await trackFailedLogin();
|
|
1118
|
-
return false;
|
|
1119
|
-
}
|
|
1120
|
-
if (e.response?.data.error && !["authorization_pending", "slow_down"].includes(e.response.data.error)) {
|
|
1121
|
-
logger.debug(e);
|
|
1122
|
-
spinnerFail();
|
|
1123
|
-
await trackFailedLogin();
|
|
1124
|
-
return false;
|
|
1125
|
-
}
|
|
1126
|
-
await new Promise((resolve) => {
|
|
1127
|
-
setTimeout(resolve, deviceAuthResponse.data.interval * 1e3);
|
|
1128
|
-
});
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
spinner.succeed("Authentication successful!");
|
|
1132
|
-
logger.log("You are now logged into Strapi Cloud.");
|
|
1133
|
-
logger.log(
|
|
1134
|
-
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
1135
|
-
);
|
|
1136
|
-
logger.log(chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
1137
|
-
try {
|
|
1138
|
-
await cloudApiService.track("didLogin", { loginMethod: "cli" });
|
|
1139
|
-
} catch (e) {
|
|
1140
|
-
logger.debug("Failed to track login", e);
|
|
1141
|
-
}
|
|
1142
|
-
};
|
|
1143
|
-
await authenticate();
|
|
1144
|
-
return isAuthenticated;
|
|
1145
|
-
};
|
|
1146
1185
|
const command$2 = ({ command: command2, ctx }) => {
|
|
1147
1186
|
command2.command("cloud:login").alias("login").description("Strapi Cloud Login").addHelpText(
|
|
1148
1187
|
"after",
|
|
1149
1188
|
"\nAfter running this command, you will be prompted to enter your authentication information."
|
|
1150
|
-
).option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("login",
|
|
1189
|
+
).option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("login", loginAction)(ctx));
|
|
1151
1190
|
};
|
|
1152
1191
|
const login = {
|
|
1153
1192
|
name: "login",
|
|
1154
1193
|
description: "Strapi Cloud Login",
|
|
1155
|
-
action:
|
|
1194
|
+
action: loginAction,
|
|
1156
1195
|
command: command$2
|
|
1157
1196
|
};
|
|
1197
|
+
const openModule = import("open");
|
|
1158
1198
|
const action = async (ctx) => {
|
|
1159
1199
|
const { logger } = ctx;
|
|
1160
1200
|
const { retrieveToken, eraseToken } = await tokenServiceFactory(ctx);
|
|
@@ -1163,9 +1203,21 @@ const action = async (ctx) => {
|
|
|
1163
1203
|
logger.log("You're already logged out.");
|
|
1164
1204
|
return;
|
|
1165
1205
|
}
|
|
1166
|
-
const cloudApiService = await cloudApiFactory(token);
|
|
1206
|
+
const cloudApiService = await cloudApiFactory(ctx, token);
|
|
1207
|
+
const config = await cloudApiService.config();
|
|
1208
|
+
const cliConfig2 = config.data;
|
|
1167
1209
|
try {
|
|
1168
1210
|
await eraseToken();
|
|
1211
|
+
openModule.then((open) => {
|
|
1212
|
+
open.default(
|
|
1213
|
+
`${cliConfig2.baseUrl}/oidc/logout?client_id=${encodeURIComponent(
|
|
1214
|
+
cliConfig2.clientId
|
|
1215
|
+
)}&logout_hint=${encodeURIComponent(token)}
|
|
1216
|
+
`
|
|
1217
|
+
).catch((e) => {
|
|
1218
|
+
logger.debug(e.message, e);
|
|
1219
|
+
});
|
|
1220
|
+
});
|
|
1169
1221
|
logger.log(
|
|
1170
1222
|
"🔌 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."
|
|
1171
1223
|
);
|
|
@@ -1189,12 +1241,12 @@ const logout = {
|
|
|
1189
1241
|
command: command$1
|
|
1190
1242
|
};
|
|
1191
1243
|
const command = ({ command: command2, ctx }) => {
|
|
1192
|
-
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$
|
|
1244
|
+
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));
|
|
1193
1245
|
};
|
|
1194
1246
|
const createProject = {
|
|
1195
1247
|
name: "create-project",
|
|
1196
1248
|
description: "Create a new project",
|
|
1197
|
-
action: action$
|
|
1249
|
+
action: action$2,
|
|
1198
1250
|
command
|
|
1199
1251
|
};
|
|
1200
1252
|
const cli = {
|