@kollors/deep-json-server 1.0.0-alpha.7 → 1.0.0-alpha.9
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 +168 -109
- package/README.ru.md +171 -112
- package/dist/index.d.ts +5 -6
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/src/auth/contract.d.ts +6 -2
- package/dist/src/auth/contract.js +8 -1
- package/dist/src/auth/contract.js.map +1 -1
- package/dist/src/auth/input.d.ts +18 -0
- package/dist/src/auth/input.js +34 -0
- package/dist/src/auth/input.js.map +1 -0
- package/dist/src/auth/password.d.ts +4 -0
- package/dist/src/auth/password.js +5 -1
- package/dist/src/auth/password.js.map +1 -1
- package/dist/src/auth/routes.d.ts +1 -1
- package/dist/src/auth/routes.js +4 -1
- package/dist/src/auth/routes.js.map +1 -1
- package/dist/src/auth/service.d.ts +48 -9
- package/dist/src/auth/service.js +143 -68
- package/dist/src/auth/service.js.map +1 -1
- package/dist/src/auth/store.d.ts +26 -0
- package/dist/src/auth/store.js +82 -0
- package/dist/src/auth/store.js.map +1 -0
- package/dist/src/cli/index.d.ts +2 -2
- package/dist/src/cli/index.js +70 -84
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/core/config-values.d.ts +28 -0
- package/dist/src/core/config-values.js +53 -0
- package/dist/src/core/config-values.js.map +1 -0
- package/dist/src/core/constants.d.ts +1 -1
- package/dist/src/core/constants.js +1 -1
- package/dist/src/core/database.d.ts +10 -12
- package/dist/src/core/database.js +4 -4
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/engine.d.ts +3 -2
- package/dist/src/core/engine.js +53 -44
- package/dist/src/core/engine.js.map +1 -1
- package/dist/src/core/lifecycle/mutation.d.ts +3 -3
- package/dist/src/core/lifecycle/mutation.js +2 -2
- package/dist/src/core/lifecycle/mutation.js.map +1 -1
- package/dist/src/core/lifecycle/options.d.ts +1 -0
- package/dist/src/core/lifecycle/options.js +2 -4
- package/dist/src/core/lifecycle/options.js.map +1 -1
- package/dist/src/core/model.d.ts +18 -3
- package/dist/src/core/model.js +17 -7
- package/dist/src/core/model.js.map +1 -1
- package/dist/src/core/mutations/write.d.ts +1 -2
- package/dist/src/core/mutations/write.js.map +1 -1
- package/dist/src/core/operations.d.ts +33 -0
- package/dist/src/core/operations.js +10 -0
- package/dist/src/core/operations.js.map +1 -0
- package/dist/src/core/pagination.d.ts +2 -2
- package/dist/src/core/pagination.js +3 -5
- package/dist/src/core/pagination.js.map +1 -1
- package/dist/src/core/paths.d.ts +2 -2
- package/dist/src/core/paths.js +15 -5
- package/dist/src/core/paths.js.map +1 -1
- package/dist/src/core/storage.d.ts +2 -0
- package/dist/src/core/storage.js +2 -0
- package/dist/src/core/storage.js.map +1 -0
- package/dist/src/files/contract.d.ts +6 -7
- package/dist/src/files/contract.js.map +1 -1
- package/dist/src/files/disk-store.js +3 -20
- package/dist/src/files/disk-store.js.map +1 -1
- package/dist/src/files/index.d.ts +1 -1
- package/dist/src/files/index.js +5 -2
- package/dist/src/files/index.js.map +1 -1
- package/dist/src/files/memory-store.js +16 -16
- package/dist/src/files/memory-store.js.map +1 -1
- package/dist/src/files/streams.d.ts +5 -0
- package/dist/src/files/streams.js +20 -0
- package/dist/src/files/streams.js.map +1 -0
- package/dist/src/graphql/entry.d.ts +11 -2
- package/dist/src/graphql/entry.js +12 -2
- package/dist/src/graphql/entry.js.map +1 -1
- package/dist/src/graphql/{public.d.ts → generate.d.ts} +3 -2
- package/dist/src/graphql/{public.js → generate.js} +4 -2
- package/dist/src/graphql/generate.js.map +1 -0
- package/dist/src/graphql/resolvers.js +1 -1
- package/dist/src/graphql/resolvers.js.map +1 -1
- package/dist/src/graphql/schema.js +6 -3
- package/dist/src/graphql/schema.js.map +1 -1
- package/dist/src/openapi/auth.d.ts +2 -2
- package/dist/src/openapi/auth.js +82 -15
- package/dist/src/openapi/auth.js.map +1 -1
- package/dist/src/openapi/document.js +16 -13
- package/dist/src/openapi/document.js.map +1 -1
- package/dist/src/openapi/entry.d.ts +12 -1
- package/dist/src/openapi/entry.js +12 -1
- package/dist/src/openapi/entry.js.map +1 -1
- package/dist/src/openapi/{public.d.ts → generate.d.ts} +9 -16
- package/dist/src/openapi/generate.js +41 -0
- package/dist/src/openapi/generate.js.map +1 -0
- package/dist/src/openapi/options.d.ts +18 -0
- package/dist/src/openapi/options.js +13 -0
- package/dist/src/openapi/options.js.map +1 -0
- package/dist/src/openapi/write.d.ts +5 -0
- package/dist/src/openapi/write.js +12 -0
- package/dist/src/openapi/write.js.map +1 -0
- package/dist/src/rest/routes.js +6 -9
- package/dist/src/rest/routes.js.map +1 -1
- package/dist/src/server/config.d.ts +29 -34
- package/dist/src/server/config.js +83 -211
- package/dist/src/server/config.js.map +1 -1
- package/dist/src/server/create.d.ts +3 -5
- package/dist/src/server/create.js +35 -29
- package/dist/src/server/create.js.map +1 -1
- package/dist/src/server/features.d.ts +0 -11
- package/dist/src/server/features.js +0 -20
- package/dist/src/server/features.js.map +1 -1
- package/dist/src/server/model.d.ts +6 -0
- package/dist/src/server/model.js +14 -0
- package/dist/src/server/model.js.map +1 -0
- package/dist/src/server/public.d.ts +1 -2
- package/package.json +1 -1
- package/dist/src/graphql/lazy.d.ts +0 -10
- package/dist/src/graphql/lazy.js +0 -13
- package/dist/src/graphql/lazy.js.map +0 -1
- package/dist/src/graphql/public.js.map +0 -1
- package/dist/src/openapi/index.d.ts +0 -13
- package/dist/src/openapi/index.js +0 -37
- package/dist/src/openapi/index.js.map +0 -1
- package/dist/src/openapi/lazy.d.ts +0 -11
- package/dist/src/openapi/lazy.js +0 -13
- package/dist/src/openapi/lazy.js.map +0 -1
- package/dist/src/openapi/public.js +0 -26
- package/dist/src/openapi/public.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A JSON mock server with REST, GraphQL, related records, file uploads and schema exports. Supports user login, owner and administrator permissions, record timestamps and soft deletion. Requires Node.js 22 or newer.
|
|
6
6
|
|
|
7
|
-
**1.0.0-alpha.
|
|
7
|
+
**1.0.0-alpha.9 is a prerelease.** When upgrading from the previous alpha, add `storage`, use `source` for data sources, move definitions under `models`, and move timestamps and soft deletion settings to the schema root. Configuration sections now enable modules; use `--generate` or `--generate-only` for exports. The second `createServer` argument has been removed.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ A JSON mock server with REST, GraphQL, related records, file uploads and schema
|
|
|
12
12
|
npm install @kollors/deep-json-server@alpha
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
To install a specific version, use `@1.0.0-alpha.
|
|
15
|
+
To install a specific version, use `@1.0.0-alpha.9`.
|
|
16
16
|
|
|
17
17
|
## Quick start
|
|
18
18
|
|
|
@@ -31,9 +31,7 @@ Create two files in the same directory.
|
|
|
31
31
|
`server.config.js`:
|
|
32
32
|
|
|
33
33
|
```js
|
|
34
|
-
export default {
|
|
35
|
-
database: { path: './database.json' },
|
|
36
|
-
};
|
|
34
|
+
export default { storage: 'file', database: { source: './database.json' } };
|
|
37
35
|
```
|
|
38
36
|
|
|
39
37
|
```sh
|
|
@@ -46,47 +44,53 @@ Add a [model schema](#model-schema) to define relations and validation. See [que
|
|
|
46
44
|
|
|
47
45
|
## Configuration
|
|
48
46
|
|
|
47
|
+
With `storage: 'file'`, all sources and the schema are paths. With `'memory'`, they are in-memory data. Modes cannot be mixed. The presence of `auth`, `files`, `graphql` and `openapi` enables those modules; `graphql: {}` and `openapi: {}` use the default endpoints.
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
export default {
|
|
51
|
+
storage: 'file',
|
|
52
|
+
database: { source: './database.json', schema: './schema.json' },
|
|
53
|
+
auth: { source: './users.json', expiresIn: 3600 },
|
|
54
|
+
files: { source: './uploads' },
|
|
55
|
+
graphql: { path: './generated/schema.graphql' },
|
|
56
|
+
openapi: { path: './generated/openapi.yaml' },
|
|
57
|
+
server: { host: '127.0.0.1', port: 4001 },
|
|
58
|
+
};
|
|
59
|
+
```
|
|
60
|
+
|
|
49
61
|
| Setting | Meaning |
|
|
50
62
|
|---|---|
|
|
51
|
-
| `
|
|
52
|
-
| `database.
|
|
53
|
-
| `database.
|
|
54
|
-
| `
|
|
55
|
-
| `openapi.enabled` | Enable the specification endpoint; default `false` |
|
|
56
|
-
| `openapi.endpoint` | Specification path; default `/openapi.json` |
|
|
57
|
-
| `openapi.path` | YAML export destination |
|
|
58
|
-
| `openapi.info` | Optional metadata object: required `title` and `version`, optional `description` |
|
|
59
|
-
| `graphql.enabled` | Enable GraphQL HTTP endpoint; default `false` |
|
|
60
|
-
| `graphql.endpoint` | Endpoint path; default `/graphql` |
|
|
61
|
-
| `graphql.path` | GraphQL SDL export destination |
|
|
62
|
-
| `auth.users` | Path to a JSON array of auth users, or an in-memory array |
|
|
63
|
+
| `storage` | Required: `file` or `memory`; applies to all sources and the schema |
|
|
64
|
+
| `database.source` | Database JSON path or collection object |
|
|
65
|
+
| `database.schema` | Schema JSON path or schema object; optional for REST |
|
|
66
|
+
| `auth.source` | Users JSON path or user array |
|
|
63
67
|
| `auth.expiresIn` | Session lifetime in seconds; default 3600 |
|
|
68
|
+
| `files.source` | Files directory or initial file array |
|
|
69
|
+
| `files.metadata` | For `file` only: metadata JSON path; defaults to `_database.json` inside `files.source` |
|
|
70
|
+
| `graphql.endpoint` | HTTP endpoint; default `/graphql` |
|
|
71
|
+
| `graphql.path` | GraphQL SDL export destination |
|
|
72
|
+
| `openapi.endpoint` | HTTP endpoint; default `/openapi.json` |
|
|
73
|
+
| `openapi.path` | OpenAPI export destination |
|
|
74
|
+
| `openapi.info` | Metadata: required `title` and `version`, optional `description` |
|
|
64
75
|
| `server.host`, `server.port` | Defaults `127.0.0.1`, `4001`; CLI also reads `HOST`/`PORT` |
|
|
65
76
|
| `server.pageSize`, `server.maxPageSize` | Defaults 10 and 100; default size is capped by the maximum |
|
|
66
77
|
| `server.cors`, `server.logger` | Default `true`; logger also accepts Fastify logger options |
|
|
67
78
|
| `server.maxFileSize` | Default 100 MiB |
|
|
68
|
-
| `files.data` | In-memory binary files |
|
|
69
|
-
| `files.directory`, `files.metadata` | Disk storage directory and metadata JSON file; both required |
|
|
70
79
|
|
|
71
|
-
Relative paths resolve from the configuration file
|
|
72
|
-
|
|
73
|
-
Set `server.port` to `0` to let the operating system choose an available port. The OpenAPI endpoint uses a relative server URL.
|
|
80
|
+
Relative paths resolve from the configuration file directory, or from the working directory with `createServer(config)`. In-memory data, including the schema, is copied. Port `0` lets the system choose an available port.
|
|
74
81
|
|
|
75
82
|
### CLI
|
|
76
83
|
|
|
77
|
-
|
|
|
84
|
+
| Flag | Action |
|
|
78
85
|
|---|---|
|
|
79
|
-
| `--
|
|
80
|
-
| `--
|
|
81
|
-
| `--soft-delete` | Enable soft deletion globally |
|
|
82
|
-
| `--graphql` | Enable the GraphQL API |
|
|
83
|
-
| `--openapi` | Enable the OpenAPI endpoint |
|
|
86
|
+
| `--generate` | Export schemas, then start the server |
|
|
87
|
+
| `--generate-only` | Export schemas and exit |
|
|
84
88
|
| `--host <host>` | Server address |
|
|
85
89
|
| `--port <port>` | Server port |
|
|
86
|
-
| `--help
|
|
87
|
-
| `--version
|
|
90
|
+
| `--help, -h` | Help |
|
|
91
|
+
| `--version, -v` | Package version |
|
|
88
92
|
|
|
89
|
-
|
|
93
|
+
Address precedence: CLI → configuration → `HOST`/`PORT` → defaults. Without generation flags, only the server starts. `--generate` and `--generate-only` are mutually exclusive.
|
|
90
94
|
|
|
91
95
|
## Model schema
|
|
92
96
|
|
|
@@ -94,28 +98,52 @@ Examples: [database](examples/database.json), [model schema](examples/schema.jso
|
|
|
94
98
|
|
|
95
99
|
```json
|
|
96
100
|
{
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
101
|
+
"api": [
|
|
102
|
+
"openapi",
|
|
103
|
+
"graphql"
|
|
104
|
+
],
|
|
105
|
+
"models": {
|
|
106
|
+
"Country": {
|
|
107
|
+
"collection": "countries",
|
|
108
|
+
"fields": {
|
|
109
|
+
"id": {
|
|
110
|
+
"type": "string",
|
|
111
|
+
"primary": true,
|
|
112
|
+
"generated": "uuid"
|
|
113
|
+
},
|
|
114
|
+
"name": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"required": true
|
|
117
|
+
},
|
|
118
|
+
"users": {
|
|
119
|
+
"type": "User[]",
|
|
120
|
+
"target": "countryId"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"User": {
|
|
125
|
+
"collection": "users",
|
|
126
|
+
"fields": {
|
|
127
|
+
"id": {
|
|
128
|
+
"type": "string",
|
|
129
|
+
"primary": true,
|
|
130
|
+
"generated": "uuid"
|
|
131
|
+
},
|
|
132
|
+
"fullName": {
|
|
133
|
+
"type": "string",
|
|
134
|
+
"required": true
|
|
135
|
+
},
|
|
136
|
+
"country": {
|
|
137
|
+
"type": "Country",
|
|
138
|
+
"source": "countryId"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
113
141
|
}
|
|
114
142
|
}
|
|
115
143
|
}
|
|
116
144
|
```
|
|
117
145
|
|
|
118
|
-
`api`
|
|
146
|
+
Model definitions belong in `models`. The schema root can define `api`, `timestamps` and `softDelete`; a model can override each setting. API precedence is model → schema root → configuration sections. Arrays replace the inherited value; `[]` excludes a model from GraphQL and OpenAPI while REST remains available. An explicit list does not activate an absent module. Related models must allow the same format. Model names must be valid identifiers; type and operation collisions cause errors. `and`, `or` and `not` are reserved filter names.
|
|
119
147
|
|
|
120
148
|
| Capability | With schema | Without schema |
|
|
121
149
|
|---|---|---|
|
|
@@ -252,10 +280,7 @@ const scope = [
|
|
|
252
280
|
fullName: true,
|
|
253
281
|
movies: [
|
|
254
282
|
{ id: true, title: true },
|
|
255
|
-
{
|
|
256
|
-
order: [{ field: 'title', direction: 'ASC' }],
|
|
257
|
-
pager: { page: 1, pageSize: 5 },
|
|
258
|
-
},
|
|
283
|
+
{ order: [{ field: 'title', direction: 'ASC' }], pager: { page: 1, pageSize: 5 } },
|
|
259
284
|
],
|
|
260
285
|
},
|
|
261
286
|
{
|
|
@@ -346,10 +371,10 @@ mutation {
|
|
|
346
371
|
|
|
347
372
|
### GraphQL
|
|
348
373
|
|
|
349
|
-
Set `database.schema` and
|
|
374
|
+
Set `database.schema` and add `graphql: {}` to the configuration:
|
|
350
375
|
|
|
351
376
|
```sh
|
|
352
|
-
npx deep-json-server
|
|
377
|
+
npx deep-json-server server.config.js
|
|
353
378
|
```
|
|
354
379
|
|
|
355
380
|
Send requests to `/graphql` using POST with `Content-Type: application/json` and a body of `{ "query": "…", "variables": {} }`. Change the path through `graphql.endpoint`.
|
|
@@ -386,35 +411,33 @@ Errors include `extensions.code`: `INVALID_INPUT`, `INVALID_QUERY`, `NOT_FOUND`,
|
|
|
386
411
|
|
|
387
412
|
## OpenAPI and schema exports
|
|
388
413
|
|
|
389
|
-
Exports use OpenAPI 3.0.3.
|
|
390
|
-
|
|
391
|
-
To serve the specification over HTTP, set `database.schema` and enable `openapi.enabled: true`, or start the server with `--openapi`. The JSON document is available at `/openapi.json` by default; change the path through `openapi.endpoint`. Open it in a separately installed Swagger UI or import it into an API client.
|
|
392
|
-
|
|
393
|
-
To generate schemas, specify the format and configuration file:
|
|
394
|
-
|
|
395
|
-
```sh
|
|
396
|
-
npx deep-json-server generate openapi server.config.js
|
|
397
|
-
npx deep-json-server generate graphql server.config.js
|
|
398
|
-
npx deep-json-server generate openapi,graphql server.config.js
|
|
399
|
-
```
|
|
414
|
+
Exports use OpenAPI 3.0.3. Add `openapi: {}` and `database.schema` to serve the specification at `/openapi.json`. Change the route with `openapi.endpoint`. Open the document in Swagger UI or import it into an API client.
|
|
400
415
|
|
|
401
|
-
|
|
416
|
+
Set output paths to save schemas:
|
|
402
417
|
|
|
403
418
|
```js
|
|
404
419
|
export default {
|
|
405
|
-
|
|
420
|
+
storage: 'file',
|
|
421
|
+
database: { source: './database.json', schema: './schema.json' },
|
|
406
422
|
openapi: { path: './generated/openapi.yaml' },
|
|
407
423
|
graphql: { path: './generated/schema.graphql' },
|
|
408
424
|
};
|
|
409
425
|
```
|
|
410
426
|
|
|
411
|
-
|
|
427
|
+
```bash
|
|
428
|
+
npx deep-json-server server.config.js --generate-only
|
|
429
|
+
npx deep-json-server server.config.js --generate
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
`--generate-only` exports and exits; `--generate` starts the server after exporting. Configuration sections select the formats. Each selected format requires its own `path`. Missing sections, missing destinations or generation errors fail the command before server startup.
|
|
433
|
+
|
|
434
|
+
Export reads only the schema. Database records, auth users and file storage are not opened; configuration values are still validated. The schema is loaded once, including when export is followed by startup. All destinations and selected schemas are checked before writing. Outputs cannot overwrite the configuration, database, schema, users, counters or file metadata. A disk write failure can leave an already saved file from another format.
|
|
412
435
|
|
|
413
436
|
## Authentication
|
|
414
437
|
|
|
415
|
-
The `auth` section enables
|
|
438
|
+
The `auth` section enables registration, login and permission checks for record changes in REST and GraphQL. Reads and all file operations remain public.
|
|
416
439
|
|
|
417
|
-
|
|
440
|
+
Define the first administrator in the initial data. For example, create `auth.json` with `setup-auth.mjs`:
|
|
418
441
|
|
|
419
442
|
```js
|
|
420
443
|
import { writeFile } from 'node:fs/promises';
|
|
@@ -422,64 +445,99 @@ import { hashPassword } from '@kollors/deep-json-server/auth';
|
|
|
422
445
|
|
|
423
446
|
const password = process.env.DJS_PASSWORD;
|
|
424
447
|
if (!password) throw new Error('Set DJS_PASSWORD');
|
|
425
|
-
await writeFile(
|
|
426
|
-
|
|
427
|
-
|
|
448
|
+
await writeFile(
|
|
449
|
+
'./auth.json',
|
|
450
|
+
JSON.stringify(
|
|
451
|
+
[{ id: '1', username: 'admin', passwordHash: await hashPassword(password), isAdmin: true }],
|
|
452
|
+
null,
|
|
453
|
+
2,
|
|
454
|
+
),
|
|
455
|
+
{ flag: 'wx', mode: 0o600 },
|
|
456
|
+
);
|
|
428
457
|
```
|
|
429
458
|
|
|
430
459
|
Set `DJS_PASSWORD` and run `node setup-auth.mjs`. Add the file to your server configuration:
|
|
431
460
|
|
|
432
461
|
```js
|
|
433
462
|
export default {
|
|
434
|
-
|
|
435
|
-
|
|
463
|
+
storage: 'file',
|
|
464
|
+
database: { source: './database.json' },
|
|
465
|
+
auth: { source: './auth.json', expiresIn: 3600 },
|
|
436
466
|
};
|
|
437
467
|
```
|
|
438
468
|
|
|
439
|
-
Start with `npx deep-json-server server.config.js`.
|
|
440
|
-
|
|
441
|
-
| REST request | Input | Response |
|
|
442
|
-
|---|---|---|
|
|
443
|
-
| `POST /auth/login` | JSON `{ "username": "admin", "password": "…" }` | `{ accessToken, expiresIn, user: { id, username, isAdmin } }` |
|
|
444
|
-
| `GET /auth/me` | Bearer token | `{ id, username, isAdmin }` |
|
|
445
|
-
| `POST /auth/logout` | Bearer token | `{ success: true }` |
|
|
469
|
+
Start with `npx deep-json-server server.config.js`. Each initial user needs a unique string `id`, a unique `username` and a `passwordHash` created by the helper. `isAdmin` defaults to `false`. Passwords use salted scrypt hashes.
|
|
446
470
|
|
|
447
|
-
|
|
471
|
+
With `storage: 'memory'`, pass an array in `auth.source`:
|
|
448
472
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
## Record dates, deletion and ownership
|
|
473
|
+
```js
|
|
474
|
+
import { hashPassword } from '@kollors/deep-json-server/auth';
|
|
452
475
|
|
|
453
|
-
|
|
476
|
+
const password = process.env.DJS_PASSWORD;
|
|
477
|
+
if (!password) throw new Error('Set DJS_PASSWORD');
|
|
454
478
|
|
|
455
|
-
```js
|
|
456
479
|
export default {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
480
|
+
storage: 'memory',
|
|
481
|
+
database: { source: { items: [] } },
|
|
482
|
+
auth: {
|
|
483
|
+
source: [
|
|
484
|
+
{ id: '1', username: 'admin', passwordHash: await hashPassword(password), isAdmin: true },
|
|
485
|
+
],
|
|
462
486
|
},
|
|
463
|
-
auth: { users: './auth.json' },
|
|
464
487
|
};
|
|
465
488
|
```
|
|
466
489
|
|
|
467
|
-
|
|
490
|
+
Auth users are stored separately from database collections. With `storage: 'file'`, registration, password changes and admin changes are saved to `auth.source` through `lowdb`. With `'memory'`, changes stay in an internal copy and disappear on restart; the original array is unchanged. A file write failure leaves users and sessions unchanged. The file is read at startup; restart after manual edits.
|
|
491
|
+
|
|
492
|
+
| REST request | JSON body | Response |
|
|
493
|
+
|---|---|---|
|
|
494
|
+
| `POST /auth/register` | `{ "username": "anna", "password": "…" }` | `201`: `{ id, username, isAdmin: false }` |
|
|
495
|
+
| `POST /auth/login` | `{ "username": "anna", "password": "…" }` | `{ accessToken, expiresIn, user: { id, username, isAdmin } }` |
|
|
496
|
+
| `GET /auth/me` | — | `{ id, username, isAdmin }` |
|
|
497
|
+
| `POST /auth/logout` | — | `{ success: true }` |
|
|
498
|
+
| `PATCH /auth/users/:id/password` | `{ "currentPassword": "…", "newPassword": "…" }` | `{ success: true }` |
|
|
499
|
+
| `PATCH /auth/users/:id/admin` | `{ "isAdmin": true }` | `{ id, username, isAdmin }` |
|
|
500
|
+
|
|
501
|
+
Registration and login are public. Send `Authorization: Bearer <accessToken>` for the other methods. Registration creates an ordinary user with a generated `id`; requests cannot include `id`, `passwordHash` or `isAdmin`. Usernames are case-sensitive and unique; duplicates return `409`. A username must contain a non-whitespace character and be at most 256 characters long. Passwords must contain 1–1024 characters. Values are not trimmed. Registration does not create a session: log in afterwards.
|
|
502
|
+
|
|
503
|
+
Users can change only their own password by supplying `currentPassword` and `newPassword`. Administrators follow the same rule for their own password. An administrator can change an ordinary user's password with just `newPassword`. Changing another administrator's password returns `403`. A successful password change ends all sessions of the target user, including the current session when changing your own password; log in again. An incorrect current password returns `401` without changing sessions.
|
|
504
|
+
|
|
505
|
+
Only administrators can change `isAdmin`. They can grant or remove another user's admin status. An administrator can remove their own status only if another administrator remains; otherwise the request returns `409`. This check accounts for concurrent requests. Existing tokens use the new permissions as soon as the change is saved, including for GraphQL mutations. An administrator may demote another administrator and then change their password as an ordinary user.
|
|
506
|
+
|
|
507
|
+
Invalid or expired tokens return `401`, insufficient permissions return `403`, and an absent user for an otherwise permitted operation returns `404`. Invalid request bodies return `400`. Login, registration and password changes may return `429` when too many password computations are running; login also limits active sessions. Sessions are kept in memory and disappear on restart. Logout revokes only the supplied token.
|
|
508
|
+
|
|
509
|
+
OpenAPI describes all auth routes and their Bearer token requirements. In Swagger UI, paste a token from login into **Authorize**. For schema exports, enable auth in the configuration and run `npx deep-json-server server.config.js --generate-only`; the users file is not read during generation. Auth methods are exposed through REST. GraphQL checks the same token when changing records. GraphQL and OpenAPI require `database.schema`.
|
|
510
|
+
|
|
511
|
+
## Record dates, deletion and ownership
|
|
512
|
+
|
|
513
|
+
Set defaults at the schema root. Here `Note` inherits soft deletion and disables timestamps:
|
|
468
514
|
|
|
469
515
|
```json
|
|
470
516
|
{
|
|
471
|
-
"
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
"
|
|
475
|
-
|
|
476
|
-
"
|
|
477
|
-
"
|
|
517
|
+
"timestamps": true,
|
|
518
|
+
"softDelete": true,
|
|
519
|
+
"models": {
|
|
520
|
+
"Note": {
|
|
521
|
+
"collection": "notes",
|
|
522
|
+
"timestamps": false,
|
|
523
|
+
"fields": {
|
|
524
|
+
"id": {
|
|
525
|
+
"type": "string",
|
|
526
|
+
"primary": true,
|
|
527
|
+
"generated": "uuid"
|
|
528
|
+
},
|
|
529
|
+
"text": {
|
|
530
|
+
"type": "string",
|
|
531
|
+
"required": true
|
|
532
|
+
}
|
|
533
|
+
}
|
|
478
534
|
}
|
|
479
535
|
}
|
|
480
536
|
}
|
|
481
537
|
```
|
|
482
538
|
|
|
539
|
+
Precedence: model → schema root → `false`. Explicit `false` disables an inherited setting. Without a schema, timestamps and soft deletion are disabled.
|
|
540
|
+
|
|
483
541
|
| Field | Enabled by | Meaning |
|
|
484
542
|
|---|---|---|
|
|
485
543
|
| `createdAt`, `updatedAt` | `timestamps` | Creation and last update time |
|
|
@@ -516,8 +574,9 @@ Files are available through REST and documented in OpenAPI. Add storage to the c
|
|
|
516
574
|
|
|
517
575
|
```js
|
|
518
576
|
export default {
|
|
519
|
-
|
|
520
|
-
|
|
577
|
+
storage: 'file',
|
|
578
|
+
database: { source: './database.json' },
|
|
579
|
+
files: { source: './uploads', metadata: './files.json' },
|
|
521
580
|
};
|
|
522
581
|
```
|
|
523
582
|
|
|
@@ -527,7 +586,7 @@ Start the server:
|
|
|
527
586
|
npx deep-json-server server.config.js
|
|
528
587
|
```
|
|
529
588
|
|
|
530
|
-
For temporary tests,
|
|
589
|
+
For temporary tests, choose `storage: 'memory'` and pass an array in `files.source`. 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.
|
|
531
590
|
|
|
532
591
|
Upload one file directly as the request body. `Content-Name` contains the URI-encoded file name, `Content-Type` contains its MIME type, and the optional `Content-Directory` contains the URI-encoded relative directory:
|
|
533
592
|
|
|
@@ -578,9 +637,9 @@ Content-Type: application/json
|
|
|
578
637
|
}
|
|
579
638
|
```
|
|
580
639
|
|
|
581
|
-
`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.
|
|
640
|
+
`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.source`, and all returned URLs are relative to the server origin.
|
|
582
641
|
|
|
583
|
-
In disk mode, the binary is stored at `<files.
|
|
642
|
+
In disk mode, the binary is stored at `<files.source>/<directory>/<name>`. Metadata stores `directory`, `mimeType` and `name`; the server reads the size from the file and builds its URLs. Directories and the metadata file are created when needed.
|
|
584
643
|
|
|
585
644
|
Use one server process per disk database and file store. Stop it before editing stored files or metadata manually. Storage paths cannot contain symbolic links. Uploads and renames cannot overwrite the database, counters, schema, auth users, loaded configuration or metadata file.
|
|
586
645
|
|
|
@@ -600,7 +659,7 @@ await server.listen();
|
|
|
600
659
|
|
|
601
660
|
The `openapi()` and `graphql()` methods return schemas and require `database.schema`. `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.
|
|
602
661
|
|
|
603
|
-
|
|
662
|
+
`createServer(config)` takes one argument. Configuration sections control modules exactly as in the CLI. The `openapi()` and `graphql()` methods require their respective sections. They return schemas without writing files.
|
|
604
663
|
|
|
605
664
|
The root import `@kollors/deep-json-server` also provides these functions. Server adapters load when enabled. Generators can be used independently:
|
|
606
665
|
|
|
@@ -614,7 +673,7 @@ await writeOpenapi(document, './generated/openapi.yaml');
|
|
|
614
673
|
await writeGraphql(sdl, './generated/schema.graphql');
|
|
615
674
|
```
|
|
616
675
|
|
|
617
|
-
|
|
676
|
+
Standalone generators accept a schema path or object without a server configuration. The selected function supplies the default format; schema and model `api` settings can restrict it. Timestamps and soft deletion come from the schema. `{ auth: true }` adds ownership fields; OpenAPI also describes auth routes and token requirements. `hashPassword()` is available from the root package.
|
|
618
677
|
|
|
619
678
|
`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. Pagination sizes must be positive integers; `pageSize` cannot exceed `maxPageSize`.
|
|
620
679
|
|