@strapi/cloud-cli 0.0.0-experimental.3b8cc96a7394e7143a734079f23163e4316d01f5 → 0.1.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.
Files changed (63) hide show
  1. package/LICENSE +1 -1
  2. package/package.json +8 -54
  3. package/bin/index.js +0 -7
  4. package/dist/bin.d.ts +0 -5
  5. package/dist/bin.d.ts.map +0 -1
  6. package/dist/bin.js +0 -172
  7. package/dist/bin.js.map +0 -1
  8. package/dist/config/api.d.ts +0 -4
  9. package/dist/config/api.d.ts.map +0 -1
  10. package/dist/config/local.d.ts +0 -8
  11. package/dist/config/local.d.ts.map +0 -1
  12. package/dist/create-project/action.d.ts +0 -4
  13. package/dist/create-project/action.d.ts.map +0 -1
  14. package/dist/create-project/index.d.ts +0 -9
  15. package/dist/create-project/index.d.ts.map +0 -1
  16. package/dist/deploy-project/action.d.ts +0 -4
  17. package/dist/deploy-project/action.d.ts.map +0 -1
  18. package/dist/deploy-project/command.d.ts +0 -7
  19. package/dist/deploy-project/command.d.ts.map +0 -1
  20. package/dist/deploy-project/index.d.ts +0 -11
  21. package/dist/deploy-project/index.d.ts.map +0 -1
  22. package/dist/index.d.ts +0 -13
  23. package/dist/index.d.ts.map +0 -1
  24. package/dist/index.js +0 -1004
  25. package/dist/index.js.map +0 -1
  26. package/dist/index.mjs +0 -948
  27. package/dist/index.mjs.map +0 -1
  28. package/dist/login/action.d.ts +0 -4
  29. package/dist/login/action.d.ts.map +0 -1
  30. package/dist/login/command.d.ts +0 -7
  31. package/dist/login/command.d.ts.map +0 -1
  32. package/dist/login/index.d.ts +0 -11
  33. package/dist/login/index.d.ts.map +0 -1
  34. package/dist/logout/action.d.ts +0 -4
  35. package/dist/logout/action.d.ts.map +0 -1
  36. package/dist/logout/command.d.ts +0 -7
  37. package/dist/logout/command.d.ts.map +0 -1
  38. package/dist/logout/index.d.ts +0 -11
  39. package/dist/logout/index.d.ts.map +0 -1
  40. package/dist/services/build-logs.d.ts +0 -4
  41. package/dist/services/build-logs.d.ts.map +0 -1
  42. package/dist/services/cli-api.d.ts +0 -37
  43. package/dist/services/cli-api.d.ts.map +0 -1
  44. package/dist/services/index.d.ts +0 -5
  45. package/dist/services/index.d.ts.map +0 -1
  46. package/dist/services/logger.d.ts +0 -22
  47. package/dist/services/logger.d.ts.map +0 -1
  48. package/dist/services/notification.d.ts +0 -3
  49. package/dist/services/notification.d.ts.map +0 -1
  50. package/dist/services/strapi-info-save.d.ts +0 -15
  51. package/dist/services/strapi-info-save.d.ts.map +0 -1
  52. package/dist/services/token.d.ts +0 -12
  53. package/dist/services/token.d.ts.map +0 -1
  54. package/dist/types.d.ts +0 -33
  55. package/dist/types.d.ts.map +0 -1
  56. package/dist/utils/compress-files.d.ts +0 -4
  57. package/dist/utils/compress-files.d.ts.map +0 -1
  58. package/dist/utils/helpers.d.ts +0 -3
  59. package/dist/utils/helpers.d.ts.map +0 -1
  60. package/dist/utils/pkg.d.ts +0 -121
  61. package/dist/utils/pkg.d.ts.map +0 -1
  62. package/dist/utils/tests/compress-files.test.d.ts +0 -2
  63. package/dist/utils/tests/compress-files.test.d.ts.map +0 -1
