@kollors/deep-json-server 1.0.0-alpha.1 → 1.0.0-alpha.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 (124) hide show
  1. package/README.md +104 -53
  2. package/README.ru.md +103 -50
  3. package/dist/index.d.ts +5 -1
  4. package/dist/index.js +1 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/src/cli.d.ts +2 -2
  7. package/dist/src/cli.js +97 -48
  8. package/dist/src/cli.js.map +1 -1
  9. package/dist/src/config.d.ts +14 -1
  10. package/dist/src/config.js +56 -8
  11. package/dist/src/config.js.map +1 -1
  12. package/dist/src/constants.d.ts +1 -0
  13. package/dist/src/constants.js +1 -0
  14. package/dist/src/constants.js.map +1 -1
  15. package/dist/src/database.d.ts +0 -1
  16. package/dist/src/database.js +12 -10
  17. package/dist/src/database.js.map +1 -1
  18. package/dist/src/engine.d.ts +21 -10
  19. package/dist/src/engine.js +77 -144
  20. package/dist/src/engine.js.map +1 -1
  21. package/dist/src/errors.d.ts +6 -0
  22. package/dist/src/errors.js +9 -0
  23. package/dist/src/errors.js.map +1 -0
  24. package/dist/src/features.d.ts +8 -0
  25. package/dist/src/features.js +18 -0
  26. package/dist/src/features.js.map +1 -0
  27. package/dist/src/files/contract.d.ts +0 -30
  28. package/dist/src/files/contract.js +6 -47
  29. package/dist/src/files/contract.js.map +1 -1
  30. package/dist/src/files/disk-store.d.ts +2 -1
  31. package/dist/src/files/disk-store.js +28 -18
  32. package/dist/src/files/disk-store.js.map +1 -1
  33. package/dist/src/files/http.d.ts +31 -0
  34. package/dist/src/files/http.js +44 -0
  35. package/dist/src/files/http.js.map +1 -0
  36. package/dist/src/files/index.d.ts +1 -1
  37. package/dist/src/files/index.js +1 -1
  38. package/dist/src/files/index.js.map +1 -1
  39. package/dist/src/files/memory-store.js +8 -7
  40. package/dist/src/files/memory-store.js.map +1 -1
  41. package/dist/src/files/openapi.js +2 -4
  42. package/dist/src/files/openapi.js.map +1 -1
  43. package/dist/src/files/routes.js +3 -2
  44. package/dist/src/files/routes.js.map +1 -1
  45. package/dist/src/graphql/entry.d.ts +3 -0
  46. package/dist/src/graphql/entry.js +3 -0
  47. package/dist/src/graphql/entry.js.map +1 -0
  48. package/dist/src/graphql/preflight.d.ts +3 -0
  49. package/dist/src/graphql/preflight.js +30 -0
  50. package/dist/src/graphql/preflight.js.map +1 -0
  51. package/dist/src/graphql/public.d.ts +3 -0
  52. package/dist/src/graphql/public.js +11 -0
  53. package/dist/src/graphql/public.js.map +1 -0
  54. package/dist/src/graphql/resolvers.d.ts +8 -0
  55. package/dist/src/graphql/resolvers.js +38 -0
  56. package/dist/src/graphql/resolvers.js.map +1 -0
  57. package/dist/src/graphql/routes.d.ts +4 -0
  58. package/dist/src/graphql/routes.js +27 -0
  59. package/dist/src/graphql/routes.js.map +1 -0
  60. package/dist/src/graphql/write.d.ts +1 -0
  61. package/dist/src/graphql/write.js +7 -0
  62. package/dist/src/graphql/write.js.map +1 -0
  63. package/dist/src/graphql.d.ts +1 -2
  64. package/dist/src/graphql.js +24 -34
  65. package/dist/src/graphql.js.map +1 -1
  66. package/dist/src/http/errors.d.ts +6 -0
  67. package/dist/src/http/errors.js +3 -0
  68. package/dist/src/http/errors.js.map +1 -0
  69. package/dist/src/model.d.ts +2 -3
  70. package/dist/src/model.js +54 -12
  71. package/dist/src/model.js.map +1 -1
  72. package/dist/src/openapi/document.js +36 -29
  73. package/dist/src/openapi/document.js.map +1 -1
  74. package/dist/src/openapi/entry.d.ts +3 -0
  75. package/dist/src/openapi/entry.js +2 -0
  76. package/dist/src/openapi/entry.js.map +1 -0
  77. package/dist/src/openapi/helpers.d.ts +17 -0
  78. package/dist/src/openapi/helpers.js +4 -0
  79. package/dist/src/openapi/helpers.js.map +1 -0
  80. package/dist/src/openapi/index.js +6 -4
  81. package/dist/src/openapi/index.js.map +1 -1
  82. package/dist/src/openapi/public.d.ts +17 -0
  83. package/dist/src/openapi/public.js +18 -0
  84. package/dist/src/openapi/public.js.map +1 -0
  85. package/dist/src/pagination.d.ts +7 -0
  86. package/dist/src/pagination.js +12 -0
  87. package/dist/src/pagination.js.map +1 -0
  88. package/dist/src/paths.d.ts +6 -0
  89. package/dist/src/paths.js +47 -0
  90. package/dist/src/paths.js.map +1 -0
  91. package/dist/src/query/contract.d.ts +3 -0
  92. package/dist/src/query/contract.js +19 -0
  93. package/dist/src/query/contract.js.map +1 -0
  94. package/dist/src/query/filter.d.ts +3 -1
  95. package/dist/src/query/filter.js +78 -76
  96. package/dist/src/query/filter.js.map +1 -1
  97. package/dist/src/query/options.d.ts +1 -14
  98. package/dist/src/query/options.js +6 -109
  99. package/dist/src/query/options.js.map +1 -1
  100. package/dist/src/relation-metadata.d.ts +0 -1
  101. package/dist/src/relation-metadata.js +0 -1
  102. package/dist/src/relation-metadata.js.map +1 -1
  103. package/dist/src/rest/options.d.ts +14 -0
  104. package/dist/src/rest/options.js +108 -0
  105. package/dist/src/rest/options.js.map +1 -0
  106. package/dist/src/rest/projection.d.ts +6 -0
  107. package/dist/src/rest/projection.js +38 -0
  108. package/dist/src/rest/projection.js.map +1 -0
  109. package/dist/src/rest/routes.d.ts +3 -0
  110. package/dist/src/rest/routes.js +48 -0
  111. package/dist/src/rest/routes.js.map +1 -0
  112. package/dist/src/schema.d.ts +8 -0
  113. package/dist/src/schema.js +13 -0
  114. package/dist/src/schema.js.map +1 -0
  115. package/dist/src/server/public.d.ts +3 -0
  116. package/dist/src/server/public.js +2 -0
  117. package/dist/src/server/public.js.map +1 -0
  118. package/dist/src/server.d.ts +5 -7
  119. package/dist/src/server.js +86 -143
  120. package/dist/src/server.js.map +1 -1
  121. package/dist/src/utils.d.ts +0 -7
  122. package/dist/src/utils.js +0 -4
  123. package/dist/src/utils.js.map +1 -1
  124. package/package.json +13 -1
