modern-cms 1.1.4 → 1.1.6

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/README.md CHANGED
@@ -84,7 +84,7 @@ npm run dev
84
84
 
85
85
  Then open the web app at the URL you chose (default `http://localhost:3000`) and log in at `/admin` with the admin email/password from the wizard.
86
86
 
87
- > **Prefer yarn for the scaffolded project too?** `yarn install` works fine, and `dev`/`db:migrate`/`db:seed` all run correctly (they use `tsx`, which doesn't type-check). The one caveat: yarn's dependency hoisting can occasionally produce a duplicate `@types/express`, which shows up as spurious TypeScript errors only if you run `npm run build` or `tsc` directly running `npm install` once resolves it.
87
+ > **Prefer yarn for the scaffolded project too?** `yarn install` works fine, and `dev`/`build`/`db:migrate`/`db:seed` all run correctly. A stray duplicate `@types/express` (pulled in by `@types/multer`'s unpinned `"*"` dependency range) used to break `tsc`/`npm run build` under both npm and yarn the generated `package.json` now pins it via `overrides` (npm) and `resolutions` (yarn), so a fresh install with either tool is clean.
88
88
  >
89
89
  > **Logged in with the wrong password?** The admin user is only created the *first* time `db:seed` runs — editing `.env` afterward doesn't retroactively change it. Run `npm run db:reset-admin && npm run db:seed` to delete and recreate it from the current `.env` values.
90
90
 
package/bin/modern-cms.js CHANGED
@@ -40,10 +40,10 @@ function onCancel() {
40
40
  }
41
41
 
42
42
  async function main() {
43
- console.log("\nmodern-cms — self-hosted drag-and-drop website CMS\n");
43
+ console.log("\n🚀 modern-cms — self-hosted drag-and-drop website CMS\n");
44
44
 
45
45
  const { targetDir } = await prompts(
46
- { type: "text", name: "targetDir", message: "Where should the project be created?", initial: "./modern-cms-app" },
46
+ { type: "text", name: "targetDir", message: "📁 Where should the project be created?", initial: "./modern-cms-app" },
47
47
  { onCancel }
48
48
  );
49
49
  const dest = path.resolve(process.cwd(), targetDir);
@@ -52,19 +52,20 @@ async function main() {
52
52
  process.exit(1);
53
53
  }
54
54
 
55
- console.log(`\nCopying project files into ${dest} ...`);
55
+ console.log(`\n📦 Copying project files into ${dest} ...`);
56
56
  copyDir(TEMPLATE_DIR, dest);
57
57
 
58
58
  // --- Database ---
59
+ console.log("\n🗄️ Database");
59
60
  const db = await prompts(
60
61
  [
61
62
  {
62
63
  type: "select",
63
64
  name: "engine",
64
- message: "Database",
65
+ message: "Database engine",
65
66
  choices: [
66
- { title: "PostgreSQL", value: "postgresql" },
67
- { title: "MySQL", value: "mysql" },
67
+ { title: "🐘 PostgreSQL", value: "postgresql" },
68
+ { title: "🐬 MySQL", value: "mysql" },
68
69
  ],
69
70
  },
70
71
  { type: "text", name: "host", message: "Database host", initial: "localhost" },
@@ -92,6 +93,7 @@ async function main() {
92
93
  }
93
94
 
94
95
  // --- Ports ---
96
+ console.log("\n🔌 Ports");
95
97
  const ports = await prompts(
96
98
  [
97
99
  { type: "text", name: "webPort", message: "Web app port", initial: "3000" },
@@ -101,15 +103,16 @@ async function main() {
101
103
  );
102
104
 
103
105
  // --- Storage ---
106
+ console.log("\n☁️ File storage");
104
107
  const { provider } = await prompts(
105
108
  {
106
109
  type: "select",
107
110
  name: "provider",
108
- message: "File storage (AWS S3, Azure Blob Storage, or Cloudinary)",
111
+ message: "Storage provider",
109
112
  choices: [
110
- { title: "AWS S3 (or any S3-compatible: MinIO, R2, Spaces...)", value: "s3" },
111
- { title: "Azure Blob Storage", value: "azure" },
112
- { title: "Cloudinary", value: "cloudinary" },
113
+ { title: "🪣 AWS S3 (or any S3-compatible: MinIO, R2, Spaces...)", value: "s3" },
114
+ { title: "🔷 Azure Blob Storage", value: "azure" },
115
+ { title: "🌤️ Cloudinary", value: "cloudinary" },
113
116
  ],
114
117
  },
115
118
  { onCancel }
@@ -160,6 +163,7 @@ async function main() {
160
163
 
161
164
  // --- Site / admin (necessary extras beyond what was asked for: the app needs to
162
165
  // know its own public URLs, and the CMS needs an initial admin login) ---
166
+ console.log("\n👤 Site & admin account");
163
167
  const site = await prompts(
164
168
  [
165
169
  { type: "text", name: "siteUrl", message: "Public site URL", initial: `http://localhost:${ports.webPort}` },
@@ -190,11 +194,11 @@ async function main() {
190
194
  fs.writeFileSync(path.join(dest, ".env"), rootEnv);
191
195
 
192
196
  if (!site.adminPassword) {
193
- console.log(`\nGenerated admin password: ${adminPassword}\n(save this — it's only shown once)`);
197
+ console.log(`\n🔑 Generated admin password: ${adminPassword}\n (save this — it's only shown once)`);
194
198
  }
195
199
 
196
- console.log("\nDone! Generated .env files for apps/api and apps/web.\n");
197
- console.log("Next steps:");
200
+ console.log("\n✅ Done! Generated .env files for apps/api and apps/web.\n");
201
+ console.log("👉 Next steps:");
198
202
  console.log(` cd ${targetDir}`);
199
203
  console.log(" npm install");
200
204
  if (usesDbPush(db.engine)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modern-cms",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Self-hosted, drag-and-drop website CMS (Next.js + Express + Prisma). Interactive installer scaffolds a full project with your choice of PostgreSQL/MySQL and AWS S3/Azure Blob/Cloudinary storage.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -60,7 +60,7 @@ npm run db:seed
60
60
  npm run dev
61
61
  ```
62
62
 
63
- > **Using yarn to install the scaffolded project itself?** `yarn install` works fine, and `npm run dev` / `db:migrate` / `db:seed` all run correctly under a yarn-installed `node_modules` (they invoke `tsx`, which doesn't type-check). The one thing to watch for: yarn's dependency hoisting can occasionally produce a duplicate `@types/express` in the tree, which shows up as spurious TypeScript errors *only* if you run `npm run build` or `tsc` directly. If that happens, running `npm install` once (even alongside your yarn workflow) resolves it that's yarn's hoisting, not a bug in the project.
63
+ > **Using yarn to install the scaffolded project itself?** `yarn install` works fine `npm run dev` / `build` / `db:migrate` / `db:seed` all run correctly under a yarn-installed `node_modules`. (Earlier versions of this README blamed a duplicate `@types/express` type error on "yarn's hoisting" that diagnosis was wrong. The real cause is that `@types/multer` depends on `@types/express@"*"`, which both npm and yarn will happily resolve to a stray v5 copy alongside the project's pinned v4, breaking `tsc`/`npm run build` under either package manager. The root `package.json`'s `overrides` + `resolutions` fields pin that nested dependency to v4 for both, so this no longer happens with a fresh install.)
64
64
 
65
65
  See [`packages/modern-cms/README.md`](packages/modern-cms/README.md) for the full prompt-by-prompt reference and configuration details.
66
66
 
@@ -2,6 +2,7 @@ import express from "express";
2
2
  import cors from "cors";
3
3
  import cookieParser from "cookie-parser";
4
4
  import { env } from "./env.js";
5
+ import { initStorage } from "./lib/storage/index.js";
5
6
  import { securityHeaders } from "./middleware/securityHeaders.js";
6
7
  import { authRouter } from "./routes/auth.routes.js";
7
8
  import { pagesRouter } from "./routes/pages.routes.js";
@@ -61,6 +62,8 @@ app.use((err: any, _req: express.Request, res: express.Response, _next: express.
61
62
  res.status(err.status ?? 500).json({ error: err.message ?? "Internal server error" });
62
63
  });
63
64
 
65
+ initStorage();
66
+
64
67
  app.listen(env.port, () => {
65
68
  console.log(`pg-cms API listening on http://localhost:${env.port}`);
66
69
  });
@@ -6,7 +6,21 @@ import { createCloudinaryStorage } from "./cloudinary.js";
6
6
 
7
7
  let cached: StorageProvider | null = null;
8
8
 
9
+ // Printed once, at first upload/delete — tells you exactly where files are actually
10
+ // going (bucket/container/cloud + folder), since that's the #1 source of "my upload
11
+ // succeeded but I can't find the file" confusion when double-checking the wrong place.
12
+ function logActiveProvider() {
13
+ if (env.storageProvider === "azure") {
14
+ console.log(`[storage] Using Azure Blob Storage — container "${env.azure!.container}"`);
15
+ } else if (env.storageProvider === "cloudinary") {
16
+ console.log(`[storage] Using Cloudinary — cloud "${env.cloudinary!.cloudName}", folder "${env.cloudinary!.folder}"`);
17
+ } else {
18
+ console.log(`[storage] Using S3 — bucket "${env.s3!.bucket}" at ${env.s3!.endpoint}`);
19
+ }
20
+ }
21
+
9
22
  function build(): StorageProvider {
23
+ logActiveProvider();
10
24
  if (env.storageProvider === "azure") return createAzureStorage();
11
25
  if (env.storageProvider === "cloudinary") return createCloudinaryStorage();
12
26
  return createS3Storage();
@@ -16,6 +30,12 @@ function getStorage(): StorageProvider {
16
30
  return (cached ??= build());
17
31
  }
18
32
 
33
+ /** Called once at server boot so the active provider/destination is visible in the
34
+ * logs immediately, rather than only appearing after the first upload. */
35
+ export function initStorage(): void {
36
+ getStorage();
37
+ }
38
+
19
39
  export async function uploadBuffer(key: string, buffer: Buffer, contentType: string): Promise<string> {
20
40
  return getStorage().upload(key, buffer, contentType);
21
41
  }
@@ -9,6 +9,14 @@
9
9
  "packages/*",
10
10
  "apps/*"
11
11
  ],
12
+ "overrides": {
13
+ "@types/multer": {
14
+ "@types/express": "^4.17.21"
15
+ }
16
+ },
17
+ "resolutions": {
18
+ "**/@types/multer/**/@types/express": "^4.17.21"
19
+ },
12
20
  "scripts": {
13
21
  "dev": "concurrently -n api,web -c blue,green \"npm run dev -w apps/api\" \"npm run dev -w apps/web\"",
14
22
  "dev:api": "npm run dev -w apps/api",