Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
3 changes: 2 additions & 1 deletion lib/config/command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from '@nestjs/common';
import * as pc from 'picocolors';
import pc from 'picocolors';
import { Command, ConsoleIO } from '../console';
import { Obj } from '../utils';
import { Arr } from '../utils/array';
Expand Down Expand Up @@ -28,6 +28,7 @@ export class ViewConfigCommand {
printRows.push([pc.green(row[0]), pc.yellow(row[1])].join(' '));
}

// eslint-disable-next-line no-console
console.log(printRows.join('\n'));
}
}
4 changes: 0 additions & 4 deletions lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
export class BoatConstants {
static boatjsOptions = 'intent/core_options';
}

export class IntentDecoratorTypes {
static consoleCommand = '@intent/console/command';
static queueJob = '@intent/queue/job';
Expand Down
1 change: 1 addition & 0 deletions lib/exceptions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './genericException';
export * from './intentExceptionFilter';
export * from './invalidValue';
export * from './invalidValueType';
export { HttpException, Catch } from '@nestjs/common';
2 changes: 1 addition & 1 deletion lib/exceptions/intentExceptionFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ArgumentsHost, HttpException, Type } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
import { IntentConfig } from '../config/service';
import { Log } from '../logger';
import { Request, Response } from '../rest';
import { Request, Response } from '../rest/foundation';
import { Package } from '../utils';

export abstract class IntentExceptionFilter extends BaseExceptionFilter {
Expand Down
6 changes: 3 additions & 3 deletions lib/explorer.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Injectable } from '@nestjs/common';
import { DiscoveryService, MetadataScanner } from '@nestjs/core';
import { CommandMeta, CommandMetaOptions } from './console';
import { ConsoleConstants } from './console/constants';
import { EventMetadata } from './events';
import { IntentEventConstants } from './events/constants';
import { Injectable } from './foundation';
import { GenericFunction } from './interfaces';
import { JOB_NAME, JOB_OPTIONS } from './queue/constants';
import { QueueMetadata } from './queue/metadata';
Expand Down Expand Up @@ -32,7 +32,7 @@ export class IntentExplorer {
Object.getPrototypeOf(instance),
(key: string) => {
this.lookupJobs(instance, key);
this.lookupListeners(instance, key);
this.lookupEventListeners(instance, key);
this.lookupConsoleCommands(instance, key);
},
);
Expand All @@ -50,7 +50,7 @@ export class IntentExplorer {
});
}

lookupListeners(instance: Record<string, any>, key: string) {
lookupEventListeners(instance: Record<string, any>, key: string) {
const methodRef = instance[key];
const hasEventMeta = Reflect.hasMetadata(
IntentEventConstants.eventName,
Expand Down
46 changes: 46 additions & 0 deletions lib/foundation/app-container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Provider } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import {
IntentApplication,
IntentApplicationContext,
Type,
} from '../interfaces';
import { ImportType, ServiceProvider } from './service-provider';

export abstract class IntentAppContainer {
static serviceProviders: ServiceProvider[] = [];

add(...serviceProviders: Type<ServiceProvider>[]) {
for (const sp of serviceProviders) {
const instance = new sp();
instance.register();
IntentAppContainer.serviceProviders.push(instance);
}
}

scanImports(): ImportType[] {
const imports: ImportType[] = [];
for (const serviceProvider of IntentAppContainer.serviceProviders) {
imports.push(...serviceProvider.getAllImports());
}
return imports;
}

scanProviders(): Provider[] {
const providers: Provider[] = [];

for (const serviceProvider of IntentAppContainer.serviceProviders) {
providers.push(...serviceProvider.getAllProviders());
}

return providers;
}

async boot(app: IntentApplication | IntentApplicationContext): Promise<void> {
for (const serviceProvider of IntentAppContainer.serviceProviders) {
serviceProvider.boot(app);
}
}

abstract build();
}
17 changes: 17 additions & 0 deletions lib/foundation/container-factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NestFactory } from '@nestjs/core';
import { IntentApplicationContext, Type } from '../interfaces';
import { ModuleBuilder } from './module-builder';
import { IntentAppContainer } from './app-container';

export class ContainerFactory {
static async createStandalone(
containerCls: Type<IntentAppContainer>,
): Promise<IntentApplicationContext> {
const container = new containerCls();
container.build();
const module = ModuleBuilder.build(container);
const app = await NestFactory.createApplicationContext(module);
container.boot(app);
return app;
}
}
4 changes: 4 additions & 0 deletions lib/foundation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { Injectable, Inject, Optional } from '@nestjs/common';
export * from './module-builder';
export * from './service-provider';
export * from './app-container';
65 changes: 65 additions & 0 deletions lib/foundation/module-builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { Type } from '../interfaces';
import { IntentGuard, Kernel } from '../rest';
import { MiddlewareConfigurator } from '../rest/foundation/middlewares/configurator';
import { IntentAppContainer } from './app-container';

export class ModuleBuilder {
static build(container: IntentAppContainer, kernel?: Kernel) {
const providers = container.scanProviders();
const controllers = kernel?.controllers() || [];
/**
* Scan for global middlewares
*/
const globalMiddlewares = kernel?.middlewares() || [];
const globalGuards = ModuleBuilder.buildGlobalGuardProviders(
kernel?.guards() || [],
);

@Module({
imports: container.scanImports(),
providers: [...providers, ...globalGuards],
controllers: controllers,
})
class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
if (!kernel) return;
/**
* Apply global middleware for all routes if any found.
*/
if (globalMiddlewares.length) {
consumer.apply(...globalMiddlewares).forRoutes('');
}

const middlewareConfigurator = new MiddlewareConfigurator();
kernel.routeMiddlewares(middlewareConfigurator);
/**
* Apply route specific middlewares
*/
if (middlewareConfigurator.hasAnyRule()) {
for (const rule of middlewareConfigurator.getAllRules()) {
consumer
.apply(rule.middleware)
.exclude(...rule.excludedFor)
.forRoutes(...rule.appliedFor);
}
}
}
}

return AppModule;
}

