@ask-ell/back-end 0.1.1 → 0.2.1
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/jest.config.ts +0 -1
- package/package.json +3 -2
- package/project.json +4 -7
- package/src/add-ons/add-on.interface.ts +3 -3
- package/src/add-ons/add-on.wrapper.ts +24 -29
- package/src/add-ons/implementations/security/security.add-on.ts +3 -4
- package/src/add-ons/implementations/sentry/sentry.add-on.interface.ts +5 -5
- package/src/add-ons/implementations/sentry/sentry.add-on.state.interface.ts +1 -1
- package/src/add-ons/implementations/sentry/sentry.add-on.ts +8 -9
- package/src/add-ons/implementations/swagger/swagger.add-on.interface.ts +5 -4
- package/src/add-ons/implementations/swagger/swagger.add-on.state.interface.ts +3 -2
- package/src/add-ons/implementations/swagger/swagger.add-on.ts +29 -13
- package/src/add-ons/implementations/swagger/types.ts +1 -1
- package/src/add-ons/index.ts +2 -1
- package/src/add-ons/types.ts +5 -5
- package/src/application.base.ts +15 -12
- package/src/application.factory.ts +23 -0
- package/src/error.interceptor.ts +25 -0
- package/src/index.ts +3 -2
- package/src/keyv.store.adapter.factory.ts +30 -24
- package/src/requirement.module.ts +51 -49
- package/src/scripts/move-keyv-data.script.ts +69 -48
- package/src/scripts/update-dependencies-versions.script.ts +161 -127
- package/src/secrets/docker.secret.getter.ts +6 -5
- package/src/secrets/file.secret.getter.ts +19 -16
- package/src/secrets/index.ts +2 -2
- package/src/secrets/local.secret.getter.ts +6 -5
- package/src/utils/tmp.ts +11 -12
package/jest.config.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ask-ell/back-end",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"helmet": "*",
|
|
21
21
|
"keyv": "*",
|
|
22
22
|
"pg": "*",
|
|
23
|
-
"tslib": "*"
|
|
23
|
+
"tslib": "*",
|
|
24
|
+
"rxjs": "*"
|
|
24
25
|
}
|
|
25
26
|
}
|
package/project.json
CHANGED
|
@@ -8,22 +8,19 @@
|
|
|
8
8
|
"build": {
|
|
9
9
|
"executor": "@nx/js:tsc",
|
|
10
10
|
"dependsOn": ["^build"],
|
|
11
|
-
"outputs": [
|
|
12
|
-
"{options.outputPath}"
|
|
13
|
-
],
|
|
11
|
+
"outputs": ["{options.outputPath}"],
|
|
14
12
|
"options": {
|
|
15
13
|
"outputPath": "dist/packages/back-end",
|
|
16
14
|
"main": "packages/back-end/src/index.ts",
|
|
17
15
|
"tsConfig": "packages/back-end/tsconfig.lib.json",
|
|
18
|
-
"assets": [
|
|
19
|
-
"packages/back-end/*.md"
|
|
20
|
-
]
|
|
16
|
+
"assets": ["packages/back-end/*.md"]
|
|
21
17
|
}
|
|
22
18
|
},
|
|
23
19
|
"test": {
|
|
24
20
|
"options": {
|
|
25
21
|
"passWithNoTests": true
|
|
26
22
|
}
|
|
27
|
-
}
|
|
23
|
+
},
|
|
24
|
+
"format": {}
|
|
28
25
|
}
|
|
29
26
|
}
|
|
@@ -1,36 +1,31 @@
|
|
|
1
|
-
import { INestApplication } from
|
|
2
|
-
|
|
3
|
-
import { IAddOn } from "./add-on.interface";
|
|
4
|
-
import { SecurityAddOn } from "./implementations/security/security.add-on";
|
|
5
|
-
import { AddOnWrapperParams } from "./types";
|
|
6
|
-
import { SwaggerAddon } from "./implementations/swagger/swagger.add-on";
|
|
7
|
-
import { SentryAddon } from "./implementations/sentry/sentry.add-on";
|
|
1
|
+
import { INestApplication } from '@nestjs/common';
|
|
8
2
|
|
|
3
|
+
import { IAddOn } from './add-on.interface';
|
|
4
|
+
import { SecurityAddOn } from './implementations/security/security.add-on';
|
|
5
|
+
import { AddOnWrapperParams } from './types';
|
|
6
|
+
import { SwaggerAddon } from './implementations/swagger/swagger.add-on';
|
|
7
|
+
import { SentryAddon } from './implementations/sentry/sentry.add-on';
|
|
9
8
|
|
|
10
9
|
export class AddOnWrapper<T> implements IAddOn<T> {
|
|
11
|
-
|
|
12
|
-
new SecurityAddOn()
|
|
13
|
-
];
|
|
10
|
+
private implementations: IAddOn<T>[] = [new SecurityAddOn()];
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this.appendImplementations();
|
|
19
|
-
}
|
|
12
|
+
constructor(private params: AddOnWrapperParams) {
|
|
13
|
+
this.appendImplementations();
|
|
14
|
+
}
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
apply(application: INestApplication<T>): void {
|
|
17
|
+
this.implementations.forEach((addOn: IAddOn<T>): void => {
|
|
18
|
+
addOn.apply(application);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
22
|
+
private appendImplementations(): void {
|
|
23
|
+
const { sentry, swagger } = this.params;
|
|
24
|
+
if (swagger) {
|
|
25
|
+
this.implementations.push(new SwaggerAddon(swagger));
|
|
26
|
+
}
|
|
27
|
+
if (sentry) {
|
|
28
|
+
this.implementations.push(new SentryAddon(sentry));
|
|
35
29
|
}
|
|
36
|
-
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { INestApplication, ValidationPipe } from
|
|
1
|
+
import { INestApplication, ValidationPipe } from '@nestjs/common';
|
|
2
2
|
import helmet from 'helmet';
|
|
3
3
|
|
|
4
|
-
import { IAddOn } from
|
|
5
|
-
|
|
4
|
+
import { IAddOn } from '../../add-on.interface';
|
|
6
5
|
|
|
7
6
|
export class SecurityAddOn<T> implements IAddOn<T> {
|
|
8
7
|
apply(application: INestApplication<T>): void {
|
|
@@ -11,7 +10,7 @@ export class SecurityAddOn<T> implements IAddOn<T> {
|
|
|
11
10
|
application.useGlobalPipes(
|
|
12
11
|
new ValidationPipe({
|
|
13
12
|
transform: true,
|
|
14
|
-
whitelist: false
|
|
13
|
+
whitelist: false,
|
|
15
14
|
})
|
|
16
15
|
);
|
|
17
16
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { IEntity } from
|
|
2
|
-
|
|
3
|
-
import { ISentryAddOnState } from "./sentry.add-on.state.interface";
|
|
4
|
-
import { IAddOn } from "../../add-on.interface";
|
|
1
|
+
import { IEntity } from '@ask-ell/core';
|
|
5
2
|
|
|
3
|
+
import { ISentryAddOnState } from './sentry.add-on.state.interface';
|
|
4
|
+
import { IAddOn } from '../../add-on.interface';
|
|
6
5
|
|
|
7
6
|
export interface ISentryAddOn<T>
|
|
8
|
-
extends IEntity<ISentryAddOnState>,
|
|
7
|
+
extends IEntity<ISentryAddOnState>,
|
|
8
|
+
IAddOn<T> {}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { Entity, type IResult, ok } from
|
|
2
|
-
import { NestSentryConfiguration } from
|
|
3
|
-
|
|
4
|
-
import { ISentryAddOnState } from "./sentry.add-on.state.interface";
|
|
5
|
-
import { ISentryAddOn } from "./sentry.add-on.interface";
|
|
1
|
+
import { Entity, type IResult, ok } from '@ask-ell/core';
|
|
2
|
+
import { NestSentryConfiguration } from '@ask-ell/nest';
|
|
6
3
|
|
|
4
|
+
import { ISentryAddOnState } from './sentry.add-on.state.interface';
|
|
5
|
+
import { ISentryAddOn } from './sentry.add-on.interface';
|
|
7
6
|
|
|
8
7
|
export class SentryAddon<T>
|
|
9
8
|
extends Entity<ISentryAddOnState>
|
|
@@ -17,9 +16,9 @@ export class SentryAddon<T>
|
|
|
17
16
|
const { host, projectId, publicKey } = this.getSnapshot();
|
|
18
17
|
|
|
19
18
|
new NestSentryConfiguration({
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
publicKey,
|
|
20
|
+
host,
|
|
21
|
+
projectId,
|
|
23
22
|
}).init();
|
|
24
23
|
}
|
|
25
|
-
}
|
|
24
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { IEntity } from
|
|
1
|
+
import { IEntity } from '@ask-ell/core';
|
|
2
2
|
|
|
3
|
-
import { ISwaggerAddOnState } from
|
|
4
|
-
import { IAddOn } from
|
|
3
|
+
import { ISwaggerAddOnState } from './swagger.add-on.state.interface';
|
|
4
|
+
import { IAddOn } from '../../add-on.interface';
|
|
5
5
|
|
|
6
6
|
export interface ISwaggerAddOn<T>
|
|
7
|
-
extends IEntity<ISwaggerAddOnState>,
|
|
7
|
+
extends IEntity<ISwaggerAddOnState>,
|
|
8
|
+
IAddOn<T> {}
|
|
@@ -1,28 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
Entity,
|
|
3
|
+
ILogger,
|
|
4
|
+
type IResult,
|
|
5
|
+
isOnDevelopmentMode,
|
|
6
|
+
ok,
|
|
7
|
+
} from '@ask-ell/core';
|
|
8
|
+
import { NestLogger } from '@ask-ell/nest';
|
|
9
|
+
import { type INestApplication } from '@nestjs/common';
|
|
3
10
|
import {
|
|
4
11
|
DocumentBuilder,
|
|
5
12
|
type OpenAPIObject,
|
|
6
13
|
SwaggerModule,
|
|
7
|
-
} from
|
|
8
|
-
|
|
9
|
-
import { ISwaggerAddOnState } from "./swagger.add-on.state.interface";
|
|
10
|
-
import { ISwaggerAddOn } from "./swagger.add-on.interface";
|
|
11
|
-
import { AuthMethod } from "./types";
|
|
14
|
+
} from '@nestjs/swagger';
|
|
12
15
|
|
|
16
|
+
import { ISwaggerAddOnState } from './swagger.add-on.state.interface';
|
|
17
|
+
import { ISwaggerAddOn } from './swagger.add-on.interface';
|
|
18
|
+
import { AuthMethod } from './types';
|
|
13
19
|
|
|
14
20
|
export class SwaggerAddon<T>
|
|
15
21
|
extends Entity<ISwaggerAddOnState>
|
|
16
22
|
implements ISwaggerAddOn<T>
|
|
17
23
|
{
|
|
24
|
+
private logger: ILogger = NestLogger.fromClass(SwaggerAddon);
|
|
25
|
+
|
|
18
26
|
checkStateValidity(): IResult<void> {
|
|
19
27
|
return ok();
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
apply(application: INestApplication<T>): void {
|
|
23
|
-
const { title, auths } = this.getSnapshot();
|
|
31
|
+
const { title, auths, enabledInProduction } = this.getSnapshot();
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
if (!enabledInProduction && !isOnDevelopmentMode()) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const documentBuilder: DocumentBuilder = new DocumentBuilder().setTitle(
|
|
38
|
+
title
|
|
39
|
+
);
|
|
26
40
|
|
|
27
41
|
auths?.forEach((auth: AuthMethod): void => {
|
|
28
42
|
if (auth === 'bearer') {
|
|
@@ -30,14 +44,16 @@ export class SwaggerAddon<T>
|
|
|
30
44
|
}
|
|
31
45
|
});
|
|
32
46
|
|
|
33
|
-
const documentBuild: Omit<OpenAPIObject,
|
|
47
|
+
const documentBuild: Omit<OpenAPIObject, 'paths'> = documentBuilder.build();
|
|
34
48
|
|
|
35
49
|
const documentFactory = (): OpenAPIObject =>
|
|
36
50
|
SwaggerModule.createDocument(application, documentBuild);
|
|
37
51
|
|
|
38
|
-
SwaggerModule.setup(
|
|
52
|
+
SwaggerModule.setup('/swagger', application, documentFactory, {
|
|
39
53
|
customSiteTitle: title,
|
|
40
|
-
jsonDocumentUrl:
|
|
54
|
+
jsonDocumentUrl: '/swagger/json',
|
|
41
55
|
});
|
|
56
|
+
|
|
57
|
+
this.logger.log('Swagger initialized');
|
|
42
58
|
}
|
|
43
|
-
}
|
|
59
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type AuthMethod = 'bearer' | 'cookie';
|
|
1
|
+
export type AuthMethod = 'bearer' | 'cookie';
|
package/src/add-ons/index.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from './add-on.wrapper'
|
|
1
|
+
export * from './add-on.wrapper';
|
|
2
|
+
export * from './types';
|
package/src/add-ons/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ISentryAddOnState } from
|
|
2
|
-
import { ISwaggerAddOnState } from
|
|
1
|
+
import { ISentryAddOnState } from './implementations/sentry/sentry.add-on.state.interface';
|
|
2
|
+
import { ISwaggerAddOnState } from './implementations/swagger/swagger.add-on.state.interface';
|
|
3
3
|
|
|
4
4
|
export type AddOnWrapperParams = Partial<{
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}>;
|
|
5
|
+
swagger: ISwaggerAddOnState;
|
|
6
|
+
sentry: ISentryAddOnState;
|
|
7
|
+
}>;
|
package/src/application.base.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { DynamicModule, Provider } from
|
|
1
|
+
import { DynamicModule, Provider, Module, Global } from '@nestjs/common';
|
|
2
2
|
|
|
3
|
-
import { RequirementModule } from
|
|
3
|
+
import { RequirementModule } from './requirement.module';
|
|
4
4
|
|
|
5
|
+
@Global()
|
|
6
|
+
@Module({
|
|
7
|
+
imports: [RequirementModule],
|
|
8
|
+
})
|
|
5
9
|
export class ApplicationBase {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
10
|
+
static withProviders(providers: Provider[]): DynamicModule {
|
|
11
|
+
const providersAndExports: Provider[] = [...providers];
|
|
12
|
+
return {
|
|
13
|
+
module: this,
|
|
14
|
+
providers: providersAndExports,
|
|
15
|
+
exports: [...providersAndExports],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ConsoleLogger, DynamicModule, INestApplication } from '@nestjs/common';
|
|
2
|
+
import { NestFactory } from '@nestjs/core';
|
|
3
|
+
import { IServerProvider } from '@ask-ell/node';
|
|
4
|
+
|
|
5
|
+
import { AddOnWrapper, AddOnWrapperParams } from './add-ons';
|
|
6
|
+
|
|
7
|
+
type NestApplicationFactoryParams = {
|
|
8
|
+
params: AddOnWrapperParams;
|
|
9
|
+
module: DynamicModule;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export async function createNestApplication({
|
|
13
|
+
params,
|
|
14
|
+
module,
|
|
15
|
+
}: NestApplicationFactoryParams): Promise<IServerProvider> {
|
|
16
|
+
const application: INestApplication = await NestFactory.create(module, {
|
|
17
|
+
logger: new ConsoleLogger({
|
|
18
|
+
json: true,
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
new AddOnWrapper(params).apply(application);
|
|
22
|
+
return application;
|
|
23
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Entity, IResult, ok } from '@ask-ell/core';
|
|
2
|
+
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
|
|
3
|
+
import { catchError, Observable, throwError } from 'rxjs';
|
|
4
|
+
|
|
5
|
+
type ErrorInterceptorProps = {
|
|
6
|
+
errorConvertor: (error: unknown) => unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export class ErrorInterceptor
|
|
10
|
+
extends Entity<ErrorInterceptorProps>
|
|
11
|
+
implements NestInterceptor
|
|
12
|
+
{
|
|
13
|
+
override checkStateValidity(): IResult {
|
|
14
|
+
return ok();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
intercept(_: ExecutionContext, next: CallHandler): Observable<unknown> {
|
|
18
|
+
const { errorConvertor } = this.getSnapshot();
|
|
19
|
+
return next.handle().pipe(
|
|
20
|
+
catchError((error: unknown): Observable<never> => {
|
|
21
|
+
return throwError((): unknown => errorConvertor(error));
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module @ask-ell/back-end
|
|
3
3
|
*/
|
|
4
|
-
export * from './add-ons';
|
|
5
4
|
export * from './scripts';
|
|
5
|
+
export * from './application.base';
|
|
6
|
+
export * from './application.factory';
|
|
7
|
+
export * from './error.interceptor';
|
|
6
8
|
export * from './keyv.store.adapter.factory';
|
|
7
|
-
export * from "./application.base";
|
|
@@ -1,37 +1,43 @@
|
|
|
1
|
-
import { Injectable } from
|
|
2
|
-
import { KeyvStoreAdapter } from
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { KeyvStoreAdapter } from 'keyv';
|
|
3
3
|
import KeyvSqlite from '@keyv/sqlite';
|
|
4
4
|
import KeyvPostgres from '@keyv/postgres';
|
|
5
|
-
import { ILogger, MaybeUndefined } from
|
|
5
|
+
import { ILogger, MaybeUndefined } from '@ask-ell/core';
|
|
6
6
|
import { NestLogger } from '@ask-ell/nest';
|
|
7
|
-
import { join } from
|
|
8
|
-
|
|
9
|
-
import { createTmpFolder, TMP_FOLDER_PATH } from "./utils";
|
|
7
|
+
import { join } from 'node:path';
|
|
10
8
|
|
|
9
|
+
import { createTmpFolder, TMP_FOLDER_PATH } from './utils';
|
|
11
10
|
|
|
12
11
|
type CreateKeyvStoreAdapterOptions = {
|
|
13
|
-
|
|
14
|
-
}
|
|
12
|
+
postgresUri: MaybeUndefined<string>;
|
|
13
|
+
};
|
|
15
14
|
|
|
16
15
|
@Injectable()
|
|
17
16
|
export class KeyvStoreAdapterFactory {
|
|
18
|
-
|
|
17
|
+
private logger: ILogger = NestLogger.fromClass(KeyvStoreAdapterFactory);
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
create(options: CreateKeyvStoreAdapterOptions): KeyvStoreAdapter {
|
|
20
|
+
const adapter: KeyvStoreAdapter = this.getKeyvStoreAdapter(options);
|
|
21
|
+
this.logger.log(
|
|
22
|
+
`Connected to database with adapter "${adapter.constructor.name}"`
|
|
23
|
+
);
|
|
24
|
+
return adapter;
|
|
25
|
+
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
private getKeyvStoreAdapter({
|
|
28
|
+
postgresUri,
|
|
29
|
+
}: CreateKeyvStoreAdapterOptions): KeyvStoreAdapter {
|
|
30
|
+
if (!postgresUri) {
|
|
31
|
+
createTmpFolder(this.logger);
|
|
32
|
+
const localDatabaseFilePath: string = join(
|
|
33
|
+
TMP_FOLDER_PATH,
|
|
34
|
+
'database.sqlite'
|
|
35
|
+
);
|
|
36
|
+
return new KeyvSqlite(localDatabaseFilePath);
|
|
36
37
|
}
|
|
38
|
+
|
|
39
|
+
return new KeyvPostgres({
|
|
40
|
+
uri: postgresUri,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
37
43
|
}
|
|
@@ -1,57 +1,59 @@
|
|
|
1
|
-
import { Global, Module } from
|
|
2
|
-
import { ConfigModule } from
|
|
3
|
-
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from
|
|
4
|
-
import { ThrottlerGuard, ThrottlerModule } from
|
|
5
|
-
import type { ILogger } from
|
|
6
|
-
import {
|
|
1
|
+
import { Global, Module } from '@nestjs/common';
|
|
2
|
+
import { ConfigModule } from '@nestjs/config';
|
|
3
|
+
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core';
|
|
4
|
+
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
|
|
5
|
+
import type { ILogger } from '@ask-ell/core';
|
|
6
|
+
import {
|
|
7
|
+
NestLogger,
|
|
8
|
+
HealthModule,
|
|
9
|
+
ResponseFormatInterceptor,
|
|
10
|
+
HttpExceptionFilter,
|
|
11
|
+
} from '@ask-ell/nest';
|
|
7
12
|
import { SentryGlobalFilter, SentryModule } from '@sentry/nestjs/setup';
|
|
8
13
|
|
|
9
|
-
import { KeyvStoreAdapterFactory } from
|
|
10
|
-
import { dockerSecretGetter, localSecretGetter } from
|
|
11
|
-
|
|
14
|
+
import { KeyvStoreAdapterFactory } from './keyv.store.adapter.factory';
|
|
15
|
+
import { dockerSecretGetter, localSecretGetter } from './secrets';
|
|
12
16
|
|
|
13
17
|
const configModuleLogger: ILogger = NestLogger.fromClass(ConfigModule);
|
|
14
18
|
|
|
15
19
|
@Global()
|
|
16
20
|
@Module({
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
KeyvStoreAdapterFactory
|
|
55
|
-
]
|
|
21
|
+
imports: [
|
|
22
|
+
HealthModule,
|
|
23
|
+
SentryModule.forRoot(),
|
|
24
|
+
ThrottlerModule.forRoot([
|
|
25
|
+
{
|
|
26
|
+
ttl: 60000,
|
|
27
|
+
limit: 30,
|
|
28
|
+
},
|
|
29
|
+
]),
|
|
30
|
+
ConfigModule.forRoot({
|
|
31
|
+
isGlobal: true,
|
|
32
|
+
load: [
|
|
33
|
+
dockerSecretGetter(configModuleLogger),
|
|
34
|
+
localSecretGetter(configModuleLogger),
|
|
35
|
+
],
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
38
|
+
providers: [
|
|
39
|
+
KeyvStoreAdapterFactory,
|
|
40
|
+
{
|
|
41
|
+
provide: APP_GUARD,
|
|
42
|
+
useClass: ThrottlerGuard,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
provide: APP_INTERCEPTOR,
|
|
46
|
+
useClass: ResponseFormatInterceptor,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
provide: APP_FILTER,
|
|
50
|
+
useClass: HttpExceptionFilter,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
provide: APP_FILTER,
|
|
54
|
+
useClass: SentryGlobalFilter,
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
exports: [ConfigModule, SentryModule, KeyvStoreAdapterFactory],
|
|
56
58
|
})
|
|
57
|
-
export class RequirementModule {
|
|
59
|
+
export class RequirementModule {}
|
|
@@ -3,65 +3,86 @@ import { Script, ExecuteOptions } from '@ask-ell/node';
|
|
|
3
3
|
import { NestLogger } from '@ask-ell/nest';
|
|
4
4
|
import { Client, QueryResult } from 'pg';
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
type KeyvRowData<Value = unknown> = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
7
|
+
key: string;
|
|
8
|
+
value: Value;
|
|
9
|
+
};
|
|
11
10
|
|
|
12
11
|
export class MoveKeyvDataScript extends Script {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
12
|
+
constructor() {
|
|
13
|
+
super({
|
|
14
|
+
arguments: [
|
|
15
|
+
{
|
|
16
|
+
name: 'origin',
|
|
17
|
+
description: 'Origin Postgres database URI',
|
|
18
|
+
required: true,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'target',
|
|
22
|
+
description: 'Target Postgres database URI',
|
|
23
|
+
required: true,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
logger: NestLogger.fromClass(MoveKeyvDataScript),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
async execute({
|
|
31
|
+
logger,
|
|
32
|
+
arguments: { origin, target },
|
|
33
|
+
prompts: { confirm },
|
|
34
|
+
}: ExecuteOptions): Promise<void> {
|
|
35
|
+
const originPostgresClient: Client = new Client(origin);
|
|
36
|
+
const targetPostgresClient: Client = new Client(target);
|
|
26
37
|
|
|
27
|
-
|
|
38
|
+
logger.log('Reading databases...');
|
|
28
39
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
await Promise.all([
|
|
41
|
+
originPostgresClient.connect(),
|
|
42
|
+
targetPostgresClient.connect(),
|
|
43
|
+
]);
|
|
33
44
|
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
try {
|
|
46
|
+
const { rows }: QueryResult<KeyvRowData> =
|
|
47
|
+
await originPostgresClient.query('SELECT * FROM keyv');
|
|
36
48
|
|
|
37
|
-
|
|
38
|
-
|
|
49
|
+
const rowsCount: number = rows.length;
|
|
50
|
+
logger.log(
|
|
51
|
+
`You're going to insert ${rowsCount} keyv entries from the original database to the target database.`
|
|
52
|
+
);
|
|
39
53
|
|
|
40
|
-
|
|
54
|
+
const confirmed: boolean = await confirm(
|
|
55
|
+
'Are you sure you want to proceed?'
|
|
56
|
+
);
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
await targetPostgresClient.query('INSERT INTO keyv (key, value) VALUES ($1, $2)', [key, value]);
|
|
51
|
-
incrementor.increment();
|
|
52
|
-
}
|
|
58
|
+
if (confirmed) {
|
|
59
|
+
logger.log('Inserting entries into the target database...');
|
|
60
|
+
const incrementor: PercentageIncrementor = new PercentageIncrementor(
|
|
61
|
+
rowsCount
|
|
62
|
+
);
|
|
63
|
+
incrementor.onIncrement(({ achivmentOnPercent }): void => {
|
|
64
|
+
logger.log(`Progress: ${achivmentOnPercent}%`);
|
|
65
|
+
});
|
|
53
66
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
await Promise.all([
|
|
61
|
-
originPostgresClient.end(),
|
|
62
|
-
targetPostgresClient.end()
|
|
63
|
-
]);
|
|
64
|
-
logger.log('Database connections closed.');
|
|
67
|
+
for (const { key, value } of rows) {
|
|
68
|
+
await targetPostgresClient.query(
|
|
69
|
+
'INSERT INTO keyv (key, value) VALUES ($1, $2)',
|
|
70
|
+
[key, value]
|
|
71
|
+
);
|
|
72
|
+
incrementor.increment();
|
|
65
73
|
}
|
|
74
|
+
|
|
75
|
+
logger.log(`${rowsCount} entries inserted into the target database.`);
|
|
76
|
+
logger.log('Migration completed successfully.');
|
|
77
|
+
} else {
|
|
78
|
+
logger.log('Migration cancelled.');
|
|
79
|
+
}
|
|
80
|
+
} finally {
|
|
81
|
+
await Promise.all([
|
|
82
|
+
originPostgresClient.end(),
|
|
83
|
+
targetPostgresClient.end(),
|
|
84
|
+
]);
|
|
85
|
+
logger.log('Database connections closed.');
|
|
66
86
|
}
|
|
87
|
+
}
|
|
67
88
|
}
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
MaybeUndefined,
|
|
3
|
+
StringDictionnary,
|
|
4
|
+
UnknownEnvironmentVariableError,
|
|
5
|
+
} from '@ask-ell/core';
|
|
6
|
+
import { NestLogger } from '@ask-ell/nest';
|
|
7
|
+
import { ExecuteOptions, Script } from '@ask-ell/node';
|
|
4
8
|
import { spawnSync } from 'node:child_process';
|
|
5
|
-
import { writeFileSync } from
|
|
9
|
+
import { writeFileSync } from 'node:fs';
|
|
6
10
|
import { mkdir } from 'node:fs/promises';
|
|
7
11
|
import { join } from 'node:path';
|
|
8
12
|
|
|
9
|
-
|
|
10
13
|
const PROJECT_ROOT_PATH: MaybeUndefined<string> = process.env['PWD'];
|
|
11
14
|
|
|
12
|
-
function makeSureThatProjectRootPathIsDefined(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
function makeSureThatProjectRootPathIsDefined(
|
|
16
|
+
projectRootPath: MaybeUndefined<string>
|
|
17
|
+
): asserts projectRootPath is string {
|
|
18
|
+
if (!projectRootPath) {
|
|
19
|
+
throw new UnknownEnvironmentVariableError('PWD');
|
|
20
|
+
}
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
makeSureThatProjectRootPathIsDefined(PROJECT_ROOT_PATH);
|
|
@@ -20,148 +25,177 @@ makeSureThatProjectRootPathIsDefined(PROJECT_ROOT_PATH);
|
|
|
20
25
|
const NX_GRAPH_FILE_PATH: string = join(PROJECT_ROOT_PATH, 'tmp/graph.json');
|
|
21
26
|
|
|
22
27
|
type PackageContent = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
version: string;
|
|
29
|
+
dependencies: StringDictionnary;
|
|
30
|
+
devDependencies: StringDictionnary;
|
|
26
31
|
};
|
|
27
32
|
|
|
28
33
|
const ROOT_PACKAGE_FILE_PATH: string = join(PROJECT_ROOT_PATH, `package.json`);
|
|
29
34
|
const ROOT_PACKAGE_CONTENT: PackageContent = require(ROOT_PACKAGE_FILE_PATH);
|
|
30
35
|
|
|
31
|
-
|
|
32
36
|
function getOrganisationPackageFile(packageId: string): PackageContent {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
makeSureThatProjectRootPathIsDefined(PROJECT_ROOT_PATH);
|
|
38
|
+
const packageFilePath = join(
|
|
39
|
+
PROJECT_ROOT_PATH,
|
|
40
|
+
`packages/${packageId}/package.json`
|
|
41
|
+
);
|
|
42
|
+
return require(packageFilePath);
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
type UpdateDependenciesVersionsScriptParams = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
46
|
+
organisationPackagePrefix: string;
|
|
47
|
+
blackListedPackages: string[];
|
|
48
|
+
};
|
|
42
49
|
|
|
43
|
-
type WorkspaceDependenciesMapElement = {
|
|
50
|
+
type WorkspaceDependenciesMapElement = {
|
|
51
|
+
id: string;
|
|
52
|
+
dependencies: string[];
|
|
53
|
+
source: PackageContent;
|
|
54
|
+
};
|
|
44
55
|
|
|
45
56
|
type WorkspaceDependenciesMap = {
|
|
46
|
-
|
|
57
|
+
[id: string]: WorkspaceDependenciesMapElement;
|
|
47
58
|
};
|
|
48
59
|
|
|
49
60
|
export class UpdateDependenciesVersionsScript extends Script {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
private organisationPackagePrefix: string;
|
|
62
|
+
private blackListedPackages: string[];
|
|
63
|
+
private workspaceDependenciesMap: WorkspaceDependenciesMap =
|
|
64
|
+
this.getWorkspaceDependenciesMap();
|
|
65
|
+
|
|
66
|
+
constructor({
|
|
67
|
+
organisationPackagePrefix,
|
|
68
|
+
blackListedPackages,
|
|
69
|
+
}: UpdateDependenciesVersionsScriptParams) {
|
|
70
|
+
super({
|
|
71
|
+
logger: NestLogger.fromClass(UpdateDependenciesVersionsScript),
|
|
72
|
+
arguments: [
|
|
73
|
+
{
|
|
74
|
+
name: 'targetedPackage',
|
|
75
|
+
description: 'Target package',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
});
|
|
79
|
+
this.organisationPackagePrefix = organisationPackagePrefix;
|
|
80
|
+
this.blackListedPackages = blackListedPackages;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async execute({
|
|
84
|
+
logger,
|
|
85
|
+
arguments: { targetedPackage },
|
|
86
|
+
}: ExecuteOptions): Promise<void> {
|
|
87
|
+
const workspaceDependenciesMapElements: WorkspaceDependenciesMapElement[] =
|
|
88
|
+
Object.values(this.workspaceDependenciesMap).filter(
|
|
89
|
+
({ id }: WorkspaceDependenciesMapElement): boolean =>
|
|
90
|
+
this.isTargetedPackage(targetedPackage)(id)
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
for (const {
|
|
94
|
+
id,
|
|
95
|
+
dependencies,
|
|
96
|
+
source,
|
|
97
|
+
} of workspaceDependenciesMapElements) {
|
|
98
|
+
logger.log(`package.json file updating for project "${id}"...`);
|
|
99
|
+
|
|
100
|
+
if (!PROJECT_ROOT_PATH) {
|
|
101
|
+
throw new UnknownEnvironmentVariableError('PWD');
|
|
102
|
+
}
|
|
103
|
+
const packagePath: string = join(
|
|
104
|
+
PROJECT_ROOT_PATH,
|
|
105
|
+
`dist/packages/${id}`
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
await mkdir(packagePath, { recursive: true });
|
|
109
|
+
const packageFilePath: string = join(PROJECT_ROOT_PATH, 'package.json');
|
|
110
|
+
|
|
111
|
+
const packageFileContent: PackageContent = { ...source };
|
|
112
|
+
|
|
113
|
+
if (dependencies.length && !packageFileContent.dependencies) {
|
|
114
|
+
packageFileContent.dependencies = {};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
dependencies.forEach((dependency: string): void => {
|
|
118
|
+
const versionTag = this.isAOrganisationPackage(dependency)
|
|
119
|
+
? `^${
|
|
120
|
+
this.workspaceDependenciesMap[
|
|
121
|
+
dependency.replace(this.organisationPackagePrefix, '')
|
|
122
|
+
].source.version
|
|
123
|
+
}`
|
|
124
|
+
: ROOT_PACKAGE_CONTENT.devDependencies[dependency];
|
|
125
|
+
packageFileContent.dependencies[dependency] = versionTag;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
writeFileSync(
|
|
129
|
+
packageFilePath,
|
|
130
|
+
JSON.stringify(packageFileContent, null, 2) + '\n'
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
console.log(`package.json file updated for project "${id}"`);
|
|
69
134
|
}
|
|
70
135
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
arguments: {
|
|
74
|
-
targetedPackage
|
|
75
|
-
}
|
|
76
|
-
}: ExecuteOptions): Promise<void> {
|
|
77
|
-
const workspaceDependenciesMapElements: WorkspaceDependenciesMapElement[] = Object
|
|
78
|
-
.values(this.workspaceDependenciesMap)
|
|
79
|
-
.filter(({ id }: WorkspaceDependenciesMapElement): boolean => this.isTargetedPackage(targetedPackage)(id));
|
|
80
|
-
|
|
81
|
-
for (const { id, dependencies, source } of workspaceDependenciesMapElements) {
|
|
82
|
-
logger.log(`package.json file updating for project "${id}"...`);
|
|
83
|
-
|
|
84
|
-
if (!PROJECT_ROOT_PATH) {
|
|
85
|
-
throw new UnknownEnvironmentVariableError('PWD');
|
|
86
|
-
}
|
|
87
|
-
const packagePath: string = join(PROJECT_ROOT_PATH, `dist/packages/${id}`);
|
|
88
|
-
|
|
89
|
-
await mkdir(packagePath, { recursive: true });
|
|
90
|
-
const packageFilePath: string = join(PROJECT_ROOT_PATH, 'package.json');
|
|
91
|
-
|
|
92
|
-
const packageFileContent: PackageContent = { ...source };
|
|
93
|
-
|
|
94
|
-
if (dependencies.length && !packageFileContent.dependencies) {
|
|
95
|
-
packageFileContent.dependencies = {};
|
|
96
|
-
}
|
|
136
|
+
console.log('Package files updated.');
|
|
137
|
+
}
|
|
97
138
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
? `^${this.workspaceDependenciesMap[dependency.replace(this.organisationPackagePrefix, '')].source.version}`
|
|
101
|
-
: ROOT_PACKAGE_CONTENT.devDependencies[dependency];
|
|
102
|
-
packageFileContent.dependencies[dependency] = versionTag;
|
|
103
|
-
});
|
|
139
|
+
getWorkspaceDependenciesMap(): WorkspaceDependenciesMap {
|
|
140
|
+
const workspaceDependenciesMap: WorkspaceDependenciesMap = {};
|
|
104
141
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
console.log('Package files updated.')
|
|
142
|
+
const nxGraphResult = spawnSync(
|
|
143
|
+
'npx',
|
|
144
|
+
['nx', 'graph', '--file', NX_GRAPH_FILE_PATH],
|
|
145
|
+
{ stdio: 'inherit' }
|
|
146
|
+
);
|
|
147
|
+
if (nxGraphResult.status !== 0) {
|
|
148
|
+
throw new Error(`"nx graph" failed with status ${nxGraphResult.status}`);
|
|
114
149
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
for (const dependency of dependencies) {
|
|
139
|
-
workspaceDependenciesMap[packageId].dependencies.push(dependency);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
150
|
+
const nxGraph = require(NX_GRAPH_FILE_PATH);
|
|
151
|
+
|
|
152
|
+
const packageIds = Object.entries(nxGraph.graph.dependencies).map(
|
|
153
|
+
([packageId]) => packageId
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
for (const packageId of packageIds.filter(this.isNotBlackListed)) {
|
|
157
|
+
console.log(`Scanning dependencies for package ${packageId}...`);
|
|
158
|
+
const packageFileContent = getOrganisationPackageFile(packageId);
|
|
159
|
+
const dependencies = packageFileContent.dependencies
|
|
160
|
+
? Object.entries(packageFileContent.dependencies).map(
|
|
161
|
+
([dependency]) => dependency
|
|
162
|
+
)
|
|
163
|
+
: [];
|
|
164
|
+
|
|
165
|
+
workspaceDependenciesMap[packageId] = {
|
|
166
|
+
id: packageId,
|
|
167
|
+
dependencies: [],
|
|
168
|
+
source: packageFileContent,
|
|
169
|
+
};
|
|
170
|
+
if (packageFileContent.dependencies) {
|
|
171
|
+
for (const dependency of dependencies) {
|
|
172
|
+
workspaceDependenciesMap[packageId].dependencies.push(dependency);
|
|
142
173
|
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
143
176
|
|
|
144
|
-
|
|
177
|
+
console.log('Dependencies scan done.');
|
|
145
178
|
|
|
146
|
-
|
|
147
|
-
|
|
179
|
+
return workspaceDependenciesMap;
|
|
180
|
+
}
|
|
148
181
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
182
|
+
private isTargetedPackage =
|
|
183
|
+
(targetPackageId: MaybeUndefined<string>) => (packageId: string) => {
|
|
184
|
+
if (targetPackageId) {
|
|
185
|
+
return packageId === targetPackageId;
|
|
186
|
+
}
|
|
187
|
+
return true;
|
|
188
|
+
};
|
|
155
189
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
190
|
+
private isAOrganisationPackage(packageName: string): boolean {
|
|
191
|
+
return packageName.includes(this.organisationPackagePrefix);
|
|
192
|
+
}
|
|
159
193
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
194
|
+
private isBlackListed(packageId: string): boolean {
|
|
195
|
+
return this.blackListedPackages.includes(packageId);
|
|
196
|
+
}
|
|
163
197
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
198
|
+
private isNotBlackListed(packageId: string): boolean {
|
|
199
|
+
return !this.isBlackListed(packageId);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { FileSecretGetter, fileSecretGetter } from
|
|
2
|
-
|
|
1
|
+
import { FileSecretGetter, fileSecretGetter } from './file.secret.getter';
|
|
3
2
|
|
|
4
3
|
const DOCKER_SECRETS_DIRECTORY = '/run/secrets';
|
|
5
4
|
|
|
6
|
-
export const dockerSecretGetter: FileSecretGetter = fileSecretGetter
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export const dockerSecretGetter: FileSecretGetter = fileSecretGetter(
|
|
6
|
+
DOCKER_SECRETS_DIRECTORY
|
|
7
|
+
)(
|
|
8
|
+
'Application is not running inside Docker container. Docker secrets will be unavailable.'
|
|
9
|
+
);
|
|
@@ -1,24 +1,27 @@
|
|
|
1
|
-
import { Dirent, existsSync, readdirSync, readFileSync } from
|
|
2
|
-
import { join } from
|
|
3
|
-
import { ILogger } from
|
|
4
|
-
|
|
5
|
-
import { SecretGetter } from "./types";
|
|
1
|
+
import { Dirent, existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { ILogger } from '@ask-ell/core';
|
|
6
4
|
|
|
5
|
+
import { SecretGetter } from './types';
|
|
7
6
|
|
|
8
7
|
export type FileSecretGetter = (logger: ILogger) => SecretGetter;
|
|
9
8
|
|
|
10
|
-
export const fileSecretGetter =
|
|
9
|
+
export const fileSecretGetter =
|
|
10
|
+
(rootDirectoryPath: string) =>
|
|
11
|
+
(warningMessage: string): FileSecretGetter =>
|
|
12
|
+
(logger: ILogger): SecretGetter =>
|
|
13
|
+
(): object => {
|
|
11
14
|
const isDirectoryExists: boolean = existsSync(rootDirectoryPath);
|
|
12
|
-
if(!isDirectoryExists){
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
if (!isDirectoryExists) {
|
|
16
|
+
logger.warn(warningMessage);
|
|
17
|
+
return {};
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
return readdirSync(rootDirectoryPath, { withFileTypes: true })
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
21
|
+
.filter((entry: Dirent<string>): boolean => entry.isFile())
|
|
22
|
+
.reduce((secrets: Record<string, string>, entry): object => {
|
|
23
|
+
const filePath: string = join(rootDirectoryPath, entry.name);
|
|
24
|
+
secrets[entry.name] = readFileSync(filePath, 'utf-8').trim();
|
|
25
|
+
return secrets;
|
|
26
|
+
}, {});
|
|
27
|
+
};
|
package/src/secrets/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './docker.secret.getter'
|
|
2
|
-
export * from './local.secret.getter'
|
|
1
|
+
export * from './docker.secret.getter';
|
|
2
|
+
export * from './local.secret.getter';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { fileSecretGetter, FileSecretGetter } from
|
|
2
|
-
|
|
1
|
+
import { fileSecretGetter, FileSecretGetter } from './file.secret.getter';
|
|
3
2
|
|
|
4
3
|
const LOCAL_SECRETS_DIRECTORY = '.secrets';
|
|
5
4
|
|
|
6
|
-
export const localSecretGetter: FileSecretGetter = fileSecretGetter
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export const localSecretGetter: FileSecretGetter = fileSecretGetter(
|
|
6
|
+
LOCAL_SECRETS_DIRECTORY
|
|
7
|
+
)(
|
|
8
|
+
'Secrets directory not exists on this project. Local secrets will be unavailable.'
|
|
9
|
+
);
|
package/src/utils/tmp.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { ILogger } from
|
|
2
|
-
import { existsSync, mkdirSync } from
|
|
3
|
-
import { join } from
|
|
4
|
-
|
|
1
|
+
import { ILogger } from '@ask-ell/core';
|
|
2
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
5
4
|
|
|
6
5
|
export const TMP_FOLDER_PATH: string = join(process.cwd(), 'tmp');
|
|
7
6
|
|
|
8
7
|
export const createTmpFolder = (logger: ILogger): void => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
8
|
+
const isTmpFolderExists: boolean = existsSync(TMP_FOLDER_PATH);
|
|
9
|
+
if (isTmpFolderExists) {
|
|
10
|
+
logger.info(`"${TMP_FOLDER_PATH}" folder already exists.`);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
mkdirSync(TMP_FOLDER_PATH);
|
|
14
|
+
logger.info(`"${TMP_FOLDER_PATH}" folder created.`);
|
|
15
|
+
};
|