@lexho111/plainblog 0.5.24 → 0.5.25

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
@@ -74,6 +74,21 @@ 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
+
77
92
  ### provide custom style sheets
78
93
 
79
94
  ```
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 (e) {
59
+ } catch (err) {
60
+ console.error(err);
60
61
  throw new Error("Missing optional dependencies");
61
62
  }
62
63
  } else {
@@ -39,7 +39,8 @@ export default class PostgresAdapter extends SequelizeAdapter {
39
39
  stdio: "inherit",
40
40
  });
41
41
  pgPkg = await import("pg");
42
- } catch (e) {
42
+ } catch (err) {
43
+ console.error(err);
43
44
  throw new Error("Missing optional dependencies");
44
45
  }
45
46
  }
@@ -37,7 +37,8 @@ export default class SequelizeAdapter {
37
37
  stdio: "inherit",
38
38
  });
39
39
  sequelizePkg = await import("sequelize");
40
- } catch (e) {
40
+ } catch (err) {
41
+ console.error(err);
41
42
  throw new Error("Missing optional dependencies");
42
43
  }
43
44
  } else {
@@ -27,7 +27,8 @@ export default class SqliteAdapter extends SequelizeAdapter {
27
27
  stdio: "inherit",
28
28
  });
29
29
  sqlite3Pkg = await import("sqlite3");
30
- } catch (e) {
30
+ } catch (err) {
31
+ console.error(err);
31
32
  throw new Error("Missing optional dependencies");
32
33
  }
33
34
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexho111/plainblog",
3
- "version": "0.5.24",
3
+ "version": "0.5.25",
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
- "typescript": "^5.9.3"
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
  }
@@ -1 +1,2 @@
1
- body{font-family:Arial}.grid{border:0 solid #000;display:grid;grid-gap:.25rem;gap:.25rem;grid-template-columns:1fr}.grid article{border:0 solid #ccc;border-radius:4px;min-width:0;word-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;-webkit-text-decoration:underline;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%}}
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 */