@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/src/server.js CHANGED
@@ -1,27 +1,19 @@
1
1
  import Fastify from 'fastify';
2
- import { JSONFilePreset } from 'lowdb/node';
3
- import { randomBytes } from 'node:crypto';
4
- import { readFile } from 'node:fs/promises';
5
- import { matchesWhere, paginateItems, parsePagination, parseWhere, sortItems, validateWhere } from './query.js';
6
- import { embedItem, parseEmbedPaths } from './relations.js';
7
- import { createHttpError, getResourceNames, isObject, isSafeKey, resolveDatabasePath, validateDatabase } from './utils.js';
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 findItem = (collection, id) => collection.find((item) => isObject(item) && String(item.id) === id);
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
- databaseWriteQueue = operation.catch(() => undefined);
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
- return operation;
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
- server.addHook('onRequest', async(_request, reply) => {
81
- Object.entries(CORS_HEADERS).forEach(([header, value]) => reply.header(header, value));
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
- server.options('/', async(_request, reply) => reply.code(204).send());
91
- server.options('/*', async(_request, reply) => reply.code(204).send());
92
- server.get('/', async() => ({ resources: getResourceNames(database.data) }));
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('/:resource', async(request) => {
95
- const collection = getCollection(database, request.params.resource);
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, request.params.resource, embedPaths, relationIndexes));
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('/:resource/:id', async(request) => {
111
- const item = findItem(getCollection(database, request.params.resource), request.params.id);
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
- return embedItem(database, item, request.params.resource, parseEmbedPaths(request.query._embed));
76
+ validateEmbedPaths(store.database, resource, collection, embedPaths);
77
+
78
+ return embedItem(store.database, item, resource, embedPaths);
118
79
  });
119
80
 
120
- server.post('/:resource', async(request, reply) => {
121
- const item = await updateDatabase(() => {
122
- const collection = getCollection(database, request.params.resource);
123
- const createdItem = { ...getRequestBody(request.body), id: randomBytes(8).toString('base64url') };
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('/:resource/:id', async(request) => {
134
- return updateDatabase(() => {
135
- const collection = getCollection(database, request.params.resource);
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('/:resource/:id', async(request) => {
151
- return updateDatabase(() => {
152
- const collection = getCollection(database, request.params.resource);
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('/:resource/:id', async(request) => {
168
- return updateDatabase(() => {
169
- const collection = getCollection(database, request.params.resource);
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
- export async function startServer({ databasePath, host = '127.0.0.1', logger = true, port = 4001 } = {}) {
196
- if (!Number.isInteger(port) || port < 1 || port > 65_535) {
197
- throw new Error('Порт должен быть целым числом от 1 до 65535');
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) => value.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join('');
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('');
@@ -0,0 +1,2 @@
1
+ export { createOpenApiDocument, generateOpenApi } from './src/openapi/index.js';
2
+ export { createServer, startServer } from './src/server.js';
@@ -0,0 +1,5 @@
1
+ export declare const DEFAULT_HOST = "127.0.0.1";
2
+ export declare const DEFAULT_MAX_FILE_SIZE: number;
3
+ export declare const DEFAULT_PAGE_SIZE = 10;
4
+ export declare const DEFAULT_PORT = 4001;
5
+ export declare const MAX_PAGE_SIZE = 1000;
@@ -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,5 @@
1
+ export declare const registerFileRoutes: (server: any, { directoryPath, maxFileSize, metadataPath }: {
2
+ directoryPath: any;
3
+ maxFileSize: any;
4
+ metadataPath: any;
5
+ }) => Promise<void>;
@@ -0,0 +1,3 @@
1
+ export declare const validateSchemaConfig: (schemaConfig: any, resources: any) => any;
2
+ export declare const applyConfiguredFields: (schema: any, resource: any, resourceConfig: any) => any;
3
+ export declare const readSchemaConfig: (schemaPath: any) => Promise<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,3 @@
1
+ export declare function matchesWhere(value: any, where: any): any;
2
+ export declare const parseWhere: (query: any) => any;
3
+ export declare const validateWhere: (where: any, items: any, path?: string) => void;
@@ -0,0 +1,3 @@
1
+ export { matchesWhere, parseWhere, validateWhere } from './filter.js';
2
+ export { paginateItems, parsePagination } from './pagination.js';
3
+ export { sortItems } from './sort.js';
@@ -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;