import { Model } from 'mongoose'; import { AttendanceRecord, Logger, SingleTenantConfig, TargetModelConfig, AnyDocument, OperationContext } from './types.js'; /** * ClockIn Dependency Injection Container * * Simple, type-safe DI container for service management. * Each ClockIn instance has its own container - no global singletons. * * @module @classytic/clockin/core/container */ /** * Runtime options stored in container */ interface ClockInRuntimeOptions { singleTenant?: SingleTenantConfig | null; debug?: boolean; logger?: Logger; } type Factory = () => T; /** * Lightweight DI Container with type-safe accessors * * Each ClockIn instance creates its own container, avoiding global state issues * in serverless and multi-app environments. * * @example * ```typescript * const container = new Container(); * container.singleton('logger', myLogger); * container.factory('service', () => new MyService(container.get('logger'))); * * // Type-safe access for well-known keys * const logger = container.get('logger'); * * // Or use typed helper methods * const attendanceModel = container.getAttendanceModel(); * ``` */ declare class Container { private singletons; private factories; /** * Register a singleton value */ singleton(key: string, value: T): this; /** * Register a factory function (lazy instantiation) */ factory(key: string, factory: Factory): this; /** * Get a value from the container * @throws Error if key not found */ get(key: string): T; /** * Check if key exists */ has(key: string): boolean; /** * Get all registered keys */ keys(): string[]; /** * Clear all registrations */ clear(): void; /** * Get the AttendanceModel (strongly typed) * @throws Error if not registered */ getAttendanceModel(): Model; /** * Get all registered models */ getModels(): Record>; /** * Get logger */ getLogger(): Logger; /** * Get runtime options */ getOptions(): ClockInRuntimeOptions; /** * Get config registry */ getConfigRegistry(): Map; /** * Get allowed target models */ getAllowedTargetModels(): Set; /** * Check if single-tenant mode is enabled */ isSingleTenant(): boolean; /** * Get organization ID for single-tenant mode */ getOrganizationId(): string | null; } /** * ClockIn Result Type * * Rust-inspired Result for explicit error handling * No more try/catch spaghetti - errors as values * * @module @classytic/clockin/core/result */ /** Success variant */ interface Ok { readonly ok: true; readonly value: T; readonly error?: never; } /** Error variant */ interface Err { readonly ok: false; readonly error: E; readonly value?: never; } /** * Create a successful result * * @example * ```typescript * const result = ok({ checkIn, stats }); * ``` */ declare function ok(value: T): Ok; /** * Create an error result * * @example * ```typescript * const result = err(new MemberNotFoundError()); * ``` */ declare function err(error: E): Err; /** * Check if result is Ok */ declare function isOk(result: Result): result is Ok; /** * Check if result is Err */ declare function isErr(result: Result): result is Err; /** * Unwrap a result, throwing if Err * * @throws The error if result is Err */ declare function unwrap(result: Result): T; /** * Unwrap with a default value */ declare function unwrapOr(result: Result, defaultValue: T): T; /** * Unwrap with a default factory */ declare function unwrapOrElse(result: Result, fn: (error: E) => T): T; /** * Map over the Ok value */ declare function map(result: Result, fn: (value: T) => U): Result; /** * Map over the Err value */ declare function mapErr(result: Result, fn: (error: E) => F): Result; /** * Chain results (flatMap) */ declare function flatMap(result: Result, fn: (value: T) => Result): Result; /** * Wrap an async function in Result * * @example * ```typescript * const result = await tryCatch(() => fetchMember(id)); * if (isOk(result)) { * console.log(result.value); * } * ``` */ declare function tryCatch(fn: () => Promise): Promise>; /** * Synchronous version of tryCatch */ declare function tryCatchSync(fn: () => T): Result; /** * Combine multiple results into one * Returns first error or array of all values */ declare function all(results: Result[]): Result; /** * Pattern match on a result * * @example * ```typescript * const message = match(result, { * ok: (value) => `Success: ${value.id}`, * err: (error) => `Error: ${error.message}`, * }); * ``` */ declare function match(result: Result, handlers: { ok: (value: T) => U; err: (error: E) => U; }): U; /** Result type - either Ok or Err */ type Result = Ok | Err; declare const Result: { ok: typeof ok; err: typeof err; isOk: typeof isOk; isErr: typeof isErr; unwrap: typeof unwrap; unwrapOr: typeof unwrapOr; unwrapOrElse: typeof unwrapOrElse; map: typeof map; mapErr: typeof mapErr; flatMap: typeof flatMap; tryCatch: typeof tryCatch; tryCatchSync: typeof tryCatchSync; all: typeof all; match: typeof match; }; /** * Member Resolver * * Provides pluggable member resolution for bulk operations. * Allows customization of how members are looked up by identifier. * * @module @classytic/clockin/core/resolver */ /** * Member resolver interface. * * Implement this interface to customize how members are resolved by identifier * in bulk operations. * * @example * ```typescript * // Custom resolver that looks up by membership code * class MembershipCodeResolver implements MemberResolver { * constructor(private container: Container) {} * * async resolve( * identifier: string, * targetModel: string, * context: OperationContext * ): Promise { * const Model = this.container.get>('models')[targetModel]; * return Model.findOne({ * organizationId: context.organizationId, * membershipCode: identifier, * }); * } * } * ``` */ interface MemberResolver { /** * Resolve a member by identifier. * * @param identifier - User-provided identifier (email, code, id, etc.) * @param targetModel - The target model name * @param context - Operation context with organizationId, session, etc. * @returns The resolved member document, or null if not found */ resolve(identifier: string, targetModel: string, context: OperationContext): Promise; } /** * Default member resolver options. */ interface DefaultMemberResolverOptions { /** * Fields to search for the identifier, in order of priority. * * The resolver will try each field until a match is found. * * @default ['customer.email', 'email', 'membershipCode', 'employeeId', '_id'] */ identifierFields?: string[]; /** * Whether to try parsing the identifier as an ObjectId. * If true and the identifier is a valid ObjectId, it will also search by _id. * * @default true */ tryObjectId?: boolean; } /** * Default member resolver. * * Looks up members by trying multiple identifier fields in sequence. * This is the default resolver used when no custom resolver is provided. * * @example * ```typescript * const resolver = new DefaultMemberResolver(container, { * identifierFields: ['membershipCode', 'customer.email', 'email'], * }); * * const member = await resolver.resolve('MEM-001', 'Membership', context); * ``` */ declare class DefaultMemberResolver implements MemberResolver { private container; private options; constructor(container: Container, options?: DefaultMemberResolverOptions); /** * Get model from container (supports multi-connection setups) */ private getModel; /** * Check if a string is a valid ObjectId. */ private isValidObjectId; resolve(identifier: string, targetModel: string, context: OperationContext): Promise; } /** * Composite resolver that tries multiple resolvers in sequence. * * Useful when you have multiple resolution strategies. * * @example * ```typescript * const resolver = new CompositeResolver([ * new MembershipCodeResolver(container), * new EmailResolver(container), * new DefaultMemberResolver(container), * ]); * ``` */ declare class CompositeResolver implements MemberResolver { private resolvers; constructor(resolvers: MemberResolver[]); resolve(identifier: string, targetModel: string, context: OperationContext): Promise; } /** * Factory function to create a resolver based on configuration. * * @param container - DI container * @param options - Resolver options * @returns Configured member resolver */ declare function createResolver(container: Container, options?: DefaultMemberResolverOptions): MemberResolver; export { Container as C, DefaultMemberResolver as D, type Err as E, type MemberResolver as M, type Ok as O, Result as R, isErr as a, unwrapOr as b, unwrapOrElse as c, mapErr as d, err as e, flatMap as f, tryCatchSync as g, all as h, isOk as i, match as j, CompositeResolver as k, createResolver as l, map as m, type DefaultMemberResolverOptions as n, ok as o, tryCatch as t, unwrap as u };