@pradip1995/create-storefront-app 0.3.0 → 0.3.1
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 +7 -1
- package/lib/versions.js +1 -1
- package/package.json +1 -1
- package/templates/backend/.cursor/commands/seed-backend.md +10 -5
- package/templates/backend/.cursor/rules/medusa-backend.mdc +2 -3
- package/templates/backend/config/README.md +12 -10
- package/templates/backend/src/scripts/seed.ts +0 -2
- package/templates/docker/Makefile +3 -1
- package/templates/root/.cursor/commands/docker-dev.md +3 -8
- package/templates/root/.cursor/rules/monorepo-layout.mdc +1 -1
- package/templates/root/scripts/sync-publishable-key.mjs +108 -0
- package/templates/shared/.cursor/rules/customize-sections.mdc +7 -1
- package/templates/shared/.cursor/rules/storefront-architecture.mdc +1 -1
- package/templates/shared/README.md +2 -2
|
@@ -195,7 +195,7 @@ function scaffoldProject(args) {
|
|
|
195
195
|
"storefront:build": "npm run storefront:build --prefix storefront",
|
|
196
196
|
"dev:backend": "npm run dev --prefix backend",
|
|
197
197
|
"build:backend": "npm run build --prefix backend",
|
|
198
|
-
seed: "npm run seed --prefix backend",
|
|
198
|
+
seed: "npm run seed --prefix backend && node scripts/sync-publishable-key.mjs --from-db",
|
|
199
199
|
},
|
|
200
200
|
}
|
|
201
201
|
writeJson(join(projectRoot, "package.json"), rootPkg)
|
|
@@ -208,6 +208,12 @@ function scaffoldProject(args) {
|
|
|
208
208
|
scaffoldStorefront(join(projectRoot, "storefront"), args)
|
|
209
209
|
scaffoldBackend(join(projectRoot, "backend"), args)
|
|
210
210
|
scaffoldDocker(projectRoot, args)
|
|
211
|
+
|
|
212
|
+
mkdirSync(join(projectRoot, "scripts"), { recursive: true })
|
|
213
|
+
cpSync(
|
|
214
|
+
join(PKG_ROOT, "templates/root/scripts/sync-publishable-key.mjs"),
|
|
215
|
+
join(projectRoot, "scripts/sync-publishable-key.mjs")
|
|
216
|
+
)
|
|
211
217
|
} else {
|
|
212
218
|
scaffoldStorefront(projectRoot, args, { flat: true })
|
|
213
219
|
writeFileSync(
|
package/lib/versions.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Published package semver ranges — bump when releasing framework/components. */
|
|
2
2
|
export const COMMERCE_CORE_VERSION = "^4.0.2"
|
|
3
3
|
export const FRAMEWORK_VERSION = "^0.2.1"
|
|
4
|
-
export const FRAMEWORK_COMPILER_VERSION = "^0.2.
|
|
4
|
+
export const FRAMEWORK_COMPILER_VERSION = "^0.2.6"
|
|
5
5
|
export const COMPONENTS_VERSION = ">=0.2.0 <0.4.0"
|
|
6
6
|
|
|
7
7
|
export const FRAMEWORK_PACKAGES = [
|
package/package.json
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
# Seed Medusa backend
|
|
2
2
|
|
|
3
|
-
From project root:
|
|
3
|
+
From project root (recommended — also syncs publishable key to storefront):
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm run seed
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Backend only:
|
|
4
10
|
|
|
5
11
|
```bash
|
|
6
12
|
cd backend
|
|
7
13
|
npm run seed
|
|
14
|
+
node ../scripts/sync-publishable-key.mjs --from-db
|
|
8
15
|
```
|
|
9
16
|
|
|
10
17
|
Requires PostgreSQL running and `DATABASE_URL` set in `backend/.env`.
|
|
11
18
|
|
|
12
|
-
After seed
|
|
19
|
+
## After seed
|
|
13
20
|
|
|
14
|
-
|
|
15
|
-
2. Copy publishable API key from Admin into `storefront/.env.local`
|
|
16
|
-
3. Start storefront: `cd ../storefront && npm run dev`
|
|
21
|
+
`scripts/sync-publishable-key.mjs` reads the publishable key from Postgres and updates `storefront/.env.local`. Then start storefront: `npm run dev:storefront`.
|
|
@@ -12,7 +12,7 @@ alwaysApply: false
|
|
|
12
12
|
|------|---------|
|
|
13
13
|
| `medusa-config.ts` | Plugins + modules wiring |
|
|
14
14
|
| `config/medusa-plugin-versions.json` | npm version map for all plugins |
|
|
15
|
-
| `config/homepage-config.json` | Dynamic-config schema
|
|
15
|
+
| `config/homepage-config.json` | Dynamic-config schema — **synced from storefront build** when sections change |
|
|
16
16
|
| `.env` | Database, CORS, secrets, integrations |
|
|
17
17
|
| `src/scripts/seed.ts` | Region, sales channel, publishable API key, sample product |
|
|
18
18
|
|
|
@@ -31,8 +31,7 @@ From project root: `make up-infra` then local `npm run dev`, or `make up` for fu
|
|
|
31
31
|
|
|
32
32
|
## After seed
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
2. Copy token into `storefront/.env.local` as `NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY`
|
|
34
|
+
From project root, `npm run seed` or `make seed` syncs the publishable key into `storefront/.env.local` (via `scripts/sync-publishable-key.mjs`, reads from Postgres — no backend code changes).
|
|
36
35
|
|
|
37
36
|
## Plugin versions
|
|
38
37
|
|
|
@@ -2,20 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
| File | Purpose |
|
|
4
4
|
|------|---------|
|
|
5
|
-
| `homepage-config.json` | **Schema**
|
|
6
|
-
| `homepage-config.defaults.json` |
|
|
5
|
+
| `homepage-config.json` | **Schema** for Medusa Admin — **auto-synced** from storefront build |
|
|
6
|
+
| `homepage-config.defaults.json` | Default values from schema `defaultValue` fields (auto-synced) |
|
|
7
7
|
|
|
8
8
|
## Workflow
|
|
9
9
|
|
|
10
|
-
1. Edit
|
|
11
|
-
2. Run
|
|
12
|
-
3.
|
|
13
|
-
4.
|
|
10
|
+
1. Edit **`storefront/pages.config.json`** (add/remove/reorder segments).
|
|
11
|
+
2. Run **`npm run storefront:build`** in `storefront/` (or `npm run dev:storefront`).
|
|
12
|
+
3. `storefront-build` writes filtered schema here based on segments + workflows in use.
|
|
13
|
+
4. Restart Medusa backend so Admin picks up schema changes.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Optional manual refresh of defaults only:
|
|
16
16
|
|
|
17
|
+
```bash
|
|
18
|
+
cd backend && npm run dynamic-config:defaults
|
|
17
19
|
```
|
|
18
|
-
GET /store/dynamic-config
|
|
19
|
-
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Runtime content is edited in **Medusa Admin** (Dynamic Config). The storefront loads values via `GET /store/dynamic-config`.
|
|
22
|
+
|
|
23
|
+
Override entire schema: add `storefront/dynamic-config.schema.json` (see framework docs).
|
|
@@ -206,7 +206,5 @@ export default async function seedStore({ container }: ExecArgs) {
|
|
|
206
206
|
logger.info("=== Seed complete ===")
|
|
207
207
|
logger.info(`Region: ${SEED_REGION_NAME} (${SEED_COUNTRIES.join(", ")})`)
|
|
208
208
|
logger.info(`Publishable API key id: ${publishableKey.id}`)
|
|
209
|
-
logger.info("Copy the publishable key token from Medusa Admin → Settings → Publishable API Keys")
|
|
210
|
-
logger.info("into storefront/.env.local as NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY")
|
|
211
209
|
logger.info(`Sample product: ${products[0]?.handle}`)
|
|
212
210
|
}
|
|
@@ -72,8 +72,10 @@ health: ## Check backend and storefront HTTP health
|
|
|
72
72
|
admin-create: ## Create admin user (ADMIN_EMAIL / ADMIN_PASSWORD)
|
|
73
73
|
$(COMPOSE) exec backend npx medusa user -e $(ADMIN_EMAIL) -p '$(ADMIN_PASSWORD)'
|
|
74
74
|
|
|
75
|
-
seed: ## Run Medusa seed
|
|
75
|
+
seed: ## Run Medusa seed, then sync publishable key to storefront env
|
|
76
76
|
$(COMPOSE) exec backend npx medusa exec ./src/scripts/seed.ts
|
|
77
|
+
@token=$$($(COMPOSE) exec -T postgres psql -U {{POSTGRES_USER}} -d {{POSTGRES_DB}} -tAc "SELECT token FROM api_key WHERE type = 'publishable' AND deleted_at IS NULL AND revoked_at IS NULL ORDER BY created_at DESC LIMIT 1" | tr -d '[:space:]'); \
|
|
78
|
+
node scripts/sync-publishable-key.mjs "$$token"
|
|
77
79
|
|
|
78
80
|
db-shell: ## Open psql in postgres container
|
|
79
81
|
$(COMPOSE) exec postgres psql -U {{POSTGRES_USER}} -d {{POSTGRES_DB}}
|
|
@@ -19,14 +19,9 @@ npm run dev:storefront # terminal 2
|
|
|
19
19
|
|
|
20
20
|
## After seed
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
`make seed` runs Medusa seed unchanged, then `scripts/sync-publishable-key.mjs` reads the token from Postgres and updates:
|
|
23
23
|
|
|
24
|
-
- `storefront/.env.local`
|
|
25
|
-
- `docker/frontend.build.defaults`
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
make build-storefront
|
|
29
|
-
make up-storefront
|
|
30
|
-
```
|
|
24
|
+
- `storefront/.env.local`
|
|
25
|
+
- `docker/.env` and `docker/frontend.build.defaults` (when using Docker)
|
|
31
26
|
|
|
32
27
|
Mailpit: http://localhost:8025
|
|
@@ -33,7 +33,7 @@ See `Makefile` and command `docker-dev`.
|
|
|
33
33
|
1. Set `DATABASE_URL` in `backend/.env`
|
|
34
34
|
2. `npm run dev:backend` (migrations)
|
|
35
35
|
3. `npm run seed` (region, API key, sample product)
|
|
36
|
-
4.
|
|
36
|
+
4. Run `npm run seed` from project root (syncs publishable key to `storefront/.env.local` via Postgres)
|
|
37
37
|
|
|
38
38
|
## Build
|
|
39
39
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Sync NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY into storefront/.env.local and docker env files.
|
|
4
|
+
* Does not modify Medusa backend — reads the token from Postgres after seed.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node scripts/sync-publishable-key.mjs --from-db
|
|
8
|
+
* node scripts/sync-publishable-key.mjs pk_abc123...
|
|
9
|
+
* echo pk_abc... | node scripts/sync-publishable-key.mjs --stdin
|
|
10
|
+
*/
|
|
11
|
+
import { execSync } from "child_process"
|
|
12
|
+
import { existsSync, readFileSync, writeFileSync } from "fs"
|
|
13
|
+
import { dirname, join } from "path"
|
|
14
|
+
import { fileURLToPath } from "url"
|
|
15
|
+
|
|
16
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
17
|
+
const projectRoot = join(__dirname, "..")
|
|
18
|
+
const ENV_KEY = "NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY"
|
|
19
|
+
|
|
20
|
+
const SQL = `SELECT token FROM api_key WHERE type = 'publishable' AND deleted_at IS NULL AND revoked_at IS NULL ORDER BY created_at DESC LIMIT 1`
|
|
21
|
+
|
|
22
|
+
function upsertEnvLine(content, key, value) {
|
|
23
|
+
const line = `${key}=${value}`
|
|
24
|
+
const regex = new RegExp(`^${key}=.*$`, "m")
|
|
25
|
+
if (regex.test(content)) return content.replace(regex, line)
|
|
26
|
+
return `${content.replace(/\n?$/, "")}\n${line}\n`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function updateEnvFile(filePath, token) {
|
|
30
|
+
if (!existsSync(filePath)) return false
|
|
31
|
+
writeFileSync(filePath, upsertEnvLine(readFileSync(filePath, "utf8"), ENV_KEY, token))
|
|
32
|
+
return true
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function parseEnvFile(path) {
|
|
36
|
+
if (!existsSync(path)) return {}
|
|
37
|
+
const vars = {}
|
|
38
|
+
for (const line of readFileSync(path, "utf8").split("\n")) {
|
|
39
|
+
const m = line.match(/^([A-Z0-9_]+)=(.*)$/)
|
|
40
|
+
if (m) vars[m[1]] = m[2]
|
|
41
|
+
}
|
|
42
|
+
return vars
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function readDatabaseUrl() {
|
|
46
|
+
const backendEnv = join(projectRoot, "backend", ".env")
|
|
47
|
+
const vars = parseEnvFile(backendEnv)
|
|
48
|
+
return vars.DATABASE_URL || process.env.DATABASE_URL || null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function queryTokenViaPsql(databaseUrl) {
|
|
52
|
+
const out = execSync(`psql "${databaseUrl}" -tAc "${SQL}"`, {
|
|
53
|
+
encoding: "utf8",
|
|
54
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
55
|
+
})
|
|
56
|
+
return out.trim()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isValidToken(token) {
|
|
60
|
+
return typeof token === "string" && token.startsWith("pk_") && !token.includes("...")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function resolveToken() {
|
|
64
|
+
const args = process.argv.slice(2)
|
|
65
|
+
|
|
66
|
+
if (args.includes("--stdin")) {
|
|
67
|
+
const fromStdin = readFileSync(0, "utf8").trim()
|
|
68
|
+
if (isValidToken(fromStdin)) return fromStdin
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const positional = args.filter((a) => !a.startsWith("--"))
|
|
72
|
+
if (positional[0] && isValidToken(positional[0])) return positional[0]
|
|
73
|
+
|
|
74
|
+
if (args.includes("--from-db") || args.length === 0) {
|
|
75
|
+
const databaseUrl = readDatabaseUrl()
|
|
76
|
+
if (!databaseUrl) {
|
|
77
|
+
throw new Error("DATABASE_URL not found in backend/.env")
|
|
78
|
+
}
|
|
79
|
+
const token = queryTokenViaPsql(databaseUrl)
|
|
80
|
+
if (isValidToken(token)) return token
|
|
81
|
+
throw new Error("No publishable API key in database — run seed first")
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
throw new Error("Pass pk_ token, --stdin, or --from-db")
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const token = resolveToken()
|
|
89
|
+
const targets = [
|
|
90
|
+
join(projectRoot, "storefront", ".env.local"),
|
|
91
|
+
join(projectRoot, "docker", ".env"),
|
|
92
|
+
join(projectRoot, "docker", "frontend.build.defaults"),
|
|
93
|
+
]
|
|
94
|
+
const updated = targets.filter((p) => updateEnvFile(p, token))
|
|
95
|
+
|
|
96
|
+
if (updated.length === 0) {
|
|
97
|
+
console.error("sync-publishable-key: no env files updated (storefront/.env.local missing?)")
|
|
98
|
+
process.exit(1)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log("sync-publishable-key: set NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY in:")
|
|
102
|
+
for (const p of updated) {
|
|
103
|
+
console.log(` ${p.replace(`${projectRoot}/`, "")}`)
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error(`sync-publishable-key: ${error.message}`)
|
|
107
|
+
process.exit(1)
|
|
108
|
+
}
|
|
@@ -20,7 +20,13 @@ Each entry in `segments` renders top-to-bottom:
|
|
|
20
20
|
]
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
**Reorder
|
|
23
|
+
**Reorder / add / remove sections** — edit `pages.config.json`, then:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm run storefront:build
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This regenerates the Next.js app **and** syncs `backend/config/homepage-config.json` (Admin fields for your active segments). Restart the backend after schema changes.
|
|
24
30
|
|
|
25
31
|
**Remove** — delete the line and remove the package from `package.json` if unused elsewhere.
|
|
26
32
|
|
|
@@ -24,7 +24,7 @@ This folder (`storefront/`) is a **config client**, not a hand-written Next.js a
|
|
|
24
24
|
|------|---------|
|
|
25
25
|
| `.generated-app/` | Full Next.js app from `storefront-build` |
|
|
26
26
|
|
|
27
|
-
Homepage content (hero, promo, logo, etc.)
|
|
27
|
+
Homepage content (hero, promo, logo, etc.) comes from Medusa `GET /store/dynamic-config`. The **schema** in `../backend/config/homepage-config.json` is updated automatically when you run `npm run storefront:build` after changing `pages.config.json`.
|
|
28
28
|
|
|
29
29
|
After any change to config, deps, or `theme-overrides.css`:
|
|
30
30
|
|
|
@@ -30,7 +30,7 @@ make admin-create
|
|
|
30
30
|
| API | {{BACKEND_URL}} |
|
|
31
31
|
| Mailpit | http://localhost:8025 |
|
|
32
32
|
|
|
33
|
-
After `make seed
|
|
33
|
+
After `make seed` or `npm run seed`, the publishable key is read from Postgres and written to `storefront/.env.local` and `docker/` env files (no backend code changes).
|
|
34
34
|
|
|
35
35
|
Default admin: `make admin-create` (see `Makefile` for `ADMIN_EMAIL` / `ADMIN_PASSWORD`).
|
|
36
36
|
|
|
@@ -94,7 +94,7 @@ make clean # remove containers + volumes
|
|
|
94
94
|
| Home sections | `storefront/pages.config.json` |
|
|
95
95
|
| Colors / fonts | `storefront/theme-overrides.css` |
|
|
96
96
|
| Medusa plugins | `backend/medusa-config.ts` + `backend/config/medusa-plugin-versions.json` |
|
|
97
|
-
| Homepage admin fields | `backend/config/homepage-config.json` |
|
|
97
|
+
| Homepage admin fields | `backend/config/homepage-config.json` (auto-synced on `storefront:build`) |
|
|
98
98
|
| Docker secrets | `docker/.env` |
|
|
99
99
|
|
|
100
100
|
Cursor guides: `.cursor/` in each folder.
|