@ferreirasw/yoke-common
v0.5.0
Published
Shared utilities, types, and messaging infrastructure for Yoke microservices
Maintainers
Readme
@ferreirasw/yoke-common
Shared utilities, types, and messaging infrastructure for Yoke microservices.
Installation
npm install @ferreirasw/yoke-commonFeatures
- Enums: Shared enums for business logic (Modality, TaxRegime, RiskProfile, Status enums, etc.)
- Messaging: RabbitMQ infrastructure with exchanges, routing keys, and message types
- DTOs: Standardized DTOs for pagination and API responses
- Filters: Global exception filters for consistent error handling
- Interceptors: Logging interceptors for request/response tracking
- Utilities: Common validation and formatting utilities (CPF, CNPJ, currency, etc.)
Table of Contents
Enums
All shared enums for consistent business logic across microservices.
Usage Example
import {
Modality,
TaxRegime,
RiskProfile,
ProductStatus,
QuotationStatus,
} from '@ferreirasw/yoke-common';
// Use in your entities
@Entity()
export class Product {
@Column({ type: 'enum', enum: Modality })
modality: Modality;
@Column({ type: 'enum', enum: TaxRegime })
taxRegime: TaxRegime;
@Column({ type: 'enum', enum: ProductStatus, default: ProductStatus.ACTIVE })
status: ProductStatus;
}Available Enums
Modality: PGBL, VGBL, ANYTaxRegime: PROGRESSIVE, REGRESSIVE, ANYRiskProfile: CONSERVATIVE, MODERATE, BOLD, AGGRESSIVEProductStatus: ACTIVE, INACTIVE, SUSPENDEDQuotationStatus: PENDING, COMPLETED, EXPIRED, CANCELLEDFundStatus: ACTIVE, INACTIVEInsurerStatus: ACTIVE, INACTIVE, SUSPENDEDCoverageType: DEATH, DISABILITY, TERM_PENSION, LIFETIME_INCOME, TEMPORARY_INCOMEBenchmark: CDI, SELIC, IPCA, IBOVESPA, IBRX, IGPMAction(CASL): Manage, Create, Read, ReadAll, Update, UpdateAll, Delete, DeleteAll
Messaging (RabbitMQ)
Centralized RabbitMQ infrastructure for event-driven communication between microservices.
Exchanges and Routing Keys
import { EXCHANGES, ROUTING_KEYS } from '@ferreirasw/yoke-common';
// Publish an event
await eventsService.publishEvent(
EXCHANGES.PRODUCT,
ROUTING_KEYS.PRODUCT_CREATED,
{ productId: '123', name: 'Product A' }
);BaseEventsService
Extend the BaseEventsService in your microservice:
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { BaseEventsService, EXCHANGES } from '@ferreirasw/yoke-common';
@Injectable()
export class ProductEventsService extends BaseEventsService {
constructor(configService: ConfigService) {
super(configService, 'ProductEventsService');
}
protected async setupExchanges(channel: any): Promise<void> {
// Assert your service's exchanges
await channel.assertExchange(EXCHANGES.PRODUCT, 'topic', { durable: true });
await channel.assertExchange(EXCHANGES.FUND, 'topic', { durable: true });
await channel.assertExchange(EXCHANGES.COVERAGE, 'topic', { durable: true });
await channel.assertExchange(EXCHANGES.INSURER, 'topic', { durable: true });
}
}Then register in your module:
import { Module } from '@nestjs/common';
import { ProductEventsService } from './events/product-events.service';
@Module({
providers: [ProductEventsService],
exports: [ProductEventsService],
})
export class EventsModule {}Message Types
Type-safe message interfaces for all events:
import {
ProductCreatedMessage,
EXCHANGES,
ROUTING_KEYS,
} from '@ferreirasw/yoke-common';
const message: ProductCreatedMessage = {
productId: product.id,
insurerId: product.insurerId,
name: product.name,
description: product.description,
modality: product.modality,
taxRegime: product.taxRegime,
status: product.status,
minContribution: product.minContribution,
maxContribution: product.maxContribution,
entryFee: product.entryFee,
administrationFee: product.administrationFee,
timestamp: Date.now(),
source: 'product-microservice',
};
await this.eventsService.publishEvent(
EXCHANGES.PRODUCT,
ROUTING_KEYS.PRODUCT_CREATED,
message
);DTOs and Interfaces
Pagination
import {
PaginationDto,
PaginatedResult,
PaginationHelper,
} from '@ferreirasw/yoke-common';
// In your controller
@Get()
async findAll(@Query() pagination: PaginationDto) {
const [data, total] = await this.productService.findAll(pagination);
return PaginationHelper.createResult(
data,
total,
pagination.page,
pagination.limit
);
}
// In your service
async findAll(pagination: PaginationDto) {
const offset = pagination.getOffset();
const limit = pagination.getLimit();
const [data, total] = await this.repository.findAndCount({
skip: offset,
take: limit,
order: {
[pagination.sortBy || 'createdAt']: pagination.sortOrder || 'DESC',
},
});
return [data, total];
}API Responses
import {
ApiResponse,
ResponseBuilder,
} from '@ferreirasw/yoke-common';
// Success response
@Post()
async create(@Body() createDto: CreateProductDto) {
const product = await this.productService.create(createDto);
return ResponseBuilder.success(product, 'Product created successfully');
}
// Error response (usually handled by exception filter)
throw new BadRequestException(
ResponseBuilder.error('VALIDATION_FAILED', 'Invalid input data')
);Filters and Interceptors
Exception Filter
// In main.ts
import { AllExceptionsFilter } from '@ferreirasw/yoke-common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Register global exception filter
app.useGlobalFilters(new AllExceptionsFilter());
await app.listen(3000);
}Logging Interceptor
// In main.ts
import { LoggingInterceptor } from '@ferreirasw/yoke-common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Register global logging interceptor
app.useGlobalInterceptors(
new LoggingInterceptor({
logRequestBody: process.env.NODE_ENV === 'development',
logResponseData: false, // Disable in production for security
})
);
await app.listen(3000);
}Utilities
Validation Utilities
import {
isValidCPF,
isValidCNPJ,
formatCPF,
formatCNPJ,
formatCurrency,
calculateAge,
} from '@ferreirasw/yoke-common';
// Validate CPF
if (isValidCPF('123.456.789-09')) {
console.log('Valid CPF');
}
// Validate CNPJ
if (isValidCNPJ('11.222.333/0001-81')) {
console.log('Valid CNPJ');
}
// Format values
const formattedCPF = formatCPF('12345678909'); // '123.456.789-09'
const formattedCNPJ = formatCNPJ('11222333000181'); // '11.222.333/0001-81'
const formattedPrice = formatCurrency(1234.56); // 'R$ 1.234,56'
// Calculate age
const age = calculateAge(new Date('1990-01-15')); // 36 (as of 2026)Publishing Updates
Prerequisites
- Login to npm with ferreirasw account:
npm login
# Enter credentials for ferreirasw
npm whoami # Should output: ferreiraswPublishing Workflow
Make your changes to the codebase
Update CHANGELOG.md with your changes
Bump the version using semantic versioning:
# For bug fixes (0.1.0 -> 0.1.1)
npm version patch
# For new features (0.1.0 -> 0.2.0)
npm version minor
# For breaking changes (0.1.0 -> 1.0.0)
npm version major- Build and publish:
npm run build
npm publish --access public- Push to git with tags:
git push origin main --tagsUsing in Microservices
After publishing, install in your microservices:
cd /path/to/account-microservice
npm install @ferreirasw/yoke-common@latest
cd /path/to/product-microservice
npm install @ferreirasw/yoke-common@latest
cd /path/to/quotation-microservice
npm install @ferreirasw/yoke-common@latestUpdating Microservices
When a new version is published:
npm update @ferreirasw/yoke-commonOr install a specific version:
npm install @ferreirasw/[email protected]Development
Building
npm run buildLinting
npm run lintFormatting
npm run formatLicense
MIT
Support
For issues or questions, please create an issue in the repository.
