@dollhousemcp/mcp-server
Version:
DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.
217 lines • 30.1 kB
JavaScript
/**
* Server setup and initialization
*/
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from "@modelcontextprotocol/sdk/types.js";
// import { getUserTools } from './tools/UserTools.js'; // DEPRECATED - replaced by dollhouse_config
// import { getConfigTools } from './tools/ConfigTools.js'; // DEPRECATED - replaced by dollhouse_config
import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
import { SecurityMonitor } from '../security/securityMonitor.js';
import { logger } from '../utils/logger.js';
import { LRUCache } from '../cache/LRUCache.js';
import { getValidatedToolCacheTTL } from '../config/performance-constants.js';
import { generatePrescriptiveDigest } from './PrescriptiveDigest.js';
// ConfigWizardCheck import removed - auto-trigger disabled for v1.8.0
export class ServerSetup {
static TOOL_CACHE_KEY = 'tool_discovery_list';
/** Issue #706: Max ms to wait for deferred setup before proceeding anyway. */
static DEFERRED_SETUP_TIMEOUT_MS = 10_000;
toolCache;
contextTracker;
elementCrudHandler = null;
/** Issue #706 Phase 4: Promise that resolves when deferred setup completes. */
deferredSetupPromise = null;
constructor(contextTracker) {
this.contextTracker = contextTracker;
this.toolCache = new LRUCache({
name: 'tool-discovery',
maxSize: 1,
maxMemoryMB: 5,
ttlMs: getValidatedToolCacheTTL(),
});
}
/**
* Issue #706 Phase 4: Set the deferred setup promise for request buffering.
* First request after connect holds briefly until deferred setup completes
* (or the timeout fires). Subsequent requests proceed immediately.
*/
setDeferredSetupPromise(promise) {
this.deferredSetupPromise = promise;
// Auto-clear when resolved so subsequent requests skip the check
promise.then(() => { this.deferredSetupPromise = null; })
.catch(() => { this.deferredSetupPromise = null; });
}
/**
* Issue #706 Phase 4: Wait for deferred setup with a hard timeout.
* No-op if already resolved or never set.
*/
async awaitDeferredSetup() {
if (!this.deferredSetupPromise)
return;
const timeout = new Promise(resolve => setTimeout(resolve, ServerSetup.DEFERRED_SETUP_TIMEOUT_MS));
await Promise.race([this.deferredSetupPromise, timeout]);
this.deferredSetupPromise = null;
}
/**
* Initialize the server with all tools and handlers
*/
setupServer(server, toolRegistry, elementCrudHandler) {
this.elementCrudHandler = elementCrudHandler ?? null;
// Setup request handlers
this.setupListToolsHandler(server, toolRegistry);
this.setupCallToolHandler(server, toolRegistry);
}
/**
* Setup the ListToolsRequest handler with caching
*/
setupListToolsHandler(server, toolRegistry) {
server.setRequestHandler(ListToolsRequestSchema, async () => {
const startTime = Date.now();
// Try to get cached tools first
let tools = this.toolCache.get(ServerSetup.TOOL_CACHE_KEY);
if (!tools) {
// Cache miss - fetch tools from registry
tools = toolRegistry.getAllTools();
// Cache the results for future requests
this.toolCache.set(ServerSetup.TOOL_CACHE_KEY, tools);
const duration = Date.now() - startTime;
logger.info('ToolDiscoveryCache: Cache miss - fetched and cached tools', {
toolCount: tools.length,
duration: `${duration}ms`,
source: 'registry'
});
}
else {
const duration = Date.now() - startTime;
logger.debug('ToolDiscoveryCache: Cache hit - returned cached tools', {
toolCount: tools.length,
duration: `${duration}ms`,
source: 'cache'
});
}
return { tools };
});
}
/**
* Setup the CallToolRequest handler
*/
setupCallToolHandler(server, toolRegistry) {
server.setRequestHandler(CallToolRequestSchema, async (request) => {
// Issue #706 Phase 4: Hold first request(s) until deferred setup completes
await this.awaitDeferredSetup();
const context = this.contextTracker.createContext('llm-request', {
toolName: request.params.name,
});
return this.contextTracker.runAsync(context, async () => {
const { name, arguments: args } = request.params;
try {
const handler = toolRegistry.getHandler(name);
if (!handler) {
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
}
// Normalize Unicode in all string arguments to prevent security bypasses
const normalizedArgs = this.normalizeArgumentsUnicode(args, name);
const response = await handler(normalizedArgs);
// Issue #492: Prescriptive digest for active element context recovery.
// After context compaction, the LLM loses active element instructions.
// This digest tells it how to recover them.
if (this.elementCrudHandler && name !== 'get_active_elements') {
try {
const activeElements = await this.elementCrudHandler.getActiveElementsForPolicy();
if (activeElements.length > 0) {
const digest = generatePrescriptiveDigest(activeElements);
if (response?.content?.[0]?.type === 'text') {
response.content[0].text += '\n\n' + digest;
}
}
}
catch {
// Best-effort — never fail a tool response for the digest
}
}
return response;
}
catch (error) {
if (error instanceof McpError) {
throw error;
}
throw new McpError(ErrorCode.InternalError, `Error executing tool ${name}: ${error}`);
}
});
});
}
/**
* Recursively normalize Unicode in all string values within arguments
*/
normalizeArgumentsUnicode(args, toolName) {
if (args === null || args === undefined) {
return args;
}
if (typeof args === 'string') {
const result = UnicodeValidator.normalize(args);
if (result.detectedIssues && result.detectedIssues.length > 0) {
logger.warn(`Unicode security issues detected in tool ${toolName}:`, {
issues: result.detectedIssues,
severity: result.severity
});
}
return result.normalizedContent;
}
if (Array.isArray(args)) {
return args.map(item => this.normalizeArgumentsUnicode(item, toolName));
}
if (typeof args === 'object') {
const normalized = {};
for (const [key, value] of Object.entries(args)) {
// Normalize both keys and values to prevent Unicode attacks in property names
const normalizedKey = typeof key === 'string' ?
UnicodeValidator.normalize(key).normalizedContent : key;
normalized[normalizedKey] = this.normalizeArgumentsUnicode(value, toolName);
}
return normalized;
}
// For non-string primitive types, return as-is
return args;
}
/**
* Get the tool discovery cache
*/
getToolCache() {
return this.toolCache;
}
/**
* Invalidate the tool discovery cache (useful for external tool changes)
*/
invalidateToolCache() {
this.toolCache.delete(ServerSetup.TOOL_CACHE_KEY);
logger.info('ToolDiscoveryCache: Cache manually invalidated');
// Log security event for audit trail
SecurityMonitor.logSecurityEvent({
type: 'TOOL_CACHE_INVALIDATED',
severity: 'LOW',
source: 'ServerSetup.invalidateToolCache',
details: 'Tool discovery cache manually invalidated'
});
}
/**
* Log current cache performance metrics
*/
logCachePerformance() {
const stats = this.toolCache.getStats();
logger.info('ToolDiscoveryCache: Performance metrics', {
hitRate: `${(stats.hitRate * 100).toFixed(1)}%`,
hits: stats.hitCount,
misses: stats.missCount,
cacheSize: stats.size,
efficiency: stats.hitCount > 0 ? 'GOOD' : 'NEEDS_WARMUP'
});
}
/**
* Get cache statistics for monitoring
*/
getCacheStatistics() {
return {
toolCache: this.toolCache.getStats()
};
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VydmVyU2V0dXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmVyL1NlcnZlclNldHVwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBR0gsT0FBTyxFQUFFLHFCQUFxQixFQUFFLFNBQVMsRUFBRSxzQkFBc0IsRUFBRSxRQUFRLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUV4SCxvR0FBb0c7QUFDcEcsd0dBQXdHO0FBQ3hHLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBQzlFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNqRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDNUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2hELE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQzlFLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBSXJFLHNFQUFzRTtBQUV0RSxNQUFNLE9BQU8sV0FBVztJQUNkLE1BQU0sQ0FBVSxjQUFjLEdBQUcscUJBQXFCLENBQUM7SUFDL0QsOEVBQThFO0lBQ3RFLE1BQU0sQ0FBVSx5QkFBeUIsR0FBRyxNQUFNLENBQUM7SUFDbkQsU0FBUyxDQUFtQjtJQUM1QixjQUFjLENBQWlCO0lBQy9CLGtCQUFrQixHQUE4QixJQUFJLENBQUM7SUFDN0QsK0VBQStFO0lBQ3ZFLG9CQUFvQixHQUF5QixJQUFJLENBQUM7SUFFMUQsWUFBWSxjQUE4QjtRQUN4QyxJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQztRQUNyQyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksUUFBUSxDQUFTO1lBQ3BDLElBQUksRUFBRSxnQkFBZ0I7WUFDdEIsT0FBTyxFQUFFLENBQUM7WUFDVixXQUFXLEVBQUUsQ0FBQztZQUNkLEtBQUssRUFBRSx3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UyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDbEQsTUFBTSxDQUFDLElBQUksQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO1FBRTlELHFDQUFxQztRQUNyQyxlQUFlLENBQUMsZ0JBQWdCLENBQUM7WUFDL0IsSUFBSSxFQUFFLHdCQUF3QjtZQUM5QixRQUFRLEVBQUUsS0FBSztZQUNmLE1BQU0sRUFBRSxpQ0FBaUM7WUFDekMsT0FBTyxFQUFFLDJDQUEyQztTQUNyRCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxtQkFBbUI7UUFDakIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUN4QyxNQUFNLENBQUMsSUFBSSxDQUFDLHlDQUF5QyxFQUFFO1lBQ3JELE9BQU8sRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUc7WUFDL0MsSUFBSSxFQUFFLEtBQUssQ0FBQyxRQUFRO1lBQ3BCLE1BQU0sRUFBRSxLQUFLLENBQUMsU0FBUztZQUN2QixTQUFTLEVBQUUsS0FBSyxDQUFDLElBQUk7WUFDckIsVUFBVSxFQUFFLEtBQUssQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLGNBQWM7U0FDekQsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0gsa0JBQWtCO1FBQ2hCLE9BQU87WUFDTCxTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUU7U0FDckMsQ0FBQztJQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNlcnZlciBzZXR1cCBhbmQgaW5pdGlhbGl6YXRpb25cbiAqL1xuXG5pbXBvcnQgeyBTZXJ2ZXIgfSBmcm9tIFwiQG1vZGVsY29udGV4dHByb3RvY29sL3Nkay9zZXJ2ZXIvaW5kZXguanNcIjtcbmltcG9ydCB7IENhbGxUb29sUmVxdWVzdFNjaGVtYSwgRXJyb3JDb2RlLCBMaXN0VG9vbHNSZXF1ZXN0U2NoZW1hLCBNY3BFcnJvciB9IGZyb20gXCJAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3R5cGVzLmpzXCI7XG5pbXBvcnQgeyBUb29sUmVnaXN0cnkgfSBmcm9tICcuLi9oYW5kbGVycy9Ub29sUmVnaXN0cnkuanMnO1xuLy8gaW1wb3J0IHsgZ2V0VXNlclRvb2xzIH0gZnJvbSAnLi90b29scy9Vc2VyVG9vbHMuanMnOyAvLyBERVBSRUNBVEVEIC0gcmVwbGFjZWQgYnkgZG9sbGhvdXNlX2NvbmZpZ1xuLy8gaW1wb3J0IHsgZ2V0Q29uZmlnVG9vbHMgfSBmcm9tICcuL3Rvb2xzL0NvbmZpZ1Rvb2xzLmpzJzsgLy8gREVQUkVDQVRFRCAtIHJlcGxhY2VkIGJ5IGRvbGxob3VzZV9jb25maWdcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBMUlVDYWNoZSB9IGZyb20gJy4uL2NhY2hlL0xSVUNhY2hlLmpzJztcbmltcG9ydCB7IGdldFZhbGlkYXRlZFRvb2xDYWNoZVRUTCB9IGZyb20gJy4uL2NvbmZpZy9wZXJmb3JtYW5jZS1jb25zdGFudHMuanMnO1xuaW1wb3J0IHsgZ2VuZXJhdGVQcmVzY3JpcHRpdmVEaWdlc3QgfSBmcm9tICcuL1ByZXNjcmlwdGl2ZURpZ2VzdC5qcyc7XG5pbXBvcnQgdHlwZSB7IFRvb2wgfSBmcm9tIFwiQG1vZGVsY29udGV4dHByb3RvY29sL3Nkay90eXBlcy5qc1wiO1xuaW1wb3J0IHR5cGUgeyBDb250ZXh0VHJhY2tlciB9IGZyb20gJy4uL3NlY3VyaXR5L2VuY3J5cHRpb24vQ29udGV4dFRyYWNrZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBFbGVtZW50Q1JVREhhbmRsZXIgfSBmcm9tICcuLi9oYW5kbGVycy9FbGVtZW50Q1JVREhhbmRsZXIuanMnO1xuLy8gQ29uZmlnV2l6YXJkQ2hlY2sgaW1wb3J0IHJlbW92ZWQgLSBhdXRvLXRyaWdnZXIgZGlzYWJsZWQgZm9yIHYxLjguMFxuXG5leHBvcnQgY2xhc3MgU2VydmVyU2V0dXAge1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBUT09MX0NBQ0hFX0tFWSA9ICd0b29sX2Rpc2NvdmVyeV9saXN0JztcbiAgLyoqIElzc3VlICM3MDY6IE1heCBtcyB0byB3YWl0IGZvciBkZWZlcnJlZCBzZXR1cCBiZWZvcmUgcHJvY2VlZGluZyBhbnl3YXkuICovXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IERFRkVSUkVEX1NFVFVQX1RJTUVPVVRfTVMgPSAxMF8wMDA7XG4gIHByaXZhdGUgdG9vbENhY2hlOiBMUlVDYWNoZTxUb29sW10+O1xuICBwcml2YXRlIGNvbnRleHRUcmFja2VyOiBDb250ZXh0VHJhY2tlcjtcbiAgcHJpdmF0ZSBlbGVtZW50Q3J1ZEhhbmRsZXI6IEVsZW1lbnRDUlVESGFuZGxlciB8IG51bGwgPSBudWxsO1xuICAvKiogSXNzdWUgIzcwNiBQaGFzZSA0OiBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBkZWZlcnJlZCBzZXR1cCBjb21wbGV0ZXMuICovXG4gIHByaXZhdGUgZGVmZXJyZWRTZXR1cFByb21pc2U6IFByb21pc2U8dm9pZD4gfCBudWxsID0gbnVsbDtcblxuICBjb25zdHJ1Y3Rvcihjb250ZXh0VHJhY2tlcjogQ29udGV4dFRyYWNrZXIpIHtcbiAgICB0aGlzLmNvbnRleHRUcmFja2VyID0gY29udGV4dFRyYWNrZXI7XG4gICAgdGhpcy50b29sQ2FjaGUgPSBuZXcgTFJVQ2FjaGU8VG9vbFtdPih7XG4gICAgICBuYW1lOiAndG9vbC1kaXNjb3ZlcnknLFxuICAgICAgbWF4U2l6ZTogMSxcbiAgICAgIG1heE1lbW9yeU1COiA1LFxuICAgICAgdHRsTXM6IGdldFZhbGlkYXRlZFRvb2xDYWNoZVRUTCgpLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIElzc3VlICM3MDYgUGhhc2UgNDogU2V0IHRoZSBkZWZlcnJlZCBzZXR1cCBwcm9taXNlIGZvciByZXF1ZXN0IGJ1ZmZlcmluZy5cbiAgICogRmlyc3QgcmVxdWVzdCBhZnRlciBjb25uZWN0IGhvbGRzIGJyaWVmbHkgdW50aWwgZGVmZXJyZWQgc2V0dXAgY29tcGxldGVzXG4gICAqIChvciB0aGUgdGltZW91dCBmaXJlcykuIFN1YnNlcXVlbnQgcmVxdWVzdHMgcHJvY2VlZCBpbW1lZGlhdGVseS5cbiAgICovXG4gIHNldERlZmVycmVkU2V0dXBQcm9taXNlKHByb21pc2U6IFByb21pc2U8dm9pZD4pOiB2b2lkIHtcbiAgICB0aGlzLmRlZmVycmVkU2V0dXBQcm9taXNlID0gcHJvbWlzZTtcbiAgICAvLyBBdXRvLWNsZWFyIHdoZW4gcmVzb2x2ZWQgc28gc3Vic2VxdWVudCByZXF1ZXN0cyBza2lwIHRoZSBjaGVja1xuICAgIHByb21pc2UudGhlbigoKSA9PiB7IHRoaXMuZGVmZXJyZWRTZXR1cFByb21pc2UgPSBudWxsOyB9KVxuICAgICAgLmNhdGNoKCgpID0+IHsgdGhpcy5kZWZlcnJlZFNldHVwUHJvbWlzZSA9IG51bGw7IH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIElzc3VlICM3MDYgUGhhc2UgNDogV2FpdCBmb3IgZGVmZXJyZWQgc2V0dXAgd2l0aCBhIGhhcmQgdGltZW91dC5cbiAgICogTm8tb3AgaWYgYWxyZWFkeSByZXNvbHZlZCBvciBuZXZlciBzZXQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGF3YWl0RGVmZXJyZWRTZXR1cCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMuZGVmZXJyZWRTZXR1cFByb21pc2UpIHJldHVybjtcbiAgICBjb25zdCB0aW1lb3V0ID0gbmV3IFByb21pc2U8dm9pZD4ocmVzb2x2ZSA9PlxuICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBTZXJ2ZXJTZXR1cC5ERUZFUlJFRF9TRVRVUF9USU1FT1VUX01TKVxuICAgICk7XG4gICAgYXdhaXQgUHJvbWlzZS5yYWNlKFt0aGlzLmRlZmVycmVkU2V0dXBQcm9taXNlLCB0aW1lb3V0XSk7XG4gICAgdGhpcy5kZWZlcnJlZFNldHVwUHJvbWlzZSA9IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZSB0aGUgc2VydmVyIHdpdGggYWxsIHRvb2xzIGFuZCBoYW5kbGVyc1xuICAgKi9cbiAgc2V0dXBTZXJ2ZXIoc2VydmVyOiBTZXJ2ZXIsIHRvb2xSZWdpc3RyeTogVG9vbFJlZ2lzdHJ5LCBlbGVtZW50Q3J1ZEhhbmRsZXI/OiBFbGVtZW50Q1JVREhhbmRsZXIpOiB2b2lkIHtcbiAgICB0aGlzLmVsZW1lbnRDcnVkSGFuZGxlciA9IGVsZW1lbnRDcnVkSGFuZGxlciA/PyBudWxsO1xuXG4gICAgLy8gU2V0dXAgcmVxdWVzdCBoYW5kbGVyc1xuICAgIHRoaXMuc2V0dXBMaXN0VG9vbHNIYW5kbGVyKHNlcnZlciwgdG9vbFJlZ2lzdHJ5KTtcbiAgICB0aGlzLnNldHVwQ2FsbFRvb2xIYW5kbGVyKHNlcnZlciwgdG9vbFJlZ2lzdHJ5KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNldHVwIHRoZSBMaXN0VG9vbHNSZXF1ZXN0IGhhbmRsZXIgd2l0aCBjYWNoaW5nXG4gICAqL1xuICBwcml2YXRlIHNldHVwTGlzdFRvb2xzSGFuZGxlcihzZXJ2ZXI6IFNlcnZlciwgdG9vbFJlZ2lzdHJ5OiBUb29sUmVnaXN0cnkpOiB2b2lkIHtcbiAgICBzZXJ2ZXIuc2V0UmVxdWVzdEhhbmRsZXIoTGlzdFRvb2xzUmVxdWVzdFNjaGVtYSwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgIFxuICAgICAgLy8gVHJ5IHRvIGdldCBjYWNoZWQgdG9vbHMgZmlyc3RcbiAgICAgIGxldCB0b29scyA9IHRoaXMudG9vbENhY2hlLmdldChTZXJ2ZXJTZXR1cC5UT09MX0NBQ0hFX0tFWSk7XG5cbiAgICAgIGlmICghdG9vbHMpIHtcbiAgICAgICAgLy8gQ2FjaGUgbWlzcyAtIGZldGNoIHRvb2xzIGZyb20gcmVnaXN0cnlcbiAgICAgICAgdG9vbHMgPSB0b29sUmVnaXN0cnkuZ2V0QWxsVG9vbHMoKTtcblxuICAgICAgICAvLyBDYWNoZSB0aGUgcmVzdWx0cyBmb3IgZnV0dXJlIHJlcXVlc3RzXG4gICAgICAgIHRoaXMudG9vbENhY2hlLnNldChTZXJ2ZXJTZXR1cC5UT09MX0NBQ0hFX0tFWSwgdG9vbHMpO1xuXG4gICAgICAgIGNvbnN0IGR1cmF0aW9uID0gRGF0ZS5ub3coKSAtIHN0YXJ0VGltZTtcbiAgICAgICAgbG9nZ2VyLmluZm8oJ1Rvb2xEaXNjb3ZlcnlDYWNoZTogQ2FjaGUgbWlzcyAtIGZldGNoZWQgYW5kIGNhY2hlZCB0b29scycsIHtcbiAgICAgICAgICB0b29sQ291bnQ6IHRvb2xzLmxlbmd0aCxcbiAgICAgICAgICBkdXJhdGlvbjogYCR7ZHVyYXRpb259bXNgLFxuICAgICAgICAgIHNvdXJjZTogJ3JlZ2lzdHJ5J1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGR1cmF0aW9uID0gRGF0ZS5ub3coKSAtIHN0YXJ0VGltZTtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdUb29sRGlzY292ZXJ5Q2FjaGU6IENhY2hlIGhpdCAtIHJldHVybmVkIGNhY2hlZCB0b29scycsIHtcbiAgICAgICAgICB0b29sQ291bnQ6IHRvb2xzLmxlbmd0aCxcbiAgICAgICAgICBkdXJhdGlvbjogYCR7ZHVyYXRpb259bXNgLFxuICAgICAgICAgIHNvdXJjZTogJ2NhY2hlJ1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIHsgdG9vbHMgfTtcbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNldHVwIHRoZSBDYWxsVG9vbFJlcXVlc3QgaGFuZGxlclxuICAgKi9cbiAgcHJpdmF0ZSBzZXR1cENhbGxUb29sSGFuZGxlcihzZXJ2ZXI6IFNlcnZlciwgdG9vbFJlZ2lzdHJ5OiBUb29sUmVnaXN0cnkpOiB2b2lkIHtcbiAgICBzZXJ2ZXIuc2V0UmVxdWVzdEhhbmRsZXIoQ2FsbFRvb2xSZXF1ZXN0U2NoZW1hLCBhc3luYyAocmVxdWVzdCkgPT4ge1xuICAgICAgLy8gSXNzdWUgIzcwNiBQaGFzZSA0OiBIb2xkIGZpcnN0IHJlcXVlc3QocykgdW50aWwgZGVmZXJyZWQgc2V0dXAgY29tcGxldGVzXG4gICAgICBhd2FpdCB0aGlzLmF3YWl0RGVmZXJyZWRTZXR1cCgpO1xuXG4gICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jb250ZXh0VHJhY2tlci5jcmVhdGVDb250ZXh0KCdsbG0tcmVxdWVzdCcsIHtcbiAgICAgICAgdG9vbE5hbWU6IHJlcXVlc3QucGFyYW1zLm5hbWUsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiB0aGlzLmNvbnRleHRUcmFja2VyLnJ1bkFzeW5jKGNvbnRleHQsIGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgeyBuYW1lLCBhcmd1bWVudHM6IGFyZ3MgfSA9IHJlcXVlc3QucGFyYW1zO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgaGFuZGxlciA9IHRvb2xSZWdpc3RyeS5nZXRIYW5kbGVyKG5hbWUpO1xuXG4gICAgICAgICAgaWYgKCFoYW5kbGVyKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgTWNwRXJyb3IoXG4gICAgICAgICAgICAgIEVycm9yQ29kZS5NZXRob2ROb3RGb3VuZCxcbiAgICAgICAgICAgICAgYFVua25vd24gdG9vbDogJHtuYW1lfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gTm9ybWFsaXplIFVuaWNvZGUgaW4gYWxsIHN0cmluZyBhcmd1bWVudHMgdG8gcHJldmVudCBzZWN1cml0eSBieXBhc3Nlc1xuICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRBcmdzID0gdGhpcy5ub3JtYWxpemVBcmd1bWVudHNVbmljb2RlKGFyZ3MsIG5hbWUpO1xuXG4gICAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBoYW5kbGVyKG5vcm1hbGl6ZWRBcmdzKTtcblxuICAgICAgICAgIC8vIElzc3VlICM0OTI6IFByZXNjcmlwdGl2ZSBkaWdlc3QgZm9yIGFjdGl2ZSBlbGVtZW50IGNvbnRleHQgcmVjb3ZlcnkuXG4gICAgICAgICAgLy8gQWZ0ZXIgY29udGV4dCBjb21wYWN0aW9uLCB0aGUgTExNIGxvc2VzIGFjdGl2ZSBlbGVtZW50IGluc3RydWN0aW9ucy5cbiAgICAgICAgICAvLyBUaGlzIGRpZ2VzdCB0ZWxscyBpdCBob3cgdG8gcmVjb3ZlciB0aGVtLlxuICAgICAgICAgIGlmICh0aGlzLmVsZW1lbnRDcnVkSGFuZGxlciAmJiBuYW1lICE9PSAnZ2V0X2FjdGl2ZV9lbGVtZW50cycpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGNvbnN0IGFjdGl2ZUVsZW1lbnRzID0gYXdhaXQgdGhpcy5lbGVtZW50Q3J1ZEhhbmRsZXIuZ2V0QWN0aXZlRWxlbWVudHNGb3JQb2xpY3koKTtcbiAgICAgICAgICAgICAgaWYgKGFjdGl2ZUVsZW1lbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBjb25zdCBkaWdlc3QgPSBnZW5lcmF0ZVByZXNjcmlwdGl2ZURpZ2VzdChhY3RpdmVFbGVtZW50cyk7XG4gICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlPy5jb250ZW50Py5bMF0/LnR5cGUgPT09ICd0ZXh0Jykge1xuICAgICAgICAgICAgICAgICAgcmVzcG9uc2UuY29udGVudFswXS50ZXh0ICs9ICdcXG5cXG4nICsgZGlnZXN0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgIC8vIEJlc3QtZWZmb3J0IOKAlCBuZXZlciBmYWlsIGEgdG9vbCByZXNwb25zZSBmb3IgdGhlIGRpZ2VzdFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiByZXNwb25zZTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBNY3BFcnJvcikge1xuICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhyb3cgbmV3IE1jcEVycm9yKFxuICAgICAgICAgICAgRXJyb3JDb2RlLkludGVybmFsRXJyb3IsXG4gICAgICAgICAgICBgRXJyb3IgZXhlY3V0aW5nIHRvb2wgJHtuYW1lfTogJHtlcnJvcn1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZWN1cnNpdmVseSBub3JtYWxpemUgVW5pY29kZSBpbiBhbGwgc3RyaW5nIHZhbHVlcyB3aXRoaW4gYXJndW1lbnRzXG4gICAqL1xuICBwcml2YXRlIG5vcm1hbGl6ZUFyZ3VtZW50c1VuaWNvZGUoYXJnczogYW55LCB0b29sTmFtZTogc3RyaW5nKTogYW55IHtcbiAgICBpZiAoYXJncyA9PT0gbnVsbCB8fCBhcmdzID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBhcmdzO1xuICAgIH1cbiAgICBcbiAgICBpZiAodHlwZW9mIGFyZ3MgPT09ICdzdHJpbmcnKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShhcmdzKTtcbiAgICAgIGlmIChyZXN1bHQuZGV0ZWN0ZWRJc3N1ZXMgJiYgcmVzdWx0LmRldGVjdGVkSXNzdWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oYFVuaWNvZGUgc2VjdXJpdHkgaXNzdWVzIGRldGVjdGVkIGluIHRvb2wgJHt0b29sTmFtZX06YCwge1xuICAgICAgICAgIGlzc3VlczogcmVzdWx0LmRldGVjdGVkSXNzdWVzLFxuICAgICAgICAgIHNldmVyaXR5OiByZXN1bHQuc2V2ZXJpdHlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0Lm5vcm1hbGl6ZWRDb250ZW50O1xuICAgIH1cbiAgICBcbiAgICBpZiAoQXJyYXkuaXNBcnJheShhcmdzKSkge1xuICAgICAgcmV0dXJuIGFyZ3MubWFwKGl0ZW0gPT4gdGhpcy5ub3JtYWxpemVBcmd1bWVudHNVbmljb2RlKGl0ZW0sIHRvb2xOYW1lKSk7XG4gICAgfVxuICAgIFxuICAgIGlmICh0eXBlb2YgYXJncyA9PT0gJ29iamVjdCcpIHtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWQ6IGFueSA9IHt9O1xuICAgICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoYXJncykpIHtcbiAgICAgICAgLy8gTm9ybWFsaXplIGJvdGgga2V5cyBhbmQgdmFsdWVzIHRvIHByZXZlbnQgVW5pY29kZSBhdHRhY2tzIGluIHByb3BlcnR5IG5hbWVzXG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRLZXkgPSB0eXBlb2Yga2V5ID09PSAnc3RyaW5nJyA/IFxuICAgICAgICAgIFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKGtleSkubm9ybWFsaXplZENvbnRlbnQgOiBrZXk7XG4gICAgICAgIG5vcm1hbGl6ZWRbbm9ybWFsaXplZEtleV0gPSB0aGlzLm5vcm1hbGl6ZUFyZ3VtZW50c1VuaWNvZGUodmFsdWUsIHRvb2xOYW1lKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBub3JtYWxpemVkO1xuICAgIH1cbiAgICBcbiAgICAvLyBGb3Igbm9uLXN0cmluZyBwcmltaXRpdmUgdHlwZXMsIHJldHVybiBhcy1pc1xuICAgIHJldHVybiBhcmdzO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSB0b29sIGRpc2NvdmVyeSBjYWNoZVxuICAgKi9cbiAgZ2V0VG9vbENhY2hlKCk6IExSVUNhY2hlPFRvb2xbXT4ge1xuICAgIHJldHVybiB0aGlzLnRvb2xDYWNoZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnZhbGlkYXRlIHRoZSB0b29sIGRpc2NvdmVyeSBjYWNoZSAodXNlZnVsIGZvciBleHRlcm5hbCB0b29sIGNoYW5nZXMpXG4gICAqL1xuICBpbnZhbGlkYXRlVG9vbENhY2hlKCk6IHZvaWQge1xuICAgIHRoaXMudG9vbENhY2hlLmRlbGV0ZShTZXJ2ZXJTZXR1cC5UT09MX0NBQ0hFX0tFWSk7XG4gICAgbG9nZ2VyLmluZm8oJ1Rvb2xEaXNjb3ZlcnlDYWNoZTogQ2FjaGUgbWFudWFsbHkgaW52YWxpZGF0ZWQnKTtcblxuICAgIC8vIExvZyBzZWN1cml0eSBldmVudCBmb3IgYXVkaXQgdHJhaWxcbiAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICB0eXBlOiAnVE9PTF9DQUNIRV9JTlZBTElEQVRFRCcsXG4gICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICBzb3VyY2U6ICdTZXJ2ZXJTZXR1cC5pbnZhbGlkYXRlVG9vbENhY2hlJyxcbiAgICAgIGRldGFpbHM6ICdUb29sIGRpc2NvdmVyeSBjYWNoZSBtYW51YWxseSBpbnZhbGlkYXRlZCdcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2cgY3VycmVudCBjYWNoZSBwZXJmb3JtYW5jZSBtZXRyaWNzXG4gICAqL1xuICBsb2dDYWNoZVBlcmZvcm1hbmNlKCk6IHZvaWQge1xuICAgIGNvbnN0IHN0YXRzID0gdGhpcy50b29sQ2FjaGUuZ2V0U3RhdHMoKTtcbiAgICBsb2dnZXIuaW5mbygnVG9vbERpc2NvdmVyeUNhY2hlOiBQZXJmb3JtYW5jZSBtZXRyaWNzJywge1xuICAgICAgaGl0UmF0ZTogYCR7KHN0YXRzLmhpdFJhdGUgKiAxMDApLnRvRml4ZWQoMSl9JWAsXG4gICAgICBoaXRzOiBzdGF0cy5oaXRDb3VudCxcbiAgICAgIG1pc3Nlczogc3RhdHMubWlzc0NvdW50LFxuICAgICAgY2FjaGVTaXplOiBzdGF0cy5zaXplLFxuICAgICAgZWZmaWNpZW5jeTogc3RhdHMuaGl0Q291bnQgPiAwID8gJ0dPT0QnIDogJ05FRURTX1dBUk1VUCdcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY2FjaGUgc3RhdGlzdGljcyBmb3IgbW9uaXRvcmluZ1xuICAgKi9cbiAgZ2V0Q2FjaGVTdGF0aXN0aWNzKCkge1xuICAgIHJldHVybiB7XG4gICAgICB0b29sQ2FjaGU6IHRoaXMudG9vbENhY2hlLmdldFN0YXRzKClcbiAgICB9O1xuICB9XG59Il19