Skip to main content
Glama

DollhouseMCP

by DollhouseMCP
filesystem.tsโ€ข3.71 kB
/** * Filesystem and string manipulation utilities */ import * as fs from 'fs/promises'; import * as path from 'path'; import { ADJECTIVES, ANIMALS } from '../config/constants.js'; /** * Generate an anonymous ID for users without identity */ export function generateAnonymousId(): string { const adjective = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)]; const animal = ANIMALS[Math.floor(Math.random() * ANIMALS.length)]; const random = Math.random().toString(36).substring(2, 6); return `anon-${adjective}-${animal}-${random}`; } /** * Generate a unique ID for personas */ // Pre-compiled regex for better performance (avoids creating regex on each character) const ALPHANUMERIC_REGEX = /[a-z0-9]/; export function generateUniqueId(personaName: string, author?: string): string { const now = new Date(); const dateStr = now.toISOString().slice(0, 10).replaceAll('-', ''); const timeStr = now.toTimeString().slice(0, 8).replaceAll(':', ''); // SECURITY FIX: Prevent ReDoS by using a single-pass approach // Previously: Multiple replace() operations with unbounded quantifiers could cause exponential backtracking // Now: Single-pass transformation with built-in length limit const normalized = personaName.toLowerCase(); const sanitizedName = normalized .split('') .map(char => ALPHANUMERIC_REGEX.test(char) ? char : '-') .join('') .substring(0, 100) // Limit after transformation to preserve structure .replaceAll(/(^-+)|(-+$)/g, '') // Only trim leading/trailing hyphens .replaceAll(/-{2,}/g, '-'); // Collapse multiple hyphens const whoMadeIt = author || generateAnonymousId(); return `${sanitizedName}_${dateStr}-${timeStr}_${whoMadeIt}`; } /** * Convert text to URL-safe slug */ export function slugify(text: string): string { // SECURITY FIX: Prevent ReDoS by using a single-pass approach // Previously: Multiple replace() operations with unbounded quantifiers could cause exponential backtracking // Now: Single-pass transformation with built-in length limit const normalized = text.toLowerCase(); const transformed = normalized .split('') .map(char => ALPHANUMERIC_REGEX.test(char) ? char : '-') .join(''); // SECURITY FIX: Avoid polynomial regex by using separate operations // Trim leading hyphens let start = 0; while (start < transformed.length && transformed[start] === '-') { start++; } // Trim trailing hyphens let end = transformed.length - 1; while (end >= start && transformed[end] === '-') { end--; } // Extract the trimmed portion and collapse multiple hyphens const trimmed = transformed.slice(start, end + 1); return trimmed.replaceAll(/-{2,}/g, '-'); // This is safe as it's linear } /** * Ensure a directory exists, create if it doesn't */ export async function ensureDirectory(dirPath: string): Promise<void> { try { await fs.access(dirPath); } catch { await fs.mkdir(dirPath, { recursive: true }); } } /** * Check if a file exists */ export async function fileExists(filePath: string): Promise<boolean> { try { await fs.access(filePath); return true; } catch { return false; } } /** * Get file size in bytes */ export async function getFileSize(filePath: string): Promise<number> { const stats = await fs.stat(filePath); return stats.size; } /** * Create a backup of a directory */ export async function createBackup(sourcePath: string, backupPath: string): Promise<void> { // Ensure backup directory exists const backupDir = path.dirname(backupPath); await ensureDirectory(backupDir); // Copy directory recursively await fs.cp(sourcePath, backupPath, { recursive: true }); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DollhouseMCP/DollhouseMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server