@strapi/cloud-cli 0.1.0 → 4.25.0
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 +1 -1
- package/bin/index.js +7 -0
- package/dist/bin.js +177 -0
- package/dist/bin.js.map +1 -0
- package/dist/index.js +1231 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1171 -0
- package/dist/index.mjs.map +1 -0
- package/dist/src/bin.d.ts +4 -0
- package/dist/src/bin.d.ts.map +1 -0
- package/dist/src/config/api.d.ts +5 -0
- package/dist/src/config/api.d.ts.map +1 -0
- package/dist/src/config/local.d.ts +9 -0
- package/dist/src/config/local.d.ts.map +1 -0
- package/dist/src/create-project/action.d.ts +4 -0
- package/dist/src/create-project/action.d.ts.map +1 -0
- package/dist/src/create-project/command.d.ts +7 -0
- package/dist/src/create-project/command.d.ts.map +1 -0
- package/dist/src/create-project/index.d.ts +7 -0
- package/dist/src/create-project/index.d.ts.map +1 -0
- package/dist/src/deploy-project/action.d.ts +4 -0
- package/dist/src/deploy-project/action.d.ts.map +1 -0
- package/dist/src/deploy-project/command.d.ts +7 -0
- package/dist/src/deploy-project/command.d.ts.map +1 -0
- package/dist/src/deploy-project/index.d.ts +7 -0
- package/dist/src/deploy-project/index.d.ts.map +1 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/login/action.d.ts +4 -0
- package/dist/src/login/action.d.ts.map +1 -0
- package/dist/src/login/command.d.ts +7 -0
- package/dist/src/login/command.d.ts.map +1 -0
- package/dist/src/login/index.d.ts +7 -0
- package/dist/src/login/index.d.ts.map +1 -0
- package/dist/src/logout/action.d.ts +4 -0
- package/dist/src/logout/action.d.ts.map +1 -0
- package/dist/src/logout/command.d.ts +7 -0
- package/dist/src/logout/command.d.ts.map +1 -0
- package/dist/src/logout/index.d.ts +11 -0
- package/dist/src/logout/index.d.ts.map +1 -0
- package/dist/src/services/build-logs.d.ts +4 -0
- package/dist/src/services/build-logs.d.ts.map +1 -0
- package/dist/src/services/cli-api.d.ts +39 -0
- package/dist/src/services/cli-api.d.ts.map +1 -0
- package/dist/src/services/index.d.ts +5 -0
- package/dist/src/services/index.d.ts.map +1 -0
- package/dist/src/services/logger.d.ts +22 -0
- package/dist/src/services/logger.d.ts.map +1 -0
- package/dist/src/services/notification.d.ts +3 -0
- package/dist/src/services/notification.d.ts.map +1 -0
- package/dist/src/services/strapi-info-save.d.ts +12 -0
- package/dist/src/services/strapi-info-save.d.ts.map +1 -0
- package/dist/src/services/token.d.ts +12 -0
- package/dist/src/services/token.d.ts.map +1 -0
- package/dist/src/types.d.ts +44 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils/compress-files.d.ts +4 -0
- package/dist/src/utils/compress-files.d.ts.map +1 -0
- package/dist/src/utils/helpers.d.ts +3 -0
- package/dist/src/utils/helpers.d.ts.map +1 -0
- package/dist/src/utils/pkg.d.ts +121 -0
- package/dist/src/utils/pkg.d.ts.map +1 -0
- package/dist/src/utils/tests/compress-files.test.d.ts +2 -0
- package/dist/src/utils/tests/compress-files.test.d.ts.map +1 -0
- package/package.json +56 -8
package/dist/index.js
ADDED
|
@@ -0,0 +1,1231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
25
|
+
const crypto$1 = require("crypto");
|
|
26
|
+
const fse = require("fs-extra");
|
|
27
|
+
const path = require("path");
|
|
28
|
+
const chalk = require("chalk");
|
|
29
|
+
const axios = require("axios");
|
|
30
|
+
const crypto = require("node:crypto");
|
|
31
|
+
const utils = require("@strapi/utils");
|
|
32
|
+
const fs = require("fs");
|
|
33
|
+
const tar = require("tar");
|
|
34
|
+
const minimatch = require("minimatch");
|
|
35
|
+
const inquirer = require("inquirer");
|
|
36
|
+
const fp = require("lodash/fp");
|
|
37
|
+
const os = require("os");
|
|
38
|
+
const XDGAppPaths = require("xdg-app-paths");
|
|
39
|
+
const jwksClient = require("jwks-rsa");
|
|
40
|
+
const jwt = require("jsonwebtoken");
|
|
41
|
+
const stringify = require("fast-safe-stringify");
|
|
42
|
+
const ora = require("ora");
|
|
43
|
+
const cliProgress = require("cli-progress");
|
|
44
|
+
const EventSource = require("eventsource");
|
|
45
|
+
const fs$1 = require("fs/promises");
|
|
46
|
+
const pkgUp = require("pkg-up");
|
|
47
|
+
const yup = require("yup");
|
|
48
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
49
|
+
function _interopNamespace(e) {
|
|
50
|
+
if (e && e.__esModule)
|
|
51
|
+
return e;
|
|
52
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
53
|
+
if (e) {
|
|
54
|
+
for (const k in e) {
|
|
55
|
+
if (k !== "default") {
|
|
56
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
57
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
get: () => e[k]
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
n.default = e;
|
|
65
|
+
return Object.freeze(n);
|
|
66
|
+
}
|
|
67
|
+
const crypto__default = /* @__PURE__ */ _interopDefault(crypto$1);
|
|
68
|
+
const fse__default = /* @__PURE__ */ _interopDefault(fse);
|
|
69
|
+
const path__namespace = /* @__PURE__ */ _interopNamespace(path);
|
|
70
|
+
const chalk__default = /* @__PURE__ */ _interopDefault(chalk);
|
|
71
|
+
const axios__default = /* @__PURE__ */ _interopDefault(axios);
|
|
72
|
+
const crypto__namespace = /* @__PURE__ */ _interopNamespace(crypto);
|
|
73
|
+
const fs__namespace = /* @__PURE__ */ _interopNamespace(fs);
|
|
74
|
+
const tar__namespace = /* @__PURE__ */ _interopNamespace(tar);
|
|
75
|
+
const inquirer__default = /* @__PURE__ */ _interopDefault(inquirer);
|
|
76
|
+
const os__default = /* @__PURE__ */ _interopDefault(os);
|
|
77
|
+
const XDGAppPaths__default = /* @__PURE__ */ _interopDefault(XDGAppPaths);
|
|
78
|
+
const jwksClient__default = /* @__PURE__ */ _interopDefault(jwksClient);
|
|
79
|
+
const jwt__default = /* @__PURE__ */ _interopDefault(jwt);
|
|
80
|
+
const stringify__default = /* @__PURE__ */ _interopDefault(stringify);
|
|
81
|
+
const ora__default = /* @__PURE__ */ _interopDefault(ora);
|
|
82
|
+
const cliProgress__namespace = /* @__PURE__ */ _interopNamespace(cliProgress);
|
|
83
|
+
const EventSource__default = /* @__PURE__ */ _interopDefault(EventSource);
|
|
84
|
+
const fs__default = /* @__PURE__ */ _interopDefault(fs$1);
|
|
85
|
+
const pkgUp__default = /* @__PURE__ */ _interopDefault(pkgUp);
|
|
86
|
+
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
|
87
|
+
const apiConfig = {
|
|
88
|
+
apiBaseUrl: utils.env("STRAPI_CLI_CLOUD_API", "https://cloud-cli-api.strapi.io"),
|
|
89
|
+
dashboardBaseUrl: utils.env("STRAPI_CLI_CLOUD_DASHBOARD", "https://cloud.strapi.io")
|
|
90
|
+
};
|
|
91
|
+
const IGNORED_PATTERNS = [
|
|
92
|
+
"**/.git/**",
|
|
93
|
+
"**/node_modules/**",
|
|
94
|
+
"**/build/**",
|
|
95
|
+
"**/dist/**",
|
|
96
|
+
"**/.cache/**",
|
|
97
|
+
"**/.circleci/**",
|
|
98
|
+
"**/.github/**",
|
|
99
|
+
"**/.gitignore",
|
|
100
|
+
"**/.gitkeep",
|
|
101
|
+
"**/.gitlab-ci.yml",
|
|
102
|
+
"**/.idea/**",
|
|
103
|
+
"**/.vscode/**"
|
|
104
|
+
];
|
|
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
|
+
const isIgnoredFile = (folderPath, file, ignorePatterns) => {
|
|
123
|
+
ignorePatterns.push(...IGNORED_PATTERNS);
|
|
124
|
+
const relativeFilePath = path__namespace.join(folderPath, file);
|
|
125
|
+
let isIgnored = false;
|
|
126
|
+
for (const pattern of ignorePatterns) {
|
|
127
|
+
if (pattern.startsWith("!")) {
|
|
128
|
+
if (minimatch.minimatch(relativeFilePath, pattern.slice(1), { matchBase: true, dot: true })) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
} else if (minimatch.minimatch(relativeFilePath, pattern, { matchBase: true, dot: true })) {
|
|
132
|
+
if (path__namespace.basename(file) !== ".gitkeep") {
|
|
133
|
+
isIgnored = true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return isIgnored;
|
|
138
|
+
};
|
|
139
|
+
const readGitignore = (folderPath) => {
|
|
140
|
+
const gitignorePath = path__namespace.resolve(folderPath, ".gitignore");
|
|
141
|
+
if (!fs__namespace.existsSync(gitignorePath))
|
|
142
|
+
return [];
|
|
143
|
+
const gitignoreContent = fs__namespace.readFileSync(gitignorePath, "utf8");
|
|
144
|
+
return gitignoreContent.split(/\r?\n/).filter((line) => Boolean(line.trim()) && !line.startsWith("#"));
|
|
145
|
+
};
|
|
146
|
+
const compressFilesToTar = async (storagePath, folderToCompress, filename) => {
|
|
147
|
+
const ignorePatterns = readGitignore(folderToCompress);
|
|
148
|
+
const filesToCompress = getFiles(folderToCompress, ignorePatterns);
|
|
149
|
+
return tar__namespace.c(
|
|
150
|
+
{
|
|
151
|
+
gzip: true,
|
|
152
|
+
file: path__namespace.resolve(storagePath, filename)
|
|
153
|
+
},
|
|
154
|
+
filesToCompress
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
const APP_FOLDER_NAME = "com.strapi.cli";
|
|
158
|
+
const CONFIG_FILENAME = "config.json";
|
|
159
|
+
async function checkDirectoryExists(directoryPath) {
|
|
160
|
+
try {
|
|
161
|
+
const fsStat = await fse__default.default.lstat(directoryPath);
|
|
162
|
+
return fsStat.isDirectory();
|
|
163
|
+
} catch (e) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function getTmpStoragePath() {
|
|
168
|
+
const storagePath = path__namespace.default.join(os__default.default.tmpdir(), APP_FOLDER_NAME);
|
|
169
|
+
await fse__default.default.ensureDir(storagePath);
|
|
170
|
+
return storagePath;
|
|
171
|
+
}
|
|
172
|
+
async function getConfigPath() {
|
|
173
|
+
const configDirs = XDGAppPaths__default.default(APP_FOLDER_NAME).configDirs();
|
|
174
|
+
const configPath = configDirs.find(checkDirectoryExists);
|
|
175
|
+
if (!configPath) {
|
|
176
|
+
await fse__default.default.ensureDir(configDirs[0]);
|
|
177
|
+
return configDirs[0];
|
|
178
|
+
}
|
|
179
|
+
return configPath;
|
|
180
|
+
}
|
|
181
|
+
async function getLocalConfig() {
|
|
182
|
+
const configPath = await getConfigPath();
|
|
183
|
+
const configFilePath = path__namespace.default.join(configPath, CONFIG_FILENAME);
|
|
184
|
+
await fse__default.default.ensureFile(configFilePath);
|
|
185
|
+
try {
|
|
186
|
+
return await fse__default.default.readJSON(configFilePath, { encoding: "utf8", throws: true });
|
|
187
|
+
} catch (e) {
|
|
188
|
+
return {};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function saveLocalConfig(data) {
|
|
192
|
+
const configPath = await getConfigPath();
|
|
193
|
+
const configFilePath = path__namespace.default.join(configPath, CONFIG_FILENAME);
|
|
194
|
+
await fse__default.default.writeJson(configFilePath, data, { encoding: "utf8", spaces: 2, mode: 384 });
|
|
195
|
+
}
|
|
196
|
+
const name = "@strapi/cloud-cli";
|
|
197
|
+
const version = "4.24.5";
|
|
198
|
+
const description = "Commands to interact with the Strapi Cloud";
|
|
199
|
+
const keywords = [
|
|
200
|
+
"strapi",
|
|
201
|
+
"cloud",
|
|
202
|
+
"cli"
|
|
203
|
+
];
|
|
204
|
+
const homepage = "https://strapi.io";
|
|
205
|
+
const bugs = {
|
|
206
|
+
url: "https://github.com/strapi/strapi/issues"
|
|
207
|
+
};
|
|
208
|
+
const repository = {
|
|
209
|
+
type: "git",
|
|
210
|
+
url: "git://github.com/strapi/strapi.git"
|
|
211
|
+
};
|
|
212
|
+
const license = "SEE LICENSE IN LICENSE";
|
|
213
|
+
const author = {
|
|
214
|
+
name: "Strapi Solutions SAS",
|
|
215
|
+
email: "hi@strapi.io",
|
|
216
|
+
url: "https://strapi.io"
|
|
217
|
+
};
|
|
218
|
+
const maintainers = [
|
|
219
|
+
{
|
|
220
|
+
name: "Strapi Solutions SAS",
|
|
221
|
+
email: "hi@strapi.io",
|
|
222
|
+
url: "https://strapi.io"
|
|
223
|
+
}
|
|
224
|
+
];
|
|
225
|
+
const main = "./dist/index.js";
|
|
226
|
+
const module$1 = "./dist/index.mjs";
|
|
227
|
+
const source = "./src/index.ts";
|
|
228
|
+
const types = "./dist/src/index.d.ts";
|
|
229
|
+
const bin = "./bin/index.js";
|
|
230
|
+
const files = [
|
|
231
|
+
"./dist",
|
|
232
|
+
"./bin"
|
|
233
|
+
];
|
|
234
|
+
const scripts = {
|
|
235
|
+
build: "pack-up build",
|
|
236
|
+
clean: "run -T rimraf ./dist",
|
|
237
|
+
lint: "run -T eslint .",
|
|
238
|
+
watch: "pack-up watch"
|
|
239
|
+
};
|
|
240
|
+
const dependencies = {
|
|
241
|
+
"@strapi/utils": "4.24.5",
|
|
242
|
+
axios: "1.6.0",
|
|
243
|
+
chalk: "4.1.2",
|
|
244
|
+
"cli-progress": "3.12.0",
|
|
245
|
+
commander: "8.3.0",
|
|
246
|
+
eventsource: "2.0.2",
|
|
247
|
+
"fast-safe-stringify": "2.1.1",
|
|
248
|
+
"fs-extra": "10.0.0",
|
|
249
|
+
inquirer: "8.2.5",
|
|
250
|
+
jsonwebtoken: "9.0.0",
|
|
251
|
+
"jwks-rsa": "3.1.0",
|
|
252
|
+
lodash: "4.17.21",
|
|
253
|
+
minimatch: "9.0.3",
|
|
254
|
+
open: "8.4.0",
|
|
255
|
+
ora: "5.4.1",
|
|
256
|
+
"pkg-up": "3.1.0",
|
|
257
|
+
tar: "6.1.13",
|
|
258
|
+
"xdg-app-paths": "8.3.0",
|
|
259
|
+
yup: "0.32.9"
|
|
260
|
+
};
|
|
261
|
+
const devDependencies = {
|
|
262
|
+
"@strapi/pack-up": "4.23.0",
|
|
263
|
+
"@types/cli-progress": "3.11.5",
|
|
264
|
+
"@types/eventsource": "1.1.15",
|
|
265
|
+
"@types/lodash": "^4.14.191",
|
|
266
|
+
"eslint-config-custom": "4.24.5",
|
|
267
|
+
tsconfig: "4.24.5"
|
|
268
|
+
};
|
|
269
|
+
const engines = {
|
|
270
|
+
node: ">=18.0.0 <=20.x.x",
|
|
271
|
+
npm: ">=6.0.0"
|
|
272
|
+
};
|
|
273
|
+
const packageJson = {
|
|
274
|
+
name,
|
|
275
|
+
version,
|
|
276
|
+
description,
|
|
277
|
+
keywords,
|
|
278
|
+
homepage,
|
|
279
|
+
bugs,
|
|
280
|
+
repository,
|
|
281
|
+
license,
|
|
282
|
+
author,
|
|
283
|
+
maintainers,
|
|
284
|
+
main,
|
|
285
|
+
module: module$1,
|
|
286
|
+
source,
|
|
287
|
+
types,
|
|
288
|
+
bin,
|
|
289
|
+
files,
|
|
290
|
+
scripts,
|
|
291
|
+
dependencies,
|
|
292
|
+
devDependencies,
|
|
293
|
+
engines
|
|
294
|
+
};
|
|
295
|
+
const VERSION = "v1";
|
|
296
|
+
async function cloudApiFactory(token) {
|
|
297
|
+
const localConfig = await getLocalConfig();
|
|
298
|
+
const customHeaders = {
|
|
299
|
+
"x-device-id": localConfig.deviceId,
|
|
300
|
+
"x-app-version": packageJson.version,
|
|
301
|
+
"x-os-name": os__default.default.type(),
|
|
302
|
+
"x-os-version": os__default.default.version(),
|
|
303
|
+
"x-language": Intl.DateTimeFormat().resolvedOptions().locale,
|
|
304
|
+
"x-node-version": process.versions.node
|
|
305
|
+
};
|
|
306
|
+
const axiosCloudAPI = axios__default.default.create({
|
|
307
|
+
baseURL: `${apiConfig.apiBaseUrl}/${VERSION}`,
|
|
308
|
+
headers: {
|
|
309
|
+
"Content-Type": "application/json",
|
|
310
|
+
...customHeaders
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
if (token) {
|
|
314
|
+
axiosCloudAPI.defaults.headers.Authorization = `Bearer ${token}`;
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
deploy({ filePath, project }, { onUploadProgress }) {
|
|
318
|
+
return axiosCloudAPI.post(
|
|
319
|
+
`/deploy/${project.name}`,
|
|
320
|
+
{ file: fse__default.default.createReadStream(filePath) },
|
|
321
|
+
{
|
|
322
|
+
headers: {
|
|
323
|
+
"Content-Type": "multipart/form-data"
|
|
324
|
+
},
|
|
325
|
+
onUploadProgress
|
|
326
|
+
}
|
|
327
|
+
);
|
|
328
|
+
},
|
|
329
|
+
async createProject({ name: name2, nodeVersion, region, plan }) {
|
|
330
|
+
const response = await axiosCloudAPI.post("/project", {
|
|
331
|
+
projectName: name2,
|
|
332
|
+
region,
|
|
333
|
+
nodeVersion,
|
|
334
|
+
plan
|
|
335
|
+
});
|
|
336
|
+
return {
|
|
337
|
+
data: {
|
|
338
|
+
id: response.data.id,
|
|
339
|
+
name: response.data.name,
|
|
340
|
+
nodeVersion: response.data.nodeVersion,
|
|
341
|
+
region: response.data.region
|
|
342
|
+
},
|
|
343
|
+
status: response.status
|
|
344
|
+
};
|
|
345
|
+
},
|
|
346
|
+
getUserInfo() {
|
|
347
|
+
return axiosCloudAPI.get("/user");
|
|
348
|
+
},
|
|
349
|
+
config() {
|
|
350
|
+
return axiosCloudAPI.get("/config");
|
|
351
|
+
},
|
|
352
|
+
listProjects() {
|
|
353
|
+
return axiosCloudAPI.get("/projects");
|
|
354
|
+
},
|
|
355
|
+
track(event, payload = {}) {
|
|
356
|
+
return axiosCloudAPI.post("/track", {
|
|
357
|
+
event,
|
|
358
|
+
payload
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
const LOCAL_SAVE_FILENAME = ".strapi-cloud.json";
|
|
364
|
+
async function save(data, { directoryPath } = {}) {
|
|
365
|
+
const alreadyInFileData = await retrieve({ directoryPath });
|
|
366
|
+
const storedData = { ...alreadyInFileData, ...data };
|
|
367
|
+
const pathToFile = path__namespace.default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
|
|
368
|
+
await fse__default.default.ensureDir(path__namespace.default.dirname(pathToFile));
|
|
369
|
+
await fse__default.default.writeJson(pathToFile, storedData, { encoding: "utf8" });
|
|
370
|
+
}
|
|
371
|
+
async function retrieve({
|
|
372
|
+
directoryPath
|
|
373
|
+
} = {}) {
|
|
374
|
+
const pathToFile = path__namespace.default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
|
|
375
|
+
const pathExists = await fse__default.default.pathExists(pathToFile);
|
|
376
|
+
if (!pathExists) {
|
|
377
|
+
return {};
|
|
378
|
+
}
|
|
379
|
+
return fse__default.default.readJSON(pathToFile, { encoding: "utf8" });
|
|
380
|
+
}
|
|
381
|
+
const strapiInfoSave = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
382
|
+
__proto__: null,
|
|
383
|
+
LOCAL_SAVE_FILENAME,
|
|
384
|
+
retrieve,
|
|
385
|
+
save
|
|
386
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
387
|
+
let cliConfig;
|
|
388
|
+
async function tokenServiceFactory({ logger }) {
|
|
389
|
+
const cloudApiService = await cloudApiFactory();
|
|
390
|
+
async function saveToken(str) {
|
|
391
|
+
const appConfig = await getLocalConfig();
|
|
392
|
+
if (!appConfig) {
|
|
393
|
+
logger.error("There was a problem saving your token. Please try again.");
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
appConfig.token = str;
|
|
397
|
+
try {
|
|
398
|
+
await saveLocalConfig(appConfig);
|
|
399
|
+
} catch (e) {
|
|
400
|
+
logger.debug(e);
|
|
401
|
+
logger.error("There was a problem saving your token. Please try again.");
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
async function retrieveToken() {
|
|
405
|
+
const appConfig = await getLocalConfig();
|
|
406
|
+
if (appConfig.token) {
|
|
407
|
+
if (await isTokenValid(appConfig.token)) {
|
|
408
|
+
return appConfig.token;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return void 0;
|
|
412
|
+
}
|
|
413
|
+
async function validateToken(idToken, jwksUrl) {
|
|
414
|
+
const client = jwksClient__default.default({
|
|
415
|
+
jwksUri: jwksUrl
|
|
416
|
+
});
|
|
417
|
+
const getKey = (header, callback) => {
|
|
418
|
+
client.getSigningKey(header.kid, (e, key) => {
|
|
419
|
+
if (e) {
|
|
420
|
+
callback(e);
|
|
421
|
+
} else if (key) {
|
|
422
|
+
const publicKey = "publicKey" in key ? key.publicKey : key.rsaPublicKey;
|
|
423
|
+
callback(null, publicKey);
|
|
424
|
+
} else {
|
|
425
|
+
callback(new Error("Key not found"));
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
};
|
|
429
|
+
const decodedToken = jwt__default.default.decode(idToken, { complete: true });
|
|
430
|
+
if (!decodedToken) {
|
|
431
|
+
if (typeof idToken === "undefined" || idToken === "") {
|
|
432
|
+
logger.warn("You need to be logged in to use this feature. Please log in and try again.");
|
|
433
|
+
} else {
|
|
434
|
+
logger.error(
|
|
435
|
+
"There seems to be a problem with your login information. Please try logging in again."
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return new Promise((resolve, reject) => {
|
|
440
|
+
jwt__default.default.verify(idToken, getKey, (err) => {
|
|
441
|
+
if (err) {
|
|
442
|
+
reject(err);
|
|
443
|
+
} else {
|
|
444
|
+
resolve();
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
async function isTokenValid(token) {
|
|
450
|
+
try {
|
|
451
|
+
const config = await cloudApiService.config();
|
|
452
|
+
cliConfig = config.data;
|
|
453
|
+
if (token) {
|
|
454
|
+
await validateToken(token, cliConfig.jwksUrl);
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
return false;
|
|
458
|
+
} catch (e) {
|
|
459
|
+
logger.debug(e);
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
async function eraseToken() {
|
|
464
|
+
const appConfig = await getLocalConfig();
|
|
465
|
+
if (!appConfig) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
delete appConfig.token;
|
|
469
|
+
try {
|
|
470
|
+
await saveLocalConfig(appConfig);
|
|
471
|
+
} catch (e) {
|
|
472
|
+
logger.debug(e);
|
|
473
|
+
logger.error(
|
|
474
|
+
"There was an issue removing your login information. Please try logging out again."
|
|
475
|
+
);
|
|
476
|
+
throw e;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
async function getValidToken() {
|
|
480
|
+
const token = await retrieveToken();
|
|
481
|
+
if (!token) {
|
|
482
|
+
logger.log("No token found. Please login first.");
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
if (!await isTokenValid(token)) {
|
|
486
|
+
logger.log("Unable to proceed: Token is expired or not valid. Please login again.");
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
489
|
+
return token;
|
|
490
|
+
}
|
|
491
|
+
return {
|
|
492
|
+
saveToken,
|
|
493
|
+
retrieveToken,
|
|
494
|
+
validateToken,
|
|
495
|
+
isTokenValid,
|
|
496
|
+
eraseToken,
|
|
497
|
+
getValidToken
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
const stringifyArg = (arg) => {
|
|
501
|
+
return typeof arg === "object" ? stringify__default.default(arg) : arg;
|
|
502
|
+
};
|
|
503
|
+
const createLogger = (options = {}) => {
|
|
504
|
+
const { silent = false, debug = false, timestamp = true } = options;
|
|
505
|
+
const state = { errors: 0, warning: 0 };
|
|
506
|
+
return {
|
|
507
|
+
get warnings() {
|
|
508
|
+
return state.warning;
|
|
509
|
+
},
|
|
510
|
+
get errors() {
|
|
511
|
+
return state.errors;
|
|
512
|
+
},
|
|
513
|
+
async debug(...args) {
|
|
514
|
+
if (silent || !debug) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
console.log(
|
|
518
|
+
chalk__default.default.cyan(`[DEBUG]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
|
|
519
|
+
...args.map(stringifyArg)
|
|
520
|
+
);
|
|
521
|
+
},
|
|
522
|
+
info(...args) {
|
|
523
|
+
if (silent) {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
console.info(
|
|
527
|
+
chalk__default.default.blue(`[INFO]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
|
|
528
|
+
...args.map(stringifyArg)
|
|
529
|
+
);
|
|
530
|
+
},
|
|
531
|
+
log(...args) {
|
|
532
|
+
if (silent) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
console.info(
|
|
536
|
+
chalk__default.default.blue(`${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
|
|
537
|
+
...args.map(stringifyArg)
|
|
538
|
+
);
|
|
539
|
+
},
|
|
540
|
+
success(...args) {
|
|
541
|
+
if (silent) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
console.info(
|
|
545
|
+
chalk__default.default.green(`[SUCCESS]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
|
|
546
|
+
...args.map(stringifyArg)
|
|
547
|
+
);
|
|
548
|
+
},
|
|
549
|
+
warn(...args) {
|
|
550
|
+
state.warning += 1;
|
|
551
|
+
if (silent) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
console.warn(
|
|
555
|
+
chalk__default.default.yellow(`[WARN]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
|
|
556
|
+
...args.map(stringifyArg)
|
|
557
|
+
);
|
|
558
|
+
},
|
|
559
|
+
error(...args) {
|
|
560
|
+
state.errors += 1;
|
|
561
|
+
if (silent) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
console.error(
|
|
565
|
+
chalk__default.default.red(`[ERROR]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
|
|
566
|
+
...args.map(stringifyArg)
|
|
567
|
+
);
|
|
568
|
+
},
|
|
569
|
+
// @ts-expect-error – returning a subpart of ora is fine because the types tell us what is what.
|
|
570
|
+
spinner(text) {
|
|
571
|
+
if (silent) {
|
|
572
|
+
return {
|
|
573
|
+
succeed() {
|
|
574
|
+
return this;
|
|
575
|
+
},
|
|
576
|
+
fail() {
|
|
577
|
+
return this;
|
|
578
|
+
},
|
|
579
|
+
start() {
|
|
580
|
+
return this;
|
|
581
|
+
},
|
|
582
|
+
text: "",
|
|
583
|
+
isSpinning: false
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
return ora__default.default(text);
|
|
587
|
+
},
|
|
588
|
+
progressBar(totalSize, text) {
|
|
589
|
+
if (silent) {
|
|
590
|
+
return {
|
|
591
|
+
start() {
|
|
592
|
+
return this;
|
|
593
|
+
},
|
|
594
|
+
stop() {
|
|
595
|
+
return this;
|
|
596
|
+
},
|
|
597
|
+
update() {
|
|
598
|
+
return this;
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
const progressBar = new cliProgress__namespace.SingleBar({
|
|
603
|
+
format: `${text ? `${text} |` : ""}${chalk__default.default.green("{bar}")}| {percentage}%`,
|
|
604
|
+
barCompleteChar: "█",
|
|
605
|
+
barIncompleteChar: "░",
|
|
606
|
+
hideCursor: true,
|
|
607
|
+
forceRedraw: true
|
|
608
|
+
});
|
|
609
|
+
progressBar.start(totalSize, 0);
|
|
610
|
+
return progressBar;
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
};
|
|
614
|
+
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
615
|
+
__proto__: null,
|
|
616
|
+
cloudApiFactory,
|
|
617
|
+
createLogger,
|
|
618
|
+
local: strapiInfoSave,
|
|
619
|
+
tokenServiceFactory
|
|
620
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
621
|
+
async function handleError(ctx, error) {
|
|
622
|
+
const tokenService = await tokenServiceFactory(ctx);
|
|
623
|
+
const { logger } = ctx;
|
|
624
|
+
logger.debug(error);
|
|
625
|
+
if (error instanceof axios.AxiosError) {
|
|
626
|
+
const errorMessage = typeof error.response?.data === "string" ? error.response.data : null;
|
|
627
|
+
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
|
+
case 403:
|
|
633
|
+
logger.error(
|
|
634
|
+
errorMessage || "You do not have permission to create a project. Please contact support for assistance."
|
|
635
|
+
);
|
|
636
|
+
return;
|
|
637
|
+
case 400:
|
|
638
|
+
logger.error(errorMessage || "Invalid input. Please check your inputs and try again.");
|
|
639
|
+
return;
|
|
640
|
+
case 503:
|
|
641
|
+
logger.error(
|
|
642
|
+
"Strapi Cloud project creation is currently unavailable. Please try again later."
|
|
643
|
+
);
|
|
644
|
+
return;
|
|
645
|
+
default:
|
|
646
|
+
if (errorMessage) {
|
|
647
|
+
logger.error(errorMessage);
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
break;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
logger.error(
|
|
654
|
+
"We encountered an issue while creating your project. Please try again in a moment. If the problem persists, contact support for assistance."
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
const action$3 = async (ctx) => {
|
|
658
|
+
const { logger } = ctx;
|
|
659
|
+
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
660
|
+
const token = await getValidToken();
|
|
661
|
+
if (!token) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
const cloudApi = await cloudApiFactory(token);
|
|
665
|
+
const { data: config } = await cloudApi.config();
|
|
666
|
+
const { questions, defaults: defaultValues } = config.projectCreation;
|
|
667
|
+
const projectAnswersDefaulted = fp.defaults(defaultValues);
|
|
668
|
+
const projectAnswers = await inquirer__default.default.prompt(questions);
|
|
669
|
+
const projectInput = projectAnswersDefaulted(projectAnswers);
|
|
670
|
+
const spinner = logger.spinner("Setting up your project...").start();
|
|
671
|
+
try {
|
|
672
|
+
const { data } = await cloudApi.createProject(projectInput);
|
|
673
|
+
await save({ project: data });
|
|
674
|
+
spinner.succeed("Project created successfully!");
|
|
675
|
+
return data;
|
|
676
|
+
} catch (e) {
|
|
677
|
+
spinner.fail("Failed to create project on Strapi Cloud.");
|
|
678
|
+
await handleError(ctx, e);
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
function notificationServiceFactory({ logger }) {
|
|
682
|
+
return (url, token, cliConfig2) => {
|
|
683
|
+
const CONN_TIMEOUT = Number(cliConfig2.notificationsConnectionTimeout);
|
|
684
|
+
const es = new EventSource__default.default(url, {
|
|
685
|
+
headers: {
|
|
686
|
+
Authorization: `Bearer ${token}`
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
let timeoutId;
|
|
690
|
+
const resetTimeout = () => {
|
|
691
|
+
clearTimeout(timeoutId);
|
|
692
|
+
timeoutId = setTimeout(() => {
|
|
693
|
+
logger.log(
|
|
694
|
+
"We were unable to connect to the server at this time. This could be due to a temporary issue. Please try again in a moment."
|
|
695
|
+
);
|
|
696
|
+
es.close();
|
|
697
|
+
}, CONN_TIMEOUT);
|
|
698
|
+
};
|
|
699
|
+
es.onopen = resetTimeout;
|
|
700
|
+
es.onmessage = (event) => {
|
|
701
|
+
resetTimeout();
|
|
702
|
+
const data = JSON.parse(event.data);
|
|
703
|
+
if (data.message) {
|
|
704
|
+
logger.log(data.message);
|
|
705
|
+
}
|
|
706
|
+
if (data.event === "deploymentFinished" || data.event === "deploymentFailed") {
|
|
707
|
+
es.close();
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
};
|
|
711
|
+
}
|
|
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
|
+
const buildLogsServiceFactory = ({ logger }) => {
|
|
745
|
+
return async (url, token, cliConfig2) => {
|
|
746
|
+
const CONN_TIMEOUT = Number(cliConfig2.buildLogsConnectionTimeout);
|
|
747
|
+
const MAX_RETRIES = Number(cliConfig2.buildLogsMaxRetries);
|
|
748
|
+
return new Promise((resolve, reject) => {
|
|
749
|
+
let timeoutId = null;
|
|
750
|
+
let retries = 0;
|
|
751
|
+
const connect = (url2) => {
|
|
752
|
+
const spinner = logger.spinner("Connecting to server to get build logs");
|
|
753
|
+
spinner.start();
|
|
754
|
+
const es = new EventSource__default.default(`${url2}`, {
|
|
755
|
+
headers: {
|
|
756
|
+
Authorization: `Bearer ${token}`
|
|
757
|
+
}
|
|
758
|
+
});
|
|
759
|
+
const clearExistingTimeout = () => {
|
|
760
|
+
if (timeoutId) {
|
|
761
|
+
clearTimeout(timeoutId);
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
const resetTimeout = () => {
|
|
765
|
+
clearExistingTimeout();
|
|
766
|
+
timeoutId = setTimeout(() => {
|
|
767
|
+
if (spinner.isSpinning) {
|
|
768
|
+
spinner.fail(
|
|
769
|
+
"We were unable to connect to the server to get build logs at this time. This could be due to a temporary issue."
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
es.close();
|
|
773
|
+
reject(new Error("Connection timed out"));
|
|
774
|
+
}, CONN_TIMEOUT);
|
|
775
|
+
};
|
|
776
|
+
es.onopen = resetTimeout;
|
|
777
|
+
es.addEventListener("finished", (event) => {
|
|
778
|
+
const data = JSON.parse(event.data);
|
|
779
|
+
logger.log(data.msg);
|
|
780
|
+
es.close();
|
|
781
|
+
clearExistingTimeout();
|
|
782
|
+
resolve(null);
|
|
783
|
+
});
|
|
784
|
+
es.addEventListener("log", (event) => {
|
|
785
|
+
if (spinner.isSpinning) {
|
|
786
|
+
spinner.succeed();
|
|
787
|
+
}
|
|
788
|
+
resetTimeout();
|
|
789
|
+
const data = JSON.parse(event.data);
|
|
790
|
+
logger.log(data.msg);
|
|
791
|
+
});
|
|
792
|
+
es.onerror = async () => {
|
|
793
|
+
retries += 1;
|
|
794
|
+
if (retries > MAX_RETRIES) {
|
|
795
|
+
spinner.fail("We were unable to connect to the server to get build logs at this time.");
|
|
796
|
+
es.close();
|
|
797
|
+
reject(new Error("Max retries reached"));
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
};
|
|
801
|
+
connect(url);
|
|
802
|
+
});
|
|
803
|
+
};
|
|
804
|
+
};
|
|
805
|
+
async function upload(ctx, project, token, maxProjectFileSize) {
|
|
806
|
+
const cloudApi = await cloudApiFactory(token);
|
|
807
|
+
try {
|
|
808
|
+
const storagePath = await getTmpStoragePath();
|
|
809
|
+
const projectFolder = path__namespace.default.resolve(process.cwd());
|
|
810
|
+
const packageJson2 = await loadPkg(ctx);
|
|
811
|
+
if (!packageJson2) {
|
|
812
|
+
ctx.logger.error(
|
|
813
|
+
"Unable to deploy the project. Please make sure the package.json file is correctly formatted."
|
|
814
|
+
);
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
ctx.logger.log("📦 Compressing project...");
|
|
818
|
+
const hashname = crypto__namespace.createHash("sha512").update(packageJson2.name).digest("hex");
|
|
819
|
+
const compressedFilename = `${hashname}.tar.gz`;
|
|
820
|
+
try {
|
|
821
|
+
ctx.logger.debug(
|
|
822
|
+
"Compression parameters\n",
|
|
823
|
+
`Storage path: ${storagePath}
|
|
824
|
+
`,
|
|
825
|
+
`Project folder: ${projectFolder}
|
|
826
|
+
`,
|
|
827
|
+
`Compressed filename: ${compressedFilename}`
|
|
828
|
+
);
|
|
829
|
+
await compressFilesToTar(storagePath, projectFolder, compressedFilename);
|
|
830
|
+
ctx.logger.log("📦 Project compressed successfully!");
|
|
831
|
+
} catch (e) {
|
|
832
|
+
ctx.logger.error(
|
|
833
|
+
"⚠️ Project compression failed. Try again later or check for large/incompatible files."
|
|
834
|
+
);
|
|
835
|
+
ctx.logger.debug(e);
|
|
836
|
+
process.exit(1);
|
|
837
|
+
}
|
|
838
|
+
const tarFilePath = path__namespace.default.resolve(storagePath, compressedFilename);
|
|
839
|
+
const fileStats = await fse__default.default.stat(tarFilePath);
|
|
840
|
+
if (fileStats.size > maxProjectFileSize) {
|
|
841
|
+
ctx.logger.log(
|
|
842
|
+
"Unable to proceed: Your project is too big to be transferred, please use a git repo instead."
|
|
843
|
+
);
|
|
844
|
+
try {
|
|
845
|
+
await fse__default.default.remove(tarFilePath);
|
|
846
|
+
} catch (e) {
|
|
847
|
+
ctx.logger.log("Unable to remove file: ", tarFilePath);
|
|
848
|
+
ctx.logger.debug(e);
|
|
849
|
+
}
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
ctx.logger.info("🚀 Uploading project...");
|
|
853
|
+
const progressBar = ctx.logger.progressBar(100, "Upload Progress");
|
|
854
|
+
try {
|
|
855
|
+
const { data } = await cloudApi.deploy(
|
|
856
|
+
{ filePath: tarFilePath, project },
|
|
857
|
+
{
|
|
858
|
+
onUploadProgress(progressEvent) {
|
|
859
|
+
const total = progressEvent.total || fileStats.size;
|
|
860
|
+
const percentage = Math.round(progressEvent.loaded * 100 / total);
|
|
861
|
+
progressBar.update(percentage);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
);
|
|
865
|
+
progressBar.update(100);
|
|
866
|
+
progressBar.stop();
|
|
867
|
+
ctx.logger.success("✨ Upload finished!");
|
|
868
|
+
return data.build_id;
|
|
869
|
+
} catch (e) {
|
|
870
|
+
progressBar.stop();
|
|
871
|
+
if (e instanceof axios.AxiosError && e.response?.data) {
|
|
872
|
+
if (e.response.status === 404) {
|
|
873
|
+
ctx.logger.error(
|
|
874
|
+
`The project does not exist. Remove the ${LOCAL_SAVE_FILENAME} file and try again.`
|
|
875
|
+
);
|
|
876
|
+
} else {
|
|
877
|
+
ctx.logger.error(e.response.data);
|
|
878
|
+
}
|
|
879
|
+
} else {
|
|
880
|
+
ctx.logger.error("An error occurred while deploying the project. Please try again later.");
|
|
881
|
+
}
|
|
882
|
+
ctx.logger.debug(e);
|
|
883
|
+
} finally {
|
|
884
|
+
await fse__default.default.remove(tarFilePath);
|
|
885
|
+
}
|
|
886
|
+
process.exit(0);
|
|
887
|
+
} catch (e) {
|
|
888
|
+
ctx.logger.error("An error occurred while deploying the project. Please try again later.");
|
|
889
|
+
ctx.logger.debug(e);
|
|
890
|
+
process.exit(1);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
async function getProject(ctx) {
|
|
894
|
+
const { project } = await retrieve();
|
|
895
|
+
if (!project) {
|
|
896
|
+
try {
|
|
897
|
+
return await action$3(ctx);
|
|
898
|
+
} catch (e) {
|
|
899
|
+
ctx.logger.error("An error occurred while deploying the project. Please try again later.");
|
|
900
|
+
ctx.logger.debug(e);
|
|
901
|
+
process.exit(1);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return project;
|
|
905
|
+
}
|
|
906
|
+
const action$2 = async (ctx) => {
|
|
907
|
+
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
908
|
+
const cloudApiService = await cloudApiFactory();
|
|
909
|
+
const token = await getValidToken();
|
|
910
|
+
if (!token) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
const project = await getProject(ctx);
|
|
914
|
+
if (!project) {
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
try {
|
|
918
|
+
await cloudApiService.track("willDeployWithCLI", { projectInternalName: project.name });
|
|
919
|
+
} catch (e) {
|
|
920
|
+
ctx.logger.debug("Failed to track willDeploy", e);
|
|
921
|
+
}
|
|
922
|
+
const notificationService = notificationServiceFactory(ctx);
|
|
923
|
+
const buildLogsService = buildLogsServiceFactory(ctx);
|
|
924
|
+
const { data: cliConfig2 } = await cloudApiService.config();
|
|
925
|
+
let maxSize = parseInt(cliConfig2.maxProjectFileSize, 10);
|
|
926
|
+
if (Number.isNaN(maxSize)) {
|
|
927
|
+
ctx.logger.debug(
|
|
928
|
+
"An error occurred while parsing the maxProjectFileSize. Using default value."
|
|
929
|
+
);
|
|
930
|
+
maxSize = 1e8;
|
|
931
|
+
}
|
|
932
|
+
const buildId = await upload(ctx, project, token, maxSize);
|
|
933
|
+
if (!buildId) {
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
try {
|
|
937
|
+
notificationService(`${apiConfig.apiBaseUrl}/notifications`, token, cliConfig2);
|
|
938
|
+
await buildLogsService(`${apiConfig.apiBaseUrl}/v1/logs/${buildId}`, token, cliConfig2);
|
|
939
|
+
ctx.logger.log(
|
|
940
|
+
"Visit the following URL for deployment logs. Your deployment will be available here shortly."
|
|
941
|
+
);
|
|
942
|
+
ctx.logger.log(
|
|
943
|
+
chalk__default.default.underline(`${apiConfig.dashboardBaseUrl}/projects/${project.name}/deployments`)
|
|
944
|
+
);
|
|
945
|
+
} catch (e) {
|
|
946
|
+
if (e instanceof Error) {
|
|
947
|
+
ctx.logger.error(e.message);
|
|
948
|
+
} else {
|
|
949
|
+
throw e;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
const assertCwdContainsStrapiProject = (name2) => {
|
|
954
|
+
const logErrorAndExit = () => {
|
|
955
|
+
console.log(
|
|
956
|
+
`You need to run ${chalk__default.default.yellow(
|
|
957
|
+
`strapi ${name2}`
|
|
958
|
+
)} in a Strapi project. Make sure you are in the right directory.`
|
|
959
|
+
);
|
|
960
|
+
process.exit(1);
|
|
961
|
+
};
|
|
962
|
+
try {
|
|
963
|
+
const pkgJSON = require(`${process.cwd()}/package.json`);
|
|
964
|
+
if (!fp.has("dependencies.@strapi/strapi", pkgJSON) && !fp.has("devDependencies.@strapi/strapi", pkgJSON)) {
|
|
965
|
+
logErrorAndExit();
|
|
966
|
+
}
|
|
967
|
+
} catch (err) {
|
|
968
|
+
logErrorAndExit();
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
const runAction = (name2, action2) => (...args) => {
|
|
972
|
+
assertCwdContainsStrapiProject(name2);
|
|
973
|
+
Promise.resolve().then(() => {
|
|
974
|
+
return action2(...args);
|
|
975
|
+
}).catch((error) => {
|
|
976
|
+
console.error(error);
|
|
977
|
+
process.exit(1);
|
|
978
|
+
});
|
|
979
|
+
};
|
|
980
|
+
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$2)(ctx));
|
|
982
|
+
};
|
|
983
|
+
const deployProject = {
|
|
984
|
+
name: "deploy-project",
|
|
985
|
+
description: "Deploy a Strapi Cloud project",
|
|
986
|
+
action: action$2,
|
|
987
|
+
command: command$3
|
|
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;
|
|
1145
|
+
};
|
|
1146
|
+
const command$2 = ({ command: command2, ctx }) => {
|
|
1147
|
+
command2.command("cloud:login").alias("login").description("Strapi Cloud Login").addHelpText(
|
|
1148
|
+
"after",
|
|
1149
|
+
"\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", action$1)(ctx));
|
|
1151
|
+
};
|
|
1152
|
+
const login = {
|
|
1153
|
+
name: "login",
|
|
1154
|
+
description: "Strapi Cloud Login",
|
|
1155
|
+
action: action$1,
|
|
1156
|
+
command: command$2
|
|
1157
|
+
};
|
|
1158
|
+
const action = async (ctx) => {
|
|
1159
|
+
const { logger } = ctx;
|
|
1160
|
+
const { retrieveToken, eraseToken } = await tokenServiceFactory(ctx);
|
|
1161
|
+
const token = await retrieveToken();
|
|
1162
|
+
if (!token) {
|
|
1163
|
+
logger.log("You're already logged out.");
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
const cloudApiService = await cloudApiFactory(token);
|
|
1167
|
+
try {
|
|
1168
|
+
await eraseToken();
|
|
1169
|
+
logger.log(
|
|
1170
|
+
"🔌 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
|
+
);
|
|
1172
|
+
} catch (e) {
|
|
1173
|
+
logger.error("🥲 Oops! Something went wrong while logging you out. Please try again.");
|
|
1174
|
+
logger.debug(e);
|
|
1175
|
+
}
|
|
1176
|
+
try {
|
|
1177
|
+
await cloudApiService.track("didLogout", { loginMethod: "cli" });
|
|
1178
|
+
} catch (e) {
|
|
1179
|
+
logger.debug("Failed to track logout event", e);
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
1182
|
+
const command$1 = ({ command: command2, ctx }) => {
|
|
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));
|
|
1184
|
+
};
|
|
1185
|
+
const logout = {
|
|
1186
|
+
name: "logout",
|
|
1187
|
+
description: "Strapi Cloud Logout",
|
|
1188
|
+
action,
|
|
1189
|
+
command: command$1
|
|
1190
|
+
};
|
|
1191
|
+
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$3)(ctx));
|
|
1193
|
+
};
|
|
1194
|
+
const createProject = {
|
|
1195
|
+
name: "create-project",
|
|
1196
|
+
description: "Create a new project",
|
|
1197
|
+
action: action$3,
|
|
1198
|
+
command
|
|
1199
|
+
};
|
|
1200
|
+
const cli = {
|
|
1201
|
+
deployProject,
|
|
1202
|
+
login,
|
|
1203
|
+
logout,
|
|
1204
|
+
createProject
|
|
1205
|
+
};
|
|
1206
|
+
const cloudCommands = [deployProject, login, logout];
|
|
1207
|
+
async function initCloudCLIConfig() {
|
|
1208
|
+
const localConfig = await getLocalConfig();
|
|
1209
|
+
if (!localConfig.deviceId) {
|
|
1210
|
+
localConfig.deviceId = crypto__default.default.randomUUID();
|
|
1211
|
+
}
|
|
1212
|
+
await saveLocalConfig(localConfig);
|
|
1213
|
+
}
|
|
1214
|
+
async function buildStrapiCloudCommands({
|
|
1215
|
+
command: command2,
|
|
1216
|
+
ctx,
|
|
1217
|
+
argv
|
|
1218
|
+
}) {
|
|
1219
|
+
await initCloudCLIConfig();
|
|
1220
|
+
for (const cloudCommand of cloudCommands) {
|
|
1221
|
+
try {
|
|
1222
|
+
await cloudCommand.command({ command: command2, ctx, argv });
|
|
1223
|
+
} catch (e) {
|
|
1224
|
+
console.error(`Failed to load command ${cloudCommand.name}`, e);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
exports.buildStrapiCloudCommands = buildStrapiCloudCommands;
|
|
1229
|
+
exports.cli = cli;
|
|
1230
|
+
exports.services = index;
|
|
1231
|
+
//# sourceMappingURL=index.js.map
|