{"version":3,"sources":["../../src/core/index.ts","../../src/core/types.ts","../../src/core/errors.ts","../../src/core/deferred.ts","../../src/config/index.ts","../../src/config/provider.ts","../../src/core/operations.ts"],"sourcesContent":["/**\r\n * Credits system core - framework agnostic\r\n *\r\n * This module provides the core credits functionality without any\r\n * framework-specific dependencies (no Next.js, no React, no Firebase types).\r\n *\r\n * Use this module when:\r\n * - Building non-Next.js applications\r\n * - Creating the TypeScript SDK\r\n * - Copy-pasting the credits system to other projects\r\n *\r\n * @example\r\n * ```typescript\r\n * import {\r\n *   calculateAvailableCredits,\r\n *   CreditError,\r\n *   CreditErrorCode,\r\n *   genericDeferred,\r\n * } from '@nehorai/credits/core';\r\n * ```\r\n */\r\n\r\n// ==================== Types ====================\r\nexport type {\r\n  BuiltinTier,\r\n  SubscriptionTier,\r\n  CreditOperationType,\r\n  AIProviderType,\r\n  ResourceType,\r\n  ReservationStatus,\r\n  TransactionType,\r\n  CreditSource,\r\n  JournalReferenceType,\r\n  PortableUserCredits,\r\n  PortableReservation,\r\n  PortableTransaction,\r\n  PortableJournalEntry,\r\n  PortableUsageLog,\r\n  CreditCheckResult,\r\n  MonthlyResetResult,\r\n  SubscriptionExpiryResult,\r\n  UsageHistoryEntry,\r\n  UsageHistoryResponse,\r\n  TierConfig,\r\n  WithCreditsOptions,\r\n} from \"./types.js\";\r\n\r\n// ==================== Type Utilities ====================\r\nexport {\r\n  calculateAvailableCredits,\r\n  toPortableTimestamp,\r\n  toDate,\r\n} from \"./types.js\";\r\n\r\n// ==================== Errors ====================\r\nexport type { CreditErrorCodeType } from \"./errors.js\";\r\n\r\nexport {\r\n  CreditError,\r\n  CreditErrorCode,\r\n  isCreditError,\r\n  isInsufficientCreditsError,\r\n  createInsufficientCreditsError,\r\n  createReservationNotFoundError,\r\n  createReservationExpiredError,\r\n  createReservationAlreadyProcessedError,\r\n  createUserNotFoundError,\r\n  createInvalidOperationTypeError,\r\n} from \"./errors.js\";\r\n\r\n// ==================== Deferred Execution ====================\r\nexport type { DeferredExecutor } from \"./deferred.js\";\r\n\r\nexport {\r\n  genericDeferred,\r\n  synchronousDeferred,\r\n  noopDeferred,\r\n  createDeferredExecutor,\r\n} from \"./deferred.js\";\r\n\r\n// ==================== Operations ====================\r\nexport {\r\n  commitReservationWithJournal,\r\n  releaseReservationWithJournal,\r\n  reserveCreditsForOperation,\r\n} from \"./operations.js\";\r\n","/**\r\n * Portable credits types - framework and database agnostic\r\n *\r\n * These types use standard JavaScript types (string, Date) instead of\r\n * Firebase-specific types (Timestamp). This makes the credits system\r\n * portable to other environments without Firebase dependencies.\r\n *\r\n * Note: Firestore Timestamp is handled by the credits-firestore adapter.\r\n */\r\n\r\n// ==================== Utility Functions ====================\r\n\r\n/**\r\n * Calculate available credits from balance, bonus, and reserved amounts.\r\n *\r\n * Available = balance + bonusCredits - reserved\r\n *\r\n * @param balance - Regular monthly credits\r\n * @param bonusCredits - Purchased/admin credits\r\n * @param reserved - Credits locked for in-flight operations\r\n * @returns Available credits for new operations\r\n */\r\nexport function calculateAvailableCredits(\r\n  balance: number,\r\n  bonusCredits: number,\r\n  reserved: number\r\n): number {\r\n  return balance + bonusCredits - reserved;\r\n}\r\n\r\n/**\r\n * Convert various timestamp formats to ISO string.\r\n *\r\n * Handles:\r\n * - Date objects\r\n * - ISO string (returned as-is)\r\n * - Timestamp-like objects with toDate() method (Firebase)\r\n * - undefined/null (returns current time)\r\n *\r\n * @param value - Value to convert\r\n * @returns ISO 8601 string\r\n */\r\nexport function toPortableTimestamp(value: unknown): string {\r\n  if (!value) {\r\n    return new Date().toISOString();\r\n  }\r\n\r\n  if (typeof value === \"string\") {\r\n    return value;\r\n  }\r\n\r\n  if (value instanceof Date) {\r\n    return value.toISOString();\r\n  }\r\n\r\n  if (\r\n    typeof value === \"object\" &&\r\n    value !== null &&\r\n    \"toDate\" in value &&\r\n    typeof (value as { toDate: () => Date }).toDate === \"function\"\r\n  ) {\r\n    return (value as { toDate: () => Date }).toDate().toISOString();\r\n  }\r\n\r\n  return new Date().toISOString();\r\n}\r\n\r\n/**\r\n * Convert various timestamp formats to Date object.\r\n *\r\n * Handles:\r\n * - Date objects (returned as-is)\r\n * - ISO string\r\n * - Timestamp-like objects with toDate() method (Firebase)\r\n * - Invalid values (returns current date)\r\n *\r\n * @param value - Value to convert\r\n * @returns Date object\r\n */\r\nexport function toDate(value: unknown): Date {\r\n  if (value instanceof Date) {\r\n    return value;\r\n  }\r\n\r\n  if (typeof value === \"string\") {\r\n    return new Date(value);\r\n  }\r\n\r\n  if (\r\n    typeof value === \"object\" &&\r\n    value !== null &&\r\n    \"toDate\" in value &&\r\n    typeof (value as { toDate: () => Date }).toDate === \"function\"\r\n  ) {\r\n    return (value as { toDate: () => Date }).toDate();\r\n  }\r\n\r\n  return new Date();\r\n}\r\n\r\n// ==================== Subscription Types ====================\r\n\r\n/**\r\n * Built-in tier ids (autocomplete) — apps may add more via config.\r\n */\r\nexport type BuiltinTier = \"free\" | \"basic\" | \"premium\" | \"unlimited\";\r\n\r\n/**\r\n * Subscription tiers for the credits system.\r\n *\r\n * Any built-in OR any config-defined tier id. The `(string & {})` keeps builtin\r\n * autocomplete while accepting arbitrary configured tiers.\r\n */\r\nexport type SubscriptionTier = BuiltinTier | (string & {});\r\n\r\n// ==================== Operation Types ====================\r\n\r\n/**\r\n * Operation types for cost tracking (provider-agnostic)\r\n *\r\n * Dynamic string type - any operation configured in the system is valid.\r\n */\r\nexport type CreditOperationType = string;\r\n\r\n/**\r\n * AI providers\r\n */\r\nexport type AIProviderType = \"gemini\";\r\n\r\n/**\r\n * Resource type for usage logging\r\n */\r\nexport type ResourceType = string;\r\n\r\n// ==================== User Credits ====================\r\n\r\n/**\r\n * Portable user credits balance\r\n *\r\n * Uses ISO string timestamps instead of Firebase Timestamp.\r\n * This type is safe for JSON serialization and works across frameworks.\r\n */\r\nexport interface PortableUserCredits {\r\n  userId: string;\r\n  /** Current available balance (monthly credits, reset each month) */\r\n  balance: number;\r\n  /** Bonus credits from purchases/admin (never reset, persist until used) */\r\n  bonusCredits: number;\r\n  /** Credits currently reserved for in-flight operations */\r\n  reserved: number;\r\n  /** User's subscription tier */\r\n  tier: SubscriptionTier;\r\n  /** Monthly credit limit based on tier (0 = unlimited) */\r\n  monthlyLimit: number;\r\n  /** Credits used this month (resets monthly) */\r\n  monthlyUsed: number;\r\n  /** When monthly credits reset (start of next month) - ISO 8601 */\r\n  monthlyResetAt: string;\r\n  /** Subscription expiry (null/undefined for free tier) - ISO 8601 or null */\r\n  subscriptionExpiresAt?: string | null;\r\n  /** Creation timestamp - ISO 8601 */\r\n  createdAt: string;\r\n  /** Last update timestamp - ISO 8601 */\r\n  updatedAt: string;\r\n}\r\n\r\n// ==================== Reservation Types ====================\r\n\r\n/**\r\n * Credit reservation status for two-phase commit\r\n */\r\nexport type ReservationStatus = \"reserved\" | \"committed\" | \"released\" | \"expired\";\r\n\r\n/**\r\n * Portable credit reservation\r\n *\r\n * Used for two-phase commit to prevent double-spending.\r\n */\r\nexport interface PortableReservation {\r\n  id: string;\r\n  userId: string;\r\n  /** Amount of credits reserved */\r\n  amount: number;\r\n  /** Operation type for tracking */\r\n  operationType: CreditOperationType;\r\n  /** Current status of reservation */\r\n  status: ReservationStatus;\r\n  /** When reservation was created - ISO 8601 */\r\n  createdAt: string;\r\n  /** When reservation expires (for cleanup) - ISO 8601 */\r\n  expiresAt: string;\r\n  /** When reservation was committed/released - ISO 8601 or undefined */\r\n  completedAt?: string;\r\n}\r\n\r\n// ==================== Result Types ====================\r\n\r\n/**\r\n * Result of a credit check operation\r\n */\r\nexport interface CreditCheckResult {\r\n  /** Whether user has sufficient credits */\r\n  hasCredits: boolean;\r\n  /** Current balance (balance + bonusCredits) */\r\n  balance: number;\r\n  /** Required credits for operation */\r\n  required: number;\r\n  /** Shortfall if insufficient */\r\n  shortfall: number;\r\n}\r\n\r\n/**\r\n * Result of monthly reset operation\r\n */\r\nexport interface MonthlyResetResult {\r\n  /** Whether the reset was performed */\r\n  wasReset: boolean;\r\n  /** The user credits after the operation */\r\n  credits: PortableUserCredits;\r\n}\r\n\r\n/**\r\n * Result of subscription expiry check\r\n */\r\nexport interface SubscriptionExpiryResult {\r\n  /** Whether the subscription was downgraded */\r\n  wasDowngraded: boolean;\r\n  /** Whether user is in grace period */\r\n  inGracePeriod: boolean;\r\n  /** Days remaining in grace period (0 if not in grace) */\r\n  graceDaysRemaining: number;\r\n  /** The user credits after the operation */\r\n  credits: PortableUserCredits;\r\n}\r\n\r\n// ==================== Transaction Types ====================\r\n\r\n/**\r\n * Credit transaction type\r\n */\r\nexport type TransactionType = \"purchase\" | \"subscription\" | \"bonus\" | \"refund\" | \"adjustment\";\r\n\r\n/**\r\n * Portable credit transaction\r\n */\r\nexport interface PortableTransaction {\r\n  id: string;\r\n  userId: string;\r\n  type: TransactionType;\r\n  /** Amount of credits (positive for additions, negative for deductions) */\r\n  amount: number;\r\n  description: string;\r\n  /** Reference to payment provider */\r\n  paymentRef?: string;\r\n  previousBalance: number;\r\n  newBalance: number;\r\n  createdAt: string;\r\n}\r\n\r\n// ==================== Journal Types ====================\r\n\r\n/**\r\n * Source of a credit journal entry\r\n */\r\nexport type CreditSource =\r\n  | \"operation_commit\"\r\n  | \"operation_release\"\r\n  | \"purchase\"\r\n  | \"subscription_grant\"\r\n  | \"subscription_upgrade\"\r\n  | \"subscription_downgrade\"\r\n  | \"monthly_reset\"\r\n  | \"bonus\"\r\n  | \"refund\"\r\n  | \"admin_adjustment\"\r\n  | \"expiry\"\r\n  | \"reservation_expired\";\r\n\r\n/**\r\n * Type of reference for a journal entry\r\n */\r\nexport type JournalReferenceType =\r\n  | \"reservation\"\r\n  | \"transaction\"\r\n  | \"adjustment\"\r\n  | \"reset\"\r\n  | \"subscription\";\r\n\r\n/**\r\n * Portable credit journal entry for audit trail\r\n */\r\nexport interface PortableJournalEntry {\r\n  id: string;\r\n  userId: string;\r\n  /** Type of entry - debit decreases balance, credit increases balance */\r\n  entryType: \"debit\" | \"credit\";\r\n  /** Amount of credits involved */\r\n  amount: number;\r\n  /** Balance after this entry */\r\n  balanceAfter: number;\r\n  /** Source of the credit change */\r\n  source: CreditSource;\r\n  /** Reference ID (e.g., reservationId, transactionId) */\r\n  referenceId: string;\r\n  /** Type of reference */\r\n  referenceType: JournalReferenceType;\r\n  /** Human-readable description */\r\n  description: string;\r\n  /** Additional metadata */\r\n  metadata?: Record<string, unknown>;\r\n  /** When this entry was created - ISO 8601 */\r\n  createdAt: string;\r\n}\r\n\r\n// ==================== Usage Types ====================\r\n\r\n/**\r\n * Portable usage log entry\r\n */\r\nexport interface PortableUsageLog {\r\n  id: string;\r\n  userId: string;\r\n  operationType: CreditOperationType;\r\n  provider: AIProviderType;\r\n  creditsUsed: number;\r\n  success: boolean;\r\n  errorMessage?: string;\r\n  resourceId?: string;\r\n  resourceType?: ResourceType;\r\n  requestId?: string;\r\n  metadata?: Record<string, unknown>;\r\n  createdAt: string;\r\n}\r\n\r\n/**\r\n * User-friendly usage history entry\r\n */\r\nexport interface UsageHistoryEntry {\r\n  id: string;\r\n  /** Type of entry for display */\r\n  type: \"usage\" | \"purchase\" | \"bonus\" | \"reset\" | \"refund\" | \"adjustment\";\r\n  /** Positive = earned, Negative = spent */\r\n  creditsChange: number;\r\n  /** Balance after this entry */\r\n  balanceAfter: number;\r\n  /** Human-readable description */\r\n  description: string;\r\n  /** When this occurred - ISO 8601 */\r\n  createdAt: string;\r\n}\r\n\r\n/**\r\n * Paginated usage history response\r\n */\r\nexport interface UsageHistoryResponse {\r\n  entries: UsageHistoryEntry[];\r\n  pagination: {\r\n    total: number;\r\n    limit: number;\r\n    offset: number;\r\n    hasMore: boolean;\r\n  };\r\n}\r\n\r\n// ==================== Tier Configuration ====================\r\n\r\n/**\r\n * Tier configuration for credit limits and pricing\r\n */\r\nexport interface TierConfig {\r\n  tier: SubscriptionTier;\r\n  monthlyCredits: number;\r\n  priceUsd: number;\r\n  features: string[];\r\n  /** Free/default tier marker — no subscription expiry, balance untouched on tier change. Defaults to priceUsd === 0. */\r\n  isFree?: boolean;\r\n  /** Unlimited tier marker. Defaults to monthlyCredits === 0. */\r\n  unlimited?: boolean;\r\n  /** Tier assigned to brand-new users. Defaults to the tier flagged isFree. */\r\n  isDefault?: boolean;\r\n}\r\n\r\n// ==================== Options Types ====================\r\n\r\n/**\r\n * Options for withCredits HOF\r\n */\r\nexport interface WithCreditsOptions {\r\n  /** Operation type for cost lookup */\r\n  operationType: CreditOperationType;\r\n  /** AI provider (defaults to \"gemini\") */\r\n  provider?: AIProviderType;\r\n  /** Custom cost override (use with caution) */\r\n  customCost?: number;\r\n  /** Resource ID for usage logging */\r\n  resourceId?: string;\r\n  /** Resource type for usage logging */\r\n  resourceType?: ResourceType;\r\n}\r\n\r\n// ==================== Constants ====================\r\n","/**\r\n * Credit system error classes - framework agnostic\r\n *\r\n * Provides typed error handling for credit operations.\r\n * These errors can be used across different environments.\r\n */\r\n\r\n/**\r\n * Error codes for credit operations\r\n */\r\nexport const CreditErrorCode = {\r\n  INSUFFICIENT_CREDITS: \"INSUFFICIENT_CREDITS\",\r\n  RESERVATION_NOT_FOUND: \"RESERVATION_NOT_FOUND\",\r\n  RESERVATION_EXPIRED: \"RESERVATION_EXPIRED\",\r\n  RESERVATION_ALREADY_PROCESSED: \"RESERVATION_ALREADY_PROCESSED\",\r\n  USER_NOT_FOUND: \"USER_NOT_FOUND\",\r\n  INVALID_OPERATION_TYPE: \"INVALID_OPERATION_TYPE\",\r\n  CONFIGURATION_ERROR: \"CONFIGURATION_ERROR\",\r\n  DATABASE_ERROR: \"DATABASE_ERROR\",\r\n} as const;\r\n\r\nexport type CreditErrorCodeType = (typeof CreditErrorCode)[keyof typeof CreditErrorCode];\r\n\r\n/**\r\n * Custom error class for credit operations\r\n *\r\n * Provides structured error information including:\r\n * - Error code for programmatic handling\r\n * - Human-readable message\r\n * - Optional details for debugging\r\n */\r\nexport class CreditError extends Error {\r\n  public readonly code: CreditErrorCodeType;\r\n  public readonly details?: Record<string, unknown>;\r\n\r\n  constructor(\r\n    message: string,\r\n    code: CreditErrorCodeType,\r\n    details?: Record<string, unknown>\r\n  ) {\r\n    super(message);\r\n    this.name = \"CreditError\";\r\n    this.code = code;\r\n    this.details = details;\r\n\r\n    // Maintains proper stack trace for where error was thrown\r\n    if (Error.captureStackTrace) {\r\n      Error.captureStackTrace(this, CreditError);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Convert to JSON-serializable object\r\n   */\r\n  toJSON(): { name: string; code: string; message: string; details?: Record<string, unknown> } {\r\n    return {\r\n      name: this.name,\r\n      code: this.code,\r\n      message: this.message,\r\n      ...(this.details && { details: this.details }),\r\n    };\r\n  }\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is a CreditError\r\n */\r\nexport function isCreditError(error: unknown): error is CreditError {\r\n  return error instanceof CreditError;\r\n}\r\n\r\n/**\r\n * Check if an error represents insufficient credits\r\n *\r\n * Works with both CreditError and regular Error instances.\r\n * Useful for handling errors from different sources.\r\n */\r\nexport function isInsufficientCreditsError(error: unknown): boolean {\r\n  if (isCreditError(error)) {\r\n    return error.code === CreditErrorCode.INSUFFICIENT_CREDITS;\r\n  }\r\n\r\n  if (error instanceof Error) {\r\n    return error.message.toLowerCase().includes(\"insufficient credits\");\r\n  }\r\n\r\n  return false;\r\n}\r\n\r\n/**\r\n * Create an insufficient credits error\r\n */\r\nexport function createInsufficientCreditsError(\r\n  required: number,\r\n  available: number\r\n): CreditError {\r\n  return new CreditError(\r\n    `Insufficient credits: available ${available}, required ${required}`,\r\n    CreditErrorCode.INSUFFICIENT_CREDITS,\r\n    { required, available, shortfall: required - available }\r\n  );\r\n}\r\n\r\n/**\r\n * Create a reservation not found error\r\n */\r\nexport function createReservationNotFoundError(reservationId: string): CreditError {\r\n  return new CreditError(\r\n    `Reservation ${reservationId} not found`,\r\n    CreditErrorCode.RESERVATION_NOT_FOUND,\r\n    { reservationId }\r\n  );\r\n}\r\n\r\n/**\r\n * Create a reservation expired error\r\n */\r\nexport function createReservationExpiredError(reservationId: string): CreditError {\r\n  return new CreditError(\r\n    `Reservation ${reservationId} has expired`,\r\n    CreditErrorCode.RESERVATION_EXPIRED,\r\n    { reservationId }\r\n  );\r\n}\r\n\r\n/**\r\n * Create a reservation already processed error\r\n */\r\nexport function createReservationAlreadyProcessedError(\r\n  reservationId: string,\r\n  status: string\r\n): CreditError {\r\n  return new CreditError(\r\n    `Reservation ${reservationId} has already been ${status}`,\r\n    CreditErrorCode.RESERVATION_ALREADY_PROCESSED,\r\n    { reservationId, status }\r\n  );\r\n}\r\n\r\n/**\r\n * Create a user not found error\r\n */\r\nexport function createUserNotFoundError(userId: string): CreditError {\r\n  return new CreditError(\r\n    `User ${userId} not found`,\r\n    CreditErrorCode.USER_NOT_FOUND,\r\n    { userId }\r\n  );\r\n}\r\n\r\n/**\r\n * Create an invalid operation type error\r\n */\r\nexport function createInvalidOperationTypeError(\r\n  operationType: string,\r\n  validTypes: string[]\r\n): CreditError {\r\n  return new CreditError(\r\n    `Invalid operation type: ${operationType}. Valid types: ${validTypes.join(\", \")}`,\r\n    CreditErrorCode.INVALID_OPERATION_TYPE,\r\n    { operationType, validTypes }\r\n  );\r\n}\r\n","/**\r\n * Deferred execution abstraction - framework agnostic\r\n *\r\n * Provides a way to schedule work to run after the current operation completes.\r\n * Different frameworks can provide their own implementations:\r\n * - Next.js: uses `after()` from `next/server`\r\n * - Generic: uses `setImmediate()` or `setTimeout()`\r\n * - Testing: can use synchronous execution\r\n */\r\n\r\n/**\r\n * Interface for deferred execution\r\n *\r\n * Implementations should schedule the function to run asynchronously\r\n * without blocking the current operation.\r\n */\r\nexport interface DeferredExecutor {\r\n  /**\r\n   * Schedule a function to run asynchronously\r\n   *\r\n   * The function should be executed after the current operation completes.\r\n   * Errors should be caught and logged, not propagated.\r\n   *\r\n   * @param fn - Async function to execute\r\n   */\r\n  defer(fn: () => Promise<void>): void;\r\n}\r\n\r\n/**\r\n * Generic deferred executor using setImmediate/setTimeout\r\n *\r\n * Works in Node.js and browser environments.\r\n * Suitable for non-framework environments or testing.\r\n */\r\nexport const genericDeferred: DeferredExecutor = {\r\n  defer(fn: () => Promise<void>): void {\r\n    // Use setImmediate in Node.js, setTimeout as fallback\r\n    const scheduler = typeof setImmediate !== \"undefined\" ? setImmediate : setTimeout;\r\n    scheduler(() => {\r\n      fn().catch((error) => {\r\n        console.error(\"[Credits] Deferred task error:\", error);\r\n      });\r\n    });\r\n  },\r\n};\r\n\r\n/**\r\n * Synchronous deferred executor\r\n *\r\n * Executes the function immediately (fire-and-forget).\r\n * Useful for testing or when deferred execution isn't needed.\r\n */\r\nexport const synchronousDeferred: DeferredExecutor = {\r\n  defer(fn: () => Promise<void>): void {\r\n    fn().catch((error) => {\r\n      console.error(\"[Credits] Deferred task error:\", error);\r\n    });\r\n  },\r\n};\r\n\r\n/**\r\n * Create a custom deferred executor\r\n *\r\n * Allows frameworks to provide their own scheduling mechanism.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Next.js adapter\r\n * import { after } from 'next/server';\r\n *\r\n * const nextJsDeferred = createDeferredExecutor((fn) => after(fn));\r\n * ```\r\n *\r\n * @param schedule - Function that schedules async work\r\n * @returns DeferredExecutor instance\r\n */\r\nexport function createDeferredExecutor(\r\n  schedule: (fn: () => Promise<void>) => void\r\n): DeferredExecutor {\r\n  return {\r\n    defer: schedule,\r\n  };\r\n}\r\n\r\n/**\r\n * No-op deferred executor\r\n *\r\n * Discards deferred work. Useful when you want to disable\r\n * background tasks (e.g., in certain test scenarios).\r\n */\r\nexport const noopDeferred: DeferredExecutor = {\r\n  defer(_fn: () => Promise<void>): void {\r\n    // Intentionally do nothing\r\n  },\r\n};\r\n","import { z } from \"zod\";\r\nimport type { SubscriptionTier, TierConfig } from \"../core/types.js\";\r\nimport { getConfigProvider } from \"./provider.js\";\r\n\r\n/**\r\n * Schema for tier configuration\r\n */\r\nconst tierConfigSchema = z.object({\r\n  tier: z.string().min(1),\r\n  monthlyCredits: z.number().min(0),\r\n  priceUsd: z.number().min(0),\r\n  features: z.array(z.string()),\r\n  isFree: z.boolean().optional(),\r\n  unlimited: z.boolean().optional(),\r\n  isDefault: z.boolean().optional(),\r\n});\r\n\r\n/**\r\n * Schema for credit system configuration\r\n */\r\nconst creditSystemConfigSchema = z.object({\r\n  /**\r\n   * Operation costs in credits\r\n   * Keys are operation type names (any non-empty string)\r\n   * Values are positive numbers representing credit cost\r\n   */\r\n  operationCosts: z.record(\r\n    z.string().min(1),\r\n    z.number().positive()\r\n  ),\r\n\r\n  /**\r\n   * Display labels for operation types (English canonical labels).\r\n   * Falls back to auto-generating from snake_case keys if not provided.\r\n   */\r\n  operationLabels: z.record(\r\n    z.string().min(1),\r\n    z.string().min(1)\r\n  ).optional().default({}),\r\n\r\n  /**\r\n   * Tier configurations\r\n   */\r\n  tierConfigs: z.record(\r\n    z.string().min(1),\r\n    tierConfigSchema\r\n  ),\r\n\r\n  /**\r\n   * Reservation expiry time in milliseconds\r\n   */\r\n  reservationExpiryMs: z.number().positive().default(5 * 60 * 1000),\r\n\r\n  /**\r\n   * Default credits for new users (free tier)\r\n   */\r\n  defaultFreeCredits: z.number().positive().default(25),\r\n\r\n  /**\r\n   * Grace period in days after subscription expires before downgrade\r\n   */\r\n  subscriptionGracePeriodDays: z.number().min(0).default(3),\r\n\r\n  /**\r\n   * Low balance notification threshold\r\n   */\r\n  lowBalanceThreshold: z.number().min(0).default(10),\r\n\r\n  /**\r\n   * Cooldown in hours between low balance notifications\r\n   */\r\n  lowBalanceNotificationCooldownHours: z.number().positive().default(24),\r\n\r\n  /**\r\n   * Feature flags for optional features\r\n   */\r\n  features: z.object({\r\n    journalEntries: z.boolean().default(true),\r\n    notifications: z.boolean().default(true),\r\n    subscriptionExpiry: z.boolean().default(true),\r\n    usageHistory: z.boolean().default(true),\r\n  }).default({\r\n    journalEntries: true,\r\n    notifications: true,\r\n    subscriptionExpiry: true,\r\n    usageHistory: true,\r\n  }),\r\n});\r\n\r\n/**\r\n * Credit system configuration type\r\n */\r\nexport type CreditSystemConfig = z.infer<typeof creditSystemConfigSchema>;\r\n\r\n/**\r\n * Default configuration\r\n */\r\nconst DEFAULT_CONFIG: CreditSystemConfig = {\r\n  operationCosts: {\r\n    story_generation: 5,\r\n    conversation: 2,\r\n    image_generation: 10,\r\n    template_generation: 10,\r\n  },\r\n  operationLabels: {\r\n    story_generation: \"Story generation\",\r\n    conversation: \"Conversation\",\r\n    image_generation: \"Image generation\",\r\n    template_generation: \"Template generation\",\r\n  },\r\n  tierConfigs: {\r\n    free: {\r\n      tier: \"free\",\r\n      monthlyCredits: 25,\r\n      priceUsd: 0,\r\n      isFree: true,\r\n      isDefault: true,\r\n      features: [\r\n        \"25 credits per month\",\r\n        \"Basic story generation\",\r\n        \"Standard image quality\",\r\n      ],\r\n    },\r\n    basic: {\r\n      tier: \"basic\",\r\n      monthlyCredits: 200,\r\n      priceUsd: 9.99,\r\n      features: [\r\n        \"200 credits per month\",\r\n        \"All story features\",\r\n        \"High quality images\",\r\n        \"Priority support\",\r\n      ],\r\n    },\r\n    premium: {\r\n      tier: \"premium\",\r\n      monthlyCredits: 500,\r\n      priceUsd: 19.99,\r\n      features: [\r\n        \"500 credits per month\",\r\n        \"All features\",\r\n        \"Highest quality images\",\r\n        \"Early access to new features\",\r\n        \"Priority support\",\r\n      ],\r\n    },\r\n    unlimited: {\r\n      tier: \"unlimited\",\r\n      monthlyCredits: 0, // 0 = unlimited\r\n      unlimited: true,\r\n      priceUsd: 49.99,\r\n      features: [\r\n        \"Unlimited credits\",\r\n        \"All features\",\r\n        \"Highest quality images\",\r\n        \"Early access to new features\",\r\n        \"Dedicated support\",\r\n      ],\r\n    },\r\n  },\r\n  reservationExpiryMs: 5 * 60 * 1000, // 5 minutes\r\n  defaultFreeCredits: 25,\r\n  subscriptionGracePeriodDays: 3,\r\n  lowBalanceThreshold: 10,\r\n  lowBalanceNotificationCooldownHours: 24,\r\n  features: {\r\n    journalEntries: true,\r\n    notifications: true,\r\n    subscriptionExpiry: true,\r\n    usageHistory: true,\r\n  },\r\n};\r\n\r\n/**\r\n * Current configuration (can be overridden)\r\n */\r\nlet currentConfig: CreditSystemConfig = DEFAULT_CONFIG;\r\n\r\n/**\r\n * Load configuration from environment variables\r\n * Can be extended to load from other sources (file, remote config, etc.)\r\n *\r\n * Operation costs are loaded from CREDITS_OPERATION_COSTS as JSON:\r\n * CREDITS_OPERATION_COSTS={\"story_generation\":5,\"image_generation\":10}\r\n */\r\nexport function loadConfigFromEnv(): Partial<CreditSystemConfig> {\r\n  const envConfig: Partial<CreditSystemConfig> = {};\r\n\r\n  // Load operation costs from env as JSON\r\n  const operationCostsEnv = process.env.CREDITS_OPERATION_COSTS;\r\n  if (operationCostsEnv) {\r\n    try {\r\n      const parsed = JSON.parse(operationCostsEnv);\r\n      if (typeof parsed === \"object\" && parsed !== null) {\r\n        envConfig.operationCosts = {\r\n          ...DEFAULT_CONFIG.operationCosts,\r\n          ...parsed,\r\n        };\r\n      }\r\n    } catch {\r\n      console.warn(\"[Credits Config] Failed to parse CREDITS_OPERATION_COSTS env var as JSON\");\r\n    }\r\n  }\r\n\r\n  // Load other settings from env\r\n  const reservationExpiry = process.env.CREDITS_RESERVATION_EXPIRY_MS;\r\n  if (reservationExpiry) {\r\n    envConfig.reservationExpiryMs = parseInt(reservationExpiry, 10);\r\n  }\r\n\r\n  const defaultCredits = process.env.CREDITS_DEFAULT_FREE;\r\n  if (defaultCredits) {\r\n    envConfig.defaultFreeCredits = parseInt(defaultCredits, 10);\r\n  }\r\n\r\n  const gracePeriod = process.env.CREDITS_GRACE_PERIOD_DAYS;\r\n  if (gracePeriod) {\r\n    envConfig.subscriptionGracePeriodDays = parseInt(gracePeriod, 10);\r\n  }\r\n\r\n  const lowBalanceThreshold = process.env.CREDITS_LOW_BALANCE_THRESHOLD;\r\n  if (lowBalanceThreshold) {\r\n    envConfig.lowBalanceThreshold = parseInt(lowBalanceThreshold, 10);\r\n  }\r\n\r\n  // Load feature flags\r\n  const featuresEnv = process.env.CREDITS_FEATURES;\r\n  if (featuresEnv) {\r\n    try {\r\n      const features = JSON.parse(featuresEnv);\r\n      envConfig.features = {\r\n        ...DEFAULT_CONFIG.features,\r\n        ...features,\r\n      };\r\n    } catch {\r\n      console.warn(\"[Credits Config] Failed to parse CREDITS_FEATURES env var\");\r\n    }\r\n  }\r\n\r\n  return envConfig;\r\n}\r\n\r\n/**\r\n * Initialize configuration\r\n * Merges default config with environment overrides\r\n */\r\nexport function initializeConfig(overrides?: Partial<CreditSystemConfig>): CreditSystemConfig {\r\n  const envConfig = loadConfigFromEnv();\r\n\r\n  const mergedConfig = {\r\n    ...DEFAULT_CONFIG,\r\n    ...envConfig,\r\n    ...overrides,\r\n    operationCosts: {\r\n      ...DEFAULT_CONFIG.operationCosts,\r\n      ...envConfig.operationCosts,\r\n      ...overrides?.operationCosts,\r\n    },\r\n    operationLabels: {\r\n      ...DEFAULT_CONFIG.operationLabels,\r\n      ...envConfig.operationLabels,\r\n      ...overrides?.operationLabels,\r\n    },\r\n    tierConfigs: {\r\n      ...DEFAULT_CONFIG.tierConfigs,\r\n      ...envConfig.tierConfigs,\r\n      ...overrides?.tierConfigs,\r\n    },\r\n    features: {\r\n      ...DEFAULT_CONFIG.features,\r\n      ...envConfig.features,\r\n      ...overrides?.features,\r\n    },\r\n  };\r\n\r\n  // Validate configuration\r\n  const result = creditSystemConfigSchema.safeParse(mergedConfig);\r\n  if (!result.success) {\r\n    console.error(\"[Credits Config] Invalid configuration:\", result.error.issues);\r\n    throw new Error(\"Invalid credit system configuration\");\r\n  }\r\n\r\n  currentConfig = result.data;\r\n  return currentConfig;\r\n}\r\n\r\n/**\r\n * Get the current configuration.\r\n * If an external provider is registered, delegates to it.\r\n * Otherwise falls back to the local currentConfig.\r\n */\r\nexport function getConfig(): CreditSystemConfig {\r\n  const provider = getConfigProvider();\r\n  if (provider) {\r\n    return provider.getConfig();\r\n  }\r\n  return currentConfig;\r\n}\r\n\r\n/**\r\n * Get all valid operation types from configuration\r\n * Returns the keys of the operationCosts object\r\n */\r\nexport function getValidOperationTypes(): string[] {\r\n  return Object.keys(getConfig().operationCosts);\r\n}\r\n\r\n/**\r\n * Check if an operation type is valid (configured in the system)\r\n * @param type - The operation type to check\r\n * @returns true if the operation type is configured\r\n */\r\nexport function isValidOperationType(type: string): boolean {\r\n  return type in getConfig().operationCosts;\r\n}\r\n\r\n/**\r\n * Get operation cost from configuration\r\n * @throws Error if the operation type is not configured\r\n */\r\nexport function getConfigOperationCost(operationType: string): number {\r\n  const cost = getConfig().operationCosts[operationType];\r\n  if (cost === undefined) {\r\n    throw new Error(\r\n      `Unknown operation type: ${operationType}. Valid types: ${getValidOperationTypes().join(\", \")}`\r\n    );\r\n  }\r\n  return cost;\r\n}\r\n\r\n/**\r\n * Get all valid tier ids from configuration\r\n * Returns the keys of the tierConfigs object\r\n */\r\nexport function getValidTiers(): string[] {\r\n  return Object.keys(getConfig().tierConfigs);\r\n}\r\n\r\n/**\r\n * Check if a tier id is valid (configured in the system)\r\n */\r\nexport function isValidTier(tier: string): boolean {\r\n  return tier in getConfig().tierConfigs;\r\n}\r\n\r\n/**\r\n * Check if a tier is the free/default tier.\r\n * Falls back to priceUsd === 0 when the isFree flag is not set.\r\n */\r\nexport function isFreeTier(tier: SubscriptionTier): boolean {\r\n  const c = getConfig().tierConfigs[tier];\r\n  if (!c) return false;\r\n  return c.isFree ?? c.priceUsd === 0;\r\n}\r\n\r\n/**\r\n * Check if a tier is unlimited.\r\n * Falls back to monthlyCredits === 0 when the unlimited flag is not set.\r\n */\r\nexport function isUnlimitedTier(tier: SubscriptionTier): boolean {\r\n  const c = getConfig().tierConfigs[tier];\r\n  if (!c) return false;\r\n  return c.unlimited ?? c.monthlyCredits === 0;\r\n}\r\n\r\n/**\r\n * Get the tier assigned to brand-new users.\r\n * Prefers the tier flagged isDefault, then the first isFree tier, then \"free\".\r\n */\r\nexport function getDefaultTier(): SubscriptionTier {\r\n  const entries = Object.entries(getConfig().tierConfigs);\r\n  const def =\r\n    entries.find(([, c]) => c.isDefault)?.[0] ??\r\n    entries.find(([, c]) => c.isFree ?? c.priceUsd === 0)?.[0];\r\n  return def ?? \"free\";\r\n}\r\n\r\n/**\r\n * Magic balance assigned to unlimited tiers on upgrade.\r\n * Kept at 999999 for back-compat with stored/displayed balances.\r\n */\r\nexport const UNLIMITED_BALANCE_SENTINEL = 999999;\r\n\r\n/**\r\n * Get the magic balance assigned to unlimited tiers on upgrade.\r\n */\r\nexport function getUnlimitedSentinelBalance(): number {\r\n  return UNLIMITED_BALANCE_SENTINEL;\r\n}\r\n\r\n/**\r\n * Get tier configuration from configuration.\r\n * Falls back to the default tier (with a warning) if the tier is unknown.\r\n */\r\nexport function getConfigTierConfig(tier: SubscriptionTier): TierConfig {\r\n  const cfg = getConfig().tierConfigs[tier];\r\n  if (cfg) return cfg;\r\n  const fallback = getDefaultTier();\r\n  console.warn(\r\n    `[Credits Config] Unknown tier \"${tier}\". Falling back to \"${fallback}\". Valid: ${getValidTiers().join(\", \")}`\r\n  );\r\n  return getConfig().tierConfigs[fallback]!;\r\n}\r\n\r\n/**\r\n * Get monthly limit for a tier from configuration\r\n * Returns Infinity for unlimited tier\r\n */\r\nexport function getConfigMonthlyLimit(tier: SubscriptionTier): number {\r\n  return isUnlimitedTier(tier) ? Infinity : getConfigTierConfig(tier).monthlyCredits;\r\n}\r\n\r\n/**\r\n * Runtime zod validator for tier ids. Validates against the LIVE config keys\r\n * at parse time, so apps that add tiers via config get correct validation.\r\n */\r\nexport const tierSchema = z\r\n  .string()\r\n  .refine(isValidTier, { message: \"Unknown subscription tier\" }) as unknown as z.ZodType<SubscriptionTier>;\r\n\r\n/**\r\n * Parse/validate a tier id against the live config keys.\r\n * @throws ZodError if the tier is not configured\r\n */\r\nexport function parseTier(value: unknown): SubscriptionTier {\r\n  return tierSchema.parse(value);\r\n}\r\n\r\n/**\r\n * Check if a feature is enabled\r\n */\r\nexport function isFeatureEnabled(feature: keyof CreditSystemConfig[\"features\"]): boolean {\r\n  return getConfig().features[feature];\r\n}\r\n\r\n/**\r\n * Convert a snake_case string to Title Case.\r\n * E.g., \"story_generation\" -> \"Story Generation\"\r\n */\r\nfunction snakeCaseToTitleCase(str: string): string {\r\n  return str\r\n    .replace(/_/g, \" \")\r\n    .replace(/\\b\\w/g, (c) => c.toUpperCase());\r\n}\r\n\r\n/**\r\n * Get the display label for an operation type.\r\n * Falls back to converting snake_case to Title Case if no label is configured.\r\n */\r\nexport function getOperationLabel(operationType: string): string {\r\n  const labels = getConfig().operationLabels;\r\n  if (labels && operationType in labels) {\r\n    return labels[operationType];\r\n  }\r\n  return snakeCaseToTitleCase(operationType);\r\n}\r\n\r\n/**\r\n * Get all operation labels as a record.\r\n * For any operation in operationCosts that lacks a label, generates one from the key.\r\n */\r\nexport function getOperationLabels(): Record<string, string> {\r\n  const config = getConfig();\r\n  const result: Record<string, string> = {};\r\n  for (const key of Object.keys(config.operationCosts)) {\r\n    result[key] = config.operationLabels?.[key]\r\n      ?? snakeCaseToTitleCase(key);\r\n  }\r\n  return result;\r\n}\r\n\r\n/**\r\n * Reset configuration to defaults (for testing)\r\n */\r\nexport function resetConfig(): void {\r\n  currentConfig = DEFAULT_CONFIG;\r\n}\r\n\r\n// Initialize configuration on module load\r\ninitializeConfig();\r\n","import type { CreditSystemConfig } from \"./index.js\";\r\n\r\n/** Interface for external config providers (e.g. Firestore-backed) */\r\nexport interface ICreditConfigProvider {\r\n  getConfig(): CreditSystemConfig;\r\n}\r\n\r\nlet configProvider: ICreditConfigProvider | null = null;\r\n\r\n/** Register an external config provider. Called once at app startup. */\r\nexport function registerConfigProvider(provider: ICreditConfigProvider): void {\r\n  configProvider = provider;\r\n}\r\n\r\n/** Get the registered provider, or null if none registered. */\r\nexport function getConfigProvider(): ICreditConfigProvider | null {\r\n  return configProvider;\r\n}\r\n\r\n/** Clear registered provider (for testing). */\r\nexport function clearConfigProvider(): void {\r\n  configProvider = null;\r\n}\r\n","/**\r\n * Core credit operations - framework agnostic\r\n *\r\n * Contains the business logic for credit operations that can be\r\n * used by any adapter or service implementation.\r\n */\r\n\r\nimport type { ICreditRepository } from \"../repository/types.js\";\r\nimport type { PortableReservation } from \"./types.js\";\r\nimport { getOperationLabel } from \"../config/index.js\";\r\n\r\n/**\r\n * Commit a reservation with journal entry\r\n *\r\n * @param repository - The credit repository\r\n * @param userId - User ID\r\n * @param reservationId - Reservation to commit\r\n */\r\nexport async function commitReservationWithJournal(\r\n  repository: ICreditRepository,\r\n  userId: string,\r\n  reservationId: string\r\n): Promise<void> {\r\n  // Get the reservation to know the amount\r\n  const reservation = await repository.getReservation(userId, reservationId);\r\n  if (!reservation) {\r\n    throw new Error(`Reservation ${reservationId} not found`);\r\n  }\r\n\r\n  // Commit the reservation atomically\r\n  await repository.commitReservationAtomic(userId, reservationId);\r\n\r\n  // Create journal entry\r\n  const credits = await repository.getUserCredits(userId);\r\n  if (credits) {\r\n    await repository.createJournalEntry({\r\n      userId,\r\n      entryType: \"debit\",\r\n      amount: reservation.amount,\r\n      balanceAfter: credits.balance,\r\n      source: \"operation_commit\",\r\n      referenceId: reservationId,\r\n      referenceType: \"reservation\",\r\n      description: `Committed ${reservation.amount} credits for ${getOperationLabel(reservation.operationType)}`,\r\n      metadata: {\r\n        operationType: reservation.operationType,\r\n      },\r\n    });\r\n  }\r\n}\r\n\r\n/**\r\n * Release a reservation with journal entry\r\n *\r\n * @param repository - The credit repository\r\n * @param userId - User ID\r\n * @param reservationId - Reservation to release\r\n */\r\nexport async function releaseReservationWithJournal(\r\n  repository: ICreditRepository,\r\n  userId: string,\r\n  reservationId: string\r\n): Promise<void> {\r\n  // Get the reservation to check its state\r\n  const reservation = await repository.getReservation(userId, reservationId);\r\n\r\n  // Release the reservation atomically\r\n  await repository.releaseReservationAtomic(userId, reservationId);\r\n\r\n  // Create journal entry only if reservation was in reserved state\r\n  if (reservation?.status === \"reserved\") {\r\n    const credits = await repository.getUserCredits(userId);\r\n    if (credits) {\r\n      await repository.createJournalEntry({\r\n        userId,\r\n        entryType: \"credit\",\r\n        amount: 0, // No actual credits returned (they were reserved, not spent)\r\n        balanceAfter: credits.balance,\r\n        source: \"operation_release\",\r\n        referenceId: reservationId,\r\n        referenceType: \"reservation\",\r\n        description: `Released ${reservation.amount} reserved credits for ${getOperationLabel(reservation.operationType)}`,\r\n        metadata: {\r\n          operationType: reservation.operationType,\r\n          amount: reservation.amount,\r\n        },\r\n      });\r\n    }\r\n  }\r\n}\r\n\r\n/**\r\n * Reserve credits for an operation\r\n *\r\n * @param repository - The credit repository\r\n * @param userId - User ID\r\n * @param amount - Credits to reserve\r\n * @param operationType - Type of operation\r\n * @param expiryMs - Reservation expiry time in milliseconds\r\n * @returns The reservation\r\n */\r\nexport async function reserveCreditsForOperation(\r\n  repository: ICreditRepository,\r\n  userId: string,\r\n  amount: number,\r\n  operationType: string,\r\n  expiryMs: number = 5 * 60 * 1000\r\n): Promise<PortableReservation> {\r\n  const expiresAt = new Date(Date.now() + expiryMs);\r\n  return repository.reserveCreditsAtomic(userId, amount, operationType, expiresAt);\r\n}\r\n"],"mappings":"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","names":[]}