@kollors/deep-json-server 1.0.0-alpha.1 → 1.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/README.md +522 -179
  2. package/README.ru.md +525 -180
  3. package/dist/bin/deep-json-server.js +1 -1
  4. package/dist/bin/deep-json-server.js.map +1 -1
  5. package/dist/index.d.ts +13 -6
  6. package/dist/index.js +4 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/src/auth/contract.d.ts +31 -0
  9. package/dist/src/auth/contract.js +12 -0
  10. package/dist/src/auth/contract.js.map +1 -0
  11. package/dist/src/auth/input.d.ts +18 -0
  12. package/dist/src/auth/input.js +34 -0
  13. package/dist/src/auth/input.js.map +1 -0
  14. package/dist/src/auth/password.d.ts +17 -0
  15. package/dist/src/auth/password.js +41 -0
  16. package/dist/src/auth/password.js.map +1 -0
  17. package/dist/src/auth/public.d.ts +3 -0
  18. package/dist/src/auth/public.js +5 -0
  19. package/dist/src/auth/public.js.map +1 -0
  20. package/dist/src/auth/routes.d.ts +6 -0
  21. package/dist/src/auth/routes.js +18 -0
  22. package/dist/src/auth/routes.js.map +1 -0
  23. package/dist/src/auth/service.d.ts +78 -0
  24. package/dist/src/auth/service.js +218 -0
  25. package/dist/src/auth/service.js.map +1 -0
  26. package/dist/src/auth/store.d.ts +26 -0
  27. package/dist/src/auth/store.js +82 -0
  28. package/dist/src/auth/store.js.map +1 -0
  29. package/dist/src/cli/index.d.ts +7 -0
  30. package/dist/src/cli/index.js +122 -0
  31. package/dist/src/cli/index.js.map +1 -0
  32. package/dist/src/core/config-values.d.ts +28 -0
  33. package/dist/src/core/config-values.js +53 -0
  34. package/dist/src/core/config-values.js.map +1 -0
  35. package/dist/src/{constants.d.ts → core/constants.d.ts} +1 -0
  36. package/dist/src/{constants.js → core/constants.js} +1 -0
  37. package/dist/src/core/constants.js.map +1 -0
  38. package/dist/src/core/database.d.ts +48 -0
  39. package/dist/src/{database.js → core/database.js} +36 -14
  40. package/dist/src/core/database.js.map +1 -0
  41. package/dist/src/core/engine.d.ts +65 -0
  42. package/dist/src/core/engine.js +312 -0
  43. package/dist/src/core/engine.js.map +1 -0
  44. package/dist/src/core/errors.d.ts +9 -0
  45. package/dist/src/core/errors.js +12 -0
  46. package/dist/src/core/errors.js.map +1 -0
  47. package/dist/src/core/http-errors.d.ts +9 -0
  48. package/dist/src/core/http-errors.js +15 -0
  49. package/dist/src/core/http-errors.js.map +1 -0
  50. package/dist/src/core/lifecycle/mutation.d.ts +49 -0
  51. package/dist/src/core/lifecycle/mutation.js +170 -0
  52. package/dist/src/core/lifecycle/mutation.js.map +1 -0
  53. package/dist/src/core/lifecycle/options.d.ts +21 -0
  54. package/dist/src/core/lifecycle/options.js +19 -0
  55. package/dist/src/core/lifecycle/options.js.map +1 -0
  56. package/dist/src/core/model.d.ts +145 -0
  57. package/dist/src/{model.js → core/model.js} +224 -33
  58. package/dist/src/core/model.js.map +1 -0
  59. package/dist/src/core/mutations/write.d.ts +26 -0
  60. package/dist/src/core/mutations/write.js +284 -0
  61. package/dist/src/core/mutations/write.js.map +1 -0
  62. package/dist/src/core/operations.d.ts +33 -0
  63. package/dist/src/core/operations.js +10 -0
  64. package/dist/src/core/operations.js.map +1 -0
  65. package/dist/src/core/pagination.d.ts +10 -0
  66. package/dist/src/core/pagination.js +13 -0
  67. package/dist/src/core/pagination.js.map +1 -0
  68. package/dist/src/core/paths.d.ts +16 -0
  69. package/dist/src/core/paths.js +64 -0
  70. package/dist/src/core/paths.js.map +1 -0
  71. package/dist/src/core/query/contract.d.ts +6 -0
  72. package/dist/src/core/query/contract.js +22 -0
  73. package/dist/src/core/query/contract.js.map +1 -0
  74. package/dist/src/core/query/filter.d.ts +6 -0
  75. package/dist/src/core/query/filter.js +100 -0
  76. package/dist/src/core/query/filter.js.map +1 -0
  77. package/dist/src/core/query/options.d.ts +30 -0
  78. package/dist/src/core/query/options.js +44 -0
  79. package/dist/src/core/query/options.js.map +1 -0
  80. package/dist/src/core/records.d.ts +46 -0
  81. package/dist/src/core/records.js +69 -0
  82. package/dist/src/core/records.js.map +1 -0
  83. package/dist/src/core/relation-metadata.d.ts +15 -0
  84. package/dist/src/{relation-metadata.js → core/relation-metadata.js} +7 -2
  85. package/dist/src/core/relation-metadata.js.map +1 -0
  86. package/dist/src/core/storage.d.ts +2 -0
  87. package/dist/src/core/storage.js +2 -0
  88. package/dist/src/core/storage.js.map +1 -0
  89. package/dist/src/core/types.d.ts +10 -0
  90. package/dist/src/{types.js.map → core/types.js.map} +1 -1
  91. package/dist/src/core/utils.d.ts +56 -0
  92. package/dist/src/core/utils.js +102 -0
  93. package/dist/src/core/utils.js.map +1 -0
  94. package/dist/src/files/contract.d.ts +32 -30
  95. package/dist/src/files/contract.js +29 -48
  96. package/dist/src/files/contract.js.map +1 -1
  97. package/dist/src/files/disk-store.d.ts +5 -1
  98. package/dist/src/files/disk-store.js +49 -32
  99. package/dist/src/files/disk-store.js.map +1 -1
  100. package/dist/src/files/http.d.ts +36 -0
  101. package/dist/src/files/http.js +53 -0
  102. package/dist/src/files/http.js.map +1 -0
  103. package/dist/src/files/index.d.ts +5 -4
  104. package/dist/src/files/index.js +7 -2
  105. package/dist/src/files/index.js.map +1 -1
  106. package/dist/src/files/memory-store.d.ts +4 -1
  107. package/dist/src/files/memory-store.js +29 -22
  108. package/dist/src/files/memory-store.js.map +1 -1
  109. package/dist/src/files/routes.d.ts +3 -0
  110. package/dist/src/files/routes.js +27 -2
  111. package/dist/src/files/routes.js.map +1 -1
  112. package/dist/src/files/streams.d.ts +5 -0
  113. package/dist/src/files/streams.js +20 -0
  114. package/dist/src/files/streams.js.map +1 -0
  115. package/dist/src/graphql/entry.d.ts +12 -0
  116. package/dist/src/graphql/entry.js +13 -0
  117. package/dist/src/graphql/entry.js.map +1 -0
  118. package/dist/src/graphql/generate.d.ts +12 -0
  119. package/dist/src/graphql/generate.js +19 -0
  120. package/dist/src/graphql/generate.js.map +1 -0
  121. package/dist/src/graphql/preflight.d.ts +6 -0
  122. package/dist/src/graphql/preflight.js +42 -0
  123. package/dist/src/graphql/preflight.js.map +1 -0
  124. package/dist/src/graphql/resolvers.d.ts +17 -0
  125. package/dist/src/graphql/resolvers.js +44 -0
  126. package/dist/src/graphql/resolvers.js.map +1 -0
  127. package/dist/src/graphql/routes.d.ts +8 -0
  128. package/dist/src/graphql/routes.js +30 -0
  129. package/dist/src/graphql/routes.js.map +1 -0
  130. package/dist/src/graphql/schema.d.ts +6 -0
  131. package/dist/src/{graphql.js → graphql/schema.js} +57 -50
  132. package/dist/src/graphql/schema.js.map +1 -0
  133. package/dist/src/graphql/write.d.ts +4 -0
  134. package/dist/src/graphql/write.js +10 -0
  135. package/dist/src/graphql/write.js.map +1 -0
  136. package/dist/src/openapi/auth.d.ts +13 -0
  137. package/dist/src/openapi/auth.js +139 -0
  138. package/dist/src/openapi/auth.js.map +1 -0
  139. package/dist/src/openapi/document.d.ts +7 -3
  140. package/dist/src/openapi/document.js +147 -92
  141. package/dist/src/openapi/document.js.map +1 -1
  142. package/dist/src/openapi/entry.d.ts +14 -0
  143. package/dist/src/openapi/entry.js +13 -0
  144. package/dist/src/openapi/entry.js.map +1 -0
  145. package/dist/src/openapi/files.d.ts +6 -0
  146. package/dist/src/{files/openapi.js → openapi/files.js} +6 -5
  147. package/dist/src/openapi/files.js.map +1 -0
  148. package/dist/src/openapi/generate.d.ts +19 -0
  149. package/dist/src/openapi/generate.js +41 -0
  150. package/dist/src/openapi/generate.js.map +1 -0
  151. package/dist/src/openapi/helpers.d.ts +26 -0
  152. package/dist/src/openapi/helpers.js +13 -0
  153. package/dist/src/openapi/helpers.js.map +1 -0
  154. package/dist/src/openapi/options.d.ts +18 -0
  155. package/dist/src/openapi/options.js +13 -0
  156. package/dist/src/openapi/options.js.map +1 -0
  157. package/dist/src/{types.d.ts → openapi/types.d.ts} +2 -10
  158. package/dist/src/openapi/types.js +2 -0
  159. package/dist/src/openapi/types.js.map +1 -0
  160. package/dist/src/openapi/write.d.ts +5 -0
  161. package/dist/src/openapi/write.js +12 -0
  162. package/dist/src/openapi/write.js.map +1 -0
  163. package/dist/src/rest/options.d.ts +22 -0
  164. package/dist/src/rest/options.js +65 -0
  165. package/dist/src/rest/options.js.map +1 -0
  166. package/dist/src/rest/projection.d.ts +13 -0
  167. package/dist/src/rest/projection.js +61 -0
  168. package/dist/src/rest/projection.js.map +1 -0
  169. package/dist/src/rest/routes.d.ts +7 -0
  170. package/dist/src/rest/routes.js +49 -0
  171. package/dist/src/rest/routes.js.map +1 -0
  172. package/dist/src/server/config.d.ts +74 -0
  173. package/dist/src/server/config.js +142 -0
  174. package/dist/src/server/config.js.map +1 -0
  175. package/dist/src/server/create.d.ts +16 -0
  176. package/dist/src/server/create.js +133 -0
  177. package/dist/src/server/create.js.map +1 -0
  178. package/dist/src/server/features.d.ts +4 -0
  179. package/dist/src/server/features.js +11 -0
  180. package/dist/src/server/features.js.map +1 -0
  181. package/dist/src/server/model.d.ts +6 -0
  182. package/dist/src/server/model.js +14 -0
  183. package/dist/src/server/model.js.map +1 -0
  184. package/dist/src/server/public.d.ts +2 -0
  185. package/dist/src/server/public.js +2 -0
  186. package/dist/src/server/public.js.map +1 -0
  187. package/package.json +17 -1
  188. package/dist/src/cli.d.ts +0 -4
  189. package/dist/src/cli.js +0 -67
  190. package/dist/src/cli.js.map +0 -1
  191. package/dist/src/config.d.ts +0 -68
  192. package/dist/src/config.js +0 -161
  193. package/dist/src/config.js.map +0 -1
  194. package/dist/src/constants.js.map +0 -1
  195. package/dist/src/database.d.ts +0 -21
  196. package/dist/src/database.js.map +0 -1
  197. package/dist/src/engine.d.ts +0 -47
  198. package/dist/src/engine.js +0 -438
  199. package/dist/src/engine.js.map +0 -1
  200. package/dist/src/files/openapi.d.ts +0 -3
  201. package/dist/src/files/openapi.js.map +0 -1
  202. package/dist/src/graphql.d.ts +0 -4
  203. package/dist/src/graphql.js.map +0 -1
  204. package/dist/src/model.d.ts +0 -67
  205. package/dist/src/model.js.map +0 -1
  206. package/dist/src/openapi/index.d.ts +0 -7
  207. package/dist/src/openapi/index.js +0 -26
  208. package/dist/src/openapi/index.js.map +0 -1
  209. package/dist/src/query/filter.d.ts +0 -1
  210. package/dist/src/query/filter.js +0 -84
  211. package/dist/src/query/filter.js.map +0 -1
  212. package/dist/src/query/options.d.ts +0 -31
  213. package/dist/src/query/options.js +0 -135
  214. package/dist/src/query/options.js.map +0 -1
  215. package/dist/src/relation-metadata.d.ts +0 -10
  216. package/dist/src/relation-metadata.js.map +0 -1
  217. package/dist/src/server.d.ts +0 -14
  218. package/dist/src/server.js +0 -166
  219. package/dist/src/server.js.map +0 -1
  220. package/dist/src/utils.d.ts +0 -19
  221. package/dist/src/utils.js +0 -62
  222. package/dist/src/utils.js.map +0 -1
  223. /package/dist/src/{types.js → core/types.js} +0 -0
