@pradip1995/create-storefront-app 0.2.3 → 0.3.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/bin/create-storefront-app.js +141 -59
- package/lib/build-backend-package.js +54 -0
- package/lib/build-homepage-defaults.cjs +50 -0
- package/lib/deps.js +3 -1
- package/lib/docker-template-vars.js +32 -0
- package/lib/medusa-plugin-versions.json +55 -0
- package/lib/scaffold-backend.js +107 -0
- package/lib/scaffold-docker.js +82 -0
- package/lib/versions.js +4 -3
- package/package.json +3 -2
- package/templates/backend/.cursor/commands/seed-backend.md +16 -0
- package/templates/backend/.cursor/rules/medusa-backend.mdc +55 -0
- package/templates/backend/config/README.md +21 -0
- package/templates/backend/config/homepage-config.json +568 -0
- package/templates/backend/env.template +53 -0
- package/templates/backend/gitignore +8 -0
- package/templates/backend/medusa-config.full.ts +251 -0
- package/templates/backend/medusa-config.minimal.ts +141 -0
- package/templates/backend/scripts/build-dynamic-config-defaults.mjs +25 -0
- package/templates/backend/scripts/build-homepage-defaults.cjs +50 -0
- package/templates/backend/src/config/product-metadata-descriptors.ts +27 -0
- package/templates/backend/src/scripts/seed.ts +212 -0
- package/templates/backend/tsconfig.json +24 -0
- package/templates/docker/Makefile +86 -0
- package/templates/docker/backend/.dockerignore +8 -0
- package/templates/docker/backend/Dockerfile +30 -0
- package/templates/docker/data/README.md +12 -0
- package/templates/docker/data/dump.sql +3 -0
- package/templates/docker/docker/.env.example +36 -0
- package/templates/docker/docker/frontend.build.defaults +7 -0
- package/templates/docker/docker/gitignore +1 -0
- package/templates/docker/docker/postgres/01-create-postgres-role.sql +9 -0
- package/templates/docker/docker/postgres/docker-entrypoint-wrapper.sh +49 -0
- package/templates/docker/docker-compose.infra.yml +64 -0
- package/templates/docker/docker-compose.yml +138 -0
- package/templates/docker/storefront/.dockerignore +9 -0
- package/templates/docker/storefront/Dockerfile +53 -0
- package/templates/root/.cursor/commands/docker-dev.md +32 -0
- package/templates/root/.cursor/rules/monorepo-layout.mdc +55 -0
- package/templates/shared/.cursor/commands/change-theme-colors.md +1 -1
- package/templates/shared/.cursor/commands/fix-segment-issue.md +2 -2
- package/templates/shared/.cursor/commands/rebuild-storefront.md +1 -1
- package/templates/shared/.cursor/rules/customize-theme.mdc +1 -1
- package/templates/shared/.cursor/rules/storefront-architecture.mdc +3 -2
- package/templates/shared/.cursor/skills/fix-segment-issues/SKILL.md +1 -1
- package/templates/shared/README.md +100 -0
- package/templates/shared/root-gitignore +6 -0
- package/templates/shared/storefront-only-README.md +25 -0
|
@@ -4,6 +4,8 @@ import { join, dirname, resolve } from "path"
|
|
|
4
4
|
import { fileURLToPath } from "url"
|
|
5
5
|
import { execSync } from "child_process"
|
|
6
6
|
import { buildDependencies } from "../lib/deps.js"
|
|
7
|
+
import { scaffoldBackend } from "../lib/scaffold-backend.js"
|
|
8
|
+
import { scaffoldDocker } from "../lib/scaffold-docker.js"
|
|
7
9
|
|
|
8
10
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
9
11
|
const PKG_ROOT = join(__dirname, "..")
|
|
@@ -19,6 +21,7 @@ function parseArgs(argv) {
|
|
|
19
21
|
port: 8000,
|
|
20
22
|
install: true,
|
|
21
23
|
noPrompt: false,
|
|
24
|
+
withBackend: true,
|
|
22
25
|
}
|
|
23
26
|
const positional = []
|
|
24
27
|
|
|
@@ -32,6 +35,7 @@ function parseArgs(argv) {
|
|
|
32
35
|
else if (arg === "--default-region" && argv[i + 1]) args.defaultRegion = argv[++i]
|
|
33
36
|
else if (arg === "--port" && argv[i + 1]) args.port = Number(argv[++i])
|
|
34
37
|
else if (arg === "--no-install") args.install = false
|
|
38
|
+
else if (arg === "--no-backend") args.withBackend = false
|
|
35
39
|
else if (arg === "--no-prompt" || arg === "-y") args.noPrompt = true
|
|
36
40
|
else if (arg === "--help" || arg === "-h") args.help = true
|
|
37
41
|
else if (!arg.startsWith("-")) positional.push(arg)
|
|
@@ -43,26 +47,34 @@ function parseArgs(argv) {
|
|
|
43
47
|
|
|
44
48
|
function printHelp() {
|
|
45
49
|
console.log(`
|
|
46
|
-
create-storefront-app — Scaffold
|
|
50
|
+
create-storefront-app — Scaffold Medusa backend + segment-based storefront
|
|
47
51
|
|
|
48
52
|
Usage:
|
|
49
53
|
npx @pradip1995/create-storefront-app <project-name> [options]
|
|
50
54
|
|
|
55
|
+
Creates:
|
|
56
|
+
<project-name>/
|
|
57
|
+
backend/ Medusa v2 (medusa dev, medusa build, seed)
|
|
58
|
+
storefront/ Segment storefront (storefront-build + Next.js)
|
|
59
|
+
docker-compose.yml, Makefile, docker/ (when backend is included)
|
|
60
|
+
|
|
61
|
+
Requires: Node 20+, npm. Docker optional (see README after scaffold).
|
|
62
|
+
|
|
51
63
|
Options:
|
|
52
|
-
--preset <full|minimal> Page/segment preset (default: full)
|
|
64
|
+
--preset <full|minimal> Page/segment + plugin preset (default: full)
|
|
65
|
+
--no-backend Storefront only (no backend/ folder)
|
|
53
66
|
--dir <path> Parent directory (default: cwd)
|
|
54
67
|
--backend-url <url> Medusa backend URL (default: http://localhost:9000)
|
|
55
|
-
--publishable-key <key>
|
|
68
|
+
--publishable-key <key> Storefront publishable key placeholder (default: pk_test)
|
|
56
69
|
--base-url <url> Storefront URL (default: http://localhost:8000)
|
|
57
70
|
--default-region <code> Default country code (default: in)
|
|
58
|
-
--port <number>
|
|
71
|
+
--port <number> Storefront dev port (default: 8000)
|
|
59
72
|
--no-install Skip npm install after scaffold
|
|
60
|
-
--no-prompt, -y Non-interactive
|
|
73
|
+
--no-prompt, -y Non-interactive
|
|
61
74
|
|
|
62
75
|
Examples:
|
|
63
76
|
npx @pradip1995/create-storefront-app my-shop
|
|
64
|
-
npx @pradip1995/create-storefront-app my-shop --preset minimal
|
|
65
|
-
--publishable-key pk_xxx --backend-url http://localhost:9000
|
|
77
|
+
npx @pradip1995/create-storefront-app my-shop --preset minimal --no-install
|
|
66
78
|
`)
|
|
67
79
|
}
|
|
68
80
|
|
|
@@ -74,74 +86,54 @@ function applyTemplate(content, vars) {
|
|
|
74
86
|
return content.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? "")
|
|
75
87
|
}
|
|
76
88
|
|
|
77
|
-
function
|
|
78
|
-
const projectRoot = join(args.dir, args.name)
|
|
79
|
-
if (existsSync(projectRoot)) {
|
|
80
|
-
console.error(`Error: ${projectRoot} already exists`)
|
|
81
|
-
process.exit(1)
|
|
82
|
-
}
|
|
83
|
-
|
|
89
|
+
function scaffoldStorefront(storefrontRoot, args, { flat = false } = {}) {
|
|
84
90
|
const presetDir = join(PKG_ROOT, "templates", args.preset)
|
|
85
|
-
if (!existsSync(join(presetDir, "pages.config.json"))) {
|
|
86
|
-
console.error(`Unknown preset "${args.preset}". Use full or minimal.`)
|
|
87
|
-
process.exit(1)
|
|
88
|
-
}
|
|
89
91
|
|
|
90
|
-
mkdirSync(
|
|
91
|
-
mkdirSync(join(
|
|
92
|
+
mkdirSync(storefrontRoot, { recursive: true })
|
|
93
|
+
mkdirSync(join(storefrontRoot, "public"), { recursive: true })
|
|
92
94
|
|
|
93
|
-
const pagesConfig = JSON.parse(
|
|
94
|
-
|
|
95
|
-
)
|
|
96
|
-
writeJson(join(projectRoot, "pages.config.json"), pagesConfig)
|
|
95
|
+
const pagesConfig = JSON.parse(readFileSync(join(presetDir, "pages.config.json"), "utf8"))
|
|
96
|
+
writeJson(join(storefrontRoot, "pages.config.json"), pagesConfig)
|
|
97
97
|
|
|
98
98
|
const storefrontConfig = JSON.parse(
|
|
99
99
|
readFileSync(join(PKG_ROOT, "templates/shared/storefront.config.json"), "utf8")
|
|
100
100
|
)
|
|
101
101
|
storefrontConfig.defaultCountryCode = args.defaultRegion
|
|
102
|
-
writeJson(join(
|
|
102
|
+
writeJson(join(storefrontRoot, "storefront.config.json"), storefrontConfig)
|
|
103
103
|
|
|
104
|
-
cpSync(join(PKG_ROOT, "templates/shared/public"), join(
|
|
104
|
+
cpSync(join(PKG_ROOT, "templates/shared/public"), join(storefrontRoot, "public"), {
|
|
105
105
|
recursive: true,
|
|
106
106
|
})
|
|
107
107
|
|
|
108
108
|
const cursorTemplate = join(PKG_ROOT, "templates/shared/.cursor")
|
|
109
109
|
if (existsSync(cursorTemplate)) {
|
|
110
|
-
cpSync(cursorTemplate, join(
|
|
110
|
+
cpSync(cursorTemplate, join(storefrontRoot, ".cursor"), { recursive: true })
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
const themeOverridesTemplate = join(PKG_ROOT, "templates/shared/theme-overrides.css")
|
|
114
114
|
if (existsSync(themeOverridesTemplate)) {
|
|
115
|
-
writeFileSync(
|
|
116
|
-
join(projectRoot, "theme-overrides.css"),
|
|
117
|
-
readFileSync(themeOverridesTemplate, "utf8")
|
|
118
|
-
)
|
|
115
|
+
writeFileSync(join(storefrontRoot, "theme-overrides.css"), readFileSync(themeOverridesTemplate, "utf8"))
|
|
119
116
|
}
|
|
120
117
|
|
|
121
118
|
writeFileSync(
|
|
122
|
-
join(
|
|
119
|
+
join(storefrontRoot, ".gitignore"),
|
|
123
120
|
readFileSync(join(PKG_ROOT, "templates/shared/gitignore"), "utf8")
|
|
124
121
|
)
|
|
125
122
|
writeFileSync(
|
|
126
|
-
join(
|
|
123
|
+
join(storefrontRoot, ".npmrc"),
|
|
127
124
|
readFileSync(join(PKG_ROOT, "templates/shared/npmrc"), "utf8")
|
|
128
125
|
)
|
|
129
126
|
|
|
130
|
-
const envTemplate = readFileSync(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
BASE_URL: args.baseUrl,
|
|
139
|
-
DEFAULT_REGION: args.defaultRegion,
|
|
140
|
-
PUBLISHABLE_KEY: args.publishableKey,
|
|
141
|
-
})
|
|
142
|
-
)
|
|
127
|
+
const envTemplate = readFileSync(join(PKG_ROOT, "templates/shared/env.example"), "utf8")
|
|
128
|
+
const envVars = {
|
|
129
|
+
BACKEND_URL: args.backendUrl,
|
|
130
|
+
BASE_URL: args.baseUrl,
|
|
131
|
+
DEFAULT_REGION: args.defaultRegion,
|
|
132
|
+
PUBLISHABLE_KEY: args.publishableKey,
|
|
133
|
+
}
|
|
134
|
+
writeFileSync(join(storefrontRoot, ".env.local"), applyTemplate(envTemplate, envVars))
|
|
143
135
|
writeFileSync(
|
|
144
|
-
join(
|
|
136
|
+
join(storefrontRoot, ".env.example"),
|
|
145
137
|
applyTemplate(envTemplate, {
|
|
146
138
|
BACKEND_URL: "http://localhost:9000",
|
|
147
139
|
BASE_URL: "http://localhost:8000",
|
|
@@ -151,7 +143,7 @@ function scaffoldProject(args) {
|
|
|
151
143
|
)
|
|
152
144
|
|
|
153
145
|
const pkg = {
|
|
154
|
-
name: args.name
|
|
146
|
+
name: flat ? args.name : `${args.name}-storefront`,
|
|
155
147
|
private: true,
|
|
156
148
|
scripts: {
|
|
157
149
|
"storefront:build": "storefront-build",
|
|
@@ -161,7 +153,75 @@ function scaffoldProject(args) {
|
|
|
161
153
|
},
|
|
162
154
|
dependencies: buildDependencies(pagesConfig),
|
|
163
155
|
}
|
|
164
|
-
writeJson(join(
|
|
156
|
+
writeJson(join(storefrontRoot, "package.json"), pkg)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function scaffoldProject(args) {
|
|
160
|
+
const projectRoot = join(args.dir, args.name)
|
|
161
|
+
if (existsSync(projectRoot)) {
|
|
162
|
+
console.error(`Error: ${projectRoot} already exists`)
|
|
163
|
+
process.exit(1)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const presetDir = join(PKG_ROOT, "templates", args.preset)
|
|
167
|
+
if (!existsSync(join(presetDir, "pages.config.json"))) {
|
|
168
|
+
console.error(`Unknown preset "${args.preset}". Use full or minimal.`)
|
|
169
|
+
process.exit(1)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
mkdirSync(projectRoot, { recursive: true })
|
|
173
|
+
|
|
174
|
+
if (args.withBackend) {
|
|
175
|
+
writeFileSync(
|
|
176
|
+
join(projectRoot, ".gitignore"),
|
|
177
|
+
readFileSync(join(PKG_ROOT, "templates/shared/root-gitignore"), "utf8")
|
|
178
|
+
)
|
|
179
|
+
writeFileSync(
|
|
180
|
+
join(projectRoot, "README.md"),
|
|
181
|
+
applyTemplate(readFileSync(join(PKG_ROOT, "templates/shared/README.md"), "utf8"), {
|
|
182
|
+
PROJECT_NAME: args.name,
|
|
183
|
+
BASE_URL: args.baseUrl,
|
|
184
|
+
BACKEND_URL: args.backendUrl,
|
|
185
|
+
DEFAULT_REGION: args.defaultRegion,
|
|
186
|
+
})
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
const rootPkg = {
|
|
190
|
+
name: args.name,
|
|
191
|
+
private: true,
|
|
192
|
+
scripts: {
|
|
193
|
+
"dev:storefront": "npm run dev --prefix storefront",
|
|
194
|
+
"build:storefront": "npm run build --prefix storefront",
|
|
195
|
+
"storefront:build": "npm run storefront:build --prefix storefront",
|
|
196
|
+
"dev:backend": "npm run dev --prefix backend",
|
|
197
|
+
"build:backend": "npm run build --prefix backend",
|
|
198
|
+
seed: "npm run seed --prefix backend",
|
|
199
|
+
},
|
|
200
|
+
}
|
|
201
|
+
writeJson(join(projectRoot, "package.json"), rootPkg)
|
|
202
|
+
|
|
203
|
+
const rootCursor = join(PKG_ROOT, "templates/root/.cursor")
|
|
204
|
+
if (existsSync(rootCursor)) {
|
|
205
|
+
cpSync(rootCursor, join(projectRoot, ".cursor"), { recursive: true })
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
scaffoldStorefront(join(projectRoot, "storefront"), args)
|
|
209
|
+
scaffoldBackend(join(projectRoot, "backend"), args)
|
|
210
|
+
scaffoldDocker(projectRoot, args)
|
|
211
|
+
} else {
|
|
212
|
+
scaffoldStorefront(projectRoot, args, { flat: true })
|
|
213
|
+
writeFileSync(
|
|
214
|
+
join(projectRoot, "README.md"),
|
|
215
|
+
applyTemplate(
|
|
216
|
+
readFileSync(join(PKG_ROOT, "templates/shared/storefront-only-README.md"), "utf8"),
|
|
217
|
+
{
|
|
218
|
+
PROJECT_NAME: args.name,
|
|
219
|
+
BASE_URL: args.baseUrl,
|
|
220
|
+
DEFAULT_REGION: args.defaultRegion,
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
}
|
|
165
225
|
|
|
166
226
|
return projectRoot
|
|
167
227
|
}
|
|
@@ -174,30 +234,52 @@ function main() {
|
|
|
174
234
|
}
|
|
175
235
|
|
|
176
236
|
console.log(
|
|
177
|
-
`Creating
|
|
237
|
+
`Creating "${args.name}" (preset: ${args.preset}${args.withBackend ? ", with Medusa backend" : ""})...`
|
|
178
238
|
)
|
|
179
239
|
|
|
180
240
|
const projectRoot = scaffoldProject(args)
|
|
181
241
|
|
|
182
242
|
if (args.install) {
|
|
183
243
|
console.log("\nInstalling dependencies...")
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
244
|
+
const dirs = args.withBackend
|
|
245
|
+
? [join(projectRoot, "backend"), join(projectRoot, "storefront")]
|
|
246
|
+
: [projectRoot]
|
|
247
|
+
for (const dir of dirs) {
|
|
248
|
+
try {
|
|
249
|
+
execSync("npm install", { cwd: dir, stdio: "inherit" })
|
|
250
|
+
} catch {
|
|
251
|
+
console.warn(`Warning: npm install failed in ${dir}`)
|
|
252
|
+
}
|
|
188
253
|
}
|
|
189
254
|
}
|
|
190
255
|
|
|
191
|
-
|
|
192
|
-
|
|
256
|
+
const nextSteps = args.withBackend
|
|
257
|
+
? `
|
|
258
|
+
Next steps:
|
|
259
|
+
cd ${args.name}
|
|
260
|
+
|
|
261
|
+
Docker (full stack):
|
|
262
|
+
make up && make migrate && make seed && make admin-create
|
|
193
263
|
|
|
264
|
+
Local Node (Docker infra):
|
|
265
|
+
make up-infra
|
|
266
|
+
npm run dev:backend # terminal 1
|
|
267
|
+
npm run seed && npm run dev:storefront # terminal 2
|
|
268
|
+
|
|
269
|
+
Fully local:
|
|
270
|
+
cd backend && npm run dev # set DATABASE_URL in backend/.env
|
|
271
|
+
cd backend && npm run seed
|
|
272
|
+
cd ../storefront && npm run dev
|
|
273
|
+
|
|
274
|
+
See README.md, Makefile, and .cursor/ guides.
|
|
275
|
+
`
|
|
276
|
+
: `
|
|
194
277
|
Next steps:
|
|
195
278
|
cd ${args.name}
|
|
196
279
|
npm run dev
|
|
280
|
+
`
|
|
197
281
|
|
|
198
|
-
|
|
199
|
-
See .cursor/commands/ for theme, sections, and troubleshooting workflows.
|
|
200
|
-
`)
|
|
282
|
+
console.log(`Done! Created ${projectRoot}${nextSteps}`)
|
|
201
283
|
}
|
|
202
284
|
|
|
203
285
|
main()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFileSync } from "fs"
|
|
2
|
+
import { dirname, join } from "path"
|
|
3
|
+
import { fileURLToPath } from "url"
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
6
|
+
const VERSIONS = JSON.parse(
|
|
7
|
+
readFileSync(join(__dirname, "medusa-plugin-versions.json"), "utf8")
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
/** Build backend/package.json dependencies from medusa-plugin-versions.json */
|
|
11
|
+
export function buildBackendDependencies(preset = "full") {
|
|
12
|
+
const pluginKeys =
|
|
13
|
+
preset === "minimal" ? VERSIONS.minimalPlugins : VERSIONS.fullPlugins
|
|
14
|
+
const plugins = {}
|
|
15
|
+
for (const key of pluginKeys) {
|
|
16
|
+
if (VERSIONS.plugins[key]) plugins[key] = VERSIONS.plugins[key]
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
medusa: { ...VERSIONS.medusa },
|
|
20
|
+
plugins,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function buildBackendPackageJson(preset = "full", projectName = "backend") {
|
|
25
|
+
const { medusa, plugins } = buildBackendDependencies(preset)
|
|
26
|
+
return {
|
|
27
|
+
name: `${projectName}-backend`,
|
|
28
|
+
version: "0.0.1",
|
|
29
|
+
private: true,
|
|
30
|
+
description: "Medusa backend for segment-based storefront",
|
|
31
|
+
license: "MIT",
|
|
32
|
+
scripts: {
|
|
33
|
+
dev: "medusa develop",
|
|
34
|
+
build:
|
|
35
|
+
"TS_NODE_COMPILER=typescript TS_NODE_TRANSPILE_ONLY=true MEDUSA_ADMIN_DISABLE_SW=true medusa build",
|
|
36
|
+
start: "medusa start",
|
|
37
|
+
seed: "medusa exec ./src/scripts/seed.ts",
|
|
38
|
+
"dynamic-config:defaults": "node scripts/build-dynamic-config-defaults.mjs",
|
|
39
|
+
},
|
|
40
|
+
dependencies: {
|
|
41
|
+
...medusa,
|
|
42
|
+
...plugins,
|
|
43
|
+
},
|
|
44
|
+
devDependencies: {
|
|
45
|
+
"@types/node": "^20.12.11",
|
|
46
|
+
typescript: "^5.6.2",
|
|
47
|
+
},
|
|
48
|
+
engines: {
|
|
49
|
+
node: ">=20",
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { VERSIONS }
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build initial homepage-config values from schema structure defaultValue fields.
|
|
3
|
+
* Used by backend scaffold and `npm run dynamic-config:defaults`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
function buildDefaultsFromStructure(fields) {
|
|
7
|
+
const result = {}
|
|
8
|
+
for (const field of fields) {
|
|
9
|
+
const value = buildDefaultForField(field)
|
|
10
|
+
if (value !== undefined) {
|
|
11
|
+
result[field.id] = value
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return result
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function buildDefaultForField(field) {
|
|
18
|
+
if (field.defaultValue !== undefined) {
|
|
19
|
+
return field.defaultValue
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (field.type === "object" && field.children?.length) {
|
|
23
|
+
const nested = buildDefaultsFromStructure(field.children)
|
|
24
|
+
return Object.keys(nested).length > 0 ? nested : undefined
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (field.type === "array" && field.children?.length) {
|
|
28
|
+
const [itemSchema] = field.children
|
|
29
|
+
if (itemSchema?.type === "object" && itemSchema.children?.length) {
|
|
30
|
+
const itemDefaults = buildDefaultsFromStructure(itemSchema.children)
|
|
31
|
+
if (Object.keys(itemDefaults).length > 0) {
|
|
32
|
+
return [{ [itemSchema.id]: itemDefaults }]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return undefined
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return undefined
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function buildHomepageConfigDefaults(configSchema) {
|
|
42
|
+
if (!configSchema?.structure?.length) return {}
|
|
43
|
+
return buildDefaultsFromStructure(configSchema.structure)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
buildDefaultsFromStructure,
|
|
48
|
+
buildDefaultForField,
|
|
49
|
+
buildHomepageConfigDefaults,
|
|
50
|
+
}
|
package/lib/deps.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
COMMERCE_CORE_VERSION,
|
|
3
3
|
FRAMEWORK_VERSION,
|
|
4
|
+
FRAMEWORK_COMPILER_VERSION,
|
|
4
5
|
COMPONENTS_VERSION,
|
|
5
6
|
FRAMEWORK_PACKAGES,
|
|
6
7
|
RUNTIME_DEPS,
|
|
@@ -68,7 +69,8 @@ export function buildDependencies(pages) {
|
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
for (const name of FRAMEWORK_PACKAGES) {
|
|
71
|
-
deps[name] =
|
|
72
|
+
deps[name] =
|
|
73
|
+
name === "@pradip1995/framework-compiler" ? FRAMEWORK_COMPILER_VERSION : FRAMEWORK_VERSION
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
for (const name of [
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Derive Docker / Postgres identifiers from project name */
|
|
2
|
+
export function sanitizeProjectSlug(name) {
|
|
3
|
+
const slug = String(name)
|
|
4
|
+
.toLowerCase()
|
|
5
|
+
.replace(/[^a-z0-9]+/g, "")
|
|
6
|
+
.slice(0, 24)
|
|
7
|
+
return slug || "shop"
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Shared template vars for backend env, docker-compose, Makefile */
|
|
11
|
+
export function buildDockerTemplateVars(args) {
|
|
12
|
+
const slug = sanitizeProjectSlug(args.name)
|
|
13
|
+
const postgresUser = slug
|
|
14
|
+
const postgresPassword = `${slug}_secret`
|
|
15
|
+
const postgresDb = `${slug}_medusa`
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
PROJECT_NAME: args.name,
|
|
19
|
+
CONTAINER_PREFIX: slug,
|
|
20
|
+
POSTGRES_USER: postgresUser,
|
|
21
|
+
POSTGRES_PASSWORD: postgresPassword,
|
|
22
|
+
POSTGRES_DB: postgresDb,
|
|
23
|
+
BACKEND_URL: args.backendUrl,
|
|
24
|
+
BASE_URL: args.baseUrl,
|
|
25
|
+
DEFAULT_REGION: args.defaultRegion,
|
|
26
|
+
DATABASE_URL: `postgres://${postgresUser}:${postgresPassword}@localhost:5432/${postgresDb}?sslmode=disable`,
|
|
27
|
+
DATABASE_URL_DOCKER: `postgres://${postgresUser}:${postgresPassword}@postgres:5432/${postgresDb}?sslmode=disable`,
|
|
28
|
+
PUBLISHABLE_KEY: args.publishableKey || "pk_test",
|
|
29
|
+
ADMIN_EMAIL: `admin@${slug}.local`,
|
|
30
|
+
ADMIN_PASSWORD: `${slug.charAt(0).toUpperCase()}${slug.slice(1)}@123`,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"medusa": {
|
|
3
|
+
"@medusajs/admin-sdk": "2.12.3",
|
|
4
|
+
"@medusajs/auth-google": "2.12.3",
|
|
5
|
+
"@medusajs/cli": "2.12.3",
|
|
6
|
+
"@medusajs/framework": "2.12.3",
|
|
7
|
+
"@medusajs/medusa": "2.12.3",
|
|
8
|
+
"@medusajs/test-utils": "2.12.3"
|
|
9
|
+
},
|
|
10
|
+
"plugins": {
|
|
11
|
+
"medusa-product-helper": "0.0.73",
|
|
12
|
+
"medusa-dynamic-metadata": "0.0.7",
|
|
13
|
+
"medusa-plugin-dynamic-config": "^0.0.25",
|
|
14
|
+
"medusa-review-rating": "^0.0.38",
|
|
15
|
+
"medusa-contact-us": "^0.0.26",
|
|
16
|
+
"customer-registration": "^0.0.124",
|
|
17
|
+
"stock-monitoring": "^0.0.5",
|
|
18
|
+
"medusa-invoice-sbl": "^0.0.11",
|
|
19
|
+
"order-management": "^0.0.78",
|
|
20
|
+
"medusa-shiprocket-fulfillment-sbl": "0.0.28",
|
|
21
|
+
"medusa-notification-token-management": "^0.0.1",
|
|
22
|
+
"medusa-customer-file-upload": "0.0.1",
|
|
23
|
+
"medusa-analytics": "0.0.24",
|
|
24
|
+
"medusa-export": "^0.0.5",
|
|
25
|
+
"medusa-payment-provider": "0.0.1",
|
|
26
|
+
"@tsc_tech/medusa-plugin-smtp": "^0.0.3",
|
|
27
|
+
"medusa-twilio-sms": "^2.0.2",
|
|
28
|
+
"medusa-notification-provider": "^0.0.2"
|
|
29
|
+
},
|
|
30
|
+
"minimalPlugins": [
|
|
31
|
+
"medusa-product-helper",
|
|
32
|
+
"medusa-dynamic-metadata",
|
|
33
|
+
"medusa-plugin-dynamic-config",
|
|
34
|
+
"medusa-review-rating",
|
|
35
|
+
"medusa-contact-us",
|
|
36
|
+
"customer-registration"
|
|
37
|
+
],
|
|
38
|
+
"fullPlugins": [
|
|
39
|
+
"medusa-product-helper",
|
|
40
|
+
"stock-monitoring",
|
|
41
|
+
"medusa-invoice-sbl",
|
|
42
|
+
"medusa-dynamic-metadata",
|
|
43
|
+
"medusa-review-rating",
|
|
44
|
+
"medusa-plugin-dynamic-config",
|
|
45
|
+
"medusa-contact-us",
|
|
46
|
+
"order-management",
|
|
47
|
+
"customer-registration",
|
|
48
|
+
"medusa-shiprocket-fulfillment-sbl",
|
|
49
|
+
"medusa-notification-token-management",
|
|
50
|
+
"medusa-customer-file-upload",
|
|
51
|
+
"medusa-analytics",
|
|
52
|
+
"medusa-export",
|
|
53
|
+
"medusa-payment-provider"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"
|
|
2
|
+
import { join, dirname } from "path"
|
|
3
|
+
import { fileURLToPath } from "url"
|
|
4
|
+
import { buildBackendPackageJson, VERSIONS } from "./build-backend-package.js"
|
|
5
|
+
import { buildDockerTemplateVars } from "./docker-template-vars.js"
|
|
6
|
+
import { createRequire } from "module"
|
|
7
|
+
|
|
8
|
+
const require = createRequire(import.meta.url)
|
|
9
|
+
const { buildHomepageConfigDefaults } = require("./build-homepage-defaults.cjs")
|
|
10
|
+
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
12
|
+
const PKG_ROOT = join(__dirname, "..")
|
|
13
|
+
const BACKEND_TEMPLATE = join(PKG_ROOT, "templates", "backend")
|
|
14
|
+
|
|
15
|
+
const REGION_CURRENCY = {
|
|
16
|
+
in: { currency: "inr", name: "India" },
|
|
17
|
+
us: { currency: "usd", name: "United States" },
|
|
18
|
+
gb: { currency: "gbp", name: "United Kingdom" },
|
|
19
|
+
eu: { currency: "eur", name: "Europe" },
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function applyTemplate(content, vars) {
|
|
23
|
+
return content.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? "")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function regionMeta(defaultRegion) {
|
|
27
|
+
return (
|
|
28
|
+
REGION_CURRENCY[defaultRegion] || {
|
|
29
|
+
currency: defaultRegion.length === 2 ? defaultRegion : "usd",
|
|
30
|
+
name: defaultRegion.toUpperCase(),
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function scaffoldBackend(backendRoot, args) {
|
|
36
|
+
const { preset, name, backendUrl, baseUrl, defaultRegion } = args
|
|
37
|
+
const meta = regionMeta(defaultRegion)
|
|
38
|
+
const dockerVars = buildDockerTemplateVars(args)
|
|
39
|
+
const templateVars = {
|
|
40
|
+
PROJECT_NAME: name,
|
|
41
|
+
BACKEND_URL: backendUrl,
|
|
42
|
+
BASE_URL: baseUrl,
|
|
43
|
+
DEFAULT_REGION: defaultRegion,
|
|
44
|
+
DEFAULT_CURRENCY: meta.currency,
|
|
45
|
+
DEFAULT_REGION_NAME: meta.name,
|
|
46
|
+
POSTGRES_USER: dockerVars.POSTGRES_USER,
|
|
47
|
+
POSTGRES_PASSWORD: dockerVars.POSTGRES_PASSWORD,
|
|
48
|
+
POSTGRES_DB: dockerVars.POSTGRES_DB,
|
|
49
|
+
DATABASE_URL: dockerVars.DATABASE_URL,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
mkdirSync(backendRoot, { recursive: true })
|
|
53
|
+
|
|
54
|
+
const medusaConfigSrc =
|
|
55
|
+
preset === "minimal"
|
|
56
|
+
? join(BACKEND_TEMPLATE, "medusa-config.minimal.ts")
|
|
57
|
+
: join(BACKEND_TEMPLATE, "medusa-config.full.ts")
|
|
58
|
+
writeFileSync(join(backendRoot, "medusa-config.ts"), readFileSync(medusaConfigSrc, "utf8"))
|
|
59
|
+
|
|
60
|
+
cpSync(join(BACKEND_TEMPLATE, "tsconfig.json"), join(backendRoot, "tsconfig.json"))
|
|
61
|
+
cpSync(join(BACKEND_TEMPLATE, "gitignore"), join(backendRoot, ".gitignore"))
|
|
62
|
+
cpSync(join(PKG_ROOT, "templates/shared/npmrc"), join(backendRoot, ".npmrc"))
|
|
63
|
+
cpSync(join(BACKEND_TEMPLATE, "config"), join(backendRoot, "config"), { recursive: true })
|
|
64
|
+
cpSync(join(BACKEND_TEMPLATE, "src"), join(backendRoot, "src"), { recursive: true })
|
|
65
|
+
cpSync(join(BACKEND_TEMPLATE, "scripts"), join(backendRoot, "scripts"), { recursive: true })
|
|
66
|
+
|
|
67
|
+
const homepageSchema = JSON.parse(
|
|
68
|
+
readFileSync(join(backendRoot, "config/homepage-config.json"), "utf8")
|
|
69
|
+
)
|
|
70
|
+
writeFileSync(
|
|
71
|
+
join(backendRoot, "config/homepage-config.defaults.json"),
|
|
72
|
+
`${JSON.stringify(buildHomepageConfigDefaults(homepageSchema), null, 2)}\n`
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
writeFileSync(
|
|
76
|
+
join(backendRoot, "config", "medusa-plugin-versions.json"),
|
|
77
|
+
JSON.stringify(VERSIONS, null, 2) + "\n"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
const seedContent = applyTemplate(
|
|
81
|
+
readFileSync(join(BACKEND_TEMPLATE, "src/scripts/seed.ts"), "utf8"),
|
|
82
|
+
templateVars
|
|
83
|
+
)
|
|
84
|
+
mkdirSync(join(backendRoot, "src/scripts"), { recursive: true })
|
|
85
|
+
writeFileSync(join(backendRoot, "src/scripts/seed.ts"), seedContent)
|
|
86
|
+
|
|
87
|
+
writeFileSync(
|
|
88
|
+
join(backendRoot, ".env.template"),
|
|
89
|
+
applyTemplate(readFileSync(join(BACKEND_TEMPLATE, "env.template"), "utf8"), templateVars)
|
|
90
|
+
)
|
|
91
|
+
writeFileSync(
|
|
92
|
+
join(backendRoot, ".env"),
|
|
93
|
+
applyTemplate(readFileSync(join(BACKEND_TEMPLATE, "env.template"), "utf8"), templateVars)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
writeFileSync(
|
|
97
|
+
join(backendRoot, "package.json"),
|
|
98
|
+
JSON.stringify(buildBackendPackageJson(preset, name), null, 2) + "\n"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
const backendCursor = join(BACKEND_TEMPLATE, ".cursor")
|
|
102
|
+
if (existsSync(backendCursor)) {
|
|
103
|
+
cpSync(backendCursor, join(backendRoot, ".cursor"), { recursive: true })
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return backendRoot
|
|
107
|
+
}
|