@kollors/deep-json-server 1.0.0-rc.9 → 1.0.0
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/CHANGELOG.md +17 -5
- package/MIGRATION.md +26 -18
- package/MIGRATION.ru.md +36 -28
- package/README.md +91 -44
- package/README.ru.md +119 -72
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
First stable release of the 1.0 API, based on RC9. There are no API or stored-data format changes from RC9.
|
|
6
|
+
|
|
7
|
+
- Define models, validation and paired relations in one schema for REST, GraphQL and OpenAPI.
|
|
8
|
+
- Select fields, filter, sort and paginate root and nested lists with REST `scope` or GraphQL.
|
|
9
|
+
- Enable authentication, owner and administrator permissions, persistent file-backed sessions, timestamps and soft deletion through configuration.
|
|
10
|
+
- Upload, download, rename and delete files using disk or memory storage. Native OS locks prevent competing servers from writing to shared disk stores and recover after crashes.
|
|
11
|
+
- Verify types, lint, test coverage, dependency security and installed-package behavior on Linux, Windows and macOS with Node.js 22, 24 and 26.
|
|
12
|
+
|
|
13
|
+
The configuration, CLI and REST query format differ from 0.9.0. Follow the [migration guide](MIGRATION.md) or [Russian guide](MIGRATION.ru.md), and stop old server processes before upgrading.
|
|
14
|
+
|
|
3
15
|
## 1.0.0-rc.9
|
|
4
16
|
|
|
5
17
|
- Update vulnerable Fastify, fast-uri and brace-expansion versions within compatible ranges.
|
|
6
|
-
- Check runtime dependencies with npm audit before the full verification and publication pipeline. RC9 includes all RC8 storage, auth, query and cross-platform fixes.
|
|
18
|
+
- Check runtime dependencies with `npm audit` before the full verification and publication pipeline. RC9 includes all RC8 storage, auth, query and cross-platform fixes.
|
|
7
19
|
|
|
8
20
|
## 1.0.0-rc.8
|
|
9
21
|
|
|
@@ -46,13 +58,13 @@ When upgrading from an earlier RC, stop all old server processes before starting
|
|
|
46
58
|
## 1.0.0-rc.3
|
|
47
59
|
|
|
48
60
|
- Keep relation keys inferred from `source` in stored records while hiding them from REST, GraphQL, and OpenAPI unless declared explicitly in model `fields`.
|
|
49
|
-
-
|
|
61
|
+
- Clarify relation key selection with and without a model schema in both READMEs.
|
|
50
62
|
|
|
51
63
|
## 1.0.0-rc.2
|
|
52
64
|
|
|
53
|
-
-
|
|
54
|
-
- GraphQL-only server configurations
|
|
55
|
-
-
|
|
65
|
+
- Add 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.
|
|
66
|
+
- Remove the package metadata requirement for GraphQL-only server configurations. Keep authentication and file routes in OpenAPI when no database model enables REST.
|
|
67
|
+
- Add installed-package coverage for per-model API selection and checks for code examples in both READMEs.
|
|
56
68
|
|
|
57
69
|
## 1.0.0-rc.1
|
|
58
70
|
|
package/MIGRATION.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Migrating from 0.9.0 to 1.0.0
|
|
1
|
+
# Migrating from 0.9.0 to 1.0.0
|
|
2
2
|
|
|
3
3
|
[Русский](MIGRATION.ru.md) · [Current README](README.md)
|
|
4
4
|
|
|
5
|
-
This guide
|
|
5
|
+
This guide covers the move from `0.9.0` to `1.0.0`. Update configuration and clients together. Node.js 22 or newer is required. Back up the database, configuration, schema, uploaded files and metadata before migrating. If you already use a 1.0 release candidate, see [upgrading from a release candidate](#upgrading-from-a-release-candidate).
|
|
6
6
|
|
|
7
7
|
## 1. Choose whether you need a schema
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ export default { database: { path: './database.json' } };
|
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
```js
|
|
17
|
-
// 1.0.0
|
|
17
|
+
// 1.0.0
|
|
18
18
|
export default { storage: 'file', database: { source: './database.json' } };
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -22,7 +22,7 @@ This keeps schemaless REST and relations inferred from stored `...Id` / `...Ids`
|
|
|
22
22
|
|
|
23
23
|
## 2. Convert configuration
|
|
24
24
|
|
|
25
|
-
| 0.9.0 | 1.0.0
|
|
25
|
+
| 0.9.0 | 1.0.0 |
|
|
26
26
|
|---|---|
|
|
27
27
|
| `database.path` | `storage: 'file'` and `database.source` |
|
|
28
28
|
| `database.data` | `storage: 'memory'` and `database.source` |
|
|
@@ -56,7 +56,7 @@ Relative paths still resolve from the config directory in the CLI, and from the
|
|
|
56
56
|
|
|
57
57
|
## 3. Replace schema overrides with complete models
|
|
58
58
|
|
|
59
|
-
In 0.9.0, `$schema` supplemented field types inferred from data.
|
|
59
|
+
In 0.9.0, `$schema` supplemented field types inferred from data. In 1.0.0, each collection needs a model with `collection`, `fields`, and exactly one top-level primary key of type `string` or `number`.
|
|
60
60
|
|
|
61
61
|
| Old override | New definition |
|
|
62
62
|
|---|---|
|
|
@@ -106,7 +106,7 @@ Every explicit relation needs both declarations and a `keyOn` value. `current` s
|
|
|
106
106
|
- Self-relations pair `Genre.parents: { type: 'Genre[]', keyOn: 'current' }` with `Genre.children: { type: 'Genre[]', keyOn: 'related' }`; both use stored `Genre.parentIds`.
|
|
107
107
|
- Multiple relations between the same models require disambiguation: inverse `Country.birthUsers` uses `target: 'birthCountryId'`, and `Country.residenceUsers` uses `target: 'residenceCountryId'`. Ambiguous or missing pairs fail schema loading.
|
|
108
108
|
- Declare existing keys explicitly, as above, if clients read, filter, sort or write them. Inferred keys remain in storage but are hidden from both APIs and OpenAPI, even when selected by name.
|
|
109
|
-
-
|
|
109
|
+
- List relations targeting **non-primary** fields also infer arrays of storage keys. For example, `publishers` with `keyOn: 'current'` and `target: 'code'` infers `publisherCodes: { type: 'string[]' }` when `Publisher.code` is a string. Declare the key in `fields` if clients need direct access. Explicitly declared scalar keys retain their type.
|
|
110
110
|
|
|
111
111
|
Repair dangling direct references before startup. Writes now validate references; deleting a referenced target is restricted by default. Choose `onDelete: 'cascade'` deliberately where deleting a target should delete referring records. An inverse with no explicit `onDelete` does not add its own restriction.
|
|
112
112
|
|
|
@@ -116,13 +116,13 @@ Do not regenerate IDs while converting the schema. Existing string IDs remain va
|
|
|
116
116
|
|
|
117
117
|
`generated` is not implied by `primary`. Without it, clients must supply the primary key on create. With it, clients must omit generated fields; sending them is rejected instead of ignored as in 0.9.0.
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
Declare existing application fields in the new schema, or remove them from the copy you are migrating. A custom archive flag does not automatically become soft deletion. Auth, timestamps and soft deletion reserve their system field names; rename conflicting application fields before enabling them.
|
|
120
120
|
|
|
121
121
|
## 4. Select APIs and update startup commands
|
|
122
122
|
|
|
123
123
|
If root `api` is omitted, the server uses `['rest']`, or `['rest', 'graphql']` when `graphql` is configured. To expose the database only through GraphQL, set `api: ['graphql']` and add `graphql: {}`. A model inherits root `api` or narrows it; model `api: []` hides that model. Root `api: []` is invalid. Related models must enable the same APIs.
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
If you set root `api` explicitly, include `graphql` when the configuration has a `graphql` section and omit it otherwise. Auth and files remain REST services and appear only in OpenAPI. OpenAPI can describe these services even when the database is available only through GraphQL.
|
|
126
126
|
|
|
127
127
|
| Old CLI | New CLI |
|
|
128
128
|
|---|---|
|
|
@@ -170,15 +170,13 @@ Update response readers as well:
|
|
|
170
170
|
|
|
171
171
|
`PATCH` merges top-level fields; a supplied nested plain object replaces that object while preserving protected fields. `PUT` replaces writable fields, preserving primary, generated, read-only and system values. Required fields must be supplied for creation/replacement unless they have defaults.
|
|
172
172
|
|
|
173
|
-
Relation values are objects, for example `country: { id: '1' }`, not scalar IDs.
|
|
174
|
-
|
|
175
|
-
**When upgrading from RC6:** key-only objects no longer update the target, change its audit values or require ownership of an unchanged target. If an existing client intends to update or replace the target, include the fields to change. Declared storage keys remain available for link-only writes.
|
|
173
|
+
Relation values are objects, for example `country: { id: '1' }`, not scalar IDs. An object containing only the primary key is a reference in POST, PUT and PATCH. It preserves the target's fields, timestamps and ownership. Adding other fields updates the target: PUT replaces it and requires its mandatory fields without defaults; POST/PATCH update supplied fields. Changing an inverse relation requires permission for every record whose stored key changes. Declared storage keys, such as `countryId`, can also change links directly. Do not send the relation and its storage key in the same object.
|
|
176
174
|
|
|
177
175
|
Omitted inverse (`keyOn: 'related'`) relations survive PUT. Explicit `users: []` changes users' foreign keys to detach them; it can fail if those keys are required or the caller lacks permission. Nested changes are atomic, and modifying a shared target affects every record referring to it.
|
|
178
176
|
|
|
179
|
-
Auth, timestamps and soft deletion are
|
|
177
|
+
Auth, timestamps and soft deletion are optional. To keep writes available without login and retain physical deletion during the first migration, omit `auth` and leave `timestamps` and `softDelete` disabled, as they are by default.
|
|
180
178
|
|
|
181
|
-
If enabling auth, create a separate
|
|
179
|
+
If enabling auth, create a separate user store and set ownership for existing records. Only administrators can change records without `createdById`. The server manages ownership through the API, so set it in the copied database before startup if ordinary users must edit those records. Reads and file operations remain public. File storage saves hashed sessions in the user file and restores unexpired sessions after a restart. Existing users without `sessions` remain valid. Stop the server before manually changing a password hash, and clear that user's `sessions` at the same time.
|
|
182
180
|
|
|
183
181
|
With `softDelete`, DELETE retains records, lists hide deleted records by default, direct primary-key reads can retrieve them, and successful PUT/PATCH restores them. There is no automatic conversion of an old application archive flag. See the [lifecycle rules](README.md#record-dates-deletion-and-ownership) before enabling this feature.
|
|
184
182
|
|
|
@@ -186,12 +184,12 @@ With `softDelete`, DELETE retains records, lists hide deleted records by default
|
|
|
186
184
|
|
|
187
185
|
`createServer(config)` now takes exactly one argument. Remove the old second `{ files: false }` argument and omit `files` from the config to disable the feature.
|
|
188
186
|
|
|
189
|
-
`facade.openapi()` and `facade.graphql()` return documents without writing `target`.
|
|
187
|
+
`facade.openapi()` and `facade.graphql()` return documents without writing `target`. Both methods require `database.schema` and their respective configuration sections. OpenAPI also requires `package.source`. Use CLI generation flags or explicit writers:
|
|
190
188
|
|
|
191
189
|
```js
|
|
192
190
|
import { createServer } from '@kollors/deep-json-server';
|
|
193
191
|
import { writeOpenapi } from '@kollors/deep-json-server/openapi';
|
|
194
|
-
import config from './server.config.
|
|
192
|
+
import config from './server.config.mjs';
|
|
195
193
|
|
|
196
194
|
const facade = await createServer(config);
|
|
197
195
|
await writeOpenapi(await facade.openapi(), './generated/openapi.yaml');
|
|
@@ -202,10 +200,20 @@ await app.close();
|
|
|
202
200
|
|
|
203
201
|
Schema generation alone does not validate existing database records. Call `ready()`, `inject()` or `listen()` to initialize HTTP and check data. Regenerate clients from the new OpenAPI/GraphQL documents after changing models and queries.
|
|
204
202
|
|
|
205
|
-
## 8.
|
|
203
|
+
## 8. Check the migration and prepare rollback
|
|
206
204
|
|
|
207
|
-
1. Pin
|
|
205
|
+
1. Pin `@kollors/deep-json-server@1.0.0` and migrate a **copy** of the 0.9.0 files. Generate the schemas, then initialize the HTTP server to validate the stored data.
|
|
208
206
|
2. Check representative reads: defaults, explicit foreign keys, nested lists, filters and pagination. Check create, PATCH, PUT, link changes and deletion using disposable copied records.
|
|
209
207
|
3. If enabling auth, test an owner, an administrator and an ordinary non-owner against old records. Confirm uploaded files remain accessible through the retained metadata path.
|
|
210
|
-
4. Stop
|
|
208
|
+
4. Stop all old server processes before switching. Version 1.0.0 locks the database, auth users, upload root and file metadata with native OS locks and readable `<source-name>-lock.json` files. Use one process per writable store and stop it before manual edits.
|
|
211
209
|
5. Keep the original package version, config, schema, data and file metadata together for rollback. Restore them together; do not point 0.9.0 at data already modified by the new server. Include new increment counters (`<database>.counters.json`) and soft-delete restoration metadata in subsequent backups when used.
|
|
210
|
+
|
|
211
|
+
## Upgrading from a release candidate
|
|
212
|
+
|
|
213
|
+
RC9 and 1.0.0 use the same API and stored-data formats. If you use an earlier RC, check the following changes and compare your configuration and schema with the current README:
|
|
214
|
+
|
|
215
|
+
- **Before RC6:** explicit relations now require declarations on both models, with `keyOn: 'current'` on the side that stores the key and `keyOn: 'related'` on its inverse. Follow the paired-model example in section 3.
|
|
216
|
+
- **Before RC7:** nested objects containing only a primary key now link an existing record without updating its fields, dates or owner. Include the fields to change when you intend to update the target. Automatically inferred list keys targeting non-primary fields are now arrays; convert scalar values from earlier versions to arrays, for example `"A"` to `["A"]`. Explicitly declared key types are unchanged.
|
|
217
|
+
- **Before RC8:** stop all old processes before upgrading. Native locks and `<source-name>-lock.json` files replace the earlier lock protocol; old and new versions cannot coordinate their locks. File-backed auth sessions are now saved with users, and users without `sessions` remain valid. For a primary key named `data`, GraphQL update/replace mutations use `key` for its value and `data` for the input object; regenerate affected clients.
|
|
218
|
+
|
|
219
|
+
See [the changelog](CHANGELOG.md) for the full RC history.
|
package/MIGRATION.ru.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Переход с 0.9.0 на 1.0.0
|
|
1
|
+
# Переход с 0.9.0 на 1.0.0
|
|
2
2
|
|
|
3
3
|
[English](MIGRATION.md) · [Актуальный README](README.ru.md)
|
|
4
4
|
|
|
5
|
-
Руководство
|
|
5
|
+
Руководство описывает переход с `0.9.0` на `1.0.0`. Конфигурацию и клиентов нужно обновлять вместе. Требуется Node.js 22 или новее. Перед переходом сделайте резервную копию базы, конфигурации, схемы, загруженных файлов и метаданных. Если уже используете предварительную версию 1.0, см. [переход с релиз-кандидата](#переход-с-релиз-кандидата).
|
|
6
6
|
|
|
7
7
|
## 1. Выберите режим со схемой или без неё
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ export default { database: { path: './database.json' } };
|
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
```js
|
|
17
|
-
// 1.0.0
|
|
17
|
+
// 1.0.0
|
|
18
18
|
export default { storage: 'file', database: { source: './database.json' } };
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -22,7 +22,7 @@ REST без схемы и связи по именам хранимых поле
|
|
|
22
22
|
|
|
23
23
|
## 2. Обновите конфигурацию
|
|
24
24
|
|
|
25
|
-
| В 0.9.0 | В 1.0.0
|
|
25
|
+
| В 0.9.0 | В 1.0.0 |
|
|
26
26
|
|---|---|
|
|
27
27
|
| `database.path` | `storage: 'file'` и `database.source` |
|
|
28
28
|
| `database.data` | `storage: 'memory'` и `database.source` |
|
|
@@ -33,7 +33,7 @@ REST без схемы и связи по именам хранимых поле
|
|
|
33
33
|
| `$info` в схеме | `package.source`: `name`, `version`, необязательный `description` |
|
|
34
34
|
| `server.maxPageSize` по умолчанию `1000` | Теперь `100`; для прежнего ограничения задайте `1000` явно |
|
|
35
35
|
|
|
36
|
-
Обязательный `storage`
|
|
36
|
+
Обязательный `storage` задаёт режим хранения всех источников, включая схему и метаданные пакета. В режиме `file` указывайте пути, в `memory` — объекты и массивы с данными. Смешивать дисковые источники и данные в памяти больше нельзя. Пути экспорта `target` остаются путями к файлам в обоих режимах.
|
|
37
37
|
|
|
38
38
|
Пример конфигурации с дисковой базой и экспортом OpenAPI:
|
|
39
39
|
|
|
@@ -48,15 +48,15 @@ export default {
|
|
|
48
48
|
};
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
Создайте `schema.json` по
|
|
51
|
+
Создайте `schema.json` по примеру в следующем разделе. При наличии секции `openapi` обязателен `package.source`: имя пакета становится `info.title`, также используются `version` и необязательный `description`. Для остальных свойств старого `$info` аналога в конфигурации нет. В режиме `memory` передавайте `package: { source: { name: 'example-api', version: '1.0.0' } }`.
|
|
52
52
|
|
|
53
53
|
**Сохраните прежний `files.metadata` явно.** Без него сервер выберет `<files.source>/.files.json` и не импортирует старый `_database.json`. Формат метаданных из 0.9.0 и маршруты `/_files/*` совместимы; заголовки загрузки бинарного тела и ответ `204` на удаление файла сохраняются.
|
|
54
54
|
|
|
55
55
|
Относительные пути по-прежнему отсчитываются от каталога конфигурации в CLI и от рабочего каталога при прямом вызове `createServer(config)`.
|
|
56
56
|
|
|
57
|
-
## 3.
|
|
57
|
+
## 3. Опишите модели вместо прежних настроек схемы
|
|
58
58
|
|
|
59
|
-
В 0.9.0 `$schema` дополнял
|
|
59
|
+
В 0.9.0 `$schema` дополнял типы полей, определённые по данным. В 1.0.0 каждой коллекции нужна модель с `collection`, `fields` и одним первичным ключом верхнего уровня типа `string` или `number`.
|
|
60
60
|
|
|
61
61
|
| Старое описание | Новое описание |
|
|
62
62
|
|---|---|
|
|
@@ -66,9 +66,9 @@ export default {
|
|
|
66
66
|
| Вложенные `properties` и `items` | Поля с типами, `[]` для массивов, пути через точку для дочерних полей |
|
|
67
67
|
| Автоматический строковый `id` | Явный `{ type: 'string', primary: true, generated: 'uuid' }` |
|
|
68
68
|
|
|
69
|
-
Опишите все хранимые поля, а не только
|
|
69
|
+
Опишите все хранимые поля, а не только те, для которых раньше задавали настройки. Например, `actors` получает тип `object[]`, а `actors.fullName` — `string`. При явной схеме неизвестные поля и коллекции запрещены; исключение — автоматически определённые ключи связей. Существующие записи проверяются при инициализации HTTP-сервера.
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
Для полей с несколькими типами через `oneOf` и ограничения «только целые числа» через `integer` прямого аналога нет. Приведите данные к поддерживаемому типу или оставьте REST без схемы. Имена моделей должны быть допустимыми идентификаторами: старые имена компонентов с точками и дефисами нужно заменить.
|
|
72
72
|
|
|
73
73
|
### Полный пример с двусторонней связью
|
|
74
74
|
|
|
@@ -99,14 +99,14 @@ export default {
|
|
|
99
99
|
}
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
Объявите каждую связь с обеих сторон и укажите `keyOn` у обоих полей. Сторона `current` хранит внешний ключ; `related` использует этот ключ в другой модели. Второй экземпляр ключа или хранимый массив `users` не нужен.
|
|
103
103
|
|
|
104
104
|
- У прямой связи `target` по умолчанию равен первичному ключу целевой модели. `source` выводится из имени поля связи и целевого ключа: `country` → `countryId`, `publishers` → `publisherIds`. При первичном ключе `ref` получится `publisherRefs`.
|
|
105
105
|
- У обратной связи пути меняются местами: для `Country.users` это `source: 'id'` и `target: 'countryId'`.
|
|
106
106
|
- Связь модели с собой: `Genre.parents: { type: 'Genre[]', keyOn: 'current' }` и `Genre.children: { type: 'Genre[]', keyOn: 'related' }` используют один хранимый массив `Genre.parentIds`.
|
|
107
107
|
- Если между моделями несколько связей, укажите, какие поля образуют пары: у обратной `Country.birthUsers` задайте `target: 'birthCountryId'`, у `Country.residenceUsers` — `target: 'residenceCountryId'`. Неоднозначные и отсутствующие пары отклоняются при загрузке.
|
|
108
108
|
- Объявляйте существующие ключи в `fields`, как в примере, если клиент их читает, фильтрует, сортирует или записывает. Автоматически выведенные ключи остаются в базе, но скрыты из обоих API и OpenAPI; выбрать их даже по имени нельзя.
|
|
109
|
-
-
|
|
109
|
+
- Для списков с **непервичным** целевым полем сервер тоже определяет массив ключей. Например, `publishers` с `keyOn: 'current'` и `target: 'code'` получает `publisherCodes: { type: 'string[]' }`, если `Publisher.code` — строка. Объявите ключ в `fields`, если клиенту нужен прямой доступ к нему. Тип явно объявленного скалярного ключа сохраняется.
|
|
110
110
|
|
|
111
111
|
До запуска исправьте ссылки на отсутствующие записи. Теперь запись проверяет целостность связей, а удаление целевой записи по умолчанию запрещено, пока на неё ссылаются. Задавайте `onDelete: 'cascade'` только там, где удаление цели должно удалять ссылающиеся записи. Обратная связь без явно указанного `onDelete` не добавляет собственного запрета.
|
|
112
112
|
|
|
@@ -116,13 +116,13 @@ export default {
|
|
|
116
116
|
|
|
117
117
|
`primary` не включает `generated` автоматически. Без `generated` клиент сам передаёт ключ при создании. С `generated` клиент должен пропускать генерируемые поля: теперь их передача отклоняется, а не игнорируется, как в 0.9.0.
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
Объявите прежние поля приложения в новой схеме или удалите их из копии, которую переносите. Пользовательский флаг архивирования не превращается в мягкое удаление автоматически. Аутентификация, даты записей и мягкое удаление резервируют свои служебные имена; переименуйте конфликтующие поля до включения этих функций.
|
|
120
120
|
|
|
121
121
|
## 4. Выберите API и обновите команды запуска
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
Если корневой `api` не задан, сервер использует `['rest']`, а при наличии секции `graphql` — `['rest', 'graphql']`. Для доступа к базе только через GraphQL задайте `api: ['graphql']` и добавьте `graphql: {}`. Модель наследует значение из корня или сужает список API; `api: []` у модели скрывает её. Корневой `api: []` недопустим. Связанные модели должны разрешать одинаковые API.
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
Если задаёте корневой `api` явно, включите в него `graphql` при наличии секции `graphql` в конфигурации и исключите в остальных случаях. Маршруты аутентификации и файлов доступны через REST и описываются только в OpenAPI. OpenAPI может описывать их и тогда, когда база доступна только через GraphQL.
|
|
126
126
|
|
|
127
127
|
| Старый флаг CLI | Замена |
|
|
128
128
|
|---|---|
|
|
@@ -166,32 +166,30 @@ const url = `/users?${new URLSearchParams({ scope: JSON.stringify(scope) })}`;
|
|
|
166
166
|
- Строковые сравнения `gt/gte/lt/lte` используют порядок без учёта регистра, с учётом числовых частей. Проверьте клиентов, полагавшихся на прежнее лексикографическое сравнение.
|
|
167
167
|
- JSON scope ограничен 10 000 символов и 32 уровнями выбора. Неизвестные поля и операторы отклоняются даже на пустых данных.
|
|
168
168
|
|
|
169
|
-
## 6. Проверьте запись и включение
|
|
169
|
+
## 6. Проверьте запись и включение аутентификации
|
|
170
170
|
|
|
171
171
|
`PATCH` объединяет поля верхнего уровня; переданный вложенный обычный объект заменяет прежний с сохранением защищённых полей. `PUT` заменяет доступные для записи поля, сохраняя первичный ключ, генерируемые, служебные и `readOnly` значения. При создании и замене нужны все обязательные поля без значений по умолчанию.
|
|
172
172
|
|
|
173
|
-
Поле связи принимает объекты, например `country: { id: '1' }`, а не скалярные ID.
|
|
174
|
-
|
|
175
|
-
**При переходе с RC6:** объект только с ключом больше не обновляет цель, не меняет её даты/авторство и не требует владения неизменяемой целевой записью. Если клиент намерен обновить или заменить цель, передавайте поля для изменения. Объявленные хранимые ключи по-прежнему позволяют менять только ссылки.
|
|
173
|
+
Поле связи принимает объекты, например `country: { id: '1' }`, а не скалярные ID. Объект только с первичным ключом считается ссылкой в POST, PUT и PATCH. Поля, даты и сведения о владельце целевой записи сохраняются. Если передать другие поля, сервер изменит целевую запись: PUT заменяет её и требует обязательные поля без значений по умолчанию, POST/PATCH обновляют переданные поля. При изменении обратной связи нужны права на каждую запись, чей хранимый ключ меняется. Объявленные хранимые ключи, например `countryId`, тоже позволяют менять ссылки напрямую. Не передавайте одновременно связь и её хранимый ключ.
|
|
176
174
|
|
|
177
175
|
Пропущенные обратные связи (`keyOn: 'related'`) сохраняются при PUT. Явное `users: []` меняет ключи пользователей, чтобы отсоединить их; операция может завершиться ошибкой при обязательных ключах или отсутствии прав. Вложенные изменения атомарны, а изменение общей целевой записи видно всем, кто на неё ссылается.
|
|
178
176
|
|
|
179
|
-
|
|
177
|
+
Аутентификация, даты записей и мягкое удаление необязательны. Чтобы на первом этапе сохранить возможность записи без входа и физическое удаление, не добавляйте `auth` и оставьте `timestamps` и `softDelete` выключенными, как по умолчанию.
|
|
180
178
|
|
|
181
|
-
Если включаете
|
|
179
|
+
Если включаете аутентификацию, создайте отдельное хранилище пользователей и задайте владельцев существующих записей. Записи без `createdById` может менять только администратор. Через API владельца назначает сервер, поэтому задайте его в копии базы до запуска, если прежние записи должны редактировать обычные пользователи. Чтение и операции с файлами остаются открытыми. Дисковый режим сохраняет хеши сессий в файле пользователей и восстанавливает действующие сессии после перезапуска. Старые пользователи без `sessions` остаются допустимыми. Для ручной замены хеша пароля остановите сервер и одновременно очистите `sessions` этого пользователя.
|
|
182
180
|
|
|
183
|
-
При `softDelete` DELETE сохраняет
|
|
181
|
+
При `softDelete` DELETE сохраняет запись в базе. Списки по умолчанию скрывают удалённые записи, запрос по первичному ключу может вернуть их, а успешный PUT/PATCH восстанавливает. Прежний пользовательский флаг архивирования не преобразуется автоматически. Перед включением прочитайте [правила дат, удаления и владения](README.ru.md#даты-записей-удаление-и-владельцы).
|
|
184
182
|
|
|
185
183
|
## 7. Обновите программное использование
|
|
186
184
|
|
|
187
185
|
`createServer(config)` принимает ровно один аргумент. Уберите прежний второй аргумент `{ files: false }`; для отключения файлов уберите `files` из конфигурации.
|
|
188
186
|
|
|
189
|
-
`facade.openapi()` и `facade.graphql()` возвращают документы без записи в `target`.
|
|
187
|
+
`facade.openapi()` и `facade.graphql()` возвращают документы без записи в `target`. Для обоих методов нужны `database.schema` и соответствующие секции конфигурации. OpenAPI также требует `package.source`. Используйте флаги генерации CLI или явную запись:
|
|
190
188
|
|
|
191
189
|
```js
|
|
192
190
|
import { createServer } from '@kollors/deep-json-server';
|
|
193
191
|
import { writeOpenapi } from '@kollors/deep-json-server/openapi';
|
|
194
|
-
import config from './server.config.
|
|
192
|
+
import config from './server.config.mjs';
|
|
195
193
|
|
|
196
194
|
const facade = await createServer(config);
|
|
197
195
|
await writeOpenapi(await facade.openapi(), './generated/openapi.yaml');
|
|
@@ -200,12 +198,22 @@ await app.ready(); // Инициализация и проверка базы б
|
|
|
200
198
|
await app.close();
|
|
201
199
|
```
|
|
202
200
|
|
|
203
|
-
|
|
201
|
+
Генерация схем не проверяет существующие записи базы. Для инициализации HTTP-сервера и проверки данных вызовите `ready()`, `inject()` или `listen()`. После изменения моделей и запросов пересоздайте клиентов из новых OpenAPI/GraphQL-документов.
|
|
204
202
|
|
|
205
203
|
## 8. Проверьте переход и подготовьте откат
|
|
206
204
|
|
|
207
|
-
1.
|
|
205
|
+
1. Установите `@kollors/deep-json-server@1.0.0` и перенесите **копию** файлов 0.9.0. Выполните генерацию схем, затем инициализируйте HTTP-сервер для проверки сохранённых данных.
|
|
208
206
|
2. Проверьте чтение по умолчанию, явные ключи, вложенные списки, фильтры и пагинацию. На одноразовых копиях записей проверьте создание, PATCH, PUT, изменение связей и удаление.
|
|
209
|
-
3. При включении
|
|
210
|
-
4. Перед переключением остановите все старые процессы
|
|
207
|
+
3. При включении аутентификации проверьте владельца, администратора и обычного пользователя без владения на старых записях. Убедитесь, что загруженные файлы доступны через прежний путь к метаданным.
|
|
208
|
+
4. Перед переключением остановите все старые процессы сервера. Версия 1.0.0 блокирует базу, файл пользователей, каталог загрузок и метаданные файлов системными блокировками и читаемыми файлами `<имя-источника>-lock.json`. Используйте один процесс на записываемое хранилище и останавливайте его перед ручными правками.
|
|
211
209
|
5. Для отката храните вместе старую версию пакета, конфигурацию, схему, базу и метаданные файлов. Восстанавливайте их вместе; не направляйте 0.9.0 на данные, уже изменённые новым сервером. В последующие резервные копии включайте новые счётчики (`<database>.counters.json`) и служебные данные восстановления мягкого удаления, если используете эти функции.
|
|
210
|
+
|
|
211
|
+
## Переход с релиз-кандидата
|
|
212
|
+
|
|
213
|
+
RC9 и 1.0.0 используют одинаковый API и формат хранимых данных. Если у вас более ранняя RC, проверьте следующие изменения и сравните конфигурацию и схему с актуальным README:
|
|
214
|
+
|
|
215
|
+
- **До RC6:** явную связь теперь нужно объявлять в обеих моделях. У стороны, где хранится ключ, укажите `keyOn: 'current'`, у обратной — `keyOn: 'related'`. Используйте пример двух моделей из раздела 3.
|
|
216
|
+
- **До RC7:** вложенный объект только с первичным ключом теперь связывает существующую запись без изменения её полей, дат и владельца. Если хотите изменить цель, передайте поля для изменения. Автоматически определённые ключи списков с непервичным целевым полем теперь имеют тип массива; преобразуйте прежние скалярные значения в массивы, например `"A"` в `["A"]`. Типы явно объявленных ключей не меняются.
|
|
217
|
+
- **До RC8:** перед обновлением остановите все старые процессы. Системные блокировки и файлы `<имя-источника>-lock.json` заменяют прежний протокол; старые и новые версии не могут согласовать блокировки. Сессии в дисковом режиме теперь сохраняются вместе с пользователями; пользователи без `sessions` остаются допустимыми. Если первичный ключ называется `data`, мутации GraphQL update/replace принимают его значение в `key`, а объект изменений — в `data`; пересоздайте затронутые клиенты.
|
|
218
|
+
|
|
219
|
+
Полная история RC — в [changelog](CHANGELOG.md).
|