create-medusa-app 2.11.2 → 2.11.3-preview-20251031120214

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.
@@ -1 +0,0 @@
1
-
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Change Log
2
2
 
3
+ ## 2.11.3-preview-20251031120214
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies []:
8
+ - @medusajs/deps@2.11.3-preview-20251031120214
9
+ - @medusajs/telemetry@2.11.3-preview-20251031120214
10
+
3
11
  ## 2.11.2
4
12
 
5
13
  ### Patch Changes
package/dist/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,14 +1,20 @@
1
1
  {
2
2
  "name": "create-medusa-app",
3
- "version": "2.11.2",
3
+ "version": "2.11.3-preview-20251031120214",
4
4
  "description": "Create a Medusa project using a single command.",
5
5
  "type": "module",
6
6
  "exports": "./dist/index.js",
7
7
  "bin": "dist/index.js",
8
8
  "license": "MIT",
9
+ "scripts": {
10
+ "dev": "node --loader ts-node/esm src/index.ts",
11
+ "start": "node dist/index.js",
12
+ "build": "tsc",
13
+ "watch": "tsc --watch"
14
+ },
9
15
  "dependencies": {
10
- "@medusajs/deps": "2.11.2",
11
- "@medusajs/telemetry": "2.11.2",
16
+ "@medusajs/deps": "2.11.3-preview-20251031120214",
17
+ "@medusajs/telemetry": "2.11.3-preview-20251031120214",
12
18
  "boxen": "^5",
13
19
  "chalk": "^5.2.0",
14
20
  "commander": "^10.0.1",
@@ -57,11 +63,5 @@
57
63
  "publishConfig": {
58
64
  "access": "public"
59
65
  },
60
- "gitHead": "41a5425405aea5045a26def95c0dc00cf4a5a44d",
61
- "scripts": {
62
- "dev": "node --loader ts-node/esm src/index.ts",
63
- "start": "node dist/index.js",
64
- "build": "tsc",
65
- "watch": "tsc --watch"
66
- }
67
- }
66
+ "gitHead": "41a5425405aea5045a26def95c0dc00cf4a5a44d"
67
+ }
@@ -1,387 +0,0 @@
1
- import inquirer from "inquirer";
2
- import slugifyType from "slugify";
3
- import chalk from "chalk";
4
- import { getDbClientAndCredentials, runCreateDb } from "../utils/create-db.js";
5
- import prepareProject from "../utils/prepare-project.js";
6
- import startMedusa from "../utils/start-medusa.js";
7
- import open from "open";
8
- import waitOn from "wait-on";
9
- import ora from "ora";
10
- import fs from "fs";
11
- import path from "path";
12
- import logMessage from "../utils/log-message.js";
13
- import createAbortController, { isAbortError, } from "../utils/create-abort-controller.js";
14
- import { track } from "@medusajs/telemetry";
15
- import boxen from "boxen";
16
- import { emojify } from "node-emoji";
17
- import ProcessManager from "../utils/process-manager.js";
18
- import { displayFactBox } from "../utils/facts.js";
19
- import { EOL } from "os";
20
- import { runCloneRepo } from "../utils/clone-repo.js";
21
- import { askForNextjsStarter, installNextjsStarter, startNextjsStarter, } from "../utils/nextjs-utils.js";
22
- import { getNodeVersion, MIN_SUPPORTED_NODE_VERSION, } from "../utils/node-version.js";
23
- const slugify = slugifyType.default;
24
- // Base class for common project functionality
25
- class BaseProjectCreator {
26
- options;
27
- args;
28
- spinner;
29
- processManager;
30
- abortController;
31
- factBoxOptions;
32
- projectName;
33
- projectPath;
34
- isProjectCreated = false;
35
- printedMessage = false;
36
- constructor(projectName, options, args) {
37
- this.options = options;
38
- this.args = args;
39
- this.spinner = ora();
40
- this.processManager = new ProcessManager();
41
- this.abortController = createAbortController(this.processManager);
42
- this.projectName = projectName;
43
- const basePath = typeof options.directoryPath === "string" ? options.directoryPath : "";
44
- this.projectPath = path.join(basePath, projectName);
45
- this.factBoxOptions = {
46
- interval: null,
47
- spinner: this.spinner,
48
- processManager: this.processManager,
49
- message: "",
50
- title: "",
51
- verbose: options.verbose || false,
52
- };
53
- }
54
- getProjectPath(projectName) {
55
- return path.join(this.options.directoryPath ?? "", projectName);
56
- }
57
- }
58
- // Plugin Project Creator
59
- class PluginProjectCreator extends BaseProjectCreator {
60
- constructor(projectName, options, args) {
61
- super(projectName, options, args);
62
- this.setupProcessManager();
63
- }
64
- async create() {
65
- track("CREATE_CLI_CMP");
66
- logMessage({
67
- message: `${emojify(":rocket:")} Starting plugin setup, this may take a few minutes.`,
68
- });
69
- this.spinner.start();
70
- this.factBoxOptions.interval = displayFactBox({
71
- ...this.factBoxOptions,
72
- title: "Setting up plugin...",
73
- });
74
- try {
75
- await this.cloneAndPreparePlugin();
76
- this.spinner.succeed(chalk.green("Plugin Prepared"));
77
- this.showSuccessMessage();
78
- }
79
- catch (e) {
80
- this.handleError(e);
81
- }
82
- }
83
- async cloneAndPreparePlugin() {
84
- await runCloneRepo({
85
- projectName: this.projectPath,
86
- repoUrl: this.options.repoUrl ?? "",
87
- abortController: this.abortController,
88
- spinner: this.spinner,
89
- verbose: this.options.verbose,
90
- });
91
- this.factBoxOptions.interval = displayFactBox({
92
- ...this.factBoxOptions,
93
- message: "Created plugin directory",
94
- });
95
- await prepareProject({
96
- isPlugin: true,
97
- directory: this.projectPath,
98
- projectName: this.projectName,
99
- spinner: this.spinner,
100
- processManager: this.processManager,
101
- abortController: this.abortController,
102
- verbose: this.options.verbose,
103
- });
104
- }
105
- handleError(e) {
106
- if (isAbortError(e)) {
107
- process.exit();
108
- }
109
- this.spinner.stop();
110
- logMessage({
111
- message: `An error occurred while preparing plugin: ${e}`,
112
- type: "error",
113
- });
114
- }
115
- showSuccessMessage() {
116
- logMessage({
117
- message: boxen(chalk.green(`Change to the \`${this.projectName}\` directory to explore your Medusa plugin.${EOL}${EOL}Check out the Medusa plugin documentation to start your development:${EOL}${EOL}https://docs.medusajs.com/${EOL}${EOL}Star us on GitHub if you like what we're building:${EOL}${EOL}https://github.com/medusajs/medusa/stargazers`), {
118
- titleAlignment: "center",
119
- textAlignment: "center",
120
- padding: 1,
121
- margin: 1,
122
- float: "center",
123
- }),
124
- });
125
- }
126
- setupProcessManager() {
127
- this.processManager.onTerminated(async () => {
128
- this.spinner.stop();
129
- if (!this.printedMessage && this.isProjectCreated) {
130
- this.printedMessage = true;
131
- this.showSuccessMessage();
132
- }
133
- return;
134
- });
135
- }
136
- }
137
- // Medusa Project Creator
138
- class MedusaProjectCreator extends BaseProjectCreator {
139
- client = null;
140
- dbConnectionString = "";
141
- isDbInitialized = false;
142
- nextjsDirectory = "";
143
- inviteToken;
144
- constructor(projectName, options, args) {
145
- super(projectName, options, args);
146
- this.setupProcessManager();
147
- }
148
- async create() {
149
- track("CREATE_CLI_CMA");
150
- try {
151
- await this.initializeProject();
152
- await this.setupProject();
153
- await this.startServices();
154
- }
155
- catch (e) {
156
- this.handleError(e);
157
- }
158
- }
159
- async initializeProject() {
160
- const installNextjs = this.options.withNextjsStarter || (await askForNextjsStarter());
161
- if (!this.options.skipDb) {
162
- await this.setupDatabase();
163
- }
164
- logMessage({
165
- message: `${emojify(":rocket:")} Starting project setup, this may take a few minutes.`,
166
- });
167
- this.spinner.start();
168
- this.factBoxOptions.interval = displayFactBox({
169
- ...this.factBoxOptions,
170
- title: "Setting up project...",
171
- });
172
- try {
173
- await runCloneRepo({
174
- projectName: this.projectPath,
175
- repoUrl: this.options.repoUrl ?? "",
176
- abortController: this.abortController,
177
- spinner: this.spinner,
178
- verbose: this.options.verbose,
179
- });
180
- this.factBoxOptions.interval = displayFactBox({
181
- ...this.factBoxOptions,
182
- message: "Created project directory",
183
- });
184
- if (installNextjs) {
185
- this.nextjsDirectory = await installNextjsStarter({
186
- directoryName: this.projectPath,
187
- abortController: this.abortController,
188
- factBoxOptions: this.factBoxOptions,
189
- verbose: this.options.verbose,
190
- processManager: this.processManager,
191
- });
192
- }
193
- }
194
- catch (e) {
195
- throw e;
196
- }
197
- }
198
- async setupDatabase() {
199
- const dbName = `medusa-${slugify(this.projectName)}`;
200
- const { client, dbConnectionString, ...rest } = await getDbClientAndCredentials({
201
- dbName,
202
- dbUrl: this.options.dbUrl,
203
- verbose: this.options.verbose,
204
- });
205
- this.client = client;
206
- this.dbConnectionString = dbConnectionString;
207
- this.isDbInitialized = true;
208
- if (!this.options.dbUrl) {
209
- this.factBoxOptions.interval = displayFactBox({
210
- ...this.factBoxOptions,
211
- title: "Creating database...",
212
- });
213
- this.client = await runCreateDb({
214
- client: this.client,
215
- dbName,
216
- spinner: this.spinner,
217
- });
218
- this.factBoxOptions.interval = displayFactBox({
219
- ...this.factBoxOptions,
220
- message: `Database ${dbName} created`,
221
- });
222
- }
223
- }
224
- async setupProject() {
225
- try {
226
- this.inviteToken = await prepareProject({
227
- isPlugin: false,
228
- directory: this.projectPath,
229
- dbConnectionString: this.dbConnectionString,
230
- seed: this.options.seed,
231
- spinner: this.spinner,
232
- processManager: this.processManager,
233
- abortController: this.abortController,
234
- skipDb: this.options.skipDb,
235
- migrations: this.options.migrations,
236
- onboardingType: this.nextjsDirectory ? "nextjs" : "default",
237
- nextjsDirectory: this.nextjsDirectory,
238
- client: this.client,
239
- verbose: this.options.verbose,
240
- });
241
- }
242
- finally {
243
- await this.client?.end();
244
- }
245
- this.spinner.succeed(chalk.green("Project Prepared"));
246
- }
247
- async startServices() {
248
- if (this.options.skipDb || !this.options.browser) {
249
- this.showSuccessMessage();
250
- process.exit();
251
- }
252
- logMessage({
253
- message: "Starting Medusa...",
254
- });
255
- startMedusa({
256
- directory: this.projectPath,
257
- abortController: this.abortController,
258
- });
259
- if (this.nextjsDirectory) {
260
- startNextjsStarter({
261
- directory: this.nextjsDirectory,
262
- abortController: this.abortController,
263
- verbose: this.options.verbose,
264
- });
265
- }
266
- this.isProjectCreated = true;
267
- await this.openBrowser();
268
- }
269
- async openBrowser() {
270
- await waitOn({
271
- resources: ["http://localhost:9000/health"],
272
- }).then(async () => {
273
- open(this.inviteToken
274
- ? `http://localhost:9000/app/invite?token=${this.inviteToken}&first_run=true`
275
- : "http://localhost:9000/app");
276
- });
277
- }
278
- handleError(e) {
279
- if (isAbortError(e)) {
280
- process.exit();
281
- }
282
- this.spinner.stop();
283
- logMessage({
284
- message: `An error occurred: ${e}`,
285
- type: "error",
286
- });
287
- }
288
- showSuccessMessage() {
289
- logMessage({
290
- message: boxen(chalk.green(`Change to the \`${this.projectName}\` directory to explore your Medusa project.${EOL}${EOL}Start your Medusa app again with the following command:${EOL}${EOL}yarn dev${EOL}${EOL}${this.inviteToken
291
- ? `After you start the Medusa app, you can set a password for your admin user with the URL http://localhost:7001/invite?token=${this.inviteToken}&first_run=true${EOL}${EOL}`
292
- : ""}${this.nextjsDirectory?.length
293
- ? `The Next.js Starter storefront was installed in the \`${this.nextjsDirectory}\` directory. Change to that directory and start it with the following command:${EOL}${EOL}npm run dev${EOL}${EOL}`
294
- : ""}Check out the Medusa documentation to start your development:${EOL}${EOL}https://docs.medusajs.com/${EOL}${EOL}Star us on GitHub if you like what we're building:${EOL}${EOL}https://github.com/medusajs/medusa/stargazers`), {
295
- titleAlignment: "center",
296
- textAlignment: "center",
297
- padding: 1,
298
- margin: 1,
299
- float: "center",
300
- }),
301
- });
302
- }
303
- setupProcessManager() {
304
- this.processManager.onTerminated(async () => {
305
- this.spinner.stop();
306
- // prevent an error from occurring if
307
- // client hasn't been declared yet
308
- if (this.isDbInitialized && this.client) {
309
- await this.client.end();
310
- }
311
- if (!this.printedMessage && this.isProjectCreated) {
312
- this.printedMessage = true;
313
- this.showSuccessMessage();
314
- }
315
- return;
316
- });
317
- }
318
- }
319
- // Project Factory
320
- class ProjectCreatorFactory {
321
- static async create(args, options) {
322
- const isPlugin = args.indexOf("--plugin") !== -1;
323
- if (isPlugin) {
324
- args.splice(args.indexOf("--plugin"), 1);
325
- }
326
- ProjectCreatorFactory.validateNodeVersion();
327
- const projectName = await ProjectCreatorFactory.getProjectName(args, options.directoryPath, isPlugin);
328
- return isPlugin
329
- ? new PluginProjectCreator(projectName, options, args)
330
- : new MedusaProjectCreator(projectName, options, args);
331
- }
332
- static validateNodeVersion() {
333
- const nodeVersion = getNodeVersion();
334
- if (nodeVersion < MIN_SUPPORTED_NODE_VERSION) {
335
- logMessage({
336
- message: `Medusa requires at least v20 of Node.js. You're using v${nodeVersion}. Please install at least v20 and try again: https://nodejs.org/en/download`,
337
- type: "error",
338
- });
339
- }
340
- }
341
- static async getProjectName(args, directoryPath, isPlugin) {
342
- let askProjectName = args.length === 0;
343
- if (args.length > 0) {
344
- const projectPath = path.join(directoryPath || "", args[0]);
345
- if (fs.existsSync(projectPath) &&
346
- fs.lstatSync(projectPath).isDirectory()) {
347
- logMessage({
348
- message: `A directory already exists with the name ${args[0]}. Please enter a different ${isPlugin ? "plugin" : "project"} name.`,
349
- type: "warn",
350
- });
351
- askProjectName = true;
352
- }
353
- }
354
- return askProjectName
355
- ? await askForProjectName(directoryPath, isPlugin)
356
- : args[0];
357
- }
358
- }
359
- async function askForProjectName(directoryPath, isPlugin) {
360
- const { projectName } = await inquirer.prompt([
361
- {
362
- type: "input",
363
- name: "projectName",
364
- message: `What's the name of your ${isPlugin ? "plugin" : "project"}?`,
365
- default: "my-medusa-store",
366
- filter: (input) => {
367
- return slugify(input).toLowerCase();
368
- },
369
- validate: (input) => {
370
- if (!input.length) {
371
- return `Please enter a ${isPlugin ? "plugin" : "project"} name`;
372
- }
373
- const projectPath = path.join(directoryPath || "", input);
374
- return fs.existsSync(projectPath) &&
375
- fs.lstatSync(projectPath).isDirectory()
376
- ? `A directory already exists with the same name. Please enter a different ${isPlugin ? "plugin" : "project"} name.`
377
- : true;
378
- },
379
- },
380
- ]);
381
- return projectName;
382
- }
383
- // Main entry point
384
- export default async (args, options) => {
385
- const projectCreator = await ProjectCreatorFactory.create(args, options);
386
- await projectCreator.create();
387
- };