@pradip1995/create-storefront-app 0.2.2 → 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 +149 -53
- 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 +28 -0
- package/templates/shared/.cursor/commands/fix-segment-issue.md +56 -0
- package/templates/shared/.cursor/commands/rebuild-storefront.md +19 -0
- package/templates/shared/.cursor/commands/update-home-sections.md +50 -0
- package/templates/shared/.cursor/rules/customize-sections.mdc +49 -0
- package/templates/shared/.cursor/rules/customize-theme.mdc +57 -0
- package/templates/shared/.cursor/rules/storefront-architecture.mdc +41 -0
- package/templates/shared/.cursor/skills/customize-storefront-theme/SKILL.md +47 -0
- package/templates/shared/.cursor/skills/fix-segment-issues/SKILL.md +68 -0
- package/templates/shared/.cursor/skills/update-storefront-sections/SKILL.md +52 -0
- package/templates/shared/README.md +100 -0
- package/templates/shared/root-gitignore +6 -0
- package/templates/shared/storefront-only-README.md +25 -0
- package/templates/shared/theme-overrides.css +16 -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,61 +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
|
+
const cursorTemplate = join(PKG_ROOT, "templates/shared/.cursor")
|
|
109
|
+
if (existsSync(cursorTemplate)) {
|
|
110
|
+
cpSync(cursorTemplate, join(storefrontRoot, ".cursor"), { recursive: true })
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const themeOverridesTemplate = join(PKG_ROOT, "templates/shared/theme-overrides.css")
|
|
114
|
+
if (existsSync(themeOverridesTemplate)) {
|
|
115
|
+
writeFileSync(join(storefrontRoot, "theme-overrides.css"), readFileSync(themeOverridesTemplate, "utf8"))
|
|
116
|
+
}
|
|
117
|
+
|
|
108
118
|
writeFileSync(
|
|
109
|
-
join(
|
|
119
|
+
join(storefrontRoot, ".gitignore"),
|
|
110
120
|
readFileSync(join(PKG_ROOT, "templates/shared/gitignore"), "utf8")
|
|
111
121
|
)
|
|
112
122
|
writeFileSync(
|
|
113
|
-
join(
|
|
123
|
+
join(storefrontRoot, ".npmrc"),
|
|
114
124
|
readFileSync(join(PKG_ROOT, "templates/shared/npmrc"), "utf8")
|
|
115
125
|
)
|
|
116
126
|
|
|
117
|
-
const envTemplate = readFileSync(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
BASE_URL: args.baseUrl,
|
|
126
|
-
DEFAULT_REGION: args.defaultRegion,
|
|
127
|
-
PUBLISHABLE_KEY: args.publishableKey,
|
|
128
|
-
})
|
|
129
|
-
)
|
|
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))
|
|
130
135
|
writeFileSync(
|
|
131
|
-
join(
|
|
136
|
+
join(storefrontRoot, ".env.example"),
|
|
132
137
|
applyTemplate(envTemplate, {
|
|
133
138
|
BACKEND_URL: "http://localhost:9000",
|
|
134
139
|
BASE_URL: "http://localhost:8000",
|
|
@@ -138,7 +143,7 @@ function scaffoldProject(args) {
|
|
|
138
143
|
)
|
|
139
144
|
|
|
140
145
|
const pkg = {
|
|
141
|
-
name: args.name
|
|
146
|
+
name: flat ? args.name : `${args.name}-storefront`,
|
|
142
147
|
private: true,
|
|
143
148
|
scripts: {
|
|
144
149
|
"storefront:build": "storefront-build",
|
|
@@ -148,7 +153,75 @@ function scaffoldProject(args) {
|
|
|
148
153
|
},
|
|
149
154
|
dependencies: buildDependencies(pagesConfig),
|
|
150
155
|
}
|
|
151
|
-
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
|
+
}
|
|
152
225
|
|
|
153
226
|
return projectRoot
|
|
154
227
|
}
|
|
@@ -161,29 +234,52 @@ function main() {
|
|
|
161
234
|
}
|
|
162
235
|
|
|
163
236
|
console.log(
|
|
164
|
-
`Creating
|
|
237
|
+
`Creating "${args.name}" (preset: ${args.preset}${args.withBackend ? ", with Medusa backend" : ""})...`
|
|
165
238
|
)
|
|
166
239
|
|
|
167
240
|
const projectRoot = scaffoldProject(args)
|
|
168
241
|
|
|
169
242
|
if (args.install) {
|
|
170
243
|
console.log("\nInstalling dependencies...")
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
+
}
|
|
175
253
|
}
|
|
176
254
|
}
|
|
177
255
|
|
|
178
|
-
|
|
179
|
-
|
|
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
|
|
180
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
|
+
: `
|
|
181
277
|
Next steps:
|
|
182
278
|
cd ${args.name}
|
|
183
279
|
npm run dev
|
|
280
|
+
`
|
|
184
281
|
|
|
185
|
-
|
|
186
|
-
`)
|
|
282
|
+
console.log(`Done! Created ${projectRoot}${nextSteps}`)
|
|
187
283
|
}
|
|
188
284
|
|
|
189
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
|
+
}
|