@kollors/deep-json-server 1.0.0-alpha.1 → 1.0.0-alpha.11

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 (244) hide show
  1. package/README.md +522 -179
  2. package/README.ru.md +525 -180
  3. package/dist/bin/deep-json-server.js +1 -1
  4. package/dist/bin/deep-json-server.js.map +1 -1
  5. package/dist/index.d.ts +13 -6
  6. package/dist/index.js +4 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/src/auth/contract.d.ts +31 -0
  9. package/dist/src/auth/contract.js +12 -0
  10. package/dist/src/auth/contract.js.map +1 -0
  11. package/dist/src/auth/input.d.ts +18 -0
  12. package/dist/src/auth/input.js +34 -0
  13. package/dist/src/auth/input.js.map +1 -0
  14. package/dist/src/auth/password.d.ts +17 -0
  15. package/dist/src/auth/password.js +41 -0
  16. package/dist/src/auth/password.js.map +1 -0
  17. package/dist/src/auth/public.d.ts +3 -0
  18. package/dist/src/auth/public.js +5 -0
  19. package/dist/src/auth/public.js.map +1 -0
  20. package/dist/src/auth/routes.d.ts +6 -0
  21. package/dist/src/auth/routes.js +18 -0
  22. package/dist/src/auth/routes.js.map +1 -0
  23. package/dist/src/auth/service.d.ts +78 -0
  24. package/dist/src/auth/service.js +218 -0
  25. package/dist/src/auth/service.js.map +1 -0
  26. package/dist/src/auth/store.d.ts +26 -0
  27. package/dist/src/auth/store.js +82 -0
  28. package/dist/src/auth/store.js.map +1 -0
  29. package/dist/src/cli/index.d.ts +7 -0
  30. package/dist/src/cli/index.js +113 -0
  31. package/dist/src/cli/index.js.map +1 -0
  32. package/dist/src/core/config-values.d.ts +28 -0
  33. package/dist/src/core/config-values.js +53 -0
  34. package/dist/src/core/config-values.js.map +1 -0
  35. package/dist/src/{constants.d.ts → core/constants.d.ts} +1 -0
  36. package/dist/src/{constants.js → core/constants.js} +1 -0
  37. package/dist/src/core/constants.js.map +1 -0
  38. package/dist/src/core/database.d.ts +48 -0
  39. package/dist/src/{database.js → core/database.js} +36 -14
  40. package/dist/src/core/database.js.map +1 -0
  41. package/dist/src/core/engine.d.ts +53 -0
  42. package/dist/src/core/engine.js +249 -0
  43. package/dist/src/core/engine.js.map +1 -0
  44. package/dist/src/core/errors.d.ts +9 -0
  45. package/dist/src/core/errors.js +12 -0
  46. package/dist/src/core/errors.js.map +1 -0
  47. package/dist/src/core/http-errors.d.ts +9 -0
  48. package/dist/src/core/http-errors.js +15 -0
  49. package/dist/src/core/http-errors.js.map +1 -0
  50. package/dist/src/core/lifecycle/mutation.d.ts +49 -0
  51. package/dist/src/core/lifecycle/mutation.js +170 -0
  52. package/dist/src/core/lifecycle/mutation.js.map +1 -0
  53. package/dist/src/core/lifecycle/options.d.ts +21 -0
  54. package/dist/src/core/lifecycle/options.js +19 -0
  55. package/dist/src/core/lifecycle/options.js.map +1 -0
  56. package/dist/src/core/model.d.ts +145 -0
  57. package/dist/src/{model.js → core/model.js} +224 -33
  58. package/dist/src/core/model.js.map +1 -0
  59. package/dist/src/core/mutations/write.d.ts +26 -0
  60. package/dist/src/core/mutations/write.js +284 -0
  61. package/dist/src/core/mutations/write.js.map +1 -0
  62. package/dist/src/core/operations.d.ts +33 -0
  63. package/dist/src/core/operations.js +10 -0
  64. package/dist/src/core/operations.js.map +1 -0
  65. package/dist/src/core/pagination.d.ts +10 -0
  66. package/dist/src/core/pagination.js +13 -0
  67. package/dist/src/core/pagination.js.map +1 -0
  68. package/dist/src/core/paths.d.ts +16 -0
  69. package/dist/src/core/paths.js +64 -0
  70. package/dist/src/core/paths.js.map +1 -0
  71. package/dist/src/core/query/contract.d.ts +6 -0
  72. package/dist/src/core/query/contract.js +22 -0
  73. package/dist/src/core/query/contract.js.map +1 -0
  74. package/dist/src/core/query/execute.d.ts +25 -0
  75. package/dist/src/core/query/execute.js +82 -0
  76. package/dist/src/core/query/execute.js.map +1 -0
  77. package/dist/src/core/query/filter.d.ts +6 -0
  78. package/dist/src/core/query/filter.js +100 -0
  79. package/dist/src/core/query/filter.js.map +1 -0
  80. package/dist/src/core/query/options.d.ts +30 -0
  81. package/dist/src/core/query/options.js +44 -0
  82. package/dist/src/core/query/options.js.map +1 -0
  83. package/dist/src/core/records.d.ts +46 -0
  84. package/dist/src/core/records.js +69 -0
  85. package/dist/src/core/records.js.map +1 -0
  86. package/dist/src/core/relation-metadata.d.ts +15 -0
  87. package/dist/src/{relation-metadata.js → core/relation-metadata.js} +7 -2
  88. package/dist/src/core/relation-metadata.js.map +1 -0
  89. package/dist/src/core/storage.d.ts +2 -0
  90. package/dist/src/core/storage.js +2 -0
  91. package/dist/src/core/storage.js.map +1 -0
  92. package/dist/src/core/types.d.ts +10 -0
  93. package/dist/src/{types.js.map → core/types.js.map} +1 -1
  94. package/dist/src/core/utils.d.ts +56 -0
  95. package/dist/src/core/utils.js +102 -0
  96. package/dist/src/core/utils.js.map +1 -0
  97. package/dist/src/files/contract.d.ts +32 -30
  98. package/dist/src/files/contract.js +29 -48
  99. package/dist/src/files/contract.js.map +1 -1
  100. package/dist/src/files/disk-metadata.d.ts +9 -0
  101. package/dist/src/files/disk-metadata.js +44 -0
  102. package/dist/src/files/disk-metadata.js.map +1 -0
  103. package/dist/src/files/disk-paths.d.ts +15 -0
  104. package/dist/src/files/disk-paths.js +100 -0
  105. package/dist/src/files/disk-paths.js.map +1 -0
  106. package/dist/src/files/disk-store.d.ts +5 -1
  107. package/dist/src/files/disk-store.js +46 -173
  108. package/dist/src/files/disk-store.js.map +1 -1
  109. package/dist/src/files/http.d.ts +36 -0
  110. package/dist/src/files/http.js +53 -0
  111. package/dist/src/files/http.js.map +1 -0
  112. package/dist/src/files/index.d.ts +5 -4
  113. package/dist/src/files/index.js +7 -2
  114. package/dist/src/files/index.js.map +1 -1
  115. package/dist/src/files/memory-store.d.ts +4 -1
  116. package/dist/src/files/memory-store.js +29 -22
  117. package/dist/src/files/memory-store.js.map +1 -1
  118. package/dist/src/files/routes.d.ts +3 -0
  119. package/dist/src/files/routes.js +27 -2
  120. package/dist/src/files/routes.js.map +1 -1
  121. package/dist/src/files/streams.d.ts +5 -0
  122. package/dist/src/files/streams.js +20 -0
  123. package/dist/src/files/streams.js.map +1 -0
  124. package/dist/src/graphql/entry.d.ts +12 -0
  125. package/dist/src/graphql/entry.js +13 -0
  126. package/dist/src/graphql/entry.js.map +1 -0
  127. package/dist/src/graphql/generate.d.ts +12 -0
  128. package/dist/src/graphql/generate.js +19 -0
  129. package/dist/src/graphql/generate.js.map +1 -0
  130. package/dist/src/graphql/preflight.d.ts +6 -0
  131. package/dist/src/graphql/preflight.js +44 -0
  132. package/dist/src/graphql/preflight.js.map +1 -0
  133. package/dist/src/graphql/resolvers.d.ts +17 -0
  134. package/dist/src/graphql/resolvers.js +44 -0
  135. package/dist/src/graphql/resolvers.js.map +1 -0
  136. package/dist/src/graphql/routes.d.ts +8 -0
  137. package/dist/src/graphql/routes.js +30 -0
  138. package/dist/src/graphql/routes.js.map +1 -0
  139. package/dist/src/graphql/schema.d.ts +6 -0
  140. package/dist/src/{graphql.js → graphql/schema.js} +59 -49
  141. package/dist/src/graphql/schema.js.map +1 -0
  142. package/dist/src/graphql/write.d.ts +4 -0
  143. package/dist/src/graphql/write.js +10 -0
  144. package/dist/src/graphql/write.js.map +1 -0
  145. package/dist/src/openapi/auth.d.ts +13 -0
  146. package/dist/src/openapi/auth.js +139 -0
  147. package/dist/src/openapi/auth.js.map +1 -0
  148. package/dist/src/openapi/document.d.ts +7 -3
  149. package/dist/src/openapi/document.js +154 -103
  150. package/dist/src/openapi/document.js.map +1 -1
  151. package/dist/src/openapi/entry.d.ts +14 -0
  152. package/dist/src/openapi/entry.js +13 -0
  153. package/dist/src/openapi/entry.js.map +1 -0
  154. package/dist/src/openapi/files.d.ts +6 -0
  155. package/dist/src/{files/openapi.js → openapi/files.js} +6 -5
  156. package/dist/src/openapi/files.js.map +1 -0
  157. package/dist/src/openapi/generate.d.ts +19 -0
  158. package/dist/src/openapi/generate.js +41 -0
  159. package/dist/src/openapi/generate.js.map +1 -0
  160. package/dist/src/openapi/helpers.d.ts +26 -0
  161. package/dist/src/openapi/helpers.js +13 -0
  162. package/dist/src/openapi/helpers.js.map +1 -0
  163. package/dist/src/openapi/options.d.ts +18 -0
  164. package/dist/src/openapi/options.js +13 -0
  165. package/dist/src/openapi/options.js.map +1 -0
  166. package/dist/src/openapi/registry.d.ts +11 -0
  167. package/dist/src/openapi/registry.js +20 -0
  168. package/dist/src/openapi/registry.js.map +1 -0
  169. package/dist/src/{types.d.ts → openapi/types.d.ts} +2 -10
  170. package/dist/src/openapi/types.js +2 -0
  171. package/dist/src/openapi/types.js.map +1 -0
  172. package/dist/src/openapi/write.d.ts +5 -0
  173. package/dist/src/openapi/write.js +12 -0
  174. package/dist/src/openapi/write.js.map +1 -0
  175. package/dist/src/rest/options.d.ts +22 -0
  176. package/dist/src/rest/options.js +65 -0
  177. package/dist/src/rest/options.js.map +1 -0
  178. package/dist/src/rest/projection.d.ts +13 -0
  179. package/dist/src/rest/projection.js +61 -0
  180. package/dist/src/rest/projection.js.map +1 -0
  181. package/dist/src/rest/routes.d.ts +7 -0
  182. package/dist/src/rest/routes.js +58 -0
  183. package/dist/src/rest/routes.js.map +1 -0
  184. package/dist/src/server/bootstrap.d.ts +7 -0
  185. package/dist/src/server/bootstrap.js +48 -0
  186. package/dist/src/server/bootstrap.js.map +1 -0
  187. package/dist/src/server/config.d.ts +74 -0
  188. package/dist/src/server/config.js +142 -0
  189. package/dist/src/server/config.js.map +1 -0
  190. package/dist/src/server/create.d.ts +16 -0
  191. package/dist/src/server/create.js +59 -0
  192. package/dist/src/server/create.js.map +1 -0
  193. package/dist/src/server/features.d.ts +4 -0
  194. package/dist/src/server/features.js +11 -0
  195. package/dist/src/server/features.js.map +1 -0
  196. package/dist/src/server/http.d.ts +12 -0
  197. package/dist/src/server/http.js +40 -0
  198. package/dist/src/server/http.js.map +1 -0
  199. package/dist/src/server/model.d.ts +6 -0
  200. package/dist/src/server/model.js +14 -0
  201. package/dist/src/server/model.js.map +1 -0
  202. package/dist/src/server/openapi-options.d.ts +6 -0
  203. package/dist/src/server/openapi-options.js +15 -0
  204. package/dist/src/server/openapi-options.js.map +1 -0
  205. package/dist/src/server/public.d.ts +2 -0
  206. package/dist/src/server/public.js +2 -0
  207. package/dist/src/server/public.js.map +1 -0
  208. package/package.json +19 -3
  209. package/dist/src/cli.d.ts +0 -4
  210. package/dist/src/cli.js +0 -67
  211. package/dist/src/cli.js.map +0 -1
  212. package/dist/src/config.d.ts +0 -68
  213. package/dist/src/config.js +0 -161
  214. package/dist/src/config.js.map +0 -1
  215. package/dist/src/constants.js.map +0 -1
  216. package/dist/src/database.d.ts +0 -21
  217. package/dist/src/database.js.map +0 -1
  218. package/dist/src/engine.d.ts +0 -47
  219. package/dist/src/engine.js +0 -438
  220. package/dist/src/engine.js.map +0 -1
  221. package/dist/src/files/openapi.d.ts +0 -3
  222. package/dist/src/files/openapi.js.map +0 -1
  223. package/dist/src/graphql.d.ts +0 -4
  224. package/dist/src/graphql.js.map +0 -1
  225. package/dist/src/model.d.ts +0 -67
  226. package/dist/src/model.js.map +0 -1
  227. package/dist/src/openapi/index.d.ts +0 -7
  228. package/dist/src/openapi/index.js +0 -26
  229. package/dist/src/openapi/index.js.map +0 -1
  230. package/dist/src/query/filter.d.ts +0 -1
  231. package/dist/src/query/filter.js +0 -84
  232. package/dist/src/query/filter.js.map +0 -1
  233. package/dist/src/query/options.d.ts +0 -31
  234. package/dist/src/query/options.js +0 -135
  235. package/dist/src/query/options.js.map +0 -1
  236. package/dist/src/relation-metadata.d.ts +0 -10
  237. package/dist/src/relation-metadata.js.map +0 -1
  238. package/dist/src/server.d.ts +0 -14
  239. package/dist/src/server.js +0 -166
  240. package/dist/src/server.js.map +0 -1
  241. package/dist/src/utils.d.ts +0 -19
  242. package/dist/src/utils.js +0 -62
  243. package/dist/src/utils.js.map +0 -1
  244. /package/dist/src/{types.js → core/types.js} +0 -0