package/README.ru.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  JSON-сервер для имитации API: REST, GraphQL, вложенные запросы, бинарные файлы и экспорт схем. Требуется Node.js 22 или новее.
6
6
 
7
- **1.0.0-alpha.1 — предварительная версия с несовместимыми изменениями.** Старые `$schema`/`$info` и параметры `_where`, `_sort`, `_embed`, `_page`, `_perPage` больше не поддерживаются.
7
+ **1.0.0-alpha.3 — предварительная версия.** При переходе с 0.x обновите схему моделей и параметры запросов по примерам ниже.
8
8
 
9
9
  ## Установка
10
10
 
@@ -12,29 +12,35 @@ JSON-сервер для имитации API: REST, GraphQL, вложенные
12
12
  npm install @kollors/deep-json-server@alpha
13
13
  ```
14
14
 
15
- Канал npm `alpha` отделён от `latest`. Для точной версии используйте `@1.0.0-alpha.1`.
15
+ Для установки конкретной версии укажите `@1.0.0-alpha.3`.
16
16
 
17
17
  ## Быстрый старт
18
18
 
19
+ Создайте два файла в одном каталоге.
20
+
21
+ `database.json`:
22
+
23
+ ```json
24
+ {
25
+ "users": [
26
+ { "id": "1", "fullName": "Мира Волкова" }
27
+ ]
28
+ }
29
+ ```
30
+
19
31
  `server.config.js`:
20
32
 
21
33
  ```js
22
34
  export default {
23
- database: { path: './database.json', schema: './schema.json' },
24
- graphql: { enabled: true, path: './generated/schema.graphql' },
25
- openapi: { path: './generated/openapi.yaml' },
26
- server: { host: '127.0.0.1', port: 4001, pageSize: 10, maxPageSize: 100 },
35
+ database: { path: './database.json' },
27
36
  };
28
37
  ```
29
38
 
30
39
  ```sh
31
40
  npx deep-json-server server.config.js
32
- npx deep-json-server --openapi-only --graphql-only server.config.js
33
41
  ```
34
42
 
35
- Вторая команда экспортирует обе схемы без запуска сервера. Обычный запуск не записывает файлы схем.
36
-
37
- Полные примеры каталога: [база](examples/database.json), [схема моделей](examples/schema.json), [конфигурация](examples/server.config.js).
43
+ Список пользователей доступен по адресу `http://127.0.0.1:4001/users`.
38
44
 
39
45
  ## Конфигурация
40
46
 
@@ -42,8 +48,10 @@ npx deep-json-server --openapi-only --graphql-only server.config.js
42
48
  |---|---|
43
49
  | `database.path` / `database.data` | Ровно один: JSON-файл или объект коллекций в памяти |
44
50
  | `database.schema` | Объект моделей или путь к JSON-файлу; необязателен для REST |
51
+ | `openapi.enabled` | Включить HTTP-маршрут спецификации; по умолчанию `false` |
52
+ | `openapi.endpoint` | Путь спецификации; по умолчанию `/openapi.json` |
45
53
  | `openapi.path` | Путь экспорта YAML |
46
- | `openapi.info` | Необязательные метаданные: `title`, `version`, `description` |
54
+ | `openapi.info` | Необязательный объект метаданных: обязательные `title` и `version`, необязательный `description` |
47
55
  | `graphql.enabled` | Включить GraphQL HTTP API; по умолчанию `false` |
48
56
  | `graphql.endpoint` | Путь GraphQL; по умолчанию `/graphql` |
49
57
  | `graphql.path` | Путь экспорта GraphQL SDL |
@@ -54,22 +62,46 @@ npx deep-json-server --openapi-only --graphql-only server.config.js
54
62
  | `files.data` | Бинарные файлы в памяти |
55
63
  | `files.directory`, `files.metadata` | Каталог файлов и JSON метаданных; необходимы оба |
56
64
 
57
- Пути конфигурационного файла разрешаются относительно него. При прямом `createServer()` — относительно рабочего каталога. Переданные данные в памяти копируются.
65
+ Относительные пути отсчитываются от каталога конфигурационного файла. При вызове `createServer()` с объектом конфигурации от рабочего каталога. Сервер работает с копией переданных данных в памяти и метаданных.
66
+
67
+ Значение `server.port: 0` позволяет системе выбрать свободный порт. OpenAPI на HTTP-эндпоинте использует относительный адрес сервера.
58
68
 
59
69
  | Флаг CLI | Действие |
60
70
  |---|---|
61
71
  | `--files` | Включить файловые маршруты |
62
72
  | `--graphql` | Включить GraphQL API |
63
- | `--openapi` | Экспортировать OpenAPI и запустить сервер |
64
- | `--openapi-only` | Только экспортировать OpenAPI |
65
- | `--graphql-schema` | Экспортировать GraphQL SDL и запустить сервер |
66
- | `--graphql-only` | Только экспортировать GraphQL SDL |
67
- | `--help` | Показать справку |
73
+ | `--openapi` | Включить HTTP-маршрут OpenAPI |
74
+ | `--host <host>` | Адрес сервера |
75
+ | `--port <port>` | Порт сервера |
76
+ | `--help`, `-h` | Справка |
77
+ | `--version`, `-v` | Версия пакета |
78
+
79
+ Приоритет настроек: CLI → конфигурация → `HOST`/`PORT` → значения по умолчанию. Файловые маршруты включаются при наличии секции `files`.
68
80
 
