modern-cms 1.1.2 → 1.1.3
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/lib.js +53 -30
- package/package.json +1 -1
- package/template/package.json +2 -2
package/bin/lib.js
CHANGED
|
@@ -20,57 +20,80 @@ export function usesDbPush(engine) {
|
|
|
20
20
|
return engine === "mysql";
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/** dotenv treats `#` as a start-of-comment marker on unquoted values (so a password
|
|
24
|
+
* like "Adm!n#2024" silently truncates to "Adm!n" — confirmed by testing dotenv.parse
|
|
25
|
+
* directly) and trims unquoted trailing whitespace. Wrapping every value in double
|
|
26
|
+
* quotes fixes both.
|
|
27
|
+
*
|
|
28
|
+
* Backslashes and embedded quotes need escaping too — dotenv's matcher stops at the
|
|
29
|
+
* first *unescaped* `"`, so a literal quote in the value would end the match early and
|
|
30
|
+
* corrupt everything after it on that line (confirmed against dotenv's own source:
|
|
31
|
+
* lib/main.js's LINE regex uses `(?:\\"|[^"])*` for double-quoted values). Note dotenv
|
|
32
|
+
* itself never un-escapes `\"`/`\\` back out on the read side (only `\n`/`\r` get
|
|
33
|
+
* expanded) — so a value containing a literal backslash or quote character can't be
|
|
34
|
+
* perfectly round-tripped by any quoting strategy; escaping still prevents the much
|
|
35
|
+
* worse failure (truncation/corrupted file), it just means those two specific
|
|
36
|
+
* characters aren't recommended in a password if byte-for-byte fidelity matters. */
|
|
37
|
+
function quoteEnvValue(value) {
|
|
38
|
+
const str = String(value ?? "");
|
|
39
|
+
return `"${str.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function envLine(key, value) {
|
|
43
|
+
return `${key}=${quoteEnvValue(value)}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
23
46
|
export function buildStorageEnvLines(provider, values) {
|
|
24
47
|
if (provider === "s3") {
|
|
25
48
|
return [
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
49
|
+
envLine("S3_ENDPOINT", values.endpoint),
|
|
50
|
+
envLine("S3_REGION", values.region),
|
|
51
|
+
envLine("S3_ACCESS_KEY_ID", values.accessKeyId),
|
|
52
|
+
envLine("S3_SECRET_ACCESS_KEY", values.secretAccessKey),
|
|
53
|
+
envLine("S3_BUCKET", values.bucket),
|
|
54
|
+
envLine("S3_PUBLIC_URL", values.publicUrl),
|
|
55
|
+
envLine("S3_FORCE_PATH_STYLE", String(values.forcePathStyle)),
|
|
33
56
|
];
|
|
34
57
|
}
|
|
35
58
|
if (provider === "azure") {
|
|
36
59
|
return [
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
...(values.publicUrl ? [
|
|
60
|
+
envLine("AZURE_STORAGE_CONNECTION_STRING", values.connectionString),
|
|
61
|
+
envLine("AZURE_STORAGE_CONTAINER", values.container),
|
|
62
|
+
...(values.publicUrl ? [envLine("AZURE_STORAGE_PUBLIC_URL", values.publicUrl)] : []),
|
|
40
63
|
];
|
|
41
64
|
}
|
|
42
65
|
return [
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
envLine("CLOUDINARY_CLOUD_NAME", values.cloudName),
|
|
67
|
+
envLine("CLOUDINARY_API_KEY", values.apiKey),
|
|
68
|
+
envLine("CLOUDINARY_API_SECRET", values.apiSecret),
|
|
69
|
+
envLine("CLOUDINARY_FOLDER", values.folder),
|
|
47
70
|
];
|
|
48
71
|
}
|
|
49
72
|
|
|
50
73
|
export function buildApiEnv({ databaseUrl, jwtSecret, adminEmail, adminPassword, storageProvider, storageEnvLines, siteUrl, apiPort, revalidateSecret }) {
|
|
51
74
|
return [
|
|
52
|
-
|
|
75
|
+
envLine("DATABASE_URL", databaseUrl),
|
|
53
76
|
"",
|
|
54
77
|
"# --- Auth ---",
|
|
55
|
-
|
|
56
|
-
"JWT_EXPIRES_IN
|
|
57
|
-
"COOKIE_NAME
|
|
78
|
+
envLine("JWT_SECRET", jwtSecret),
|
|
79
|
+
envLine("JWT_EXPIRES_IN", "7d"),
|
|
80
|
+
envLine("COOKIE_NAME", "pgcms_token"),
|
|
58
81
|
"",
|
|
59
82
|
"# --- Seed admin user ---",
|
|
60
|
-
|
|
61
|
-
|
|
83
|
+
envLine("SEED_ADMIN_EMAIL", adminEmail),
|
|
84
|
+
envLine("SEED_ADMIN_PASSWORD", adminPassword),
|
|
62
85
|
"",
|
|
63
86
|
`# --- File storage (${storageProvider}) ---`,
|
|
64
|
-
|
|
87
|
+
envLine("STORAGE_PROVIDER", storageProvider),
|
|
65
88
|
...storageEnvLines,
|
|
66
89
|
"",
|
|
67
90
|
"# --- API ---",
|
|
68
|
-
|
|
69
|
-
|
|
91
|
+
envLine("API_PORT", apiPort),
|
|
92
|
+
envLine("WEB_ORIGIN", siteUrl),
|
|
70
93
|
"",
|
|
71
94
|
"# --- Cache revalidation ---",
|
|
72
|
-
|
|
73
|
-
|
|
95
|
+
envLine("REVALIDATE_URL", siteUrl),
|
|
96
|
+
envLine("REVALIDATE_SECRET", revalidateSecret),
|
|
74
97
|
"",
|
|
75
98
|
"# --- Form integrations (optional) ---",
|
|
76
99
|
"FORMS_WEBHOOK_URL=",
|
|
@@ -79,16 +102,16 @@ export function buildApiEnv({ databaseUrl, jwtSecret, adminEmail, adminPassword,
|
|
|
79
102
|
}
|
|
80
103
|
|
|
81
104
|
export function buildWebEnv({ apiUrl, siteUrl, webPort }) {
|
|
82
|
-
return [
|
|
105
|
+
return [envLine("API_URL", apiUrl), envLine("SITE_URL", siteUrl), envLine("PORT", webPort), ""].join("\n");
|
|
83
106
|
}
|
|
84
107
|
|
|
85
108
|
export function buildRootEnv({ db, databaseUrl, storageProvider, storageEnvLines }) {
|
|
86
109
|
const s3Line = (prefix) => storageEnvLines.find((l) => l.startsWith(prefix));
|
|
87
110
|
return [
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
111
|
+
envLine("POSTGRES_USER", db.user),
|
|
112
|
+
envLine("POSTGRES_PASSWORD", db.password),
|
|
113
|
+
envLine("POSTGRES_DB", db.name),
|
|
114
|
+
envLine("DATABASE_URL", databaseUrl),
|
|
92
115
|
...(storageProvider === "s3"
|
|
93
116
|
? [s3Line("S3_ACCESS_KEY_ID="), s3Line("S3_SECRET_ACCESS_KEY="), s3Line("S3_BUCKET=")].filter(Boolean)
|
|
94
117
|
: []),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modern-cms",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
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": {
|