@kollors/deep-json-server 1.0.0-alpha.9 → 1.0.0-beta.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 +169 -128
- package/README.ru.md +169 -128
- package/dist/src/cli/index.js +14 -23
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/core/constants.d.ts +1 -1
- package/dist/src/core/constants.js +1 -1
- package/dist/src/core/constants.js.map +1 -1
- package/dist/src/core/engine.d.ts +3 -15
- package/dist/src/core/engine.js +10 -69
- package/dist/src/core/engine.js.map +1 -1
- package/dist/src/core/lifecycle/mutation.js +4 -4
- package/dist/src/core/lifecycle/mutation.js.map +1 -1
- package/dist/src/core/lifecycle/options.d.ts +15 -0
- package/dist/src/core/lifecycle/options.js +13 -0
- package/dist/src/core/lifecycle/options.js.map +1 -1
- package/dist/src/core/model.d.ts +1 -0
- package/dist/src/core/model.js +29 -4
- package/dist/src/core/model.js.map +1 -1
- package/dist/src/core/mutations/write.js +4 -0
- package/dist/src/core/mutations/write.js.map +1 -1
- package/dist/src/core/paths.js +1 -7
- package/dist/src/core/paths.js.map +1 -1
- package/dist/src/core/query/execute.d.ts +25 -0
- package/dist/src/core/query/execute.js +82 -0
- package/dist/src/core/query/execute.js.map +1 -0
- package/dist/src/core/query/filter.js +1 -1
- package/dist/src/core/query/filter.js.map +1 -1
- package/dist/src/core/query/options.js +2 -2
- package/dist/src/core/query/options.js.map +1 -1
- package/dist/src/core/records.d.ts +2 -1
- package/dist/src/core/records.js +5 -2
- package/dist/src/core/records.js.map +1 -1
- package/dist/src/files/disk-metadata.d.ts +9 -0
- package/dist/src/files/disk-metadata.js +44 -0
- package/dist/src/files/disk-metadata.js.map +1 -0
- package/dist/src/files/disk-paths.d.ts +15 -0
- package/dist/src/files/disk-paths.js +100 -0
- package/dist/src/files/disk-paths.js.map +1 -0
- package/dist/src/files/disk-store.js +21 -165
- package/dist/src/files/disk-store.js.map +1 -1
- package/dist/src/files/index.js +1 -1
- package/dist/src/files/index.js.map +1 -1
- package/dist/src/graphql/preflight.js +2 -0
- package/dist/src/graphql/preflight.js.map +1 -1
- package/dist/src/graphql/resolvers.js +7 -3
- package/dist/src/graphql/resolvers.js.map +1 -1
- package/dist/src/graphql/routes.js +4 -1
- package/dist/src/graphql/routes.js.map +1 -1
- package/dist/src/graphql/schema.js +5 -2
- package/dist/src/graphql/schema.js.map +1 -1
- package/dist/src/openapi/document.js +30 -19
- package/dist/src/openapi/document.js.map +1 -1
- package/dist/src/openapi/registry.d.ts +11 -0
- package/dist/src/openapi/registry.js +20 -0
- package/dist/src/openapi/registry.js.map +1 -0
- package/dist/src/rest/options.d.ts +11 -3
- package/dist/src/rest/options.js +15 -0
- package/dist/src/rest/options.js.map +1 -1
- package/dist/src/rest/projection.d.ts +15 -3
- package/dist/src/rest/projection.js +51 -15
- package/dist/src/rest/projection.js.map +1 -1
- package/dist/src/rest/routes.js +18 -7
- package/dist/src/rest/routes.js.map +1 -1
- package/dist/src/server/bootstrap.d.ts +7 -0
- package/dist/src/server/bootstrap.js +48 -0
- package/dist/src/server/bootstrap.js.map +1 -0
- package/dist/src/server/config.d.ts +2 -2
- package/dist/src/server/config.js +5 -5
- package/dist/src/server/config.js.map +1 -1
- package/dist/src/server/create.d.ts +1 -1
- package/dist/src/server/create.js +11 -85
- package/dist/src/server/create.js.map +1 -1
- package/dist/src/server/http.d.ts +12 -0
- package/dist/src/server/http.js +40 -0
- package/dist/src/server/http.js.map +1 -0
- package/dist/src/server/openapi-options.d.ts +6 -0
- package/dist/src/server/openapi-options.js +15 -0
- package/dist/src/server/openapi-options.js.map +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -4,15 +4,15 @@
|
|
|
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-
|
|
7
|
+
**Breaking changes: 1.0.0-beta.2.** The REST `scope` wildcard selects only scalar fields that do not store relation keys. Arrays, objects, relations and their keys must be selected explicitly. With auth enabled, record permissions are available through the virtual `actions` field.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
npm install @kollors/deep-json-server@
|
|
12
|
+
npm install @kollors/deep-json-server@beta
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
To install a specific version, use `@1.0.0-
|
|
15
|
+
To install a specific version, use `@1.0.0-beta.2`.
|
|
16
16
|
|
|
17
17
|
## Quick start
|
|
18
18
|
|
|
@@ -44,7 +44,7 @@ Add a [model schema](#model-schema) to define relations and validation. See [que
|
|
|
44
44
|
|
|
45
45
|
## Configuration
|
|
46
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
|
|
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: {}` enable only the HTTP endpoints at their defaults; add `target` to export a schema.
|
|
48
48
|
|
|
49
49
|
```js
|
|
50
50
|
export default {
|
|
@@ -52,8 +52,8 @@ export default {
|
|
|
52
52
|
database: { source: './database.json', schema: './schema.json' },
|
|
53
53
|
auth: { source: './users.json', expiresIn: 3600 },
|
|
54
54
|
files: { source: './uploads' },
|
|
55
|
-
graphql: {
|
|
56
|
-
openapi: {
|
|
55
|
+
graphql: { target: './generated/schema.graphql' },
|
|
56
|
+
openapi: { target: './generated/openapi.yaml' },
|
|
57
57
|
server: { host: '127.0.0.1', port: 4001 },
|
|
58
58
|
};
|
|
59
59
|
```
|
|
@@ -66,11 +66,11 @@ export default {
|
|
|
66
66
|
| `auth.source` | Users JSON path or user array |
|
|
67
67
|
| `auth.expiresIn` | Session lifetime in seconds; default 3600 |
|
|
68
68
|
| `files.source` | Files directory or initial file array |
|
|
69
|
-
| `files.metadata` | For `file` only: metadata JSON path; defaults to
|
|
69
|
+
| `files.metadata` | For `file` only: metadata JSON path; defaults to `.files.json` inside `files.source` |
|
|
70
70
|
| `graphql.endpoint` | HTTP endpoint; default `/graphql` |
|
|
71
|
-
| `graphql.
|
|
71
|
+
| `graphql.target` | GraphQL SDL export destination |
|
|
72
72
|
| `openapi.endpoint` | HTTP endpoint; default `/openapi.json` |
|
|
73
|
-
| `openapi.
|
|
73
|
+
| `openapi.target` | OpenAPI export destination |
|
|
74
74
|
| `openapi.info` | Metadata: required `title` and `version`, optional `description` |
|
|
75
75
|
| `server.host`, `server.port` | Defaults `127.0.0.1`, `4001`; CLI also reads `HOST`/`PORT` |
|
|
76
76
|
| `server.pageSize`, `server.maxPageSize` | Defaults 10 and 100; default size is capped by the maximum |
|
|
@@ -154,7 +154,7 @@ Model definitions belong in `models`. The schema root can define `api`, `timesta
|
|
|
154
154
|
|
|
155
155
|
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.
|
|
156
156
|
|
|
157
|
-
Schemaless REST generates an `id` and preserves arbitrary JSON fields. Filters and individual field selections use identifier-style names
|
|
157
|
+
Schemaless REST generates an `id` and preserves arbitrary JSON fields. Filters and individual field selections use identifier-style names. `scope=[{"*":true}]` returns top-level JSON scalars; arrays and objects must be selected by name. Fields with mixed value types can be read explicitly, but filtering, ordering and paging heterogeneous lists require an explicit schema.
|
|
158
158
|
|
|
159
159
|
Each model requires `collection`, the database collection and REST path name, and `fields`, its field definitions. The model name (`User`) determines GraphQL type and operation names. `api` controls format availability; `timestamps` and `softDelete` override global settings for that model.
|
|
160
160
|
|
|
@@ -212,6 +212,110 @@ Every supplied direct relation key must point to an existing record. `required:
|
|
|
212
212
|
|
|
213
213
|
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.
|
|
214
214
|
|
|
215
|
+
## Example database
|
|
216
|
+
|
|
217
|
+
```json
|
|
218
|
+
{
|
|
219
|
+
"countries": [
|
|
220
|
+
{
|
|
221
|
+
"id": "1",
|
|
222
|
+
"isArchived": false,
|
|
223
|
+
"name": "Ардения"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"id": "2",
|
|
227
|
+
"isArchived": false,
|
|
228
|
+
"name": "Велория"
|
|
229
|
+
}
|
|
230
|
+
],
|
|
231
|
+
"genres": [
|
|
232
|
+
{
|
|
233
|
+
"id": "1",
|
|
234
|
+
"isArchived": false,
|
|
235
|
+
"name": "Криминал",
|
|
236
|
+
"parentIds": []
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"id": "2",
|
|
240
|
+
"isArchived": false,
|
|
241
|
+
"name": "Гангстер",
|
|
242
|
+
"parentIds": ["1"]
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"id": "3",
|
|
246
|
+
"isArchived": false,
|
|
247
|
+
"name": "Драма",
|
|
248
|
+
"parentIds": []
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"id": "4",
|
|
252
|
+
"isArchived": false,
|
|
253
|
+
"name": "Комедия",
|
|
254
|
+
"parentIds": []
|
|
255
|
+
}
|
|
256
|
+
],
|
|
257
|
+
"movies": [
|
|
258
|
+
{
|
|
259
|
+
"actors": [
|
|
260
|
+
{
|
|
261
|
+
"genreIds": ["2", "3"],
|
|
262
|
+
"id": "movie-1-actor-1",
|
|
263
|
+
"userId": "1"
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"genreIds": ["3"],
|
|
267
|
+
"id": "movie-1-actor-2",
|
|
268
|
+
"userId": "2"
|
|
269
|
+
}
|
|
270
|
+
],
|
|
271
|
+
"coverSrc": "https://example.com/covers/shadows-of-ardenia.jpg",
|
|
272
|
+
"description": "Наследница портового города раскрывает заговор двух соперничающих семей.",
|
|
273
|
+
"id": "1",
|
|
274
|
+
"isArchived": false,
|
|
275
|
+
"publisherIds": ["2"],
|
|
276
|
+
"title": "Тени Ардении"
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"actors": [],
|
|
280
|
+
"coverSrc": "https://example.com/covers/northern-star.jpg",
|
|
281
|
+
"description": "Ночной администратор старого отеля случайно становится участником поисков пропавшей картины.",
|
|
282
|
+
"id": "2",
|
|
283
|
+
"isArchived": false,
|
|
284
|
+
"publisherIds": ["1"],
|
|
285
|
+
"title": "Полночь в «Северной звезде»"
|
|
286
|
+
}
|
|
287
|
+
],
|
|
288
|
+
"publishers": [
|
|
289
|
+
{
|
|
290
|
+
"id": "1",
|
|
291
|
+
"isArchived": false,
|
|
292
|
+
"name": "Northlight Studio"
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"id": "2",
|
|
296
|
+
"isArchived": false,
|
|
297
|
+
"name": "Aurora Pictures"
|
|
298
|
+
}
|
|
299
|
+
],
|
|
300
|
+
"users": [
|
|
301
|
+
{
|
|
302
|
+
"bornAt": "1988-03-14",
|
|
303
|
+
"countryId": "1",
|
|
304
|
+
"fullName": "Мира Волкова",
|
|
305
|
+
"id": "1",
|
|
306
|
+
"isArchived": false
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"bornAt": "1991-11-02",
|
|
310
|
+
"countryId": "2",
|
|
311
|
+
"fullName": "Леон Ветров",
|
|
312
|
+
"id": "2",
|
|
313
|
+
"isArchived": false
|
|
314
|
+
}
|
|
315
|
+
]
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
215
319
|
## Queries and responses
|
|
216
320
|
|
|
217
321
|
The movie, actor and genre examples use the full [example schema](examples/schema.json). Run them with the [example configuration](examples/server.config.js):
|
|
@@ -293,7 +397,7 @@ const params = new URLSearchParams({ scope: JSON.stringify(scope) });
|
|
|
293
397
|
const response = await fetch(`/users?${params}`);
|
|
294
398
|
```
|
|
295
399
|
|
|
296
|
-
Select
|
|
400
|
+
Select scalars and primitive arrays with `true`, and objects or relations with their own scope arrays. Without arguments, the array contains only the fields object. `"*": true` includes only scalar fields of the current model that do not store relation keys. Arrays, objects, relations, their keys and `writeOnly` fields are not included by the wildcard. A relation key remains available through an explicit selection such as `{ "*": true, "countryId": true }`. Without a schema, a key is excluded from `*` only when the server can infer its relation from the name and an existing collection.
|
|
297
401
|
|
|
298
402
|
For example, select a movie's own fields, its actors' users and sorted genres:
|
|
299
403
|
|
|
@@ -314,9 +418,9 @@ For example, select a movie's own fields, its actors' users and sorted genres:
|
|
|
314
418
|
]
|
|
315
419
|
```
|
|
316
420
|
|
|
317
|
-
Omitting `scope` returns
|
|
421
|
+
Omitting `scope` returns scalar fields, as with `[{"*":true}]`. An empty selection `[{}]` returns an object without fields. Lists retain the `{ data, total }` response structure.
|
|
318
422
|
|
|
319
|
-
Arguments are available only on lists. Single-record queries and mutation responses can set arguments on their embedded lists. Parameters are validated even on empty data; an invalid response selection rolls back record changes. Invalid scopes return `400`. The JSON length limit is 10,000 characters; selection depth is limited to 32 levels.
|
|
423
|
+
Arguments are available only on lists. A list can instead use `{ "union": [scope, ...] }`: each part is a normal list scope, parts run in array order, and the first record for each primary key is kept. This also works for nested lists. Single-record queries and mutation responses can set arguments on their embedded lists. Parameters are validated even on empty data; an invalid response selection rolls back record changes. Invalid scopes return `400`. The JSON length limit is 10,000 characters; selection depth is limited to 32 levels.
|
|
320
424
|
|
|
321
425
|
### Nested writes
|
|
322
426
|
|
|
@@ -350,7 +454,16 @@ The key name and type follow the target model. An object containing only a key s
|
|
|
350
454
|
|
|
351
455
|
A supplied list replaces the relation's membership. PATCH preserves omitted relations; PUT clears omitted writable links. `[]` clears a list and `null` clears a nullable single relation. Removing a link does not delete the related record. Required relations must remain populated.
|
|
352
456
|
|
|
353
|
-
Use either the relation field or its storage key in an object, for example `genres` or `genreIds`.
|
|
457
|
+
Use either the relation field or its storage key in an object, for example `genres` or `genreIds`. Supplying both fields returns `400 INVALID_INPUT`, even when their key sets match:
|
|
458
|
+
|
|
459
|
+
```json
|
|
460
|
+
{
|
|
461
|
+
"genreIds": ["1", "2"],
|
|
462
|
+
"genres": ["1", "2"]
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
The server neither gives one field priority nor merges the values; the entire operation is rolled back. Reverse relations update the target key. If a target path crosses an array and the server cannot identify one element to attach, provide the array with the intended keys explicitly. Protected keys cannot be changed.
|
|
354
467
|
|
|
355
468
|
All nested changes belong to the main record's transaction. A validation error, missing record or invalid response selection rolls back the entire operation. Updating a shared record affects every record linked to it.
|
|
356
469
|
|
|
@@ -419,8 +532,8 @@ Set output paths to save schemas:
|
|
|
419
532
|
export default {
|
|
420
533
|
storage: 'file',
|
|
421
534
|
database: { source: './database.json', schema: './schema.json' },
|
|
422
|
-
openapi: {
|
|
423
|
-
graphql: {
|
|
535
|
+
openapi: { target: './generated/openapi.yaml' },
|
|
536
|
+
graphql: { target: './generated/schema.graphql' },
|
|
424
537
|
};
|
|
425
538
|
```
|
|
426
539
|
|
|
@@ -429,9 +542,9 @@ npx deep-json-server server.config.js --generate-only
|
|
|
429
542
|
npx deep-json-server server.config.js --generate
|
|
430
543
|
```
|
|
431
544
|
|
|
432
|
-
`--generate-only` exports and exits; `--generate` starts the server after exporting. Configuration sections select the formats. Each selected format requires its own `
|
|
545
|
+
`--generate-only` exports and exits; `--generate` starts the server after exporting. Configuration sections select the formats. Each selected format requires its own `target`. Missing sections, missing targets or generation errors fail the command before server startup.
|
|
433
546
|
|
|
434
|
-
Export
|
|
547
|
+
Export does not open the database, user records or files. Every selected `target` is checked before writing and cannot overwrite the configuration, database, schema, users, counters or file metadata.
|
|
435
548
|
|
|
436
549
|
## Authentication
|
|
437
550
|
|
|
@@ -487,7 +600,7 @@ export default {
|
|
|
487
600
|
};
|
|
488
601
|
```
|
|
489
602
|
|
|
490
|
-
Auth users are stored separately from database
|
|
603
|
+
Auth users are stored separately from the database. In file mode, changes are saved to `auth.source`; in memory mode, they disappear on restart. The supplied user array is not modified. Restart the server after editing the file manually.
|
|
491
604
|
|
|
492
605
|
| REST request | JSON body | Response |
|
|
493
606
|
|---|---|---|
|
|
@@ -506,7 +619,39 @@ Only administrators can change `isAdmin`. They can grant or remove another user'
|
|
|
506
619
|
|
|
507
620
|
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
621
|
|
|
509
|
-
|
|
622
|
+
Every model record has a virtual `actions` object when auth is enabled. It is calculated for the current user and is never stored. In REST, request it explicitly through `scope`:
|
|
623
|
+
|
|
624
|
+
```json
|
|
625
|
+
[
|
|
626
|
+
{
|
|
627
|
+
"id": true,
|
|
628
|
+
"actions": [{ "*": true }]
|
|
629
|
+
}
|
|
630
|
+
]
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
The object contains `update`, `replace` and `delete`. An owner or administrator receives `true`; an anonymous or unrelated user receives `false`. Records without `createdById` are editable only by administrators. A missing token keeps reads public and returns false flags. A supplied invalid token returns `401` in REST or `UNAUTHENTICATED` in GraphQL.
|
|
634
|
+
|
|
635
|
+
GraphQL exposes the same field and requires its normal explicit selection:
|
|
636
|
+
|
|
637
|
+
```graphql
|
|
638
|
+
query {
|
|
639
|
+
itemList {
|
|
640
|
+
data {
|
|
641
|
+
id
|
|
642
|
+
actions {
|
|
643
|
+
update
|
|
644
|
+
replace
|
|
645
|
+
delete
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
`actions` is available on root and related model records, including mutation results. It cannot be written, filtered or ordered. Plain embedded objects and auth user responses do not receive it.
|
|
653
|
+
|
|
654
|
+
OpenAPI describes auth routes, optional Bearer authentication on record reads, required authentication on record changes and the `actions` response field. 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 reading permissions or changing records. GraphQL and OpenAPI require `database.schema`.
|
|
510
655
|
|
|
511
656
|
## Record dates, deletion and ownership
|
|
512
657
|
|
|
@@ -576,7 +721,7 @@ Files are available through REST and documented in OpenAPI. Add storage to the c
|
|
|
576
721
|
export default {
|
|
577
722
|
storage: 'file',
|
|
578
723
|
database: { source: './database.json' },
|
|
579
|
-
files: { source: './uploads'
|
|
724
|
+
files: { source: './uploads' },
|
|
580
725
|
};
|
|
581
726
|
```
|
|
582
727
|
|
|
@@ -639,7 +784,7 @@ Content-Type: application/json
|
|
|
639
784
|
|
|
640
785
|
`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.
|
|
641
786
|
|
|
642
|
-
In disk mode, the binary is stored at `<files.source>/<directory>/<name>`. Metadata
|
|
787
|
+
In disk mode, the binary is stored at `<files.source>/<directory>/<name>`. Metadata defaults to `<files.source>/.files.json`; set `files.metadata` for another location. Directories and the metadata file are created when needed.
|
|
643
788
|
|
|
644
789
|
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.
|
|
645
790
|
|
|
@@ -673,114 +818,10 @@ await writeOpenapi(document, './generated/openapi.yaml');
|
|
|
673
818
|
await writeGraphql(sdl, './generated/schema.graphql');
|
|
674
819
|
```
|
|
675
820
|
|
|
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.
|
|
821
|
+
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 and `actions` fields; OpenAPI also describes auth routes and token requirements. `hashPassword()` is available from the root package.
|
|
677
822
|
|
|
678
823
|
`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`.
|
|
679
824
|
|
|
680
|
-
## Example database
|
|
681
|
-
|
|
682
|
-
```json
|
|
683
|
-
{
|
|
684
|
-
"countries": [
|
|
685
|
-
{
|
|
686
|
-
"id": "1",
|
|
687
|
-
"isArchived": false,
|
|
688
|
-
"name": "Ардения"
|
|
689
|
-
},
|
|
690
|
-
{
|
|
691
|
-
"id": "2",
|
|
692
|
-
"isArchived": false,
|
|
693
|
-
"name": "Велория"
|
|
694
|
-
}
|
|
695
|
-
],
|
|
696
|
-
"genres": [
|
|
697
|
-
{
|
|
698
|
-
"id": "1",
|
|
699
|
-
"isArchived": false,
|
|
700
|
-
"name": "Криминал",
|
|
701
|
-
"parentIds": []
|
|
702
|
-
},
|
|
703
|
-
{
|
|
704
|
-
"id": "2",
|
|
705
|
-
"isArchived": false,
|
|
706
|
-
"name": "Гангстер",
|
|
707
|
-
"parentIds": ["1"]
|
|
708
|
-
},
|
|
709
|
-
{
|
|
710
|
-
"id": "3",
|
|
711
|
-
"isArchived": false,
|
|
712
|
-
"name": "Драма",
|
|
713
|
-
"parentIds": []
|
|
714
|
-
},
|
|
715
|
-
{
|
|
716
|
-
"id": "4",
|
|
717
|
-
"isArchived": false,
|
|
718
|
-
"name": "Комедия",
|
|
719
|
-
"parentIds": []
|
|
720
|
-
}
|
|
721
|
-
],
|
|
722
|
-
"movies": [
|
|
723
|
-
{
|
|
724
|
-
"actors": [
|
|
725
|
-
{
|
|
726
|
-
"genreIds": ["2", "3"],
|
|
727
|
-
"id": "movie-1-actor-1",
|
|
728
|
-
"userId": "1"
|
|
729
|
-
},
|
|
730
|
-
{
|
|
731
|
-
"genreIds": ["3"],
|
|
732
|
-
"id": "movie-1-actor-2",
|
|
733
|
-
"userId": "2"
|
|
734
|
-
}
|
|
735
|
-
],
|
|
736
|
-
"coverSrc": "https://example.com/covers/shadows-of-ardenia.jpg",
|
|
737
|
-
"description": "Наследница портового города раскрывает заговор двух соперничающих семей.",
|
|
738
|
-
"id": "1",
|
|
739
|
-
"isArchived": false,
|
|
740
|
-
"publisherIds": ["2"],
|
|
741
|
-
"title": "Тени Ардении"
|
|
742
|
-
},
|
|
743
|
-
{
|
|
744
|
-
"actors": [],
|
|
745
|
-
"coverSrc": "https://example.com/covers/northern-star.jpg",
|
|
746
|
-
"description": "Ночной администратор старого отеля случайно становится участником поисков пропавшей картины.",
|
|
747
|
-
"id": "2",
|
|
748
|
-
"isArchived": false,
|
|
749
|
-
"publisherIds": ["1"],
|
|
750
|
-
"title": "Полночь в «Северной звезде»"
|
|
751
|
-
}
|
|
752
|
-
],
|
|
753
|
-
"publishers": [
|
|
754
|
-
{
|
|
755
|
-
"id": "1",
|
|
756
|
-
"isArchived": false,
|
|
757
|
-
"name": "Northlight Studio"
|
|
758
|
-
},
|
|
759
|
-
{
|
|
760
|
-
"id": "2",
|
|
761
|
-
"isArchived": false,
|
|
762
|
-
"name": "Aurora Pictures"
|
|
763
|
-
}
|
|
764
|
-
],
|
|
765
|
-
"users": [
|
|
766
|
-
{
|
|
767
|
-
"bornAt": "1988-03-14",
|
|
768
|
-
"countryId": "1",
|
|
769
|
-
"fullName": "Мира Волкова",
|
|
770
|
-
"id": "1",
|
|
771
|
-
"isArchived": false
|
|
772
|
-
},
|
|
773
|
-
{
|
|
774
|
-
"bornAt": "1991-11-02",
|
|
775
|
-
"countryId": "2",
|
|
776
|
-
"fullName": "Леон Ветров",
|
|
777
|
-
"id": "2",
|
|
778
|
-
"isArchived": false
|
|
779
|
-
}
|
|
780
|
-
]
|
|
781
|
-
}
|
|
782
|
-
```
|
|
783
|
-
|
|
784
825
|
## Data storage
|
|
785
826
|
|
|
786
827
|
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.
|
|
@@ -796,6 +837,6 @@ npm run verify
|
|
|
796
837
|
|
|
797
838
|
The command checks types, code style, test coverage and installation from the package archive.
|
|
798
839
|
|
|
799
|
-
To publish a
|
|
840
|
+
To publish a prerelease, update the version in `package.json`, `package-lock.json` and `src/core/constants.ts`, then push the commit to `main`. GitHub Actions creates its `v<version>` tag and publishes through trusted publishing to the `alpha`, `beta` or `rc` channel. Stable versions publish to `latest` from an explicitly pushed version tag.
|
|
800
841
|
|
|
801
842
|
License: MIT.
|