@@ -0,0 +1,18 @@
1
+ export type OpenapiInfo = {
2
+ title: string;
3
+ version: string;
4
+ description?: string;
5
+ };
6
+ /** Проверяет метаданные спецификации и возвращает независимую копию.
7
+ * @example normalizeOpenapiInfo({ title: 'API', version: '1' }) → { title: 'API', version: '1' }; description: 42 → ошибка.
8
+ */
9
+ export declare function normalizeOpenapiInfo(value: unknown): OpenapiInfo | undefined;
10
+ export interface OpenapiOptions {
11
+ auth?: boolean;
12
+ files?: boolean;
13
+ host?: string;
14
+ port?: number;
15
+ pageSize?: number;
16
+ maxPageSize?: number;
17
+ info?: OpenapiInfo;
18
+ }
@@ -0,0 +1,13 @@
1
+ import { getObject } from '../core/config-values.js';
2
+ /** Проверяет метаданные спецификации и возвращает независимую копию.
3
+ * @example normalizeOpenapiInfo({ title: 'API', version: '1' }) → { title: 'API', version: '1' }; description: 42 → ошибка.
4
+ */
5
+ export function normalizeOpenapiInfo(value) {
6
+ const info = getObject(value, 'openapi.info');
7
+ if (!info)
8
+ return undefined;
9
+ if (typeof info.title !== 'string' || typeof info.version !== 'string' || (info.description !== undefined && typeof info.description !== 'string'))
10
+ throw new Error('Invalid OpenAPI info');
11
+ return structuredClone(info);
12
+ }
13
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../../src/openapi/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IAC9C,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC5L,OAAO,eAAe,CAAC,IAAI,CAAgB,CAAC;AAC9C,CAAC"}
@@ -1,11 +1,4 @@
1
- export type JsonPrimitive = boolean | number | string | null;
2
- export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
3
- export type JsonObject = {
4
- [key: string]: JsonValue;
5
- };
6
- export type DatabaseId = number | string;
7
- export type DatabaseRecord = JsonObject;
8
- export type DatabaseData = Record<string, DatabaseRecord[]>;
1
+ import type { JsonValue } from '../core/types.js';
9
2
  export type OpenapiType = 'array' | 'boolean' | 'integer' | 'number' | 'object' | 'string';
