import { b6 as FieldConfig, r as SanitizedNextlyConfig, b9 as PluginFieldType } from '../../_dts-chunks/auth-service.d-B0csjDLa.d.ts'; import { SupportedDialect as SupportedDialect$1 } from '@nextlyhq/adapter-drizzle/types'; import '@nextlyhq/adapter-drizzle'; import 'react'; import '../../_dts-chunks/nextly-error.d-WlStqaV9.d.ts'; import '../../_dts-chunks/error-codes.d-CbwkO1ux.d.ts'; import '../../_dts-chunks/media.d-DtIw8UQM.d.ts'; import 'zod'; import '../../_dts-chunks/storage.d-CEowrt6p.d.ts'; import 'drizzle-orm'; /** * Fold plugin schema contributions into the merged config (code-first lane). * * Pure function: appends each plugin's `contributes.{collections,singles, * components}` to the config's own arrays so the downstream merge/migration/ * sync machinery treats them like ordinary code-first entities. Runs * over ALL plugins — including disabled ones — so declarative schema stays * deterministic across environments. * * Slug collisions that involve a plugin-contributed entity are a fail-fast boot * error. Pre-existing code-vs-code duplicates are left untouched so the * plugin-free path is byte-for-byte unchanged (decisions doc G2). Collections, * singles, and components are independent namespaces (distinct table prefixes), * so a collection and a single may share a slug. * * Called at the same post-`setup` seam by both the runtime boot * (`di/register.ts`) and the CLI (`cli/utils/config-loader.ts`), which is what * keeps the two paths in agreement. * * @module plugins/schema/apply-contributions */ /** * A single, fully-resolved `extend` clause — one target slug (array targets are * pre-expanded) plus the name of the plugin that declared it. Returned by the * deferring fold for targets that aren't code/plugin entities (candidate Builder * targets, P8/R2), then resolved against the Builder set by `resolveBuilderExtends`. */ interface DeferredExtend { target: string; fields: FieldConfig[]; owner: string; } /** * Config Loader * * Loads and parses nextly.config.ts at runtime using esbuild. * Supports TypeScript, ESM, and CommonJS config files. * * @module cli/utils/config-loader * @since 1.0.0 * * @example * ```typescript * import { loadConfig, watchConfig } from 'nextly/cli/utils/config-loader'; * * // Load config once * const config = await loadConfig(); * * // Watch for changes (dev mode) * const config = await loadConfig({ watch: true }); * watchConfig((newConfig) => { * console.log('Config updated:', newConfig); * }); * ``` */ /** * Options for loading the config file. */ interface LoadConfigOptions { /** * Custom path to the config file. * If not provided, searches default locations. */ configPath?: string; /** * Working directory for resolving relative paths. * Defaults to `process.cwd()`. */ cwd?: string; /** * Enable watch mode for file changes. * When enabled, the config will be reloaded on changes. * @default false */ watch?: boolean; /** * Enable verbose logging for debugging. * @default false */ debug?: boolean; } /** * Result of loading the config file. */ interface LoadConfigResult { /** * The loaded and sanitized config. */ config: SanitizedNextlyConfig; /** * Path to the config file that was loaded. * Undefined if using default config (no file found). */ configPath?: string; /** * List of files that the config depends on. * Useful for watch mode to know what files to watch. */ dependencies: string[]; /** * Plugin `contributes.extend` clauses whose target wasn't a code/plugin entity * (candidate Builder/UI-schema targets, P8). Already resolved + validated here * against the Builder set; threaded out so `migrate-create`/`migrate-check` can * materialize the extra columns onto the Builder tables without re-folding. */ deferredExtends?: DeferredExtend[]; /** * The plugin field types this config registered, captured at the end of its * load. * * Work that outlives the load it started from — the `db:sync` watcher keeps * syncing across a save — resolves against this rather than the live registry, * which the next load clears and rebuilds. */ fieldTypes?: ReadonlyMap; } /** * Callback for config change events. */ type ConfigChangeCallback = (result: LoadConfigResult) => void; /** * Load the Nextly configuration from file. * * Searches for config files in the following locations (in order): * 1. `./nextly.config.ts` * 2. `./nextly.config.mts` * 3. `./nextly.config.js` * 4. `./nextly.config.mjs` * 5. `./src/nextly.config.ts` (and other extensions) * 6. `./config/nextly.config.ts` (and other extensions) * * If no config file is found, returns a default configuration. * * @param options - Load options * @returns Promise resolving to the loaded config result * * @example * ```typescript * // Basic usage * const { config } = await loadConfig(); * console.log(config.collections); * * // With custom path * const { config } = await loadConfig({ * configPath: './custom/nextly.config.ts' * }); * * // With watch mode * const { config } = await loadConfig({ watch: true }); * watchConfig((result) => { * console.log('Config changed:', result.config); * }); * ``` */ declare function loadConfig(options?: LoadConfigOptions): Promise; /** * Register a callback to be called when the config file changes. * Only works when config was loaded with `watch: true`. * * @param callback - Function to call when config changes * @returns Unsubscribe function * * @example * ```typescript * // Load with watch mode * await loadConfig({ watch: true }); * * // Register callback * const unsubscribe = watchConfig((result) => { * console.log('Config updated:', result.config); * }); * * // Later, unsubscribe * unsubscribe(); * ``` */ declare function watchConfig(callback: ConfigChangeCallback): () => void; /** * Clear the cached config and stop watching. * Useful for testing or when you need to force a reload. * * @example * ```typescript * // Clear cache and reload * clearConfigCache(); * const { config } = await loadConfig(); * ``` */ declare function clearConfigCache(): void; /** * Get the currently cached config without loading. * Returns null if no config is cached. * * @returns Cached config result or null * * @example * ```typescript * const cached = getCachedConfig(); * if (cached) { * console.log('Using cached config'); * } else { * const { config } = await loadConfig(); * } * ``` */ declare function getCachedConfig(): LoadConfigResult | null; /** * Check if a config file exists in the default locations. * * @param cwd - Working directory to search from * @returns Path to config file if found, undefined otherwise * * @example * ```typescript * const configPath = findNextlyConfig(); * if (configPath) { * console.log('Found config at:', configPath); * } else { * console.log('No config file found'); * } * ``` */ declare function findNextlyConfig(cwd?: string): string | undefined; /** * Supported config file extensions. */ declare const SUPPORTED_EXTENSIONS: string[]; /** * Default search directories for config files. */ declare const SEARCH_DIRECTORIES: string[]; /** * CLI Logger Utility * * Provides colored output for CLI commands with support for * verbose, quiet, and normal modes. * * @module cli/utils/logger * @since 1.0.0 */ /** * Log level for CLI output */ type LogLevel = "debug" | "info" | "warn" | "error" | "success"; /** * Logger options for customizing output behavior */ interface LoggerOptions { /** * Enable verbose output (shows debug messages) * @default false */ verbose?: boolean; /** * Enable quiet mode (only shows errors) * @default false */ quiet?: boolean; /** * Disable colors in output * @default false */ noColor?: boolean; } /** * Logger instance interface */ interface Logger { /** Log debug message (only shown in verbose mode) */ debug: (message: string, ...args: unknown[]) => void; /** Log info message */ info: (message: string, ...args: unknown[]) => void; /** Log warning message */ warn: (message: string, ...args: unknown[]) => void; /** Log error message */ error: (message: string, ...args: unknown[]) => void; /** Log success message */ success: (message: string, ...args: unknown[]) => void; /** Log a blank line */ newline: () => void; /** Log a divider line */ divider: (char?: string) => void; /** Log a header with emphasis */ header: (message: string) => void; /** Log a list item */ item: (message: string, indent?: number) => void; /** Log a key-value pair */ keyValue: (key: string, value: string | number | boolean) => void; /** Log a table (simple format) */ table: (headers: string[], rows: (string | number | boolean)[][]) => void; /** Create a spinner (returns stop function) */ spinner: (message: string) => { stop: (success?: boolean) => void; }; /** Update logger options */ setOptions: (options: LoggerOptions) => void; /** Get current options */ getOptions: () => LoggerOptions; } /** * Create a new logger instance * * @param options - Logger configuration options * @returns Logger instance * * @example * ```typescript * const logger = createLogger({ verbose: true }); * logger.info('Starting process...'); * logger.success('Done!'); * ``` */ declare function createLogger(options?: LoggerOptions): Logger; /** * Default logger instance with default options */ declare const logger: Logger; /** * Format a duration in milliseconds to a human-readable string * * @param ms - Duration in milliseconds * @returns Formatted duration string * * @example * ```typescript * formatDuration(1500) // "1.5s" * formatDuration(100) // "100ms" * formatDuration(65000) // "1m 5s" * ``` */ declare function formatDuration(ms: number): string; /** * Format a file size in bytes to a human-readable string * * @param bytes - Size in bytes * @returns Formatted size string * * @example * ```typescript * formatBytes(1024) // "1.00 KB" * formatBytes(1048576) // "1.00 MB" * ``` */ declare function formatBytes(bytes: number): string; /** * Format a count with proper pluralization * * @param count - The count * @param singular - Singular form of the word * @param plural - Plural form of the word (defaults to singular + 's') * @returns Formatted string * * @example * ```typescript * formatCount(1, 'file') // "1 file" * formatCount(5, 'file') // "5 files" * formatCount(0, 'migration') // "0 migrations" * ``` */ declare function formatCount(count: number, singular: string, plural?: string): string; /** * CLI Database Adapter Utilities * * Helper functions for creating and managing database adapters * in CLI commands. * * @module cli/utils/adapter * @since 1.0.0 */ /** * Supported database dialects */ type SupportedDialect = "postgresql" | "mysql" | "sqlite"; /** * Options for creating a database adapter */ interface CreateAdapterOptions { /** * Database dialect (postgresql, mysql, sqlite) * If not provided, will be detected from DATABASE_URL or DB_DIALECT env var */ dialect?: SupportedDialect; /** * Database connection URL * If not provided, will use DATABASE_URL env var */ databaseUrl?: string; /** * Logger instance for output */ logger?: Logger; } /** * Result of database environment validation */ interface DatabaseEnvValidation { /** Whether the environment is valid */ valid: boolean; /** Error messages if invalid */ errors: string[]; /** Detected dialect */ dialect?: SupportedDialect; /** Database URL */ databaseUrl?: string; } /** * Detect database dialect from connection URL * * @param url - Database connection URL * @returns Detected dialect or undefined */ declare function detectDialectFromUrl(url: string): SupportedDialect | undefined; /** * Validate database environment variables * * @returns Validation result with errors if any */ declare function validateDatabaseEnv(): DatabaseEnvValidation; /** * Database adapter interface (minimal for CLI use) */ interface CLIDatabaseAdapter { dialect: SupportedDialect; connect(): Promise; disconnect(): Promise; isConnected(): boolean; getCapabilities(): { dialect: SupportedDialect; }; } /** * Create a database adapter from environment or options * * @param options - Adapter creation options * @returns Database adapter instance * @throws Error if environment is invalid or adapter creation fails * * @example * ```typescript * const adapter = await createAdapter({ logger }); * try { * // Use adapter... * } finally { * await adapter.disconnect(); * } * ``` */ declare function createAdapter(options?: CreateAdapterOptions): Promise; /** * Execute a function with a database adapter, ensuring cleanup * * @param fn - Function to execute with the adapter * @param options - Adapter creation options * @returns Result of the function * * @example * ```typescript * const result = await withAdapter(async (adapter) => { * return await someOperation(adapter); * }, { logger }); * ``` */ declare function withAdapter(fn: (adapter: CLIDatabaseAdapter) => Promise, options?: CreateAdapterOptions): Promise; /** * Get a human-readable name for a dialect * * @param dialect - Database dialect * @returns Human-readable name */ declare function getDialectDisplayName(dialect: SupportedDialect): string; /** * Check if a dialect supports a specific feature * * @param dialect - Database dialect * @param feature - Feature to check * @returns Whether the feature is supported */ declare function dialectSupports(dialect: SupportedDialect, feature: "transactions" | "jsonb" | "arrays" | "uuids"): boolean; /** * Migration Discovery Utilities * * Shared utilities for discovering and grouping migration files, * including dialect-specific variant selection (e.g., .mysql.sql, .sqlite.sql). * * This ensures consistent behavior across migrate, migrate:status, and build commands. * * @module cli/utils/migration-discovery */ /** * A migration file variant with its dialect (if any) */ interface MigrationVariant { /** The file name (e.g., "0001_000000_blog_schema.mysql.sql") */ file: string; /** The dialect this file targets (mysql, sqlite, postgresql), or undefined for base files */ dialect: SupportedDialect$1 | undefined; } /** * Result of migration discovery - grouped variants for each logical migration */ interface MigrationGroup { /** Base migration name (without dialect suffix) */ baseName: string; /** All variants of this migration (base + dialect-specific) */ variants: MigrationVariant[]; } /** * Discover migration files from the migrations directory and group dialect variants. * * Groups files by base name (without dialect suffix) so that: * - 0001_000000_blog_schema.sql * - 0001_000000_blog_schema.mysql.sql * - 0001_000000_blog_schema.sqlite.sql * * Are treated as ONE logical migration named "0001_000000_blog_schema". * * @param migrationsDir - Path to the migrations directory * @returns Map of base migration names to their variants */ declare function discoverMigrationGroups(migrationsDir: string): Promise>; /** * Select the best migration variant for a given dialect. * * Priority order: * 1. Dialect-specific file (e.g., .mysql.sql for mysql dialect) * 2. Base file (no dialect suffix) * 3. First available variant (fallback) * * @param variants - Available migration variants * @param dialect - Target database dialect (optional) * @returns The selected file name, or undefined if no variants available */ declare function selectVariant(variants: MigrationVariant[], dialect?: SupportedDialect$1): string | undefined; /** * Get the sorted list of base migration names from grouped migrations. * * @param groups - Migration groups from discoverMigrationGroups * @returns Sorted array of base migration names */ declare function getSortedBaseNames(groups: Map): string[]; export { SEARCH_DIRECTORIES, SUPPORTED_EXTENSIONS, clearConfigCache, createAdapter, createLogger, detectDialectFromUrl, dialectSupports, discoverMigrationGroups, findNextlyConfig, formatBytes, formatCount, formatDuration, getCachedConfig, getDialectDisplayName, getSortedBaseNames, loadConfig, logger, selectVariant, validateDatabaseEnv, watchConfig, withAdapter }; export type { CLIDatabaseAdapter, ConfigChangeCallback, CreateAdapterOptions, DatabaseEnvValidation, LoadConfigOptions, LoadConfigResult, LogLevel, Logger, LoggerOptions, MigrationGroup, MigrationVariant, SupportedDialect };