@repo/core-utils
Framework-agnostic utilities for string processing, caching, logging, code analysis, and performance monitoring. 50+ battle-tested implementations. Works in browser, edge, and Node.js. Consumed from source for optimal tree-shaking.
Quick Start
Add battle-tested utilities in 5 minutes:
pnpm add @repo/core-utilsDual exports: /shared (all environments), /server (Node.js only). Skip to Quick Start →
Why @repo/core-utils?
Every package reimplements caching differently. Circular JSON handling varies (some crash, some truncate). Loggers lack async buffering and file rotation. Memory pressure causes OOM errors. Code analysis tools are scattered. String processing has edge cases (circular refs, large objects, special types).
@repo/core-utils solves this with framework-agnostic utilities and dual export paths for environment-specific code.
Production-ready with 50+ utilities, comprehensive tests, minimal dependencies, and dual /shared
(environment-neutral) and /server (Node.js) exports.
Use cases
- Circular-safe JSON — Stringify objects with circular references safely
- LRU caching with TTL — Cache with automatic eviction and expiration
- Async logging — High-performance logging with buffering and rotation
- Code analysis — Discover files, analyze dependencies, scan for security issues
- Memory monitoring — Track heap usage, auto-cleanup on pressure
How it works
@repo/core-utils provides dual export paths for environment compatibility:
// Shared utilities (browser, edge, Node.js)
import { safeStringify } from "@repo/core-utils/shared/stringify";
const obj = { a: 1 };
obj.self = obj; // Circular reference
const json = safeStringify(obj, 75000);
// => {"a":1,"self":"[Circular Reference]"}
// Server utilities (Node.js only)
import { BoundedCache } from "@repo/core-utils/server/cache";
const cache = new BoundedCache({
maxSize: 100,
ttl: 1800000, // 30 minutes
enableAnalytics: true
});
cache.set("key", value);
const analytics = cache.getAnalytics();
console.log(analytics.hitRate); // Cache hit rate %Uses /shared exports for environment-neutral code (pure JavaScript), and /server exports for Node.js features (file
system, Buffer, process memory).
Key features
Dual export paths — /shared (all environments), /server (Node.js only)
Circular-safe JSON — Handle circular references, deep nesting, large objects
Advanced caching — LRU + TTL, memory-aware, centralized registry
Async logging — Buffered writes, file rotation, performance stats
Code analysis — File discovery, pattern matching, dependency graphs, security scanning
Tree-shakeable — Consumed from source for optimal bundle size
Quick Start
1. Install the package
pnpm add @repo/core-utils2. Use shared utilities for JSON (all environments)
"use client";
import { safeStringify } from "@repo/core-utils/shared/stringify";
export function DebugPanel({ data }: { data: unknown }) {
// Works in browser - handles circular refs safely
const json = safeStringify(data, 50000);
return <pre className="text-xs">{json}</pre>;
}import { NextResponse } from "next/server";
import { safeStringify } from "@repo/core-utils/shared/stringify";
export function middleware(request: Request) {
// Works in edge runtime
console.log(safeStringify(request.headers));
return NextResponse.next();
}3. Use server utilities for caching (Node.js only)
import { BoundedCache } from "@repo/core-utils/server/cache";
export const userCache = new BoundedCache({
maxSize: 100,
ttl: 1800000, // 30 minutes
enableAnalytics: true
});
export async function getCachedUser(id: string) {
const cached = userCache.get(id);
if (cached) return cached;
const user = await fetchUser(id);
userCache.set(id, user);
return user;
}import { userCache } from "#/lib/cache";
export async function GET() {
const analytics = userCache.getAnalytics();
return Response.json({
hitRate: analytics.hitRate,
size: analytics.size,
memoryUsage: analytics.memoryUsage
});
}4. Add logging with AsyncLogger (Node.js only)
import { AsyncLogger } from "@repo/core-utils/server/logger";
export const logger = new AsyncLogger({
sessionId: "app-session",
logDir: "./logs",
logLevel: "info",
maxBufferSize: 16384, // 16KB buffer
maxFileSize: 10485760 // 10MB rotation
});
await logger.init();import { logger } from "#/lib/logger";
export async function POST(request: Request) {
logger.log("Processing started", "info");
try {
// Process data
logger.log("Processing completed", "info");
} catch (error) {
logger.log("Processing failed", "error", { error });
}
return Response.json({ success: true });
}That's it! You now have environment-neutral JSON processing, server-side caching with analytics, and high-performance async logging.
Memory-aware caching
Automatically clean cache on memory pressure:
import { MemoryAwareCache } from "@repo/core-utils/server/memory-aware-cache";
const cache = new MemoryAwareCache({
maxSize: 1000,
ttl: 3600000,
memoryThreshold: 150 * 1024 * 1024 // Auto-cleanup at 150MB
});Technical Details
For Developers: Technical implementation details
Overview
| Property | Value |
|---|---|
| Location | packages/core-utils |
| Dependencies | Minimal (glob, lru-cache, p-queue, zod) |
| Utilities | 50+ utilities across 6 categories |
| Build | No (consumed from source) |
Architecture: Two Export Paths
/shared - Environment-Neutral
Pure JavaScript utilities that work everywhere:
- ✅ Browser (client components)
- ✅ Edge runtime (middleware)
- ✅ Node.js (server components)
- ✅ Packages (maximum portability)
Key Feature: Zero Node.js dependencies
/server - Node.js-Specific
Advanced utilities with Node.js features:
- ✅ File system operations
- ✅ Buffer handling
- ✅ Process memory monitoring
- ✅ Performance profiling
Key Feature: Enhanced with memory tracking and advanced features
Export Paths
| Path | Description |
|---|---|
@repo/core-utils/shared/* | Environment-neutral utilities |
@repo/core-utils/server/* | Node.js-specific utilities |
String Processing
safeStringify (Shared)
Pure JSON stringification with circular reference handling.
import { safeStringify } from "@repo/core-utils/shared/stringify";
const obj = { a: 1 };
obj.self = obj; // Circular reference
// highlight-next-line
const json = safeStringify(obj, 75000);
// Output: {"a":1,"self":"[Circular Reference]"}Handles:
- Circular references
undefined, functions, symbolsMap,Set,Errorobjects- Deep nesting (max depth: 20)
- Large objects (configurable truncation)
safeStringifyPure (Shared)
With metadata about the stringification process:
import { safeStringifyPure } from "@repo/core-utils/shared/stringify";
// highlight-start
const result = safeStringifyPure(obj, {
prettify: true,
maxLength: 50000
});
// highlight-end
console.log(result.result); // JSON string
console.log(result.metadata.circularRefs); // Number of circular refs
console.log(result.metadata.truncated); // Boolean
console.log(result.metadata.originalLength); // Original lengthSafeStringifier (Server)
Advanced stringifier with Node.js features:
import { SafeStringifier } from "@repo/core-utils/server/stringify-advanced";
// highlight-start
const stringifier = new SafeStringifier({
maxLength: 100000,
prettify: true,
includeMetadata: true
});
// highlight-end
const result = stringifier.stringify(obj);
console.log(result.metadata.memoryUsage); // Heap memory used
console.log(result.metadata.executionTime); // Time in ms
console.log(result.metadata.circularRefs); // Circular references foundCaching
BoundedCache (Server)
LRU + TTL
Combines LRU eviction with TTL expiration for optimal memory management.
LRU cache with TTL, analytics, and automatic memory management:
import { BoundedCache } from "@repo/core-utils/server/cache";
// highlight-start
const cache = new BoundedCache({
maxSize: 100,
ttl: 1800000, // 30 minutes
enableAnalytics: true
});
// highlight-end
cache.set("key", value);
const value = cache.get("key");
// Analytics
const analytics = cache.getAnalytics();
console.log(analytics.hitRate); // Cache hit rate %
console.log(analytics.memoryUsage); // Estimated memory usage
console.log(analytics.size); // Current size
// Cleanup
const cleaned = cache.cleanup(); // Smart cleanup
const forceCleaned = cache.cleanup(true); // Force cleanupCacheRegistry (Server)
Centralized cache management across the application:
import { globalCacheRegistry } from "@repo/core-utils/server/cache";
// Create named caches
// highlight-start
const userCache = globalCacheRegistry.create("user-cache", {
maxSize: 50,
ttl: 600000
});
// highlight-end
const productCache = globalCacheRegistry.create("product-cache", {
maxSize: 100,
ttl: 1800000
});
// Retrieve existing cache
const sameCache = globalCacheRegistry.get("user-cache");
// Global analytics
const analytics = globalCacheRegistry.getGlobalAnalytics();
console.log(analytics.totalHits);
console.log(analytics.totalMisses);
console.log(analytics.cacheCount);
// Cleanup all caches
const results = globalCacheRegistry.cleanupAll();MemoryAwareCache (Server)
Memory Pressure
Automatically evicts entries when heap memory exceeds 150MB to prevent OOM errors.
Advanced cache with automatic memory pressure detection:
import { MemoryAwareCache } from "@repo/core-utils/server/memory-aware-cache";
// highlight-start
const cache = new MemoryAwareCache({
maxSize: 1000,
ttl: 3600000,
memoryThreshold: 150 * 1024 * 1024 // 150MB
});
// highlight-end
// Automatically monitors memory and cleans when needed
cache.set("key", largeObject);
const stats = cache.getStats();
console.log(stats.memoryPressureCleanups); // Auto-cleanup countLogging
AsyncLogger (Server)
High Performance
Buffers log messages in memory and flushes asynchronously for minimal performance impact.
High-performance async logger with buffering and file rotation:
import { AsyncLogger } from "@repo/core-utils/server/logger";
// highlight-start
const logger = new AsyncLogger({
sessionId: "analysis-session-123",
logDir: "./logs",
logLevel: "info",
maxBufferSize: 16384, // 16KB buffer
maxFileSize: 10485760, // 10MB before rotation
maxFiles: 5 // Keep 5 rotated files
});
// highlight-end
await logger.init();
logger.log("Processing started", "info");
logger.log("Error occurred", "error", { details: "..." });
// Force flush buffer to disk
logger.flush();
// Get statistics
const stats = logger.getStats();
console.log(stats.messagesLogged);
console.log(stats.bytesWritten);
console.log(stats.flushCount);
// Cleanup
await logger.close();LoggerRegistry (Server)
Centralized logger management:
import { globalLoggerRegistry } from "@repo/core-utils/server/logger";
// Create named logger
// highlight-start
const logger = globalLoggerRegistry.create("main-logger", {
sessionId: "session-123",
logLevel: "debug"
});
// highlight-end
await logger.init();
// Retrieve logger anywhere
const sameLogger = globalLoggerRegistry.get("main-logger");
// Global stats
const stats = globalLoggerRegistry.getGlobalStats();
console.log(stats.totalLoggers);
console.log(stats.totalMessages);
// Close specific logger
await globalLoggerRegistry.close("main-logger");
// Close all loggers
await globalLoggerRegistry.closeAll();Code Analysis (Server)
File Discovery
import { FileDiscovery } from "@repo/core-utils/server/file-discovery";
// highlight-start
const discovery = new FileDiscovery({
rootDir: "./src",
ignorePatterns: ["**/*.test.ts", "**/node_modules/**"]
});
// highlight-end
const files = await discovery.findFiles("**/*.ts");
console.log(files); // Array of file pathsPattern Analyzer
import { PatternAnalyzer } from "@repo/core-utils/server/pattern-analyzer";
// highlight-start
const analyzer = new PatternAnalyzer({
patterns: [
{ name: "console-log", pattern: /console\.log/g },
{ name: "todo-comment", pattern: /\/\/\s*TODO:/gi }
]
});
// highlight-end
const results = await analyzer.analyze("./src");
console.log(results.patterns); // Found patterns by fileDependency Analyzer
import { DependencyAnalyzer } from "@repo/core-utils/server/dependency-analyzer";
const analyzer = new DependencyAnalyzer();
// highlight-start
const graph = await analyzer.analyzeDependencies("./src");
// highlight-end
console.log(graph.nodes); // Files
console.log(graph.edges); // Dependencies
console.log(graph.circularDependencies); // Circular deps foundSecurity Scanner
import { SecurityScanner } from "@repo/core-utils/server/security-scanner";
// highlight-start
const scanner = new SecurityScanner({
rules: ["no-eval", "no-hardcoded-secrets", "no-sql-injection", "no-xss"]
});
// highlight-end
const results = await scanner.scan("./src");
console.log(results.vulnerabilities); // Found security issuesCode Transformation
import { CodeTransformer } from "@repo/core-utils/server/code-transformation";
const transformer = new CodeTransformer();
// highlight-start
const result = await transformer.transform("./src/file.ts", {
replaceImports: {
from: "@old/package",
to: "@new/package"
}
});
// highlight-end
console.log(result.modified); // Boolean
console.log(result.ast); // AST if neededPerformance & Monitoring (Server)
Performance Tracker
import { PerformanceTracker } from "@repo/core-utils/server/performance";
const tracker = new PerformanceTracker();
// highlight-start
tracker.start("operation-name");
// ... do work ...
tracker.end("operation-name");
// highlight-end
const metrics = tracker.getMetrics("operation-name");
console.log(metrics.duration); // Duration in ms
console.log(metrics.count); // Number of times called
console.log(metrics.average); // Average durationMemory Monitor
import { MemoryMonitor } from "@repo/core-utils/server/advanced-memory-monitor";
// highlight-start
const monitor = new MemoryMonitor({
interval: 5000, // Check every 5 seconds
threshold: 200 * 1024 * 1024, // 200MB
onThresholdExceeded: (usage) => {
console.warn(`Memory usage: ${usage.heapUsed / 1024 / 1024}MB`);
}
});
// highlight-end
monitor.start();
// Get current usage
const usage = monitor.getUsage();
console.log(usage.heapUsed);
console.log(usage.heapTotal);
console.log(usage.external);
// Stop monitoring
monitor.stop();Utility Helpers (Server)
Retry Logic
import { retry } from "@repo/core-utils/server/retry";
// highlight-start
const result = await retry(
async () => {
return await fetch("https://api.example.com/data");
},
{
maxAttempts: 3,
delay: 1000,
exponentialBackoff: true
}
);
// highlight-endBatch Processor
import { BatchProcessor } from "@repo/core-utils/server/batch-processor";
// highlight-start
const processor = new BatchProcessor({
batchSize: 100,
concurrency: 5,
processFunc: async (batch) => {
// Process batch of items
return batch.map((item) => processItem(item));
}
});
// highlight-end
const results = await processor.process(items);Worker Pool
import { WorkerPool } from "@repo/core-utils/server/worker-pool";
// highlight-start
const pool = new WorkerPool({
maxWorkers: 4,
workerScript: "./worker.js"
});
// highlight-end
await pool.init();
const result = await pool.execute({ task: "process-data", data: "..." });
await pool.shutdown();Abort Support
import { withAbort } from "@repo/core-utils/server/abort-support";
const controller = new AbortController();
// highlight-start
const result = await withAbort(async (signal) => {
return await longRunningOperation(signal);
}, controller.signal);
// highlight-end
// Abort if needed
controller.abort();Usage by Environment
Next.js Server Components
// ✅ Can use server utilities
import { SafeStringifier } from "@repo/core-utils/server/stringify-advanced";
export default async function Page() {
const data = await fetchData();
const stringifier = new SafeStringifier();
const json = stringifier.stringify(data);
return <pre>{json.result}</pre>;
}Next.js Client Components
"use client";
// ✅ Must use shared utilities only
import { safeStringify } from "@repo/core-utils/shared/stringify";
export function ClientComponent({ data }: Props) {
const json = safeStringify(data, 50000);
return <pre>{json}</pre>;
}Edge Middleware
// ✅ Must use shared utilities only
import { safeStringify } from "@repo/core-utils/shared/stringify";
export function middleware(req: NextRequest) {
const debug = safeStringify(req.headers);
console.log(debug);
return NextResponse.next();
}Packages
// ✅ Prefer shared utilities for maximum portability
import { safeStringify } from "@repo/core-utils/shared/stringify";
// ⚠️ Use server utilities only when Node.js features required
import { AsyncLogger } from "@repo/core-utils/server/logger";Testing
# Run tests
pnpm --filter @repo/core-utils test
# Watch mode
pnpm --filter @repo/core-utils test --watch
# Coverage
pnpm --filter @repo/core-utils test:coverageMigration from @repo/mcp-server
Backward Compatibility
The @repo/mcp-server package re-exports these utilities for backward compatibility.
Before:
import { safeStringify } from "@repo/mcp-server/utils/stringify";
import { BoundedCache } from "@repo/mcp-server/utils/cache";After:
import { safeStringify } from "@repo/core-utils/shared/stringify";
import { BoundedCache } from "@repo/core-utils/server/cache";Design Principles
- Framework-agnostic - Works with Next.js, React, Node.js, edge runtime
- Zero dependencies - Minimal external dependencies (only catalog versions)
- Type-safe - Full TypeScript support with exported types
- Well-tested - Comprehensive test coverage
- Performance - Optimized for production use
- Reusable - DRY principle - single implementation for all packages
Related Packages
- @repo/types - TypeScript types and utilities
- @repo/utils - Additional utility functions
- @repo/shared - Shared constants and configs
External Resources
- Node.js Performance - Performance monitoring APIs
- TypeScript AST - AST manipulation reference