10
3
  export interface OpenapiSchema {
11
4
  [key: string]: unknown;
@@ -38,6 +31,7 @@ export interface OpenapiDocument {
38
31
  components: {
39
32
  parameters: Record<string, unknown>;
40
33
  schemas: Record<string, OpenapiSchema>;
34
+ securitySchemes?: Record<string, unknown>;
41
35
  };
42
36
  info: Record<string, unknown>;
43
37
  openapi: string;
@@ -46,5 +40,3 @@ export interface OpenapiDocument {
46
40
  url: string;
47
41
  }>;
48
42
  }
49
- export type QueryValue = string | string[] | undefined;
50
- export type Query = Record<string, QueryValue>;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/openapi/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import type { OpenapiDocument } from './types.js';
2
+ /** Сохраняет документ в YAML, создавая родительские каталоги.
3
+ * @example writeOpenapi(document, './out/api.yaml') → Promise<void>; результат записан в файл.
4
+ */
5
+ export declare const writeOpenapi: (document: OpenapiDocument, outputPath: string) => Promise<void>;
@@ -0,0 +1,12 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { stringify } from 'yaml';
4
+ /** Сохраняет документ в YAML, создавая родительские каталоги.
5
+ * @example writeOpenapi(document, './out/api.yaml') → Promise<void>; результат записан в файл.
6
+ */
7
+ export const writeOpenapi = async (document, outputPath) => {
8
+ const resolvedOutputPath = resolve(outputPath);
9
+ await mkdir(dirname(resolvedOutputPath), { recursive: true });
10
+ await writeFile(resolvedOutputPath, stringify(document, { aliasDuplicateObjects: false, lineWidth: 0 }), 'utf8');
11
+ };
12
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/openapi/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAGjC;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,QAAyB,EAAE,UAAkB,EAAiB,EAAE;IACjG,MAAM,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAE/C,MAAM,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,SAAS,CAAC,kBAAkB,EAAE,SAAS,CAAC,QAAQ,EAAE,EAAE,qBAAqB,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AACnH,CAAC,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { Node } from '../core/model.js';
2
+ import { type ListOptions } from '../core/query/options.js';
3
+ export interface Fields {
4
+ [key: string]: Scope | true;
5
+ }
6
+ export type Scope = [Fields, ListOptions?];
7
+ export interface RestOptions {
8
+ scope: Scope;
9
+ }
10
+ export declare const ownScope: Scope;
11
+ /** Выбирает вложенный набор полей; для отсутствующего поля или true возвращает выбор собственных полей.
12
+ * @example scopeFor([{ '*': true }], 'name') → [{ '*': true }].
13
+ */
14
+ export declare function scopeFor(scope: Scope, key: string): Scope;
15
+ /** Читает JSON-массив выбора полей из единственного параметра URL; проверяет длину и синтаксис JSON.
16
+ * @example parseRestOptions({ scope: '[{"id":true}]' }) → { scope: [{ id: true }] }.
17
+ */
18
+ export declare function parseRestOptions(query: unknown): RestOptions;
19
+ /** Проверяет выбор полей рекурсивно; аргументы разрешены только для однородных списков.
20
+ * @example Для узла со строковым id: [{ id: true }] → undefined; [{ missing: true }] → ошибка.
21
+ */
22
+ export declare function validateScope(node: Node, scope: unknown, list?: boolean, depth?: number): asserts scope is Scope;
@@ -0,0 +1,65 @@
1
+ import { badQuery, childrenOf } from '../core/query/options.js';
2
+ import { hasOnlyKeys, isObject, isSafeKey } from '../core/utils.js';
3
+ export const ownScope = [{ '*': true }];
4
+ /** Выбирает вложенный набор полей; для отсутствующего поля или true возвращает выбор собственных полей.
5
+ * @example scopeFor([{ '*': true }], 'name') → [{ '*': true }].
6
+ */
7
+ export function scopeFor(scope, key) {
8
+ const selection = Object.hasOwn(scope[0], key) ? scope[0][key] : true;
9
+ return selection === true ? ownScope : selection;
10
+ }
11
+ /** Читает JSON-массив выбора полей из единственного параметра URL; проверяет длину и синтаксис JSON.
12
+ * @example parseRestOptions({ scope: '[{"id":true}]' }) → { scope: [{ id: true }] }.
13
+ */
14
+ export function parseRestOptions(query) {
15
+ if (!isObject(query))
16
+ badQuery('Invalid query');
17
+ for (const key of Object.keys(query))
18
+ if (key !== 'scope')
19
+ badQuery(`Unknown query parameter ${key}`);
20
+ if (query.scope === undefined)
21
+ return { scope: ownScope };
22
+ if (typeof query.scope !== 'string')
23
+ badQuery('scope must occur once and contain JSON');
24
+ if (query.scope.length > 10000)
25
+ badQuery('scope must contain at most 10000 characters');
26
+ try {
27
+ return { scope: JSON.parse(query.scope) };
28
+ }
29
+ catch {
30
+ badQuery('Invalid JSON in scope');
31
+ }
32
+ }
33
+ /** Проверяет выбор полей рекурсивно; аргументы разрешены только для однородных списков.
34
+ * @example Для узла со строковым id: [{ id: true }] → undefined; [{ missing: true }] → ошибка.
35
+ */
36
+ export function validateScope(node, scope, list = false, depth = 0) {
37
+ if (depth > 32)
38
+ badQuery('scope is too deep');
39
+ if (!Array.isArray(scope) || scope.length < 1 || scope.length > 2 || !isObject(scope[0]))
40
+ badQuery('scope must be [fields, arguments?]');
41
+ if (scope.length === 2) {
42
+ if (!list || node.mixed)
43
+ badQuery('scope arguments require a list with consistent object types');
44
+ if (!isObject(scope[1]) || !hasOnlyKeys(scope[1], ['where', 'order', 'pager']))
45
+ badQuery('Invalid scope arguments');
46
+ }
47
+ const children = childrenOf(node);
48
+ for (const [key, selection] of Object.entries(scope[0])) {
49
+ if (key === '*') {
50
+ if (selection !== true)
51
+ badQuery('scope wildcard must be true');
52
+ continue;
53
+ }
54
+ if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(key) || !isSafeKey(key))
55
+ badQuery(`Invalid scope field ${key}`);
56
+ const child = children[key];
57
+ if (!Object.hasOwn(children, key) || child.writeOnly)
58
+ badQuery(`Unknown or inaccessible scope field ${key}`);
59
+ if (child.relation || child.base === 'object')
60
+ validateScope(child, selection, child.many, depth + 1);
61
+ else if (selection !== true)
62
+ badQuery(`Scalar field ${key} must be true`);
63
+ }
64
+ }
65
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../../src/rest/options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Engine, PreparedList } from '../core/engine.js';
2
+ import type { Entity, Node } from '../core/model.js';
3
+ import { type Ref } from '../core/records.js';
4
+ import type { JsonObject } from '../core/types.js';
5
+ import { type RestOptions, type Scope } from './options.js';
6
+ /** Проверяет дерево выбора и заранее подготавливает фильтры, сортировку и пагинацию вложенных списков.
7
+ * @example Выбор без аргументов у одиночной записи → пустая Map; неверное поле → ошибка.
8
+ */
9
+ export declare function validateRest(engine: Engine, entity: Entity, options: RestOptions, list?: boolean): Map<Scope | Node, PreparedList>;
10
+ /** Строит новый объект из выбранных полей, разворачивая связи и обрабатывая вложенные списки.
11
+ * @example Запись { id: '1', name: 'Анна' } и выбор [{ name: true }] → { name: 'Анна' }.
12
+ */
13
+ export declare function project(engine: Engine, ref: Ref, scope?: Scope, plans?: Map<Node | Scope, PreparedList>): JsonObject;
@@ -0,0 +1,61 @@
1
+ import { childrenOf } from '../core/query/options.js';
2
+ import { isRef, resolveField } from '../core/records.js';
3
+ import { ownScope, scopeFor, validateScope } from './options.js';
4
+ /** Проверяет дерево выбора и заранее подготавливает фильтры, сортировку и пагинацию вложенных списков.
5
+ * @example Выбор без аргументов у одиночной записи → пустая Map; неверное поле → ошибка.
6
+ */
7
+ export function validateRest(engine, entity, options, list = false) {
8
+ validateScope(entity.root, options.scope, list);
9
+ const plans = new Map();
10
+ if (list)
11
+ plans.set(options.scope, engine.prepareOptions(entity.root, options.scope[1]));
12
+ const visit = (node, scope) => {
13
+ for (const [key, selection] of Object.entries(scope[0])) {
14
+ if (selection === true)
15
+ continue;
16
+ const child = childrenOf(node)[key];
17
+ if (selection[1])
18
+ plans.set(selection, engine.prepareOptions(child, selection[1]));
19
+ visit(child, selection);
20
+ }
21
+ };
22
+ visit(entity.root, options.scope);
23
+ return plans;
24
+ }
25
+ /** Строит новый объект из выбранных полей, разворачивая связи и обрабатывая вложенные списки.
26
+ * @example Запись { id: '1', name: 'Анна' } и выбор [{ name: true }] → { name: 'Анна' }.
27
+ */
28
+ export function project(engine, ref, scope = ownScope, plans = new Map()) {
29
+ const output = Object.create(null);
30
+ const children = childrenOf(ref.node);
31
+ for (const [key, node] of Object.entries(children)) {
32
+ if (node.writeOnly || (!Object.hasOwn(scope[0], key) && !(Object.hasOwn(scope[0], '*') && !node.relation)))
33
+ continue;
34
+ const value = resolveField(ref, node);
35
+ const selection = scopeFor(scope, key);
36
+ if (value === undefined)
37
+ continue;
38
+ if (isRef(value))
39
+ output[key] = project(engine, value, selection, plans);
40
+ else if (Array.isArray(value)) {
41
+ if (value.every(isRef) && (value.length > 0 || node.relation || node.base === 'object')) {
42
+ const planKey = selection === ownScope ? node : selection;
43
+ const prepared = plans.get(planKey) ?? engine.prepareOptions(node, selection[1]);
44
+ plans.set(planKey, prepared);
45
+ const page = engine.list(value, node, selection[1], prepared);
46
+ output[key] = { data: page.data.map((v) => project(engine, v, selection, plans)), total: page.total };
47
+ }
48
+ else
49
+ output[key] = value.map((item) => (isRef(item) ? project(engine, item, selection, plans) : structuredClone(item)));
50
+ }
51
+ else
52
+ output[key] = structuredClone(value);
53
+ }
54
+ // При выведенной модели добавляем исходные поля, которые не удалось описать.
55
+ if (!ref.context.model.explicit && scope[0]['*'] === true)
56
+ for (const [key, value] of Object.entries(ref.value))
57
+ if (!Object.hasOwn(output, key) && !children[key]?.relation && !children[key]?.writeOnly)
58
+ output[key] = structuredClone(value);
59
+ return output;
60
+ }
61
+ //# sourceMappingURL=projection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.js","sourceRoot":"","sources":["../../../src/rest/projection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { Engine } from '../core/engine.js';
3
+ import type { Authenticate } from '../core/lifecycle/options.js';
4
+ /** Регистрирует чтение коллекций и операции создания, замены, изменения и удаления записей.
5
+ * @example После регистрации GET / → { resources: [...] }; функция возвращает undefined.
6
+ */
7
+ export declare function registerRestRoutes(server: FastifyInstance, engine: Engine, authenticate?: Authenticate): void;
@@ -0,0 +1,49 @@
1
+ import { domainError } from '../core/errors.js';
2
+ import { MUTATIONS } from '../core/operations.js';
3
+ import { parseRestOptions } from './options.js';
4
+ import { project, validateRest } from './projection.js';
5
+ /** Регистрирует чтение коллекций и операции создания, замены, изменения и удаления записей.
6
+ * @example После регистрации GET / → { resources: [...] }; функция возвращает undefined.
7
+ */
8
+ export function registerRestRoutes(server, engine, authenticate) {
9
+ server.get('/', async () => ({ resources: engine.model.entities.map((entity) => entity.collection) }));
10
+ for (const initial of engine.model.entities) {
11
+ const path = `/${initial.collection}`;
12
+ const itemPath = `${path}/:${initial.primary}`;
13
+ server.get(path, async (request) => {
14
+ const context = await engine.context();
15
+ const entity = context.model.byCollection.get(initial.collection);
16
+ const options = parseRestOptions(request.query);
17
+ const plans = validateRest(engine, entity, options, true);
18
+ const page = engine.list(engine.records(context, entity), entity.root, undefined, plans.get(options.scope));
19
+ return { data: page.data.map((ref) => project(engine, ref, options.scope, plans)), total: page.total };
20
+ });
21
+ server.get(itemPath, async (request) => {
22
+ const context = await engine.context();
23
+ const entity = context.model.byCollection.get(initial.collection);
24
+ const options = parseRestOptions(request.query);
25
+ const plans = validateRest(engine, entity, options);
26
+ const ref = engine.find(context, entity, request.params[entity.primary]);
27
+ if (!ref)
28
+ throw domainError('NOT_FOUND', 'Record not found');
29
+ return project(engine, ref, options.scope, plans);
30
+ });
31
+ for (const { method, mode, hasKey, status } of MUTATIONS) {
32
+ server.route({
33
+ method,
34
+ url: hasKey ? itemPath : path,
35
+ handler: async (request, reply) => {
36
+ const actor = authenticate ? () => authenticate(request.headers.authorization) : undefined;
37
+ actor?.();
38
+ const options = parseRestOptions(request.query);
39
+ const result = await engine.mutate(initial, mode, request.params[initial.primary], request.body, (ref) => {
40
+ const plans = validateRest(engine, ref.entity, options);
41
+ return project(engine, ref, options.scope, plans);
42
+ }, actor);
43
+ return reply.code(status).send(result);
44
+ },
45
+ });
46
+ }
47
+ }
48
+ }
49
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/rest/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import type { FastifyServerOptions } from 'fastify';
2
+ import type { AuthConfig } from '../auth/contract.js';
3
+ import type { DatabaseConfig } from '../core/database.js';
4
+ import type { ModelSchema } from '../core/model.js';
5
+ import type { Storage } from '../core/storage.js';
6
+ import type { FilesConfig } from '../files/contract.js';
7
+ import { type OpenapiInfo } from '../openapi/options.js';
8
+ export type { AuthConfig } from '../auth/contract.js';
9
+ export type { DatabaseConfig } from '../core/database.js';
10
+ export type { Storage } from '../core/storage.js';
11
+ export type { FilesConfig, MemoryFile } from '../files/contract.js';
12
+ export type DatabaseSchema = ModelSchema;
13
+ export interface OpenapiConfig {
14
+ endpoint?: string;
15
+ target?: string;
16
+ info?: OpenapiInfo;
17
+ }
18
+ export interface GraphqlConfig {
19
+ target?: string;
20
+ endpoint?: string;
21
+ }
22
+ export interface ServerConfig {
23
+ cors?: boolean;
24
+ host?: string;
25
+ logger?: FastifyServerOptions['logger'];
26
+ maxFileSize?: number;
27
+ maxPageSize?: number;
28
+ pageSize?: number;
29
+ port?: number;
30
+ }
31
+ export type DeepJsonServerConfig = {
32
+ [S in Storage]: {
33
+ storage: S;
34
+ database: DatabaseConfig<S>;
35
+ files?: FilesConfig<S>;
36
+ auth?: AuthConfig<S>;
37
+ openapi?: OpenapiConfig;
38
+ graphql?: GraphqlConfig;
39
+ server?: ServerConfig;
40
+ };
41
+ }[Storage];
42
+ export interface NormalizedServerConfig {
43
+ storage: Storage;
44
+ database: DatabaseConfig;
45
+ files?: FilesConfig;
46
+ auth?: AuthConfig;
47
+ openapi?: OpenapiConfig & {
48
+ endpoint: string;
49
+ };
50
+ graphql?: GraphqlConfig & {
51
+ endpoint: string;
52
+ };
53
+ server: Required<ServerConfig>;
54
+ }
55
+ /** Нормализует объект конфигурации без чтения содержимого файлов.
56
+ * @example Путь './db.json' с directory = '/tmp' → '/tmp/db.json'.
57
+ */
58
+ export declare const normalizeServerConfig: (config: DeepJsonServerConfig, directory?: string) => NormalizedServerConfig;
59
+ /** Загружает default-экспорт ES-модуля, обходя кеш повторного импорта; выполняет код модуля.
60
+ * @example Файл /tmp/config.mjs с export default {} → { config: {}, directory: '/tmp', path: '/tmp/config.mjs' }.
61
+ */
62
+ export declare function readConfigModule(configPath: string): Promise<{
63
+ config: Record<string, unknown>;
64
+ directory: string;
65
+ path: string;
66
+ }>;
67
+ /** Возвращает сохранённый путь исходного файла для данного объекта настроек.
68
+ * @example Для объекта без зарегистрированного источника → undefined.
69
+ */
70
+ export declare const configSourcePath: (config: NormalizedServerConfig) => string | undefined;
71
+ /** Нормализует настройки и запоминает путь их источника во внутренней таблице.
72
+ * @example configure(config, '/tmp', '/tmp/config.mjs') → настройки; configSourcePath(result) → '/tmp/config.mjs'.
73
+ */
74
+ export declare function configure(config: unknown, directory: string, sourcePath?: string): NormalizedServerConfig;
@@ -0,0 +1,142 @@
1
+ import { dirname, resolve } from 'node:path';
2
+ import { pathToFileURL } from 'node:url';
3
+ import { getBoolean, getObject, getPositiveInteger, getString, normalizeAddress } from '../core/config-values.js';
4
+ import { DEFAULT_MAX_FILE_SIZE } from '../core/constants.js';
5
+ import { normalizePagination } from '../core/pagination.js';
6
+ import { assertKnownKeys, errorMessage, isObject } from '../core/utils.js';
7
+ import { normalizeOpenapiInfo } from '../openapi/options.js';
8
+ const CONFIG_KEYS = new Set(['storage', 'database', 'files', 'auth', 'openapi', 'graphql', 'server']);
9
+ const SERVER_KEYS = new Set(['cors', 'host', 'logger', 'maxFileSize', 'maxPageSize', 'pageSize', 'port']);
10
+ let configImportIndex = 0;
11
+ /** Проверяет секцию и её допустимые ключи; undefined означает отсутствие секции.
12
+ * @example section({}, 'auth', []) → {}; section(null, 'auth', []) → ошибка.
13
+ */
14
+ function section(value, name, keys) {
15
+ if (value === undefined)
16
+ return undefined;
17
+ const object = getObject(value, `config.${name}`, true);
18
+ assertKnownKeys(object, new Set(keys), `config.${name}`);
19
+ return object;
20
+ }
21
+ /** Проверяет путь либо начальные данные в соответствии с общим режимом хранения.
22
+ * @example source('db.json', 'file', 'database.source', '/tmp') → '/tmp/db.json'.
23
+ */
24
+ function source(value, storage, name, directory, array = false) {
25
+ if (storage === 'file')
26
+ return resolve(directory, getString(value, `config.${name}`, true));
27
+ if (array ? !Array.isArray(value) : !isObject(value))
28
+ throw new Error(`config.${name} must contain ${array ? 'an array' : 'an object'} for memory storage`);
29
+ try {
30
+ return structuredClone(value);
31
+ }
32
+ catch (error) {
33
+ throw new Error(`config.${name} must contain structured data`, { cause: error });
34
+ }
35
+ }
36
+ /** Проверяет секции настроек и возвращает независимые данные с абсолютными путями.
37
+ * @example { storage: 'file', database: { source: 'db.json' } } → абсолютный database.source.
38
+ */
39
+ function normalizeConfig(value, directory = '.') {
40
+ const config = getObject(value, 'config', true);
41
+ assertKnownKeys(config, CONFIG_KEYS, 'config');
42
+ if (config.storage !== 'file' && config.storage !== 'memory')
43
+ throw new Error("config.storage must be 'file' or 'memory'");
44
+ const storage = config.storage;
45
+ const database = section(config.database, 'database', ['source', 'schema']);
46
+ if (!database)
47
+ throw new Error('config.database is required');
48
+ const normalizedDatabase = {
49
+ source: source(database.source, storage, 'database.source', directory),
50
+ ...(database.schema !== undefined ? { schema: source(database.schema, storage, 'database.schema', directory) } : {}),
51
+ };
52
+ const files = section(config.files, 'files', storage === 'file' ? ['source', 'metadata'] : ['source']);
53
+ const normalizedFiles = files === undefined
54
+ ? undefined
55
+ : storage === 'file'
56
+ ? {
57
+ source: source(files.source, storage, 'files.source', directory),
58
+ metadata: files.metadata === undefined
59
+ ? resolve(directory, getString(files.source, 'config.files.source', true), '.files.json')
60
+ : resolve(directory, getString(files.metadata, 'config.files.metadata', true)),
61
+ }
62
+ : { source: source(files.source, storage, 'files.source', directory, true) };
63
+ const auth = section(config.auth, 'auth', ['source', 'expiresIn']);
64
+ let normalizedAuth;
65
+ if (auth) {
66
+ const expiresIn = getPositiveInteger(auth.expiresIn, 'config.auth.expiresIn');
67
+ if (expiresIn !== undefined && expiresIn > 2147483647)
68
+ throw new Error('config.auth.expiresIn must be at most 2147483647 seconds');
69
+ normalizedAuth = { source: source(auth.source, storage, 'auth.source', directory, true), expiresIn };
70
+ }
71
+ const openapi = section(config.openapi, 'openapi', ['target', 'info', 'endpoint']);
72
+ const graphql = section(config.graphql, 'graphql', ['target', 'endpoint']);
73
+ if ((openapi || graphql) && normalizedDatabase.schema === undefined)
74
+ throw new Error('GraphQL and OpenAPI require an explicit model schema');
75
+ const exportPath = (value, name) => (value === undefined ? undefined : resolve(directory, getString(value, name, true)));
76
+ const openapiEndpoint = getString(openapi?.endpoint, 'config.openapi.endpoint') ?? '/openapi.json';
77
+ const graphqlEndpoint = getString(graphql?.endpoint, 'config.graphql.endpoint') ?? '/graphql';
78
+ if (!/^\/[A-Za-z][A-Za-z0-9_./-]*$/.test(openapiEndpoint))
79
+ throw new Error('Invalid OpenAPI endpoint');
80
+ if (!/^\/[A-Za-z][A-Za-z0-9_/-]*$/.test(graphqlEndpoint))
81
+ throw new Error('Invalid GraphQL endpoint');
82
+ const server = getObject(config.server, 'config.server') ?? {};
83
+ assertKnownKeys(server, SERVER_KEYS, 'config.server');
84
+ const logger = server.logger;
85
+ if (logger != null && typeof logger !== 'boolean' && !isObject(logger))
86
+ throw new Error('config.server.logger must be boolean or an object');
87
+ return {
88
+ storage,
89
+ database: normalizedDatabase,
90
+ files: normalizedFiles,
91
+ auth: normalizedAuth,
92
+ openapi: openapi ? { endpoint: openapiEndpoint, target: exportPath(openapi.target, 'config.openapi.target'), info: normalizeOpenapiInfo(openapi.info) } : undefined,
93
+ graphql: graphql ? { endpoint: graphqlEndpoint, target: exportPath(graphql.target, 'config.graphql.target') } : undefined,
94
+ server: {
95
+ ...normalizeAddress(server),
96
+ ...normalizePagination(server),
97
+ cors: getBoolean(server.cors, 'config.server.cors') ?? true,
98
+ logger: (logger ?? true),
99
+ maxFileSize: getPositiveInteger(server.maxFileSize, 'config.server.maxFileSize') ?? DEFAULT_MAX_FILE_SIZE,
100
+ },
101
+ };
102
+ }
103
+ /** Нормализует объект конфигурации без чтения содержимого файлов.
104
+ * @example Путь './db.json' с directory = '/tmp' → '/tmp/db.json'.
105
+ */
106
+ export const normalizeServerConfig = (config, directory) => normalizeConfig(config, directory);
107
+ /** Загружает default-экспорт ES-модуля, обходя кеш повторного импорта; выполняет код модуля.
108
+ * @example Файл /tmp/config.mjs с export default {} → { config: {}, directory: '/tmp', path: '/tmp/config.mjs' }.
109
+ */
110
+ export async function readConfigModule(configPath) {
111
+ const resolvedConfigPath = resolve(getString(configPath, 'config', true));
112
+ let config;
113
+ try {
114
+ const configUrl = pathToFileURL(resolvedConfigPath);
115
+ // Обходим кеш модуля, чтобы повторное чтение выполняло обновлённый файл.
116
+ configUrl.searchParams.set('deep-json-server-import', String(configImportIndex++));
117
+ config = (await import(configUrl.href)).default;
118
+ }
119
+ catch (error) {
120
+ const message = errorMessage(error);
121
+ throw new Error(`Не удалось загрузить конфигурацию ${resolvedConfigPath}: ${message}`, { cause: error });
122
+ }
123
+ if (!isObject(config)) {
124
+ throw new Error('Конфигурация сервера должна экспортировать JSON-объект через export default');
125
+ }
126
+ return { config, directory: dirname(resolvedConfigPath), path: resolvedConfigPath };
127
+ }
128
+ const sourcePaths = new WeakMap();
129
+ /** Возвращает сохранённый путь исходного файла для данного объекта настроек.
130
+ * @example Для объекта без зарегистрированного источника → undefined.
131
+ */
132
+ export const configSourcePath = (config) => sourcePaths.get(config);
133
+ /** Нормализует настройки и запоминает путь их источника во внутренней таблице.
134
+ * @example configure(config, '/tmp', '/tmp/config.mjs') → настройки; configSourcePath(result) → '/tmp/config.mjs'.
135
+ */
136
+ export function configure(config, directory, sourcePath) {
137
+ const normalized = normalizeConfig(config, directory);
138
+ if (sourcePath)
139
+ sourcePaths.set(normalized, sourcePath);
140
+ return normalized;
141
+ }
142
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/server/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,kBAAkB,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAClH,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAG7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE3E,OAAO,EAAE,oBAAoB,EAAoB,MAAM,uBAAuB,CAAC;AA6C/E,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;AACtG,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAC1G,IAAI,iBAAiB,GAAG,CAAC,CAAC;AAE1B;;GAEG;AACH,SAAS,OAAO,CAAC,KAAc,EAAE,IAAY,EAAE,IAAc;IAC3D,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,UAAU,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IACxD,eAAe,CAAC,MAAM,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;IACzD,OAAO,MAAM,CAAC;AAChB,CAAC;AACD;;GAEG;AACH,SAAS,MAAM,CAAC,KAAc,EAAE,OAAgB,EAAE,IAAY,EAAE,SAAiB,EAAE,KAAK,GAAG,KAAK;IAC9F,IAAI,OAAO,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,EAAE,UAAU,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IAC5F,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,iBAAiB,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,qBAAqB,CAAC,CAAC;IAC5J,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,+BAA+B,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACnF,CAAC;AACH,CAAC;AACD;;GAEG;AACH,SAAS,eAAe,CAAC,KAAc,EAAE,SAAS,GAAG,GAAG;IACtD,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAChD,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC/C,IAAI,MAAM,CAAC,OAAO,KAAK,MAAM,IAAI,MAAM,CAAC,OAAO,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC3H,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC5E,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC9D,MAAM,kBAAkB,GAAmB;QACzC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,CAA6B;QAClG,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,CAA6B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjJ,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvG,MAAM,eAAe,GACnB,KAAK,KAAK,SAAS;QACjB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,OAAO,KAAK,MAAM;YAClB,CAAC,CAAC;gBACE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,CAAW;gBAC1E,QAAQ,EACN,KAAK,CAAC,QAAQ,KAAK,SAAS;oBAC1B,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,qBAAqB,EAAE,IAAI,CAAC,EAAE,aAAa,CAAC;oBACzF,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,uBAAuB,EAAE,IAAI,CAAC,CAAC;aACnF;YACH,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,CAAoC,EAAE,CAAC;IACtH,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;IACnE,IAAI,cAAsC,CAAC;IAC3C,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC;QAC9E,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,GAAG,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;QACnI,cAAc,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,CAAyB,EAAE,SAAS,EAAE,CAAC;IAC/H,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACnF,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;IAC3E,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,kBAAkB,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC7I,MAAM,UAAU,GAAG,CAAC,KAAc,EAAE,IAAY,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1I,MAAM,eAAe,GAAG,SAAS,CAAC,OAAO,EAAE,QAAQ,EAAE,yBAAyB,CAAC,IAAI,eAAe,CAAC;IACnG,MAAM,eAAe,GAAG,SAAS,CAAC,OAAO,EAAE,QAAQ,EAAE,yBAAyB,CAAC,IAAI,UAAU,CAAC;IAC9F,IAAI,CAAC,8BAA8B,CAAC,IAAI,CAAC,eAAe,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACvG,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,eAAe,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACtG,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,IAAI,EAAE,CAAC;IAC/D,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,IAAI,MAAM,IAAI,IAAI,IAAI,OAAO,MAAM,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IAC7I,OAAO;QACL,OAAO;QACP,QAAQ,EAAE,kBAAkB;QAC5B,KAAK,EAAE,eAAe;QACtB,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAAE,IAAI,EAAE,oBAAoB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;QACnK,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;QACzH,MAAM,EAAE;YACN,GAAG,gBAAgB,CAAC,MAAM,CAAC;YAC3B,GAAG,mBAAmB,CAAC,MAAM,CAAC;YAC9B,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,oBAAoB,CAAC,IAAI,IAAI;YAC3D,MAAM,EAAE,CAAC,MAAM,IAAI,IAAI,CAAqC;YAC5D,WAAW,EAAE,kBAAkB,CAAC,MAAM,CAAC,WAAW,EAAE,2BAA2B,CAAC,IAAI,qBAAqB;SAC1G;KACF,CAAC;AACJ,CAAC;AACD;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,MAA4B,EAAE,SAAkB,EAA0B,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAEtJ;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAkB;IACvD,MAAM,kBAAkB,GAAG,OAAO,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAC1E,IAAI,MAAe,CAAC;IAEpB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,aAAa,CAAC,kBAAkB,CAAC,CAAC;QAEpD,yEAAyE;QACzE,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,yBAAyB,EAAE,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;QACnF,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAEpC,MAAM,IAAI,KAAK,CAAC,qCAAqC,kBAAkB,KAAK,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3G,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACjG,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;AACtF,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,OAAO,EAAkC,CAAC;AAClE;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAA8B,EAAsB,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAChH;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,MAAe,EAAE,SAAiB,EAAE,UAAmB;IAC/E,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACtD,IAAI,UAAU;QAAE,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACxD,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { OpenapiDocument } from '../openapi/types.js';
3
+ import { type DeepJsonServerConfig, type NormalizedServerConfig } from './config.js';
4
+ export interface ServerFacade {
5
+ fastify(): FastifyInstance;
6
+ openapi(): Promise<OpenapiDocument>;
7
+ graphql(): Promise<string>;
8
+ }
9
+ /** Проверяет настройки и создаёт интерфейс запуска и генерации схем; сетевой порт ещё не открывает.
10
+ * @example await createServer({ storage: 'memory', database: { source: { notes: [] } } }) → объект с fastify(), openapi(), graphql().
11
+ */
12
+ export declare function createServer(config: DeepJsonServerConfig): Promise<ServerFacade>;
13
+ /** Собирает сервер из нормализованных настроек; хранилища открываются при инициализации HTTP-экземпляра.
14
+ * @example Нормализованные настройки → Promise<ServerFacade>; listen() затем открывает сетевой порт.
15
+ */
16
+ export declare function createConfiguredServer(normalized: NormalizedServerConfig): Promise<ServerFacade>;