UNPKG

invoiceddd

Version:

Complete invoice system with domain-driven design - gateway package for easy integration

439 lines (429 loc) 18.1 kB
import { ManagedRuntime as ManagedRuntime$1 } from 'effect/ManagedRuntime'; import * as _invoiceddd_domain from '@invoiceddd/domain'; export { AllDomainEvents, BusinessRuleViolationError, CreateInvoiceData, Currency, CurrencySchema, CustomerInfo, CustomerInfoSchema, DomainEvent, InvoiceConfig as DomainInvoiceConfig, EventCategories, EventTypes, FinancialCalculationService, GermanLegalInfo, Invoice, InvoiceAggregate, InvoiceCreated, InvoiceDraftRequested, InvoiceFinancials, InvoiceNumberFormatValidator, InvoicePDFData, InvoicePDFUploaded, InvoiceValidationError, Money, MoneySchema, Order, OrderItem, OrderValidationError, PDFRenderOptions, PDFRenderer, PDFRendererSchema, ResourceError, ShippingPolicy, ShippingPolicyFreeOver50, StorageError, ValidationError, calculateGrandTotal, calculateLinePrice, calculateSubtotal, createCustomerInfo, createInvoiceFinancials, createOrder, createOrderItem, createOrderWithCalculations, sanitizeInvoicePrefix, validateCustomerInfo, validateInvoice, validateInvoiceFinancials, validateOrder, validateOrderItem } from '@invoiceddd/domain'; import * as _invoiceddd_application from '@invoiceddd/application'; export { CreateInvoiceInput, CreateInvoiceOutput, CreateInvoiceUseCase, CreateInvoiceUseCaseLive, EventBus, EventPublisher, EventPublisherLive, GetInvoiceInput, GetInvoiceOutput, GetInvoiceUseCase, GetInvoiceUseCaseLive, InvoiceDraft, InvoiceFilters, InvoiceNumberConflictError, InvoiceNumberGenerationError, InvoiceNumberGenerator, InvoiceNumberRepository, InvoiceNumberUniqueChecker, InvoiceRepository, ListInvoicesInput, ListInvoicesOutput, ListInvoicesUseCase, ListInvoicesUseCaseLive, OrderRepository, PaginatedInvoices, RequestInvoiceInput, RequestInvoiceUseCase, RequestInvoiceUseCaseLive } from '@invoiceddd/application'; import { ManagedRuntime, Layer } from 'effect'; import { LayerBuilderConfig } from './factory/layer-builder.js'; export { LayerBuilder } from './factory/layer-builder.js'; import 'effect/Layer'; /** * Database configuration */ interface DatabaseConfig { readonly url: string; readonly authToken?: string; } /** * Server configuration */ interface ServerConfig { readonly port: number; readonly host: string; } /** * Storage configuration */ interface StorageConfig { readonly endpoint: string; readonly accessKey: string; readonly secretKey: string; readonly bucket: string; } /** * Invoice configuration */ interface InvoiceConfig { readonly prefix?: string | undefined; } /** * Complete application configuration */ interface AppConfig { readonly database: DatabaseConfig; readonly server: ServerConfig; readonly storage: StorageConfig; readonly invoice: InvoiceConfig; } /** * Default configuration values. * * The following default values are used when no other configuration is provided: * - `database`: * - `url`: `"":memory:""` * - `authToken`: `""` * - `server`: * - `port`: `3000` * - `host`: `"localhost"` * - `storage`: * - `endpoint`: `""` * - `accessKey`: `""` * - `secretKey`: `""` * - `bucket`: `""` * - `invoice`: * - `prefix`: `undefined` */ declare const DEFAULT_CONFIG: AppConfig; /** * Loads the application configuration by merging default values, environment variables, and user-provided overrides. * * The configuration is resolved in the following order of precedence (highest to lowest): * 1. `userConfig` (explicit overrides) * 2. Environment configuration (from `environmentConfig`) * 3. `DEFAULT_CONFIG` (hardcoded defaults) * * ### Configuration Sections and Default Values: * - `database`: * - `url`: string (default: `DEFAULT_CONFIG.database.url`) * - `authToken`: string (default: `DEFAULT_CONFIG.database.authToken`) * - `server`: * - All properties as defined in `DEFAULT_CONFIG.server` * - `storage`: * - All properties as defined in `DEFAULT_CONFIG.storage` * - `invoice`: * - All properties as defined in `DEFAULT_CONFIG.invoice` * * @param userConfig Optional partial configuration object to override defaults and environment values. * @returns A fully merged `AppConfig` object. * * @see {@link DEFAULT_CONFIG} */ declare function loadConfigWithDefaults(userConfig?: Partial<AppConfig>): AppConfig; /** * Configuration builder for common scenarios */ declare const ConfigurationBuilder: { /** * Development configuration with in-memory database */ development: (overrides?: Partial<AppConfig>) => Partial<AppConfig>; /** * Production configuration with required environment variables */ production: (overrides?: Partial<AppConfig>) => Partial<AppConfig>; /** * Testing configuration with isolated database */ testing: (overrides?: Partial<AppConfig>) => Partial<AppConfig>; }; /** * Validate configuration completeness */ declare const validateConfig: (config: AppConfig) => { isValid: boolean; errors: string[]; }; /** * Database configuration layer that provides the database config as Effect Config */ declare const createDatabaseConfigLayer: (config: AppConfig) => Layer.Layer<never, never, never>; /** * Application use case layer. * * Provides the use-cases and all their dependencies: * * - `RequestInvoiceUseCaseLive` * - `CreateInvoiceUseCaseLive` * - `ListInvoicesUseCaseLive` * - `GetInvoiceUseCaseLive` */ declare const createApplicationUseCaseLayer: <R, E, RIn>(allDependencies: Layer.Layer<R, E, RIn>) => Layer.Layer<_invoiceddd_application.RequestInvoiceUseCase | _invoiceddd_application.CreateInvoiceUseCase | _invoiceddd_application.ListInvoicesUseCase | _invoiceddd_application.GetInvoiceUseCase, E, RIn | Exclude<_invoiceddd_application.InvoiceNumberGeneratorSchema, R> | Exclude<_invoiceddd_application.OrderRepository, R> | Exclude<_invoiceddd_domain.ShippingPolicy, R> | Exclude<_invoiceddd_application.InvoiceRepository, R> | Exclude<_invoiceddd_domain.PDFRenderer, R> | Exclude<_invoiceddd_domain.FinancialCalculationService, R> | Exclude<_invoiceddd_domain.InvoiceNumberFormatValidator, R> | Exclude<_invoiceddd_application.InvoiceNumberUniqueCheckerSchema, R> | Exclude<_invoiceddd_application.EventPublisherSchema, R>>; /** * Creates and configures the application runtime by composing all necessary dependency layers. * This is useful to ensure that all parts of the application have access to the dependencies they need, * without the need of asserting them manually. So, it is kind of a convenience. * * This function loads the application configuration (merging user-provided and default values), * initializes all required dependency layers, and combines them into a complete runtime environment. * Optionally, development tools can be enabled. * * The following layers are created and merged: * - `devToolsLayer`: Provides development tools if enabled. * - `configLayer`: Provides the merged application configuration. * - `infrastructureLayer`: Sets up core infrastructure dependencies. * - `eventInfrastructureLayer`: Handles event-driven infrastructure. * - `domainServiceLayer`: Provides domain-level services, depending on configuration. * - `domainRepositoryDependentLayer`: Domain services that depend on repositories and configuration. * - `applicationServiceLayer`: Application-level services, depending on event infrastructure. * - `eventStartupLayer`: Handles event-driven startup logic. * - `applicationUseCaseLayer`: Provides application use cases, depending on all other layers. * * The layers are merged using `Layer.mergeAll` to form the complete dependency graph. * The resulting runtime is created using `ManagedRuntime.make`. * * @param userConfig - Partial user-provided configuration to override defaults. * @param _enableDevTools - Whether to enable development tools. **NOTE**: because currently, we are re-structuring the exports, this has no effect. * @returns An object containing the `runtime` and the resolved `config`. * * @see {@link loadConfigWithDefaults} for how configuration is loaded and merged. * @see {@link createDevToolsLayer} for development tools integration. * @see {@link createConfigurationLayer} for configuration layer details. * @see {@link createInfrastructureLayer} for infrastructure setup. * @see {@link createApplicationUseCaseLayer} for use case layer composition. */ declare const createApplicationRuntime: (userConfig?: Partial<AppConfig>, _enableDevTools?: boolean) => { runtime: ManagedRuntime.ManagedRuntime<unknown, Error>; config: AppConfig; }; /** * Creates and configures a custom application runtime with user-provided layers. * * This is the recommended entry point for customizing the InvoiceDDD runtime. * Supports both array-based and LayerBuilder configuration approaches. * * **NOTE**: we don't recommend using the array-based approach, and we're going to remove it in the next versions. * The reason is that it can lead to more complex and less maintainable code compared to the LayerBuilder approach, * because it doesn't reliably express dependencies between layers. * * So, always use the layer builder approach. * * @param {Partial<AppConfig>} [userConfig={}] - Partial configuration to override defaults (e.g. database URL). * @param {readonly Layer.Layer<any, any, never>[] | LayerBuilderConfig} [customLayers=[]] - Custom layers (array) or LayerBuilder configuration that replaces defaults. * @param {boolean} [_enableDevTools=false] - Whether to enable development tools (for debugging). Currently, _this has no effect_! * @returns {Promise<{ runtime: ManagedRuntime<any>, config: AppConfig }>} The configured runtime and resolved config. * * @example <caption>Builder pattern API (recommended)</caption> * ```typescript * import { createSimpleCustomRuntime, LayerBuilder, ShippingPolicy, Layer } from "invoiceddd"; * const VIPShippingPolicy = Layer.succeed(ShippingPolicy, ShippingPolicy.of({ * isFreeShippingEligible: (financials) => Effect.succeed(financials.grandTotal.amount > 10000) * })); * const customConfig = LayerBuilder.start() * .withCustomShippingPolicy(VIPShippingPolicy) * .withCustomEventBus(MyCustomEventBus) * .build(); * const { runtime } = await createSimpleCustomRuntime( * { database: { url: "file:./custom.db" } }, * customConfig * ); * ``` * * @example <caption>Array-based API (legacy, deprecated)</caption> * ```typescript * import { createSimpleCustomRuntime, ShippingPolicy, Layer } from "invoiceddd"; * const VIPShippingPolicy = Layer.succeed(ShippingPolicy, ShippingPolicy.of({ * isFreeShippingEligible: (financials) => Effect.succeed(financials.grandTotal.amount > 10000) * })); * const customLayers = [VIPShippingPolicy]; * const { runtime } = await createSimpleCustomRuntime( * { database: { url: "file:./custom.db" } }, * customLayers * ); * ``` * */ declare const createSimpleCustomRuntime: (userConfig?: Partial<AppConfig>, customLayers?: readonly Layer.Layer<any, any, never>[] | LayerBuilderConfig, _enableDevTools?: boolean) => { runtime: ManagedRuntime.ManagedRuntime<any, any>; config: AppConfig; }; /** * @fileoverview Dynamic Layer Configuration Manager * * Provides runtime layer configuration and switching capabilities built on top * of the existing LayerBuilder infrastructure. Allows for dynamic reconfiguration * of the invoice system without requiring a full restart. */ /** * Configuration profile for different runtime scenarios */ interface LayerConfigurationProfile { readonly name: string; readonly description?: string; readonly config: LayerBuilderConfig; readonly appConfig?: Partial<AppConfig> | undefined; } /** * Manager for dynamic layer configuration and runtime switching */ declare class LayerConfigurationManager { private state; private readonly enableDevTools; constructor(enableDevTools?: boolean); /** * Initialize the configuration manager with a default profile */ initialize(defaultProfile: LayerConfigurationProfile, baseAppConfig?: Partial<AppConfig>): Promise<void>; /** * Register a new configuration profile */ registerProfile(profile: LayerConfigurationProfile): void; /** * Switch to a different configuration profile */ switchToProfile(profileName: string, baseAppConfig?: Partial<AppConfig>): Promise<void>; /** * Get the current runtime */ getCurrentRuntime<R, ER>(): ManagedRuntime.ManagedRuntime<R, ER>; /** * Get the current configuration */ getCurrentConfig(): AppConfig; /** * Get the current profile name */ getCurrentProfileName(): string; /** * List all registered profiles */ listProfiles(): LayerConfigurationProfile[]; /** * Dispose the current runtime and clean up resources */ dispose(): Promise<void>; } /** * Create a configurable runtime that can be switched between different layer configurations */ declare const createConfigurableRuntime: <R, RE>(initialProfile: LayerConfigurationProfile, baseAppConfig?: Partial<AppConfig>, enableDevTools?: boolean) => Promise<{ manager: LayerConfigurationManager; runtime: ManagedRuntime.ManagedRuntime<R, RE>; config: AppConfig; }>; /** * Helper functions for common layer composition patterns */ declare const LayerCompositionHelpers: { /** * Create a development profile with in-memory storage and mock services */ createDevelopmentProfile(name?: string): LayerConfigurationProfile; /** * Create a testing profile optimized for unit tests */ createTestingProfile(name?: string): LayerConfigurationProfile; /** * Create a production profile with real services */ createProductionProfile(name?: string, customConfig?: LayerBuilderConfig): LayerConfigurationProfile; /** * Merge multiple layer configurations */ mergeConfigurations(...configs: LayerBuilderConfig[]): LayerBuilderConfig; /** * Create a profile that extends another profile with additional layers */ extendProfile(baseProfile: LayerConfigurationProfile, extensions: Partial<LayerBuilderConfig>, newName: string, newDescription?: string): LayerConfigurationProfile; }; /** * Utility for switching between predefined layer configurations at runtime */ declare class RuntimeLayerSwitcher { private manager; private profiles; constructor(manager: LayerConfigurationManager); /** * Add a profile for runtime switching */ addProfile(profile: LayerConfigurationProfile): void; /** * Switch to a profile by name */ switchTo(profileName: string, appConfig?: Partial<AppConfig>): Promise<void>; /** * Get current profile information */ getCurrentProfile(): LayerConfigurationProfile | undefined; /** * List available profiles for switching */ getAvailableProfiles(): string[]; } /** * @fileoverview Main gateway factory for the InvoiceDDD system * * Provides easy-to-use factory functions for creating a complete invoice system * with automatic dependency injection and sensible defaults. * * @example * ```typescript * import { InvoiceSystem } from 'invoiceddd'; * * const system = await InvoiceSystem.create({ * database: { url: 'file:./invoices.db' }, * server: { port: 3000 } * }); * * const invoice = await system.createInvoice(orderData); * ``` */ interface InvoiceSystemOptions { /** Configuration for the invoice system */ config?: Partial<AppConfig>; /** Whether to auto-start the HTTP server */ autoStartServer?: boolean; /** Whether to enable development tools */ enableDevTools?: boolean; } interface InvoiceSystemInstance { /** Start the HTTP server */ startServer(): Promise<void>; /** Stop the system gracefully */ stop(): Promise<void>; /** Get the application runtime for custom operations */ getRuntime(): ManagedRuntime$1<unknown, Error>; /** Get the current configuration */ getConfig(): AppConfig; } /** * Main entry point for creating an invoice system instance */ declare const InvoiceSystem: { /** * Create a new invoice system with the provided configuration */ create: (options?: InvoiceSystemOptions) => Promise<InvoiceSystemInstance>; }; /** * @fileoverview InvoiceDDD Gateway Package * * Main entry point for the InvoiceDDD system. Provides a simplified API * for setting up and using the complete invoice domain-driven design system. * * @example * ```typescript * import { InvoiceSystem, ConfigurationBuilder } from 'invoiceddd'; * * // Quick start with defaults * const system = await InvoiceSystem.create(); * await system.startServer(); * * // Custom configuration * const system = await InvoiceSystem.create({ * config: { * database: { url: 'file:./my-invoices.db' }, * server: { port: 8080 } * } * }); * * // Development setup * const devSystem = await InvoiceSystem.create({ * config: ConfigurationBuilder.development() * }); * ``` * * @packageDocumentation * @since 0.1.5 */ /** * Main InvoiceSystem factory and types * * @example * ```typescript * import { InvoiceSystem } from 'invoiceddd'; * * const system = await InvoiceSystem.create({ * config: { * database: { url: 'file:./invoices.db' }, * server: { port: 3000 } * }, * autoStartServer: true * }); * ``` */ /** * Package version and metadata */ declare const VERSION = "0.1.5"; declare const PACKAGE_NAME = "invoiceddd"; export { type AppConfig, ConfigurationBuilder, DEFAULT_CONFIG, type DatabaseConfig, type InvoiceConfig, InvoiceSystem, type InvoiceSystemInstance, type InvoiceSystemOptions, LayerCompositionHelpers, LayerConfigurationManager, type LayerConfigurationProfile, PACKAGE_NAME, RuntimeLayerSwitcher, type ServerConfig, type StorageConfig, VERSION, createApplicationRuntime, createApplicationUseCaseLayer, createConfigurableRuntime, createDatabaseConfigLayer, createSimpleCustomRuntime, loadConfigWithDefaults, validateConfig };