@fyrestack/database 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["ctx: TransactionContext","ctx: BatchContext","mappedIssues: ValidationIssue[]","firestoreAdapter: FirestoreAdapter | null","state: ChunkedBatchState","trackedBatch: WriteBatch","result: RepositoryHooks","result: ModelHooks","DEFAULT_TIMESTAMPS: TimestampsConfig","DEFAULT_AUDIT: Omit<AuditConfig, 'getCurrentUserId'>","DEFAULT_STATUS: StatusConfig","validatedProps: object","result: Record<string, unknown>","mappedIssues: ValidationIssue[]","path: string[]","config: TimestampsConfig","result: string","model","result: Record<string, unknown>","context: RepositoryHookContext","result: Model | null","queryRef: QueryReference<Model>","model","updateData: Record<string, unknown>","innerRepo: InnerRepository<Model, Path>","currentMethods: MethodsDict"],"sources":["../src/context.ts","../src/errors.ts","../src/firestore.types.ts","../src/batch.ts","../src/model.hooks.ts","../src/model.metadata.ts","../src/model.types.ts","../src/model.ts","../src/model.with-schema.ts","../src/model.with-timestamps.ts","../src/repository.helpers.ts","../src/repository.ts","../src/repository.with-methods.ts","../src/transaction.ts"],"sourcesContent":["/**\n * Async Context for FyreStack Database Operations\n *\n * Uses AsyncLocalStorage to automatically propagate transaction/batch\n * context through async call stacks without explicit parameter passing.\n *\n * - Node.js: Uses native `AsyncLocalStorage` for proper parallel isolation\n * - Browser: Uses a lightweight shim (note: parallel async isolation is limited)\n *\n * This enables a clean API:\n * ```typescript\n * await runTransaction(async () => {\n * // Context is automatically available to all repository methods\n * const user = await UserRepo.get({}, userId);\n * await UserRepo.update({}, userId, { balance: user.balance - 100 });\n * });\n * ```\n */\nimport type { Transaction, WriteBatch } from './firestore.types';\n\n// =============================================================================\n// ENVIRONMENT DETECTION\n// =============================================================================\n\n/**\n * Detect if we're running in Node.js environment\n */\nconst isNode =\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n typeof process !== 'undefined' && process.versions != null && process.versions.node != null;\n\n// =============================================================================\n// ASYNC LOCAL STORAGE IMPLEMENTATION\n// =============================================================================\n\n/**\n * Interface for AsyncLocalStorage-like implementations.\n */\ninterface IAsyncLocalStorage<T> {\n run<R>(store: T, callback: () => R): R;\n getStore(): T | undefined;\n}\n\n/**\n * Browser shim for AsyncLocalStorage.\n * Note: This implementation has limited support for parallel async operations.\n * In browsers, parallel context isolation may not work correctly.\n * For full isolation, use Node.js with native AsyncLocalStorage.\n */\nclass AsyncLocalStorageShim<T> implements IAsyncLocalStorage<T> {\n private _store: T | undefined = undefined;\n private _stack: (T | undefined)[] = [];\n\n run<R>(store: T, callback: () => R): R {\n this._stack.push(this._store);\n this._store = store;\n\n try {\n const result = callback();\n\n // If callback returns a promise, restore after it settles\n if (result && typeof (result as unknown as Promise<unknown>).then === 'function') {\n return (result as unknown as Promise<unknown>).finally(() => {\n this._store = this._stack.pop();\n }) as R;\n }\n\n // Synchronous completion - restore immediately\n this._store = this._stack.pop();\n return result;\n } catch (error) {\n // Synchronous error - restore and rethrow\n this._store = this._stack.pop();\n throw error;\n }\n }\n\n getStore(): T | undefined {\n return this._store;\n }\n}\n\n/**\n * Get the AsyncLocalStorage implementation.\n * Uses native AsyncLocalStorage in Node.js, falls back to shim in browsers.\n */\nfunction getAsyncLocalStorageClass<T>(): new () => IAsyncLocalStorage<T> {\n if (isNode) {\n try {\n // In Node.js, we can use the native AsyncLocalStorage\n // We need to hide the require call from bundlers to avoid them adding Node.js polyfills\n // Using indirect eval to construct the require call at runtime\n // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-eval\n const dynamicRequire = eval('typeof require !== \"undefined\" ? require : undefined') as NodeRequire | undefined;\n if (dynamicRequire) {\n const asyncHooks = dynamicRequire('async_hooks') as typeof import('async_hooks');\n return asyncHooks.AsyncLocalStorage as unknown as new () => IAsyncLocalStorage<T>;\n }\n } catch {\n // Fall through to shim if require fails\n }\n }\n return AsyncLocalStorageShim as unknown as new () => IAsyncLocalStorage<T>;\n}\n\n// =============================================================================\n// CONTEXT TYPES\n// =============================================================================\n\n/**\n * Transaction context - supports reads and writes.\n */\nexport interface TransactionContext {\n readonly type: 'transaction';\n readonly tx: Transaction;\n}\n\n/**\n * Batch context - write-only operations.\n */\nexport interface BatchContext {\n readonly type: 'batch';\n readonly batch: WriteBatch;\n}\n\n/**\n * Union of all operation contexts.\n */\nexport type OperationContext = TransactionContext | BatchContext;\n\n// =============================================================================\n// ASYNC CONTEXT VARIABLE\n// =============================================================================\n\n/**\n * The async context storage that holds the current operation context.\n * This propagates automatically through async/await chains.\n */\nconst AsyncLocalStorageClass = getAsyncLocalStorageClass<OperationContext | undefined>();\nconst operationContext = new AsyncLocalStorageClass();\n\n// =============================================================================\n// CONTEXT GETTERS\n// =============================================================================\n\n/**\n * Get the current operation context, if any.\n * Returns undefined when not inside a transaction or batch.\n */\nexport function getCurrentContext(): OperationContext | undefined {\n return operationContext.getStore();\n}\n\n/**\n * Check if we're currently inside a transaction.\n */\nexport function isInTransaction(): boolean {\n const ctx = operationContext.getStore();\n return ctx?.type === 'transaction';\n}\n\n/**\n * Check if we're currently inside a batch.\n */\nexport function isInBatch(): boolean {\n const ctx = operationContext.getStore();\n return ctx?.type === 'batch';\n}\n\n/**\n * Get the current transaction, if inside one.\n * Returns undefined when not in a transaction.\n */\nexport function getCurrentTransaction(): Transaction | undefined {\n const ctx = operationContext.getStore();\n return ctx?.type === 'transaction' ? ctx.tx : undefined;\n}\n\n/**\n * Get the current batch, if inside one.\n * Returns undefined when not in a batch.\n */\nexport function getCurrentBatch(): WriteBatch | undefined {\n const ctx = operationContext.getStore();\n return ctx?.type === 'batch' ? ctx.batch : undefined;\n}\n\n// =============================================================================\n// CONTEXT RUNNERS\n// =============================================================================\n\n/**\n * Run a function within a transaction context.\n * @internal Used by runTransaction()\n */\nexport function runWithTransaction<T>(tx: Transaction, fn: () => Promise<T>): Promise<T> {\n const ctx: TransactionContext = { type: 'transaction', tx };\n // Return the Promise directly without async/await to preserve the Promise chain\n // This is critical for Firebase Admin SDK which requires the callback to return a Promise\n return operationContext.run(ctx, fn);\n}\n\n/**\n * Run a function within a batch context.\n * @internal Used by writeBatch()\n */\nexport function runWithBatch<T>(batch: WriteBatch, fn: () => Promise<T>): Promise<T> {\n const ctx: BatchContext = { type: 'batch', batch };\n // Return the Promise directly without async/await to preserve the Promise chain\n return operationContext.run(ctx, fn);\n}\n\n// =============================================================================\n// TYPE GUARDS\n// =============================================================================\n\n/**\n * Type guard for transaction context.\n */\nexport function isTransactionContext(ctx?: OperationContext): ctx is TransactionContext {\n return ctx?.type === 'transaction';\n}\n\n/**\n * Type guard for batch context.\n */\nexport function isBatchContext(ctx?: OperationContext): ctx is BatchContext {\n return ctx?.type === 'batch';\n}\n","/**\n * FyreStack Custom Error Types\n *\n * Provides typed errors for better error handling and debugging.\n */\n\n/**\n * Base error class for all FyreStack errors.\n */\nexport class FyreStackError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = 'FyreStackError';\n this.code = code;\n // Maintains proper stack trace in V8 environments\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error thrown when validation fails.\n */\nexport class ValidationError extends FyreStackError {\n readonly issues: ValidationIssue[];\n\n constructor(message: string, issues: ValidationIssue[] = []) {\n super(message, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n this.issues = issues;\n }\n\n /**\n * Create a ValidationError from Standard Schema validation issues.\n */\n static fromStandardSchema(issues: readonly StandardSchemaIssue[]): ValidationError {\n const mappedIssues: ValidationIssue[] = issues.map((issue) => ({\n path: issue.path?.map((p) => (typeof p === 'object' ? String(p.key) : String(p))) ?? [],\n message: issue.message,\n }));\n\n const message =\n mappedIssues.length > 0 && mappedIssues[0] !== undefined\n ? mappedIssues.length === 1\n ? mappedIssues[0].message\n : `Validation failed with ${String(mappedIssues.length)} issues`\n : 'Validation failed';\n\n return new ValidationError(message, mappedIssues);\n }\n}\n\n/**\n * Validation issue structure.\n */\nexport interface ValidationIssue {\n /** Path to the invalid field (e.g., ['address', 'zip']) */\n path: string[];\n /** Human-readable error message */\n message: string;\n}\n\n/**\n * Standard Schema issue structure (subset of StandardSchemaV1).\n * Compatible with the path types from @standard-schema/spec.\n */\ninterface StandardSchemaIssue {\n message: string;\n path?: ReadonlyArray<PropertyKey | { key: PropertyKey }> | undefined;\n}\n\n/**\n * Error thrown when path parameters are invalid.\n */\nexport class PathParamError extends FyreStackError {\n readonly paramName: string;\n readonly paramValue: string;\n\n constructor(paramName: string, paramValue: string, reason: string) {\n super(`Invalid path parameter \"${paramName}\": ${reason}`, 'PATH_PARAM_ERROR');\n this.name = 'PathParamError';\n this.paramName = paramName;\n this.paramValue = paramValue;\n }\n}\n\n/**\n * Error thrown when Firestore adapter is not initialized.\n */\nexport class AdapterNotInitializedError extends FyreStackError {\n constructor() {\n super(\n 'Firestore adapter not initialized. Call setFirestoreAdapter() before using repositories.',\n 'ADAPTER_NOT_INITIALIZED',\n );\n this.name = 'AdapterNotInitializedError';\n }\n}\n\n/**\n * Error thrown when a model is missing required properties.\n */\nexport class ModelError extends FyreStackError {\n constructor(message: string) {\n super(message, 'MODEL_ERROR');\n this.name = 'ModelError';\n }\n}\n\n/**\n * Error thrown when a document is not found.\n */\nexport class NotFoundError extends FyreStackError {\n readonly documentPath: string;\n\n constructor(documentPath: string) {\n super(`Document not found: ${documentPath}`, 'NOT_FOUND');\n this.name = 'NotFoundError';\n this.documentPath = documentPath;\n }\n}\n\n/**\n * Error thrown when a Firestore operation fails.\n */\nexport class FirestoreError extends FyreStackError {\n readonly originalError: unknown;\n\n constructor(message: string, originalError: unknown) {\n super(message, 'FIRESTORE_ERROR');\n this.name = 'FirestoreError';\n this.originalError = originalError;\n }\n\n /**\n * Wrap a Firestore error with context.\n */\n static wrap(operation: string, error: unknown): FirestoreError {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return new FirestoreError(`Firestore ${operation} failed: ${message}`, error);\n }\n}\n\n/**\n * Validation result type for type-safe validation handling.\n */\nexport type ValidationResult<T> =\n | { valid: true; value: T }\n | { valid: false; error: ValidationError };\n\n/**\n * Helper to check if a ValidationResult is valid.\n */\nexport function isValidResult<T>(result: ValidationResult<T>): result is { valid: true; value: T } {\n return result.valid;\n}\n","/**\n * Abstract Firestore types for dependency injection.\n * Allows switching between firebase-admin and client-side firebase.\n */\nimport { AdapterNotInitializedError } from './errors';\n\n/**\n * Sentinel type for server-generated timestamps.\n * This is a branded type that represents Firebase's serverTimestamp() value.\n */\nexport interface ServerTimestampSentinel {\n /** Brand to distinguish from other objects */\n readonly __type__: 'serverTimestamp';\n}\n\n/**\n * Type guard to check if a value is a ServerTimestampSentinel.\n * Note: This checks the runtime structure, not the brand.\n */\nexport function isServerTimestamp(value: unknown): value is ServerTimestampSentinel {\n return (\n value !== null &&\n typeof value === 'object' &&\n '__type__' in value &&\n value.__type__ === 'serverTimestamp'\n );\n}\n\n/**\n * Abstract document snapshot\n */\nexport interface DocumentSnapshot<T = unknown> {\n id: string;\n exists: boolean;\n data(): T | undefined;\n}\n\n/**\n * Abstract document reference\n */\nexport interface DocumentReference<T = unknown> {\n id: string;\n path: string;\n /** Native reference for transaction/batch operations (internal use) */\n _native?: unknown;\n get(): Promise<DocumentSnapshot<T>>;\n set(data: T): Promise<void>;\n update(data: Record<string, unknown>): Promise<void>;\n delete(): Promise<void>;\n}\n\n/**\n * Abstract query snapshot\n */\nexport interface QuerySnapshot<T = unknown> {\n docs: DocumentSnapshot<T>[];\n empty: boolean;\n size: number;\n}\n\n/**\n * Supported Firestore operators\n */\nexport type WhereFilterOp =\n | '<'\n | '<='\n | '=='\n | '!='\n | '>='\n | '>'\n | 'array-contains'\n | 'array-contains-any'\n | 'in'\n | 'not-in';\n\n/**\n * Sort direction\n */\nexport type OrderByDirection = 'asc' | 'desc';\n\n/**\n * Abstract query reference - chainable query builder\n */\nexport interface QueryReference<T = unknown> {\n where(field: string, op: WhereFilterOp, value: unknown): QueryReference<T>;\n orderBy(field: string, direction?: OrderByDirection): QueryReference<T>;\n limit(count: number): QueryReference<T>;\n startAt(...values: unknown[]): QueryReference<T>;\n startAfter(...values: unknown[]): QueryReference<T>;\n endAt(...values: unknown[]): QueryReference<T>;\n endBefore(...values: unknown[]): QueryReference<T>;\n get(): Promise<QuerySnapshot<T>>;\n}\n\n/**\n * Abstract collection reference\n */\nexport interface CollectionReference<T = unknown> extends QueryReference<T> {\n path: string;\n doc(id?: string): DocumentReference<T>;\n}\n\n// =============================================================================\n// TRANSACTION & BATCH TYPES\n// =============================================================================\n\n/**\n * Options for running a transaction.\n */\nexport interface TransactionOptions {\n /** Maximum retry attempts on contention (default: 5) */\n maxAttempts?: number;\n}\n\n/**\n * Firestore Transaction handle for atomic read-write operations.\n * All reads must happen before writes within a transaction.\n */\nexport interface Transaction {\n /**\n * Read a document within the transaction.\n */\n get<T>(docRef: DocumentReference<T>): Promise<DocumentSnapshot<T>>;\n\n /**\n * Set a document within the transaction.\n */\n set<T>(docRef: DocumentReference<T>, data: T): Transaction;\n\n /**\n * Update a document within the transaction.\n */\n update(docRef: DocumentReference, data: Record<string, unknown>): Transaction;\n\n /**\n * Delete a document within the transaction.\n */\n delete(docRef: DocumentReference): Transaction;\n}\n\n/**\n * Firestore WriteBatch handle for atomic write-only operations.\n * Up to 500 operations per batch.\n */\nexport interface WriteBatch {\n /**\n * Set a document in the batch.\n */\n set<T>(docRef: DocumentReference<T>, data: T): WriteBatch;\n\n /**\n * Update a document in the batch.\n */\n update(docRef: DocumentReference, data: Record<string, unknown>): WriteBatch;\n\n /**\n * Delete a document in the batch.\n */\n delete(docRef: DocumentReference): WriteBatch;\n\n /**\n * Commit all batched operations atomically.\n */\n commit(): Promise<void>;\n}\n\n// =============================================================================\n// FIRESTORE ADAPTER\n// =============================================================================\n\n/**\n * Abstract Firestore instance - the main DI interface\n */\nexport interface FirestoreAdapter {\n collection<T = unknown>(path: string): CollectionReference<T>;\n doc<T = unknown>(path: string): DocumentReference<T>;\n\n /**\n * Returns a sentinel value for server-generated timestamp.\n * Used for createdAt/updatedAt fields.\n *\n * Note: Returns the actual Firebase sentinel value which is cast to\n * ServerTimestampSentinel for type safety. The runtime value is\n * Firebase's internal FieldValue/serverTimestamp implementation.\n */\n serverTimestamp(): ServerTimestampSentinel;\n\n /**\n * Run a transaction with automatic retry on conflicts.\n * @param updateFn - Function receiving Transaction object\n * @param options - Transaction options (maxAttempts, etc.)\n */\n runTransaction<T>(\n updateFn: (transaction: Transaction) => Promise<T>,\n options?: TransactionOptions,\n ): Promise<T>;\n\n /**\n * Create a new write batch.\n */\n batch(): WriteBatch;\n}\n\n/**\n * Global Firestore adapter instance holder\n */\nlet firestoreAdapter: FirestoreAdapter | null = null;\n\n/**\n * Set the Firestore adapter to use (call once at app initialization)\n */\nexport function setFirestoreAdapter(adapter: FirestoreAdapter): void {\n firestoreAdapter = adapter;\n}\n\n/**\n * Get the current Firestore adapter\n * @throws AdapterNotInitializedError if adapter not initialized\n */\nexport function getFirestoreAdapter(): FirestoreAdapter {\n if (!firestoreAdapter) {\n throw new AdapterNotInitializedError();\n }\n return firestoreAdapter;\n}\n\n/**\n * Reset the Firestore adapter (for testing only)\n * @internal\n */\nexport function _resetFirestoreAdapter(): void {\n firestoreAdapter = null;\n}\n","/**\n * Batch Write Support for FyreStack Database\n *\n * Provides atomic write-only operations across multiple repositories.\n * Context is automatically propagated using AsyncContext.\n */\nimport { runWithBatch } from './context';\nimport { type WriteBatch, getFirestoreAdapter } from './firestore.types';\n\n/**\n * Maximum operations per Firestore batch.\n */\nexport const MAX_BATCH_SIZE = 500;\n\n/**\n * Run operations within a write batch.\n *\n * Batches provide:\n * - Atomic writes (all succeed or all fail)\n * - Better performance than individual writes\n * - Up to 500 operations per batch\n * - Works across multiple repositories\n *\n * The batch context is **automatically propagated** to all repository\n * methods called within the batch function - no need to pass context explicitly.\n *\n * Note: Batches are write-only. Use `runTransaction` if you need reads.\n *\n * @example\n * ```typescript\n * // Bulk create users\n * await writeBatch(async () => {\n * for (const user of users) {\n * await UserRepo.save({}, user);\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Cross-repository batch write\n * await writeBatch(async () => {\n * await UserRepo.save({}, user);\n * await ProfileRepo.save({ userId: user.id }, profile);\n * await AuditRepo.save({}, auditLog);\n * });\n * ```\n *\n * @param fn - Async function to run within the batch\n */\nexport async function writeBatch(fn: () => Promise<void>): Promise<void> {\n const adapter = getFirestoreAdapter();\n const batch = adapter.batch();\n\n await runWithBatch(batch, fn);\n await batch.commit();\n}\n\n/**\n * Batch state for tracking operations in chunked batches.\n */\ninterface ChunkedBatchState {\n batch: WriteBatch;\n operationCount: number;\n}\n\n/**\n * Run operations with automatic batch chunking for large datasets.\n *\n * Automatically commits and creates new batches when exceeding 500 operations.\n * Useful for migrations or bulk imports with thousands of records.\n *\n * The batch context is **automatically propagated** to all repository\n * methods called within the function.\n *\n * @example\n * ```typescript\n * // Process 10,000 records with automatic batching\n * await writeChunkedBatch(async () => {\n * for (const user of thousandsOfUsers) {\n * await UserRepo.save({}, user);\n * // Automatically commits every 500 operations\n * }\n * });\n * ```\n *\n * @param fn - Function to run with automatic batch chunking\n */\nexport async function writeChunkedBatch(fn: () => Promise<void>): Promise<void> {\n const adapter = getFirestoreAdapter();\n\n const state: ChunkedBatchState = {\n batch: adapter.batch(),\n operationCount: 0,\n };\n\n const flushIfNeeded = async (): Promise<void> => {\n if (state.operationCount >= MAX_BATCH_SIZE) {\n await state.batch.commit();\n state.batch = adapter.batch();\n state.operationCount = 0;\n }\n };\n\n // Create a proxy batch that tracks operations and auto-flushes\n const trackedBatch: WriteBatch = {\n set(docRef, data) {\n state.batch.set(docRef, data);\n state.operationCount++;\n void flushIfNeeded();\n return trackedBatch;\n },\n update(docRef, data) {\n state.batch.update(docRef, data);\n state.operationCount++;\n void flushIfNeeded();\n return trackedBatch;\n },\n delete(docRef) {\n state.batch.delete(docRef);\n state.operationCount++;\n void flushIfNeeded();\n return trackedBatch;\n },\n async commit() {\n // Final commit handled below\n },\n };\n\n await runWithBatch(trackedBatch, fn);\n\n // Commit any remaining operations\n if (state.operationCount > 0) {\n await state.batch.commit();\n }\n}\n","/**\n * Model Hooks System\n *\n * Provides a flexible plugin architecture for model and repository features.\n * Features can register hooks that are called during model/repository lifecycle.\n *\n * This allows for extensible, user-defined features without hardcoding\n * specific behaviors into the core model or repository implementation.\n */\nimport type { Type } from '@fyrestack/core';\n\nimport type { FirestoreAdapter } from './firestore.types';\n\n// =============================================================================\n// HOOK CONTEXT\n// =============================================================================\n\n/**\n * Context passed to repository hooks during operations.\n * Provides access to the adapter, model info, and operation details.\n */\nexport interface RepositoryHookContext {\n /** The Firestore adapter for accessing Firebase functionality */\n adapter: FirestoreAdapter;\n /** The model class being operated on */\n modelClass: Type<unknown>;\n /** The collection path template */\n path: string;\n /** The resolved path parameters */\n params: Record<string, string>;\n /** The document ID (if applicable) */\n id?: string;\n}\n\n/**\n * Context passed to model hooks during construction/validation.\n */\nexport interface ModelHookContext {\n /** The model class being constructed */\n modelClass: Type<unknown>;\n}\n\n// =============================================================================\n// MODEL HOOKS\n// =============================================================================\n\n/**\n * Hooks that can be registered for model lifecycle events.\n */\nexport interface ModelHooks {\n /**\n * Called during model construction, can transform props.\n * @param props - The properties being assigned to the model\n * @param context - Model context\n * @returns Transformed props\n */\n onConstruct?: (\n props: Record<string, unknown>,\n context: ModelHookContext,\n ) => Record<string, unknown>;\n\n /**\n * Called during model validation.\n * Can throw ValidationError to fail validation.\n * @param data - The data being validated\n * @param context - Model context\n */\n onValidate?: (data: unknown, context: ModelHookContext) => void;\n}\n\n// =============================================================================\n// REPOSITORY HOOKS\n// =============================================================================\n\n/**\n * Hooks that can be registered for repository operations.\n * Hooks can transform data or perform side effects.\n */\nexport interface RepositoryHooks {\n /**\n * Called before save operation.\n * Can modify the data being saved.\n * @param data - The data to be saved\n * @param context - Repository context with adapter access\n * @returns Modified data (or original if unchanged)\n */\n beforeSave?: (\n data: Record<string, unknown>,\n context: RepositoryHookContext,\n ) => Record<string, unknown>;\n\n /**\n * Called after save operation completes successfully.\n * @param data - The data that was saved\n * @param context - Repository context\n */\n afterSave?: (data: Record<string, unknown>, context: RepositoryHookContext) => void;\n\n /**\n * Called before update operation.\n * Can modify the update data (dot-notation fields).\n * @param updates - The update data\n * @param context - Repository context with adapter access\n * @returns Modified updates (or original if unchanged)\n */\n beforeUpdate?: (\n updates: Record<string, unknown>,\n context: RepositoryHookContext,\n ) => Record<string, unknown>;\n\n /**\n * Called after update operation completes successfully.\n * @param updates - The update data that was applied\n * @param context - Repository context\n */\n afterUpdate?: (updates: Record<string, unknown>, context: RepositoryHookContext) => void;\n\n /**\n * Called before delete operation.\n * Can throw to prevent deletion.\n * @param context - Repository context\n */\n beforeDelete?: (context: RepositoryHookContext) => void;\n\n /**\n * Called after delete operation completes successfully.\n * @param context - Repository context\n */\n afterDelete?: (context: RepositoryHookContext) => void;\n\n /**\n * Called after get operation, can transform the result.\n * @param data - The fetched data (or null if not found)\n * @param context - Repository context\n * @returns Transformed data\n */\n afterGet?: (\n data: Record<string, unknown> | null,\n context: RepositoryHookContext,\n ) => Record<string, unknown> | null;\n\n /**\n * Called after find operation, can transform results.\n * @param data - Array of fetched documents\n * @param context - Repository context\n * @returns Transformed array\n */\n afterFind?: (\n data: Record<string, unknown>[],\n context: RepositoryHookContext,\n ) => Record<string, unknown>[];\n}\n\n// =============================================================================\n// COMBINED HOOKS\n// =============================================================================\n\n/**\n * Combined hooks for both model and repository lifecycle.\n */\nexport interface FeatureHooks {\n /** Hooks for model lifecycle events */\n model?: ModelHooks;\n /** Hooks for repository operations */\n repository?: RepositoryHooks;\n}\n\n// =============================================================================\n// HOOK UTILITIES\n// =============================================================================\n\n/**\n * Merge multiple repository hooks into a single hooks object.\n * When multiple hooks define the same method, they are chained in order.\n */\nexport function mergeRepositoryHooks(\n ...hooksList: (RepositoryHooks | undefined)[]\n): RepositoryHooks {\n const filtered = hooksList.filter((h): h is RepositoryHooks => h !== undefined);\n\n if (filtered.length === 0) return {};\n if (filtered.length === 1) return filtered[0] ?? {};\n\n const result: RepositoryHooks = {};\n\n const beforeSave = chainDataHooks(filtered.map((h) => h.beforeSave));\n if (beforeSave) result.beforeSave = beforeSave;\n\n const afterSave = chainVoidHooks(filtered.map((h) => h.afterSave));\n if (afterSave) result.afterSave = afterSave;\n\n const beforeUpdate = chainDataHooks(filtered.map((h) => h.beforeUpdate));\n if (beforeUpdate) result.beforeUpdate = beforeUpdate;\n\n const afterUpdate = chainVoidHooks(filtered.map((h) => h.afterUpdate));\n if (afterUpdate) result.afterUpdate = afterUpdate;\n\n const beforeDelete = chainVoidHooksNoData(filtered.map((h) => h.beforeDelete));\n if (beforeDelete) result.beforeDelete = beforeDelete;\n\n const afterDelete = chainVoidHooksNoData(filtered.map((h) => h.afterDelete));\n if (afterDelete) result.afterDelete = afterDelete;\n\n const afterGet = chainNullableDataHooks(filtered.map((h) => h.afterGet));\n if (afterGet) result.afterGet = afterGet;\n\n const afterFind = chainArrayDataHooks(filtered.map((h) => h.afterFind));\n if (afterFind) result.afterFind = afterFind;\n\n return result;\n}\n\n/**\n * Merge multiple model hooks into a single hooks object.\n */\nexport function mergeModelHooks(...hooksList: (ModelHooks | undefined)[]): ModelHooks {\n const filtered = hooksList.filter((h): h is ModelHooks => h !== undefined);\n\n if (filtered.length === 0) return {};\n if (filtered.length === 1) return filtered[0] ?? {};\n\n const result: ModelHooks = {};\n\n const onConstruct = chainModelDataHooks(filtered.map((h) => h.onConstruct));\n if (onConstruct) result.onConstruct = onConstruct;\n\n const onValidate = chainModelVoidHooks(filtered.map((h) => h.onValidate));\n if (onValidate) result.onValidate = onValidate;\n\n return result;\n}\n\n/**\n * Merge feature hooks (combines both model and repository hooks).\n */\nexport function mergeFeatureHooks(...hooksList: (FeatureHooks | undefined)[]): FeatureHooks {\n const filtered = hooksList.filter((h): h is FeatureHooks => h !== undefined);\n\n if (filtered.length === 0) return {};\n\n return {\n model: mergeModelHooks(...filtered.map((h) => h.model)),\n repository: mergeRepositoryHooks(...filtered.map((h) => h.repository)),\n };\n}\n\n// =============================================================================\n// INTERNAL CHAINING UTILITIES\n// =============================================================================\n\ntype DataHook = (\n data: Record<string, unknown>,\n context: RepositoryHookContext,\n) => Record<string, unknown>;\ntype VoidHook = (data: Record<string, unknown>, context: RepositoryHookContext) => void;\ntype VoidHookNoData = (context: RepositoryHookContext) => void;\ntype NullableDataHook = (\n data: Record<string, unknown> | null,\n context: RepositoryHookContext,\n) => Record<string, unknown> | null;\ntype ArrayDataHook = (\n data: Record<string, unknown>[],\n context: RepositoryHookContext,\n) => Record<string, unknown>[];\ntype ModelDataHook = (\n props: Record<string, unknown>,\n context: ModelHookContext,\n) => Record<string, unknown>;\ntype ModelVoidHook = (data: unknown, context: ModelHookContext) => void;\n\nfunction chainDataHooks(hooks: (DataHook | undefined)[]): DataHook | undefined {\n const filtered = hooks.filter((h): h is DataHook => h !== undefined);\n if (filtered.length === 0) return undefined;\n if (filtered.length === 1) return filtered[0];\n\n return (data, context) => {\n let result = data;\n for (const hook of filtered) {\n result = hook(result, context);\n }\n return result;\n };\n}\n\nfunction chainVoidHooks(hooks: (VoidHook | undefined)[]): VoidHook | undefined {\n const filtered = hooks.filter((h): h is VoidHook => h !== undefined);\n if (filtered.length === 0) return undefined;\n if (filtered.length === 1) return filtered[0];\n\n return (data, context) => {\n for (const hook of filtered) {\n hook(data, context);\n }\n };\n}\n\nfunction chainVoidHooksNoData(hooks: (VoidHookNoData | undefined)[]): VoidHookNoData | undefined {\n const filtered = hooks.filter((h): h is VoidHookNoData => h !== undefined);\n if (filtered.length === 0) return undefined;\n if (filtered.length === 1) return filtered[0];\n\n return (context) => {\n for (const hook of filtered) {\n hook(context);\n }\n };\n}\n\nfunction chainNullableDataHooks(\n hooks: (NullableDataHook | undefined)[],\n): NullableDataHook | undefined {\n const filtered = hooks.filter((h): h is NullableDataHook => h !== undefined);\n if (filtered.length === 0) return undefined;\n if (filtered.length === 1) return filtered[0];\n\n return (data, context) => {\n let result = data;\n for (const hook of filtered) {\n result = hook(result, context);\n }\n return result;\n };\n}\n\nfunction chainArrayDataHooks(hooks: (ArrayDataHook | undefined)[]): ArrayDataHook | undefined {\n const filtered = hooks.filter((h): h is ArrayDataHook => h !== undefined);\n if (filtered.length === 0) return undefined;\n if (filtered.length === 1) return filtered[0];\n\n return (data, context) => {\n let result = data;\n for (const hook of filtered) {\n result = hook(result, context);\n }\n return result;\n };\n}\n\nfunction chainModelDataHooks(hooks: (ModelDataHook | undefined)[]): ModelDataHook | undefined {\n const filtered = hooks.filter((h): h is ModelDataHook => h !== undefined);\n if (filtered.length === 0) return undefined;\n if (filtered.length === 1) return filtered[0];\n\n return (props, context) => {\n let result = props;\n for (const hook of filtered) {\n result = hook(result, context);\n }\n return result;\n };\n}\n\nfunction chainModelVoidHooks(hooks: (ModelVoidHook | undefined)[]): ModelVoidHook | undefined {\n const filtered = hooks.filter((h): h is ModelVoidHook => h !== undefined);\n if (filtered.length === 0) return undefined;\n if (filtered.length === 1) return filtered[0];\n\n return (data, context) => {\n for (const hook of filtered) {\n hook(data, context);\n }\n };\n}\n","/**\n * Model Metadata System\n *\n * This module provides a metadata system for model features.\n * Features register hooks that are invoked during model/repository lifecycle.\n *\n * The hooks system allows for extensible, user-defined features without\n * hardcoding specific behaviors into the core implementation.\n */\nimport type { FeatureHooks, ModelHooks, RepositoryHooks } from './model.hooks';\nimport { mergeFeatureHooks } from './model.hooks';\n\n// =============================================================================\n// CORE METADATA TYPES\n// =============================================================================\n\n/**\n * Symbol used to store metadata on model classes.\n * Using a symbol prevents conflicts with user-defined properties.\n */\nexport const MODEL_METADATA = Symbol.for('fyrestack.model.metadata');\n\n/**\n * Model metadata containing registered feature hooks.\n * This is stored on the model class and read by repositories.\n */\nexport interface ModelMetadata {\n /**\n * Combined hooks from all registered features.\n */\n hooks?: FeatureHooks;\n\n /**\n * Feature-specific configuration data.\n * Features can store their config here for introspection.\n */\n features?: Record<string, unknown>;\n}\n\n// =============================================================================\n// METADATA UTILITIES\n// =============================================================================\n\n/**\n * Get metadata from a model class.\n */\nexport function getModelMetadata(ModelClass: unknown): ModelMetadata | undefined {\n if (ModelClass !== null && typeof ModelClass === 'function' && MODEL_METADATA in ModelClass) {\n return (ModelClass as Record<symbol, ModelMetadata>)[MODEL_METADATA];\n }\n return undefined;\n}\n\n/**\n * Get repository hooks from a model class.\n */\nexport function getRepositoryHooks(ModelClass: unknown): RepositoryHooks | undefined {\n return getModelMetadata(ModelClass)?.hooks?.repository;\n}\n\n/**\n * Get model hooks from a model class.\n */\nexport function getModelHooks(ModelClass: unknown): ModelHooks | undefined {\n return getModelMetadata(ModelClass)?.hooks?.model;\n}\n\n/**\n * Check if a model has any repository hooks registered.\n */\nexport function hasRepositoryHooks(ModelClass: unknown): boolean {\n const hooks = getRepositoryHooks(ModelClass);\n return hooks !== undefined && Object.keys(hooks).length > 0;\n}\n\n/**\n * Check if a model has a specific feature registered.\n */\nexport function hasFeature(ModelClass: unknown, featureName: string): boolean {\n const metadata = getModelMetadata(ModelClass);\n return metadata?.features?.[featureName] !== undefined;\n}\n\n/**\n * Get configuration for a specific feature.\n */\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters\nexport function getFeatureConfig<T>(ModelClass: unknown, featureName: string): T | undefined {\n const metadata = getModelMetadata(ModelClass);\n return metadata?.features?.[featureName] as T | undefined;\n}\n\n// =============================================================================\n// METADATA BUILDING UTILITIES (for feature authors)\n// =============================================================================\n\n/**\n * Create metadata for a feature.\n * Used by feature functions like withTimestamps() to build metadata.\n *\n * @param featureName - Unique name for the feature\n * @param config - Feature-specific configuration (for introspection)\n * @param hooks - Hooks to register\n * @param existingMetadata - Existing metadata to merge with\n */\nexport function createFeatureMetadata(\n featureName: string,\n config: unknown,\n hooks: FeatureHooks,\n existingMetadata?: ModelMetadata,\n): ModelMetadata {\n return {\n hooks: mergeFeatureHooks(existingMetadata?.hooks, hooks),\n features: {\n ...existingMetadata?.features,\n [featureName]: config,\n },\n };\n}\n\n// =============================================================================\n// TIMESTAMP FEATURE TYPES\n// =============================================================================\n\n/**\n * Configuration for automatic timestamp management.\n */\nexport interface TimestampsConfig {\n /**\n * Field name for creation timestamp.\n * Set to `false` to disable.\n * @default 'createdAt'\n */\n createdAt: string | false;\n\n /**\n * Field name for last update timestamp.\n * Set to `false` to disable.\n * @default 'updatedAt'\n */\n updatedAt: string | false;\n\n /**\n * Whether to use Firestore serverTimestamp() for accuracy.\n * When false, uses client-side Date.\n * @default true\n */\n useServerTimestamp: boolean;\n}\n\n/**\n * User-provided options for configuring timestamps.\n * All fields are optional with sensible defaults.\n */\nexport interface TimestampsOptions {\n /**\n * Field name for creation timestamp, or `false` to disable.\n * @default 'createdAt'\n */\n createdAt?: string | false;\n\n /**\n * Field name for last update timestamp, or `false` to disable.\n * @default 'updatedAt'\n */\n updatedAt?: string | false;\n\n /**\n * Whether to use Firestore serverTimestamp().\n * @default true\n */\n useServerTimestamp?: boolean;\n}\n\n/**\n * Default timestamp configuration.\n */\nexport const DEFAULT_TIMESTAMPS: TimestampsConfig = {\n createdAt: 'createdAt',\n updatedAt: 'updatedAt',\n useServerTimestamp: true,\n};\n\n// =============================================================================\n// AUDIT FEATURE TYPES (for future implementation)\n// =============================================================================\n\n/**\n * Configuration for audit trail management.\n * Tracks which user created/modified documents.\n */\nexport interface AuditConfig {\n /**\n * Field name for creator user ID.\n * Set to `false` to disable.\n * @default 'createdBy'\n */\n createdBy: string | false;\n\n /**\n * Field name for last modifier user ID.\n * Set to `false` to disable.\n * @default 'updatedBy'\n */\n updatedBy: string | false;\n\n /**\n * Function to get the current user ID.\n * Must be provided when using audit feature.\n */\n getCurrentUserId: () => string | null;\n}\n\n/**\n * User-provided options for configuring audit trail.\n */\nexport interface AuditOptions {\n createdBy?: string | false;\n updatedBy?: string | false;\n getCurrentUserId: () => string | null;\n}\n\n/**\n * Default audit configuration.\n */\nexport const DEFAULT_AUDIT: Omit<AuditConfig, 'getCurrentUserId'> = {\n createdBy: 'createdBy',\n updatedBy: 'updatedBy',\n};\n\n// =============================================================================\n// STATUS FEATURE TYPES (for future implementation)\n// =============================================================================\n\n/**\n * Configuration for status field management including soft-delete.\n */\nexport interface StatusConfig {\n /**\n * Field name for status.\n * @default 'status'\n */\n field: string;\n\n /**\n * Available status values.\n * @default ['active', 'inactive', 'deleted']\n */\n values: readonly string[];\n\n /**\n * Default status for new documents.\n * @default 'active'\n */\n defaultValue: string;\n\n /**\n * Status value that indicates soft-deletion.\n * When set, delete operations will set this status instead of hard-deleting.\n * @default 'deleted'\n */\n deletedValue: string | false;\n\n /**\n * Field name for deletion timestamp (when soft-delete is enabled).\n * @default 'deletedAt'\n */\n deletedAt: string | false;\n}\n\n/**\n * User-provided options for configuring status.\n */\nexport interface StatusOptions {\n field?: string;\n values?: readonly string[];\n defaultValue?: string;\n deletedValue?: string | false;\n deletedAt?: string | false;\n}\n\n/**\n * Default status configuration.\n */\nexport const DEFAULT_STATUS: StatusConfig = {\n field: 'status',\n values: ['active', 'inactive', 'deleted'] as const,\n defaultValue: 'active',\n deletedValue: 'deleted',\n deletedAt: 'deletedAt',\n};\n\n// =============================================================================\n// CONVENIENCE FUNCTIONS\n// =============================================================================\n\n/**\n * Check if a model has timestamps feature.\n */\nexport function hasTimestamps(ModelClass: unknown): boolean {\n return hasFeature(ModelClass, 'timestamps');\n}\n\n/**\n * Get timestamps configuration from a model class.\n */\nexport function getTimestampsConfig(ModelClass: unknown): TimestampsConfig | undefined {\n return getFeatureConfig<TimestampsConfig>(ModelClass, 'timestamps');\n}\n\n/**\n * Check if a model has audit feature.\n */\nexport function hasAudit(ModelClass: unknown): boolean {\n return hasFeature(ModelClass, 'audit');\n}\n\n/**\n * Get audit configuration from a model class.\n */\nexport function getAuditConfig(ModelClass: unknown): AuditConfig | undefined {\n return getFeatureConfig<AuditConfig>(ModelClass, 'audit');\n}\n\n/**\n * Check if a model has status feature.\n */\nexport function hasStatus(ModelClass: unknown): boolean {\n return hasFeature(ModelClass, 'status');\n}\n\n/**\n * Get status configuration from a model class.\n */\nexport function getStatusConfig(ModelClass: unknown): StatusConfig | undefined {\n return getFeatureConfig<StatusConfig>(ModelClass, 'status');\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\n\nimport type { Type } from '@fyrestack/core';\n\nimport { type ValidationResult } from './errors';\nimport type { ModelMetadata } from './model.metadata';\n\n/**\n * Symbol for storing the schema on model instances (internal use).\n */\nexport const MODEL_SCHEMA = Symbol.for('fyrestack.model.schema');\n\n/**\n * Infer the instance type from a Model class.\n * @example\n * const UserModel = model(withSchema(UserSchema));\n * type User = InferModel<typeof UserModel>;\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type InferModel<T extends Type<any>> = InstanceType<T>;\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport type MethodsDictionary = Record<string, Function>;\n\nexport type InnerModel<\n Schema extends StandardSchemaV1 = StandardSchemaV1,\n Props extends object = object,\n Methods extends MethodsDictionary = MethodsDictionary,\n Metadata extends ModelMetadata | undefined = ModelMetadata | undefined,\n> = {\n schema: Schema;\n props: Props;\n methods: Methods;\n _metadata?: Metadata;\n};\n\nexport type ModelFeatureResult = {\n schema: StandardSchemaV1;\n props: object;\n methods: MethodsDictionary;\n _metadata?: ModelMetadata;\n};\n\nexport type ModelFeature<\n Input extends ModelFeatureResult = ModelFeatureResult,\n Output extends ModelFeatureResult = ModelFeatureResult,\n> = (\n store: InnerModel<Input['schema'], Input['props'], Input['methods'], Input['_metadata']>,\n) => InnerModel<Output['schema'], Output['props'], Output['methods'], Output['_metadata']>;\n\n// Empty feature result for the initial store\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type EmptyFeatureResult = ModelFeatureResult & { props: {}; methods: {} };\n\n/**\n * Interface for model instances with validation methods.\n */\nexport interface ModelInstance<T = unknown> {\n /**\n * Validate the current model data.\n * @returns ValidationResult with either the validated value or error\n */\n validate(): ValidationResult<T>;\n\n /**\n * Check if the model data is valid.\n * @returns true if valid, false otherwise\n */\n isValid(): boolean;\n\n /**\n * Convert model to a plain object (for Firestore writes).\n * Excludes methods, keeps only data properties.\n */\n toObject(): T;\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\n\nimport type { OmitPrivate, Prettify, Type } from '@fyrestack/core';\n\nimport { ValidationError, type ValidationIssue, type ValidationResult } from './errors';\nimport type { ModelMetadata } from './model.metadata';\nimport { MODEL_METADATA } from './model.metadata';\nimport type {\n EmptyFeatureResult,\n InnerModel,\n ModelFeature,\n ModelFeatureResult,\n} from './model.types';\nimport { MODEL_SCHEMA } from './model.types';\n\ntype ModelMembers<FeatureResult extends ModelFeatureResult> = Prettify<\n OmitPrivate<FeatureResult['props'] & FeatureResult['methods']>\n>;\n\n// Overloads for 1-9 features\nexport function model<F1 extends ModelFeatureResult>(\n f1: ModelFeature<EmptyFeatureResult, F1>,\n): Type<ModelMembers<F1>>;\nexport function model<\n F1 extends ModelFeatureResult,\n F2 extends ModelFeatureResult,\n R extends ModelFeatureResult = F1 & F2,\n>(f1: ModelFeature<EmptyFeatureResult, F1>, f2: ModelFeature<{} & F1, F2>): Type<ModelMembers<R>>;\nexport function model<\n F1 extends ModelFeatureResult,\n F2 extends ModelFeatureResult,\n F3 extends ModelFeatureResult,\n R extends ModelFeatureResult = F1 & F2 & F3,\n>(\n f1: ModelFeature<EmptyFeatureResult, F1>,\n f2: ModelFeature<{} & F1, F2>,\n f3: ModelFeature<F1 & F2, F3>,\n): Type<ModelMembers<R>>;\nexport function model<\n F1 extends ModelFeatureResult,\n F2 extends ModelFeatureResult,\n F3 extends ModelFeatureResult,\n F4 extends ModelFeatureResult,\n R extends ModelFeatureResult = F1 & F2 & F3 & F4,\n>(\n f1: ModelFeature<EmptyFeatureResult, F1>,\n f2: ModelFeature<{} & F1, F2>,\n f3: ModelFeature<F1 & F2, F3>,\n f4: ModelFeature<F1 & F2 & F3, F4>,\n): Type<ModelMembers<R>>;\nexport function model<\n F1 extends ModelFeatureResult,\n F2 extends ModelFeatureResult,\n F3 extends ModelFeatureResult,\n F4 extends ModelFeatureResult,\n F5 extends ModelFeatureResult,\n R extends ModelFeatureResult = F1 & F2 & F3 & F4 & F5,\n>(\n f1: ModelFeature<EmptyFeatureResult, F1>,\n f2: ModelFeature<{} & F1, F2>,\n f3: ModelFeature<F1 & F2, F3>,\n f4: ModelFeature<F1 & F2 & F3, F4>,\n f5: ModelFeature<F1 & F2 & F3 & F4, F5>,\n): Type<ModelMembers<R>>;\nexport function model<\n F1 extends ModelFeatureResult,\n F2 extends ModelFeatureResult,\n F3 extends ModelFeatureResult,\n F4 extends ModelFeatureResult,\n F5 extends ModelFeatureResult,\n F6 extends ModelFeatureResult,\n R extends ModelFeatureResult = F1 & F2 & F3 & F4 & F5 & F6,\n>(\n f1: ModelFeature<EmptyFeatureResult, F1>,\n f2: ModelFeature<{} & F1, F2>,\n f3: ModelFeature<F1 & F2, F3>,\n f4: ModelFeature<F1 & F2 & F3, F4>,\n f5: ModelFeature<F1 & F2 & F3 & F4, F5>,\n f6: ModelFeature<F1 & F2 & F3 & F4 & F5, F6>,\n): Type<ModelMembers<R>>;\nexport function model<\n F1 extends ModelFeatureResult,\n F2 extends ModelFeatureResult,\n F3 extends ModelFeatureResult,\n F4 extends ModelFeatureResult,\n F5 extends ModelFeatureResult,\n F6 extends ModelFeatureResult,\n F7 extends ModelFeatureResult,\n R extends ModelFeatureResult = F1 & F2 & F3 & F4 & F5 & F6 & F7,\n>(\n f1: ModelFeature<EmptyFeatureResult, F1>,\n f2: ModelFeature<{} & F1, F2>,\n f3: ModelFeature<F1 & F2, F3>,\n f4: ModelFeature<F1 & F2 & F3, F4>,\n f5: ModelFeature<F1 & F2 & F3 & F4, F5>,\n f6: ModelFeature<F1 & F2 & F3 & F4 & F5, F6>,\n f7: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6, F7>,\n): Type<ModelMembers<R>>;\nexport function model<\n F1 extends ModelFeatureResult,\n F2 extends ModelFeatureResult,\n F3 extends ModelFeatureResult,\n F4 extends ModelFeatureResult,\n F5 extends ModelFeatureResult,\n F6 extends ModelFeatureResult,\n F7 extends ModelFeatureResult,\n F8 extends ModelFeatureResult,\n R extends ModelFeatureResult = F1 & F2 & F3 & F4 & F5 & F6 & F7 & F8,\n>(\n f1: ModelFeature<EmptyFeatureResult, F1>,\n f2: ModelFeature<{} & F1, F2>,\n f3: ModelFeature<F1 & F2, F3>,\n f4: ModelFeature<F1 & F2 & F3, F4>,\n f5: ModelFeature<F1 & F2 & F3 & F4, F5>,\n f6: ModelFeature<F1 & F2 & F3 & F4 & F5, F6>,\n f7: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6, F7>,\n f8: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6 & F7, F8>,\n): Type<ModelMembers<R>>;\nexport function model<\n F1 extends ModelFeatureResult,\n F2 extends ModelFeatureResult,\n F3 extends ModelFeatureResult,\n F4 extends ModelFeatureResult,\n F5 extends ModelFeatureResult,\n F6 extends ModelFeatureResult,\n F7 extends ModelFeatureResult,\n F8 extends ModelFeatureResult,\n F9 extends ModelFeatureResult,\n R extends ModelFeatureResult = F1 & F2 & F3 & F4 & F5 & F6 & F7 & F8 & F9,\n>(\n f1: ModelFeature<EmptyFeatureResult, F1>,\n f2: ModelFeature<{} & F1, F2>,\n f3: ModelFeature<F1 & F2, F3>,\n f4: ModelFeature<F1 & F2 & F3, F4>,\n f5: ModelFeature<F1 & F2 & F3 & F4, F5>,\n f6: ModelFeature<F1 & F2 & F3 & F4 & F5, F6>,\n f7: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6, F7>,\n f8: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6 & F7, F8>,\n f9: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6 & F7 & F8, F9>,\n): Type<ModelMembers<R>>;\n\n// Implementation signature\nexport function model(\n ...features: ModelFeature[]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Type<ModelMembers<any>> {\n // Pre-compute the schema from features (done once at model definition time)\n const innerStore = features.reduce((store, feature) => feature(store), getInitialInnerStore());\n const modelSchema = innerStore.schema;\n const modelMethods = innerStore.methods;\n\n class Model {\n // Static metadata property (will be set after class definition)\n static [MODEL_METADATA]: ModelMetadata | undefined;\n\n // Instance schema reference for validation\n private readonly [MODEL_SCHEMA]: StandardSchemaV1;\n\n constructor(data?: unknown) {\n this[MODEL_SCHEMA] = modelSchema;\n\n // Validate and parse the input data using the schema\n let validatedProps: object = {};\n if (data !== undefined && data !== null) {\n if ('~standard' in modelSchema) {\n const result = modelSchema['~standard'].validate(data);\n if ('issues' in result && result.issues) {\n // Validation failed - throw explicit error\n throw toValidationError(result.issues);\n }\n if ('value' in result) {\n validatedProps = result.value as object;\n }\n } else {\n // No schema validation, use data as-is\n validatedProps = data as object;\n }\n }\n\n // Assign validated props to the instance\n for (const [key, value] of Object.entries(validatedProps)) {\n (this as Record<string, unknown>)[key] = value;\n }\n\n // Assign methods to the instance\n for (const [key, method] of Object.entries(modelMethods)) {\n (this as Record<string, unknown>)[key] = method;\n }\n }\n\n /**\n * Validate the current model data against the schema.\n * @returns ValidationResult with validated value or error\n */\n validate(): ValidationResult<unknown> {\n const schema = this[MODEL_SCHEMA];\n const data = this.toObject();\n\n if (!('~standard' in schema)) {\n return { valid: true, value: data };\n }\n\n const result = schema['~standard'].validate(data);\n\n if ('issues' in result && result.issues) {\n return {\n valid: false,\n error: toValidationError(result.issues),\n };\n }\n\n if ('value' in result) {\n return { valid: true, value: result.value };\n }\n\n return { valid: true, value: data };\n }\n\n /**\n * Check if the current model data is valid.\n * @returns true if valid, false otherwise\n */\n isValid(): boolean {\n return this.validate().valid;\n }\n\n /**\n * Convert model instance to a plain object (excludes methods).\n * Used for Firestore writes and serialization.\n */\n toObject(): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const key of Object.keys(this)) {\n const value = (this as Record<string, unknown>)[key];\n // Exclude functions (methods) and symbols\n if (typeof value !== 'function') {\n result[key] = value;\n }\n }\n\n return result;\n }\n }\n\n // Extract metadata from the final feature store and attach to Model class\n const metadata = (innerStore as { _metadata?: ModelMetadata })._metadata;\n if (metadata) {\n Model[MODEL_METADATA] = metadata;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return Model as Type<ModelMembers<any>>;\n}\n\nfunction getInitialInnerStore(): InnerModel {\n return {\n schema: {} as StandardSchemaV1,\n props: {},\n methods: {},\n };\n}\n\n/**\n * Convert Standard Schema issues to ValidationIssues.\n * Handles various path formats from different schema libraries.\n */\nfunction toValidationError(\n issues: readonly { message: string; path?: unknown }[],\n): ValidationError {\n const mappedIssues: ValidationIssue[] = issues.map((issue) => {\n let path: string[] = [];\n if (Array.isArray(issue.path)) {\n path = issue.path.map((p: unknown) => {\n if (typeof p === 'string' || typeof p === 'number' || typeof p === 'symbol') {\n return String(p);\n }\n if (p !== null && typeof p === 'object' && 'key' in p) {\n return String((p as { key: unknown }).key);\n }\n return String(p);\n });\n }\n return { path, message: issue.message };\n });\n\n const message =\n mappedIssues.length > 0 && mappedIssues[0] !== undefined\n ? mappedIssues.length === 1\n ? mappedIssues[0].message\n : `Validation failed with ${String(mappedIssues.length)} issues`\n : 'Validation failed';\n\n return new ValidationError(message, mappedIssues);\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\n\nimport type { EmptyFeatureResult, ModelFeature } from './model.types';\n\nexport function withSchema<S extends StandardSchemaV1>(\n schema: S,\n): ModelFeature<\n EmptyFeatureResult,\n {\n schema: S;\n props: StandardSchemaV1.InferOutput<S> & object;\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n methods: {};\n }\n> {\n return (store) => ({\n schema,\n props: {} as StandardSchemaV1.InferOutput<S> & object,\n methods: store.methods,\n });\n}\n","/**\n * Model Features for Automatic Field Management\n *\n * This module provides composable model features that integrate with\n * the repository layer for automatic field management.\n *\n * Features use the hook system to register lifecycle hooks without\n * hardcoding behavior into the repository implementation.\n */\nimport type { RepositoryHookContext, RepositoryHooks } from './model.hooks';\nimport {\n DEFAULT_TIMESTAMPS,\n type ModelMetadata,\n type TimestampsConfig,\n type TimestampsOptions,\n createFeatureMetadata,\n} from './model.metadata';\nimport type { InnerModel, ModelFeature, ModelFeatureResult } from './model.types';\n\n// =============================================================================\n// TIMESTAMP TYPES\n// =============================================================================\n\n/**\n * Firestore Timestamp interface - matches both firebase/firestore and firebase-admin/firestore.\n * This allows strict typing without coupling to a specific Firebase SDK.\n */\nexport interface FirestoreTimestamp {\n readonly seconds: number;\n readonly nanoseconds: number;\n toDate(): Date;\n toMillis(): number;\n}\n\n/**\n * Possible values for a timestamp field on a model instance:\n * - `Date` - after conversion from Firestore\n * - `FirestoreTimestamp` - raw Firestore Timestamp before conversion\n * - `undefined` - if not yet set\n */\nexport type TimestampValue = Date | FirestoreTimestamp | undefined;\n\n/**\n * Timestamp props type - added to model by withTimestamps.\n */\nexport type TimestampProps<\n CreatedField extends string | false = 'createdAt',\n UpdatedField extends string | false = 'updatedAt',\n> = (CreatedField extends string ? { [K in CreatedField]?: TimestampValue } : object) &\n (UpdatedField extends string ? { [K in UpdatedField]?: TimestampValue } : object);\n\n/**\n * Output type for withTimestamps feature - includes metadata\n */\ntype WithTimestampsOutput<Input extends ModelFeatureResult> = {\n schema: Input['schema'];\n props: Input['props'] & TimestampProps;\n methods: Input['methods'];\n _metadata: ModelMetadata;\n};\n\n// =============================================================================\n// TIMESTAMPS HOOK IMPLEMENTATION\n// =============================================================================\n\n/**\n * Create repository hooks for timestamp management.\n * This is the core implementation extracted into hooks.\n */\nfunction createTimestampsHooks(config: TimestampsConfig): RepositoryHooks {\n return {\n beforeSave(data: Record<string, unknown>, context: RepositoryHookContext) {\n const timestamp = config.useServerTimestamp ? context.adapter.serverTimestamp() : new Date();\n\n // Set createdAt if field is enabled and not already set\n if (\n config.createdAt !== false &&\n (data[config.createdAt] === undefined || data[config.createdAt] === null)\n ) {\n data[config.createdAt] = timestamp;\n }\n\n // Set updatedAt if field is enabled\n if (config.updatedAt !== false) {\n data[config.updatedAt] = timestamp;\n }\n\n return data;\n },\n\n beforeUpdate(updates: Record<string, unknown>, context: RepositoryHookContext) {\n // Set updatedAt if field is enabled\n if (config.updatedAt !== false) {\n const timestamp = config.useServerTimestamp\n ? context.adapter.serverTimestamp()\n : new Date();\n updates[config.updatedAt] = timestamp;\n }\n\n return updates;\n },\n };\n}\n\n// =============================================================================\n// WITH TIMESTAMPS FEATURE\n// =============================================================================\n\n/**\n * Add automatic timestamp management to a model.\n *\n * This feature registers hooks that:\n * - Set `createdAt` on save (if not already set)\n * - Set `updatedAt` on save and update\n *\n * @example\n * ```typescript\n * // Basic usage with defaults (createdAt, updatedAt)\n * const UserModel = model(\n * withSchema(UserSchema),\n * withTimestamps(),\n * );\n *\n * // Custom field names\n * const PostModel = model(\n * withSchema(PostSchema),\n * withTimestamps({ createdAt: 'publishedAt', updatedAt: 'modifiedAt' }),\n * );\n *\n * // Disable one field\n * const LogModel = model(\n * withSchema(LogSchema),\n * withTimestamps({ updatedAt: false }), // Only track creation\n * );\n *\n * // Use client-side timestamps (for offline support)\n * const OfflineModel = model(\n * withSchema(OfflineSchema),\n * withTimestamps({ useServerTimestamp: false }),\n * );\n * ```\n *\n * @param options - Optional configuration for field names and behavior\n */\nexport function withTimestamps<Input extends ModelFeatureResult>(\n options?: TimestampsOptions,\n): ModelFeature<Input, WithTimestampsOutput<Input>> {\n // Build configuration with defaults\n const config: TimestampsConfig = {\n createdAt: options?.createdAt ?? DEFAULT_TIMESTAMPS.createdAt,\n updatedAt: options?.updatedAt ?? DEFAULT_TIMESTAMPS.updatedAt,\n useServerTimestamp: options?.useServerTimestamp ?? DEFAULT_TIMESTAMPS.useServerTimestamp,\n };\n\n // Create hooks for this feature\n const hooks = createTimestampsHooks(config);\n\n return (\n store,\n ): InnerModel<\n Input['schema'],\n Input['props'] & TimestampProps,\n Input['methods'],\n ModelMetadata\n > => {\n // Build metadata using the feature metadata utility\n const newMetadata = createFeatureMetadata(\n 'timestamps',\n config,\n { repository: hooks },\n store._metadata,\n );\n\n return {\n schema: store.schema,\n props: store.props as Input['props'] & TimestampProps,\n methods: store.methods,\n _metadata: newMetadata,\n };\n };\n}\n","/**\n * Composable Repository Implementation for Firestore\n */\nimport { ModelError, PathParamError, ValidationError } from './errors';\nimport type { QueryReference } from './firestore.types';\nimport type { ExtractPathParams, TypedQueryBuilder } from './repository.types';\n\n// =============================================================================\n// TYPED QUERY BUILDER IMPLEMENTATION\n// =============================================================================\n\nexport function createTypedQueryBuilder<T>(\n queryRef: QueryReference<T>,\n): TypedQueryBuilder<T> & { _queryRef: QueryReference<T> } {\n return {\n where(field, op, value) {\n return createTypedQueryBuilder(queryRef.where(field as string, op, value));\n },\n orderBy(field, direction) {\n return createTypedQueryBuilder(queryRef.orderBy(field as string, direction));\n },\n limit(count) {\n return createTypedQueryBuilder(queryRef.limit(count));\n },\n startAt(...values: unknown[]) {\n return createTypedQueryBuilder(queryRef.startAt(...values));\n },\n startAfter(...values: unknown[]) {\n return createTypedQueryBuilder(queryRef.startAfter(...values));\n },\n endAt(...values: unknown[]) {\n return createTypedQueryBuilder(queryRef.endAt(...values));\n },\n endBefore(...values: unknown[]) {\n return createTypedQueryBuilder(queryRef.endBefore(...values));\n },\n _queryRef: queryRef,\n };\n}\n\nexport function getQueryRef<T>(builder: TypedQueryBuilder<T>): QueryReference<T> {\n return (builder as TypedQueryBuilder<T> & { _queryRef: QueryReference<T> })._queryRef;\n}\n\n// =============================================================================\n// PATH UTILITIES\n// =============================================================================\n\n/**\n * Regex for valid path parameter values.\n * Allows alphanumeric characters, underscores, and hyphens.\n */\nconst VALID_PATH_PARAM_REGEX = /^[a-zA-Z0-9_-]+$/;\n\n/**\n * Validate a single path parameter value.\n * @throws PathParamError if the value is invalid\n */\nexport function validatePathParam(paramName: string, value: string): void {\n if (!value || value.length === 0) {\n throw new PathParamError(paramName, value, 'cannot be empty');\n }\n\n if (value.includes('/')) {\n throw new PathParamError(paramName, value, 'cannot contain forward slashes');\n }\n\n if (value.includes('..')) {\n throw new PathParamError(paramName, value, 'cannot contain path traversal (..)');\n }\n\n if (value.includes('\\0')) {\n throw new PathParamError(paramName, value, 'cannot contain null bytes');\n }\n\n if (!VALID_PATH_PARAM_REGEX.test(value)) {\n throw new PathParamError(\n paramName,\n value,\n 'must only contain alphanumeric characters, underscores, or hyphens',\n );\n }\n}\n\n/**\n * Build a collection path from template and params.\n * Validates all path parameters before building.\n * @throws PathParamError if any parameter is invalid\n */\nexport function buildCollectionPath<Path extends string>(\n pathTemplate: Path,\n params: ExtractPathParams<Path>,\n): string {\n let result: string = pathTemplate;\n\n for (const [key, value] of Object.entries(params as Record<string, string>)) {\n validatePathParam(key, value);\n result = result.replace(`{${key}}`, value);\n }\n\n return result;\n}\n\n/**\n * Extract model ID from model instance or string.\n * @throws ModelError if the model doesn't have a valid ID\n */\nexport function extractId(modelOrId: unknown): string {\n if (typeof modelOrId === 'string') {\n if (!modelOrId) {\n throw new ModelError('Document ID cannot be empty');\n }\n return modelOrId;\n }\n\n if (\n modelOrId !== null &&\n typeof modelOrId === 'object' &&\n 'id' in modelOrId &&\n typeof modelOrId.id === 'string'\n ) {\n if (!modelOrId.id) {\n throw new ModelError('Model ID cannot be empty');\n }\n return modelOrId.id;\n }\n\n throw new ModelError('Model must have a string \"id\" property');\n}\n\n// =============================================================================\n// MODEL TYPE GUARDS\n// =============================================================================\n\n/**\n * Interface for models with a validate() method.\n */\nexport interface Validatable {\n validate(): { valid: boolean; error?: ValidationError };\n}\n\n/**\n * Interface for models with a toObject() method.\n */\nexport interface HasToObject {\n toObject(): Record<string, unknown>;\n}\n\n/**\n * Type guard to check if a model has a validate() method.\n */\nexport function isValidatable(model: object): model is Validatable {\n return 'validate' in model && typeof (model as Validatable).validate === 'function';\n}\n\n/**\n * Type guard to check if a model has a toObject() method.\n */\nexport function hasToObject(model: object): model is HasToObject {\n return 'toObject' in model && typeof (model as HasToObject).toObject === 'function';\n}\n\n/**\n * Validate a model instance before write operations.\n * @throws ValidationError if validation fails\n */\nexport function validateModel(model: unknown): void {\n if (model === null || typeof model !== 'object') {\n throw new ValidationError('Model must be an object');\n }\n\n // Check if model has validate() method (from our Model class)\n if (isValidatable(model)) {\n const result = model.validate();\n if (!result.valid && result.error) {\n throw result.error;\n }\n }\n}\n\n/**\n * Convert model to plain object for Firestore.\n * Uses toObject() if available, otherwise spreads the object.\n */\nexport function modelToObject(model: unknown): Record<string, unknown> {\n if (model !== null && typeof model === 'object') {\n if (hasToObject(model)) {\n return model.toObject();\n }\n // Fallback: spread and filter out functions\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(model)) {\n if (typeof value !== 'function') {\n result[key] = value;\n }\n }\n return result;\n }\n throw new ModelError('Model must be an object');\n}\n","/**\n * Composable Repository Implementation for Firestore\n */\nimport type { Prettify, Type } from '@fyrestack/core';\n\nimport { getCurrentContext, isBatchContext, isTransactionContext } from './context';\nimport { FirestoreError, ModelError, PathParamError, ValidationError } from './errors';\nimport type {\n CollectionReference,\n DocumentReference,\n FirestoreAdapter,\n QueryReference,\n} from './firestore.types';\nimport { getFirestoreAdapter } from './firestore.types';\nimport type { RepositoryHookContext } from './model.hooks';\nimport { getRepositoryHooks } from './model.metadata';\nimport {\n buildCollectionPath,\n createTypedQueryBuilder,\n extractId,\n getQueryRef,\n modelToObject,\n validateModel,\n} from './repository.helpers';\nimport type {\n BaseRepositoryMethods,\n ExtractPathParams,\n FirestoreUpdate,\n InnerRepository,\n QueryFn,\n RepositoryConfig,\n RepositoryFeature,\n RepositoryFeatureResult,\n RepositoryMethodsDictionary,\n} from './repository.types';\n\n// =============================================================================\n// REPOSITORY FACTORY\n// =============================================================================\n\n// Overload: config only (no custom features)\nexport function repository<Model, Path extends string>(\n config: RepositoryConfig<Model, Path>,\n): Type<BaseRepositoryMethods<Model, Path>>;\n\n// Overload: config + 1 feature\nexport function repository<\n Model,\n Path extends string,\n F1Methods extends RepositoryMethodsDictionary,\n>(\n config: RepositoryConfig<Model, Path>,\n f1: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F1Methods>\n >,\n): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods>>;\n\n// Overload: config + 2 features\nexport function repository<\n Model,\n Path extends string,\n F1Methods extends RepositoryMethodsDictionary,\n F2Methods extends RepositoryMethodsDictionary,\n>(\n config: RepositoryConfig<Model, Path>,\n f1: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F1Methods>\n >,\n f2: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F2Methods>\n >,\n): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods>>;\n\n// Overload: config + 3 features\nexport function repository<\n Model,\n Path extends string,\n F1Methods extends RepositoryMethodsDictionary,\n F2Methods extends RepositoryMethodsDictionary,\n F3Methods extends RepositoryMethodsDictionary,\n>(\n config: RepositoryConfig<Model, Path>,\n f1: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F1Methods>\n >,\n f2: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F2Methods>\n >,\n f3: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F3Methods>\n >,\n): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods & F3Methods>>;\n\n// Overload: config + 4 features\nexport function repository<\n Model,\n Path extends string,\n F1Methods extends RepositoryMethodsDictionary,\n F2Methods extends RepositoryMethodsDictionary,\n F3Methods extends RepositoryMethodsDictionary,\n F4Methods extends RepositoryMethodsDictionary,\n>(\n config: RepositoryConfig<Model, Path>,\n f1: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F1Methods>\n >,\n f2: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F2Methods>\n >,\n f3: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F3Methods>\n >,\n f4: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F4Methods>\n >,\n): Type<\n Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods & F3Methods & F4Methods>\n>;\n\n// Overload: config + 5 features\nexport function repository<\n Model,\n Path extends string,\n F1Methods extends RepositoryMethodsDictionary,\n F2Methods extends RepositoryMethodsDictionary,\n F3Methods extends RepositoryMethodsDictionary,\n F4Methods extends RepositoryMethodsDictionary,\n F5Methods extends RepositoryMethodsDictionary,\n>(\n config: RepositoryConfig<Model, Path>,\n f1: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F1Methods>\n >,\n f2: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F2Methods>\n >,\n f3: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F3Methods>\n >,\n f4: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F4Methods>\n >,\n f5: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F5Methods>\n >,\n): Type<\n Prettify<\n BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods & F3Methods & F4Methods & F5Methods\n >\n>;\n\n// Overload: config + 6 features\nexport function repository<\n Model,\n Path extends string,\n F1Methods extends RepositoryMethodsDictionary,\n F2Methods extends RepositoryMethodsDictionary,\n F3Methods extends RepositoryMethodsDictionary,\n F4Methods extends RepositoryMethodsDictionary,\n F5Methods extends RepositoryMethodsDictionary,\n F6Methods extends RepositoryMethodsDictionary,\n>(\n config: RepositoryConfig<Model, Path>,\n f1: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F1Methods>\n >,\n f2: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F2Methods>\n >,\n f3: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F3Methods>\n >,\n f4: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F4Methods>\n >,\n f5: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F5Methods>\n >,\n f6: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F6Methods>\n >,\n): Type<\n Prettify<\n BaseRepositoryMethods<Model, Path> &\n F1Methods &\n F2Methods &\n F3Methods &\n F4Methods &\n F5Methods &\n F6Methods\n >\n>;\n\n// Overload: config + 7 features\nexport function repository<\n Model,\n Path extends string,\n F1Methods extends RepositoryMethodsDictionary,\n F2Methods extends RepositoryMethodsDictionary,\n F3Methods extends RepositoryMethodsDictionary,\n F4Methods extends RepositoryMethodsDictionary,\n F5Methods extends RepositoryMethodsDictionary,\n F6Methods extends RepositoryMethodsDictionary,\n F7Methods extends RepositoryMethodsDictionary,\n>(\n config: RepositoryConfig<Model, Path>,\n f1: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F1Methods>\n >,\n f2: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F2Methods>\n >,\n f3: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F3Methods>\n >,\n f4: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F4Methods>\n >,\n f5: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F5Methods>\n >,\n f6: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F6Methods>\n >,\n f7: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F7Methods>\n >,\n): Type<\n Prettify<\n BaseRepositoryMethods<Model, Path> &\n F1Methods &\n F2Methods &\n F3Methods &\n F4Methods &\n F5Methods &\n F6Methods &\n F7Methods\n >\n>;\n\n// Overload: config + 8 features\nexport function repository<\n Model,\n Path extends string,\n F1Methods extends RepositoryMethodsDictionary,\n F2Methods extends RepositoryMethodsDictionary,\n F3Methods extends RepositoryMethodsDictionary,\n F4Methods extends RepositoryMethodsDictionary,\n F5Methods extends RepositoryMethodsDictionary,\n F6Methods extends RepositoryMethodsDictionary,\n F7Methods extends RepositoryMethodsDictionary,\n F8Methods extends RepositoryMethodsDictionary,\n>(\n config: RepositoryConfig<Model, Path>,\n f1: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F1Methods>\n >,\n f2: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F2Methods>\n >,\n f3: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F3Methods>\n >,\n f4: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F4Methods>\n >,\n f5: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F5Methods>\n >,\n f6: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F6Methods>\n >,\n f7: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F7Methods>\n >,\n f8: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F8Methods>\n >,\n): Type<\n Prettify<\n BaseRepositoryMethods<Model, Path> &\n F1Methods &\n F2Methods &\n F3Methods &\n F4Methods &\n F5Methods &\n F6Methods &\n F7Methods &\n F8Methods\n >\n>;\n\n// Overload: config + 9 features\nexport function repository<\n Model,\n Path extends string,\n F1Methods extends RepositoryMethodsDictionary,\n F2Methods extends RepositoryMethodsDictionary,\n F3Methods extends RepositoryMethodsDictionary,\n F4Methods extends RepositoryMethodsDictionary,\n F5Methods extends RepositoryMethodsDictionary,\n F6Methods extends RepositoryMethodsDictionary,\n F7Methods extends RepositoryMethodsDictionary,\n F8Methods extends RepositoryMethodsDictionary,\n F9Methods extends RepositoryMethodsDictionary,\n>(\n config: RepositoryConfig<Model, Path>,\n f1: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F1Methods>\n >,\n f2: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F2Methods>\n >,\n f3: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F3Methods>\n >,\n f4: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F4Methods>\n >,\n f5: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F5Methods>\n >,\n f6: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F6Methods>\n >,\n f7: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F7Methods>\n >,\n f8: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F8Methods>\n >,\n f9: RepositoryFeature<\n RepositoryFeatureResult<Model, Path>,\n RepositoryFeatureResult<Model, Path, F9Methods>\n >,\n): Type<\n Prettify<\n BaseRepositoryMethods<Model, Path> &\n F1Methods &\n F2Methods &\n F3Methods &\n F4Methods &\n F5Methods &\n F6Methods &\n F7Methods &\n F8Methods &\n F9Methods\n >\n>;\n\n// Implementation\nexport function repository<Model, Path extends string>(\n config: RepositoryConfig<Model, Path>,\n ...features: RepositoryFeature[]\n): Type<BaseRepositoryMethods<Model, Path>> {\n const { path, model: ModelClass } = config;\n\n // Get hooks from model metadata (registered by features like withTimestamps)\n const hooks = getRepositoryHooks(ModelClass);\n\n class Repository {\n private getFirestore(): FirestoreAdapter {\n return getFirestoreAdapter();\n }\n\n private getCollectionRef(params: ExtractPathParams<Path>): CollectionReference<Model> {\n const collectionPath = buildCollectionPath(path, params);\n return this.getFirestore().collection<Model>(collectionPath);\n }\n\n private getDocumentRef(params: ExtractPathParams<Path>, id: string): DocumentReference<Model> {\n return this.getCollectionRef(params).doc(id);\n }\n\n /**\n * Create hook context for repository hooks.\n */\n private createHookContext(params: ExtractPathParams<Path>, id?: string): RepositoryHookContext {\n const context: RepositoryHookContext = {\n adapter: this.getFirestore(),\n modelClass: ModelClass,\n path,\n params: params as Record<string, string>,\n };\n if (id !== undefined) {\n context.id = id;\n }\n return context;\n }\n\n async get(params: ExtractPathParams<Path>, id: string): Promise<Model | null> {\n try {\n const docRef = this.getDocumentRef(params, id);\n\n // Automatically use transaction context if available\n const ctx = getCurrentContext();\n const tx = isTransactionContext(ctx) ? ctx.tx : undefined;\n const snapshot = tx ? await tx.get(docRef) : await docRef.get();\n\n if (!snapshot.exists) {\n return null;\n }\n\n const data = snapshot.data();\n if (!data) {\n return null;\n }\n\n let result: Model | null = new ModelClass({ ...data, id: snapshot.id });\n\n // Apply afterGet hooks\n if (hooks?.afterGet) {\n const context = this.createHookContext(params, id);\n result = hooks.afterGet(\n result as Record<string, unknown> | null,\n context,\n ) as Model | null;\n }\n\n return result;\n } catch (error) {\n if (error instanceof PathParamError || error instanceof ValidationError) {\n throw error;\n }\n throw FirestoreError.wrap('get', error);\n }\n }\n\n async find(params: ExtractPathParams<Path>, queryFn?: QueryFn<Model>): Promise<Model[]> {\n try {\n const collectionRef = this.getCollectionRef(params);\n\n let queryRef: QueryReference<Model> = collectionRef;\n\n if (queryFn) {\n const typedBuilder = createTypedQueryBuilder(collectionRef);\n const resultBuilder = queryFn(typedBuilder);\n queryRef = getQueryRef(resultBuilder);\n }\n\n // Note: Firestore transactions have limitations with complex queries\n // Direct queries work fine, transaction-aware queries may need individual gets\n const snapshot = await queryRef.get();\n\n let results = snapshot.docs.map((doc) => {\n const data = doc.data();\n return new ModelClass({ ...data, id: doc.id });\n });\n\n // Apply afterFind hooks\n if (hooks?.afterFind) {\n const context = this.createHookContext(params);\n results = hooks.afterFind(results as Record<string, unknown>[], context) as Model[];\n }\n\n return results;\n } catch (error) {\n if (error instanceof PathParamError || error instanceof ValidationError) {\n throw error;\n }\n throw FirestoreError.wrap('find', error);\n }\n }\n\n async save(params: ExtractPathParams<Path>, model: Model): Promise<void> {\n try {\n // Validate model before save\n validateModel(model);\n\n const id = extractId(model);\n const docRef = this.getDocumentRef(params, id);\n\n // Convert model to plain object (exclude methods)\n let data = modelToObject(model);\n\n // Apply beforeSave hooks (e.g., timestamps)\n if (hooks?.beforeSave) {\n const context = this.createHookContext(params, id);\n data = hooks.beforeSave(data, context);\n }\n\n // Automatically detect context from AsyncContext\n const ctx = getCurrentContext();\n if (isTransactionContext(ctx)) {\n ctx.tx.set(docRef, data as Model);\n } else if (isBatchContext(ctx)) {\n ctx.batch.set(docRef, data as Model);\n } else {\n await docRef.set(data as Model);\n }\n\n // Apply afterSave hooks\n if (hooks?.afterSave) {\n const context = this.createHookContext(params, id);\n hooks.afterSave(data, context);\n }\n } catch (error) {\n if (\n error instanceof PathParamError ||\n error instanceof ValidationError ||\n error instanceof ModelError\n ) {\n throw error;\n }\n throw FirestoreError.wrap('save', error);\n }\n }\n\n async update(\n params: ExtractPathParams<Path>,\n modelOrId: Model | string,\n updates: FirestoreUpdate<Model>,\n ): Promise<void> {\n try {\n const id = extractId(modelOrId);\n const docRef = this.getDocumentRef(params, id);\n\n let updateData: Record<string, unknown> = { ...updates };\n\n // Apply beforeUpdate hooks (e.g., timestamps)\n if (hooks?.beforeUpdate) {\n const context = this.createHookContext(params, id);\n updateData = hooks.beforeUpdate(updateData, context);\n }\n\n // Automatically detect context from AsyncContext\n const ctx = getCurrentContext();\n if (isTransactionContext(ctx)) {\n ctx.tx.update(docRef, updateData);\n } else if (isBatchContext(ctx)) {\n ctx.batch.update(docRef, updateData);\n } else {\n await docRef.update(updateData);\n }\n\n // Apply afterUpdate hooks\n if (hooks?.afterUpdate) {\n const context = this.createHookContext(params, id);\n hooks.afterUpdate(updateData, context);\n }\n } catch (error) {\n if (error instanceof PathParamError || error instanceof ModelError) {\n throw error;\n }\n throw FirestoreError.wrap('update', error);\n }\n }\n\n async delete(params: ExtractPathParams<Path>, modelOrId: Model | string): Promise<void> {\n try {\n const id = extractId(modelOrId);\n const docRef = this.getDocumentRef(params, id);\n\n // Apply beforeDelete hooks\n if (hooks?.beforeDelete) {\n const context = this.createHookContext(params, id);\n hooks.beforeDelete(context);\n }\n\n // Automatically detect context from AsyncContext\n const ctx = getCurrentContext();\n if (isTransactionContext(ctx)) {\n ctx.tx.delete(docRef);\n } else if (isBatchContext(ctx)) {\n ctx.batch.delete(docRef);\n } else {\n await docRef.delete();\n }\n\n // Apply afterDelete hooks\n if (hooks?.afterDelete) {\n const context = this.createHookContext(params, id);\n hooks.afterDelete(context);\n }\n } catch (error) {\n if (error instanceof PathParamError || error instanceof ModelError) {\n throw error;\n }\n throw FirestoreError.wrap('delete', error);\n }\n }\n }\n\n // Apply features to add custom methods\n if (features.length > 0) {\n const repoInstance = new Repository();\n\n const innerRepo: InnerRepository<Model, Path> = {\n model: ModelClass,\n path,\n methods: {\n get: repoInstance.get.bind(repoInstance),\n find: repoInstance.find.bind(repoInstance),\n save: repoInstance.save.bind(repoInstance),\n update: repoInstance.update.bind(repoInstance),\n delete: repoInstance.delete.bind(repoInstance),\n },\n getCollection: repoInstance['getCollectionRef'].bind(repoInstance),\n getDocument: repoInstance['getDocumentRef'].bind(repoInstance),\n };\n\n // Apply each feature to accumulate methods\n // Type assertion required due to variance in generic feature composition\n type MethodsDict = Record<string, unknown>;\n let currentMethods: MethodsDict = innerRepo.methods;\n for (const feature of features) {\n const updatedInnerRepo = { ...innerRepo, methods: currentMethods };\n currentMethods = feature(updatedInnerRepo as Parameters<typeof feature>[0]);\n }\n\n // Create a new class with all methods\n const FinalRepository = class extends Repository {\n constructor() {\n super();\n // Assign custom methods to instance\n for (const [key, method] of Object.entries(currentMethods)) {\n if (!(key in this)) {\n (this as Record<string, unknown>)[key] = method;\n }\n }\n }\n };\n\n return FinalRepository as Type<BaseRepositoryMethods<Model, Path>>;\n }\n\n return Repository as Type<BaseRepositoryMethods<Model, Path>>;\n}\n","/**\n * Composable Repository Implementation for Firestore\n */\nimport type {\n InnerRepository,\n RepositoryFeature,\n RepositoryFeatureResult,\n RepositoryMethodsDictionary,\n} from './repository.types';\n\n// =============================================================================\n// WITH METHODS FEATURE\n// =============================================================================\n\n/**\n * Add custom methods to a repository\n */\nexport function withMethods<\n Model,\n Path extends string,\n BaseMethods extends RepositoryMethodsDictionary,\n NewMethods extends RepositoryMethodsDictionary,\n>(\n methodsFactory: (repo: InnerRepository<Model, Path, BaseMethods>) => NewMethods,\n): RepositoryFeature<\n RepositoryFeatureResult<Model, Path, BaseMethods>,\n RepositoryFeatureResult<Model, Path, BaseMethods & NewMethods>\n> {\n return (repo) => {\n // Cast is needed because the feature system uses broader types internally\n const newMethods = methodsFactory(repo as InnerRepository<Model, Path, BaseMethods>);\n return { ...repo.methods, ...newMethods };\n };\n}\n","/**\n * Transaction Support for FyreStack Database\n *\n * Provides atomic read-write operations across multiple repositories.\n * Context is automatically propagated using AsyncContext.\n */\nimport { runWithTransaction } from './context';\nimport { type TransactionOptions, getFirestoreAdapter } from './firestore.types';\n\n/**\n * Run operations within a Firestore transaction.\n *\n * Transactions provide:\n * - Atomic reads and writes across multiple repositories\n * - Automatic retry on contention (up to maxAttempts)\n * - Consistent view of data (all reads see same snapshot)\n * - All-or-nothing semantics (all writes succeed or all fail)\n *\n * The transaction context is **automatically propagated** to all repository\n * methods called within the transaction function - no need to pass context explicitly.\n *\n * @example\n * ```typescript\n * // Transfer funds between accounts atomically\n * const result = await runTransaction(async () => {\n * const fromAccount = await AccountRepo.get({}, fromId);\n * const toAccount = await AccountRepo.get({}, toId);\n *\n * if (!fromAccount || !toAccount) throw new Error('Account not found');\n * if (fromAccount.balance < amount) throw new Error('Insufficient funds');\n *\n * await AccountRepo.update({}, fromId, {\n * balance: fromAccount.balance - amount\n * });\n *\n * await AccountRepo.update({}, toId, {\n * balance: toAccount.balance + amount\n * });\n *\n * return { newBalance: fromAccount.balance - amount };\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Cross-repository transaction\n * await runTransaction(async () => {\n * const order = await OrderRepo.get({}, orderId);\n * const user = await UserRepo.get({}, order.userId);\n *\n * await OrderRepo.update({}, orderId, { status: 'paid' });\n * await UserRepo.update({}, user.id, {\n * balance: user.balance - order.total\n * });\n * });\n * ```\n *\n * @param fn - Async function to run within the transaction\n * @param options - Transaction options (maxAttempts, etc.)\n * @returns Result of the transaction function\n */\nexport async function runTransaction<T>(\n fn: () => Promise<T>,\n options?: TransactionOptions,\n): Promise<T> {\n const adapter = getFirestoreAdapter();\n\n return adapter.runTransaction(async (tx) => {\n // Run the user's function with transaction context automatically set\n return runWithTransaction(tx, fn);\n }, options);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fyrestack/database",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Database library for FyreStack - make Firestore type-safe and easy to use",
5
5
  "license": "MIT",
6
6
  "author": "FyreStack",
@@ -41,7 +41,7 @@
41
41
  "dependencies": {
42
42
  "@standard-schema/spec": "^1.1.0",
43
43
  "rxjs": "~7.8.2",
44
- "@fyrestack/core": "0.1.0"
44
+ "@fyrestack/core": "0.1.2"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "@angular/core": ">=17.0.0"