json-server 1.0.0-beta.12 → 1.0.0-beta.14

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
@@ -97,7 +97,7 @@ Run `json-server --help` for a list of options
97
97
  | <a href="https://mockend.com/" target="_blank"><img src="https://jsonplaceholder.typicode.com/mockend.svg" height="100px"></a> |
98
98
  | <a href="https://zuplo.link/json-server-gh"><img src="https://github.com/user-attachments/assets/adfee31f-a8b6-4684-9a9b-af4f03ac5b75" height="100px"></a> |
99
99
  | <a href="https://www.mintlify.com/"><img src="https://github.com/user-attachments/assets/bcc8cc48-b2d9-4577-8939-1eb4196b7cc5" height="100px"></a> |
100
- | <a href="http://git-tower.com/?utm_source=husky&utm_medium=referral"><img height="100px" alt="tower-dock-icon-light" src="https://github.com/user-attachments/assets/b6b4ab20-beff-4e5c-9845-bb9d60057196" /></a> |
100
+ | <a href="http://git-tower.com/?utm_source=husky&utm_medium=referral"><img height="100px" alt="tower-dock-icon-light" src="https://jsonplaceholder.typicode.com/tower-icon-and-logo-1400x260.png" /></a> |
101
101
  | <a href="https://serpapi.com/?utm_source=typicode"><img height="100px" src="https://github.com/user-attachments/assets/52b3039d-1e4c-4c68-951c-93f0f1e73611" /></a>
102
102
 
103
103
 