69
- Экспортеры можно объединять. Любой флаг `--*-only` исключает запуск сервера. В CLI для файлов нужен `--files`; программный API включает их при наличии секции `files`, если второй аргумент `createServer()` не переопределяет это поведение.
81
+ Для генерации укажите формат и файл конфигурации:
82
+
83
+ ```sh
84
+ npx deep-json-server generate openapi server.config.js
85
+ npx deep-json-server generate graphql server.config.js
86
+ npx deep-json-server generate openapi,graphql server.config.js
87
+ ```
88
+
89
+ Команда читает `database.schema` и сохраняет схемы в `openapi.path` и `graphql.path`. Для генерации достаточно такой конфигурации:
90
+
91
+ ```js
92
+ export default {
93
+ database: { schema: './schema.json' },
94
+ openapi: { path: './generated/openapi.yaml' },
95
+ graphql: { path: './generated/schema.graphql' },
96
+ };
97
+ ```
98
+
99
+ Для каждого формата нужен отдельный файл. Команда отклонит путь, который перезапишет конфигурацию, базу, схему или метаданные файлов.
70
100
 
71
101
  ## Схема моделей
72
102
 
103
+ Примеры: [база данных](examples/database.json), [схема моделей](examples/schema.json), [конфигурация](examples/server.config.js).
104
+
73
105
  ```json
74
106
  {
75
107
  "Country": {
@@ -102,11 +134,13 @@ npx deep-json-server --openapi-only --graphql-only server.config.js
102
134
  | Экспорт OpenAPI 3.0.3 | Доступен | Ошибка при запросе экспорта |
103
135
  | GraphQL SDL / API | Доступен | Ошибка при запросе |
104
136
 
105
- При явной схеме неизвестные поля и коллекции запрещены. Исключение — хранимые ключи, выведенные из связей. Исходная база проверяется при загрузке. Схемы можно экспортировать для пустых коллекций и пустого объекта базы. REST без схемы сохраняет обычный генерируемый ключ `id`.
137
+ При явной схеме неизвестные поля и коллекции запрещены. Исключение — хранимые ключи, выведенные из связей. Исходная база проверяется при загрузке. Генерация использует описание моделей.
138
+
139
+ REST без схемы создаёт ключ `id` и сохраняет произвольные JSON-поля. Для фильтров и выбора отдельных полей используются имена в формате идентификаторов; остальные поля возвращаются через `scope=*`. Поля с разными типами значений можно читать, но для их использования в `where`, `order` или `nested` нужна явная схема.
106
140
 
107
141
  ### Поля
108
142
 
109
- Типы: `string`, `number`, `boolean`, `object` или имя модели. Суффикс `[]` обозначает массив. Нет `integer`, `relation`, `items` и многомерных строк типов. Вложенные поля описываются через точку: `actors.fullName`. Объект внутри массива может содержать собственные массивы.
143
+ Поле `type` принимает `string`, `number`, `boolean`, `object` или имя модели. Для массива добавьте суффикс `[]`: `string[]`, `object[]`, `Genre[]`. Вложенные поля описываются через точку, например `actors.fullName`.
110
144
 
111
145
  | Свойства | Назначение |
112
146
  |---|---|
@@ -114,7 +148,7 @@ npx deep-json-server --openapi-only --graphql-only server.config.js
114
148
  | `description`, `example` | Документация и пример |
115
149
  | `required`, `nullable` | По умолчанию `false`; наличие поля и разрешение `null` независимы |
116
150
  | `default` | Значение при пропуске в create/replace; PATCH не вставляет значения по умолчанию |
117
- | `enum` | Допустимые значения; у массива — значения каждого элемента |
151
+ | `enum` | Допустимые строки, числа или логические значения; у массива — значения каждого элемента |
118
152
  | `primary` | Корневой первичный ключ: обязательный, уникальный, неизменяемый, без `null` |
119
153
  | `generated` | `uuid` для строк, `increment` для чисел; значение создаёт сервер |
120
154
  | `readOnly`, `writeOnly` | Только ответ или только входные данные; взаимно исключаются |
@@ -123,11 +157,13 @@ npx deep-json-server --openapi-only --graphql-only server.config.js
123
157
  | `minimum`, `maximum` | Включительные числовые границы |
124
158
  | `source`, `target`, `onDelete` | Описание связи |
125
159
 
126
- Ограничения строк и чисел применяются к каждому элементу `string[]`/`number[]`. `required`/`nullable` относятся ко всему массиву; `default`/`example` содержат массив целиком. Элементы массива не допускают `null`. Ограничений количества и уникальности элементов нет. Обязательный обычный массив может быть пустым.
160
+ Ограничения строк и чисел применяются к каждому элементу `string[]`/`number[]`. `required` и `nullable` относятся ко всему массиву; `default` и `example` содержат массив целиком. Элементы массива должны соответствовать его типу и быть отличны от `null`. `required` требует наличия поля; обычный массив при этом может быть пустым.
127
161
 
128
- У модели ровно один корневой первичный ключ типа string/number. Имя произвольное: `id`, `username`, `code`. Без `generated` значение передаёт клиент при создании. Генерируемые поля могут быть только корневыми, исключаются из входных типов и несовместимы с `default`. Replace сохраняет корневые генерируемые поля и `readOnly`.
162
+ У модели ровно один первичный ключ типа `string` или `number`, объявленный на верхнем уровне. Имя произвольное: `id`, `username`, `code`. Если `generated` не задан, значение передаёт клиент при создании. Генерируемые поля объявляются на верхнем уровне, исключаются из входных типов и несовместимы с `default`. При замене записи сохраняются генерируемые значения и поля `readOnly`, включая вложенные объекты. Для защиты полей внутри массива задайте `readOnly` всему массиву или содержащему его объекту. Объекты, состоящие из серверных полей, доступны только в ответах.
129
163
 
130
- Например, `LocalUser` с первичным `username` и полем `password: {"type":"string","required":true,"writeOnly":true}` получает запрос `localUser(username: ...)` и маршрут `/localUsers/{username}`. Пароль исключён из ответов, scope, фильтров и сортировки. Это не реализует хеширование и авторизацию.
164
+ Например, `LocalUser` с первичным ключом `username` и полем `password: {"type":"string","required":true,"writeOnly":true}` получает запрос `localUser(username: ...)` и маршрут `/localUsers/{username}`. Поле `writeOnly` доступно для записи и исключено из ответов, `scope`, фильтров и сортировки.
165
+
166
+ Объекты в GraphQL должны содержать хотя бы одно поле, доступное в ответе; REST допускает и пустые объекты.
131
167
 
132
168
  ### Связи
133
169
 
@@ -139,20 +175,20 @@ npx deep-json-server --openapi-only --graphql-only server.config.js
139
175
  }
140
176
  ```
