@kollors/deep-json-server 1.0.0-alpha.6 → 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.
- package/README.md +344 -230
- package/README.ru.md +341 -227
- package/dist/bin/deep-json-server.js +1 -1
- package/dist/bin/deep-json-server.js.map +1 -1
- package/dist/index.d.ts +10 -8
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/src/auth/contract.d.ts +3 -2
- package/dist/src/auth/contract.js.map +1 -1
- package/dist/src/auth/password.d.ts +9 -0
- package/dist/src/auth/password.js +12 -0
- package/dist/src/auth/password.js.map +1 -1
- package/dist/src/auth/routes.d.ts +3 -0
- package/dist/src/auth/routes.js +3 -0
- package/dist/src/auth/routes.js.map +1 -1
- package/dist/src/auth/service.d.ts +21 -0
- package/dist/src/auth/service.js +38 -7
- package/dist/src/auth/service.js.map +1 -1
- package/dist/src/cli/index.d.ts +7 -0
- package/dist/src/{cli.js → cli/index.js} +32 -14
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/{constants.d.ts → core/constants.d.ts} +1 -1
- package/dist/src/{constants.js → core/constants.js} +1 -1
- package/dist/src/core/constants.js.map +1 -0
- package/dist/src/core/database.d.ts +50 -0
- package/dist/src/{database.js → core/database.js} +21 -1
- package/dist/src/core/database.js.map +1 -0
- package/dist/src/core/engine.d.ts +64 -0
- package/dist/src/{engine.js → core/engine.js} +64 -18
- package/dist/src/core/engine.js.map +1 -0
- package/dist/src/{errors.d.ts → core/errors.d.ts} +4 -1
- package/dist/src/core/errors.js +12 -0
- package/dist/src/core/errors.js.map +1 -0
- package/dist/src/core/http-errors.d.ts +9 -0
- package/dist/src/core/http-errors.js +15 -0
- package/dist/src/core/http-errors.js.map +1 -0
- package/dist/src/core/lifecycle/mutation.d.ts +49 -0
- package/dist/src/core/lifecycle/mutation.js +170 -0
- package/dist/src/core/lifecycle/mutation.js.map +1 -0
- package/dist/src/core/lifecycle/options.d.ts +20 -0
- package/dist/src/core/lifecycle/options.js +21 -0
- package/dist/src/core/lifecycle/options.js.map +1 -0
- package/dist/src/core/model.d.ts +130 -0
- package/dist/src/{model.js → core/model.js} +106 -10
- package/dist/src/core/model.js.map +1 -0
- package/dist/src/{mutations → core/mutations}/write.d.ts +3 -2
- package/dist/src/{mutations → core/mutations}/write.js +14 -4
- package/dist/src/core/mutations/write.js.map +1 -0
- package/dist/src/core/pagination.d.ts +10 -0
- package/dist/src/{pagination.js → core/pagination.js} +3 -0
- package/dist/src/core/pagination.js.map +1 -0
- package/dist/src/core/paths.d.ts +16 -0
- package/dist/src/{paths.js → core/paths.js} +12 -0
- package/dist/src/core/paths.js.map +1 -0
- package/dist/src/core/query/contract.d.ts +6 -0
- package/dist/src/{query → core/query}/contract.js +3 -0
- package/dist/src/core/query/contract.js.map +1 -0
- package/dist/src/core/query/filter.d.ts +6 -0
- package/dist/src/{query → core/query}/filter.js +18 -4
- package/dist/src/core/query/filter.js.map +1 -0
- package/dist/src/core/query/options.d.ts +30 -0
- package/dist/src/{query → core/query}/options.js +12 -0
- package/dist/src/core/query/options.js.map +1 -0
- package/dist/src/core/records.d.ts +46 -0
- package/dist/src/{records.js → core/records.js} +24 -3
- package/dist/src/core/records.js.map +1 -0
- package/dist/src/core/relation-metadata.d.ts +15 -0
- package/dist/src/{relation-metadata.js → core/relation-metadata.js} +7 -1
- package/dist/src/core/relation-metadata.js.map +1 -0
- package/dist/src/core/types.d.ts +10 -0
- package/dist/src/{types.js.map → core/types.js.map} +1 -1
- package/dist/src/core/utils.d.ts +56 -0
- package/dist/src/core/utils.js +102 -0
- package/dist/src/core/utils.js.map +1 -0
- package/dist/src/files/contract.d.ts +33 -0
- package/dist/src/files/contract.js +25 -3
- package/dist/src/files/contract.js.map +1 -1
- package/dist/src/files/disk-store.d.ts +3 -0
- package/dist/src/files/disk-store.js +27 -3
- package/dist/src/files/disk-store.js.map +1 -1
- package/dist/src/files/http.d.ts +8 -3
- package/dist/src/files/http.js +9 -0
- package/dist/src/files/http.js.map +1 -1
- package/dist/src/files/index.d.ts +4 -3
- package/dist/src/files/index.js +3 -1
- package/dist/src/files/index.js.map +1 -1
- package/dist/src/files/memory-store.d.ts +4 -1
- package/dist/src/files/memory-store.js +8 -2
- package/dist/src/files/memory-store.js.map +1 -1
- package/dist/src/files/routes.d.ts +3 -0
- package/dist/src/files/routes.js +25 -1
- package/dist/src/files/routes.js.map +1 -1
- package/dist/src/graphql/entry.d.ts +2 -2
- package/dist/src/graphql/entry.js.map +1 -1
- package/dist/src/graphql/lazy.d.ts +10 -0
- package/dist/src/graphql/lazy.js +13 -0
- package/dist/src/graphql/lazy.js.map +1 -0
- package/dist/src/graphql/preflight.d.ts +4 -1
- package/dist/src/graphql/preflight.js +3 -0
- package/dist/src/graphql/preflight.js.map +1 -1
- package/dist/src/graphql/public.d.ts +10 -2
- package/dist/src/graphql/public.js +10 -4
- package/dist/src/graphql/public.js.map +1 -1
- package/dist/src/graphql/resolvers.d.ts +10 -2
- package/dist/src/graphql/resolvers.js +8 -2
- package/dist/src/graphql/resolvers.js.map +1 -1
- package/dist/src/graphql/routes.d.ts +6 -2
- package/dist/src/graphql/routes.js +6 -3
- package/dist/src/graphql/routes.js.map +1 -1
- package/dist/src/graphql/schema.d.ts +6 -0
- package/dist/src/{graphql.js → graphql/schema.js} +14 -11
- package/dist/src/graphql/schema.js.map +1 -0
- package/dist/src/graphql/write.d.ts +3 -0
- package/dist/src/graphql/write.js +3 -0
- package/dist/src/graphql/write.js.map +1 -1
- package/dist/src/openapi/auth.d.ts +13 -0
- package/dist/src/{auth/openapi.js → openapi/auth.js} +15 -5
- package/dist/src/openapi/auth.js.map +1 -0
- package/dist/src/openapi/document.d.ts +5 -2
- package/dist/src/openapi/document.js +29 -33
- package/dist/src/openapi/document.js.map +1 -1
- package/dist/src/openapi/entry.d.ts +2 -2
- package/dist/src/openapi/entry.js.map +1 -1
- package/dist/src/openapi/files.d.ts +6 -0
- package/dist/src/{files/openapi.js → openapi/files.js} +6 -3
- package/dist/src/openapi/files.js.map +1 -0
- package/dist/src/openapi/helpers.d.ts +10 -1
- package/dist/src/openapi/helpers.js +9 -0
- package/dist/src/openapi/helpers.js.map +1 -1
- package/dist/src/openapi/index.d.ts +7 -1
- package/dist/src/openapi/index.js +14 -5
- package/dist/src/openapi/index.js.map +1 -1
- package/dist/src/openapi/lazy.d.ts +11 -0
- package/dist/src/openapi/lazy.js +13 -0
- package/dist/src/openapi/lazy.js.map +1 -0
- package/dist/src/openapi/public.d.ts +10 -2
- package/dist/src/openapi/public.js +9 -3
- package/dist/src/openapi/public.js.map +1 -1
- package/dist/src/{types.d.ts → openapi/types.d.ts} +1 -10
- package/dist/src/openapi/types.js +2 -0
- package/dist/src/openapi/types.js.map +1 -0
- package/dist/src/rest/options.d.ts +11 -2
- package/dist/src/rest/options.js +12 -3
- package/dist/src/rest/options.js.map +1 -1
- package/dist/src/rest/projection.d.ts +10 -4
- package/dist/src/rest/projection.js +10 -4
- package/dist/src/rest/projection.js.map +1 -1
- package/dist/src/rest/routes.d.ts +6 -2
- package/dist/src/rest/routes.js +7 -3
- package/dist/src/rest/routes.js.map +1 -1
- package/dist/src/server/config.d.ts +79 -0
- package/dist/src/{config.js → server/config.js} +57 -19
- package/dist/src/server/config.js.map +1 -0
- package/dist/src/server/create.d.ts +18 -0
- package/dist/src/{server.js → server/create.js} +31 -23
- package/dist/src/server/create.js.map +1 -0
- package/dist/src/server/features.d.ts +15 -0
- package/dist/src/{features.js → server/features.js} +8 -2
- package/dist/src/server/features.js.map +1 -0
- package/dist/src/server/public.d.ts +3 -3
- package/dist/src/server/public.js +1 -1
- package/dist/src/server/public.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/auth/openapi.d.ts +0 -10
- package/dist/src/auth/openapi.js.map +0 -1
- package/dist/src/cli.d.ts +0 -4
- package/dist/src/cli.js.map +0 -1
- package/dist/src/config.d.ts +0 -86
- package/dist/src/config.js.map +0 -1
- package/dist/src/constants.js.map +0 -1
- package/dist/src/database.d.ts +0 -20
- package/dist/src/database.js.map +0 -1
- package/dist/src/engine.d.ts +0 -36
- package/dist/src/engine.js.map +0 -1
- package/dist/src/errors.js +0 -9
- package/dist/src/errors.js.map +0 -1
- package/dist/src/features.d.ts +0 -9
- package/dist/src/features.js.map +0 -1
- package/dist/src/files/openapi.d.ts +0 -3
- package/dist/src/files/openapi.js.map +0 -1
- package/dist/src/graphql.d.ts +0 -3
- package/dist/src/graphql.js.map +0 -1
- package/dist/src/http/errors.d.ts +0 -6
- package/dist/src/http/errors.js +0 -3
- package/dist/src/http/errors.js.map +0 -1
- package/dist/src/model.d.ts +0 -72
- package/dist/src/model.js.map +0 -1
- package/dist/src/mutations/write.js.map +0 -1
- package/dist/src/pagination.d.ts +0 -7
- package/dist/src/pagination.js.map +0 -1
- package/dist/src/paths.d.ts +0 -7
- package/dist/src/paths.js.map +0 -1
- package/dist/src/query/contract.d.ts +0 -3
- package/dist/src/query/contract.js.map +0 -1
- package/dist/src/query/filter.d.ts +0 -3
- package/dist/src/query/filter.js.map +0 -1
- package/dist/src/query/options.d.ts +0 -18
- package/dist/src/query/options.js.map +0 -1
- package/dist/src/records.d.ts +0 -25
- package/dist/src/records.js.map +0 -1
- package/dist/src/relation-metadata.d.ts +0 -9
- package/dist/src/relation-metadata.js.map +0 -1
- package/dist/src/schema.d.ts +0 -8
- package/dist/src/schema.js +0 -13
- package/dist/src/schema.js.map +0 -1
- package/dist/src/server.d.ts +0 -12
- package/dist/src/server.js.map +0 -1
- package/dist/src/utils.d.ts +0 -12
- package/dist/src/utils.js +0 -58
- package/dist/src/utils.js.map +0 -1
- /package/dist/src/{types.js → core/types.js} +0 -0
|
@@ -1 +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,
|
|
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,12 +1,14 @@
|
|
|
1
1
|
export type { AuthConfig, AuthSession, AuthUser, AuthUserRecord } from './src/auth/contract.js';
|
|
2
2
|
export { hashPassword } from './src/auth/public.js';
|
|
3
|
-
export type {
|
|
4
|
-
export type { ServerFeatures } from './src/features.js';
|
|
3
|
+
export type { EntityDefinition, Field, ModelSchema } from './src/core/model.js';
|
|
5
4
|
export type { FileUpdate } from './src/files/contract.js';
|
|
6
5
|
export type { FileMetadata } from './src/files/http.js';
|
|
7
|
-
export
|
|
8
|
-
export type {
|
|
9
|
-
export {
|
|
10
|
-
export type {
|
|
11
|
-
export {
|
|
12
|
-
export type {
|
|
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,4 +1,5 @@
|
|
|
1
1
|
export { hashPassword } from './src/auth/public.js';
|
|
2
|
-
export { generateGraphql,
|
|
3
|
-
export {
|
|
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';
|
|
4
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":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,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"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
export interface AuthUser {
|
|
2
2
|
id: string;
|
|
3
3
|
username: string;
|
|
4
|
+
isAdmin: boolean;
|
|
4
5
|
}
|
|
5
|
-
export interface AuthUserRecord extends AuthUser {
|
|
6
|
+
export interface AuthUserRecord extends Omit<AuthUser, 'isAdmin'> {
|
|
7
|
+
isAdmin?: boolean;
|
|
6
8
|
passwordHash: string;
|
|
7
9
|
}
|
|
8
10
|
export interface AuthConfig {
|
|
9
|
-
enabled?: boolean;
|
|
10
11
|
users: string | AuthUserRecord[];
|
|
11
12
|
/** Session lifetime in seconds. Defaults to one hour. */
|
|
12
13
|
expiresIn?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/auth/contract.ts"],"names":[],"mappings":"
|
|
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"}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
/** Проверяет формат строки с параметрами scrypt, солью и хешем; пароль не проверяет.
|
|
2
|
+
* @example validPasswordHash('plain text') → false.
|
|
3
|
+
*/
|
|
1
4
|
export declare const validPasswordHash: (value: unknown) => value is string;
|
|
5
|
+
/** Создаёт хеш пароля со случайной солью и сохраняет параметры вычисления в строке.
|
|
6
|
+
* @example hashPassword('secret') → Promise<string> вида 'scrypt$16384$8$5$<соль>$<хеш>'; результат случаен.
|
|
7
|
+
*/
|
|
2
8
|
export declare function hashPassword(password: string): Promise<string>;
|
|
9
|
+
/** Сравнивает пароль с сохранённым хешем за постоянное время после вычисления scrypt.
|
|
10
|
+
* @example verifyPassword('secret', await hashPassword('secret')) → true; другой пароль → false.
|
|
11
|
+
*/
|
|
3
12
|
export declare function verifyPassword(password: string, encoded: string): Promise<boolean>;
|
|
4
13
|
export declare const DUMMY_HASH: string;
|
|
@@ -3,10 +3,19 @@ import { MAX_PASSWORD_LENGTH } from './contract.js';
|
|
|
3
3
|
// OWASP scrypt profile: N=2^14, r=8, p=5 (16 MiB memory).
|
|
4
4
|
const PREFIX = 'scrypt$16384$8$5';
|
|
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
|
+
*/
|
|
6
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
|
+
*/
|
|
7
13
|
const derive = (password, salt) => new Promise((resolve, reject) => {
|
|
8
14
|
scrypt(password, salt, 32, { N: 16384, r: 8, p: 5 }, (error, key) => (error ? reject(error) : resolve(key)));
|
|
9
15
|
});
|
|
16
|
+
/** Создаёт хеш пароля со случайной солью и сохраняет параметры вычисления в строке.
|
|
17
|
+
* @example hashPassword('secret') → Promise<string> вида 'scrypt$16384$8$5$<соль>$<хеш>'; результат случаен.
|
|
18
|
+
*/
|
|
10
19
|
export async function hashPassword(password) {
|
|
11
20
|
if (typeof password !== 'string' || !password.length || password.length > MAX_PASSWORD_LENGTH)
|
|
12
21
|
throw new Error(`Password must contain 1..${MAX_PASSWORD_LENGTH} characters`);
|
|
@@ -14,6 +23,9 @@ export async function hashPassword(password) {
|
|
|
14
23
|
const hash = await derive(password, salt);
|
|
15
24
|
return `${PREFIX}$${salt.toString('hex')}$${hash.toString('hex')}`;
|
|
16
25
|
}
|
|
26
|
+
/** Сравнивает пароль с сохранённым хешем за постоянное время после вычисления scrypt.
|
|
27
|
+
* @example verifyPassword('secret', await hashPassword('secret')) → true; другой пароль → false.
|
|
28
|
+
*/
|
|
17
29
|
export async function verifyPassword(password, encoded) {
|
|
18
30
|
const parts = HASH_PATTERN.exec(encoded);
|
|
19
31
|
if (!parts)
|
|
@@ -1 +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,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC5H,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,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,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"}
|
|
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"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import type { FastifyInstance } from 'fastify';
|
|
2
2
|
import type { AuthService } from './service.js';
|
|
3
|
+
/** Регистрирует вход, выход и получение текущего пользователя, запрещая кеширование ответов.
|
|
4
|
+
* @example После регистрации ответы содержат Cache-Control: no-store; функция возвращает undefined.
|
|
5
|
+
*/
|
|
3
6
|
export declare function registerAuthRoutes(server: FastifyInstance, auth: AuthService): void;
|
package/dist/src/auth/routes.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { AUTH_PATHS } from './contract.js';
|
|
2
|
+
/** Регистрирует вход, выход и получение текущего пользователя, запрещая кеширование ответов.
|
|
3
|
+
* @example После регистрации ответы содержат Cache-Control: no-store; функция возвращает undefined.
|
|
4
|
+
*/
|
|
2
5
|
export function registerAuthRoutes(server, auth) {
|
|
3
6
|
server.register(async (app) => {
|
|
4
7
|
app.addHook('onRequest', async (_request, reply) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/auth/routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,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"}
|
|
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"}
|
|
@@ -6,13 +6,34 @@ export declare class AuthService {
|
|
|
6
6
|
private pendingLogins;
|
|
7
7
|
private closed;
|
|
8
8
|
constructor(users: Map<string, AuthUserRecord>, expiresIn: number);
|
|
9
|
+
/** Проверяет пароль, создаёт сессию и возвращает токен с публичными данными пользователя.
|
|
10
|
+
* @example Корректные username и password → { accessToken, expiresIn, user }; неверный пароль → исключение.
|
|
11
|
+
*/
|
|
9
12
|
login(body: unknown): Promise<AuthSession>;
|
|
13
|
+
/** Проверяет Bearer-токен и возвращает копию публичных данных пользователя.
|
|
14
|
+
* @example Заголовок 'Bearer <действительный токен>' → { id, username, isAdmin }.
|
|
15
|
+
*/
|
|
10
16
|
me(authorization: unknown): AuthUser;
|
|
17
|
+
/** Проверяет токен и удаляет соответствующую сессию.
|
|
18
|
+
* @example Действительный токен → { success: true }; повторный выход с ним → ошибка.
|
|
19
|
+
*/
|
|
11
20
|
logout(authorization: unknown): {
|
|
12
21
|
success: boolean;
|
|
13
22
|
};
|
|
23
|
+
/** Запрещает новые входы и очищает учётные записи и сессии в памяти.
|
|
24
|
+
* @example close() → undefined; последующий login() → отказ.
|
|
25
|
+
*/
|
|
14
26
|
close(): void;
|
|
27
|
+
/** Находит сессию по хешу токена и проверяет срок; просроченную сессию удаляет.
|
|
28
|
+
* @example Действительный Bearer-токен → [ключ, сессия]; отсутствующий или истёкший → ошибка.
|
|
29
|
+
*/
|
|
15
30
|
private session;
|
|
31
|
+
/** Удаляет из памяти сессии, срок которых истёк к текущему моменту.
|
|
32
|
+
* @example Одна истёкшая и одна действующая сессия → остаётся одна действующая; результат undefined.
|
|
33
|
+
*/
|
|
16
34
|
private prune;
|
|
17
35
|
}
|
|
36
|
+
/** Читает и проверяет учётные записи из массива или файла и создаёт хранилище сессий в памяти.
|
|
37
|
+
* @example createAuthService({ users: [] }) → Promise<AuthService>; повторяющиеся id → ошибка.
|
|
38
|
+
*/
|
|
18
39
|
export declare function createAuthService(config: AuthConfig): Promise<AuthService>;
|
package/dist/src/auth/service.js
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { createHash, randomBytes } from 'node:crypto';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { domainError } from '../errors.js';
|
|
4
|
-
import { isObject } from '../utils.js';
|
|
3
|
+
import { domainError } from '../core/errors.js';
|
|
4
|
+
import { hasOnlyKeys, isObject } from '../core/utils.js';
|
|
5
5
|
import { DEFAULT_SESSION_SECONDS, MAX_PASSWORD_LENGTH, MAX_USERNAME_LENGTH } from './contract.js';
|
|
6
6
|
import { DUMMY_HASH, validPasswordHash, verifyPassword } from './password.js';
|
|
7
|
+
/** Создаёт исключение отсутствия действительной сессии без раскрытия причины отказа.
|
|
8
|
+
* @example unauthorized() → Error с code = 'UNAUTHENTICATED'.
|
|
9
|
+
*/
|
|
7
10
|
const unauthorized = () => domainError('UNAUTHENTICATED', 'Invalid credentials or expired session');
|
|
11
|
+
/** Вычисляет SHA-256 строки в шестнадцатеричном виде для хранения вместо исходного токена.
|
|
12
|
+
* @example tokenKey('abc') → 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'.
|
|
13
|
+
*/
|
|
8
14
|
const tokenKey = (token) => createHash('sha256').update(token).digest('hex');
|
|
9
|
-
|
|
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 });
|
|
10
19
|
export class AuthService {
|
|
11
20
|
users;
|
|
12
21
|
expiresIn;
|
|
@@ -17,9 +26,12 @@ export class AuthService {
|
|
|
17
26
|
this.users = users;
|
|
18
27
|
this.expiresIn = expiresIn;
|
|
19
28
|
}
|
|
29
|
+
/** Проверяет пароль, создаёт сессию и возвращает токен с публичными данными пользователя.
|
|
30
|
+
* @example Корректные username и password → { accessToken, expiresIn, user }; неверный пароль → исключение.
|
|
31
|
+
*/
|
|
20
32
|
async login(body) {
|
|
21
33
|
if (!isObject(body) ||
|
|
22
|
-
|
|
34
|
+
!hasOnlyKeys(body, ['username', 'password']) ||
|
|
23
35
|
typeof body.username !== 'string' ||
|
|
24
36
|
!body.username.length ||
|
|
25
37
|
body.username.length > MAX_USERNAME_LENGTH ||
|
|
@@ -51,20 +63,32 @@ export class AuthService {
|
|
|
51
63
|
this.sessions.set(tokenKey(accessToken), { user: identity, expiresAt: Date.now() + this.expiresIn * 1000 });
|
|
52
64
|
return { accessToken, expiresIn: this.expiresIn, user: publicUser(identity) };
|
|
53
65
|
}
|
|
66
|
+
/** Проверяет Bearer-токен и возвращает копию публичных данных пользователя.
|
|
67
|
+
* @example Заголовок 'Bearer <действительный токен>' → { id, username, isAdmin }.
|
|
68
|
+
*/
|
|
54
69
|
me(authorization) {
|
|
55
70
|
const [, session] = this.session(authorization);
|
|
56
71
|
return publicUser(session.user);
|
|
57
72
|
}
|
|
73
|
+
/** Проверяет токен и удаляет соответствующую сессию.
|
|
74
|
+
* @example Действительный токен → { success: true }; повторный выход с ним → ошибка.
|
|
75
|
+
*/
|
|
58
76
|
logout(authorization) {
|
|
59
77
|
const [key] = this.session(authorization);
|
|
60
78
|
this.sessions.delete(key);
|
|
61
79
|
return { success: true };
|
|
62
80
|
}
|
|
81
|
+
/** Запрещает новые входы и очищает учётные записи и сессии в памяти.
|
|
82
|
+
* @example close() → undefined; последующий login() → отказ.
|
|
83
|
+
*/
|
|
63
84
|
close() {
|
|
64
85
|
this.closed = true;
|
|
65
86
|
this.sessions.clear();
|
|
66
87
|
this.users.clear();
|
|
67
88
|
}
|
|
89
|
+
/** Находит сессию по хешу токена и проверяет срок; просроченную сессию удаляет.
|
|
90
|
+
* @example Действительный Bearer-токен → [ключ, сессия]; отсутствующий или истёкший → ошибка.
|
|
91
|
+
*/
|
|
68
92
|
session(authorization) {
|
|
69
93
|
if (typeof authorization !== 'string')
|
|
70
94
|
throw unauthorized();
|
|
@@ -79,6 +103,9 @@ export class AuthService {
|
|
|
79
103
|
}
|
|
80
104
|
return [key, session];
|
|
81
105
|
}
|
|
106
|
+
/** Удаляет из памяти сессии, срок которых истёк к текущему моменту.
|
|
107
|
+
* @example Одна истёкшая и одна действующая сессия → остаётся одна действующая; результат undefined.
|
|
108
|
+
*/
|
|
82
109
|
prune() {
|
|
83
110
|
const now = Date.now();
|
|
84
111
|
for (const [key, session] of this.sessions)
|
|
@@ -86,6 +113,9 @@ export class AuthService {
|
|
|
86
113
|
this.sessions.delete(key);
|
|
87
114
|
}
|
|
88
115
|
}
|
|
116
|
+
/** Читает и проверяет учётные записи из массива или файла и создаёт хранилище сессий в памяти.
|
|
117
|
+
* @example createAuthService({ users: [] }) → Promise<AuthService>; повторяющиеся id → ошибка.
|
|
118
|
+
*/
|
|
89
119
|
export async function createAuthService(config) {
|
|
90
120
|
const records = typeof config.users === 'string' ? JSON.parse(await readFile(config.users, 'utf8')) : config.users;
|
|
91
121
|
if (!Array.isArray(records))
|
|
@@ -94,18 +124,19 @@ export async function createAuthService(config) {
|
|
|
94
124
|
const ids = new Set();
|
|
95
125
|
for (const record of records) {
|
|
96
126
|
if (!isObject(record) ||
|
|
97
|
-
|
|
127
|
+
!hasOnlyKeys(record, ['id', 'username', 'passwordHash', 'isAdmin']) ||
|
|
98
128
|
typeof record.id !== 'string' ||
|
|
99
129
|
!record.id.trim() ||
|
|
100
130
|
typeof record.username !== 'string' ||
|
|
101
131
|
!record.username.trim() ||
|
|
102
132
|
record.username.length > MAX_USERNAME_LENGTH ||
|
|
103
|
-
!validPasswordHash(record.passwordHash)
|
|
133
|
+
!validPasswordHash(record.passwordHash) ||
|
|
134
|
+
(record.isAdmin !== undefined && typeof record.isAdmin !== 'boolean'))
|
|
104
135
|
throw new Error('Auth users require id, username and a valid passwordHash');
|
|
105
136
|
if (ids.has(record.id) || users.has(record.username))
|
|
106
137
|
throw new Error('Auth user ids and usernames must be unique');
|
|
107
138
|
ids.add(record.id);
|
|
108
|
-
users.set(record.username, { id: record.id, username: record.username, passwordHash: record.passwordHash });
|
|
139
|
+
users.set(record.username, { id: record.id, username: record.username, passwordHash: record.passwordHash, isAdmin: record.isAdmin ?? false });
|
|
109
140
|
}
|
|
110
141
|
return new AuthService(users, config.expiresIn ?? DEFAULT_SESSION_SECONDS);
|
|
111
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/auth/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,
|
|
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,18 +1,20 @@
|
|
|
1
1
|
import process from 'node:process';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
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
|
|
|
15
|
-
--
|
|
16
|
+
--timestamps Track record creation and update times
|
|
17
|
+
--soft-delete Mark deleted records instead of removing them
|
|
16
18
|
--files Enable file routes
|
|
17
19
|
--graphql Enable the GraphQL endpoint
|
|
18
20
|
--openapi Enable the OpenAPI endpoint
|
|
@@ -22,6 +24,9 @@ Usage:
|
|
|
22
24
|
--version, -v Show version
|
|
23
25
|
|
|
24
26
|
Files are enabled when configured. Generate writes schemas to the configured paths.`;
|
|
27
|
+
/** Разбирает аргументы командной строки и запускает сервер либо экспорт; справку и версию пишет в stdout.
|
|
28
|
+
* @example runCli(['--help']) → Promise<void> и текст справки без запуска сервера.
|
|
29
|
+
*/
|
|
25
30
|
export async function runCli(args = process.argv.slice(2), services = { createServer: createConfiguredServer }) {
|
|
26
31
|
if (args.includes('--help') || args.includes('-h')) {
|
|
27
32
|
process.stdout.write(`${HELP_TEXT}\n`);
|
|
@@ -34,6 +39,7 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
|
|
|
34
39
|
const positional = [];
|
|
35
40
|
const seen = new Set();
|
|
36
41
|
const features = {};
|
|
42
|
+
const recordFlags = {};
|
|
37
43
|
let host;
|
|
38
44
|
let port;
|
|
39
45
|
for (let index = 0; index < args.length; index++) {
|
|
@@ -42,7 +48,7 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
|
|
|
42
48
|
positional.push(arg);
|
|
43
49
|
continue;
|
|
44
50
|
}
|
|
45
|
-
if (!['--files', '--graphql', '--openapi', '--
|
|
51
|
+
if (!['--files', '--graphql', '--openapi', '--timestamps', '--soft-delete', '--host', '--port'].includes(arg) || seen.has(arg))
|
|
46
52
|
throw new Error(`Неизвестный параметр или повтор: ${arg}`);
|
|
47
53
|
seen.add(arg);
|
|
48
54
|
if (arg === '--host' || arg === '--port') {
|
|
@@ -57,6 +63,10 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
|
|
|
57
63
|
port = Number(value);
|
|
58
64
|
}
|
|
59
65
|
}
|
|
66
|
+
else if (arg === '--timestamps')
|
|
67
|
+
recordFlags.timestamps = true;
|
|
68
|
+
else if (arg === '--soft-delete')
|
|
69
|
+
recordFlags.softDelete = true;
|
|
60
70
|
else
|
|
61
71
|
features[arg.slice(2)] = true;
|
|
62
72
|
}
|
|
@@ -77,8 +87,12 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
|
|
|
77
87
|
throw new Error('config.server must be an object');
|
|
78
88
|
const overrides = { host: host ?? serverOptions.host ?? process.env.HOST ?? DEFAULT_HOST, port: port ?? serverOptions.port ?? Number(process.env.PORT ?? DEFAULT_PORT) };
|
|
79
89
|
const config = generate
|
|
80
|
-
? configureGeneration(source.config, formats, source.directory, source.path, { ...overrides, files: features.files,
|
|
81
|
-
: configure({
|
|
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);
|
|
82
96
|
if (generate) {
|
|
83
97
|
if (!config.database.schema)
|
|
84
98
|
throw new Error('Generation requires an explicit model schema');
|
|
@@ -92,7 +106,9 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
|
|
|
92
106
|
const openapi = formats.includes('openapi')
|
|
93
107
|
? await generateOpenapi(config.database.schema, {
|
|
94
108
|
files: config.files != null,
|
|
95
|
-
auth: config.auth
|
|
109
|
+
auth: config.auth != null,
|
|
110
|
+
timestamps: config.database.timestamps,
|
|
111
|
+
softDelete: config.database.softDelete,
|
|
96
112
|
host: config.server.host,
|
|
97
113
|
port: config.server.port,
|
|
98
114
|
pageSize: config.server.pageSize,
|
|
@@ -100,7 +116,9 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
|
|
|
100
116
|
info: config.openapi.info,
|
|
101
117
|
})
|
|
102
118
|
: undefined;
|
|
103
|
-
const graphql = formats.includes('graphql')
|
|
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;
|
|
104
122
|
if (openapi) {
|
|
105
123
|
await writeOpenapi(openapi, config.openapi.path);
|
|
106
124
|
process.stdout.write(`OpenAPI: ${config.openapi.path}\n`);
|
|
@@ -115,4 +133,4 @@ export async function runCli(args = process.argv.slice(2), services = { createSe
|
|
|
115
133
|
await server.listen();
|
|
116
134
|
server.log.info('Deep JSON Server started');
|
|
117
135
|
}
|
|
118
|
-
//# sourceMappingURL=
|
|
136
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAuB,MAAM,uBAAuB,CAAC;AAE7E,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;oFAgBkE,CAAC;AACrF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAoD,EAAE,YAAY,EAAE,sBAAsB,EAAE;IAC7J,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,IAAI,CAAC,CAAC;QACvC,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IACD,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,MAAM,WAAW,GAAmD,EAAE,CAAC;IACvE,IAAI,IAAwB,CAAC;IAC7B,IAAI,IAAwB,CAAC;IAC7B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACjD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrB,SAAS;QACX,CAAC;QACD,IAAI,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,EAAE,CAAC,CAAC;QAC3L,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;YAC5B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAC;YAChF,IAAI,GAAG,KAAK,QAAQ;gBAAE,IAAI,GAAG,KAAK,CAAC;iBAC9B,CAAC;gBACJ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;oBAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;gBAC5D,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;aAAM,IAAI,GAAG,KAAK,cAAc;YAAE,WAAW,CAAC,UAAU,GAAG,IAAI,CAAC;aAC5D,IAAI,GAAG,KAAK,eAAe;YAAE,WAAW,CAAC,UAAU,GAAG,IAAI,CAAC;;YAC3D,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAyB,CAAC,GAAG,IAAI,CAAC;IAC7D,CAAC;IACD,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC;IAC9C,MAAM,UAAU,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACtE,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAC7G,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,IAAI,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/K,IAAI,QAAQ,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IACtI,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACnG,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACjF,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,IAAI,IAAI,aAAa,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,YAAY,EAAE,IAAI,EAAE,IAAI,IAAI,aAAa,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,YAAY,CAAC,EAAE,CAAC;IACzK,MAAM,MAAM,GAAG,QAAQ;QACrB,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,WAAW,EAM/H,CAAC;QACJ,CAAC,CAAC,SAAS,CACP;YACE,GAAG,MAAM,CAAC,MAAM;YAChB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjJ,MAAM,EAAE,EAAE,GAAG,aAAa,EAAE,GAAG,SAAS,EAAE;SAC3C,EACD,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,IAAI,CACZ,CAAC;IACN,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAC7F,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,MAA+B,CAAC,CAAC,IAAI,CAAC;YAC1D,IAAI,CAAC,IAAI;gBAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,MAAM,OAAO,CAAC,CAAC;YAC5D,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QACH,MAAM,mBAAmB,CAAC,YAAY,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAClG,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;YACzC,CAAC,CAAC,MAAM,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE;gBAC5C,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;gBAC3B,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI;gBACzB,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU;gBACtC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU;gBACtC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI;gBACxB,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI;gBACxB,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ;gBAChC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW;gBACtC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;aAC1B,CAAC;YACJ,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;YACzC,CAAC,CAAC,MAAM,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC9J,CAAC,CAAC,SAAS,CAAC;QACd,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,IAAK,CAAC,CAAC;YAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,IAAK,CAAC,CAAC;YAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAClG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -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.
|
|
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.
|
|
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;
|
|
@@ -5,6 +5,9 @@ import { JSONFile } from 'lowdb/node';
|
|
|
5
5
|
import { domainError } from './errors.js';
|
|
6
6
|
import { createSerialQueue, createUniqueId, isObject, isSafeKey, isSystemError, resolveDatabasePath } from './utils.js';
|
|
7
7
|
const RESOURCE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
8
|
+
/** Проверяет сериализуемое JSON-значение; отвергает циклы, разреженные массивы, NaN и бесконечности.
|
|
9
|
+
* @example validateJsonValue({ a: [1, null] }, 'data') → undefined; NaN → ошибка.
|
|
10
|
+
*/
|
|
8
11
|
export const validateJsonValue = (value, path, ancestors = new WeakSet()) => {
|
|
9
12
|
if (value === null || typeof value === 'string' || typeof value === 'boolean') {
|
|
10
13
|
return;
|
|
@@ -41,6 +44,9 @@ export const validateJsonValue = (value, path, ancestors = new WeakSet()) => {
|
|
|
41
44
|
}
|
|
42
45
|
ancestors.delete(value);
|
|
43
46
|
};
|
|
47
|
+
/** Проверяет объект коллекций, записи и уникальность ключей; возвращает исходный объект.
|
|
48
|
+
* @example validateDatabase({ notes: [{ id: '1' }] }) → тот же объект; повторный id → ошибка.
|
|
49
|
+
*/
|
|
44
50
|
export const validateDatabase = (data, primaryKeys) => {
|
|
45
51
|
if (!isObject(data)) {
|
|
46
52
|
throw new Error('База данных должна содержать JSON-объект');
|
|
@@ -74,6 +80,9 @@ export const validateDatabase = (data, primaryKeys) => {
|
|
|
74
80
|
});
|
|
75
81
|
return data;
|
|
76
82
|
};
|
|
83
|
+
/** Читает UTF-8 JSON-файл и проверяет, что верхний уровень является объектом.
|
|
84
|
+
* @example Файл с {"a":1} → Promise<{ a: 1 }>; файл с [] → ошибка.
|
|
85
|
+
*/
|
|
77
86
|
export const readJsonObjectFile = async (path, label) => {
|
|
78
87
|
const resolvedPath = resolve(path);
|
|
79
88
|
let source;
|
|
@@ -92,6 +101,9 @@ export const readJsonObjectFile = async (path, label) => {
|
|
|
92
101
|
}
|
|
93
102
|
return value;
|
|
94
103
|
};
|
|
104
|
+
/** Читает файл и проверяет коллекции и первичные ключи.
|
|
105
|
+
* @example Файл с {"notes":[]} → Promise<{ notes: [] }>.
|
|
106
|
+
*/
|
|
95
107
|
export const readDatabaseFile = async (databasePath, keys) => validateDatabase(await readJsonObjectFile(databasePath, 'Файл базы данных'), keys);
|
|
96
108
|
const validateDraft = (data, keys) => {
|
|
97
109
|
try {
|
|
@@ -144,8 +156,16 @@ const createMemoryDatabaseStore = (sourceData, keys) => {
|
|
|
144
156
|
});
|
|
145
157
|
return { database, read, update };
|
|
146
158
|
};
|
|
147
|
-
/**
|
|
159
|
+
/** Создаёт дисковое хранилище или хранилище в памяти по настройкам.
|
|
160
|
+
* @example createDatabaseStore({ data: { notes: [] } }) → Promise<DatabaseStore>.
|
|
161
|
+
*/
|
|
148
162
|
export const createDatabaseStore = async (config, keys) => config.data != null ? createMemoryDatabaseStore(config.data, keys) : createDiskDatabaseStore(config.path, keys);
|
|
163
|
+
/** Ищет индекс записи, сравнивая строковые представления id.
|
|
164
|
+
* @example findItemIndex([{ id: 1 }], '1') → 0; пустой массив → -1.
|
|
165
|
+
*/
|
|
149
166
|
export const findItemIndex = (collection, id) => collection.findIndex((item) => String(item.id) === String(id));
|
|
167
|
+
/** Генерирует случайный строковый id, отсутствующий в переданной коллекции.
|
|
168
|
+
* @example createId([]) → строка из 11 символов; конкретное значение зависит от генератора случайных чисел.
|
|
169
|
+
*/
|
|
150
170
|
export const createId = (collection) => createUniqueId((id) => findItemIndex(collection, id) !== -1);
|
|
151
171
|
//# sourceMappingURL=database.js.map
|