@kollors/deep-json-server 1.0.0-alpha.6 → 1.0.0-alpha.8
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 +373 -230
- package/README.ru.md +370 -227
- package/dist/bin/deep-json-server.js +1 -1
- package/dist/bin/deep-json-server.js.map +1 -1
- package/dist/index.d.ts +10 -8
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/src/auth/contract.d.ts +6 -2
- package/dist/src/auth/contract.js +8 -1
- package/dist/src/auth/contract.js.map +1 -1
- 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 +13 -0
- package/dist/src/auth/password.js +17 -1
- package/dist/src/auth/password.js.map +1 -1
- package/dist/src/auth/routes.d.ts +3 -0
- package/dist/src/auth/routes.js +6 -0
- package/dist/src/auth/routes.js.map +1 -1
- package/dist/src/auth/service.d.ts +64 -4
- package/dist/src/auth/service.js +167 -61
- package/dist/src/auth/service.js.map +1 -1
- 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.js → cli/index.js} +31 -15
- 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 -1
- package/dist/src/{constants.js → core/constants.js} +1 -1
- package/dist/src/core/constants.js.map +1 -0
- package/dist/src/core/database.d.ts +53 -0
- package/dist/src/{database.js → core/database.js} +23 -3
- package/dist/src/core/database.js.map +1 -0
- package/dist/src/core/engine.d.ts +65 -0
- package/dist/src/{engine.js → core/engine.js} +114 -59
- package/dist/src/core/engine.js.map +1 -0
- package/dist/src/{errors.d.ts → core/errors.d.ts} +4 -1
- 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 +131 -0
- package/dist/src/{model.js → core/model.js} +106 -10
- package/dist/src/core/model.js.map +1 -0
- package/dist/src/{mutations → core/mutations}/write.d.ts +4 -4
- package/dist/src/{mutations → core/mutations}/write.js +14 -4
- 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/{paths.js → core/paths.js} +16 -0
- package/dist/src/core/paths.js.map +1 -0
- package/dist/src/core/query/contract.d.ts +6 -0
- package/dist/src/{query → core/query}/contract.js +3 -0
- package/dist/src/core/query/contract.js.map +1 -0
- package/dist/src/core/query/filter.d.ts +6 -0
- package/dist/src/{query → core/query}/filter.js +18 -4
- package/dist/src/core/query/filter.js.map +1 -0
- package/dist/src/core/query/options.d.ts +30 -0
- package/dist/src/{query → core/query}/options.js +12 -0
- package/dist/src/core/query/options.js.map +1 -0
- package/dist/src/core/records.d.ts +46 -0
- package/dist/src/{records.js → core/records.js} +24 -3
- 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 -1
- package/dist/src/core/relation-metadata.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 +33 -0
- package/dist/src/files/contract.js +25 -3
- package/dist/src/files/contract.js.map +1 -1
- package/dist/src/files/disk-store.d.ts +3 -0
- package/dist/src/files/disk-store.js +25 -18
- package/dist/src/files/disk-store.js.map +1 -1
- package/dist/src/files/http.d.ts +8 -3
- package/dist/src/files/http.js +9 -0
- package/dist/src/files/http.js.map +1 -1
- package/dist/src/files/index.d.ts +4 -3
- package/dist/src/files/index.js +3 -1
- 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 +21 -15
- 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 +25 -1
- 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 -3
- package/dist/src/graphql/entry.js +12 -2
- package/dist/src/graphql/entry.js.map +1 -1
- package/dist/src/graphql/generate.d.ts +11 -0
- package/dist/src/graphql/generate.js +17 -0
- package/dist/src/graphql/generate.js.map +1 -0
- package/dist/src/graphql/preflight.d.ts +4 -1
- package/dist/src/graphql/preflight.js +3 -0
- package/dist/src/graphql/preflight.js.map +1 -1
- package/dist/src/graphql/resolvers.d.ts +10 -2
- package/dist/src/graphql/resolvers.js +8 -2
- package/dist/src/graphql/resolvers.js.map +1 -1
- package/dist/src/graphql/routes.d.ts +6 -2
- package/dist/src/graphql/routes.js +6 -3
- package/dist/src/graphql/routes.js.map +1 -1
- package/dist/src/graphql/schema.d.ts +6 -0
- package/dist/src/{graphql.js → graphql/schema.js} +20 -14
- package/dist/src/graphql/schema.js.map +1 -0
- package/dist/src/graphql/write.d.ts +3 -0
- package/dist/src/graphql/write.js +3 -0
- package/dist/src/graphql/write.js.map +1 -1
- 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 +5 -2
- package/dist/src/openapi/document.js +41 -42
- package/dist/src/openapi/document.js.map +1 -1
- package/dist/src/openapi/entry.d.ts +14 -3
- package/dist/src/openapi/entry.js +12 -1
- package/dist/src/openapi/entry.js.map +1 -1
- package/dist/src/openapi/files.d.ts +6 -0
- package/dist/src/{files/openapi.js → openapi/files.js} +6 -3
- package/dist/src/openapi/files.js.map +1 -0
- package/dist/src/openapi/generate.d.ts +19 -0
- package/dist/src/openapi/generate.js +39 -0
- package/dist/src/openapi/generate.js.map +1 -0
- package/dist/src/openapi/helpers.d.ts +10 -1
- package/dist/src/openapi/helpers.js +9 -0
- package/dist/src/openapi/helpers.js.map +1 -1
- package/dist/src/openapi/options.d.ts +20 -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} +1 -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 +11 -2
- package/dist/src/rest/options.js +12 -3
- package/dist/src/rest/options.js.map +1 -1
- package/dist/src/rest/projection.d.ts +10 -4
- package/dist/src/rest/projection.js +10 -4
- package/dist/src/rest/projection.js.map +1 -1
- package/dist/src/rest/routes.d.ts +6 -2
- package/dist/src/rest/routes.js +12 -11
- package/dist/src/rest/routes.js.map +1 -1
- package/dist/src/server/config.d.ts +76 -0
- package/dist/src/{config.js → server/config.js} +71 -74
- package/dist/src/server/config.js.map +1 -0
- package/dist/src/server/create.d.ts +18 -0
- package/dist/src/{server.js → server/create.js} +33 -28
- package/dist/src/server/create.js.map +1 -0
- package/dist/src/server/features.d.ts +15 -0
- package/dist/src/{features.js → server/features.js} +8 -2
- package/dist/src/server/features.js.map +1 -0
- package/dist/src/server/public.d.ts +3 -3
- package/dist/src/server/public.js +1 -1
- package/dist/src/server/public.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/auth/openapi.d.ts +0 -10
- package/dist/src/auth/openapi.js +0 -62
- package/dist/src/auth/openapi.js.map +0 -1
- package/dist/src/cli.d.ts +0 -4
- package/dist/src/cli.js.map +0 -1
- package/dist/src/config.d.ts +0 -86
- 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/engine.d.ts +0 -36
- package/dist/src/engine.js.map +0 -1
- package/dist/src/errors.js +0 -9
- package/dist/src/errors.js.map +0 -1
- package/dist/src/features.d.ts +0 -9
- package/dist/src/features.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/public.d.ts +0 -3
- package/dist/src/graphql/public.js +0 -11
- package/dist/src/graphql/public.js.map +0 -1
- package/dist/src/graphql.d.ts +0 -3
- package/dist/src/graphql.js.map +0 -1
- package/dist/src/http/errors.d.ts +0 -6
- package/dist/src/http/errors.js +0 -3
- package/dist/src/http/errors.js.map +0 -1
- package/dist/src/model.d.ts +0 -72
- package/dist/src/model.js.map +0 -1
- package/dist/src/mutations/write.js.map +0 -1
- package/dist/src/openapi/index.d.ts +0 -7
- package/dist/src/openapi/index.js +0 -28
- package/dist/src/openapi/index.js.map +0 -1
- package/dist/src/openapi/public.d.ts +0 -18
- package/dist/src/openapi/public.js +0 -20
- package/dist/src/openapi/public.js.map +0 -1
- package/dist/src/pagination.d.ts +0 -7
- package/dist/src/pagination.js +0 -12
- package/dist/src/pagination.js.map +0 -1
- package/dist/src/paths.d.ts +0 -7
- package/dist/src/paths.js.map +0 -1
- package/dist/src/query/contract.d.ts +0 -3
- package/dist/src/query/contract.js.map +0 -1
- package/dist/src/query/filter.d.ts +0 -3
- package/dist/src/query/filter.js.map +0 -1
- package/dist/src/query/options.d.ts +0 -18
- package/dist/src/query/options.js.map +0 -1
- package/dist/src/records.d.ts +0 -25
- package/dist/src/records.js.map +0 -1
- package/dist/src/relation-metadata.d.ts +0 -9
- package/dist/src/relation-metadata.js.map +0 -1
- package/dist/src/schema.d.ts +0 -8
- package/dist/src/schema.js +0 -13
- package/dist/src/schema.js.map +0 -1
- package/dist/src/server.d.ts +0 -12
- package/dist/src/server.js.map +0 -1
- package/dist/src/utils.d.ts +0 -12
- package/dist/src/utils.js +0 -58
- package/dist/src/utils.js.map +0 -1
- /package/dist/src/{types.js → core/types.js} +0 -0
|
@@ -1,14 +1,22 @@
|
|
|
1
|
+
import { getBoolean, getObject, getPositiveInteger, getString, normalizeAddress } from '../core/config-values.js';
|
|
2
|
+
import { DEFAULT_MAX_FILE_SIZE } from '../core/constants.js';
|
|
3
|
+
import { recordOptions } from '../core/lifecycle/options.js';
|
|
4
|
+
import { errorMessage } from '../core/utils.js';
|
|
5
|
+
import { normalizeOpenapiInfo } from '../openapi/options.js';
|
|
1
6
|
import { dirname, resolve } from 'node:path';
|
|
2
7
|
import { pathToFileURL } from 'node:url';
|
|
3
|
-
import { normalizePagination } from '
|
|
4
|
-
import { assertKnownKeys, isObject } from '
|
|
8
|
+
import { normalizePagination } from '../core/pagination.js';
|
|
9
|
+
import { assertKnownKeys, isObject } from '../core/utils.js';
|
|
5
10
|
const CONFIG_KEYS = new Set(['database', 'files', 'openapi', 'graphql', 'server', 'auth']);
|
|
6
|
-
const DATABASE_KEYS = new Set(['data', 'path', 'schema']);
|
|
11
|
+
const DATABASE_KEYS = new Set(['data', 'path', 'schema', 'timestamps', 'softDelete']);
|
|
7
12
|
const FILES_KEYS = new Set(['data', 'directory', 'metadata']);
|
|
8
13
|
const OPENAPI_KEYS = new Set(['path', 'info', 'enabled', 'endpoint']);
|
|
9
14
|
const GRAPHQL_KEYS = new Set(['path', 'enabled', 'endpoint']);
|
|
10
15
|
const SERVER_KEYS = new Set(['cors', 'host', 'logger', 'maxFileSize', 'maxPageSize', 'pageSize', 'port']);
|
|
11
16
|
let configImportIndex = 0;
|
|
17
|
+
/** Глубоко копирует структурированные данные и оборачивает ошибку неподдерживаемого значения.
|
|
18
|
+
* @example copyInput({ a: [1] }) → независимая копия { a: [1] }; функция в значении → ошибка.
|
|
19
|
+
*/
|
|
12
20
|
const copyInput = (value) => {
|
|
13
21
|
try {
|
|
14
22
|
return structuredClone(value);
|
|
@@ -17,34 +25,13 @@ const copyInput = (value) => {
|
|
|
17
25
|
throw new Error('Input must contain JSON data or binary file content', { cause: error });
|
|
18
26
|
}
|
|
19
27
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
if (!isObject(value)) {
|
|
25
|
-
throw new Error(`Ключ ${path} должен быть JSON-объектом`);
|
|
26
|
-
}
|
|
27
|
-
return value;
|
|
28
|
-
}
|
|
29
|
-
function getString(value, path, required = false) {
|
|
30
|
-
if (value == null && !required) {
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
33
|
-
if (typeof value !== 'string' || value.trim() === '') {
|
|
34
|
-
throw new Error(`Ключ ${path} должен содержать непустую строку`);
|
|
35
|
-
}
|
|
36
|
-
return value;
|
|
37
|
-
}
|
|
28
|
+
/** Делает заданный путь абсолютным относительно указанного каталога.
|
|
29
|
+
* @example resolveConfigPath('a.json', '/tmp') → '/tmp/a.json'; undefined → undefined.
|
|
30
|
+
*/
|
|
38
31
|
const resolveConfigPath = (value, directoryPath) => (value == null ? undefined : resolve(directoryPath, value));
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {
|
|
44
|
-
throw new Error(`Ключ ${path} должен быть положительным целым числом`);
|
|
45
|
-
}
|
|
46
|
-
return value;
|
|
47
|
-
};
|
|
32
|
+
/** Принимает объект описания или разрешает путь к нему относительно каталога.
|
|
33
|
+
* @example normalizeSchema('schema.json', '/tmp') → '/tmp/schema.json'.
|
|
34
|
+
*/
|
|
48
35
|
const normalizeSchema = (schema, directoryPath) => {
|
|
49
36
|
if (schema == null) {
|
|
50
37
|
return undefined;
|
|
@@ -54,6 +41,9 @@ const normalizeSchema = (schema, directoryPath) => {
|
|
|
54
41
|
}
|
|
55
42
|
return getObject(schema, 'config.database.schema', true);
|
|
56
43
|
};
|
|
44
|
+
/** Проверяет выбор между файлом и данными в памяти, разрешает пути и копирует данные.
|
|
45
|
+
* @example { path: 'db.json' } с каталогом /tmp → path: '/tmp/db.json'; одновременно data и path → ошибка.
|
|
46
|
+
*/
|
|
57
47
|
const normalizeDatabase = (value, directoryPath) => {
|
|
58
48
|
const database = getObject(value, 'config.database', true);
|
|
59
49
|
assertKnownKeys(database, DATABASE_KEYS, 'config.database');
|
|
@@ -63,11 +53,19 @@ const normalizeDatabase = (value, directoryPath) => {
|
|
|
63
53
|
throw new Error('Укажите ровно один из ключей config.database.path и config.database.data');
|
|
64
54
|
}
|
|
65
55
|
const schema = normalizeSchema(database.schema, directoryPath);
|
|
56
|
+
recordOptions({ timestamps: database.timestamps, softDelete: database.softDelete });
|
|
57
|
+
const flags = {
|
|
58
|
+
...(database.timestamps !== undefined ? { timestamps: database.timestamps } : {}),
|
|
59
|
+
...(database.softDelete !== undefined ? { softDelete: database.softDelete } : {}),
|
|
60
|
+
};
|
|
66
61
|
if (hasData) {
|
|
67
|
-
return { data: copyInput(getObject(database.data, 'config.database.data', true)), schema };
|
|
62
|
+
return { data: copyInput(getObject(database.data, 'config.database.data', true)), schema, ...flags };
|
|
68
63
|
}
|
|
69
|
-
return { path: resolve(directoryPath, getString(database.path, 'config.database.path', true)), schema };
|
|
64
|
+
return { path: resolve(directoryPath, getString(database.path, 'config.database.path', true)), schema, ...flags };
|
|
70
65
|
};
|
|
66
|
+
/** Проверяет выбор между файлами в памяти и дисковым хранилищем, разрешает пути.
|
|
67
|
+
* @example normalizeFiles(undefined, '/tmp') → undefined; { data: [] } → { data: [] }.
|
|
68
|
+
*/
|
|
71
69
|
const normalizeFiles = (value, directoryPath) => {
|
|
72
70
|
const files = getObject(value, 'config.files');
|
|
73
71
|
if (files == null) {
|
|
@@ -90,24 +88,27 @@ const normalizeFiles = (value, directoryPath) => {
|
|
|
90
88
|
metadata: resolve(directoryPath, getString(files.metadata, 'config.files.metadata', true)),
|
|
91
89
|
};
|
|
92
90
|
};
|
|
91
|
+
/** Проверяет источник учётных записей и срок сессии; массив копирует, путь делает абсолютным.
|
|
92
|
+
* @example { users: 'users.json' } с каталогом /tmp → users: '/tmp/users.json'.
|
|
93
|
+
*/
|
|
93
94
|
const normalizeAuth = (value, directory) => {
|
|
94
95
|
const auth = getObject(value, 'config.auth');
|
|
95
96
|
if (!auth)
|
|
96
97
|
return undefined;
|
|
97
|
-
assertKnownKeys(auth, new Set(['
|
|
98
|
-
if (auth.enabled !== undefined && typeof auth.enabled !== 'boolean')
|
|
99
|
-
throw new Error('config.auth.enabled must be boolean');
|
|
98
|
+
assertKnownKeys(auth, new Set(['users', 'expiresIn']), 'config.auth');
|
|
100
99
|
if (typeof auth.users !== 'string' && !Array.isArray(auth.users))
|
|
101
100
|
throw new Error('config.auth.users must be a file path or user array');
|
|
102
101
|
const expiresIn = getPositiveInteger(auth.expiresIn, 'config.auth.expiresIn');
|
|
103
102
|
if (expiresIn !== undefined && expiresIn > 2147483647)
|
|
104
103
|
throw new Error('config.auth.expiresIn must be at most 2147483647 seconds');
|
|
105
104
|
return {
|
|
106
|
-
enabled: auth.enabled,
|
|
107
105
|
users: typeof auth.users === 'string' ? resolve(directory, getString(auth.users, 'config.auth.users', true)) : copyInput(auth.users),
|
|
108
106
|
expiresIn,
|
|
109
107
|
};
|
|
110
108
|
};
|
|
109
|
+
/** Проверяет секции настроек и возвращает нормализованный объект с абсолютными путями.
|
|
110
|
+
* @example { database: { path: 'db.json' } } с каталогом /tmp → database.path: '/tmp/db.json'.
|
|
111
|
+
*/
|
|
111
112
|
const normalizeConfig = (config, directoryPath = '.') => {
|
|
112
113
|
if (!isObject(config)) {
|
|
113
114
|
throw new Error('Конфигурация сервера должна содержать JSON-объект');
|
|
@@ -120,74 +121,64 @@ const normalizeConfig = (config, directoryPath = '.') => {
|
|
|
120
121
|
const server = getObject(config.server, 'config.server') ?? {};
|
|
121
122
|
assertKnownKeys(openapi, OPENAPI_KEYS, 'config.openapi');
|
|
122
123
|
assertKnownKeys(graphql, GRAPHQL_KEYS, 'config.graphql');
|
|
123
|
-
|
|
124
|
-
throw new Error('config.openapi.enabled must be boolean');
|
|
124
|
+
const openapiEnabled = getBoolean(openapi.enabled, 'config.openapi.enabled') ?? false;
|
|
125
125
|
const openapiEndpoint = getString(openapi.endpoint, 'config.openapi.endpoint');
|
|
126
126
|
if (openapiEndpoint && !/^\/[A-Za-z][A-Za-z0-9_./-]*$/.test(openapiEndpoint))
|
|
127
127
|
throw new Error('Invalid OpenAPI endpoint');
|
|
128
|
-
|
|
129
|
-
throw new Error('config.graphql.enabled must be boolean');
|
|
128
|
+
const graphqlEnabled = getBoolean(graphql.enabled, 'config.graphql.enabled') ?? false;
|
|
130
129
|
const endpoint = getString(graphql.endpoint, 'config.graphql.endpoint');
|
|
131
130
|
if (endpoint && (!/^\/[A-Za-z][A-Za-z0-9_/-]*$/.test(endpoint) || endpoint === '/'))
|
|
132
131
|
throw new Error('Invalid GraphQL endpoint');
|
|
133
|
-
const info =
|
|
134
|
-
if (info && (typeof info.title !== 'string' || typeof info.version !== 'string'))
|
|
135
|
-
throw new Error('OpenAPI info requires title and version');
|
|
132
|
+
const info = normalizeOpenapiInfo(openapi.info);
|
|
136
133
|
assertKnownKeys(server, SERVER_KEYS, 'config.server');
|
|
137
134
|
const openapiPath = getString(openapi.path, 'config.openapi.path');
|
|
138
|
-
const cors = server.cors;
|
|
139
|
-
const host =
|
|
135
|
+
const cors = getBoolean(server.cors ?? undefined, 'config.server.cors') ?? true;
|
|
136
|
+
const { host, port } = normalizeAddress(server);
|
|
140
137
|
const logger = server.logger;
|
|
141
138
|
const maxFileSize = getPositiveInteger(server.maxFileSize, 'config.server.maxFileSize');
|
|
142
|
-
const
|
|
143
|
-
const pageSize = getPositiveInteger(server.pageSize, 'config.server.pageSize');
|
|
144
|
-
normalizePagination({ pageSize, maxPageSize });
|
|
145
|
-
const port = server.port;
|
|
146
|
-
if (port != null && (typeof port !== 'number' || !Number.isInteger(port) || port < 0 || port > 65_535)) {
|
|
147
|
-
throw new Error('Ключ config.server.port должен быть целым числом от 0 до 65535');
|
|
148
|
-
}
|
|
139
|
+
const pagination = normalizePagination(server);
|
|
149
140
|
if (logger != null && typeof logger !== 'boolean' && !isObject(logger)) {
|
|
150
141
|
throw new Error('Ключ config.server.logger должен содержать boolean или JSON-объект');
|
|
151
142
|
}
|
|
152
|
-
if (cors != null && typeof cors !== 'boolean') {
|
|
153
|
-
throw new Error('Ключ config.server.cors должен содержать boolean');
|
|
154
|
-
}
|
|
155
143
|
return {
|
|
156
144
|
database,
|
|
157
145
|
files,
|
|
158
146
|
auth: normalizeAuth(config.auth, directoryPath),
|
|
159
147
|
openapi: {
|
|
160
|
-
enabled:
|
|
161
|
-
endpoint: openapiEndpoint,
|
|
148
|
+
enabled: openapiEnabled,
|
|
149
|
+
endpoint: openapiEndpoint ?? '/openapi.json',
|
|
162
150
|
path: resolveConfigPath(openapiPath, directoryPath),
|
|
163
|
-
...(info && { info
|
|
151
|
+
...(info && { info }),
|
|
164
152
|
},
|
|
165
|
-
graphql: { path: resolveConfigPath(getString(graphql.path, 'config.graphql.path'), directoryPath), enabled:
|
|
153
|
+
graphql: { path: resolveConfigPath(getString(graphql.path, 'config.graphql.path'), directoryPath), enabled: graphqlEnabled, endpoint: endpoint ?? '/graphql' },
|
|
166
154
|
server: {
|
|
167
|
-
cors
|
|
155
|
+
cors,
|
|
168
156
|
host,
|
|
169
|
-
logger: logger,
|
|
170
|
-
maxFileSize,
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
port: port,
|
|
157
|
+
logger: (logger ?? true),
|
|
158
|
+
maxFileSize: maxFileSize ?? DEFAULT_MAX_FILE_SIZE,
|
|
159
|
+
...pagination,
|
|
160
|
+
port,
|
|
174
161
|
},
|
|
175
162
|
};
|
|
176
163
|
};
|
|
177
|
-
/**
|
|
164
|
+
/** Проверяет настройки и разрешает относительные пути, не читая содержимое файлов.
|
|
165
|
+
* @example При directoryPath = '/tmp' путь './db.json' → '/tmp/db.json'.
|
|
166
|
+
*/
|
|
178
167
|
export const normalizeServerConfig = (config, directoryPath) => normalizeConfig(config, directoryPath);
|
|
179
|
-
/**
|
|
168
|
+
/** Загружает default-экспорт ES-модуля, обходя кеш повторного импорта; выполняет код модуля.
|
|
169
|
+
* @example Файл /tmp/config.mjs с export default {} → { config: {}, directory: '/tmp', path: '/tmp/config.mjs' }.
|
|
170
|
+
*/
|
|
180
171
|
export async function readConfigModule(configPath) {
|
|
181
172
|
const resolvedConfigPath = resolve(getString(configPath, 'config', true));
|
|
182
173
|
let config;
|
|
183
174
|
try {
|
|
184
175
|
const configUrl = pathToFileURL(resolvedConfigPath);
|
|
185
|
-
//
|
|
176
|
+
// Обходим кеш модуля, чтобы повторное чтение выполняло обновлённый файл.
|
|
186
177
|
configUrl.searchParams.set('deep-json-server-import', String(configImportIndex++));
|
|
187
178
|
config = (await import(configUrl.href)).default;
|
|
188
179
|
}
|
|
189
180
|
catch (error) {
|
|
190
|
-
const message =
|
|
181
|
+
const message = errorMessage(error);
|
|
191
182
|
throw new Error(`Не удалось загрузить конфигурацию ${resolvedConfigPath}: ${message}`, { cause: error });
|
|
192
183
|
}
|
|
193
184
|
if (!isObject(config)) {
|
|
@@ -196,26 +187,32 @@ export async function readConfigModule(configPath) {
|
|
|
196
187
|
return { config, directory: dirname(resolvedConfigPath), path: resolvedConfigPath };
|
|
197
188
|
}
|
|
198
189
|
const sourcePaths = new WeakMap();
|
|
190
|
+
/** Возвращает сохранённый путь исходного файла для данного объекта настроек.
|
|
191
|
+
* @example Для объекта без зарегистрированного источника → undefined.
|
|
192
|
+
*/
|
|
199
193
|
export const configSourcePath = (config) => sourcePaths.get(config);
|
|
194
|
+
/** Нормализует настройки и запоминает путь их источника во внутренней таблице.
|
|
195
|
+
* @example configure(config, '/tmp', '/tmp/config.mjs') → настройки; configSourcePath(result) → '/tmp/config.mjs'.
|
|
196
|
+
*/
|
|
200
197
|
export function configure(config, directory, sourcePath) {
|
|
201
198
|
const normalized = normalizeConfig(config, directory);
|
|
202
199
|
if (sourcePath)
|
|
203
200
|
sourcePaths.set(normalized, sourcePath);
|
|
204
201
|
return normalized;
|
|
205
202
|
}
|
|
203
|
+
/** Выбирает настройки для указанных форматов экспорта и подставляет пустые данные вместо чтения базы.
|
|
204
|
+
* @example formats = ['graphql'] → настройки генерации GraphQL с database.data = {}.
|
|
205
|
+
*/
|
|
206
206
|
export function configureGeneration(source, formats, directory, sourcePath, overrides) {
|
|
207
207
|
assertKnownKeys(source, CONFIG_KEYS, 'config');
|
|
208
208
|
const database = getObject(source.database, 'config.database', true);
|
|
209
209
|
if (database.schema === undefined)
|
|
210
210
|
throw new Error('Generation requires an explicit model schema');
|
|
211
211
|
const openapi = formats.includes('openapi');
|
|
212
|
-
const auth = openapi ? getObject(source.auth, 'config.auth') : undefined;
|
|
213
|
-
if (auth?.enabled !== undefined && typeof auth.enabled !== 'boolean')
|
|
214
|
-
throw new Error('config.auth.enabled must be boolean');
|
|
215
212
|
const server = openapi ? (getObject(source.server, 'config.server') ?? {}) : {};
|
|
216
213
|
return configure({
|
|
217
|
-
database: { data: {}, schema: database.schema },
|
|
218
|
-
auth:
|
|
214
|
+
database: { data: {}, schema: database.schema, timestamps: overrides.timestamps ?? database.timestamps, softDelete: overrides.softDelete ?? database.softDelete },
|
|
215
|
+
auth: source.auth != null ? { users: [] } : undefined,
|
|
219
216
|
openapi: openapi ? source.openapi : undefined,
|
|
220
217
|
graphql: formats.includes('graphql') ? source.graphql : undefined,
|
|
221
218
|
files: openapi && (overrides.files || source.files != null) ? { data: [] } : undefined,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/server/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { OpenapiDocument } from '../openapi/types.js';
|
|
3
|
+
import { type DeepJsonServerConfig, type NormalizedServerConfig } from './config.js';
|
|
4
|
+
import { type ServerFeatures } from './features.js';
|
|
5
|
+
export interface ServerFacade {
|
|
6
|
+
fastify(): FastifyInstance;
|
|
7
|
+
openapi(): Promise<OpenapiDocument>;
|
|
8
|
+
graphql(): Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
export type { ServerFeatures } from './features.js';
|
|
11
|
+
/** Проверяет настройки и создаёт интерфейс запуска и генерации схем; сетевой порт ещё не открывает.
|
|
12
|
+
* @example await createServer({ database: { data: { notes: [] } } }) → объект с fastify(), openapi(), graphql().
|
|
13
|
+
*/
|
|
14
|
+
export declare function createServer(config: DeepJsonServerConfig, features?: ServerFeatures): Promise<ServerFacade>;
|
|
15
|
+
/** Собирает сервер из нормализованных настроек; хранилища открываются при инициализации HTTP-экземпляра.
|
|
16
|
+
* @example Нормализованные настройки → Promise<ServerFacade>; listen() затем открывает сетевой порт.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createConfiguredServer(normalized: NormalizedServerConfig, features?: ServerFeatures): Promise<ServerFacade>;
|
|
@@ -1,37 +1,41 @@
|
|
|
1
|
-
import { AUTH_PATHS } from '
|
|
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';
|
|
2
6
|
import { configSourcePath, normalizeServerConfig } from './config.js';
|
|
3
|
-
import { DEFAULT_HOST, DEFAULT_MAX_FILE_SIZE, DEFAULT_PORT } from './constants.js';
|
|
4
|
-
import { DomainError } from './errors.js';
|
|
5
7
|
import { resolveFeatures, validateEndpoints } from './features.js';
|
|
6
|
-
import { domainStatus } from './http/errors.js';
|
|
7
|
-
import { normalizePagination } from './pagination.js';
|
|
8
|
-
import { inputPaths } from './paths.js';
|
|
9
|
-
import { isObject } from './utils.js';
|
|
10
8
|
const CORS_HEADERS = {
|
|
11
9
|
'Access-Control-Allow-Headers': 'Content-Type',
|
|
12
10
|
'Access-Control-Allow-Methods': 'DELETE, GET, OPTIONS, PATCH, POST, PUT',
|
|
13
11
|
'Access-Control-Allow-Origin': '*',
|
|
14
12
|
};
|
|
13
|
+
/** Проверяет настройки и создаёт интерфейс запуска и генерации схем; сетевой порт ещё не открывает.
|
|
14
|
+
* @example await createServer({ database: { data: { notes: [] } } }) → объект с fastify(), openapi(), graphql().
|
|
15
|
+
*/
|
|
15
16
|
export async function createServer(config, features = {}) {
|
|
16
17
|
return createConfiguredServer(normalizeServerConfig(config), features);
|
|
17
18
|
}
|
|
19
|
+
/** Собирает сервер из нормализованных настроек; хранилища открываются при инициализации HTTP-экземпляра.
|
|
20
|
+
* @example Нормализованные настройки → Promise<ServerFacade>; listen() затем открывает сетевой порт.
|
|
21
|
+
*/
|
|
18
22
|
export async function createConfiguredServer(normalized, features = {}) {
|
|
19
23
|
const enabled = resolveFeatures(normalized, features);
|
|
20
|
-
const { loadModel, inferModel } = await import('
|
|
21
|
-
const
|
|
24
|
+
const { loadModel, inferModel } = await import('../core/model.js');
|
|
25
|
+
const recordSettings = { timestamps: normalized.database.timestamps, softDelete: normalized.database.softDelete, auth: enabled.auth };
|
|
26
|
+
const explicitModel = await loadModel(normalized.database.schema, recordSettings);
|
|
22
27
|
const { default: Fastify } = await import('fastify');
|
|
23
28
|
const corsHeaders = { ...CORS_HEADERS };
|
|
24
29
|
if (enabled.files) {
|
|
25
|
-
const { FILE_HEADERS } = await import('
|
|
30
|
+
const { FILE_HEADERS } = await import('../files/http.js');
|
|
26
31
|
corsHeaders['Access-Control-Allow-Headers'] = [...Object.values(FILE_HEADERS).map(({ name }) => name), 'Content-Type'].join(', ');
|
|
27
32
|
}
|
|
28
33
|
if (enabled.auth)
|
|
29
34
|
corsHeaders['Access-Control-Allow-Headers'] += ', Authorization';
|
|
30
|
-
const { cors
|
|
31
|
-
const
|
|
32
|
-
const openapi = async () => (await import('./openapi/public.js')).openapiFromModel(explicitModel, {
|
|
35
|
+
const { cors, logger, maxFileSize, pageSize, maxPageSize } = normalized.server;
|
|
36
|
+
const openapi = async () => (await import('../openapi/generate.js')).openapiFromModel(explicitModel, {
|
|
33
37
|
files: enabled.files,
|
|
34
|
-
|
|
38
|
+
...recordSettings,
|
|
35
39
|
pageSize,
|
|
36
40
|
maxPageSize,
|
|
37
41
|
info: normalized.openapi.info,
|
|
@@ -44,7 +48,7 @@ export async function createConfiguredServer(normalized, features = {}) {
|
|
|
44
48
|
return instance;
|
|
45
49
|
const server = Fastify({ ajv: { customOptions: { coerceTypes: false, removeAdditional: false } }, logger });
|
|
46
50
|
const originalListen = server.listen.bind(server);
|
|
47
|
-
const defaults = { host: normalized.server.host
|
|
51
|
+
const defaults = { host: normalized.server.host, port: normalized.server.port };
|
|
48
52
|
const listen = (optionsOrCallback, callback) => {
|
|
49
53
|
if (typeof optionsOrCallback === 'function') {
|
|
50
54
|
originalListen(defaults, optionsOrCallback);
|
|
@@ -62,7 +66,7 @@ export async function createConfiguredServer(normalized, features = {}) {
|
|
|
62
66
|
const status = typeof candidate === 'number' && Number.isInteger(candidate) && candidate >= 400 && candidate <= 599 ? candidate : 500;
|
|
63
67
|
if (status === 500)
|
|
64
68
|
request.log.error(error);
|
|
65
|
-
return reply.code(status).send({ error: status === 500 ? 'Внутренняя ошибка сервера' :
|
|
69
|
+
return reply.code(status).send({ error: status === 500 ? 'Внутренняя ошибка сервера' : errorMessage(error) });
|
|
66
70
|
});
|
|
67
71
|
if (cors) {
|
|
68
72
|
server.addHook('onRequest', async (_request, reply) => {
|
|
@@ -73,25 +77,26 @@ export async function createConfiguredServer(normalized, features = {}) {
|
|
|
73
77
|
server.options('/*', async (_request, reply) => reply.code(204).send());
|
|
74
78
|
}
|
|
75
79
|
server.register(async (app) => {
|
|
76
|
-
const [{ createDatabaseStore }, { Engine }, { registerRestRoutes }] = await Promise.all([import('
|
|
80
|
+
const [{ createDatabaseStore }, { Engine }, { registerRestRoutes }] = await Promise.all([import('../core/database.js'), import('../core/engine.js'), import('../rest/routes.js')]);
|
|
77
81
|
const keys = explicitModel ? new Map(explicitModel.entities.map((e) => [e.collection, e.primary])) : undefined;
|
|
78
82
|
const store = await createDatabaseStore(normalized.database, keys);
|
|
79
|
-
const model = explicitModel ?? inferModel(store.database.data);
|
|
83
|
+
const model = explicitModel ?? inferModel(store.database.data, recordSettings);
|
|
80
84
|
const engine = new Engine(store, model, pageSize, maxPageSize);
|
|
81
85
|
engine.validateData(store.database.data);
|
|
82
|
-
const graphqlPath = normalized.graphql.endpoint
|
|
83
|
-
const openapiPath = normalized.openapi.endpoint
|
|
86
|
+
const graphqlPath = normalized.graphql.endpoint;
|
|
87
|
+
const openapiPath = normalized.openapi.endpoint;
|
|
84
88
|
validateEndpoints(model.entities.map((entity) => entity.collection), [...(enabled.graphql ? [graphqlPath] : []), ...(enabled.openapi ? [openapiPath] : []), ...(enabled.auth ? Object.values(AUTH_PATHS) : [])]);
|
|
85
|
-
const auth = enabled.auth && normalized.auth ? await (await import('
|
|
89
|
+
const auth = enabled.auth && normalized.auth ? await (await import('../auth/service.js')).createAuthService(normalized.auth) : undefined;
|
|
86
90
|
if (auth) {
|
|
87
91
|
app.addHook('onClose', async () => auth.close());
|
|
88
|
-
const { registerAuthRoutes } = await import('
|
|
92
|
+
const { registerAuthRoutes } = await import('../auth/routes.js');
|
|
89
93
|
registerAuthRoutes(app, auth);
|
|
90
94
|
}
|
|
91
|
-
|
|
95
|
+
const authenticate = auth ? (header) => auth.me(header) : undefined;
|
|
96
|
+
registerRestRoutes(app, engine, authenticate);
|
|
92
97
|
if (enabled.graphql) {
|
|
93
|
-
const [{ registerGraphqlRoutes }, { buildGraphql }] = await Promise.all([import('
|
|
94
|
-
registerGraphqlRoutes(app, buildGraphql(model), engine, graphqlPath);
|
|
98
|
+
const [{ registerGraphqlRoutes }, { buildGraphql }] = await Promise.all([import('../graphql/routes.js'), import('../graphql/schema.js')]);
|
|
99
|
+
registerGraphqlRoutes(app, buildGraphql(model), engine, graphqlPath, authenticate);
|
|
95
100
|
}
|
|
96
101
|
if (enabled.openapi) {
|
|
97
102
|
const document = await openapi();
|
|
@@ -100,7 +105,7 @@ export async function createConfiguredServer(normalized, features = {}) {
|
|
|
100
105
|
}
|
|
101
106
|
const files = normalized.files;
|
|
102
107
|
if (enabled.files && files) {
|
|
103
|
-
const { createFileStore, registerFileRoutes } = await import('
|
|
108
|
+
const { createFileStore, registerFileRoutes } = await import('../files/index.js');
|
|
104
109
|
const protectedPaths = inputPaths({ database: normalized.database, auth: normalized.auth }, '.', configSourcePath(normalized));
|
|
105
110
|
registerFileRoutes(app, { getStore: () => createFileStore(files, protectedPaths), maxFileSize });
|
|
106
111
|
}
|
|
@@ -112,8 +117,8 @@ export async function createConfiguredServer(normalized, features = {}) {
|
|
|
112
117
|
fastify: getFastify,
|
|
113
118
|
openapi,
|
|
114
119
|
graphql: async () => {
|
|
115
|
-
return (await import('
|
|
120
|
+
return (await import('../graphql/generate.js')).graphqlFromModel(explicitModel);
|
|
116
121
|
},
|
|
117
122
|
};
|
|
118
123
|
}
|
|
119
|
-
//# sourceMappingURL=
|
|
124
|
+
//# 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,15 @@
|
|
|
1
|
+
import type { NormalizedServerConfig } from './config.js';
|
|
2
|
+
export interface ServerFeatures {
|
|
3
|
+
auth?: boolean;
|
|
4
|
+
files?: boolean;
|
|
5
|
+
graphql?: boolean;
|
|
6
|
+
openapi?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Вычисляет включённые модули с учётом явных переопределений и проверяет обязательные настройки.
|
|
9
|
+
* @example Пустые секции и переопределение { graphql: true } → graphql: true, остальные флаги false.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveFeatures(config: NormalizedServerConfig, features?: ServerFeatures): Required<ServerFeatures>;
|
|
12
|
+
/** Проверяет, что пути не повторяются и не перекрывают коллекции или файловые маршруты.
|
|
13
|
+
* @example validateEndpoints(['users'], ['/users/1']) → ошибка; ['users'], ['/api'] → undefined.
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateEndpoints(collections: string[], endpoints: string[]): void;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { isObject } from '
|
|
1
|
+
import { isObject } from '../core/utils.js';
|
|
2
|
+
/** Вычисляет включённые модули с учётом явных переопределений и проверяет обязательные настройки.
|
|
3
|
+
* @example Пустые секции и переопределение { graphql: true } → graphql: true, остальные флаги false.
|
|
4
|
+
*/
|
|
2
5
|
export function resolveFeatures(config, features = {}) {
|
|
3
6
|
if (!isObject(features) || Object.entries(features).some(([key, value]) => !['files', 'graphql', 'openapi', 'auth'].includes(key) || typeof value !== 'boolean'))
|
|
4
7
|
throw new Error('features supports boolean files, graphql, openapi and auth keys');
|
|
5
8
|
const overrides = features;
|
|
6
9
|
const resolved = {
|
|
7
|
-
auth: overrides.auth ?? config.auth
|
|
10
|
+
auth: overrides.auth ?? config.auth != null,
|
|
8
11
|
files: overrides.files ?? config.files != null,
|
|
9
12
|
graphql: overrides.graphql ?? config.graphql.enabled ?? false,
|
|
10
13
|
openapi: overrides.openapi ?? config.openapi.enabled ?? false,
|
|
@@ -15,6 +18,9 @@ export function resolveFeatures(config, features = {}) {
|
|
|
15
18
|
throw new Error('Для файловых маршрутов укажите секцию config.files');
|
|
16
19
|
return resolved;
|
|
17
20
|
}
|
|
21
|
+
/** Проверяет, что пути не повторяются и не перекрывают коллекции или файловые маршруты.
|
|
22
|
+
* @example validateEndpoints(['users'], ['/users/1']) → ошибка; ['users'], ['/api'] → undefined.
|
|
23
|
+
*/
|
|
18
24
|
export function validateEndpoints(collections, endpoints) {
|
|
19
25
|
if (new Set(endpoints).size !== endpoints.length)
|
|
20
26
|
throw new Error('API endpoints conflict');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features.js","sourceRoot":"","sources":["../../../src/server/features.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAQ5C;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAA8B,EAAE,QAAQ,GAAmB,EAAE;IAC3F,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,KAAK,KAAK,SAAS,CAAC;QAC9J,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,MAAM,SAAS,GAAmB,QAAQ,CAAC;IAC3C,MAAM,QAAQ,GAAG;QACf,IAAI,EAAE,SAAS,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,IAAI;QAC3C,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,IAAI,IAAI;QAC9C,OAAO,EAAE,SAAS,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,KAAK;QAC7D,OAAO,EAAE,SAAS,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,KAAK;KAC9D,CAAC;IACF,IAAI,QAAQ,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACnG,IAAI,QAAQ,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAC3G,OAAO,QAAQ,CAAC;AAClB,CAAC;AACD;;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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { AuthConfig, DatabaseConfig, DeepJsonServerConfig, FilesConfig, GraphqlConfig, MemoryFile, OpenapiConfig, ServerConfig } from '
|
|
2
|
-
export type
|
|
3
|
-
export {
|
|
1
|
+
export type { AuthConfig, DatabaseConfig, DeepJsonServerConfig, FilesConfig, GraphqlConfig, MemoryFile, OpenapiConfig, ServerConfig } from './config.js';
|
|
2
|
+
export { createServer, type ServerFacade } from './create.js';
|
|
3
|
+
export type { ServerFeatures } from './features.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { createServer } from '
|
|
1
|
+
export { createServer } from './create.js';
|
|
2
2
|
//# sourceMappingURL=public.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/server/public.ts"],"names":[],"mappings":"
|
|
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,10 +0,0 @@
|
|
|
1
|
-
import type { OpenapiDocument, OpenapiSchema } from '../types.js';
|
|
2
|
-
export declare const AUTH_SCHEMAS: Record<string, OpenapiSchema>;
|
|
3
|
-
export declare const AUTH_SECURITY_SCHEMES: {
|
|
4
|
-
AuthBearer: {
|
|
5
|
-
type: string;
|
|
6
|
-
scheme: string;
|
|
7
|
-
description: string;
|
|
8
|
-
};
|
|
9
|
-
};
|
|
10
|
-
export declare function authOpenapiPaths(): OpenapiDocument['paths'];
|
package/dist/src/auth/openapi.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { json, ref, response } from '../openapi/helpers.js';
|
|
2
|
-
import { AUTH_PATHS, MAX_PASSWORD_LENGTH, MAX_USERNAME_LENGTH } from './contract.js';
|
|
3
|
-
export const AUTH_SCHEMAS = {
|
|
4
|
-
AuthUser: { type: 'object', additionalProperties: false, required: ['id', 'username'], properties: { id: { type: 'string' }, username: { type: 'string' } } },
|
|
5
|
-
AuthLoginInput: {
|
|
6
|
-
type: 'object',
|
|
7
|
-
additionalProperties: false,
|
|
8
|
-
required: ['username', 'password'],
|
|
9
|
-
properties: {
|
|
10
|
-
username: { type: 'string', minLength: 1, maxLength: MAX_USERNAME_LENGTH },
|
|
11
|
-
password: { type: 'string', format: 'password', writeOnly: true, minLength: 1, maxLength: MAX_PASSWORD_LENGTH },
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
AuthSession: {
|
|
15
|
-
type: 'object',
|
|
16
|
-
additionalProperties: false,
|
|
17
|
-
required: ['accessToken', 'expiresIn', 'user'],
|
|
18
|
-
properties: {
|
|
19
|
-
accessToken: { type: 'string' },
|
|
20
|
-
expiresIn: { type: 'integer', minimum: 1 },
|
|
21
|
-
user: ref('AuthUser'),
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
AuthLogoutResult: { type: 'object', additionalProperties: false, required: ['success'], properties: { success: { type: 'boolean' } } },
|
|
25
|
-
};
|
|
26
|
-
export const AUTH_SECURITY_SCHEMES = { AuthBearer: { type: 'http', scheme: 'bearer', description: 'Session token returned by POST /auth/login. Used only by GET /auth/me and POST /auth/logout.' } };
|
|
27
|
-
export function authOpenapiPaths() {
|
|
28
|
-
const unauthorized = response('Invalid credentials or expired session', ref('Error'));
|
|
29
|
-
return {
|
|
30
|
-
[AUTH_PATHS.login]: {
|
|
31
|
-
post: {
|
|
32
|
-
operationId: 'authLogin',
|
|
33
|
-
tags: ['auth'],
|
|
34
|
-
security: [],
|
|
35
|
-
requestBody: { required: true, ...json(ref('AuthLoginInput')) },
|
|
36
|
-
responses: {
|
|
37
|
-
200: response('Session created', ref('AuthSession')),
|
|
38
|
-
400: response('Invalid input', ref('Error')),
|
|
39
|
-
401: unauthorized,
|
|
40
|
-
429: response('Too many login attempts or sessions', ref('Error')),
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
[AUTH_PATHS.me]: {
|
|
45
|
-
get: {
|
|
46
|
-
operationId: 'authMe',
|
|
47
|
-
tags: ['auth'],
|
|
48
|
-
security: [{ AuthBearer: [] }],
|
|
49
|
-
responses: { 200: response('Current auth user', ref('AuthUser')), 401: unauthorized },
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
[AUTH_PATHS.logout]: {
|
|
53
|
-
post: {
|
|
54
|
-
operationId: 'authLogout',
|
|
55
|
-
tags: ['auth'],
|
|
56
|
-
security: [{ AuthBearer: [] }],
|
|
57
|
-
responses: { 200: response('Session revoked', ref('AuthLogoutResult')), 401: unauthorized },
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
//# sourceMappingURL=openapi.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../../src/auth/openapi.ts"],"names":[],"mappings":"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"}
|