141
177
 
142
- `Genre` возвращает объект, `Genre[]` — список. Без `source` используем первичный ключ текущей модели, без `target` — первичный ключ целевой. Пути полные, от корня соответствующей записи. Внутри `actors` путь `actors.genreIds` читает ключи текущего актёра. Пропущенный `source` означает ключ корневой модели, а не `actors.id`.
178
+ `Genre` возвращает объект, `Genre[]` — список. По умолчанию `source` указывает на первичный ключ текущей модели, `target` — целевой. Это правило действует и для вложенных связей. Пути задаются от корня соответствующей записи: в примере `actors.genreIds` содержит ключи жанров текущего актёра.
143
179
 
144
- Хранимые ключи остаются в базе и входят в собственные поля. Их типы выводятся из сопоставляемых ключей. Для необъявленного source, ссылающегося на первичный ключ цели, множественная связь означает массив ключей, одиночная одно значение. Если сопоставление неоднозначно, нужное хранимое поле следует описать явно. Генерация не зависит от первой записи базы.
180
+ Ключи связей хранятся в базе и входят в собственные поля записи. Их типы выводятся из сопоставляемых ключей. Если поле `source` ссылается на первичный ключ целевой модели, его можно не объявлять отдельно: для множественной связи создаётся описание массива ключей, для одиночной одного значения. При неоднозначном сопоставлении опишите хранимое поле явно.
145
181
 
146
182
  Обратная связь: `User.movies = {"type":"Movie[]","target":"actors.userId"}`. Фильм возвращается один раз, даже если совпало несколько актёров. Несколько совпадений для одиночной связи — ошибка.
147
183
 
148
- Каждая переданная прямая ссылка должна существовать. `required: true` у связи требует хотя бы одну связанную запись до фильтрации и пагинации ответа. Обратная связь с первичным source может быть пустой, если не объявлена обязательной. Отсутствующая одиночная связь возвращает `null`.
184
+ Каждый переданный ключ прямой связи должен указывать на существующую запись. `required: true` у связи требует хотя бы одну связанную запись до фильтрации и пагинации ответа. Обратная связь с первичным ключом в `source` может быть пустой, если не объявлена обязательной. Отсутствующая одиночная связь возвращает `null`.
149
185
 
150
186
  `onDelete` срабатывает **при удалении целевой записи**:
151
187
 
152
188
  - `restrict` — по умолчанию: запретить удаление, пока на цель ссылается сохраняемая запись.
153
- - `cascade` — удалить ссылающуюся запись. Для `User.country` удаление страны удаляет пользователей. Для `Movie.actors.user` удаление пользователя удаляет соответствующие элементы actors, сохраняя фильм.
189
+ - `cascade` — удалить ссылающуюся запись. Для `User.country` удаление страны удаляет пользователей. Для `Movie.actors.user` удаление пользователя удаляет соответствующие элементы `actors`, сохраняя фильм.
154
190
 
155
- Сначала вычисляется весь каскад, обрабатываются циклы и проверяются ограничения, затем сохраняется результат. Ошибка отменяет всю операцию. Политики действуют и на явно объявленные обратные связи; при описании обоих направлений учитывайте оба правила.
191
+ Каскадное удаление выполняется целиком, включая циклические связи. Ошибка проверки отменяет всю операцию. Правила `onDelete` действуют и на явно объявленные обратные связи; при описании обоих направлений учитывайте оба правила.
156
192
 
157
193
  ## Запросы и ответы
158
194
 
@@ -162,9 +198,11 @@ npx deep-json-server --openapi-only --graphql-only server.config.js
162
198
  { "data": [], "total": 0 }
163
199
  ```
164
200
 
165
- Массивы примитивов остаются обычными массивами. У каждого списка объектов есть необязательные `where`, `order`, `pager`. Порядок обработки: фильтрация → сортировка → пагинация. `total` считается после фильтрации, до пагинации. Страницы начинаются с 1; отсутствие pager включает пагинацию по умолчанию. Превышение максимума, дробные и неположительные значения — ошибка. За пределами списка возвращается пустой data с правильным total.
201
+ Массивы примитивов возвращаются обычными массивами. Каждый список объектов принимает необязательные `where`, `order` и `pager`. Порядок обработки: фильтрация → сортировка → пагинация. `total` число записей после фильтрации, до пагинации.
202
+
203
+ В `pager` задаются `page` и `pageSize`. По умолчанию возвращается первая страница с размером из `server.pageSize`. Оба значения должны быть положительными целыми числами; `pageSize` ограничен `server.maxPageSize`. За пределами списка возвращается пустой `data` с общим числом найденных записей в `total`.
166
204
 
167
- Фильтры: `eq`, `ne`, `in`; для строк `contains`, `startsWith`, `endsWith`; сравнения `gt`, `gte`, `lt`, `lte`. Логика `and`, `or`, `not`. У массивов есть `some`, `every`, `none`; у примитивных массивов также `contains`, `in`. Поиск строк не учитывает регистр. Условия полей записываются объектами операторов, без сокращения до скалярного значения.
205
+ Фильтры: `eq`, `ne`, `in`; для строк `contains`, `startsWith`, `endsWith`; сравнения `gt`, `gte`, `lt`, `lte`. Условия объединяются через `and`, `or`, `not`. У массивов есть `some`, `every`, `none`; у примитивных массивов также `contains`, `in`. Поиск строк не учитывает регистр. Условие поля задаётся объектом с оператором, например `{ "id": { "eq": "1" } }`.
168
206
 
169
207
  ```json
