Skip to content

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

typescript
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

typescript
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

typescript
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

typescript
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)

typescript
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

typescript
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.

typescript
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.

typescript
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.

typescript
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

typescript
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

typescript
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

typescript
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

typescript
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.

typescript
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.

typescript
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).

typescript
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

typescript
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

typescript
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.

typescript
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.

typescript
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

ServicePurpose
DeviceParserServiceParse User-Agent headers into IDeviceInfo (browser, OS, device type)
HostServiceHost configuration (title, logo, features, health endpoints)
UserAvatarGeneratorServiceGenerate deterministic avatars from user identifiers
UsernameGeneratorServiceGenerate random usernames from word lists

Module Summary

ExportTypeDescription
ConfigModuleNestJS ModuleConfiguration registration and validation
MappingModuleNestJS ModuleMapping profile registration
EventModuleNestJS ModuleEvent pub/sub system
IdentifierModuleNestJS ModuleID generation strategy
HostModuleNestJS ModuleHost services and templates
HealthModuleNestJS ModuleHealth check orchestration
MappingServiceServiceCentral object mapping
ConfigServiceServiceType-safe config access
BcryptServiceServicePassword hashing
CryptoServiceServiceUUID generation
OtpServiceServiceTOTP generation/verification
EventHubServiceEvent publish/subscribe
ContentTemplateEngineServiceTemplate compilation
MemoryLayeredCacheClassIn-memory LRU cache
RedisLayeredCacheClassRedis-backed cache

Released under the MIT License.