@kollors/deep-json-server 1.0.0-alpha.1 → 1.0.0-alpha.2
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 +83 -49
- package/README.ru.md +81 -45
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/src/cli.js +88 -46
- package/dist/src/cli.js.map +1 -1
- package/dist/src/config.d.ts +2 -0
- package/dist/src/config.js +17 -4
- package/dist/src/config.js.map +1 -1
- package/dist/src/constants.d.ts +1 -0
- package/dist/src/constants.js +1 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/engine.d.ts +4 -4
- package/dist/src/engine.js +54 -121
- package/dist/src/engine.js.map +1 -1
- package/dist/src/errors.d.ts +6 -0
- package/dist/src/errors.js +9 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/features.d.ts +8 -0
- package/dist/src/features.js +18 -0
- package/dist/src/features.js.map +1 -0
- package/dist/src/files/disk-store.js +4 -4
- package/dist/src/files/disk-store.js.map +1 -1
- package/dist/src/graphql/preflight.d.ts +3 -0
- package/dist/src/graphql/preflight.js +28 -0
- package/dist/src/graphql/preflight.js.map +1 -0
- package/dist/src/graphql/routes.d.ts +4 -0
- package/dist/src/graphql/routes.js +28 -0
- package/dist/src/graphql/routes.js.map +1 -0
- package/dist/src/graphql.d.ts +1 -1
- package/dist/src/graphql.js +32 -28
- package/dist/src/graphql.js.map +1 -1
- package/dist/src/model.d.ts +1 -3
- package/dist/src/model.js +35 -9
- package/dist/src/model.js.map +1 -1
- package/dist/src/openapi/document.js +25 -22
- package/dist/src/openapi/document.js.map +1 -1
- package/dist/src/query/contract.d.ts +3 -0
- package/dist/src/query/contract.js +19 -0
- package/dist/src/query/contract.js.map +1 -0
- package/dist/src/query/filter.d.ts +4 -1
- package/dist/src/query/filter.js +76 -76
- package/dist/src/query/filter.js.map +1 -1
- package/dist/src/query/options.d.ts +1 -14
- package/dist/src/query/options.js +2 -107
- package/dist/src/query/options.js.map +1 -1
- package/dist/src/rest/options.d.ts +14 -0
- package/dist/src/rest/options.js +108 -0
- package/dist/src/rest/options.js.map +1 -0
- package/dist/src/rest/projection.d.ts +6 -0
- package/dist/src/rest/projection.js +37 -0
- package/dist/src/rest/projection.js.map +1 -0
- package/dist/src/rest/routes.d.ts +3 -0
- package/dist/src/rest/routes.js +48 -0
- package/dist/src/rest/routes.js.map +1 -0
- package/dist/src/schema.d.ts +17 -0
- package/dist/src/schema.js +23 -0
- package/dist/src/schema.js.map +1 -0
- package/dist/src/server.d.ts +2 -5
- package/dist/src/server.js +68 -132
- package/dist/src/server.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A JSON-backed mock server with REST, GraphQL, nested queries, binary files and schema exports. Requires Node.js 22 or newer.
|
|
6
6
|
|
|
7
|
-
**1.0.0-alpha.
|
|
7
|
+
**1.0.0-alpha.2 is a prerelease.** When upgrading from 0.x, update your model schema and query parameters using the examples below.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -12,29 +12,35 @@ A JSON-backed mock server with REST, GraphQL, nested queries, binary files and s
|
|
|
12
12
|
npm install @kollors/deep-json-server@alpha
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
To install a specific version, use `@1.0.0-alpha.2`.
|
|
16
16
|
|
|
17
17
|
## Quick start
|
|
18
18
|
|
|
19
|
+
Create two files in the same directory.
|
|
20
|
+
|
|
21
|
+
`database.json`:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"users": [
|
|
26
|
+
{ "id": "1", "fullName": "Мира Волкова" }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
19
31
|
`server.config.js`:
|
|
20
32
|
|
|
21
33
|
```js
|
|
22
34
|
export default {
|
|
23
|
-
database: { path: './database.json'
|
|
24
|
-
graphql: { enabled: true, path: './generated/schema.graphql' },
|
|
25
|
-
openapi: { path: './generated/openapi.yaml' },
|
|
26
|
-
server: { host: '127.0.0.1', port: 4001, pageSize: 10, maxPageSize: 100 },
|
|
35
|
+
database: { path: './database.json' },
|
|
27
36
|
};
|
|
28
37
|
```
|
|
29
38
|
|
|
30
39
|
```sh
|
|
31
40
|
npx deep-json-server server.config.js
|
|
32
|
-
npx deep-json-server --openapi-only --graphql-only server.config.js
|
|
33
41
|
```
|
|
34
42
|
|
|
35
|
-
The
|
|
36
|
-
|
|
37
|
-
Complete catalog examples: [database](examples/database.json), [model schema](examples/schema.json), [configuration](examples/server.config.js).
|
|
43
|
+
The user list is available at `http://127.0.0.1:4001/users`.
|
|
38
44
|
|
|
39
45
|
## Configuration
|
|
40
46
|
|
|
@@ -42,6 +48,8 @@ Complete catalog examples: [database](examples/database.json), [model schema](ex
|
|
|
42
48
|
|---|---|
|
|
43
49
|
| `database.path` / `database.data` | Exactly one: JSON file or in-memory collection object |
|
|
44
50
|
| `database.schema` | Model object or JSON schema-file path; optional for REST |
|
|
51
|
+
| `openapi.enabled` | Enable the specification endpoint; default `false` |
|
|
52
|
+
| `openapi.endpoint` | Specification path; default `/openapi.json` |
|
|
45
53
|
| `openapi.path` | YAML export destination |
|
|
46
54
|
| `openapi.info` | Optional `title`, `version`, `description` |
|
|
47
55
|
| `graphql.enabled` | Enable GraphQL HTTP endpoint; default `false` |
|
|
@@ -54,24 +62,34 @@ Complete catalog examples: [database](examples/database.json), [model schema](ex
|
|
|
54
62
|
| `files.data` | In-memory binary files |
|
|
55
63
|
| `files.directory`, `files.metadata` | Disk storage directory and metadata JSON file; both required |
|
|
56
64
|
|
|
57
|
-
|
|
65
|
+
Relative paths resolve from the configuration file's directory. When passing a configuration object to `createServer()`, paths resolve from the working directory. The server works with a copy of in-memory input.
|
|
58
66
|
|
|
59
|
-
CLI
|
|
60
|
-
|
|
61
|
-
| Flag | Action |
|
|
67
|
+
| CLI flag | Action |
|
|
62
68
|
|---|---|
|
|
63
|
-
| `--files` | Enable
|
|
64
|
-
| `--graphql` | Enable GraphQL
|
|
65
|
-
| `--openapi` |
|
|
66
|
-
| `--
|
|
67
|
-
| `--
|
|
68
|
-
| `--
|
|
69
|
-
| `--
|
|
69
|
+
| `--files` | Enable file routes |
|
|
70
|
+
| `--graphql` | Enable the GraphQL API |
|
|
71
|
+
| `--openapi` | Enable the OpenAPI endpoint |
|
|
72
|
+
| `--host <host>` | Server address |
|
|
73
|
+
| `--port <port>` | Server port |
|
|
74
|
+
| `--help`, `-h` | Show help |
|
|
75
|
+
| `--version`, `-v` | Show package version |
|
|
76
|
+
|
|
77
|
+
Setting priority: CLI → configuration → `HOST`/`PORT` → defaults. File routes are enabled when `files` is configured.
|
|
78
|
+
|
|
79
|
+
To generate schemas, specify the format and configuration file:
|
|
70
80
|
|
|
71
|
-
|
|
81
|
+
```sh
|
|
82
|
+
npx deep-json-server generate openapi server.config.js
|
|
83
|
+
npx deep-json-server generate graphql server.config.js
|
|
84
|
+
npx deep-json-server generate openapi,graphql server.config.js
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The command reads `database.schema` and writes schemas to `openapi.path` and `graphql.path`. Generation requires no database contents or file store.
|
|
72
88
|
|
|
73
89
|
## Model schema
|
|
74
90
|
|
|
91
|
+
Examples: [database](examples/database.json), [model schema](examples/schema.json), [configuration](examples/server.config.js).
|
|
92
|
+
|
|
75
93
|
```json
|
|
76
94
|
{
|
|
77
95
|
"Country": {
|
|
@@ -104,11 +122,11 @@ Both exporters can be combined. Any `--*-only` flag prevents startup. CLI file r
|
|
|
104
122
|
| OpenAPI 3.0.3 export | Available | Error when requested |
|
|
105
123
|
| GraphQL SDL / API | Available | Error when requested |
|
|
106
124
|
|
|
107
|
-
Explicit schemas are strict: undeclared fields and collections are rejected, except storage keys inferred from relations. Existing data is validated on startup.
|
|
125
|
+
Explicit schemas are strict: undeclared fields and collections are rejected, except storage keys inferred from relations. Existing data is validated on startup. Generation uses the model definitions. Schemaless REST generates an `id` and preserves arbitrary JSON fields. Filters and individual field selections use identifier-style names; other fields are returned through `scope=*`.
|
|
108
126
|
|
|
109
127
|
### Fields
|
|
110
128
|
|
|
111
|
-
|
|
129
|
+
The `type` property accepts `string`, `number`, `boolean`, `object`, or a model name. Append `[]` for an array: `string[]`, `object[]`, `Genre[]`. Use dotted paths for nested fields, such as `actors.fullName`.
|
|
112
130
|
|
|
113
131
|
| Properties | Meaning |
|
|
114
132
|
|---|---|
|
|
@@ -125,11 +143,11 @@ Types: `string`, `number`, `boolean`, `object`, or a model name. Append `[]` for
|
|
|
125
143
|
| `minimum`, `maximum` | Inclusive numeric bounds |
|
|
126
144
|
| `source`, `target`, `onDelete` | Relation metadata |
|
|
127
145
|
|
|
128
|
-
String
|
|
146
|
+
String and numeric constraints on `string[]`/`number[]` apply to every element. `required` and `nullable` apply to the entire array; `default` and `example` contain a complete array. Elements must match the array's type and be non-null. `required` requires the field to be present; an ordinary array may still be empty.
|
|
129
147
|
|
|
130
|
-
|
|
148
|
+
Each model requires exactly one primary key of type `string` or `number`, declared at the top level. The name is arbitrary: `id`, `username`, `code`. If `generated` is omitted, the client supplies the value on creation. Generated fields must be declared at the top level, are excluded from input types and cannot have `default`. Replacing a record preserves generated values and read-only fields, including nested objects. To protect fields inside an array, mark the entire array or its containing object as `readOnly`. Objects containing only server-managed fields are output-only.
|
|
131
149
|
|
|
132
|
-
For example, a `LocalUser` with primary `username` and `password: {"type":"string","required":true,"writeOnly":true}` has `localUser(username: ...)` and `/localUsers/{username}`. `writeOnly`
|
|
150
|
+
For example, a `LocalUser` with primary key `username` and `password: {"type":"string","required":true,"writeOnly":true}` has `localUser(username: ...)` and `/localUsers/{username}`. A `writeOnly` field accepts input and is excluded from responses, `scope`, filters and ordering.
|
|
133
151
|
|
|
134
152
|
### Relations
|
|
135
153
|
|
|
@@ -141,20 +159,20 @@ For example, a `LocalUser` with primary `username` and `password: {"type":"strin
|
|
|
141
159
|
}
|
|
142
160
|
```
|
|
143
161
|
|
|
144
|
-
`Genre`
|
|
162
|
+
`Genre` returns an object; `Genre[]` returns a list. `source` defaults to the current model's primary key, `target` to the target model's primary key. These defaults also apply to nested relations. Paths start at the root of their respective records: in this example, `actors.genreIds` contains the current actor's genre keys.
|
|
145
163
|
|
|
146
|
-
|
|
164
|
+
Relation keys are stored in the database and included among the record's own fields. Their types are inferred from the matched keys. A `source` field pointing to a target primary key can be omitted from the field declarations: the schema infers an array of keys for a list relation or a scalar key for a single relation. Declare the storage field explicitly when the mapping is ambiguous.
|
|
147
165
|
|
|
148
166
|
Reverse example: `User.movies = {"type":"Movie[]","target":"actors.userId"}`. A movie is returned once even if several actors match. A single relation resolving to multiple targets is invalid.
|
|
149
167
|
|
|
150
|
-
Every supplied direct
|
|
168
|
+
Every supplied direct relation key must point to an existing record. `required: true` on a relation requires at least one target before response filtering/pagination. Reverse relations using the primary key as `source` may be empty unless required. Missing single relations return `null`.
|
|
151
169
|
|
|
152
170
|
`onDelete` describes what happens **when a target record is deleted**:
|
|
153
171
|
|
|
154
172
|
- `restrict` (default): refuse deletion while a surviving owner refers to the target.
|
|
155
173
|
- `cascade`: delete the referring owner. For `User.country`, deleting the country deletes its users. For `Movie.actors.user`, deleting the user removes matching actor elements and retains the movie.
|
|
156
174
|
|
|
157
|
-
|
|
175
|
+
Cascading deletion runs as one operation, including cyclic relations. A validation failure cancels the entire operation. `onDelete` rules also apply to explicitly declared reverse relations; account for both rules when defining both directions.
|
|
158
176
|
|
|
159
177
|
## Queries and responses
|
|
160
178
|
|
|
@@ -164,9 +182,11 @@ Collections and lists of objects, including embedded `object[]` fields, return:
|
|
|
164
182
|
{ "data": [], "total": 0 }
|
|
165
183
|
```
|
|
166
184
|
|
|
167
|
-
Primitive arrays
|
|
185
|
+
Primitive arrays are returned as plain arrays. Every object list accepts optional `where`, `order` and `pager`. Processing order is filter → sort → pagination. `total` is the filtered record count before pagination.
|
|
168
186
|
|
|
169
|
-
`
|
|
187
|
+
Use `page` and `pageSize` in `pager`. The default is the first page with the size from `server.pageSize`. Both values must be positive integers; `pageSize` is limited by `server.maxPageSize`. Out-of-range pages return empty `data` with the total matching record count in `total`.
|
|
188
|
+
|
|
189
|
+
`where` uses field operators `eq`, `ne`, `in`, string `contains`/`startsWith`/`endsWith`, and comparisons `gt`, `gte`, `lt`, `lte`. Combine conditions with `and`, `or`, `not`. Arrays support `some`, `every`, `none`; primitive arrays also support `contains`, `in`. String matching is case-insensitive. A field condition is an object containing an operator, such as `{ "id": { "eq": "1" } }`.
|
|
170
190
|
|
|
171
191
|
```json
|
|
172
192
|
{
|
|
@@ -182,9 +202,9 @@ Primitive arrays remain plain arrays. Every object list accepts optional `where`
|
|
|
182
202
|
}
|
|
183
203
|
```
|
|
184
204
|
|
|
185
|
-
Root
|
|
205
|
+
Root `where` selects records from the main collection. `where` inside a relation filters its elements while retaining the parent record. Each nested list is processed independently. Filtering by a relation works independently of its inclusion in the response.
|
|
186
206
|
|
|
187
|
-
`order` is an array of `{ "field": "fullName", "direction": "ASC" }` rules. Earlier rules have priority;
|
|
207
|
+
`order` is an array of `{ "field": "fullName", "direction": "ASC" }` rules. Earlier rules have priority; equal values retain storage order. Null and missing values compare equally. REST uses dotted field paths; GraphQL uses generated enums (`profile_name` for `profile.name`). Ambiguous enum names cause a generation error. Sorting supports scalar fields of the current object, including nested fields. Related lists accept their own `order`.
|
|
188
208
|
|
|
189
209
|
### REST
|
|
190
210
|
|
|
@@ -197,7 +217,7 @@ Root filters choose parents. Filters inside a selected relation only trim that r
|
|
|
197
217
|
| PATCH | `/users/{id}` | `userUpdate` |
|
|
198
218
|
| DELETE | `/users/{id}` | `userDelete` |
|
|
199
219
|
|
|
200
|
-
The path
|
|
220
|
+
The path parameter name follows the primary key. POST, PUT and PATCH accept a JSON record object. PUT replaces the record while retaining its key and server-managed fields. PATCH merges fields at the top level; supplied nested objects are replaced while preserving their read-only fields. Creation and replacement require all mandatory fields. Updates validate supplied values and the final record. Missing records return `404`; conflicts return `409`. DELETE returns the deleted record.
|
|
201
221
|
|
|
202
222
|
Query parameters `where`, `order`, `pager`, `nested` contain JSON. `scope` is a selection string. Example shown before URL encoding:
|
|
203
223
|
|
|
@@ -215,7 +235,7 @@ const params = new URLSearchParams({
|
|
|
215
235
|
const response = await fetch(`/users?${params}`);
|
|
216
236
|
```
|
|
217
237
|
|
|
218
|
-
`scope=*,actors(user(id,fullName),genres(*))` selects own fields and
|
|
238
|
+
`scope=*,actors(user(id,fullName),genres(*))` selects own fields and the specified relations. `*` includes the current object's own fields and stored keys, except `writeOnly` fields. Relations are listed explicitly. The default selection is own fields. Lists retain the `{ data, total }` response structure.
|
|
219
239
|
|
|
220
240
|
`nested` maps full response paths to list options:
|
|
221
241
|
|
|
@@ -229,7 +249,7 @@ const response = await fetch(`/users?${params}`);
|
|
|
229
249
|
}
|
|
230
250
|
```
|
|
231
251
|
|
|
232
|
-
A nested
|
|
252
|
+
A path in `nested` must be selected by `scope` and point to an object list. Single-record routes and mutations accept `scope` and `nested`; root `where`, `order` and `pager` apply to collection GET. Invalid names and unsafe paths return `400`.
|
|
233
253
|
|
|
234
254
|
### GraphQL
|
|
235
255
|
|
|
@@ -252,10 +272,9 @@ query {
|
|
|
252
272
|
}
|
|
253
273
|
```
|
|
254
274
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
String primary keys use GraphQL `ID`; ordinary strings use `String`, numbers use `Float`, pagination uses `Int`. Schema enums preserve valid string labels; other values receive `VALUE_0`, `VALUE_1`, etc. Schema constraints such as string length and formats are enforced by the shared runtime validator; SDL alone cannot express all constraints. Introspection and ordinary query/mutation execution are supported; this release does not add subscriptions or bulk mutations.
|
|
275
|
+
The query `user(id: ...)` returns one record or `null` if it is missing. Mutations are `userCreate(data: ...)`, `userReplace(id: ..., data: ...)`, `userUpdate(id: ..., data: ...)`, `userDelete(id: ...)`. For models containing only generated fields, the create mutation takes no `data` argument. Writes and validation follow the same rules as REST. Relations selected in a mutation result determine the response contents.
|
|
258
276
|
|
|
277
|
+
String primary keys use GraphQL `ID`; ordinary strings use `String`, numbers use `Float`, and pagination parameters use `Int`. Schema enums preserve valid string labels; other values receive `VALUE_0`, `VALUE_1`, etc. String lengths, formats and other model constraints are validated by the server during request execution. Introspection is available for exploring the schema. Selected list arguments are validated before executing mutations. Errors include `extensions.code`: `INVALID_INPUT`, `INVALID_QUERY`, `NOT_FOUND`, `CONFLICT` or `INTERNAL_ERROR`.
|
|
259
278
|
|
|
260
279
|
## Example database
|
|
261
280
|
|
|
@@ -363,10 +382,10 @@ String primary keys use GraphQL `ID`; ordinary strings use `String`, numbers use
|
|
|
363
382
|
|
|
364
383
|
## Files
|
|
365
384
|
|
|
366
|
-
Add `files.directory` and `files.metadata` to the
|
|
385
|
+
Add `files.directory` and `files.metadata` to the configuration and start the server:
|
|
367
386
|
|
|
368
387
|
```bash
|
|
369
|
-
deep-json-server
|
|
388
|
+
deep-json-server server.config.js
|
|
370
389
|
```
|
|
371
390
|
|
|
372
391
|
For temporary tests, use `files.data` instead. Each initial record contains `name`, `mimeType`, binary `content` as a `Uint8Array`, and an optional `directory`. Uploaded files then remain in memory until the process exits.
|
|
@@ -422,9 +441,9 @@ Content-Type: application/json
|
|
|
422
441
|
|
|
423
442
|
`PATCH` returns the updated metadata with status `200`; if a file already exists at the new path, the server returns `409`. `DELETE` returns `204` without a response body. A missing file returns `404` on every path-based operation. File paths in URLs are relative to `files.directory`, and all returned URLs are relative to the server origin.
|
|
424
443
|
|
|
425
|
-
In disk mode, the binary is stored at `<files.directory>/<directory>/<name>`. The metadata file contains only `directory`, `mimeType`, and `name`; `size` is read from the actual file, while response URLs are computed. The server creates directories automatically and keeps validated metadata in memory while running. Use a disk-backed database and file storage from only one server process at a time, and do not edit stored files or metadata until that process stops. Paths below `files.directory` may not contain symbolic links, and file names are restricted to values that are portable across supported operating systems. The metadata file may be absent initially and is created on the first upload.
|
|
444
|
+
In disk mode, the binary is stored at `<files.directory>/<directory>/<name>`. The metadata file contains only `directory`, `mimeType`, and `name`; `size` is read from the actual file, while response URLs are computed. The server creates directories automatically and keeps validated metadata in memory while running. Use a disk-backed database and file storage from only one server process at a time, and do not edit stored files or metadata until that process stops. Paths below `files.directory` may not contain symbolic links, and file names are restricted to values that are portable across supported operating systems. The metadata file may be absent initially and is created on the first upload.
|
|
426
445
|
|
|
427
|
-
|
|
446
|
+
Send the file as a binary request body. In a browser, use `xhr.send(file)` and track progress through `XMLHttpRequest.upload.onprogress`. The default maximum size is 100 MiB and can be changed through `server.maxFileSize`. Missing or unsafe headers and paths return `400`, an exceeded limit returns `413`, and a missing, malformed, or Fastify-unsupported `Content-Type` returns `400` or `415`, depending on which validation stage rejects it.
|
|
428
447
|
|
|
429
448
|
## Programmatic API
|
|
430
449
|
|
|
@@ -440,19 +459,34 @@ await server.listen();
|
|
|
440
459
|
// await server.close();
|
|
441
460
|
```
|
|
442
461
|
|
|
443
|
-
|
|
462
|
+
The `openapi()` and `graphql()` methods return schemas. `fastify()` returns the server instance for configuration and startup. The database and enabled services initialize on `ready()`, `listen()` or the first `inject()`; initialization errors stop startup. Override server features with `createServer(config, { files: false, graphql: true, openapi: true })`.
|
|
463
|
+
|
|
464
|
+
Generators can also be used independently:
|
|
465
|
+
|
|
466
|
+
```js
|
|
467
|
+
import { generateOpenapi, generateGraphql, writeOpenapi, writeGraphql } from '@kollors/deep-json-server';
|
|
468
|
+
|
|
469
|
+
const document = await generateOpenapi('./schema.json', { files: true });
|
|
470
|
+
const sdl = await generateGraphql('./schema.json');
|
|
471
|
+
await writeOpenapi(document, './generated/openapi.yaml');
|
|
472
|
+
await writeGraphql(sdl, './generated/schema.graphql');
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
`generateOpenapi()` also accepts `host`, `port`, `pageSize`, `maxPageSize` and `info`. Pass a schema object instead of a path if preferred. Servers and generators use their own copy of the model.
|
|
444
476
|
|
|
445
477
|
## Storage and development
|
|
446
478
|
|
|
447
|
-
Updates
|
|
479
|
+
Updates run sequentially within one server instance and are validated on a copy of the data before saving. Use one server process per database file. `increment` counters are stored next to the database in `<database path>.counters.json`; keep that file with the database. Numbers are reserved before the data write, so a failed write can leave gaps but cannot reuse a reserved number.
|
|
448
480
|
|
|
449
|
-
|
|
481
|
+
The server is intended for mocking APIs. Implement authentication and password hashing in your application if needed.
|
|
450
482
|
|
|
451
483
|
```sh
|
|
452
484
|
npm ci
|
|
453
485
|
npm run verify
|
|
454
486
|
```
|
|
455
487
|
|
|
456
|
-
|
|
488
|
+
The command checks types, code style, test coverage and installation from the package archive.
|
|
489
|
+
|
|
490
|
+
To publish a new alpha, update the version in `package.json` and push to `main`. GitHub Actions creates the version tag and publishes to npm `alpha` through trusted publishing. Already published versions are skipped. If the tag exists but publication failed, a retry uses that tag and verifies that the package files match it. Pushing a version tag also triggers publication; stable versions publish to `latest`.
|
|
457
491
|
|
|
458
492
|
License: MIT.
|