170
208
  {
@@ -180,9 +218,9 @@ npx deep-json-server --openapi-only --graphql-only server.config.js
180
218
  }
181
219
  ```
182
220
 
183
- Корневой where выбирает родителей. Where внутри связи фильтрует её элементы, сохраняя родителя. Каждый вложенный список обрабатывается отдельно. Для фильтра по связи не нужно раскрывать её в ответе.
221
+ Корневой `where` выбирает записи основной коллекции. `where` внутри связи фильтрует её элементы, сохраняя родительскую запись. Каждый вложенный список обрабатывается отдельно. Фильтрация по связи работает независимо от её включения в ответ.
184
222
 
185
- `order` — массив правил `{ "field": "fullName", "direction": "ASC" }`. Первое правило приоритетнее; полные совпадения сохраняют порядок хранения. `null` и отсутствующее значение сравниваются одинаково. REST использует путь `profile.name`, GraphQL — enum `profile_name`. Неоднозначные имена enum вызывают ошибку генерации. Сортировка родителей по связям и массивам пока не поддерживается; внутри связи сортировка доступна.
223
+ `order` — массив правил `{ "field": "fullName", "direction": "ASC" }`. Первое правило приоритетнее; при равных значениях сохраняется порядок хранения. `null` и отсутствующее значение сравниваются одинаково. REST использует путь `profile.name`, GraphQL — enum `profile_name`. Неоднозначные имена enum вызывают ошибку генерации. Сортировка доступна по скалярным полям текущего объекта, включая вложенные поля. Для связанных списков задаётся собственный `order`.
186
224
 
187
225
  ### REST
188
226
 
@@ -195,7 +233,7 @@ npx deep-json-server --openapi-only --graphql-only server.config.js
195
233
  | PATCH | `/users/{id}` | `userUpdate` |
196
234
  | DELETE | `/users/{id}` | `userDelete` |
197
235
 
198
- Имя параметра пути соответствует первичному ключу. POST/PUT/PATCH принимают обычный объект записи. PUT заменяет запись с сохранением ключа и корневых серверных полей. PATCH поверхностно объединяет поля; переданные вложенные объекты заменяются целиком. Create/replace проверяют обязательность. Update проверяет переданные значения и итоговую запись. Отсутствующая запись — 404, конфликт — 409. DELETE возвращает удалённую запись.
236
+ Имя параметра пути соответствует первичному ключу. POST, PUT и PATCH принимают JSON-объект записи. PUT заменяет запись с сохранением ключа и серверных полей. PATCH объединяет поля на верхнем уровне; переданные вложенные объекты заменяются с сохранением их полей `readOnly`. Создание и замена требуют всех обязательных полей. При обновлении проверяются переданные значения и итоговая запись. Отсутствующая запись — `404`, конфликт — `409`. DELETE возвращает удалённую запись.
199
237
 
200
238
  Параметры `where`, `order`, `pager`, `nested` содержат JSON; `scope` — строку выбора. Пример до URL-кодирования:
201
239
 
@@ -213,7 +251,7 @@ const params = new URLSearchParams({
213
251
  const response = await fetch(`/users?${params}`);
214
252
  ```
215
253
 
216
- `scope=*,actors(user(id,fullName),genres(*))` выбирает собственные поля и явные связи. `*` включает собственные поля текущего объекта и хранимые ключи, исключает writeOnly и не раскрывает связи. Без scope выбираются собственные поля. Оболочки data/total сохраняются.
254
+ `scope=*,actors(user(id,fullName),genres(*))` выбирает собственные поля и указанные связи. `*` включает собственные поля текущего объекта и хранимые ключи, кроме полей `writeOnly`. Связи перечисляются явно. По умолчанию выбираются собственные поля. Списки сохраняют структуру ответа `{ data, total }`.
217
255
 
218
256
  `nested` сопоставляет полные пути ответа и настройки списков:
219
257
 
@@ -227,7 +265,7 @@ const response = await fetch(`/users?${params}`);
227
265
  }
228
266
  ```
229
267
 
230
- Путь nested должен быть выбран через scope и вести к списку объектов. Одиночные маршруты и мутации принимают scope/nested; корневые where/order/pager применяются только к GET коллекции. Неизвестные имена и небезопасные пути возвращают 400.
268
+ Путь в `nested` должен быть выбран через `scope` и вести к списку объектов. Маршруты отдельных записей и мутации принимают `scope` и `nested`; корневые `where`, `order` и `pager` применяются к GET коллекции. Неизвестные имена и небезопасные пути возвращают `400`.
231
269
 
232
270
  ### GraphQL
233
271
 
@@ -250,10 +288,9 @@ query {
250
288
  }
251
289
  ```
252
290
 
253
- Одиночный запрос — `user(id: ...)`, без ById; отсутствующая запись даёт null. Мутации: `userCreate(data: ...)`, `userReplace(id: ..., data: ...)`, `userUpdate(id: ..., data: ...)`, `userDelete(id: ...)`. Если модель содержит только генерируемые поля, создание не имеет аргумента data. Используются те же операции хранения и проверки, что в REST. Выбор связей в результате мутации управляет только ответом.
254
-
255
- Строковый первичный ключ представлен GraphQL ID, обычные строки — String, числа — Float, пагинация — Int. Enum сохраняет допустимые строковые имена; остальные значения получают имена VALUE_0, VALUE_1 и т. д. Длины строк и форматы проверяет общий валидатор во время выполнения: SDL не выражает все ограничения. Доступны интроспекция, обычные query и mutation; подписки и массовые мутации не добавлены.
291
+ Запрос `user(id: ...)` возвращает одну запись или `null`, если она отсутствует. Мутации: `userCreate(data: ...)`, `userReplace(id: ..., data: ...)`, `userUpdate(id: ..., data: ...)`, `userDelete(id: ...)`. Для модели, состоящей из генерируемых полей, мутация создания вызывается без аргумента `data`. Правила записи и валидации совпадают с REST. Связи, выбранные в результате мутации, определяют содержимое ответа.
256
292
 
