@kollors/deep-json-server 1.0.0-alpha.5 → 1.0.0-alpha.7

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 (215) hide show
  1. package/README.md +346 -188
  2. package/README.ru.md +343 -185
  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 +12 -8
  6. package/dist/index.js +4 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/src/auth/contract.d.ts +27 -0
  9. package/dist/src/auth/contract.js +5 -0
  10. package/dist/src/auth/contract.js.map +1 -0
  11. package/dist/src/auth/password.d.ts +13 -0
  12. package/dist/src/auth/password.js +37 -0
  13. package/dist/src/auth/password.js.map +1 -0
  14. package/dist/src/auth/public.d.ts +3 -0
  15. package/dist/src/auth/public.js +5 -0
  16. package/dist/src/auth/public.js.map +1 -0
  17. package/dist/src/auth/routes.d.ts +6 -0
  18. package/dist/src/auth/routes.js +15 -0
  19. package/dist/src/auth/routes.js.map +1 -0
  20. package/dist/src/auth/service.d.ts +39 -0
  21. package/dist/src/auth/service.js +143 -0
  22. package/dist/src/auth/service.js.map +1 -0
  23. package/dist/src/cli/index.d.ts +7 -0
  24. package/dist/src/{cli.js → cli/index.js} +32 -12
  25. package/dist/src/cli/index.js.map +1 -0
  26. package/dist/src/{constants.d.ts → core/constants.d.ts} +1 -1
  27. package/dist/src/{constants.js → core/constants.js} +1 -1
  28. package/dist/src/core/constants.js.map +1 -0
  29. package/dist/src/core/database.d.ts +50 -0
  30. package/dist/src/{database.js → core/database.js} +21 -1
  31. package/dist/src/core/database.js.map +1 -0
  32. package/dist/src/core/engine.d.ts +64 -0
  33. package/dist/src/{engine.js → core/engine.js} +64 -18
  34. package/dist/src/core/engine.js.map +1 -0
  35. package/dist/src/core/errors.d.ts +9 -0
  36. package/dist/src/core/errors.js +12 -0
  37. package/dist/src/core/errors.js.map +1 -0
  38. package/dist/src/core/http-errors.d.ts +9 -0
  39. package/dist/src/core/http-errors.js +15 -0
  40. package/dist/src/core/http-errors.js.map +1 -0
  41. package/dist/src/core/lifecycle/mutation.d.ts +49 -0
  42. package/dist/src/core/lifecycle/mutation.js +170 -0
  43. package/dist/src/core/lifecycle/mutation.js.map +1 -0
  44. package/dist/src/core/lifecycle/options.d.ts +20 -0
  45. package/dist/src/core/lifecycle/options.js +21 -0
  46. package/dist/src/core/lifecycle/options.js.map +1 -0
  47. package/dist/src/core/model.d.ts +130 -0
  48. package/dist/src/{model.js → core/model.js} +106 -10
  49. package/dist/src/core/model.js.map +1 -0
  50. package/dist/src/{mutations → core/mutations}/write.d.ts +3 -2
  51. package/dist/src/{mutations → core/mutations}/write.js +14 -4
  52. package/dist/src/core/mutations/write.js.map +1 -0
  53. package/dist/src/core/pagination.d.ts +10 -0
  54. package/dist/src/{pagination.js → core/pagination.js} +3 -0
  55. package/dist/src/core/pagination.js.map +1 -0
  56. package/dist/src/core/paths.d.ts +16 -0
  57. package/dist/src/{paths.js → core/paths.js} +14 -1
  58. package/dist/src/core/paths.js.map +1 -0
  59. package/dist/src/core/query/contract.d.ts +6 -0
  60. package/dist/src/{query → core/query}/contract.js +3 -0
  61. package/dist/src/core/query/contract.js.map +1 -0
  62. package/dist/src/core/query/filter.d.ts +6 -0
  63. package/dist/src/{query → core/query}/filter.js +18 -4
  64. package/dist/src/core/query/filter.js.map +1 -0
  65. package/dist/src/core/query/options.d.ts +30 -0
  66. package/dist/src/{query → core/query}/options.js +12 -0
  67. package/dist/src/core/query/options.js.map +1 -0
  68. package/dist/src/core/records.d.ts +46 -0
  69. package/dist/src/{records.js → core/records.js} +24 -3
  70. package/dist/src/core/records.js.map +1 -0
  71. package/dist/src/core/relation-metadata.d.ts +15 -0
  72. package/dist/src/{relation-metadata.js → core/relation-metadata.js} +7 -1
  73. package/dist/src/core/relation-metadata.js.map +1 -0
  74. package/dist/src/core/types.d.ts +10 -0
  75. package/dist/src/{types.js.map → core/types.js.map} +1 -1
  76. package/dist/src/core/utils.d.ts +56 -0
  77. package/dist/src/core/utils.js +102 -0
  78. package/dist/src/core/utils.js.map +1 -0
  79. package/dist/src/files/contract.d.ts +33 -0
  80. package/dist/src/files/contract.js +25 -3
  81. package/dist/src/files/contract.js.map +1 -1
  82. package/dist/src/files/disk-store.d.ts +3 -0
  83. package/dist/src/files/disk-store.js +27 -3
  84. package/dist/src/files/disk-store.js.map +1 -1
  85. package/dist/src/files/http.d.ts +8 -3
  86. package/dist/src/files/http.js +9 -0
  87. package/dist/src/files/http.js.map +1 -1
  88. package/dist/src/files/index.d.ts +4 -3
  89. package/dist/src/files/index.js +3 -1
  90. package/dist/src/files/index.js.map +1 -1
  91. package/dist/src/files/memory-store.d.ts +4 -1
  92. package/dist/src/files/memory-store.js +8 -2
  93. package/dist/src/files/memory-store.js.map +1 -1
  94. package/dist/src/files/routes.d.ts +3 -0
  95. package/dist/src/files/routes.js +25 -1
  96. package/dist/src/files/routes.js.map +1 -1
  97. package/dist/src/graphql/entry.d.ts +2 -2
  98. package/dist/src/graphql/entry.js.map +1 -1
  99. package/dist/src/graphql/lazy.d.ts +10 -0
  100. package/dist/src/graphql/lazy.js +13 -0
  101. package/dist/src/graphql/lazy.js.map +1 -0
  102. package/dist/src/graphql/preflight.d.ts +4 -1
  103. package/dist/src/graphql/preflight.js +3 -0
  104. package/dist/src/graphql/preflight.js.map +1 -1
  105. package/dist/src/graphql/public.d.ts +10 -2
  106. package/dist/src/graphql/public.js +10 -4
  107. package/dist/src/graphql/public.js.map +1 -1
  108. package/dist/src/graphql/resolvers.d.ts +10 -2
  109. package/dist/src/graphql/resolvers.js +8 -2
  110. package/dist/src/graphql/resolvers.js.map +1 -1
  111. package/dist/src/graphql/routes.d.ts +6 -2
  112. package/dist/src/graphql/routes.js +6 -3
  113. package/dist/src/graphql/routes.js.map +1 -1
  114. package/dist/src/graphql/schema.d.ts +6 -0
  115. package/dist/src/{graphql.js → graphql/schema.js} +14 -11
  116. package/dist/src/graphql/schema.js.map +1 -0
  117. package/dist/src/graphql/write.d.ts +3 -0
  118. package/dist/src/graphql/write.js +3 -0
  119. package/dist/src/graphql/write.js.map +1 -1
  120. package/dist/src/openapi/auth.d.ts +13 -0
  121. package/dist/src/openapi/auth.js +72 -0
  122. package/dist/src/openapi/auth.js.map +1 -0
  123. package/dist/src/openapi/document.d.ts +7 -3
  124. package/dist/src/openapi/document.js +49 -34
  125. package/dist/src/openapi/document.js.map +1 -1
  126. package/dist/src/openapi/entry.d.ts +2 -2
  127. package/dist/src/openapi/entry.js.map +1 -1
  128. package/dist/src/openapi/files.d.ts +6 -0
  129. package/dist/src/{files/openapi.js → openapi/files.js} +6 -3
  130. package/dist/src/openapi/files.js.map +1 -0
  131. package/dist/src/openapi/helpers.d.ts +10 -1
  132. package/dist/src/openapi/helpers.js +9 -0
  133. package/dist/src/openapi/helpers.js.map +1 -1
  134. package/dist/src/openapi/index.d.ts +7 -1
  135. package/dist/src/openapi/index.js +14 -5
  136. package/dist/src/openapi/index.js.map +1 -1
  137. package/dist/src/openapi/lazy.d.ts +11 -0
  138. package/dist/src/openapi/lazy.js +13 -0
  139. package/dist/src/openapi/lazy.js.map +1 -0
  140. package/dist/src/openapi/public.d.ts +11 -2
  141. package/dist/src/openapi/public.js +12 -4
  142. package/dist/src/openapi/public.js.map +1 -1
  143. package/dist/src/{types.d.ts → openapi/types.d.ts} +2 -10
  144. package/dist/src/openapi/types.js +2 -0
  145. package/dist/src/openapi/types.js.map +1 -0
  146. package/dist/src/rest/options.d.ts +11 -2
  147. package/dist/src/rest/options.js +12 -3
  148. package/dist/src/rest/options.js.map +1 -1
  149. package/dist/src/rest/projection.d.ts +10 -4
  150. package/dist/src/rest/projection.js +10 -4
  151. package/dist/src/rest/projection.js.map +1 -1
  152. package/dist/src/rest/routes.d.ts +6 -2
  153. package/dist/src/rest/routes.js +7 -3
  154. package/dist/src/rest/routes.js.map +1 -1
  155. package/dist/src/server/config.d.ts +79 -0
  156. package/dist/src/{config.js → server/config.js} +73 -12
  157. package/dist/src/server/config.js.map +1 -0
  158. package/dist/src/server/create.d.ts +18 -0
  159. package/dist/src/{server.js → server/create.js} +39 -21
  160. package/dist/src/server/create.js.map +1 -0
  161. package/dist/src/server/features.d.ts +15 -0
  162. package/dist/src/server/features.js +31 -0
  163. package/dist/src/server/features.js.map +1 -0
  164. package/dist/src/server/public.d.ts +3 -3
  165. package/dist/src/server/public.js +1 -1
  166. package/dist/src/server/public.js.map +1 -1
  167. package/package.json +5 -1
  168. package/dist/src/cli.d.ts +0 -4
  169. package/dist/src/cli.js.map +0 -1
  170. package/dist/src/config.d.ts +0 -81
  171. package/dist/src/config.js.map +0 -1
  172. package/dist/src/constants.js.map +0 -1
  173. package/dist/src/database.d.ts +0 -20
  174. package/dist/src/database.js.map +0 -1
  175. package/dist/src/engine.d.ts +0 -36
  176. package/dist/src/engine.js.map +0 -1
  177. package/dist/src/errors.d.ts +0 -6
  178. package/dist/src/errors.js +0 -9
  179. package/dist/src/errors.js.map +0 -1
  180. package/dist/src/features.d.ts +0 -8
  181. package/dist/src/features.js +0 -18
  182. package/dist/src/features.js.map +0 -1
  183. package/dist/src/files/openapi.d.ts +0 -3
  184. package/dist/src/files/openapi.js.map +0 -1
  185. package/dist/src/graphql.d.ts +0 -3
  186. package/dist/src/graphql.js.map +0 -1
  187. package/dist/src/http/errors.d.ts +0 -6
  188. package/dist/src/http/errors.js +0 -3
  189. package/dist/src/http/errors.js.map +0 -1
  190. package/dist/src/model.d.ts +0 -72
  191. package/dist/src/model.js.map +0 -1
  192. package/dist/src/mutations/write.js.map +0 -1
  193. package/dist/src/pagination.d.ts +0 -7
  194. package/dist/src/pagination.js.map +0 -1
  195. package/dist/src/paths.d.ts +0 -6
  196. package/dist/src/paths.js.map +0 -1
  197. package/dist/src/query/contract.d.ts +0 -3
  198. package/dist/src/query/contract.js.map +0 -1
  199. package/dist/src/query/filter.d.ts +0 -3
  200. package/dist/src/query/filter.js.map +0 -1
  201. package/dist/src/query/options.d.ts +0 -18
  202. package/dist/src/query/options.js.map +0 -1
  203. package/dist/src/records.d.ts +0 -25
  204. package/dist/src/records.js.map +0 -1
  205. package/dist/src/relation-metadata.d.ts +0 -9
  206. package/dist/src/relation-metadata.js.map +0 -1
  207. package/dist/src/schema.d.ts +0 -8
  208. package/dist/src/schema.js +0 -13
  209. package/dist/src/schema.js.map +0 -1
  210. package/dist/src/server.d.ts +0 -12
  211. package/dist/src/server.js.map +0 -1
  212. package/dist/src/utils.d.ts +0 -12
  213. package/dist/src/utils.js +0 -58
  214. package/dist/src/utils.js.map +0 -1
  215. /package/dist/src/{types.js → core/types.js} +0 -0
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import process from 'node:process';
3
- import { runCli } from '../src/cli.js';
3
+ import { runCli } from '../src/cli/index.js';
4
4
  try {
5
5
  await runCli();
6
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"deep-json-server.js","sourceRoot":"","sources":["../../bin/deep-json-server.ts"],"names":[],"mappings":";AAEA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,IAAI,CAAC;IACH,MAAM,MAAM,EAAE,CAAC;AACjB,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"deep-json-server.js","sourceRoot":"","sources":["../../bin/deep-json-server.ts"],"names":[],"mappings":";AAEA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,IAAI,CAAC;IACH,MAAM,MAAM,EAAE,CAAC;AACjB,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,14 @@
1
- export type { DatabaseConfig, DeepJsonServerConfig, FilesConfig, GraphqlConfig, MemoryFile, OpenapiConfig, ServerConfig } from './src/config.js';
2
- export type { ServerFeatures } from './src/features.js';
1
+ export type { AuthConfig, AuthSession, AuthUser, AuthUserRecord } from './src/auth/contract.js';
2
+ export { hashPassword } from './src/auth/public.js';
3
+ export type { EntityDefinition, Field, ModelSchema } from './src/core/model.js';
3
4
  export type { FileUpdate } from './src/files/contract.js';
4
5
  export type { FileMetadata } from './src/files/http.js';
5
- export type { EntityDefinition, Field, ModelSchema } from './src/model.js';
6
- export type { OpenapiOptions } from './src/schema.js';
7
- export { generateGraphql, generateOpenapi, writeGraphql, writeOpenapi } from './src/schema.js';
8
- export type { ServerFacade } from './src/server.js';
9
- export { createServer } from './src/server.js';
10
- export type { OpenapiDocument } from './src/types.js';
6
+ export { generateGraphql, writeGraphql } from './src/graphql/lazy.js';
7
+ export type { GraphqlOptions } from './src/graphql/public.js';
8
+ export { generateOpenapi, writeOpenapi } from './src/openapi/lazy.js';
9
+ export type { OpenapiOptions } from './src/openapi/public.js';
10
+ export type { OpenapiDocument } from './src/openapi/types.js';
11
+ export type { DatabaseConfig, DeepJsonServerConfig, FilesConfig, GraphqlConfig, MemoryFile, OpenapiConfig, ServerConfig } from './src/server/config.js';
12
+ export type { ServerFacade } from './src/server/create.js';
13
+ export { createServer } from './src/server/create.js';
14
+ export type { ServerFeatures } from './src/server/features.js';
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
- export { generateGraphql, generateOpenapi, writeGraphql, writeOpenapi } from './src/schema.js';
2
- export { createServer } from './src/server.js';
1
+ export { hashPassword } from './src/auth/public.js';
2
+ export { generateGraphql, writeGraphql } from './src/graphql/lazy.js';
3
+ export { generateOpenapi, writeOpenapi } from './src/openapi/lazy.js';
4
+ export { createServer } from './src/server/create.js';
3
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/F,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIpD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAKtE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,27 @@
1
+ export interface AuthUser {
2
+ id: string;
3
+ username: string;
4
+ isAdmin: boolean;
5
+ }
6
+ export interface AuthUserRecord extends Omit<AuthUser, 'isAdmin'> {
7
+ isAdmin?: boolean;
8
+ passwordHash: string;
9
+ }
10
+ export interface AuthConfig {
11
+ users: string | AuthUserRecord[];
12
+ /** Session lifetime in seconds. Defaults to one hour. */
13
+ expiresIn?: number;
14
+ }
15
+ export interface AuthSession {
16
+ accessToken: string;
17
+ expiresIn: number;
18
+ user: AuthUser;
19
+ }
20
+ export declare const AUTH_PATHS: {
21
+ readonly login: '/auth/login';
22
+ readonly me: '/auth/me';
23
+ readonly logout: '/auth/logout';
24
+ };
25
+ export declare const DEFAULT_SESSION_SECONDS = 3600;
26
+ export declare const MAX_USERNAME_LENGTH = 256;
27
+ export declare const MAX_PASSWORD_LENGTH = 1024;
@@ -0,0 +1,5 @@
1
+ export const AUTH_PATHS = { login: '/auth/login', me: '/auth/me', logout: '/auth/logout' };
2
+ export const DEFAULT_SESSION_SECONDS = 3600;
3
+ export const MAX_USERNAME_LENGTH = 256;
4
+ export const MAX_PASSWORD_LENGTH = 1024;
5
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/auth/contract.ts"],"names":[],"mappings":"AAmBA,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAW,CAAC;AACpG,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AACvC,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC"}
@@ -0,0 +1,13 @@
1
+ /** Проверяет формат строки с параметрами scrypt, солью и хешем; пароль не проверяет.
2
+ * @example validPasswordHash('plain text') → false.
3
+ */
4
+ export declare const validPasswordHash: (value: unknown) => value is string;
5
+ /** Создаёт хеш пароля со случайной солью и сохраняет параметры вычисления в строке.
6
+ * @example hashPassword('secret') → Promise<string> вида 'scrypt$16384$8$5$<соль>$<хеш>'; результат случаен.
7
+ */
8
+ export declare function hashPassword(password: string): Promise<string>;
9
+ /** Сравнивает пароль с сохранённым хешем за постоянное время после вычисления scrypt.
10
+ * @example verifyPassword('secret', await hashPassword('secret')) → true; другой пароль → false.
11
+ */
12
+ export declare function verifyPassword(password: string, encoded: string): Promise<boolean>;
13
+ export declare const DUMMY_HASH: string;
@@ -0,0 +1,37 @@
1
+ import { randomBytes, scrypt, timingSafeEqual } from 'node:crypto';
2
+ import { MAX_PASSWORD_LENGTH } from './contract.js';
3
+ // OWASP scrypt profile: N=2^14, r=8, p=5 (16 MiB memory).
4
+ const PREFIX = 'scrypt$16384$8$5';
5
+ const HASH_PATTERN = /^scrypt\$16384\$8\$5\$([0-9a-f]{32})\$([0-9a-f]{64})$/;
6
+ /** Проверяет формат строки с параметрами scrypt, солью и хешем; пароль не проверяет.
7
+ * @example validPasswordHash('plain text') → false.
8
+ */
9
+ export const validPasswordHash = (value) => typeof value === 'string' && HASH_PATTERN.test(value);
10
+ /** Вычисляет 32 байта scrypt для пароля и заданной соли.
11
+ * @example derive('secret', Buffer.alloc(16)) → Promise<Buffer> длиной 32 байта; одинаковые входы дают одинаковый результат.
12
+ */
13
+ const derive = (password, salt) => new Promise((resolve, reject) => {
14
+ scrypt(password, salt, 32, { N: 16384, r: 8, p: 5 }, (error, key) => (error ? reject(error) : resolve(key)));
15
+ });
16
+ /** Создаёт хеш пароля со случайной солью и сохраняет параметры вычисления в строке.
17
+ * @example hashPassword('secret') → Promise<string> вида 'scrypt$16384$8$5$<соль>$<хеш>'; результат случаен.
18
+ */
19
+ export async function hashPassword(password) {
20
+ if (typeof password !== 'string' || !password.length || password.length > MAX_PASSWORD_LENGTH)
21
+ throw new Error(`Password must contain 1..${MAX_PASSWORD_LENGTH} characters`);
22
+ const salt = randomBytes(16);
23
+ const hash = await derive(password, salt);
24
+ return `${PREFIX}$${salt.toString('hex')}$${hash.toString('hex')}`;
25
+ }
26
+ /** Сравнивает пароль с сохранённым хешем за постоянное время после вычисления scrypt.
27
+ * @example verifyPassword('secret', await hashPassword('secret')) → true; другой пароль → false.
28
+ */
29
+ export async function verifyPassword(password, encoded) {
30
+ const parts = HASH_PATTERN.exec(encoded);
31
+ if (!parts)
32
+ return false;
33
+ const actual = await derive(password, Buffer.from(parts[1], 'hex'));
34
+ return timingSafeEqual(actual, Buffer.from(parts[2], 'hex'));
35
+ }
36
+ export const DUMMY_HASH = `${PREFIX}$${'0'.repeat(32)}$${'0'.repeat(64)}`;
37
+ //# sourceMappingURL=password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.js","sourceRoot":"","sources":["../../../src/auth/password.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,0DAA0D;AAC1D,MAAM,MAAM,GAAG,kBAAkB,CAAC;AAClC,MAAM,YAAY,GAAG,uDAAuD,CAAC;AAC7E;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC5H;;GAEG;AACH,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAE,IAAY,EAAmB,EAAE,CACjE,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC9B,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC/G,CAAC,CAAC,CAAC;AACL;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,GAAG,mBAAmB;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,mBAAmB,aAAa,CAAC,CAAC;IAC7K,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC1C,OAAO,GAAG,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AACrE,CAAC;AACD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,OAAe;IACpE,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACpE,OAAO,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AAC/D,CAAC;AACD,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ export type { AuthConfig, AuthSession, AuthUser, AuthUserRecord } from './contract.js';
2
+ /** Creates a salted password hash for an auth user fixture. */
3
+ export declare function hashPassword(password: string): Promise<string>;
@@ -0,0 +1,5 @@
1
+ /** Creates a salted password hash for an auth user fixture. */
2
+ export async function hashPassword(password) {
3
+ return (await import('./password.js')).hashPassword(password);
4
+ }
5
+ //# sourceMappingURL=public.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/auth/public.ts"],"names":[],"mappings":"AACA,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,OAAO,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { AuthService } from './service.js';
3
+ /** Регистрирует вход, выход и получение текущего пользователя, запрещая кеширование ответов.
4
+ * @example После регистрации ответы содержат Cache-Control: no-store; функция возвращает undefined.
5
+ */
6
+ export declare function registerAuthRoutes(server: FastifyInstance, auth: AuthService): void;
@@ -0,0 +1,15 @@
1
+ import { AUTH_PATHS } from './contract.js';
2
+ /** Регистрирует вход, выход и получение текущего пользователя, запрещая кеширование ответов.
3
+ * @example После регистрации ответы содержат Cache-Control: no-store; функция возвращает undefined.
4
+ */
5
+ export function registerAuthRoutes(server, auth) {
6
+ server.register(async (app) => {
7
+ app.addHook('onRequest', async (_request, reply) => {
8
+ reply.header('Cache-Control', 'no-store');
9
+ });
10
+ app.post(AUTH_PATHS.login, async (request) => auth.login(request.body));
11
+ app.get(AUTH_PATHS.me, async (request) => auth.me(request.headers.authorization));
12
+ app.post(AUTH_PATHS.logout, async (request) => auth.logout(request.headers.authorization));
13
+ });
14
+ }
15
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/auth/routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAuB,EAAE,IAAiB;IAC3E,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC5B,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;YACjD,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACxE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;QAClF,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;IAC7F,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { type AuthConfig, type AuthSession, type AuthUser, type AuthUserRecord } from './contract.js';
2
+ export declare class AuthService {
3
+ private users;
4
+ private expiresIn;
5
+ private sessions;
6
+ private pendingLogins;
7
+ private closed;
8
+ constructor(users: Map<string, AuthUserRecord>, expiresIn: number);
9
+ /** Проверяет пароль, создаёт сессию и возвращает токен с публичными данными пользователя.
10
+ * @example Корректные username и password → { accessToken, expiresIn, user }; неверный пароль → исключение.
11
+ */
12
+ login(body: unknown): Promise<AuthSession>;
13
+ /** Проверяет Bearer-токен и возвращает копию публичных данных пользователя.
14
+ * @example Заголовок 'Bearer <действительный токен>' → { id, username, isAdmin }.
15
+ */
16
+ me(authorization: unknown): AuthUser;
17
+ /** Проверяет токен и удаляет соответствующую сессию.
18
+ * @example Действительный токен → { success: true }; повторный выход с ним → ошибка.
19
+ */
20
+ logout(authorization: unknown): {
21
+ success: boolean;
22
+ };
23
+ /** Запрещает новые входы и очищает учётные записи и сессии в памяти.
24
+ * @example close() → undefined; последующий login() → отказ.
25
+ */
26
+ close(): void;
27
+ /** Находит сессию по хешу токена и проверяет срок; просроченную сессию удаляет.
28
+ * @example Действительный Bearer-токен → [ключ, сессия]; отсутствующий или истёкший → ошибка.
29
+ */
30
+ private session;
31
+ /** Удаляет из памяти сессии, срок которых истёк к текущему моменту.
32
+ * @example Одна истёкшая и одна действующая сессия → остаётся одна действующая; результат undefined.
33
+ */
34
+ private prune;
35
+ }
36
+ /** Читает и проверяет учётные записи из массива или файла и создаёт хранилище сессий в памяти.
37
+ * @example createAuthService({ users: [] }) → Promise<AuthService>; повторяющиеся id → ошибка.
38
+ */
39
+ export declare function createAuthService(config: AuthConfig): Promise<AuthService>;
@@ -0,0 +1,143 @@
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { domainError } from '../core/errors.js';
4
+ import { hasOnlyKeys, isObject } from '../core/utils.js';
5
+ import { DEFAULT_SESSION_SECONDS, MAX_PASSWORD_LENGTH, MAX_USERNAME_LENGTH } from './contract.js';
6
+ import { DUMMY_HASH, validPasswordHash, verifyPassword } from './password.js';
7
+ /** Создаёт исключение отсутствия действительной сессии без раскрытия причины отказа.
8
+ * @example unauthorized() → Error с code = 'UNAUTHENTICATED'.
9
+ */
10
+ const unauthorized = () => domainError('UNAUTHENTICATED', 'Invalid credentials or expired session');
11
+ /** Вычисляет SHA-256 строки в шестнадцатеричном виде для хранения вместо исходного токена.
12
+ * @example tokenKey('abc') → 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'.
13
+ */
14
+ const tokenKey = (token) => createHash('sha256').update(token).digest('hex');
15
+ /** Возвращает публичные поля пользователя в новом объекте; отсутствие isAdmin означает false.
16
+ * @example publicUser({ id: '1', username: 'anna' }) → { id: '1', username: 'anna', isAdmin: false }.
17
+ */
18
+ const publicUser = (user) => ({ id: user.id, username: user.username, isAdmin: user.isAdmin ?? false });
19
+ export class AuthService {
20
+ users;
21
+ expiresIn;
22
+ sessions = new Map();
23
+ pendingLogins = 0;
24
+ closed = false;
25
+ constructor(users, expiresIn) {
26
+ this.users = users;
27
+ this.expiresIn = expiresIn;
28
+ }
29
+ /** Проверяет пароль, создаёт сессию и возвращает токен с публичными данными пользователя.
30
+ * @example Корректные username и password → { accessToken, expiresIn, user }; неверный пароль → исключение.
31
+ */
32
+ async login(body) {
33
+ if (!isObject(body) ||
34
+ !hasOnlyKeys(body, ['username', 'password']) ||
35
+ typeof body.username !== 'string' ||
36
+ !body.username.length ||
37
+ body.username.length > MAX_USERNAME_LENGTH ||
38
+ typeof body.password !== 'string' ||
39
+ !body.password.length ||
40
+ body.password.length > MAX_PASSWORD_LENGTH)
41
+ throw domainError('INVALID_INPUT', 'Supply username and password');
42
+ if (this.closed)
43
+ throw unauthorized();
44
+ if (this.pendingLogins >= 4)
45
+ throw domainError('TOO_MANY_REQUESTS', 'Too many simultaneous login attempts');
46
+ this.pendingLogins++;
47
+ let user;
48
+ let valid;
49
+ try {
50
+ user = this.users.get(body.username);
51
+ valid = await verifyPassword(body.password, user?.passwordHash ?? DUMMY_HASH);
52
+ }
53
+ finally {
54
+ this.pendingLogins--;
55
+ }
56
+ if (!user || !valid || this.closed)
57
+ throw unauthorized();
58
+ this.prune();
59
+ if (this.sessions.size >= 10000)
60
+ throw domainError('TOO_MANY_REQUESTS', 'Session limit reached');
61
+ const accessToken = randomBytes(32).toString('base64url');
62
+ const identity = publicUser(user);
63
+ this.sessions.set(tokenKey(accessToken), { user: identity, expiresAt: Date.now() + this.expiresIn * 1000 });
64
+ return { accessToken, expiresIn: this.expiresIn, user: publicUser(identity) };
65
+ }
66
+ /** Проверяет Bearer-токен и возвращает копию публичных данных пользователя.
67
+ * @example Заголовок 'Bearer <действительный токен>' → { id, username, isAdmin }.
68
+ */
69
+ me(authorization) {
70
+ const [, session] = this.session(authorization);
71
+ return publicUser(session.user);
72
+ }
73
+ /** Проверяет токен и удаляет соответствующую сессию.
74
+ * @example Действительный токен → { success: true }; повторный выход с ним → ошибка.
75
+ */
76
+ logout(authorization) {
77
+ const [key] = this.session(authorization);
78
+ this.sessions.delete(key);
79
+ return { success: true };
80
+ }
81
+ /** Запрещает новые входы и очищает учётные записи и сессии в памяти.
82
+ * @example close() → undefined; последующий login() → отказ.
83
+ */
84
+ close() {
85
+ this.closed = true;
86
+ this.sessions.clear();
87
+ this.users.clear();
88
+ }
89
+ /** Находит сессию по хешу токена и проверяет срок; просроченную сессию удаляет.
90
+ * @example Действительный Bearer-токен → [ключ, сессия]; отсутствующий или истёкший → ошибка.
91
+ */
92
+ session(authorization) {
93
+ if (typeof authorization !== 'string')
94
+ throw unauthorized();
95
+ const match = /^Bearer ([A-Za-z0-9_-]{43})$/i.exec(authorization);
96
+ if (!match)
97
+ throw unauthorized();
98
+ const key = tokenKey(match[1]);
99
+ const session = this.sessions.get(key);
100
+ if (!session || session.expiresAt <= Date.now()) {
101
+ this.sessions.delete(key);
102
+ throw unauthorized();
103
+ }
104
+ return [key, session];
105
+ }
106
+ /** Удаляет из памяти сессии, срок которых истёк к текущему моменту.
107
+ * @example Одна истёкшая и одна действующая сессия → остаётся одна действующая; результат undefined.
108
+ */
109
+ prune() {
110
+ const now = Date.now();
111
+ for (const [key, session] of this.sessions)
112
+ if (session.expiresAt <= now)
113
+ this.sessions.delete(key);
114
+ }
115
+ }
116
+ /** Читает и проверяет учётные записи из массива или файла и создаёт хранилище сессий в памяти.
117
+ * @example createAuthService({ users: [] }) → Promise<AuthService>; повторяющиеся id → ошибка.
118
+ */
119
+ export async function createAuthService(config) {
120
+ const records = typeof config.users === 'string' ? JSON.parse(await readFile(config.users, 'utf8')) : config.users;
121
+ if (!Array.isArray(records))
122
+ throw new Error('Auth users must be an array');
123
+ const users = new Map();
124
+ const ids = new Set();
125
+ for (const record of records) {
126
+ if (!isObject(record) ||
127
+ !hasOnlyKeys(record, ['id', 'username', 'passwordHash', 'isAdmin']) ||
128
+ typeof record.id !== 'string' ||
129
+ !record.id.trim() ||
130
+ typeof record.username !== 'string' ||
131
+ !record.username.trim() ||
132
+ record.username.length > MAX_USERNAME_LENGTH ||
133
+ !validPasswordHash(record.passwordHash) ||
134
+ (record.isAdmin !== undefined && typeof record.isAdmin !== 'boolean'))
135
+ throw new Error('Auth users require id, username and a valid passwordHash');
136
+ if (ids.has(record.id) || users.has(record.username))
137
+ throw new Error('Auth user ids and usernames must be unique');
138
+ ids.add(record.id);
139
+ users.set(record.username, { id: record.id, username: record.username, passwordHash: record.passwordHash, isAdmin: record.isAdmin ?? false });
140
+ }
141
+ return new AuthService(users, config.expiresIn ?? DEFAULT_SESSION_SECONDS);
142
+ }
143
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/auth/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { createConfiguredServer } from '../server/create.js';
2
+ /** Разбирает аргументы командной строки и запускает сервер либо экспорт; справку и версию пишет в stdout.
3
+ * @example runCli(['--help']) → Promise<void> и текст справки без запуска сервера.
4
+ */
5
+ export declare function runCli(args?: string[], services?: {
6
+ createServer: typeof createConfiguredServer;
7
+ }): Promise<void>;
@@ -1,17 +1,20 @@
1
1
  import process from 'node:process';
2
- import { configure, configureGeneration, readConfigModule } from './config.js';
3
- import { DEFAULT_HOST, DEFAULT_PORT, VERSION } from './constants.js';
4
- import { resolveFeatures } from './features.js';
5
- import { inputPaths, validateExportPaths } from './paths.js';
6
- import { generateGraphql, generateOpenapi, writeGraphql, writeOpenapi } from './schema.js';
7
- import { createConfiguredServer } from './server.js';
8
- import { isObject } from './utils.js';
2
+ import { DEFAULT_HOST, DEFAULT_PORT, VERSION } from '../core/constants.js';
3
+ import { inputPaths, validateExportPaths } from '../core/paths.js';
4
+ import { isObject } from '../core/utils.js';
5
+ import { generateGraphql, writeGraphql } from '../graphql/lazy.js';
6
+ import { generateOpenapi, writeOpenapi } from '../openapi/lazy.js';
7
+ import { configure, configureGeneration, readConfigModule } from '../server/config.js';
8
+ import { createConfiguredServer } from '../server/create.js';
9
+ import { resolveFeatures } from '../server/features.js';
9
10
  const HELP_TEXT = `Deep JSON Server
10
11
 
11
12
  Usage:
12
13
  deep-json-server [options] <server.config.js>
13
14
  deep-json-server generate <openapi|graphql|openapi,graphql> <server.config.js>
14
15
 
16
+ --timestamps Track record creation and update times
17
+ --soft-delete Mark deleted records instead of removing them
15
18
  --files Enable file routes
16
19
  --graphql Enable the GraphQL endpoint
17
20
  --openapi Enable the OpenAPI endpoint
@@ -21,6 +24,9 @@ Usage:
21
24
  --version, -v Show version
22
25
 
23
26
  Files are enabled when configured. Generate writes schemas to the configured paths.`;
27
+ /** Разбирает аргументы командной строки и запускает сервер либо экспорт; справку и версию пишет в stdout.
28
+ * @example runCli(['--help']) → Promise<void> и текст справки без запуска сервера.
29
+ */
24
30
  export async function runCli(args = process.argv.slice(2), services = { createServer: createConfiguredServer }) {
25
31
  if (args.includes('--help') || args.includes('-h')) {
26
32
  process.stdout.write(`${HELP_TEXT}\n`);
@@ -33,6 +39,7 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
33
39
  const positional = [];
34
40
  const seen = new Set();
35
41
  const features = {};
42
+ const recordFlags = {};
36
43
  let host;
37
44
  let port;
38
45
  for (let index = 0; index < args.length; index++) {
@@ -41,7 +48,7 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
41
48
  positional.push(arg);
42
49
  continue;
43
50
  }
44
- if (!['--files', '--graphql', '--openapi', '--host', '--port'].includes(arg) || seen.has(arg))
51
+ if (!['--files', '--graphql', '--openapi', '--timestamps', '--soft-delete', '--host', '--port'].includes(arg) || seen.has(arg))
45
52
  throw new Error(`Неизвестный параметр или повтор: ${arg}`);
46
53
  seen.add(arg);
47
54
  if (arg === '--host' || arg === '--port') {
@@ -56,6 +63,10 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
56
63
  port = Number(value);
57
64
  }
58
65
  }
66
+ else if (arg === '--timestamps')
67
+ recordFlags.timestamps = true;
68
+ else if (arg === '--soft-delete')
69
+ recordFlags.softDelete = true;
59
70
  else
60
71
  features[arg.slice(2)] = true;
61
72
  }
@@ -76,8 +87,12 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
76
87
  throw new Error('config.server must be an object');
77
88
  const overrides = { host: host ?? serverOptions.host ?? process.env.HOST ?? DEFAULT_HOST, port: port ?? serverOptions.port ?? Number(process.env.PORT ?? DEFAULT_PORT) };
78
89
  const config = generate
79
- ? configureGeneration(source.config, formats, source.directory, source.path, { ...overrides, files: features.files })
80
- : configure({ ...source.config, server: { ...serverOptions, ...overrides } }, source.directory, source.path);
90
+ ? configureGeneration(source.config, formats, source.directory, source.path, { ...overrides, files: features.files, ...recordFlags })
91
+ : configure({
92
+ ...source.config,
93
+ ...(Object.keys(recordFlags).length ? { database: { ...(isObject(source.config.database) ? source.config.database : {}), ...recordFlags } } : {}),
94
+ server: { ...serverOptions, ...overrides },
95
+ }, source.directory, source.path);
81
96
  if (generate) {
82
97
  if (!config.database.schema)
83
98
  throw new Error('Generation requires an explicit model schema');
@@ -91,6 +106,9 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
91
106
  const openapi = formats.includes('openapi')
92
107
  ? await generateOpenapi(config.database.schema, {
93
108
  files: config.files != null,
109
+ auth: config.auth != null,
110
+ timestamps: config.database.timestamps,
111
+ softDelete: config.database.softDelete,
94
112
  host: config.server.host,
95
113
  port: config.server.port,
96
114
  pageSize: config.server.pageSize,
@@ -98,7 +116,9 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
98
116
  info: config.openapi.info,
99
117
  })
100
118
  : undefined;
101
- const graphql = formats.includes('graphql') ? await generateGraphql(config.database.schema) : undefined;
119
+ const graphql = formats.includes('graphql')
120
+ ? await generateGraphql(config.database.schema, { auth: config.auth != null, timestamps: config.database.timestamps, softDelete: config.database.softDelete })
121
+ : undefined;
102
122
  if (openapi) {
103
123
  await writeOpenapi(openapi, config.openapi.path);
104
124
  process.stdout.write(`OpenAPI: ${config.openapi.path}\n`);
@@ -113,4 +133,4 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
113
133
  await server.listen();
114
134
  server.log.info('Deep JSON Server started');
115
135
  }
116
- //# sourceMappingURL=cli.js.map
136
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -3,4 +3,4 @@ export declare const DEFAULT_MAX_FILE_SIZE: number;
3
3
  export declare const DEFAULT_MAX_PAGE_SIZE = 100;
4
4
  export declare const DEFAULT_PAGE_SIZE = 10;
5
5
  export declare const DEFAULT_PORT = 4001;
6
- export declare const VERSION = "1.0.0-alpha.5";
6
+ export declare const VERSION = "1.0.0-alpha.7";
@@ -3,5 +3,5 @@ export const DEFAULT_MAX_FILE_SIZE = 100 * 1024 * 1024;
3
3
  export const DEFAULT_MAX_PAGE_SIZE = 100;
4
4
  export const DEFAULT_PAGE_SIZE = 10;
5
5
  export const DEFAULT_PORT = 4001;
6
- export const VERSION = '1.0.0-alpha.5';
6
+ export const VERSION = '1.0.0-alpha.7';
7
7
  //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/core/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC;AACxC,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AACvD,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AACzC,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AACpC,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC;AACjC,MAAM,CAAC,MAAM,OAAO,GAAG,eAAe,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { RecordOptions } from './lifecycle/options.js';
2
+ import type { ModelSchema } from './model.js';
3
+ import type { DatabaseData, DatabaseRecord } from './types.js';
4
+ export type DatabaseConfig = Pick<RecordOptions, 'timestamps' | 'softDelete'> & ({
5
+ data: DatabaseData;
6
+ path?: never;
7
+ schema?: ModelSchema | string;
8
+ } | {
9
+ data?: never;
10
+ path: string;
11
+ schema?: ModelSchema | string;
12
+ });
13
+ export interface DatabaseContainer {
14
+ data: DatabaseData;
15
+ counters?: Record<string, number>;
16
+ }
17
+ export interface DatabaseStore {
18
+ database: DatabaseContainer;
19
+ path?: string;
20
+ read(): Promise<DatabaseData>;
21
+ update<T>(operation: (database: DatabaseContainer) => T): Promise<T>;
22
+ }
23
+ /** Проверяет сериализуемое JSON-значение; отвергает циклы, разреженные массивы, NaN и бесконечности.
24
+ * @example validateJsonValue({ a: [1, null] }, 'data') → undefined; NaN → ошибка.
25
+ */
26
+ export declare const validateJsonValue: (value: unknown, path: string, ancestors?: WeakSet<object>) => void;
27
+ /** Проверяет объект коллекций, записи и уникальность ключей; возвращает исходный объект.
28
+ * @example validateDatabase({ notes: [{ id: '1' }] }) → тот же объект; повторный id → ошибка.
29
+ */
30
+ export declare const validateDatabase: (data: unknown, primaryKeys?: Map<string, string>) => DatabaseData;
31
+ /** Читает UTF-8 JSON-файл и проверяет, что верхний уровень является объектом.
32
+ * @example Файл с {"a":1} → Promise<{ a: 1 }>; файл с [] → ошибка.
33
+ */
34
+ export declare const readJsonObjectFile: (path: string, label: string) => Promise<Record<string, unknown>>;
35
+ /** Читает файл и проверяет коллекции и первичные ключи.
36
+ * @example Файл с {"notes":[]} → Promise<{ notes: [] }>.
37
+ */
38
+ export declare const readDatabaseFile: (databasePath: string, keys?: Map<string, string>) => Promise<DatabaseData>;
39
+ /** Создаёт дисковое хранилище или хранилище в памяти по настройкам.
40
+ * @example createDatabaseStore({ data: { notes: [] } }) → Promise<DatabaseStore>.
41
+ */
42
+ export declare const createDatabaseStore: (config: DatabaseConfig, keys?: Map<string, string>) => Promise<DatabaseStore>;
43
+ /** Ищет индекс записи, сравнивая строковые представления id.
44
+ * @example findItemIndex([{ id: 1 }], '1') → 0; пустой массив → -1.
45
+ */
46
+ export declare const findItemIndex: (collection: DatabaseRecord[], id: unknown) => number;
47
+ /** Генерирует случайный строковый id, отсутствующий в переданной коллекции.
48
+ * @example createId([]) → строка из 11 символов; конкретное значение зависит от генератора случайных чисел.
49
+ */
50
+ export declare const createId: (collection: DatabaseRecord[]) => string;