@@ -1,5 +1,8 @@
1
1
  import type { FastifyInstance } from 'fastify';
2
2
  import { type FileStore } from './contract.js';
3
+ /** Регистрирует обработчики загрузки, чтения, перемещения и удаления файлов.
4
+ * @example После регистрации GET по существующему пути → поток файла; функция возвращает undefined.
5
+ */
3
6
  export declare const registerFileRoutes: (fastify: FastifyInstance, { getStore, maxFileSize }: {
4
7
  getStore: () => Promise<FileStore>;
5
8
  maxFileSize: number;
@@ -1,5 +1,9 @@
1
- import { createHttpError } from '../utils.js';
2
- import { createFileMetadata, FILE_HEADERS, FILE_ROUTES, FILE_UPDATE_SCHEMA, getDownloadName, getFileKey, getPathLocation, normalizeMimeType, PATCH_BODY_LIMIT, validateDirectory, validateName, } from './contract.js';
1
+ import { createHttpError } from '../core/http-errors.js';
2
+ import { getFileKey, getPathLocation, normalizeMimeType, validateDirectory, validateName } from './contract.js';
3
+ import { createFileMetadata, FILE_HEADERS, FILE_ROUTES, FILE_UPDATE_SCHEMA, getDownloadName, PATCH_BODY_LIMIT } from './http.js';
4
+ /** Декодирует строку из URL-кодировки; отсутствие или повреждённая кодировка дают ошибку 400.
5
+ * @example decodeHeader('a%20b', 'Name') → 'a b'; decodeHeader('%', 'Name') → ошибка.
6
+ */
3
7
  const decodeHeader = (value, name) => {
4
8
  if (typeof value !== 'string') {
5
9
  throw createHttpError(400, `Заголовок ${name} обязателен`);
@@ -11,8 +15,17 @@ const decodeHeader = (value, name) => {
11
15
  throw createHttpError(400, `Заголовок ${name} содержит некорректное значение`);
12
16
  }
13
17
  };
18
+ /** Декодирует и проверяет имя файла из заголовка.
19
+ * @example getContentName('a%20b.txt') → 'a b.txt'.
20
+ */
14
21
  const getContentName = (value) => validateName(decodeHeader(value, FILE_HEADERS.name.name), `Заголовок ${FILE_HEADERS.name.name}`);
22
+ /** Декодирует относительный каталог; отсутствующее значение заменяет пустой строкой.
23
+ * @example getContentDirectory(undefined) → ''; getContentDirectory('my%20photos') → 'my photos'.
24
+ */
15
25
  const getContentDirectory = (value) => (value == null ? '' : validateDirectory(decodeHeader(value, FILE_HEADERS.directory.name), `Заголовок ${FILE_HEADERS.directory.name}`));
26
+ /** Читает строковый логический флаг перезаписи; отсутствие означает false.
27
+ * @example getContentOverride('true') → true; getContentOverride(undefined) → false; 'yes' → ошибка.
28
+ */
16
29
  const getContentOverride = (value) => {
17
30
  if (value == null || value === 'false') {
18
31
  return false;
@@ -22,17 +35,29 @@ const getContentOverride = (value) => {
22
35
  }
23
36
  throw createHttpError(400, `Заголовок ${FILE_HEADERS.override.name} должен содержать true или false`);
24
37
  };
38
+ /** Извлекает и проверяет путь из параметра маршрута.
39
+ * @example При request.params = { '*': 'photos/a.jpg' } → 'photos/a.jpg'.
40
+ */
25
41
  const getRequestPath = (request) => getFileKey(getPathLocation(request.params['*']));
42
+ /** Проверяет переданные имя и каталог и возвращает только заданные значения.
43
+ * @example normalizeUpdate({ name: 'a.txt' }) → { name: 'a.txt' }.
44
+ */
26
45
  const normalizeUpdate = (body) => ({
27
46
  ...(body.directory != null && { directory: validateDirectory(body.directory, 'Ключ body.directory') }),
28
47
  ...(body.name != null && { name: validateName(body.name, 'Ключ body.name') }),
29
48
  });
49
+ /** Читает поток из хранилища и отправляет его с MIME-типом и заголовком скачивания или просмотра.
50
+ * @example При disposition = 'inline' ответ содержит Content-Disposition: inline и байты файла.
51
+ */
30
52
  const sendFile = async (store, path, reply, disposition) => {
31
53
  const { file, stream } = await store.get(path);
32
54
  reply.header('Content-Disposition', `${disposition}; filename*=UTF-8''${getDownloadName(file.name)}`);
33
55
  reply.type(file.mimeType);
34
56
  return reply.send(stream);
35
57
  };
58
+ /** Регистрирует обработчики загрузки, чтения, перемещения и удаления файлов.
59
+ * @example После регистрации GET по существующему пути → поток файла; функция возвращает undefined.
60
+ */
36
61
  export const registerFileRoutes = (fastify, { getStore, maxFileSize }) => {
37
62
  fastify.register(async (fileServer) => {
38
63
  const store = await getStore();
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/files/routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/files/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Transform } from 'node:stream';
2
+ /** Создаёт преобразующий поток, который считает байты и отклоняет превышение лимита.
3
+ * @example Лимит 3 и поток 'abcd' → ошибка; поток 'abc' проходит без изменения.
4
+ */
5
+ export declare const createSizeLimiter: (maxFileSize: number, onSize: (size: number) => void) => Transform;
@@ -0,0 +1,20 @@
1
+ import { Transform } from 'node:stream';
2
+ import { domainError } from '../core/errors.js';
3
+ /** Создаёт преобразующий поток, который считает байты и отклоняет превышение лимита.
4
+ * @example Лимит 3 и поток 'abcd' → ошибка; поток 'abc' проходит без изменения.
5
+ */
6
+ export const createSizeLimiter = (maxFileSize, onSize) => {
7
+ let size = 0;
8
+ return new Transform({
9
+ transform(chunk, _encoding, callback) {
10
+ size += chunk.length;
11
+ if (size > maxFileSize) {
12
+ callback(domainError('PAYLOAD_TOO_LARGE', `Размер файла не должен превышать ${maxFileSize} байт`));
13
+ return;
14
+ }
15
+ onSize(size);
16
+ callback(null, chunk);
17
+ },
18
+ });
19
+ };
20
+ //# sourceMappingURL=streams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streams.js","sourceRoot":"","sources":["../../../src/files/streams.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAA0B,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,WAAmB,EAAE,MAA8B,EAAa,EAAE;IAClG,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,SAAS,CAAC;QACnB,SAAS,CAAC,KAAa,EAAE,SAAyB,EAAE,QAA2B;YAC7E,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC;YAErB,IAAI,IAAI,GAAG,WAAW,EAAE,CAAC;gBACvB,QAAQ,CAAC,WAAW,CAAC,mBAAmB,EAAE,oCAAoC,WAAW,OAAO,CAAC,CAAC,CAAC;gBACnG,OAAO;YACT,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,CAAC;YACb,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC;KACF,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ export type { EntityDefinition, Field, ModelSchema } from '../core/model.js';
2
+ import type { ModelSchema } from '../core/model.js';
3
+ import type { GraphqlOptions } from './generate.js';
4
+ /** Загружает генератор при первом обращении и передаёт ему описание и параметры.
5
+ * @example Описание и параметры → Promise со схемой; при импорте этой обёртки генератор ещё не загружается.
6
+ */
7
+ export declare function generateGraphql(schema: ModelSchema | string, options?: GraphqlOptions): Promise<string>;
8
+ /** Загружает модуль записи по требованию и сохраняет схему в указанный файл.
9
+ * @example Схема и путь → Promise<void>; файл появляется после успешного завершения.
10
+ */
11
+ export declare function writeGraphql(sdl: string, path: string): Promise<void>;
12
+ export type { GraphqlOptions } from './generate.js';
@@ -0,0 +1,13 @@
1
+ /** Загружает генератор при первом обращении и передаёт ему описание и параметры.
2
+ * @example Описание и параметры → Promise со схемой; при импорте этой обёртки генератор ещё не загружается.
3
+ */
4
+ export async function generateGraphql(schema, options) {
5
+ return (await import('./generate.js')).generateGraphql(schema, options);
6
+ }
7
+ /** Загружает модуль записи по требованию и сохраняет схему в указанный файл.
8
+ * @example Схема и путь → Promise<void>; файл появляется после успешного завершения.
9
+ */
10
+ export async function writeGraphql(sdl, path) {
11
+ return (await import('./write.js')).writeGraphql(sdl, path);
12
+ }
13
+ //# sourceMappingURL=entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../../src/graphql/entry.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAA4B,EAAE,OAAwB;IAC1F,OAAO,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC1E,CAAC;AACD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,IAAY;IAC1D,OAAO,CAAC,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface GraphqlOptions {
2
+ auth?: boolean;
3
+ }
4
+ import { type Model, type ModelSchema } from '../core/model.js';
5
+ /** Проверяет доступность формата и возвращает текст схемы из подготовленной модели.
6
+ * @example Подготовленная модель с сущностью Note → SDL с типом Note и операциями note, noteList.
7
+ */
8
+ export declare function graphqlFromModel(model: Model | undefined): string;
9
+ /** Загружает описание из объекта или файла и возвращает текст схемы.
10
+ * @example Корректное описание сущностей → Promise<string> с SDL; некорректное → ошибка.
11
+ */
12
+ export declare function generateGraphql(schema: ModelSchema | string, options?: GraphqlOptions): Promise<string>;
@@ -0,0 +1,19 @@
1
+ import { assertKnownKeys } from '../core/utils.js';
2
+ import { printSchema } from 'graphql';
3
+ import { assertApi, loadModel } from '../core/model.js';
4
+ import { buildGraphql } from './schema.js';
5
+ /** Проверяет доступность формата и возвращает текст схемы из подготовленной модели.
6
+ * @example Подготовленная модель с сущностью Note → SDL с типом Note и операциями note, noteList.
7
+ */
8
+ export function graphqlFromModel(model) {
9
+ assertApi(model, 'graphql');
10
+ return printSchema(buildGraphql(model));
11
+ }
12
+ /** Загружает описание из объекта или файла и возвращает текст схемы.
13
+ * @example Корректное описание сущностей → Promise<string> с SDL; некорректное → ошибка.
14
+ */
15
+ export async function generateGraphql(schema, options = {}) {
16
+ assertKnownKeys(options, new Set(['auth']), 'options');
17
+ return graphqlFromModel(await loadModel(schema, { auth: options.auth, api: ['graphql'] }));
18
+ }
19
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/graphql/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAKnD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAgC,MAAM,kBAAkB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAwB;IACvD,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAC5B,OAAO,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1C,CAAC;AACD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAA4B,EAAE,OAAO,GAAmB,EAAE;IAC9F,eAAe,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACvD,OAAO,gBAAgB,CAAC,MAAM,SAAS,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7F,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { type FieldNode, type GraphQLResolveInfo } from 'graphql';
2
+ import type { Engine, PreparedList } from '../core/engine.js';
3
+ /** Обходит выбранные поля, фрагменты и директивы и подготавливает аргументы списков до изменения данных.
4
+ * @example Запрос без списков → пустая Map; выбранный список с pageSize: 0 → ошибка.
5
+ */
6
+ export declare function preflight(info: GraphQLResolveInfo, engine: Engine): Map<FieldNode, PreparedList>;
@@ -0,0 +1,44 @@
1
+ import { GraphQLIncludeDirective, GraphQLSkipDirective, getArgumentValues, getDirectiveValues, getNamedType, isObjectType, } from 'graphql';
2
+ /** Обходит выбранные поля, фрагменты и директивы и подготавливает аргументы списков до изменения данных.
3
+ * @example Запрос без списков → пустая Map; выбранный список с pageSize: 0 → ошибка.
4
+ */
5
+ export function preflight(info, engine) {
6
+ const prepared = new Map();
7
+ const root = info.operation.operation === 'mutation' ? info.schema.getMutationType() : info.schema.getQueryType();
8
+ if (!root)
9
+ throw new Error('GraphQL operation root is unavailable');
10
+ const visited = new Map();
11
+ const walk = (selectionSet, parent) => {
12
+ let parents = visited.get(selectionSet);
13
+ if (!parents) {
14
+ parents = new Set();
15
+ visited.set(selectionSet, parents);
16
+ }
17
+ if (parents.has(parent))
18
+ return;
19
+ parents.add(parent);
20
+ for (const selection of selectionSet.selections) {
21
+ if (getDirectiveValues(GraphQLSkipDirective, selection, info.variableValues)?.if === true || getDirectiveValues(GraphQLIncludeDirective, selection, info.variableValues)?.if === false)
22
+ continue;
23
+ if (selection.kind === 'FragmentSpread') {
24
+ walk(info.fragments[selection.name.value].selectionSet, parent);
25
+ continue;
26
+ }
27
+ if (selection.kind === 'InlineFragment') {
28
+ walk(selection.selectionSet, parent);
29
+ continue;
30
+ }
31
+ const field = parent.getFields()[selection.name.value];
32
+ if (!field)
33
+ continue;
34
+ if (field.extensions.listNode && !prepared.has(selection))
35
+ prepared.set(selection, engine.prepareOptions(field.extensions.listNode, getArgumentValues(field, selection, info.variableValues)));
36
+ const type = getNamedType(field.type);
37
+ if (selection.selectionSet && isObjectType(type))
38
+ walk(selection.selectionSet, type);
39
+ }
40
+ };
41
+ walk(info.operation.selectionSet, root);
42
+ return prepared;
43
+ }
44
+ //# sourceMappingURL=preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../../src/graphql/preflight.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,uBAAuB,EAGvB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,YAAY,GAEb,MAAM,SAAS,CAAC;AAGjB;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAwB,EAAE,MAAc;IAChE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;IAClH,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4C,CAAC;IACpE,MAAM,IAAI,GAAG,CAAC,YAA8B,EAAE,MAAyB,EAAQ,EAAE;QAC/E,IAAI,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACrC,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,OAAO;QAChC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,KAAK,MAAM,SAAS,IAAI,YAAY,CAAC,UAAU,EAAE,CAAC;YAChD,IAAI,kBAAkB,CAAC,oBAAoB,EAAE,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,KAAK,IAAI,IAAI,kBAAkB,CAAC,uBAAuB,EAAE,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,KAAK,KAAK;gBAAE,SAAS;YACjM,IAAI,SAAS,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;gBACxC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;gBAChE,SAAS;YACX,CAAC;YACD,IAAI,SAAS,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;gBACxC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;gBACrC,SAAS;YACX,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvD,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;gBACvD,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,QAAgB,EAAE,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;YAC9I,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,SAAS,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,CAAC;gBAAE,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACvF,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACxC,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type FieldNode, type GraphQLResolveInfo, type GraphQLSchema } from 'graphql';
2
+ import type { Engine, PreparedList } from '../core/engine.js';
3
+ import type { Actor } from '../core/lifecycle/options.js';
4
+ import { type Context } from '../core/records.js';
5
+ export interface GraphqlContext {
6
+ actor?: () => Actor;
7
+ snapshot(): Promise<Context>;
8
+ prepare(info: GraphQLResolveInfo): Promise<Map<FieldNode, PreparedList>>;
9
+ }
10
+ /** Создаёт кеш снимка данных и проверки аргументов на время одного запроса.
11
+ * @example Повторные вызовы context.snapshot() возвращают тот же Promise<Context>.
12
+ */
13
+ export declare function createGraphqlContext(engine: Engine): GraphqlContext;
14
+ /** Назначает полям схемы обработчики чтения и изменения записей; изменяет переданную схему.
15
+ * @example После вызова поле запроса имеет resolve; возвращаемое значение → undefined.
16
+ */
17
+ export declare function attachResolvers(schema: GraphQLSchema, engine: Engine): void;
@@ -0,0 +1,44 @@
1
+ import { isObjectType } from 'graphql';
2
+ import { resolveField } from '../core/records.js';
3
+ import { preflight } from './preflight.js';
4
+ /** Создаёт кеш снимка данных и проверки аргументов на время одного запроса.
5
+ * @example Повторные вызовы context.snapshot() возвращают тот же Promise<Context>.
6
+ */
7
+ export function createGraphqlContext(engine) {
8
+ let snapshot;
9
+ let prepared;
10
+ return {
11
+ snapshot: () => (snapshot ??= engine.context()),
12
+ prepare: (info) => (prepared ??= Promise.resolve().then(() => preflight(info, engine))),
13
+ };
14
+ }
15
+ /** Назначает полям схемы обработчики чтения и изменения записей; изменяет переданную схему.
16
+ * @example После вызова поле запроса имеет resolve; возвращаемое значение → undefined.
17
+ */
18
+ export function attachResolvers(schema, engine) {
19
+ for (const type of Object.values(schema.getTypeMap())) {
20
+ if (!isObjectType(type))
21
+ continue;
22
+ for (const field of Object.values(type.getFields())) {
23
+ const { entity, operation, node, listNode } = field.extensions;
24
+ if (entity && operation)
25
+ field.resolve = async (_root, args, context, info) => {
26
+ const plans = await context.prepare(info);
27
+ if (operation === 'find')
28
+ return engine.find(await context.snapshot(), entity, args[entity.primary]) ?? null;
29
+ if (operation === 'list')
30
+ return engine.list(engine.records(await context.snapshot(), entity), entity.root, args, plans.get(info.fieldNodes[0]));
31
+ return engine.mutate(entity, operation, args[entity.primary], args.data ?? {}, undefined, context.actor);
32
+ };
33
+ else if (node)
34
+ field.resolve = async (ref, args, context, info) => {
35
+ const value = resolveField(ref, node);
36
+ if (!listNode || value == null)
37
+ return value;
38
+ const plans = await context.prepare(info);
39
+ return engine.list(value, listNode, args, plans.get(info.fieldNodes[0]));
40
+ };
41
+ }
42
+ }
43
+ }
44
+ //# sourceMappingURL=resolvers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolvers.js","sourceRoot":"","sources":["../../../src/graphql/resolvers.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+D,YAAY,EAAE,MAAM,SAAS,CAAC;AAMpG,OAAO,EAA0B,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAO3C;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,IAAI,QAAsC,CAAC;IAC3C,IAAI,QAA2D,CAAC;IAChE,OAAO;QACL,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC;QAC/C,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;KACxF,CAAC;AACJ,CAAC;AACD;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAqB,EAAE,MAAc;IACnE,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;YAAE,SAAS;QAClC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC;YACpD,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,UAA2G,CAAC;YAChK,IAAI,MAAM,IAAI,SAAS;gBACrB,KAAK,CAAC,OAAO,GAAG,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAuB,EAAE,IAAI,EAAE,EAAE;oBACnE,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;oBAC1C,IAAI,SAAS,KAAK,MAAM;wBAAE,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC;oBAC7G,IAAI,SAAS,KAAK,MAAM;wBAAE,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACjJ,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC3G,CAAC,CAAC;iBACC,IAAI,IAAI;gBACX,KAAK,CAAC,OAAO,GAAG,KAAK,EAAE,GAAQ,EAAE,IAAiB,EAAE,OAAuB,EAAE,IAAI,EAAE,EAAE;oBACnF,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;oBACtC,IAAI,CAAC,QAAQ,IAAI,KAAK,IAAI,IAAI;wBAAE,OAAO,KAAK,CAAC;oBAC7C,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;oBAC1C,OAAO,MAAM,CAAC,IAAI,CAAC,KAAc,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpF,CAAC,CAAC;QACN,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { GraphQLSchema } from 'graphql';
3
+ import type { Engine } from '../core/engine.js';
4
+ import type { Authenticate } from '../core/lifecycle/options.js';
5
+ /** Регистрирует обработчик GraphQL, контекст запроса и преобразование ошибок.
6
+ * @example После регистрации POST на заданный path выполняет запрос; прикладная ошибка попадает в errors[].extensions.code.
7
+ */
8
+ export declare function registerGraphqlRoutes(server: FastifyInstance, schema: GraphQLSchema, engine: Engine, path: string, authenticate?: Authenticate): void;
@@ -0,0 +1,30 @@
1
+ import mercurius from 'mercurius';
2
+ import { DomainError } from '../core/errors.js';
3
+ import { attachResolvers, createGraphqlContext } from './resolvers.js';
4
+ /** Регистрирует обработчик GraphQL, контекст запроса и преобразование ошибок.
5
+ * @example После регистрации POST на заданный path выполняет запрос; прикладная ошибка попадает в errors[].extensions.code.
6
+ */
7
+ export function registerGraphqlRoutes(server, schema, engine, path, authenticate) {
8
+ attachResolvers(schema, engine);
9
+ server.register(mercurius, {
10
+ schema,
11
+ path,
12
+ queryDepth: 32,
13
+ context: (request) => ({ ...createGraphqlContext(engine), ...(authenticate ? { actor: () => authenticate(request.headers.authorization) } : {}) }),
14
+ errorFormatter: (execution, context) => {
15
+ const formatted = mercurius.defaultErrorFormatter(execution, context);
16
+ formatted.response.errors = execution.errors.map((error) => {
17
+ const original = error.originalError;
18
+ if (original instanceof DomainError)
19
+ return { ...error.toJSON(), extensions: { ...error.extensions, code: original.code } };
20
+ if (original && !('errors' in original) && !(original instanceof Error && original.name === 'GraphQLError')) {
21
+ context.reply?.request.log.error(original);
22
+ return { message: 'Internal server error', locations: error.locations, path: error.path, extensions: { code: 'INTERNAL_ERROR' } };
23
+ }
24
+ return error.toJSON();
25
+ });
26
+ return formatted;
27
+ },
28
+ });
29
+ }
30
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/graphql/routes.ts"],"names":[],"mappings":"AAEA,OAAO,SAAS,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACvE;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAuB,EAAE,MAAqB,EAAE,MAAc,EAAE,IAAY,EAAE,YAA2B;IAC7I,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE;QACzB,MAAM;QACN,IAAI;QACJ,UAAU,EAAE,EAAE;QACd,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,oBAAoB,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAClJ,cAAc,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE;YACrC,MAAM,SAAS,GAAG,SAAS,CAAC,qBAAqB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACtE,SAAS,CAAC,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;gBACzD,MAAM,QAAQ,GAAG,KAAK,CAAC,aAAa,CAAC;gBACrC,IAAI,QAAQ,YAAY,WAAW;oBAAE,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC5H,IAAI,QAAQ,IAAI,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,YAAY,KAAK,IAAI,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,EAAE,CAAC;oBAC5G,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;oBAC3C,OAAO,EAAE,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,CAAC;gBACpI,CAAC;gBACD,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;YACxB,CAAC,CAAC,CAAC;YACH,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { GraphQLSchema } from 'graphql';
2
+ import { type Model } from '../core/model.js';
3
+ /** Строит типы, фильтры, аргументы и операции по модели, проверяя конфликты имён.
4
+ * @example Модель с сущностью Note → GraphQLSchema с типом Note; повторяющееся имя типа → ошибка.
5
+ */
6
+ export declare function buildGraphql(model: Model): GraphQLSchema;
@@ -1,8 +1,13 @@
1
1
  import { assertValidSchema, GraphQLBoolean, GraphQLEnumType, GraphQLFloat, GraphQLID, GraphQLInputObjectType, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, } from 'graphql';
2
- import { resolveField } from './engine.js';
3
- import { assertApi, nodeName, operationName } from './model.js';
4
- import { sortableFields } from './query/options.js';
5
- export function buildGraphql(model, engine) {
2
+ import { assertApi, canonicalNode, nodeName, operationName, writable } from '../core/model.js';
3
+ import { MUTATIONS } from '../core/operations.js';
4
+ import { operatorsFor } from '../core/query/contract.js';
5
+ import { sortableFields } from '../core/query/options.js';
6
+ import { capitalize } from '../core/utils.js';
7
+ /** Строит типы, фильтры, аргументы и операции по модели, проверяя конфликты имён.
8
+ * @example Модель с сущностью Note → GraphQLSchema с типом Note; повторяющееся имя типа → ошибка.
9
+ */
10
+ export function buildGraphql(model) {
6
11
  assertApi(model, 'graphql');
7
12
  const names = new Set(['String', 'Float', 'Int', 'Boolean', 'ID', 'Query', 'Mutation', 'Pager', 'OrderDirection']);
8
13
  const reserve = (name) => {
@@ -20,7 +25,6 @@ export function buildGraphql(model, engine) {
20
25
  const enums = new Map();
21
26
  const pager = new GraphQLInputObjectType({ name: 'Pager', fields: { page: { type: GraphQLInt }, pageSize: { type: GraphQLInt } } });
22
27
  const direction = new GraphQLEnumType({ name: 'OrderDirection', values: { ASC: { value: 'ASC' }, DESC: { value: 'DESC' } } });
23
- const canonical = (entity, node) => (node.relation ? [node.relation, node.relation.root] : [entity, node]);
24
28
  function scalar(entity, node, constrained = true) {
25
29
  if (constrained && node.enum) {
26
30
  let type = enums.get(node);
@@ -36,10 +40,12 @@ export function buildGraphql(model, engine) {
36
40
  return node.base === 'number' ? GraphQLFloat : node.base === 'boolean' ? GraphQLBoolean : node.primary ? GraphQLID : GraphQLString;
37
41
  }
38
42
  function output(entity, node) {
39
- [entity, node] = canonical(entity, node);
43
+ [entity, node] = canonicalNode(entity, node);
40
44
  let type = objects.get(node);
41
45
  if (type)
42
46
  return type;
47
+ if (!Object.values(node.children).some((child) => !child.writeOnly))
48
+ throw new Error(`GraphQL object ${nodeName(entity, node)} must contain at least one visible field`);
43
49
  type = new GraphQLObjectType({
44
50
  name: reserve(nodeName(entity, node)),
45
51
  fields: () => Object.fromEntries(Object.entries(node.children)
@@ -56,11 +62,8 @@ export function buildGraphql(model, engine) {
56
62
  {
57
63
  type: childType,
58
64
  description: child.description,
65
+ extensions: { node: child, ...(object && child.many ? { listNode: child } : {}) },
59
66
  args: object && child.many ? listArgs(entity, child) : undefined,
60
- resolve: (ref, args) => {
61
- const value = resolveField(ref, child);
62
- return object && child.many && value != null ? engine.list(value, child, args) : value;
63
- },
64
67
  },
65
68
  ];
66
69
  })),
@@ -69,7 +72,7 @@ export function buildGraphql(model, engine) {
69
72
  return type;
70
73
  }
71
74
  function page(entity, node) {
72
- [entity, node] = canonical(entity, node);
75
+ [entity, node] = canonicalNode(entity, node);
73
76
  let type = pages.get(node);
74
77
  if (type)
75
78
  return type;
@@ -80,9 +83,15 @@ export function buildGraphql(model, engine) {
80
83
  pages.set(node, type);
81
84
  return type;
82
85
  }
83
- function input(entity, node, mode, root = false) {
84
- const name = `${nodeName(entity, node)}${mode[0].toUpperCase() + mode.slice(1)}`;
85
- let type = inputs.get(name);
86
+ function input(entity, node, mode, root = false, nested = false) {
87
+ const name = `${nodeName(entity, node)}${nested ? 'Nested' : ''}${capitalize(mode)}`;
88
+ const variant = `${mode}:${root}:${nested}`;
89
+ let variants = inputs.get(node);
90
+ if (!variants) {
91
+ variants = new Map();
92
+ inputs.set(node, variants);
93
+ }
94
+ let type = variants.get(variant);
86
95
  if (type)
87
96
  return type;
88
97
  type = new GraphQLInputObjectType({
@@ -90,23 +99,28 @@ export function buildGraphql(model, engine) {
90
99
  fields: () => {
91
100
  const fields = {};
92
101
  for (const [key, child] of Object.entries(node.children)) {
93
- if (child.relation || child.generated || child.readOnly || (child.primary && mode !== 'create'))
102
+ const lookup = nested && child.primary;
103
+ if (!lookup && !writable(child, mode, true))
94
104
  continue;
95
- let childType = child.base === 'object' ? input(entity, child, mode) : scalar(entity, child);
105
+ let childType = child.relation
106
+ ? input(child.relation, child.relation.root, mode, true, true)
107
+ : child.base === 'object'
108
+ ? input(entity, child, mode)
109
+ : scalar(entity, child);
96
110
  if (child.many)
97
111
  childType = new GraphQLList(new GraphQLNonNull(childType));
98
- if (child.required && !child.nullable && !(root && mode === 'update') && child.default === undefined)
112
+ if (!lookup && !child.relation && !child.relationKey && child.required && !child.nullable && !(root && (mode === 'update' || (nested && mode === 'create'))) && child.default === undefined)
99
113
  childType = new GraphQLNonNull(childType);
100
114
  fields[key] = { type: childType, description: child.description };
101
115
  }
102
116
  return fields;
103
117
  },
104
118
  });
105
- inputs.set(name, type);
119
+ variants.set(variant, type);
106
120
  return type;
107
121
  }
108
122
  function where(entity, node) {
109
- [entity, node] = canonical(entity, node);
123
+ [entity, node] = canonicalNode(entity, node);
110
124
  let type = wheres.get(node);
111
125
  if (type)
112
126
  return type;
@@ -138,29 +152,19 @@ export function buildGraphql(model, engine) {
138
152
  type = new GraphQLInputObjectType({
139
153
  name: reserve(`${nodeName(entity, node)}Filter`),
140
154
  fields: () => {
141
- const fields = { not: { type: type } };
142
- const object = node.relation || node.base === 'object';
143
- if (node.many) {
144
- const element = object ? where(entity, node) : filter(entity, { ...node, many: false, path: `${node.path}_element` });
145
- for (const key of ['some', 'every', 'none'])
155
+ const fields = {};
156
+ const element = node.many ? (node.relation || node.base === 'object' ? where(entity, node) : filter(entity, { ...node, many: false, path: `${node.path}_element` })) : undefined;
157
+ for (const [key, operand] of Object.entries(operatorsFor(node))) {
158
+ const value = scalar(entity, node);
159
+ if (operand === 'condition')
160
+ fields[key] = { type: type };
161
+ else if (operand === 'element') {
162
+ if (!element)
163
+ throw new Error(`Missing element filter for ${node.path}`);
146
164
  fields[key] = { type: element };
147
- if (!object) {
148
- const value = scalar(entity, node);
149
- fields.contains = { type: value };
150
- fields.in = { type: new GraphQLList(value) };
151
165
  }
152
- }
153
- else {
154
- const value = scalar(entity, node);
155
- for (const key of ['eq', 'ne'])
156
- fields[key] = { type: value };
157
- fields.in = { type: new GraphQLList(value) };
158
- if (node.base !== 'boolean')
159
- for (const key of ['gt', 'gte', 'lt', 'lte'])
160
- fields[key] = { type: scalar(entity, node, false) };
161
- if (node.base === 'string')
162
- for (const key of ['contains', 'startsWith', 'endsWith'])
163
- fields[key] = { type: GraphQLString };
166
+ else
167
+ fields[key] = { type: operand === 'values' ? new GraphQLList(value) : operand === 'comparison' ? scalar(entity, node, false) : operand === 'text' ? GraphQLString : value };
164
168
  }
165
169
  return fields;
166
170
  },
@@ -169,7 +173,7 @@ export function buildGraphql(model, engine) {
169
173
  return type;
170
174
  }
171
175
  function order(entity, node) {
172
- [entity, node] = canonical(entity, node);
176
+ [entity, node] = canonicalNode(entity, node);
173
177
  let type = orders.get(node);
174
178
  if (type)
175
179
  return type;
@@ -196,21 +200,27 @@ export function buildGraphql(model, engine) {
196
200
  if (queries[operation])
197
201
  throw new Error(`GraphQL operation collision: ${operation}`);
198
202
  const keyArg = { [entity.primary]: { type: new GraphQLNonNull(scalar(entity, entity.fields[entity.primary], false)) } };
199
- queries[name] = { type: output(entity, entity.root), args: keyArg, resolve: (_root, args, ctx) => engine.find(ctx.snapshot, entity, args[entity.primary]) ?? null };
203
+ queries[name] = {
204
+ type: output(entity, entity.root),
205
+ args: keyArg,
206
+ extensions: { entity, operation: 'find' },
207
+ };
200
208
  queries[`${name}List`] = {
201
209
  type: new GraphQLNonNull(page(entity, entity.root)),
202
210
  args: listArgs(entity, entity.root),
203
- resolve: (_root, args, ctx) => engine.list(engine.records(ctx.snapshot, entity), entity.root, args),
211
+ extensions: { listNode: entity.root, entity, operation: 'list' },
204
212
  };
205
- for (const mode of ['create', 'replace', 'update', 'delete']) {
206
- const operation = `${name}${mode[0].toUpperCase() + mode.slice(1)}`;
213
+ for (const { mode, hasKey, hasBody } of MUTATIONS) {
214
+ const operation = `${name}${capitalize(mode)}`;
207
215
  if (mutations[operation])
208
216
  throw new Error(`GraphQL operation collision: ${operation}`);
209
- const fields = Object.values(entity.root.children).filter((child) => !child.relation && !child.generated && !child.readOnly && (!child.primary || mode === 'create'));
217
+ const args = { ...(hasKey ? keyArg : {}) };
218
+ if (hasBody && Object.values(entity.root.children).some((child) => writable(child, mode, true)))
219
+ args.data = { type: new GraphQLNonNull(input(entity, entity.root, mode, true)) };
210
220
  mutations[operation] = {
211
221
  type: output(entity, entity.root),
212
- args: { ...(mode !== 'create' ? keyArg : {}), ...(mode !== 'delete' && fields.length ? { data: { type: new GraphQLNonNull(input(entity, entity.root, mode, true)) } } : {}) },
213
- resolve: (_root, args) => engine.mutate(entity, mode, args[entity.primary], args.data ?? {}),
222
+ args,
223
+ extensions: { entity, operation: mode },
214
224
  };
215
225
  }
216
226
  }
@@ -220,4 +230,4 @@ export function buildGraphql(model, engine) {
220
230
  assertValidSchema(schema);
221
231
  return schema;
222
232
  }
223
- //# sourceMappingURL=graphql.js.map
233
+ //# sourceMappingURL=schema.js.map