build: use strict null checks part 1

This commit is contained in:
Kamil Myśliwiec
2024-11-26 12:46:59 +01:00
parent 38367e8e88
commit 10fdf16c47
51 changed files with 413 additions and 304 deletions

View File

@@ -128,8 +128,8 @@ export class Module {
} }
get entryProviders(): Array<InstanceWrapper<Injectable>> { get entryProviders(): Array<InstanceWrapper<Injectable>> {
return Array.from(this._entryProviderKeys).map(token => return Array.from(this._entryProviderKeys).map(
this.providers.get(token), token => this.providers.get(token)!,
); );
} }
@@ -379,7 +379,7 @@ export class Module {
new InstanceWrapper({ new InstanceWrapper({
token: providerToken, token: providerToken,
name: (providerToken as Function)?.name || providerToken, name: (providerToken as Function)?.name || providerToken,
metatype: null, metatype: null!,
instance: value, instance: value,
isResolved: true, isResolved: true,
async: value instanceof Promise, async: value instanceof Promise,
@@ -497,7 +497,7 @@ export class Module {
token: controller, token: controller,
name: controller.name, name: controller.name,
metatype: controller, metatype: controller,
instance: null, instance: null!,
isResolved: false, isResolved: false,
scope: getClassScope(controller), scope: getClassScope(controller),
durable: isDurable(controller), durable: isDurable(controller),
@@ -532,11 +532,11 @@ export class Module {
if (options.isProvider && this.hasProvider(toReplace)) { if (options.isProvider && this.hasProvider(toReplace)) {
const originalProvider = this._providers.get(toReplace); const originalProvider = this._providers.get(toReplace);
return originalProvider.mergeWith({ provide: toReplace, ...options }); return originalProvider!.mergeWith({ provide: toReplace, ...options });
} else if (!options.isProvider && this.hasInjectable(toReplace)) { } else if (!options.isProvider && this.hasInjectable(toReplace)) {
const originalInjectable = this._injectables.get(toReplace); const originalInjectable = this._injectables.get(toReplace);
return originalInjectable.mergeWith({ return originalInjectable!.mergeWith({
provide: toReplace, provide: toReplace,
...options, ...options,
}); });

View File

@@ -91,7 +91,7 @@ export class GraphInspector {
} }
public insertAttachedEnhancer(wrapper: InstanceWrapper) { public insertAttachedEnhancer(wrapper: InstanceWrapper) {
const existingNode = this.graph.getNodeById(wrapper.id); const existingNode = this.graph.getNodeById(wrapper.id)!;
existingNode.metadata.global = true; existingNode.metadata.global = true;
this.graph.insertAttachedEnhancer(existingNode.id); this.graph.insertAttachedEnhancer(existingNode.id);
@@ -123,12 +123,12 @@ export class GraphInspector {
sourceModuleName: moduleRef.name, sourceModuleName: moduleRef.name,
durable: wrapper.isDependencyTreeDurable(), durable: wrapper.isDependencyTreeDurable(),
static: wrapper.isDependencyTreeStatic(), static: wrapper.isDependencyTreeStatic(),
scope: wrapper.scope, scope: wrapper.scope!,
transient: wrapper.isTransient, transient: wrapper.isTransient,
exported: moduleRef.exports.has(wrapper.token), exported: moduleRef.exports.has(wrapper.token),
token: wrapper.token, token: wrapper.token,
subtype: wrapper.subtype, subtype: wrapper.subtype,
initTime: wrapper.initTime, initTime: wrapper.initTime!,
}, },
}); });
} }
@@ -168,7 +168,7 @@ export class GraphInspector {
const moduleRef = this.container.getModuleByKey(entry.moduleToken); const moduleRef = this.container.getModuleByKey(entry.moduleToken);
const sourceInstanceWrapper = const sourceInstanceWrapper =
moduleRef.controllers.get(entry.classRef) ?? moduleRef.controllers.get(entry.classRef) ??
moduleRef.providers.get(entry.classRef); moduleRef.providers.get(entry.classRef)!;
const existingSourceNode = this.graph.getNodeById( const existingSourceNode = this.graph.getNodeById(
sourceInstanceWrapper.id, sourceInstanceWrapper.id,
) as ClassNode; ) as ClassNode;
@@ -190,7 +190,7 @@ export class GraphInspector {
}); });
} else { } else {
const name = const name =
entry.enhancerRef.constructor?.name ?? entry.enhancerRef!.constructor?.name ??
(entry.enhancerRef as Function).name; (entry.enhancerRef as Function).name;
enhancers.push({ enhancers.push({
@@ -219,7 +219,7 @@ export class GraphInspector {
targetClassName: target.name, targetClassName: target.name,
sourceClassToken: source.token, sourceClassToken: source.token,
targetClassToken: target.token, targetClassToken: target.token,
targetModuleName: target.host?.name, targetModuleName: target.host?.name!,
keyOrIndex, keyOrIndex,
injectionType, injectionType,
}, },

View File

@@ -41,19 +41,19 @@ export class InterceptorsContextCreator extends ContextCreator {
inquirerId?: string, inquirerId?: string,
): R { ): R {
if (isEmpty(metadata)) { if (isEmpty(metadata)) {
return [] as R; return [] as any[] as R;
} }
return iterate(metadata) return iterate(metadata)
.filter( .filter(
interceptor => interceptor =>
interceptor && (interceptor.name || interceptor.intercept), interceptor && (interceptor.name || interceptor.intercept),
) )
.map(interceptor => .map(
this.getInterceptorInstance(interceptor, contextId, inquirerId), interceptor =>
this.getInterceptorInstance(interceptor, contextId, inquirerId)!,
) )
.filter( .filter((interceptor: NestInterceptor) =>
(interceptor: NestInterceptor) => interceptor ? isFunction(interceptor.intercept) : false,
interceptor && isFunction(interceptor.intercept),
) )
.toArray() as R; .toArray() as R;
} }
@@ -63,7 +63,7 @@ export class InterceptorsContextCreator extends ContextCreator {
contextId = STATIC_CONTEXT, contextId = STATIC_CONTEXT,
inquirerId?: string, inquirerId?: string,
): NestInterceptor | null { ): NestInterceptor | null {
const isObject = (metatype as NestInterceptor).intercept; const isObject = !!(metatype as NestInterceptor).intercept;
if (isObject) { if (isObject) {
return metatype as NestInterceptor; return metatype as NestInterceptor;
} }
@@ -99,7 +99,7 @@ export class InterceptorsContextCreator extends ContextCreator {
inquirerId?: string, inquirerId?: string,
): T { ): T {
if (!this.config) { if (!this.config) {
return [] as T; return [] as unknown[] as T;
} }
const globalInterceptors = this.config.getGlobalInterceptors() as T; const globalInterceptors = this.config.getGlobalInterceptors() as T;
if (contextId === STATIC_CONTEXT && !inquirerId) { if (contextId === STATIC_CONTEXT && !inquirerId) {

View File

@@ -34,7 +34,10 @@ export class MetadataScanner {
visitedNames.set(property, true); visitedNames.set(property, true);
// reason: https://github.com/nestjs/nest/pull/10821#issuecomment-1411916533 // reason: https://github.com/nestjs/nest/pull/10821#issuecomment-1411916533
const descriptor = Object.getOwnPropertyDescriptor(prototype, property); const descriptor = Object.getOwnPropertyDescriptor(
prototype,
property,
)!;
if ( if (
descriptor.set || descriptor.set ||

View File

@@ -338,8 +338,8 @@ export class MiddlewareModule<
} }
private getContextId(request: unknown, isTreeDurable: boolean): ContextId { private getContextId(request: unknown, isTreeDurable: boolean): ContextId {
const contextId = ContextIdFactory.getByRequest(request); const contextId = ContextIdFactory.getByRequest(request!);
if (!request[REQUEST_CONTEXT_ID]) { if (!request![REQUEST_CONTEXT_ID]) {
Object.defineProperty(request, REQUEST_CONTEXT_ID, { Object.defineProperty(request, REQUEST_CONTEXT_ID, {
value: contextId, value: contextId,
enumerable: false, enumerable: false,

View File

@@ -112,9 +112,9 @@ export function isMiddlewareRouteExcluded(
if (excludedRoutes.length <= 0) { if (excludedRoutes.length <= 0) {
return false; return false;
} }
const reqMethod = httpAdapter.getRequestMethod(req); const reqMethod = httpAdapter.getRequestMethod?.(req)!;
const originalUrl = httpAdapter.getRequestUrl(req); const originalUrl = httpAdapter.getRequestUrl?.(req)!;
const queryParamsIndex = originalUrl && originalUrl.indexOf('?'); const queryParamsIndex = originalUrl ? originalUrl.indexOf('?') : -1;
const pathname = const pathname =
queryParamsIndex >= 0 queryParamsIndex >= 0
? originalUrl.slice(0, queryParamsIndex) ? originalUrl.slice(0, queryParamsIndex)

View File

@@ -26,15 +26,15 @@ import { NestContainer } from '../injector/container';
import { Injector } from '../injector/injector'; import { Injector } from '../injector/injector';
import { ContextId, InstanceWrapper } from '../injector/instance-wrapper'; import { ContextId, InstanceWrapper } from '../injector/instance-wrapper';
import { Module } from '../injector/module'; import { Module } from '../injector/module';
import {
InterceptorsConsumer,
InterceptorsContextCreator,
} from '../interceptors';
import { GraphInspector } from '../inspector/graph-inspector'; import { GraphInspector } from '../inspector/graph-inspector';
import { import {
Entrypoint, Entrypoint,
HttpEntrypointMetadata, HttpEntrypointMetadata,
} from '../inspector/interfaces/entrypoint.interface'; } from '../inspector/interfaces/entrypoint.interface';
import {
InterceptorsConsumer,
InterceptorsContextCreator,
} from '../interceptors';
import { MetadataScanner } from '../metadata-scanner'; import { MetadataScanner } from '../metadata-scanner';
import { PipesConsumer, PipesContextCreator } from '../pipes'; import { PipesConsumer, PipesContextCreator } from '../pipes';
import { ExceptionsFilter } from './interfaces/exceptions-filter.interface'; import { ExceptionsFilter } from './interfaces/exceptions-filter.interface';

View File

@@ -78,7 +78,7 @@ export class RouterModule {
private updateTargetModulesCache(moduleCtor: Type<unknown>) { private updateTargetModulesCache(moduleCtor: Type<unknown>) {
let moduleClassSet: WeakSet<ModuleClass>; let moduleClassSet: WeakSet<ModuleClass>;
if (targetModulesByContainer.has(this.modulesContainer)) { if (targetModulesByContainer.has(this.modulesContainer)) {
moduleClassSet = targetModulesByContainer.get(this.modulesContainer); moduleClassSet = targetModulesByContainer.get(this.modulesContainer)!;
} else { } else {
moduleClassSet = new WeakSet<ModuleClass>(); moduleClassSet = new WeakSet<ModuleClass>();
targetModulesByContainer.set(this.modulesContainer, moduleClassSet); targetModulesByContainer.set(this.modulesContainer, moduleClassSet);

View File

@@ -1,8 +1,12 @@
import { normalizePath, isString } from '@nestjs/common/utils/shared.utils'; import { Type } from '@nestjs/common';
import { isString, normalizePath } from '@nestjs/common/utils/shared.utils';
import { Routes } from '../interfaces/routes.interface'; import { Routes } from '../interfaces/routes.interface';
export function flattenRoutePaths(routes: Routes) { export function flattenRoutePaths(routes: Routes) {
const result = []; const result: Array<{
module: Type;
path: string;
}> = [];
routes.forEach(item => { routes.forEach(item => {
if (item.module && item.path) { if (item.module && item.path) {
result.push({ module: item.module, path: item.path }); result.push({ module: item.module, path: item.path });
@@ -15,7 +19,7 @@ export function flattenRoutePaths(routes: Routes) {
normalizePath(item.path) + normalizePath(child.path), normalizePath(item.path) + normalizePath(child.path),
); );
} else { } else {
result.push({ path: item.path, module: child }); result.push({ path: item.path, module: child as any as Type });
} }
}); });
result.push(...flattenRoutePaths(childrenRef)); result.push(...flattenRoutePaths(childrenRef));

View File

@@ -138,7 +138,7 @@ export class DependenciesScanner {
...((moduleDefinition as DynamicModule).imports || []), ...((moduleDefinition as DynamicModule).imports || []),
]; ];
let registeredModuleRefs = []; let registeredModuleRefs: Module[] = [];
for (const [index, innerModule] of modules.entries()) { for (const [index, innerModule] of modules.entries()) {
// In case of a circular dependency (ES module system), JavaScript will resolve the type to `undefined`. // In case of a circular dependency (ES module system), JavaScript will resolve the type to `undefined`.
if (innerModule === undefined) { if (innerModule === undefined) {
@@ -152,7 +152,7 @@ export class DependenciesScanner {
} }
const moduleRefs = await this.scanForModules({ const moduleRefs = await this.scanForModules({
moduleDefinition: innerModule, moduleDefinition: innerModule,
scope: [].concat(scope, moduleDefinition), scope: ([] as Array<Type>).concat(scope, moduleDefinition as Type),
ctxRegistry, ctxRegistry,
overrides, overrides,
lazy, lazy,
@@ -215,7 +215,7 @@ export class DependenciesScanner {
...this.container.getDynamicMetadataByToken( ...this.container.getDynamicMetadataByToken(
token, token,
MODULE_METADATA.IMPORTS as 'imports', MODULE_METADATA.IMPORTS as 'imports',
), )!,
]; ];
for (const related of modules) { for (const related of modules) {
await this.insertImport(related, token, context); await this.insertImport(related, token, context);
@@ -228,7 +228,7 @@ export class DependenciesScanner {
...this.container.getDynamicMetadataByToken( ...this.container.getDynamicMetadataByToken(
token, token,
MODULE_METADATA.PROVIDERS as 'providers', MODULE_METADATA.PROVIDERS as 'providers',
), )!,
]; ];
providers.forEach(provider => { providers.forEach(provider => {
this.insertProvider(provider, token); this.insertProvider(provider, token);
@@ -242,7 +242,7 @@ export class DependenciesScanner {
...this.container.getDynamicMetadataByToken( ...this.container.getDynamicMetadataByToken(
token, token,
MODULE_METADATA.CONTROLLERS as 'controllers', MODULE_METADATA.CONTROLLERS as 'controllers',
), )!,
]; ];
controllers.forEach(item => { controllers.forEach(item => {
this.insertController(item, token); this.insertController(item, token);
@@ -267,7 +267,7 @@ export class DependenciesScanner {
...this.container.getDynamicMetadataByToken( ...this.container.getDynamicMetadataByToken(
token, token,
MODULE_METADATA.EXPORTS as 'exports', MODULE_METADATA.EXPORTS as 'exports',
), )!,
]; ];
exports.forEach(exportedProvider => exports.forEach(exportedProvider =>
this.insertExportedProvider(exportedProvider, token), this.insertExportedProvider(exportedProvider, token),
@@ -285,19 +285,25 @@ export class DependenciesScanner {
); );
const methodInjectables = this.metadataScanner const methodInjectables = this.metadataScanner
.getAllMethodNames(component.prototype) .getAllMethodNames(component.prototype)
.reduce((acc, method) => { .reduce(
const methodInjectable = this.reflectKeyMetadata( (acc, method) => {
component, const methodInjectable = this.reflectKeyMetadata(
metadataKey, component,
method, metadataKey,
); method,
);
if (methodInjectable) { if (methodInjectable) {
acc.push(methodInjectable); acc.push(methodInjectable);
} }
return acc; return acc;
}, []); },
[] as Array<{
methodKey: string;
metadata: Type<Injectable>[];
}>,
);
controllerInjectables.forEach(injectable => controllerInjectables.forEach(injectable =>
this.insertInjectable( this.insertInjectable(
@@ -308,13 +314,13 @@ export class DependenciesScanner {
), ),
); );
methodInjectables.forEach(methodInjectable => { methodInjectables.forEach(methodInjectable => {
methodInjectable.metadata.forEach(injectable => methodInjectable.metadata!.forEach(injectable =>
this.insertInjectable( this.insertInjectable(
injectable, injectable,
token, token,
component, component,
ENHANCER_KEY_TO_SUBTYPE_MAP[metadataKey], ENHANCER_KEY_TO_SUBTYPE_MAP[metadataKey],
methodInjectable.methodKey, methodInjectable.methodKey!,
), ),
); );
}); });
@@ -392,7 +398,7 @@ export class DependenciesScanner {
const calculateDistance = ( const calculateDistance = (
moduleRef: Module, moduleRef: Module,
distance = 1, distance = 1,
modulesStack = [], modulesStack: Module[] = [],
) => { ) => {
const localModulesStack = [...modulesStack]; const localModulesStack = [...modulesStack];
if (!moduleRef || localModulesStack.includes(moduleRef)) { if (!moduleRef || localModulesStack.includes(moduleRef)) {
@@ -412,7 +418,7 @@ export class DependenciesScanner {
}; };
const rootModule = modulesGenerator.next().value; const rootModule = modulesGenerator.next().value;
calculateDistance(rootModule); calculateDistance(rootModule!);
} }
public async insertImport(related: any, token: string, context: string) { public async insertImport(related: any, token: string, context: string) {
@@ -478,7 +484,7 @@ export class DependenciesScanner {
const factoryOrClassProvider = newProvider as const factoryOrClassProvider = newProvider as
| FactoryProvider | FactoryProvider
| ClassProvider; | ClassProvider;
if (this.isRequestOrTransient(factoryOrClassProvider.scope)) { if (this.isRequestOrTransient(factoryOrClassProvider.scope!)) {
return this.container.addInjectable(newProvider, token, enhancerSubtype); return this.container.addInjectable(newProvider, token, enhancerSubtype);
} }
this.container.addProvider(newProvider, token, enhancerSubtype); this.container.addProvider(newProvider, token, enhancerSubtype);
@@ -629,10 +635,10 @@ export class DependenciesScanner {
*/ */
public addScopedEnhancersMetadata() { public addScopedEnhancersMetadata() {
iterate(this.applicationProvidersApplyMap) iterate(this.applicationProvidersApplyMap)
.filter(wrapper => this.isRequestOrTransient(wrapper.scope)) .filter(wrapper => this.isRequestOrTransient(wrapper.scope!))
.forEach(({ moduleKey, providerKey }) => { .forEach(({ moduleKey, providerKey }) => {
const modulesContainer = this.container.getModules(); const modulesContainer = this.container.getModules();
const { injectables } = modulesContainer.get(moduleKey); const { injectables } = modulesContainer.get(moduleKey)!;
const instanceWrapper = injectables.get(providerKey); const instanceWrapper = injectables.get(providerKey);
const iterableIterator = modulesContainer.values(); const iterableIterator = modulesContainer.values();
@@ -644,7 +650,7 @@ export class DependenciesScanner {
) )
.flatten() .flatten()
.forEach(controllerOrEntryProvider => .forEach(controllerOrEntryProvider =>
controllerOrEntryProvider.addEnhancerMetadata(instanceWrapper), controllerOrEntryProvider.addEnhancerMetadata(instanceWrapper!),
); );
}); });
} }
@@ -659,7 +665,7 @@ export class DependenciesScanner {
collectionKey: 'providers' | 'injectables', collectionKey: 'providers' | 'injectables',
) => { ) => {
const modules = this.container.getModules(); const modules = this.container.getModules();
const collection = modules.get(moduleKey)[collectionKey]; const collection = modules.get(moduleKey)![collectionKey];
return collection.get(providerKey); return collection.get(providerKey);
}; };
@@ -667,12 +673,12 @@ export class DependenciesScanner {
this.applicationProvidersApplyMap.forEach( this.applicationProvidersApplyMap.forEach(
({ moduleKey, providerKey, type, scope }) => { ({ moduleKey, providerKey, type, scope }) => {
let instanceWrapper: InstanceWrapper; let instanceWrapper: InstanceWrapper;
if (this.isRequestOrTransient(scope)) { if (this.isRequestOrTransient(scope!)) {
instanceWrapper = getInstanceWrapper( instanceWrapper = getInstanceWrapper(
moduleKey, moduleKey,
providerKey, providerKey,
'injectables', 'injectables',
); )!;
this.graphInspector.insertAttachedEnhancer(instanceWrapper); this.graphInspector.insertAttachedEnhancer(instanceWrapper);
return applyRequestProvidersMap[type as string](instanceWrapper); return applyRequestProvidersMap[type as string](instanceWrapper);
@@ -681,7 +687,7 @@ export class DependenciesScanner {
moduleKey, moduleKey,
providerKey, providerKey,
'providers', 'providers',
); )!;
this.graphInspector.insertAttachedEnhancer(instanceWrapper); this.graphInspector.insertAttachedEnhancer(instanceWrapper);
applyProvidersMap[type as string](instanceWrapper.instance); applyProvidersMap[type as string](instanceWrapper.instance);
}, },

View File

@@ -64,7 +64,7 @@ export class Reflector {
const value = options.transform const value = options.transform
? options.transform(metadataValue) ? options.transform(metadataValue)
: metadataValue; : metadataValue;
SetMetadata(metadataKey, value ?? {})(target, key, descriptor); SetMetadata(metadataKey, value ?? {})(target, key!, descriptor);
}; };
decoratorFn.KEY = metadataKey; decoratorFn.KEY = metadataKey;
@@ -256,7 +256,7 @@ export class Reflector {
public getAllAndOverride<TResult = any, TKey = any>( public getAllAndOverride<TResult = any, TKey = any>(
metadataKeyOrDecorator: TKey, metadataKeyOrDecorator: TKey,
targets: (Type<any> | Function)[], targets: (Type<any> | Function)[],
): TResult { ): TResult | undefined {
for (const target of targets) { for (const target of targets) {
const result = this.get(metadataKeyOrDecorator, target); const result = this.get(metadataKeyOrDecorator, target);
if (result !== undefined) { if (result !== undefined) {

View File

@@ -43,7 +43,7 @@ export class ClientGrpcProxy
); );
} }
constructor(protected readonly options: GrpcOptions['options']) { constructor(protected readonly options: Required<GrpcOptions>['options']) {
super(); super();
this.url = this.getOptionsProp(options, 'url') || GRPC_DEFAULT_URL; this.url = this.getOptionsProp(options, 'url') || GRPC_DEFAULT_URL;
@@ -166,10 +166,10 @@ export class ClientGrpcProxy
methodName: string, methodName: string,
): (...args: any[]) => Observable<any> { ): (...args: any[]) => Observable<any> {
return (...args: any[]) => { return (...args: any[]) => {
const isRequestStream = client[methodName].requestStream; const isRequestStream = client![methodName].requestStream;
const stream = new Observable(observer => { const stream = new Observable(observer => {
let isClientCanceled = false; let isClientCanceled = false;
let upstreamSubscription: Subscription; let upstreamSubscription: Subscription | null = null;
const upstreamSubjectOrData = args[0]; const upstreamSubjectOrData = args[0];
const maybeMetadata = args[1]; const maybeMetadata = args[1];
@@ -179,8 +179,8 @@ export class ClientGrpcProxy
const call = const call =
isRequestStream && isUpstreamSubject isRequestStream && isUpstreamSubject
? client[methodName](maybeMetadata) ? client![methodName](maybeMetadata)
: client[methodName](...args); : client![methodName](...args);
if (isRequestStream && isUpstreamSubject) { if (isRequestStream && isUpstreamSubject) {
upstreamSubscription = upstreamSubjectOrData.subscribe( upstreamSubscription = upstreamSubjectOrData.subscribe(
@@ -295,7 +295,7 @@ export class ClientGrpcProxy
public createClients(): any[] { public createClients(): any[] {
const grpcContext = this.loadProto(); const grpcContext = this.loadProto();
const packageOption = this.getOptionsProp(this.options, 'package'); const packageOption = this.getOptionsProp(this.options, 'package');
const grpcPackages = []; const grpcPackages: any[] = [];
const packageNames = Array.isArray(packageOption) const packageNames = Array.isArray(packageOption)
? packageOption ? packageOption
: [packageOption]; : [packageOption];

View File

@@ -73,15 +73,15 @@ export class ClientKafka
} }
get producer(): Producer { get producer(): Producer {
if (!this._consumer) { if (!this._producer) {
throw new Error( throw new Error(
'No producer initialized. Please, call the "connect" method first.', 'No producer initialized. Please, call the "connect" method first.',
); );
} }
return this._producer; return this._producer!;
} }
constructor(protected readonly options: KafkaOptions['options']) { constructor(protected readonly options: Required<KafkaOptions>['options']) {
super(); super();
const clientOptions = this.getOptionsProp( const clientOptions = this.getOptionsProp(
@@ -135,7 +135,7 @@ export class ClientKafka
public async connect(): Promise<Producer> { public async connect(): Promise<Producer> {
if (this.initialized) { if (this.initialized) {
return this.initialized.then(() => this._producer); return this.initialized.then(() => this._producer!);
} }
/* eslint-disable-next-line no-async-promise-executor */ /* eslint-disable-next-line no-async-promise-executor */
this.initialized = new Promise(async (resolve, reject) => { this.initialized = new Promise(async (resolve, reject) => {
@@ -160,7 +160,7 @@ export class ClientKafka
}, },
); );
this._consumer = this.client.consumer(consumerOptions); this._consumer = this.client!.consumer(consumerOptions);
this.registerConsumerEventListeners(); this.registerConsumerEventListeners();
// Set member assignments on join and rebalance // Set member assignments on join and rebalance
@@ -172,7 +172,7 @@ export class ClientKafka
await this.bindTopics(); await this.bindTopics();
} }
this._producer = this.client.producer(this.options.producer || {}); this._producer = this.client!.producer(this.options.producer || {});
this.registerProducerEventListeners(); this.registerProducerEventListeners();
await this._producer.connect(); await this._producer.connect();
@@ -181,7 +181,7 @@ export class ClientKafka
reject(err); reject(err);
} }
}); });
return this.initialized.then(() => this._producer); return this.initialized.then(() => this._producer!);
} }
public async bindTopics(): Promise<void> { public async bindTopics(): Promise<void> {
@@ -217,13 +217,13 @@ export class ClientKafka
public createResponseCallback(): (payload: EachMessagePayload) => any { public createResponseCallback(): (payload: EachMessagePayload) => any {
return async (payload: EachMessagePayload) => { return async (payload: EachMessagePayload) => {
const rawMessage = this.parser.parse<KafkaMessage>( const rawMessage = this.parser!.parse<KafkaMessage>(
Object.assign(payload.message, { Object.assign(payload.message, {
topic: payload.topic, topic: payload.topic,
partition: payload.partition, partition: payload.partition,
}), }),
); );
if (isUndefined(rawMessage.headers[KafkaHeaders.CORRELATION_ID])) { if (isUndefined(rawMessage.headers![KafkaHeaders.CORRELATION_ID])) {
return; return;
} }
const { err, response, isDisposed, id } = const { err, response, isDisposed, id } =
@@ -270,6 +270,9 @@ export class ClientKafka
} }
protected registerConsumerEventListeners() { protected registerConsumerEventListeners() {
if (!this._consumer) {
return;
}
this._consumer.on(this._consumer.events.CONNECT, () => this._consumer.on(this._consumer.events.CONNECT, () =>
this._status$.next(KafkaStatus.CONNECTED), this._status$.next(KafkaStatus.CONNECTED),
); );
@@ -288,6 +291,9 @@ export class ClientKafka
} }
protected registerProducerEventListeners() { protected registerProducerEventListeners() {
if (!this._producer) {
return;
}
this._producer.on(this._producer.events.CONNECT, () => this._producer.on(this._producer.events.CONNECT, () =>
this._status$.next(KafkaStatus.CONNECTED), this._status$.next(KafkaStatus.CONNECTED),
); );
@@ -309,7 +315,7 @@ export class ClientKafka
this.options.send || {}, this.options.send || {},
); );
return this._producer.send(message); return this._producer!.send(message);
} }
protected getReplyTopicPartition(topic: string): string { protected getReplyTopicPartition(topic: string): string {
@@ -355,13 +361,14 @@ export class ClientKafka
this.options.send || {}, this.options.send || {},
); );
return this._producer.send(message); return this._producer!.send(message);
}) })
.catch(err => errorCallback(err)); .catch(err => errorCallback(err));
return cleanup; return cleanup;
} catch (err) { } catch (err) {
errorCallback(err); errorCallback(err);
return () => null;
} }
} }

View File

@@ -28,8 +28,8 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
protected readonly logger = new Logger(ClientProxy.name); protected readonly logger = new Logger(ClientProxy.name);
protected readonly subscriptionsCount = new Map<string, number>(); protected readonly subscriptionsCount = new Map<string, number>();
protected readonly url: string; protected readonly url: string;
protected mqttClient: MqttClient; protected mqttClient: MqttClient | null = null;
protected connectionPromise: Promise<any>; protected connectionPromise: Promise<any> | null = null;
protected isInitialConnection = false; protected isInitialConnection = false;
protected isReconnecting = false; protected isReconnecting = false;
protected pendingEventListeners: Array<{ protected pendingEventListeners: Array<{
@@ -37,7 +37,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
callback: MqttEvents[keyof MqttEvents]; callback: MqttEvents[keyof MqttEvents];
}> = []; }> = [];
constructor(protected readonly options: MqttOptions['options']) { constructor(protected readonly options: Required<MqttOptions>['options']) {
super(); super();
this.url = this.getOptionsProp(this.options, 'url') ?? MQTT_DEFAULT_URL; this.url = this.getOptionsProp(this.options, 'url') ?? MQTT_DEFAULT_URL;
@@ -64,7 +64,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
public connect(): Promise<any> { public connect(): Promise<any> {
if (this.mqttClient) { if (this.mqttClient) {
return this.connectionPromise; return this.connectionPromise!;
} }
this.mqttClient = this.createClient(); this.mqttClient = this.createClient();
this.registerErrorListener(this.mqttClient); this.registerErrorListener(this.mqttClient);
@@ -75,7 +75,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
this.registerCloseListener(this.mqttClient); this.registerCloseListener(this.mqttClient);
this.pendingEventListeners.forEach(({ event, callback }) => this.pendingEventListeners.forEach(({ event, callback }) =>
this.mqttClient.on(event, callback), this.mqttClient!.on(event, callback),
); );
this.pendingEventListeners = []; this.pendingEventListeners = [];
@@ -233,7 +233,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
const options = serializedPacket.options; const options = serializedPacket.options;
delete serializedPacket.options; delete serializedPacket.options;
this.mqttClient.publish( this.mqttClient!.publish(
this.getRequestPattern(pattern), this.getRequestPattern(pattern),
JSON.stringify(serializedPacket), JSON.stringify(serializedPacket),
this.mergePacketOptions(options), this.mergePacketOptions(options),
@@ -241,7 +241,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
}; };
if (subscriptionsCount <= 0) { if (subscriptionsCount <= 0) {
this.mqttClient.subscribe( this.mqttClient!.subscribe(
responseChannel, responseChannel,
(err: any) => !err && publishPacket(), (err: any) => !err && publishPacket(),
); );
@@ -255,6 +255,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
}; };
} catch (err) { } catch (err) {
callback({ err }); callback({ err });
return () => {};
} }
} }
@@ -267,7 +268,7 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
delete serializedPacket.options; delete serializedPacket.options;
return new Promise<void>((resolve, reject) => return new Promise<void>((resolve, reject) =>
this.mqttClient.publish( this.mqttClient!.publish(
pattern, pattern,
JSON.stringify(serializedPacket), JSON.stringify(serializedPacket),
this.mergePacketOptions(options), this.mergePacketOptions(options),
@@ -277,11 +278,11 @@ export class ClientMqtt extends ClientProxy<MqttEvents, MqttStatus> {
} }
protected unsubscribeFromChannel(channel: string) { protected unsubscribeFromChannel(channel: string) {
const subscriptionCount = this.subscriptionsCount.get(channel); const subscriptionCount = this.subscriptionsCount.get(channel)!;
this.subscriptionsCount.set(channel, subscriptionCount - 1); this.subscriptionsCount.set(channel, subscriptionCount - 1);
if (subscriptionCount - 1 <= 0) { if (subscriptionCount - 1 <= 0) {
this.mqttClient.unsubscribe(channel); this.mqttClient!.unsubscribe(channel);
} }
} }

View File

@@ -29,13 +29,13 @@ type NatsMsg = any;
export class ClientNats extends ClientProxy<NatsEvents, NatsStatus> { export class ClientNats extends ClientProxy<NatsEvents, NatsStatus> {
protected readonly logger = new Logger(ClientNats.name); protected readonly logger = new Logger(ClientNats.name);
protected natsClient: Client; protected natsClient: Client | null = null;
protected connectionPromise: Promise<Client>; protected connectionPromise: Promise<Client> | null = null;
protected statusEventEmitter = new EventEmitter<{ protected statusEventEmitter = new EventEmitter<{
[key in keyof NatsEvents]: Parameters<NatsEvents[key]>; [key in keyof NatsEvents]: Parameters<NatsEvents[key]>;
}>(); }>();
constructor(protected readonly options: NatsOptions['options']) { constructor(protected readonly options: Required<NatsOptions>['options']) {
super(); super();
natsPackage = loadPackage('nats', ClientNats.name, () => require('nats')); natsPackage = loadPackage('nats', ClientNats.name, () => require('nats'));
@@ -229,6 +229,7 @@ export class ClientNats extends ClientProxy<NatsEvents, NatsStatus> {
return () => subscription.unsubscribe(); return () => subscription.unsubscribe();
} catch (err) { } catch (err) {
callback({ err }); callback({ err });
return () => {};
} }
} }

View File

@@ -49,21 +49,27 @@ export class ClientProxyFactory {
switch (transport) { switch (transport) {
case Transport.REDIS: case Transport.REDIS:
return new ClientRedis( return new ClientRedis(
options as RedisOptions['options'], options as Required<RedisOptions>['options'],
) as ClientProxy; ) as ClientProxy;
case Transport.NATS: case Transport.NATS:
return new ClientNats(options as NatsOptions['options']) as ClientProxy; return new ClientNats(
options as Required<NatsOptions>['options'],
) as ClientProxy;
case Transport.MQTT: case Transport.MQTT:
return new ClientMqtt(options as MqttOptions['options']) as ClientProxy; return new ClientMqtt(
options as Required<MqttOptions>['options'],
) as ClientProxy;
case Transport.GRPC: case Transport.GRPC:
return new ClientGrpcProxy(options as GrpcOptions['options']); return new ClientGrpcProxy(options as GrpcOptions['options']);
case Transport.RMQ: case Transport.RMQ:
return new ClientRMQ(options as RmqOptions['options']) as ClientProxy; return new ClientRMQ(
options as Required<RmqOptions>['options'],
) as ClientProxy;
case Transport.KAFKA: case Transport.KAFKA:
return new ClientKafka(options as KafkaOptions['options']); return new ClientKafka(options as Required<KafkaOptions>['options']);
default: default:
return new ClientTCP( return new ClientTCP(
options as TcpClientOptions['options'], options as Required<TcpClientOptions>['options'],
) as ClientProxy; ) as ClientProxy;
} }
} }

View File

@@ -177,10 +177,28 @@ export abstract class ClientProxy<
} }
protected getOptionsProp< protected getOptionsProp<
T extends ClientOptions['options'], Options extends ClientOptions['options'],
K extends keyof T, Attribute extends keyof Options,
>(obj: T, prop: K, defaultValue: T[K] = undefined) { >(obj: Options, prop: Attribute): Options[Attribute];
return obj && prop in obj ? obj[prop] : defaultValue; protected getOptionsProp<
Options extends ClientOptions['options'],
Attribute extends keyof Options,
DefaultValue extends Options[Attribute] = Options[Attribute],
>(
obj: Options,
prop: Attribute,
defaultValue: DefaultValue,
): Required<Options>[Attribute];
protected getOptionsProp<
Options extends ClientOptions['options'],
Attribute extends keyof Options,
DefaultValue extends Options[Attribute] = Options[Attribute],
>(
obj: Options,
prop: Attribute,
defaultValue: DefaultValue = undefined as DefaultValue,
) {
return obj && prop in obj ? obj![prop] : defaultValue;
} }
protected normalizePattern(pattern: MsPattern): string { protected normalizePattern(pattern: MsPattern): string {
@@ -190,30 +208,26 @@ export abstract class ClientProxy<
protected initializeSerializer(options: ClientOptions['options']) { protected initializeSerializer(options: ClientOptions['options']) {
this.serializer = this.serializer =
(options && (options &&
( (options as
options as | RedisOptions['options']
| RedisOptions['options'] | NatsOptions['options']
| NatsOptions['options'] | MqttOptions['options']
| MqttOptions['options'] | TcpClientOptions['options']
| TcpClientOptions['options'] | RmqOptions['options']
| RmqOptions['options'] | KafkaOptions['options'])!.serializer) ||
| KafkaOptions['options']
).serializer) ||
new IdentitySerializer(); new IdentitySerializer();
} }
protected initializeDeserializer(options: ClientOptions['options']) { protected initializeDeserializer(options: ClientOptions['options']) {
this.deserializer = this.deserializer =
(options && (options &&
( (options as
options as | RedisOptions['options']
| RedisOptions['options'] | NatsOptions['options']
| NatsOptions['options'] | MqttOptions['options']
| MqttOptions['options'] | TcpClientOptions['options']
| TcpClientOptions['options'] | RmqOptions['options']
| RmqOptions['options'] | KafkaOptions['options'])!.deserializer) ||
| KafkaOptions['options']
).deserializer) ||
new IncomingResponseDeserializer(); new IncomingResponseDeserializer();
} }
} }

View File

@@ -34,7 +34,7 @@ export class ClientRedis extends ClientProxy<RedisEvents, RedisStatus> {
callback: RedisEvents[keyof RedisEvents]; callback: RedisEvents[keyof RedisEvents];
}> = []; }> = [];
constructor(protected readonly options: RedisOptions['options']) { constructor(protected readonly options: Required<RedisOptions>['options']) {
super(); super();
redisPackage = loadPackage('ioredis', ClientRedis.name, () => redisPackage = loadPackage('ioredis', ClientRedis.name, () =>
@@ -209,11 +209,11 @@ export class ClientRedis extends ClientProxy<RedisEvents, RedisStatus> {
); );
return; return;
} }
if (times > this.getOptionsProp(this.options, 'retryAttempts')) { if (times > this.getOptionsProp(this.options, 'retryAttempts', 0)) {
this.logger.error('Retry time exhausted'); this.logger.error('Retry time exhausted');
return; return;
} }
return this.getOptionsProp(this.options, 'retryDelay') ?? 5000; return this.getOptionsProp(this.options, 'retryDelay', 5000);
} }
public createResponseCallback(): ( public createResponseCallback(): (
@@ -280,6 +280,7 @@ export class ClientRedis extends ClientProxy<RedisEvents, RedisStatus> {
}; };
} catch (err) { } catch (err) {
callback({ err }); callback({ err });
return () => {};
} }
} }
@@ -295,7 +296,7 @@ export class ClientRedis extends ClientProxy<RedisEvents, RedisStatus> {
} }
protected unsubscribeFromChannel(channel: string) { protected unsubscribeFromChannel(channel: string) {
const subscriptionCount = this.subscriptionsCount.get(channel); const subscriptionCount = this.subscriptionsCount.get(channel)!;
this.subscriptionsCount.set(channel, subscriptionCount - 1); this.subscriptionsCount.set(channel, subscriptionCount - 1);
if (subscriptionCount - 1 <= 0) { if (subscriptionCount - 1 <= 0) {

View File

@@ -68,15 +68,19 @@ export class ClientRMQ extends ClientProxy<RmqEvents, RmqStatus> {
protected replyQueue: string; protected replyQueue: string;
protected noAssert: boolean; protected noAssert: boolean;
constructor(protected readonly options: RmqOptions['options']) { constructor(protected readonly options: Required<RmqOptions>['options']) {
super(); super();
this.queue = this.queue = this.getOptionsProp(this.options, 'queue', RQM_DEFAULT_QUEUE);
this.getOptionsProp(this.options, 'queue') || RQM_DEFAULT_QUEUE; this.queueOptions = this.getOptionsProp(
this.queueOptions = this.options,
this.getOptionsProp(this.options, 'queueOptions') || 'queueOptions',
RQM_DEFAULT_QUEUE_OPTIONS; RQM_DEFAULT_QUEUE_OPTIONS,
this.replyQueue = );
this.getOptionsProp(this.options, 'replyQueue') || REPLY_QUEUE; this.replyQueue = this.getOptionsProp(
this.options,
'replyQueue',
REPLY_QUEUE,
);
this.noAssert = this.noAssert =
this.getOptionsProp(this.options, 'noAssert') ?? this.getOptionsProp(this.options, 'noAssert') ??
this.queueOptions.noAssert ?? this.queueOptions.noAssert ??
@@ -300,7 +304,10 @@ export class ClientRMQ extends ClientProxy<RmqEvents, RmqStatus> {
): Promise<void>; ): Promise<void>;
public async handleMessage( public async handleMessage(
packet: unknown, packet: unknown,
options: Record<string, unknown> | ((packet: WritePacket) => any), options:
| Record<string, unknown>
| ((packet: WritePacket) => any)
| undefined,
callback?: (packet: WritePacket) => any, callback?: (packet: WritePacket) => any,
): Promise<void> { ): Promise<void> {
if (isFunction(options)) { if (isFunction(options)) {
@@ -313,13 +320,13 @@ export class ClientRMQ extends ClientProxy<RmqEvents, RmqStatus> {
options, options,
); );
if (isDisposed || err) { if (isDisposed || err) {
callback({ callback?.({
err, err,
response, response,
isDisposed: true, isDisposed: true,
}); });
} }
callback({ callback?.({
err, err,
response, response,
}); });
@@ -372,6 +379,7 @@ export class ClientRMQ extends ClientProxy<RmqEvents, RmqStatus> {
return () => this.responseEmitter.removeListener(correlationId, listener); return () => this.responseEmitter.removeListener(correlationId, listener);
} catch (err) { } catch (err) {
callback({ err }); callback({ err });
return () => {};
} }
} }

View File

@@ -19,19 +19,18 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
protected readonly host: string; protected readonly host: string;
protected readonly socketClass: Type<TcpSocket>; protected readonly socketClass: Type<TcpSocket>;
protected readonly tlsOptions?: ConnectionOptions; protected readonly tlsOptions?: ConnectionOptions;
protected socket: TcpSocket; protected socket: TcpSocket | null = null;
protected connectionPromise: Promise<any>; protected connectionPromise: Promise<any> | null = null;
protected pendingEventListeners: Array<{ protected pendingEventListeners: Array<{
event: keyof TcpEvents; event: keyof TcpEvents;
callback: TcpEvents[keyof TcpEvents]; callback: TcpEvents[keyof TcpEvents];
}> = []; }> = [];
constructor(options: TcpClientOptions['options']) { constructor(options: Required<TcpClientOptions>['options']) {
super(); super();
this.port = this.getOptionsProp(options, 'port') || TCP_DEFAULT_PORT; this.port = this.getOptionsProp(options, 'port', TCP_DEFAULT_PORT);
this.host = this.getOptionsProp(options, 'host') || TCP_DEFAULT_HOST; this.host = this.getOptionsProp(options, 'host', TCP_DEFAULT_HOST);
this.socketClass = this.socketClass = this.getOptionsProp(options, 'socketClass', JsonSocket);
this.getOptionsProp(options, 'socketClass') || JsonSocket;
this.tlsOptions = this.getOptionsProp(options, 'tlsOptions'); this.tlsOptions = this.getOptionsProp(options, 'tlsOptions');
this.initializeSerializer(options); this.initializeSerializer(options);
@@ -48,13 +47,13 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
this.registerErrorListener(this.socket); this.registerErrorListener(this.socket);
this.pendingEventListeners.forEach(({ event, callback }) => this.pendingEventListeners.forEach(({ event, callback }) =>
this.socket.on(event, callback as any), this.socket!.on(event, callback as any),
); );
this.pendingEventListeners = []; this.pendingEventListeners = [];
const source$ = this.connect$(this.socket.netSocket).pipe( const source$ = this.connect$(this.socket.netSocket).pipe(
tap(() => { tap(() => {
this.socket.on('message', (buffer: WritePacket & PacketId) => this.socket!.on('message', (buffer: WritePacket & PacketId) =>
this.handleResponse(buffer), this.handleResponse(buffer),
); );
}), }),
@@ -105,7 +104,6 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
...this.tlsOptions, ...this.tlsOptions,
port: this.port, port: this.port,
host: this.host, host: this.host,
socket,
}); });
} else { } else {
socket = new net.Socket(); socket = new net.Socket();
@@ -148,7 +146,7 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
public handleClose() { public handleClose() {
this.socket = null; this.socket = null;
this.connectionPromise = undefined; this.connectionPromise = null;
if (this.routingMap.size > 0) { if (this.routingMap.size > 0) {
const err = new Error('Connection closed'); const err = new Error('Connection closed');
@@ -188,11 +186,12 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
const serializedPacket = this.serializer.serialize(packet); const serializedPacket = this.serializer.serialize(packet);
this.routingMap.set(packet.id, callback); this.routingMap.set(packet.id, callback);
this.socket.sendMessage(serializedPacket); this.socket!.sendMessage(serializedPacket);
return () => this.routingMap.delete(packet.id); return () => this.routingMap.delete(packet.id);
} catch (err) { } catch (err) {
callback({ err }); callback({ err });
return () => {};
} }
} }
@@ -202,6 +201,6 @@ export class ClientTCP extends ClientProxy<TcpEvents, TcpStatus> {
...packet, ...packet,
pattern, pattern,
}); });
return this.socket.sendMessage(serializedPacket); return this.socket!.sendMessage(serializedPacket);
} }
} }

View File

@@ -1,17 +1,17 @@
import { import {
isObject,
isNumber,
isNil, isNil,
isNumber,
isObject,
isSymbol, isSymbol,
} from '@nestjs/common/utils/shared.utils'; } from '@nestjs/common/utils/shared.utils';
import { import {
PATTERN_EXTRAS_METADATA,
PATTERN_HANDLER_METADATA, PATTERN_HANDLER_METADATA,
PATTERN_METADATA, PATTERN_METADATA,
TRANSPORT_METADATA, TRANSPORT_METADATA,
PATTERN_EXTRAS_METADATA,
} from '../constants'; } from '../constants';
import { PatternHandler } from '../enums/pattern-handler.enum';
import { Transport } from '../enums'; import { Transport } from '../enums';
import { PatternHandler } from '../enums/pattern-handler.enum';
/** /**
* Subscribes to incoming events which fulfils chosen pattern. * Subscribes to incoming events which fulfils chosen pattern.
@@ -43,7 +43,7 @@ export const EventPattern: {
extras = transportOrExtras; extras = transportOrExtras;
} else { } else {
transport = transportOrExtras as Transport | symbol; transport = transportOrExtras as Transport | symbol;
extras = maybeExtras; extras = maybeExtras!;
} }
return ( return (
target: object, target: object,
@@ -52,7 +52,7 @@ export const EventPattern: {
) => { ) => {
Reflect.defineMetadata( Reflect.defineMetadata(
PATTERN_METADATA, PATTERN_METADATA,
[].concat(metadata), ([] as any[]).concat(metadata),
descriptor.value, descriptor.value,
); );
Reflect.defineMetadata( Reflect.defineMetadata(

View File

@@ -1,23 +1,23 @@
import { import {
isObject,
isNumber,
isNil, isNil,
isNumber,
isObject,
isSymbol, isSymbol,
} from '@nestjs/common/utils/shared.utils'; } from '@nestjs/common/utils/shared.utils';
import { import {
PATTERN_EXTRAS_METADATA,
PATTERN_HANDLER_METADATA, PATTERN_HANDLER_METADATA,
PATTERN_METADATA, PATTERN_METADATA,
TRANSPORT_METADATA, TRANSPORT_METADATA,
PATTERN_EXTRAS_METADATA,
} from '../constants'; } from '../constants';
import { PatternHandler } from '../enums/pattern-handler.enum';
import { PatternMetadata } from '../interfaces/pattern-metadata.interface';
import { Transport } from '../enums'; import { Transport } from '../enums';
import { PatternHandler } from '../enums/pattern-handler.enum';
import { import {
InvalidGrpcDecoratorException, InvalidGrpcDecoratorException,
RpcDecoratorMetadata, RpcDecoratorMetadata,
} from '../errors/invalid-grpc-message-decorator.exception'; } from '../errors/invalid-grpc-message-decorator.exception';
import { PatternMetadata } from '../interfaces/pattern-metadata.interface';
export enum GrpcMethodStreamingType { export enum GrpcMethodStreamingType {
NO_STREAMING = 'no_stream', NO_STREAMING = 'no_stream',
@@ -61,8 +61,9 @@ export const MessagePattern: {
extras = transportOrExtras; extras = transportOrExtras;
} else { } else {
transport = transportOrExtras as Transport | symbol; transport = transportOrExtras as Transport | symbol;
extras = maybeExtras; extras = maybeExtras!;
} }
return ( return (
target: object, target: object,
key: string | symbol, key: string | symbol,
@@ -71,7 +72,7 @@ export const MessagePattern: {
try { try {
Reflect.defineMetadata( Reflect.defineMetadata(
PATTERN_METADATA, PATTERN_METADATA,
[].concat(metadata), ([] as any[]).concat(metadata),
descriptor.value, descriptor.value,
); );
Reflect.defineMetadata( Reflect.defineMetadata(
@@ -100,7 +101,10 @@ export const MessagePattern: {
*/ */
export function GrpcMethod(service?: string): MethodDecorator; export function GrpcMethod(service?: string): MethodDecorator;
export function GrpcMethod(service: string, method?: string): MethodDecorator; export function GrpcMethod(service: string, method?: string): MethodDecorator;
export function GrpcMethod(service: string, method?: string): MethodDecorator { export function GrpcMethod(
service: string | undefined,
method?: string,
): MethodDecorator {
return ( return (
target: object, target: object,
key: string | symbol, key: string | symbol,
@@ -126,7 +130,7 @@ export function GrpcStreamMethod(
method?: string, method?: string,
): MethodDecorator; ): MethodDecorator;
export function GrpcStreamMethod( export function GrpcStreamMethod(
service: string, service: string | undefined,
method?: string, method?: string,
): MethodDecorator { ): MethodDecorator {
return ( return (
@@ -160,7 +164,7 @@ export function GrpcStreamCall(
method?: string, method?: string,
): MethodDecorator; ): MethodDecorator;
export function GrpcStreamCall( export function GrpcStreamCall(
service: string, service: string | undefined,
method?: string, method?: string,
): MethodDecorator { ): MethodDecorator {
return ( return (

View File

@@ -18,9 +18,8 @@ export class RpcException extends Error {
) { ) {
this.message = (this.error as Record<string, any>).message; this.message = (this.error as Record<string, any>).message;
} else if (this.constructor) { } else if (this.constructor) {
this.message = this.constructor.name this.message =
.match(/[A-Z][a-z]+|[0-9]+/g) this.constructor!.name!.match(/[A-Z][a-z]+|[0-9]+/g)!.join(' ');
.join(' ');
} }
} }

View File

@@ -39,8 +39,9 @@ export class ListenerMetadataExplorer {
const instancePrototype = Object.getPrototypeOf(instance); const instancePrototype = Object.getPrototypeOf(instance);
return this.metadataScanner return this.metadataScanner
.getAllMethodNames(instancePrototype) .getAllMethodNames(instancePrototype)
.map(method => .map(
this.exploreMethodMetadata(instance, instancePrototype, method), method =>
this.exploreMethodMetadata(instance, instancePrototype, method)!,
) )
.filter(metadata => metadata); .filter(metadata => metadata);
} }
@@ -49,7 +50,7 @@ export class ListenerMetadataExplorer {
instance: Controller, instance: Controller,
instancePrototype: object, instancePrototype: object,
methodKey: string, methodKey: string,
): EventOrMessageListenerDefinition { ): EventOrMessageListenerDefinition | undefined {
const prototypeCallback = instancePrototype[methodKey]; const prototypeCallback = instancePrototype[methodKey];
const handlerType = Reflect.getMetadata( const handlerType = Reflect.getMetadata(
PATTERN_HANDLER_METADATA, PATTERN_HANDLER_METADATA,

View File

@@ -85,7 +85,7 @@ export class ListenersController {
acc.push({ ...handler, patterns: [pattern] }), acc.push({ ...handler, patterns: [pattern] }),
); );
return acc; return acc;
}, []) }, [] as EventOrMessageListenerDefinition[])
.forEach((definition: EventOrMessageListenerDefinition) => { .forEach((definition: EventOrMessageListenerDefinition) => {
const { const {
patterns: [pattern], patterns: [pattern],
@@ -98,7 +98,7 @@ export class ListenersController {
this.insertEntrypointDefinition( this.insertEntrypointDefinition(
instanceWrapper, instanceWrapper,
definition, definition,
serverInstance.transportId, serverInstance.transportId!,
); );
if (isStatic) { if (isStatic) {

View File

@@ -1,8 +1,10 @@
import { import {
DynamicModule, DynamicModule,
ForwardReference,
Module, Module,
OnApplicationShutdown, OnApplicationShutdown,
Provider, Provider,
Type,
} from '@nestjs/common'; } from '@nestjs/common';
import { ClientProxy, ClientProxyFactory } from '../client'; import { ClientProxy, ClientProxyFactory } from '../client';
import { import {
@@ -44,7 +46,9 @@ export class ClientsModule {
option.imports && !accImports.includes(option.imports) option.imports && !accImports.includes(option.imports)
? accImports.concat(option.imports) ? accImports.concat(option.imports)
: accImports, : accImports,
[], [] as Array<
DynamicModule | Promise<DynamicModule> | ForwardReference | Type
>,
); );
return { return {
module: ClientsModule, module: ClientsModule,
@@ -64,8 +68,8 @@ export class ClientsModule {
return [ return [
this.createAsyncOptionsProvider(options), this.createAsyncOptionsProvider(options),
{ {
provide: options.useClass, provide: options.useClass!,
useClass: options.useClass, useClass: options.useClass!,
}, },
]; ];
} }
@@ -86,7 +90,7 @@ export class ClientsModule {
(optionsFactory: ClientsModuleOptionsFactory) => (optionsFactory: ClientsModuleOptionsFactory) =>
optionsFactory.createClientOptions(), optionsFactory.createClientOptions(),
), ),
inject: [options.useExisting || options.useClass], inject: [options.useExisting || options.useClass!],
}; };
} }
@@ -94,7 +98,7 @@ export class ClientsModule {
useFactory: ClientsProviderAsyncOptions['useFactory'], useFactory: ClientsProviderAsyncOptions['useFactory'],
) { ) {
return async (...args: any[]) => { return async (...args: any[]) => {
const clientOptions = await useFactory(...args); const clientOptions = await useFactory!(...args);
const clientProxyRef = ClientProxyFactory.create(clientOptions); const clientProxyRef = ClientProxyFactory.create(clientOptions);
return this.assignOnAppShutdownHook(clientProxyRef); return this.assignOnAppShutdownHook(clientProxyRef);
}; };

View File

@@ -64,7 +64,7 @@ export class NestMicroservice
) { ) {
super(container, config); super(container, config);
this.injector = new Injector({ preview: config.preview }); this.injector = new Injector({ preview: config.preview! });
this.microservicesModule.register( this.microservicesModule.register(
container, container,
this.graphInspector, this.graphInspector,

View File

@@ -1,8 +1,14 @@
import { Transport } from '../enums/transport.enum'; import { Transport } from '../enums/transport.enum';
import { import {
CustomStrategy, CustomStrategy,
GrpcOptions,
KafkaOptions,
MicroserviceOptions, MicroserviceOptions,
MqttOptions, MqttOptions,
NatsOptions,
RedisOptions,
RmqOptions,
TcpOptions,
} from '../interfaces'; } from '../interfaces';
import { ServerGrpc } from './server-grpc'; import { ServerGrpc } from './server-grpc';
import { ServerKafka } from './server-kafka'; import { ServerKafka } from './server-kafka';
@@ -20,19 +26,19 @@ export class ServerFactory {
>; >;
switch (transport) { switch (transport) {
case Transport.REDIS: case Transport.REDIS:
return new ServerRedis(options); return new ServerRedis(options as Required<RedisOptions>['options']);
case Transport.NATS: case Transport.NATS:
return new ServerNats(options); return new ServerNats(options as Required<NatsOptions>['options']);
case Transport.MQTT: case Transport.MQTT:
return new ServerMqtt(options); return new ServerMqtt(options as Required<MqttOptions>['options']);
case Transport.GRPC: case Transport.GRPC:
return new ServerGrpc(options); return new ServerGrpc(options as Required<GrpcOptions>['options']);
case Transport.KAFKA: case Transport.KAFKA:
return new ServerKafka(options); return new ServerKafka(options as Required<KafkaOptions>['options']);
case Transport.RMQ: case Transport.RMQ:
return new ServerRMQ(options); return new ServerRMQ(options as Required<RmqOptions>['options']);
default: default:
return new ServerTCP(options); return new ServerTCP(options as Required<TcpOptions>['options']);
} }
} }
} }

View File

@@ -63,7 +63,7 @@ export class ServerGrpc extends Server<never, never> {
); );
} }
constructor(private readonly options: GrpcOptions['options']) { constructor(private readonly options: Readonly<GrpcOptions>['options']) {
super(); super();
this.url = this.getOptionsProp(options, 'url') || GRPC_DEFAULT_URL; this.url = this.getOptionsProp(options, 'url') || GRPC_DEFAULT_URL;
@@ -96,7 +96,7 @@ export class ServerGrpc extends Server<never, never> {
public async start(callback?: () => void) { public async start(callback?: () => void) {
await this.bindEvents(); await this.bindEvents();
callback(); callback?.();
} }
public async bindEvents() { public async bindEvents() {
@@ -136,7 +136,7 @@ export class ServerGrpc extends Server<never, never> {
const service = {}; const service = {};
for (const methodName in grpcService.prototype) { for (const methodName in grpcService.prototype) {
let methodHandler = null; let methodHandler: MessageHandler | null = null;
let streamingType = GrpcMethodStreamingType.NO_STREAMING; let streamingType = GrpcMethodStreamingType.NO_STREAMING;
const methodFunction = grpcService.prototype[methodName]; const methodFunction = grpcService.prototype[methodName];
@@ -190,13 +190,13 @@ export class ServerGrpc extends Server<never, never> {
methodName: string, methodName: string,
streaming: GrpcMethodStreamingType, streaming: GrpcMethodStreamingType,
grpcMethod: { path?: string }, grpcMethod: { path?: string },
) { ): MessageHandler {
let pattern = this.createPattern(serviceName, methodName, streaming); let pattern = this.createPattern(serviceName, methodName, streaming);
let methodHandler = this.messageHandlers.get(pattern); let methodHandler = this.messageHandlers.get(pattern)!;
if (!methodHandler) { if (!methodHandler) {
const packageServiceName = grpcMethod.path?.split?.('/')[1]; const packageServiceName = grpcMethod.path?.split?.('/')[1];
pattern = this.createPattern(packageServiceName, methodName, streaming); pattern = this.createPattern(packageServiceName!, methodName, streaming);
methodHandler = this.messageHandlers.get(pattern); methodHandler = this.messageHandlers.get(pattern)!;
} }
return methodHandler; return methodHandler;
} }

View File

@@ -39,23 +39,28 @@ export class ServerKafka extends Server<never, KafkaStatus> {
public readonly transportId = Transport.KAFKA; public readonly transportId = Transport.KAFKA;
protected logger = new Logger(ServerKafka.name); protected logger = new Logger(ServerKafka.name);
protected client: Kafka = null; protected client: Kafka | null = null;
protected consumer: Consumer = null; protected consumer: Consumer | null = null;
protected producer: Producer = null; protected producer: Producer | null = null;
protected parser: KafkaParser = null; protected parser: KafkaParser | null = null;
protected brokers: string[] | BrokersFunction; protected brokers: string[] | BrokersFunction;
protected clientId: string; protected clientId: string;
protected groupId: string; protected groupId: string;
constructor(protected readonly options: KafkaOptions['options']) { constructor(protected readonly options: Required<KafkaOptions>['options']) {
super(); super();
const clientOptions = const clientOptions = this.getOptionsProp(
this.getOptionsProp(this.options, 'client') || ({} as KafkaConfig); this.options,
const consumerOptions = 'client',
this.getOptionsProp(this.options, 'consumer') || ({} as ConsumerConfig); {} as KafkaConfig,
const postfixId = );
this.getOptionsProp(this.options, 'postfixId') ?? '-server'; const consumerOptions = this.getOptionsProp(
this.options,
'consumer',
{} as ConsumerConfig,
);
const postfixId = this.getOptionsProp(this.options, 'postfixId', '-server');
this.brokers = clientOptions.brokers || [KAFKA_DEFAULT_BROKER]; this.brokers = clientOptions.brokers || [KAFKA_DEFAULT_BROKER];
@@ -98,8 +103,8 @@ export class ServerKafka extends Server<never, KafkaStatus> {
const consumerOptions = Object.assign(this.options.consumer || {}, { const consumerOptions = Object.assign(this.options.consumer || {}, {
groupId: this.groupId, groupId: this.groupId,
}); });
this.consumer = this.client.consumer(consumerOptions); this.consumer = this.client!.consumer(consumerOptions);
this.producer = this.client.producer(this.options.producer); this.producer = this.client!.producer(this.options.producer);
this.registerConsumerEventListeners(); this.registerConsumerEventListeners();
this.registerProducerEventListeners(); this.registerProducerEventListeners();
@@ -110,6 +115,9 @@ export class ServerKafka extends Server<never, KafkaStatus> {
} }
protected registerConsumerEventListeners() { protected registerConsumerEventListeners() {
if (!this.consumer) {
return;
}
this.consumer.on(this.consumer.events.CONNECT, () => this.consumer.on(this.consumer.events.CONNECT, () =>
this._status$.next(KafkaStatus.CONNECTED), this._status$.next(KafkaStatus.CONNECTED),
); );
@@ -128,6 +136,9 @@ export class ServerKafka extends Server<never, KafkaStatus> {
} }
protected registerProducerEventListeners() { protected registerProducerEventListeners() {
if (!this.producer) {
return;
}
this.producer.on(this.producer.events.CONNECT, () => this.producer.on(this.producer.events.CONNECT, () =>
this._status$.next(KafkaStatus.CONNECTED), this._status$.next(KafkaStatus.CONNECTED),
); );
@@ -151,7 +162,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
const consumerSubscribeOptions = this.options.subscribe || {}; const consumerSubscribeOptions = this.options.subscribe || {};
if (registeredPatterns.length > 0) { if (registeredPatterns.length > 0) {
await this.consumer.subscribe({ await this.consumer!.subscribe({
...consumerSubscribeOptions, ...consumerSubscribeOptions,
topics: registeredPatterns, topics: registeredPatterns,
}); });
@@ -178,7 +189,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
public async handleMessage(payload: EachMessagePayload) { public async handleMessage(payload: EachMessagePayload) {
const channel = payload.topic; const channel = payload.topic;
const rawMessage = this.parser.parse<KafkaMessage>( const rawMessage = this.parser!.parse<KafkaMessage>(
Object.assign(payload.message, { Object.assign(payload.message, {
topic: payload.topic, topic: payload.topic,
partition: payload.partition, partition: payload.partition,
@@ -194,9 +205,9 @@ export class ServerKafka extends Server<never, KafkaStatus> {
rawMessage, rawMessage,
payload.partition, payload.partition,
payload.topic, payload.topic,
this.consumer, this.consumer!,
payload.heartbeat, payload.heartbeat,
this.producer, this.producer!,
]); ]);
const handler = this.getHandlerByPattern(packet.pattern); const handler = this.getHandlerByPattern(packet.pattern);
// if the correlation id or reply topic is not set // if the correlation id or reply topic is not set
@@ -291,7 +302,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
}, },
this.options.send || {}, this.options.send || {},
); );
return this.producer.send(replyMessage); return this.producer!.send(replyMessage);
} }
public assignIsDisposedHeader( public assignIsDisposedHeader(
@@ -301,7 +312,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
if (!outgoingResponse.isDisposed) { if (!outgoingResponse.isDisposed) {
return; return;
} }
outgoingMessage.headers[KafkaHeaders.NEST_IS_DISPOSED] = Buffer.alloc(1); outgoingMessage.headers![KafkaHeaders.NEST_IS_DISPOSED] = Buffer.alloc(1);
} }
public assignErrorHeader( public assignErrorHeader(
@@ -315,7 +326,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
typeof outgoingResponse.err === 'object' typeof outgoingResponse.err === 'object'
? JSON.stringify(outgoingResponse.err) ? JSON.stringify(outgoingResponse.err)
: outgoingResponse.err; : outgoingResponse.err;
outgoingMessage.headers[KafkaHeaders.NEST_ERR] = outgoingMessage.headers![KafkaHeaders.NEST_ERR] =
Buffer.from(stringifiedError); Buffer.from(stringifiedError);
} }
@@ -323,7 +334,7 @@ export class ServerKafka extends Server<never, KafkaStatus> {
correlationId: string, correlationId: string,
outgoingMessage: Message, outgoingMessage: Message,
) { ) {
outgoingMessage.headers[KafkaHeaders.CORRELATION_ID] = outgoingMessage.headers![KafkaHeaders.CORRELATION_ID] =
Buffer.from(correlationId); Buffer.from(correlationId);
} }

View File

@@ -41,9 +41,9 @@ export class ServerMqtt extends Server<MqttEvents, MqttStatus> {
callback: MqttEvents[keyof MqttEvents]; callback: MqttEvents[keyof MqttEvents];
}> = []; }> = [];
constructor(private readonly options: MqttOptions['options']) { constructor(private readonly options: Required<MqttOptions>['options']) {
super(); super();
this.url = this.getOptionsProp(options, 'url') || MQTT_DEFAULT_URL; this.url = this.getOptionsProp(options, 'url', MQTT_DEFAULT_URL);
mqttPackage = this.loadPackage('mqtt', ServerMqtt.name, () => mqttPackage = this.loadPackage('mqtt', ServerMqtt.name, () =>
require('mqtt'), require('mqtt'),
@@ -87,7 +87,7 @@ export class ServerMqtt extends Server<MqttEvents, MqttStatus> {
const registeredPatterns = [...this.messageHandlers.keys()]; const registeredPatterns = [...this.messageHandlers.keys()];
registeredPatterns.forEach(pattern => { registeredPatterns.forEach(pattern => {
const { isEventHandler } = this.messageHandlers.get(pattern); const { isEventHandler } = this.messageHandlers.get(pattern)!;
mqttClient.subscribe( mqttClient.subscribe(
isEventHandler ? pattern : this.getRequestPattern(pattern), isEventHandler ? pattern : this.getRequestPattern(pattern),
this.getOptionsProp(this.options, 'subscribeOptions'), this.getOptionsProp(this.options, 'subscribeOptions'),
@@ -120,7 +120,7 @@ export class ServerMqtt extends Server<MqttEvents, MqttStatus> {
): Promise<any> { ): Promise<any> {
const rawPacket = this.parseMessage(buffer.toString()); const rawPacket = this.parseMessage(buffer.toString());
const packet = await this.deserializer.deserialize(rawPacket, { channel }); const packet = await this.deserializer.deserialize(rawPacket, { channel });
const mqttContext = new MqttContext([channel, originalPacket]); const mqttContext = new MqttContext([channel, originalPacket!]);
if (isUndefined((packet as IncomingRequest).id)) { if (isUndefined((packet as IncomingRequest).id)) {
return this.handleEvent(channel, packet, mqttContext); return this.handleEvent(channel, packet, mqttContext);
} }

View File

@@ -44,7 +44,7 @@ export class ServerNats<
}>(); }>();
private readonly subscriptions: Subscription[] = []; private readonly subscriptions: Subscription[] = [];
constructor(private readonly options: NatsOptions['options']) { constructor(private readonly options: Required<NatsOptions>['options']) {
super(); super();
natsPackage = this.loadPackage('nats', ServerNats.name, () => natsPackage = this.loadPackage('nats', ServerNats.name, () =>
@@ -211,7 +211,7 @@ export class ServerNats<
case 'pingTimer': case 'pingTimer':
if (this.options.debug) { if (this.options.debug) {
this.logger.debug( this.logger.debug!(
`NatsStatus: type: "${status.type}", data: "${data}".`, `NatsStatus: type: "${status.type}", data: "${data}".`,
); );
} }

View File

@@ -38,7 +38,7 @@ export class ServerRedis extends Server<RedisEvents, RedisStatus> {
callback: RedisEvents[keyof RedisEvents]; callback: RedisEvents[keyof RedisEvents];
}> = []; }> = [];
constructor(protected readonly options: RedisOptions['options']) { constructor(protected readonly options: Required<RedisOptions>['options']) {
super(); super();
redisPackage = this.loadPackage('ioredis', ServerRedis.name, () => redisPackage = this.loadPackage('ioredis', ServerRedis.name, () =>
@@ -78,7 +78,7 @@ export class ServerRedis extends Server<RedisEvents, RedisStatus> {
Promise.all([this.subClient.connect(), this.pubClient.connect()]) Promise.all([this.subClient.connect(), this.pubClient.connect()])
.then(() => { .then(() => {
this.bindEvents(this.subClient, this.pubClient); this.bindEvents(this.subClient, this.pubClient);
callback(); callback?.();
}) })
.catch(callback); .catch(callback);
} }
@@ -90,7 +90,7 @@ export class ServerRedis extends Server<RedisEvents, RedisStatus> {
); );
const subscribePatterns = [...this.messageHandlers.keys()]; const subscribePatterns = [...this.messageHandlers.keys()];
subscribePatterns.forEach(pattern => { subscribePatterns.forEach(pattern => {
const { isEventHandler } = this.messageHandlers.get(pattern); const { isEventHandler } = this.messageHandlers.get(pattern)!;
const channel = isEventHandler const channel = isEventHandler
? pattern ? pattern
@@ -258,11 +258,11 @@ export class ServerRedis extends Server<RedisEvents, RedisStatus> {
); );
return; return;
} }
if (times > this.getOptionsProp(this.options, 'retryAttempts')) { if (times > this.getOptionsProp(this.options, 'retryAttempts', 0)) {
this.logger.error(`Retry time exhausted`); this.logger.error(`Retry time exhausted`);
return; return;
} }
return this.getOptionsProp(this.options, 'retryDelay') ?? 5000; return this.getOptionsProp(this.options, 'retryDelay', 5000);
} }
public unwrap<T>(): T { public unwrap<T>(): T {

View File

@@ -65,7 +65,7 @@ export class ServerRMQ extends Server<RmqEvents, RmqStatus> {
callback: RmqEvents[keyof RmqEvents]; callback: RmqEvents[keyof RmqEvents];
}> = []; }> = [];
constructor(protected readonly options: RmqOptions['options']) { constructor(protected readonly options: Required<RmqOptions>['options']) {
super(); super();
this.urls = this.getOptionsProp(this.options, 'urls') || [RQM_DEFAULT_URL]; this.urls = this.getOptionsProp(this.options, 'urls') || [RQM_DEFAULT_URL];
this.queue = this.queue =
@@ -113,7 +113,7 @@ export class ServerRMQ extends Server<RmqEvents, RmqStatus> {
this._status$.next(RmqStatus.CONNECTED); this._status$.next(RmqStatus.CONNECTED);
this.channel = this.server.createChannel({ this.channel = this.server.createChannel({
json: false, json: false,
setup: (channel: any) => this.setupChannel(channel, callback), setup: (channel: any) => this.setupChannel(channel, callback!),
}); });
}); });

View File

@@ -41,7 +41,7 @@ export class ServerTCP extends Server<TcpEvents, TcpStatus> {
callback: TcpEvents[keyof TcpEvents]; callback: TcpEvents[keyof TcpEvents];
}> = []; }> = [];
constructor(private readonly options: TcpOptions['options']) { constructor(private readonly options: Required<TcpOptions>['options']) {
super(); super();
this.port = this.getOptionsProp(options, 'port', TCP_DEFAULT_PORT); this.port = this.getOptionsProp(options, 'port', TCP_DEFAULT_PORT);
this.host = this.getOptionsProp(options, 'host', TCP_DEFAULT_HOST); this.host = this.getOptionsProp(options, 'host', TCP_DEFAULT_HOST);
@@ -121,14 +121,14 @@ export class ServerTCP extends Server<TcpEvents, TcpStatus> {
this.isManuallyTerminated || this.isManuallyTerminated ||
!this.getOptionsProp(this.options, 'retryAttempts') || !this.getOptionsProp(this.options, 'retryAttempts') ||
this.retryAttemptsCount >= this.retryAttemptsCount >=
this.getOptionsProp(this.options, 'retryAttempts') this.getOptionsProp(this.options, 'retryAttempts', 0)
) { ) {
return undefined; return undefined;
} }
++this.retryAttemptsCount; ++this.retryAttemptsCount;
return setTimeout( return setTimeout(
() => this.server.listen(this.port, this.host), () => this.server.listen(this.port, this.host),
this.getOptionsProp(this.options, 'retryDelay') || 0, this.getOptionsProp(this.options, 'retryDelay', 0),
); );
} }

View File

@@ -102,7 +102,7 @@ export abstract class Server<
callback.extras = extras; callback.extras = extras;
if (this.messageHandlers.has(normalizedPattern) && isEventHandler) { if (this.messageHandlers.has(normalizedPattern) && isEventHandler) {
const headRef = this.messageHandlers.get(normalizedPattern); const headRef = this.messageHandlers.get(normalizedPattern)!;
const getTail = (handler: MessageHandler) => const getTail = (handler: MessageHandler) =>
handler?.next ? getTail(handler.next) : handler; handler?.next ? getTail(handler.next) : handler;
@@ -120,7 +120,7 @@ export abstract class Server<
public getHandlerByPattern(pattern: string): MessageHandler | null { public getHandlerByPattern(pattern: string): MessageHandler | null {
const route = this.getRouteFromPattern(pattern); const route = this.getRouteFromPattern(pattern);
return this.messageHandlers.has(route) return this.messageHandlers.has(route)
? this.messageHandlers.get(route) ? this.messageHandlers.get(route)!
: null; : null;
} }
@@ -128,12 +128,13 @@ export abstract class Server<
stream$: Observable<any>, stream$: Observable<any>,
respond: (data: WritePacket) => Promise<unknown> | void, respond: (data: WritePacket) => Promise<unknown> | void,
): Subscription { ): Subscription {
let dataBuffer: WritePacket[] = null; let dataBuffer: WritePacket[] | null = null;
const scheduleOnNextTick = (data: WritePacket) => { const scheduleOnNextTick = (data: WritePacket) => {
if (!dataBuffer) { if (!dataBuffer) {
dataBuffer = [data]; dataBuffer = [data];
process.nextTick(async () => { process.nextTick(async () => {
for (const item of dataBuffer) { for (const item of dataBuffer!) {
await respond(item); await respond(item);
} }
dataBuffer = null; dataBuffer = null;
@@ -197,10 +198,28 @@ export abstract class Server<
} }
public getOptionsProp< public getOptionsProp<
T extends MicroserviceOptions['options'], Options extends MicroserviceOptions['options'],
K extends keyof T, Attribute extends keyof Options,
>(obj: T, prop: K, defaultValue: T[K] = undefined) { >(obj: Options, prop: Attribute): Options[Attribute];
return obj && prop in obj ? obj[prop] : defaultValue; public getOptionsProp<
Options extends MicroserviceOptions['options'],
Attribute extends keyof Options,
DefaultValue extends Options[Attribute] = Options[Attribute],
>(
obj: Options,
prop: Attribute,
defaultValue: DefaultValue,
): Required<Options>[Attribute];
public getOptionsProp<
Options extends MicroserviceOptions['options'],
Attribute extends keyof Options,
DefaultValue extends Options[Attribute] = Options[Attribute],
>(
obj: Options,
prop: Attribute,
defaultValue: DefaultValue = undefined as DefaultValue,
) {
return obj && prop in obj ? obj![prop] : defaultValue;
} }
protected handleError(error: string) { protected handleError(error: string) {
@@ -218,30 +237,26 @@ export abstract class Server<
protected initializeSerializer(options: ClientOptions['options']) { protected initializeSerializer(options: ClientOptions['options']) {
this.serializer = this.serializer =
(options && (options &&
( (options as
options as | RedisOptions['options']
| RedisOptions['options'] | NatsOptions['options']
| NatsOptions['options'] | MqttOptions['options']
| MqttOptions['options'] | TcpOptions['options']
| TcpOptions['options'] | RmqOptions['options']
| RmqOptions['options'] | KafkaOptions['options'])!.serializer) ||
| KafkaOptions['options']
).serializer) ||
new IdentitySerializer(); new IdentitySerializer();
} }
protected initializeDeserializer(options: ClientOptions['options']) { protected initializeDeserializer(options: ClientOptions['options']) {
this.deserializer = this.deserializer =
(options && (options! &&
( (options as
options as | RedisOptions['options']
| RedisOptions['options'] | NatsOptions['options']
| NatsOptions['options'] | MqttOptions['options']
| MqttOptions['options'] | TcpOptions['options']
| TcpOptions['options'] | RmqOptions['options']
| RmqOptions['options'] | KafkaOptions['options'])!.deserializer) ||
| KafkaOptions['options']
).deserializer) ||
new IncomingRequestDeserializer(); new IncomingRequestDeserializer();
} }

View File

@@ -11,12 +11,13 @@ export function createRpcParamDecorator(
return (...pipes: (Type<PipeTransform> | PipeTransform)[]) => return (...pipes: (Type<PipeTransform> | PipeTransform)[]) =>
(target, key, index) => { (target, key, index) => {
const args = const args =
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key) || {}; Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key!) ||
{};
Reflect.defineMetadata( Reflect.defineMetadata(
PARAM_ARGS_METADATA, PARAM_ARGS_METADATA,
assignMetadata(args, paramtype, index, undefined, ...pipes), assignMetadata(args, paramtype, index, undefined, ...pipes),
target.constructor, target.constructor,
key, key!,
); );
}; };
} }
@@ -29,7 +30,7 @@ export const createPipesRpcParamDecorator =
): ParameterDecorator => ): ParameterDecorator =>
(target, key, index) => { (target, key, index) => {
const args = const args =
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key) || {}; Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key!) || {};
const hasParamData = isNil(data) || isString(data); const hasParamData = isNil(data) || isString(data);
const paramData = hasParamData ? data : undefined; const paramData = hasParamData ? data : undefined;
@@ -37,8 +38,8 @@ export const createPipesRpcParamDecorator =
Reflect.defineMetadata( Reflect.defineMetadata(
PARAM_ARGS_METADATA, PARAM_ARGS_METADATA,
assignMetadata(args, paramtype, index, paramData, ...paramPipes), assignMetadata(args, paramtype, index, paramData!, ...paramPipes),
target.constructor, target.constructor,
key, key!,
); );
}; };

View File

@@ -1,13 +1,12 @@
import type { Server } from 'http';
import { import {
HttpStatus, HttpStatus,
InternalServerErrorException, InternalServerErrorException,
Logger, Logger,
RequestMethod, RequestMethod,
StreamableFile, StreamableFile,
VERSION_NEUTRAL,
VersioningOptions, VersioningOptions,
VersioningType, VersioningType,
VERSION_NEUTRAL,
} from '@nestjs/common'; } from '@nestjs/common';
import { VersionValue } from '@nestjs/common/interfaces'; import { VersionValue } from '@nestjs/common/interfaces';
import { import {
@@ -24,13 +23,14 @@ import {
} from '@nestjs/common/utils/shared.utils'; } from '@nestjs/common/utils/shared.utils';
import { AbstractHttpAdapter } from '@nestjs/core/adapters/http-adapter'; import { AbstractHttpAdapter } from '@nestjs/core/adapters/http-adapter';
import { RouterMethodFactory } from '@nestjs/core/helpers/router-method-factory'; import { RouterMethodFactory } from '@nestjs/core/helpers/router-method-factory';
import * as bodyparser from 'body-parser';
import { import {
json as bodyParserJson, json as bodyParserJson,
urlencoded as bodyParserUrlencoded, urlencoded as bodyParserUrlencoded,
} from 'body-parser'; } from 'body-parser';
import * as bodyparser from 'body-parser';
import * as cors from 'cors'; import * as cors from 'cors';
import * as express from 'express'; import * as express from 'express';
import type { Server } from 'http';
import * as http from 'http'; import * as http from 'http';
import * as https from 'https'; import * as https from 'https';
import { Duplex, pipeline } from 'stream'; import { Duplex, pipeline } from 'stream';
@@ -94,7 +94,7 @@ export class ExpressAdapter extends AbstractHttpAdapter<
body.errorHandler(err, response); body.errorHandler(err, response);
}), }),
response, response,
(err: Error) => { (err: any) => {
if (err) { if (err) {
body.errorLogger(err); body.errorLogger(err);
} }
@@ -218,7 +218,7 @@ export class ExpressAdapter extends AbstractHttpAdapter<
} }
public enableCors(options: CorsOptions | CorsOptionsDelegate<any>) { public enableCors(options: CorsOptions | CorsOptionsDelegate<any>) {
return this.use(cors(options)); return this.use(cors(options as any));
} }
public createMiddlewareFactory( public createMiddlewareFactory(
@@ -233,7 +233,7 @@ export class ExpressAdapter extends AbstractHttpAdapter<
const isHttpsEnabled = options && options.httpsOptions; const isHttpsEnabled = options && options.httpsOptions;
if (isHttpsEnabled) { if (isHttpsEnabled) {
this.httpServer = https.createServer( this.httpServer = https.createServer(
options.httpsOptions, options.httpsOptions!,
this.getInstance(), this.getInstance(),
); );
} else { } else {
@@ -246,8 +246,8 @@ export class ExpressAdapter extends AbstractHttpAdapter<
} }
public registerParserMiddleware(prefix?: string, rawBody?: boolean) { public registerParserMiddleware(prefix?: string, rawBody?: boolean) {
const bodyParserJsonOptions = getBodyParserOptions(rawBody); const bodyParserJsonOptions = getBodyParserOptions(rawBody!);
const bodyParserUrlencodedOptions = getBodyParserOptions(rawBody, { const bodyParserUrlencodedOptions = getBodyParserOptions(rawBody!, {
extended: true, extended: true,
}); });
@@ -260,13 +260,15 @@ export class ExpressAdapter extends AbstractHttpAdapter<
.forEach(parserKey => this.use(parserMiddleware[parserKey])); .forEach(parserKey => this.use(parserMiddleware[parserKey]));
} }
public useBodyParser<Options = NestExpressBodyParserOptions>( public useBodyParser<
Options extends NestExpressBodyParserOptions = NestExpressBodyParserOptions,
>(
type: NestExpressBodyParserType, type: NestExpressBodyParserType,
rawBody: boolean, rawBody: boolean,
options?: Omit<Options, 'verify'>, options?: Omit<Options, 'verify'>,
): this { ): this {
const parserOptions = getBodyParserOptions<Options>(rawBody, options); const parserOptions = getBodyParserOptions<Options>(rawBody, options);
const parser = bodyparser[type](parserOptions); const parser = bodyparser[type](parserOptions!);
this.use(parser); this.use(parser);
@@ -425,6 +427,8 @@ export class ExpressAdapter extends AbstractHttpAdapter<
return handlerForHeaderVersioning; return handlerForHeaderVersioning;
} }
throw new Error('Unsupported versioning options');
} }
private trackOpenConnections() { private trackOpenConnections() {

View File

@@ -51,8 +51,8 @@ export class MulterModule {
return [ return [
this.createAsyncOptionsProvider(options), this.createAsyncOptionsProvider(options),
{ {
provide: options.useClass, provide: options.useClass!,
useClass: options.useClass, useClass: options.useClass!,
}, },
]; ];
} }
@@ -71,7 +71,7 @@ export class MulterModule {
provide: MULTER_MODULE_OPTIONS, provide: MULTER_MODULE_OPTIONS,
useFactory: async (optionsFactory: MulterOptionsFactory) => useFactory: async (optionsFactory: MulterOptionsFactory) =>
optionsFactory.createMulterOptions(), optionsFactory.createMulterOptions(),
inject: [options.useExisting || options.useClass], inject: [options.useExisting || options.useClass!],
}; };
} }
} }

View File

@@ -159,7 +159,7 @@ export class FastifyAdapter<
return { return {
get(version: string | Array<string>) { get(version: string | Array<string>) {
if (Array.isArray(version)) { if (Array.isArray(version)) {
return versions.get(version.find(v => versions.has(v))) || null; return versions.get(version.find(v => versions.has(v))!) || null;
} }
return versions.get(version) || null; return versions.get(version) || null;
}, },
@@ -427,11 +427,11 @@ export class FastifyAdapter<
response.statusCode = statusCode; response.statusCode = statusCode;
return response; return response;
} }
return response.code(statusCode); return (response as TReply).code(statusCode);
} }
public end(response: TReply, message?: string) { public end(response: TReply, message?: string) {
response.raw.end(message); response.raw.end(message!);
} }
public render( public render(
@@ -475,7 +475,7 @@ export class FastifyAdapter<
public inject( public inject(
opts?: InjectOptions | string, opts?: InjectOptions | string,
): LightMyRequestChain | Promise<LightMyRequestResponse> { ): LightMyRequestChain | Promise<LightMyRequestResponse> {
return this.instance.inject(opts); return this.instance.inject(opts!);
} }
public async close() { public async close() {
@@ -539,7 +539,7 @@ export class FastifyAdapter<
} }
public getRequestMethod(request: TRequest): string { public getRequestMethod(request: TRequest): string {
return request.raw ? request.raw.method : request.method; return request.raw ? request.raw.method! : request.method;
} }
public getRequestUrl(request: TRequest): string; public getRequestUrl(request: TRequest): string;
@@ -581,7 +581,7 @@ export class FastifyAdapter<
type, type,
parserOptions, parserOptions,
( (
req: RawBodyRequest<FastifyRequest<unknown, TServer, TRawRequest>>, req: RawBodyRequest<FastifyRequest<any, TServer, TRawRequest>>,
body: Buffer, body: Buffer,
done, done,
) => { ) => {
@@ -708,7 +708,7 @@ export class FastifyAdapter<
} }
private getRequestOriginalUrl(rawRequest: TRawRequest) { private getRequestOriginalUrl(rawRequest: TRawRequest) {
return rawRequest.originalUrl || rawRequest.url; return rawRequest.originalUrl || rawRequest.url!;
} }
private injectRouteOptions( private injectRouteOptions(

View File

@@ -70,7 +70,11 @@ export class WsAdapter extends AbstractWsAdapter {
path?: string; path?: string;
}, },
) { ) {
const { server, path, ...wsOptions } = options; const { server, path, ...wsOptions } = options as {
namespace?: string;
server?: any;
path?: string;
};
if (wsOptions?.namespace) { if (wsOptions?.namespace) {
const error = new Error( const error = new Error(
'"WsAdapter" does not support namespaces. If you need namespaces in your project, consider using the "@nestjs/platform-socket.io" package instead.', '"WsAdapter" does not support namespaces. If you need namespaces in your project, consider using the "@nestjs/platform-socket.io" package instead.',
@@ -88,7 +92,7 @@ export class WsAdapter extends AbstractWsAdapter {
}), }),
); );
this.addWsServerToRegistry(wsServer, port, path); this.addWsServerToRegistry(wsServer, port, path!);
return wsServer; return wsServer;
} }
@@ -157,7 +161,7 @@ export class WsAdapter extends AbstractWsAdapter {
if (!message) { if (!message) {
return EMPTY; return EMPTY;
} }
const messageHandler = handlersMap.get(message.event); const messageHandler = handlersMap.get(message.event)!;
const { callback } = messageHandler; const { callback } = messageHandler;
return transform(callback(message.data, message.event)); return transform(callback(message.data, message.event));
} catch { } catch {
@@ -213,8 +217,8 @@ export class WsAdapter extends AbstractWsAdapter {
httpServer.on('upgrade', (request, socket, head) => { httpServer.on('upgrade', (request, socket, head) => {
try { try {
const baseUrl = 'ws://' + request.headers.host + '/'; const baseUrl = 'ws://' + request.headers.host + '/';
const pathname = new URL(request.url, baseUrl).pathname; const pathname = new URL(request.url!, baseUrl).pathname;
const wsServersCollection = this.wsServersRegistry.get(port); const wsServersCollection = this.wsServersRegistry.get(port)!;
let isRequestDelegated = false; let isRequestDelegated = false;
for (const wsServer of wsServersCollection) { for (const wsServer of wsServersCollection) {

View File

@@ -59,6 +59,12 @@ export class TestingInjector extends Injector {
metatype: wrapper.metatype, metatype: wrapper.metatype,
}); });
const internalCoreModule = this.container.getInternalCoreModuleRef(); const internalCoreModule = this.container.getInternalCoreModuleRef();
if (!internalCoreModule) {
throw new Error(
'Expected to have internal core module reference at this point.',
);
}
internalCoreModule.addCustomProvider( internalCoreModule.addCustomProvider(
{ {
provide: name, provide: name,

View File

@@ -160,7 +160,7 @@ export class TestingModuleBuilder {
private getRootModule() { private getRootModule() {
const modules = this.container.getModules().values(); const modules = this.container.getModules().values();
return modules.next().value; return modules.next().value!;
} }
private async createInstancesOfDependencies( private async createInstancesOfDependencies(

View File

@@ -16,7 +16,9 @@
"sourceMap": false, "sourceMap": false,
"allowJs": false, "allowJs": false,
"strict": true, "strict": true,
"strictNullChecks": false, "strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"strictPropertyInitialization": false,
"types": ["node"] "types": ["node"]
} }
} }

View File

@@ -33,6 +33,6 @@ export class ExceptionFiltersContext extends BaseExceptionFilterContext {
} }
public getGlobalMetadata<T extends any[]>(): T { public getGlobalMetadata<T extends any[]>(): T {
return [] as T; return [] as any[] as T;
} }
} }

View File

@@ -15,9 +15,8 @@ export class WsException extends Error {
) { ) {
this.message = (this.error as Record<string, any>).message; this.message = (this.error as Record<string, any>).message;
} else if (this.constructor) { } else if (this.constructor) {
this.message = this.constructor.name this.message =
.match(/[A-Z][a-z]+|[0-9]+/g) this.constructor!.name!.match(/[A-Z][a-z]+|[0-9]+/g)!.join(' ');
.join(' ');
} }
} }

View File

@@ -21,14 +21,14 @@ export class GatewayMetadataExplorer {
const instancePrototype = Object.getPrototypeOf(instance); const instancePrototype = Object.getPrototypeOf(instance);
return this.metadataScanner return this.metadataScanner
.getAllMethodNames(instancePrototype) .getAllMethodNames(instancePrototype)
.map(method => this.exploreMethodMetadata(instancePrototype, method)) .map(method => this.exploreMethodMetadata(instancePrototype, method)!)
.filter(metadata => metadata); .filter(metadata => metadata);
} }
public exploreMethodMetadata( public exploreMethodMetadata(
instancePrototype: object, instancePrototype: object,
methodName: string, methodName: string,
): MessageMappingProperties { ): MessageMappingProperties | null {
const callback = instancePrototype[methodName]; const callback = instancePrototype[methodName];
const isMessageMapping = Reflect.getMetadata( const isMessageMapping = Reflect.getMetadata(
MESSAGE_MAPPING_METADATA, MESSAGE_MAPPING_METADATA,

View File

@@ -15,7 +15,7 @@ export class SocketsContainer {
options: T, options: T,
): ServerAndEventStreamsHost { ): ServerAndEventStreamsHost {
const uniqueToken = this.generateHashByOptions(options); const uniqueToken = this.generateHashByOptions(options);
return this.serverAndEventStreamsHosts.get(uniqueToken); return this.serverAndEventStreamsHosts.get(uniqueToken)!;
} }
public addOne<T extends GatewayMetadata = any>( public addOne<T extends GatewayMetadata = any>(

View File

@@ -11,12 +11,13 @@ export function createWsParamDecorator(
return (...pipes: (Type<PipeTransform> | PipeTransform)[]) => return (...pipes: (Type<PipeTransform> | PipeTransform)[]) =>
(target, key, index) => { (target, key, index) => {
const args = const args =
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key) || {}; Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key!) ||
{};
Reflect.defineMetadata( Reflect.defineMetadata(
PARAM_ARGS_METADATA, PARAM_ARGS_METADATA,
assignMetadata(args, paramtype, index, undefined, ...pipes), assignMetadata(args, paramtype, index, undefined, ...pipes),
target.constructor, target.constructor,
key, key!,
); );
}; };
} }
@@ -29,15 +30,15 @@ export const createPipesWsParamDecorator =
): ParameterDecorator => ): ParameterDecorator =>
(target, key, index) => { (target, key, index) => {
const args = const args =
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key) || {}; Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key!) || {};
const hasParamData = isNil(data) || isString(data); const hasParamData = isNil(data) || isString(data);
const paramData = hasParamData ? data : undefined; const paramData = hasParamData ? data : undefined;
const paramPipes = hasParamData ? pipes : [data, ...pipes]; const paramPipes = hasParamData ? pipes : [data, ...pipes];
Reflect.defineMetadata( Reflect.defineMetadata(
PARAM_ARGS_METADATA, PARAM_ARGS_METADATA,
assignMetadata(args, paramtype, index, paramData, ...paramPipes), assignMetadata(args, paramtype, index, paramData!, ...paramPipes),
target.constructor, target.constructor,
key, key!,
); );
}; };

View File

@@ -156,7 +156,7 @@ export class WebSocketsController {
.pipe( .pipe(
distinctUntilChanged((prev, curr) => compareElementAt(prev, curr, 0)), distinctUntilChanged((prev, curr) => compareElementAt(prev, curr, 0)),
) )
.subscribe((args: unknown[]) => instance.handleConnection(...args)); .subscribe((args: unknown[]) => instance.handleConnection!(...args));
} }
} }

View File

@@ -4,6 +4,8 @@
"noImplicitAny": false, "noImplicitAny": false,
"noUnusedLocals": false, "noUnusedLocals": false,
"removeComments": true, "removeComments": true,
"strictNullChecks": true,
"strictPropertyInitialization": false,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"noLib": false, "noLib": false,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,