package/dist/index.js DELETED
@@ -1,1004 +0,0 @@
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 fs = require("fs");
26
- const path = require("path");
27
- const axios = require("axios");
28
- const crypto = require("node:crypto");
29
- const utils = require("@strapi/utils");
30
- const tar = require("tar");
31
- const minimatch = require("minimatch");
32
- const inquirer = require("inquirer");
33
- const fp = require("lodash/fp");
34
- const jwksClient = require("jwks-rsa");
35
- const jwt = require("jsonwebtoken");
36
- const os = require("os");
37
- const XDGAppPaths = require("xdg-app-paths");
38
- const chalk = require("chalk");
39
- const ora = require("ora");
40
- const cliProgress = require("cli-progress");
41
- const EventSource = require("eventsource");
42
- const fs$1 = require("fs/promises");
43
- const pkgUp = require("pkg-up");
44
- const yup = require("yup");
45
- const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
46
- function _interopNamespace(e) {
47
- if (e && e.__esModule)
48
- return e;
49
- const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
50
- if (e) {
51
- for (const k in e) {
52
- if (k !== "default") {
53
- const d = Object.getOwnPropertyDescriptor(e, k);
54
- Object.defineProperty(n, k, d.get ? d : {
55
- enumerable: true,
56
- get: () => e[k]
57
- });
58
- }
59
- }
60
- }
61
- n.default = e;
62
- return Object.freeze(n);
63
- }
64
- const fs__namespace = /* @__PURE__ */ _interopNamespace(fs);
65
- const path__namespace = /* @__PURE__ */ _interopNamespace(path);
66
- const axios__default = /* @__PURE__ */ _interopDefault(axios);
67
- const crypto__namespace = /* @__PURE__ */ _interopNamespace(crypto);
68
- const tar__namespace = /* @__PURE__ */ _interopNamespace(tar);
69
- const inquirer__default = /* @__PURE__ */ _interopDefault(inquirer);
70
- const jwksClient__default = /* @__PURE__ */ _interopDefault(jwksClient);
71
- const jwt__default = /* @__PURE__ */ _interopDefault(jwt);
72
- const os__default = /* @__PURE__ */ _interopDefault(os);
73
- const XDGAppPaths__default = /* @__PURE__ */ _interopDefault(XDGAppPaths);
74
- const chalk__default = /* @__PURE__ */ _interopDefault(chalk);
75
- const ora__default = /* @__PURE__ */ _interopDefault(ora);
76
- const cliProgress__namespace = /* @__PURE__ */ _interopNamespace(cliProgress);
77
- const EventSource__default = /* @__PURE__ */ _interopDefault(EventSource);
78
- const fs__default = /* @__PURE__ */ _interopDefault(fs$1);
79
- const pkgUp__default = /* @__PURE__ */ _interopDefault(pkgUp);
80
- const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
81
- const apiConfig = {
82
- apiBaseUrl: utils.env("STRAPI_CLI_CLOUD_API", "https://cli.cloud.strapi.io")
83
- };
84
- const IGNORED_PATTERNS = [
85
- "**/.git/**",
86
- "**/node_modules/**",
87
- "**/build/**",
88
- "**/dist/**",
89
- "**/.cache/**",
90
- "**/.circleci/**",
91
- "**/.github/**",
92
- "**/.gitignore",
93
- "**/.gitkeep",
94
- "**/.gitlab-ci.yml",
95
- "**/.idea/**",
96
- "**/.vscode/**"
97
- ];
98
- const getFiles = (dirPath, ignorePatterns = [], arrayOfFiles = [], subfolder = "") => {
99
- const entries = fs__namespace.readdirSync(path__namespace.join(dirPath, subfolder));
100
- entries.forEach((entry) => {
101
- const entryPathFromRoot = path__namespace.join(subfolder, entry);
102
- const entryPath = path__namespace.relative(dirPath, entryPathFromRoot);
103
- const isIgnored = isIgnoredFile(dirPath, entryPathFromRoot, ignorePatterns);
104
- if (isIgnored) {
105
- return;
106
- }
107
- if (fs__namespace.statSync(entryPath).isDirectory()) {
108
- getFiles(dirPath, ignorePatterns, arrayOfFiles, entryPathFromRoot);
109
- } else {
110
- arrayOfFiles.push(entryPath);
111
- }
112
- });
113
- return arrayOfFiles;
114
- };
115
- const isIgnoredFile = (folderPath, file, ignorePatterns) => {
116
- ignorePatterns.push(...IGNORED_PATTERNS);
117
- const relativeFilePath = path__namespace.join(folderPath, file);
118
- let isIgnored = false;
119
- for (const pattern of ignorePatterns) {
120
- if (pattern.startsWith("!")) {
121
- if (minimatch.minimatch(relativeFilePath, pattern.slice(1), { matchBase: true, dot: true })) {
122
- return false;
123
- }
124
- } else if (minimatch.minimatch(relativeFilePath, pattern, { matchBase: true, dot: true })) {
125
- if (path__namespace.basename(file) !== ".gitkeep") {
126
- isIgnored = true;
127
- }
128
- }
129
- }
130
- return isIgnored;
131
- };
132
- const readGitignore = (folderPath) => {
133
- const gitignorePath = path__namespace.resolve(folderPath, ".gitignore");
134
- if (!fs__namespace.existsSync(gitignorePath))
135
- return [];
136
- const gitignoreContent = fs__namespace.readFileSync(gitignorePath, "utf8");
137
- return gitignoreContent.split("\n").filter((line) => Boolean(line.trim()) && !line.startsWith("#"));
138
- };
139
- const compressFilesToTar = async (storagePath, folderToCompress, filename) => {
140
- const ignorePatterns = readGitignore(folderToCompress);
141
- const filesToCompress = getFiles(folderToCompress, ignorePatterns);
142
- return tar__namespace.c(
143
- {
144
- gzip: true,
145
- file: path__namespace.resolve(storagePath, filename)
146
- },
147
- filesToCompress
148
- );
149
- };
150
- const VERSION = "v1";
151
- function cloudApiFactory(token) {
152
- const axiosCloudAPI = axios__default.default.create({
153
- baseURL: `${apiConfig.apiBaseUrl}/${VERSION}`,
154
- headers: {
155
- "Content-Type": "application/json"
156
- }
157
- });
158
- if (token) {
159
- axiosCloudAPI.defaults.headers.Authorization = `Bearer ${token}`;
160
- }
161
- return {
162
- deploy({ filePath, project }, { onUploadProgress }) {
163
- return axiosCloudAPI.post(
164
- `/deploy/${project.name}`,
165
- { file: fs__namespace.createReadStream(filePath) },
166
- {
167
- headers: {
168
- "Content-Type": "multipart/form-data"
169
- },
170
- onUploadProgress
171
- }
172
- );
173
- },
174
- async createProject({ name, nodeVersion, region, plan }) {
175
- const response = await axiosCloudAPI.post("/project", {
176
- projectName: name,
177
- region,
178
- nodeVersion,
179
- plan
180
- });
181
- return {
182
- data: {
183
- id: response.data.id,
184
- name: response.data.name,
185
- nodeVersion: response.data.nodeVersion,
186
- region: response.data.region
187
- },
188
- status: response.status
189
- };
190
- },
191
- getUserInfo() {
192
- return axiosCloudAPI.get("/user");
193
- },
194
- config() {
195
- return axiosCloudAPI.get("/config");
196
- },
197
- listProjects() {
198
- return axiosCloudAPI.get("/projects");
199
- }
200
- };
201
- }
202
- const LOCAL_SAVE_FILENAME = ".strapi-cloud.json";
203
- function save(data, { directoryPath } = {}) {
204
- const storedData = { ...retrieve(), ...data };
205
- const pathToFile = path__namespace.default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
206
- if (!fs__namespace.default.existsSync(path__namespace.default.dirname(pathToFile))) {
207
- fs__namespace.default.mkdirSync(path__namespace.default.dirname(pathToFile), { recursive: true });
208
- }
209
- fs__namespace.default.writeFileSync(pathToFile, JSON.stringify(storedData), "utf8");
210
- }
211
- function retrieve({ directoryPath } = {}) {
212
- const pathToFile = path__namespace.default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
213
- if (!fs__namespace.default.existsSync(pathToFile)) {
214
- return {};
215
- }
216
- return JSON.parse(fs__namespace.default.readFileSync(pathToFile, "utf8"));
217
- }
218
- function erase({ directoryPath } = {}) {
219
- const pathToFile = path__namespace.default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
220
- if (fs__namespace.default.existsSync(pathToFile)) {
221
- fs__namespace.default.unlinkSync(pathToFile);
222
- }
223
- }
224
- const strapiInfoSave = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
225
- __proto__: null,
226
- LOCAL_SAVE_FILENAME,
227
- erase,
228
- retrieve,
229
- save
230
- }, Symbol.toStringTag, { value: "Module" }));
231
- const APP_FOLDER_NAME = "com.strapi.cli";
232
- const CONFIG_FILENAME = "config.json";
233
- function checkDirectoryExists(directoryPath) {
234
- try {
235
- return fs__namespace.default.lstatSync(directoryPath).isDirectory();
236
- } catch (e) {
237
- return false;
238
- }
239
- }
240
- function getTmpStoragePath() {
241
- const storagePath = path__namespace.default.join(os__default.default.tmpdir(), APP_FOLDER_NAME);
242
- if (!checkDirectoryExists(storagePath)) {
243
- fs__namespace.default.mkdirSync(storagePath, { recursive: true });
244
- }
245
- return storagePath;
246
- }
247
- function getConfigPath() {
248
- const configDirs = XDGAppPaths__default.default(APP_FOLDER_NAME).configDirs();
249
- const configPath = configDirs.find(checkDirectoryExists);
250
- if (!configPath) {
251
- fs__namespace.default.mkdirSync(configDirs[0], { recursive: true });
252
- return configDirs[0];
253
- }
254
- return configPath;
255
- }
256
- function getLocalConfig() {
257
- const configPath = getConfigPath();
258
- const configFilePath = path__namespace.default.join(configPath, CONFIG_FILENAME);
259
- if (!fs__namespace.default.existsSync(configFilePath)) {
260
- return {};
261
- }
262
- try {
263
- return JSON.parse(fs__namespace.default.readFileSync(configFilePath, "utf8"));
264
- } catch (e) {
265
- return {};
266
- }
267
- }
268
- function saveLocalConfig(data) {
269
- const configPath = getConfigPath();
270
- const configFilePath = path__namespace.default.join(configPath, CONFIG_FILENAME);
271
- fs__namespace.default.writeFileSync(configFilePath, JSON.stringify(data), { encoding: "utf8", mode: 384 });
272
- }
273
- const cloudApiService$1 = cloudApiFactory();
274
- let cliConfig;
275
- function tokenServiceFactory({ logger }) {
276
- function saveToken(str) {
277
- const appConfig = getLocalConfig();
278
- if (!appConfig) {
279
- logger.error("There was a problem saving your token. Please try again.");
280
- return;
281
- }
282
- appConfig.token = str;
283
- try {
284
- saveLocalConfig(appConfig);
285
- } catch (error) {
286
- logger.debug(error);
287
- logger.error("There was a problem saving your token. Please try again.");
288
- }
289
- }
290
- async function retrieveToken() {
291
- const appConfig = getLocalConfig();
292
- if (appConfig.token) {
293
- if (await isTokenValid(appConfig.token)) {
294
- return appConfig.token;
295
- }
296
- }
297
- return void 0;
298
- }
299
- async function validateToken(idToken, jwksUrl) {
300
- const client = jwksClient__default.default({
301
- jwksUri: jwksUrl
302
- });
303
- const getKey = (header, callback) => {
304
- client.getSigningKey(header.kid, (err, key) => {
305
- if (err) {
306
- callback(err);
307
- } else if (key) {
308
- const publicKey = "publicKey" in key ? key.publicKey : key.rsaPublicKey;
309
- callback(null, publicKey);
310
- } else {
311
- callback(new Error("Key not found"));
312
- }
313
- });
314
- };
315
- const decodedToken = jwt__default.default.decode(idToken, { complete: true });
316
- if (!decodedToken) {
317
- if (typeof idToken === "undefined" || idToken === "") {
318
- logger.warn("You need to be logged in to use this feature. Please log in and try again.");
319
- } else {
320
- logger.error(
321
- "There seems to be a problem with your login information. Please try logging in again."
322
- );
323
- }
324
- }
325
- return new Promise((resolve, reject) => {
326
- jwt__default.default.verify(idToken, getKey, (err) => {
327
- if (err) {
328
- reject(err);
329
- } else {
330
- resolve();
331
- }
332
- });
333
- });
334
- }
335
- async function isTokenValid(token) {
336
- try {
337
- const config = await cloudApiService$1.config();
338
- cliConfig = config.data;
339
- if (token) {
340
- await validateToken(token, cliConfig.jwksUrl);
341
- return true;
342
- }
343
- return false;
344
- } catch (error) {
345
- logger.debug(error);
346
- return false;
347
- }
348
- }
349
- function eraseToken() {
350
- const appConfig = getLocalConfig();
351
- if (!appConfig) {
352
- return;
353
- }
354
- delete appConfig.token;
355
- try {
356
- saveLocalConfig(appConfig);
357
- } catch (error) {
358
- logger.debug(error);
359
- logger.error(
360
- "There was an issue removing your login information. Please try logging out again."
361
- );
362
- }
363
- }
364
- async function getValidToken() {
365
- const token = await retrieveToken();
366
- if (!token) {
367
- logger.log("No token found. Please login first.");
368
- return null;
369
- }
370
- if (!await isTokenValid(token)) {
371
- logger.log("Unable to proceed: Token is expired or not valid. Please login again.");
372
- return null;
373
- }
374
- return token;
375
- }
376
- return {
377
- saveToken,
378
- retrieveToken,
379
- validateToken,
380
- isTokenValid,
381
- eraseToken,
382
- getValidToken
383
- };
384
- }
385
- const createLogger = (options = {}) => {
386
- const { silent = false, debug = false, timestamp = true } = options;
387
- const state = { errors: 0, warning: 0 };
388
- return {
389
- get warnings() {
390
- return state.warning;
391
- },
392
- get errors() {
393
- return state.errors;
394
- },
395
- debug(...args) {
396
- if (silent || !debug) {
397
- return;
398
- }
399
- console.log(
400
- chalk__default.default.cyan(`[DEBUG]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
401
- ...args
402
- );
403
- },
404
- info(...args) {
405
- if (silent) {
406
- return;
407
- }
408
- console.info(
409
- chalk__default.default.blue(`[INFO]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
410
- ...args
411
- );
412
- },
413
- log(...args) {
414
- if (silent) {
415
- return;
416
- }
417
- console.info(chalk__default.default.blue(`${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`), ...args);
418
- },
419
- success(...args) {
420
- if (silent) {
421
- return;
422
- }
423
- console.info(
424
- chalk__default.default.green(`[SUCCESS]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
425
- ...args
426
- );
427
- },
428
- warn(...args) {
429
- state.warning += 1;
430
- if (silent) {
431
- return;
432
- }
433
- console.warn(
434
- chalk__default.default.yellow(`[WARN]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
435
- ...args
436
- );
437
- },
438
- error(...args) {
439
- state.errors += 1;
440
- if (silent) {
441
- return;
442
- }
443
- console.error(
444
- chalk__default.default.red(`[ERROR]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
445
- ...args
446
- );
447
- },
448
- // @ts-expect-error – returning a subpart of ora is fine because the types tell us what is what.
449
- spinner(text) {
450
- if (silent) {
451
- return {
452
- succeed() {
453
- return this;
454
- },
455
- fail() {
456
- return this;
457
- },
458
- start() {
459
- return this;
460
- },
461
- text: "",
462
- isSpinning: false
463
- };
464
- }
465
- return ora__default.default(text);
466
- },
467
- progressBar(totalSize, text) {
468
- if (silent) {
469
- return {
470
- start() {
471
- return this;
472
- },
473
- stop() {
474
- return this;
475
- },
476
- update() {
477
- return this;
478
- }
479
- };
480
- }
481
- const progressBar = new cliProgress__namespace.SingleBar({
482
- format: `${text ? `${text} |` : ""}${chalk__default.default.green("{bar}")}| {percentage}%`,
483
- barCompleteChar: "█",
484
- barIncompleteChar: "░",
485
- hideCursor: true,
486
- forceRedraw: true
487
- });
488
- progressBar.start(totalSize, 0);
489
- return progressBar;
490
- }
491
- };
492
- };
493
- const index$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
494
- __proto__: null,
495
- cloudApiFactory,
496
- createLogger,
497
- local: strapiInfoSave,
498
- tokenServiceFactory
499
- }, Symbol.toStringTag, { value: "Module" }));
500
- function handleError(ctx, error) {
501
- const tokenService = tokenServiceFactory(ctx);
502
- const { logger } = ctx;
503
- logger.debug(JSON.stringify(error));
504
- if (error instanceof axios.AxiosError) {
505
- switch (error.response?.status) {
506
- case 401:
507
- logger.error("Your session has expired. Please log in again.");
508
- tokenService.eraseToken();
509
- return;
510
- case 403:
511
- logger.error(
512
- error.response.data || "You do not have permission to create a project. Please contact support for assistance."
513
- );
514
- return;
515
- case 400:
516
- logger.error("Invalid input. Please check your inputs and try again.");
517
- return;
518
- }
519
- }
520
- logger.error(
521
- "We encountered an issue while creating your project. Please try again in a moment. If the problem persists, contact support for assistance."
522
- );
523
- }
524
- const action$3 = (ctx) => {
525
- const { getValidToken } = tokenServiceFactory(ctx);
526
- return async () => {
527
- const token = await getValidToken();
528
- if (!token) {
529
- return;
530
- }
531
- const cloudApi = cloudApiFactory(token);
532
- const { data: config } = await cloudApi.config();
533
- const { questions, defaults: defaultValues } = config.projectCreation;
534
- const projectAnswersDefaulted = fp.defaults(defaultValues);
535
- const projectAnswers = await inquirer__default.default.prompt(questions);
536
- const projectInput = projectAnswersDefaulted(projectAnswers);
537
- try {
538
- const { data } = await cloudApi.createProject(projectInput);
539
- save({ project: data });
540
- return data;
541
- } catch (error) {
542
- handleError(ctx, error);
543
- }
544
- };
545
- };
546
- const CONN_TIMEOUT = 5 * 60 * 1e3;
547
- function notificationServiceFactory({ logger }) {
548
- return (url, token) => {
549
- const es = new EventSource__default.default(url, {
550
- headers: {
551
- Authorization: `Bearer ${token}`
552
- }
553
- });
554
- let timeoutId;
555
- const resetTimeout = () => {
556
- clearTimeout(timeoutId);
557
- timeoutId = setTimeout(() => {
558
- logger.log(
559
- "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."
560
- );
561
- es.close();
562
- }, CONN_TIMEOUT);
563
- };
564
- es.onopen = resetTimeout;
565
- es.onmessage = (event) => {
566
- resetTimeout();
567
- const data = JSON.parse(event.data);
568
- if (data.message) {
569
- logger.log(data.message);
570
- }
571
- if (data.event === "deploymentFinished" || data.event === "deploymentFailed") {
572
- es.close();
573
- }
574
- };
575
- };
576
- }
577
- yup__namespace.object({
578
- name: yup__namespace.string().required(),
579
- exports: yup__namespace.lazy(
580
- (value) => yup__namespace.object(
581
- typeof value === "object" ? Object.entries(value).reduce((acc, [key, value2]) => {
582
- if (typeof value2 === "object") {
583
- acc[key] = yup__namespace.object({
584
- types: yup__namespace.string().optional(),
585
- source: yup__namespace.string().required(),
586
- module: yup__namespace.string().optional(),
587
- import: yup__namespace.string().required(),
588
- require: yup__namespace.string().required(),
589
- default: yup__namespace.string().required()
590
- }).noUnknown(true);
591
- } else {
592
- acc[key] = yup__namespace.string().matches(/^\.\/.*\.json$/).required();
593
- }
594
- return acc;
595
- }, {}) : void 0
596
- ).optional()
597
- )
598
- });
599
- const loadPkg = async ({ cwd, logger }) => {
600
- const pkgPath = await pkgUp__default.default({ cwd });
601
- if (!pkgPath) {
602
- throw new Error("Could not find a package.json in the current directory");
603
- }
604
- const buffer = await fs__default.default.readFile(pkgPath);
605
- const pkg = JSON.parse(buffer.toString());
606
- logger.debug("Loaded package.json:", os__default.default.EOL, pkg);
607
- return pkg;
608
- };
609
- const buildLogsServiceFactory = ({ logger }) => {
610
- return async (url, token) => {
611
- const CONN_TIMEOUT2 = 12e4;
612
- const MAX_RETRIES = 5;
613
- return new Promise((resolve, reject) => {
614
- let timeoutId = null;
615
- let retries = 0;
616
- const connect = (url2) => {
617
- const spinner = logger.spinner("Connecting to server to get build logs");
618
- spinner.start();
619
- const es = new EventSource__default.default(`${url2}`, {
620
- headers: {
621
- Authorization: `Bearer ${token}`
622
- }
623
- });
624
- const clearExistingTimeout = () => {
625
- if (timeoutId) {
626
- clearTimeout(timeoutId);
627
- }
628
- };
629
- const resetTimeout = () => {
630
- clearExistingTimeout();
631
- timeoutId = setTimeout(() => {
632
- logger.log(
633
- "We were unable to connect to the server to get build logs at this time. This could be due to a temporary issue."
634
- );
635
- es.close();
636
- reject(new Error("Connection timed out"));
637
- }, CONN_TIMEOUT2);
638
- };
639
- es.onopen = resetTimeout;
640
- es.addEventListener("finished", (event) => {
641
- const data = JSON.parse(event.data);
642
- logger.log(data.msg);
643
- es.close();
644
- clearExistingTimeout();
645
- resolve(null);
646
- });
647
- es.addEventListener("log", (event) => {
648
- if (spinner.isSpinning) {
649
- spinner.succeed();
650
- }
651
- resetTimeout();
652
- const data = JSON.parse(event.data);
653
- logger.log(data.msg);
654
- });
655
- es.onerror = async () => {
656
- retries += 1;
657
- if (retries > MAX_RETRIES) {
658
- spinner.fail("We were unable to connect to the server to get build logs at this time.");
659
- es.close();
660
- reject(new Error("Max retries reached"));
661
- }
662
- };
663
- };
664
- connect(url);
665
- });
666
- };
667
- };
668
- const FILE_SIZE_LIMIT = 100 * 1024 * 1024;
669
- async function upload(ctx, project, token) {
670
- const cloudApi = cloudApiFactory(token);
671
- try {
672
- const storagePath = getTmpStoragePath();
673
- const projectFolder = path__namespace.default.resolve(process.cwd());
674
- const packageJson = await loadPkg(ctx);
675
- if (!packageJson) {
676
- ctx.logger.error(
677
- "Unable to deploy the project. Please make sure the package.json file is correctly formatted."
678
- );
679
- return;
680
- }
681
- ctx.logger.log("📦 Compressing project...");
682
- const hashname = crypto__namespace.createHash("sha512").update(packageJson.name).digest("hex");
683
- const compressedFilename = `${hashname}.tar.gz`;
684
- try {
685
- ctx.logger.debug(
686
- "Compression parameters\n",
687
- `Storage path: ${storagePath}
688
- `,
689
- `Project folder: ${projectFolder}
690
- `,
691
- `Compressed filename: ${compressedFilename}`
692
- );
693
- await compressFilesToTar(storagePath, projectFolder, compressedFilename);
694
- ctx.logger.log("📦 Project compressed successfully!");
695
- } catch (error) {
696
- ctx.logger.error(
697
- "⚠️ Project compression failed. Try again later or check for large/incompatible files."
698
- );
699
- ctx.logger.debug(error);
700
- process.exit(1);
701
- }
702
- const tarFilePath = path__namespace.default.resolve(storagePath, compressedFilename);
703
- const fileStats = fs__namespace.default.statSync(tarFilePath);
704
- if (fileStats.size > FILE_SIZE_LIMIT) {
705
- return ctx.logger.log(
706
- "Unable to proceed: Your project is too big to be transferred, please use a git repo instead."
707
- );
708
- }
709
- ctx.logger.info("🚀 Uploading project...");
710
- const progressBar = ctx.logger.progressBar(100, "Upload Progress");
711
- try {
712
- const { data } = await cloudApi.deploy(
713
- { filePath: tarFilePath, project },
714
- {
715
- onUploadProgress(progressEvent) {
716
- const total = progressEvent.total || fileStats.size;
717
- const percentage = Math.round(progressEvent.loaded * 100 / total);
718
- progressBar.update(percentage);
719
- }
720
- }
721
- );
722
- progressBar.update(100);
723
- progressBar.stop();
724
- ctx.logger.success("✨ Upload finished!");
725
- return data.build_id;
726
- } catch (error) {
727
- progressBar.stop();
728
- if (error instanceof axios.AxiosError && error.response?.data) {
729
- if (error.response.status === 404) {
730
- ctx.logger.error(
731
- `The project does not exist. Remove the ${LOCAL_SAVE_FILENAME} file and try again.`
732
- );
733
- } else {
734
- ctx.logger.error(error.response.data);
735
- }
736
- } else {
737
- ctx.logger.error("An error occurred while deploying the project. Please try again later.");
738
- }
739
- ctx.logger.debug(JSON.stringify(error));
740
- } finally {
741
- fs__namespace.default.rmSync(tarFilePath, { force: true });
742
- }
743
- process.exit(0);
744
- } catch (e) {
745
- ctx.logger.error("An error occurred while deploying the project. Please try again later.");
746
- ctx.logger.debug(JSON.stringify(e));
747
- process.exit(1);
748
- }
749
- }
750
- async function getProject(ctx) {
751
- const { project } = retrieve();
752
- if (!project) {
753
- try {
754
- return await action$3(ctx)();
755
- } catch (error) {
756
- ctx.logger.error("An error occurred while deploying the project. Please try again later.");
757
- ctx.logger.debug(JSON.stringify(error));
758
- process.exit(1);
759
- }
760
- }
761
- return project;
762
- }
763
- const action$2 = async (ctx) => {
764
- const { getValidToken } = tokenServiceFactory(ctx);
765
- const token = await getValidToken();
766
- if (!token) {
767
- return;
768
- }
769
- const project = await getProject(ctx);
770
- if (!project) {
771
- return;
772
- }
773
- const notificationService = notificationServiceFactory(ctx);
774
- const buildLogsService = buildLogsServiceFactory(ctx);
775
- const buildId = await upload(ctx, project, token);
776
- try {
777
- await Promise.all([
778
- notificationService(`${apiConfig.apiBaseUrl}/notifications`, token),
779
- buildLogsService(`${apiConfig.apiBaseUrl}/v1/logs/${buildId}`, token)
780
- ]);
781
- } catch (e) {
782
- if (e instanceof Error) {
783
- ctx.logger.error(e.message);
784
- }
785
- }
786
- };
787
- const assertCwdContainsStrapiProject = (name) => {
788
- const logErrorAndExit = () => {
789
- console.log(
790
- `You need to run ${chalk__default.default.yellow(
791
- `strapi ${name}`
792
- )} in a Strapi project. Make sure you are in the right directory.`
793
- );
794
- process.exit(1);
795
- };
796
- try {
797
- const pkgJSON = require(`${process.cwd()}/package.json`);
798
- if (!fp.has("dependencies.@strapi/strapi", pkgJSON) && !fp.has("devDependencies.@strapi/strapi", pkgJSON)) {
799
- logErrorAndExit();
800
- }
801
- } catch (err) {
802
- logErrorAndExit();
803
- }
804
- };
805
- const runAction = (name, action2) => (...args) => {
806
- assertCwdContainsStrapiProject(name);
807
- Promise.resolve().then(() => {
808
- return action2(...args);
809
- }).catch((error) => {
810
- console.error(error);
811
- process.exit(1);
812
- });
813
- };
814
- const command$2 = ({ command: command2, ctx }) => {
815
- return command2.command("cloud:deploy").alias("deploy").description("Deploy a Strapi Cloud project").action(() => runAction("deploy", action$2)(ctx));
816
- };
817
- const index$3 = {
818
- name: "deploy-project",
819
- description: "Deploy a Strapi Cloud project",
820
- action: action$2,
821
- command: command$2
822
- };
823
- const deployProject = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
824
- __proto__: null,
825
- action: action$2,
826
- command: command$2,
827
- default: index$3
828
- }, Symbol.toStringTag, { value: "Module" }));
829
- const openModule = import("open");
830
- const cloudApiService = cloudApiFactory();
831
- const action$1 = async (ctx) => {
832
- const { logger } = ctx;
833
- const tokenService = tokenServiceFactory(ctx);
834
- let cliConfig2;
835
- try {
836
- logger.info("🔌 Connecting to the Strapi Cloud API...");
837
- const config = await cloudApiService.config();
838
- cliConfig2 = config.data;
839
- } catch (error) {
840
- logger.error("🥲 Oops! Something went wrong while logging you in. Please try again.");
841
- logger.debug(error);
842
- return;
843
- }
844
- logger.debug("🔐 Creating device authentication request...", {
845
- client_id: cliConfig2.clientId,
846
- scope: cliConfig2.scope,
847
- audience: cliConfig2.audience
848
- });
849
- const deviceAuthResponse = await axios__default.default.post(cliConfig2.deviceCodeAuthUrl, {
850
- client_id: cliConfig2.clientId,
851
- scope: cliConfig2.scope,
852
- audience: cliConfig2.audience
853
- }).catch((error) => {
854
- logger.error("There was an issue with the authentication process. Please try again.");
855
- if (error.message) {
856
- logger.debug(error.message, error);
857
- } else {
858
- logger.debug(error);
859
- }
860
- });
861
- openModule.then((open) => {
862
- open.default(deviceAuthResponse.data.verification_uri_complete).catch((err) => {
863
- logger.error("We encountered an issue opening the browser. Please try again later.");
864
- logger.debug(err.message, err);
865
- });
866
- });
867
- logger.log("If a browser tab does not open automatically, please follow the next steps:");
868
- logger.log(
869
- `1. Open this url in your device: ${deviceAuthResponse.data.verification_uri_complete}`
870
- );
871
- logger.log(
872
- `2. Enter the following code: ${deviceAuthResponse.data.user_code} and confirm to login.
873
- `
874
- );
875
- const tokenPayload = {
876
- grant_type: "urn:ietf:params:oauth:grant-type:device_code",
877
- device_code: deviceAuthResponse.data.device_code,
878
- client_id: cliConfig2.clientId
879
- };
880
- let isAuthenticated = false;
881
- const authenticate = async () => {
882
- const spinner = logger.spinner("Waiting for authentication");
883
- spinner.start();
884
- const spinnerFail = () => spinner.fail("Authentication failed!");
885
- while (!isAuthenticated) {
886
- try {
887
- const tokenResponse = await axios__default.default.post(cliConfig2.tokenUrl, tokenPayload);
888
- const authTokenData = tokenResponse.data;
889
- if (tokenResponse.status === 200) {
890
- try {
891
- logger.debug("🔐 Validating token...");
892
- await tokenService.validateToken(authTokenData.id_token, cliConfig2.jwksUrl);
893
- logger.debug("🔐 Token validation successful!");
894
- } catch (error) {
895
- logger.debug(error);
896
- spinnerFail();
897
- throw new Error("Unable to proceed: Token validation failed");
898
- }
899
- const cloudApiService2 = cloudApiFactory(authTokenData.access_token);
900
- logger.debug("🔍 Fetching user information...");
901
- await cloudApiService2.getUserInfo();
902
- logger.debug("🔍 User information fetched successfully!");
903
- try {
904
- logger.debug("📝 Saving login information...");
905
- await tokenService.saveToken(authTokenData.access_token);
906
- logger.debug("📝 Login information saved successfully!");
907
- isAuthenticated = true;
908
- } catch (error) {
909
- logger.error(
910
- "There was a problem saving your login information. Please try logging in again."
911
- );
912
- logger.debug(error);
913
- spinnerFail();
914
- return;
915
- }
916
- }
917
- } catch (error) {
918
- if (error.message === "Unable to proceed: Token validation failed") {
919
- logger.error(
920
- "There seems to be a problem with your login information. Please try logging in again."
921
- );
922
- spinnerFail();
923
- return;
924
- }
925
- if (error.response?.data.error && !["authorization_pending", "slow_down"].includes(error.response.data.error)) {
926
- logger.debug(error);
927
- spinnerFail();
928
- return;
929
- }
930
- await new Promise((resolve) => {
931
- setTimeout(resolve, deviceAuthResponse.data.interval * 1e3);
932
- });
933
- }
934
- }
935
- spinner.succeed("Authentication successful!");
936
- logger.log("You are now logged in to Strapi Cloud.");
937
- };
938
- await authenticate();
939
- };
940
- const command$1 = ({ command: command2, ctx }) => {
941
- return command2.command("cloud:login").alias("login").description("Strapi Cloud Login").addHelpText("after", "\nAfter running this command, you will be prompted to enter your authentication information.").action(() => runAction("login", action$1)(ctx));
942
- };
943
- const index$2 = {
944
- name: "login",
945
- description: "Strapi Cloud Login",
946
- action: action$1,
947
- command: command$1
948
- };
949
- const login = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
950
- __proto__: null,
951
- action: action$1,
952
- command: command$1,
953
- default: index$2
954
- }, Symbol.toStringTag, { value: "Module" }));
955
- const action = async (ctx) => {
956
- const { logger } = ctx;
957
- const { retrieveToken, eraseToken } = tokenServiceFactory(ctx);
958
- const token = await retrieveToken();
959
- if (!token) {
960
- logger.log("You're already logged out.");
961
- return;
962
- }
963
- try {
964
- await eraseToken();
965
- logger.log("🔌 You have been logged out.");
966
- } catch (error) {
967
- logger.error("🥲 Oops! Something went wrong while logging you out. Please try again.");
968
- logger.debug(error);
969
- }
970
- };
971
- const command = ({ command: command2, ctx }) => {
972
- return command2.command("cloud:logout").alias("logout").description("Strapi Cloud Logout").action(() => runAction("logout", action)(ctx));
973
- };
974
- const index$1 = {
975
- name: "logout",
976
- description: "Strapi Cloud Logout",
977
- action,
978
- command
979
- };
980
- const logout = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
981
- __proto__: null,
982
- action,
983
- command,
984
- default: index$1
985
- }, Symbol.toStringTag, { value: "Module" }));
986
- const index = {
987
- name: "create-project",
988
- description: "Create a new project",
989
- action: action$3
990
- };
991
- const createProject = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
992
- __proto__: null,
993
- action: action$3,
994
- default: index
995
- }, Symbol.toStringTag, { value: "Module" }));
996
- const cli = {
997
- deployProject,
998
- login,
999
- logout,
1000
- createProject
1001
- };
1002
- exports.cli = cli;
1003
- exports.services = index$4;
1004
- //# sourceMappingURL=index.js.map