Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ npm run dev
npx ts-mock-proxy
```

Y ou'll be prompted for:
You'll be prompted for:
- Types directory location
- Server port (default: 8080)
- Optional features (hot-reload, caching, latency simulation)
Expand Down
113 changes: 11 additions & 102 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 16 additions & 6 deletions src/core/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,18 @@ export function dynamicRouteHandler(config: ServerConfig) {
// Check the cache first (only for single objects, not arrays)
let mockData: Record<string, unknown> | Record<string, unknown>[];

if (config.cache && mapping.filePath && !mapping.isArray) {
const cached = schemaCache.get(mapping.typeName, mapping.filePath);
const { filePath } = mapping;

if (!filePath) {
res.status(500).json({
error: 'Mock generation failed',
message: `No file path found for type "${mapping.typeName}"`,
});
return;
}

if (config.cache && !mapping.isArray) {
const cached = schemaCache.get(mapping.typeName, filePath);

if (cached) {
mockData = cached.schema;
Expand All @@ -59,21 +69,21 @@ export function dynamicRouteHandler(config: ServerConfig) {
// Generate the mock data
if (mapping.isArray) {
mockData = generateMockArray(
mapping.filePath!,
filePath,
mapping.typeName
);
} else {
mockData = generateMockFromInterface(
mapping.filePath!,
filePath,
mapping.typeName
);
}

// Store in cache if enabled
if (config.cache && mapping.filePath && !mapping.isArray) {
if (config.cache && !mapping.isArray) {
schemaCache.set(
mapping.typeName,
mapping.filePath,
filePath,
mockData as Record<string, unknown>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export function startServer(

// Configure the logger in verbose mode if necessary
if (config.verbose) {
logger.setVerbose(true);
logger.info('Verbose mode enabled');
}

Expand Down
1 change: 0 additions & 1 deletion src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export interface ServerConfig {
/** Server port */
port: number;


/** Simulated latency (min-max in milliseconds) */
latency?: {
min: number;
Expand Down
37 changes: 20 additions & 17 deletions src/utils/configPersistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@ import { logger } from './logger';

const CONFIG_FILE = path.join(process.cwd(), '.mock-config.json');

/**
* Validates that a parsed JSON object has the shape of a ServerConfig.
* Used to avoid silent failures when loading a malformed or outdated config file.
*/
function isValidSavedConfig(obj: unknown): obj is ServerConfig {
if (typeof obj !== 'object' || obj === null) return false;
const s = obj as Record<string, unknown>;
if (typeof s['typesDir'] !== 'string') return false;
if (typeof s['port'] !== 'number') return false;
if (typeof s['hotReload'] !== 'boolean') return false;
if (typeof s['cache'] !== 'boolean') return false;
if (typeof s['verbose'] !== 'boolean') return false;
if (s['latency'] !== undefined) {
if (typeof s['latency'] !== 'object' || s['latency'] === null) return false;
const latency = s['latency'] as Record<string, unknown>;
if (typeof latency['min'] !== 'number' || typeof latency['max'] !== 'number') return false;
}
return true;
}

/**
* Save the server configuration to a file for later reuse
* @param config The configuration to save
Expand Down Expand Up @@ -38,23 +58,6 @@ export function loadSavedConfig(): ServerConfig | null {
const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
const parsed = JSON.parse(content);

// Minimal runtime validation to avoid silent failures from malformed or
// outdated config files. We check required fields and types.
function isValidSavedConfig(obj: unknown): obj is ServerConfig {
if (typeof obj !== 'object' || obj === null) return false;
const s = obj as any;
if (typeof s.typesDir !== 'string') return false;
if (typeof s.port !== 'number') return false;
if (typeof s.hotReload !== 'boolean') return false;
if (typeof s.cache !== 'boolean') return false;
if (typeof s.verbose !== 'boolean') return false;
if (s.latency !== undefined) {
if (typeof s.latency !== 'object' || s.latency === null) return false;
if (typeof s.latency.min !== 'number' || typeof s.latency.max !== 'number') return false;
}
return true;
}

if (!isValidSavedConfig(parsed)) {
logger.warn(`Saved configuration at ${CONFIG_FILE} is malformed or missing required fields — ignoring.`);
return null;
Expand Down
4 changes: 4 additions & 0 deletions src/utils/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import chalk from 'chalk';
export class Logger {
constructor(private verbose: boolean = false) {}

setVerbose(verbose: boolean): void {
this.verbose = verbose;
}

info(message: string, ...args: unknown[]): void {
console.log(chalk.blue('ℹ'), message, ...args);
}
Expand Down
5 changes: 0 additions & 5 deletions src/utils/typeMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,6 @@ export function buildTypeMap(directory: string): Map<string, string> {
}
}

if (typeMap.size > 0) {
// Debug: Log discovered endpoints
// console.debug(`[typeMapping] Discovered ${typeMap.size} endpoints:`, Array.from(typeMap.keys()));
}

return typeMap;
}

Expand Down