@kollors/deep-json-server 0.3.2 → 0.5.0
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 +206 -37
- package/README.ru.md +206 -37
- package/bin/deep-json-server.js +11 -0
- package/index.js +1 -11
- package/package.json +22 -5
- package/src/cli.js +67 -51
- package/src/config.js +97 -0
- package/src/constants.js +5 -0
- package/src/database.js +128 -0
- package/src/files.js +278 -0
- package/src/openapi/config.js +110 -0
- package/src/openapi/document.js +331 -0
- package/src/openapi/index.js +25 -0
- package/src/openapi/inference.js +187 -0
- package/src/{query.js → query/filter.js} +23 -113
- package/src/query/index.js +3 -0
- package/src/query/pagination.js +50 -0
- package/src/query/sort.js +63 -0
- package/src/relation-metadata.js +40 -0
- package/src/relations.js +62 -24
- package/src/server.js +132 -101
- package/src/utils.js +7 -18
- package/types/index.d.ts +2 -0
- package/types/src/constants.d.ts +5 -0
- package/types/src/database.d.ts +8 -0
- package/types/src/files.d.ts +5 -0
- package/types/src/openapi/config.d.ts +3 -0
- package/types/src/openapi/document.d.ts +12 -0
- package/types/src/openapi/index.d.ts +14 -0
- package/types/src/openapi/inference.d.ts +9 -0
- package/types/src/query/filter.d.ts +3 -0
- package/types/src/query/index.d.ts +3 -0
- package/types/src/query/pagination.d.ts +13 -0
- package/types/src/query/sort.d.ts +1 -0
- package/types/src/relation-metadata.d.ts +9 -0
- package/types/src/relations.d.ts +3 -0
- package/types/src/server.d.ts +30 -0
- package/types/src/utils.d.ts +10 -0
- package/src/openapi.js +0 -520
package/src/server.js
CHANGED
|
@@ -1,27 +1,19 @@
|
|
|
1
1
|
import Fastify from 'fastify';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { DEFAULT_HOST, DEFAULT_MAX_FILE_SIZE, DEFAULT_PORT, MAX_PAGE_SIZE } from './constants.js';
|
|
3
|
+
import { createDatabaseStore, createId, findItem, getCollection } from './database.js';
|
|
4
|
+
import { registerFileRoutes } from './files.js';
|
|
5
|
+
import { readSchemaConfig } from './openapi/config.js';
|
|
6
|
+
import { createOpenApiDocument } from './openapi/index.js';
|
|
7
|
+
import { matchesWhere, paginateItems, parsePagination, parseWhere, sortItems, validateWhere } from './query/index.js';
|
|
8
|
+
import { embedItem, parseEmbedPaths, validateEmbedPaths } from './relations.js';
|
|
9
|
+
import { createHttpError, getResourceNames, isObject, resolveDatabasePath } from './utils.js';
|
|
8
10
|
|
|
9
11
|
const CORS_HEADERS = {
|
|
10
|
-
'Access-Control-Allow-Headers': 'Content-Type',
|
|
12
|
+
'Access-Control-Allow-Headers': 'Content-Name, Content-Type',
|
|
11
13
|
'Access-Control-Allow-Methods': 'DELETE, GET, OPTIONS, PATCH, POST, PUT',
|
|
12
14
|
'Access-Control-Allow-Origin': '*',
|
|
13
15
|
};
|
|
14
16
|
|
|
15
|
-
const getCollection = (database, resource) => {
|
|
16
|
-
const collection = isSafeKey(resource) ? database.data[resource] : undefined;
|
|
17
|
-
|
|
18
|
-
if (!Array.isArray(collection)) {
|
|
19
|
-
throw createHttpError(404, 'Ресурс не найден');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return collection;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
17
|
const getRequestBody = (body) => {
|
|
26
18
|
if (!isObject(body)) {
|
|
27
19
|
throw createHttpError(400, 'Тело запроса должно быть JSON-объектом');
|
|
@@ -30,97 +22,66 @@ const getRequestBody = (body) => {
|
|
|
30
22
|
return body;
|
|
31
23
|
};
|
|
32
24
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
const readDatabaseFile = async(databasePath) => {
|
|
36
|
-
let source;
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
source = await readFile(databasePath, 'utf8');
|
|
40
|
-
} catch (error) {
|
|
41
|
-
if (error?.code === 'ENOENT') {
|
|
42
|
-
throw new Error(`Файл базы данных не найден: ${databasePath}`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
throw error;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const data = JSON.parse(source);
|
|
49
|
-
|
|
50
|
-
return validateDatabase(data);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export async function createServer({ databasePath, logger = true } = {}) {
|
|
54
|
-
const resolvedDatabasePath = resolveDatabasePath(databasePath);
|
|
55
|
-
const initialData = await readDatabaseFile(resolvedDatabasePath);
|
|
56
|
-
const database = await JSONFilePreset(resolvedDatabasePath, initialData);
|
|
57
|
-
const server = Fastify({ logger });
|
|
58
|
-
let databaseWriteQueue = Promise.resolve();
|
|
59
|
-
|
|
60
|
-
const readDatabase = async() => {
|
|
61
|
-
database.data = await readDatabaseFile(resolvedDatabasePath);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const updateDatabase = (update) => {
|
|
65
|
-
const operation = databaseWriteQueue.then(async() => {
|
|
66
|
-
await readDatabase();
|
|
67
|
-
|
|
68
|
-
const result = update();
|
|
69
|
-
|
|
70
|
-
await database.write();
|
|
71
|
-
|
|
72
|
-
return result;
|
|
73
|
-
});
|
|
25
|
+
const getSchemaName = (reference) => reference.split('/').at(-1);
|
|
74
26
|
|
|
75
|
-
|
|
27
|
+
const addRequestSchemas = (server, document, resources) => {
|
|
28
|
+
const requestSchemaNames = new Set(
|
|
29
|
+
resources.flatMap((resource) => {
|
|
30
|
+
const resourcePath = document.paths[`/${resource}`];
|
|
31
|
+
const itemPath = document.paths[`/${resource}/{id}`];
|
|
76
32
|
|
|
77
|
-
|
|
78
|
-
|
|
33
|
+
return [getSchemaName(resourcePath.post.requestBody.content['application/json'].schema.$ref), getSchemaName(itemPath.patch.requestBody.content['application/json'].schema.$ref)];
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
79
36
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
server.addHook('preHandler', async(request) => {
|
|
85
|
-
if (request.method === 'GET') {
|
|
86
|
-
await readDatabase();
|
|
87
|
-
}
|
|
37
|
+
requestSchemaNames.forEach((schemaName) => {
|
|
38
|
+
server.addSchema({ $id: schemaName, ...document.components.schemas[schemaName] });
|
|
88
39
|
});
|
|
40
|
+
};
|
|
89
41
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
42
|
+
const registerResourceRoutes = (server, store, resource, document, maxPageSize) => {
|
|
43
|
+
const resourcePath = `/${resource}`;
|
|
44
|
+
const itemPath = `/${resource}/:id`;
|
|
45
|
+
const createSchemaName = getSchemaName(document.paths[resourcePath].post.requestBody.content['application/json'].schema.$ref);
|
|
46
|
+
const updateSchemaName = getSchemaName(document.paths[`/${resource}/{id}`].patch.requestBody.content['application/json'].schema.$ref);
|
|
93
47
|
|
|
94
|
-
server.get(
|
|
95
|
-
const collection = getCollection(database,
|
|
48
|
+
server.get(resourcePath, async (request) => {
|
|
49
|
+
const collection = getCollection(store.database, resource);
|
|
96
50
|
const where = parseWhere(request.query);
|
|
97
51
|
const embedPaths = parseEmbedPaths(request.query._embed);
|
|
52
|
+
const pagination = parsePagination(request.query, maxPageSize);
|
|
53
|
+
|
|
54
|
+
validateEmbedPaths(store.database, resource, collection, embedPaths);
|
|
55
|
+
|
|
98
56
|
const relationIndexes = new Map();
|
|
99
|
-
const embeddedItems = collection.map((item) => embedItem(database, item,
|
|
100
|
-
const pagination = parsePagination(request.query);
|
|
57
|
+
const embeddedItems = collection.map((item) => embedItem(store.database, item, resource, embedPaths, relationIndexes));
|
|
101
58
|
|
|
102
59
|
validateWhere(where, embeddedItems);
|
|
103
60
|
|
|
104
61
|
const filteredItems = embeddedItems.filter((item) => matchesWhere(item, where));
|
|
105
|
-
const sortedItems = sortItems(filteredItems, request.query._sort);
|
|
62
|
+
const sortedItems = sortItems(filteredItems, request.query._sort, embeddedItems);
|
|
106
63
|
|
|
107
64
|
return paginateItems(sortedItems, pagination.page, pagination.pageSize);
|
|
108
65
|
});
|
|
109
66
|
|
|
110
|
-
server.get(
|
|
111
|
-
const
|
|
67
|
+
server.get(itemPath, async (request) => {
|
|
68
|
+
const collection = getCollection(store.database, resource);
|
|
69
|
+
const item = findItem(collection, request.params.id);
|
|
70
|
+
const embedPaths = parseEmbedPaths(request.query._embed);
|
|
112
71
|
|
|
113
72
|
if (item == null) {
|
|
114
73
|
throw createHttpError(404, 'Запись не найдена');
|
|
115
74
|
}
|
|
116
75
|
|
|
117
|
-
|
|
76
|
+
validateEmbedPaths(store.database, resource, collection, embedPaths);
|
|
77
|
+
|
|
78
|
+
return embedItem(store.database, item, resource, embedPaths);
|
|
118
79
|
});
|
|
119
80
|
|
|
120
|
-
server.post(
|
|
121
|
-
const item = await
|
|
122
|
-
const collection = getCollection(database,
|
|
123
|
-
const createdItem = { ...getRequestBody(request.body), id:
|
|
81
|
+
server.post(resourcePath, { schema: { body: { $ref: `${createSchemaName}#` } } }, async (request, reply) => {
|
|
82
|
+
const item = await store.update((database) => {
|
|
83
|
+
const collection = getCollection(database, resource);
|
|
84
|
+
const createdItem = { ...getRequestBody(request.body), id: createId(collection) };
|
|
124
85
|
|
|
125
86
|
collection.push(createdItem);
|
|
126
87
|
|
|
@@ -130,9 +91,9 @@ export async function createServer({ databasePath, logger = true } = {}) {
|
|
|
130
91
|
return reply.code(201).send(item);
|
|
131
92
|
});
|
|
132
93
|
|
|
133
|
-
server.put(
|
|
134
|
-
|
|
135
|
-
const collection = getCollection(database,
|
|
94
|
+
server.put(itemPath, { schema: { body: { $ref: `${createSchemaName}#` } } }, async (request) =>
|
|
95
|
+
store.update((database) => {
|
|
96
|
+
const collection = getCollection(database, resource);
|
|
136
97
|
const currentItem = findItem(collection, request.params.id);
|
|
137
98
|
|
|
138
99
|
if (currentItem == null) {
|
|
@@ -144,12 +105,12 @@ export async function createServer({ databasePath, logger = true } = {}) {
|
|
|
144
105
|
collection.splice(collection.indexOf(currentItem), 1, item);
|
|
145
106
|
|
|
146
107
|
return item;
|
|
147
|
-
})
|
|
148
|
-
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
149
110
|
|
|
150
|
-
server.patch(
|
|
151
|
-
|
|
152
|
-
const collection = getCollection(database,
|
|
111
|
+
server.patch(itemPath, { schema: { body: { $ref: `${updateSchemaName}#` } } }, async (request) =>
|
|
112
|
+
store.update((database) => {
|
|
113
|
+
const collection = getCollection(database, resource);
|
|
153
114
|
const currentItem = findItem(collection, request.params.id);
|
|
154
115
|
|
|
155
116
|
if (currentItem == null) {
|
|
@@ -161,12 +122,12 @@ export async function createServer({ databasePath, logger = true } = {}) {
|
|
|
161
122
|
collection.splice(collection.indexOf(currentItem), 1, item);
|
|
162
123
|
|
|
163
124
|
return item;
|
|
164
|
-
})
|
|
165
|
-
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
166
127
|
|
|
167
|
-
server.delete(
|
|
168
|
-
|
|
169
|
-
const collection = getCollection(database,
|
|
128
|
+
server.delete(itemPath, async (request) =>
|
|
129
|
+
store.update((database) => {
|
|
130
|
+
const collection = getCollection(database, resource);
|
|
170
131
|
const currentItem = findItem(collection, request.params.id);
|
|
171
132
|
|
|
172
133
|
if (currentItem == null) {
|
|
@@ -176,9 +137,62 @@ export async function createServer({ databasePath, logger = true } = {}) {
|
|
|
176
137
|
collection.splice(collection.indexOf(currentItem), 1);
|
|
177
138
|
|
|
178
139
|
return currentItem;
|
|
140
|
+
}),
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Creates a Fastify server without opening a network port.
|
|
146
|
+
* @param {{ databasePath: string, filesDirectoryPath?: string, filesMetadataPath?: string, logger?: boolean | Record<string, unknown>, maxFileSize?: number, maxPageSize?: number, schemaPath?: string }} options Server options.
|
|
147
|
+
* @returns {Promise<import('fastify').FastifyInstance>} Fastify server.
|
|
148
|
+
*/
|
|
149
|
+
export async function createServer(options) {
|
|
150
|
+
const { databasePath, filesDirectoryPath, filesMetadataPath, logger = true, maxFileSize = DEFAULT_MAX_FILE_SIZE, maxPageSize = MAX_PAGE_SIZE, schemaPath } = options ?? {};
|
|
151
|
+
|
|
152
|
+
if (!Number.isInteger(maxPageSize) || maxPageSize < 1) {
|
|
153
|
+
throw new Error('Максимальный размер страницы должен быть положительным целым числом');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!Number.isInteger(maxFileSize) || maxFileSize < 1) {
|
|
157
|
+
throw new Error('Максимальный размер файла должен быть положительным целым числом');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const store = await createDatabaseStore(databasePath);
|
|
161
|
+
const schemaConfig = await readSchemaConfig(schemaPath);
|
|
162
|
+
const document = createOpenApiDocument(store.database.data, schemaConfig);
|
|
163
|
+
const resources = getResourceNames(store.database.data);
|
|
164
|
+
const server = Fastify({ logger });
|
|
165
|
+
|
|
166
|
+
addRequestSchemas(server, document, resources);
|
|
167
|
+
|
|
168
|
+
server.addHook('onRequest', async (_request, reply) => {
|
|
169
|
+
Object.entries(CORS_HEADERS).forEach(([header, value]) => {
|
|
170
|
+
reply.header(header, value);
|
|
179
171
|
});
|
|
180
172
|
});
|
|
181
173
|
|
|
174
|
+
server.addHook('preHandler', async (request) => {
|
|
175
|
+
if (request.method === 'GET') {
|
|
176
|
+
await store.read();
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
server.options('/', async (_request, reply) => reply.code(204).send());
|
|
181
|
+
server.options('/*', async (_request, reply) => reply.code(204).send());
|
|
182
|
+
server.get('/', async () => ({ resources }));
|
|
183
|
+
|
|
184
|
+
resources.forEach((resource) => {
|
|
185
|
+
registerResourceRoutes(server, store, resource, document, maxPageSize);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if ((filesDirectoryPath == null) !== (filesMetadataPath == null)) {
|
|
189
|
+
throw new Error('Для файловых маршрутов укажите filesDirectoryPath и filesMetadataPath');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (filesDirectoryPath != null) {
|
|
193
|
+
await registerFileRoutes(server, { directoryPath: filesDirectoryPath, maxFileSize, metadataPath: filesMetadataPath });
|
|
194
|
+
}
|
|
195
|
+
|
|
182
196
|
server.setErrorHandler((error, request, reply) => {
|
|
183
197
|
const statusCode = Number.isInteger(error.statusCode) ? error.statusCode : 500;
|
|
184
198
|
|
|
@@ -192,13 +206,30 @@ export async function createServer({ databasePath, logger = true } = {}) {
|
|
|
192
206
|
return server;
|
|
193
207
|
}
|
|
194
208
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Creates and starts a Fastify server.
|
|
211
|
+
* @param {{ databasePath: string, filesDirectoryPath?: string, filesMetadataPath?: string, host?: string, logger?: boolean | Record<string, unknown>, maxFileSize?: number, maxPageSize?: number, port?: number, schemaPath?: string }} options Server options.
|
|
212
|
+
* @returns {Promise<import('fastify').FastifyInstance>} Listening Fastify server.
|
|
213
|
+
*/
|
|
214
|
+
export async function startServer(options) {
|
|
215
|
+
const {
|
|
216
|
+
databasePath,
|
|
217
|
+
filesDirectoryPath,
|
|
218
|
+
filesMetadataPath,
|
|
219
|
+
host = DEFAULT_HOST,
|
|
220
|
+
logger = true,
|
|
221
|
+
maxFileSize = DEFAULT_MAX_FILE_SIZE,
|
|
222
|
+
maxPageSize = MAX_PAGE_SIZE,
|
|
223
|
+
port = DEFAULT_PORT,
|
|
224
|
+
schemaPath,
|
|
225
|
+
} = options ?? {};
|
|
226
|
+
|
|
227
|
+
if (!Number.isInteger(port) || port < 0 || port > 65_535) {
|
|
228
|
+
throw new Error('Порт должен быть целым числом от 0 до 65535');
|
|
198
229
|
}
|
|
199
230
|
|
|
200
231
|
const resolvedDatabasePath = resolveDatabasePath(databasePath);
|
|
201
|
-
const server = await createServer({ databasePath: resolvedDatabasePath, logger });
|
|
232
|
+
const server = await createServer({ databasePath: resolvedDatabasePath, filesDirectoryPath, filesMetadataPath, logger, maxFileSize, maxPageSize, schemaPath });
|
|
202
233
|
|
|
203
234
|
await server.listen({ host, port });
|
|
204
235
|
server.log.info({ database: resolvedDatabasePath }, 'Deep JSON Server запущен');
|
package/src/utils.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { realpathSync } from 'node:fs';
|
|
2
1
|
import { resolve } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
2
|
import pluralize from 'pluralize';
|
|
5
3
|
|
|
6
4
|
const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
@@ -14,25 +12,10 @@ export const createHttpError = (statusCode, message) => {
|
|
|
14
12
|
};
|
|
15
13
|
|
|
16
14
|
export const getResourceNames = (data) => Object.keys(data);
|
|
17
|
-
export const isMainModule = (filePath, moduleUrl) => filePath != null && realpathSync(resolve(filePath)) === fileURLToPath(moduleUrl);
|
|
18
15
|
export const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
19
16
|
export const isSafeKey = (key) => !UNSAFE_KEYS.has(key);
|
|
20
17
|
export const toArray = (value) => (Array.isArray(value) ? value : [value]);
|
|
21
18
|
|
|
22
|
-
export const validateDatabase = (data) => {
|
|
23
|
-
if (!isObject(data)) {
|
|
24
|
-
throw new Error('База данных должна содержать JSON-объект');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const invalidResource = Object.entries(data).find(([, value]) => !Array.isArray(value));
|
|
28
|
-
|
|
29
|
-
if (invalidResource != null) {
|
|
30
|
-
throw new Error(`Ресурс «${invalidResource[0]}» должен содержать JSON-массив`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return data;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
19
|
export const isEqual = (left, right) => {
|
|
37
20
|
if (Object.is(left, right)) {
|
|
38
21
|
return true;
|
|
@@ -60,6 +43,12 @@ export const resolveDatabasePath = (databasePath) => {
|
|
|
60
43
|
return resolve(databasePath);
|
|
61
44
|
};
|
|
62
45
|
|
|
46
|
+
export const isIdEqual = (left, right) => left != null && right != null && String(left) === String(right);
|
|
63
47
|
export const singularize = (value) => pluralize.singular(value);
|
|
64
48
|
|
|
65
|
-
export const toPascalCase = (value) =>
|
|
49
|
+
export const toPascalCase = (value) =>
|
|
50
|
+
value
|
|
51
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
52
|
+
.filter(Boolean)
|
|
53
|
+
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
54
|
+
.join('');
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const validateDatabase: (data: any) => any;
|
|
2
|
+
export declare const readJsonObject: (path: any, label: any) => Promise<any>;
|
|
3
|
+
export declare const readDatabaseFile: (databasePath: any) => Promise<any>;
|
|
4
|
+
/** @returns {Promise<any>} Internal LowDB-backed store. */
|
|
5
|
+
export declare const createDatabaseStore: (databasePath: any) => Promise<any>;
|
|
6
|
+
export declare const getCollection: (database: any, resource: any) => any[];
|
|
7
|
+
export declare const findItem: (collection: any, id: any) => any;
|
|
8
|
+
export declare const createId: (collection: any) => any;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates an OpenAPI 3.0 document from a database and optional schema configuration.
|
|
3
|
+
* @param {Record<string, Array<Record<string, unknown>>>} database Database contents.
|
|
4
|
+
* @param {Record<string, unknown>} [schemaConfig] Schema configuration.
|
|
5
|
+
* @param {{ files?: boolean, host?: string, port?: number }} [serverOptions] Server address and optional features used in the generated document.
|
|
6
|
+
* @returns {Record<string, unknown>} OpenAPI document.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createOpenApiDocument(database: Record<string, Array<Record<string, unknown>>>, schemaConfig?: Record<string, unknown>, { files, host, port }?: {
|
|
9
|
+
files?: boolean;
|
|
10
|
+
host?: string;
|
|
11
|
+
port?: number;
|
|
12
|
+
}): Record<string, unknown>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { createOpenApiDocument } from './document.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates an OpenAPI YAML file.
|
|
4
|
+
* @param {{ databasePath: string, files?: boolean, host?: string, outputPath: string, port?: number, schemaPath?: string }} options Generation options.
|
|
5
|
+
* @returns {Promise<Record<string, unknown>>} Generated OpenAPI document.
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateOpenApi({ databasePath, files, host, outputPath, port, schemaPath }: {
|
|
8
|
+
databasePath: string;
|
|
9
|
+
files?: boolean;
|
|
10
|
+
host?: string;
|
|
11
|
+
outputPath: string;
|
|
12
|
+
port?: number;
|
|
13
|
+
schemaPath?: string;
|
|
14
|
+
}): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const mergeSchemas: (schemas: any) => any;
|
|
2
|
+
export declare const mergeSchemaOverrides: (schema: any, overrides: any) => any;
|
|
3
|
+
export declare const applyRequiredFields: (schema: any, path: any, requiredFields: any) => any;
|
|
4
|
+
export declare const inferSchema: (values: any) => any;
|
|
5
|
+
export declare function inferObjectSchema(values: any): any;
|
|
6
|
+
export declare const ensureGeneratedIdSchema: (schema: any) => any;
|
|
7
|
+
export declare const getSchemasAtPath: (schema: any, keys: any) => any;
|
|
8
|
+
export declare const updateSchemasAtPath: (schema: any, keys: any, update: any) => any;
|
|
9
|
+
export declare const omitId: (schema: any, keepRequired: any) => any;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const parsePagination: (query: any, maxPageSize?: number) => {
|
|
2
|
+
page: any;
|
|
3
|
+
pageSize: any;
|
|
4
|
+
};
|
|
5
|
+
export declare const paginateItems: (items: any, page: any, pageSize: any) => {
|
|
6
|
+
data: any;
|
|
7
|
+
first: number;
|
|
8
|
+
items: any;
|
|
9
|
+
last: number;
|
|
10
|
+
next: any;
|
|
11
|
+
pages: number;
|
|
12
|
+
prev: number | null;
|
|
13
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sortItems: (items: any, sort: any, validationItems?: any) => any[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const getRelationKeys: (...names: any[]) => string[];
|
|
2
|
+
export declare const resolveRelationResource: (resourceNames: any, relation: any, sourceResource: any) => any;
|
|
3
|
+
export declare const getRelationMetadata: (key: any, resourceNames: any, sourceResource: any) => {
|
|
4
|
+
isMany: boolean;
|
|
5
|
+
relationName: any;
|
|
6
|
+
reverseRelationName: any;
|
|
7
|
+
sourceResource: any;
|
|
8
|
+
targetResource: any;
|
|
9
|
+
} | undefined;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const parseEmbedPaths: (embed: any) => any[];
|
|
2
|
+
export declare const validateEmbedPaths: (database: any, resource: any, items: any, embedPaths: any) => void;
|
|
3
|
+
export declare const embedItem: (database: any, item: any, resource: any, embedPaths: any, indexes?: Map<any, any>) => any;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a Fastify server without opening a network port.
|
|
3
|
+
* @param {{ databasePath: string, filesDirectoryPath?: string, filesMetadataPath?: string, logger?: boolean | Record<string, unknown>, maxFileSize?: number, maxPageSize?: number, schemaPath?: string }} options Server options.
|
|
4
|
+
* @returns {Promise<import('fastify').FastifyInstance>} Fastify server.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createServer(options: {
|
|
7
|
+
databasePath: string;
|
|
8
|
+
filesDirectoryPath?: string;
|
|
9
|
+
filesMetadataPath?: string;
|
|
10
|
+
logger?: boolean | Record<string, unknown>;
|
|
11
|
+
maxFileSize?: number;
|
|
12
|
+
maxPageSize?: number;
|
|
13
|
+
schemaPath?: string;
|
|
14
|
+
}): Promise<import('fastify').FastifyInstance>;
|
|
15
|
+
/**
|
|
16
|
+
* Creates and starts a Fastify server.
|
|
17
|
+
* @param {{ databasePath: string, filesDirectoryPath?: string, filesMetadataPath?: string, host?: string, logger?: boolean | Record<string, unknown>, maxFileSize?: number, maxPageSize?: number, port?: number, schemaPath?: string }} options Server options.
|
|
18
|
+
* @returns {Promise<import('fastify').FastifyInstance>} Listening Fastify server.
|
|
19
|
+
*/
|
|
20
|
+
export declare function startServer(options: {
|
|
21
|
+
databasePath: string;
|
|
22
|
+
filesDirectoryPath?: string;
|
|
23
|
+
filesMetadataPath?: string;
|
|
24
|
+
host?: string;
|
|
25
|
+
logger?: boolean | Record<string, unknown>;
|
|
26
|
+
maxFileSize?: number;
|
|
27
|
+
maxPageSize?: number;
|
|
28
|
+
port?: number;
|
|
29
|
+
schemaPath?: string;
|
|
30
|
+
}): Promise<import('fastify').FastifyInstance>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const createHttpError: (statusCode: any, message: any) => Error;
|
|
2
|
+
export declare const getResourceNames: (data: any) => string[];
|
|
3
|
+
export declare const isObject: (value: any) => boolean;
|
|
4
|
+
export declare const isSafeKey: (key: any) => boolean;
|
|
5
|
+
export declare const toArray: (value: any) => any[];
|
|
6
|
+
export declare const isEqual: (left: any, right: any) => any;
|
|
7
|
+
export declare const resolveDatabasePath: (databasePath: any) => any;
|
|
8
|
+
export declare const isIdEqual: (left: any, right: any) => boolean;
|
|
9
|
+
export declare const singularize: (value: any) => any;
|
|
10
|
+
export declare const toPascalCase: (value: any) => any;
|