create-medusa-app 3.0.0-snapshot-20250410112222 → 3.0.0-snapshot-20251104004624

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/CHANGELOG.md CHANGED
@@ -1,11 +1,166 @@
1
1
  # Change Log
2
2
 
3
- ## 3.0.0-snapshot-20250410112222
3
+ ## 3.0.0-snapshot-20251104004624
4
+
5
+ ### Patch Changes
6
+
7
+ - [#13910](https://github.com/medusajs/medusa/pull/13910) [`224ab39a81e8d3cf3d6fa3ff5eee82541f64728d`](https://github.com/medusajs/medusa/commit/224ab39a81e8d3cf3d6fa3ff5eee82541f64728d) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Dependencies cleanup and improvements
8
+
9
+ - [#13940](https://github.com/medusajs/medusa/pull/13940) [`afb40d437b3cc4ceb015df70985b2f005f40eaff`](https://github.com/medusajs/medusa/commit/afb40d437b3cc4ceb015df70985b2f005f40eaff) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Cleanup and organize deps
10
+
11
+ - [#13932](https://github.com/medusajs/medusa/pull/13932) [`37563987b8fe75c9acfe62957a33e8398977647a`](https://github.com/medusajs/medusa/commit/37563987b8fe75c9acfe62957a33e8398977647a) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Fix dependencies vulnerabilities
12
+
13
+ - Updated dependencies [[`224ab39a81e8d3cf3d6fa3ff5eee82541f64728d`](https://github.com/medusajs/medusa/commit/224ab39a81e8d3cf3d6fa3ff5eee82541f64728d), [`afb40d437b3cc4ceb015df70985b2f005f40eaff`](https://github.com/medusajs/medusa/commit/afb40d437b3cc4ceb015df70985b2f005f40eaff), [`37563987b8fe75c9acfe62957a33e8398977647a`](https://github.com/medusajs/medusa/commit/37563987b8fe75c9acfe62957a33e8398977647a)]:
14
+ - @medusajs/deps@3.0.0-snapshot-20251104004624
15
+ - @medusajs/telemetry@3.0.0-snapshot-20251104004624
16
+
17
+ ## 2.11.2
18
+
19
+ ### Patch Changes
20
+
21
+ - Updated dependencies []:
22
+ - @medusajs/deps@2.11.2
23
+ - @medusajs/telemetry@2.11.2
24
+
25
+ ## 2.11.1
26
+
27
+ ### Patch Changes
28
+
29
+ - Updated dependencies []:
30
+ - @medusajs/deps@2.11.1
31
+ - @medusajs/telemetry@2.11.1
32
+
33
+ ## 2.11.0
34
+
35
+ ### Patch Changes
36
+
37
+ - [#13439](https://github.com/medusajs/medusa/pull/13439) [`12a96a7c7015f011f5e29a1d387f835e514ba536`](https://github.com/medusajs/medusa/commit/12a96a7c7015f011f5e29a1d387f835e514ba536) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Move peer deps into a single package and re export from framework
38
+
39
+ - [#13450](https://github.com/medusajs/medusa/pull/13450) [`8ece06d8ed6a197ebb370918c49a3ec5c21dd186`](https://github.com/medusajs/medusa/commit/8ece06d8ed6a197ebb370918c49a3ec5c21dd186) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Upgrade mikro orm 6.5.4
40
+
41
+ - Updated dependencies [[`0cbd9f0bc315b3eda1770ac301061f1576856387`](https://github.com/medusajs/medusa/commit/0cbd9f0bc315b3eda1770ac301061f1576856387), [`12a96a7c7015f011f5e29a1d387f835e514ba536`](https://github.com/medusajs/medusa/commit/12a96a7c7015f011f5e29a1d387f835e514ba536), [`41651721450c99e5f38cfbb87a6a47ab067ece86`](https://github.com/medusajs/medusa/commit/41651721450c99e5f38cfbb87a6a47ab067ece86), [`fc67fd0b36f53f0c0897df54ecea02061e65e816`](https://github.com/medusajs/medusa/commit/fc67fd0b36f53f0c0897df54ecea02061e65e816), [`c54c5ed6de2c9686f89aeef86c5c607c4b5f1cf3`](https://github.com/medusajs/medusa/commit/c54c5ed6de2c9686f89aeef86c5c607c4b5f1cf3), [`02b6d013822b9665f868c4ea6d1b5cfe58723459`](https://github.com/medusajs/medusa/commit/02b6d013822b9665f868c4ea6d1b5cfe58723459)]:
42
+ - @medusajs/deps@2.11.0
43
+ - @medusajs/telemetry@2.11.0
44
+
45
+ ## 2.10.3
46
+
47
+ ### Patch Changes
48
+
49
+ - Updated dependencies []:
50
+ - @medusajs/telemetry@2.10.3
51
+
52
+ ## 2.10.2
53
+
54
+ ### Patch Changes
55
+
56
+ - Updated dependencies []:
57
+ - @medusajs/telemetry@2.10.2
58
+
59
+ ## 2.10.1
60
+
61
+ ### Patch Changes
62
+
63
+ - Updated dependencies []:
64
+ - @medusajs/telemetry@2.10.1
65
+
66
+ ## 2.10.0
67
+
68
+ ### Patch Changes
69
+
70
+ - Updated dependencies []:
71
+ - @medusajs/telemetry@2.10.0
72
+
73
+ ## 2.9.0
74
+
75
+ ### Patch Changes
76
+
77
+ - Updated dependencies []:
78
+ - @medusajs/telemetry@2.9.0
79
+
80
+ ## 2.8.8
81
+
82
+ ### Patch Changes
83
+
84
+ - Updated dependencies []:
85
+ - @medusajs/telemetry@2.8.8
86
+
87
+ ## 2.8.7
88
+
89
+ ### Patch Changes
90
+
91
+ - [#12882](https://github.com/medusajs/medusa/pull/12882) [`779ed018b9c1328d6554a0f3d3569147edaeae56`](https://github.com/medusajs/medusa/commit/779ed018b9c1328d6554a0f3d3569147edaeae56) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(create-medusa-app): Allow to create project with specific medusa version
92
+
93
+ - Updated dependencies []:
94
+ - @medusajs/telemetry@2.8.7
95
+
96
+ ## 2.8.6
97
+
98
+ ### Patch Changes
99
+
100
+ - Updated dependencies []:
101
+ - @medusajs/telemetry@2.8.6
102
+
103
+ ## 2.8.5
104
+
105
+ ### Patch Changes
106
+
107
+ - [#12707](https://github.com/medusajs/medusa/pull/12707) [`774702153f389e59476ea0a027b8caeb5075f92a`](https://github.com/medusajs/medusa/commit/774702153f389e59476ea0a027b8caeb5075f92a) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(create-medusa-app): remove "Created admin user" message
108
+
109
+ - [#12714](https://github.com/medusajs/medusa/pull/12714) [`2e861a94492a486e2cbdb8d442f25611be1bc3bf`](https://github.com/medusajs/medusa/commit/2e861a94492a486e2cbdb8d442f25611be1bc3bf) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(create-medusa-app): ensure the same package manager is used consistently
110
+
111
+ - Updated dependencies []:
112
+ - @medusajs/telemetry@2.8.5
113
+
114
+ ## 2.8.4
115
+
116
+ ### Patch Changes
117
+
118
+ - Updated dependencies []:
119
+ - @medusajs/telemetry@2.8.4
120
+
121
+ ## 2.8.3
122
+
123
+ ### Patch Changes
124
+
125
+ - Updated dependencies []:
126
+ - @medusajs/telemetry@2.8.3
127
+
128
+ ## 2.8.2
129
+
130
+ ### Patch Changes
131
+
132
+ - Updated dependencies []:
133
+ - @medusajs/telemetry@2.8.2
134
+
135
+ ## 2.8.1
136
+
137
+ ### Patch Changes
138
+
139
+ - Updated dependencies []:
140
+ - @medusajs/telemetry@2.8.1
141
+
142
+ ## 2.8.0
143
+
144
+ ### Patch Changes
145
+
146
+ - [#12360](https://github.com/medusajs/medusa/pull/12360) [`f74586e772f2800952e52b6eaceb25de93c1691c`](https://github.com/medusajs/medusa/commit/f74586e772f2800952e52b6eaceb25de93c1691c) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(create-medusa-app): updates to text and prompts
147
+
148
+ - Updated dependencies []:
149
+ - @medusajs/telemetry@2.8.0
150
+
151
+ ## 2.7.1
152
+
153
+ ### Patch Changes
154
+
155
+ - Updated dependencies []:
156
+ - @medusajs/telemetry@2.7.1
157
+
158
+ ## 2.7.0
4
159
 
5
160
  ### Patch Changes
6
161
 
7
162
  - Updated dependencies []:
8
- - @medusajs/telemetry@3.0.0-snapshot-20250410112222
163
+ - @medusajs/telemetry@2.7.0
9
164
 
10
165
  ## 2.6.1
11
166
 
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ program
6
6
  .argument("[project-name]", "Name of the project to create.")
7
7
  .option("--plugin", "Create a plugin instead of a project.")
8
8
  .option("--repo-url <url>", "URL of repository to use to setup project.")
9
+ .option("--version <version>", "The version of Medusa packages to install.")
9
10
  .option("--seed", "Seed the created database with demo data.")
10
11
  .option("--skip-db", "Skips creating the database, running migrations, and seeding, and subsequently skips opening the browser.", false)
11
12
  .option("--db-url <url>", "Skips database creation and sets the database URL to the provided URL. Throws an error if can't connect to the database. Will still run migrations and open the admin after project creation.")
@@ -8,12 +8,14 @@ const execute = async (command, { verbose = false, needOutput = false }) => {
8
8
  const childProcess = spawnSync(commandStr, {
9
9
  ...options,
10
10
  shell: true,
11
- stdio: needOutput
12
- ? "pipe"
13
- : [process.stdin, process.stdout, process.stderr],
11
+ stdio: needOutput ?
12
+ "pipe" :
13
+ [process.stdin, process.stdout, process.stderr],
14
14
  });
15
- if (childProcess.error) {
16
- throw childProcess.error;
15
+ if (childProcess.error || childProcess.status !== 0) {
16
+ throw childProcess.error ||
17
+ childProcess.stderr?.toString() ||
18
+ `${commandStr} failed with status ${childProcess.status}`;
17
19
  }
18
20
  if (childProcess.signal &&
19
21
  ["SIGINT", "SIGTERM"].includes(childProcess.signal)) {
@@ -2,24 +2,24 @@ import boxen from "boxen";
2
2
  import chalk from "chalk";
3
3
  import { emojify } from "node-emoji";
4
4
  const facts = [
5
- "You can specify a product's availability in one or more sales channels.",
6
- "Payment and shipping options and providers can be configured per region.",
7
- "Tax-inclusive pricing allows you to set prices for products, shipping options, and more without having to worry about calculating taxes.",
5
+ "Specify a product's availability in one or more sales channels.",
6
+ "Payment providers can be configured per region.",
7
+ "Tax-inclusive pricing allows you to set prices for products and shipping options while delegating tax calculations to Medusa.",
8
8
  "Medusa provides multi-currency and region support, with full control over prices for each currency and region.",
9
- "You can organize customers by customer groups and set special prices for them.",
10
- "You can specify the inventory of products per location and sales channel.",
11
- "Publishable-API Keys allow you to send requests to the backend within a scoped resource.",
12
- "You can create custom endpoints by creating a TypeScript file under the src/api directory.",
13
- "You can listen to events to perform asynchronous actions using Subscribers.",
14
- "A data model represents a table in the database. You can create a table by creating a custom data model and migration in a module.",
15
- "Medusa's store endpoint paths are prefixed by /store. The admin endpoints are prefixed by /admin.",
16
- "Medusa provides a JavaScript client and a React library that you can use to build a storefront or a custom admin.",
17
- "Modules hold your custom features and data models. You create them under the src/modules directory. Each module must have a service.",
18
- "A service is a class with methods related to a functionality or a data model. You create a service in a module.",
9
+ "Organize customers by customer groups and set special prices for them.",
10
+ "Specify the inventory of products per location and sales channel.",
11
+ "Publishable-API Keys allow you to send scoped requests to the server's store API routes.",
12
+ "API Routes expose business logic to clients, such as storefronts and admin customizations.",
13
+ "Subscribers are asynchronous functions that are executed when an event is emitted.",
14
+ "Data models represent tables in the database. They are created using Medusa's Data Modeling Language (DML).",
15
+ "Medusa's store API routes are prefixed by /store. The admin API routes are prefixed by /admin.",
16
+ "The JS SDK allows you to send requests to the Medusa server from your storefront or admin customizations.",
17
+ "Modules are reusable packages of functionalities related to a single commerce domain or integration.",
18
+ "Modules have a main service that provides data-management and integration functionalities.",
19
19
  "Modules allow you to replace an entire functionality with your custom logic.",
20
- "The event bus module is responsible for triggering events and relaying them to subscribers.",
21
- "The cache module is responsible for caching data that requires heavy computation.",
22
- "A workflow is a series of steps that are defined once and executed anywhere. Workflows are created under the src/workflows directory.",
20
+ "Infrastructure Modules are interchangeable modules that implement features and integrations related to the Medusa server's infrastructure.",
21
+ "Commerce Modules are built-in modules that provide core commerce logic specific to domains like Product, Cart and Order.",
22
+ "Workflows are a series of queries and actions, called steps, that complete a task.",
23
23
  "A workflow's steps can be retried or rolled back in case of an error.",
24
24
  ];
25
25
  export const getFact = () => {
@@ -7,6 +7,7 @@ import { isAbortError } from "./create-abort-controller.js";
7
7
  import execute from "./execute.js";
8
8
  import { displayFactBox } from "./facts.js";
9
9
  import logMessage from "./log-message.js";
10
+ import { updatePackageVersions } from "./update-package-versions.js";
10
11
  const NEXTJS_REPO = "https://github.com/medusajs/nextjs-starter-medusa";
11
12
  const NEXTJS_BRANCH = "main";
12
13
  export async function askForNextjsStarter() {
@@ -14,16 +15,16 @@ export async function askForNextjsStarter() {
14
15
  {
15
16
  type: "confirm",
16
17
  name: "installNextjs",
17
- message: `Would you like to create the Next.js storefront? You can also create it later`,
18
+ message: `Would you like to install the Next.js Starter Storefront? You can also install it later.`,
18
19
  default: false,
19
20
  },
20
21
  ]);
21
22
  return installNextjs;
22
23
  }
23
- export async function installNextjsStarter({ directoryName, abortController, factBoxOptions, verbose = false, processManager, }) {
24
+ export async function installNextjsStarter({ directoryName, abortController, factBoxOptions, verbose = false, processManager, version, }) {
24
25
  factBoxOptions.interval = displayFactBox({
25
26
  ...factBoxOptions,
26
- title: "Installing Next.js Storefront...",
27
+ title: "Installing Next.js Starter Storefront...",
27
28
  });
28
29
  let nextjsDirectory = `${directoryName}-storefront`;
29
30
  if (fs.existsSync(nextjsDirectory) &&
@@ -41,6 +42,10 @@ export async function installNextjsStarter({ directoryName, abortController, fac
41
42
  env: process.env,
42
43
  },
43
44
  ], { verbose });
45
+ if (version) {
46
+ const packageJsonPath = path.join(nextjsDirectory, "package.json");
47
+ updatePackageVersions(packageJsonPath, version, { applyChanges: true });
48
+ }
44
49
  const execOptions = {
45
50
  signal: abortController?.signal,
46
51
  cwd: nextjsDirectory,
@@ -66,7 +71,7 @@ export async function installNextjsStarter({ directoryName, abortController, fac
66
71
  process.exit();
67
72
  }
68
73
  logMessage({
69
- message: `An error occurred while installing Next.js storefront: ${e}`,
74
+ message: `An error occurred while installing Next.js Starter Storefront: ${e}`,
70
75
  type: "error",
71
76
  });
72
77
  }
@@ -77,7 +82,7 @@ export async function installNextjsStarter({ directoryName, abortController, fac
77
82
  fs.renameSync(path.join(nextjsDirectory, ".env.template"), path.join(nextjsDirectory, ".env.local"));
78
83
  displayFactBox({
79
84
  ...factBoxOptions,
80
- message: `Installed Next.js Starter successfully in the ${nextjsDirectory} directory.`,
85
+ message: `Installed Next.js Starter Storefront successfully in the ${nextjsDirectory} directory.`,
81
86
  });
82
87
  return nextjsDirectory;
83
88
  }
@@ -0,0 +1,68 @@
1
+ import execute from "./execute.js";
2
+ export default class PackageManager {
3
+ packageManager;
4
+ processManager;
5
+ verbose;
6
+ constructor(processManager, verbose = false) {
7
+ this.processManager = processManager;
8
+ this.verbose = verbose;
9
+ }
10
+ async setPackageManager(execOptions) {
11
+ if (this.packageManager) {
12
+ return;
13
+ }
14
+ // check whether yarn is available
15
+ await this.processManager.runProcess({
16
+ process: async () => {
17
+ try {
18
+ await execute([`yarn -v`, execOptions], { verbose: this.verbose });
19
+ // yarn is available
20
+ this.packageManager = "yarn";
21
+ }
22
+ catch (e) {
23
+ // yarn isn't available
24
+ // use npm
25
+ this.packageManager = "npm";
26
+ }
27
+ },
28
+ ignoreERESOLVE: true,
29
+ });
30
+ }
31
+ async installDependencies(execOptions) {
32
+ if (!this.packageManager) {
33
+ await this.setPackageManager(execOptions);
34
+ }
35
+ const command = this.packageManager === "yarn" ?
36
+ `yarn` : `npm install`;
37
+ await this.processManager.runProcess({
38
+ process: async () => {
39
+ await execute([command, execOptions], {
40
+ verbose: this.verbose
41
+ });
42
+ },
43
+ ignoreERESOLVE: true,
44
+ });
45
+ }
46
+ async runCommand(command, execOptions) {
47
+ if (!this.packageManager) {
48
+ await this.setPackageManager(execOptions);
49
+ }
50
+ const commandStr = this.getCommandStr(command);
51
+ await this.processManager.runProcess({
52
+ process: async () => {
53
+ await execute([commandStr, execOptions], {
54
+ verbose: this.verbose
55
+ });
56
+ },
57
+ ignoreERESOLVE: true,
58
+ });
59
+ }
60
+ getCommandStr(command) {
61
+ if (!this.packageManager) {
62
+ throw new Error("Package manager not set");
63
+ }
64
+ return this.packageManager === "yarn"
65
+ ? `yarn ${command}`
66
+ : `npm run ${command}`;
67
+ }
68
+ }
@@ -1,4 +1,4 @@
1
- import pg from "pg";
1
+ import pg from "@medusajs/deps/pg";
2
2
  const { Client } = pg;
3
3
  export const DEFAULT_HOST = "localhost";
4
4
  export const DEFAULT_PORT = 5432;
@@ -3,6 +3,7 @@ import path from "path";
3
3
  import execute from "./execute.js";
4
4
  import { EOL } from "os";
5
5
  import { displayFactBox } from "./facts.js";
6
+ import { updatePackageVersions } from "./update-package-versions.js";
6
7
  const ADMIN_EMAIL = "admin@medusa-test.com";
7
8
  let STORE_CORS = "http://localhost:8000";
8
9
  let ADMIN_CORS = "http://localhost:5173,http://localhost:9000";
@@ -17,7 +18,7 @@ export default async (prepareOptions) => {
17
18
  }
18
19
  return prepareProject(prepareOptions);
19
20
  };
20
- async function preparePlugin({ directory, projectName, spinner, processManager, abortController, verbose = false, }) {
21
+ async function preparePlugin({ directory, projectName, spinner, processManager, abortController, verbose = false, packageManager, }) {
21
22
  // initialize execution options
22
23
  const execOptions = {
23
24
  cwd: directory,
@@ -43,28 +44,14 @@ async function preparePlugin({ directory, projectName, spinner, processManager,
43
44
  title: "Installing dependencies...",
44
45
  processManager,
45
46
  });
46
- await processManager.runProcess({
47
- process: async () => {
48
- try {
49
- await execute([`yarn`, execOptions], { verbose });
50
- }
51
- catch (e) {
52
- // yarn isn't available
53
- // use npm
54
- await execute([`npm install --legacy-peer-deps`, execOptions], {
55
- verbose,
56
- });
57
- }
58
- },
59
- ignoreERESOLVE: true,
60
- });
47
+ await packageManager.installDependencies(execOptions);
61
48
  factBoxOptions.interval = displayFactBox({
62
49
  ...factBoxOptions,
63
50
  message: "Installed Dependencies",
64
51
  });
65
52
  displayFactBox({ ...factBoxOptions, message: "Finished Preparation" });
66
53
  }
67
- async function prepareProject({ directory, projectName, dbName, dbConnectionString, seed, spinner, processManager, abortController, skipDb, migrations, onboardingType = "default", nextjsDirectory = "", client, verbose = false, }) {
54
+ async function prepareProject({ directory, projectName, dbName, dbConnectionString, seed, spinner, processManager, abortController, skipDb, migrations, onboardingType = "default", nextjsDirectory = "", client, verbose = false, packageManager, version, }) {
68
55
  // initialize execution options
69
56
  const execOptions = {
70
57
  cwd: directory,
@@ -90,6 +77,10 @@ async function prepareProject({ directory, projectName, dbName, dbConnectionStri
90
77
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
91
78
  // Update name
92
79
  packageJson.name = projectName;
80
+ // Update medusa dependencies versions
81
+ if (version) {
82
+ updatePackageVersions(packageJson, version);
83
+ }
93
84
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
94
85
  // initialize the invite token to return
95
86
  let inviteToken = undefined;
@@ -112,21 +103,7 @@ async function prepareProject({ directory, projectName, dbName, dbConnectionStri
112
103
  title: "Installing dependencies...",
113
104
  processManager,
114
105
  });
115
- await processManager.runProcess({
116
- process: async () => {
117
- try {
118
- await execute([`yarn`, execOptions], { verbose });
119
- }
120
- catch (e) {
121
- // yarn isn't available
122
- // use npm
123
- await execute([`npm install --legacy-peer-deps`, execOptions], {
124
- verbose,
125
- });
126
- }
127
- },
128
- ignoreERESOLVE: true,
129
- });
106
+ await packageManager.installDependencies(execOptions);
130
107
  factBoxOptions.interval = displayFactBox({
131
108
  ...factBoxOptions,
132
109
  message: "Installed Dependencies",
@@ -167,11 +144,6 @@ async function prepareProject({ directory, projectName, dbName, dbConnectionStri
167
144
  ...factBoxOptions,
168
145
  message: "Ran Migrations",
169
146
  });
170
- // create admin user
171
- factBoxOptions.interval = displayFactBox({
172
- ...factBoxOptions,
173
- title: "Creating an admin user...",
174
- });
175
147
  await processManager.runProcess({
176
148
  process: async () => {
177
149
  const proc = await execute([`npx medusa user -e ${ADMIN_EMAIL} --invite`, npxOptions], { verbose, needOutput: true });
@@ -180,10 +152,6 @@ async function prepareProject({ directory, projectName, dbName, dbConnectionStri
180
152
  inviteToken = match?.groups?.token;
181
153
  },
182
154
  });
183
- factBoxOptions.interval = displayFactBox({
184
- ...factBoxOptions,
185
- message: "Created admin user",
186
- });
187
155
  // TODO for now we just seed the default data
188
156
  // we should add onboarding seeding again if it makes
189
157
  // since once we re-introduce the onboarding flow.
@@ -191,19 +159,7 @@ async function prepareProject({ directory, projectName, dbName, dbConnectionStri
191
159
  ...factBoxOptions,
192
160
  title: "Seeding database...",
193
161
  });
194
- await processManager.runProcess({
195
- process: async () => {
196
- try {
197
- await execute([`yarn seed`, execOptions], { verbose });
198
- }
199
- catch (e) {
200
- // yarn isn't available
201
- // use npm
202
- await execute([`npm run seed`, execOptions], { verbose });
203
- }
204
- },
205
- ignoreERESOLVE: true,
206
- });
162
+ await packageManager.runCommand("seed", execOptions);
207
163
  displayFactBox({
208
164
  ...factBoxOptions,
209
165
  message: "Seeded database with demo data",
@@ -2,12 +2,14 @@ import ora from "ora";
2
2
  import path from "path";
3
3
  import createAbortController from "../create-abort-controller.js";
4
4
  import ProcessManager from "../process-manager.js";
5
+ import PackageManager from "../package-manager.js";
5
6
  // Base class for common project functionality
6
7
  export class BaseProjectCreator {
7
8
  options;
8
9
  args;
9
10
  spinner;
10
11
  processManager;
12
+ packageManager;
11
13
  abortController;
12
14
  factBoxOptions;
13
15
  projectName;
@@ -19,6 +21,7 @@ export class BaseProjectCreator {
19
21
  this.args = args;
20
22
  this.spinner = ora();
21
23
  this.processManager = new ProcessManager();
24
+ this.packageManager = new PackageManager(this.processManager);
22
25
  this.abortController = createAbortController(this.processManager);
23
26
  this.projectName = projectName;
24
27
  const basePath = typeof options.directoryPath === "string" ? options.directoryPath : "";
@@ -55,6 +55,7 @@ export class PluginProjectCreator extends BaseProjectCreator {
55
55
  processManager: this.processManager,
56
56
  abortController: this.abortController,
57
57
  verbose: this.options.verbose,
58
+ packageManager: this.packageManager,
58
59
  });
59
60
  }
60
61
  handleError(e) {
@@ -70,6 +70,7 @@ export class MedusaProjectCreator extends BaseProjectCreator {
70
70
  factBoxOptions: this.factBoxOptions,
71
71
  verbose: this.options.verbose,
72
72
  processManager: this.processManager,
73
+ version: this.options.version,
73
74
  });
74
75
  }
75
76
  }
@@ -121,6 +122,8 @@ export class MedusaProjectCreator extends BaseProjectCreator {
121
122
  nextjsDirectory: this.nextjsDirectory,
122
123
  client: this.client,
123
124
  verbose: this.options.verbose,
125
+ packageManager: this.packageManager,
126
+ version: this.options.version,
124
127
  });
125
128
  }
126
129
  finally {
@@ -170,11 +173,12 @@ export class MedusaProjectCreator extends BaseProjectCreator {
170
173
  });
171
174
  }
172
175
  showSuccessMessage() {
176
+ const commandStr = this.packageManager.getCommandStr(`dev`);
173
177
  logMessage({
174
- 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
175
- ? `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}`
178
+ message: boxen(chalk.green(`Change to the \`${this.projectName}\` directory to explore your Medusa project.${EOL}${EOL}Start your Medusa application again with the following command:${EOL}${EOL}${commandStr}${EOL}${EOL}${this.inviteToken
179
+ ? `After you start the Medusa application, you can create an admin user with the URL http://localhost:9000/app/invite?token=${this.inviteToken}&first_run=true${EOL}${EOL}`
176
180
  : ""}${this.nextjsDirectory?.length
177
- ? `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}`
181
+ ? `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}${commandStr}${EOL}${EOL}`
178
182
  : ""}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`), {
179
183
  titleAlignment: "center",
180
184
  textAlignment: "center",
@@ -36,6 +36,15 @@ export class ProjectCreatorFactory {
36
36
  });
37
37
  askProjectName = true;
38
38
  }
39
+ else if (args[0].includes(".")) {
40
+ // We don't allow projects to have a dot in the name, as this causes issues for
41
+ // for MikroORM path resolutions.
42
+ logMessage({
43
+ message: `Project names cannot contain a dot (.) character. Please enter a different ${isPlugin ? "plugin" : "project"} name.`,
44
+ type: "error",
45
+ });
46
+ askProjectName = true;
47
+ }
39
48
  }
40
49
  return askProjectName
41
50
  ? await askForProjectName(directoryPath, isPlugin)
@@ -53,6 +62,11 @@ async function askForProjectName(directoryPath, isPlugin) {
53
62
  return slugify(input).toLowerCase();
54
63
  },
55
64
  validate: (input) => {
65
+ // We don't allow projects to have a dot in the name, as this causes issues for
66
+ // for MikroORM path resolutions.
67
+ if (input.includes(".")) {
68
+ return `Project names cannot contain a dot (.) character. Please enter a different ${isPlugin ? "plugin" : "project"} name.`;
69
+ }
56
70
  if (!input.length) {
57
71
  return `Please enter a ${isPlugin ? "plugin" : "project"} name`;
58
72
  }
@@ -0,0 +1,23 @@
1
+ import { readFileSync, writeFileSync } from "fs";
2
+ export function updatePackageVersions(packageJsonOrPath, version, { applyChanges = false } = {}) {
3
+ const packageJson = typeof packageJsonOrPath === "string"
4
+ ? JSON.parse(readFileSync(packageJsonOrPath, "utf-8"))
5
+ : packageJsonOrPath;
6
+ if (packageJson.dependencies) {
7
+ for (const dependency of Object.keys(packageJson.dependencies)) {
8
+ if (dependency.startsWith("@medusajs/")) {
9
+ packageJson.dependencies[dependency] = version;
10
+ }
11
+ }
12
+ }
13
+ if (packageJson.devDependencies) {
14
+ for (const dependency of Object.keys(packageJson.devDependencies)) {
15
+ if (dependency.startsWith("@medusajs/")) {
16
+ packageJson.devDependencies[dependency] = version;
17
+ }
18
+ }
19
+ }
20
+ if (applyChanges && typeof packageJsonOrPath === "string") {
21
+ writeFileSync(packageJsonOrPath, JSON.stringify(packageJson, null, 2));
22
+ }
23
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-medusa-app",
3
- "version": "3.0.0-snapshot-20250410112222",
3
+ "version": "3.0.0-snapshot-20251104004624",
4
4
  "description": "Create a Medusa project using a single command.",
5
5
  "type": "module",
6
6
  "exports": "./dist/index.js",
@@ -10,48 +10,26 @@
10
10
  "dev": "node --loader ts-node/esm src/index.ts",
11
11
  "start": "node dist/index.js",
12
12
  "build": "tsc",
13
- "watch": "tsc --watch"
13
+ "watch": "yarn run -T tsc --watch"
14
14
  },
15
15
  "dependencies": {
16
- "@medusajs/telemetry": "3.0.0-snapshot-20250410112222",
17
- "boxen": "^5",
18
- "chalk": "^5.2.0",
19
- "commander": "^10.0.1",
20
- "inquirer": "^9.2.2",
16
+ "@medusajs/deps": "3.0.0-snapshot-20251104004624",
17
+ "@medusajs/telemetry": "3.0.0-snapshot-20251104004624",
18
+ "boxen": "^5.0.1",
19
+ "chalk": "^4.1.2",
20
+ "commander": "^11.0.0",
21
+ "inquirer": "^8.0.0",
21
22
  "nanoid": "^4.0.2",
22
23
  "node-emoji": "^2.0.2",
23
24
  "node-fetch": "^3.3.1",
24
25
  "open": "^9.1.0",
25
- "ora": "^6.3.0",
26
- "pg": "^8.11.3",
26
+ "ora": "^5.4.1",
27
27
  "slugify": "^1.6.6",
28
28
  "uuid": "^9.0.0",
29
- "validator": "^13.9.0",
30
- "wait-on": "^7.0.1",
29
+ "validator": "^13.15.20",
30
+ "wait-on": "^9.0.1",
31
31
  "winston": "^3.9.0"
32
32
  },
33
- "devDependencies": {
34
- "@types/chalk": "^2.2.0",
35
- "@types/commander": "^2.12.2",
36
- "@types/configstore": "^6.0.0",
37
- "@types/inquirer": "^9.0.3",
38
- "@types/node": "^20.12.11",
39
- "@types/node-emoji": "^1.8.2",
40
- "@types/pg": "^8.6.6",
41
- "@types/uuid": "^9.0.1",
42
- "@types/validator": "^13.7.17",
43
- "@types/wait-on": "^5.3.1",
44
- "@typescript-eslint/eslint-plugin": "^6.19.0",
45
- "@typescript-eslint/parser": "^6.19.0",
46
- "configstore": "^6.0.0",
47
- "eslint": "^8.40.0",
48
- "eslint-config-google": "^0.14.0",
49
- "eslint-config-prettier": "^8.8.0",
50
- "eslint-plugin-prettier": "^4.2.1",
51
- "prettier": "^2.8.8",
52
- "ts-node": "^10.9.1",
53
- "typescript": "^5.6.2"
54
- },
55
33
  "engines": {
56
34
  "node": ">=14.16"
57
35
  },
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ program
7
7
  .argument("[project-name]", "Name of the project to create.")
8
8
  .option("--plugin", "Create a plugin instead of a project.")
9
9
  .option("--repo-url <url>", "URL of repository to use to setup project.")
10
+ .option("--version <version>", "The version of Medusa packages to install.")
10
11
  .option("--seed", "Seed the created database with demo data.")
11
12
  .option(
12
13
  "--skip-db",
@@ -1,5 +1,5 @@
1
1
  import { EOL } from "os"
2
- import pg from "pg"
2
+ import type pg from "@medusajs/deps/pg"
3
3
  import postgresClient, {
4
4
  DEFAULT_HOST,
5
5
  DEFAULT_PORT,
@@ -32,13 +32,15 @@ const execute = async (
32
32
  const childProcess = spawnSync(commandStr, {
33
33
  ...options,
34
34
  shell: true,
35
- stdio: needOutput
36
- ? "pipe"
37
- : [process.stdin, process.stdout, process.stderr],
35
+ stdio: needOutput ?
36
+ "pipe" :
37
+ [process.stdin, process.stdout, process.stderr],
38
38
  })
39
39
 
40
- if (childProcess.error) {
41
- throw childProcess.error
40
+ if (childProcess.error || childProcess.status !== 0) {
41
+ throw childProcess.error ||
42
+ childProcess.stderr?.toString() ||
43
+ `${commandStr} failed with status ${childProcess.status}`
42
44
  }
43
45
 
44
46
  if (
@@ -14,24 +14,24 @@ export type FactBoxOptions = {
14
14
  }
15
15
 
16
16
  const facts = [
17
- "You can specify a product's availability in one or more sales channels.",
18
- "Payment and shipping options and providers can be configured per region.",
19
- "Tax-inclusive pricing allows you to set prices for products, shipping options, and more without having to worry about calculating taxes.",
17
+ "Specify a product's availability in one or more sales channels.",
18
+ "Payment providers can be configured per region.",
19
+ "Tax-inclusive pricing allows you to set prices for products and shipping options while delegating tax calculations to Medusa.",
20
20
  "Medusa provides multi-currency and region support, with full control over prices for each currency and region.",
21
- "You can organize customers by customer groups and set special prices for them.",
22
- "You can specify the inventory of products per location and sales channel.",
23
- "Publishable-API Keys allow you to send requests to the backend within a scoped resource.",
24
- "You can create custom endpoints by creating a TypeScript file under the src/api directory.",
25
- "You can listen to events to perform asynchronous actions using Subscribers.",
26
- "A data model represents a table in the database. You can create a table by creating a custom data model and migration in a module.",
27
- "Medusa's store endpoint paths are prefixed by /store. The admin endpoints are prefixed by /admin.",
28
- "Medusa provides a JavaScript client and a React library that you can use to build a storefront or a custom admin.",
29
- "Modules hold your custom features and data models. You create them under the src/modules directory. Each module must have a service.",
30
- "A service is a class with methods related to a functionality or a data model. You create a service in a module.",
21
+ "Organize customers by customer groups and set special prices for them.",
22
+ "Specify the inventory of products per location and sales channel.",
23
+ "Publishable-API Keys allow you to send scoped requests to the server's store API routes.",
24
+ "API Routes expose business logic to clients, such as storefronts and admin customizations.",
25
+ "Subscribers are asynchronous functions that are executed when an event is emitted.",
26
+ "Data models represent tables in the database. They are created using Medusa's Data Modeling Language (DML).",
27
+ "Medusa's store API routes are prefixed by /store. The admin API routes are prefixed by /admin.",
28
+ "The JS SDK allows you to send requests to the Medusa server from your storefront or admin customizations.",
29
+ "Modules are reusable packages of functionalities related to a single commerce domain or integration.",
30
+ "Modules have a main service that provides data-management and integration functionalities.",
31
31
  "Modules allow you to replace an entire functionality with your custom logic.",
32
- "The event bus module is responsible for triggering events and relaying them to subscribers.",
33
- "The cache module is responsible for caching data that requires heavy computation.",
34
- "A workflow is a series of steps that are defined once and executed anywhere. Workflows are created under the src/workflows directory.",
32
+ "Infrastructure Modules are interchangeable modules that implement features and integrations related to the Medusa server's infrastructure.",
33
+ "Commerce Modules are built-in modules that provide core commerce logic specific to domains like Product, Cart and Order.",
34
+ "Workflows are a series of queries and actions, called steps, that complete a task.",
35
35
  "A workflow's steps can be retried or rolled back in case of an error.",
36
36
  ]
37
37
 
@@ -1,7 +1,7 @@
1
1
  import winston from "winston"
2
2
 
3
3
  const consoleTransport = new winston.transports.Console({
4
- format: winston.format.printf((log) => log.message),
4
+ format: winston.format.printf((log) => log.message as string),
5
5
  })
6
6
  const options = {
7
7
  transports: [consoleTransport],
@@ -8,6 +8,7 @@ import execute from "./execute.js"
8
8
  import { displayFactBox, FactBoxOptions } from "./facts.js"
9
9
  import logMessage from "./log-message.js"
10
10
  import ProcessManager from "./process-manager.js"
11
+ import { updatePackageVersions } from "./update-package-versions.js"
11
12
 
12
13
  const NEXTJS_REPO = "https://github.com/medusajs/nextjs-starter-medusa"
13
14
  const NEXTJS_BRANCH = "main"
@@ -17,7 +18,7 @@ export async function askForNextjsStarter(): Promise<boolean> {
17
18
  {
18
19
  type: "confirm",
19
20
  name: "installNextjs",
20
- message: `Would you like to create the Next.js storefront? You can also create it later`,
21
+ message: `Would you like to install the Next.js Starter Storefront? You can also install it later.`,
21
22
  default: false,
22
23
  },
23
24
  ])
@@ -31,6 +32,7 @@ type InstallOptions = {
31
32
  factBoxOptions: FactBoxOptions
32
33
  verbose?: boolean
33
34
  processManager: ProcessManager
35
+ version?: string
34
36
  }
35
37
 
36
38
  export async function installNextjsStarter({
@@ -39,10 +41,11 @@ export async function installNextjsStarter({
39
41
  factBoxOptions,
40
42
  verbose = false,
41
43
  processManager,
44
+ version,
42
45
  }: InstallOptions): Promise<string> {
43
46
  factBoxOptions.interval = displayFactBox({
44
47
  ...factBoxOptions,
45
- title: "Installing Next.js Storefront...",
48
+ title: "Installing Next.js Starter Storefront...",
46
49
  })
47
50
 
48
51
  let nextjsDirectory = `${directoryName}-storefront`
@@ -70,6 +73,12 @@ export async function installNextjsStarter({
70
73
  ],
71
74
  { verbose }
72
75
  )
76
+
77
+ if (version) {
78
+ const packageJsonPath = path.join(nextjsDirectory, "package.json")
79
+ updatePackageVersions(packageJsonPath, version, { applyChanges: true })
80
+ }
81
+
73
82
  const execOptions = {
74
83
  signal: abortController?.signal,
75
84
  cwd: nextjsDirectory,
@@ -94,7 +103,7 @@ export async function installNextjsStarter({
94
103
  }
95
104
 
96
105
  logMessage({
97
- message: `An error occurred while installing Next.js storefront: ${e}`,
106
+ message: `An error occurred while installing Next.js Starter Storefront: ${e}`,
98
107
  type: "error",
99
108
  })
100
109
  }
@@ -111,7 +120,7 @@ export async function installNextjsStarter({
111
120
 
112
121
  displayFactBox({
113
122
  ...factBoxOptions,
114
- message: `Installed Next.js Starter successfully in the ${nextjsDirectory} directory.`,
123
+ message: `Installed Next.js Starter Storefront successfully in the ${nextjsDirectory} directory.`,
115
124
  })
116
125
 
117
126
  return nextjsDirectory
@@ -0,0 +1,87 @@
1
+ import execute from "./execute.js"
2
+ import ProcessManager from "./process-manager.js"
3
+
4
+ export default class PackageManager {
5
+ protected packageManager?: "npm" | "yarn"
6
+ protected processManager: ProcessManager
7
+ protected verbose
8
+
9
+ constructor(processManager: ProcessManager, verbose = false) {
10
+ this.processManager = processManager
11
+ this.verbose = verbose
12
+ }
13
+
14
+ async setPackageManager(execOptions: Record<string, unknown>): Promise<void> {
15
+ if (this.packageManager) {
16
+ return
17
+ }
18
+
19
+ // check whether yarn is available
20
+ await this.processManager.runProcess({
21
+ process: async () => {
22
+ try {
23
+ await execute([`yarn -v`, execOptions], { verbose: this.verbose })
24
+ // yarn is available
25
+ this.packageManager = "yarn"
26
+ } catch (e) {
27
+ // yarn isn't available
28
+ // use npm
29
+ this.packageManager = "npm"
30
+ }
31
+ },
32
+ ignoreERESOLVE: true,
33
+ })
34
+ }
35
+
36
+ async installDependencies(
37
+ execOptions: Record<string, unknown>,
38
+ ) {
39
+ if (!this.packageManager) {
40
+ await this.setPackageManager(execOptions)
41
+ }
42
+
43
+ const command = this.packageManager === "yarn" ?
44
+ `yarn` : `npm install`
45
+
46
+ await this.processManager.runProcess({
47
+ process: async () => {
48
+ await execute([command, execOptions], {
49
+ verbose: this.verbose
50
+ })
51
+ },
52
+ ignoreERESOLVE: true,
53
+ })
54
+ }
55
+
56
+ async runCommand(
57
+ command: string,
58
+ execOptions: Record<string, unknown>,
59
+ ) {
60
+ if (!this.packageManager) {
61
+ await this.setPackageManager(execOptions)
62
+ }
63
+
64
+ const commandStr = this.getCommandStr(command)
65
+
66
+ await this.processManager.runProcess({
67
+ process: async () => {
68
+ await execute([commandStr, execOptions], {
69
+ verbose: this.verbose
70
+ })
71
+ },
72
+ ignoreERESOLVE: true,
73
+ })
74
+ }
75
+
76
+ getCommandStr(
77
+ command: string,
78
+ ): string {
79
+ if (!this.packageManager) {
80
+ throw new Error("Package manager not set")
81
+ }
82
+
83
+ return this.packageManager === "yarn"
84
+ ? `yarn ${command}`
85
+ : `npm run ${command}`
86
+ }
87
+ }
@@ -1,6 +1,6 @@
1
- import pg from "pg"
1
+ import pg from "@medusajs/deps/pg"
2
2
 
3
- const { Client } = pg
3
+ const { Client } = pg as any
4
4
 
5
5
  export const DEFAULT_HOST = "localhost"
6
6
  export const DEFAULT_PORT = 5432
@@ -5,7 +5,9 @@ import execute from "./execute.js"
5
5
  import { EOL } from "os"
6
6
  import { displayFactBox, FactBoxOptions } from "./facts.js"
7
7
  import ProcessManager from "./process-manager.js"
8
- import type { Client } from "pg"
8
+ import type { Client } from "@medusajs/deps/pg"
9
+ import PackageManager from "./package-manager.js"
10
+ import { updatePackageVersions } from "./update-package-versions.js"
9
11
 
10
12
  const ADMIN_EMAIL = "admin@medusa-test.com"
11
13
  let STORE_CORS = "http://localhost:8000"
@@ -24,6 +26,7 @@ type PreparePluginOptions = {
24
26
  processManager: ProcessManager
25
27
  abortController?: AbortController
26
28
  verbose?: boolean
29
+ packageManager: PackageManager
27
30
  }
28
31
 
29
32
  type PrepareProjectOptions = {
@@ -42,6 +45,8 @@ type PrepareProjectOptions = {
42
45
  nextjsDirectory?: string
43
46
  client: Client | null
44
47
  verbose?: boolean
48
+ packageManager: PackageManager
49
+ version?: string
45
50
  }
46
51
 
47
52
  type PrepareOptions = PreparePluginOptions | PrepareProjectOptions
@@ -66,6 +71,7 @@ async function preparePlugin({
66
71
  processManager,
67
72
  abortController,
68
73
  verbose = false,
74
+ packageManager,
69
75
  }: PreparePluginOptions) {
70
76
  // initialize execution options
71
77
  const execOptions = {
@@ -98,20 +104,7 @@ async function preparePlugin({
98
104
  processManager,
99
105
  })
100
106
 
101
- await processManager.runProcess({
102
- process: async () => {
103
- try {
104
- await execute([`yarn`, execOptions], { verbose })
105
- } catch (e) {
106
- // yarn isn't available
107
- // use npm
108
- await execute([`npm install --legacy-peer-deps`, execOptions], {
109
- verbose,
110
- })
111
- }
112
- },
113
- ignoreERESOLVE: true,
114
- })
107
+ await packageManager.installDependencies(execOptions)
115
108
 
116
109
  factBoxOptions.interval = displayFactBox({
117
110
  ...factBoxOptions,
@@ -136,6 +129,8 @@ async function prepareProject({
136
129
  nextjsDirectory = "",
137
130
  client,
138
131
  verbose = false,
132
+ packageManager,
133
+ version,
139
134
  }: PrepareProjectOptions) {
140
135
  // initialize execution options
141
136
  const execOptions = {
@@ -167,6 +162,11 @@ async function prepareProject({
167
162
  // Update name
168
163
  packageJson.name = projectName
169
164
 
165
+ // Update medusa dependencies versions
166
+ if (version) {
167
+ updatePackageVersions(packageJson, version)
168
+ }
169
+
170
170
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
171
171
 
172
172
  // initialize the invite token to return
@@ -196,20 +196,7 @@ async function prepareProject({
196
196
  processManager,
197
197
  })
198
198
 
199
- await processManager.runProcess({
200
- process: async () => {
201
- try {
202
- await execute([`yarn`, execOptions], { verbose })
203
- } catch (e) {
204
- // yarn isn't available
205
- // use npm
206
- await execute([`npm install --legacy-peer-deps`, execOptions], {
207
- verbose,
208
- })
209
- }
210
- },
211
- ignoreERESOLVE: true,
212
- })
199
+ await packageManager.installDependencies(execOptions)
213
200
 
214
201
  factBoxOptions.interval = displayFactBox({
215
202
  ...factBoxOptions,
@@ -262,12 +249,6 @@ async function prepareProject({
262
249
  message: "Ran Migrations",
263
250
  })
264
251
 
265
- // create admin user
266
- factBoxOptions.interval = displayFactBox({
267
- ...factBoxOptions,
268
- title: "Creating an admin user...",
269
- })
270
-
271
252
  await processManager.runProcess({
272
253
  process: async () => {
273
254
  const proc = await execute(
@@ -283,11 +264,6 @@ async function prepareProject({
283
264
  },
284
265
  })
285
266
 
286
- factBoxOptions.interval = displayFactBox({
287
- ...factBoxOptions,
288
- message: "Created admin user",
289
- })
290
-
291
267
  // TODO for now we just seed the default data
292
268
  // we should add onboarding seeding again if it makes
293
269
  // since once we re-introduce the onboarding flow.
@@ -296,18 +272,7 @@ async function prepareProject({
296
272
  title: "Seeding database...",
297
273
  })
298
274
 
299
- await processManager.runProcess({
300
- process: async () => {
301
- try {
302
- await execute([`yarn seed`, execOptions], { verbose })
303
- } catch (e) {
304
- // yarn isn't available
305
- // use npm
306
- await execute([`npm run seed`, execOptions], { verbose })
307
- }
308
- },
309
- ignoreERESOLVE: true,
310
- })
275
+ await packageManager.runCommand("seed", execOptions)
311
276
 
312
277
  displayFactBox({
313
278
  ...factBoxOptions,
@@ -3,6 +3,7 @@ import path from "path"
3
3
  import createAbortController from "../create-abort-controller.js"
4
4
  import { FactBoxOptions } from "../facts.js"
5
5
  import ProcessManager from "../process-manager.js"
6
+ import PackageManager from "../package-manager.js"
6
7
 
7
8
  export interface ProjectOptions {
8
9
  repoUrl?: string
@@ -15,6 +16,7 @@ export interface ProjectOptions {
15
16
  withNextjsStarter?: boolean
16
17
  verbose?: boolean
17
18
  plugin?: boolean
19
+ version?: string
18
20
  }
19
21
 
20
22
  export interface ProjectCreator {
@@ -25,6 +27,7 @@ export interface ProjectCreator {
25
27
  export abstract class BaseProjectCreator {
26
28
  protected spinner: Ora
27
29
  protected processManager: ProcessManager
30
+ protected packageManager: PackageManager
28
31
  protected abortController: AbortController
29
32
  protected factBoxOptions: FactBoxOptions
30
33
  protected projectName: string
@@ -39,6 +42,7 @@ export abstract class BaseProjectCreator {
39
42
  ) {
40
43
  this.spinner = ora()
41
44
  this.processManager = new ProcessManager()
45
+ this.packageManager = new PackageManager(this.processManager)
42
46
  this.abortController = createAbortController(this.processManager)
43
47
  this.projectName = projectName
44
48
  const basePath =
@@ -72,6 +72,7 @@ export class PluginProjectCreator
72
72
  processManager: this.processManager,
73
73
  abortController: this.abortController,
74
74
  verbose: this.options.verbose,
75
+ packageManager: this.packageManager,
75
76
  })
76
77
  }
77
78
 
@@ -96,6 +96,7 @@ export class MedusaProjectCreator
96
96
  factBoxOptions: this.factBoxOptions,
97
97
  verbose: this.options.verbose,
98
98
  processManager: this.processManager,
99
+ version: this.options.version,
99
100
  })
100
101
  }
101
102
  } catch (e) {
@@ -153,6 +154,8 @@ export class MedusaProjectCreator
153
154
  nextjsDirectory: this.nextjsDirectory,
154
155
  client: this.client,
155
156
  verbose: this.options.verbose,
157
+ packageManager: this.packageManager,
158
+ version: this.options.version,
156
159
  })
157
160
  } finally {
158
161
  await this.client?.end()
@@ -214,18 +217,19 @@ export class MedusaProjectCreator
214
217
  }
215
218
 
216
219
  protected showSuccessMessage(): void {
220
+ const commandStr = this.packageManager.getCommandStr(`dev`)
217
221
  logMessage({
218
222
  message: boxen(
219
223
  chalk.green(
220
224
  `Change to the \`${
221
225
  this.projectName
222
- }\` directory to explore your Medusa project.${EOL}${EOL}Start your Medusa app again with the following command:${EOL}${EOL}yarn dev${EOL}${EOL}${
226
+ }\` directory to explore your Medusa project.${EOL}${EOL}Start your Medusa application again with the following command:${EOL}${EOL}${commandStr}${EOL}${EOL}${
223
227
  this.inviteToken
224
- ? `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}`
228
+ ? `After you start the Medusa application, you can create an admin user with the URL http://localhost:9000/app/invite?token=${this.inviteToken}&first_run=true${EOL}${EOL}`
225
229
  : ""
226
230
  }${
227
231
  this.nextjsDirectory?.length
228
- ? `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}`
232
+ ? `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}${commandStr}${EOL}${EOL}`
229
233
  : ""
230
234
  }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`
231
235
  ),
@@ -57,6 +57,16 @@ export class ProjectCreatorFactory {
57
57
  type: "warn",
58
58
  })
59
59
  askProjectName = true
60
+ } else if (args[0].includes(".")) {
61
+ // We don't allow projects to have a dot in the name, as this causes issues for
62
+ // for MikroORM path resolutions.
63
+ logMessage({
64
+ message: `Project names cannot contain a dot (.) character. Please enter a different ${
65
+ isPlugin ? "plugin" : "project"
66
+ } name.`,
67
+ type: "error",
68
+ })
69
+ askProjectName = true
60
70
  }
61
71
  }
62
72
 
@@ -80,6 +90,14 @@ async function askForProjectName(
80
90
  return slugify(input).toLowerCase()
81
91
  },
82
92
  validate: (input) => {
93
+ // We don't allow projects to have a dot in the name, as this causes issues for
94
+ // for MikroORM path resolutions.
95
+ if (input.includes(".")) {
96
+ return `Project names cannot contain a dot (.) character. Please enter a different ${
97
+ isPlugin ? "plugin" : "project"
98
+ } name.`
99
+ }
100
+
83
101
  if (!input.length) {
84
102
  return `Please enter a ${isPlugin ? "plugin" : "project"} name`
85
103
  }
@@ -0,0 +1,31 @@
1
+ import { readFileSync, writeFileSync } from "fs"
2
+
3
+ export function updatePackageVersions(
4
+ packageJsonOrPath: string | Record<string, any>,
5
+ version: string,
6
+ { applyChanges = false }: { applyChanges?: boolean } = {}
7
+ ) {
8
+ const packageJson =
9
+ typeof packageJsonOrPath === "string"
10
+ ? JSON.parse(readFileSync(packageJsonOrPath, "utf-8"))
11
+ : packageJsonOrPath
12
+
13
+ if (packageJson.dependencies) {
14
+ for (const dependency of Object.keys(packageJson.dependencies)) {
15
+ if (dependency.startsWith("@medusajs/")) {
16
+ packageJson.dependencies[dependency] = version
17
+ }
18
+ }
19
+ }
20
+ if (packageJson.devDependencies) {
21
+ for (const dependency of Object.keys(packageJson.devDependencies)) {
22
+ if (dependency.startsWith("@medusajs/")) {
23
+ packageJson.devDependencies[dependency] = version
24
+ }
25
+ }
26
+ }
27
+
28
+ if (applyChanges && typeof packageJsonOrPath === "string") {
29
+ writeFileSync(packageJsonOrPath, JSON.stringify(packageJson, null, 2))
30
+ }
31
+ }