@kollors/deep-json-server 1.0.0-rc.1 → 1.0.0-rc.3

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/MIGRATION.md +4 -4
  3. package/README.md +59 -26
  4. package/README.ru.md +59 -26
  5. package/dist/src/cli/index.js +1 -1
  6. package/dist/src/cli/index.js.map +1 -1
  7. package/dist/src/core/constants.d.ts +1 -1
  8. package/dist/src/core/constants.js +1 -1
  9. package/dist/src/core/model/infer.js +2 -2
  10. package/dist/src/core/model/infer.js.map +1 -1
  11. package/dist/src/core/model/load.js +9 -4
  12. package/dist/src/core/model/load.js.map +1 -1
  13. package/dist/src/core/model/policy.d.ts +1 -1
  14. package/dist/src/core/model/policy.js +6 -3
  15. package/dist/src/core/model/policy.js.map +1 -1
  16. package/dist/src/core/model/types.d.ts +5 -3
  17. package/dist/src/core/query/filter.js +1 -1
  18. package/dist/src/core/query/filter.js.map +1 -1
  19. package/dist/src/core/query/options.js +2 -2
  20. package/dist/src/core/query/options.js.map +1 -1
  21. package/dist/src/graphql/schema.js +3 -3
  22. package/dist/src/graphql/schema.js.map +1 -1
  23. package/dist/src/openapi/document.d.ts +3 -2
  24. package/dist/src/openapi/document.js +8 -7
  25. package/dist/src/openapi/document.js.map +1 -1
  26. package/dist/src/openapi/generate.js +8 -3
  27. package/dist/src/openapi/generate.js.map +1 -1
  28. package/dist/src/openapi/options.d.ts +1 -0
  29. package/dist/src/rest/options.js +1 -1
  30. package/dist/src/rest/options.js.map +1 -1
  31. package/dist/src/rest/projection.js +2 -1
  32. package/dist/src/rest/projection.js.map +1 -1
  33. package/dist/src/rest/routes.js +2 -2
  34. package/dist/src/rest/routes.js.map +1 -1
  35. package/dist/src/server/bootstrap.js +7 -2
  36. package/dist/src/server/bootstrap.js.map +1 -1
  37. package/dist/src/server/config.d.ts +1 -5
  38. package/dist/src/server/config.js +3 -3
  39. package/dist/src/server/config.js.map +1 -1
  40. package/dist/src/server/create.js +1 -1
  41. package/dist/src/server/create.js.map +1 -1
  42. package/dist/src/server/model.js +10 -2
  43. package/dist/src/server/model.js.map +1 -1
  44. package/dist/src/server/openapi-options.d.ts +2 -1
  45. package/dist/src/server/openapi-options.js +2 -1
  46. package/dist/src/server/openapi-options.js.map +1 -1
  47. package/dist/src/server/public.d.ts +1 -1
  48. package/dist/src/server/public.js.map +1 -1
  49. package/examples/schema.json +16 -5
  50. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0-rc.3
4
+
5
+ - Keep relation keys inferred from `source` in stored records while hiding them from REST, GraphQL, and OpenAPI unless declared explicitly in model `fields`.
6
+ - Clarified relation key selection with and without a model schema in both READMEs.
7
+
8
+ ## 1.0.0-rc.2
9
+
10
+ - Added root schema `api` to select REST, GraphQL, or both for database routes, and per-model `api` selection with matching formats. Authentication and file routes remain REST endpoints; OpenAPI includes only enabled REST routes.
11
+ - GraphQL-only server configurations no longer require package metadata. OpenAPI keeps authentication and file routes when no database model enables REST.
12
+ - Added installed-package coverage for per-model API selection and checks for code examples in both READMEs.
13
+
3
14
  ## 1.0.0-rc.1
4
15
 
5
16
  First release candidate for the 1.0 API. This release includes schema-driven REST, GraphQL, OpenAPI export, authentication, record ownership, timestamps, soft deletion, and file storage. It also makes CLI and API error messages consistently English and checks TypeScript declarations from an installed package archive.
package/MIGRATION.md CHANGED
@@ -1,4 +1,4 @@
1
- # Migrating from 0.9.0 to 1.0.0-rc.1
1
+ # Migrating from 0.9.0 to 1.0.0-rc.3
2
2
 
3
3
  Version 1.0 changes configuration and request syntax. Update the server configuration and client requests together. Back up any file database, auth records, and file metadata before changing the running server.
4
4
 
@@ -6,7 +6,7 @@ Version 1.0 changes configuration and request syntax. Update the server configur
6
6
 
7
7
  Declare a storage mode and use `source` for each enabled component:
8
8
 
9
- | 0.9.0 | 1.0.0-rc.1 |
9
+ | 0.9.0 | 1.0.0-rc.3 |
10
10
  |---|---|
11
11
  | `database.path` | `storage: 'file'`, `database.source` |
12
12
  | `database.data` | `storage: 'memory'`, `database.source` |
@@ -14,7 +14,7 @@ Declare a storage mode and use `source` for each enabled component:
14
14
  | `files.data` | `files.source` in memory mode |
15
15
  | `openapi.path` | `openapi.target` |
16
16
 
17
- The `storage` mode applies to the database, schema, auth records, files, and package metadata. GraphQL and OpenAPI require a model schema and `package.source`. The schema format has changed: define models under `models`, with a `collection`, fields, and one primary key per model. Start with the [current schema example](examples/schema.json), then validate your existing records against it. The [configuration example](examples/server.config.js) shows all required paths.
17
+ The `storage` mode applies to the database, schema, auth records, files, and package metadata. GraphQL and OpenAPI require a model schema; OpenAPI also requires `package.source`. The schema format has changed: define models under `models`, with a `collection`, fields, and one primary key per model. Use root `api` to enable REST, GraphQL, or both for the database; a model's optional `api` array can narrow that choice. Start with the [current schema example](examples/schema.json), then validate your existing records against it. The [configuration example](examples/server.config.js) shows all required paths.
18
18
 
19
19
  ## CLI