package/lib/app.js CHANGED
@@ -52,18 +52,22 @@ function parseListParams(req) {
52
52
  function withBody(action) {
53
53
  return async (req, res, next) => {
54
54
  const { name = '' } = req.params;
55
- if (isItem(req.body)) {
56
- res.locals['data'] = await action(name, req.body);
55
+ if (!isItem(req.body)) {
56
+ res.status(400).json({ error: 'Body must be a JSON object' });
57
+ return;
57
58
  }
59
+ res.locals['data'] = await action(name, req.body);
58
60
  next?.();
59
61
  };
60
62
  }
61
63
  function withIdAndBody(action) {
62
64
  return async (req, res, next) => {
63
65
  const { name = '', id = '' } = req.params;
64
- if (isItem(req.body)) {
65
- res.locals['data'] = await action(name, id, req.body);
66
+ if (!isItem(req.body)) {
67
+ res.status(400).json({ error: 'Body must be a JSON object' });
68
+ return;
66
69
  }
70
+ res.locals['data'] = await action(name, id, req.body);
67
71
  next?.();
68
72
  };
69
73
  }
package/lib/random-id.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { randomBytes } from 'node:crypto';
2
2
  export function randomId() {
3
- return randomBytes(2).toString('hex');
3
+ return randomBytes(8).toString('base64url');
4
4
  }
package/lib/service.js CHANGED
@@ -104,7 +104,7 @@ export class Service {
104
104
  const items = this.#get(name);
105
105
  if (items === undefined || !Array.isArray(items))
106
106
  return;
107
- const item = { id: randomId(), ...data };
107
+ const item = { ...data, id: randomId() };
108
108
  items.push(item);
109
109
  await this.#db.write();
110
110
  return item;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-server",
3
- "version": "1.0.0-beta.12",
3
+ "version": "1.0.0-beta.14",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "JSON",
package/views/index.html CHANGED
@@ -1,95 +1,147 @@
1
1
  <!doctype html>
2
- <html>
2
+ <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>JSON Server</title>
6
7
  <style>
7
- html {
8
- font-size: 16px;
9
- line-height: 1.5;
10
- background-color: #fff;
11
- color: #000;
8
+ :root {
9
+ color-scheme: light dark;
10
+ --fg: light-dark(#111, #e8e8e8);
11
+ --bg: light-dark(#fff, #111214);
12
+ --muted: light-dark(#999, #9aa0a6);
13
+ --line: light-dark(#e5e5e5, #2c2f34);
14
+ --accent: light-dark(#6366f1, #8b90ff);
15
+ --chip-bg: light-dark(#111, #f5f5f5);
16
+ --chip-fg: light-dark(#fff, #111214);
12
17
  }
13
-
14
18
  body {
15
- margin: 0 auto;
16
- max-width: 720px;
17
- padding: 0 16px;
18
- font-family: sans-serif;
19
+ margin: 40px auto;
20
+ max-width: 400px;
21
+ padding: 0 24px;
22
+ font-family:
23
+ ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
24
+ background-color: var(--bg);
25
+ color: var(--fg);
26
+ line-height: 1.5;
27
+ font-size: 14px;
28
+ transition:
29
+ background-color 0.2s ease,
30
+ color 0.2s ease,
31
+ border-color 0.2s ease;
19
32
  }
20
-
21
33
  a {
22
- color: #db2777;
23
- text-decoration: none;
34
+ color: inherit;
24
35
  }
25
-
26
36
  header {
27
- margin-bottom: 32px;
28
- padding: 16px 0;
37
+ margin-bottom: 40px;
38
+ color: var(--muted);
29
39
  }
30
-
31
- nav {
40
+ .topbar {
32
41
  display: flex;
33
42
  justify-content: space-between;
43
+ align-items: baseline;
44
+ margin-bottom: 12px;
45
+ padding-top: 12px;
46
+ border-top: 1px solid var(--line);
34
47
  }
35
-
36
- nav div a {
37
- margin-left: 16px;
48
+ .topbar a {
49
+ text-decoration: none;
50
+ transition: color 0.1s ease;
38
51
  }
39
-
40
- ul {
41
- margin: 0;
42
- padding: 0;
43
- list-style: none;
52
+ .topbar a:first-child {
53
+ color: var(--fg);
44
54
  }
45
-
46
- li {
55
+ .topbar a:hover {
56
+ color: var(--accent);
57
+ }
58
+ .section-title {
47
59
  margin-bottom: 8px;
60
+ color: var(--muted);
48
61
  }
49
-
50
- /* Dark mode styles */
51
- @media (prefers-color-scheme: dark) {
52
- html {
53
- background-color: #1e293b;
54
- color: #fff;
55
- }
56
-
57
- a {
58
- }
62
+ .list {
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: 4px;
66
+ }
67
+ .list a {
68
+ display: flex;
69
+ justify-content: space-between;
70
+ align-items: center;
71
+ padding: 8px 0;
72
+ text-decoration: none;
73
+ transition: color 0.1s ease;
74
+ }
75
+ .list a:hover {
76
+ color: var(--accent);
77
+ }
78
+ .meta {
79
+ color: var(--muted);
80
+ font-size: 13px;
81
+ }
82
+ .empty {
83
+ color: var(--muted);
84
+ }
85
+ footer {
86
+ margin-top: 48px;
87
+ padding-top: 12px;
88
+ border-top: 1px solid var(--line);
89
+ color: var(--muted);
90
+ font-size: 13px;
91
+ }
92
+ .heart {
93
+ position: fixed;
94
+ bottom: 20px;
95
+ right: 24px;
96
+ display: inline-flex;
97
+ align-items: center;
98
+ justify-content: center;
99
+ width: 32px;
100
+ height: 32px;
101
+ border-radius: 50%;
102
+ color: var(--chip-fg);
103
+ background-color: var(--chip-bg);
104
+ text-decoration: none;
105
+ transition: transform 0.15s ease;
106
+ }
107
+ .heart:hover {
108
+ transform: scale(1.1);
59
109
  }
60
110
  </style>
61
111
  </head>
62
112
 
63
113
  <body>
114
+ <% const resources = Object.entries(it.data ?? {}); %>
115
+
64
116
  <header>
65
- <nav>
66
- <strong>JSON Server</strong>
67
- <div>
68
- <a href="https://github.com/typicode/json-server">Docs</a>
69
- <a href="https://github.com/sponsors/typicode">♡ Sponsor</a>
70
- </div>
71
- </nav>
117
+ <div class="topbar">
118
+ <a href="https://github.com/typicode/json-server" target="_blank">json-server</a>
119
+ <a href="https://github.com/typicode/json-server" target="_blank">README</a>
120
+ </div>
121
+ <div class="intro">Available REST resources from db.json.</div>
72
122
  </header>
73
- <main class="my-12">
74
- <p
75
- class="bg-gradient-to-r from-purple-500 via-pink-500 to-red-500 text-transparent bg-clip-text"
76
- >
77
- ✧*。٩(ˊᗜˋ*)و✧*。
78
- </p>
79
- <% if (Object.keys(it.data).length===0) { %>
80
- <p>No resources found in JSON file</p>
81
- <% } %> <% Object.entries(it.data).forEach(function([name]) { %>
82
- <ul>
83
- <li>
84
- <a href="<%= name %>">/<%= name %></a>
85
- <span>
86
- <% if (Array.isArray(it.data[name])) { %> - <%= it.data[name].length %> <%=
87
- it.data[name].length> 1 ? 'items' : 'item' %>
88
- </span>
89
- <% } %>
90
- </li>
91
- </ul>
92
- <% }) %>
93
- </main>
123
+
124
+ <div class="section-title">Resources</div>
125
+
126
+ <div class="list">
127
+ <% if (resources.length === 0) { %>
128
+ <span class="empty">No resources in db.json.</span>
129
+ <% } else { %> <% resources.forEach(function([name, value]) { const isCollection =
130
+ Array.isArray(value); %>
131
+ <a href="/<%= name %>">
132
+ <span>/<%= name %></span>
133
+ <span class="meta">
134
+ <% if (isCollection) { %> <%= value.length %> items <% } else { %> object <% } %>
135
+ </span>
136
+ </a>
137
+ <% }) %> <% } %>
138
+ </div>
139
+
140
+ <footer>
141
+ <span>To replace this page, create public/index.html.</span>
142
+ </footer>
143
+
144
+ <a href="https://github.com/sponsors/typicode" target="_blank" class="heart">❤</a>
145
+
94
146
  </body>
95
147
  </html>