@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.
- package/README.md +522 -179
- package/README.ru.md +525 -180
- package/dist/bin/deep-json-server.js +1 -1
- package/dist/bin/deep-json-server.js.map +1 -1
- package/dist/index.d.ts +13 -6
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/src/auth/contract.d.ts +31 -0
- package/dist/src/auth/contract.js +12 -0
- package/dist/src/auth/contract.js.map +1 -0
- package/dist/src/auth/input.d.ts +18 -0
- package/dist/src/auth/input.js +34 -0
- package/dist/src/auth/input.js.map +1 -0
- package/dist/src/auth/password.d.ts +17 -0
- package/dist/src/auth/password.js +41 -0
- package/dist/src/auth/password.js.map +1 -0
- package/dist/src/auth/public.d.ts +3 -0
- package/dist/src/auth/public.js +5 -0
- package/dist/src/auth/public.js.map +1 -0
- package/dist/src/auth/routes.d.ts +6 -0
- package/dist/src/auth/routes.js +18 -0
- package/dist/src/auth/routes.js.map +1 -0
- package/dist/src/auth/service.d.ts +78 -0
- package/dist/src/auth/service.js +218 -0
- package/dist/src/auth/service.js.map +1 -0
- package/dist/src/auth/store.d.ts +26 -0
- package/dist/src/auth/store.js +82 -0
- package/dist/src/auth/store.js.map +1 -0
- package/dist/src/cli/index.d.ts +7 -0
- package/dist/src/cli/index.js +113 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/core/config-values.d.ts +28 -0
- package/dist/src/core/config-values.js +53 -0
- package/dist/src/core/config-values.js.map +1 -0
- package/dist/src/{constants.d.ts → core/constants.d.ts} +1 -0
- package/dist/src/{constants.js → core/constants.js} +1 -0
- package/dist/src/core/constants.js.map +1 -0
- package/dist/src/core/database.d.ts +48 -0
- package/dist/src/{database.js → core/database.js} +36 -14
- package/dist/src/core/database.js.map +1 -0
- package/dist/src/core/engine.d.ts +53 -0
- package/dist/src/core/engine.js +249 -0
- package/dist/src/core/engine.js.map +1 -0
- package/dist/src/core/errors.d.ts +9 -0
- package/dist/src/core/errors.js +12 -0
- package/dist/src/core/errors.js.map +1 -0
- package/dist/src/core/http-errors.d.ts +9 -0
- package/dist/src/core/http-errors.js +15 -0
- package/dist/src/core/http-errors.js.map +1 -0
- package/dist/src/core/lifecycle/mutation.d.ts +49 -0
- package/dist/src/core/lifecycle/mutation.js +170 -0
- package/dist/src/core/lifecycle/mutation.js.map +1 -0
- package/dist/src/core/lifecycle/options.d.ts +21 -0
- package/dist/src/core/lifecycle/options.js +19 -0
- package/dist/src/core/lifecycle/options.js.map +1 -0
- package/dist/src/core/model.d.ts +145 -0
- package/dist/src/{model.js → core/model.js} +224 -33
- package/dist/src/core/model.js.map +1 -0
- package/dist/src/core/mutations/write.d.ts +26 -0
- package/dist/src/core/mutations/write.js +284 -0
- package/dist/src/core/mutations/write.js.map +1 -0
- package/dist/src/core/operations.d.ts +33 -0
- package/dist/src/core/operations.js +10 -0
- package/dist/src/core/operations.js.map +1 -0
- package/dist/src/core/pagination.d.ts +10 -0
- package/dist/src/core/pagination.js +13 -0
- package/dist/src/core/pagination.js.map +1 -0
- package/dist/src/core/paths.d.ts +16 -0
- package/dist/src/core/paths.js +64 -0
- package/dist/src/core/paths.js.map +1 -0
- package/dist/src/core/query/contract.d.ts +6 -0
- package/dist/src/core/query/contract.js +22 -0
- package/dist/src/core/query/contract.js.map +1 -0
- package/dist/src/core/query/execute.d.ts +25 -0
- package/dist/src/core/query/execute.js +82 -0
- package/dist/src/core/query/execute.js.map +1 -0
- package/dist/src/core/query/filter.d.ts +6 -0
- package/dist/src/core/query/filter.js +100 -0
- package/dist/src/core/query/filter.js.map +1 -0
- package/dist/src/core/query/options.d.ts +30 -0
- package/dist/src/core/query/options.js +44 -0
- package/dist/src/core/query/options.js.map +1 -0
- package/dist/src/core/records.d.ts +46 -0
- package/dist/src/core/records.js +69 -0
- package/dist/src/core/records.js.map +1 -0
- package/dist/src/core/relation-metadata.d.ts +15 -0
- package/dist/src/{relation-metadata.js → core/relation-metadata.js} +7 -2
- package/dist/src/core/relation-metadata.js.map +1 -0
- package/dist/src/core/storage.d.ts +2 -0
- package/dist/src/core/storage.js +2 -0
- package/dist/src/core/storage.js.map +1 -0
- package/dist/src/core/types.d.ts +10 -0
- package/dist/src/{types.js.map → core/types.js.map} +1 -1
- package/dist/src/core/utils.d.ts +56 -0
- package/dist/src/core/utils.js +102 -0
- package/dist/src/core/utils.js.map +1 -0
- package/dist/src/files/contract.d.ts +32 -30
- package/dist/src/files/contract.js +29 -48
- package/dist/src/files/contract.js.map +1 -1
- package/dist/src/files/disk-metadata.d.ts +9 -0
- package/dist/src/files/disk-metadata.js +44 -0
- package/dist/src/files/disk-metadata.js.map +1 -0
- package/dist/src/files/disk-paths.d.ts +15 -0
- package/dist/src/files/disk-paths.js +100 -0
- package/dist/src/files/disk-paths.js.map +1 -0
- package/dist/src/files/disk-store.d.ts +5 -1
- package/dist/src/files/disk-store.js +46 -173
- package/dist/src/files/disk-store.js.map +1 -1
- package/dist/src/files/http.d.ts +36 -0
- package/dist/src/files/http.js +53 -0
- package/dist/src/files/http.js.map +1 -0
- package/dist/src/files/index.d.ts +5 -4
- package/dist/src/files/index.js +7 -2
- package/dist/src/files/index.js.map +1 -1
- package/dist/src/files/memory-store.d.ts +4 -1
- package/dist/src/files/memory-store.js +29 -22
- package/dist/src/files/memory-store.js.map +1 -1
- package/dist/src/files/routes.d.ts +3 -0
- package/dist/src/files/routes.js +27 -2
- package/dist/src/files/routes.js.map +1 -1
- package/dist/src/files/streams.d.ts +5 -0
- package/dist/src/files/streams.js +20 -0
- package/dist/src/files/streams.js.map +1 -0
- package/dist/src/graphql/entry.d.ts +12 -0
- package/dist/src/graphql/entry.js +13 -0
- package/dist/src/graphql/entry.js.map +1 -0
- package/dist/src/graphql/generate.d.ts +12 -0
- package/dist/src/graphql/generate.js +19 -0
- package/dist/src/graphql/generate.js.map +1 -0
- package/dist/src/graphql/preflight.d.ts +6 -0
- package/dist/src/graphql/preflight.js +44 -0
- package/dist/src/graphql/preflight.js.map +1 -0
- package/dist/src/graphql/resolvers.d.ts +17 -0
- package/dist/src/graphql/resolvers.js +44 -0
- package/dist/src/graphql/resolvers.js.map +1 -0
- package/dist/src/graphql/routes.d.ts +8 -0
- package/dist/src/graphql/routes.js +30 -0
- package/dist/src/graphql/routes.js.map +1 -0
- package/dist/src/graphql/schema.d.ts +6 -0
- package/dist/src/{graphql.js → graphql/schema.js} +59 -49
- package/dist/src/graphql/schema.js.map +1 -0
- package/dist/src/graphql/write.d.ts +4 -0
- package/dist/src/graphql/write.js +10 -0
- package/dist/src/graphql/write.js.map +1 -0
- package/dist/src/openapi/auth.d.ts +13 -0
- package/dist/src/openapi/auth.js +139 -0
- package/dist/src/openapi/auth.js.map +1 -0
- package/dist/src/openapi/document.d.ts +7 -3
- package/dist/src/openapi/document.js +154 -103
- package/dist/src/openapi/document.js.map +1 -1
- package/dist/src/openapi/entry.d.ts +14 -0
- package/dist/src/openapi/entry.js +13 -0
- package/dist/src/openapi/entry.js.map +1 -0
- package/dist/src/openapi/files.d.ts +6 -0
- package/dist/src/{files/openapi.js → openapi/files.js} +6 -5
- package/dist/src/openapi/files.js.map +1 -0
- package/dist/src/openapi/generate.d.ts +19 -0
- package/dist/src/openapi/generate.js +41 -0
- package/dist/src/openapi/generate.js.map +1 -0
- package/dist/src/openapi/helpers.d.ts +26 -0
- package/dist/src/openapi/helpers.js +13 -0
- package/dist/src/openapi/helpers.js.map +1 -0
- package/dist/src/openapi/options.d.ts +18 -0
- package/dist/src/openapi/options.js +13 -0
- package/dist/src/openapi/options.js.map +1 -0
- package/dist/src/openapi/registry.d.ts +11 -0
- package/dist/src/openapi/registry.js +20 -0
- package/dist/src/openapi/registry.js.map +1 -0
- package/dist/src/{types.d.ts → openapi/types.d.ts} +2 -10
- package/dist/src/openapi/types.js +2 -0
- package/dist/src/openapi/types.js.map +1 -0
- package/dist/src/openapi/write.d.ts +5 -0
- package/dist/src/openapi/write.js +12 -0
- package/dist/src/openapi/write.js.map +1 -0
- package/dist/src/rest/options.d.ts +22 -0
- package/dist/src/rest/options.js +65 -0
- package/dist/src/rest/options.js.map +1 -0
- package/dist/src/rest/projection.d.ts +13 -0
- package/dist/src/rest/projection.js +61 -0
- package/dist/src/rest/projection.js.map +1 -0
- package/dist/src/rest/routes.d.ts +7 -0
- package/dist/src/rest/routes.js +58 -0
- package/dist/src/rest/routes.js.map +1 -0
- package/dist/src/server/bootstrap.d.ts +7 -0
- package/dist/src/server/bootstrap.js +48 -0
- package/dist/src/server/bootstrap.js.map +1 -0
- package/dist/src/server/config.d.ts +74 -0
- package/dist/src/server/config.js +142 -0
- package/dist/src/server/config.js.map +1 -0
- package/dist/src/server/create.d.ts +16 -0
- package/dist/src/server/create.js +59 -0
- package/dist/src/server/create.js.map +1 -0
- package/dist/src/server/features.d.ts +4 -0
- package/dist/src/server/features.js +11 -0
- package/dist/src/server/features.js.map +1 -0
- package/dist/src/server/http.d.ts +12 -0
- package/dist/src/server/http.js +40 -0
- package/dist/src/server/http.js.map +1 -0
- package/dist/src/server/model.d.ts +6 -0
- package/dist/src/server/model.js +14 -0
- package/dist/src/server/model.js.map +1 -0
- package/dist/src/server/openapi-options.d.ts +6 -0
- package/dist/src/server/openapi-options.js +15 -0
- package/dist/src/server/openapi-options.js.map +1 -0
- package/dist/src/server/public.d.ts +2 -0
- package/dist/src/server/public.js +2 -0
- package/dist/src/server/public.js.map +1 -0
- package/package.json +19 -3
- package/dist/src/cli.d.ts +0 -4
- package/dist/src/cli.js +0 -67
- package/dist/src/cli.js.map +0 -1
- package/dist/src/config.d.ts +0 -68
- package/dist/src/config.js +0 -161
- package/dist/src/config.js.map +0 -1
- package/dist/src/constants.js.map +0 -1
- package/dist/src/database.d.ts +0 -21
- package/dist/src/database.js.map +0 -1
- package/dist/src/engine.d.ts +0 -47
- package/dist/src/engine.js +0 -438
- package/dist/src/engine.js.map +0 -1
- package/dist/src/files/openapi.d.ts +0 -3
- package/dist/src/files/openapi.js.map +0 -1
- package/dist/src/graphql.d.ts +0 -4
- package/dist/src/graphql.js.map +0 -1
- package/dist/src/model.d.ts +0 -67
- package/dist/src/model.js.map +0 -1
- package/dist/src/openapi/index.d.ts +0 -7
- package/dist/src/openapi/index.js +0 -26
- package/dist/src/openapi/index.js.map +0 -1
- package/dist/src/query/filter.d.ts +0 -1
- package/dist/src/query/filter.js +0 -84
- package/dist/src/query/filter.js.map +0 -1
- package/dist/src/query/options.d.ts +0 -31
- package/dist/src/query/options.js +0 -135
- package/dist/src/query/options.js.map +0 -1
- package/dist/src/relation-metadata.d.ts +0 -10
- package/dist/src/relation-metadata.js.map +0 -1
- package/dist/src/server.d.ts +0 -14
- package/dist/src/server.js +0 -166
- package/dist/src/server.js.map +0 -1
- package/dist/src/utils.d.ts +0 -19
- package/dist/src/utils.js +0 -62
- package/dist/src/utils.js.map +0 -1
- /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;
|
package/dist/src/files/routes.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { createHttpError } from '../
|
|
2
|
-
import {
|
|
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":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,
|
|
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 {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
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] =
|
|
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] =
|
|
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)}${
|
|
85
|
-
|
|
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
|
-
|
|
102
|
+
const lookup = nested && child.primary;
|
|
103
|
+
if (!lookup && !writable(child, mode, true))
|
|
94
104
|
continue;
|
|
95
|
-
let childType = 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
|
-
|
|
119
|
+
variants.set(variant, type);
|
|
106
120
|
return type;
|
|
107
121
|
}
|
|
108
122
|
function where(entity, node) {
|
|
109
|
-
[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 = {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
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
|
-
|
|
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] =
|
|
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] = {
|
|
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
|
-
|
|
211
|
+
extensions: { listNode: entity.root, entity, operation: 'list' },
|
|
204
212
|
};
|
|
205
|
-
for (const mode
|
|
206
|
-
const operation = `${name}${
|
|
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
|
|
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
|
|
213
|
-
|
|
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=
|
|
233
|
+
//# sourceMappingURL=schema.js.map
|