20
20
 
@@ -32,7 +32,7 @@ const scope = [
32
32
  const url = `/movies?${new URLSearchParams({ scope: JSON.stringify(scope) })}`;
33
33
  ```
34
34
 
35
- Without an explicit `scope`, the response contains scalar fields only. `"*": true` also selects only scalar fields that do not store relation keys. Select arrays, objects, relations, and relation keys explicitly. Related lists can have their own filters, order, and pagination. Review clients that expect embedded relations or relation keys in default responses.
35
+ Without an explicit `scope`, the response contains scalar fields only. `"*": true` also selects only scalar fields that do not store relation keys. Select arrays, objects, relations, and declared relation keys explicitly. Relation keys omitted from `fields` remain in the database but are unavailable in REST, GraphQL, and OpenAPI. Related lists can have their own filters, order, and pagination. Review clients that expect embedded relations or relation keys in default responses.
36
36
 
37
37
  ## Records and auth
38
38
 
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  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.
8
8
 
9
- **Breaking changes in 1.0.0.** See the [migration guide](MIGRATION.md) when upgrading from 0.9.0. 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.
9
+ **Breaking changes in 1.0.0.** See the [migration guide](MIGRATION.md) when upgrading from 0.9.0. The REST `scope` wildcard selects only scalar fields that do not store relation keys. Arrays, objects, relations and explicitly declared relation keys must be selected explicitly. With auth enabled, record permissions are available through the virtual `actions` field.
10
10
 
11
11
  ## Installation
12
12
 
@@ -14,7 +14,7 @@ A JSON mock server with REST, GraphQL, related records, file uploads and schema
14
14
  npm install @kollors/deep-json-server@rc
15
15
  ```
16
16
 
17
- To install this release candidate, use `@1.0.0-rc.1`.
17
+ To install this release candidate, use `@1.0.0-rc.3`.
18
18
 
19
19
  ## Quick start
20
20
 
@@ -46,7 +46,7 @@ Add a [model schema](#model-schema) to define relations and validation. See [que
46
46
 
47
47
  ## Configuration
48
48
 
49
- With `storage: 'file'`, provide paths for every source and the schema. With `'memory'`, provide data directly. Use the same mode throughout the configuration. Add `auth`, `files`, `graphql` or `openapi` to enable those features. `graphql: {}` and `openapi: {}` expose HTTP endpoints at their default paths; add `target` to export a schema.
49
+ With `storage: 'file'`, provide paths for every source and the schema. With `'memory'`, provide data directly. Use the same mode throughout the configuration. Add `auth` or `files` to enable those REST services. Add `graphql` to configure the GraphQL endpoint and `openapi` to serve the REST specification. `graphql: {}` and `openapi: {}` use default endpoint paths; add `target` to export a schema. GraphQL must also be enabled by root `api` in the model schema.
50
50
 
51
51
  ```js
52
52
  export default {
@@ -74,7 +74,7 @@ export default {
74
74
  | `graphql.target` | GraphQL SDL export destination |
75
75
  | `openapi.endpoint` | HTTP endpoint; default `/openapi.json` |
76
76
  | `openapi.target` | OpenAPI export destination |
77
- | `package.source` | Project `package.json`; required when `openapi` or `graphql` is configured |
77
+ | `package.source` | Project `package.json`; required when `openapi` is configured |
78
78
  | `server.host`, `server.port` | Defaults `127.0.0.1`, `4001`; CLI also reads `HOST`/`PORT` |
79
79
  | `server.pageSize`, `server.maxPageSize` | Defaults 10 and 100; default size is capped by the maximum |
80
80
  | `server.cors`, `server.logger` | Default `true`; logger also accepts Fastify logger options |
@@ -84,6 +84,36 @@ export default {
84
84
 
85
85
  Relative paths resolve from the configuration file directory, or from the working directory with `createServer(config)`. In-memory data, including the schema and package metadata, is copied. Port `0` lets the system choose an available port.
86
86
 
87
+ To expose the database only through GraphQL while keeping authentication and files as REST endpoints documented by OpenAPI, use:
88
+
89
+ ```js
90
+ export default {
91
+ storage: 'file',
92
+ database: { source: './database.json', schema: './schema.json' },
93
+ auth: { source: './users.json' },
94
+ files: { source: './uploads' },
95
+ graphql: {},
96
+ openapi: {},
97
+ package: { source: './package.json' },
98
+ };
99
+ ```
100
+
101
+ Set the root `api` in `schema.json`:
102
+
103
+ ```json
104
+ {
105
+ "api": ["graphql"],
106
+ "models": {
107
+ "Item": {
108
+ "collection": "items",
109
+ "fields": { "id": { "type": "string", "primary": true } }
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ Use `"api": ["rest"]` with `openapi: {}` for REST and its OpenAPI description, or `["rest", "graphql"]` with both sections for both database APIs. The `graphql` section is required exactly when the schema root includes `graphql`. OpenAPI describes database routes only when REST is enabled; authentication and file routes are included whenever their sections are configured.
116
+
87
117
  ### CLI
88
118
 
89
119
  | Flag | Action |
@@ -103,10 +133,7 @@ Examples: [database](examples/database.json), [model schema](examples/schema.jso
103
133
 
104
134
  ```json
105
135
  {
106
- "api": [
107
- "openapi",
108
- "graphql"
109
- ],
136
+ "api": ["rest", "graphql"],
110
137
  "models": {
111
138
  "Country": {
112
139
  "collection": "countries",
@@ -148,7 +175,11 @@ Examples: [database](examples/database.json), [model schema](examples/schema.jso
148
175
  }
149
176
  ```
150
177
 
151
- Model definitions belong in `models`. The schema root can define `timestamps` and `softDelete`; a model can override each setting. The `openapi` and `graphql` configuration sections enable the corresponding API. A model's `api` array only limits these enabled formats: `[]` excludes the model from GraphQL and OpenAPI while REST remains available. If no model enables a requested format, generation fails with a clear error. 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.
178
+ Model definitions belong in `models`. The schema root accepts `models`, `api`, `timestamps` and `softDelete`. Root `api` selects database routes. When omitted, it defaults to REST and also GraphQL if the server config has a `graphql` section. A model can override the global timestamp and soft-deletion settings. A model's optional `api` array can narrow access to `['rest']`, `['graphql']`, both, or `[]` to hide it from both. A model cannot enable an API absent from root `api`. OpenAPI includes models with REST enabled. GraphQL generation needs at least one GraphQL model; REST OpenAPI generation needs at least one REST model. On a GraphQL-only server, OpenAPI can still describe configured auth and file routes. Related models must allow the same API. Model names must be valid identifiers; type and operation collisions cause errors. `and`, `or` and `not` are reserved filter names.
179
+
180
+ For example, with root `api: ['rest', 'graphql']`, a model set to `api: ['rest']` has REST routes and OpenAPI paths but no GraphQL operations; a model set to `api: ['graphql']` has GraphQL operations but no REST routes or OpenAPI paths.
181
+
182
+ An excluded model remains part of the database schema and its stored records are still validated. Its `api` setting controls how clients can access it.
152
183
 
153
184
  | Capability | With schema | Without schema |
154
185
  |---|---|---|
@@ -157,11 +188,11 @@ Model definitions belong in `models`. The schema root can define `timestamps` an
157
188
  | OpenAPI 3.0.3 export | Available | Error when requested |
158
189
  | GraphQL SDL / API | Available | Error when requested |
159
190
 
160
- 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.
191
+ Explicit schemas are strict: undeclared fields and collections are rejected, except storage keys inferred from relations. Inferred keys remain in stored records but are not API fields. Existing data is validated on startup. Generation uses the model definitions.
161
192
 
162
193
  Schemaless REST generates an `id` and preserves arbitrary JSON fields. Newly inferred relations are available to subsequent reads and writes without restarting the server. 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.
163
194
 
164
- 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.
195
+ Each model requires `collection` (the database collection name, also used as its REST path when REST is enabled) and `fields` (field definitions). The model name (`User`) determines GraphQL type and operation names. `api` controls route availability; `timestamps` and `softDelete` override global settings for that model.
165
196
 
166
197
  ### Fields
167
198
 
@@ -206,11 +237,11 @@ Objects used in GraphQL must have at least one field visible in responses; REST
206
237
 
207
238
  `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.
208
239
 
209
- 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.
240
+ Relation keys remain in the database even when they are absent from `fields`. A `source` field pointing to a target primary key can be omitted: the server infers an array of keys for a list relation or a scalar key for a single relation. An inferred key is internal: REST and GraphQL cannot read, select, filter, sort or write it directly, and OpenAPI does not describe it. The relation itself remains available. Declare the key in `fields`, for example `"countryId": { "type": "string" }`, to expose it in the APIs. An ambiguous mapping also requires an explicit declaration.
210
241
 
211
242
  Reverse example: `User.movies = {"type":"Movie[]","target":"actors.userId"}`. A movie is returned once even if several actors match. A single relation that matches multiple records causes an error.
212
243
 
213
- 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`.
244
+ Every directly supplied, explicitly declared 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`.
214
245
 
215
246
  `onDelete` describes what happens **when a target record is deleted**:
216
247
 
@@ -363,7 +394,7 @@ Root `where` selects records from the main collection. `where` inside a relation
363
394
 
364
395
  ### REST
365
396
 
366
- `GET /` returns collection names: `{ "resources": ["users", "movies"] }`. Each collection has these routes:
397
+ When REST is enabled by root `api`, `GET /` lists only REST-enabled models: `{ "resources": ["users", "movies"] }`. A GraphQL-only server has no `GET /` database route. Each REST-enabled collection has these routes:
367
398
 
368
399
  | Method | Path | Operation |
369
400
  |---|---|---|
@@ -404,7 +435,7 @@ const params = new URLSearchParams({ scope: JSON.stringify(scope) });
404
435
  const response = await fetch(`/users?${params}`);
405
436
  ```
406
437
 
407
- 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.
438
+ 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. With a schema, a relation key can be selected as `{ "*": true, "countryId": true }` only if it is declared in `fields`. Without a schema, a key present in stored records can be selected explicitly even if omitted from `*`; the wildcard omits it when the server infers a relation from its name and an existing collection.
408
439
 
409
440
  For example, select a movie's own fields, its actors' users and sorted genres:
410
441
 
@@ -431,7 +462,7 @@ Arguments are available only on lists. A list can instead use `{ "union": [scope
431
462
 
432
463
  ### Nested writes
433
464
 
434
- Storage keys such as `genreIds: ["1"]` only set a relation. Relation fields also accept records to create or update:
465
+ Explicitly declared storage keys such as `genreIds: ["1"]` only set a relation. Relation fields also accept records to create or update:
435
466
 
436
467
  ```http
437
468
  PATCH /movies/1
@@ -461,7 +492,7 @@ The key name and type follow the target model. An object containing only a key s
461
492
 
462
493
  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.
463
494
 
464
- 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:
495
+ When the storage key is declared in `fields`, use either the relation field or its key in an object, for example `genres` or `genreIds`. Supplying both fields returns `400 INVALID_INPUT`, even when their key sets match:
465
496
 
466
497
  ```json
467
498
  {
@@ -470,11 +501,11 @@ Use either the relation field or its storage key in an object, for example `genr
470
501
  }
471
502
  ```
472
503
 
473
- The server rejects both fields together and rolls back the operation. Relation fields accept objects only; use `genreIds` to change links without creating or updating related records. 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.
504
+ The server rejects both fields together and rolls back the operation. Relation fields accept objects only; a declared key such as `genreIds` changes links without creating or updating related records. 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.
474
505
 
475
506
  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.
476
507
 
477
- GraphQL accepts typed objects in relation fields. To change only the links in a replace mutation, use storage keys such as `genreIds`. For example:
508
+ GraphQL accepts typed objects in relation fields. To change only the links in a replace mutation, use a declared storage key such as `genreIds`. For example:
478
509
 
479
510
  ```graphql
480
511
  mutation {
@@ -491,7 +522,7 @@ mutation {
491
522
 
492
523
  ### GraphQL
493
524
 
494
- Set `database.schema` and add `graphql: {}` plus `package.source` to the configuration:
525
+ Set `database.schema`, include `graphql` in the schema's root `api`, and add `graphql: {}` to the configuration:
495
526
 
496
527
  ```sh
497
528
  npx deep-json-server server.config.js
@@ -531,7 +562,7 @@ Errors include `extensions.code`: `INVALID_INPUT`, `INVALID_QUERY`, `NOT_FOUND`,
531
562
 
532
563
  ## OpenAPI and schema exports
533
564
 
534
- Exports use OpenAPI 3.0.3. Add `openapi: {}`, `database.schema` and `package.source` to serve the specification at `/openapi.json`. Change the route with `openapi.endpoint`. OpenAPI `info.title`, `info.version` and optional `info.description` come from the configured `package.json`. Open the document in Swagger UI or import it into an API client.
565
+ Exports use OpenAPI 3.0.3. Add `openapi: {}`, `database.schema` and `package.source` to serve the specification at `/openapi.json`. Change the route with `openapi.endpoint`. Database paths appear only for REST-enabled models; a GraphQL-only database can still produce a document for configured auth and file routes. OpenAPI `info.title`, `info.version` and optional `info.description` come from the configured `package.json`. Open the document in Swagger UI or import it into an API client.
535
566
 
536
567
  Set output paths to save schemas:
537
568
 
@@ -550,7 +581,7 @@ npx deep-json-server server.config.js --generate-only
550
581
  npx deep-json-server server.config.js --generate
551
582
  ```
552
583
 
553
- `--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.
584
+ `--generate-only` exports and exits; `--generate` starts the server after exporting. Configuration sections select the formats. Each selected format requires its own `target`. The OpenAPI HTTP endpoint returns JSON; file exports from `writeOpenapi()` and the CLI are YAML. Missing sections, missing targets or generation errors fail the command before server startup.
554
585
 
555
586
  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.
556
587
 
@@ -659,7 +690,7 @@ query {
659
690
 
660
691
  `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.
661
692
 
662
- 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`.
693
+ When `openapi` is configured, its document 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`.
663
694
 
664
695
  ## Record dates, deletion and ownership
665
696
 
@@ -723,7 +754,7 @@ REST returns 401 for an invalid or missing token and 403 for insufficient permis
723
754
 
724
755
  ## Files
725
756
 
726
- Files are available through REST and documented in OpenAPI. Add storage to the configuration:
757
+ Files are available through REST and appear in the OpenAPI document when `openapi` is configured. Add storage to the configuration:
727
758
 
728
759
  ```js
729
760
  export default {
@@ -814,7 +845,9 @@ await server.listen();
814
845
 
815
846
  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.
816
847
 
817
- `createServer(config)` takes the same configuration object as the CLI. When `openapi` or `graphql` is configured, `package.source` is required. The `openapi()` and `graphql()` methods require their respective sections. They return schemas without writing files.
848
+ `createServer(config)` takes the same configuration object as the CLI. When `openapi` is configured, `package.source` is required. The `openapi()` and `graphql()` methods require their respective sections. They return schemas without writing files.
849
+
850
+ The returned Fastify instance accepts standard `listen()` options, including a Unix socket path. Calling `listen()` without options uses `server.host` and `server.port`.
818
851
 
819
852
  The root import `@kollors/deep-json-server` also provides these functions. Server adapters load when enabled. Generators can be used independently:
820
853
 
@@ -828,7 +861,7 @@ await writeOpenapi(document, './generated/openapi.yaml');
828
861
  await writeGraphql(sdl, './generated/schema.graphql');
829
862
  ```
830
863
 
831
- Standalone generators accept a schema path or object without a server configuration. The selected function supplies the default format; a model's `api` setting 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.
864
+ Standalone generators accept a schema path or object without a server configuration. If root `api` is omitted, `generateOpenapi()` defaults it to REST and `generateGraphql()` to GraphQL. Explicit root and model `api` values still apply; the selected format must have an enabled model. 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.
832
865
 
833
866
  `generateOpenapi()` requires `packagePath` and also accepts `host`, `port`, `pageSize` and `maxPageSize`. It reads OpenAPI metadata from that package. 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`.
834
867
 
package/README.ru.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  JSON-сервер для создания тестового API с REST, GraphQL, связями между записями, загрузкой файлов и экспортом схем. Поддерживает вход пользователей, права владельца и администратора, даты записей и мягкое удаление. Требуется Node.js 22 или новее.
8
8
 
9
- **Изменения в 1.0.0, нарушающие совместимость.** При переходе с 0.9.0 воспользуйтесь [инструкцией по миграции](MIGRATION.md). `*` в REST `scope` выбирает только скалярные поля, которые не хранят ключи связей. Массивы, объекты, связи и их ключи нужно указывать явно. При включённой аутентификации права на запись доступны через виртуальное поле `actions`.
9
+ **Изменения в 1.0.0, нарушающие совместимость.** При переходе с 0.9.0 воспользуйтесь [инструкцией по миграции](MIGRATION.md). `*` в REST `scope` выбирает только скалярные поля, которые не хранят ключи связей. Массивы, объекты, связи и явно объявленные ключи связей нужно указывать в выборе полей. При включённой аутентификации права на запись доступны через виртуальное поле `actions`.
10
10
 
11
11
  ## Установка
12
12
 
@@ -14,7 +14,7 @@ JSON-сервер для создания тестового API с REST, GraphQ
14
14
  npm install @kollors/deep-json-server@rc
15
15
  ```
16
16
 
17
- Для установки этого релиз-кандидата укажите `@1.0.0-rc.1`.
17
+ Для установки этого релиз-кандидата укажите `@1.0.0-rc.3`.
18
18
 
19
19
  ## Быстрый старт
20
20
 
@@ -46,7 +46,7 @@ npx deep-json-server server.config.js
46
46
 
47
47
  ## Конфигурация
48
48
 
49
- При `storage: 'file'` задайте пути для всех источников и схемы, при `'memory'` — передайте данные напрямую. Используйте один режим во всей конфигурации. Секции `auth`, `files`, `graphql` и `openapi` включают соответствующие возможности. `graphql: {}` и `openapi: {}` открывают HTTP-маршруты по стандартным адресам; для экспорта схемы добавьте `target`.
49
+ При `storage: 'file'` задайте пути для всех источников и схемы, при `'memory'` — передайте данные напрямую. Используйте один режим во всей конфигурации. Секции `auth` и `files` включают соответствующие REST-маршруты. Секция `graphql` настраивает маршрут GraphQL, а `openapi` публикует описание REST. `graphql: {}` и `openapi: {}` используют стандартные пути; для экспорта схемы добавьте `target`. GraphQL должен быть также включён корневым `api` схемы моделей.
50
50
 
51
51
  ```js
52
52
  export default {
@@ -74,7 +74,7 @@ export default {
74
74
  | `graphql.target` | Файл для экспорта GraphQL SDL |
75
75
  | `openapi.endpoint` | HTTP-маршрут; по умолчанию `/openapi.json` |
76
76
  | `openapi.target` | Файл для экспорта OpenAPI |
77
- | `package.source` | `package.json` проекта; обязателен при наличии `openapi` или `graphql` |
77
+ | `package.source` | `package.json` проекта; обязателен при наличии `openapi` |
78
78
  | `server.host`, `server.port` | По умолчанию `127.0.0.1`, `4001`; CLI также читает `HOST`/`PORT` |
79
79
  | `server.pageSize`, `server.maxPageSize` | По умолчанию 10 и 100; размер по умолчанию ограничен максимумом |
80
80
  | `server.cors`, `server.logger` | По умолчанию `true`; logger принимает также настройки Fastify |
@@ -84,6 +84,36 @@ export default {
84
84
 
85
85
  Относительные пути разрешаются от каталога файла конфигурации; при вызове `createServer(config)` — от рабочего каталога. Данные в памяти, включая схему и метаданные пакета, копируются. Порт `0` позволяет системе выбрать свободный порт.
86
86
 
87
+ Чтобы открыть базу только через GraphQL, а аутентификацию и файлы оставить в REST с описанием OpenAPI, укажите:
88
+
89
+ ```js
90
+ export default {
91
+ storage: 'file',
92
+ database: { source: './database.json', schema: './schema.json' },
93
+ auth: { source: './users.json' },
94
+ files: { source: './uploads' },
95
+ graphql: {},
96
+ openapi: {},
97
+ package: { source: './package.json' },
98
+ };
99
+ ```
100
+
101
+ В корне `schema.json` задайте `api`:
102
+
103
+ ```json
104
+ {
105
+ "api": ["graphql"],
106
+ "models": {
107
+ "Item": {
108
+ "collection": "items",
109
+ "fields": { "id": { "type": "string", "primary": true } }
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ Для REST с описанием OpenAPI используйте `"api": ["rest"]` и `openapi: {}`; для обоих API базы — `["rest", "graphql"]` с обеими секциями. Секция `graphql` обязательна тогда и только тогда, когда корневой `api` содержит `graphql`. OpenAPI описывает маршруты базы, только если включён REST; маршруты аутентификации и файлов включаются при наличии соответствующих секций.
116
+
87
117
  ### CLI
88
118
 
89
119
  | Флаг | Действие |
@@ -103,10 +133,7 @@ export default {
103
133
 
104
134
  ```json
105
135
  {
106
- "api": [
107
- "openapi",
108
- "graphql"
109
- ],
136
+ "api": ["rest", "graphql"],
110
137
  "models": {
111
138
  "Country": {
112
139
  "collection": "countries",
@@ -148,7 +175,11 @@ export default {
148
175
  }
149
176
  ```
150
177
 
151
- Модели находятся в `models`. В корне схемы можно задать `timestamps` и `softDelete`; у модели эти параметры переопределяют общие значения. Секции конфигурации `openapi` и `graphql` включают соответствующий API. Массив `api` у модели только ограничивает включённые форматы: `[]` исключает модель из GraphQL и OpenAPI, но REST продолжает работать. Если ни одна модель не включает запрошенный формат, генерация завершится понятной ошибкой. Связанные модели должны разрешать тот же формат. Имена моделей должны быть допустимыми идентификаторами; конфликты типов и операций вызывают ошибку. Имена `and`, `or`, `not` зарезервированы фильтрами.
178
+ Модели задаются в `models`. Корень схемы принимает `models`, `api`, `timestamps` и `softDelete`. Корневой `api` выбирает маршруты базы. Если его нет, по умолчанию включён REST и дополнительно GraphQL при наличии секции `graphql` в конфигурации сервера. У модели настройки дат и мягкого удаления могут переопределять общие значения. Необязательный массив `api` у модели может сузить доступ до `['rest']`, `['graphql']`, обоих вариантов или `[]`, чтобы скрыть модель полностью. Модель не может включить API, отсутствующий в корневом `api`. OpenAPI включает модели, доступные через REST. Для генерации GraphQL нужна хотя бы одна GraphQL-модель; для генерации OpenAPI с маршрутами базы — хотя бы одна REST-модель. Если база доступна только через GraphQL, OpenAPI всё равно может описывать настроенные маршруты auth и файлов. Связанные модели должны разрешать тот же API. Имена моделей должны быть допустимыми идентификаторами; конфликты типов и операций вызывают ошибку. Имена `and`, `or`, `not` зарезервированы фильтрами.
179
+
180
+ Например, при корневом `api: ['rest', 'graphql']` модель с `api: ['rest']` получает REST-маршруты и пути в OpenAPI без операций GraphQL, а модель с `api: ['graphql']` — операции GraphQL без REST-маршрутов и путей в OpenAPI.
181
+
182
+ Исключённая из API модель остаётся частью схемы базы, а её сохранённые записи продолжают проверяться. Поле `api` управляет доступом клиентов к модели.
152
183
 
153
184
  | Возможность | Со схемой | Без схемы |
154
185
  |---|---|---|
@@ -157,11 +188,11 @@ export default {
157
188
  | Экспорт OpenAPI 3.0.3 | Доступен | Ошибка при запросе экспорта |
158
189
  | GraphQL SDL / API | Доступен | Ошибка при запросе |
159
190
 
160
- При явной схеме неизвестные поля и коллекции запрещены. Исключение — хранимые ключи, выведенные из связей. Исходная база проверяется при загрузке. Генерация использует описание моделей.
191
+ При явной схеме неизвестные поля и коллекции запрещены. Исключение — хранимые ключи, выведенные из связей. Они остаются в записях базы, но не становятся полями API. Исходная база проверяется при загрузке. Генерация использует описание моделей.
161
192
 
162
193
  REST без схемы создаёт ключ `id` и сохраняет произвольные JSON-поля. Новые выведенные связи доступны для последующего чтения и записи без перезапуска сервера. Для фильтров и выбора отдельных полей используются имена в формате идентификаторов. `scope=[{"*":true}]` возвращает скаляры верхнего уровня; массивы и объекты выбираются по имени. Поля с разными типами значений можно запросить явно, но фильтрация, сортировка и пагинация неоднородных списков требуют явной схемы.
163
194
 
164
- У модели обязательны `collection` — имя коллекции в базе и REST-пути — и `fields` — описание полей. Имя модели (`User`) задаёт имена типов и операций GraphQL. `api` управляет доступностью форматов, а `timestamps` и `softDelete` переопределяют глобальные настройки для этой модели.
195
+ У модели обязательны `collection` (имя коллекции в базе и REST-путь, если включён REST) и `fields` (описание полей). Имя модели (`User`) задаёт имена типов и операций GraphQL. `api` управляет доступностью маршрутов, а `timestamps` и `softDelete` переопределяют глобальные настройки для этой модели.
165
196
 
166
197
  ### Поля
167
198
 
@@ -206,11 +237,11 @@ REST без схемы создаёт ключ `id` и сохраняет про
206
237
 
207
238
  `Genre` возвращает объект, `Genre[]` — список. По умолчанию `source` указывает на первичный ключ текущей модели, `target` — целевой. Это правило действует и для вложенных связей. Пути задаются от корня соответствующей записи: в примере `actors.genreIds` содержит ключи жанров текущего актёра.
208
239
 
209
- Ключи связей хранятся в базе и входят в собственные поля записи. Их типы выводятся из сопоставляемых ключей. Если поле `source` ссылается на первичный ключ целевой модели, его можно не объявлять отдельно: для множественной связи создаётся описание массива ключей, для одиночной — одного значения. При неоднозначном сопоставлении опишите хранимое поле явно.
240
+ Ключи связей остаются в базе, даже если их нет в `fields`. Если поле `source` ссылается на первичный ключ целевой модели, его можно не объявлять отдельно: сервер выведет массив ключей для множественной связи или одно значение для одиночной. Такой ключ остаётся внутренним: REST и GraphQL не позволяют читать, выбирать, фильтровать, сортировать или записывать его напрямую, а OpenAPI его не описывает. Сама связь при этом доступна. Чтобы открыть ключ в API, объявите его в `fields`, например `"countryId": { "type": "string" }`. Неоднозначное сопоставление тоже требует явного объявления.
210
241
 
211
242
  Обратная связь: `User.movies = {"type":"Movie[]","target":"actors.userId"}`. Фильм возвращается один раз, даже если совпало несколько актёров. Несколько совпадений для одиночной связи — ошибка.
212
243
 
213
- Каждый переданный ключ прямой связи должен указывать на существующую запись. `required: true` у связи требует хотя бы одну связанную запись до фильтрации и пагинации ответа. Обратная связь с первичным ключом в `source` может быть пустой, если не объявлена обязательной. Отсутствующая одиночная связь возвращает `null`.
244
+ Каждый переданный напрямую и явно объявленный ключ связи должен указывать на существующую запись. `required: true` у связи требует хотя бы одну связанную запись до фильтрации и пагинации ответа. Обратная связь с первичным ключом в `source` может быть пустой, если не объявлена обязательной. Отсутствующая одиночная связь возвращает `null`.
214
245
 
215
246
  `onDelete` срабатывает **при удалении целевой записи**:
216
247
 
@@ -363,7 +394,7 @@ npx deep-json-server examples/server.config.js
363
394
 
364
395
  ### REST
365
396
 
366
- `GET /` возвращает имена коллекций: `{ "resources": ["users", "movies"] }`. Для каждой коллекции доступны следующие маршруты:
397
+ Если REST включён корневым `api`, `GET /` перечисляет только REST-модели: `{ "resources": ["users", "movies"] }`. При базе только с GraphQL маршрута `GET /` нет. Для каждой REST-коллекции доступны следующие маршруты:
367
398
 
368
399
  | Метод | Путь | Операция |
369
400
  |---|---|---|
@@ -404,7 +435,7 @@ const params = new URLSearchParams({ scope: JSON.stringify(scope) });
404
435
  const response = await fetch(`/users?${params}`);
405
436
  ```
406
437
 
407
- Скаляры и массивы примитивов выбираются через `true`, объекты и связи — через свой массив `scope`. Если аргументы не нужны, в массиве остаётся только объект полей. `"*": true` включает только скалярные поля текущей модели, которые не хранят ключи связей. Массивы, объекты, связи, их ключи и поля `writeOnly` в него не входят. Ключ связи можно выбрать явно, например `{ "*": true, "countryId": true }`. Без схемы ключ исключается из `*`, только если сервер смог вывести для него связь по имени и существующей коллекции.
438
+ Скаляры и массивы примитивов выбираются через `true`, объекты и связи — через свой массив `scope`. Если аргументы не нужны, в массиве остаётся только объект полей. `"*": true` включает только скалярные поля текущей модели, которые не хранят ключи связей. Массивы, объекты, связи, их ключи и поля `writeOnly` в него не входят. Со схемой ключ связи можно выбрать через `{ "*": true, "countryId": true }`, только если он объявлен в `fields`. Без схемы ключ, присутствующий в записях базы, можно выбрать явно, даже если его нет в `*`; из `*` он исключается, когда сервер выводит связь по имени ключа и существующей коллекции.
408
439
 
409
440
  Например, собственные поля фильма, пользователи актёров и отсортированные жанры:
410
441
 
@@ -431,7 +462,7 @@ const response = await fetch(`/users?${params}`);
431
462
 
432
463
  ### Вложенная запись
433
464
 
434
- Поля ключей, например `genreIds: ["1"]`, только задают связь. В поля связей можно передавать записи для создания или обновления:
465
+ Явно объявленные поля ключей, например `genreIds: ["1"]`, только задают связь. В поля связей можно передавать записи для создания или обновления:
435
466
 
436
467
  ```http
437
468
  PATCH /movies/1
@@ -461,7 +492,7 @@ Content-Type: application/json
461
492
 
462
493
  Переданный список заменяет состав связи. PATCH сохраняет пропущенные связи, PUT очищает пропущенные связи, ключи которых доступны для записи. `[]` очищает список, `null` — одиночную связь с разрешённым `nullable`. Разрыв связи не удаляет связанную запись. Обязательные связи должны оставаться заполненными.
463
494
 
464
- В одном объекте указывайте либо связь, либо её хранимый ключ: например, `genres` или `genreIds`. Одновременная передача обоих полей возвращает `400 INVALID_INPUT`, даже если наборы ключей совпадают:
495
+ Если хранимый ключ объявлен в `fields`, в одном объекте указывайте либо связь, либо её ключ: например, `genres` или `genreIds`. Одновременная передача обоих полей возвращает `400 INVALID_INPUT`, даже если наборы ключей совпадают:
465
496
 
466
497
  ```json
467
498
  {
@@ -470,11 +501,11 @@ Content-Type: application/json
470
501
  }
471
502
  ```
472
503
 
473
- Сервер не выбирает приоритет и не объединяет значения; вся операция отменяется. Поле связи принимает только объекты; для изменения одних ссылок без создания и обновления связанных записей используйте `genreIds`. Для обратной связи сервер меняет целевой ключ. Если путь проходит через массив и нельзя однозначно выбрать элемент для связи, передайте массив с нужными ключами явно. Защищённые ключи изменять нельзя.
504
+ Сервер не выбирает приоритет и не объединяет значения; вся операция отменяется. Поле связи принимает только объекты; для изменения одних ссылок без создания и обновления связанных записей используйте объявленный ключ, например `genreIds`. Для обратной связи сервер меняет целевой ключ. Если путь проходит через массив и нельзя однозначно выбрать элемент для связи, передайте массив с нужными ключами явно. Защищённые ключи изменять нельзя.
474
505
 
475
506
  Все вложенные изменения входят в транзакцию основной записи. Ошибка проверки, отсутствующая запись или неверный выбор полей ответа отменяет всю операцию. Изменения общей записи видны всем, кто с ней связан.
476
507
 
477
- GraphQL принимает в полях связей типизированные объекты. Чтобы при замене изменить только связи, используйте поля ключей, например `genreIds`. Пример:
508
+ GraphQL принимает в полях связей типизированные объекты. Чтобы при замене изменить только связи, используйте объявленные поля ключей, например `genreIds`. Пример:
478
509
 
479
510
  ```graphql
480
511
  mutation {
@@ -491,7 +522,7 @@ mutation {
491
522
 
492
523
  ### GraphQL
493
524
 
494
- Укажите `database.schema` и добавьте в конфигурацию `graphql: {}` вместе с `package.source`:
525
+ Укажите `database.schema`, включите `graphql` в корневой `api` схемы и добавьте в конфигурацию `graphql: {}`:
495
526
 
496
527
  ```sh
497
528
  npx deep-json-server server.config.js
@@ -531,7 +562,7 @@ query {
531
562
 
532
563
  ## OpenAPI и экспорт схем
533
564
 
534
- Экспорт использует OpenAPI 3.0.3. Добавьте `openapi: {}`, `database.schema` и `package.source`, чтобы получать спецификацию по HTTP на `/openapi.json`. Путь меняется через `openapi.endpoint`. Поля OpenAPI `info.title`, `info.version` и необязательное `info.description` берутся из настроенного `package.json`. Спецификацию можно открыть в Swagger UI или импортировать в API-клиент.
565
+ Экспорт использует OpenAPI 3.0.3. Добавьте `openapi: {}`, `database.schema` и `package.source`, чтобы получать спецификацию по HTTP на `/openapi.json`. Путь меняется через `openapi.endpoint`. Маршруты базы включаются только для REST-моделей; при базе только с GraphQL документ всё равно может описывать настроенные маршруты auth и файлов. Поля OpenAPI `info.title`, `info.version` и необязательное `info.description` берутся из настроенного `package.json`. Спецификацию можно открыть в Swagger UI или импортировать в API-клиент.
535
566
 
536
567
  Для сохранения схем задайте пути экспорта:
537
568
 
@@ -550,7 +581,7 @@ npx deep-json-server server.config.js --generate-only
550
581
  npx deep-json-server server.config.js --generate
551
582
  ```
552
583
 
553
- `--generate-only` экспортирует и завершает работу, `--generate` после экспорта запускает сервер. Форматы определяются наличием секций. Для каждого выбранного формата обязателен свой `target`. Если секций нет, отсутствует `target` или генерация завершилась ошибкой, команда возвращает ошибку и сервер не запускается.
584
+ `--generate-only` экспортирует и завершает работу, `--generate` после экспорта запускает сервер. Форматы определяются наличием секций. Для каждого выбранного формата обязателен свой `target`. HTTP-маршрут OpenAPI возвращает JSON; `writeOpenapi()` и CLI записывают YAML. Если секций нет, отсутствует `target` или генерация завершилась ошибкой, команда возвращает ошибку и сервер не запускается.
554
585
 
555
586
  Экспорт не открывает базу, учётные записи и файлы. Перед записью проверяются все выбранные `target`; они не могут совпадать с конфигурацией, базой, схемой, пользователями, счётчиками или метаданными файлов.
556
587
 
@@ -659,7 +690,7 @@ query {
659
690
 
660
691
  `actions` доступен у корневых и связанных записей моделей, включая результаты мутаций. Его нельзя записывать, фильтровать или сортировать. Обычные вложенные объекты и ответы методов auth это поле не получают.
661
692
 
662
- OpenAPI описывает маршруты auth, необязательную Bearer-аутентификацию при чтении записей, обязательную при изменениях и поле ответа `actions`. В Swagger UI токен из ответа на вход можно вставить в **Authorize**. Для экспорта схем включите auth в конфигурации и выполните `npx deep-json-server server.config.js --generate-only`; файл учётных записей при генерации не читается. Методы auth доступны через REST. В GraphQL тот же токен проверяется при чтении прав и изменении записей. Для GraphQL и OpenAPI нужна `database.schema`.
693
+ Когда настроен `openapi`, его документ описывает маршруты auth, необязательную Bearer-аутентификацию при чтении записей, обязательную при изменениях и поле ответа `actions`. В Swagger UI токен из ответа на вход можно вставить в **Authorize**. Для экспорта схем включите auth в конфигурации и выполните `npx deep-json-server server.config.js --generate-only`; файл учётных записей при генерации не читается. Методы auth доступны через REST. В GraphQL тот же токен проверяется при чтении прав и изменении записей. Для GraphQL и OpenAPI нужна `database.schema`.
663
694
 
664
695
  ## Даты записей, удаление и владельцы
665
696
 
@@ -723,7 +754,7 @@ REST возвращает 401 при отсутствии действитель
723
754
 
724
755
  ## Файлы
725
756
 
726
- Файлы доступны через REST и описываются в OpenAPI. Добавьте хранилище в конфигурацию:
757
+ Файлы доступны через REST и появляются в документе OpenAPI, если настроена секция `openapi`. Добавьте хранилище в конфигурацию:
727
758
 
728
759
  ```js
729
760
  export default {
@@ -814,7 +845,9 @@ await server.listen();
814
845
 
815
846
  Методы `openapi()` и `graphql()` возвращают схемы и требуют `database.schema`. `fastify()` возвращает экземпляр сервера для настройки и запуска. База и включённые сервисы инициализируются при `ready()`, `listen()` или первом `inject()`; ошибка инициализации останавливает запуск.
816
847
 
817
- `createServer(config)` принимает тот же объект конфигурации, что и CLI. При наличии `openapi` или `graphql` обязателен `package.source`. Для методов `openapi()` и `graphql()` нужна соответствующая секция. Методы возвращают схему и не записывают файлы.
848
+ `createServer(config)` принимает тот же объект конфигурации, что и CLI. При наличии `openapi` обязателен `package.source`. Для методов `openapi()` и `graphql()` нужна соответствующая секция. Методы возвращают схему и не записывают файлы.
849
+
850
+ Полученный экземпляр Fastify принимает обычные параметры `listen()`, включая путь Unix-сокета. Вызов `listen()` без параметров использует `server.host` и `server.port`.
818
851
 
819
852
  Эти функции доступны и через общий импорт `@kollors/deep-json-server`. Адаптеры сервера загружаются при включении. Генераторы можно использовать отдельно:
820
853
 
@@ -828,7 +861,7 @@ await writeOpenapi(document, './generated/openapi.yaml');
828
861
  await writeGraphql(sdl, './generated/schema.graphql');
829
862
  ```
830
863
 
831
- Отдельные генераторы принимают путь или объект схемы и не требуют конфигурации сервера. Выбранная функция задаёт формат по умолчанию; `api` у модели может его ограничить. `timestamps` и `softDelete` берутся из схемы. Опция `{ auth: true }` добавляет поля владельца и `actions`; OpenAPI также описывает маршруты auth и требования токена. `hashPassword()` доступна и через общий импорт пакета.
864
+ Отдельные генераторы принимают путь или объект схемы и не требуют конфигурации сервера. Если корневой `api` не задан, `generateOpenapi()` использует REST по умолчанию, а `generateGraphql()` — GraphQL. Явные значения `api` в корне и у моделей сохраняют силу; для выбранного формата нужна хотя бы одна доступная модель. `timestamps` и `softDelete` берутся из схемы. Опция `{ auth: true }` добавляет поля владельца и `actions`; OpenAPI также описывает маршруты auth и требования токена. `hashPassword()` доступна и через общий импорт пакета.
832
865
 
833
866
  Для `generateOpenapi()` обязателен `packagePath`; дополнительно доступны `host`, `port`, `pageSize` и `maxPageSize`. Метаданные OpenAPI читаются из указанного пакета. Вместо пути можно передать объект схемы. Сервер и генераторы работают с собственной копией модели. Размеры страниц должны быть положительными целыми числами; `pageSize` не может превышать `maxPageSize`.
834
867
 
@@ -44,7 +44,7 @@ async function generate(config, source, directory, sourcePath, openapiInfo) {
44
44
  const model = await configuredModel(config);
45
45
  if (config.openapi && !openapiInfo)
46
46
  throw new Error('OpenAPI package metadata is not configured');
47
- const openapi = config.openapi ? (await import('../openapi/generate.js')).openapiFromModel(model, openapiOptions(config, openapiInfo)) : undefined;
47
+ const openapi = config.openapi ? (await import('../openapi/generate.js')).openapiFromModel(model, openapiOptions(config, openapiInfo, model)) : undefined;
48
48
  const graphql = config.graphql ? (await import('../graphql/generate.js')).graphqlFromModel(model) : undefined;
49
49
  if (openapi && config.openapi?.target) {
50
50
  await writeOpenapi(openapi, config.openapi.target);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}