platform-core
The foundation library that every other Archipel package depends on. Provides caching, configuration management, cryptography, object mapping, template engines, event pub/sub, and shared utilities.
Package: @breadstone/archipel-platform-core
Installation
import {
ConfigModule,
ConfigRegistry,
MappingModule,
MappingService,
BcryptService,
CryptoService,
OtpService,
MemoryLayeredCache,
RedisLayeredCache,
ContentTemplateEngine,
EventHub,
} from '@breadstone/archipel-platform-core';Configuration System
Type-safe, module-scoped configuration with validation.
Defining Config Keys
import { createConfigKey, type IConfigRegistryEntry } from '@breadstone/archipel-platform-core';
// Type-safe config keys with phantom types
const SMTP_HOST = createConfigKey<string>('SMTP_HOST');
const SMTP_PORT = createConfigKey<number>('SMTP_PORT');
const SMTP_SECURE = createConfigKey<boolean>('SMTP_SECURE');
export const MY_MODULE_CONFIG_ENTRIES: ReadonlyArray<IConfigRegistryEntry> = [
{ key: SMTP_HOST, module: 'my-module', required: true, description: 'SMTP server hostname' },
{ key: SMTP_PORT, module: 'my-module', required: false, defaultValue: 587, description: 'SMTP port' },
{ key: SMTP_SECURE, module: 'my-module', required: false, defaultValue: true },
];Registering in a Module
import { Module } from '@nestjs/common';
import { ConfigModule } from '@breadstone/archipel-platform-core';
import { MY_MODULE_CONFIG_ENTRIES } from './env';
@Module({
imports: [ConfigModule.register('my-module', MY_MODULE_CONFIG_ENTRIES)],
})
export class MyModule {}Using the ConfigService
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@breadstone/archipel-platform-core';
@Injectable()
export class SmtpClient {
private readonly _host: string;
private readonly _port: number;
constructor(configService: ConfigService) {
this._host = configService.get<string>('SMTP_HOST');
this._port = configService.tryGet<number>('SMTP_PORT', 587);
}
}ConfigRegistry (Static Access)
import { ConfigRegistry } from '@breadstone/archipel-platform-core';
// List all registered modules
const modules = ConfigRegistry.getModules(); // ['my-module', 'platform-auth', ...]
// Get all required entries
const required = ConfigRegistry.getRequired();
// Get entries grouped by module
const grouped = ConfigRegistry.getByModule();Caching
Layered caching with pluggable backends, metrics, and stale-while-revalidate support.
ILayeredCache Interface
interface ILayeredCache<TKey, TValue> {
get(key: TKey): TValue | undefined;
getAsync(key: TKey): Promise<TValue | undefined>;
set(key: TKey, value: TValue): void;
setAsync(key: TKey, value: TValue): Promise<void>;
invalidate(key: TKey): void;
invalidateAsync(key: TKey): Promise<void>;
warm?(key: TKey): Promise<TValue | undefined>;
stats?(): ICacheStats;
}MemoryLayeredCache
In-memory LRU cache with TTL and stale-while-revalidate.
import { MemoryLayeredCache } from '@breadstone/archipel-platform-core';
const productCache = new MemoryLayeredCache<string, IProduct>(
async (key) => {
// Load function — called on cache miss
return await this._productRepository.findById(key);
},
{
ttlMs: 60_000, // 60 seconds TTL
staleWhileRevalidate: true, // Serve stale data while refreshing
maxEntries: 1000, // LRU eviction after 1000 entries
cacheName: 'products', // For metrics labeling
metricsRecorder: telemetryRecorder,
},
);
// Usage
const product = await productCache.getAsync('prod-123');
// Invalidate after mutation
productCache.invalidate('prod-123');
// Check stats
const stats = productCache.stats();
// → { hits: 142, misses: 23, loads: 23, loadErrors: 0, evictions: 0 }RedisLayeredCache
Redis-backed distributed cache for multi-instance deployments.
import { RedisLayeredCache } from '@breadstone/archipel-platform-core';
const sessionCache = new RedisLayeredCache<string, ISessionData>(
async (key) => await this._sessionStore.findByToken(key),
{
url: 'redis://localhost:6379',
keyPrefix: 'session:',
ttlSeconds: 3600,
serialize: (value) => JSON.stringify(value),
deserialize: (raw) => JSON.parse(raw),
cacheName: 'sessions',
},
);ICacheMetricsRecorder
Integrate cache metrics with your observability stack.
import type { ICacheMetricsRecorder } from '@breadstone/archipel-platform-core';
class MyMetricsRecorder implements ICacheMetricsRecorder {
public recordHit(cache: string): void {
/* prometheus counter */
}
public recordMiss(cache: string): void {
/* prometheus counter */
}
public recordLoadSuccess(cache: string): void {
/* ... */
}
public recordLoadError(cache: string): void {
/* ... */
}
public recordEviction(cache: string): void {
/* ... */
}
}Mapping Service
Centralized object mapping with type-safe keys and profiles.
Defining Mapping Keys
import { createMappingKey } from '@breadstone/archipel-platform-core';
import type { IUserEntity } from './entities';
import type { UserResponse } from './responses';
export const USER_TO_RESPONSE = createMappingKey<IUserEntity, UserResponse>('UserEntity→UserResponse');
export const USER_TO_SUMMARY = createMappingKey<IUserEntity, UserSummary>('UserEntity→UserSummary');Creating a Mapping Profile
import { Injectable } from '@nestjs/common';
import { MappingProfileBase, type IMappingBuilder } from '@breadstone/archipel-platform-core';
import { USER_TO_RESPONSE, USER_TO_SUMMARY } from './mapping-keys';
@Injectable()
export class UserMappingProfile extends MappingProfileBase {
public override configure(builder: IMappingBuilder): void {
builder.createKeyedMap(USER_TO_RESPONSE, (source) => ({
id: source.id,
name: source.userName,
email: source.email,
verified: source.isVerified,
roles: [...source.roles],
}));
builder.createKeyedMap(USER_TO_SUMMARY, (source) => ({
id: source.id,
displayName: source.userName ?? source.email ?? 'Anonymous',
}));
}
}Registering Profiles in a Module
import { Module } from '@nestjs/common';
import { MappingModule } from '@breadstone/archipel-platform-core';
import { UserMappingProfile } from './mappers/UserMappingProfile';
import { OrderMappingProfile } from './mappers/OrderMappingProfile';
@Module({
imports: [MappingModule.withProfiles([UserMappingProfile, OrderMappingProfile])],
})
export class AppModule {}Using in a Controller
import { Controller, Get, Param } from '@nestjs/common';
import { MappingService } from '@breadstone/archipel-platform-core';
import { USER_TO_RESPONSE } from './mapping-keys';
@Controller('users')
export class UserController {
constructor(
private readonly _userService: UserService,
private readonly _mappingService: MappingService,
) {}
@Get(':id')
public async getUser(@Param('id') id: string): Promise<UserResponse> {
const entity = await this._userService.findById(id);
return this._mappingService.map(USER_TO_RESPONSE, entity);
}
}Cryptography & OTP
BcryptService
Password hashing with bcrypt.
import { BcryptService } from '@breadstone/archipel-platform-core';
@Injectable()
export class AccountService {
constructor(private readonly _bcrypt: BcryptService) {}
public async register(password: string): Promise<void> {
const hash = await this._bcrypt.hash(password);
// Store hash in database
}
public async verifyPassword(input: string, storedHash: string): Promise<boolean> {
return this._bcrypt.compare(input, storedHash);
}
}CryptoService
UUID-based identifier generation.
import { CryptoService } from '@breadstone/archipel-platform-core';
const crypto = new CryptoService();
const token = crypto.getRandomGuid('verify');
// → "verify-a1b2c3d4-e5f6-7890-abcd-ef1234567890"OtpService
TOTP one-time password generation and verification (otplib).
import { OtpService } from '@breadstone/archipel-platform-core';
import type { IOtpService } from '@breadstone/archipel-platform-core';
@Injectable()
export class MfaSetupService {
constructor(@Inject(OTP_SERVICE_TOKEN) private readonly _otp: IOtpService) {}
public setup(userEmail: string): { secret: string; uri: string } {
const secret = this._otp.generateSecret();
const uri = this._otp.generateUri({
issuer: 'MyApp',
label: userEmail,
secret,
});
return { secret, uri };
}
public verify(token: string, secret: string): boolean {
return this._otp.verify(token, secret);
// Window = 1 → accepts current + previous 30s interval
}
}Event System
Type-safe publish/subscribe with RxJS.
Defining Events
import { createEventKey, type IEventMap } from '@breadstone/archipel-platform-core';
interface IOrderEvents extends IEventMap {
'order.created': { orderId: string; userId: string };
'order.shipped': { orderId: string; trackingNumber: string };
'order.cancelled': { orderId: string; reason: string };
}
export const ORDER_CREATED = createEventKey<IOrderEvents, 'order.created'>('order.created');
export const ORDER_SHIPPED = createEventKey<IOrderEvents, 'order.shipped'>('order.shipped');Publishing & Subscribing
import { EventHub } from '@breadstone/archipel-platform-core';
import { ORDER_CREATED, ORDER_SHIPPED } from './events';
@Injectable()
export class OrderService {
constructor(private readonly _events: EventHub) {}
public async createOrder(userId: string): Promise<void> {
const orderId = '...';
// ... create order logic
this._events.publish(ORDER_CREATED, { orderId, userId });
}
}
@Injectable()
export class NotificationService {
constructor(events: EventHub) {
events.subscribe(ORDER_CREATED, (payload) => {
// payload is typed as { orderId: string; userId: string }
this.sendOrderConfirmation(payload.userId, payload.orderId);
});
}
}Content Template Engine
Handlebars-style template compilation with block helpers.
import { ContentTemplateEngine } from '@breadstone/archipel-platform-core';
const engine = new ContentTemplateEngine();
// Simple variable substitution
const result = engine.compileTemplate('Hello {{name}}, welcome to {{app}}!', { name: 'Alice', app: 'MyApp' });
// → "Hello Alice, welcome to MyApp!"
// Block helpers
const list = engine.compileTemplate('{{#each items}}- {{this.name}}: {{this.price}}€\n{{/each}}', {
items: [
{ name: 'Widget', price: 9.99 },
{ name: 'Gadget', price: 19.99 },
],
});
// Conditionals
const conditional = engine.compileTemplate('{{#if isPremium}}Premium Member{{/if}}{{#if !isPremium}}Free Tier{{/if}}', {
isPremium: true,
});Identifier Generation
Pluggable ID generation via IdentifierModule.
import { IdentifierModule, ID_GENERATOR_TOKEN, type IIdGenerator } from '@breadstone/archipel-platform-core';
// Module setup — choose strategy
@Module({
imports: [IdentifierModule.register('CUID')],
})
export class AppModule {}
// Usage in a service
@Injectable()
export class OrderService {
constructor(@Inject(ID_GENERATOR_TOKEN) private readonly _idGen: IIdGenerator) {}
public createOrder(): string {
return this._idGen.generate(); // CUID, UUID, or GUID depending on registration
}
}Utility Services
| Service | Purpose |
|---|---|
DeviceParserService | Parse User-Agent headers into IDeviceInfo (browser, OS, device type) |
HostService | Host configuration (title, logo, features, health endpoints) |
UserAvatarGeneratorService | Generate deterministic avatars from user identifiers |
UsernameGeneratorService | Generate random usernames from word lists |
Module Summary
| Export | Type | Description |
|---|---|---|
ConfigModule | NestJS Module | Configuration registration and validation |
MappingModule | NestJS Module | Mapping profile registration |
EventModule | NestJS Module | Event pub/sub system |
IdentifierModule | NestJS Module | ID generation strategy |
HostModule | NestJS Module | Host services and templates |
HealthModule | NestJS Module | Health check orchestration |
MappingService | Service | Central object mapping |
ConfigService | Service | Type-safe config access |
BcryptService | Service | Password hashing |
CryptoService | Service | UUID generation |
OtpService | Service | TOTP generation/verification |
EventHub | Service | Event publish/subscribe |
ContentTemplateEngine | Service | Template compilation |
MemoryLayeredCache | Class | In-memory LRU cache |
RedisLayeredCache | Class | Redis-backed cache |