@kollors/deep-json-server 0.9.0 → 1.0.0-alpha.10
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 +566 -347
- package/README.ru.md +560 -341
- 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 -5
- 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 +122 -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} +2 -1
- package/dist/src/{constants.js → core/constants.js} +2 -1
- 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} +64 -29
- package/dist/src/core/database.js.map +1 -0
- package/dist/src/core/engine.d.ts +65 -0
- package/dist/src/core/engine.js +312 -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/core/model.js +510 -0
- 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/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-store.d.ts +5 -1
- package/dist/src/files/disk-store.js +61 -33
- 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 +42 -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/schema.js +230 -0
- 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 +11 -7
- package/dist/src/openapi/document.js +287 -318
- 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/openapi/files.js +87 -0
- 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/{types.d.ts → openapi/types.d.ts} +2 -12
- 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 +49 -0
- package/dist/src/rest/routes.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 +133 -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/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/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 +25 -4
- package/dist/src/cli.d.ts +0 -4
- package/dist/src/cli.js +0 -80
- package/dist/src/cli.js.map +0 -1
- package/dist/src/config.d.ts +0 -54
- package/dist/src/config.js +0 -145
- package/dist/src/config.js.map +0 -1
- package/dist/src/constants.js.map +0 -1
- package/dist/src/database.d.ts +0 -20
- package/dist/src/database.js.map +0 -1
- package/dist/src/openapi/config.d.ts +0 -11
- package/dist/src/openapi/config.js +0 -204
- package/dist/src/openapi/config.js.map +0 -1
- package/dist/src/openapi/index.d.ts +0 -10
- package/dist/src/openapi/index.js +0 -27
- package/dist/src/openapi/index.js.map +0 -1
- package/dist/src/openapi/inference.d.ts +0 -14
- package/dist/src/openapi/inference.js +0 -145
- package/dist/src/openapi/inference.js.map +0 -1
- package/dist/src/query/filter.d.ts +0 -6
- package/dist/src/query/filter.js +0 -248
- package/dist/src/query/filter.js.map +0 -1
- package/dist/src/query/index.d.ts +0 -3
- package/dist/src/query/index.js +0 -4
- package/dist/src/query/index.js.map +0 -1
- package/dist/src/query/pagination.d.ts +0 -11
- package/dist/src/query/pagination.js +0 -28
- package/dist/src/query/pagination.js.map +0 -1
- package/dist/src/query/sort.d.ts +0 -1
- package/dist/src/query/sort.js +0 -54
- package/dist/src/query/sort.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/relations.d.ts +0 -12
- package/dist/src/relations.js +0 -155
- package/dist/src/relations.js.map +0 -1
- package/dist/src/server.d.ts +0 -13
- package/dist/src/server.js +0 -188
- package/dist/src/server.js.map +0 -1
- package/dist/src/utils.d.ts +0 -20
- package/dist/src/utils.js +0 -63
- package/dist/src/utils.js.map +0 -1
- /package/dist/src/{types.js → core/types.js} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { Engine } from '../core/engine.js';
|
|
3
|
+
import type { Authenticate } from '../core/lifecycle/options.js';
|
|
4
|
+
/** Регистрирует чтение коллекций и операции создания, замены, изменения и удаления записей.
|
|
5
|
+
* @example После регистрации GET / → { resources: [...] }; функция возвращает undefined.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerRestRoutes(server: FastifyInstance, engine: Engine, authenticate?: Authenticate): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { domainError } from '../core/errors.js';
|
|
2
|
+
import { MUTATIONS } from '../core/operations.js';
|
|
3
|
+
import { parseRestOptions } from './options.js';
|
|
4
|
+
import { project, validateRest } from './projection.js';
|
|
5
|
+
/** Регистрирует чтение коллекций и операции создания, замены, изменения и удаления записей.
|
|
6
|
+
* @example После регистрации GET / → { resources: [...] }; функция возвращает undefined.
|
|
7
|
+
*/
|
|
8
|
+
export function registerRestRoutes(server, engine, authenticate) {
|
|
9
|
+
server.get('/', async () => ({ resources: engine.model.entities.map((entity) => entity.collection) }));
|
|
10
|
+
for (const initial of engine.model.entities) {
|
|
11
|
+
const path = `/${initial.collection}`;
|
|
12
|
+
const itemPath = `${path}/:${initial.primary}`;
|
|
13
|
+
server.get(path, async (request) => {
|
|
14
|
+
const context = await engine.context();
|
|
15
|
+
const entity = context.model.byCollection.get(initial.collection);
|
|
16
|
+
const options = parseRestOptions(request.query);
|
|
17
|
+
const plans = validateRest(engine, entity, options, true);
|
|
18
|
+
const page = engine.list(engine.records(context, entity), entity.root, undefined, plans.get(options.scope));
|
|
19
|
+
return { data: page.data.map((ref) => project(engine, ref, options.scope, plans)), total: page.total };
|
|
20
|
+
});
|
|
21
|
+
server.get(itemPath, async (request) => {
|
|
22
|
+
const context = await engine.context();
|
|
23
|
+
const entity = context.model.byCollection.get(initial.collection);
|
|
24
|
+
const options = parseRestOptions(request.query);
|
|
25
|
+
const plans = validateRest(engine, entity, options);
|
|
26
|
+
const ref = engine.find(context, entity, request.params[entity.primary]);
|
|
27
|
+
if (!ref)
|
|
28
|
+
throw domainError('NOT_FOUND', 'Record not found');
|
|
29
|
+
return project(engine, ref, options.scope, plans);
|
|
30
|
+
});
|
|
31
|
+
for (const { method, mode, hasKey, status } of MUTATIONS) {
|
|
32
|
+
server.route({
|
|
33
|
+
method,
|
|
34
|
+
url: hasKey ? itemPath : path,
|
|
35
|
+
handler: async (request, reply) => {
|
|
36
|
+
const actor = authenticate ? () => authenticate(request.headers.authorization) : undefined;
|
|
37
|
+
actor?.();
|
|
38
|
+
const options = parseRestOptions(request.query);
|
|
39
|
+
const result = await engine.mutate(initial, mode, request.params[initial.primary], request.body, (ref) => {
|
|
40
|
+
const plans = validateRest(engine, ref.entity, options);
|
|
41
|
+
return project(engine, ref, options.scope, plans);
|
|
42
|
+
}, actor);
|
|
43
|
+
return reply.code(status).send(result);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/rest/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { FastifyServerOptions } from 'fastify';
|
|
2
|
+
import type { AuthConfig } from '../auth/contract.js';
|
|
3
|
+
import type { DatabaseConfig } from '../core/database.js';
|
|
4
|
+
import type { ModelSchema } from '../core/model.js';
|
|
5
|
+
import type { Storage } from '../core/storage.js';
|
|
6
|
+
import type { FilesConfig } from '../files/contract.js';
|
|
7
|
+
import { type OpenapiInfo } from '../openapi/options.js';
|
|
8
|
+
export type { AuthConfig } from '../auth/contract.js';
|
|
9
|
+
export type { DatabaseConfig } from '../core/database.js';
|
|
10
|
+
export type { Storage } from '../core/storage.js';
|
|
11
|
+
export type { FilesConfig, MemoryFile } from '../files/contract.js';
|
|
12
|
+
export type DatabaseSchema = ModelSchema;
|
|
13
|
+
export interface OpenapiConfig {
|
|
14
|
+
endpoint?: string;
|
|
15
|
+
target?: string;
|
|
16
|
+
info?: OpenapiInfo;
|
|
17
|
+
}
|
|
18
|
+
export interface GraphqlConfig {
|
|
19
|
+
target?: string;
|
|
20
|
+
endpoint?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ServerConfig {
|
|
23
|
+
cors?: boolean;
|
|
24
|
+
host?: string;
|
|
25
|
+
logger?: FastifyServerOptions['logger'];
|
|
26
|
+
maxFileSize?: number;
|
|
27
|
+
maxPageSize?: number;
|
|
28
|
+
pageSize?: number;
|
|
29
|
+
port?: number;
|
|
30
|
+
}
|
|
31
|
+
export type DeepJsonServerConfig = {
|
|
32
|
+
[S in Storage]: {
|
|
33
|
+
storage: S;
|
|
34
|
+
database: DatabaseConfig<S>;
|
|
35
|
+
files?: FilesConfig<S>;
|
|
36
|
+
auth?: AuthConfig<S>;
|
|
37
|
+
openapi?: OpenapiConfig;
|
|
38
|
+
graphql?: GraphqlConfig;
|
|
39
|
+
server?: ServerConfig;
|
|
40
|
+
};
|
|
41
|
+
}[Storage];
|
|
42
|
+
export interface NormalizedServerConfig {
|
|
43
|
+
storage: Storage;
|
|
44
|
+
database: DatabaseConfig;
|
|
45
|
+
files?: FilesConfig;
|
|
46
|
+
auth?: AuthConfig;
|
|
47
|
+
openapi?: OpenapiConfig & {
|
|
48
|
+
endpoint: string;
|
|
49
|
+
};
|
|
50
|
+
graphql?: GraphqlConfig & {
|
|
51
|
+
endpoint: string;
|
|
52
|
+
};
|
|
53
|
+
server: Required<ServerConfig>;
|
|
54
|
+
}
|
|
55
|
+
/** Нормализует объект конфигурации без чтения содержимого файлов.
|
|
56
|
+
* @example Путь './db.json' с directory = '/tmp' → '/tmp/db.json'.
|
|
57
|
+
*/
|
|
58
|
+
export declare const normalizeServerConfig: (config: DeepJsonServerConfig, directory?: string) => NormalizedServerConfig;
|
|
59
|
+
/** Загружает default-экспорт ES-модуля, обходя кеш повторного импорта; выполняет код модуля.
|
|
60
|
+
* @example Файл /tmp/config.mjs с export default {} → { config: {}, directory: '/tmp', path: '/tmp/config.mjs' }.
|
|
61
|
+
*/
|
|
62
|
+
export declare function readConfigModule(configPath: string): Promise<{
|
|
63
|
+
config: Record<string, unknown>;
|
|
64
|
+
directory: string;
|
|
65
|
+
path: string;
|
|
66
|
+
}>;
|
|
67
|
+
/** Возвращает сохранённый путь исходного файла для данного объекта настроек.
|
|
68
|
+
* @example Для объекта без зарегистрированного источника → undefined.
|
|
69
|
+
*/
|
|
70
|
+
export declare const configSourcePath: (config: NormalizedServerConfig) => string | undefined;
|
|
71
|
+
/** Нормализует настройки и запоминает путь их источника во внутренней таблице.
|
|
72
|
+
* @example configure(config, '/tmp', '/tmp/config.mjs') → настройки; configSourcePath(result) → '/tmp/config.mjs'.
|
|
73
|
+
*/
|
|
74
|
+
export declare function configure(config: unknown, directory: string, sourcePath?: string): NormalizedServerConfig;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { dirname, resolve } from 'node:path';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { getBoolean, getObject, getPositiveInteger, getString, normalizeAddress } from '../core/config-values.js';
|
|
4
|
+
import { DEFAULT_MAX_FILE_SIZE } from '../core/constants.js';
|
|
5
|
+
import { normalizePagination } from '../core/pagination.js';
|
|
6
|
+
import { assertKnownKeys, errorMessage, isObject } from '../core/utils.js';
|
|
7
|
+
import { normalizeOpenapiInfo } from '../openapi/options.js';
|
|
8
|
+
const CONFIG_KEYS = new Set(['storage', 'database', 'files', 'auth', 'openapi', 'graphql', 'server']);
|
|
9
|
+
const SERVER_KEYS = new Set(['cors', 'host', 'logger', 'maxFileSize', 'maxPageSize', 'pageSize', 'port']);
|
|
10
|
+
let configImportIndex = 0;
|
|
11
|
+
/** Проверяет секцию и её допустимые ключи; undefined означает отсутствие секции.
|
|
12
|
+
* @example section({}, 'auth', []) → {}; section(null, 'auth', []) → ошибка.
|
|
13
|
+
*/
|
|
14
|
+
function section(value, name, keys) {
|
|
15
|
+
if (value === undefined)
|
|
16
|
+
return undefined;
|
|
17
|
+
const object = getObject(value, `config.${name}`, true);
|
|
18
|
+
assertKnownKeys(object, new Set(keys), `config.${name}`);
|
|
19
|
+
return object;
|
|
20
|
+
}
|
|
21
|
+
/** Проверяет путь либо начальные данные в соответствии с общим режимом хранения.
|
|
22
|
+
* @example source('db.json', 'file', 'database.source', '/tmp') → '/tmp/db.json'.
|
|
23
|
+
*/
|
|
24
|
+
function source(value, storage, name, directory, array = false) {
|
|
25
|
+
if (storage === 'file')
|
|
26
|
+
return resolve(directory, getString(value, `config.${name}`, true));
|
|
27
|
+
if (array ? !Array.isArray(value) : !isObject(value))
|
|
28
|
+
throw new Error(`config.${name} must contain ${array ? 'an array' : 'an object'} for memory storage`);
|
|
29
|
+
try {
|
|
30
|
+
return structuredClone(value);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw new Error(`config.${name} must contain structured data`, { cause: error });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Проверяет секции настроек и возвращает независимые данные с абсолютными путями.
|
|
37
|
+
* @example { storage: 'file', database: { source: 'db.json' } } → абсолютный database.source.
|
|
38
|
+
*/
|
|
39
|
+
function normalizeConfig(value, directory = '.') {
|
|
40
|
+
const config = getObject(value, 'config', true);
|
|
41
|
+
assertKnownKeys(config, CONFIG_KEYS, 'config');
|
|
42
|
+
if (config.storage !== 'file' && config.storage !== 'memory')
|
|
43
|
+
throw new Error("config.storage must be 'file' or 'memory'");
|
|
44
|
+
const storage = config.storage;
|
|
45
|
+
const database = section(config.database, 'database', ['source', 'schema']);
|
|
46
|
+
if (!database)
|
|
47
|
+
throw new Error('config.database is required');
|
|
48
|
+
const normalizedDatabase = {
|
|
49
|
+
source: source(database.source, storage, 'database.source', directory),
|
|
50
|
+
...(database.schema !== undefined ? { schema: source(database.schema, storage, 'database.schema', directory) } : {}),
|
|
51
|
+
};
|
|
52
|
+
const files = section(config.files, 'files', storage === 'file' ? ['source', 'metadata'] : ['source']);
|
|
53
|
+
const normalizedFiles = files === undefined
|
|
54
|
+
? undefined
|
|
55
|
+
: storage === 'file'
|
|
56
|
+
? {
|
|
57
|
+
source: source(files.source, storage, 'files.source', directory),
|
|
58
|
+
metadata: files.metadata === undefined
|
|
59
|
+
? resolve(directory, getString(files.source, 'config.files.source', true), '.files.json')
|
|
60
|
+
: resolve(directory, getString(files.metadata, 'config.files.metadata', true)),
|
|
61
|
+
}
|
|
62
|
+
: { source: source(files.source, storage, 'files.source', directory, true) };
|
|
63
|
+
const auth = section(config.auth, 'auth', ['source', 'expiresIn']);
|
|
64
|
+
let normalizedAuth;
|
|
65
|
+
if (auth) {
|
|
66
|
+
const expiresIn = getPositiveInteger(auth.expiresIn, 'config.auth.expiresIn');
|
|
67
|
+
if (expiresIn !== undefined && expiresIn > 2147483647)
|
|
68
|
+
throw new Error('config.auth.expiresIn must be at most 2147483647 seconds');
|
|
69
|
+
normalizedAuth = { source: source(auth.source, storage, 'auth.source', directory, true), expiresIn };
|
|
70
|
+
}
|
|
71
|
+
const openapi = section(config.openapi, 'openapi', ['target', 'info', 'endpoint']);
|
|
72
|
+
const graphql = section(config.graphql, 'graphql', ['target', 'endpoint']);
|
|
73
|
+
if ((openapi || graphql) && normalizedDatabase.schema === undefined)
|
|
74
|
+
throw new Error('GraphQL and OpenAPI require an explicit model schema');
|
|
75
|
+
const exportPath = (value, name) => (value === undefined ? undefined : resolve(directory, getString(value, name, true)));
|
|
76
|
+
const openapiEndpoint = getString(openapi?.endpoint, 'config.openapi.endpoint') ?? '/openapi.json';
|
|
77
|
+
const graphqlEndpoint = getString(graphql?.endpoint, 'config.graphql.endpoint') ?? '/graphql';
|
|
78
|
+
if (!/^\/[A-Za-z][A-Za-z0-9_./-]*$/.test(openapiEndpoint))
|
|
79
|
+
throw new Error('Invalid OpenAPI endpoint');
|
|
80
|
+
if (!/^\/[A-Za-z][A-Za-z0-9_/-]*$/.test(graphqlEndpoint))
|
|
81
|
+
throw new Error('Invalid GraphQL endpoint');
|
|
82
|
+
const server = getObject(config.server, 'config.server') ?? {};
|
|
83
|
+
assertKnownKeys(server, SERVER_KEYS, 'config.server');
|
|
84
|
+
const logger = server.logger;
|
|
85
|
+
if (logger != null && typeof logger !== 'boolean' && !isObject(logger))
|
|
86
|
+
throw new Error('config.server.logger must be boolean or an object');
|
|
87
|
+
return {
|
|
88
|
+
storage,
|
|
89
|
+
database: normalizedDatabase,
|
|
90
|
+
files: normalizedFiles,
|
|
91
|
+
auth: normalizedAuth,
|
|
92
|
+
openapi: openapi ? { endpoint: openapiEndpoint, target: exportPath(openapi.target, 'config.openapi.target'), info: normalizeOpenapiInfo(openapi.info) } : undefined,
|
|
93
|
+
graphql: graphql ? { endpoint: graphqlEndpoint, target: exportPath(graphql.target, 'config.graphql.target') } : undefined,
|
|
94
|
+
server: {
|
|
95
|
+
...normalizeAddress(server),
|
|
96
|
+
...normalizePagination(server),
|
|
97
|
+
cors: getBoolean(server.cors, 'config.server.cors') ?? true,
|
|
98
|
+
logger: (logger ?? true),
|
|
99
|
+
maxFileSize: getPositiveInteger(server.maxFileSize, 'config.server.maxFileSize') ?? DEFAULT_MAX_FILE_SIZE,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** Нормализует объект конфигурации без чтения содержимого файлов.
|
|
104
|
+
* @example Путь './db.json' с directory = '/tmp' → '/tmp/db.json'.
|
|
105
|
+
*/
|
|
106
|
+
export const normalizeServerConfig = (config, directory) => normalizeConfig(config, directory);
|
|
107
|
+
/** Загружает default-экспорт ES-модуля, обходя кеш повторного импорта; выполняет код модуля.
|
|
108
|
+
* @example Файл /tmp/config.mjs с export default {} → { config: {}, directory: '/tmp', path: '/tmp/config.mjs' }.
|
|
109
|
+
*/
|
|
110
|
+
export async function readConfigModule(configPath) {
|
|
111
|
+
const resolvedConfigPath = resolve(getString(configPath, 'config', true));
|
|
112
|
+
let config;
|
|
113
|
+
try {
|
|
114
|
+
const configUrl = pathToFileURL(resolvedConfigPath);
|
|
115
|
+
// Обходим кеш модуля, чтобы повторное чтение выполняло обновлённый файл.
|
|
116
|
+
configUrl.searchParams.set('deep-json-server-import', String(configImportIndex++));
|
|
117
|
+
config = (await import(configUrl.href)).default;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
const message = errorMessage(error);
|
|
121
|
+
throw new Error(`Не удалось загрузить конфигурацию ${resolvedConfigPath}: ${message}`, { cause: error });
|
|
122
|
+
}
|
|
123
|
+
if (!isObject(config)) {
|
|
124
|
+
throw new Error('Конфигурация сервера должна экспортировать JSON-объект через export default');
|
|
125
|
+
}
|
|
126
|
+
return { config, directory: dirname(resolvedConfigPath), path: resolvedConfigPath };
|
|
127
|
+
}
|
|
128
|
+
const sourcePaths = new WeakMap();
|
|
129
|
+
/** Возвращает сохранённый путь исходного файла для данного объекта настроек.
|
|
130
|
+
* @example Для объекта без зарегистрированного источника → undefined.
|
|
131
|
+
*/
|
|
132
|
+
export const configSourcePath = (config) => sourcePaths.get(config);
|
|
133
|
+
/** Нормализует настройки и запоминает путь их источника во внутренней таблице.
|
|
134
|
+
* @example configure(config, '/tmp', '/tmp/config.mjs') → настройки; configSourcePath(result) → '/tmp/config.mjs'.
|
|
135
|
+
*/
|
|
136
|
+
export function configure(config, directory, sourcePath) {
|
|
137
|
+
const normalized = normalizeConfig(config, directory);
|
|
138
|
+
if (sourcePath)
|
|
139
|
+
sourcePaths.set(normalized, sourcePath);
|
|
140
|
+
return normalized;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/server/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { OpenapiDocument } from '../openapi/types.js';
|
|
3
|
+
import { type DeepJsonServerConfig, type NormalizedServerConfig } from './config.js';
|
|
4
|
+
export interface ServerFacade {
|
|
5
|
+
fastify(): FastifyInstance;
|
|
6
|
+
openapi(): Promise<OpenapiDocument>;
|
|
7
|
+
graphql(): Promise<string>;
|
|
8
|
+
}
|
|
9
|
+
/** Проверяет настройки и создаёт интерфейс запуска и генерации схем; сетевой порт ещё не открывает.
|
|
10
|
+
* @example await createServer({ storage: 'memory', database: { source: { notes: [] } } }) → объект с fastify(), openapi(), graphql().
|
|
11
|
+
*/
|
|
12
|
+
export declare function createServer(config: DeepJsonServerConfig): Promise<ServerFacade>;
|
|
13
|
+
/** Собирает сервер из нормализованных настроек; хранилища открываются при инициализации HTTP-экземпляра.
|
|
14
|
+
* @example Нормализованные настройки → Promise<ServerFacade>; listen() затем открывает сетевой порт.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createConfiguredServer(normalized: NormalizedServerConfig): Promise<ServerFacade>;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { AUTH_PATHS } from '../auth/contract.js';
|
|
2
|
+
import { DomainError } from '../core/errors.js';
|
|
3
|
+
import { domainStatus } from '../core/http-errors.js';
|
|
4
|
+
import { inputPaths } from '../core/paths.js';
|
|
5
|
+
import { errorMessage, isObject } from '../core/utils.js';
|
|
6
|
+
import { configSourcePath, normalizeServerConfig } from './config.js';
|
|
7
|
+
import { validateEndpoints } from './features.js';
|
|
8
|
+
import { configuredModel } from './model.js';
|
|
9
|
+
const CORS_HEADERS = {
|
|
10
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
11
|
+
'Access-Control-Allow-Methods': 'DELETE, GET, OPTIONS, PATCH, POST, PUT',
|
|
12
|
+
'Access-Control-Allow-Origin': '*',
|
|
13
|
+
};
|
|
14
|
+
/** Проверяет настройки и создаёт интерфейс запуска и генерации схем; сетевой порт ещё не открывает.
|
|
15
|
+
* @example await createServer({ storage: 'memory', database: { source: { notes: [] } } }) → объект с fastify(), openapi(), graphql().
|
|
16
|
+
*/
|
|
17
|
+
export async function createServer(config) {
|
|
18
|
+
if (arguments.length !== 1)
|
|
19
|
+
throw new Error('createServer accepts only a configuration object');
|
|
20
|
+
return createConfiguredServer(normalizeServerConfig(config));
|
|
21
|
+
}
|
|
22
|
+
/** Собирает сервер из нормализованных настроек; хранилища открываются при инициализации HTTP-экземпляра.
|
|
23
|
+
* @example Нормализованные настройки → Promise<ServerFacade>; listen() затем открывает сетевой порт.
|
|
24
|
+
*/
|
|
25
|
+
export async function createConfiguredServer(normalized) {
|
|
26
|
+
const enabled = { auth: normalized.auth !== undefined, files: normalized.files !== undefined };
|
|
27
|
+
const { inferModel } = await import('../core/model.js');
|
|
28
|
+
const recordSettings = { auth: enabled.auth };
|
|
29
|
+
const explicitModel = await configuredModel(normalized);
|
|
30
|
+
const { default: Fastify } = await import('fastify');
|
|
31
|
+
const corsHeaders = { ...CORS_HEADERS };
|
|
32
|
+
if (enabled.files) {
|
|
33
|
+
const { FILE_HEADERS } = await import('../files/http.js');
|
|
34
|
+
corsHeaders['Access-Control-Allow-Headers'] = [...Object.values(FILE_HEADERS).map(({ name }) => name), 'Content-Type'].join(', ');
|
|
35
|
+
}
|
|
36
|
+
if (enabled.auth)
|
|
37
|
+
corsHeaders['Access-Control-Allow-Headers'] += ', Authorization';
|
|
38
|
+
const { cors, logger, maxFileSize, pageSize, maxPageSize } = normalized.server;
|
|
39
|
+
const openapi = async () => {
|
|
40
|
+
if (!normalized.openapi)
|
|
41
|
+
throw new Error('OpenAPI is not configured');
|
|
42
|
+
return (await import('../openapi/generate.js')).openapiFromModel(explicitModel, {
|
|
43
|
+
files: enabled.files,
|
|
44
|
+
...recordSettings,
|
|
45
|
+
pageSize,
|
|
46
|
+
maxPageSize,
|
|
47
|
+
info: normalized.openapi.info,
|
|
48
|
+
host: normalized.server.host,
|
|
49
|
+
port: normalized.server.port,
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
let instance;
|
|
53
|
+
const getFastify = () => {
|
|
54
|
+
if (instance)
|
|
55
|
+
return instance;
|
|
56
|
+
const server = Fastify({ ajv: { customOptions: { coerceTypes: false, removeAdditional: false } }, logger });
|
|
57
|
+
const originalListen = server.listen.bind(server);
|
|
58
|
+
const defaults = { host: normalized.server.host, port: normalized.server.port };
|
|
59
|
+
const listen = (optionsOrCallback, callback) => {
|
|
60
|
+
if (typeof optionsOrCallback === 'function') {
|
|
61
|
+
originalListen(defaults, optionsOrCallback);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (callback) {
|
|
65
|
+
originalListen({ ...defaults, ...optionsOrCallback }, callback);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
return originalListen({ ...defaults, ...optionsOrCallback });
|
|
69
|
+
};
|
|
70
|
+
server.listen = listen;
|
|
71
|
+
server.setErrorHandler((error, request, reply) => {
|
|
72
|
+
const candidate = error instanceof DomainError ? domainStatus[error.code] : isObject(error) ? error.statusCode : undefined;
|
|
73
|
+
const status = typeof candidate === 'number' && Number.isInteger(candidate) && candidate >= 400 && candidate <= 599 ? candidate : 500;
|
|
74
|
+
if (status === 500)
|
|
75
|
+
request.log.error(error);
|
|
76
|
+
return reply.code(status).send({ error: status === 500 ? 'Внутренняя ошибка сервера' : errorMessage(error) });
|
|
77
|
+
});
|
|
78
|
+
if (cors) {
|
|
79
|
+
server.addHook('onRequest', async (_request, reply) => {
|
|
80
|
+
for (const [key, value] of Object.entries(corsHeaders))
|
|
81
|
+
reply.header(key, value);
|
|
82
|
+
});
|
|
83
|
+
server.options('/', async (_request, reply) => reply.code(204).send());
|
|
84
|
+
server.options('/*', async (_request, reply) => reply.code(204).send());
|
|
85
|
+
}
|
|
86
|
+
server.register(async (app) => {
|
|
87
|
+
const [{ createDatabaseStore }, { Engine }, { registerRestRoutes }] = await Promise.all([import('../core/database.js'), import('../core/engine.js'), import('../rest/routes.js')]);
|
|
88
|
+
const keys = explicitModel ? new Map(explicitModel.entities.map((e) => [e.collection, e.primary])) : undefined;
|
|
89
|
+
const store = await createDatabaseStore(normalized.database, keys);
|
|
90
|
+
const model = explicitModel ?? inferModel(store.database.data, recordSettings);
|
|
91
|
+
const engine = new Engine(store, model, pageSize, maxPageSize);
|
|
92
|
+
engine.validateData(store.database.data);
|
|
93
|
+
const graphqlPath = normalized.graphql?.endpoint;
|
|
94
|
+
const openapiPath = normalized.openapi?.endpoint;
|
|
95
|
+
validateEndpoints(model.entities.map((entity) => entity.collection), [...(graphqlPath ? [graphqlPath] : []), ...(openapiPath ? [openapiPath] : []), ...(enabled.auth ? Object.values(AUTH_PATHS) : [])]);
|
|
96
|
+
const auth = enabled.auth && normalized.auth ? await (await import('../auth/service.js')).createAuthService(normalized.auth) : undefined;
|
|
97
|
+
if (auth) {
|
|
98
|
+
app.addHook('onClose', async () => auth.close());
|
|
99
|
+
const { registerAuthRoutes } = await import('../auth/routes.js');
|
|
100
|
+
registerAuthRoutes(app, auth);
|
|
101
|
+
}
|
|
102
|
+
const authenticate = auth ? (header) => auth.me(header) : undefined;
|
|
103
|
+
registerRestRoutes(app, engine, authenticate);
|
|
104
|
+
if (graphqlPath) {
|
|
105
|
+
const [{ registerGraphqlRoutes }, { buildGraphql }] = await Promise.all([import('../graphql/routes.js'), import('../graphql/schema.js')]);
|
|
106
|
+
registerGraphqlRoutes(app, buildGraphql(model), engine, graphqlPath, authenticate);
|
|
107
|
+
}
|
|
108
|
+
if (openapiPath) {
|
|
109
|
+
const document = await openapi();
|
|
110
|
+
document.servers = [{ url: '/' }];
|
|
111
|
+
app.get(openapiPath, async () => document);
|
|
112
|
+
}
|
|
113
|
+
const files = normalized.files;
|
|
114
|
+
if (enabled.files && files) {
|
|
115
|
+
const { createFileStore, registerFileRoutes } = await import('../files/index.js');
|
|
116
|
+
const protectedPaths = inputPaths({ database: normalized.database, auth: normalized.auth }, '.', configSourcePath(normalized));
|
|
117
|
+
registerFileRoutes(app, { getStore: () => createFileStore(files, protectedPaths), maxFileSize });
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
instance = server;
|
|
121
|
+
return server;
|
|
122
|
+
};
|
|
123
|
+
return {
|
|
124
|
+
fastify: getFastify,
|
|
125
|
+
openapi,
|
|
126
|
+
graphql: async () => {
|
|
127
|
+
if (!normalized.graphql)
|
|
128
|
+
throw new Error('GraphQL is not configured');
|
|
129
|
+
return (await import('../graphql/generate.js')).graphqlFromModel(explicitModel);
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/server/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Проверяет, что пути не повторяются и не перекрывают коллекции или файловые маршруты.
|
|
2
|
+
* @example validateEndpoints(['users'], ['/users/1']) → ошибка; ['users'], ['/api'] → undefined.
|
|
3
|
+
*/
|
|
4
|
+
export declare function validateEndpoints(collections: string[], endpoints: string[]): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Проверяет, что пути не повторяются и не перекрывают коллекции или файловые маршруты.
|
|
2
|
+
* @example validateEndpoints(['users'], ['/users/1']) → ошибка; ['users'], ['/api'] → undefined.
|
|
3
|
+
*/
|
|
4
|
+
export function validateEndpoints(collections, endpoints) {
|
|
5
|
+
if (new Set(endpoints).size !== endpoints.length)
|
|
6
|
+
throw new Error('API endpoints conflict');
|
|
7
|
+
for (const endpoint of endpoints)
|
|
8
|
+
if (collections.some((collection) => endpoint === `/${collection}` || endpoint.startsWith(`/${collection}/`)) || endpoint.startsWith('/_files/'))
|
|
9
|
+
throw new Error(`API endpoint conflicts with a resource route: ${endpoint}`);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=features.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features.js","sourceRoot":"","sources":["../../../src/server/features.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAqB,EAAE,SAAmB;IAC1E,IAAI,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5F,KAAK,MAAM,QAAQ,IAAI,SAAS;QAC9B,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,QAAQ,KAAK,IAAI,UAAU,EAAE,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC;YAC9I,MAAM,IAAI,KAAK,CAAC,iDAAiD,QAAQ,EAAE,CAAC,CAAC;AACnF,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Model } from '../core/model.js';
|
|
2
|
+
import type { NormalizedServerConfig } from './config.js';
|
|
3
|
+
/** Загружает схему один раз для заданного объекта настроек; база и учётные записи не читаются.
|
|
4
|
+
* @example Повторные вызовы с одним config → тот же Promise<Model | undefined>.
|
|
5
|
+
*/
|
|
6
|
+
export declare function configuredModel(config: NormalizedServerConfig): Promise<Model | undefined>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const models = new WeakMap();
|
|
2
|
+
/** Загружает схему один раз для заданного объекта настроек; база и учётные записи не читаются.
|
|
3
|
+
* @example Повторные вызовы с одним config → тот же Promise<Model | undefined>.
|
|
4
|
+
*/
|
|
5
|
+
export function configuredModel(config) {
|
|
6
|
+
let model = models.get(config);
|
|
7
|
+
if (!model) {
|
|
8
|
+
const api = [...(config.openapi ? ['openapi'] : []), ...(config.graphql ? ['graphql'] : [])];
|
|
9
|
+
model = import('../core/model.js').then(({ loadModel }) => loadModel(config.database.schema, { auth: config.auth !== undefined, api }));
|
|
10
|
+
models.set(config, model);
|
|
11
|
+
}
|
|
12
|
+
return model;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/server/model.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,GAAG,IAAI,OAAO,EAAsD,CAAC;AACjF;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAA8B;IAC5D,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,GAAG,GAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAkB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAkB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5H,KAAK,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACxI,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/server/public.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAqB,MAAM,aAAa,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kollors/deep-json-server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "JSON mock server with nested
|
|
3
|
+
"version": "1.0.0-alpha.10",
|
|
4
|
+
"description": "JSON mock server with schema-driven REST, GraphQL, nested queries and OpenAPI generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -12,6 +12,22 @@
|
|
|
12
12
|
".": {
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./server": {
|
|
17
|
+
"types": "./dist/src/server/public.d.ts",
|
|
18
|
+
"import": "./dist/src/server/public.js"
|
|
19
|
+
},
|
|
20
|
+
"./openapi": {
|
|
21
|
+
"types": "./dist/src/openapi/entry.d.ts",
|
|
22
|
+
"import": "./dist/src/openapi/entry.js"
|
|
23
|
+
},
|
|
24
|
+
"./graphql": {
|
|
25
|
+
"types": "./dist/src/graphql/entry.d.ts",
|
|
26
|
+
"import": "./dist/src/graphql/entry.js"
|
|
27
|
+
},
|
|
28
|
+
"./auth": {
|
|
29
|
+
"types": "./dist/src/auth/public.d.ts",
|
|
30
|
+
"import": "./dist/src/auth/public.js"
|
|
15
31
|
}
|
|
16
32
|
},
|
|
17
33
|
"files": [
|
|
@@ -36,8 +52,12 @@
|
|
|
36
52
|
"node": ">=22"
|
|
37
53
|
},
|
|
38
54
|
"dependencies": {
|
|
55
|
+
"ajv": "^8.20.0",
|
|
56
|
+
"ajv-formats": "^3.0.1",
|
|
39
57
|
"fastify": "^5.12.3",
|
|
58
|
+
"graphql": "^16.14.2",
|
|
40
59
|
"lowdb": "^7.0.1",
|
|
60
|
+
"mercurius": "^16.10.0",
|
|
41
61
|
"pluralize": "^8.0.0",
|
|
42
62
|
"yaml": "^2.8.1"
|
|
43
63
|
},
|
|
@@ -55,14 +75,15 @@
|
|
|
55
75
|
"deep-filter",
|
|
56
76
|
"file-upload",
|
|
57
77
|
"json",
|
|
58
|
-
"json-server",
|
|
59
78
|
"mock",
|
|
60
79
|
"mock-api",
|
|
61
80
|
"mock-server",
|
|
62
81
|
"openapi",
|
|
63
82
|
"relations",
|
|
64
83
|
"rest",
|
|
65
|
-
"rest-api"
|
|
84
|
+
"rest-api",
|
|
85
|
+
"graphql",
|
|
86
|
+
"openapi-generator"
|
|
66
87
|
],
|
|
67
88
|
"author": "kollors",
|
|
68
89
|
"license": "MIT",
|
package/dist/src/cli.d.ts
DELETED