@lexho111/plainblog 0.5.24 → 0.5.26
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 +21 -0
- package/api-server.js +70 -0
- package/build-styles.js +2 -1
- package/model/PostgresAdapter.js +2 -1
- package/model/SequelizeAdapter.js +2 -1
- package/model/SqliteAdapter.js +2 -1
- package/package.json +10 -3
- package/public/styles.min.css +2 -1
package/README.md
CHANGED
|
@@ -74,6 +74,27 @@ await blog.init(); // load data from database
|
|
|
74
74
|
blog.startServer(8080);
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
The API should respond to GET-Requests (*http://example.com:5432/blog*) with json like this:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
{
|
|
81
|
+
"title": "My Remote Blog",
|
|
82
|
+
"articles": [
|
|
83
|
+
{
|
|
84
|
+
"title": "Welcome to the API Server",
|
|
85
|
+
"content": "This content is served from a separate API server.",
|
|
86
|
+
"createdAt": "2026-01-12T11:21:55.561Z"
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Post requests should look like:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
curl -X POST http://example.com:5432/blog -H "Content-Type: application/json" -d "{\"title\": \"My new Article.\", \"content\": \"This is the content.\"}"
|
|
96
|
+
```
|
|
97
|
+
|
|
77
98
|
### provide custom style sheets
|
|
78
99
|
|
|
79
100
|
```
|
package/api-server.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import http from "http";
|
|
2
|
+
|
|
3
|
+
const PORT = 5432;
|
|
4
|
+
|
|
5
|
+
// In-memory data store
|
|
6
|
+
const blogData = {
|
|
7
|
+
title: "My Remote Blog",
|
|
8
|
+
articles: [
|
|
9
|
+
{
|
|
10
|
+
title: "Welcome to the API Server",
|
|
11
|
+
content: "This content is served from a separate API server.",
|
|
12
|
+
createdAt: new Date().toISOString(),
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const server = http.createServer((req, res) => {
|
|
18
|
+
// Set CORS headers to allow requests from the blog application
|
|
19
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
20
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
21
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
22
|
+
|
|
23
|
+
// Handle preflight requests
|
|
24
|
+
if (req.method === "OPTIONS") {
|
|
25
|
+
res.writeHead(204);
|
|
26
|
+
res.end();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
31
|
+
|
|
32
|
+
if (url.pathname === "/blog") {
|
|
33
|
+
if (req.method === "GET") {
|
|
34
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
35
|
+
res.end(JSON.stringify(blogData));
|
|
36
|
+
} else if (req.method === "POST") {
|
|
37
|
+
let body = "";
|
|
38
|
+
req.on("data", (chunk) => (body += chunk.toString()));
|
|
39
|
+
req.on("end", () => {
|
|
40
|
+
try {
|
|
41
|
+
const newArticle = JSON.parse(body);
|
|
42
|
+
if (!newArticle.createdAt) {
|
|
43
|
+
newArticle.createdAt = new Date().toISOString();
|
|
44
|
+
}
|
|
45
|
+
// Add the new article to the beginning of the list
|
|
46
|
+
blogData.articles.unshift(newArticle);
|
|
47
|
+
|
|
48
|
+
console.log("New article received:", newArticle.title);
|
|
49
|
+
|
|
50
|
+
res.writeHead(201, { "Content-Type": "application/json" });
|
|
51
|
+
res.end(JSON.stringify(newArticle));
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error("Error parsing JSON:", error);
|
|
54
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
55
|
+
res.end(JSON.stringify({ error: "Invalid JSON" }));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
} else {
|
|
59
|
+
res.writeHead(405); // Method Not Allowed
|
|
60
|
+
res.end();
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
res.writeHead(404); // Not Found
|
|
64
|
+
res.end();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
server.listen(PORT, () => {
|
|
69
|
+
console.log(`API Server running at http://localhost:${PORT}/blog`);
|
|
70
|
+
});
|
package/build-styles.js
CHANGED
|
@@ -56,7 +56,8 @@ async function runPostcss(css) {
|
|
|
56
56
|
postcss = (await import("postcss")).default;
|
|
57
57
|
autoprefixer = (await import("autoprefixer")).default;
|
|
58
58
|
cssnano = (await import("cssnano")).default;
|
|
59
|
-
} catch (
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error(err);
|
|
60
61
|
throw new Error("Missing optional dependencies");
|
|
61
62
|
}
|
|
62
63
|
} else {
|
package/model/PostgresAdapter.js
CHANGED
package/model/SqliteAdapter.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lexho111/plainblog",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.26",
|
|
4
4
|
"description": "A tool for creating and serving a minimalist, single-page blog.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -16,14 +16,21 @@
|
|
|
16
16
|
],
|
|
17
17
|
"author": "lexho111",
|
|
18
18
|
"license": "ISC",
|
|
19
|
-
"dependencies": {},
|
|
20
19
|
"devDependencies": {
|
|
21
20
|
"@eslint/js": "^9.39.2",
|
|
22
21
|
"@types/node": "^25.0.3",
|
|
22
|
+
"autoprefixer": "^10.4.23",
|
|
23
|
+
"cssnano": "^7.1.2",
|
|
23
24
|
"eslint": "^9.39.2",
|
|
24
25
|
"eslint-plugin-jest": "^28.6.0",
|
|
25
26
|
"globals": "^17.0.0",
|
|
26
27
|
"jest": "^29.7.0",
|
|
27
|
-
"
|
|
28
|
+
"pg": "^8.16.3",
|
|
29
|
+
"pg-hstore": "^2.3.4",
|
|
30
|
+
"postcss": "^8.5.6",
|
|
31
|
+
"sequelize": "^6.37.7",
|
|
32
|
+
"sqlite3": "^5.1.7",
|
|
33
|
+
"typescript": "^5.9.3",
|
|
34
|
+
"w3c-css-validator": "^1.4.1"
|
|
28
35
|
}
|
|
29
36
|
}
|
package/public/styles.min.css
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
body{font-family:Arial}.grid{border:0 solid #000;display:grid;
|
|
1
|
+
body{font-family:Arial;font-family:Arial,sans-serif}h1{color:#333}.grid{border:0 solid #000;display:grid;gap:.25rem;grid-template-columns:1fr}.grid article{border:0 solid #ccc;border-radius:4px;min-width:0;overflow-wrap:break-word;padding:.25rem}.grid article h2{color:#353535;margin-bottom:5px}.grid article .datetime{color:#757575;margin:0}.grid article p{margin-bottom:0;margin-top:10px}article a,article a:visited,h1{color:#696969}nav a{color:#3b40c1;font-size:20px;text-decoration:underline}nav a:visited{color:#3b40c1;text-decoration-color:#3b40c1}#wrapper{max-width:500px;width:100%}@media screen and (max-width:1000px){*{font-size:4vw}#wrapper{box-sizing:border-box;max-width:100%;padding:0 10px;width:100%}}
|
|
2
|
+
/* source-hash: a07f631befba4b6bc703f8709f5ef455faafeff4e5f00b62f835576eea7fb529 */
|