static buildGlobalGuardProviders(guards: Type<IntentGuard>[]) {
const providers = [];
for (const guard of guards) {
providers.push({
provide: APP_GUARD,
useClass: guard,
});
}

return providers;
}
}
77 changes: 77 additions & 0 deletions lib/foundation/service-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {
DynamicModule,
ForwardReference,
InjectionToken,
OptionalFactoryDependency,
Provider,
} from '@nestjs/common';
import {
IntentApplication,
IntentApplicationContext,
Type,
} from '../interfaces';

export type ImportType =
| Type<any>
| DynamicModule
| Promise<DynamicModule>
| ForwardReference;

export abstract class ServiceProvider {
private providers: Provider[] = [];
private imports: ImportType[] = [];

getAllImports(): ImportType[] {
return this.imports;
}

getAllProviders(): Provider[] {
return this.providers;
}

import(...imports: ImportType[]): this {
this.imports.push(...imports);
return this;
}

bind(...cls: Provider[]): this {
this.providers.push(...cls);
return this;
}

bindWithValue(token: string | symbol | Type<any>, valueFn: any): this {
this.providers.push({ provide: token, useValue: valueFn });
return this;
}

bindWithClass(token: string | symbol | Type<any>, cls: Type<any>): this {
this.providers.push({
provide: token,
useClass: cls,
});
return this;
}

bindWithExisting(token: string, cls: Type<any>): this {
this.providers.push({ provide: token, useExisting: cls });
return this;
}

bindWithFactory<T>(
token: string | symbol | Type<any>,
factory: (...args: any[]) => T | Promise<T>,
inject?: Array<InjectionToken | OptionalFactoryDependency>,
) {
this.providers.push({ provide: token, useFactory: factory, inject });
}

/**
* Use this method to register any provider.
*/
abstract register();

/**
* Use this method to run
*/
abstract boot(app: IntentApplication | IntentApplicationContext);
}
4 changes: 3 additions & 1 deletion lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './module';
export * from './serviceProvider';
export * from './utils';
export * from './constants';
export * from './interfaces';
Expand All @@ -17,3 +17,5 @@ export * from './mailer';
export * from './events';
export * from './validator';
export * from './config/service';
export * from './foundation';
export { registerAs } from '@nestjs/config';
11 changes: 11 additions & 0 deletions lib/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { NestExpressApplication } from '@nestjs/platform-express';
import { INestApplicationContext } from '@nestjs/common';

export type GenericFunction = (...args: any[]) => any;
export type GenericClass = Record<string, any>;

export * from './transformer';
export * from './config';

// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
export interface Type<T = any> extends Function {
new (...args: any[]): T;
}

export type IntentApplication = NestExpressApplication;
export type IntentApplicationContext = INestApplicationContext;
25 changes: 10 additions & 15 deletions lib/mailer/message.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { render } from '@react-email/render';
// eslint-disable-next-line import/no-named-as-default
import IntentMailComponent from '../../resources/mail/emails';
import { IntentConfig } from '../config/service';
import { GENERIC_MAIL, RAW_MAIL, VIEW_BASED_MAIL } from './constants';
Expand All @@ -9,11 +10,10 @@ import {
MailMessagePayload,
} from './interfaces';
import { AttachmentOptions } from './interfaces/provider';
import { MailerService } from './service';

export class MailMessage {
private mailSubject?: string;
private viewFile?: (payload: Record<string, any>) => JSX.Element;
private viewFile?: (payload: Record<string, any>) => Element;
private templateString?: string;
private payload: MailMessagePayload = {};
private mailType: MailType;
Expand Down Expand Up @@ -61,7 +61,7 @@ export class MailMessage {
* @param payload
*/
view(
component: (payload: Record<string, any>) => JSX.Element,
component: (payload: Record<string, any>) => Element,
payload?: Record<string, any>,
): this {
this.mailType = VIEW_BASED_MAIL;
Expand Down Expand Up @@ -196,20 +196,15 @@ export class MailMessage {
return this;
}

toHtml(): string {
return this.getMailData().html;
}

/**
* Method to compile templates
*/
private _compileTemplate(): string {
private async _compileTemplate(): Promise<string> {
if (this.compiledHtml) return this.compiledHtml;
const config = MailerService.getConfig();

if (this.mailType === GENERIC_MAIL) {
const templateConfig = IntentConfig.get('mailers.template');
const html = render(
const html = await render(
IntentMailComponent({
header: { value: { title: templateConfig.appName } },
footer: {
Expand All @@ -229,7 +224,7 @@ export class MailMessage {

if (this.mailType === VIEW_BASED_MAIL && this.viewFile) {
const component = this.viewFile;
const html = render(component(this.payload));
const html = await render(component(this.payload));

this.compiledHtml = html;
return this.compiledHtml;
Expand All @@ -245,14 +240,14 @@ export class MailMessage {
/**
* Returns the maildata payload
*/
getMailData(): MailData {
async getMailData(): Promise<MailData> {
if (typeof (this as any).handle === 'function') {
(this as any)['handle']();
}

return {
subject: this.mailSubject,
html: this._compileTemplate(),
html: await this._compileTemplate(),
attachments: this.attachments,
};
}
Expand All @@ -261,7 +256,7 @@ export class MailMessage {
* Render the email template.
* Returns the complete html of the mail.
*/
render(): string {
return this._compileTemplate();
async render(): Promise<string> {
return await this._compileTemplate();
}
}
Loading