@strapi/cloud-cli 0.0.0-next.a64ced5364618f917adb31b8684b4e3c01c58862 → 0.0.0-next.ae38a9dcdeddea4b4c0978686fb024413e5c54f5
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 +405 -287
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +404 -284
- 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/create-project/utils/apply-default-name.d.ts +7 -0
- package/dist/src/create-project/utils/apply-default-name.d.ts.map +1 -0
- package/dist/src/create-project/utils/get-project-name-from-pkg.d.ts +3 -0
- package/dist/src/create-project/utils/get-project-name-from-pkg.d.ts.map +1 -0
- package/dist/src/deploy-project/action.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/list-projects/action.d.ts +4 -0
- package/dist/src/list-projects/action.d.ts.map +1 -0
- package/dist/src/list-projects/command.d.ts +7 -0
- package/dist/src/list-projects/command.d.ts.map +1 -0
- package/dist/src/list-projects/index.d.ts +7 -0
- package/dist/src/list-projects/index.d.ts.map +1 -0
- 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 +10 -3
- 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/dist/src/utils/compress-files.d.ts.map +1 -1
- package/dist/src/utils/pkg.d.ts.map +1 -1
- package/package.json +6 -5
- package/dist/src/utils/tests/compress-files.test.d.ts +0 -2
- package/dist/src/utils/tests/compress-files.test.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -29,7 +29,6 @@ const chalk = require("chalk");
|
|
|
29
29
|
const axios = require("axios");
|
|
30
30
|
const crypto = require("node:crypto");
|
|
31
31
|
const utils = require("@strapi/utils");
|
|
32
|
-
const fs = require("fs");
|
|
33
32
|
const tar = require("tar");
|
|
34
33
|
const minimatch = require("minimatch");
|
|
35
34
|
const inquirer = require("inquirer");
|
|
@@ -41,10 +40,10 @@ const jwt = require("jsonwebtoken");
|
|
|
41
40
|
const stringify = require("fast-safe-stringify");
|
|
42
41
|
const ora = require("ora");
|
|
43
42
|
const cliProgress = require("cli-progress");
|
|
44
|
-
const EventSource = require("eventsource");
|
|
45
|
-
const fs$1 = require("fs/promises");
|
|
46
43
|
const pkgUp = require("pkg-up");
|
|
47
44
|
const yup = require("yup");
|
|
45
|
+
const _ = require("lodash");
|
|
46
|
+
const EventSource = require("eventsource");
|
|
48
47
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
49
48
|
function _interopNamespace(e) {
|
|
50
49
|
if (e && e.__esModule)
|
|
@@ -65,12 +64,11 @@ function _interopNamespace(e) {
|
|
|
65
64
|
return Object.freeze(n);
|
|
66
65
|
}
|
|
67
66
|
const crypto__default = /* @__PURE__ */ _interopDefault(crypto$1);
|
|
68
|
-
const
|
|
67
|
+
const fse__namespace = /* @__PURE__ */ _interopNamespace(fse);
|
|
69
68
|
const path__namespace = /* @__PURE__ */ _interopNamespace(path);
|
|
70
69
|
const chalk__default = /* @__PURE__ */ _interopDefault(chalk);
|
|
71
70
|
const axios__default = /* @__PURE__ */ _interopDefault(axios);
|
|
72
71
|
const crypto__namespace = /* @__PURE__ */ _interopNamespace(crypto);
|
|
73
|
-
const fs__namespace = /* @__PURE__ */ _interopNamespace(fs);
|
|
74
72
|
const tar__namespace = /* @__PURE__ */ _interopNamespace(tar);
|
|
75
73
|
const inquirer__default = /* @__PURE__ */ _interopDefault(inquirer);
|
|
76
74
|
const os__default = /* @__PURE__ */ _interopDefault(os);
|
|
@@ -80,10 +78,10 @@ const jwt__default = /* @__PURE__ */ _interopDefault(jwt);
|
|
|
80
78
|
const stringify__default = /* @__PURE__ */ _interopDefault(stringify);
|
|
81
79
|
const ora__default = /* @__PURE__ */ _interopDefault(ora);
|
|
82
80
|
const cliProgress__namespace = /* @__PURE__ */ _interopNamespace(cliProgress);
|
|
83
|
-
const EventSource__default = /* @__PURE__ */ _interopDefault(EventSource);
|
|
84
|
-
const fs__default = /* @__PURE__ */ _interopDefault(fs$1);
|
|
85
81
|
const pkgUp__default = /* @__PURE__ */ _interopDefault(pkgUp);
|
|
86
82
|
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
|
83
|
+
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
84
|
+
const EventSource__default = /* @__PURE__ */ _interopDefault(EventSource);
|
|
87
85
|
const apiConfig = {
|
|
88
86
|
apiBaseUrl: utils.env("STRAPI_CLI_CLOUD_API", "https://cloud-cli-api.strapi.io"),
|
|
89
87
|
dashboardBaseUrl: utils.env("STRAPI_CLI_CLOUD_DASHBOARD", "https://cloud.strapi.io")
|
|
@@ -102,23 +100,6 @@ const IGNORED_PATTERNS = [
|
|
|
102
100
|
"**/.idea/**",
|
|
103
101
|
"**/.vscode/**"
|
|
104
102
|
];
|
|
105
|
-
const getFiles = (dirPath, ignorePatterns = [], arrayOfFiles = [], subfolder = "") => {
|
|
106
|
-
const entries = fs__namespace.readdirSync(path__namespace.join(dirPath, subfolder));
|
|
107
|
-
entries.forEach((entry) => {
|
|
108
|
-
const entryPathFromRoot = path__namespace.join(subfolder, entry);
|
|
109
|
-
const entryPath = path__namespace.relative(dirPath, entryPathFromRoot);
|
|
110
|
-
const isIgnored = isIgnoredFile(dirPath, entryPathFromRoot, ignorePatterns);
|
|
111
|
-
if (isIgnored) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (fs__namespace.statSync(entryPath).isDirectory()) {
|
|
115
|
-
getFiles(dirPath, ignorePatterns, arrayOfFiles, entryPathFromRoot);
|
|
116
|
-
} else {
|
|
117
|
-
arrayOfFiles.push(entryPath);
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
return arrayOfFiles;
|
|
121
|
-
};
|
|
122
103
|
const isIgnoredFile = (folderPath, file, ignorePatterns) => {
|
|
123
104
|
ignorePatterns.push(...IGNORED_PATTERNS);
|
|
124
105
|
const relativeFilePath = path__namespace.join(folderPath, file);
|
|
@@ -136,16 +117,35 @@ const isIgnoredFile = (folderPath, file, ignorePatterns) => {
|
|
|
136
117
|
}
|
|
137
118
|
return isIgnored;
|
|
138
119
|
};
|
|
139
|
-
const
|
|
120
|
+
const getFiles = async (dirPath, ignorePatterns = [], subfolder = "") => {
|
|
121
|
+
const arrayOfFiles = [];
|
|
122
|
+
const entries = await fse__namespace.readdir(path__namespace.join(dirPath, subfolder));
|
|
123
|
+
for (const entry of entries) {
|
|
124
|
+
const entryPathFromRoot = path__namespace.join(subfolder, entry);
|
|
125
|
+
const entryPath = path__namespace.relative(dirPath, entryPathFromRoot);
|
|
126
|
+
const isIgnored = isIgnoredFile(dirPath, entryPathFromRoot, ignorePatterns);
|
|
127
|
+
if (!isIgnored) {
|
|
128
|
+
if (fse__namespace.statSync(entryPath).isDirectory()) {
|
|
129
|
+
const subFiles = await getFiles(dirPath, ignorePatterns, entryPathFromRoot);
|
|
130
|
+
arrayOfFiles.push(...subFiles);
|
|
131
|
+
} else {
|
|
132
|
+
arrayOfFiles.push(entryPath);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return arrayOfFiles;
|
|
137
|
+
};
|
|
138
|
+
const readGitignore = async (folderPath) => {
|
|
140
139
|
const gitignorePath = path__namespace.resolve(folderPath, ".gitignore");
|
|
141
|
-
|
|
140
|
+
const pathExist = await fse__namespace.pathExists(gitignorePath);
|
|
141
|
+
if (!pathExist)
|
|
142
142
|
return [];
|
|
143
|
-
const gitignoreContent =
|
|
143
|
+
const gitignoreContent = await fse__namespace.readFile(gitignorePath, "utf8");
|
|
144
144
|
return gitignoreContent.split(/\r?\n/).filter((line) => Boolean(line.trim()) && !line.startsWith("#"));
|
|
145
145
|
};
|
|
146
146
|
const compressFilesToTar = async (storagePath, folderToCompress, filename) => {
|
|
147
|
-
const ignorePatterns = readGitignore(folderToCompress);
|
|
148
|
-
const filesToCompress = getFiles(folderToCompress, ignorePatterns);
|
|
147
|
+
const ignorePatterns = await readGitignore(folderToCompress);
|
|
148
|
+
const filesToCompress = await getFiles(folderToCompress, ignorePatterns);
|
|
149
149
|
return tar__namespace.c(
|
|
150
150
|
{
|
|
151
151
|
gzip: true,
|
|
@@ -158,7 +158,7 @@ const APP_FOLDER_NAME = "com.strapi.cli";
|
|
|
158
158
|
const CONFIG_FILENAME = "config.json";
|
|
159
159
|
async function checkDirectoryExists(directoryPath) {
|
|
160
160
|
try {
|
|
161
|
-
const fsStat = await
|
|
161
|
+
const fsStat = await fse__namespace.default.lstat(directoryPath);
|
|
162
162
|
return fsStat.isDirectory();
|
|
163
163
|
} catch (e) {
|
|
164
164
|
return false;
|
|
@@ -166,14 +166,14 @@ async function checkDirectoryExists(directoryPath) {
|
|
|
166
166
|
}
|
|
167
167
|
async function getTmpStoragePath() {
|
|
168
168
|
const storagePath = path__namespace.default.join(os__default.default.tmpdir(), APP_FOLDER_NAME);
|
|
169
|
-
await
|
|
169
|
+
await fse__namespace.default.ensureDir(storagePath);
|
|
170
170
|
return storagePath;
|
|
171
171
|
}
|
|
172
172
|
async function getConfigPath() {
|
|
173
173
|
const configDirs = XDGAppPaths__default.default(APP_FOLDER_NAME).configDirs();
|
|
174
174
|
const configPath = configDirs.find(checkDirectoryExists);
|
|
175
175
|
if (!configPath) {
|
|
176
|
-
await
|
|
176
|
+
await fse__namespace.default.ensureDir(configDirs[0]);
|
|
177
177
|
return configDirs[0];
|
|
178
178
|
}
|
|
179
179
|
return configPath;
|
|
@@ -181,9 +181,9 @@ async function getConfigPath() {
|
|
|
181
181
|
async function getLocalConfig() {
|
|
182
182
|
const configPath = await getConfigPath();
|
|
183
183
|
const configFilePath = path__namespace.default.join(configPath, CONFIG_FILENAME);
|
|
184
|
-
await
|
|
184
|
+
await fse__namespace.default.ensureFile(configFilePath);
|
|
185
185
|
try {
|
|
186
|
-
return await
|
|
186
|
+
return await fse__namespace.default.readJSON(configFilePath, { encoding: "utf8", throws: true });
|
|
187
187
|
} catch (e) {
|
|
188
188
|
return {};
|
|
189
189
|
}
|
|
@@ -191,10 +191,10 @@ async function getLocalConfig() {
|
|
|
191
191
|
async function saveLocalConfig(data) {
|
|
192
192
|
const configPath = await getConfigPath();
|
|
193
193
|
const configFilePath = path__namespace.default.join(configPath, CONFIG_FILENAME);
|
|
194
|
-
await
|
|
194
|
+
await fse__namespace.default.writeJson(configFilePath, data, { encoding: "utf8", spaces: 2, mode: 384 });
|
|
195
195
|
}
|
|
196
196
|
const name = "@strapi/cloud-cli";
|
|
197
|
-
const version = "4.25.
|
|
197
|
+
const version = "4.25.4";
|
|
198
198
|
const description = "Commands to interact with the Strapi Cloud";
|
|
199
199
|
const keywords = [
|
|
200
200
|
"strapi",
|
|
@@ -235,10 +235,11 @@ const scripts = {
|
|
|
235
235
|
build: "pack-up build",
|
|
236
236
|
clean: "run -T rimraf ./dist",
|
|
237
237
|
lint: "run -T eslint .",
|
|
238
|
+
"test:unit": "run -T jest",
|
|
238
239
|
watch: "pack-up watch"
|
|
239
240
|
};
|
|
240
241
|
const dependencies = {
|
|
241
|
-
"@strapi/utils": "4.25.
|
|
242
|
+
"@strapi/utils": "4.25.4",
|
|
242
243
|
axios: "1.6.0",
|
|
243
244
|
chalk: "4.1.2",
|
|
244
245
|
"cli-progress": "3.12.0",
|
|
@@ -263,8 +264,8 @@ const devDependencies = {
|
|
|
263
264
|
"@types/cli-progress": "3.11.5",
|
|
264
265
|
"@types/eventsource": "1.1.15",
|
|
265
266
|
"@types/lodash": "^4.14.191",
|
|
266
|
-
"eslint-config-custom": "4.25.
|
|
267
|
-
tsconfig: "4.25.
|
|
267
|
+
"eslint-config-custom": "4.25.4",
|
|
268
|
+
tsconfig: "4.25.4"
|
|
268
269
|
};
|
|
269
270
|
const engines = {
|
|
270
271
|
node: ">=18.0.0 <=20.x.x",
|
|
@@ -293,7 +294,7 @@ const packageJson = {
|
|
|
293
294
|
engines
|
|
294
295
|
};
|
|
295
296
|
const VERSION = "v1";
|
|
296
|
-
async function cloudApiFactory(token) {
|
|
297
|
+
async function cloudApiFactory({ logger }, token) {
|
|
297
298
|
const localConfig = await getLocalConfig();
|
|
298
299
|
const customHeaders = {
|
|
299
300
|
"x-device-id": localConfig.deviceId,
|
|
@@ -317,7 +318,7 @@ async function cloudApiFactory(token) {
|
|
|
317
318
|
deploy({ filePath, project }, { onUploadProgress }) {
|
|
318
319
|
return axiosCloudAPI.post(
|
|
319
320
|
`/deploy/${project.name}`,
|
|
320
|
-
{ file:
|
|
321
|
+
{ file: fse__namespace.default.createReadStream(filePath) },
|
|
321
322
|
{
|
|
322
323
|
headers: {
|
|
323
324
|
"Content-Type": "multipart/form-data"
|
|
@@ -346,11 +347,33 @@ async function cloudApiFactory(token) {
|
|
|
346
347
|
getUserInfo() {
|
|
347
348
|
return axiosCloudAPI.get("/user");
|
|
348
349
|
},
|
|
349
|
-
config() {
|
|
350
|
-
|
|
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
|
+
}
|
|
351
363
|
},
|
|
352
|
-
listProjects() {
|
|
353
|
-
|
|
364
|
+
async listProjects() {
|
|
365
|
+
try {
|
|
366
|
+
const response = await axiosCloudAPI.get("/projects");
|
|
367
|
+
if (response.status !== 200) {
|
|
368
|
+
throw new Error("Error fetching cloud projects from the server.");
|
|
369
|
+
}
|
|
370
|
+
return response;
|
|
371
|
+
} catch (error) {
|
|
372
|
+
logger.debug(
|
|
373
|
+
"🥲 Oops! Couldn't retrieve your project's list from the server. Please try again."
|
|
374
|
+
);
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
354
377
|
},
|
|
355
378
|
track(event, payload = {}) {
|
|
356
379
|
return axiosCloudAPI.post("/track", {
|
|
@@ -365,18 +388,18 @@ async function save(data, { directoryPath } = {}) {
|
|
|
365
388
|
const alreadyInFileData = await retrieve({ directoryPath });
|
|
366
389
|
const storedData = { ...alreadyInFileData, ...data };
|
|
367
390
|
const pathToFile = path__namespace.default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
|
|
368
|
-
await
|
|
369
|
-
await
|
|
391
|
+
await fse__namespace.default.ensureDir(path__namespace.default.dirname(pathToFile));
|
|
392
|
+
await fse__namespace.default.writeJson(pathToFile, storedData, { encoding: "utf8" });
|
|
370
393
|
}
|
|
371
394
|
async function retrieve({
|
|
372
395
|
directoryPath
|
|
373
396
|
} = {}) {
|
|
374
397
|
const pathToFile = path__namespace.default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
|
|
375
|
-
const pathExists = await
|
|
398
|
+
const pathExists = await fse__namespace.default.pathExists(pathToFile);
|
|
376
399
|
if (!pathExists) {
|
|
377
400
|
return {};
|
|
378
401
|
}
|
|
379
|
-
return
|
|
402
|
+
return fse__namespace.default.readJSON(pathToFile, { encoding: "utf8" });
|
|
380
403
|
}
|
|
381
404
|
const strapiInfoSave = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
382
405
|
__proto__: null,
|
|
@@ -386,7 +409,7 @@ const strapiInfoSave = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defi
|
|
|
386
409
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
387
410
|
let cliConfig;
|
|
388
411
|
async function tokenServiceFactory({ logger }) {
|
|
389
|
-
const cloudApiService = await cloudApiFactory();
|
|
412
|
+
const cloudApiService = await cloudApiFactory({ logger });
|
|
390
413
|
async function saveToken(str) {
|
|
391
414
|
const appConfig = await getLocalConfig();
|
|
392
415
|
if (!appConfig) {
|
|
@@ -435,14 +458,17 @@ async function tokenServiceFactory({ logger }) {
|
|
|
435
458
|
"There seems to be a problem with your login information. Please try logging in again."
|
|
436
459
|
);
|
|
437
460
|
}
|
|
461
|
+
return Promise.reject(new Error("Invalid token"));
|
|
438
462
|
}
|
|
439
463
|
return new Promise((resolve, reject) => {
|
|
440
464
|
jwt__default.default.verify(idToken, getKey, (err) => {
|
|
441
465
|
if (err) {
|
|
442
466
|
reject(err);
|
|
443
|
-
} else {
|
|
444
|
-
resolve();
|
|
445
467
|
}
|
|
468
|
+
if (decodedToken.payload.exp < Math.floor(Date.now() / 1e3)) {
|
|
469
|
+
reject(new Error("Token is expired"));
|
|
470
|
+
}
|
|
471
|
+
resolve();
|
|
446
472
|
});
|
|
447
473
|
});
|
|
448
474
|
}
|
|
@@ -476,15 +502,15 @@ async function tokenServiceFactory({ logger }) {
|
|
|
476
502
|
throw e;
|
|
477
503
|
}
|
|
478
504
|
}
|
|
479
|
-
async function getValidToken() {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
logger.log(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
505
|
+
async function getValidToken(ctx, loginAction2) {
|
|
506
|
+
let token = await retrieveToken();
|
|
507
|
+
while (!token || !await isTokenValid(token)) {
|
|
508
|
+
logger.log(
|
|
509
|
+
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."
|
|
510
|
+
);
|
|
511
|
+
if (!await loginAction2(ctx))
|
|
512
|
+
return null;
|
|
513
|
+
token = await retrieveToken();
|
|
488
514
|
}
|
|
489
515
|
return token;
|
|
490
516
|
}
|
|
@@ -618,17 +644,235 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
|
|
|
618
644
|
local: strapiInfoSave,
|
|
619
645
|
tokenServiceFactory
|
|
620
646
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
621
|
-
|
|
647
|
+
yup__namespace.object({
|
|
648
|
+
name: yup__namespace.string().required(),
|
|
649
|
+
exports: yup__namespace.lazy(
|
|
650
|
+
(value) => yup__namespace.object(
|
|
651
|
+
typeof value === "object" ? Object.entries(value).reduce((acc, [key, value2]) => {
|
|
652
|
+
if (typeof value2 === "object") {
|
|
653
|
+
acc[key] = yup__namespace.object({
|
|
654
|
+
types: yup__namespace.string().optional(),
|
|
655
|
+
source: yup__namespace.string().required(),
|
|
656
|
+
module: yup__namespace.string().optional(),
|
|
657
|
+
import: yup__namespace.string().required(),
|
|
658
|
+
require: yup__namespace.string().required(),
|
|
659
|
+
default: yup__namespace.string().required()
|
|
660
|
+
}).noUnknown(true);
|
|
661
|
+
} else {
|
|
662
|
+
acc[key] = yup__namespace.string().matches(/^\.\/.*\.json$/).required();
|
|
663
|
+
}
|
|
664
|
+
return acc;
|
|
665
|
+
}, {}) : void 0
|
|
666
|
+
).optional()
|
|
667
|
+
)
|
|
668
|
+
});
|
|
669
|
+
const loadPkg = async ({ cwd, logger }) => {
|
|
670
|
+
const pkgPath = await pkgUp__default.default({ cwd });
|
|
671
|
+
if (!pkgPath) {
|
|
672
|
+
throw new Error("Could not find a package.json in the current directory");
|
|
673
|
+
}
|
|
674
|
+
const buffer = await fse__namespace.readFile(pkgPath);
|
|
675
|
+
const pkg = JSON.parse(buffer.toString());
|
|
676
|
+
logger.debug("Loaded package.json:", os__default.default.EOL, pkg);
|
|
677
|
+
return pkg;
|
|
678
|
+
};
|
|
679
|
+
async function getProjectNameFromPackageJson(ctx) {
|
|
680
|
+
try {
|
|
681
|
+
const packageJson2 = await loadPkg(ctx);
|
|
682
|
+
return packageJson2.name || "my-strapi-project";
|
|
683
|
+
} catch (e) {
|
|
684
|
+
return "my-strapi-project";
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
function applyDefaultName(newDefaultName, questions, defaultValues) {
|
|
688
|
+
const newDefaultValues = ___default.default.cloneDeep(defaultValues);
|
|
689
|
+
newDefaultValues.name = newDefaultName;
|
|
690
|
+
const newQuestions = questions.map((question) => {
|
|
691
|
+
const questionCopy = ___default.default.cloneDeep(question);
|
|
692
|
+
if (questionCopy.name === "name") {
|
|
693
|
+
questionCopy.default = newDefaultName;
|
|
694
|
+
}
|
|
695
|
+
return questionCopy;
|
|
696
|
+
});
|
|
697
|
+
return { newQuestions, newDefaultValues };
|
|
698
|
+
}
|
|
699
|
+
const openModule$1 = import("open");
|
|
700
|
+
async function promptLogin(ctx) {
|
|
701
|
+
const response = await inquirer__default.default.prompt([
|
|
702
|
+
{
|
|
703
|
+
type: "confirm",
|
|
704
|
+
name: "login",
|
|
705
|
+
message: "Would you like to login?"
|
|
706
|
+
}
|
|
707
|
+
]);
|
|
708
|
+
if (response.login) {
|
|
709
|
+
const loginSuccessful = await loginAction(ctx);
|
|
710
|
+
return loginSuccessful;
|
|
711
|
+
}
|
|
712
|
+
return false;
|
|
713
|
+
}
|
|
714
|
+
async function loginAction(ctx) {
|
|
715
|
+
const { logger } = ctx;
|
|
622
716
|
const tokenService = await tokenServiceFactory(ctx);
|
|
717
|
+
const existingToken = await tokenService.retrieveToken();
|
|
718
|
+
const cloudApiService = await cloudApiFactory(ctx, existingToken || void 0);
|
|
719
|
+
const trackFailedLogin = async () => {
|
|
720
|
+
try {
|
|
721
|
+
await cloudApiService.track("didNotLogin", { loginMethod: "cli" });
|
|
722
|
+
} catch (e) {
|
|
723
|
+
logger.debug("Failed to track failed login", e);
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
if (existingToken) {
|
|
727
|
+
const isTokenValid = await tokenService.isTokenValid(existingToken);
|
|
728
|
+
if (isTokenValid) {
|
|
729
|
+
try {
|
|
730
|
+
const userInfo = await cloudApiService.getUserInfo();
|
|
731
|
+
const { email } = userInfo.data.data;
|
|
732
|
+
if (email) {
|
|
733
|
+
logger.log(`You are already logged into your account (${email}).`);
|
|
734
|
+
} else {
|
|
735
|
+
logger.log("You are already logged in.");
|
|
736
|
+
}
|
|
737
|
+
logger.log(
|
|
738
|
+
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
739
|
+
);
|
|
740
|
+
logger.log(chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
741
|
+
return true;
|
|
742
|
+
} catch (e) {
|
|
743
|
+
logger.debug("Failed to fetch user info", e);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
let cliConfig2;
|
|
748
|
+
try {
|
|
749
|
+
logger.info("🔌 Connecting to the Strapi Cloud API...");
|
|
750
|
+
const config = await cloudApiService.config();
|
|
751
|
+
cliConfig2 = config.data;
|
|
752
|
+
} catch (e) {
|
|
753
|
+
logger.error("🥲 Oops! Something went wrong while logging you in. Please try again.");
|
|
754
|
+
logger.debug(e);
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
try {
|
|
758
|
+
await cloudApiService.track("willLoginAttempt", {});
|
|
759
|
+
} catch (e) {
|
|
760
|
+
logger.debug("Failed to track login attempt", e);
|
|
761
|
+
}
|
|
762
|
+
logger.debug("🔐 Creating device authentication request...", {
|
|
763
|
+
client_id: cliConfig2.clientId,
|
|
764
|
+
scope: cliConfig2.scope,
|
|
765
|
+
audience: cliConfig2.audience
|
|
766
|
+
});
|
|
767
|
+
const deviceAuthResponse = await axios__default.default.post(cliConfig2.deviceCodeAuthUrl, {
|
|
768
|
+
client_id: cliConfig2.clientId,
|
|
769
|
+
scope: cliConfig2.scope,
|
|
770
|
+
audience: cliConfig2.audience
|
|
771
|
+
}).catch((e) => {
|
|
772
|
+
logger.error("There was an issue with the authentication process. Please try again.");
|
|
773
|
+
if (e.message) {
|
|
774
|
+
logger.debug(e.message, e);
|
|
775
|
+
} else {
|
|
776
|
+
logger.debug(e);
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
openModule$1.then((open) => {
|
|
780
|
+
open.default(deviceAuthResponse.data.verification_uri_complete).catch((e) => {
|
|
781
|
+
logger.error("We encountered an issue opening the browser. Please try again later.");
|
|
782
|
+
logger.debug(e.message, e);
|
|
783
|
+
});
|
|
784
|
+
});
|
|
785
|
+
logger.log("If a browser tab does not open automatically, please follow the next steps:");
|
|
786
|
+
logger.log(
|
|
787
|
+
`1. Open this url in your device: ${deviceAuthResponse.data.verification_uri_complete}`
|
|
788
|
+
);
|
|
789
|
+
logger.log(
|
|
790
|
+
`2. Enter the following code: ${deviceAuthResponse.data.user_code} and confirm to login.
|
|
791
|
+
`
|
|
792
|
+
);
|
|
793
|
+
const tokenPayload = {
|
|
794
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
795
|
+
device_code: deviceAuthResponse.data.device_code,
|
|
796
|
+
client_id: cliConfig2.clientId
|
|
797
|
+
};
|
|
798
|
+
let isAuthenticated = false;
|
|
799
|
+
const authenticate = async () => {
|
|
800
|
+
const spinner = logger.spinner("Waiting for authentication");
|
|
801
|
+
spinner.start();
|
|
802
|
+
const spinnerFail = () => spinner.fail("Authentication failed!");
|
|
803
|
+
while (!isAuthenticated) {
|
|
804
|
+
try {
|
|
805
|
+
const tokenResponse = await axios__default.default.post(cliConfig2.tokenUrl, tokenPayload);
|
|
806
|
+
const authTokenData = tokenResponse.data;
|
|
807
|
+
if (tokenResponse.status === 200) {
|
|
808
|
+
try {
|
|
809
|
+
logger.debug("🔐 Validating token...");
|
|
810
|
+
await tokenService.validateToken(authTokenData.id_token, cliConfig2.jwksUrl);
|
|
811
|
+
logger.debug("🔐 Token validation successful!");
|
|
812
|
+
} catch (e) {
|
|
813
|
+
logger.debug(e);
|
|
814
|
+
spinnerFail();
|
|
815
|
+
throw new Error("Unable to proceed: Token validation failed");
|
|
816
|
+
}
|
|
817
|
+
logger.debug("🔍 Fetching user information...");
|
|
818
|
+
const cloudApiServiceWithToken = await cloudApiFactory(ctx, authTokenData.access_token);
|
|
819
|
+
await cloudApiServiceWithToken.getUserInfo();
|
|
820
|
+
logger.debug("🔍 User information fetched successfully!");
|
|
821
|
+
try {
|
|
822
|
+
logger.debug("📝 Saving login information...");
|
|
823
|
+
await tokenService.saveToken(authTokenData.access_token);
|
|
824
|
+
logger.debug("📝 Login information saved successfully!");
|
|
825
|
+
isAuthenticated = true;
|
|
826
|
+
} catch (e) {
|
|
827
|
+
logger.error(
|
|
828
|
+
"There was a problem saving your login information. Please try logging in again."
|
|
829
|
+
);
|
|
830
|
+
logger.debug(e);
|
|
831
|
+
spinnerFail();
|
|
832
|
+
return false;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
} catch (e) {
|
|
836
|
+
if (e.message === "Unable to proceed: Token validation failed") {
|
|
837
|
+
logger.error(
|
|
838
|
+
"There seems to be a problem with your login information. Please try logging in again."
|
|
839
|
+
);
|
|
840
|
+
spinnerFail();
|
|
841
|
+
await trackFailedLogin();
|
|
842
|
+
return false;
|
|
843
|
+
}
|
|
844
|
+
if (e.response?.data.error && !["authorization_pending", "slow_down"].includes(e.response.data.error)) {
|
|
845
|
+
logger.debug(e);
|
|
846
|
+
spinnerFail();
|
|
847
|
+
await trackFailedLogin();
|
|
848
|
+
return false;
|
|
849
|
+
}
|
|
850
|
+
await new Promise((resolve) => {
|
|
851
|
+
setTimeout(resolve, deviceAuthResponse.data.interval * 1e3);
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
spinner.succeed("Authentication successful!");
|
|
856
|
+
logger.log("You are now logged into Strapi Cloud.");
|
|
857
|
+
logger.log(
|
|
858
|
+
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
859
|
+
);
|
|
860
|
+
logger.log(chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
861
|
+
try {
|
|
862
|
+
await cloudApiService.track("didLogin", { loginMethod: "cli" });
|
|
863
|
+
} catch (e) {
|
|
864
|
+
logger.debug("Failed to track login", e);
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
await authenticate();
|
|
868
|
+
return isAuthenticated;
|
|
869
|
+
}
|
|
870
|
+
async function handleError(ctx, error) {
|
|
623
871
|
const { logger } = ctx;
|
|
624
872
|
logger.debug(error);
|
|
625
873
|
if (error instanceof axios.AxiosError) {
|
|
626
874
|
const errorMessage = typeof error.response?.data === "string" ? error.response.data : null;
|
|
627
875
|
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
876
|
case 403:
|
|
633
877
|
logger.error(
|
|
634
878
|
errorMessage || "You do not have permission to create a project. Please contact support for assistance."
|
|
@@ -654,28 +898,48 @@ async function handleError(ctx, error) {
|
|
|
654
898
|
"We encountered an issue while creating your project. Please try again in a moment. If the problem persists, contact support for assistance."
|
|
655
899
|
);
|
|
656
900
|
}
|
|
901
|
+
async function createProject$1(ctx, cloudApi, projectInput) {
|
|
902
|
+
const { logger } = ctx;
|
|
903
|
+
const spinner = logger.spinner("Setting up your project...").start();
|
|
904
|
+
try {
|
|
905
|
+
const { data } = await cloudApi.createProject(projectInput);
|
|
906
|
+
await save({ project: data });
|
|
907
|
+
spinner.succeed("Project created successfully!");
|
|
908
|
+
return data;
|
|
909
|
+
} catch (e) {
|
|
910
|
+
spinner.fail("An error occurred while creating the project on Strapi Cloud.");
|
|
911
|
+
throw e;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
657
914
|
const action$3 = async (ctx) => {
|
|
658
915
|
const { logger } = ctx;
|
|
659
|
-
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
660
|
-
const token = await getValidToken();
|
|
916
|
+
const { getValidToken, eraseToken } = await tokenServiceFactory(ctx);
|
|
917
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
661
918
|
if (!token) {
|
|
662
919
|
return;
|
|
663
920
|
}
|
|
664
|
-
const cloudApi = await cloudApiFactory(token);
|
|
921
|
+
const cloudApi = await cloudApiFactory(ctx, token);
|
|
665
922
|
const { data: config } = await cloudApi.config();
|
|
666
|
-
const { questions,
|
|
923
|
+
const { newQuestions: questions, newDefaultValues: defaultValues } = applyDefaultName(
|
|
924
|
+
await getProjectNameFromPackageJson(ctx),
|
|
925
|
+
config.projectCreation.questions,
|
|
926
|
+
config.projectCreation.defaults
|
|
927
|
+
);
|
|
667
928
|
const projectAnswersDefaulted = fp.defaults(defaultValues);
|
|
668
929
|
const projectAnswers = await inquirer__default.default.prompt(questions);
|
|
669
930
|
const projectInput = projectAnswersDefaulted(projectAnswers);
|
|
670
|
-
const spinner = logger.spinner("Setting up your project...").start();
|
|
671
931
|
try {
|
|
672
|
-
|
|
673
|
-
await save({ project: data });
|
|
674
|
-
spinner.succeed("Project created successfully!");
|
|
675
|
-
return data;
|
|
932
|
+
return await createProject$1(ctx, cloudApi, projectInput);
|
|
676
933
|
} catch (e) {
|
|
677
|
-
|
|
678
|
-
|
|
934
|
+
if (e instanceof axios.AxiosError && e.response?.status === 401) {
|
|
935
|
+
logger.warn("Oops! Your session has expired. Please log in again to retry.");
|
|
936
|
+
await eraseToken();
|
|
937
|
+
if (await promptLogin(ctx)) {
|
|
938
|
+
return await createProject$1(ctx, cloudApi, projectInput);
|
|
939
|
+
}
|
|
940
|
+
} else {
|
|
941
|
+
await handleError(ctx, e);
|
|
942
|
+
}
|
|
679
943
|
}
|
|
680
944
|
};
|
|
681
945
|
function notificationServiceFactory({ logger }) {
|
|
@@ -709,38 +973,6 @@ function notificationServiceFactory({ logger }) {
|
|
|
709
973
|
};
|
|
710
974
|
};
|
|
711
975
|
}
|
|
712
|
-
yup__namespace.object({
|
|
713
|
-
name: yup__namespace.string().required(),
|
|
714
|
-
exports: yup__namespace.lazy(
|
|
715
|
-
(value) => yup__namespace.object(
|
|
716
|
-
typeof value === "object" ? Object.entries(value).reduce((acc, [key, value2]) => {
|
|
717
|
-
if (typeof value2 === "object") {
|
|
718
|
-
acc[key] = yup__namespace.object({
|
|
719
|
-
types: yup__namespace.string().optional(),
|
|
720
|
-
source: yup__namespace.string().required(),
|
|
721
|
-
module: yup__namespace.string().optional(),
|
|
722
|
-
import: yup__namespace.string().required(),
|
|
723
|
-
require: yup__namespace.string().required(),
|
|
724
|
-
default: yup__namespace.string().required()
|
|
725
|
-
}).noUnknown(true);
|
|
726
|
-
} else {
|
|
727
|
-
acc[key] = yup__namespace.string().matches(/^\.\/.*\.json$/).required();
|
|
728
|
-
}
|
|
729
|
-
return acc;
|
|
730
|
-
}, {}) : void 0
|
|
731
|
-
).optional()
|
|
732
|
-
)
|
|
733
|
-
});
|
|
734
|
-
const loadPkg = async ({ cwd, logger }) => {
|
|
735
|
-
const pkgPath = await pkgUp__default.default({ cwd });
|
|
736
|
-
if (!pkgPath) {
|
|
737
|
-
throw new Error("Could not find a package.json in the current directory");
|
|
738
|
-
}
|
|
739
|
-
const buffer = await fs__default.default.readFile(pkgPath);
|
|
740
|
-
const pkg = JSON.parse(buffer.toString());
|
|
741
|
-
logger.debug("Loaded package.json:", os__default.default.EOL, pkg);
|
|
742
|
-
return pkg;
|
|
743
|
-
};
|
|
744
976
|
const buildLogsServiceFactory = ({ logger }) => {
|
|
745
977
|
return async (url, token, cliConfig2) => {
|
|
746
978
|
const CONN_TIMEOUT = Number(cliConfig2.buildLogsConnectionTimeout);
|
|
@@ -803,7 +1035,7 @@ const buildLogsServiceFactory = ({ logger }) => {
|
|
|
803
1035
|
};
|
|
804
1036
|
};
|
|
805
1037
|
async function upload(ctx, project, token, maxProjectFileSize) {
|
|
806
|
-
const cloudApi = await cloudApiFactory(token);
|
|
1038
|
+
const cloudApi = await cloudApiFactory(ctx, token);
|
|
807
1039
|
try {
|
|
808
1040
|
const storagePath = await getTmpStoragePath();
|
|
809
1041
|
const projectFolder = path__namespace.default.resolve(process.cwd());
|
|
@@ -836,13 +1068,13 @@ async function upload(ctx, project, token, maxProjectFileSize) {
|
|
|
836
1068
|
process.exit(1);
|
|
837
1069
|
}
|
|
838
1070
|
const tarFilePath = path__namespace.default.resolve(storagePath, compressedFilename);
|
|
839
|
-
const fileStats = await
|
|
1071
|
+
const fileStats = await fse__namespace.default.stat(tarFilePath);
|
|
840
1072
|
if (fileStats.size > maxProjectFileSize) {
|
|
841
1073
|
ctx.logger.log(
|
|
842
1074
|
"Unable to proceed: Your project is too big to be transferred, please use a git repo instead."
|
|
843
1075
|
);
|
|
844
1076
|
try {
|
|
845
|
-
await
|
|
1077
|
+
await fse__namespace.default.remove(tarFilePath);
|
|
846
1078
|
} catch (e) {
|
|
847
1079
|
ctx.logger.log("Unable to remove file: ", tarFilePath);
|
|
848
1080
|
ctx.logger.debug(e);
|
|
@@ -881,7 +1113,7 @@ async function upload(ctx, project, token, maxProjectFileSize) {
|
|
|
881
1113
|
}
|
|
882
1114
|
ctx.logger.debug(e);
|
|
883
1115
|
} finally {
|
|
884
|
-
await
|
|
1116
|
+
await fse__namespace.default.remove(tarFilePath);
|
|
885
1117
|
}
|
|
886
1118
|
process.exit(0);
|
|
887
1119
|
} catch (e) {
|
|
@@ -905,8 +1137,7 @@ async function getProject(ctx) {
|
|
|
905
1137
|
}
|
|
906
1138
|
const action$2 = async (ctx) => {
|
|
907
1139
|
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
908
|
-
const
|
|
909
|
-
const token = await getValidToken();
|
|
1140
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
910
1141
|
if (!token) {
|
|
911
1142
|
return;
|
|
912
1143
|
}
|
|
@@ -914,6 +1145,7 @@ const action$2 = async (ctx) => {
|
|
|
914
1145
|
if (!project) {
|
|
915
1146
|
return;
|
|
916
1147
|
}
|
|
1148
|
+
const cloudApiService = await cloudApiFactory(ctx);
|
|
917
1149
|
try {
|
|
918
1150
|
await cloudApiService.track("willDeployWithCLI", { projectInternalName: project.name });
|
|
919
1151
|
} catch (e) {
|
|
@@ -977,185 +1209,29 @@ const runAction = (name2, action2) => (...args) => {
|
|
|
977
1209
|
process.exit(1);
|
|
978
1210
|
});
|
|
979
1211
|
};
|
|
980
|
-
const command$
|
|
1212
|
+
const command$4 = ({ command: command2, ctx }) => {
|
|
981
1213
|
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));
|
|
982
1214
|
};
|
|
983
1215
|
const deployProject = {
|
|
984
1216
|
name: "deploy-project",
|
|
985
1217
|
description: "Deploy a Strapi Cloud project",
|
|
986
1218
|
action: action$2,
|
|
987
|
-
command: command$
|
|
988
|
-
};
|
|
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;
|
|
1219
|
+
command: command$4
|
|
1145
1220
|
};
|
|
1146
|
-
const command$
|
|
1221
|
+
const command$3 = ({ command: command2, ctx }) => {
|
|
1147
1222
|
command2.command("cloud:login").alias("login").description("Strapi Cloud Login").addHelpText(
|
|
1148
1223
|
"after",
|
|
1149
1224
|
"\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",
|
|
1225
|
+
).option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("login", loginAction)(ctx));
|
|
1151
1226
|
};
|
|
1152
1227
|
const login = {
|
|
1153
1228
|
name: "login",
|
|
1154
1229
|
description: "Strapi Cloud Login",
|
|
1155
|
-
action:
|
|
1156
|
-
command: command$
|
|
1230
|
+
action: loginAction,
|
|
1231
|
+
command: command$3
|
|
1157
1232
|
};
|
|
1158
|
-
const
|
|
1233
|
+
const openModule = import("open");
|
|
1234
|
+
const action$1 = async (ctx) => {
|
|
1159
1235
|
const { logger } = ctx;
|
|
1160
1236
|
const { retrieveToken, eraseToken } = await tokenServiceFactory(ctx);
|
|
1161
1237
|
const token = await retrieveToken();
|
|
@@ -1163,9 +1239,21 @@ const action = async (ctx) => {
|
|
|
1163
1239
|
logger.log("You're already logged out.");
|
|
1164
1240
|
return;
|
|
1165
1241
|
}
|
|
1166
|
-
const cloudApiService = await cloudApiFactory(token);
|
|
1242
|
+
const cloudApiService = await cloudApiFactory(ctx, token);
|
|
1243
|
+
const config = await cloudApiService.config();
|
|
1244
|
+
const cliConfig2 = config.data;
|
|
1167
1245
|
try {
|
|
1168
1246
|
await eraseToken();
|
|
1247
|
+
openModule.then((open) => {
|
|
1248
|
+
open.default(
|
|
1249
|
+
`${cliConfig2.baseUrl}/oidc/logout?client_id=${encodeURIComponent(
|
|
1250
|
+
cliConfig2.clientId
|
|
1251
|
+
)}&logout_hint=${encodeURIComponent(token)}
|
|
1252
|
+
`
|
|
1253
|
+
).catch((e) => {
|
|
1254
|
+
logger.debug(e.message, e);
|
|
1255
|
+
});
|
|
1256
|
+
});
|
|
1169
1257
|
logger.log(
|
|
1170
1258
|
"🔌 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
1259
|
);
|
|
@@ -1179,31 +1267,61 @@ const action = async (ctx) => {
|
|
|
1179
1267
|
logger.debug("Failed to track logout event", e);
|
|
1180
1268
|
}
|
|
1181
1269
|
};
|
|
1182
|
-
const command$
|
|
1183
|
-
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));
|
|
1270
|
+
const command$2 = ({ command: command2, ctx }) => {
|
|
1271
|
+
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$1)(ctx));
|
|
1184
1272
|
};
|
|
1185
1273
|
const logout = {
|
|
1186
1274
|
name: "logout",
|
|
1187
1275
|
description: "Strapi Cloud Logout",
|
|
1188
|
-
action,
|
|
1189
|
-
command: command$
|
|
1276
|
+
action: action$1,
|
|
1277
|
+
command: command$2
|
|
1190
1278
|
};
|
|
1191
|
-
const command = ({ command: command2, ctx }) => {
|
|
1279
|
+
const command$1 = ({ command: command2, ctx }) => {
|
|
1192
1280
|
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));
|
|
1193
1281
|
};
|
|
1194
1282
|
const createProject = {
|
|
1195
1283
|
name: "create-project",
|
|
1196
1284
|
description: "Create a new project",
|
|
1197
1285
|
action: action$3,
|
|
1286
|
+
command: command$1
|
|
1287
|
+
};
|
|
1288
|
+
const action = async (ctx) => {
|
|
1289
|
+
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
1290
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
1291
|
+
const { logger } = ctx;
|
|
1292
|
+
if (!token) {
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
const cloudApiService = await cloudApiFactory(ctx, token);
|
|
1296
|
+
const spinner = logger.spinner("Fetching your projects...").start();
|
|
1297
|
+
try {
|
|
1298
|
+
const {
|
|
1299
|
+
data: { data: projectList }
|
|
1300
|
+
} = await cloudApiService.listProjects();
|
|
1301
|
+
spinner.succeed();
|
|
1302
|
+
logger.log(projectList);
|
|
1303
|
+
} catch (e) {
|
|
1304
|
+
ctx.logger.debug("Failed to list projects", e);
|
|
1305
|
+
spinner.fail("An error occurred while fetching your projects from Strapi Cloud.");
|
|
1306
|
+
}
|
|
1307
|
+
};
|
|
1308
|
+
const command = ({ command: command2, ctx }) => {
|
|
1309
|
+
command2.command("cloud:projects").alias("projects").description("List Strapi Cloud projects").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("listProjects", action)(ctx));
|
|
1310
|
+
};
|
|
1311
|
+
const listProjects = {
|
|
1312
|
+
name: "list-projects",
|
|
1313
|
+
description: "List Strapi Cloud projects",
|
|
1314
|
+
action,
|
|
1198
1315
|
command
|
|
1199
1316
|
};
|
|
1200
1317
|
const cli = {
|
|
1201
1318
|
deployProject,
|
|
1202
1319
|
login,
|
|
1203
1320
|
logout,
|
|
1204
|
-
createProject
|
|
1321
|
+
createProject,
|
|
1322
|
+
listProjects
|
|
1205
1323
|
};
|
|
1206
|
-
const cloudCommands = [deployProject, login, logout];
|
|
1324
|
+
const cloudCommands = [deployProject, login, logout, listProjects];
|
|
1207
1325
|
async function initCloudCLIConfig() {
|
|
1208
1326
|
const localConfig = await getLocalConfig();
|
|
1209
1327
|
if (!localConfig.deviceId) {
|