293
+ Строковый первичный ключ представлен типом GraphQL `ID`, обычные строки — `String`, числа — `Float`, параметры пагинации — `Int`. Enum сохраняет допустимые строковые имена; остальные значения получают имена `VALUE_0`, `VALUE_1` и т. д. Длины строк, форматы и другие ограничения модели проверяются сервером при выполнении запроса. Для просмотра схемы доступна интроспекция. Параметры выбранных списков проверяются до выполнения мутаций. Ошибки содержат `extensions.code`: `INVALID_INPUT`, `INVALID_QUERY`, `NOT_FOUND`, `CONFLICT` или `INTERNAL_ERROR`.
257
294
 
258
295
  ## Пример базы данных
259
296
 
@@ -361,10 +398,10 @@ query {
361
398
 
362
399
  ## Файлы
363
400
 
364
- Добавьте `files.directory` и `files.metadata` в конфиг сервера, затем передайте `--files`, чтобы включить загрузку бинарных файлов:
401
+ Добавьте `files.directory` и `files.metadata` в конфигурацию и запустите сервер:
365
402
 
366
403
  ```bash
367
- deep-json-server --files server.config.js
404
+ deep-json-server server.config.js
368
405
  ```
369
406
 
370
407
  Для временных тестов вместо этого используйте `files.data`. Каждая начальная запись содержит `name`, `mimeType`, бинарное `content` в виде `Uint8Array` и необязательный `directory`. Загруженные файлы в таком режиме остаются в памяти до завершения процесса.
@@ -420,37 +457,53 @@ Content-Type: application/json
420
457
 
421
458
  `PATCH` возвращает обновлённые метаданные со статусом `200`; если по новому пути уже существует файл, сервер возвращает `409`. `DELETE` отвечает статусом `204` без тела. Если файл не найден, любая операция по пути возвращает `404`. Пути в URL задаются относительно `files.directory`, а все возвращаемые URL — относительно адреса сервера.
422
459
 
423
- При хранении на диске бинарный файл находится по пути `<files.directory>/<directory>/<name>`. Файл метаданных содержит только `directory`, `mimeType` и `name`; `size` считывается у фактического файла, а URL вычисляются. Используйте дисковую базу и файловое хранилище только из одного процесса сервера одновременно и не редактируйте сохранённые файлы или метаданные до его остановки. Сервер автоматически создаёт директории, пути внутри `files.directory` не могут содержать символические ссылки, а имена файлов ограничены переносимыми между поддерживаемыми операционными системами значениями. Изначально файл метаданных может отсутствовать: он создаётся при первой загрузке. Метаданные, созданные версиями до перехода на адресацию по пути, несовместимы с новым форматом.
460
+ При хранении на диске бинарный файл находится по пути `<files.directory>/<directory>/<name>`. Метаданные содержат `directory`, `mimeType` и `name`; размер сервер читает из файла, а URL формирует сам. Директории и файл метаданных создаются по мере необходимости.
461
+
462
+ Используйте один процесс сервера для дисковой базы и файлового хранилища. Перед ручным изменением файлов или метаданных остановите его. Пути в хранилище не могут содержать символические ссылки. Загрузка и переименование не могут перезаписать базу, счётчики, схему, загруженную конфигурацию или файл метаданных.
424
463
 
425
- Используется бинарное тело запроса, а не `multipart/form-data`, поэтому `XMLHttpRequest.upload.onprogress` может показывать прогресс при непосредственной отправке `File` через `xhr.send(file)`. Максимальный размер по умолчанию равен 100 МиБ и настраивается через `server.maxFileSize`. Отсутствующие или небезопасные заголовки и пути возвращают `400`, превышение лимита — `413`, а отсутствующий, некорректный или не поддерживаемый Fastify `Content-Type` — `400` либо `415` в зависимости от этапа проверки.
464
+ Отправляйте файл как бинарное тело запроса. В браузере для этого можно использовать `xhr.send(file)`, а прогресс отслеживать через `XMLHttpRequest.upload.onprogress`. Максимальный размер по умолчанию равен 100 МиБ и настраивается через `server.maxFileSize`. Отсутствующие или небезопасные заголовки и пути возвращают `400`, превышение лимита — `413`, а отсутствующий, некорректный или не поддерживаемый Fastify `Content-Type` — `400` либо `415` в зависимости от этапа проверки.
426
465
 
427
466
  ## Программный API
428
467
 
429
468
  ```js
430
- import { createServer } from '@kollors/deep-json-server';
469
+ import { createServer } from '@kollors/deep-json-server/server';
431
470
  import config from './server.config.js';
432
471
 
433
472
  const facade = await createServer(config);
434
- const openapi = await facade.openapi();
435
- const sdl = await facade.graphql();
436
473
  const server = facade.fastify();
437
474
  await server.listen();
438
475
  // await server.close();
439
476
  ```
440
477
 
441
- Аксессоры ленивые: экспорт не открывает порт и не инициализирует дисковое файловое хранилище. Возможности сервера можно переопределить через `createServer(config, { files: false, graphql: true })`.
478
+ Методы `openapi()` и `graphql()` возвращают схемы и требуют `database.schema`. `fastify()` возвращает экземпляр сервера для настройки и запуска. База и включённые сервисы инициализируются при `ready()`, `listen()` или первом `inject()`; ошибка инициализации останавливает запуск. Возможности сервера можно переопределить через `createServer(config, { files: false, graphql: true, openapi: true })`.
479
+
480
+ Эти функции доступны и через общий импорт `@kollors/deep-json-server`. Адаптеры сервера загружаются при включении. Генераторы можно использовать отдельно:
481
+
482
+ ```js
483
+ import { generateOpenapi, writeOpenapi } from '@kollors/deep-json-server/openapi';
484
+ import { generateGraphql, writeGraphql } from '@kollors/deep-json-server/graphql';
485
+
486
+ const document = await generateOpenapi('./schema.json', { files: true });
487
+ const sdl = await generateGraphql('./schema.json');
488
+ await writeOpenapi(document, './generated/openapi.yaml');
489
+ await writeGraphql(sdl, './generated/schema.graphql');
490
+ ```
491
+
492
+ `generateOpenapi()` также принимает `host`, `port`, `pageSize`, `maxPageSize` и `info`. Вместо пути можно передать объект схемы. Сервер и генераторы работают с собственной копией модели. Размеры страниц должны быть положительными целыми числами; `pageSize` не может превышать `maxPageSize`.
442
493
 
443
494
  ## Хранение и разработка
444
495
 
445
- Изменения выполняются последовательно внутри экземпляра сервера и проверяются на копии данных до сохранения. Для одного файла базы используйте один пишущий сервер. Счётчики increment хранятся рядом с базой в `<путь базы>.counters.json`; сохраняйте этот файл вместе с базой. Номера резервируются до записи данных: сбой может оставить пропуск, но не приводит к повторной выдаче номера. UUID создаётся встроенным crypto Node.js.
496
+ Изменения выполняются последовательно внутри экземпляра сервера и проверяются на копии данных до сохранения. Для одного файла базы используйте один процесс сервера. Счётчики `increment` хранятся рядом с базой в `<путь базы>.counters.json`; сохраняйте этот файл вместе с базой. Номера резервируются до записи данных: сбой может оставить пропуск, но не приводит к повторной выдаче номера.
446
497
 
447
- Это сервер для имитации API: авторизации и хеширования паролей нет. Файловые маршруты сохраняют отдельное хранилище и собственную валидацию.
498
+ Сервер предназначен для имитации API. Авторизацию и хеширование паролей при необходимости реализуйте в приложении.
448
499
 
449
500
  ```sh
450
501
  npm ci
451
502
  npm run verify
452
503
  ```
453
504
 
454
- Проверка включает типы, линтер, пороги покрытия и установку упакованного пакета. Новая alpha-версия package.json в main создаёт свой тег и публикуется через GitHub Actions trusted publishing в канал npm alpha. Если тег уже существует, автоматическая публикация пропускается. Явная отправка тега версии также запускает публикацию; стабильные версии используют latest. Скрипт проверяет совпадение Git-тега и версии пакета.
505
+ Команда проверяет типы, стиль кода, покрытие тестами и установку пакета из архива.
506
+
507
+ Для публикации новой альфы обновите версию в `package.json`, `package-lock.json` и `src/constants.ts`, затем отправьте изменения в `main`. GitHub Actions создаст тег версии и опубликует пакет в канал npm `alpha` через trusted publishing. Уже опубликованная версия пропускается. Если тег создан, а публикация не завершилась, повторный запуск использует этот тег и проверяет соответствие ему файлов пакета. Отправка тега версии также запускает публикацию; стабильные версии публикуются в `latest`.
455
508
 
456
509
  Лицензия: MIT.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  export type { DatabaseConfig, DeepJsonServerConfig, FilesConfig, GraphqlConfig, MemoryFile, OpenapiConfig, ServerConfig } from './src/config.js';
2
- export type { FileMetadata, FileUpdate } from './src/files/contract.js';
2
+ export type { ServerFeatures } from './src/features.js';
3
+ export type { FileUpdate } from './src/files/contract.js';
4
+ export type { FileMetadata } from './src/files/http.js';
3
5
  export type { EntityDefinition, Field, ModelSchema } from './src/model.js';
6
+ export type { OpenapiOptions } from './src/schema.js';
7
+ export { generateGraphql, generateOpenapi, writeGraphql, writeOpenapi } from './src/schema.js';
4
8
  export type { ServerFacade } from './src/server.js';
5
9
  export { createServer } from './src/server.js';
6
10
  export type { OpenapiDocument } from './src/types.js';
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
+ export { generateGraphql, generateOpenapi, writeGraphql, writeOpenapi } from './src/schema.js';
1
2
  export { createServer } from './src/server.js';
2
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/F,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/src/cli.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { createServer } from './server.js';
1
+ import { createConfiguredServer } from './server.js';
2
2
  export declare function runCli(args?: string[], services?: {
3
- createServer: typeof createServer;
3
+ createServer: typeof createConfiguredServer;
4
4
  }): Promise<void>;
package/dist/src/cli.js CHANGED
@@ -1,66 +1,115 @@
1
1
  import process from 'node:process';
2
- import { readServerConfig } from './config.js';
3
- import { DEFAULT_HOST, DEFAULT_PORT } from './constants.js';
4
- import { createServer } from './server.js';
2
+ import { configure, configureGeneration, readConfigModule } from './config.js';
3
+ import { DEFAULT_HOST, DEFAULT_PORT, VERSION } from './constants.js';
4
+ import { resolveFeatures } from './features.js';
5
+ import { inputPaths, validateExportPaths } from './paths.js';
6
+ import { generateGraphql, generateOpenapi, writeGraphql, writeOpenapi } from './schema.js';
7
+ import { createConfiguredServer } from './server.js';
8
+ import { isObject } from './utils.js';
5
9
  const HELP_TEXT = `Deep JSON Server
6
10
 
7
11
  Usage:
8
- deep-json-server [--files] [--graphql] [--openapi | --openapi-only] [--graphql-schema | --graphql-only] <server.config.js>
12
+ deep-json-server [options] <server.config.js>
13
+ deep-json-server generate <openapi|graphql|openapi,graphql> <server.config.js>
9
14
 
10
- --files Enable binary file routes
11
- --graphql Enable the GraphQL endpoint
12
- --openapi Export OpenAPI and start the server
13
- --openapi-only Export OpenAPI without starting the server
14
- --graphql-schema Export GraphQL SDL and start the server
15
- --graphql-only Export GraphQL SDL without starting the server
16
- --help Show help
15
+ --files Enable file routes
16
+ --graphql Enable the GraphQL endpoint
17
+ --openapi Enable the OpenAPI endpoint
18
+ --host <host> Server address
19
+ --port <port> Server port
20
+ --help, -h Show help
21
+ --version, -v Show version
17
22
 
18
- Both exporters can be combined; any --*-only flag prevents server startup.`;
19
- export async function runCli(args = process.argv.slice(2), services = { createServer }) {
20
- if (args.includes('--help')) {
23
+ Files are enabled when configured. Generate writes schemas to the configured paths.`;
24
+ export async function runCli(args = process.argv.slice(2), services = { createServer: createConfiguredServer }) {
25
+ if (args.includes('--help') || args.includes('-h')) {
21
26
  process.stdout.write(`${HELP_TEXT}\n`);
22
27
  return;
23
28
  }
24
- const flags = new Set();
25
- let configPath;
26
- for (const arg of args) {
27
- if (arg.startsWith('-')) {
28
- if (!['--files', '--graphql', '--openapi', '--openapi-only', '--graphql-schema', '--graphql-only'].includes(arg) || flags.has(arg))
29
- throw new Error(`Неизвестный параметр или повтор: ${arg}`);
30
- flags.add(arg);
29
+ if (args.includes('--version') || args.includes('-v')) {
30
+ process.stdout.write(`${VERSION}\n`);
31
+ return;
32
+ }
33
+ const positional = [];
34
+ const seen = new Set();
35
+ const features = {};
36
+ let host;
37
+ let port;
38
+ for (let index = 0; index < args.length; index++) {
39
+ const arg = args[index];
40
+ if (!arg.startsWith('-')) {
41
+ positional.push(arg);
42
+ continue;
43
+ }
44
+ if (!['--files', '--graphql', '--openapi', '--host', '--port'].includes(arg) || seen.has(arg))
45
+ throw new Error(`Неизвестный параметр или повтор: ${arg}`);
46
+ seen.add(arg);
47
+ if (arg === '--host' || arg === '--port') {
48
+ const value = args[++index];
49
+ if (!value || value.startsWith('-'))
50
+ throw new Error(`Укажите значение ${arg}`);
51
+ if (arg === '--host')
52
+ host = value;
53
+ else {
54
+ if (!/^\d+$/.test(value))
55
+ throw new Error('Invalid --port');
56
+ port = Number(value);
57
+ }
31
58
  }
32
- else if (configPath === undefined)
33
- configPath = arg;
34
59
  else
35
- throw new Error('Можно указать только один файл конфигурации');
60
+ features[arg.slice(2)] = true;
36
61
  }
62
+ const generate = positional[0] === 'generate';
63
+ const configPath = positional[generate ? 2 : 0];
37
64
  if (!configPath)
38
65
  throw new Error('Укажите путь к файлу конфигурации');
39
- if ((flags.has('--openapi') && flags.has('--openapi-only')) || (flags.has('--graphql-schema') && flags.has('--graphql-only')))
40
- throw new Error('Режимы одного экспортера нельзя использовать одновременно');
41
- const config = await readServerConfig(configPath);
42
- const openapi = flags.has('--openapi') || flags.has('--openapi-only');
43
- const graphql = flags.has('--graphql-schema') || flags.has('--graphql-only');
44
- if (openapi && !config.openapi.path)
45
- throw new Error('Укажите config.openapi.path');
46
- if (graphql && !config.graphql.path)
47
- throw new Error('Укажите config.graphql.path');
48
- if (flags.has('--files') && !config.files)
49
- throw new Error('Укажите config.files');
50
- const runtimeConfig = { ...config, server: { ...config.server, host: config.server.host ?? process.env.HOST ?? DEFAULT_HOST, port: config.server.port ?? Number(process.env.PORT ?? DEFAULT_PORT) } };
51
- const only = flags.has('--openapi-only') || flags.has('--graphql-only');
52
- const facade = await services.createServer(runtimeConfig, { files: flags.has('--files'), graphql: only ? false : flags.has('--graphql') || config.graphql.enabled === true });
53
- if (openapi) {
54
- await facade.openapi();
55
- process.stdout.write(`OpenAPI: ${config.openapi.path}\n`);
56
- }
57
- if (graphql) {
58
- await facade.graphql();
59
- process.stdout.write(`GraphQL: ${config.graphql.path}\n`);
60
- }
61
- if (only)
66
+ if (positional.length !== (generate ? 3 : 1))
67
+ throw new Error('Можно указать только один файл конфигурации');
68
+ const formats = generate ? positional[1].split(',') : [];
69
+ if (generate && (formats.some((format) => !['openapi', 'graphql'].includes(format)) || new Set(formats).size !== formats.length))
70
+ throw new Error('Invalid generation format');
71
+ if (generate && (features.graphql || features.openapi))
72
+ throw new Error('Endpoint flags are only available when starting the server');
73
+ const source = await readConfigModule(configPath);
74
+ const serverOptions = generate && !formats.includes('openapi') ? {} : (source.config.server ?? {});
75
+ if (!isObject(serverOptions))
76
+ throw new Error('config.server must be an object');
77
+ const overrides = { host: host ?? serverOptions.host ?? process.env.HOST ?? DEFAULT_HOST, port: port ?? serverOptions.port ?? Number(process.env.PORT ?? DEFAULT_PORT) };
78
+ const config = generate
79
+ ? configureGeneration(source.config, formats, source.directory, source.path, { ...overrides, files: features.files })
80
+ : configure({ ...source.config, server: { ...serverOptions, ...overrides } }, source.directory, source.path);
81
+ if (generate) {
82
+ if (!config.database.schema)
83
+ throw new Error('Generation requires an explicit model schema');
84
+ const destinations = formats.map((format) => {
85
+ const path = config[format].path;
86
+ if (!path)
87
+ throw new Error(`Укажите config.${format}.path`);
88
+ return path;
89
+ });
90
+ await validateExportPaths(destinations, inputPaths(source.config, source.directory, source.path));
91
+ const openapi = formats.includes('openapi')
92
+ ? await generateOpenapi(config.database.schema, {
93
+ files: config.files != null,
94
+ host: config.server.host,
95
+ port: config.server.port,
96
+ pageSize: config.server.pageSize,
97
+ maxPageSize: config.server.maxPageSize,
98
+ info: config.openapi.info,
99
+ })
100
+ : undefined;
101
+ const graphql = formats.includes('graphql') ? await generateGraphql(config.database.schema) : undefined;
102
+ if (openapi) {
103
+ await writeOpenapi(openapi, config.openapi.path);
104
+ process.stdout.write(`OpenAPI: ${config.openapi.path}\n`);
105
+ }
106
+ if (graphql) {
107
+ await writeGraphql(graphql, config.graphql.path);
108
+ process.stdout.write(`GraphQL: ${config.graphql.path}\n`);
109
+ }
62
110
  return;
63
- const server = facade.fastify();
111
+ }
112
+ const server = (await services.createServer(config, resolveFeatures(config, features))).fastify();
64
113
  await server.listen();
65
114
  server.log.info('Deep JSON Server started');
66
115
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}