@signa-app/nest-modules
v0.2.5
Published
Reusable NestJS modules for Signa services.
Readme
signa-modules
Reusable NestJS modules for Signa services.
Package Shape
This repository is a single npm package with independent module entry points. The root entry point exports the public API for all stable modules, while subpath exports allow consumers to import only the area they need.
import { CloudStorageModule } from "@signa-app/nest-modules";
import { CloudStorageService } from "@signa-app/nest-modules/cloud-storage";
import { KafkaModule } from "@signa-app/nest-modules/kafka";Source Layout
src/
index.ts
modules/
<module-name>/
index.ts
<module-name>.module.ts
<module-name>.service.ts
<module-name>.options.ts
<module-name>.tokens.ts
providers/
types/Use src/modules/<module-name>/index.ts as the only public export file for a
module. Keep internal providers, helpers, and implementation details unexported.
Module Contract
Reusable modules should be application-agnostic:
- expose
forRoot()andforRootAsync()when configuration is required; - accept dependencies through options, injection tokens, or imported modules;
- avoid reading
process.envdirectly inside providers; - avoid importing application modules;
- keep controllers optional and export services intentionally;
- declare Nest packages and shared runtime packages as
peerDependencies; - keep DTOs, option interfaces, tokens, and public services stable and exported;
- keep persistence, transport, and third-party clients replaceable where possible.
Adding A Module
Create a folder under src/modules:
src/modules/cloud-storage/
index.ts
cloud-storage.module.ts
cloud-storage.service.ts
cloud-storage.options.ts
cloud-storage.tokens.tsThen export it from src/index.ts only after the public API is ready:
export * from "./modules/cloud-storage";If a module needs a direct subpath import, add it to package.json exports:
"./cloud-storage": {
"types": "./dist/modules/cloud-storage/index.d.ts",
"default": "./dist/modules/cloud-storage/index.js"
}Configuration
Environment variables belong to the consuming application. Modules in this
package accept ready-to-use options through forRoot() or forRootAsync().
CloudStorageModule.forRoot({
bucketName: "signa-files",
accountId: "cloudflare-account-id",
accessKeyId: "access-key",
secretAccessKey: "secret-key",
uploadContentType: "application/zip",
uploadUrlExpiresInSeconds: 3600,
});Kafka modules use the same contract:
KafkaModule.forRoot({
clientId: "payments-api",
brokers: ["localhost:9092"],
asConsumer: true,
asProducer: true,
defaultTopic: "signa-payment-status.local",
consumerConfig: {
groupId: "payments-api-group",
},
});With @nestjs/config in a client application:
CloudStorageModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
bucketName: config.getOrThrow("CLOUD_STORAGE_BUCKET_NAME"),
accountId: config.getOrThrow("CLOUD_STORAGE_ACCOUNT_ID"),
accessKeyId: config.getOrThrow("CLOUD_STORAGE_ACCESS_KEY_ID"),
secretAccessKey: config.getOrThrow("CLOUD_STORAGE_SECRET_ACCESS_KEY"),
uploadContentType: "application/zip",
}),
});With Kafka:
KafkaModule.forRootAsync({
imports: [ConfigModule],
asConsumer: true,
asProducer: true,
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
clientId: config.getOrThrow("KAFKA_CLIENT_ID"),
brokers: config.getOrThrow<string>("KAFKA_BROKERS").split(","),
defaultTopic: config.get("KAFKA_TOPIC"),
ssl: config.get("KAFKA_SSL") === "true",
sasl: {
mechanism: "plain",
username: config.getOrThrow("KAFKA_USERNAME"),
password: config.getOrThrow("KAFKA_PASSWORD"),
},
consumerConfig: {
groupId: config.getOrThrow("KAFKA_CONSUMER_GROUP_ID"),
},
}),
});Without a Nest application context:
const logService = new LogService();
const cloudStorageService = new CloudStorageService(
{
bucketName: "signa-files",
accountId: "cloudflare-account-id",
accessKeyId: "access-key",
secretAccessKey: "secret-key",
},
logService,
);Build
npm install
npm run build
npm run pack:checkPublishing
npm version patch
npm publish --access public --registry=https://registry.npmjs.org/