json-server 1.0.0-beta.3 → 1.0.0-beta.4

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
@@ -1,11 +1,12 @@
1
- # json-server
1
+ # JSON-Server
2
2
 
3
3
  [![Node.js CI](https://github.com/typicode/json-server/actions/workflows/node.js.yml/badge.svg)](https://github.com/typicode/json-server/actions/workflows/node.js.yml)
4
4
 
5
5
  > [!IMPORTANT]
6
6
  > Viewing beta v1 documentation – usable but expect breaking changes. For stable version, see [here](https://github.com/typicode/json-server/tree/v0)
7
7
 
8
- 👋 _Hey! Using React, Vue or Astro? Check my new project [MistCSS](https://github.com/typicode/mistcss) to write 50% less code._
8
+ > [!NOTE]
9
+ > Using React ⚛️ ? Check my new project [MistCSS](https://github.com/typicode/mistcss) to write type-safe styles (works with TailwindCSS)
9
10
 
10
11
  ## Install
11
12
 
@@ -40,15 +41,15 @@ Create a `db.json` or `db.json5` file
40
41
  ```json5
41
42
  {
42
43
  posts: [
43
- { id: '1', title: 'a title', views: 100 },
44
- { id: '2', title: 'another title', views: 200 },
44
+ { id: "1", title: "a title", views: 100 },
45
+ { id: "2", title: "another title", views: 200 },
45
46
  ],
46
47
  comments: [
47
- { id: '1', text: 'a comment about post 1', postId: '1' },
48
- { id: '2', text: 'another comment about post 1', postId: '1' },
48
+ { id: "1", text: "a comment about post 1", postId: "1" },
49
+ { id: "2", text: "another comment about post 1", postId: "1" },
49
50
  ],
50
51
  profile: {
51
- name: 'typicode',
52
+ name: "typicode",
52
53
  },
53
54
  }
54
55
  ```
@@ -78,27 +79,32 @@ Run `json-server --help` for a list of options
78
79
 
79
80
  ## Sponsors ✨
80
81
 
81
- | Sponsors |
82
- | :---: |
83
- | <a href="https://mockend.com/" target="_blank"><img src="https://jsonplaceholder.typicode.com/mockend.svg" height="100px"></a> |
84
- | <a href="https://zuplo.link/json-server-gh"><img src="https://github.com/typicode/json-server/assets/5502029/928b7526-0fdf-46ae-80d9-27fa0ef5f430"></a> |
82
+ ### Gold
85
83
 
86
- | Sponsors |
87
- | :---: |
88
- | <a href="https://konghq.com/products/kong-konnect?utm_medium=referral&utm_source=github&utm_campaign=platform&utm_content=json-server"><img src="https://github.com/typicode/json-server/assets/5502029/e8d8ecb2-3c45-4f60-92d0-a060b820fa7f" height="75px"></a> |
84
+ | |
85
+ | :--------------------------------------------------------------------------------------------------------------------------------------------------------: |
86
+ | <a href="https://mockend.com/" target="_blank"><img src="https://jsonplaceholder.typicode.com/mockend.svg" height="100px"></a> |
87
+ | <a href="https://zuplo.link/json-server-gh"><img src="https://github.com/user-attachments/assets/adfee31f-a8b6-4684-9a9b-af4f03ac5b75" height="100px"></a> |
88
+ | <a href="https://www.mintlify.com/"><img src="https://github.com/user-attachments/assets/bcc8cc48-b2d9-4577-8939-1eb4196b7cc5" height="100px"></a> |
89
89
 
90
- | Sponsors | |
91
- | :---: | :---: |
92
- | <a href="https://www.storyblok.com/" target="_blank"><img src="https://github.com/typicode/json-server/assets/5502029/c6b10674-4ada-4616-91b8-59d30046b45a" height="35px"></a> | <a href="https://betterstack.com/" target="_blank"><img src="https://github.com/typicode/json-server/assets/5502029/44679f8f-9671-470d-b77e-26d90b90cbdc" height="35px"></a> |
93
- | <a href="https://route4me.com"><img src="https://github.com/user-attachments/assets/4eab0bac-119e-4b27-8183-8b136190b776" height="35px" alt="Delivery Routing Software and Route Optimization Software"></a> | <a href="https://www.speechanddebate.org"><img src="https://github.com/user-attachments/assets/cc7980e4-2147-4499-8de4-4d0c265d0c07" height="35px"></a> |
90
+ ### Silver
91
+
92
+ | |
93
+ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
94
+ | <a href="https://requestly.com?utm_source=githubsponsor&utm_medium=jsonserver&utm_campaign=jsonserver"><img src="https://github.com/user-attachments/assets/f7e7b3cf-97e2-46b8-81c8-cb3992662a1c" style="height:70px; width:auto;"></a> |
94
95
 
96
+ ### Bronze
97
+
98
+ | | |
99
+ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
100
+ | <a href="https://www.storyblok.com/" target="_blank"><img src="https://github.com/typicode/json-server/assets/5502029/c6b10674-4ada-4616-91b8-59d30046b45a" height="35px"></a> | <a href="https://betterstack.com/" target="_blank"><img src="https://github.com/typicode/json-server/assets/5502029/44679f8f-9671-470d-b77e-26d90b90cbdc" height="35px"></a> |
95
101
 
96
102
  [Become a sponsor and have your company logo here](https://github.com/users/typicode/sponsorship)
97
103
 
98
104
  ## Sponsorware
99
105
 
100
106
  > [!NOTE]
101
- > This project uses the [Fair Source License](https://fair.io/). Only organizations with 3+ users are kindly asked to contribute a small amount through sponsorship [sponsor](https://github.com/sponsors/typicode) for usage. __This license helps keep the project sustainable and healthy, benefiting everyone.__
107
+ > This project uses the [Fair Source License](https://fair.io/). Only organizations with 3+ users are kindly asked to contribute a small amount through sponsorship [sponsor](https://github.com/sponsors/typicode) for usage. **This license helps keep the project sustainable and healthy, benefiting everyone.**
102
108
  >
103
109
  > For more information, FAQs, and the rationale behind this, visit [https://fair.io/](https://fair.io/).
104
110
 
package/lib/app.js CHANGED
@@ -3,9 +3,10 @@ import { fileURLToPath } from 'node:url';
3
3
  import { App } from '@tinyhttp/app';
4
4
  import { cors } from '@tinyhttp/cors';
5
5
  import { Eta } from 'eta';
6
+ import { Low } from 'lowdb';
6
7
  import { json } from 'milliparsec';
7
8
  import sirv from 'sirv';
8
- import { isItem, Service } from './service.js';
9
+ import { isItem, Service } from "./service.js";
9
10
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
11
  const isProduction = process.env['NODE_ENV'] === 'production';
11
12
  const eta = new Eta({
@@ -33,22 +34,21 @@ export function createApp(db, options = {}) {
33
34
  })
34
35
  .options('*', cors());
35
36
  // Body parser
36
- // @ts-expect-error expected
37
37
  app.use(json());
38
38
  app.get('/', (_req, res) => res.send(eta.render('index.html', { data: db.data })));
39
39
  app.get('/:name', (req, res, next) => {
40
40
  const { name = '' } = req.params;
41
- const query = Object.fromEntries(Object.entries(req.query)
42
- .map(([key, value]) => {
41
+ const query = {};
42
+ Object.keys(req.query).forEach((key) => {
43
+ let value = req.query[key];
43
44
  if (['_start', '_end', '_limit', '_page', '_per_page'].includes(key) &&
44
45
  typeof value === 'string') {
45
- return [key, parseInt(value)];
46
+ value = parseInt(value);
46
47
  }
47
- else {
48
- return [key, value];
48
+ if (!Number.isNaN(value)) {
49
+ query[key] = value;
49
50
  }
50
- })
51
- .filter(([, value]) => !Number.isNaN(value)));
51
+ });
52
52
  res.locals['data'] = service.find(name, query);
53
53
  next?.();
54
54
  });
package/lib/bin.js CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync, readFileSync, writeFileSync } from 'node:fs';
3
- import { extname } from 'node:path';
4
- import { parseArgs } from 'node:util';
5
- import chalk from 'chalk';
6
- import { watch } from 'chokidar';
7
- import JSON5 from 'json5';
8
- import { Low } from 'lowdb';
9
- import { DataFile, JSONFile } from 'lowdb/node';
10
- import { fileURLToPath } from 'node:url';
11
- import { createApp } from './app.js';
12
- import { Observer } from './observer.js';
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { extname } from "node:path";
4
+ import { parseArgs } from "node:util";
5
+ import chalk from "chalk";
6
+ import { watch } from "chokidar";
7
+ import JSON5 from "json5";
8
+ import { Low } from "lowdb";
9
+ import { DataFile, JSONFile } from "lowdb/node";
10
+ import { fileURLToPath } from "node:url";
11
+ import { createApp } from "./app.js";
12
+ import { Observer } from "./observer.js";
13
13
  function help() {
14
14
  console.log(`Usage: json-server [options] <file>
15
15
 
@@ -27,44 +27,44 @@ function args() {
27
27
  const { values, positionals } = parseArgs({
28
28
  options: {
29
29
  port: {
30
- type: 'string',
31
- short: 'p',
32
- default: process.env['PORT'] ?? '3000',
30
+ type: "string",
31
+ short: "p",
32
+ default: process.env["PORT"] ?? "3000",
33
33
  },
34
34
  host: {
35
- type: 'string',
36
- short: 'h',
37
- default: process.env['HOST'] ?? 'localhost',
35
+ type: "string",
36
+ short: "h",
37
+ default: process.env["HOST"] ?? "localhost",
38
38
  },
39
39
  static: {
40
- type: 'string',
41
- short: 's',
40
+ type: "string",
41
+ short: "s",
42
42
  multiple: true,
43
43
  default: [],
44
44
  },
45
45
  help: {
46
- type: 'boolean',
46
+ type: "boolean",
47
47
  },
48
48
  version: {
49
- type: 'boolean',
49
+ type: "boolean",
50
50
  },
51
51
  // Deprecated
52
52
  watch: {
53
- type: 'boolean',
54
- short: 'w',
53
+ type: "boolean",
54
+ short: "w",
55
55
  },
56
56
  },
57
57
  allowPositionals: true,
58
58
  });
59
59
  // --version
60
60
  if (values.version) {
61
- const pkg = JSON.parse(readFileSync(fileURLToPath(new URL('../package.json', import.meta.url)), 'utf-8'));
61
+ const pkg = JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf-8"));
62
62
  console.log(pkg.version);
63
63
  process.exit();
64
64
  }
65
65
  // Handle --watch
66
66
  if (values.watch) {
67
- console.log(chalk.yellow('--watch/-w can be omitted, JSON Server 1+ watches for file changes by default'));
67
+ console.log(chalk.yellow("--watch/-w can be omitted, JSON Server 1+ watches for file changes by default"));
68
68
  }
69
69
  if (values.help || positionals.length === 0) {
70
70
  help();
@@ -72,15 +72,15 @@ function args() {
72
72
  }
73
73
  // App args and options
74
74
  return {
75
- file: positionals[0] ?? '',
75
+ file: positionals[0] ?? "",
76
76
  port: parseInt(values.port),
77
77
  host: values.host,
78
78
  static: values.static,
79
79
  };
80
80
  }
81
81
  catch (e) {
82
- if (e.code === 'ERR_PARSE_ARGS_UNKNOWN_OPTION') {
83
- console.log(chalk.red(e.message.split('.')[0]));
82
+ if (e.code === "ERR_PARSE_ARGS_UNKNOWN_OPTION") {
83
+ console.log(chalk.red(e.message.split(".")[0]));
84
84
  help();
85
85
  process.exit(1);
86
86
  }
@@ -95,12 +95,12 @@ if (!existsSync(file)) {
95
95
  process.exit(1);
96
96
  }
97
97
  // Handle empty string JSON file
98
- if (readFileSync(file, 'utf-8').trim() === '') {
99
- writeFileSync(file, '{}');
98
+ if (readFileSync(file, "utf-8").trim() === "") {
99
+ writeFileSync(file, "{}");
100
100
  }
101
101
  // Set up database
102
102
  let adapter;
103
- if (extname(file) === '.json5') {
103
+ if (extname(file) === ".json5") {
104
104
  adapter = new DataFile(file, {
105
105
  parse: JSON5.parse,
106
106
  stringify: JSON5.stringify,
@@ -115,41 +115,41 @@ await db.read();
115
115
  // Create app
116
116
  const app = createApp(db, { logger: false, static: staticArr });
117
117
  function logRoutes(data) {
118
- console.log(chalk.bold('Endpoints:'));
118
+ console.log(chalk.bold("Endpoints:"));
119
119
  if (Object.keys(data).length === 0) {
120
120
  console.log(chalk.gray(`No endpoints found, try adding some data to ${file}`));
121
121
  return;
122
122
  }
123
123
  console.log(Object.keys(data)
124
124
  .map((key) => `${chalk.gray(`http://${host}:${port}/`)}${chalk.blue(key)}`)
125
- .join('\n'));
125
+ .join("\n"));
126
126
  }
127
- const kaomojis = ['♡⸜(˶˃ ᵕ ˂˶)⸝♡', '♡( ◡‿◡ )', '( ˶ˆ ᗜ ˆ˵ )', '(˶ᵔ ᵕ ᵔ˶)'];
127
+ const kaomojis = ["♡⸜(˶˃ ᵕ ˂˶)⸝♡", "♡( ◡‿◡ )", "( ˶ˆ ᗜ ˆ˵ )", "(˶ᵔ ᵕ ᵔ˶)"];
128
128
  function randomItem(items) {
129
129
  const index = Math.floor(Math.random() * items.length);
130
- return items.at(index) ?? '';
130
+ return items.at(index) ?? "";
131
131
  }
132
132
  app.listen(port, () => {
133
133
  console.log([
134
134
  chalk.bold(`JSON Server started on PORT :${port}`),
135
- chalk.gray('Press CTRL-C to stop'),
135
+ chalk.gray("Press CTRL-C to stop"),
136
136
  chalk.gray(`Watching ${file}...`),
137
- '',
137
+ "",
138
138
  chalk.magenta(randomItem(kaomojis)),
139
- '',
140
- chalk.bold('Index:'),
139
+ "",
140
+ chalk.bold("Index:"),
141
141
  chalk.gray(`http://localhost:${port}/`),
142
- '',
143
- chalk.bold('Static files:'),
144
- chalk.gray('Serving ./public directory if it exists'),
145
- '',
146
- ].join('\n'));
142
+ "",
143
+ chalk.bold("Static files:"),
144
+ chalk.gray("Serving ./public directory if it exists"),
145
+ "",
146
+ ].join("\n"));
147
147
  logRoutes(db.data);
148
148
  });
149
149
  // Watch file for changes
150
- if (process.env['NODE_ENV'] !== 'production') {
150
+ if (process.env["NODE_ENV"] !== "production") {
151
151
  let writing = false; // true if the file is being written to by the app
152
- let prevEndpoints = '';
152
+ let prevEndpoints = "";
153
153
  observer.onWriteStart = () => {
154
154
  writing = true;
155
155
  };
@@ -169,12 +169,12 @@ if (process.env['NODE_ENV'] !== 'production') {
169
169
  logRoutes(data);
170
170
  }
171
171
  };
172
- watch(file).on('change', () => {
172
+ watch(file).on("change", () => {
173
173
  // Do no reload if the file is being written to by the app
174
174
  if (!writing) {
175
175
  db.read().catch((e) => {
176
176
  if (e instanceof SyntaxError) {
177
- return console.log(chalk.red(['', `Error parsing ${file}`, e.message].join('\n')));
177
+ return console.log(chalk.red(["", `Error parsing ${file}`, e.message].join("\n")));
178
178
  }
179
179
  console.log(e);
180
180
  });
package/lib/service.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { randomBytes } from 'node:crypto';
2
2
  import { getProperty } from 'dot-prop';
3
3
  import inflection from 'inflection';
4
+ import { Low } from 'lowdb';
4
5
  import sortOn from 'sort-on';
5
6
  export function isItem(obj) {
6
7
  return typeof obj === 'object' && obj !== null;
@@ -12,15 +13,14 @@ export function isData(obj) {
12
13
  const data = obj;
13
14
  return Object.values(data).every((value) => Array.isArray(value) && value.every(isItem));
14
15
  }
15
- var Condition;
16
- (function (Condition) {
17
- Condition["lt"] = "lt";
18
- Condition["lte"] = "lte";
19
- Condition["gt"] = "gt";
20
- Condition["gte"] = "gte";
21
- Condition["ne"] = "ne";
22
- Condition["default"] = "";
23
- })(Condition || (Condition = {}));
16
+ const Condition = {
17
+ lt: 'lt',
18
+ lte: 'lte',
19
+ gt: 'gt',
20
+ gte: 'gte',
21
+ ne: 'ne',
22
+ default: '',
23
+ };
24
24
  function isCondition(value) {
25
25
  return Object.values(Condition).includes(value);
26
26
  }
@@ -149,15 +149,7 @@ export class Service {
149
149
  conds.push([field, op, value]);
150
150
  continue;
151
151
  }
152
- if ([
153
- '_embed',
154
- '_sort',
155
- '_start',
156
- '_end',
157
- '_limit',
158
- '_page',
159
- '_per_page',
160
- ].includes(key)) {
152
+ if (['_embed', '_sort', '_start', '_end', '_limit', '_page', '_per_page'].includes(key)) {
161
153
  continue;
162
154
  }
163
155
  conds.push([key, Condition.default, value]);
@@ -172,32 +164,28 @@ export class Service {
172
164
  switch (op) {
173
165
  // item_gt=value
174
166
  case Condition.gt: {
175
- if (!(typeof itemValue === 'number' &&
176
- itemValue > parseInt(paramValue))) {
167
+ if (!(typeof itemValue === 'number' && itemValue > parseInt(paramValue))) {
177
168
  return false;
178
169
  }
179
170
  break;
180
171
  }
181
172
  // item_gte=value
182
173
  case Condition.gte: {
183
- if (!(typeof itemValue === 'number' &&
184
- itemValue >= parseInt(paramValue))) {
174
+ if (!(typeof itemValue === 'number' && itemValue >= parseInt(paramValue))) {
185
175
  return false;
186
176
  }
187
177
  break;
188
178
  }
189
179
  // item_lt=value
190
180
  case Condition.lt: {
191
- if (!(typeof itemValue === 'number' &&
192
- itemValue < parseInt(paramValue))) {
181
+ if (!(typeof itemValue === 'number' && itemValue < parseInt(paramValue))) {
193
182
  return false;
194
183
  }
195
184
  break;
196
185
  }
197
186
  // item_lte=value
198
187
  case Condition.lte: {
199
- if (!(typeof itemValue === 'number' &&
200
- itemValue <= parseInt(paramValue))) {
188
+ if (!(typeof itemValue === 'number' && itemValue <= parseInt(paramValue))) {
201
189
  return false;
202
190
  }
203
191
  break;
@@ -223,6 +211,8 @@ export class Service {
223
211
  return itemValue === paramValue;
224
212
  case 'boolean':
225
213
  return itemValue === (paramValue === 'true');
214
+ case 'undefined':
215
+ return false;
226
216
  }
227
217
  }
228
218
  }
@@ -286,7 +276,7 @@ export class Service {
286
276
  const item = this.#get(name);
287
277
  if (item === undefined || Array.isArray(item))
288
278
  return;
289
- const nextItem = (this.#db.data[name] = isPatch ? { item, ...body } : body);
279
+ const nextItem = (this.#db.data[name] = isPatch ? { ...item, ...body } : body);
290
280
  await this.#db.write();
291
281
  return nextItem;
292
282
  }
package/package.json CHANGED
@@ -1,63 +1,58 @@
1
1
  {
2
2
  "name": "json-server",
3
- "version": "1.0.0-beta.3",
3
+ "version": "1.0.0-beta.4",
4
4
  "description": "",
5
- "type": "module",
5
+ "keywords": [],
6
+ "license": "SEE LICENSE IN ./LICENSE",
7
+ "author": "typicode <typicode@gmail.com>",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/typicode/json-server.git"
11
+ },
6
12
  "bin": {
7
13
  "json-server": "lib/bin.js"
8
14
  },
9
- "types": "lib",
10
15
  "files": [
11
16
  "lib",
12
17
  "views"
13
18
  ],
14
- "engines": {
15
- "node": ">=18.3"
16
- },
17
- "scripts": {
18
- "dev": "tsx watch src/bin.ts fixtures/db.json",
19
- "build": "rm -rf lib && tsc",
20
- "test": "node --import tsx/esm --test src/*.test.ts",
21
- "lint": "eslint src",
22
- "prepare": "husky",
23
- "prepublishOnly": "npm run build"
24
- },
25
- "keywords": [],
26
- "author": "typicode <typicode@gmail.com>",
27
- "license": "SEE LICENSE IN ./LICENSE",
28
- "repository": {
29
- "type": "git",
30
- "url": "git+https://github.com/typicode/json-server.git"
19
+ "type": "module",
20
+ "dependencies": {
21
+ "@tinyhttp/app": "^3.0.1",
22
+ "@tinyhttp/cors": "^2.0.1",
23
+ "@tinyhttp/logger": "^2.1.0",
24
+ "chalk": "^5.6.2",
25
+ "chokidar": "^5.0.0",
26
+ "dot-prop": "^10.1.0",
27
+ "eta": "^4.5.0",
28
+ "inflection": "^3.0.2",
29
+ "json5": "^2.2.3",
30
+ "lowdb": "^7.0.1",
31
+ "milliparsec": "^5.1.0",
32
+ "sirv": "^3.0.2",
33
+ "sort-on": "^7.0.0"
31
34
  },
32
35
  "devDependencies": {
33
- "@eslint/js": "^9.11.0",
34
- "@sindresorhus/tsconfig": "^6.0.0",
35
- "@tailwindcss/typography": "^0.5.15",
36
- "@types/node": "^22.5.5",
37
- "concurrently": "^9.0.1",
38
- "eslint": "^9.11.0",
36
+ "@types/node": "^25.0.8",
37
+ "concurrently": "^9.2.1",
39
38
  "get-port": "^7.1.0",
40
- "globals": "^15.9.0",
41
- "husky": "^9.1.6",
39
+ "husky": "^9.1.7",
40
+ "oxfmt": "^0.24.0",
41
+ "oxlint": "^1.39.0",
42
42
  "tempy": "^3.1.0",
43
- "tsx": "^4.19.1",
44
- "type-fest": "^4.26.1",
45
- "typescript": "^5.6.2",
46
- "typescript-eslint": "^8.6.0"
43
+ "type-fest": "^5.4.0",
44
+ "typescript": "^5.9.3"
47
45
  },
48
- "dependencies": {
49
- "@tinyhttp/app": "^2.4.0",
50
- "@tinyhttp/cors": "^2.0.1",
51
- "@tinyhttp/logger": "^2.0.0",
52
- "chalk": "^5.3.0",
53
- "chokidar": "^4.0.1",
54
- "dot-prop": "^9.0.0",
55
- "eta": "^3.5.0",
56
- "inflection": "^3.0.0",
57
- "json5": "^2.2.3",
58
- "lowdb": "^7.0.1",
59
- "milliparsec": "^4.0.0",
60
- "sirv": "^2.0.4",
61
- "sort-on": "^6.1.0"
46
+ "engines": {
47
+ "node": ">=22.12.0"
48
+ },
49
+ "scripts": {
50
+ "dev": "node --watch --experimental-strip-types src/bin.ts fixtures/db.json",
51
+ "build": "rm -rf lib && tsc",
52
+ "typecheck": "tsc --noEmit",
53
+ "test": "node --experimental-strip-types --test src/*.test.ts",
54
+ "lint": "oxlint src",
55
+ "fmt": "oxfmt",
56
+ "fmt:check": "oxfmt --check"
62
57
  }
63
- }
58
+ }
package/views/index.html CHANGED
@@ -1,97 +1,95 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <style>
7
+ html {
8
+ font-size: 16px;
9
+ line-height: 1.5;
10
+ background-color: #fff;
11
+ color: #000;
12
+ }
3
13
 
4
- <head>
5
- <meta charset="UTF-8" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <style>
8
- html {
9
- font-size: 16px;
10
- line-height: 1.5;
11
- background-color: #fff;
12
- color: #000;
13
- }
14
-
15
- body {
16
- margin: 0 auto;
17
- max-width: 720px;
18
- padding: 0 16px;
19
- font-family: sans-serif;
20
- }
21
-
22
- a {
23
- color: #db2777;
24
- text-decoration: none;
25
- }
14
+ body {
15
+ margin: 0 auto;
16
+ max-width: 720px;
17
+ padding: 0 16px;
18
+ font-family: sans-serif;
19
+ }
26
20
 
27
- header {
28
- margin-bottom: 32px;
29
- padding: 16px 0;
30
- }
21
+ a {
22
+ color: #db2777;
23
+ text-decoration: none;
24
+ }
31
25
 
32
- nav {
33
- display: flex;
34
- justify-content: space-between;
35
- }
26
+ header {
27
+ margin-bottom: 32px;
28
+ padding: 16px 0;
29
+ }
36
30
 
37
- nav div a {
38
- margin-left: 16px;
39
- }
31
+ nav {
32
+ display: flex;
33
+ justify-content: space-between;
34
+ }
40
35
 
41
- ul {
42
- margin: 0;
43
- padding: 0;
44
- list-style: none;
45
- }
36
+ nav div a {
37
+ margin-left: 16px;
38
+ }
46
39
 
47
- li {
48
- margin-bottom: 8px;
49
- }
40
+ ul {
41
+ margin: 0;
42
+ padding: 0;
43
+ list-style: none;
44
+ }
50
45
 
51
- /* Dark mode styles */
52
- @media (prefers-color-scheme: dark) {
53
- html {
54
- background-color: #1e293b;
55
- color: #fff;
46
+ li {
47
+ margin-bottom: 8px;
56
48
  }
57
49
 
58
- a {
50
+ /* Dark mode styles */
51
+ @media (prefers-color-scheme: dark) {
52
+ html {
53
+ background-color: #1e293b;
54
+ color: #fff;
55
+ }
59
56
 
57
+ a {
58
+ }
60
59
  }
61
- }
62
-
63
- </style>
64
- </head>
60
+ </style>
61
+ </head>
65
62
 
66
- <body>
67
- <header>
68
- <nav>
69
- <strong>JSON Server</strong>
70
- <div>
71
- <a href="https://github.com/typicode/json-server">Docs</a>
72
- <a href="https://github.com/sponsors/typicode">♡ Sponsor</a>
73
- </div>
74
- </nav>
75
- </header>
76
- <main class="my-12">
77
- <p class="bg-gradient-to-r from-purple-500 via-pink-500 to-red-500 text-transparent bg-clip-text">✧*。٩(ˊᗜˋ*)و✧*。</p>
78
- <% if (Object.keys(it.data).length===0) { %>
63
+ <body>
64
+ <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>
72
+ </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) { %>
79
80
  <p>No resources found in JSON file</p>
80
- <% } %>
81
- <% Object.entries(it.data).forEach(function([name]) { %>
81
+ <% } %> <% Object.entries(it.data).forEach(function([name]) { %>
82
82
  <ul>
83
83
  <li>
84
84
  <a href="<%= name %>">/<%= name %></a>
85
85
  <span>
86
- <% if (Array.isArray(it.data[name])) { %>
87
- - <%= it.data[name].length %>
88
- <%= it.data[name].length> 1 ? 'items' : 'item' %>
86
+ <% if (Array.isArray(it.data[name])) { %> - <%= it.data[name].length %> <%=
87
+ it.data[name].length> 1 ? 'items' : 'item' %>
89
88
  </span>
90
89
  <% } %>
91
90
  </li>
92
91
  </ul>
93
- <% }) %>
94
- </main>
95
- </body>
96
-
97
- </html>
92
+ <% }) %>
93
+ </main>
94
+ </body>
95
+ </html>
package/lib/app.d.ts DELETED
@@ -1,8 +0,0 @@
1
- import { App } from '@tinyhttp/app';
2
- import { Low } from 'lowdb';
3
- import { Data } from './service.js';
4
- export type AppOptions = {
5
- logger?: boolean;
6
- static?: string[];
7
- };
8
- export declare function createApp(db: Low<Data>, options?: AppOptions): App<import("@tinyhttp/app").Request, import("@tinyhttp/app").Response<unknown>>;
package/lib/bin.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/lib/observer.d.ts DELETED
@@ -1,11 +0,0 @@
1
- import { Adapter } from 'lowdb';
2
- export declare class Observer<T> {
3
- #private;
4
- onReadStart: () => void;
5
- onReadEnd: (data: T | null) => void;
6
- onWriteStart: () => void;
7
- onWriteEnd: () => void;
8
- constructor(adapter: Adapter<T>);
9
- read(): Promise<T | null>;
10
- write(arg: T): Promise<void>;
11
- }
package/lib/service.d.ts DELETED
@@ -1,38 +0,0 @@
1
- import { Low } from 'lowdb';
2
- export type Item = Record<string, unknown>;
3
- export type Data = Record<string, Item[] | Item>;
4
- export declare function isItem(obj: unknown): obj is Item;
5
- export declare function isData(obj: unknown): obj is Record<string, Item[]>;
6
- export type PaginatedItems = {
7
- first: number;
8
- prev: number | null;
9
- next: number | null;
10
- last: number;
11
- pages: number;
12
- items: number;
13
- data: Item[];
14
- };
15
- export declare class Service {
16
- #private;
17
- constructor(db: Low<Data>);
18
- has(name: string): boolean;
19
- findById(name: string, id: string, query: {
20
- _embed?: string[] | string;
21
- }): Item | undefined;
22
- find(name: string, query?: {
23
- [key: string]: unknown;
24
- _embed?: string | string[];
25
- _sort?: string;
26
- _start?: number;
27
- _end?: number;
28
- _limit?: number;
29
- _page?: number;
30
- _per_page?: number;
31
- }): Item[] | PaginatedItems | Item | undefined;
32
- create(name: string, data?: Omit<Item, 'id'>): Promise<Item | undefined>;
33
- update(name: string, body?: Item): Promise<Item | undefined>;
34
- patch(name: string, body?: Item): Promise<Item | undefined>;
35
- updateById(name: string, id: string, body?: Item): Promise<Item | undefined>;
36
- patchById(name: string, id: string, body?: Item): Promise<Item | undefined>;
37
- destroyById(name: string, id: string, dependent?: string | string[]): Promise<Item | undefined>;
38
- }