modern-cms 1.1.5 → 1.1.7

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/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.5",
3
+ "version": "1.1.7",
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": {
@@ -4,7 +4,7 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "dev": "tsx watch src/index.ts",
7
+ "dev": "tsx --watch src/index.ts",
8
8
  "build": "tsc -p tsconfig.json",
9
9
  "start": "node dist/index.js",
10
10
  "db:migrate": "prisma migrate dev",
@@ -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
  }