rest_api_faker 0.0.1 → 0.0.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.
package/README.md CHANGED
@@ -4,8 +4,8 @@
4
4
 
5
5
  Created with ❤️ for front-end developers who need a quick back-end for prototyping and mocking.
6
6
 
7
- [![CI](https://github.com/hamidmayeli/api-faker/actions/workflows/ci.yml/badge.svg)](https://github.com/hamidmayeli/api-faker/actions/workflows/ci.yml)
8
- [![Coverage](https://codecov.io/gh/hamidmayeli/api-faker/branch/main/graph/badge.svg)](https://codecov.io/gh/hamidmayeli/api-faker)
7
+ [![CI](https://github.com/hamidmayeli/rest_api_faker/actions/workflows/ci.yml/badge.svg)](https://github.com/hamidmayeli/rest_api_faker/actions/workflows/ci.yml)
8
+ [![Coverage](https://codecov.io/gh/hamidmayeli/rest_api_faker/branch/main/graph/badge.svg)](https://codecov.io/gh/hamidmayeli/rest_api_faker)
9
9
  [![Tests](https://img.shields.io/badge/tests-223%20passing-brightgreen)]()
10
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue)]()
11
11
  [![License](https://img.shields.io/badge/license-MIT-blue)]()
@@ -81,13 +81,13 @@ pnpm add -g rest_api_faker
81
81
  **2. Start the server:**
82
82
 
83
83
  ```bash
84
- api-faker db.json
84
+ rest_api_faker db.json
85
85
  ```
86
86
 
87
87
  Or with watch mode to auto-reload on file changes:
88
88
 
89
89
  ```bash
90
- api-faker --watch db.json
90
+ rest_api_faker --watch db.json
91
91
  ```
92
92
 
93
93
  **3. Access your API:**
@@ -110,10 +110,10 @@ That's it! 🎉 You now have a fully functional REST API.
110
110
  ### CLI Options
111
111
 
112
112
  ```bash
113
- api-faker [options] <source>
113
+ rest_api_faker [options] <source>
114
114
 
115
115
  Options:
116
- -c, --config <path> Path to config file (default: "api-faker.json")
116
+ -c, --config <path> Path to config file (default: "rest_api_faker.json")
117
117
  -p, --port <number> Set port (default: 3000)
118
118
  -H, --host <string> Set host (default: "localhost")
119
119
  -w, --watch Watch file(s) for changes
@@ -133,11 +133,11 @@ Options:
133
133
  -v, --version Show version number
134
134
 
135
135
  Examples:
136
- api-faker db.json Start with db.json
137
- api-faker --watch db.json Start with auto-reload
138
- api-faker --port 4000 db.json Start on port 4000
139
- api-faker file.js Use a JavaScript file
140
- api-faker --routes routes.json Use custom routes
136
+ rest_api_faker db.json Start with db.json
137
+ rest_api_faker --watch db.json Start with auto-reload
138
+ rest_api_faker --port 4000 db.json Start on port 4000
139
+ rest_api_faker file.js Use a JavaScript file
140
+ rest_api_faker --routes routes.json Use custom routes
141
141
  ```
142
142
 
143
143
  ### Routes
@@ -301,7 +301,7 @@ POST /posts/1/comments
301
301
 
302
302
  ## Configuration
303
303
 
304
- You can use a configuration file instead of CLI options. Create an `api-faker.json` file:
304
+ You can use a configuration file instead of CLI options. Create an `rest_api_faker.json` file:
305
305
 
306
306
  ```json
307
307
  {
@@ -324,13 +324,13 @@ You can use a configuration file instead of CLI options. Create an `api-faker.js
324
324
  Then simply run:
325
325
 
326
326
  ```bash
327
- api-faker db.json
327
+ rest_api_faker db.json
328
328
  ```
329
329
 
330
330
  **Using a custom config file:**
331
331
 
332
332
  ```bash
333
- api-faker db.json --config my-config.json
333
+ rest_api_faker db.json --config my-config.json
334
334
  ```
335
335
 
336
336
  **Note:** CLI arguments override config file values.
@@ -353,7 +353,7 @@ Create a `routes.json` file with URL rewrite rules:
353
353
  Use it:
354
354
 
355
355
  ```bash
356
- api-faker db.json --routes routes.json
356
+ rest_api_faker db.json --routes routes.json
357
357
  ```
358
358
 
359
359
  Now you can access:
@@ -383,7 +383,7 @@ module.exports = function (req, res, next) {
383
383
  Use it:
384
384
 
385
385
  ```bash
386
- api-faker db.json --middlewares middleware.js
386
+ rest_api_faker db.json --middlewares middleware.js
387
387
  ```
388
388
 
389
389
  See [examples/README.md](examples/README.md) for more examples.
@@ -394,19 +394,19 @@ See [examples/README.md](examples/README.md) for more examples.
394
394
 
395
395
  ```bash
396
396
  # Start with default settings
397
- api-faker db.json
397
+ rest_api_faker db.json
398
398
 
399
399
  # Start with watch mode
400
- api-faker --watch db.json
400
+ rest_api_faker --watch db.json
401
401
 
402
402
  # Start on a different port
403
- api-faker --port 4000 db.json
403
+ rest_api_faker --port 4000 db.json
404
404
 
405
405
  # Read-only mode (only GET requests)
406
- api-faker --read-only db.json
406
+ rest_api_faker --read-only db.json
407
407
 
408
408
  # Add delay to all responses (useful for testing loading states)
409
- api-faker --delay 1000 db.json
409
+ rest_api_faker --delay 1000 db.json
410
410
  ```
411
411
 
412
412
  ### Using JavaScript for Dynamic Data
@@ -445,7 +445,7 @@ module.exports = function () {
445
445
  Start the server:
446
446
 
447
447
  ```bash
448
- api-faker db.js
448
+ rest_api_faker db.js
449
449
  ```
450
450
 
451
451
  **Tip:** Use libraries like [Faker.js](https://fakerjs.dev/) for more realistic data.
@@ -479,7 +479,7 @@ module.exports = function (req, res, next) {
479
479
  Use it:
480
480
 
481
481
  ```bash
482
- api-faker db.json --middlewares auth-middleware.js
482
+ rest_api_faker db.json --middlewares auth-middleware.js
483
483
  ```
484
484
 
485
485
  Now all POST, PUT, PATCH, DELETE requests require the `Authorization: Bearer secret-token` header.
@@ -511,7 +511,7 @@ Create a `vercel.json`:
511
511
  Create a `server.js`:
512
512
 
513
513
  ```javascript
514
- const jsonServer = require('api-faker');
514
+ const jsonServer = require('rest_api_faker');
515
515
  const server = jsonServer.create();
516
516
  const router = jsonServer.router('db.json');
517
517
  const middlewares = jsonServer.defaults();
@@ -539,7 +539,7 @@ web: node server.js
539
539
  Create a `server.js`:
540
540
 
541
541
  ```javascript
542
- const jsonServer = require('api-faker');
542
+ const jsonServer = require('rest_api_faker');
543
543
  const server = jsonServer.create();
544
544
  const router = jsonServer.router('db.json');
545
545
  const middlewares = jsonServer.defaults();
@@ -568,7 +568,7 @@ git push heroku main
568
568
  You can also use API Faker programmatically in your Node.js applications:
569
569
 
570
570
  ```javascript
571
- const jsonServer = require('api-faker');
571
+ const jsonServer = require('rest_api_faker');
572
572
  const server = jsonServer.create();
573
573
  const router = jsonServer.router('db.json');
574
574
  const middlewares = jsonServer.defaults();
package/dist/cli.js CHANGED
@@ -1596,11 +1596,11 @@ function getVersion() {
1596
1596
  }
1597
1597
  }
1598
1598
  function parseCli() {
1599
- const argv = (0, import_yargs.default)((0, import_helpers.hideBin)(process.argv)).scriptName("api-faker").usage("Usage: $0 [options] <source>").example("$0 db.json", "Start API Faker with db.json").example("$0 file.js", "Start API Faker with a JS file").example("$0 http://example.com/db.json", "Start API Faker with a remote schema").option("config", {
1599
+ const argv = (0, import_yargs.default)((0, import_helpers.hideBin)(process.argv)).scriptName("rest_api_faker").usage("Usage: $0 [options] <source>").example("$0 db.json", "Start API Faker with db.json").example("$0 file.js", "Start API Faker with a JS file").example("$0 http://example.com/db.json", "Start API Faker with a remote schema").option("config", {
1600
1600
  alias: "c",
1601
1601
  type: "string",
1602
1602
  description: "Path to config file",
1603
- default: "api-faker.json"
1603
+ default: "rest_api_faker.json"
1604
1604
  }).option("port", {
1605
1605
  alias: "p",
1606
1606
  type: "number",
@@ -1672,7 +1672,7 @@ function parseCli() {
1672
1672
  type: "boolean",
1673
1673
  description: "Suppress log messages from output",
1674
1674
  default: false
1675
- }).help("help", "Show help").alias("h", "help").version(getVersion()).alias("v", "version").epilogue("For more information, visit https://github.com/hamidmayeli/api-faker").parseSync();
1675
+ }).help("help", "Show help").alias("h", "help").version(getVersion()).alias("v", "version").epilogue("For more information, visit https://github.com/hamidmayeli/rest_api_faker").parseSync();
1676
1676
  let fileConfig = null;
1677
1677
  try {
1678
1678
  fileConfig = loadConfig(argv.config);
@@ -1731,7 +1731,7 @@ async function main() {
1731
1731
  }
1732
1732
  if (!config.source) {
1733
1733
  logger.error("No source file specified");
1734
- logger.info('Run "api-faker --help" for usage information');
1734
+ logger.info('Run "rest_api_faker --help" for usage information');
1735
1735
  process.exit(1);
1736
1736
  }
1737
1737
  if (!config.quiet) {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/database.ts","../src/server.ts","../src/router.ts","../src/logger.ts","../src/query.ts","../src/relationships.ts","../src/static.ts","../src/loader.ts","../src/rewriter.ts","../src/config.ts"],"sourcesContent":["import yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { readFileSync, existsSync } from 'fs';\nimport { resolve } from 'path';\nimport { watch } from 'chokidar';\nimport { Database } from './database';\nimport { createServer, startServer, ServerOptions } from './server';\nimport { loadConfig, mergeConfig, Config } from './config';\nimport { logger } from './logger';\n\n/**\n * CLI configuration interface\n */\ninterface CliConfig {\n source: string | undefined;\n port: number;\n host: string;\n watch: boolean;\n routes: string | undefined;\n middlewares: string | undefined;\n static: string | undefined;\n noStatic: boolean;\n readOnly: boolean;\n noCors: boolean;\n noGzip: boolean;\n snapshots: string;\n delay: number | undefined;\n id: string;\n foreignKeySuffix: string;\n quiet: boolean;\n config: string;\n}\n\n/**\n * Get package version\n */\nfunction getVersion(): string {\n try {\n const packageJson = JSON.parse(\n readFileSync(resolve(__dirname, '../package.json'), 'utf-8')\n ) as { version: string };\n return packageJson.version;\n } catch {\n return '0.0.0';\n }\n}\n\n/**\n * Parse and validate CLI arguments\n */\nfunction parseCli(): CliConfig {\n const argv = yargs(hideBin(process.argv))\n .scriptName('api-faker')\n .usage('Usage: $0 [options] <source>')\n .example('$0 db.json', 'Start API Faker with db.json')\n .example('$0 file.js', 'Start API Faker with a JS file')\n .example('$0 http://example.com/db.json', 'Start API Faker with a remote schema')\n .option('config', {\n alias: 'c',\n type: 'string',\n description: 'Path to config file',\n default: 'api-faker.json',\n })\n .option('port', {\n alias: 'p',\n type: 'number',\n description: 'Set port',\n default: 3000,\n })\n .option('host', {\n alias: 'H',\n type: 'string',\n description: 'Set host',\n default: 'localhost',\n })\n .option('watch', {\n alias: 'w',\n type: 'boolean',\n description: 'Watch file(s)',\n default: false,\n })\n .option('routes', {\n alias: 'r',\n type: 'string',\n description: 'Path to routes file',\n })\n .option('middlewares', {\n alias: 'm',\n type: 'string',\n description: 'Path to middleware file',\n })\n .option('static', {\n alias: 's',\n type: 'string',\n description: 'Set static files directory',\n default: './public',\n })\n .option('no-static', {\n type: 'boolean',\n description: 'Disable static file serving',\n default: false,\n })\n .option('read-only', {\n alias: 'ro',\n type: 'boolean',\n description: 'Allow only GET requests',\n default: false,\n })\n .option('no-cors', {\n alias: 'nc',\n type: 'boolean',\n description: 'Disable Cross-Origin Resource Sharing',\n default: false,\n })\n .option('no-gzip', {\n alias: 'ng',\n type: 'boolean',\n description: 'Disable GZIP Content-Encoding',\n default: false,\n })\n .option('snapshots', {\n alias: 'S',\n type: 'string',\n description: 'Set snapshots directory',\n default: '.',\n })\n .option('delay', {\n alias: 'd',\n type: 'number',\n description: 'Add delay to responses (ms)',\n })\n .option('id', {\n alias: 'i',\n type: 'string',\n description: 'Set database id property',\n default: 'id',\n })\n .option('foreignKeySuffix', {\n alias: 'fks',\n type: 'string',\n description: 'Set foreign key suffix',\n default: 'Id',\n })\n .option('quiet', {\n alias: 'q',\n type: 'boolean',\n description: 'Suppress log messages from output',\n default: false,\n })\n .help('help', 'Show help')\n .alias('h', 'help')\n .version(getVersion())\n .alias('v', 'version')\n .epilogue('For more information, visit https://github.com/hamidmayeli/api-faker')\n .parseSync();\n\n // Load config file if it exists\n let fileConfig: Config | null = null;\n try {\n fileConfig = loadConfig(argv.config);\n } catch (error) {\n logger.error(\n `Failed to load config file: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n\n // Build CLI config object (only values explicitly provided by CLI)\n const cliConfig: Partial<Config> = {};\n\n // Only include CLI values that were explicitly set (not defaults)\n // We check if the value is different from the default or if it was provided\n if (argv.port !== 3000) cliConfig.port = argv.port;\n if (argv.host !== 'localhost') cliConfig.host = argv.host;\n if (argv.watch) cliConfig.watch = argv.watch;\n if (argv.routes) cliConfig.routes = argv.routes;\n if (argv.middlewares) cliConfig.middlewares = argv.middlewares;\n if (argv.static !== './public') cliConfig.static = argv.static;\n if (argv['read-only']) cliConfig.readOnly = argv['read-only'];\n if (argv['no-cors']) cliConfig.noCors = argv['no-cors'];\n if (argv['no-gzip']) cliConfig.noGzip = argv['no-gzip'];\n if (argv.snapshots !== '.') cliConfig.snapshots = argv.snapshots;\n if (argv.delay !== undefined) cliConfig.delay = argv.delay;\n if (argv.id !== 'id') cliConfig.id = argv.id;\n if (argv.foreignKeySuffix !== 'Id') cliConfig.foreignKeySuffix = argv.foreignKeySuffix;\n if (argv.quiet) cliConfig.quiet = argv.quiet;\n\n // Merge config file with CLI args (CLI takes precedence)\n const merged = mergeConfig(cliConfig, fileConfig);\n\n return {\n source: argv._[0] as string | undefined,\n port: merged.port ?? 3000,\n host: merged.host ?? 'localhost',\n watch: merged.watch ?? false,\n routes: merged.routes,\n middlewares: merged.middlewares,\n static: merged.static ?? './public',\n noStatic: argv['no-static'],\n readOnly: merged.readOnly ?? false,\n noCors: merged.noCors ?? false,\n noGzip: merged.noGzip ?? false,\n snapshots: merged.snapshots ?? '.',\n delay: merged.delay,\n id: merged.id ?? 'id',\n foreignKeySuffix: merged.foreignKeySuffix ?? 'Id',\n quiet: merged.quiet ?? false,\n config: argv.config,\n };\n}\n\n/**\n * Main CLI entry point\n */\nasync function main(): Promise<void> {\n const config = parseCli();\n\n if (!config.quiet) {\n logger.log(`\n ╔═══════════════════════════════════════╗\n ║ ║\n ║ API Faker v${getVersion().padEnd(19)}║\n ║ ║\n ╚═══════════════════════════════════════╝\n `);\n }\n\n if (!config.source) {\n logger.error('No source file specified');\n logger.info('Run \"api-faker --help\" for usage information');\n process.exit(1);\n }\n\n if (!config.quiet) {\n logger.info(`Source: ${config.source}`);\n logger.info(`Port: ${String(config.port)}`);\n logger.info(`Host: ${config.host}`);\n logger.log('');\n logger.info('Loading database...');\n }\n\n try {\n // Initialize database\n const db = new Database(config.source, {\n idField: config.id,\n foreignKeySuffix: config.foreignKeySuffix,\n });\n\n await db.init();\n\n if (!config.quiet) {\n const data = db.getData();\n const resources = Object.keys(data);\n logger.success(`Loaded ${String(resources.length)} resource(s): ${resources.join(', ')}`);\n logger.log('');\n }\n\n // Create and start server\n const serverOptions: ServerOptions = {\n port: config.port,\n host: config.host,\n readOnly: config.readOnly,\n noCors: config.noCors,\n noGzip: config.noGzip,\n quiet: config.quiet,\n idField: config.id,\n foreignKeySuffix: config.foreignKeySuffix,\n enabled: !config.noStatic,\n };\n\n // Add static directory if specified\n if (config.static) {\n serverOptions.directory = config.static;\n }\n\n // Add custom routes if specified\n if (config.routes) {\n serverOptions.routes = config.routes;\n }\n\n // Add custom middlewares if specified\n if (config.middlewares) {\n serverOptions.middlewares = config.middlewares;\n }\n\n // Only add delay if it's defined\n if (config.delay !== undefined) {\n serverOptions.delay = config.delay;\n }\n\n const app = await createServer(db, serverOptions);\n\n const server = startServer(app, {\n port: config.port,\n host: config.host,\n quiet: config.quiet,\n });\n\n // Set up file watching if enabled\n if (config.watch && config.source && existsSync(config.source)) {\n const watcher = watch(config.source, {\n ignoreInitial: true,\n persistent: true,\n });\n\n watcher.on('change', (path) => {\n if (!config.quiet) {\n logger.log('');\n logger.info(`File changed: ${path}`);\n logger.info('Reloading database...');\n }\n\n db.init()\n .then(() => {\n if (!config.quiet) {\n const data = db.getData();\n const resources = Object.keys(data);\n logger.success(\n `Reloaded ${String(resources.length)} resource(s): ${resources.join(', ')}`\n );\n }\n })\n .catch((error: unknown) => {\n logger.error(\n `Failed to reload database: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n });\n });\n\n watcher.on('error', (error) => {\n logger.error(`Watcher error: ${error instanceof Error ? error.message : String(error)}`);\n });\n\n if (!config.quiet) {\n logger.info(`Watching ${config.source} for changes...`);\n logger.log('');\n }\n\n // Handle graceful shutdown\n process.on('SIGINT', () => {\n if (!config.quiet) {\n logger.log('');\n logger.info('Shutting down...');\n }\n watcher.close().catch(() => {\n // Ignore errors during shutdown\n });\n server.close(() => {\n process.exit(0);\n });\n });\n }\n } catch (error) {\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n}\n\n// Run CLI\nmain().catch((error: unknown) => {\n logger.error(`Fatal error: ${error instanceof Error ? error.message : 'Unknown error'}`);\n process.exit(1);\n});\n","import { Low } from 'lowdb';\nimport { JSONFile } from 'lowdb/node';\nimport { existsSync } from 'fs';\nimport { resolve, extname } from 'path';\nimport { pathToFileURL } from 'url';\n\n/**\n * Database data structure\n */\nexport interface DatabaseData {\n [key: string]: unknown;\n}\n\n/**\n * Database configuration options\n */\nexport interface DatabaseOptions {\n idField?: string;\n foreignKeySuffix?: string;\n}\n\n/**\n * Database class for managing JSON data with lowdb\n */\nexport class Database {\n private db: Low<DatabaseData>;\n private filePath: string;\n private options: Required<DatabaseOptions>;\n\n /**\n * Creates a new Database instance\n *\n * @param source - Path to JSON file or object with data\n * @param options - Database configuration options\n *\n * @example\n * ```typescript\n * const db = new Database('db.json', { idField: 'id' });\n * await db.init();\n * ```\n */\n constructor(source: string | DatabaseData, options: DatabaseOptions = {}) {\n this.options = {\n idField: options.idField || 'id',\n foreignKeySuffix: options.foreignKeySuffix || 'Id',\n };\n\n if (typeof source === 'string') {\n this.filePath = resolve(source);\n const adapter = new JSONFile<DatabaseData>(this.filePath);\n this.db = new Low(adapter, {});\n } else {\n this.filePath = '';\n // For in-memory database with object data\n const adapter = new JSONFile<DatabaseData>(':memory:');\n this.db = new Low(adapter, source);\n }\n }\n\n /**\n * Initialize the database by reading from file or using provided data\n * Supports .json, .js, .ts, and .mjs files\n *\n * @throws Error if file doesn't exist or contains invalid data\n */\n async init(): Promise<void> {\n if (this.filePath && !existsSync(this.filePath)) {\n const ext = this.filePath.endsWith('.js') ? '.js' : '.json';\n throw new Error(\n `Database file not found: ${this.filePath}\\n` +\n `\\nMake sure the file exists and the path is correct.\\n` +\n `Expected format: ${ext === '.js' ? 'JavaScript module exporting data' : 'JSON file with data structure'}`\n );\n }\n\n // Check if file is a JavaScript/TypeScript module\n if (this.filePath) {\n const ext = extname(this.filePath).toLowerCase();\n\n if (ext === '.js' || ext === '.mjs' || ext === '.cjs' || ext === '.ts') {\n // Load JavaScript module\n try {\n const fileUrl = pathToFileURL(this.filePath).href;\n const module = (await import(fileUrl)) as { default?: unknown } & Record<string, unknown>;\n const data: unknown = module.default ?? module;\n\n // If it's a function, call it to get the data\n if (typeof data === 'function') {\n const result: unknown = await Promise.resolve((data as () => unknown)());\n if (typeof result !== 'object' || result === null) {\n throw new Error('JavaScript module function must return an object');\n }\n this.db.data = result as DatabaseData;\n } else if (typeof data === 'object' && data !== null) {\n this.db.data = data as DatabaseData;\n } else {\n throw new Error('JavaScript module must export an object or function');\n }\n } catch (error) {\n throw new Error(\n `Failed to load JavaScript module: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n } else {\n // Load JSON file\n await this.db.read();\n }\n } else {\n // In-memory database\n await this.db.read();\n }\n\n if (typeof this.db.data !== 'object') {\n this.db.data = {};\n }\n\n // Ensure all collections are arrays or objects\n for (const key in this.db.data) {\n const value = this.db.data[key];\n if (value !== null && typeof value !== 'object') {\n throw new Error(`Invalid data structure: ${key} must be an array or object`);\n }\n }\n }\n\n /**\n * Get all data from the database\n *\n * @returns Complete database data\n */\n getData(): DatabaseData {\n return this.db.data;\n }\n\n /**\n * Get a specific collection (array) or resource (object)\n *\n * @param name - Name of the collection/resource\n * @returns Collection array, resource object, or undefined\n */\n getCollection(name: string): unknown {\n return this.db.data[name];\n }\n\n /**\n * Get a single item from a collection by ID\n *\n * @param collectionName - Name of the collection\n * @param id - ID of the item\n * @returns The item or undefined\n */\n getById(collectionName: string, id: string | number): unknown {\n const collection = this.db.data[collectionName];\n\n if (!Array.isArray(collection)) {\n return undefined;\n }\n\n return collection.find((item) => {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n const record = item as Record<string, unknown>;\n return record[this.options.idField] === id || record[this.options.idField] === Number(id);\n });\n }\n\n /**\n * Generate next ID for a collection\n *\n * @param collectionName - Name of the collection\n * @returns Next available ID\n */\n generateId(collectionName: string): number {\n const collection = this.db.data[collectionName];\n\n if (!Array.isArray(collection)) {\n return 1;\n }\n\n let maxId = 0;\n for (const item of collection) {\n if (typeof item === 'object' && item !== null) {\n const record = item as Record<string, unknown>;\n const idValue: unknown = record[this.options.idField];\n if (typeof idValue === 'number' && idValue > maxId) {\n maxId = idValue;\n }\n }\n }\n\n return maxId + 1;\n }\n\n /**\n * Create a new item in a collection\n *\n * @param collectionName - Name of the collection\n * @param data - Data to insert\n * @returns Created item with ID\n * @throws Error if collection is not an array\n */\n async create(\n collectionName: string,\n data: Record<string, unknown>\n ): Promise<Record<string, unknown>> {\n let collection = this.db.data[collectionName];\n\n // Create collection if it doesn't exist\n if (!collection) {\n collection = [];\n this.db.data[collectionName] = collection;\n }\n\n if (!Array.isArray(collection)) {\n throw new Error(`Cannot create in ${collectionName}: not a collection`);\n }\n\n // Generate ID if not provided or use provided ID\n const idValue: unknown =\n data[this.options.idField] !== undefined\n ? data[this.options.idField]\n : this.generateId(collectionName);\n\n // Check if ID already exists\n const existingItem = this.getById(collectionName, idValue as string | number);\n if (existingItem) {\n throw new Error(`Item with ${this.options.idField}=${String(idValue)} already exists`);\n }\n\n const newItem: Record<string, unknown> = { ...data, [this.options.idField]: idValue };\n collection.push(newItem);\n\n await this.save();\n return newItem;\n }\n\n /**\n * Update an item in a collection (full replacement)\n *\n * @param collectionName - Name of the collection\n * @param id - ID of the item\n * @param data - New data (ID field will be preserved)\n * @returns Updated item or undefined if not found\n */\n async update(\n collectionName: string,\n id: string | number,\n data: Record<string, unknown>\n ): Promise<Record<string, unknown> | undefined> {\n const collection = this.db.data[collectionName];\n\n if (!Array.isArray(collection)) {\n return undefined;\n }\n\n const index = collection.findIndex((item) => {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n const record = item as Record<string, unknown>;\n return record[this.options.idField] === id || record[this.options.idField] === Number(id);\n });\n\n if (index === -1) {\n return undefined;\n }\n\n // Preserve the ID (convert to number if it's a numeric string)\n const originalItem = collection[index] as Record<string, unknown>;\n const originalId: unknown = originalItem[this.options.idField];\n const updatedItem: Record<string, unknown> = { ...data, [this.options.idField]: originalId };\n collection[index] = updatedItem;\n\n await this.save();\n return updatedItem;\n }\n\n /**\n * Patch an item in a collection (partial update)\n *\n * @param collectionName - Name of the collection\n * @param id - ID of the item\n * @param data - Partial data to merge (ID field will be ignored)\n * @returns Updated item or undefined if not found\n */\n async patch(\n collectionName: string,\n id: string | number,\n data: Record<string, unknown>\n ): Promise<Record<string, unknown> | undefined> {\n const collection = this.db.data[collectionName];\n\n if (!Array.isArray(collection)) {\n return undefined;\n }\n\n const index = collection.findIndex((item) => {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n const record = item as Record<string, unknown>;\n return record[this.options.idField] === id || record[this.options.idField] === Number(id);\n });\n\n if (index === -1) {\n return undefined;\n }\n\n const currentItem = collection[index] as Record<string, unknown>;\n // Merge data but ignore ID field in the patch data\n const { [this.options.idField]: _ignoredId, ...patchData } = data;\n const patchedItem = { ...currentItem, ...patchData };\n\n collection[index] = patchedItem;\n\n await this.save();\n return patchedItem;\n }\n\n /**\n * Delete an item from a collection\n *\n * @param collectionName - Name of the collection\n * @param id - ID of the item\n * @returns true if deleted, false if not found\n */\n async delete(collectionName: string, id: string | number): Promise<boolean> {\n const collection = this.db.data[collectionName];\n\n if (!Array.isArray(collection)) {\n return false;\n }\n\n const index = collection.findIndex((item) => {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n const record = item as Record<string, unknown>;\n return record[this.options.idField] === id || record[this.options.idField] === Number(id);\n });\n\n if (index === -1) {\n return false;\n }\n\n collection.splice(index, 1);\n await this.save();\n return true;\n }\n\n /**\n * Update or create a singular resource\n *\n * @param resourceName - Name of the resource\n * @param data - Resource data\n * @returns Updated resource\n */\n async updateSingular(\n resourceName: string,\n data: Record<string, unknown>\n ): Promise<Record<string, unknown>> {\n this.db.data[resourceName] = data;\n await this.save();\n return data;\n }\n\n /**\n * Save the database to file\n */\n async save(): Promise<void> {\n await this.db.write();\n }\n\n /**\n * Check if a resource is a collection (array) or singular (object)\n *\n * @param name - Name of the resource\n * @returns true if collection, false if singular or doesn't exist\n */\n isCollection(name: string): boolean {\n return Array.isArray(this.db.data[name]);\n }\n\n /**\n * Get ID field name\n */\n getIdField(): string {\n return this.options.idField;\n }\n\n /**\n * Get foreign key suffix\n */\n getForeignKeySuffix(): string {\n return this.options.foreignKeySuffix;\n }\n}\n","import express, { Express } from 'express';\nimport cors from 'cors';\nimport compression from 'compression';\nimport { Database } from './database';\nimport { createRouter, RouterOptions } from './router';\nimport { createStaticMiddleware, createHomepageMiddleware, StaticOptions } from './static';\nimport { loadMiddlewares } from './loader';\nimport { loadRewriteRules, createRewriterMiddleware } from './rewriter';\nimport { logger } from './logger';\n\n/**\n * Server configuration options\n */\nexport interface ServerOptions extends RouterOptions, StaticOptions {\n port?: number;\n host?: string;\n noCors?: boolean;\n noGzip?: boolean;\n delay?: number;\n quiet?: boolean;\n routes?: string;\n middlewares?: string;\n}\n\n/**\n * Create Express server with API Faker\n *\n * @param db - Database instance\n * @param options - Server configuration options\n * @returns Express application\n *\n * @example\n * ```typescript\n * const db = new Database('db.json');\n * await db.init();\n * const app = await createServer(db, { port: 3000 });\n * ```\n */\nexport async function createServer(\n db: Database,\n options: Partial<ServerOptions> = {}\n): Promise<Express> {\n const app = express();\n\n // CORS\n if (!options.noCors) {\n app.use(cors());\n }\n\n // GZIP compression\n if (!options.noGzip) {\n app.use(compression());\n }\n\n // JSON body parser\n app.use(express.json());\n\n // Delay middleware (for testing/simulation)\n if (options.delay && options.delay > 0) {\n const delay = options.delay;\n app.use((_req, _res, next) => {\n setTimeout(() => {\n next();\n }, delay);\n });\n }\n\n // Request logger (unless quiet)\n if (!options.quiet) {\n app.use((req, _res, next) => {\n logger.request(req.method, req.url);\n next();\n });\n }\n\n // Custom middlewares (load before routes)\n if (options.middlewares) {\n try {\n const middlewares = await loadMiddlewares(options.middlewares);\n for (const middleware of middlewares) {\n app.use(middleware);\n }\n if (!options.quiet) {\n logger.success(`Loaded custom middlewares from ${options.middlewares}`);\n }\n } catch (error) {\n logger.error(\n `Failed to load middlewares: ${error instanceof Error ? error.message : String(error)}`\n );\n throw error;\n }\n }\n\n // Homepage middleware (must be before static to allow custom index.html)\n app.use(createHomepageMiddleware(options));\n\n // Static file server\n app.use(createStaticMiddleware(options));\n\n // Custom route rewriting (load before all routes)\n if (options.routes) {\n try {\n const rules = await loadRewriteRules(options.routes);\n const rewriter = createRewriterMiddleware(rules);\n app.use(rewriter);\n if (!options.quiet) {\n logger.success(`Loaded route rewrite rules from ${options.routes}`);\n }\n } catch (error) {\n logger.error(\n `Failed to load routes: ${error instanceof Error ? error.message : String(error)}`\n );\n throw error;\n }\n }\n\n // Special endpoint: /db (full database dump)\n app.get('/db', (_req, res) => {\n res.json(db.getData());\n });\n\n // API routes\n const router = createRouter(db, options);\n app.use(router);\n\n // 404 handler\n app.use((_req, res) => {\n res.status(404).json({ error: 'Not Found' });\n });\n\n return app;\n}\n\n/**\n * Start the server\n *\n * @param app - Express application\n * @param options - Server options (port, host)\n * @returns Server instance\n */\nexport function startServer(\n app: Express,\n options: Pick<ServerOptions, 'port' | 'host' | 'quiet'> = {}\n): ReturnType<Express['listen']> {\n const port = options.port || 3000;\n const host = options.host || 'localhost';\n\n return app.listen(port, host, () => {\n if (!options.quiet) {\n logger.banner([\n '🚀 API Faker is running!',\n '',\n ' Resources:',\n ` http://${host}:${String(port)}/`,\n '',\n ' Home:',\n ` http://${host}:${String(port)}`,\n ]);\n }\n });\n}\n","import { Router, Request, Response, NextFunction } from 'express';\nimport { Database } from './database';\nimport { logger } from './logger';\nimport { parseQuery, applyQuery, generateLinkHeader } from './query';\nimport { parseRelationships, applyRelationships, getForeignKey } from './relationships';\n\n/**\n * Helper to safely get route param (Express guarantees route params exist)\n */\nfunction getParam(req: Request, name: string): string {\n const value = req.params[name];\n if (value === undefined) {\n throw new Error(`Route parameter '${name}' is missing`);\n }\n return value;\n}\n\n/**\n * Router configuration options\n */\nexport interface RouterOptions {\n idField?: string;\n foreignKeySuffix?: string;\n readOnly?: boolean;\n}\n\n/**\n * Create API Faker router with CRUD operations\n *\n * @param db - Database instance\n * @param options - Router configuration options\n * @returns Express router\n *\n * @example\n * ```typescript\n * const db = new Database('db.json');\n * await db.init();\n * const router = createRouter(db);\n * app.use(router);\n * ```\n */\nexport function createRouter(db: Database, options: Partial<RouterOptions> = {}): Router {\n const router = Router();\n const readOnly = options.readOnly || false;\n const idField = options.idField || 'id';\n const foreignKeySuffix = options.foreignKeySuffix || 'Id';\n\n /**\n * Validate Content-Type for write operations\n */\n const validateContentType = (req: Request, _res: Response, next: NextFunction): void => {\n const contentType = req.get('Content-Type');\n if (!contentType || !contentType.includes('application/json')) {\n // Express still parses but we should warn about missing header\n // In real json-server, this would still work but without actual data modification\n logger.warn('Content-Type should be application/json');\n }\n next();\n };\n\n /**\n * GET /db - Return entire database\n */\n router.get('/db', (_req: Request, res: Response) => {\n res.json(db.getData());\n });\n\n /**\n * GET /:resource - Get all items in a collection or singular resource\n */\n router.get('/:resource', (req: Request, res: Response): void => {\n const resource = getParam(req, 'resource');\n const data = db.getCollection(resource);\n\n if (data === undefined) {\n res.status(404).json({ error: `Resource '${resource}' not found` });\n return;\n }\n // For collections (arrays), apply query parameters\n if (Array.isArray(data)) {\n const queryOptions = parseQuery(req);\n const { data: filtered, total } = applyQuery(data, queryOptions);\n\n // Apply relationships (_embed, _expand)\n const { embed, expand } = parseRelationships(req.query as Record<string, unknown>);\n const withRelationships = applyRelationships(\n filtered as Record<string, unknown>[],\n resource,\n embed,\n expand,\n db,\n idField,\n foreignKeySuffix\n );\n\n // Add X-Total-Count header\n res.set('X-Total-Count', String(total));\n\n // Add Link header for pagination\n if (queryOptions.page !== undefined && queryOptions.limit !== undefined) {\n const linkHeader = generateLinkHeader(req, queryOptions.page, queryOptions.limit, total);\n res.set('Link', linkHeader);\n }\n\n res.json(withRelationships);\n return;\n }\n\n // For singular resources (objects), return as-is\n res.json(data);\n });\n\n /**\n * GET /:resource/:id - Get single item by ID\n */\n router.get('/:resource/:id', (req: Request, res: Response): void => {\n const resource = getParam(req, 'resource');\n const id = getParam(req, 'id');\n\n // Check if resource is a collection\n if (!db.isCollection(resource)) {\n res.status(404).json({ error: `Collection '${resource}' not found` });\n return;\n }\n\n const item = db.getById(resource, id);\n\n if (!item) {\n res.status(404).json({ error: `Item with id '${id}' not found in '${resource}'` });\n return;\n }\n\n // Apply relationships if requested\n const { embed, expand } = parseRelationships(req.query as Record<string, unknown>);\n if (embed.length > 0 || expand.length > 0) {\n const withRelationships = applyRelationships(\n [item as Record<string, unknown>],\n resource,\n embed,\n expand,\n db,\n idField,\n foreignKeySuffix\n );\n res.json(withRelationships[0]);\n return;\n }\n\n res.json(item);\n });\n\n /**\n * GET /:parent/:parentId/:children - Get nested children\n */\n router.get('/:parent/:parentId/:children', (req: Request, res: Response): void => {\n const parent = getParam(req, 'parent');\n const parentId = getParam(req, 'parentId');\n const children = getParam(req, 'children');\n\n // Verify parent exists\n if (!db.isCollection(parent)) {\n res.status(404).json({ error: `Collection '${parent}' not found` });\n return;\n }\n\n const parentItem = db.getById(parent, parentId);\n if (!parentItem) {\n res.status(404).json({ error: `Parent item with id '${parentId}' not found in '${parent}'` });\n return;\n }\n\n // Get children collection\n const childrenData = db.getCollection(children);\n if (!Array.isArray(childrenData)) {\n res.status(404).json({ error: `Collection '${children}' not found` });\n return;\n }\n\n // Filter children by parent foreign key\n const foreignKey = getForeignKey(parent, foreignKeySuffix);\n const filtered = childrenData.filter((child) => {\n if (typeof child !== 'object' || child === null) return false;\n const childFk = (child as Record<string, unknown>)[foreignKey];\n return (\n childFk === parentId ||\n (typeof childFk === 'number' || typeof childFk === 'string'\n ? String(childFk) === parentId\n : false)\n );\n });\n\n // Apply query parameters\n const queryOptions = parseQuery(req);\n const { data: result, total } = applyQuery(filtered, queryOptions);\n\n res.set('X-Total-Count', String(total));\n res.json(result);\n });\n\n /**\n * POST /:parent/:parentId/:children - Create nested child\n */\n router.post(\n '/:parent/:parentId/:children',\n validateContentType,\n async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const parent = getParam(req, 'parent');\n const parentId = getParam(req, 'parentId');\n const children = getParam(req, 'children');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n // Verify parent exists\n if (!db.isCollection(parent)) {\n return res.status(404).json({ error: `Collection '${parent}' not found` });\n }\n\n const parentItem = db.getById(parent, parentId);\n if (!parentItem) {\n return res\n .status(404)\n .json({ error: `Parent item with id '${parentId}' not found in '${parent}'` });\n }\n\n // Auto-set foreign key\n const foreignKey = getForeignKey(parent, foreignKeySuffix);\n data[foreignKey] = parentId;\n\n try {\n const created = await db.create(children, data);\n return res.status(201).json(created);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n }\n );\n\n /**\n * POST /:resource - Create new item\n */\n router.post('/:resource', validateContentType, async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n try {\n // Handle singular resources\n if (!db.isCollection(resource) && db.getCollection(resource) !== undefined) {\n const updated = await db.updateSingular(resource, data);\n return res.status(200).json(updated);\n }\n\n // Create in collection\n const created = await db.create(resource, data);\n return res.status(201).json(created);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n });\n\n /**\n * PUT /:resource/:id - Full update of item\n */\n router.put('/:resource/:id', validateContentType, async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const id = getParam(req, 'id');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n if (!db.isCollection(resource)) {\n return res.status(404).json({ error: `Collection '${resource}' not found` });\n }\n\n try {\n const updated = await db.update(resource, id, data);\n\n if (!updated) {\n return res.status(404).json({ error: `Item with id '${id}' not found in '${resource}'` });\n }\n\n return res.json(updated);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n });\n\n /**\n * PATCH /:resource/:id - Partial update of item\n */\n router.patch('/:resource/:id', validateContentType, async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const id = getParam(req, 'id');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n if (!db.isCollection(resource)) {\n return res.status(404).json({ error: `Collection '${resource}' not found` });\n }\n\n try {\n const patched = await db.patch(resource, id, data);\n\n if (!patched) {\n return res.status(404).json({ error: `Item with id '${id}' not found in '${resource}'` });\n }\n\n return res.json(patched);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n });\n\n /**\n * PUT /:resource - Full update of singular resource\n */\n router.put('/:resource', validateContentType, async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n // Only allow for singular resources (objects, not arrays)\n if (db.isCollection(resource)) {\n return res\n .status(400)\n .json({\n error: `Cannot PUT to collection '${resource}'. Use POST or PUT /${resource}/:id`,\n });\n }\n\n try {\n const updated = await db.updateSingular(resource, data);\n return res.json(updated);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n });\n\n /**\n * PATCH /:resource - Partial update of singular resource\n */\n router.patch('/:resource', validateContentType, async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n // Only allow for singular resources\n if (db.isCollection(resource)) {\n return res\n .status(400)\n .json({ error: `Cannot PATCH collection '${resource}'. Use PATCH /${resource}/:id` });\n }\n\n const current = db.getCollection(resource) as Record<string, unknown> | undefined;\n\n if (!current || typeof current !== 'object') {\n return res.status(404).json({ error: `Resource '${resource}' not found` });\n }\n\n try {\n const merged = { ...current, ...data };\n const updated = await db.updateSingular(resource, merged);\n return res.json(updated);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n });\n\n /**\n * DELETE /:resource/:id - Delete item by ID\n */\n router.delete('/:resource/:id', async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const id = getParam(req, 'id');\n\n if (!db.isCollection(resource)) {\n return res.status(404).json({ error: `Collection '${resource}' not found` });\n }\n\n const deleted = await db.delete(resource, id);\n\n if (!deleted) {\n return res.status(404).json({ error: `Item with id '${id}' not found in '${resource}'` });\n }\n\n // Return 204 No Content\n return res.status(204).send();\n });\n\n return router;\n}\n","import pc from 'picocolors';\n\n/**\n * Logger utility for colored console output\n *\n * Provides consistent, color-coded logging throughout the application.\n * Follows a standard format: [LEVEL] Message\n */\nexport const logger = {\n /**\n * Log success message in green\n *\n * @param message - Success message\n *\n * @example\n * ```typescript\n * logger.success('Server started successfully');\n * // Output: ✓ Server started successfully (in green)\n * ```\n */\n success(message: string): void {\n console.log(pc.green(`✓ ${message}`));\n },\n\n /**\n * Log error message in red\n *\n * @param message - Error message\n *\n * @example\n * ```typescript\n * logger.error('Failed to load file');\n * // Output: ✗ Failed to load file (in red)\n * ```\n */\n error(message: string): void {\n console.error(pc.red(`✗ ${message}`));\n },\n\n /**\n * Log warning message in yellow\n *\n * @param message - Warning message\n *\n * @example\n * ```typescript\n * logger.warn('Using default port');\n * // Output: ⚠ Using default port (in yellow)\n * ```\n */\n warn(message: string): void {\n console.warn(pc.yellow(`⚠ ${message}`));\n },\n\n /**\n * Log info message in cyan\n *\n * @param message - Info message\n *\n * @example\n * ```typescript\n * logger.info('Watching for changes...');\n * // Output: ℹ Watching for changes... (in cyan)\n * ```\n */\n info(message: string): void {\n console.log(pc.cyan(`ℹ ${message}`));\n },\n\n /**\n * Log plain message without color\n *\n * @param message - Message to log\n *\n * @example\n * ```typescript\n * logger.log('http://localhost:3000');\n * // Output: http://localhost:3000\n * ```\n */\n log(message: string): void {\n console.log(message);\n },\n\n /**\n * Log request in gray (for non-quiet mode)\n *\n * @param method - HTTP method\n * @param url - Request URL\n *\n * @example\n * ```typescript\n * logger.request('GET', '/api/users');\n * // Output: [timestamp] GET /api/users (in gray)\n * ```\n */\n request(method: string, url: string): void {\n const timestamp = new Date().toLocaleTimeString();\n console.log(pc.gray(`[${timestamp}] ${method} ${url}`));\n },\n\n /**\n * Log formatted banner\n *\n * @param lines - Array of lines to display\n *\n * @example\n * ```typescript\n * logger.banner([\n * '🚀 API Faker is running!',\n * '',\n * ' Resources:',\n * ' http://localhost:3000/'\n * ]);\n * ```\n */\n banner(lines: string[]): void {\n console.log();\n for (const line of lines) {\n // Color URLs in cyan\n if (line.includes('http://') || line.includes('https://')) {\n const colored = line.replace(/(https?:\\/\\/[^\\s]+)/g, (url) => pc.cyan(url));\n console.log(colored);\n } else if (line.startsWith('🚀')) {\n // Color rocket emoji line in bold\n console.log(pc.bold(line));\n } else {\n console.log(line);\n }\n }\n console.log();\n },\n};\n","/**\n * Query processing module for filtering, sorting, pagination, etc.\n */\n\nimport type { Request } from 'express';\n\n/**\n * Query options extracted from request\n */\nexport interface QueryOptions {\n filters: Record<string, string | string[]>;\n operators: Record<string, Record<string, string>>;\n sort: string[];\n order: string[];\n page?: number;\n limit?: number;\n start?: number;\n end?: number;\n q?: string;\n}\n\n/**\n * Parse query parameters from request\n *\n * @param req - Express request object\n * @returns Parsed query options\n *\n * @example\n * parseQuery(req) // { filters: { title: 'value' }, sort: ['id'], order: ['asc'] }\n */\nexport function parseQuery(req: Request): QueryOptions {\n const query = req.query;\n const filters: Record<string, string | string[]> = {};\n const operators: Record<string, Record<string, string>> = {};\n const sort: string[] = [];\n const order: string[] = [];\n let page: number | undefined;\n let limit: number | undefined;\n let start: number | undefined;\n let end: number | undefined;\n let q: string | undefined;\n\n for (const [key, value] of Object.entries(query)) {\n // Skip non-string and non-array values\n const stringValue =\n typeof value === 'string'\n ? value\n : Array.isArray(value) && value.length > 0 && typeof value[0] === 'string'\n ? value[0]\n : null;\n\n if (stringValue === null && !Array.isArray(value)) {\n continue;\n }\n\n // Special query parameters\n if (key === '_sort') {\n if (typeof value === 'string') {\n sort.push(...value.split(','));\n } else if (Array.isArray(value)) {\n for (const v of value) {\n if (typeof v === 'string') {\n sort.push(v);\n }\n }\n }\n continue;\n }\n\n if (key === '_order') {\n if (typeof value === 'string') {\n order.push(...value.split(','));\n } else if (Array.isArray(value)) {\n for (const v of value) {\n if (typeof v === 'string') {\n order.push(v);\n }\n }\n }\n continue;\n }\n\n if (key === '_page' && stringValue) {\n const parsed = parseInt(stringValue, 10);\n if (!isNaN(parsed) && parsed > 0) {\n page = parsed;\n }\n continue;\n }\n\n if (key === '_limit' && stringValue) {\n const parsed = parseInt(stringValue, 10);\n if (!isNaN(parsed) && parsed > 0) {\n limit = parsed;\n }\n continue;\n }\n\n if (key === '_start' && stringValue) {\n const parsed = parseInt(stringValue, 10);\n if (!isNaN(parsed) && parsed >= 0) {\n start = parsed;\n }\n continue;\n }\n\n if (key === '_end' && stringValue) {\n const parsed = parseInt(stringValue, 10);\n if (!isNaN(parsed) && parsed >= 0) {\n end = parsed;\n }\n continue;\n }\n\n if (key === 'q' && stringValue) {\n q = stringValue;\n continue;\n }\n\n // Operator filters (_gte, _lte, _ne, _like)\n const operatorMatch = key.match(/^(.+)_(gte|lte|ne|like)$/);\n if (operatorMatch && stringValue) {\n const field = operatorMatch[1];\n const operator = operatorMatch[2];\n\n if (field && operator) {\n if (!operators[field]) {\n operators[field] = {};\n }\n operators[field][operator] = stringValue;\n }\n continue;\n }\n\n // Regular filters\n if (typeof value === 'string') {\n filters[key] = value;\n } else if (Array.isArray(value)) {\n const stringValues = value.filter((v): v is string => typeof v === 'string');\n if (stringValues.length > 0) {\n filters[key] = stringValues;\n }\n }\n }\n\n const result: QueryOptions = {\n filters,\n operators,\n sort,\n order,\n };\n\n if (page !== undefined) result.page = page;\n if (limit !== undefined) result.limit = limit;\n if (start !== undefined) result.start = start;\n if (end !== undefined) result.end = end;\n if (q !== undefined) result.q = q;\n\n return result;\n}\n\n/**\n * Get nested property value from object\n *\n * @param obj - Object to get property from\n * @param path - Dot-separated property path\n * @returns Property value or undefined\n *\n * @example\n * getNestedValue({ user: { name: 'John' } }, 'user.name') // 'John'\n */\nfunction getNestedValue(obj: unknown, path: string): unknown {\n if (typeof obj !== 'object' || obj === null) {\n return undefined;\n }\n\n const keys = path.split('.');\n let current: unknown = obj;\n\n for (const key of keys) {\n if (typeof current !== 'object' || current === null || !(key in current)) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[key];\n }\n\n return current;\n}\n\n/**\n * Check if item matches filter criteria\n *\n * @param item - Item to check\n * @param filters - Filter criteria\n * @returns True if item matches all filters\n *\n * @example\n * matchesFilters({ title: 'test' }, { title: 'test' }) // true\n */\nfunction matchesFilters(item: unknown, filters: Record<string, string | string[]>): boolean {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n\n for (const [key, filterValue] of Object.entries(filters)) {\n const itemValue = getNestedValue(item, key);\n\n if (Array.isArray(filterValue)) {\n // Multiple values - item must match at least one\n const matched = filterValue.some((val) => String(itemValue) === val);\n if (!matched) {\n return false;\n }\n } else {\n // Single value - exact match\n if (String(itemValue) !== filterValue) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * Check if item matches operator criteria\n *\n * @param item - Item to check\n * @param operators - Operator criteria\n * @returns True if item matches all operators\n *\n * @example\n * matchesOperators({ age: 25 }, { age: { _gte: '18' } }) // true\n */\nfunction matchesOperators(\n item: unknown,\n operators: Record<string, Record<string, string>>\n): boolean {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n\n for (const [key, ops] of Object.entries(operators)) {\n const itemValue = getNestedValue(item, key);\n\n for (const [operator, filterValue] of Object.entries(ops)) {\n if (operator === 'gte') {\n if (Number(itemValue) < Number(filterValue)) {\n return false;\n }\n } else if (operator === 'lte') {\n if (Number(itemValue) > Number(filterValue)) {\n return false;\n }\n } else if (operator === 'ne') {\n if (String(itemValue) === filterValue) {\n return false;\n }\n } else if (operator === 'like') {\n const itemStr = String(itemValue).toLowerCase();\n const filterStr = filterValue.toLowerCase();\n if (!itemStr.includes(filterStr)) {\n return false;\n }\n }\n }\n }\n\n return true;\n}\n\n/**\n * Check if item matches full-text search\n *\n * @param item - Item to check\n * @param searchText - Text to search for\n * @returns True if any string property contains search text\n *\n * @example\n * matchesSearch({ title: 'Hello World' }, 'world') // true\n */\nfunction matchesSearch(item: unknown, searchText: string): boolean {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n\n const lowerSearch = searchText.toLowerCase();\n\n function searchObject(obj: unknown): boolean {\n if (typeof obj === 'string') {\n return obj.toLowerCase().includes(lowerSearch);\n }\n\n if (typeof obj === 'object' && obj !== null) {\n return Object.values(obj).some(searchObject);\n }\n\n return false;\n }\n\n return searchObject(item);\n}\n\n/**\n * Apply filtering, sorting, pagination, etc. to data array\n *\n * @param data - Array of items to process\n * @param options - Query options\n * @returns Processed array and total count (before pagination)\n *\n * @example\n * applyQuery([{ id: 1 }, { id: 2 }], { limit: 1 }) // { data: [{ id: 1 }], total: 2 }\n */\nexport function applyQuery<T>(data: T[], options: QueryOptions): { data: T[]; total: number } {\n let result = [...data];\n\n // Apply full-text search\n if (options.q) {\n const searchText = options.q;\n result = result.filter((item) => matchesSearch(item, searchText));\n }\n\n // Apply filters\n if (Object.keys(options.filters).length > 0) {\n result = result.filter((item) => matchesFilters(item, options.filters));\n }\n\n // Apply operators\n if (Object.keys(options.operators).length > 0) {\n result = result.filter((item) => matchesOperators(item, options.operators));\n }\n\n // Store total before pagination\n const total = result.length;\n\n // Apply sorting\n if (options.sort.length > 0) {\n const sortFields = options.sort;\n const sortOrders = options.order;\n\n result.sort((a, b) => {\n for (let i = 0; i < sortFields.length; i++) {\n const field = sortFields[i];\n if (!field) continue;\n\n const order = sortOrders[i] === 'desc' ? -1 : 1;\n\n const aVal = getNestedValue(a, field);\n const bVal = getNestedValue(b, field);\n\n if (aVal === bVal) continue;\n\n // Handle null/undefined\n if (aVal === undefined || aVal === null) return 1 * order;\n if (bVal === undefined || bVal === null) return -1 * order;\n\n // Compare values\n if (aVal < bVal) return -1 * order;\n if (aVal > bVal) return 1 * order;\n }\n return 0;\n });\n }\n\n // Apply slicing (_start and _end)\n if (options.start !== undefined || options.end !== undefined) {\n const start = options.start ?? 0;\n const end = options.end ?? result.length;\n result = result.slice(start, end);\n }\n // Apply pagination (_page and _limit)\n else if (options.page !== undefined && options.limit !== undefined) {\n const start = (options.page - 1) * options.limit;\n result = result.slice(start, start + options.limit);\n }\n // Apply limit only\n else if (options.limit !== undefined) {\n result = result.slice(0, options.limit);\n }\n\n return { data: result, total };\n}\n\n/**\n * Generate Link header for pagination\n *\n * @param req - Express request object\n * @param page - Current page\n * @param limit - Items per page\n * @param total - Total number of items\n * @returns Link header value\n *\n * @example\n * generateLinkHeader(req, 2, 10, 100) // '<...>; rel=\"first\", <...>; rel=\"prev\", ...'\n */\nexport function generateLinkHeader(\n req: Request,\n page: number,\n limit: number,\n total: number\n): string {\n const host = req.get('host') ?? 'localhost';\n const baseUrl = `${req.protocol}://${host}${req.path}`;\n const query = new URLSearchParams(req.query as Record<string, string>);\n const lastPage = Math.ceil(total / limit);\n\n const links: string[] = [];\n\n // First page\n query.set('_page', '1');\n query.set('_limit', String(limit));\n links.push(`<${baseUrl}?${query.toString()}>; rel=\"first\"`);\n\n // Previous page\n if (page > 1) {\n query.set('_page', String(page - 1));\n links.push(`<${baseUrl}?${query.toString()}>; rel=\"prev\"`);\n }\n\n // Next page\n if (page < lastPage) {\n query.set('_page', String(page + 1));\n links.push(`<${baseUrl}?${query.toString()}>; rel=\"next\"`);\n }\n\n // Last page\n query.set('_page', String(lastPage));\n links.push(`<${baseUrl}?${query.toString()}>; rel=\"last\"`);\n\n return links.join(', ');\n}\n","/**\n * Relationships module for handling _embed and _expand parameters\n */\n\nimport type { Database } from './database';\n\n/**\n * Detect foreign key relationships based on naming conventions\n *\n * @param collectionName - Name of the collection (e.g., 'posts')\n * @param foreignKeySuffix - Suffix for foreign keys (default: 'Id')\n * @returns Possible foreign key name (e.g., 'postId')\n *\n * @example\n * getForeignKey('posts', 'Id') // 'postId'\n * getForeignKey('users', '_id') // 'user_id'\n */\nexport function getForeignKey(collectionName: string, foreignKeySuffix: string): string {\n // Remove trailing 's' for singular form\n const singular = collectionName.endsWith('s') ? collectionName.slice(0, -1) : collectionName;\n\n return `${singular}${foreignKeySuffix}`;\n}\n\n/**\n * Embed child resources into parent items\n *\n * @param items - Parent items to embed children into\n * @param parentCollection - Name of parent collection\n * @param childCollection - Name of child collection\n * @param db - Database instance\n * @param idField - ID field name (default: 'id')\n * @param foreignKeySuffix - Foreign key suffix (default: 'Id')\n * @returns Items with embedded children\n *\n * @example\n * embedChildren([{ id: 1 }], 'posts', 'comments', db)\n * // [{ id: 1, comments: [{ id: 1, postId: 1, body: '...' }] }]\n */\nexport function embedChildren<T extends Record<string, unknown>>(\n items: T[],\n parentCollection: string,\n childCollection: string,\n db: Database,\n idField: string,\n foreignKeySuffix: string\n): T[] {\n const children = db.getCollection(childCollection);\n\n // If children collection doesn't exist or isn't an array, return items unchanged\n if (!Array.isArray(children)) {\n return items;\n }\n\n const foreignKey = getForeignKey(parentCollection, foreignKeySuffix);\n\n return items.map((item) => {\n // Find all children that reference this parent\n const matchingChildren = children.filter((child) => {\n if (typeof child !== 'object' || child === null) return false;\n const childFk = (child as Record<string, unknown>)[foreignKey];\n const parentId = item[idField];\n return childFk === parentId || String(childFk) === String(parentId);\n });\n\n return {\n ...item,\n [childCollection]: matchingChildren,\n };\n });\n}\n\n/**\n * Expand parent resource into child items\n *\n * @param items - Child items to expand parent into\n * @param childCollection - Name of child collection\n * @param parentCollection - Name of parent collection\n * @param db - Database instance\n * @param idField - ID field name (default: 'id')\n * @param foreignKeySuffix - Foreign key suffix (default: 'Id')\n * @returns Items with expanded parent\n *\n * @example\n * expandParent([{ id: 1, postId: 1 }], 'comments', 'posts', db)\n * // [{ id: 1, postId: 1, post: { id: 1, title: '...' } }]\n */\nexport function expandParent<T extends Record<string, unknown>>(\n items: T[],\n _childCollection: string,\n parentCollection: string,\n db: Database,\n idField: string,\n foreignKeySuffix: string\n): T[] {\n const parents = db.getCollection(parentCollection);\n\n // If parent collection doesn't exist or isn't an array, return items unchanged\n if (!Array.isArray(parents)) {\n return items;\n }\n\n const foreignKey = getForeignKey(parentCollection, foreignKeySuffix);\n\n return items.map((item) => {\n const foreignKeyValue: unknown = item[foreignKey];\n\n if (foreignKeyValue === undefined) {\n return item;\n }\n\n // Find the parent that matches this foreign key\n const parent: unknown = parents.find((p) => {\n if (typeof p !== 'object' || p === null) return false;\n const parentRecord = p as Record<string, unknown>;\n const parentId: unknown = parentRecord[idField];\n // Handle both numeric and string IDs\n if (typeof foreignKeyValue === 'number' || typeof foreignKeyValue === 'string') {\n return parentId === foreignKeyValue || String(parentId) === String(foreignKeyValue);\n }\n return false;\n });\n\n if (!parent || typeof parent !== 'object') {\n return item;\n }\n\n // Use singular form for parent property name\n const parentPropName = parentCollection.endsWith('s')\n ? parentCollection.slice(0, -1)\n : parentCollection;\n\n return {\n ...item,\n [parentPropName]: parent as Record<string, unknown>,\n };\n });\n}\n\n/**\n * Apply relationship parameters (_embed, _expand) to query results\n *\n * @param data - Query results\n * @param resource - Resource name\n * @param embed - Collections to embed\n * @param expand - Collections to expand\n * @param db - Database instance\n * @param idField - ID field name\n * @param foreignKeySuffix - Foreign key suffix\n * @returns Data with relationships applied\n *\n * @example\n * applyRelationships(posts, 'posts', ['comments'], [], db)\n */\nexport function applyRelationships<T extends Record<string, unknown>>(\n data: T[],\n resource: string,\n embed: string[],\n expand: string[],\n db: Database,\n idField: string,\n foreignKeySuffix: string\n): T[] {\n let result = data;\n\n // Apply embeds (include children)\n for (const childCollection of embed) {\n result = embedChildren(result, resource, childCollection, db, idField, foreignKeySuffix);\n }\n\n // Apply expands (include parent)\n for (const parentCollection of expand) {\n result = expandParent(result, resource, parentCollection, db, idField, foreignKeySuffix);\n }\n\n return result;\n}\n\n/**\n * Parse relationship parameters from query\n *\n * @param query - Express query object\n * @returns Arrays of collections to embed and expand\n *\n * @example\n * parseRelationships({ _embed: 'comments' }) // { embed: ['comments'], expand: [] }\n * parseRelationships({ _embed: ['comments', 'likes'] }) // { embed: ['comments', 'likes'], expand: [] }\n */\nexport function parseRelationships(query: Record<string, unknown>): {\n embed: string[];\n expand: string[];\n} {\n const embed: string[] = [];\n const expand: string[] = [];\n\n // Parse _embed\n const embedParam = query._embed;\n if (typeof embedParam === 'string') {\n embed.push(...embedParam.split(','));\n } else if (Array.isArray(embedParam)) {\n for (const e of embedParam) {\n if (typeof e === 'string') {\n embed.push(e);\n }\n }\n }\n\n // Parse _expand\n const expandParam = query._expand;\n if (typeof expandParam === 'string') {\n expand.push(...expandParam.split(','));\n } else if (Array.isArray(expandParam)) {\n for (const e of expandParam) {\n if (typeof e === 'string') {\n expand.push(e);\n }\n }\n }\n\n return { embed, expand };\n}\n","/**\n * Static file server module\n */\n\nimport express, { RequestHandler } from 'express';\nimport { existsSync } from 'fs';\nimport { resolve } from 'path';\n\n/**\n * Static server options\n */\nexport interface StaticOptions {\n directory?: string;\n enabled?: boolean;\n}\n\n/**\n * Create static file server middleware\n *\n * @param options - Static server configuration\n * @returns Express middleware for serving static files\n *\n * @example\n * ```typescript\n * const staticMiddleware = createStaticMiddleware({ directory: './public' });\n * app.use(staticMiddleware);\n * ```\n */\nexport function createStaticMiddleware(options: StaticOptions = {}): RequestHandler {\n const directory = options.directory || './public';\n const enabled = options.enabled !== false;\n const staticPath = resolve(process.cwd(), directory);\n\n // If disabled or directory doesn't exist, return pass-through middleware\n if (!enabled || !existsSync(staticPath)) {\n return (_req, _res, next) => {\n next();\n };\n }\n\n // Serve static files from the directory\n return express.static(staticPath, {\n index: 'index.html',\n dotfiles: 'ignore',\n redirect: true,\n });\n}\n\n/**\n * Create homepage middleware that serves index.html or shows default page\n *\n * @param options - Static server configuration\n * @returns Express request handler\n */\nexport function createHomepageMiddleware(options: StaticOptions = {}): RequestHandler {\n const directory = options.directory || './public';\n const enabled = options.enabled !== false;\n const staticPath = resolve(process.cwd(), directory);\n const indexPath = resolve(staticPath, 'index.html');\n\n return (req, res, next) => {\n // Only handle root path\n if (req.path !== '/') {\n next();\n return;\n }\n\n // If static serving is enabled and index.html exists, let static middleware handle it\n if (enabled && existsSync(indexPath)) {\n next();\n return;\n }\n\n // Otherwise, show default homepage with available routes\n const host = req.get('host') || 'localhost:3000';\n const protocol = req.protocol;\n const baseUrl = `${protocol}://${host}`;\n\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.send(`<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>API Faker</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n line-height: 1.6;\n color: #333;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n min-height: 100vh;\n padding: 2rem;\n }\n .container {\n max-width: 800px;\n margin: 0 auto;\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n padding: 3rem;\n }\n h1 {\n color: #667eea;\n font-size: 2.5rem;\n margin-bottom: 1rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n }\n h2 {\n color: #555;\n font-size: 1.5rem;\n margin-top: 2rem;\n margin-bottom: 1rem;\n border-bottom: 2px solid #667eea;\n padding-bottom: 0.5rem;\n }\n .intro {\n color: #666;\n font-size: 1.1rem;\n margin-bottom: 2rem;\n }\n .endpoint {\n background: #f8f9fa;\n border-left: 4px solid #667eea;\n padding: 1rem;\n margin-bottom: 1rem;\n border-radius: 4px;\n }\n .endpoint a {\n color: #667eea;\n text-decoration: none;\n font-family: 'Monaco', 'Courier New', monospace;\n font-weight: bold;\n }\n .endpoint a:hover {\n text-decoration: underline;\n }\n .endpoint p {\n color: #666;\n margin-top: 0.5rem;\n font-size: 0.95rem;\n }\n .info-box {\n background: #e3f2fd;\n border-left: 4px solid #2196f3;\n padding: 1rem;\n margin-top: 2rem;\n border-radius: 4px;\n }\n .info-box p {\n color: #1565c0;\n margin: 0;\n }\n code {\n background: #f5f5f5;\n padding: 0.2rem 0.4rem;\n border-radius: 3px;\n font-family: 'Monaco', 'Courier New', monospace;\n font-size: 0.9em;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <h1>🚀 API Faker</h1>\n <p class=\"intro\">\n Your JSON REST API is up and running! Use the endpoints below to interact with your data.\n </p>\n\n <h2>📡 Endpoints</h2>\n <div class=\"endpoint\">\n <a href=\"${baseUrl}/db\" target=\"_blank\">${baseUrl}/db</a>\n <p>View the full database</p>\n </div>\n\n <h2>💡 Tips</h2>\n <div class=\"info-box\">\n <p>\n Use query parameters to filter, sort, and paginate your data. \n Examples: <code>?_sort=name&_order=asc</code>, <code>?_page=1&_limit=10</code>\n </p>\n </div>\n </div>\n</body>\n</html>`);\n };\n}\n","import { pathToFileURL } from 'node:url';\nimport { RequestHandler } from 'express';\n\n/**\n * Load a JavaScript or TypeScript module dynamically\n *\n * @param filePath - Path to the module file\n * @returns Module exports\n * @throws Error if module cannot be loaded\n *\n * @example\n * ```typescript\n * const module = await loadModule('./routes.js');\n * ```\n */\nexport async function loadModule(filePath: string): Promise<unknown> {\n try {\n const fileUrl = pathToFileURL(filePath).href;\n const module = (await import(fileUrl)) as { default?: unknown } & Record<string, unknown>;\n return module;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to load module '${filePath}': ${message}\\n` +\n `\\nMake sure:\\n` +\n ` - The file exists and is a valid JavaScript file\\n` +\n ` - The file doesn't have syntax errors\\n` +\n ` - All dependencies are installed`\n );\n }\n}\n\n/**\n * Load custom middleware from a file\n *\n * @param filePath - Path to the middleware file\n * @returns Array of Express middleware functions\n * @throws Error if middleware file is invalid\n *\n * @example\n * ```typescript\n * // middleware.js\n * module.exports = (req, res, next) => {\n * console.log('Custom middleware');\n * next();\n * };\n *\n * // Or export array\n * module.exports = [\n * (req, res, next) => { console.log('First'); next(); },\n * (req, res, next) => { console.log('Second'); next(); }\n * ];\n *\n * // Usage\n * const middlewares = await loadMiddlewares('./middleware.js');\n * middlewares.forEach(mw => app.use(mw));\n * ```\n */\nexport async function loadMiddlewares(filePath: string): Promise<RequestHandler[]> {\n const module = await loadModule(filePath);\n\n // Check for default export first (ES modules or wrapped CommonJS)\n let middlewareExport: unknown;\n if (typeof module === 'object' && module !== null && 'default' in module) {\n const defaultExport = (module as { default: unknown }).default;\n // If default is also an object with a default property, unwrap it\n if (typeof defaultExport === 'object' && defaultExport !== null && 'default' in defaultExport) {\n middlewareExport = (defaultExport as { default: unknown }).default;\n } else {\n middlewareExport = defaultExport;\n }\n } else {\n middlewareExport = module;\n }\n\n // Normalize to array\n const middlewares = Array.isArray(middlewareExport) ? middlewareExport : [middlewareExport];\n\n // Validate all are functions\n for (let i = 0; i < middlewares.length; i++) {\n const mw: unknown = middlewares[i];\n if (typeof mw !== 'function') {\n const indexStr = String(i);\n throw new Error(\n `Middleware file '${filePath}' at index ${indexStr} is not a function, got ${typeof mw}`\n );\n }\n }\n\n return middlewares as RequestHandler[];\n}\n","import { RequestHandler } from 'express';\nimport { readFile } from 'node:fs/promises';\n\n/**\n * Route rewrite rules mapping\n * Maps incoming URL patterns to target URL patterns\n *\n * @example\n * ```json\n * {\n * \"/api/*\": \"/$1\",\n * \"/me\": \"/profile\",\n * \"/news/top\": \"/news?_sort=date&_order=asc&_limit=10\"\n * }\n * ```\n */\nexport type RewriteRules = Record<string, string>;\n\n/**\n * Load rewrite rules from a JSON file\n *\n * @param filePath - Path to the JSON file containing route mappings\n * @returns Rewrite rules object\n * @throws Error if file cannot be loaded or parsed\n *\n * @example\n * ```typescript\n * const rules = await loadRewriteRules('./routes.json');\n * const middleware = createRewriterMiddleware(rules);\n * app.use(middleware);\n * ```\n */\nexport async function loadRewriteRules(filePath: string): Promise<RewriteRules> {\n try {\n const content = await readFile(filePath, 'utf-8');\n const rules = JSON.parse(content) as unknown;\n\n if (typeof rules !== 'object' || rules === null || Array.isArray(rules)) {\n throw new Error('Routes file must contain a JSON object with route mappings');\n }\n\n // Validate all keys and values are strings\n for (const [key, value] of Object.entries(rules)) {\n if (typeof value !== 'string') {\n throw new Error(`Route mapping for '${key}' must be a string, got ${typeof value}`);\n }\n }\n\n return rules as RewriteRules;\n } catch (error) {\n if (error instanceof Error && error.message.includes('Routes file must contain')) {\n throw error;\n }\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to load routes from '${filePath}': ${message}\\n` +\n `\\nExpected format:\\n` +\n `{\\n` +\n ` \"/api/*\": \"/$1\",\\n` +\n ` \"/users/:id\": \"/api/users/:id\"\\n` +\n `}\\n` +\n `\\nSee examples/routes.json for more examples.`\n );\n }\n}\n\n/**\n * Convert a route pattern with wildcards and parameters to a RegExp\n *\n * @param pattern - Route pattern (e.g., '/api/*', '/posts/:id')\n * @returns Regular expression and parameter names\n *\n * @example\n * ```typescript\n * const { regex, params } = patternToRegex('/api/*');\n * // regex: /^\\/api\\/(.*)$/\n * // params: ['$1']\n *\n * const { regex, params } = patternToRegex('/posts/:id/comments/:commentId');\n * // regex: /^\\/posts\\/([^\\/]+)\\/comments\\/([^\\/]+)$/\n * // params: ['id', 'commentId']\n * ```\n */\nfunction patternToRegex(pattern: string): { regex: RegExp; params: string[] } {\n const params: string[] = [];\n\n // Escape special regex characters except * and :\n let regexPattern = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Replace :param with capturing group and collect param names\n regexPattern = regexPattern.replace(/:([^/]+)/g, (_match, param: string) => {\n params.push(param);\n return '([^/]+)';\n });\n\n // Replace * with capturing group\n regexPattern = regexPattern.replace(/\\*/g, () => {\n params.push(`$${String(params.length + 1)}`);\n return '(.*)';\n });\n\n return {\n regex: new RegExp(`^${regexPattern}$`),\n params,\n };\n}\n\n/**\n * Rewrite a URL based on a pattern and substitution\n *\n * @param url - Original URL\n * @param fromPattern - Pattern to match (with * or :param)\n * @param toPattern - Target pattern with $1, $2, etc. or :param\n * @returns Rewritten URL or null if pattern doesn't match\n *\n * @example\n * ```typescript\n * rewriteUrl('/api/posts', '/api/*', '/$1') // → '/posts'\n * rewriteUrl('/me', '/me', '/profile') // → '/profile'\n * rewriteUrl('/posts/1', '/posts/:id', '/items/:id') // → '/items/1'\n * ```\n */\nfunction rewriteUrl(url: string, fromPattern: string, toPattern: string): string | null {\n const { regex, params } = patternToRegex(fromPattern);\n const match = url.match(regex);\n\n if (!match) {\n return null;\n }\n\n // Extract captured values\n const captures = match.slice(1);\n\n // Build the replacement URL\n let result = toPattern;\n\n // Replace $1, $2, etc. with captured values\n for (let i = 0; i < captures.length; i++) {\n const value = captures[i];\n if (value !== undefined) {\n result = result.replace(`$${String(i + 1)}`, value);\n }\n }\n\n // Replace :param with captured values (for named parameters)\n for (let i = 0; i < params.length; i++) {\n const param = params[i];\n const value = captures[i];\n if (param && !param.startsWith('$') && value !== undefined) {\n result = result.replace(`:${param}`, value);\n }\n }\n\n return result;\n}\n\n/**\n * Create Express middleware that rewrites URLs based on rules\n *\n * @param rules - Route rewrite rules\n * @returns Express middleware function\n *\n * @example\n * ```typescript\n * const rules = {\n * '/api/*': '/$1',\n * '/me': '/profile',\n * '/posts/:category': '/posts?category=:category'\n * };\n *\n * const rewriter = createRewriterMiddleware(rules);\n * app.use(rewriter);\n * ```\n */\nexport function createRewriterMiddleware(rules: RewriteRules): RequestHandler {\n return (req, _res, next) => {\n // Try each rule in order\n for (const [from, to] of Object.entries(rules)) {\n const rewritten = rewriteUrl(req.url, from, to);\n\n if (rewritten !== null) {\n req.url = rewritten;\n break; // Apply only the first matching rule\n }\n }\n\n next();\n };\n}\n","import { readFileSync, existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\n/**\n * Find the closest matching string using Levenshtein distance\n *\n * @param input - Input string to match\n * @param candidates - Array of candidate strings\n * @returns Closest match or null if no good match found\n */\nfunction findClosestMatch(input: string, candidates: string[]): string | null {\n /* eslint-disable @typescript-eslint/no-non-null-assertion */\n const levenshtein = (a: string, b: string): number => {\n const matrix: number[][] = [];\n\n for (let i = 0; i <= b.length; i++) {\n matrix[i] = [i];\n }\n\n for (let j = 0; j <= a.length; j++) {\n matrix[0]![j] = j;\n }\n\n for (let i = 1; i <= b.length; i++) {\n for (let j = 1; j <= a.length; j++) {\n if (b.charAt(i - 1) === a.charAt(j - 1)) {\n matrix[i]![j] = matrix[i - 1]![j - 1]!;\n } else {\n matrix[i]![j] = Math.min(\n matrix[i - 1]![j - 1]! + 1,\n matrix[i]![j - 1]! + 1,\n matrix[i - 1]![j]! + 1\n );\n }\n }\n }\n\n return matrix[b.length]![a.length]!;\n };\n /* eslint-enable @typescript-eslint/no-non-null-assertion */\n\n let closestMatch: string | null = null;\n let minDistance = Infinity;\n\n for (const candidate of candidates) {\n const distance = levenshtein(input.toLowerCase(), candidate.toLowerCase());\n if (distance < minDistance && distance <= 3) {\n // Only suggest if distance is 3 or less\n minDistance = distance;\n closestMatch = candidate;\n }\n }\n\n return closestMatch;\n}\n\n/**\n * Configuration options that can be specified in config file or CLI\n */\nexport interface Config {\n port?: number;\n host?: string;\n watch?: boolean;\n routes?: string;\n middlewares?: string;\n static?: string;\n readOnly?: boolean;\n noCors?: boolean;\n noGzip?: boolean;\n snapshots?: string;\n delay?: number;\n id?: string;\n foreignKeySuffix?: string;\n quiet?: boolean;\n}\n\n/**\n * Load configuration from a JSON file\n *\n * @param configPath - Path to the configuration file\n * @returns Configuration object or null if file doesn't exist\n * @throws Error if file exists but is invalid JSON or contains invalid options\n *\n * @example\n * ```typescript\n * const config = loadConfig('api-faker.json');\n * if (config) {\n * console.log('Loaded config:', config);\n * }\n * ```\n */\nexport function loadConfig(configPath: string): Config | null {\n const resolvedPath = resolve(configPath);\n\n // If file doesn't exist, return null (not an error)\n if (!existsSync(resolvedPath)) {\n return null;\n }\n\n try {\n const content = readFileSync(resolvedPath, 'utf-8');\n const config = JSON.parse(content) as unknown;\n\n // Validate config is an object\n if (typeof config !== 'object' || config === null || Array.isArray(config)) {\n throw new Error('Config file must contain a JSON object');\n }\n\n // Validate config properties\n validateConfig(config as Record<string, unknown>);\n\n return config as Config;\n } catch (error) {\n if (error instanceof Error && error.message.includes('Config file must contain')) {\n throw error;\n }\n throw new Error(\n `Failed to load config from '${configPath}': ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * Validate configuration object\n *\n * @param config - Configuration object to validate\n * @throws Error if configuration contains invalid options\n */\nfunction validateConfig(config: Record<string, unknown>): void {\n const validOptions = new Set([\n 'port',\n 'host',\n 'watch',\n 'routes',\n 'middlewares',\n 'static',\n 'readOnly',\n 'noCors',\n 'noGzip',\n 'snapshots',\n 'delay',\n 'id',\n 'foreignKeySuffix',\n 'quiet',\n ]);\n\n // Check for unknown options\n for (const key of Object.keys(config)) {\n if (!validOptions.has(key)) {\n const suggestion = findClosestMatch(key, Array.from(validOptions));\n const didYouMean = suggestion ? ` Did you mean '${suggestion}'?` : '';\n throw new Error(\n `Unknown config option: '${key}'.${didYouMean} Valid options are: ${Array.from(validOptions).join(', ')}`\n );\n }\n }\n\n // Validate types\n if (\n 'port' in config &&\n (typeof config.port !== 'number' || config.port < 0 || config.port > 65535)\n ) {\n throw new Error(\"Config option 'port' must be a number between 0 and 65535\");\n }\n\n if ('host' in config && typeof config.host !== 'string') {\n throw new Error(\"Config option 'host' must be a string\");\n }\n\n if ('watch' in config && typeof config.watch !== 'boolean') {\n throw new Error(\"Config option 'watch' must be a boolean\");\n }\n\n if ('routes' in config && typeof config.routes !== 'string') {\n throw new Error(\"Config option 'routes' must be a string\");\n }\n\n if ('middlewares' in config && typeof config.middlewares !== 'string') {\n throw new Error(\"Config option 'middlewares' must be a string\");\n }\n\n if ('static' in config && typeof config.static !== 'string') {\n throw new Error(\"Config option 'static' must be a string\");\n }\n\n if ('readOnly' in config && typeof config.readOnly !== 'boolean') {\n throw new Error(\"Config option 'readOnly' must be a boolean\");\n }\n\n if ('noCors' in config && typeof config.noCors !== 'boolean') {\n throw new Error(\"Config option 'noCors' must be a boolean\");\n }\n\n if ('noGzip' in config && typeof config.noGzip !== 'boolean') {\n throw new Error(\"Config option 'noGzip' must be a boolean\");\n }\n\n if ('snapshots' in config && typeof config.snapshots !== 'string') {\n throw new Error(\"Config option 'snapshots' must be a string\");\n }\n\n if ('delay' in config && (typeof config.delay !== 'number' || config.delay < 0)) {\n throw new Error(\"Config option 'delay' must be a non-negative number\");\n }\n\n if ('id' in config && typeof config.id !== 'string') {\n throw new Error(\"Config option 'id' must be a string\");\n }\n\n if ('foreignKeySuffix' in config && typeof config.foreignKeySuffix !== 'string') {\n throw new Error(\"Config option 'foreignKeySuffix' must be a string\");\n }\n\n if ('quiet' in config && typeof config.quiet !== 'boolean') {\n throw new Error(\"Config option 'quiet' must be a boolean\");\n }\n}\n\n/**\n * Merge CLI arguments with config file\n * CLI arguments take precedence over config file values\n *\n * @param cliConfig - Configuration from CLI arguments\n * @param fileConfig - Configuration from config file\n * @returns Merged configuration\n *\n * @example\n * ```typescript\n * const fileConfig = loadConfig('api-faker.json');\n * const merged = mergeConfig(cliArgs, fileConfig);\n * ```\n */\nexport function mergeConfig(cliConfig: Partial<Config>, fileConfig: Config | null): Config {\n if (!fileConfig) {\n return cliConfig as Config;\n }\n\n // CLI arguments override config file values\n return {\n ...fileConfig,\n ...cliConfig,\n };\n}\n"],"mappings":"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","names":["import_fs","import_path","module","import_express","pc","import_express","import_fs","import_path","express","module","express","cors","compression","yargs"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/database.ts","../src/server.ts","../src/router.ts","../src/logger.ts","../src/query.ts","../src/relationships.ts","../src/static.ts","../src/loader.ts","../src/rewriter.ts","../src/config.ts"],"sourcesContent":["import yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { readFileSync, existsSync } from 'fs';\nimport { resolve } from 'path';\nimport { watch } from 'chokidar';\nimport { Database } from './database';\nimport { createServer, startServer, ServerOptions } from './server';\nimport { loadConfig, mergeConfig, Config } from './config';\nimport { logger } from './logger';\n\n/**\n * CLI configuration interface\n */\ninterface CliConfig {\n source: string | undefined;\n port: number;\n host: string;\n watch: boolean;\n routes: string | undefined;\n middlewares: string | undefined;\n static: string | undefined;\n noStatic: boolean;\n readOnly: boolean;\n noCors: boolean;\n noGzip: boolean;\n snapshots: string;\n delay: number | undefined;\n id: string;\n foreignKeySuffix: string;\n quiet: boolean;\n config: string;\n}\n\n/**\n * Get package version\n */\nfunction getVersion(): string {\n try {\n const packageJson = JSON.parse(\n readFileSync(resolve(__dirname, '../package.json'), 'utf-8')\n ) as { version: string };\n return packageJson.version;\n } catch {\n return '0.0.0';\n }\n}\n\n/**\n * Parse and validate CLI arguments\n */\nfunction parseCli(): CliConfig {\n const argv = yargs(hideBin(process.argv))\n .scriptName('rest_api_faker')\n .usage('Usage: $0 [options] <source>')\n .example('$0 db.json', 'Start API Faker with db.json')\n .example('$0 file.js', 'Start API Faker with a JS file')\n .example('$0 http://example.com/db.json', 'Start API Faker with a remote schema')\n .option('config', {\n alias: 'c',\n type: 'string',\n description: 'Path to config file',\n default: 'rest_api_faker.json',\n })\n .option('port', {\n alias: 'p',\n type: 'number',\n description: 'Set port',\n default: 3000,\n })\n .option('host', {\n alias: 'H',\n type: 'string',\n description: 'Set host',\n default: 'localhost',\n })\n .option('watch', {\n alias: 'w',\n type: 'boolean',\n description: 'Watch file(s)',\n default: false,\n })\n .option('routes', {\n alias: 'r',\n type: 'string',\n description: 'Path to routes file',\n })\n .option('middlewares', {\n alias: 'm',\n type: 'string',\n description: 'Path to middleware file',\n })\n .option('static', {\n alias: 's',\n type: 'string',\n description: 'Set static files directory',\n default: './public',\n })\n .option('no-static', {\n type: 'boolean',\n description: 'Disable static file serving',\n default: false,\n })\n .option('read-only', {\n alias: 'ro',\n type: 'boolean',\n description: 'Allow only GET requests',\n default: false,\n })\n .option('no-cors', {\n alias: 'nc',\n type: 'boolean',\n description: 'Disable Cross-Origin Resource Sharing',\n default: false,\n })\n .option('no-gzip', {\n alias: 'ng',\n type: 'boolean',\n description: 'Disable GZIP Content-Encoding',\n default: false,\n })\n .option('snapshots', {\n alias: 'S',\n type: 'string',\n description: 'Set snapshots directory',\n default: '.',\n })\n .option('delay', {\n alias: 'd',\n type: 'number',\n description: 'Add delay to responses (ms)',\n })\n .option('id', {\n alias: 'i',\n type: 'string',\n description: 'Set database id property',\n default: 'id',\n })\n .option('foreignKeySuffix', {\n alias: 'fks',\n type: 'string',\n description: 'Set foreign key suffix',\n default: 'Id',\n })\n .option('quiet', {\n alias: 'q',\n type: 'boolean',\n description: 'Suppress log messages from output',\n default: false,\n })\n .help('help', 'Show help')\n .alias('h', 'help')\n .version(getVersion())\n .alias('v', 'version')\n .epilogue('For more information, visit https://github.com/hamidmayeli/rest_api_faker')\n .parseSync();\n\n // Load config file if it exists\n let fileConfig: Config | null = null;\n try {\n fileConfig = loadConfig(argv.config);\n } catch (error) {\n logger.error(\n `Failed to load config file: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n\n // Build CLI config object (only values explicitly provided by CLI)\n const cliConfig: Partial<Config> = {};\n\n // Only include CLI values that were explicitly set (not defaults)\n // We check if the value is different from the default or if it was provided\n if (argv.port !== 3000) cliConfig.port = argv.port;\n if (argv.host !== 'localhost') cliConfig.host = argv.host;\n if (argv.watch) cliConfig.watch = argv.watch;\n if (argv.routes) cliConfig.routes = argv.routes;\n if (argv.middlewares) cliConfig.middlewares = argv.middlewares;\n if (argv.static !== './public') cliConfig.static = argv.static;\n if (argv['read-only']) cliConfig.readOnly = argv['read-only'];\n if (argv['no-cors']) cliConfig.noCors = argv['no-cors'];\n if (argv['no-gzip']) cliConfig.noGzip = argv['no-gzip'];\n if (argv.snapshots !== '.') cliConfig.snapshots = argv.snapshots;\n if (argv.delay !== undefined) cliConfig.delay = argv.delay;\n if (argv.id !== 'id') cliConfig.id = argv.id;\n if (argv.foreignKeySuffix !== 'Id') cliConfig.foreignKeySuffix = argv.foreignKeySuffix;\n if (argv.quiet) cliConfig.quiet = argv.quiet;\n\n // Merge config file with CLI args (CLI takes precedence)\n const merged = mergeConfig(cliConfig, fileConfig);\n\n return {\n source: argv._[0] as string | undefined,\n port: merged.port ?? 3000,\n host: merged.host ?? 'localhost',\n watch: merged.watch ?? false,\n routes: merged.routes,\n middlewares: merged.middlewares,\n static: merged.static ?? './public',\n noStatic: argv['no-static'],\n readOnly: merged.readOnly ?? false,\n noCors: merged.noCors ?? false,\n noGzip: merged.noGzip ?? false,\n snapshots: merged.snapshots ?? '.',\n delay: merged.delay,\n id: merged.id ?? 'id',\n foreignKeySuffix: merged.foreignKeySuffix ?? 'Id',\n quiet: merged.quiet ?? false,\n config: argv.config,\n };\n}\n\n/**\n * Main CLI entry point\n */\nasync function main(): Promise<void> {\n const config = parseCli();\n\n if (!config.quiet) {\n logger.log(`\n ╔═══════════════════════════════════════╗\n ║ ║\n ║ API Faker v${getVersion().padEnd(19)}║\n ║ ║\n ╚═══════════════════════════════════════╝\n `);\n }\n\n if (!config.source) {\n logger.error('No source file specified');\n logger.info('Run \"rest_api_faker --help\" for usage information');\n process.exit(1);\n }\n\n if (!config.quiet) {\n logger.info(`Source: ${config.source}`);\n logger.info(`Port: ${String(config.port)}`);\n logger.info(`Host: ${config.host}`);\n logger.log('');\n logger.info('Loading database...');\n }\n\n try {\n // Initialize database\n const db = new Database(config.source, {\n idField: config.id,\n foreignKeySuffix: config.foreignKeySuffix,\n });\n\n await db.init();\n\n if (!config.quiet) {\n const data = db.getData();\n const resources = Object.keys(data);\n logger.success(`Loaded ${String(resources.length)} resource(s): ${resources.join(', ')}`);\n logger.log('');\n }\n\n // Create and start server\n const serverOptions: ServerOptions = {\n port: config.port,\n host: config.host,\n readOnly: config.readOnly,\n noCors: config.noCors,\n noGzip: config.noGzip,\n quiet: config.quiet,\n idField: config.id,\n foreignKeySuffix: config.foreignKeySuffix,\n enabled: !config.noStatic,\n };\n\n // Add static directory if specified\n if (config.static) {\n serverOptions.directory = config.static;\n }\n\n // Add custom routes if specified\n if (config.routes) {\n serverOptions.routes = config.routes;\n }\n\n // Add custom middlewares if specified\n if (config.middlewares) {\n serverOptions.middlewares = config.middlewares;\n }\n\n // Only add delay if it's defined\n if (config.delay !== undefined) {\n serverOptions.delay = config.delay;\n }\n\n const app = await createServer(db, serverOptions);\n\n const server = startServer(app, {\n port: config.port,\n host: config.host,\n quiet: config.quiet,\n });\n\n // Set up file watching if enabled\n if (config.watch && config.source && existsSync(config.source)) {\n const watcher = watch(config.source, {\n ignoreInitial: true,\n persistent: true,\n });\n\n watcher.on('change', (path) => {\n if (!config.quiet) {\n logger.log('');\n logger.info(`File changed: ${path}`);\n logger.info('Reloading database...');\n }\n\n db.init()\n .then(() => {\n if (!config.quiet) {\n const data = db.getData();\n const resources = Object.keys(data);\n logger.success(\n `Reloaded ${String(resources.length)} resource(s): ${resources.join(', ')}`\n );\n }\n })\n .catch((error: unknown) => {\n logger.error(\n `Failed to reload database: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n });\n });\n\n watcher.on('error', (error) => {\n logger.error(`Watcher error: ${error instanceof Error ? error.message : String(error)}`);\n });\n\n if (!config.quiet) {\n logger.info(`Watching ${config.source} for changes...`);\n logger.log('');\n }\n\n // Handle graceful shutdown\n process.on('SIGINT', () => {\n if (!config.quiet) {\n logger.log('');\n logger.info('Shutting down...');\n }\n watcher.close().catch(() => {\n // Ignore errors during shutdown\n });\n server.close(() => {\n process.exit(0);\n });\n });\n }\n } catch (error) {\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n}\n\n// Run CLI\nmain().catch((error: unknown) => {\n logger.error(`Fatal error: ${error instanceof Error ? error.message : 'Unknown error'}`);\n process.exit(1);\n});\n","import { Low } from 'lowdb';\nimport { JSONFile } from 'lowdb/node';\nimport { existsSync } from 'fs';\nimport { resolve, extname } from 'path';\nimport { pathToFileURL } from 'url';\n\n/**\n * Database data structure\n */\nexport interface DatabaseData {\n [key: string]: unknown;\n}\n\n/**\n * Database configuration options\n */\nexport interface DatabaseOptions {\n idField?: string;\n foreignKeySuffix?: string;\n}\n\n/**\n * Database class for managing JSON data with lowdb\n */\nexport class Database {\n private db: Low<DatabaseData>;\n private filePath: string;\n private options: Required<DatabaseOptions>;\n\n /**\n * Creates a new Database instance\n *\n * @param source - Path to JSON file or object with data\n * @param options - Database configuration options\n *\n * @example\n * ```typescript\n * const db = new Database('db.json', { idField: 'id' });\n * await db.init();\n * ```\n */\n constructor(source: string | DatabaseData, options: DatabaseOptions = {}) {\n this.options = {\n idField: options.idField || 'id',\n foreignKeySuffix: options.foreignKeySuffix || 'Id',\n };\n\n if (typeof source === 'string') {\n this.filePath = resolve(source);\n const adapter = new JSONFile<DatabaseData>(this.filePath);\n this.db = new Low(adapter, {});\n } else {\n this.filePath = '';\n // For in-memory database with object data\n const adapter = new JSONFile<DatabaseData>(':memory:');\n this.db = new Low(adapter, source);\n }\n }\n\n /**\n * Initialize the database by reading from file or using provided data\n * Supports .json, .js, .ts, and .mjs files\n *\n * @throws Error if file doesn't exist or contains invalid data\n */\n async init(): Promise<void> {\n if (this.filePath && !existsSync(this.filePath)) {\n const ext = this.filePath.endsWith('.js') ? '.js' : '.json';\n throw new Error(\n `Database file not found: ${this.filePath}\\n` +\n `\\nMake sure the file exists and the path is correct.\\n` +\n `Expected format: ${ext === '.js' ? 'JavaScript module exporting data' : 'JSON file with data structure'}`\n );\n }\n\n // Check if file is a JavaScript/TypeScript module\n if (this.filePath) {\n const ext = extname(this.filePath).toLowerCase();\n\n if (ext === '.js' || ext === '.mjs' || ext === '.cjs' || ext === '.ts') {\n // Load JavaScript module\n try {\n const fileUrl = pathToFileURL(this.filePath).href;\n const module = (await import(fileUrl)) as { default?: unknown } & Record<string, unknown>;\n const data: unknown = module.default ?? module;\n\n // If it's a function, call it to get the data\n if (typeof data === 'function') {\n const result: unknown = await Promise.resolve((data as () => unknown)());\n if (typeof result !== 'object' || result === null) {\n throw new Error('JavaScript module function must return an object');\n }\n this.db.data = result as DatabaseData;\n } else if (typeof data === 'object' && data !== null) {\n this.db.data = data as DatabaseData;\n } else {\n throw new Error('JavaScript module must export an object or function');\n }\n } catch (error) {\n throw new Error(\n `Failed to load JavaScript module: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n } else {\n // Load JSON file\n await this.db.read();\n }\n } else {\n // In-memory database\n await this.db.read();\n }\n\n if (typeof this.db.data !== 'object') {\n this.db.data = {};\n }\n\n // Ensure all collections are arrays or objects\n for (const key in this.db.data) {\n const value = this.db.data[key];\n if (value !== null && typeof value !== 'object') {\n throw new Error(`Invalid data structure: ${key} must be an array or object`);\n }\n }\n }\n\n /**\n * Get all data from the database\n *\n * @returns Complete database data\n */\n getData(): DatabaseData {\n return this.db.data;\n }\n\n /**\n * Get a specific collection (array) or resource (object)\n *\n * @param name - Name of the collection/resource\n * @returns Collection array, resource object, or undefined\n */\n getCollection(name: string): unknown {\n return this.db.data[name];\n }\n\n /**\n * Get a single item from a collection by ID\n *\n * @param collectionName - Name of the collection\n * @param id - ID of the item\n * @returns The item or undefined\n */\n getById(collectionName: string, id: string | number): unknown {\n const collection = this.db.data[collectionName];\n\n if (!Array.isArray(collection)) {\n return undefined;\n }\n\n return collection.find((item) => {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n const record = item as Record<string, unknown>;\n return record[this.options.idField] === id || record[this.options.idField] === Number(id);\n });\n }\n\n /**\n * Generate next ID for a collection\n *\n * @param collectionName - Name of the collection\n * @returns Next available ID\n */\n generateId(collectionName: string): number {\n const collection = this.db.data[collectionName];\n\n if (!Array.isArray(collection)) {\n return 1;\n }\n\n let maxId = 0;\n for (const item of collection) {\n if (typeof item === 'object' && item !== null) {\n const record = item as Record<string, unknown>;\n const idValue: unknown = record[this.options.idField];\n if (typeof idValue === 'number' && idValue > maxId) {\n maxId = idValue;\n }\n }\n }\n\n return maxId + 1;\n }\n\n /**\n * Create a new item in a collection\n *\n * @param collectionName - Name of the collection\n * @param data - Data to insert\n * @returns Created item with ID\n * @throws Error if collection is not an array\n */\n async create(\n collectionName: string,\n data: Record<string, unknown>\n ): Promise<Record<string, unknown>> {\n let collection = this.db.data[collectionName];\n\n // Create collection if it doesn't exist\n if (!collection) {\n collection = [];\n this.db.data[collectionName] = collection;\n }\n\n if (!Array.isArray(collection)) {\n throw new Error(`Cannot create in ${collectionName}: not a collection`);\n }\n\n // Generate ID if not provided or use provided ID\n const idValue: unknown =\n data[this.options.idField] !== undefined\n ? data[this.options.idField]\n : this.generateId(collectionName);\n\n // Check if ID already exists\n const existingItem = this.getById(collectionName, idValue as string | number);\n if (existingItem) {\n throw new Error(`Item with ${this.options.idField}=${String(idValue)} already exists`);\n }\n\n const newItem: Record<string, unknown> = { ...data, [this.options.idField]: idValue };\n collection.push(newItem);\n\n await this.save();\n return newItem;\n }\n\n /**\n * Update an item in a collection (full replacement)\n *\n * @param collectionName - Name of the collection\n * @param id - ID of the item\n * @param data - New data (ID field will be preserved)\n * @returns Updated item or undefined if not found\n */\n async update(\n collectionName: string,\n id: string | number,\n data: Record<string, unknown>\n ): Promise<Record<string, unknown> | undefined> {\n const collection = this.db.data[collectionName];\n\n if (!Array.isArray(collection)) {\n return undefined;\n }\n\n const index = collection.findIndex((item) => {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n const record = item as Record<string, unknown>;\n return record[this.options.idField] === id || record[this.options.idField] === Number(id);\n });\n\n if (index === -1) {\n return undefined;\n }\n\n // Preserve the ID (convert to number if it's a numeric string)\n const originalItem = collection[index] as Record<string, unknown>;\n const originalId: unknown = originalItem[this.options.idField];\n const updatedItem: Record<string, unknown> = { ...data, [this.options.idField]: originalId };\n collection[index] = updatedItem;\n\n await this.save();\n return updatedItem;\n }\n\n /**\n * Patch an item in a collection (partial update)\n *\n * @param collectionName - Name of the collection\n * @param id - ID of the item\n * @param data - Partial data to merge (ID field will be ignored)\n * @returns Updated item or undefined if not found\n */\n async patch(\n collectionName: string,\n id: string | number,\n data: Record<string, unknown>\n ): Promise<Record<string, unknown> | undefined> {\n const collection = this.db.data[collectionName];\n\n if (!Array.isArray(collection)) {\n return undefined;\n }\n\n const index = collection.findIndex((item) => {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n const record = item as Record<string, unknown>;\n return record[this.options.idField] === id || record[this.options.idField] === Number(id);\n });\n\n if (index === -1) {\n return undefined;\n }\n\n const currentItem = collection[index] as Record<string, unknown>;\n // Merge data but ignore ID field in the patch data\n const { [this.options.idField]: _ignoredId, ...patchData } = data;\n const patchedItem = { ...currentItem, ...patchData };\n\n collection[index] = patchedItem;\n\n await this.save();\n return patchedItem;\n }\n\n /**\n * Delete an item from a collection\n *\n * @param collectionName - Name of the collection\n * @param id - ID of the item\n * @returns true if deleted, false if not found\n */\n async delete(collectionName: string, id: string | number): Promise<boolean> {\n const collection = this.db.data[collectionName];\n\n if (!Array.isArray(collection)) {\n return false;\n }\n\n const index = collection.findIndex((item) => {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n const record = item as Record<string, unknown>;\n return record[this.options.idField] === id || record[this.options.idField] === Number(id);\n });\n\n if (index === -1) {\n return false;\n }\n\n collection.splice(index, 1);\n await this.save();\n return true;\n }\n\n /**\n * Update or create a singular resource\n *\n * @param resourceName - Name of the resource\n * @param data - Resource data\n * @returns Updated resource\n */\n async updateSingular(\n resourceName: string,\n data: Record<string, unknown>\n ): Promise<Record<string, unknown>> {\n this.db.data[resourceName] = data;\n await this.save();\n return data;\n }\n\n /**\n * Save the database to file\n */\n async save(): Promise<void> {\n await this.db.write();\n }\n\n /**\n * Check if a resource is a collection (array) or singular (object)\n *\n * @param name - Name of the resource\n * @returns true if collection, false if singular or doesn't exist\n */\n isCollection(name: string): boolean {\n return Array.isArray(this.db.data[name]);\n }\n\n /**\n * Get ID field name\n */\n getIdField(): string {\n return this.options.idField;\n }\n\n /**\n * Get foreign key suffix\n */\n getForeignKeySuffix(): string {\n return this.options.foreignKeySuffix;\n }\n}\n","import express, { Express } from 'express';\nimport cors from 'cors';\nimport compression from 'compression';\nimport { Database } from './database';\nimport { createRouter, RouterOptions } from './router';\nimport { createStaticMiddleware, createHomepageMiddleware, StaticOptions } from './static';\nimport { loadMiddlewares } from './loader';\nimport { loadRewriteRules, createRewriterMiddleware } from './rewriter';\nimport { logger } from './logger';\n\n/**\n * Server configuration options\n */\nexport interface ServerOptions extends RouterOptions, StaticOptions {\n port?: number;\n host?: string;\n noCors?: boolean;\n noGzip?: boolean;\n delay?: number;\n quiet?: boolean;\n routes?: string;\n middlewares?: string;\n}\n\n/**\n * Create Express server with API Faker\n *\n * @param db - Database instance\n * @param options - Server configuration options\n * @returns Express application\n *\n * @example\n * ```typescript\n * const db = new Database('db.json');\n * await db.init();\n * const app = await createServer(db, { port: 3000 });\n * ```\n */\nexport async function createServer(\n db: Database,\n options: Partial<ServerOptions> = {}\n): Promise<Express> {\n const app = express();\n\n // CORS\n if (!options.noCors) {\n app.use(cors());\n }\n\n // GZIP compression\n if (!options.noGzip) {\n app.use(compression());\n }\n\n // JSON body parser\n app.use(express.json());\n\n // Delay middleware (for testing/simulation)\n if (options.delay && options.delay > 0) {\n const delay = options.delay;\n app.use((_req, _res, next) => {\n setTimeout(() => {\n next();\n }, delay);\n });\n }\n\n // Request logger (unless quiet)\n if (!options.quiet) {\n app.use((req, _res, next) => {\n logger.request(req.method, req.url);\n next();\n });\n }\n\n // Custom middlewares (load before routes)\n if (options.middlewares) {\n try {\n const middlewares = await loadMiddlewares(options.middlewares);\n for (const middleware of middlewares) {\n app.use(middleware);\n }\n if (!options.quiet) {\n logger.success(`Loaded custom middlewares from ${options.middlewares}`);\n }\n } catch (error) {\n logger.error(\n `Failed to load middlewares: ${error instanceof Error ? error.message : String(error)}`\n );\n throw error;\n }\n }\n\n // Homepage middleware (must be before static to allow custom index.html)\n app.use(createHomepageMiddleware(options));\n\n // Static file server\n app.use(createStaticMiddleware(options));\n\n // Custom route rewriting (load before all routes)\n if (options.routes) {\n try {\n const rules = await loadRewriteRules(options.routes);\n const rewriter = createRewriterMiddleware(rules);\n app.use(rewriter);\n if (!options.quiet) {\n logger.success(`Loaded route rewrite rules from ${options.routes}`);\n }\n } catch (error) {\n logger.error(\n `Failed to load routes: ${error instanceof Error ? error.message : String(error)}`\n );\n throw error;\n }\n }\n\n // Special endpoint: /db (full database dump)\n app.get('/db', (_req, res) => {\n res.json(db.getData());\n });\n\n // API routes\n const router = createRouter(db, options);\n app.use(router);\n\n // 404 handler\n app.use((_req, res) => {\n res.status(404).json({ error: 'Not Found' });\n });\n\n return app;\n}\n\n/**\n * Start the server\n *\n * @param app - Express application\n * @param options - Server options (port, host)\n * @returns Server instance\n */\nexport function startServer(\n app: Express,\n options: Pick<ServerOptions, 'port' | 'host' | 'quiet'> = {}\n): ReturnType<Express['listen']> {\n const port = options.port || 3000;\n const host = options.host || 'localhost';\n\n return app.listen(port, host, () => {\n if (!options.quiet) {\n logger.banner([\n '🚀 API Faker is running!',\n '',\n ' Resources:',\n ` http://${host}:${String(port)}/`,\n '',\n ' Home:',\n ` http://${host}:${String(port)}`,\n ]);\n }\n });\n}\n","import { Router, Request, Response, NextFunction } from 'express';\nimport { Database } from './database';\nimport { logger } from './logger';\nimport { parseQuery, applyQuery, generateLinkHeader } from './query';\nimport { parseRelationships, applyRelationships, getForeignKey } from './relationships';\n\n/**\n * Helper to safely get route param (Express guarantees route params exist)\n */\nfunction getParam(req: Request, name: string): string {\n const value = req.params[name];\n if (value === undefined) {\n throw new Error(`Route parameter '${name}' is missing`);\n }\n return value;\n}\n\n/**\n * Router configuration options\n */\nexport interface RouterOptions {\n idField?: string;\n foreignKeySuffix?: string;\n readOnly?: boolean;\n}\n\n/**\n * Create API Faker router with CRUD operations\n *\n * @param db - Database instance\n * @param options - Router configuration options\n * @returns Express router\n *\n * @example\n * ```typescript\n * const db = new Database('db.json');\n * await db.init();\n * const router = createRouter(db);\n * app.use(router);\n * ```\n */\nexport function createRouter(db: Database, options: Partial<RouterOptions> = {}): Router {\n const router = Router();\n const readOnly = options.readOnly || false;\n const idField = options.idField || 'id';\n const foreignKeySuffix = options.foreignKeySuffix || 'Id';\n\n /**\n * Validate Content-Type for write operations\n */\n const validateContentType = (req: Request, _res: Response, next: NextFunction): void => {\n const contentType = req.get('Content-Type');\n if (!contentType || !contentType.includes('application/json')) {\n // Express still parses but we should warn about missing header\n // In real json-server, this would still work but without actual data modification\n logger.warn('Content-Type should be application/json');\n }\n next();\n };\n\n /**\n * GET /db - Return entire database\n */\n router.get('/db', (_req: Request, res: Response) => {\n res.json(db.getData());\n });\n\n /**\n * GET /:resource - Get all items in a collection or singular resource\n */\n router.get('/:resource', (req: Request, res: Response): void => {\n const resource = getParam(req, 'resource');\n const data = db.getCollection(resource);\n\n if (data === undefined) {\n res.status(404).json({ error: `Resource '${resource}' not found` });\n return;\n }\n // For collections (arrays), apply query parameters\n if (Array.isArray(data)) {\n const queryOptions = parseQuery(req);\n const { data: filtered, total } = applyQuery(data, queryOptions);\n\n // Apply relationships (_embed, _expand)\n const { embed, expand } = parseRelationships(req.query as Record<string, unknown>);\n const withRelationships = applyRelationships(\n filtered as Record<string, unknown>[],\n resource,\n embed,\n expand,\n db,\n idField,\n foreignKeySuffix\n );\n\n // Add X-Total-Count header\n res.set('X-Total-Count', String(total));\n\n // Add Link header for pagination\n if (queryOptions.page !== undefined && queryOptions.limit !== undefined) {\n const linkHeader = generateLinkHeader(req, queryOptions.page, queryOptions.limit, total);\n res.set('Link', linkHeader);\n }\n\n res.json(withRelationships);\n return;\n }\n\n // For singular resources (objects), return as-is\n res.json(data);\n });\n\n /**\n * GET /:resource/:id - Get single item by ID\n */\n router.get('/:resource/:id', (req: Request, res: Response): void => {\n const resource = getParam(req, 'resource');\n const id = getParam(req, 'id');\n\n // Check if resource is a collection\n if (!db.isCollection(resource)) {\n res.status(404).json({ error: `Collection '${resource}' not found` });\n return;\n }\n\n const item = db.getById(resource, id);\n\n if (!item) {\n res.status(404).json({ error: `Item with id '${id}' not found in '${resource}'` });\n return;\n }\n\n // Apply relationships if requested\n const { embed, expand } = parseRelationships(req.query as Record<string, unknown>);\n if (embed.length > 0 || expand.length > 0) {\n const withRelationships = applyRelationships(\n [item as Record<string, unknown>],\n resource,\n embed,\n expand,\n db,\n idField,\n foreignKeySuffix\n );\n res.json(withRelationships[0]);\n return;\n }\n\n res.json(item);\n });\n\n /**\n * GET /:parent/:parentId/:children - Get nested children\n */\n router.get('/:parent/:parentId/:children', (req: Request, res: Response): void => {\n const parent = getParam(req, 'parent');\n const parentId = getParam(req, 'parentId');\n const children = getParam(req, 'children');\n\n // Verify parent exists\n if (!db.isCollection(parent)) {\n res.status(404).json({ error: `Collection '${parent}' not found` });\n return;\n }\n\n const parentItem = db.getById(parent, parentId);\n if (!parentItem) {\n res.status(404).json({ error: `Parent item with id '${parentId}' not found in '${parent}'` });\n return;\n }\n\n // Get children collection\n const childrenData = db.getCollection(children);\n if (!Array.isArray(childrenData)) {\n res.status(404).json({ error: `Collection '${children}' not found` });\n return;\n }\n\n // Filter children by parent foreign key\n const foreignKey = getForeignKey(parent, foreignKeySuffix);\n const filtered = childrenData.filter((child) => {\n if (typeof child !== 'object' || child === null) return false;\n const childFk = (child as Record<string, unknown>)[foreignKey];\n return (\n childFk === parentId ||\n (typeof childFk === 'number' || typeof childFk === 'string'\n ? String(childFk) === parentId\n : false)\n );\n });\n\n // Apply query parameters\n const queryOptions = parseQuery(req);\n const { data: result, total } = applyQuery(filtered, queryOptions);\n\n res.set('X-Total-Count', String(total));\n res.json(result);\n });\n\n /**\n * POST /:parent/:parentId/:children - Create nested child\n */\n router.post(\n '/:parent/:parentId/:children',\n validateContentType,\n async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const parent = getParam(req, 'parent');\n const parentId = getParam(req, 'parentId');\n const children = getParam(req, 'children');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n // Verify parent exists\n if (!db.isCollection(parent)) {\n return res.status(404).json({ error: `Collection '${parent}' not found` });\n }\n\n const parentItem = db.getById(parent, parentId);\n if (!parentItem) {\n return res\n .status(404)\n .json({ error: `Parent item with id '${parentId}' not found in '${parent}'` });\n }\n\n // Auto-set foreign key\n const foreignKey = getForeignKey(parent, foreignKeySuffix);\n data[foreignKey] = parentId;\n\n try {\n const created = await db.create(children, data);\n return res.status(201).json(created);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n }\n );\n\n /**\n * POST /:resource - Create new item\n */\n router.post('/:resource', validateContentType, async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n try {\n // Handle singular resources\n if (!db.isCollection(resource) && db.getCollection(resource) !== undefined) {\n const updated = await db.updateSingular(resource, data);\n return res.status(200).json(updated);\n }\n\n // Create in collection\n const created = await db.create(resource, data);\n return res.status(201).json(created);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n });\n\n /**\n * PUT /:resource/:id - Full update of item\n */\n router.put('/:resource/:id', validateContentType, async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const id = getParam(req, 'id');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n if (!db.isCollection(resource)) {\n return res.status(404).json({ error: `Collection '${resource}' not found` });\n }\n\n try {\n const updated = await db.update(resource, id, data);\n\n if (!updated) {\n return res.status(404).json({ error: `Item with id '${id}' not found in '${resource}'` });\n }\n\n return res.json(updated);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n });\n\n /**\n * PATCH /:resource/:id - Partial update of item\n */\n router.patch('/:resource/:id', validateContentType, async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const id = getParam(req, 'id');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n if (!db.isCollection(resource)) {\n return res.status(404).json({ error: `Collection '${resource}' not found` });\n }\n\n try {\n const patched = await db.patch(resource, id, data);\n\n if (!patched) {\n return res.status(404).json({ error: `Item with id '${id}' not found in '${resource}'` });\n }\n\n return res.json(patched);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n });\n\n /**\n * PUT /:resource - Full update of singular resource\n */\n router.put('/:resource', validateContentType, async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n // Only allow for singular resources (objects, not arrays)\n if (db.isCollection(resource)) {\n return res\n .status(400)\n .json({\n error: `Cannot PUT to collection '${resource}'. Use POST or PUT /${resource}/:id`,\n });\n }\n\n try {\n const updated = await db.updateSingular(resource, data);\n return res.json(updated);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n });\n\n /**\n * PATCH /:resource - Partial update of singular resource\n */\n router.patch('/:resource', validateContentType, async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const data = req.body as Record<string, unknown>;\n\n if (typeof data !== 'object') {\n return res.status(400).json({ error: 'Request body must be a JSON object' });\n }\n\n // Only allow for singular resources\n if (db.isCollection(resource)) {\n return res\n .status(400)\n .json({ error: `Cannot PATCH collection '${resource}'. Use PATCH /${resource}/:id` });\n }\n\n const current = db.getCollection(resource) as Record<string, unknown> | undefined;\n\n if (!current || typeof current !== 'object') {\n return res.status(404).json({ error: `Resource '${resource}' not found` });\n }\n\n try {\n const merged = { ...current, ...data };\n const updated = await db.updateSingular(resource, merged);\n return res.json(updated);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return res.status(400).json({ error: message });\n }\n });\n\n /**\n * DELETE /:resource/:id - Delete item by ID\n */\n router.delete('/:resource/:id', async (req: Request, res: Response) => {\n if (readOnly) {\n return res.status(403).json({ error: 'Read-only mode enabled' });\n }\n\n const resource = getParam(req, 'resource');\n const id = getParam(req, 'id');\n\n if (!db.isCollection(resource)) {\n return res.status(404).json({ error: `Collection '${resource}' not found` });\n }\n\n const deleted = await db.delete(resource, id);\n\n if (!deleted) {\n return res.status(404).json({ error: `Item with id '${id}' not found in '${resource}'` });\n }\n\n // Return 204 No Content\n return res.status(204).send();\n });\n\n return router;\n}\n","import pc from 'picocolors';\n\n/**\n * Logger utility for colored console output\n *\n * Provides consistent, color-coded logging throughout the application.\n * Follows a standard format: [LEVEL] Message\n */\nexport const logger = {\n /**\n * Log success message in green\n *\n * @param message - Success message\n *\n * @example\n * ```typescript\n * logger.success('Server started successfully');\n * // Output: ✓ Server started successfully (in green)\n * ```\n */\n success(message: string): void {\n console.log(pc.green(`✓ ${message}`));\n },\n\n /**\n * Log error message in red\n *\n * @param message - Error message\n *\n * @example\n * ```typescript\n * logger.error('Failed to load file');\n * // Output: ✗ Failed to load file (in red)\n * ```\n */\n error(message: string): void {\n console.error(pc.red(`✗ ${message}`));\n },\n\n /**\n * Log warning message in yellow\n *\n * @param message - Warning message\n *\n * @example\n * ```typescript\n * logger.warn('Using default port');\n * // Output: ⚠ Using default port (in yellow)\n * ```\n */\n warn(message: string): void {\n console.warn(pc.yellow(`⚠ ${message}`));\n },\n\n /**\n * Log info message in cyan\n *\n * @param message - Info message\n *\n * @example\n * ```typescript\n * logger.info('Watching for changes...');\n * // Output: ℹ Watching for changes... (in cyan)\n * ```\n */\n info(message: string): void {\n console.log(pc.cyan(`ℹ ${message}`));\n },\n\n /**\n * Log plain message without color\n *\n * @param message - Message to log\n *\n * @example\n * ```typescript\n * logger.log('http://localhost:3000');\n * // Output: http://localhost:3000\n * ```\n */\n log(message: string): void {\n console.log(message);\n },\n\n /**\n * Log request in gray (for non-quiet mode)\n *\n * @param method - HTTP method\n * @param url - Request URL\n *\n * @example\n * ```typescript\n * logger.request('GET', '/api/users');\n * // Output: [timestamp] GET /api/users (in gray)\n * ```\n */\n request(method: string, url: string): void {\n const timestamp = new Date().toLocaleTimeString();\n console.log(pc.gray(`[${timestamp}] ${method} ${url}`));\n },\n\n /**\n * Log formatted banner\n *\n * @param lines - Array of lines to display\n *\n * @example\n * ```typescript\n * logger.banner([\n * '🚀 API Faker is running!',\n * '',\n * ' Resources:',\n * ' http://localhost:3000/'\n * ]);\n * ```\n */\n banner(lines: string[]): void {\n console.log();\n for (const line of lines) {\n // Color URLs in cyan\n if (line.includes('http://') || line.includes('https://')) {\n const colored = line.replace(/(https?:\\/\\/[^\\s]+)/g, (url) => pc.cyan(url));\n console.log(colored);\n } else if (line.startsWith('🚀')) {\n // Color rocket emoji line in bold\n console.log(pc.bold(line));\n } else {\n console.log(line);\n }\n }\n console.log();\n },\n};\n","/**\n * Query processing module for filtering, sorting, pagination, etc.\n */\n\nimport type { Request } from 'express';\n\n/**\n * Query options extracted from request\n */\nexport interface QueryOptions {\n filters: Record<string, string | string[]>;\n operators: Record<string, Record<string, string>>;\n sort: string[];\n order: string[];\n page?: number;\n limit?: number;\n start?: number;\n end?: number;\n q?: string;\n}\n\n/**\n * Parse query parameters from request\n *\n * @param req - Express request object\n * @returns Parsed query options\n *\n * @example\n * parseQuery(req) // { filters: { title: 'value' }, sort: ['id'], order: ['asc'] }\n */\nexport function parseQuery(req: Request): QueryOptions {\n const query = req.query;\n const filters: Record<string, string | string[]> = {};\n const operators: Record<string, Record<string, string>> = {};\n const sort: string[] = [];\n const order: string[] = [];\n let page: number | undefined;\n let limit: number | undefined;\n let start: number | undefined;\n let end: number | undefined;\n let q: string | undefined;\n\n for (const [key, value] of Object.entries(query)) {\n // Skip non-string and non-array values\n const stringValue =\n typeof value === 'string'\n ? value\n : Array.isArray(value) && value.length > 0 && typeof value[0] === 'string'\n ? value[0]\n : null;\n\n if (stringValue === null && !Array.isArray(value)) {\n continue;\n }\n\n // Special query parameters\n if (key === '_sort') {\n if (typeof value === 'string') {\n sort.push(...value.split(','));\n } else if (Array.isArray(value)) {\n for (const v of value) {\n if (typeof v === 'string') {\n sort.push(v);\n }\n }\n }\n continue;\n }\n\n if (key === '_order') {\n if (typeof value === 'string') {\n order.push(...value.split(','));\n } else if (Array.isArray(value)) {\n for (const v of value) {\n if (typeof v === 'string') {\n order.push(v);\n }\n }\n }\n continue;\n }\n\n if (key === '_page' && stringValue) {\n const parsed = parseInt(stringValue, 10);\n if (!isNaN(parsed) && parsed > 0) {\n page = parsed;\n }\n continue;\n }\n\n if (key === '_limit' && stringValue) {\n const parsed = parseInt(stringValue, 10);\n if (!isNaN(parsed) && parsed > 0) {\n limit = parsed;\n }\n continue;\n }\n\n if (key === '_start' && stringValue) {\n const parsed = parseInt(stringValue, 10);\n if (!isNaN(parsed) && parsed >= 0) {\n start = parsed;\n }\n continue;\n }\n\n if (key === '_end' && stringValue) {\n const parsed = parseInt(stringValue, 10);\n if (!isNaN(parsed) && parsed >= 0) {\n end = parsed;\n }\n continue;\n }\n\n if (key === 'q' && stringValue) {\n q = stringValue;\n continue;\n }\n\n // Operator filters (_gte, _lte, _ne, _like)\n const operatorMatch = key.match(/^(.+)_(gte|lte|ne|like)$/);\n if (operatorMatch && stringValue) {\n const field = operatorMatch[1];\n const operator = operatorMatch[2];\n\n if (field && operator) {\n if (!operators[field]) {\n operators[field] = {};\n }\n operators[field][operator] = stringValue;\n }\n continue;\n }\n\n // Regular filters\n if (typeof value === 'string') {\n filters[key] = value;\n } else if (Array.isArray(value)) {\n const stringValues = value.filter((v): v is string => typeof v === 'string');\n if (stringValues.length > 0) {\n filters[key] = stringValues;\n }\n }\n }\n\n const result: QueryOptions = {\n filters,\n operators,\n sort,\n order,\n };\n\n if (page !== undefined) result.page = page;\n if (limit !== undefined) result.limit = limit;\n if (start !== undefined) result.start = start;\n if (end !== undefined) result.end = end;\n if (q !== undefined) result.q = q;\n\n return result;\n}\n\n/**\n * Get nested property value from object\n *\n * @param obj - Object to get property from\n * @param path - Dot-separated property path\n * @returns Property value or undefined\n *\n * @example\n * getNestedValue({ user: { name: 'John' } }, 'user.name') // 'John'\n */\nfunction getNestedValue(obj: unknown, path: string): unknown {\n if (typeof obj !== 'object' || obj === null) {\n return undefined;\n }\n\n const keys = path.split('.');\n let current: unknown = obj;\n\n for (const key of keys) {\n if (typeof current !== 'object' || current === null || !(key in current)) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[key];\n }\n\n return current;\n}\n\n/**\n * Check if item matches filter criteria\n *\n * @param item - Item to check\n * @param filters - Filter criteria\n * @returns True if item matches all filters\n *\n * @example\n * matchesFilters({ title: 'test' }, { title: 'test' }) // true\n */\nfunction matchesFilters(item: unknown, filters: Record<string, string | string[]>): boolean {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n\n for (const [key, filterValue] of Object.entries(filters)) {\n const itemValue = getNestedValue(item, key);\n\n if (Array.isArray(filterValue)) {\n // Multiple values - item must match at least one\n const matched = filterValue.some((val) => String(itemValue) === val);\n if (!matched) {\n return false;\n }\n } else {\n // Single value - exact match\n if (String(itemValue) !== filterValue) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * Check if item matches operator criteria\n *\n * @param item - Item to check\n * @param operators - Operator criteria\n * @returns True if item matches all operators\n *\n * @example\n * matchesOperators({ age: 25 }, { age: { _gte: '18' } }) // true\n */\nfunction matchesOperators(\n item: unknown,\n operators: Record<string, Record<string, string>>\n): boolean {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n\n for (const [key, ops] of Object.entries(operators)) {\n const itemValue = getNestedValue(item, key);\n\n for (const [operator, filterValue] of Object.entries(ops)) {\n if (operator === 'gte') {\n if (Number(itemValue) < Number(filterValue)) {\n return false;\n }\n } else if (operator === 'lte') {\n if (Number(itemValue) > Number(filterValue)) {\n return false;\n }\n } else if (operator === 'ne') {\n if (String(itemValue) === filterValue) {\n return false;\n }\n } else if (operator === 'like') {\n const itemStr = String(itemValue).toLowerCase();\n const filterStr = filterValue.toLowerCase();\n if (!itemStr.includes(filterStr)) {\n return false;\n }\n }\n }\n }\n\n return true;\n}\n\n/**\n * Check if item matches full-text search\n *\n * @param item - Item to check\n * @param searchText - Text to search for\n * @returns True if any string property contains search text\n *\n * @example\n * matchesSearch({ title: 'Hello World' }, 'world') // true\n */\nfunction matchesSearch(item: unknown, searchText: string): boolean {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n\n const lowerSearch = searchText.toLowerCase();\n\n function searchObject(obj: unknown): boolean {\n if (typeof obj === 'string') {\n return obj.toLowerCase().includes(lowerSearch);\n }\n\n if (typeof obj === 'object' && obj !== null) {\n return Object.values(obj).some(searchObject);\n }\n\n return false;\n }\n\n return searchObject(item);\n}\n\n/**\n * Apply filtering, sorting, pagination, etc. to data array\n *\n * @param data - Array of items to process\n * @param options - Query options\n * @returns Processed array and total count (before pagination)\n *\n * @example\n * applyQuery([{ id: 1 }, { id: 2 }], { limit: 1 }) // { data: [{ id: 1 }], total: 2 }\n */\nexport function applyQuery<T>(data: T[], options: QueryOptions): { data: T[]; total: number } {\n let result = [...data];\n\n // Apply full-text search\n if (options.q) {\n const searchText = options.q;\n result = result.filter((item) => matchesSearch(item, searchText));\n }\n\n // Apply filters\n if (Object.keys(options.filters).length > 0) {\n result = result.filter((item) => matchesFilters(item, options.filters));\n }\n\n // Apply operators\n if (Object.keys(options.operators).length > 0) {\n result = result.filter((item) => matchesOperators(item, options.operators));\n }\n\n // Store total before pagination\n const total = result.length;\n\n // Apply sorting\n if (options.sort.length > 0) {\n const sortFields = options.sort;\n const sortOrders = options.order;\n\n result.sort((a, b) => {\n for (let i = 0; i < sortFields.length; i++) {\n const field = sortFields[i];\n if (!field) continue;\n\n const order = sortOrders[i] === 'desc' ? -1 : 1;\n\n const aVal = getNestedValue(a, field);\n const bVal = getNestedValue(b, field);\n\n if (aVal === bVal) continue;\n\n // Handle null/undefined\n if (aVal === undefined || aVal === null) return 1 * order;\n if (bVal === undefined || bVal === null) return -1 * order;\n\n // Compare values\n if (aVal < bVal) return -1 * order;\n if (aVal > bVal) return 1 * order;\n }\n return 0;\n });\n }\n\n // Apply slicing (_start and _end)\n if (options.start !== undefined || options.end !== undefined) {\n const start = options.start ?? 0;\n const end = options.end ?? result.length;\n result = result.slice(start, end);\n }\n // Apply pagination (_page and _limit)\n else if (options.page !== undefined && options.limit !== undefined) {\n const start = (options.page - 1) * options.limit;\n result = result.slice(start, start + options.limit);\n }\n // Apply limit only\n else if (options.limit !== undefined) {\n result = result.slice(0, options.limit);\n }\n\n return { data: result, total };\n}\n\n/**\n * Generate Link header for pagination\n *\n * @param req - Express request object\n * @param page - Current page\n * @param limit - Items per page\n * @param total - Total number of items\n * @returns Link header value\n *\n * @example\n * generateLinkHeader(req, 2, 10, 100) // '<...>; rel=\"first\", <...>; rel=\"prev\", ...'\n */\nexport function generateLinkHeader(\n req: Request,\n page: number,\n limit: number,\n total: number\n): string {\n const host = req.get('host') ?? 'localhost';\n const baseUrl = `${req.protocol}://${host}${req.path}`;\n const query = new URLSearchParams(req.query as Record<string, string>);\n const lastPage = Math.ceil(total / limit);\n\n const links: string[] = [];\n\n // First page\n query.set('_page', '1');\n query.set('_limit', String(limit));\n links.push(`<${baseUrl}?${query.toString()}>; rel=\"first\"`);\n\n // Previous page\n if (page > 1) {\n query.set('_page', String(page - 1));\n links.push(`<${baseUrl}?${query.toString()}>; rel=\"prev\"`);\n }\n\n // Next page\n if (page < lastPage) {\n query.set('_page', String(page + 1));\n links.push(`<${baseUrl}?${query.toString()}>; rel=\"next\"`);\n }\n\n // Last page\n query.set('_page', String(lastPage));\n links.push(`<${baseUrl}?${query.toString()}>; rel=\"last\"`);\n\n return links.join(', ');\n}\n","/**\n * Relationships module for handling _embed and _expand parameters\n */\n\nimport type { Database } from './database';\n\n/**\n * Detect foreign key relationships based on naming conventions\n *\n * @param collectionName - Name of the collection (e.g., 'posts')\n * @param foreignKeySuffix - Suffix for foreign keys (default: 'Id')\n * @returns Possible foreign key name (e.g., 'postId')\n *\n * @example\n * getForeignKey('posts', 'Id') // 'postId'\n * getForeignKey('users', '_id') // 'user_id'\n */\nexport function getForeignKey(collectionName: string, foreignKeySuffix: string): string {\n // Remove trailing 's' for singular form\n const singular = collectionName.endsWith('s') ? collectionName.slice(0, -1) : collectionName;\n\n return `${singular}${foreignKeySuffix}`;\n}\n\n/**\n * Embed child resources into parent items\n *\n * @param items - Parent items to embed children into\n * @param parentCollection - Name of parent collection\n * @param childCollection - Name of child collection\n * @param db - Database instance\n * @param idField - ID field name (default: 'id')\n * @param foreignKeySuffix - Foreign key suffix (default: 'Id')\n * @returns Items with embedded children\n *\n * @example\n * embedChildren([{ id: 1 }], 'posts', 'comments', db)\n * // [{ id: 1, comments: [{ id: 1, postId: 1, body: '...' }] }]\n */\nexport function embedChildren<T extends Record<string, unknown>>(\n items: T[],\n parentCollection: string,\n childCollection: string,\n db: Database,\n idField: string,\n foreignKeySuffix: string\n): T[] {\n const children = db.getCollection(childCollection);\n\n // If children collection doesn't exist or isn't an array, return items unchanged\n if (!Array.isArray(children)) {\n return items;\n }\n\n const foreignKey = getForeignKey(parentCollection, foreignKeySuffix);\n\n return items.map((item) => {\n // Find all children that reference this parent\n const matchingChildren = children.filter((child) => {\n if (typeof child !== 'object' || child === null) return false;\n const childFk = (child as Record<string, unknown>)[foreignKey];\n const parentId = item[idField];\n return childFk === parentId || String(childFk) === String(parentId);\n });\n\n return {\n ...item,\n [childCollection]: matchingChildren,\n };\n });\n}\n\n/**\n * Expand parent resource into child items\n *\n * @param items - Child items to expand parent into\n * @param childCollection - Name of child collection\n * @param parentCollection - Name of parent collection\n * @param db - Database instance\n * @param idField - ID field name (default: 'id')\n * @param foreignKeySuffix - Foreign key suffix (default: 'Id')\n * @returns Items with expanded parent\n *\n * @example\n * expandParent([{ id: 1, postId: 1 }], 'comments', 'posts', db)\n * // [{ id: 1, postId: 1, post: { id: 1, title: '...' } }]\n */\nexport function expandParent<T extends Record<string, unknown>>(\n items: T[],\n _childCollection: string,\n parentCollection: string,\n db: Database,\n idField: string,\n foreignKeySuffix: string\n): T[] {\n const parents = db.getCollection(parentCollection);\n\n // If parent collection doesn't exist or isn't an array, return items unchanged\n if (!Array.isArray(parents)) {\n return items;\n }\n\n const foreignKey = getForeignKey(parentCollection, foreignKeySuffix);\n\n return items.map((item) => {\n const foreignKeyValue: unknown = item[foreignKey];\n\n if (foreignKeyValue === undefined) {\n return item;\n }\n\n // Find the parent that matches this foreign key\n const parent: unknown = parents.find((p) => {\n if (typeof p !== 'object' || p === null) return false;\n const parentRecord = p as Record<string, unknown>;\n const parentId: unknown = parentRecord[idField];\n // Handle both numeric and string IDs\n if (typeof foreignKeyValue === 'number' || typeof foreignKeyValue === 'string') {\n return parentId === foreignKeyValue || String(parentId) === String(foreignKeyValue);\n }\n return false;\n });\n\n if (!parent || typeof parent !== 'object') {\n return item;\n }\n\n // Use singular form for parent property name\n const parentPropName = parentCollection.endsWith('s')\n ? parentCollection.slice(0, -1)\n : parentCollection;\n\n return {\n ...item,\n [parentPropName]: parent as Record<string, unknown>,\n };\n });\n}\n\n/**\n * Apply relationship parameters (_embed, _expand) to query results\n *\n * @param data - Query results\n * @param resource - Resource name\n * @param embed - Collections to embed\n * @param expand - Collections to expand\n * @param db - Database instance\n * @param idField - ID field name\n * @param foreignKeySuffix - Foreign key suffix\n * @returns Data with relationships applied\n *\n * @example\n * applyRelationships(posts, 'posts', ['comments'], [], db)\n */\nexport function applyRelationships<T extends Record<string, unknown>>(\n data: T[],\n resource: string,\n embed: string[],\n expand: string[],\n db: Database,\n idField: string,\n foreignKeySuffix: string\n): T[] {\n let result = data;\n\n // Apply embeds (include children)\n for (const childCollection of embed) {\n result = embedChildren(result, resource, childCollection, db, idField, foreignKeySuffix);\n }\n\n // Apply expands (include parent)\n for (const parentCollection of expand) {\n result = expandParent(result, resource, parentCollection, db, idField, foreignKeySuffix);\n }\n\n return result;\n}\n\n/**\n * Parse relationship parameters from query\n *\n * @param query - Express query object\n * @returns Arrays of collections to embed and expand\n *\n * @example\n * parseRelationships({ _embed: 'comments' }) // { embed: ['comments'], expand: [] }\n * parseRelationships({ _embed: ['comments', 'likes'] }) // { embed: ['comments', 'likes'], expand: [] }\n */\nexport function parseRelationships(query: Record<string, unknown>): {\n embed: string[];\n expand: string[];\n} {\n const embed: string[] = [];\n const expand: string[] = [];\n\n // Parse _embed\n const embedParam = query._embed;\n if (typeof embedParam === 'string') {\n embed.push(...embedParam.split(','));\n } else if (Array.isArray(embedParam)) {\n for (const e of embedParam) {\n if (typeof e === 'string') {\n embed.push(e);\n }\n }\n }\n\n // Parse _expand\n const expandParam = query._expand;\n if (typeof expandParam === 'string') {\n expand.push(...expandParam.split(','));\n } else if (Array.isArray(expandParam)) {\n for (const e of expandParam) {\n if (typeof e === 'string') {\n expand.push(e);\n }\n }\n }\n\n return { embed, expand };\n}\n","/**\n * Static file server module\n */\n\nimport express, { RequestHandler } from 'express';\nimport { existsSync } from 'fs';\nimport { resolve } from 'path';\n\n/**\n * Static server options\n */\nexport interface StaticOptions {\n directory?: string;\n enabled?: boolean;\n}\n\n/**\n * Create static file server middleware\n *\n * @param options - Static server configuration\n * @returns Express middleware for serving static files\n *\n * @example\n * ```typescript\n * const staticMiddleware = createStaticMiddleware({ directory: './public' });\n * app.use(staticMiddleware);\n * ```\n */\nexport function createStaticMiddleware(options: StaticOptions = {}): RequestHandler {\n const directory = options.directory || './public';\n const enabled = options.enabled !== false;\n const staticPath = resolve(process.cwd(), directory);\n\n // If disabled or directory doesn't exist, return pass-through middleware\n if (!enabled || !existsSync(staticPath)) {\n return (_req, _res, next) => {\n next();\n };\n }\n\n // Serve static files from the directory\n return express.static(staticPath, {\n index: 'index.html',\n dotfiles: 'ignore',\n redirect: true,\n });\n}\n\n/**\n * Create homepage middleware that serves index.html or shows default page\n *\n * @param options - Static server configuration\n * @returns Express request handler\n */\nexport function createHomepageMiddleware(options: StaticOptions = {}): RequestHandler {\n const directory = options.directory || './public';\n const enabled = options.enabled !== false;\n const staticPath = resolve(process.cwd(), directory);\n const indexPath = resolve(staticPath, 'index.html');\n\n return (req, res, next) => {\n // Only handle root path\n if (req.path !== '/') {\n next();\n return;\n }\n\n // If static serving is enabled and index.html exists, let static middleware handle it\n if (enabled && existsSync(indexPath)) {\n next();\n return;\n }\n\n // Otherwise, show default homepage with available routes\n const host = req.get('host') || 'localhost:3000';\n const protocol = req.protocol;\n const baseUrl = `${protocol}://${host}`;\n\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.send(`<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>API Faker</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n line-height: 1.6;\n color: #333;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n min-height: 100vh;\n padding: 2rem;\n }\n .container {\n max-width: 800px;\n margin: 0 auto;\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n padding: 3rem;\n }\n h1 {\n color: #667eea;\n font-size: 2.5rem;\n margin-bottom: 1rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n }\n h2 {\n color: #555;\n font-size: 1.5rem;\n margin-top: 2rem;\n margin-bottom: 1rem;\n border-bottom: 2px solid #667eea;\n padding-bottom: 0.5rem;\n }\n .intro {\n color: #666;\n font-size: 1.1rem;\n margin-bottom: 2rem;\n }\n .endpoint {\n background: #f8f9fa;\n border-left: 4px solid #667eea;\n padding: 1rem;\n margin-bottom: 1rem;\n border-radius: 4px;\n }\n .endpoint a {\n color: #667eea;\n text-decoration: none;\n font-family: 'Monaco', 'Courier New', monospace;\n font-weight: bold;\n }\n .endpoint a:hover {\n text-decoration: underline;\n }\n .endpoint p {\n color: #666;\n margin-top: 0.5rem;\n font-size: 0.95rem;\n }\n .info-box {\n background: #e3f2fd;\n border-left: 4px solid #2196f3;\n padding: 1rem;\n margin-top: 2rem;\n border-radius: 4px;\n }\n .info-box p {\n color: #1565c0;\n margin: 0;\n }\n code {\n background: #f5f5f5;\n padding: 0.2rem 0.4rem;\n border-radius: 3px;\n font-family: 'Monaco', 'Courier New', monospace;\n font-size: 0.9em;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <h1>🚀 API Faker</h1>\n <p class=\"intro\">\n Your JSON REST API is up and running! Use the endpoints below to interact with your data.\n </p>\n\n <h2>📡 Endpoints</h2>\n <div class=\"endpoint\">\n <a href=\"${baseUrl}/db\" target=\"_blank\">${baseUrl}/db</a>\n <p>View the full database</p>\n </div>\n\n <h2>💡 Tips</h2>\n <div class=\"info-box\">\n <p>\n Use query parameters to filter, sort, and paginate your data. \n Examples: <code>?_sort=name&_order=asc</code>, <code>?_page=1&_limit=10</code>\n </p>\n </div>\n </div>\n</body>\n</html>`);\n };\n}\n","import { pathToFileURL } from 'node:url';\nimport { RequestHandler } from 'express';\n\n/**\n * Load a JavaScript or TypeScript module dynamically\n *\n * @param filePath - Path to the module file\n * @returns Module exports\n * @throws Error if module cannot be loaded\n *\n * @example\n * ```typescript\n * const module = await loadModule('./routes.js');\n * ```\n */\nexport async function loadModule(filePath: string): Promise<unknown> {\n try {\n const fileUrl = pathToFileURL(filePath).href;\n const module = (await import(fileUrl)) as { default?: unknown } & Record<string, unknown>;\n return module;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to load module '${filePath}': ${message}\\n` +\n `\\nMake sure:\\n` +\n ` - The file exists and is a valid JavaScript file\\n` +\n ` - The file doesn't have syntax errors\\n` +\n ` - All dependencies are installed`\n );\n }\n}\n\n/**\n * Load custom middleware from a file\n *\n * @param filePath - Path to the middleware file\n * @returns Array of Express middleware functions\n * @throws Error if middleware file is invalid\n *\n * @example\n * ```typescript\n * // middleware.js\n * module.exports = (req, res, next) => {\n * console.log('Custom middleware');\n * next();\n * };\n *\n * // Or export array\n * module.exports = [\n * (req, res, next) => { console.log('First'); next(); },\n * (req, res, next) => { console.log('Second'); next(); }\n * ];\n *\n * // Usage\n * const middlewares = await loadMiddlewares('./middleware.js');\n * middlewares.forEach(mw => app.use(mw));\n * ```\n */\nexport async function loadMiddlewares(filePath: string): Promise<RequestHandler[]> {\n const module = await loadModule(filePath);\n\n // Check for default export first (ES modules or wrapped CommonJS)\n let middlewareExport: unknown;\n if (typeof module === 'object' && module !== null && 'default' in module) {\n const defaultExport = (module as { default: unknown }).default;\n // If default is also an object with a default property, unwrap it\n if (typeof defaultExport === 'object' && defaultExport !== null && 'default' in defaultExport) {\n middlewareExport = (defaultExport as { default: unknown }).default;\n } else {\n middlewareExport = defaultExport;\n }\n } else {\n middlewareExport = module;\n }\n\n // Normalize to array\n const middlewares = Array.isArray(middlewareExport) ? middlewareExport : [middlewareExport];\n\n // Validate all are functions\n for (let i = 0; i < middlewares.length; i++) {\n const mw: unknown = middlewares[i];\n if (typeof mw !== 'function') {\n const indexStr = String(i);\n throw new Error(\n `Middleware file '${filePath}' at index ${indexStr} is not a function, got ${typeof mw}`\n );\n }\n }\n\n return middlewares as RequestHandler[];\n}\n","import { RequestHandler } from 'express';\nimport { readFile } from 'node:fs/promises';\n\n/**\n * Route rewrite rules mapping\n * Maps incoming URL patterns to target URL patterns\n *\n * @example\n * ```json\n * {\n * \"/api/*\": \"/$1\",\n * \"/me\": \"/profile\",\n * \"/news/top\": \"/news?_sort=date&_order=asc&_limit=10\"\n * }\n * ```\n */\nexport type RewriteRules = Record<string, string>;\n\n/**\n * Load rewrite rules from a JSON file\n *\n * @param filePath - Path to the JSON file containing route mappings\n * @returns Rewrite rules object\n * @throws Error if file cannot be loaded or parsed\n *\n * @example\n * ```typescript\n * const rules = await loadRewriteRules('./routes.json');\n * const middleware = createRewriterMiddleware(rules);\n * app.use(middleware);\n * ```\n */\nexport async function loadRewriteRules(filePath: string): Promise<RewriteRules> {\n try {\n const content = await readFile(filePath, 'utf-8');\n const rules = JSON.parse(content) as unknown;\n\n if (typeof rules !== 'object' || rules === null || Array.isArray(rules)) {\n throw new Error('Routes file must contain a JSON object with route mappings');\n }\n\n // Validate all keys and values are strings\n for (const [key, value] of Object.entries(rules)) {\n if (typeof value !== 'string') {\n throw new Error(`Route mapping for '${key}' must be a string, got ${typeof value}`);\n }\n }\n\n return rules as RewriteRules;\n } catch (error) {\n if (error instanceof Error && error.message.includes('Routes file must contain')) {\n throw error;\n }\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to load routes from '${filePath}': ${message}\\n` +\n `\\nExpected format:\\n` +\n `{\\n` +\n ` \"/api/*\": \"/$1\",\\n` +\n ` \"/users/:id\": \"/api/users/:id\"\\n` +\n `}\\n` +\n `\\nSee examples/routes.json for more examples.`\n );\n }\n}\n\n/**\n * Convert a route pattern with wildcards and parameters to a RegExp\n *\n * @param pattern - Route pattern (e.g., '/api/*', '/posts/:id')\n * @returns Regular expression and parameter names\n *\n * @example\n * ```typescript\n * const { regex, params } = patternToRegex('/api/*');\n * // regex: /^\\/api\\/(.*)$/\n * // params: ['$1']\n *\n * const { regex, params } = patternToRegex('/posts/:id/comments/:commentId');\n * // regex: /^\\/posts\\/([^\\/]+)\\/comments\\/([^\\/]+)$/\n * // params: ['id', 'commentId']\n * ```\n */\nfunction patternToRegex(pattern: string): { regex: RegExp; params: string[] } {\n const params: string[] = [];\n\n // Escape special regex characters except * and :\n let regexPattern = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Replace :param with capturing group and collect param names\n regexPattern = regexPattern.replace(/:([^/]+)/g, (_match, param: string) => {\n params.push(param);\n return '([^/]+)';\n });\n\n // Replace * with capturing group\n regexPattern = regexPattern.replace(/\\*/g, () => {\n params.push(`$${String(params.length + 1)}`);\n return '(.*)';\n });\n\n return {\n regex: new RegExp(`^${regexPattern}$`),\n params,\n };\n}\n\n/**\n * Rewrite a URL based on a pattern and substitution\n *\n * @param url - Original URL\n * @param fromPattern - Pattern to match (with * or :param)\n * @param toPattern - Target pattern with $1, $2, etc. or :param\n * @returns Rewritten URL or null if pattern doesn't match\n *\n * @example\n * ```typescript\n * rewriteUrl('/api/posts', '/api/*', '/$1') // → '/posts'\n * rewriteUrl('/me', '/me', '/profile') // → '/profile'\n * rewriteUrl('/posts/1', '/posts/:id', '/items/:id') // → '/items/1'\n * ```\n */\nfunction rewriteUrl(url: string, fromPattern: string, toPattern: string): string | null {\n const { regex, params } = patternToRegex(fromPattern);\n const match = url.match(regex);\n\n if (!match) {\n return null;\n }\n\n // Extract captured values\n const captures = match.slice(1);\n\n // Build the replacement URL\n let result = toPattern;\n\n // Replace $1, $2, etc. with captured values\n for (let i = 0; i < captures.length; i++) {\n const value = captures[i];\n if (value !== undefined) {\n result = result.replace(`$${String(i + 1)}`, value);\n }\n }\n\n // Replace :param with captured values (for named parameters)\n for (let i = 0; i < params.length; i++) {\n const param = params[i];\n const value = captures[i];\n if (param && !param.startsWith('$') && value !== undefined) {\n result = result.replace(`:${param}`, value);\n }\n }\n\n return result;\n}\n\n/**\n * Create Express middleware that rewrites URLs based on rules\n *\n * @param rules - Route rewrite rules\n * @returns Express middleware function\n *\n * @example\n * ```typescript\n * const rules = {\n * '/api/*': '/$1',\n * '/me': '/profile',\n * '/posts/:category': '/posts?category=:category'\n * };\n *\n * const rewriter = createRewriterMiddleware(rules);\n * app.use(rewriter);\n * ```\n */\nexport function createRewriterMiddleware(rules: RewriteRules): RequestHandler {\n return (req, _res, next) => {\n // Try each rule in order\n for (const [from, to] of Object.entries(rules)) {\n const rewritten = rewriteUrl(req.url, from, to);\n\n if (rewritten !== null) {\n req.url = rewritten;\n break; // Apply only the first matching rule\n }\n }\n\n next();\n };\n}\n","import { readFileSync, existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\n/**\n * Find the closest matching string using Levenshtein distance\n *\n * @param input - Input string to match\n * @param candidates - Array of candidate strings\n * @returns Closest match or null if no good match found\n */\nfunction findClosestMatch(input: string, candidates: string[]): string | null {\n /* eslint-disable @typescript-eslint/no-non-null-assertion */\n const levenshtein = (a: string, b: string): number => {\n const matrix: number[][] = [];\n\n for (let i = 0; i <= b.length; i++) {\n matrix[i] = [i];\n }\n\n for (let j = 0; j <= a.length; j++) {\n matrix[0]![j] = j;\n }\n\n for (let i = 1; i <= b.length; i++) {\n for (let j = 1; j <= a.length; j++) {\n if (b.charAt(i - 1) === a.charAt(j - 1)) {\n matrix[i]![j] = matrix[i - 1]![j - 1]!;\n } else {\n matrix[i]![j] = Math.min(\n matrix[i - 1]![j - 1]! + 1,\n matrix[i]![j - 1]! + 1,\n matrix[i - 1]![j]! + 1\n );\n }\n }\n }\n\n return matrix[b.length]![a.length]!;\n };\n /* eslint-enable @typescript-eslint/no-non-null-assertion */\n\n let closestMatch: string | null = null;\n let minDistance = Infinity;\n\n for (const candidate of candidates) {\n const distance = levenshtein(input.toLowerCase(), candidate.toLowerCase());\n if (distance < minDistance && distance <= 3) {\n // Only suggest if distance is 3 or less\n minDistance = distance;\n closestMatch = candidate;\n }\n }\n\n return closestMatch;\n}\n\n/**\n * Configuration options that can be specified in config file or CLI\n */\nexport interface Config {\n port?: number;\n host?: string;\n watch?: boolean;\n routes?: string;\n middlewares?: string;\n static?: string;\n readOnly?: boolean;\n noCors?: boolean;\n noGzip?: boolean;\n snapshots?: string;\n delay?: number;\n id?: string;\n foreignKeySuffix?: string;\n quiet?: boolean;\n}\n\n/**\n * Load configuration from a JSON file\n *\n * @param configPath - Path to the configuration file\n * @returns Configuration object or null if file doesn't exist\n * @throws Error if file exists but is invalid JSON or contains invalid options\n *\n * @example\n * ```typescript\n * const config = loadConfig('rest_api_faker.json');\n * if (config) {\n * console.log('Loaded config:', config);\n * }\n * ```\n */\nexport function loadConfig(configPath: string): Config | null {\n const resolvedPath = resolve(configPath);\n\n // If file doesn't exist, return null (not an error)\n if (!existsSync(resolvedPath)) {\n return null;\n }\n\n try {\n const content = readFileSync(resolvedPath, 'utf-8');\n const config = JSON.parse(content) as unknown;\n\n // Validate config is an object\n if (typeof config !== 'object' || config === null || Array.isArray(config)) {\n throw new Error('Config file must contain a JSON object');\n }\n\n // Validate config properties\n validateConfig(config as Record<string, unknown>);\n\n return config as Config;\n } catch (error) {\n if (error instanceof Error && error.message.includes('Config file must contain')) {\n throw error;\n }\n throw new Error(\n `Failed to load config from '${configPath}': ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * Validate configuration object\n *\n * @param config - Configuration object to validate\n * @throws Error if configuration contains invalid options\n */\nfunction validateConfig(config: Record<string, unknown>): void {\n const validOptions = new Set([\n 'port',\n 'host',\n 'watch',\n 'routes',\n 'middlewares',\n 'static',\n 'readOnly',\n 'noCors',\n 'noGzip',\n 'snapshots',\n 'delay',\n 'id',\n 'foreignKeySuffix',\n 'quiet',\n ]);\n\n // Check for unknown options\n for (const key of Object.keys(config)) {\n if (!validOptions.has(key)) {\n const suggestion = findClosestMatch(key, Array.from(validOptions));\n const didYouMean = suggestion ? ` Did you mean '${suggestion}'?` : '';\n throw new Error(\n `Unknown config option: '${key}'.${didYouMean} Valid options are: ${Array.from(validOptions).join(', ')}`\n );\n }\n }\n\n // Validate types\n if (\n 'port' in config &&\n (typeof config.port !== 'number' || config.port < 0 || config.port > 65535)\n ) {\n throw new Error(\"Config option 'port' must be a number between 0 and 65535\");\n }\n\n if ('host' in config && typeof config.host !== 'string') {\n throw new Error(\"Config option 'host' must be a string\");\n }\n\n if ('watch' in config && typeof config.watch !== 'boolean') {\n throw new Error(\"Config option 'watch' must be a boolean\");\n }\n\n if ('routes' in config && typeof config.routes !== 'string') {\n throw new Error(\"Config option 'routes' must be a string\");\n }\n\n if ('middlewares' in config && typeof config.middlewares !== 'string') {\n throw new Error(\"Config option 'middlewares' must be a string\");\n }\n\n if ('static' in config && typeof config.static !== 'string') {\n throw new Error(\"Config option 'static' must be a string\");\n }\n\n if ('readOnly' in config && typeof config.readOnly !== 'boolean') {\n throw new Error(\"Config option 'readOnly' must be a boolean\");\n }\n\n if ('noCors' in config && typeof config.noCors !== 'boolean') {\n throw new Error(\"Config option 'noCors' must be a boolean\");\n }\n\n if ('noGzip' in config && typeof config.noGzip !== 'boolean') {\n throw new Error(\"Config option 'noGzip' must be a boolean\");\n }\n\n if ('snapshots' in config && typeof config.snapshots !== 'string') {\n throw new Error(\"Config option 'snapshots' must be a string\");\n }\n\n if ('delay' in config && (typeof config.delay !== 'number' || config.delay < 0)) {\n throw new Error(\"Config option 'delay' must be a non-negative number\");\n }\n\n if ('id' in config && typeof config.id !== 'string') {\n throw new Error(\"Config option 'id' must be a string\");\n }\n\n if ('foreignKeySuffix' in config && typeof config.foreignKeySuffix !== 'string') {\n throw new Error(\"Config option 'foreignKeySuffix' must be a string\");\n }\n\n if ('quiet' in config && typeof config.quiet !== 'boolean') {\n throw new Error(\"Config option 'quiet' must be a boolean\");\n }\n}\n\n/**\n * Merge CLI arguments with config file\n * CLI arguments take precedence over config file values\n *\n * @param cliConfig - Configuration from CLI arguments\n * @param fileConfig - Configuration from config file\n * @returns Merged configuration\n *\n * @example\n * ```typescript\n * const fileConfig = loadConfig('rest_api_faker.json');\n * const merged = mergeConfig(cliArgs, fileConfig);\n * ```\n */\nexport function mergeConfig(cliConfig: Partial<Config>, fileConfig: Config | null): Config {\n if (!fileConfig) {\n return cliConfig as Config;\n }\n\n // CLI arguments override config file values\n return {\n ...fileConfig,\n ...cliConfig,\n };\n}\n"],"mappings":"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","names":["import_fs","import_path","module","import_express","pc","import_express","import_fs","import_path","express","module","express","cors","compression","yargs"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * API Faker - Main entry point for programmatic usage\n *\n * @example\n * ```typescript\n * import { create, router, defaults } from 'api-faker';\n *\n * const server = create();\n * const apiRouter = router('db.json');\n *\n * server.use(defaults());\n * server.use(apiRouter);\n * server.listen(3000);\n * ```\n */\n\n// TODO: Implement in Phase 7\nexport function create(): void {\n throw new Error('Not implemented yet - coming in Phase 7');\n}\n\nexport function router(): void {\n throw new Error('Not implemented yet - coming in Phase 7');\n}\n\nexport function defaults(): void {\n throw new Error('Not implemented yet - coming in Phase 7');\n}\n\nexport function rewriter(): void {\n throw new Error('Not implemented yet - coming in Phase 7');\n}\n\nexport const bodyParser = {};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBO,SAAS,SAAe;AAC7B,QAAM,IAAI,MAAM,yCAAyC;AAC3D;AAEO,SAAS,SAAe;AAC7B,QAAM,IAAI,MAAM,yCAAyC;AAC3D;AAEO,SAAS,WAAiB;AAC/B,QAAM,IAAI,MAAM,yCAAyC;AAC3D;AAEO,SAAS,WAAiB;AAC/B,QAAM,IAAI,MAAM,yCAAyC;AAC3D;AAEO,IAAM,aAAa,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * API Faker - Main entry point for programmatic usage\n *\n * @example\n * ```typescript\n * import { create, router, defaults } from 'rest_api_faker';\n *\n * const server = create();\n * const apiRouter = router('db.json');\n *\n * server.use(defaults());\n * server.use(apiRouter);\n * server.listen(3000);\n * ```\n */\n\n// TODO: Implement in Phase 7\nexport function create(): void {\n throw new Error('Not implemented yet - coming in Phase 7');\n}\n\nexport function router(): void {\n throw new Error('Not implemented yet - coming in Phase 7');\n}\n\nexport function defaults(): void {\n throw new Error('Not implemented yet - coming in Phase 7');\n}\n\nexport function rewriter(): void {\n throw new Error('Not implemented yet - coming in Phase 7');\n}\n\nexport const bodyParser = {};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBO,SAAS,SAAe;AAC7B,QAAM,IAAI,MAAM,yCAAyC;AAC3D;AAEO,SAAS,SAAe;AAC7B,QAAM,IAAI,MAAM,yCAAyC;AAC3D;AAEO,SAAS,WAAiB;AAC/B,QAAM,IAAI,MAAM,yCAAyC;AAC3D;AAEO,SAAS,WAAiB;AAC/B,QAAM,IAAI,MAAM,yCAAyC;AAC3D;AAEO,IAAM,aAAa,CAAC;","names":[]}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "rest_api_faker",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Get a full fake REST API with zero coding in less than 30 seconds",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "bin": {
8
- "rest_api_faker": "./bin/rest_api_faker.js"
8
+ "rest_api_faker": "./dist/cli.js"
9
9
  },
10
10
  "files": [
11
11
  "dist",
@@ -60,7 +60,7 @@
60
60
  },
61
61
  "scripts": {
62
62
  "build": "tsup",
63
- "dev": "tsup && nodemon --watch dist --exec \"node bin/api-faker.js db.json\"",
63
+ "dev": "tsup && nodemon --watch dist --exec \"node dist/cli.js db.json\"",
64
64
  "test": "vitest",
65
65
  "test:run": "vitest run",
66
66
  "test:coverage": "vitest --coverage",