alepha
Version:
Alepha is a convention-driven TypeScript framework for building robust, end-to-end type-safe applications, from serverless APIs to full-stack React apps.
954 lines (953 loc) • 33.1 kB
TypeScript
import * as _alepha_core1 from "alepha";
import { Alepha, Descriptor, KIND, Service, Static, TSchema } from "alepha";
import { DateTimeProvider, DurationLike } from "alepha/datetime";
import * as _alepha_logger0 from "alepha/logger";
//#region src/providers/TopicProvider.d.ts
/**
* Base class for topic providers.
*/
declare abstract class TopicProvider {
protected readonly alepha: Alepha;
/**
* Publish a message to a topic.
*
* @param topic - The topic to publish to.
* @param message - The message to publish.
*/
abstract publish(topic: string, message: string): Promise<void>;
/**
* Subscribe to a topic.
*
* @param topic - The topic to subscribe to.
* @param callback - The callback to call when a message is received.
*/
abstract subscribe(topic: string, callback: SubscribeCallback): Promise<UnSubscribeFn>;
/**
* Unsubscribe from a topic.
*
* @param topic - The topic to unsubscribe from.
*/
abstract unsubscribe(topic: string): Promise<void>;
/**
* Returns the list of $subscribers for this provider.
*/
protected subscribers(): Array<() => Promise<unknown>>;
}
type SubscribeCallback = (message: string) => Promise<void> | void;
type UnSubscribeFn = () => Promise<void>;
//#endregion
//#region src/descriptors/$topic.d.ts
/**
* Creates a topic descriptor for pub/sub messaging and event-driven architecture.
*
* This descriptor provides a powerful publish/subscribe system that enables decoupled communication
* between different parts of your application. Topics allow multiple publishers to send messages
* and multiple subscribers to receive them, creating flexible event-driven architectures with
* support for real-time messaging and asynchronous event processing.
*
* **Key Features**
*
* - **Publish/Subscribe Pattern**: Decoupled communication between publishers and subscribers
* - **Multiple Subscribers**: One-to-many message distribution with automatic fan-out
* - **Type-Safe Messages**: Full TypeScript support with schema validation using TypeBox
* - **Real-time Processing**: Immediate message delivery to active subscribers
* - **Event Filtering**: Subscribe to specific message types using filter functions
* - **Timeout Support**: Wait for specific messages with configurable timeouts
* - **Multiple Backends**: Support for in-memory, Redis, and custom topic providers
* - **Error Resilience**: Built-in error handling and message processing recovery
*
* **Use Cases**
*
* Perfect for event-driven architectures and real-time communication:
* - User activity notifications
* - Real-time chat and messaging systems
* - System event broadcasting
* - Microservice communication
* - Live data updates and synchronization
* - Application state change notifications
* - Webhook and external API event handling
*
* @example
* **Basic topic with publish/subscribe:**
* ```ts
* import { $topic } from "alepha/topic";
* import { t } from "alepha";
*
* class NotificationService {
* userActivity = $topic({
* name: "user-activity",
* schema: {
* payload: t.object({
* userId: t.string(),
* action: t.enum(["login", "logout", "purchase"]),
* timestamp: t.number(),
* metadata: t.optional(t.record(t.string(), t.any()))
* })
* },
* handler: async (message) => {
* // This subscriber runs automatically for all messages
* console.log(`User ${message.payload.userId} performed ${message.payload.action}`);
* }
* });
*
* async trackUserLogin(userId: string) {
* // Publish event - all subscribers will receive it
* await this.userActivity.publish({
* userId,
* action: "login",
* timestamp: Date.now(),
* metadata: { source: "web", ip: "192.168.1.1" }
* });
* }
*
* async setupAdditionalSubscriber() {
* // Add another subscriber dynamically
* await this.userActivity.subscribe(async (message) => {
* if (message.payload.action === "purchase") {
* await this.sendPurchaseConfirmation(message.payload.userId);
* }
* });
* }
* }
* ```
*
* @example
* **Real-time chat system with multiple subscribers:**
* ```ts
* class ChatService {
* messagesTopic = $topic({
* name: "chat-messages",
* description: "Real-time chat messages for all rooms",
* schema: {
* payload: t.object({
* messageId: t.string(),
* roomId: t.string(),
* userId: t.string(),
* content: t.string(),
* timestamp: t.number(),
* messageType: t.enum(["text", "image", "file"])
* })
* }
* });
*
* async sendMessage(roomId: string, userId: string, content: string) {
* await this.messagesTopic.publish({
* messageId: generateId(),
* roomId,
* userId,
* content,
* timestamp: Date.now(),
* messageType: "text"
* });
* }
*
* // Different services can subscribe to the same topic
* async setupMessageLogging() {
* await this.messagesTopic.subscribe(async (message) => {
* // Log all messages for compliance
* await this.auditLogger.log({
* action: "message_sent",
* roomId: message.payload.roomId,
* userId: message.payload.userId,
* timestamp: message.payload.timestamp
* });
* });
* }
*
* async setupNotificationService() {
* await this.messagesTopic.subscribe(async (message) => {
* // Send push notifications to offline users
* const offlineUsers = await this.getOfflineUsersInRoom(message.payload.roomId);
* await this.sendPushNotifications(offlineUsers, {
* title: `New message in ${message.payload.roomId}`,
* body: message.payload.content
* });
* });
* }
* }
* ```
*
* @example
* **Event filtering and waiting for specific messages:**
* ```ts
* class OrderService {
* orderEvents = $topic({
* name: "order-events",
* schema: {
* payload: t.object({
* orderId: t.string(),
* status: t.union([
* t.literal("created"),
* t.literal("paid"),
* t.literal("shipped"),
* t.literal("delivered"),
* t.literal("cancelled")
* ]),
* timestamp: t.number(),
* data: t.optional(t.record(t.string(), t.any()))
* })
* }
* });
*
* async processOrder(orderId: string) {
* // Publish order created event
* await this.orderEvents.publish({
* orderId,
* status: "created",
* timestamp: Date.now()
* });
*
* // Wait for payment confirmation with timeout
* try {
* const paymentEvent = await this.orderEvents.wait({
* timeout: [5, "minutes"],
* filter: (message) =>
* message.payload.orderId === orderId &&
* message.payload.status === "paid"
* });
*
* console.log(`Order ${orderId} was paid at ${paymentEvent.payload.timestamp}`);
*
* // Continue with shipping...
* await this.initiateShipping(orderId);
*
* } catch (error) {
* if (error instanceof TopicTimeoutError) {
* console.log(`Payment timeout for order ${orderId}`);
* await this.cancelOrder(orderId);
* }
* }
* }
*
* async setupOrderTracking() {
* // Subscribe only to shipping events
* await this.orderEvents.subscribe(async (message) => {
* if (message.payload.status === "shipped") {
* await this.updateTrackingInfo(message.payload.orderId, message.payload.data);
* await this.notifyCustomer(message.payload.orderId, "Your order has shipped!");
* }
* });
* }
* }
* ```
*
* @example
* **Redis-backed topic for distributed systems:**
* ```ts
* class DistributedEventSystem {
* systemEvents = $topic({
* name: "system-events",
* provider: RedisTopicProvider, // Use Redis for cross-service communication
* schema: {
* payload: t.object({
* eventType: t.string(),
* serviceId: t.string(),
* data: t.record(t.string(), t.any()),
* timestamp: t.number(),
* correlationId: t.optional(t.string())
* })
* },
* handler: async (message) => {
* // Central event handler for all system events
* await this.processSystemEvent(message.payload);
* }
* });
*
* async publishServiceHealth(serviceId: string, healthy: boolean) {
* await this.systemEvents.publish({
* eventType: "service.health",
* serviceId,
* data: { healthy, checkedAt: new Date().toISOString() },
* timestamp: Date.now()
* });
* }
*
* async setupHealthMonitoring() {
* await this.systemEvents.subscribe(async (message) => {
* if (message.payload.eventType === "service.health") {
* await this.updateServiceStatus(
* message.payload.serviceId,
* message.payload.data.healthy
* );
*
* if (!message.payload.data.healthy) {
* await this.alertOnCall(`Service ${message.payload.serviceId} is down`);
* }
* }
* });
* }
* }
* ```
*/
declare const $topic: {
<T extends TopicMessageSchema>(options: TopicDescriptorOptions<T>): TopicDescriptor<T>;
[KIND]: typeof TopicDescriptor;
};
interface TopicDescriptorOptions<T extends TopicMessageSchema> {
/**
* Unique name identifier for the topic.
*
* This name is used for:
* - Topic identification across the pub/sub system
* - Message routing between publishers and subscribers
* - Logging and debugging topic-related operations
* - Provider-specific topic management (channels, keys, etc.)
*
* If not provided, defaults to the property key where the topic is declared.
*
* **Naming Conventions**:
* - Use descriptive, hierarchical names: "user.activity", "order.events"
* - Avoid spaces and special characters
* - Consider using dot notation for categorization
* - Keep names concise but meaningful
*
* @example "user-activity"
* @example "chat.messages"
* @example "system.health.checks"
* @example "payment.webhooks"
*/
name?: string;
/**
* Human-readable description of the topic's purpose and usage.
*
* Used for:
* - Documentation generation and API references
* - Developer onboarding and understanding
* - Monitoring dashboards and admin interfaces
* - Team communication about system architecture
*
* **Description Best Practices**:
* - Explain what events/messages this topic handles
* - Mention key use cases and subscribers
* - Include any important timing or ordering guarantees
* - Note any special processing requirements
*
* @example "Real-time user activity events for analytics and notifications"
* @example "Order lifecycle events from creation to delivery"
* @example "Chat messages broadcast to all room participants"
* @example "System health checks and service status updates"
*/
description?: string;
/**
* Topic provider configuration for message storage and delivery.
*
* Options:
* - **"memory"**: In-memory provider (default for development, lost on restart)
* - **Service<TopicProvider>**: Custom provider class (e.g., RedisTopicProvider)
* - **undefined**: Uses the default topic provider from dependency injection
*
* **Provider Selection Guidelines**:
* - **Development**: Use "memory" for fast, simple testing without external dependencies
* - **Production**: Use Redis or message brokers for persistence and scalability
* - **Distributed systems**: Use Redis/RabbitMQ for cross-service communication
* - **High-throughput**: Use specialized providers with connection pooling
* - **Real-time**: Ensure provider supports low-latency message delivery
*
* **Provider Capabilities**:
* - Message persistence and durability
* - Subscriber management and connection handling
* - Message ordering and delivery guarantees
* - Horizontal scaling and load distribution
*
* @default Uses injected TopicProvider
* @example "memory"
* @example RedisTopicProvider
* @example RabbitMQTopicProvider
*/
provider?: "memory" | Service<TopicProvider>;
/**
* TypeBox schema defining the structure of messages published to this topic.
*
* The schema must include:
* - **payload**: Required schema for the main message data
* - **headers**: Optional schema for message metadata
*
* This schema:
* - Validates all messages published to the topic
* - Provides full TypeScript type inference for subscribers
* - Ensures type safety between publishers and subscribers
* - Enables automatic serialization/deserialization
*
* **Schema Design Best Practices**:
* - Keep payload schemas focused and cohesive
* - Use optional fields for data that might not always be present
* - Include timestamp fields for event ordering
* - Consider versioning for schema evolution
* - Use union types for different event types in the same topic
*
* @example
* ```ts
* {
* payload: t.object({
* eventId: t.string(),
* eventType: t.enum(["created", "updated"]),
* data: t.record(t.string(), t.any()),
* timestamp: t.number(),
* userId: t.optional(t.string())
* }),
* headers: t.optional(t.object({
* source: t.string(),
* correlationId: t.string()
* }))
* }
* ```
*/
schema: T;
/**
* Default subscriber handler function that processes messages published to this topic.
*
* This handler:
* - Automatically subscribes when the topic is initialized
* - Receives all messages published to the topic
* - Runs for every message without additional subscription setup
* - Can be supplemented with additional subscribers via `subscribe()` method
* - Should handle errors gracefully to avoid breaking other subscribers
*
* **Handler Design Guidelines**:
* - Keep handlers focused on a single responsibility
* - Use proper error handling and logging
* - Consider performance impact for high-frequency topics
* - Make handlers idempotent when possible
* - Validate business rules within the handler logic
* - Log important processing steps for debugging
*
* **Error Handling Strategy**:
* - Log errors but don't re-throw to avoid affecting other subscribers
* - Use try-catch blocks for external service calls
* - Consider implementing circuit breakers for resilience
* - Monitor error rates and patterns for system health
*
* @param message - The topic message with validated payload and headers
* @param message.payload - The typed message data based on the schema
* @returns Promise that resolves when processing is complete
*
* @example
* ```ts
* handler: async (message) => {
* const { eventType, data, timestamp } = message.payload;
*
* try {
* // Log message receipt
* this.logger.info(`Processing ${eventType} event`, { timestamp, data });
*
* // Process based on event type
* switch (eventType) {
* case "created":
* await this.handleCreation(data);
* break;
* case "updated":
* await this.handleUpdate(data);
* break;
* default:
* this.logger.warn(`Unknown event type: ${eventType}`);
* }
*
* this.logger.info(`Successfully processed ${eventType} event`);
*
* } catch (error) {
* // Log error but don't re-throw to avoid affecting other subscribers
* this.logger.error(`Failed to process ${eventType} event`, {
* error: error.message,
* eventType,
* timestamp,
* data
* });
* }
* }
* ```
*/
handler?: TopicHandler<T>;
}
declare class TopicDescriptor<T extends TopicMessageSchema> extends Descriptor<TopicDescriptorOptions<T>> {
protected readonly log: _alepha_logger0.Logger;
protected readonly dateTimeProvider: DateTimeProvider;
readonly provider: TopicProvider;
get name(): string;
publish(payload: TopicMessage<T>["payload"]): Promise<void>;
subscribe(handler: TopicHandler<T>): Promise<UnSubscribeFn>;
wait(options?: TopicWaitOptions<T>): Promise<TopicMessage<T>>;
protected $provider(): TopicProvider;
protected parseMessage(message: string): TopicMessage<T>;
}
interface TopicMessage<T extends TopicMessageSchema> {
payload: Static<T["payload"]>;
}
interface TopicWaitOptions<T extends TopicMessageSchema> {
timeout?: DurationLike;
filter?: (message: {
payload: Static<T["payload"]>;
}) => boolean;
}
interface TopicMessageSchema {
payload: TSchema;
}
type TopicHandler<T extends TopicMessageSchema = TopicMessageSchema> = (message: TopicMessage<T>) => unknown;
//#endregion
//#region src/descriptors/$subscriber.d.ts
/**
* Creates a subscriber descriptor to listen for messages from a specific topic.
*
* This descriptor creates a dedicated message subscriber that connects to a topic and processes
* its messages using a custom handler function. Subscribers provide a clean way to separate
* message publishing from consumption, enabling scalable pub/sub architectures where multiple
* subscribers can react to the same events independently.
*
* ## Key Features
*
* - **Topic Integration**: Seamlessly connects to any $topic descriptor
* - **Type Safety**: Full TypeScript support inherited from the connected topic's schema
* - **Dedicated Processing**: Isolated message processing logic separate from the topic
* - **Real-time Processing**: Immediate message delivery when events are published
* - **Error Isolation**: Subscriber errors don't affect other subscribers or the topic
* - **Scalability**: Multiple subscribers can listen to the same topic independently
*
* ## Use Cases
*
* Perfect for creating specialized event handlers:
* - Notification services for user events
* - Analytics and logging systems
* - Data synchronization between services
* - Real-time UI updates
* - Event-driven workflow triggers
* - Audit and compliance logging
*
* @example
* **Basic subscriber setup:**
* ```ts
* import { $topic, $subscriber } from "alepha/topic";
* import { t } from "alepha";
*
* class UserActivityService {
* // Define the topic
* userEvents = $topic({
* name: "user-activity",
* schema: {
* payload: t.object({
* userId: t.string(),
* action: t.enum(["login", "logout", "purchase"]),
* timestamp: t.number(),
* metadata: t.optional(t.record(t.string(), t.any()))
* })
* }
* });
*
* // Create a dedicated subscriber for this topic
* activityLogger = $subscriber({
* topic: this.userEvents,
* handler: async (message) => {
* const { userId, action, timestamp } = message.payload;
*
* await this.auditLogger.log({
* event: 'user_activity',
* userId,
* action,
* timestamp,
* source: 'user-activity-topic'
* });
*
* this.log.info(`User ${userId} performed ${action} at ${new Date(timestamp).toISOString()}`);
* }
* });
*
* async trackUserLogin(userId: string, metadata: Record<string, any>) {
* // Publish to topic - subscriber will automatically process it
* await this.userEvents.publish({
* userId,
* action: "login",
* timestamp: Date.now(),
* metadata
* });
* }
* }
* ```
*
* @example
* **Multiple specialized subscribers for different concerns:**
* ```ts
* class OrderEventHandlers {
* orderEvents = $topic({
* name: "order-events",
* schema: {
* payload: t.object({
* orderId: t.string(),
* customerId: t.string(),
* status: t.union([
* t.literal("created"),
* t.literal("paid"),
* t.literal("shipped"),
* t.literal("delivered")
* ]),
* data: t.optional(t.record(t.string(), t.any()))
* })
* }
* });
*
* // Analytics subscriber
* analyticsSubscriber = $subscriber({
* topic: this.orderEvents,
* handler: async (message) => {
* await this.analytics.track('order_status_changed', {
* orderId: message.payload.orderId,
* customerId: message.payload.customerId,
* status: message.payload.status,
* timestamp: Date.now()
* });
* }
* });
*
* // Email notification subscriber
* emailSubscriber = $subscriber({
* topic: this.orderEvents,
* handler: async (message) => {
* const { customerId, orderId, status } = message.payload;
*
* const templates = {
* 'paid': 'order-confirmation',
* 'shipped': 'order-shipped',
* 'delivered': 'order-delivered'
* };
*
* const template = templates[status];
* if (template) {
* await this.emailService.send({
* customerId,
* template,
* data: { orderId, status }
* });
* }
* }
* });
*
* // Inventory management subscriber
* inventorySubscriber = $subscriber({
* topic: this.orderEvents,
* handler: async (message) => {
* if (message.payload.status === 'paid') {
* await this.inventoryService.reserveItems(message.payload.orderId);
* } else if (message.payload.status === 'delivered') {
* await this.inventoryService.confirmDelivery(message.payload.orderId);
* }
* }
* });
* }
* ```
*
* @example
* **Subscriber with advanced error handling and filtering:**
* ```ts
* class NotificationSubscriber {
* systemEvents = $topic({
* name: "system-events",
* schema: {
* payload: t.object({
* eventType: t.string(),
* severity: t.enum(["info", "warning", "error"]),
* serviceId: t.string(),
* message: t.string(),
* data: t.optional(t.record(t.string(), t.any()))
* })
* }
* });
*
* alertSubscriber = $subscriber({
* topic: this.systemEvents,
* handler: async (message) => {
* const { eventType, severity, serviceId, message: eventMessage, data } = message.payload;
*
* try {
* // Only process error events for alerting
* if (severity !== 'error') {
* return;
* }
*
* // Log the event
* this.logger.error(`System alert from ${serviceId}`, {
* eventType,
* message: eventMessage,
* data
* });
*
* // Send alerts based on service criticality
* const criticalServices = ['payment', 'auth', 'database'];
* const isCritical = criticalServices.includes(serviceId);
*
* if (isCritical) {
* // Immediate alert for critical services
* await this.alertService.sendImmediate({
* title: `Critical Error in ${serviceId}`,
* message: eventMessage,
* severity: 'critical',
* metadata: { eventType, serviceId, data }
* });
* } else {
* // Queue non-critical alerts for batching
* await this.alertService.queueAlert({
* title: `Error in ${serviceId}`,
* message: eventMessage,
* severity: 'error',
* metadata: { eventType, serviceId, data }
* });
* }
*
* // Update service health status
* await this.healthMonitor.recordError(serviceId, eventType);
*
* } catch (error) {
* // Log subscriber errors but don't re-throw
* // This prevents one failing subscriber from affecting others
* this.log.error(`Alert subscriber failed`, {
* originalEvent: { eventType, serviceId, severity },
* subscriberError: error.message
* });
* }
* }
* });
* }
* ```
*
* @example
* **Subscriber for real-time data aggregation:**
* ```ts
* class MetricsAggregator {
* userActivityTopic = $topic({
* name: "user-metrics",
* schema: {
* payload: t.object({
* userId: t.string(),
* sessionId: t.string(),
* eventType: t.string(),
* timestamp: t.number(),
* duration: t.optional(t.number()),
* metadata: t.optional(t.record(t.string(), t.any()))
* })
* }
* });
*
* metricsSubscriber = $subscriber({
* topic: this.userActivityTopic,
* handler: async (message) => {
* const { userId, sessionId, eventType, timestamp, duration, metadata } = message.payload;
*
* // Update real-time metrics
* await Promise.all([
* // Update user activity counters
* this.metricsStore.increment(`user:${userId}:events:${eventType}`, 1),
* this.metricsStore.increment(`global:events:${eventType}`, 1),
*
* // Track session activity
* this.sessionStore.updateActivity(sessionId, timestamp),
*
* // Record duration metrics if provided
* duration ? this.metricsStore.recordDuration(`events:${eventType}:duration`, duration) : Promise.resolve(),
*
* // Update time-based aggregations
* this.timeSeriesStore.addPoint({
* metric: `user_activity.${eventType}`,
* timestamp,
* value: 1,
* tags: { userId, sessionId }
* })
* ]);
*
* // Trigger real-time dashboard updates
* await this.dashboardService.updateRealTimeStats({
* eventType,
* userId,
* timestamp
* });
*
* this.logger.debug(`Processed metrics for ${eventType}`, {
* userId,
* eventType,
* timestamp
* });
* }
* });
* }
* ```
*/
declare const $subscriber: {
<T extends TopicMessageSchema>(options: SubscriberDescriptorOptions<T>): SubscriberDescriptor<T>;
[KIND]: typeof SubscriberDescriptor;
};
interface SubscriberDescriptorOptions<T extends TopicMessageSchema> {
/**
* The topic descriptor that this subscriber will listen to for messages.
*
* This establishes the connection between the subscriber and its source topic:
* - The subscriber inherits the topic's message schema for type safety
* - Messages published to the topic will be automatically delivered to this subscriber
* - Multiple subscribers can listen to the same topic independently
* - The subscriber will use the topic's provider and configuration settings
*
* **Topic Integration Benefits**:
* - Type safety: Subscriber handler gets fully typed message payloads
* - Schema validation: Messages are validated before reaching the subscriber
* - Real-time delivery: Messages are delivered immediately upon publication
* - Error isolation: Subscriber errors don't affect the topic or other subscribers
* - Monitoring: Topic metrics include subscriber processing statistics
*
* @example
* ```ts
* // First, define a topic
* userEvents = $topic({
* name: "user-activity",
* schema: {
* payload: t.object({ userId: t.string(), action: t.string() })
* }
* });
*
* // Then, create a subscriber for that topic
* activitySubscriber = $subscriber({
* topic: this.userEvents, // Reference the topic descriptor
* handler: async (message) => { } // Process messages here
* });
* ```
*/
topic: TopicDescriptor<T>;
/**
* Message handler function that processes individual messages from the topic.
*
* This function:
* - Receives fully typed and validated message payloads from the connected topic
* - Executes immediately when messages are published to the topic
* - Should implement the core business logic for reacting to these events
* - Runs independently of other subscribers to the same topic
* - Should handle errors gracefully to avoid affecting other subscribers
* - Has access to the full Alepha dependency injection container
*
* **Handler Design Guidelines**:
* - Keep handlers focused on a single responsibility
* - Use proper error handling and logging
* - Consider performance impact for high-frequency topics
* - Make handlers idempotent when possible for reliability
* - Validate business rules within the handler logic
* - Log important processing steps for debugging and monitoring
*
* **Error Handling Strategy**:
* - Log errors but don't re-throw to avoid affecting other subscribers
* - Use try-catch blocks for external service calls
* - Implement circuit breakers for resilience with external systems
* - Monitor error rates and patterns for system health
* - Consider implementing retry logic for temporary failures
*
* **Performance Considerations**:
* - Keep handler execution time minimal for high-throughput topics
* - Use background queues for heavy processing triggered by events
* - Implement batching for efficiency when processing many similar events
* - Consider async processing patterns for non-critical operations
*
* @param message - The topic message with validated payload and optional headers
* @param message.payload - The typed message data based on the topic's schema
* @returns Promise that resolves when processing is complete
*
* @example
* ```ts
* handler: async (message) => {
* const { userId, eventType, timestamp } = message.payload;
*
* try {
* // Log event receipt
* this.logger.info(`Processing ${eventType} event for user ${userId}`, {
* timestamp,
* userId,
* eventType
* });
*
* // Perform event-specific processing
* switch (eventType) {
* case 'user.login':
* await this.updateLastLogin(userId, timestamp);
* await this.sendWelcomeNotification(userId);
* break;
* case 'user.logout':
* await this.updateSessionDuration(userId, timestamp);
* break;
* case 'user.purchase':
* await this.updateRewardsPoints(userId, message.payload.purchaseAmount);
* await this.triggerRecommendations(userId);
* break;
* default:
* this.logger.warn(`Unknown event type: ${eventType}`);
* }
*
* // Update analytics
* await this.analytics.track(eventType, {
* userId,
* timestamp,
* source: 'topic-subscriber'
* });
*
* this.logger.info(`Successfully processed ${eventType} for user ${userId}`);
*
* } catch (error) {
* // Log error but don't re-throw to avoid affecting other subscribers
* this.logger.error(`Failed to process ${eventType} for user ${userId}`, {
* error: error.message,
* stack: error.stack,
* userId,
* eventType,
* timestamp
* });
*
* // Optionally send to error tracking service
* await this.errorTracker.captureException(error, {
* context: { userId, eventType, timestamp },
* tags: { component: 'topic-subscriber' }
* });
* }
* }
* ```
*/
handler: TopicHandler<T>;
}
declare class SubscriberDescriptor<T extends TopicMessageSchema> extends Descriptor<SubscriberDescriptorOptions<T>> {}
//#endregion
//#region src/errors/TopicTimeoutError.d.ts
declare class TopicTimeoutError extends Error {
readonly topic: string;
readonly timeout: number;
constructor(topic: string, timeout: number);
}
//#endregion
//#region src/providers/MemoryTopicProvider.d.ts
declare class MemoryTopicProvider extends TopicProvider {
protected readonly log: _alepha_logger0.Logger;
protected readonly subscriptions: Record<string, SubscribeCallback[]>;
protected readonly start: _alepha_core1.HookDescriptor<"start">;
/**
* Publish a message to a topic.
*
* @param topic
* @param message
*/
publish(topic: string, message: string): Promise<void>;
/**
* Subscribe to a topic.
*
* @param topic - The topic to subscribe to.
* @param callback
*/
subscribe(topic: string, callback: SubscribeCallback): Promise<UnSubscribeFn>;
/**
* Unsubscribe from a topic.
*
* @param topic - The topic to unsubscribe from.
*/
unsubscribe(topic: string): Promise<void>;
}
//#endregion
//#region src/index.d.ts
/**
* Generic interface for pub/sub messaging.
* Gives you the ability to create topics and subscribers.
* This module provides only a memory implementation of the topic provider.
*
* @see {@link $topic}
* @see {@link $subscriber}
* @module alepha.topic
*/
declare const AlephaTopic: _alepha_core1.Service<_alepha_core1.Module>;
//#endregion
export { $subscriber, $topic, AlephaTopic, MemoryTopicProvider, SubscribeCallback, SubscriberDescriptor, SubscriberDescriptorOptions, TopicDescriptor, TopicDescriptorOptions, TopicHandler, TopicMessage, TopicMessageSchema, TopicProvider, TopicTimeoutError, TopicWaitOptions, UnSubscribeFn };
//# sourceMappingURL=index.d.ts.map