@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.
@@ -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"
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@pradip1995/create-storefront-app",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Scaffold a segment-based Medusa storefront using @pradip1995/framework packages",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -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
- 1. Start backend: `npm run dev`
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 (sync with storefront build) |
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
- 1. Open Medusa Admin Settings Publishable API Keys
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** — field definitions for Medusa Admin (`medusa-plugin-dynamic-config`) |
6
- | `homepage-config.defaults.json` | **Default values** extracted from schema `defaultValue` fields (reference + bootstrap) |
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 `homepage-config.json` when adding/removing admin fields.
11
- 2. Run `npm run dynamic-config:defaults` to refresh default values.
12
- 3. Restart backend schema is loaded from `medusa-config.ts`.
13
- 4. Set live content in **Medusa Admin** (Dynamic Config).
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
- The **storefront does not copy this schema**. It reads runtime values from:
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
- Configure values in Admin after `npm run seed`.
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 script (regions, publishable key, sample product)
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
- Copy publishable API key into:
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` (local dev)
25
- - `docker/frontend.build.defaults` + rebuild storefront image (Docker)
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. Copy publishable key `storefront/.env.local`
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** change array order, then `npm run storefront:build`.
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.) is **not** generated here — it comes from Medusa `GET /store/dynamic-config`. Schema lives in `../backend/config/homepage-config.json`.
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`, update `docker/frontend.build.defaults` and `storefront/.env.local` with the publishable key, then `make build-storefront` if using Docker for the storefront.
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.