create-strapi-app 5.8.1 → 5.10.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/dist/index.js CHANGED
@@ -1,508 +1,503 @@
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 path = require("node:path");
26
- const os$1 = require("node:os");
27
- const chalk = require("chalk");
28
- const commander = require("commander");
29
- const crypto = require("crypto");
30
- const fse = require("fs-extra");
31
- const inquirer = require("inquirer");
32
- const cloudCli = require("@strapi/cloud-cli");
33
- const execa = require("execa");
34
- const url = require("node:url");
35
- const node_stream = require("node:stream");
36
- const promises = require("node:stream/promises");
37
- const tar = require("tar");
38
- const retry = require("async-retry");
39
- const os = require("os");
40
- const _ = require("lodash");
41
- const path$1 = require("path");
42
- const semver = require("semver");
43
- const nodeMachineId = require("node-machine-id");
44
- const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
45
- function _interopNamespace(e) {
46
- if (e && e.__esModule) return e;
47
- const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
1
+ 'use strict';
2
+
3
+ var path = require('node:path');
4
+ var os$1 = require('node:os');
5
+ var chalk = require('chalk');
6
+ var commander = require('commander');
7
+ var crypto = require('crypto');
8
+ var fse = require('fs-extra');
9
+ var inquirer = require('inquirer');
10
+ var cloudCli = require('@strapi/cloud-cli');
11
+ var execa = require('execa');
12
+ var url = require('node:url');
13
+ var node_stream = require('node:stream');
14
+ var promises = require('node:stream/promises');
15
+ var tar = require('tar');
16
+ var retry = require('async-retry');
17
+ var os = require('os');
18
+ var _ = require('lodash');
19
+ var path$1 = require('path');
20
+ var semver = require('semver');
21
+ var nodeMachineId = require('node-machine-id');
22
+
23
+ function _interopNamespaceDefault(e) {
24
+ var n = Object.create(null);
48
25
  if (e) {
49
- for (const k in e) {
50
- if (k !== "default") {
51
- const d = Object.getOwnPropertyDescriptor(e, k);
26
+ Object.keys(e).forEach(function (k) {
27
+ if (k !== 'default') {
28
+ var d = Object.getOwnPropertyDescriptor(e, k);
52
29
  Object.defineProperty(n, k, d.get ? d : {
53
30
  enumerable: true,
54
- get: () => e[k]
31
+ get: function () { return e[k]; }
55
32
  });
56
33
  }
57
- }
34
+ });
58
35
  }
59
36
  n.default = e;
60
37
  return Object.freeze(n);
61
38
  }
62
- const path__default = /* @__PURE__ */ _interopDefault(path);
63
- const os__default$1 = /* @__PURE__ */ _interopDefault(os$1);
64
- const chalk__default = /* @__PURE__ */ _interopDefault(chalk);
65
- const commander__default = /* @__PURE__ */ _interopDefault(commander);
66
- const crypto__default = /* @__PURE__ */ _interopDefault(crypto);
67
- const fse__default = /* @__PURE__ */ _interopDefault(fse);
68
- const inquirer__default = /* @__PURE__ */ _interopDefault(inquirer);
69
- const execa__default = /* @__PURE__ */ _interopDefault(execa);
70
- const url__default = /* @__PURE__ */ _interopDefault(url);
71
- const tar__namespace = /* @__PURE__ */ _interopNamespace(tar);
72
- const retry__default = /* @__PURE__ */ _interopDefault(retry);
73
- const os__default = /* @__PURE__ */ _interopDefault(os);
74
- const ___default = /* @__PURE__ */ _interopDefault(_);
75
- const semver__default = /* @__PURE__ */ _interopDefault(semver);
39
+
40
+ var tar__namespace = /*#__PURE__*/_interopNamespaceDefault(tar);
41
+
76
42
  async function directory() {
77
- const { directory: directory2 } = await inquirer__default.default.prompt([
78
- {
79
- type: "input",
80
- default: "my-strapi-project",
81
- name: "directory",
82
- message: "What is the name of your project?"
83
- }
84
- ]);
85
- return directory2;
43
+ const { directory } = await inquirer.prompt([
44
+ {
45
+ type: 'input',
46
+ default: 'my-strapi-project',
47
+ name: 'directory',
48
+ message: 'What is the name of your project?'
49
+ }
50
+ ]);
51
+ return directory;
86
52
  }
87
53
  async function typescript() {
88
- const { useTypescript } = await inquirer__default.default.prompt([
89
- {
90
- type: "confirm",
91
- name: "useTypescript",
92
- message: "Start with Typescript?",
93
- default: true
94
- }
95
- ]);
96
- return useTypescript;
54
+ const { useTypescript } = await inquirer.prompt([
55
+ {
56
+ type: 'confirm',
57
+ name: 'useTypescript',
58
+ message: 'Start with Typescript?',
59
+ default: true
60
+ }
61
+ ]);
62
+ return useTypescript;
97
63
  }
98
64
  async function example() {
99
- const { useExample } = await inquirer__default.default.prompt([
100
- {
101
- type: "confirm",
102
- name: "useExample",
103
- message: "Start with an example structure & data?",
104
- default: false
105
- }
106
- ]);
107
- return useExample;
65
+ const { useExample } = await inquirer.prompt([
66
+ {
67
+ type: 'confirm',
68
+ name: 'useExample',
69
+ message: 'Start with an example structure & data?',
70
+ default: false
71
+ }
72
+ ]);
73
+ return useExample;
108
74
  }
109
75
  async function gitInit() {
110
- const { gitInit: gitInit2 } = await inquirer__default.default.prompt([
111
- {
112
- type: "confirm",
113
- name: "gitInit",
114
- message: "Initialize a git repository?",
115
- default: true
116
- }
117
- ]);
118
- return gitInit2;
76
+ const { gitInit } = await inquirer.prompt([
77
+ {
78
+ type: 'confirm',
79
+ name: 'gitInit',
80
+ message: 'Initialize a git repository?',
81
+ default: true
82
+ }
83
+ ]);
84
+ return gitInit;
119
85
  }
120
86
  async function installDependencies(packageManager) {
121
- const { installDependencies: installDependencies2 } = await inquirer__default.default.prompt([
122
- {
123
- type: "confirm",
124
- name: "installDependencies",
125
- message: `Install dependencies with ${packageManager}?`,
126
- default: true
127
- }
128
- ]);
129
- return installDependencies2;
87
+ const { installDependencies } = await inquirer.prompt([
88
+ {
89
+ type: 'confirm',
90
+ name: 'installDependencies',
91
+ message: `Install dependencies with ${packageManager}?`,
92
+ default: true
93
+ }
94
+ ]);
95
+ return installDependencies;
130
96
  }
97
+
98
+ // TODO: move styles to API
131
99
  const supportedStyles = {
132
- magentaBright: chalk__default.default.magentaBright,
133
- blueBright: chalk__default.default.blueBright,
134
- yellowBright: chalk__default.default.yellowBright,
135
- green: chalk__default.default.green,
136
- red: chalk__default.default.red,
137
- bold: chalk__default.default.bold,
138
- italic: chalk__default.default.italic
100
+ magentaBright: chalk.magentaBright,
101
+ blueBright: chalk.blueBright,
102
+ yellowBright: chalk.yellowBright,
103
+ green: chalk.green,
104
+ red: chalk.red,
105
+ bold: chalk.bold,
106
+ italic: chalk.italic
139
107
  };
140
108
  function parseToChalk(template) {
141
- let result = template;
142
- for (const [color, chalkFunction] of Object.entries(supportedStyles)) {
143
- const regex = new RegExp(`{${color}}(.*?){/${color}}`, "g");
144
- result = result.replace(regex, (_2, p1) => chalkFunction(p1.trim()));
145
- }
146
- return result;
109
+ let result = template;
110
+ for (const [color, chalkFunction] of Object.entries(supportedStyles)){
111
+ const regex = new RegExp(`{${color}}(.*?){/${color}}`, 'g');
112
+ result = result.replace(regex, (_, p1)=>chalkFunction(p1.trim()));
113
+ }
114
+ return result;
147
115
  }
116
+
148
117
  function assertCloudError(e) {
149
- if (e.response === void 0) {
150
- throw Error("Expected CloudError");
151
- }
118
+ if (e.response === undefined) {
119
+ throw Error('Expected CloudError');
120
+ }
152
121
  }
153
122
  async function handleCloudLogin() {
154
- const logger2 = cloudCli.services.createLogger({
155
- silent: false,
156
- debug: process.argv.includes("--debug"),
157
- timestamp: false
158
- });
159
- const cloudApiService = await cloudCli.services.cloudApiFactory({ logger: logger2 });
160
- const defaultErrorMessage = "An error occurred while trying to interact with Strapi Cloud. Use strapi deploy command once the project is generated.";
161
- try {
162
- const { data: config } = await cloudApiService.config();
163
- logger2.log(parseToChalk(config.projectCreation.introText));
164
- } catch (e) {
165
- logger2.debug(e);
166
- logger2.error(defaultErrorMessage);
167
- return;
168
- }
169
- const { userChoice } = await inquirer__default.default.prompt([
170
- {
171
- type: "list",
172
- name: "userChoice",
173
- message: `Please log in or sign up.`,
174
- choices: ["Login/Sign up", "Skip"]
175
- }
176
- ]);
177
- if (userChoice !== "Skip") {
178
- const cliContext = {
179
- logger: logger2,
180
- cwd: process.cwd()
181
- };
123
+ const logger = cloudCli.services.createLogger({
124
+ silent: false,
125
+ debug: process.argv.includes('--debug'),
126
+ timestamp: false
127
+ });
128
+ const cloudApiService = await cloudCli.services.cloudApiFactory({
129
+ logger
130
+ });
131
+ const defaultErrorMessage = 'An error occurred while trying to interact with Strapi Cloud. Use strapi deploy command once the project is generated.';
182
132
  try {
183
- await cloudCli.cli.login.action(cliContext);
133
+ const { data: config } = await cloudApiService.config();
134
+ logger.log(parseToChalk(config.projectCreation.introText));
184
135
  } catch (e) {
185
- logger2.debug(e);
186
- try {
187
- assertCloudError(e);
188
- if (e.response.status === 403) {
189
- const message = typeof e.response.data === "string" ? e.response.data : "We are sorry, but we are not able to log you into Strapi Cloud at the moment.";
190
- logger2.warn(message);
191
- return;
136
+ logger.debug(e);
137
+ logger.error(defaultErrorMessage);
138
+ return;
139
+ }
140
+ const { userChoice } = await inquirer.prompt([
141
+ {
142
+ type: 'list',
143
+ name: 'userChoice',
144
+ message: `Please log in or sign up.`,
145
+ choices: [
146
+ 'Login/Sign up',
147
+ 'Skip'
148
+ ]
149
+ }
150
+ ]);
151
+ if (userChoice !== 'Skip') {
152
+ const cliContext = {
153
+ logger,
154
+ cwd: process.cwd()
155
+ };
156
+ try {
157
+ await cloudCli.cli.login.action(cliContext);
158
+ } catch (e) {
159
+ logger.debug(e);
160
+ try {
161
+ assertCloudError(e);
162
+ if (e.response.status === 403) {
163
+ const message = typeof e.response.data === 'string' ? e.response.data : 'We are sorry, but we are not able to log you into Strapi Cloud at the moment.';
164
+ logger.warn(message);
165
+ return;
166
+ }
167
+ } catch (e) {
168
+ /* empty */ }
169
+ logger.error(defaultErrorMessage);
192
170
  }
193
- } catch (e2) {
194
- }
195
- logger2.error(defaultErrorMessage);
196
171
  }
197
- }
198
172
  }
199
- const stripTrailingSlash = (str) => {
200
- return str.endsWith("/") ? str.slice(0, -1) : str;
173
+
174
+ const stripTrailingSlash = (str)=>{
175
+ return str.endsWith('/') ? str.slice(0, -1) : str;
201
176
  };
177
+ // Merge template with new project being created
202
178
  async function copyTemplate(scope, rootPath) {
203
- const { template } = scope;
204
- if (!template) {
205
- throw new Error("Missing template or example app option");
206
- }
207
- if (await isOfficialTemplate(template, scope.templateBranch)) {
208
- await retry__default.default(
209
- () => downloadGithubRepo(rootPath, {
210
- owner: "strapi",
211
- repo: "strapi",
212
- branch: scope.templateBranch,
213
- subPath: `templates/${template}`
214
- }),
215
- {
216
- retries: 3,
217
- onRetry(err, attempt) {
218
- console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
219
- }
220
- }
221
- );
222
- return;
223
- }
224
- if (isLocalTemplate(template)) {
225
- const filePath = template.startsWith("file://") ? url__default.default.fileURLToPath(template) : template;
226
- await fse__default.default.copy(filePath, rootPath);
227
- }
228
- if (isGithubShorthand(template)) {
229
- const [owner, repo, ...pathSegments] = template.split("/");
230
- const subPath = pathSegments.length ? pathSegments.join("/") : scope.templatePath;
231
- await retry__default.default(
232
- () => downloadGithubRepo(rootPath, { owner, repo, branch: scope.templateBranch, subPath }),
233
- {
234
- retries: 3,
235
- onRetry(err, attempt) {
236
- console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
237
- }
238
- }
239
- );
240
- return;
241
- }
242
- if (isGithubRepo(template)) {
243
- const url2 = new URL(template);
244
- const [owner, repo, t, branch, ...pathSegments] = stripTrailingSlash(
245
- url2.pathname.slice(1)
246
- ).split("/");
247
- if (t !== void 0 && t !== "tree") {
248
- throw new Error(`Invalid GitHub template URL: ${template}`);
249
- }
250
- if (scope.templateBranch) {
251
- await retry__default.default(
252
- () => downloadGithubRepo(rootPath, {
253
- owner,
254
- repo,
255
- branch: scope.templateBranch,
256
- subPath: scope.templatePath
257
- }),
258
- {
259
- retries: 3,
260
- onRetry(err, attempt) {
261
- console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
262
- }
179
+ const { template } = scope;
180
+ if (!template) {
181
+ throw new Error('Missing template or example app option');
182
+ }
183
+ if (await isOfficialTemplate(template, scope.templateBranch)) {
184
+ await retry(()=>downloadGithubRepo(rootPath, {
185
+ owner: 'strapi',
186
+ repo: 'strapi',
187
+ branch: scope.templateBranch,
188
+ subPath: `templates/${template}`
189
+ }), {
190
+ retries: 3,
191
+ onRetry (err, attempt) {
192
+ console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
193
+ }
194
+ });
195
+ return;
196
+ }
197
+ if (isLocalTemplate(template)) {
198
+ const filePath = template.startsWith('file://') ? url.fileURLToPath(template) : template;
199
+ await fse.copy(filePath, rootPath);
200
+ }
201
+ if (isGithubShorthand(template)) {
202
+ const [owner, repo, ...pathSegments] = template.split('/');
203
+ const subPath = pathSegments.length ? pathSegments.join('/') : scope.templatePath;
204
+ await retry(()=>downloadGithubRepo(rootPath, {
205
+ owner,
206
+ repo,
207
+ branch: scope.templateBranch,
208
+ subPath
209
+ }), {
210
+ retries: 3,
211
+ onRetry (err, attempt) {
212
+ console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
213
+ }
214
+ });
215
+ return;
216
+ }
217
+ if (isGithubRepo(template)) {
218
+ const url = new URL(template);
219
+ const [owner, repo, t, branch, ...pathSegments] = stripTrailingSlash(url.pathname.slice(1)).split('/');
220
+ if (t !== undefined && t !== 'tree') {
221
+ throw new Error(`Invalid GitHub template URL: ${template}`);
263
222
  }
264
- );
265
- return;
266
- }
267
- await retry__default.default(
268
- () => downloadGithubRepo(rootPath, {
269
- owner,
270
- repo,
271
- branch: decodeURIComponent(branch) ?? scope.templateBranch,
272
- subPath: pathSegments.length ? decodeURIComponent(pathSegments.join("/")) : scope.templatePath
273
- }),
274
- {
275
- retries: 3,
276
- onRetry(err, attempt) {
277
- console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
223
+ if (scope.templateBranch) {
224
+ await retry(()=>downloadGithubRepo(rootPath, {
225
+ owner,
226
+ repo,
227
+ branch: scope.templateBranch,
228
+ subPath: scope.templatePath
229
+ }), {
230
+ retries: 3,
231
+ onRetry (err, attempt) {
232
+ console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
233
+ }
234
+ });
235
+ return;
278
236
  }
279
- }
280
- );
281
- throw new Error(`Invalid GitHub template URL: ${template}`);
282
- }
237
+ await retry(()=>downloadGithubRepo(rootPath, {
238
+ owner,
239
+ repo,
240
+ branch: decodeURIComponent(branch) ?? scope.templateBranch,
241
+ subPath: pathSegments.length ? decodeURIComponent(pathSegments.join('/')) : scope.templatePath
242
+ }), {
243
+ retries: 3,
244
+ onRetry (err, attempt) {
245
+ console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`);
246
+ }
247
+ });
248
+ throw new Error(`Invalid GitHub template URL: ${template}`);
249
+ }
283
250
  }
284
251
  async function downloadGithubRepo(rootPath, { owner, repo, branch, subPath }) {
285
- const filePath = subPath ? subPath.split("/").join(path__default.default.posix.sep) : null;
286
- let checkContentUrl = `https://api.github.com/repos/${owner}/${repo}/contents`;
287
- if (filePath) {
288
- checkContentUrl = `${checkContentUrl}/${filePath}`;
289
- }
290
- if (branch) {
291
- checkContentUrl = `${checkContentUrl}?ref=${branch}`;
292
- }
293
- const checkRes = await fetch(checkContentUrl, {
294
- method: "HEAD"
295
- });
296
- if (checkRes.status !== 200) {
297
- throw new Error(
298
- `Could not find a template at https://github.com/${owner}/${repo}${branch ? ` on branch ${branch}` : ""}${filePath ? ` at path ${filePath}` : ""}`
299
- );
300
- }
301
- let url2 = `https://api.github.com/repos/${owner}/${repo}/tarball`;
302
- if (branch) {
303
- url2 = `${url2}/${branch}`;
304
- }
305
- const res = await fetch(url2);
306
- if (!res.body) {
307
- throw new Error(`Failed to download ${url2}`);
308
- }
309
- await promises.pipeline(
310
- // @ts-expect-error - Readable is not a valid source
311
- node_stream.Readable.fromWeb(res.body),
312
- tar__namespace.x({
313
- cwd: rootPath,
314
- strip: filePath ? filePath.split("/").length + 1 : 1,
315
- filter(path2) {
316
- if (filePath) {
317
- return path2.split("/").slice(1).join("/").startsWith(filePath);
252
+ const filePath = subPath ? subPath.split('/').join(path.posix.sep) : null;
253
+ let checkContentUrl = `https://api.github.com/repos/${owner}/${repo}/contents`;
254
+ if (filePath) {
255
+ checkContentUrl = `${checkContentUrl}/${filePath}`;
256
+ }
257
+ if (branch) {
258
+ checkContentUrl = `${checkContentUrl}?ref=${branch}`;
259
+ }
260
+ const checkRes = await fetch(checkContentUrl, {
261
+ method: 'HEAD'
262
+ });
263
+ if (checkRes.status !== 200) {
264
+ throw new Error(`Could not find a template at https://github.com/${owner}/${repo}${branch ? ` on branch ${branch}` : ''}${filePath ? ` at path ${filePath}` : ''}`);
265
+ }
266
+ let url = `https://api.github.com/repos/${owner}/${repo}/tarball`;
267
+ if (branch) {
268
+ url = `${url}/${branch}`;
269
+ }
270
+ const res = await fetch(url);
271
+ if (!res.body) {
272
+ throw new Error(`Failed to download ${url}`);
273
+ }
274
+ await promises.pipeline(// @ts-expect-error - Readable is not a valid source
275
+ node_stream.Readable.fromWeb(res.body), tar__namespace.x({
276
+ cwd: rootPath,
277
+ strip: filePath ? filePath.split('/').length + 1 : 1,
278
+ filter (path) {
279
+ if (filePath) {
280
+ return path.split('/').slice(1).join('/').startsWith(filePath);
281
+ }
282
+ return true;
318
283
  }
319
- return true;
320
- }
321
- })
322
- );
284
+ }));
323
285
  }
324
286
  function isLocalTemplate(template) {
325
- return template.startsWith("file://") || fse__default.default.existsSync(path__default.default.isAbsolute(template) ? template : path__default.default.resolve(process.cwd(), template));
287
+ return template.startsWith('file://') || fse.existsSync(path.isAbsolute(template) ? template : path.resolve(process.cwd(), template));
326
288
  }
327
289
  function isGithubShorthand(value) {
328
- if (isValidUrl(value)) {
329
- return false;
330
- }
331
- return /^[\w-]+\/[\w-.]+(\/[\w-.]+)*$/.test(value);
290
+ if (isValidUrl(value)) {
291
+ return false;
292
+ }
293
+ return /^[\w-]+\/[\w-.]+(\/[\w-.]+)*$/.test(value);
332
294
  }
333
295
  function isGithubRepo(value) {
334
- try {
335
- const url2 = new URL(value);
336
- return url2.origin === "https://github.com";
337
- } catch {
338
- return false;
339
- }
296
+ try {
297
+ const url = new URL(value);
298
+ return url.origin === 'https://github.com';
299
+ } catch {
300
+ return false;
301
+ }
340
302
  }
341
303
  function isValidUrl(value) {
342
- try {
343
- new URL(value);
344
- return true;
345
- } catch {
346
- return false;
347
- }
304
+ try {
305
+ // eslint-disable-next-line no-new
306
+ new URL(value);
307
+ return true;
308
+ } catch {
309
+ return false;
310
+ }
348
311
  }
312
+ const OFFICIAL_NAME_REGEX = /^[a-zA-Z]*$/;
349
313
  async function isOfficialTemplate(template, branch) {
350
- if (isValidUrl(template)) {
351
- return false;
352
- }
353
- const res = await fetch(
354
- `https://api.github.com/repos/strapi/strapi/contents/templates/${template}?${branch ? `ref=${branch}` : ""}`,
355
- { method: "HEAD" }
356
- );
357
- return res.status === 200;
314
+ if (isValidUrl(template) || !OFFICIAL_NAME_REGEX.test(template)) {
315
+ return false;
316
+ }
317
+ const res = await fetch(`https://api.github.com/repos/strapi/strapi/contents/templates/${template}?${branch ? `ref=${branch}` : ''}`, {
318
+ method: 'HEAD'
319
+ });
320
+ return res.status === 200;
358
321
  }
322
+
359
323
  async function isInGitRepository(rootDir) {
360
- try {
361
- await execa__default.default("git", ["rev-parse", "--is-inside-work-tree"], { stdio: "ignore", cwd: rootDir });
362
- return true;
363
- } catch (_2) {
364
- return false;
365
- }
324
+ try {
325
+ await execa('git', [
326
+ 'rev-parse',
327
+ '--is-inside-work-tree'
328
+ ], {
329
+ stdio: 'ignore',
330
+ cwd: rootDir
331
+ });
332
+ return true;
333
+ } catch (_) {
334
+ return false;
335
+ }
366
336
  }
367
337
  async function isInMercurialRepository(rootDir) {
368
- try {
369
- await execa__default.default("hg", ["-cwd", ".", "root"], { stdio: "ignore", cwd: rootDir });
370
- return true;
371
- } catch (_2) {
372
- return false;
373
- }
338
+ try {
339
+ await execa('hg', [
340
+ '-cwd',
341
+ '.',
342
+ 'root'
343
+ ], {
344
+ stdio: 'ignore',
345
+ cwd: rootDir
346
+ });
347
+ return true;
348
+ } catch (_) {
349
+ return false;
350
+ }
374
351
  }
375
352
  async function tryGitInit(rootDir) {
376
- try {
377
- await execa__default.default("git", ["--version"], { stdio: "ignore" });
378
- if (await isInGitRepository(rootDir) || await isInMercurialRepository(rootDir)) {
379
- return false;
380
- }
381
- await execa__default.default("git", ["init"], { stdio: "ignore", cwd: rootDir });
382
- await execa__default.default("git", ["add", "."], { stdio: "ignore", cwd: rootDir });
383
- await execa__default.default("git", ["commit", "-m", "Initial commit from Strapi"], {
384
- stdio: "ignore",
385
- cwd: rootDir
386
- });
387
- return true;
388
- } catch (e) {
389
- console.error("Error while trying to initialize git:", e);
390
- return false;
391
- }
353
+ try {
354
+ await execa('git', [
355
+ '--version'
356
+ ], {
357
+ stdio: 'ignore'
358
+ });
359
+ if (await isInGitRepository(rootDir) || await isInMercurialRepository(rootDir)) {
360
+ return false;
361
+ }
362
+ await execa('git', [
363
+ 'init'
364
+ ], {
365
+ stdio: 'ignore',
366
+ cwd: rootDir
367
+ });
368
+ await execa('git', [
369
+ 'add',
370
+ '.'
371
+ ], {
372
+ stdio: 'ignore',
373
+ cwd: rootDir
374
+ });
375
+ await execa('git', [
376
+ 'commit',
377
+ '-m',
378
+ 'Initial commit from Strapi'
379
+ ], {
380
+ stdio: 'ignore',
381
+ cwd: rootDir
382
+ });
383
+ return true;
384
+ } catch (e) {
385
+ console.error('Error while trying to initialize git:', e);
386
+ return false;
387
+ }
392
388
  }
389
+
390
+ // Add properties from the package.json strapi key in the metadata
393
391
  function addPackageJsonStrapiMetadata(metadata, scope) {
394
- const { packageJsonStrapi = {} } = scope;
395
- return ___default.default.defaults(metadata, packageJsonStrapi);
392
+ const { packageJsonStrapi = {} } = scope;
393
+ return _.defaults(metadata, packageJsonStrapi);
396
394
  }
397
- const boolToString = (value) => (value === true).toString();
398
- const getProperties = (scope, error) => {
399
- const eventProperties = {
400
- error: typeof error === "string" ? error : error && error.message
401
- };
402
- const userProperties = {
403
- os: os__default.default.type(),
404
- osPlatform: os__default.default.platform(),
405
- osArch: os__default.default.arch(),
406
- osRelease: os__default.default.release(),
407
- nodeVersion: process.versions.node
408
- };
409
- const groupProperties = {
410
- version: scope.strapiVersion,
411
- docker: scope.docker,
412
- useYarn: scope.packageManager === "yarn",
413
- packageManager: scope.packageManager,
414
- /** @deprecated */
415
- useTypescriptOnServer: boolToString(scope.useTypescript),
416
- /** @deprecated */
417
- useTypescriptOnAdmin: boolToString(scope.useTypescript),
418
- useTypescript: boolToString(scope.useTypescript),
419
- isHostedOnStrapiCloud: process.env.STRAPI_HOSTING === "strapi.cloud",
420
- noRun: boolToString(scope.runApp),
421
- projectId: scope.uuid,
422
- useExample: boolToString(scope.useExample),
423
- gitInit: boolToString(scope.gitInit),
424
- installDependencies: boolToString(scope.installDependencies)
425
- };
426
- return {
427
- eventProperties,
428
- userProperties,
429
- groupProperties: addPackageJsonStrapiMetadata(groupProperties, scope)
430
- };
395
+ const boolToString = (value)=>(value === true).toString();
396
+ const getProperties = (scope, error)=>{
397
+ const eventProperties = {
398
+ error: typeof error === 'string' ? error : error && error.message
399
+ };
400
+ const userProperties = {
401
+ os: os.type(),
402
+ osPlatform: os.platform(),
403
+ osArch: os.arch(),
404
+ osRelease: os.release(),
405
+ nodeVersion: process.versions.node
406
+ };
407
+ const groupProperties = {
408
+ version: scope.strapiVersion,
409
+ docker: scope.docker,
410
+ useYarn: scope.packageManager === 'yarn',
411
+ packageManager: scope.packageManager,
412
+ /** @deprecated */ useTypescriptOnServer: boolToString(scope.useTypescript),
413
+ /** @deprecated */ useTypescriptOnAdmin: boolToString(scope.useTypescript),
414
+ useTypescript: boolToString(scope.useTypescript),
415
+ isHostedOnStrapiCloud: process.env.STRAPI_HOSTING === 'strapi.cloud',
416
+ noRun: boolToString(scope.runApp),
417
+ projectId: scope.uuid,
418
+ useExample: boolToString(scope.useExample),
419
+ gitInit: boolToString(scope.gitInit),
420
+ installDependencies: boolToString(scope.installDependencies)
421
+ };
422
+ return {
423
+ eventProperties,
424
+ userProperties,
425
+ groupProperties: addPackageJsonStrapiMetadata(groupProperties, scope)
426
+ };
431
427
  };
432
428
  function trackEvent(event, payload) {
433
- if (process.env.NODE_ENV === "test") {
434
- return;
435
- }
436
- try {
437
- return fetch("https://analytics.strapi.io/api/v2/track", {
438
- method: "POST",
439
- body: JSON.stringify({
440
- event,
441
- ...payload
442
- }),
443
- signal: AbortSignal.timeout(1e3),
444
- headers: {
445
- "Content-Type": "application/json",
446
- "X-Strapi-Event": event
447
- }
448
- }).catch(() => {
449
- });
450
- } catch (err) {
451
- return Promise.resolve();
452
- }
429
+ if (process.env.NODE_ENV === 'test') {
430
+ return;
431
+ }
432
+ try {
433
+ return fetch('https://analytics.strapi.io/api/v2/track', {
434
+ method: 'POST',
435
+ body: JSON.stringify({
436
+ event,
437
+ ...payload
438
+ }),
439
+ signal: AbortSignal.timeout(1000),
440
+ headers: {
441
+ 'Content-Type': 'application/json',
442
+ 'X-Strapi-Event': event
443
+ }
444
+ }).catch(()=>{});
445
+ } catch (err) {
446
+ /** ignore errors */ return Promise.resolve();
447
+ }
453
448
  }
454
449
  async function trackError({ scope, error }) {
455
- const properties = getProperties(scope, error);
456
- try {
457
- return await trackEvent("didNotCreateProject", {
458
- deviceId: scope.deviceId,
459
- ...properties
460
- });
461
- } catch (err) {
462
- return Promise.resolve();
463
- }
450
+ const properties = getProperties(scope, error);
451
+ try {
452
+ return await trackEvent('didNotCreateProject', {
453
+ deviceId: scope.deviceId,
454
+ ...properties
455
+ });
456
+ } catch (err) {
457
+ /** ignore errors */ return Promise.resolve();
458
+ }
464
459
  }
465
- async function trackUsage({
466
- event,
467
- scope,
468
- error
469
- }) {
470
- const properties = getProperties(scope, error);
471
- try {
472
- return await trackEvent(event, {
473
- deviceId: scope.deviceId,
474
- ...properties
475
- });
476
- } catch (err) {
477
- return Promise.resolve();
478
- }
460
+ async function trackUsage({ event, scope, error }) {
461
+ const properties = getProperties(scope, error);
462
+ try {
463
+ return await trackEvent(event, {
464
+ deviceId: scope.deviceId,
465
+ ...properties
466
+ });
467
+ } catch (err) {
468
+ /** ignore errors */ return Promise.resolve();
469
+ }
479
470
  }
471
+
480
472
  const engines = {
481
- node: ">=18.0.0 <=22.x.x",
482
- npm: ">=6.0.0"
473
+ node: '>=18.0.0 <=22.x.x',
474
+ npm: '>=6.0.0'
483
475
  };
476
+
484
477
  async function createPackageJSON(scope) {
485
- const { sortPackageJson } = await import("sort-package-json");
486
- const pkgJSONPath = path$1.join(scope.rootPath, "package.json");
487
- const existingPkg = await fse__default.default.readJSON(pkgJSONPath).catch(() => ({}));
488
- const pkg = {
489
- name: _.kebabCase(scope.name),
490
- private: true,
491
- version: "0.1.0",
492
- description: "A Strapi application",
493
- devDependencies: scope.devDependencies ?? {},
494
- dependencies: scope.dependencies ?? {},
495
- strapi: {
496
- ...scope.packageJsonStrapi ?? {},
497
- uuid: scope.uuid
498
- },
499
- engines
500
- };
501
- await fse__default.default.writeJSON(pkgJSONPath, sortPackageJson(_.merge(existingPkg, pkg)), {
502
- spaces: 2
503
- });
478
+ const { sortPackageJson } = await import('sort-package-json');
479
+ const pkgJSONPath = path$1.join(scope.rootPath, 'package.json');
480
+ const existingPkg = await fse.readJSON(pkgJSONPath).catch(()=>({}));
481
+ const pkg = {
482
+ name: _.kebabCase(scope.name),
483
+ private: true,
484
+ version: '0.1.0',
485
+ description: 'A Strapi application',
486
+ devDependencies: scope.devDependencies ?? {},
487
+ dependencies: scope.dependencies ?? {},
488
+ strapi: {
489
+ ...scope.packageJsonStrapi ?? {},
490
+ uuid: scope.uuid
491
+ },
492
+ engines
493
+ };
494
+ // copy templates
495
+ await fse.writeJSON(pkgJSONPath, sortPackageJson(_.merge(existingPkg, pkg)), {
496
+ spaces: 2
497
+ });
504
498
  }
505
- const generateASecret = () => crypto__default.default.randomBytes(16).toString("base64");
499
+
500
+ const generateASecret = ()=>crypto.randomBytes(16).toString('base64');
506
501
  const envTmpl = `
507
502
  # Server
508
503
  HOST=0.0.0.0
@@ -525,77 +520,74 @@ DATABASE_SSL=<%= database.connection.ssl %>
525
520
  DATABASE_FILENAME=<%= database.connection.filename %>
526
521
  `;
527
522
  function generateDotEnv(scope) {
528
- const compile = ___default.default.template(envTmpl);
529
- return compile({
530
- appKeys: new Array(4).fill(null).map(generateASecret).join(","),
531
- apiTokenSalt: generateASecret(),
532
- transferTokenSalt: generateASecret(),
533
- adminJwtToken: generateASecret(),
534
- database: {
535
- client: scope.database.client,
536
- connection: {
537
- ...scope.database.connection,
538
- ssl: scope.database.connection?.ssl || false
539
- }
540
- }
541
- });
523
+ const compile = _.template(envTmpl);
524
+ return compile({
525
+ appKeys: new Array(4).fill(null).map(generateASecret).join(','),
526
+ apiTokenSalt: generateASecret(),
527
+ transferTokenSalt: generateASecret(),
528
+ adminJwtToken: generateASecret(),
529
+ database: {
530
+ client: scope.database.client,
531
+ connection: {
532
+ ...scope.database.connection,
533
+ ssl: scope.database.connection?.ssl || false
534
+ }
535
+ }
536
+ });
542
537
  }
538
+
543
539
  function isStderrError(error) {
544
- return typeof error === "object" && error !== null && "stderr" in error && typeof error.stderr === "string";
540
+ return typeof error === 'object' && error !== null && 'stderr' in error && typeof error.stderr === 'string';
545
541
  }
542
+
546
543
  const MAX_PREFIX_LENGTH = 8;
547
- const badge = (text, bgColor, textColor = chalk__default.default.black) => {
548
- const wrappedText = ` ${text} `;
549
- const repeat = Math.max(0, MAX_PREFIX_LENGTH - wrappedText.length);
550
- return " ".repeat(repeat) + bgColor(textColor(wrappedText));
544
+ const badge = (text, bgColor, textColor = chalk.black)=>{
545
+ const wrappedText = ` ${text} `;
546
+ const repeat = Math.max(0, MAX_PREFIX_LENGTH - wrappedText.length);
547
+ return ' '.repeat(repeat) + bgColor(textColor(wrappedText));
551
548
  };
552
- const textIndent = (text, indentFirst = true, indent = MAX_PREFIX_LENGTH + 2) => {
553
- const parts = Array.isArray(text) ? text : [text];
554
- return parts.map((part, i) => {
555
- if (i === 0 && !indentFirst) {
556
- return part;
557
- }
558
- return " ".repeat(indent) + part;
559
- }).join("\n");
549
+ const textIndent = (text, indentFirst = true, indent = MAX_PREFIX_LENGTH + 2)=>{
550
+ const parts = Array.isArray(text) ? text : [
551
+ text
552
+ ];
553
+ return parts.map((part, i)=>{
554
+ if (i === 0 && !indentFirst) {
555
+ return part;
556
+ }
557
+ return ' '.repeat(indent) + part;
558
+ }).join('\n');
560
559
  };
561
560
  const logger = {
562
- log(message) {
563
- console.log(textIndent(message));
564
- },
565
- title(title, message) {
566
- const prefix = badge(title, chalk__default.default.bgBlueBright);
567
- console.log(`
568
- ${prefix} ${message}`);
569
- },
570
- info(message) {
571
- console.log(`${" ".repeat(7)}${chalk__default.default.cyan("●")} ${message}`);
572
- },
573
- success(message) {
574
- console.log(`
575
- ${" ".repeat(7)}${chalk__default.default.green("✓")} ${chalk__default.default.green(message)}`);
576
- },
577
- fatal(message) {
578
- const prefix = badge("Error", chalk__default.default.bgRed);
579
- if (message) {
580
- console.error(`
581
- ${prefix} ${textIndent(message, false)}
582
- `);
583
- }
584
- process.exit(1);
585
- },
586
- error(message) {
587
- const prefix = badge("Error", chalk__default.default.bgRed);
588
- console.error(`
589
- ${prefix} ${textIndent(message, false)}
590
- `);
591
- },
592
- warn(message) {
593
- const prefix = badge("Warn", chalk__default.default.bgYellow);
594
- console.warn(`
595
- ${prefix} ${textIndent(message, false)}
596
- `);
597
- }
561
+ log (message) {
562
+ console.log(textIndent(message));
563
+ },
564
+ title (title, message) {
565
+ const prefix = badge(title, chalk.bgBlueBright);
566
+ console.log(`\n${prefix} ${message}`);
567
+ },
568
+ info (message) {
569
+ console.log(`${' '.repeat(7)}${chalk.cyan('●')} ${message}`);
570
+ },
571
+ success (message) {
572
+ console.log(`\n${' '.repeat(7)}${chalk.green('✓')} ${chalk.green(message)}`);
573
+ },
574
+ fatal (message) {
575
+ const prefix = badge('Error', chalk.bgRed);
576
+ if (message) {
577
+ console.error(`\n${prefix} ${textIndent(message, false)}\n`);
578
+ }
579
+ process.exit(1);
580
+ },
581
+ error (message) {
582
+ const prefix = badge('Error', chalk.bgRed);
583
+ console.error(`\n${prefix} ${textIndent(message, false)}\n`);
584
+ },
585
+ warn (message) {
586
+ const prefix = badge('Warn', chalk.bgYellow);
587
+ console.warn(`\n${prefix} ${textIndent(message, false)}\n`);
588
+ }
598
589
  };
590
+
599
591
  const baseGitIgnore = `
600
592
  ############################
601
593
  # OS X
@@ -730,591 +722,743 @@ build
730
722
  .strapi-cloud.json
731
723
  `;
732
724
  const gitIgnore = baseGitIgnore.trim();
733
- const installArguments = ["install"];
725
+
726
+ const installArguments = [
727
+ 'install'
728
+ ];
729
+ // Set command line options for specific package managers, with full semver ranges
734
730
  const installArgumentsMap = {
735
- npm: {
736
- "*": ["--legacy-peer-deps"]
737
- },
738
- yarn: {
739
- "<4": ["--network-timeout", "1000000"],
740
- "*": []
741
- },
742
- pnpm: {
743
- "*": []
744
- }
731
+ npm: {
732
+ '*': [
733
+ '--legacy-peer-deps'
734
+ ]
735
+ },
736
+ yarn: {
737
+ '<4': [
738
+ '--network-timeout',
739
+ '1000000'
740
+ ],
741
+ '*': []
742
+ },
743
+ pnpm: {
744
+ '*': []
745
+ }
745
746
  };
747
+ // Set environment variables for specific package managers, with full semver ranges
746
748
  const installEnvMap = {
747
- yarn: {
748
- ">=4": { YARN_HTTP_TIMEOUT: "1000000" },
749
- "*": {}
750
- },
751
- npm: {
752
- "*": {}
753
- },
754
- pnpm: {
755
- "*": {}
756
- }
757
- };
758
- const getPackageManagerVersion = async (packageManager, options) => {
759
- try {
760
- const { stdout } = await execa__default.default(packageManager, ["--version"], options);
761
- return stdout.trim();
762
- } catch (err) {
763
- throw new Error(`Error detecting ${packageManager} version: ${err}`);
764
- }
749
+ yarn: {
750
+ '>=4': {
751
+ YARN_HTTP_TIMEOUT: '1000000'
752
+ },
753
+ '*': {}
754
+ },
755
+ npm: {
756
+ '*': {}
757
+ },
758
+ pnpm: {
759
+ '*': {}
760
+ }
765
761
  };
766
- function mergeMatchingVersionRanges(version2, versionMap, mergeFn) {
767
- return Object.keys(versionMap).reduce((acc, range) => {
768
- if (semver__default.default.satisfies(version2, range) || range === "*") {
769
- return mergeFn(acc, versionMap[range]);
762
+ /**
763
+ * Retrieves the version of the specified package manager.
764
+ *
765
+ * Executes the package manager's `--version` command to determine its version.
766
+ *
767
+ * @param packageManager - The name of the package manager (e.g., 'npm', 'yarn', 'pnpm').
768
+ * @param options - Optional execution options to pass to `execa`.
769
+ * @returns A promise that resolves to the trimmed version string of the package manager.
770
+ *
771
+ * @throws Will throw an error if the package manager's version cannot be determined.
772
+ */ const getPackageManagerVersion = async (packageManager, options)=>{
773
+ try {
774
+ const { stdout } = await execa(packageManager, [
775
+ '--version'
776
+ ], options);
777
+ return stdout.trim();
778
+ } catch (err) {
779
+ throw new Error(`Error detecting ${packageManager} version: ${err}`);
770
780
  }
771
- return acc;
772
- }, versionMap["*"]);
781
+ };
782
+ /**
783
+ * Merges all matching semver ranges using a custom merge function.
784
+ *
785
+ * Iterates over the `versionMap`, checking if the provided `version` satisfies each semver range.
786
+ * If it does, the corresponding value is merged using the provided `mergeFn`.
787
+ * The merging starts with the value associated with the wildcard '*' key.
788
+ *
789
+ * @param version - The package manager version to check against the ranges.
790
+ * @param versionMap - A map of semver ranges to corresponding values (arguments or environment variables).
791
+ * @param mergeFn - A function that defines how to merge two values (accumulated and current).
792
+ * @returns The merged result of all matching ranges.
793
+ */ function mergeMatchingVersionRanges(version, versionMap, mergeFn) {
794
+ return Object.keys(versionMap).reduce((acc, range)=>{
795
+ if (semver.satisfies(version, range) || range === '*') {
796
+ return mergeFn(acc, versionMap[range]);
797
+ }
798
+ return acc;
799
+ }, versionMap['*']); // Start with the wildcard entry
773
800
  }
774
801
  function mergeArguments(acc, curr) {
775
- return [...acc, ...curr];
802
+ return [
803
+ ...acc,
804
+ ...curr
805
+ ];
776
806
  }
777
807
  function mergeEnvVars(acc, curr) {
778
- return { ...acc, ...curr };
808
+ return {
809
+ ...acc,
810
+ ...curr
811
+ };
779
812
  }
780
- const getInstallArgs = async (packageManager, options) => {
781
- const packageManagerVersion = await getPackageManagerVersion(packageManager, options);
782
- const envMap = installEnvMap[packageManager];
783
- const envArgs = packageManagerVersion ? mergeMatchingVersionRanges(packageManagerVersion, envMap, mergeEnvVars) : envMap["*"];
784
- const argsMap = installArgumentsMap[packageManager];
785
- const cmdArgs = packageManagerVersion ? mergeMatchingVersionRanges(packageManagerVersion, argsMap, mergeArguments) : argsMap["*"];
786
- return { envArgs, cmdArgs: [...installArguments, ...cmdArgs], version: packageManagerVersion };
813
+ /**
814
+ * Retrieves the install arguments and environment variables for a given package manager.
815
+ *
816
+ * This function determines the correct command line arguments and environment variables
817
+ * based on the package manager's version. It uses predefined semver ranges to match
818
+ * the package manager's version and merges all applicable settings.
819
+ *
820
+ * The arguments and environment variables are sourced from:
821
+ * - `installArgumentsMap` for command line arguments.
822
+ * - `installEnvMap` for environment variables.
823
+ *
824
+ * The function ensures that all matching semver ranges are considered and merged appropriately.
825
+ * It always includes the base `installArguments` (e.g., `['install']`) and applies any additional
826
+ * arguments or environment variables as defined by the matched version ranges.
827
+ *
828
+ * @param packageManager - The name of the package manager (e.g., 'npm', 'yarn', 'pnpm').
829
+ * @param options - Optional execution options to pass to `execa`.
830
+ * @returns An object containing:
831
+ * - `cmdArgs`: The full array of install arguments for the given package manager and version.
832
+ * - `envArgs`: The merged environment variables applicable to the package manager and version.
833
+ *
834
+ * @throws Will throw an error if the package manager version cannot be determined.
835
+ */ const getInstallArgs = async (packageManager, options)=>{
836
+ const packageManagerVersion = await getPackageManagerVersion(packageManager, options);
837
+ // Get environment variables
838
+ const envMap = installEnvMap[packageManager];
839
+ const envArgs = packageManagerVersion ? mergeMatchingVersionRanges(packageManagerVersion, envMap, mergeEnvVars) : envMap['*'];
840
+ // Get install arguments
841
+ const argsMap = installArgumentsMap[packageManager];
842
+ const cmdArgs = packageManagerVersion ? mergeMatchingVersionRanges(packageManagerVersion, argsMap, mergeArguments) : argsMap['*'];
843
+ return {
844
+ envArgs,
845
+ cmdArgs: [
846
+ ...installArguments,
847
+ ...cmdArgs
848
+ ],
849
+ version: packageManagerVersion
850
+ };
787
851
  };
852
+
788
853
  async function createStrapi(scope) {
789
- const { rootPath } = scope;
790
- try {
791
- await fse__default.default.ensureDir(rootPath);
792
- await createApp(scope);
793
- } catch (error) {
794
- await fse__default.default.remove(rootPath);
795
- throw error;
796
- }
854
+ const { rootPath } = scope;
855
+ try {
856
+ await fse.ensureDir(rootPath);
857
+ await createApp(scope);
858
+ } catch (error) {
859
+ await fse.remove(rootPath);
860
+ throw error;
861
+ }
797
862
  }
798
863
  async function createApp(scope) {
799
- const {
800
- rootPath,
801
- useTypescript,
802
- useExample,
803
- installDependencies: installDependencies2,
804
- isQuickstart,
805
- template,
806
- packageManager,
807
- gitInit: gitInit2,
808
- runApp
809
- } = scope;
810
- const shouldRunSeed = useExample && installDependencies2;
811
- await trackUsage({ event: "willCreateProject", scope });
812
- logger.title("Strapi", `Creating a new application at ${chalk__default.default.green(rootPath)}`);
813
- if (!isQuickstart) {
814
- await trackUsage({ event: "didChooseCustomDatabase", scope });
815
- } else {
816
- await trackUsage({ event: "didChooseQuickstart", scope });
817
- }
818
- if (!template) {
819
- let templateName = useExample ? "example" : "vanilla";
820
- if (!useTypescript) {
821
- templateName = `${templateName}-js`;
864
+ const { rootPath, useTypescript, useExample, installDependencies, isQuickstart, template, packageManager, gitInit, runApp } = scope;
865
+ const shouldRunSeed = useExample && installDependencies;
866
+ await trackUsage({
867
+ event: 'willCreateProject',
868
+ scope
869
+ });
870
+ logger.title('Strapi', `Creating a new application at ${chalk.green(rootPath)}`);
871
+ if (!isQuickstart) {
872
+ await trackUsage({
873
+ event: 'didChooseCustomDatabase',
874
+ scope
875
+ });
876
+ } else {
877
+ await trackUsage({
878
+ event: 'didChooseQuickstart',
879
+ scope
880
+ });
822
881
  }
823
- const internalTemplatePath = path.join(__dirname, "../templates", templateName);
824
- if (await fse__default.default.exists(internalTemplatePath)) {
825
- await fse__default.default.copy(internalTemplatePath, rootPath);
882
+ if (!template) {
883
+ let templateName = useExample ? 'example' : 'vanilla';
884
+ if (!useTypescript) {
885
+ templateName = `${templateName}-js`;
886
+ }
887
+ const internalTemplatePath = path.join(__dirname, '../templates', templateName);
888
+ if (await fse.exists(internalTemplatePath)) {
889
+ await fse.copy(internalTemplatePath, rootPath);
890
+ }
891
+ } else {
892
+ try {
893
+ logger.info(`${chalk.cyan('Installing template')} ${template}`);
894
+ await copyTemplate(scope, rootPath);
895
+ logger.success('Template copied successfully.');
896
+ } catch (error) {
897
+ if (error instanceof Error) {
898
+ logger.fatal(`Template installation failed: ${error.message}`);
899
+ }
900
+ throw error;
901
+ }
902
+ if (!fse.existsSync(path.join(rootPath, 'package.json'))) {
903
+ logger.fatal(`Missing ${chalk.bold('package.json')} in template`);
904
+ }
826
905
  }
827
- } else {
906
+ await trackUsage({
907
+ event: 'didCopyProjectFiles',
908
+ scope
909
+ });
828
910
  try {
829
- logger.info(`${chalk__default.default.cyan("Installing template")} ${template}`);
830
- await copyTemplate(scope, rootPath);
831
- logger.success("Template copied successfully.");
832
- } catch (error) {
833
- if (error instanceof Error) {
834
- logger.fatal(`Template installation failed: ${error.message}`);
835
- }
836
- throw error;
911
+ await createPackageJSON(scope);
912
+ await trackUsage({
913
+ event: 'didWritePackageJSON',
914
+ scope
915
+ });
916
+ // ensure node_modules is created
917
+ await fse.ensureDir(path.join(rootPath, 'node_modules'));
918
+ // create config/database
919
+ await fse.writeFile(path.join(rootPath, '.env'), generateDotEnv(scope));
920
+ await trackUsage({
921
+ event: 'didCopyConfigurationFiles',
922
+ scope
923
+ });
924
+ } catch (err) {
925
+ await fse.remove(rootPath);
926
+ throw err;
837
927
  }
838
- if (!fse__default.default.existsSync(path.join(rootPath, "package.json"))) {
839
- logger.fatal(`Missing ${chalk__default.default.bold("package.json")} in template`);
928
+ if (installDependencies) {
929
+ try {
930
+ logger.title('deps', `Installing dependencies with ${chalk.cyan(packageManager)}`);
931
+ await trackUsage({
932
+ event: 'willInstallProjectDependencies',
933
+ scope
934
+ });
935
+ await runInstall(scope);
936
+ await trackUsage({
937
+ event: 'didInstallProjectDependencies',
938
+ scope
939
+ });
940
+ logger.success(`Dependencies installed`);
941
+ } catch (error) {
942
+ const stderr = isStderrError(error) ? error.stderr : '';
943
+ await trackUsage({
944
+ event: 'didNotInstallProjectDependencies',
945
+ scope,
946
+ error: stderr.slice(-1024)
947
+ });
948
+ logger.fatal([
949
+ chalk.bold('Oh, it seems that you encountered an error while installing dependencies in your project'),
950
+ '',
951
+ `Don't give up, your project was created correctly`,
952
+ '',
953
+ `Fix the issues mentioned in the installation errors and try to run the following command:`,
954
+ '',
955
+ `cd ${chalk.green(rootPath)} && ${chalk.cyan(packageManager)} install`
956
+ ]);
957
+ }
840
958
  }
841
- }
842
- await trackUsage({ event: "didCopyProjectFiles", scope });
843
- try {
844
- await createPackageJSON(scope);
845
- await trackUsage({ event: "didWritePackageJSON", scope });
846
- await fse__default.default.ensureDir(path.join(rootPath, "node_modules"));
847
- await fse__default.default.writeFile(path.join(rootPath, ".env"), generateDotEnv(scope));
848
- await trackUsage({ event: "didCopyConfigurationFiles", scope });
849
- } catch (err) {
850
- await fse__default.default.remove(rootPath);
851
- throw err;
852
- }
853
- if (installDependencies2) {
854
- try {
855
- logger.title("deps", `Installing dependencies with ${chalk__default.default.cyan(packageManager)}`);
856
- await trackUsage({ event: "willInstallProjectDependencies", scope });
857
- await runInstall(scope);
858
- await trackUsage({ event: "didInstallProjectDependencies", scope });
859
- logger.success(`Dependencies installed`);
860
- } catch (error) {
861
- const stderr = isStderrError(error) ? error.stderr : "";
862
- await trackUsage({
863
- event: "didNotInstallProjectDependencies",
864
- scope,
865
- error: stderr.slice(-1024)
866
- });
867
- logger.fatal([
868
- chalk__default.default.bold(
869
- "Oh, it seems that you encountered an error while installing dependencies in your project"
870
- ),
871
- "",
872
- `Don't give up, your project was created correctly`,
873
- "",
874
- `Fix the issues mentioned in the installation errors and try to run the following command:`,
875
- "",
876
- `cd ${chalk__default.default.green(rootPath)} && ${chalk__default.default.cyan(packageManager)} install`
877
- ]);
959
+ await trackUsage({
960
+ event: 'didCreateProject',
961
+ scope
962
+ });
963
+ // make sure a gitignore file is created regardless of the user using git or not
964
+ if (!await fse.exists(path.join(rootPath, '.gitignore'))) {
965
+ await fse.writeFile(path.join(rootPath, '.gitignore'), gitIgnore);
878
966
  }
879
- }
880
- await trackUsage({ event: "didCreateProject", scope });
881
- if (!await fse__default.default.exists(path.join(rootPath, ".gitignore"))) {
882
- await fse__default.default.writeFile(path.join(rootPath, ".gitignore"), gitIgnore);
883
- }
884
- if (gitInit2) {
885
- logger.title("git", "Initializing git repository.");
886
- await tryGitInit(rootPath);
887
- logger.success("Initialized a git repository.");
888
- }
889
- if (shouldRunSeed) {
890
- if (await fse__default.default.exists(path.join(rootPath, "scripts/seed.js"))) {
891
- logger.title("Seed", "Seeding your database with sample data");
892
- try {
893
- await execa__default.default(packageManager, ["run", "seed:example"], {
894
- stdio: "inherit",
895
- cwd: rootPath
896
- });
897
- logger.success("Sample data added to your database");
898
- } catch (error) {
899
- logger.error("Failed to seed your database. Skipping");
900
- }
967
+ // Init git
968
+ if (gitInit) {
969
+ logger.title('git', 'Initializing git repository.');
970
+ await tryGitInit(rootPath);
971
+ logger.success('Initialized a git repository.');
901
972
  }
902
- }
903
- const cmd = chalk__default.default.cyan(`${packageManager} run`);
904
- logger.title("Strapi", `Your application was created!`);
905
- logger.log([
906
- "Available commands in your project:",
907
- "",
908
- "Start Strapi in watch mode. (Changes in Strapi project files will trigger a server restart)",
909
- `${cmd} develop`,
910
- "",
911
- "Start Strapi without watch mode.",
912
- `${cmd} start`,
913
- "",
914
- "Build Strapi admin panel.",
915
- `${cmd} build`,
916
- "",
917
- "Deploy Strapi project.",
918
- `${cmd} deploy`,
919
- ""
920
- ]);
921
- if (useExample) {
922
- logger.log(["Seed your database with sample data.", `${cmd} seed:example`, ""]);
923
- }
924
- logger.log(["Display all available commands.", `${cmd} strapi
925
- `]);
926
- if (installDependencies2) {
973
+ if (shouldRunSeed) {
974
+ if (await fse.exists(path.join(rootPath, 'scripts/seed.js'))) {
975
+ logger.title('Seed', 'Seeding your database with sample data');
976
+ try {
977
+ await execa(packageManager, [
978
+ 'run',
979
+ 'seed:example'
980
+ ], {
981
+ stdio: 'inherit',
982
+ cwd: rootPath
983
+ });
984
+ logger.success('Sample data added to your database');
985
+ } catch (error) {
986
+ logger.error('Failed to seed your database. Skipping');
987
+ }
988
+ }
989
+ }
990
+ const cmd = chalk.cyan(`${packageManager} run`);
991
+ logger.title('Strapi', `Your application was created!`);
927
992
  logger.log([
928
- "To get started run",
929
- "",
930
- `${chalk__default.default.cyan("cd")} ${rootPath}`,
931
- !shouldRunSeed && useExample ? `${cmd} seed:example && ${cmd} develop` : `${cmd} develop`
993
+ 'Available commands in your project:',
994
+ '',
995
+ 'Start Strapi in watch mode. (Changes in Strapi project files will trigger a server restart)',
996
+ `${cmd} develop`,
997
+ '',
998
+ 'Start Strapi without watch mode.',
999
+ `${cmd} start`,
1000
+ '',
1001
+ 'Build Strapi admin panel.',
1002
+ `${cmd} build`,
1003
+ '',
1004
+ 'Deploy Strapi project.',
1005
+ `${cmd} deploy`,
1006
+ ''
932
1007
  ]);
933
- } else {
1008
+ if (useExample) {
1009
+ logger.log([
1010
+ 'Seed your database with sample data.',
1011
+ `${cmd} seed:example`,
1012
+ ''
1013
+ ]);
1014
+ }
934
1015
  logger.log([
935
- "To get started run",
936
- "",
937
- `${chalk__default.default.cyan("cd")} ${rootPath}`,
938
- `${chalk__default.default.cyan(packageManager)} install`,
939
- !shouldRunSeed && useExample ? `${cmd} seed:example && ${cmd} develop` : `${cmd} develop`
1016
+ 'Display all available commands.',
1017
+ `${cmd} strapi\n`
940
1018
  ]);
941
- }
942
- if (runApp && installDependencies2) {
943
- logger.title("Run", "Running your Strapi application");
944
- try {
945
- await trackUsage({ event: "willStartServer", scope });
946
- await execa__default.default(packageManager, ["run", "develop"], {
947
- stdio: "inherit",
948
- cwd: rootPath,
949
- env: {
950
- FORCE_COLOR: "1"
1019
+ if (installDependencies) {
1020
+ logger.log([
1021
+ 'To get started run',
1022
+ '',
1023
+ `${chalk.cyan('cd')} ${rootPath}`,
1024
+ !shouldRunSeed && useExample ? `${cmd} seed:example && ${cmd} develop` : `${cmd} develop`
1025
+ ]);
1026
+ } else {
1027
+ logger.log([
1028
+ 'To get started run',
1029
+ '',
1030
+ `${chalk.cyan('cd')} ${rootPath}`,
1031
+ `${chalk.cyan(packageManager)} install`,
1032
+ !shouldRunSeed && useExample ? `${cmd} seed:example && ${cmd} develop` : `${cmd} develop`
1033
+ ]);
1034
+ }
1035
+ if (runApp && installDependencies) {
1036
+ logger.title('Run', 'Running your Strapi application');
1037
+ try {
1038
+ await trackUsage({
1039
+ event: 'willStartServer',
1040
+ scope
1041
+ });
1042
+ await execa(packageManager, [
1043
+ 'run',
1044
+ 'develop'
1045
+ ], {
1046
+ stdio: 'inherit',
1047
+ cwd: rootPath,
1048
+ env: {
1049
+ FORCE_COLOR: '1'
1050
+ }
1051
+ });
1052
+ } catch (error) {
1053
+ if (typeof error === 'string' || error instanceof Error) {
1054
+ await trackUsage({
1055
+ event: 'didNotStartServer',
1056
+ scope,
1057
+ error
1058
+ });
1059
+ }
1060
+ logger.fatal('Failed to start your Strapi application');
951
1061
  }
952
- });
953
- } catch (error) {
954
- if (typeof error === "string" || error instanceof Error) {
955
- await trackUsage({
956
- event: "didNotStartServer",
957
- scope,
958
- error
959
- });
960
- }
961
- logger.fatal("Failed to start your Strapi application");
962
1062
  }
963
- }
964
1063
  }
965
1064
  async function runInstall({ rootPath, packageManager }) {
966
- const { envArgs, cmdArgs } = await getInstallArgs(packageManager, {
967
- cwd: rootPath,
968
- env: {
969
- ...process.env,
970
- NODE_ENV: "development"
971
- }
972
- });
973
- const options = {
974
- cwd: rootPath,
975
- stdio: "inherit",
976
- env: {
977
- ...process.env,
978
- ...envArgs,
979
- NODE_ENV: "development"
980
- }
981
- };
982
- const proc = execa__default.default(packageManager, cmdArgs, options);
983
- return proc;
1065
+ // include same cwd and env to ensure version check returns same version we use below
1066
+ const { envArgs, cmdArgs } = await getInstallArgs(packageManager, {
1067
+ cwd: rootPath,
1068
+ env: {
1069
+ ...process.env,
1070
+ NODE_ENV: 'development'
1071
+ }
1072
+ });
1073
+ const options = {
1074
+ cwd: rootPath,
1075
+ stdio: 'inherit',
1076
+ env: {
1077
+ ...process.env,
1078
+ ...envArgs,
1079
+ NODE_ENV: 'development'
1080
+ }
1081
+ };
1082
+ const proc = execa(packageManager, cmdArgs, options);
1083
+ return proc;
984
1084
  }
1085
+
985
1086
  function checkNodeRequirements() {
986
- const currentNodeVersion = process.versions.node;
987
- if (!semver__default.default.satisfies(currentNodeVersion, engines.node)) {
988
- logger.fatal([
989
- chalk__default.default.red(`You are running ${chalk__default.default.bold(`Node.js ${currentNodeVersion}`)}`),
990
- `Strapi requires ${chalk__default.default.bold(chalk__default.default.green(`Node.js ${engines.node}`))}`,
991
- "Please make sure to use the right version of Node."
992
- ]);
993
- } else if (semver__default.default.major(currentNodeVersion) % 2 !== 0) {
994
- logger.warn([
995
- chalk__default.default.yellow(`You are running ${chalk__default.default.bold(`Node.js ${currentNodeVersion}`)}`),
996
- `Strapi only supports ${chalk__default.default.bold(chalk__default.default.green("LTS versions of Node.js"))}, other versions may not be compatible.`
997
- ]);
998
- }
1087
+ const currentNodeVersion = process.versions.node;
1088
+ // error if the node version isn't supported
1089
+ if (!semver.satisfies(currentNodeVersion, engines.node)) {
1090
+ logger.fatal([
1091
+ chalk.red(`You are running ${chalk.bold(`Node.js ${currentNodeVersion}`)}`),
1092
+ `Strapi requires ${chalk.bold(chalk.green(`Node.js ${engines.node}`))}`,
1093
+ 'Please make sure to use the right version of Node.'
1094
+ ]);
1095
+ } else if (semver.major(currentNodeVersion) % 2 !== 0) {
1096
+ logger.warn([
1097
+ chalk.yellow(`You are running ${chalk.bold(`Node.js ${currentNodeVersion}`)}`),
1098
+ `Strapi only supports ${chalk.bold(chalk.green('LTS versions of Node.js'))}, other versions may not be compatible.`
1099
+ ]);
1100
+ }
999
1101
  }
1000
- async function checkInstallPath(directory2) {
1001
- const rootPath = path.resolve(directory2);
1002
- if (await fse__default.default.pathExists(rootPath)) {
1003
- const stat = await fse__default.default.stat(rootPath);
1004
- if (!stat.isDirectory()) {
1005
- logger.fatal(
1006
- `${chalk__default.default.green(
1007
- rootPath
1008
- )} is not a directory. Make sure to create a Strapi application in an empty directory.`
1009
- );
1010
- }
1011
- const files = await fse__default.default.readdir(rootPath);
1012
- if (files.length > 1) {
1013
- logger.fatal([
1014
- "You can only create a Strapi app in an empty directory",
1015
- `Make sure ${chalk__default.default.green(rootPath)} is empty.`
1016
- ]);
1102
+
1103
+ // Checks if the an empty directory exists at rootPath
1104
+ async function checkInstallPath(directory) {
1105
+ const rootPath = path.resolve(directory);
1106
+ if (await fse.pathExists(rootPath)) {
1107
+ const stat = await fse.stat(rootPath);
1108
+ if (!stat.isDirectory()) {
1109
+ logger.fatal(`${chalk.green(rootPath)} is not a directory. Make sure to create a Strapi application in an empty directory.`);
1110
+ }
1111
+ const files = await fse.readdir(rootPath);
1112
+ if (files.length > 1) {
1113
+ logger.fatal([
1114
+ 'You can only create a Strapi app in an empty directory',
1115
+ `Make sure ${chalk.green(rootPath)} is empty.`
1116
+ ]);
1117
+ }
1017
1118
  }
1018
- }
1019
- return rootPath;
1119
+ return rootPath;
1020
1120
  }
1121
+
1021
1122
  function machineID() {
1022
- try {
1023
- const deviceId = nodeMachineId.machineIdSync();
1024
- return deviceId;
1025
- } catch (error) {
1026
- const deviceId = crypto.randomUUID();
1027
- return deviceId;
1028
- }
1123
+ try {
1124
+ const deviceId = nodeMachineId.machineIdSync();
1125
+ return deviceId;
1126
+ } catch (error) {
1127
+ const deviceId = crypto.randomUUID();
1128
+ return deviceId;
1129
+ }
1029
1130
  }
1030
- const DBOptions = ["dbclient", "dbhost", "dbport", "dbname", "dbusername", "dbpassword"];
1031
- const VALID_CLIENTS = ["sqlite", "mysql", "postgres"];
1131
+
1132
+ const DBOptions = [
1133
+ 'dbclient',
1134
+ 'dbhost',
1135
+ 'dbport',
1136
+ 'dbname',
1137
+ 'dbusername',
1138
+ 'dbpassword'
1139
+ ];
1140
+ const VALID_CLIENTS = [
1141
+ 'sqlite',
1142
+ 'mysql',
1143
+ 'postgres'
1144
+ ];
1032
1145
  const DEFAULT_CONFIG = {
1033
- client: "sqlite",
1034
- connection: {
1035
- filename: ".tmp/data.db"
1036
- }
1146
+ client: 'sqlite',
1147
+ connection: {
1148
+ filename: '.tmp/data.db'
1149
+ }
1037
1150
  };
1038
1151
  async function dbPrompt() {
1039
- const { useDefault } = await inquirer__default.default.prompt([
1040
- {
1041
- type: "confirm",
1042
- name: "useDefault",
1043
- message: "Do you want to use the default database (sqlite) ?",
1044
- default: true
1045
- }
1046
- ]);
1047
- if (useDefault) {
1048
- return DEFAULT_CONFIG;
1049
- }
1050
- const { client } = await inquirer__default.default.prompt([
1051
- {
1052
- type: "list",
1053
- name: "client",
1054
- message: "Choose your default database client",
1055
- choices: ["sqlite", "postgres", "mysql"],
1056
- default: "sqlite"
1057
- }
1058
- ]);
1059
- const questions = dbQuestions[client].map((q) => q({ client }));
1060
- const responses = await inquirer__default.default.prompt(questions);
1061
- return {
1062
- client,
1063
- connection: responses
1064
- };
1152
+ const { useDefault } = await inquirer.prompt([
1153
+ {
1154
+ type: 'confirm',
1155
+ name: 'useDefault',
1156
+ message: 'Do you want to use the default database (sqlite) ?',
1157
+ default: true
1158
+ }
1159
+ ]);
1160
+ if (useDefault) {
1161
+ return DEFAULT_CONFIG;
1162
+ }
1163
+ const { client } = await inquirer.prompt([
1164
+ {
1165
+ type: 'list',
1166
+ name: 'client',
1167
+ message: 'Choose your default database client',
1168
+ choices: [
1169
+ 'sqlite',
1170
+ 'postgres',
1171
+ 'mysql'
1172
+ ],
1173
+ default: 'sqlite'
1174
+ }
1175
+ ]);
1176
+ const questions = dbQuestions[client].map((q)=>q({
1177
+ client
1178
+ }));
1179
+ const responses = await inquirer.prompt(questions);
1180
+ return {
1181
+ client,
1182
+ connection: responses
1183
+ };
1065
1184
  }
1066
1185
  async function getDatabaseInfos(options) {
1067
- if (options.skipDb) {
1068
- return DEFAULT_CONFIG;
1069
- }
1070
- if (options.dbclient && !VALID_CLIENTS.includes(options.dbclient)) {
1071
- logger.fatal(
1072
- `Invalid --dbclient: ${options.dbclient}, expected one of ${VALID_CLIENTS.join(", ")}`
1073
- );
1074
- }
1075
- const matchingArgs = DBOptions.filter((key) => key in options);
1076
- const missingArgs = DBOptions.filter((key) => !(key in options));
1077
- if (matchingArgs.length > 0 && matchingArgs.length !== DBOptions.length && options.dbclient !== "sqlite") {
1078
- logger.fatal(`Required database arguments are missing: ${missingArgs.join(", ")}.`);
1079
- }
1080
- const hasDBOptions = DBOptions.some((key) => key in options);
1081
- if (!hasDBOptions) {
1082
- if (options.quickstart) {
1083
- return DEFAULT_CONFIG;
1186
+ if (options.skipDb) {
1187
+ return DEFAULT_CONFIG;
1084
1188
  }
1085
- return dbPrompt();
1086
- }
1087
- if (!options.dbclient) {
1088
- return logger.fatal("Please specify the database client");
1089
- }
1090
- const database2 = {
1091
- client: options.dbclient,
1092
- connection: {
1093
- host: options.dbhost,
1094
- port: options.dbport,
1095
- database: options.dbname,
1096
- username: options.dbusername,
1097
- password: options.dbpassword,
1098
- filename: options.dbfile
1099
- }
1100
- };
1101
- if (options.dbssl !== void 0) {
1102
- database2.connection.ssl = options.dbssl === "true";
1103
- }
1104
- return database2;
1189
+ if (options.dbclient && !VALID_CLIENTS.includes(options.dbclient)) {
1190
+ logger.fatal(`Invalid --dbclient: ${options.dbclient}, expected one of ${VALID_CLIENTS.join(', ')}`);
1191
+ }
1192
+ const matchingArgs = DBOptions.filter((key)=>key in options);
1193
+ const missingArgs = DBOptions.filter((key)=>!(key in options));
1194
+ if (matchingArgs.length > 0 && matchingArgs.length !== DBOptions.length && options.dbclient !== 'sqlite') {
1195
+ logger.fatal(`Required database arguments are missing: ${missingArgs.join(', ')}.`);
1196
+ }
1197
+ const hasDBOptions = DBOptions.some((key)=>key in options);
1198
+ if (!hasDBOptions) {
1199
+ if (options.quickstart) {
1200
+ return DEFAULT_CONFIG;
1201
+ }
1202
+ return dbPrompt();
1203
+ }
1204
+ if (!options.dbclient) {
1205
+ return logger.fatal('Please specify the database client');
1206
+ }
1207
+ const database = {
1208
+ client: options.dbclient,
1209
+ connection: {
1210
+ host: options.dbhost,
1211
+ port: options.dbport,
1212
+ database: options.dbname,
1213
+ username: options.dbusername,
1214
+ password: options.dbpassword,
1215
+ filename: options.dbfile
1216
+ }
1217
+ };
1218
+ if (options.dbssl !== undefined) {
1219
+ database.connection.ssl = options.dbssl === 'true';
1220
+ }
1221
+ return database;
1105
1222
  }
1106
1223
  const sqlClientModule = {
1107
- mysql: { mysql2: "3.9.8" },
1108
- postgres: { pg: "8.8.0" },
1109
- sqlite: { "better-sqlite3": "11.3.0" }
1224
+ mysql: {
1225
+ mysql2: '3.9.8'
1226
+ },
1227
+ postgres: {
1228
+ pg: '8.8.0'
1229
+ },
1230
+ sqlite: {
1231
+ 'better-sqlite3': '11.3.0'
1232
+ }
1110
1233
  };
1111
1234
  function addDatabaseDependencies(scope) {
1112
- scope.dependencies = {
1113
- ...scope.dependencies,
1114
- ...sqlClientModule[scope.database.client]
1115
- };
1235
+ scope.dependencies = {
1236
+ ...scope.dependencies,
1237
+ ...sqlClientModule[scope.database.client]
1238
+ };
1116
1239
  }
1117
1240
  const DEFAULT_PORTS = {
1118
- postgres: 5432,
1119
- mysql: 3306,
1120
- sqlite: void 0
1241
+ postgres: 5432,
1242
+ mysql: 3306,
1243
+ sqlite: undefined
1121
1244
  };
1122
- const database = () => ({
1123
- type: "input",
1124
- name: "database",
1125
- message: "Database name:",
1126
- default: "strapi",
1127
- validate(value) {
1128
- if (value.includes(".")) {
1129
- return `The database name can't contain a "."`;
1130
- }
1131
- return true;
1132
- }
1133
- });
1134
- const host = () => ({
1135
- type: "input",
1136
- name: "host",
1137
- message: "Host:",
1138
- default: "127.0.0.1"
1139
- });
1140
- const port = ({ client }) => ({
1141
- type: "input",
1142
- name: "port",
1143
- message: "Port:",
1144
- default: DEFAULT_PORTS[client]
1145
- });
1146
- const username = () => ({
1147
- type: "input",
1148
- name: "username",
1149
- message: "Username:"
1150
- });
1151
- const password = () => ({
1152
- type: "password",
1153
- name: "password",
1154
- message: "Password:",
1155
- mask: "*"
1156
- });
1157
- const ssl = () => ({
1158
- type: "confirm",
1159
- name: "ssl",
1160
- message: "Enable SSL connection:",
1161
- default: false
1162
- });
1163
- const filename = () => ({
1164
- type: "input",
1165
- name: "filename",
1166
- message: "Filename:",
1167
- default: ".tmp/data.db"
1168
- });
1245
+ const database = ()=>({
1246
+ type: 'input',
1247
+ name: 'database',
1248
+ message: 'Database name:',
1249
+ default: 'strapi',
1250
+ validate (value) {
1251
+ if (value.includes('.')) {
1252
+ return `The database name can't contain a "."`;
1253
+ }
1254
+ return true;
1255
+ }
1256
+ });
1257
+ const host = ()=>({
1258
+ type: 'input',
1259
+ name: 'host',
1260
+ message: 'Host:',
1261
+ default: '127.0.0.1'
1262
+ });
1263
+ const port = ({ client })=>({
1264
+ type: 'input',
1265
+ name: 'port',
1266
+ message: 'Port:',
1267
+ default: DEFAULT_PORTS[client]
1268
+ });
1269
+ const username = ()=>({
1270
+ type: 'input',
1271
+ name: 'username',
1272
+ message: 'Username:'
1273
+ });
1274
+ const password = ()=>({
1275
+ type: 'password',
1276
+ name: 'password',
1277
+ message: 'Password:',
1278
+ mask: '*'
1279
+ });
1280
+ const ssl = ()=>({
1281
+ type: 'confirm',
1282
+ name: 'ssl',
1283
+ message: 'Enable SSL connection:',
1284
+ default: false
1285
+ });
1286
+ const filename = ()=>({
1287
+ type: 'input',
1288
+ name: 'filename',
1289
+ message: 'Filename:',
1290
+ default: '.tmp/data.db'
1291
+ });
1169
1292
  const dbQuestions = {
1170
- sqlite: [filename],
1171
- postgres: [database, host, port, username, password, ssl],
1172
- mysql: [database, host, port, username, password, ssl]
1293
+ sqlite: [
1294
+ filename
1295
+ ],
1296
+ postgres: [
1297
+ database,
1298
+ host,
1299
+ port,
1300
+ username,
1301
+ password,
1302
+ ssl
1303
+ ],
1304
+ mysql: [
1305
+ database,
1306
+ host,
1307
+ port,
1308
+ username,
1309
+ password,
1310
+ ssl
1311
+ ]
1173
1312
  };
1174
- const { version } = fse__default.default.readJSONSync(path.join(__dirname, "..", "package.json"));
1175
- const command = new commander__default.default.Command("create-strapi-app").version(version).arguments("[directory]").usage("[directory] [options]").option("--quickstart", "Quickstart app creation (deprecated)").option("--no-run", "Do not start the application after it is created.").option("--ts, --typescript", "Initialize the project with TypeScript (default)").option("--js, --javascript", "Initialize the project with Javascript").option("--use-npm", "Use npm as the project package manager").option("--use-yarn", "Use yarn as the project package manager").option("--use-pnpm", "Use pnpm as the project package manager").option("--install", "Install dependencies").option("--no-install", "Do not install dependencies").option("--skip-cloud", "Skip cloud login and project creation").option("--example", "Use an example app").option("--no-example", "Do not use an example app").option("--git-init", "Initialize a git repository").option("--no-git-init", "Do no initialize a git repository").option("--dbclient <dbclient>", "Database client").option("--dbhost <dbhost>", "Database host").option("--dbport <dbport>", "Database port").option("--dbname <dbname>", "Database name").option("--dbusername <dbusername>", "Database username").option("--dbpassword <dbpassword>", "Database password").option("--dbssl <dbssl>", "Database SSL").option("--dbfile <dbfile>", "Database file path for sqlite").option("--skip-db", "Skip database configuration").option("--template <template>", "Specify a Strapi template").option("--template-branch <templateBranch>", "Specify a branch for the template").option("--template-path <templatePath>", "Specify a path to the template inside the repository").description("create a new application");
1313
+
1314
+ const { version } = fse.readJSONSync(path.join(__dirname, '..', 'package.json'));
1315
+ const command = new commander.Command('create-strapi-app').version(version).arguments('[directory]').usage('[directory] [options]').option('--quickstart', 'Quickstart app creation (deprecated)').option('--no-run', 'Do not start the application after it is created.')// setup options
1316
+ .option('--ts, --typescript', 'Initialize the project with TypeScript (default)').option('--js, --javascript', 'Initialize the project with Javascript')// Package manager options
1317
+ .option('--use-npm', 'Use npm as the project package manager').option('--use-yarn', 'Use yarn as the project package manager').option('--use-pnpm', 'Use pnpm as the project package manager')// dependencies options
1318
+ .option('--install', 'Install dependencies').option('--no-install', 'Do not install dependencies')// Cloud options
1319
+ .option('--skip-cloud', 'Skip cloud login and project creation')// Example app
1320
+ .option('--example', 'Use an example app').option('--no-example', 'Do not use an example app')// git options
1321
+ .option('--git-init', 'Initialize a git repository').option('--no-git-init', 'Do no initialize a git repository')// Database options
1322
+ .option('--dbclient <dbclient>', 'Database client').option('--dbhost <dbhost>', 'Database host').option('--dbport <dbport>', 'Database port').option('--dbname <dbname>', 'Database name').option('--dbusername <dbusername>', 'Database username').option('--dbpassword <dbpassword>', 'Database password').option('--dbssl <dbssl>', 'Database SSL').option('--dbfile <dbfile>', 'Database file path for sqlite').option('--skip-db', 'Skip database configuration').option('--template <template>', 'Specify a Strapi template').option('--template-branch <templateBranch>', 'Specify a branch for the template').option('--template-path <templatePath>', 'Specify a path to the template inside the repository').description('create a new application');
1176
1323
  async function run(args) {
1177
- const options = command.parse(args).opts();
1178
- const directory$1 = command.args[0];
1179
- logger.title(
1180
- "Strapi",
1181
- `${chalk__default.default.green(chalk__default.default.bold(`v${version}`))} ${chalk__default.default.bold("🚀 Let's create your new project")}
1182
- `
1183
- );
1184
- if ((options.javascript !== void 0 || options.typescript !== void 0) && options.template !== void 0) {
1185
- logger.fatal(
1186
- `You cannot use ${chalk__default.default.bold("--javascript")} or ${chalk__default.default.bold("--typescript")} with ${chalk__default.default.bold("--template")}`
1187
- );
1188
- }
1189
- if (options.javascript === true && options.typescript === true) {
1190
- logger.fatal(
1191
- `You cannot use both ${chalk__default.default.bold("--typescript")} (--ts) and ${chalk__default.default.bold("--javascript")} (--js) flags together`
1192
- );
1193
- }
1194
- if (options.example === true && options.template !== void 0) {
1195
- logger.fatal(`You cannot use ${chalk__default.default.bold("--example")} with ${chalk__default.default.bold("--template")}`);
1196
- }
1197
- if (options.template !== void 0 && options.template.startsWith("-")) {
1198
- logger.fatal(`Template name ${chalk__default.default.bold(`"${options.template}"`)} is invalid`);
1199
- }
1200
- if ([options.useNpm, options.usePnpm, options.useYarn].filter(Boolean).length > 1) {
1201
- logger.fatal(
1202
- `You cannot specify multiple package managers at the same time ${chalk__default.default.bold("(--use-npm, --use-pnpm, --use-yarn)")}`
1203
- );
1204
- }
1205
- if (options.quickstart && !directory$1) {
1206
- logger.fatal(
1207
- `Please specify the ${chalk__default.default.bold("<directory>")} of your project when using ${chalk__default.default.bold("--quickstart")}`
1208
- );
1209
- }
1210
- checkNodeRequirements();
1211
- const appDirectory = directory$1 || await directory();
1212
- const rootPath = await checkInstallPath(appDirectory);
1213
- if (!options.skipCloud) {
1214
- await handleCloudLogin();
1215
- }
1216
- const tmpPath = path.join(os__default$1.default.tmpdir(), `strapi${crypto__default.default.randomBytes(6).toString("hex")}`);
1217
- const scope = {
1218
- rootPath,
1219
- name: path.basename(rootPath),
1220
- packageManager: getPkgManager(options),
1221
- database: await getDatabaseInfos(options),
1222
- template: options.template,
1223
- templateBranch: options.templateBranch,
1224
- templatePath: options.templatePath,
1225
- isQuickstart: options.quickstart,
1226
- useExample: false,
1227
- runApp: options.quickstart === true && options.run !== false,
1228
- strapiVersion: version,
1229
- packageJsonStrapi: {
1230
- template: options.template
1231
- },
1232
- uuid: (process.env.STRAPI_UUID_PREFIX || "") + crypto__default.default.randomUUID(),
1233
- docker: process.env.DOCKER === "true",
1234
- deviceId: machineID(),
1235
- tmpPath,
1236
- gitInit: true,
1237
- devDependencies: {},
1238
- dependencies: {
1239
- "@strapi/strapi": version,
1240
- "@strapi/plugin-users-permissions": version,
1241
- "@strapi/plugin-cloud": version,
1242
- // third party
1243
- react: "^18.0.0",
1244
- "react-dom": "^18.0.0",
1245
- "react-router-dom": "^6.0.0",
1246
- "styled-components": "^6.0.0"
1247
- }
1248
- };
1249
- if (options.template !== void 0) {
1250
- scope.useExample = false;
1251
- } else if (options.example === true) {
1252
- scope.useExample = true;
1253
- } else if (options.example === false || options.quickstart === true) {
1254
- scope.useExample = false;
1255
- } else {
1256
- scope.useExample = await example();
1257
- }
1258
- if (options.javascript === true) {
1259
- scope.useTypescript = false;
1260
- } else if (options.typescript === true || options.quickstart) {
1261
- scope.useTypescript = true;
1262
- } else if (!options.template) {
1263
- scope.useTypescript = await typescript();
1264
- }
1265
- if (options.install === true || options.quickstart) {
1266
- scope.installDependencies = true;
1267
- } else if (options.install === false) {
1268
- scope.installDependencies = false;
1269
- } else {
1270
- scope.installDependencies = await installDependencies(scope.packageManager);
1271
- }
1272
- if (scope.useTypescript) {
1273
- scope.devDependencies = {
1274
- ...scope.devDependencies,
1275
- typescript: "^5",
1276
- "@types/node": "^20",
1277
- "@types/react": "^18",
1278
- "@types/react-dom": "^18"
1324
+ const options = command.parse(args).opts();
1325
+ const directory$1 = command.args[0];
1326
+ logger.title('Strapi', `${chalk.green(chalk.bold(`v${version}`))} ${chalk.bold("🚀 Let's create your new project")}\n`);
1327
+ if ((options.javascript !== undefined || options.typescript !== undefined) && options.template !== undefined) {
1328
+ logger.fatal(`You cannot use ${chalk.bold('--javascript')} or ${chalk.bold('--typescript')} with ${chalk.bold('--template')}`);
1329
+ }
1330
+ if (options.javascript === true && options.typescript === true) {
1331
+ logger.fatal(`You cannot use both ${chalk.bold('--typescript')} (--ts) and ${chalk.bold('--javascript')} (--js) flags together`);
1332
+ }
1333
+ // Only prompt the example app option if there is no template option
1334
+ if (options.example === true && options.template !== undefined) {
1335
+ logger.fatal(`You cannot use ${chalk.bold('--example')} with ${chalk.bold('--template')}`);
1336
+ }
1337
+ if (options.template !== undefined && options.template.startsWith('-')) {
1338
+ logger.fatal(`Template name ${chalk.bold(`"${options.template}"`)} is invalid`);
1339
+ }
1340
+ if ([
1341
+ options.useNpm,
1342
+ options.usePnpm,
1343
+ options.useYarn
1344
+ ].filter(Boolean).length > 1) {
1345
+ logger.fatal(`You cannot specify multiple package managers at the same time ${chalk.bold('(--use-npm, --use-pnpm, --use-yarn)')}`);
1346
+ }
1347
+ if (options.quickstart && !directory$1) {
1348
+ logger.fatal(`Please specify the ${chalk.bold('<directory>')} of your project when using ${chalk.bold('--quickstart')}`);
1349
+ }
1350
+ checkNodeRequirements();
1351
+ const appDirectory = directory$1 || await directory();
1352
+ const rootPath = await checkInstallPath(appDirectory);
1353
+ if (!options.skipCloud) {
1354
+ await handleCloudLogin();
1355
+ }
1356
+ const tmpPath = path.join(os$1.tmpdir(), `strapi${crypto.randomBytes(6).toString('hex')}`);
1357
+ const scope = {
1358
+ rootPath,
1359
+ name: path.basename(rootPath),
1360
+ packageManager: getPkgManager(options),
1361
+ database: await getDatabaseInfos(options),
1362
+ template: options.template,
1363
+ templateBranch: options.templateBranch,
1364
+ templatePath: options.templatePath,
1365
+ isQuickstart: options.quickstart,
1366
+ useExample: false,
1367
+ runApp: options.quickstart === true && options.run !== false,
1368
+ strapiVersion: version,
1369
+ packageJsonStrapi: {
1370
+ template: options.template
1371
+ },
1372
+ uuid: (process.env.STRAPI_UUID_PREFIX || '') + crypto.randomUUID(),
1373
+ docker: process.env.DOCKER === 'true',
1374
+ deviceId: machineID(),
1375
+ tmpPath,
1376
+ gitInit: true,
1377
+ devDependencies: {},
1378
+ dependencies: {
1379
+ '@strapi/strapi': version,
1380
+ '@strapi/plugin-users-permissions': version,
1381
+ '@strapi/plugin-cloud': version,
1382
+ // third party
1383
+ react: '^18.0.0',
1384
+ 'react-dom': '^18.0.0',
1385
+ 'react-router-dom': '^6.0.0',
1386
+ 'styled-components': '^6.0.0'
1387
+ }
1279
1388
  };
1280
- }
1281
- if (options.gitInit === true || options.quickstart) {
1282
- scope.gitInit = true;
1283
- } else if (options.gitInit === false) {
1284
- scope.gitInit = false;
1285
- } else {
1286
- scope.gitInit = await gitInit();
1287
- }
1288
- addDatabaseDependencies(scope);
1289
- try {
1290
- await createStrapi(scope);
1291
- } catch (error) {
1292
- if (!(error instanceof Error)) {
1293
- throw error;
1294
- }
1295
- await trackError({ scope, error });
1296
- logger.fatal(error.message);
1297
- }
1389
+ if (options.template !== undefined) {
1390
+ scope.useExample = false;
1391
+ } else if (options.example === true) {
1392
+ scope.useExample = true;
1393
+ } else if (options.example === false || options.quickstart === true) {
1394
+ scope.useExample = false;
1395
+ } else {
1396
+ scope.useExample = await example();
1397
+ }
1398
+ if (options.javascript === true) {
1399
+ scope.useTypescript = false;
1400
+ } else if (options.typescript === true || options.quickstart) {
1401
+ scope.useTypescript = true;
1402
+ } else if (!options.template) {
1403
+ scope.useTypescript = await typescript();
1404
+ }
1405
+ if (options.install === true || options.quickstart) {
1406
+ scope.installDependencies = true;
1407
+ } else if (options.install === false) {
1408
+ scope.installDependencies = false;
1409
+ } else {
1410
+ scope.installDependencies = await installDependencies(scope.packageManager);
1411
+ }
1412
+ if (scope.useTypescript) {
1413
+ scope.devDependencies = {
1414
+ ...scope.devDependencies,
1415
+ typescript: '^5',
1416
+ '@types/node': '^20',
1417
+ '@types/react': '^18',
1418
+ '@types/react-dom': '^18'
1419
+ };
1420
+ }
1421
+ if (options.gitInit === true || options.quickstart) {
1422
+ scope.gitInit = true;
1423
+ } else if (options.gitInit === false) {
1424
+ scope.gitInit = false;
1425
+ } else {
1426
+ scope.gitInit = await gitInit();
1427
+ }
1428
+ addDatabaseDependencies(scope);
1429
+ try {
1430
+ await createStrapi(scope);
1431
+ } catch (error) {
1432
+ if (!(error instanceof Error)) {
1433
+ throw error;
1434
+ }
1435
+ await trackError({
1436
+ scope,
1437
+ error
1438
+ });
1439
+ logger.fatal(error.message);
1440
+ }
1298
1441
  }
1299
1442
  function getPkgManager(options) {
1300
- if (options.useNpm === true) {
1301
- return "npm";
1302
- }
1303
- if (options.usePnpm === true) {
1304
- return "pnpm";
1305
- }
1306
- if (options.useYarn === true) {
1307
- return "yarn";
1308
- }
1309
- const userAgent = process.env.npm_config_user_agent || "";
1310
- if (userAgent.startsWith("yarn")) {
1311
- return "yarn";
1312
- }
1313
- if (userAgent.startsWith("pnpm")) {
1314
- return "pnpm";
1315
- }
1316
- return "npm";
1443
+ if (options.useNpm === true) {
1444
+ return 'npm';
1445
+ }
1446
+ if (options.usePnpm === true) {
1447
+ return 'pnpm';
1448
+ }
1449
+ if (options.useYarn === true) {
1450
+ return 'yarn';
1451
+ }
1452
+ const userAgent = process.env.npm_config_user_agent || '';
1453
+ if (userAgent.startsWith('yarn')) {
1454
+ return 'yarn';
1455
+ }
1456
+ if (userAgent.startsWith('pnpm')) {
1457
+ return 'pnpm';
1458
+ }
1459
+ return 'npm';
1317
1460
  }
1461
+
1318
1462
  exports.createStrapi = createStrapi;
1319
1463
  exports.run = run;
1320
1464
  //# sourceMappingURL=index.js.map