@dollhousemcp/mcp-server 2.0.11 → 2.0.12-rc.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/config/ConfigManager.d.ts +34 -0
  3. package/dist/config/ConfigManager.d.ts.map +1 -1
  4. package/dist/config/ConfigManager.js +46 -1
  5. package/dist/config/env.d.ts +18 -0
  6. package/dist/config/env.d.ts.map +1 -1
  7. package/dist/config/env.js +89 -2
  8. package/dist/di/Container.d.ts +1 -0
  9. package/dist/di/Container.d.ts.map +1 -1
  10. package/dist/di/Container.js +38 -2
  11. package/dist/elements/agents/AgentManager.js +2 -2
  12. package/dist/generated/version.d.ts +2 -2
  13. package/dist/generated/version.d.ts.map +1 -1
  14. package/dist/generated/version.js +3 -3
  15. package/dist/handlers/mcp-aql/GatekeeperSession.d.ts.map +1 -1
  16. package/dist/handlers/mcp-aql/GatekeeperSession.js +3 -2
  17. package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts.map +1 -1
  18. package/dist/handlers/mcp-aql/MCPAQLHandler.js +11 -3
  19. package/dist/handlers/mcp-aql/OperationSchema.d.ts.map +1 -1
  20. package/dist/handlers/mcp-aql/OperationSchema.js +11 -6
  21. package/dist/handlers/mcp-aql/policies/ToolClassification.d.ts.map +1 -1
  22. package/dist/handlers/mcp-aql/policies/ToolClassification.js +8 -1
  23. package/dist/index.js +53 -3
  24. package/dist/security/InputNormalizer.d.ts +4 -6
  25. package/dist/security/InputNormalizer.d.ts.map +1 -1
  26. package/dist/security/InputNormalizer.js +10 -16
  27. package/dist/security/audit/config/suppressions.d.ts.map +1 -1
  28. package/dist/security/audit/config/suppressions.js +26 -1
  29. package/dist/security/constants.d.ts +7 -0
  30. package/dist/security/constants.d.ts.map +1 -1
  31. package/dist/security/constants.js +10 -1
  32. package/dist/security/contentValidator.d.ts.map +1 -1
  33. package/dist/security/contentValidator.js +14 -6
  34. package/dist/security/encryption/PatternEncryptor.d.ts.map +1 -1
  35. package/dist/security/encryption/PatternEncryptor.js +18 -10
  36. package/dist/security/securityMonitor.d.ts +1 -1
  37. package/dist/security/securityMonitor.d.ts.map +1 -1
  38. package/dist/security/securityMonitor.js +1 -1
  39. package/dist/security/tokenManager.d.ts +18 -2
  40. package/dist/security/tokenManager.d.ts.map +1 -1
  41. package/dist/security/tokenManager.js +47 -15
  42. package/dist/security/validators/unicodeValidator.d.ts +4 -5
  43. package/dist/security/validators/unicodeValidator.d.ts.map +1 -1
  44. package/dist/security/validators/unicodeValidator.js +19 -20
  45. package/dist/services/VerificationNotifier.d.ts.map +1 -1
  46. package/dist/services/VerificationNotifier.js +15 -13
  47. package/dist/services/validation/GenericElementValidator.js +5 -5
  48. package/dist/web/console/IngestRoutes.d.ts +14 -2
  49. package/dist/web/console/IngestRoutes.d.ts.map +1 -1
  50. package/dist/web/console/IngestRoutes.js +69 -5
  51. package/dist/web/console/LeaderElection.d.ts +37 -3
  52. package/dist/web/console/LeaderElection.d.ts.map +1 -1
  53. package/dist/web/console/LeaderElection.js +67 -7
  54. package/dist/web/console/LeaderForwardingSink.d.ts +19 -3
  55. package/dist/web/console/LeaderForwardingSink.d.ts.map +1 -1
  56. package/dist/web/console/LeaderForwardingSink.js +44 -9
  57. package/dist/web/console/PromotionManager.d.ts +29 -0
  58. package/dist/web/console/PromotionManager.d.ts.map +1 -0
  59. package/dist/web/console/PromotionManager.js +94 -0
  60. package/dist/web/console/SessionNames.d.ts +7 -0
  61. package/dist/web/console/SessionNames.d.ts.map +1 -1
  62. package/dist/web/console/SessionNames.js +10 -1
  63. package/dist/web/console/UnifiedConsole.d.ts +26 -1
  64. package/dist/web/console/UnifiedConsole.d.ts.map +1 -1
  65. package/dist/web/console/UnifiedConsole.js +143 -20
  66. package/dist/web/portDiscovery.d.ts +4 -3
  67. package/dist/web/portDiscovery.d.ts.map +1 -1
  68. package/dist/web/portDiscovery.js +7 -5
  69. package/dist/web/public/app.js +35 -18
  70. package/dist/web/public/consoleAuth.js +152 -0
  71. package/dist/web/public/index.html +243 -9
  72. package/dist/web/public/logs.js +1 -1
  73. package/dist/web/public/metrics.js +3 -3
  74. package/dist/web/public/permissions.js +1 -1
  75. package/dist/web/public/security.css +396 -0
  76. package/dist/web/public/security.js +393 -0
  77. package/dist/web/public/sessions.css +54 -4
  78. package/dist/web/public/sessions.js +46 -6
  79. package/dist/web/public/setup.css +439 -0
  80. package/dist/web/public/setup.js +490 -18
  81. package/dist/web/public/styles.css +10 -0
  82. package/dist/web/routes/permissionRoutes.d.ts.map +1 -1
  83. package/dist/web/routes/permissionRoutes.js +8 -3
  84. package/dist/web/routes/setupRoutes.d.ts +4 -0
  85. package/dist/web/routes/setupRoutes.d.ts.map +1 -1
  86. package/dist/web/routes/setupRoutes.js +418 -7
  87. package/dist/web/routes.d.ts.map +1 -1
  88. package/dist/web/routes.js +9 -5
  89. package/dist/web/server.d.ts +49 -3
  90. package/dist/web/server.d.ts.map +1 -1
  91. package/dist/web/server.js +282 -82
  92. package/package.json +11 -2
  93. package/server.json +2 -2
@@ -13,11 +13,63 @@
13
13
  * @since v2.1.0 — Issue #1700
14
14
  */
15
15
  import { logger } from '../../utils/logger.js';
16
- import { electLeader, isLeaderWebConsoleReachable, forceClaimLeadership, startHeartbeat, registerLeaderCleanup, } from './LeaderElection.js';
16
+ import { electLeader, isLeaderWebConsoleReachable, forceClaimLeadership, startHeartbeat, registerLeaderCleanup, detectLegacyLeader, } from './LeaderElection.js';
17
17
  import { createIngestRoutes } from './IngestRoutes.js';
18
18
  import { LeaderForwardingLogSink, SessionHeartbeat, } from './LeaderForwardingSink.js';
19
- /** Fixed port for the unified console leader */
20
- const CONSOLE_PORT = 3939;
19
+ import { PromotionManager } from './PromotionManager.js';
20
+ import { ConsoleTokenStore } from './consoleToken.js';
21
+ import { env } from '../../config/env.js';
22
+ /**
23
+ * Default console port from the env var. Used as fallback when no port
24
+ * is provided via config file or options. The resolution hierarchy is:
25
+ * 1. options.port (from config file, resolved by the DI container)
26
+ * 2. DOLLHOUSE_WEB_CONSOLE_PORT env var
27
+ * 3. 41715 (hardcoded default in env.ts)
28
+ */
29
+ const DEFAULT_CONSOLE_PORT = env.DOLLHOUSE_WEB_CONSOLE_PORT;
30
+ /**
31
+ * Check for a running legacy (pre-authentication) DollhouseMCP console and
32
+ * log a WARN-level message if one is found (#1794).
33
+ *
34
+ * Extracted from `startUnifiedConsole` so the wiring can be integration-
35
+ * tested in isolation without spinning up a full web server and leader
36
+ * election. The implementation is fire-and-forget: detection failures
37
+ * are logged at DEBUG and never propagate, because a failure here must
38
+ * not block leader election of the authenticated console.
39
+ *
40
+ * @param currentPort - The port the authenticated console intends to
41
+ * bind to. Used in the warning message to help the
42
+ * user tell the two consoles apart.
43
+ * @param detect - Optional injection point for the detection
44
+ * function. Defaults to `detectLegacyLeader`. Tests
45
+ * pass a stub.
46
+ * @param log - Optional injection point for the logger. Defaults
47
+ * to the module logger. Tests pass a spy.
48
+ * @returns The legacy leader info from `detect()`, or null if detection
49
+ * threw. Exposed so tests can assert the full result shape.
50
+ */
51
+ export async function warnIfLegacyConsolePresent(currentPort, detect = detectLegacyLeader, log = logger) {
52
+ try {
53
+ const legacy = await detect();
54
+ if (legacy.legacyRunning) {
55
+ log.warn(`[UnifiedConsole] Legacy (pre-authentication) DollhouseMCP console detected ` +
56
+ `(pid=${legacy.pid}, port=${legacy.port}). Both consoles will run ` +
57
+ `independently on different ports with different security posture. ` +
58
+ `The authenticated console (this process) uses port ${currentPort}; ` +
59
+ `the legacy console uses port ${legacy.port ?? 3939}. ` +
60
+ `For consistent security, update the legacy installation to a ` +
61
+ `version with the authenticated console.`);
62
+ }
63
+ return legacy;
64
+ }
65
+ catch (err) {
66
+ // Best-effort — never block election on a detection failure
67
+ log.debug('[UnifiedConsole] Legacy leader detection failed', {
68
+ error: err instanceof Error ? err.message : String(err),
69
+ });
70
+ return null;
71
+ }
72
+ }
21
73
  /**
22
74
  * Start the unified web console.
23
75
  *
@@ -25,29 +77,54 @@ const CONSOLE_PORT = 3939;
25
77
  * or sets up event forwarding (follower).
26
78
  */
27
79
  export async function startUnifiedConsole(options) {
28
- let election = await electLeader(options.sessionId, CONSOLE_PORT);
80
+ // Resolve port: options (config file) → env var → default
81
+ const consolePort = options.port || DEFAULT_CONSOLE_PORT;
82
+ logger.debug(`[UnifiedConsole] Port resolved: ${consolePort}` +
83
+ (options.port ? ' (from config file)' : ` (from env/default)`));
84
+ // Legacy-leader detection (#1794) — warn the user if a pre-auth
85
+ // DollhouseMCP console is running alongside this authenticated one.
86
+ // They will coexist fine because of port + lock + token file isolation,
87
+ // but the user should know both exist so the differing security posture
88
+ // between them doesn't look like a bug.
89
+ await warnIfLegacyConsolePresent(consolePort);
90
+ let election = await electLeader(options.sessionId, consolePort);
29
91
  // If we lost the election, check if the leader is actually running a web console.
30
92
  // An MCP stdio process may hold leadership but not serve web routes.
31
93
  // In that case, force a takeover so the web console works properly.
32
94
  if (election.role === 'follower') {
33
95
  const reachable = await isLeaderWebConsoleReachable(election.leaderInfo);
34
96
  if (!reachable) {
35
- election = await forceClaimLeadership(options.sessionId, CONSOLE_PORT);
97
+ election = await forceClaimLeadership(options.sessionId, consolePort);
36
98
  }
37
99
  }
38
100
  if (election.role === 'leader') {
39
- return startAsLeader(options, election);
101
+ return startAsLeader(options, election, consolePort);
40
102
  }
41
103
  else {
42
- return startAsFollower(options, election);
104
+ return startAsFollower(options, election, consolePort);
43
105
  }
44
106
  }
45
107
  /**
46
108
  * Start as the console leader.
47
- * Binds port 3939, mounts all routes including ingestion, starts heartbeat.
109
+ * Binds the resolved console port (config file env var → default),
110
+ * mounts all routes including ingestion, starts heartbeat.
48
111
  */
49
- async function startAsLeader(options, election) {
112
+ async function startAsLeader(options, election, consolePort = DEFAULT_CONSOLE_PORT) {
50
113
  const { startWebServer } = await import('../server.js');
114
+ const { pickRandomPuppetName } = await import('./SessionNames.js');
115
+ // Initialize the console token store (#1780). Creates the token file on
116
+ // first run, reads the existing tokens on subsequent runs. The token is
117
+ // persistent across restarts — only rotated on explicit request (Phase 2).
118
+ // Feature flag DOLLHOUSE_WEB_AUTH_ENABLED controls enforcement; the file
119
+ // is generated regardless so consumers can attach tokens preemptively.
120
+ const tokenStore = new ConsoleTokenStore(env.DOLLHOUSE_CONSOLE_TOKEN_FILE);
121
+ const primaryToken = await tokenStore.ensureInitialized(pickRandomPuppetName());
122
+ logger.info('[UnifiedConsole] Console token store initialized', {
123
+ tokenId: primaryToken.id,
124
+ tokenName: primaryToken.name,
125
+ file: tokenStore.getFilePath(),
126
+ authEnforced: env.DOLLHOUSE_WEB_AUTH_ENABLED,
127
+ });
51
128
  // Pre-create a placeholder broadcast that we'll wire up after the server starts
52
129
  let liveBroadcast;
53
130
  let liveMetricsOnSnapshot;
@@ -58,15 +135,41 @@ async function startAsLeader(options, election) {
58
135
  });
59
136
  // Register the leader as a session
60
137
  ingestResult.registerLeaderSession(options.sessionId, process.pid);
61
- // Start the web server with ingest routes mounted before the SPA fallback
62
- const webResult = await startWebServer({
138
+ // Register the web console itself so the session indicator is never empty (#1805)
139
+ ingestResult.registerConsoleSession();
140
+ // Start the web server with ingest routes mounted before the SPA fallback.
141
+ // If the port is occupied by a stale process, retry with exponential backoff.
142
+ const serverOpts = {
63
143
  portfolioDir: options.portfolioDir,
64
144
  memorySink: options.memorySink,
65
145
  metricsSink: options.metricsSink,
66
- port: CONSOLE_PORT,
146
+ port: consolePort,
67
147
  additionalRouters: [ingestResult.router],
148
+ tokenStore,
68
149
  ...(options.mcpAqlHandler ? { mcpAqlHandler: options.mcpAqlHandler } : {}),
69
- });
150
+ };
151
+ const BIND_RETRY_DELAYS = env.DOLLHOUSE_CONSOLE_BIND_RETRY_DELAYS?.length
152
+ ? env.DOLLHOUSE_CONSOLE_BIND_RETRY_DELAYS
153
+ : [1000, 2000, 4000];
154
+ const webResult = await startWebServer(serverOpts);
155
+ // If the port is occupied, retry the bind only — don't recreate the Express
156
+ // app and routes (startWebServer early-returns when serverRunning is false
157
+ // but the app is already configured). We call retryBind on the existing app.
158
+ if (webResult.bindResult && !webResult.bindResult.success && webResult.bindResult.error === 'EADDRINUSE' && webResult.app) {
159
+ const { retryBind } = await import('../server.js');
160
+ for (let i = 0; i < BIND_RETRY_DELAYS.length; i++) {
161
+ logger.warn(`[UnifiedConsole] Port ${consolePort} occupied — retry ${i + 1}/${BIND_RETRY_DELAYS.length} in ${BIND_RETRY_DELAYS[i]}ms`);
162
+ await new Promise(r => setTimeout(r, BIND_RETRY_DELAYS[i]));
163
+ const retryResult = await retryBind(webResult.app, consolePort, serverOpts);
164
+ if (retryResult.success) {
165
+ webResult.bindResult = retryResult;
166
+ break;
167
+ }
168
+ }
169
+ if (webResult.bindResult && !webResult.bindResult.success) {
170
+ logger.error(`[UnifiedConsole] Leader failed to bind port ${consolePort} after ${BIND_RETRY_DELAYS.length} retries — console unavailable`);
171
+ }
172
+ }
70
173
  // Wire SSE broadcasts for this leader's own events
71
174
  options.wireSSEBroadcasts(webResult, options.metricsSink);
72
175
  // Now wire the live broadcast functions into the ingest routes
@@ -87,13 +190,13 @@ async function startAsLeader(options, election) {
87
190
  const stopHeartbeat = startHeartbeat(election.leaderInfo);
88
191
  registerLeaderCleanup();
89
192
  logger.info('[UnifiedConsole] Leader started', {
90
- sessionId: options.sessionId, port: CONSOLE_PORT, pid: process.pid,
193
+ sessionId: options.sessionId, port: consolePort, pid: process.pid,
91
194
  role: 'leader', ingestRoutes: ['/api/ingest/logs', '/api/ingest/metrics', '/api/ingest/session', '/api/sessions'],
92
195
  });
93
196
  return {
94
197
  role: 'leader',
95
198
  election,
96
- port: CONSOLE_PORT,
199
+ port: consolePort,
97
200
  cleanup: async () => {
98
201
  stopHeartbeat();
99
202
  },
@@ -103,13 +206,33 @@ async function startAsLeader(options, election) {
103
206
  * Start as a follower.
104
207
  * Registers forwarding sinks with the LogManager, starts session heartbeat.
105
208
  */
106
- async function startAsFollower(options, election) {
209
+ async function startAsFollower(options, election, consolePort = DEFAULT_CONSOLE_PORT) {
107
210
  const leaderUrl = `http://127.0.0.1:${election.leaderInfo.port}`;
108
- // Register a forwarding log sink
109
- const forwardingSink = new LeaderForwardingLogSink(leaderUrl, options.sessionId);
211
+ // Read the console auth token (#1780) written by the leader. May be null
212
+ // if the file doesn't exist yet — the sinks handle that gracefully and
213
+ // simply omit the Bearer header, which is fine when auth is not enforced.
214
+ const { getPrimaryTokenFromFile } = await import('./consoleToken.js');
215
+ const authToken = await getPrimaryTokenFromFile(env.DOLLHOUSE_CONSOLE_TOKEN_FILE);
216
+ if (authToken) {
217
+ logger.debug('[UnifiedConsole] Follower loaded console auth token');
218
+ }
219
+ else {
220
+ logger.debug('[UnifiedConsole] No console auth token file found; follower will POST without Bearer header');
221
+ }
222
+ // Per-instance promotion manager — tracks its own attempt counter so
223
+ // multiple followers don't interfere with each other's promotion budgets.
224
+ const promotionMgr = new PromotionManager(options, consolePort, startAsLeader, startAsFollower);
225
+ // Declare sessionHeartbeat before the sink so the closure can capture it.
226
+ // Both are initialized before the callback could possibly fire (needs 5+ failed flushes).
227
+ let sessionHeartbeat;
228
+ // Register a forwarding log sink with leader-death callback (#1850).
229
+ const forwardingSink = new LeaderForwardingLogSink(leaderUrl, options.sessionId, authToken, () => {
230
+ promotionMgr.promote(forwardingSink, sessionHeartbeat)
231
+ .catch(err => logger.error('[UnifiedConsole] Promotion crashed', { error: String(err) }));
232
+ });
110
233
  options.registerLogSink(forwardingSink);
111
234
  // Start session heartbeat to the leader
112
- const sessionHeartbeat = new SessionHeartbeat(leaderUrl, options.sessionId, process.pid);
235
+ sessionHeartbeat = new SessionHeartbeat(leaderUrl, options.sessionId, process.pid, authToken);
113
236
  await sessionHeartbeat.start();
114
237
  logger.info('[UnifiedConsole] Follower started', {
115
238
  sessionId: options.sessionId, pid: process.pid, role: 'follower',
@@ -125,4 +248,4 @@ async function startAsFollower(options, election) {
125
248
  },
126
249
  };
127
250
  }
128
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVW5pZmllZENvbnNvbGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd2ViL2NvbnNvbGUvVW5pZmllZENvbnNvbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7R0FhRztBQU1ILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUMvQyxPQUFPLEVBQ0wsV0FBVyxFQUNYLDJCQUEyQixFQUMzQixvQkFBb0IsRUFDcEIsY0FBYyxFQUNkLHFCQUFxQixHQUV0QixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3ZELE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsZ0JBQWdCLEdBQ2pCLE1BQU0sMkJBQTJCLENBQUM7QUFFbkMsZ0RBQWdEO0FBQ2hELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQztBQWtDMUI7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLG1CQUFtQixDQUFDLE9BQThCO0lBQ3RFLElBQUksUUFBUSxHQUFHLE1BQU0sV0FBVyxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFFbEUsa0ZBQWtGO0lBQ2xGLHFFQUFxRTtJQUNyRSxvRUFBb0U7SUFDcEUsSUFBSSxRQUFRLENBQUMsSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO1FBQ2pDLE1BQU0sU0FBUyxHQUFHLE1BQU0sMkJBQTJCLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3pFLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNmLFFBQVEsR0FBRyxNQUFNLG9CQUFvQixDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsWUFBWSxDQUFDLENBQUM7UUFDekUsQ0FBQztJQUNILENBQUM7SUFFRCxJQUFJLFFBQVEsQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDL0IsT0FBTyxhQUFhLENB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biAqIFVuaWZpZWQgd2ViIGNvbnNvbGUgb3JjaGVzdHJhdG9yLlxuICpcbiAqIFRpZXMgdG9nZXRoZXIgbGVhZGVyIGVsZWN0aW9uLCBjb25zb2xlIHN0YXJ0dXAsIGZvbGxvd2VyIHdpcmluZyxcbiAqIGFuZCBzZXNzaW9uIGxpZmVjeWNsZSBtYW5hZ2VtZW50LiBUaGlzIGlzIHRoZSBtYWluIGVudHJ5IHBvaW50XG4gKiBjYWxsZWQgYnkgdGhlIERJIGNvbnRhaW5lciBkdXJpbmcgZGVmZXJyZWQgc2V0dXAuXG4gKlxuICogRmxvdzpcbiAqIDEuIFJ1biBsZWFkZXIgZWxlY3Rpb24gKHJlYWQgbG9jayBmaWxlLCBjbGFpbSBvciBmb2xsb3cpXG4gKiAyLiBJZiBsZWFkZXI6IHN0YXJ0IHdlYiBzZXJ2ZXIgb24gZml4ZWQgcG9ydCwgbW91bnQgaW5nZXN0IHJvdXRlcywgc3RhcnQgaGVhcnRiZWF0XG4gKiAzLiBJZiBmb2xsb3dlcjogcmVnaXN0ZXIgZm9yd2FyZGluZyBzaW5rcyB3aXRoIExvZ01hbmFnZXIsIHN0YXJ0IHNlc3Npb24gaGVhcnRiZWF0XG4gKlxuICogQHNpbmNlIHYyLjEuMCDigJQgSXNzdWUgIzE3MDBcbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFVuaWZpZWRMb2dFbnRyeSB9IGZyb20gJy4uLy4uL2xvZ2dpbmcvdHlwZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBNZXRyaWNTbmFwc2hvdCB9IGZyb20gJy4uLy4uL21ldHJpY3MvdHlwZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBNZW1vcnlMb2dTaW5rIH0gZnJvbSAnLi4vLi4vbG9nZ2luZy9zaW5rcy9NZW1vcnlMb2dTaW5rLmpzJztcbmltcG9ydCB0eXBlIHsgTWVtb3J5TWV0cmljc1NpbmsgfSBmcm9tICcuLi8uLi9tZXRyaWNzL3NpbmtzL01lbW9yeU1ldHJpY3NTaW5rLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uLy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQge1xuICBlbGVjdExlYWRlcixcbiAgaXNMZWFkZXJXZWJDb25zb2xlUmVhY2hhYmxlLFxuICBmb3JjZUNsYWltTGVhZGVyc2hpcCxcbiAgc3RhcnRIZWFydGJlYXQsXG4gIHJlZ2lzdGVyTGVhZGVyQ2xlYW51cCxcbiAgdHlwZSBFbGVjdGlvblJlc3VsdCxcbn0gZnJvbSAnLi9MZWFkZXJFbGVjdGlvbi5qcyc7XG5pbXBvcnQgeyBjcmVhdGVJbmdlc3RSb3V0ZXMgfSBmcm9tICcuL0luZ2VzdFJvdXRlcy5qcyc7XG5pbXBvcnQge1xuICBMZWFkZXJGb3J3YXJkaW5nTG9nU2luayxcbiAgU2Vzc2lvbkhlYXJ0YmVhdCxcbn0gZnJvbSAnLi9MZWFkZXJGb3J3YXJkaW5nU2luay5qcyc7XG5cbi8qKiBGaXhlZCBwb3J0IGZvciB0aGUgdW5pZmllZCBjb25zb2xlIGxlYWRlciAqL1xuY29uc3QgQ09OU09MRV9QT1JUID0gMzkzOTtcblxuLyoqXG4gKiBPcHRpb25zIGZvciBzdGFydGluZyB0aGUgdW5pZmllZCBjb25zb2xlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFVuaWZpZWRDb25zb2xlT3B0aW9ucyB7XG4gIC8qKiBUaGlzIHByb2Nlc3MncyB1bmlxdWUgc2Vzc2lvbiBJRCAqL1xuICBzZXNzaW9uSWQ6IHN0cmluZztcbiAgLyoqIFBvcnRmb2xpbyBiYXNlIGRpcmVjdG9yeSAoZm9yIHN0YXJ0V2ViU2VydmVyKSAqL1xuICBwb3J0Zm9saW9EaXI6IHN0cmluZztcbiAgLyoqIExvZyBtZW1vcnkgc2luayAoZm9yIGNvbnNvbGUgaGlzdG9yeSkgKi9cbiAgbWVtb3J5U2luazogTWVtb3J5TG9nU2luaztcbiAgLyoqIE1ldHJpY3MgbWVtb3J5IHNpbmsgKi9cbiAgbWV0cmljc1Npbms/OiBNZW1vcnlNZXRyaWNzU2luaztcbiAgLyoqIE1DUC1BUUwgaGFuZGxlciBmb3IgcGVybWlzc2lvbiByb3V0ZXMgKHR5cGVkIGFzIGFueSB0byBhdm9pZCBjaXJjdWxhciBpbXBvcnRzKSAqL1xuICBtY3BBcWxIYW5kbGVyPzogYW55O1xuICAvKiogQ2FsbGJhY2sgdG8gcmVnaXN0ZXIgYSBsb2cgc2luayB3aXRoIHRoZSBMb2dNYW5hZ2VyICovXG4gIHJlZ2lzdGVyTG9nU2luazogKHNpbms6IHsgd3JpdGUoZW50cnk6IFVuaWZpZWRMb2dFbnRyeSk6IHZvaWQ7IGZsdXNoKCk6IFByb21pc2U8dm9pZD47IGNsb3NlKCk6IFByb21pc2U8dm9pZD4gfSkgPT4gdm9pZDtcbiAgLyoqIENhbGxiYWNrIHRvIHdpcmUgU1NFIGJyb2FkY2FzdHMgYWZ0ZXIgd2ViIHNlcnZlciBzdGFydHMgKi9cbiAgd2lyZVNTRUJyb2FkY2FzdHM6ICh3ZWJSZXN1bHQ6IHsgbG9nQnJvYWRjYXN0PzogKGVudHJ5OiBVbmlmaWVkTG9nRW50cnkpID0+IHZvaWQ7IG1ldHJpY3NPblNuYXBzaG90PzogKHNuYXBzaG90OiBNZXRyaWNTbmFwc2hvdCkgPT4gdm9pZCB9LCBtZXRyaWNzU2luaz86IE1lbW9yeU1ldHJpY3NTaW5rKSA9PiB2b2lkO1xufVxuXG4vKipcbiAqIFJlc3VsdCBvZiBzdGFydGluZyB0aGUgdW5pZmllZCBjb25zb2xlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFVuaWZpZWRDb25zb2xlUmVzdWx0IHtcbiAgcm9sZTogJ2xlYWRlcicgfCAnZm9sbG93ZXInO1xuICBlbGVjdGlvbjogRWxlY3Rpb25SZXN1bHQ7XG4gIC8qKiBQb3J0IHRoZSBjb25zb2xlIGlzIHJ1bm5pbmcgb24gKGxlYWRlciBvbmx5KSAqL1xuICBwb3J0PzogbnVtYmVyO1xuICAvKiogQ2xlYW51cCBmdW5jdGlvbiB0byBjYWxsIG9uIHNodXRkb3duICovXG4gIGNsZWFudXA6ICgpID0+IFByb21pc2U8dm9pZD47XG59XG5cbi8qKlxuICogU3RhcnQgdGhlIHVuaWZpZWQgd2ViIGNvbnNvbGUuXG4gKlxuICogUnVucyBsZWFkZXIgZWxlY3Rpb24sIHRoZW4gZWl0aGVyIHN0YXJ0cyB0aGUgZnVsbCBjb25zb2xlIChsZWFkZXIpXG4gKiBvciBzZXRzIHVwIGV2ZW50IGZvcndhcmRpbmcgKGZvbGxvd2VyKS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0VW5pZmllZENvbnNvbGUob3B0aW9uczogVW5pZmllZENvbnNvbGVPcHRpb25zKTogUHJvbWlzZTxVbmlmaWVkQ29uc29sZVJlc3VsdD4ge1xuICBsZXQgZWxlY3Rpb24gPSBhd2FpdCBlbGVjdExlYWRlcihvcHRpb25zLnNlc3Npb25JZCwgQ09OU09MRV9QT1JUKTtcblxuICAvLyBJZiB3ZSBsb3N0IHRoZSBlbGVjdGlvbiwgY2hlY2sgaWYgdGhlIGxlYWRlciBpcyBhY3R1YWxseSBydW5uaW5nIGEgd2ViIGNvbnNvbGUuXG4gIC8vIEFuIE1DUCBzdGRpbyBwcm9jZXNzIG1heSBob2xkIGxlYWRlcnNoaXAgYnV0IG5vdCBzZXJ2ZSB3ZWIgcm91dGVzLlxuICAvLyBJbiB0aGF0IGNhc2UsIGZvcmNlIGEgdGFrZW92ZXIgc28gdGhlIHdlYiBjb25zb2xlIHdvcmtzIHByb3Blcmx5LlxuICBpZiAoZWxlY3Rpb24ucm9sZSA9PT0gJ2ZvbGxvd2VyJykge1xuICAgIGNvbnN0IHJlYWNoYWJsZSA9IGF3YWl0IGlzTGVhZGVyV2ViQ29uc29sZVJlYWNoYWJsZShlbGVjdGlvbi5sZWFkZXJJbmZvKTtcbiAgICBpZiAoIXJlYWNoYWJsZSkge1xuICAgICAgZWxlY3Rpb24gPSBhd2FpdCBmb3JjZUNsYWltTGVhZGVyc2hpcChvcHRpb25zLnNlc3Npb25JZCwgQ09OU09MRV9QT1JUKTtcbiAgICB9XG4gIH1cblxuICBpZiAoZWxlY3Rpb24ucm9sZSA9PT0gJ2xlYWRlcicpIHtcbiAgICByZXR1cm4gc3RhcnRBc0xlYWRlcihvcHRpb25zLCBlbGVjdGlvbik7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIHN0YXJ0QXNGb2xsb3dlcihvcHRpb25zLCBlbGVjdGlvbik7XG4gIH1cbn1cblxuLyoqXG4gKiBTdGFydCBhcyB0aGUgY29uc29sZSBsZWFkZXIuXG4gKiBCaW5kcyBwb3J0IDM5MzksIG1vdW50cyBhbGwgcm91dGVzIGluY2x1ZGluZyBpbmdlc3Rpb24sIHN0YXJ0cyBoZWFydGJlYXQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHN0YXJ0QXNMZWFkZXIoXG4gIG9wdGlvbnM6IFVuaWZpZWRDb25zb2xlT3B0aW9ucyxcbiAgZWxlY3Rpb246IEVsZWN0aW9uUmVzdWx0LFxuKTogUHJvbWlzZTxVbmlmaWVkQ29uc29sZVJlc3VsdD4ge1xuICBjb25zdCB7IHN0YXJ0V2ViU2VydmVyIH0gPSBhd2FpdCBpbXBvcnQoJy4uL3NlcnZlci5qcycpO1xuXG4gIC8vIFByZS1jcmVhdGUgYSBwbGFjZWhvbGRlciBicm9hZGNhc3QgdGhhdCB3ZSdsbCB3aXJlIHVwIGFmdGVyIHRoZSBzZXJ2ZXIgc3RhcnRzXG4gIGxldCBsaXZlQnJvYWRjYXN0OiAoKGVudHJ5OiBVbmlmaWVkTG9nRW50cnkpID0+IHZvaWQpIHwgdW5kZWZpbmVkO1xuICBsZXQgbGl2ZU1ldHJpY3NPblNuYXBzaG90OiAoKHNuYXBzaG90OiBNZXRyaWNTbmFwc2hvdCkgPT4gdm9pZCkgfCB1bmRlZmluZWQ7XG5cbiAgLy8gQ3JlYXRlIGluZ2VzdGlvbiByb3V0ZXMgd2l0aCBhIGRlZmVycmVkIGJyb2FkY2FzdCAod2lyZWQgYWZ0ZXIgc2VydmVyIHN0YXJ0cylcbiAgY29uc3QgaW5nZXN0UmVzdWx0ID0gY3JlYXRlSW5nZXN0Um91dGVzKHtcbiAgICBsb2dCcm9hZGNhc3Q6IChlbnRyeSkgPT4gbGl2ZUJyb2FkY2FzdD8uKGVudHJ5KSxcbiAgICBtZXRyaWNzT25TbmFwc2hvdDogKHNuYXBzaG90KSA9PiBsaXZlTWV0cmljc09uU25hcHNob3Q/LihzbmFwc2hvdCksXG4gIH0pO1xuXG4gIC8vIFJlZ2lzdGVyIHRoZSBsZWFkZXIgYXMgYSBzZXNzaW9uXG4gIGluZ2VzdFJlc3VsdC5yZWdpc3RlckxlYWRlclNlc3Npb24ob3B0aW9ucy5zZXNzaW9uSWQsIHByb2Nlc3MucGlkKTtcblxuICAvLyBTdGFydCB0aGUgd2ViIHNlcnZlciB3aXRoIGluZ2VzdCByb3V0ZXMgbW91bnRlZCBiZWZvcmUgdGhlIFNQQSBmYWxsYmFja1xuICBjb25zdCB3ZWJSZXN1bHQgPSBhd2FpdCBzdGFydFdlYlNlcnZlcih7XG4gICAgcG9ydGZvbGlvRGlyOiBvcHRpb25zLnBvcnRmb2xpb0RpcixcbiAgICBtZW1vcnlTaW5rOiBvcHRpb25zLm1lbW9yeVNpbmssXG4gICAgbWV0cmljc1Npbms6IG9wdGlvbnMubWV0cmljc1NpbmssXG4gICAgcG9ydDogQ09OU09MRV9QT1JULFxuICAgIGFkZGl0aW9uYWxSb3V0ZXJzOiBbaW5nZXN0UmVzdWx0LnJvdXRlcl0sXG4gICAgLi4uKG9wdGlvbnMubWNwQXFsSGFuZGxlciA/IHsgbWNwQXFsSGFuZGxlcjogb3B0aW9ucy5tY3BBcWxIYW5kbGVyIH0gOiB7fSksXG4gIH0pO1xuXG4gIC8vIFdpcmUgU1NFIGJyb2FkY2FzdHMgZm9yIHRoaXMgbGVhZGVyJ3Mgb3duIGV2ZW50c1xuICBvcHRpb25zLndpcmVTU0VCcm9hZGNhc3RzKHdlYlJlc3VsdCwgb3B0aW9ucy5tZXRyaWNzU2luayk7XG5cbiAgLy8gTm93IHdpcmUgdGhlIGxpdmUgYnJvYWRjYXN0IGZ1bmN0aW9ucyBpbnRvIHRoZSBpbmdlc3Qgcm91dGVzXG4gIGlmICh3ZWJSZXN1bHQubG9nQnJvYWRjYXN0KSB7XG4gICAgY29uc3Qgb3JpZ2luYWxCcm9hZGNhc3QgPSB3ZWJSZXN1bHQubG9nQnJvYWRjYXN0O1xuICAgIC8vIFN0YW1wIGxlYWRlcidzIG93biBlbnRyaWVzIHdpdGggc2Vzc2lvbiBJRFxuICAgIGxpdmVCcm9hZGNhc3QgPSAoZW50cnk6IFVuaWZpZWRMb2dFbnRyeSkgPT4ge1xuICAgICAgY29uc3Qgc3RhbXBlZDogVW5pZmllZExvZ0VudHJ5ID0ge1xuICAgICAgICAuLi5lbnRyeSxcbiAgICAgICAgZGF0YTogeyAuLi5lbnRyeS5kYXRhLCBfc2Vzc2lvbklkOiBvcHRpb25zLnNlc3Npb25JZCB9LFxuICAgICAgfTtcbiAgICAgIG9yaWdpbmFsQnJvYWRjYXN0KHN0YW1wZWQpO1xuICAgIH07XG4gIH1cbiAgbGl2ZU1ldHJpY3NPblNuYXBzaG90ID0gd2ViUmVzdWx0Lm1ldHJpY3NPblNuYXBzaG90O1xuXG4gIGxvZ2dlci5pbmZvKCdbVW5pZmllZENvbnNvbGVdIEluZ2VzdGlvbiByb3V0ZXMgbW91bnRlZCcpO1xuXG4gIC8vIFN0YXJ0IGhlYXJ0YmVhdCBhbmQgcmVnaXN0ZXIgY2xlYW51cFxuICBjb25zdCBzdG9wSGVhcnRiZWF0ID0gc3RhcnRIZWFydGJlYXQoZWxlY3Rpb24ubGVhZGVySW5mbyk7XG4gIHJlZ2lzdGVyTGVhZGVyQ2xlYW51cCgpO1xuXG4gIGxvZ2dlci5pbmZvKCdbVW5pZmllZENvbnNvbGVdIExlYWRlciBzdGFydGVkJywge1xuICAgIHNlc3Npb25JZDogb3B0aW9ucy5zZXNzaW9uSWQsIHBvcnQ6IENPTlNPTEVfUE9SVCwgcGlkOiBwcm9jZXNzLnBpZCxcbiAgICByb2xlOiAnbGVhZGVyJywgaW5nZXN0Um91dGVzOiBbJy9hcGkvaW5nZXN0L2xvZ3MnLCAnL2FwaS9pbmdlc3QvbWV0cmljcycsICcvYXBpL2luZ2VzdC9zZXNzaW9uJywgJy9hcGkvc2Vzc2lvbnMnXSxcbiAgfSk7XG5cbiAgcmV0dXJuIHtcbiAgICByb2xlOiAnbGVhZGVyJyxcbiAgICBlbGVjdGlvbixcbiAgICBwb3J0OiBDT05TT0xFX1BPUlQsXG4gICAgY2xlYW51cDogYXN5bmMgKCkgPT4ge1xuICAgICAgc3RvcEhlYXJ0YmVhdCgpO1xuICAgIH0sXG4gIH07XG59XG5cbi8qKlxuICogU3RhcnQgYXMgYSBmb2xsb3dlci5cbiAqIFJlZ2lzdGVycyBmb3J3YXJkaW5nIHNpbmtzIHdpdGggdGhlIExvZ01hbmFnZXIsIHN0YXJ0cyBzZXNzaW9uIGhlYXJ0YmVhdC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc3RhcnRBc0ZvbGxvd2VyKFxuICBvcHRpb25zOiBVbmlmaWVkQ29uc29sZU9wdGlvbnMsXG4gIGVsZWN0aW9uOiBFbGVjdGlvblJlc3VsdCxcbik6IFByb21pc2U8VW5pZmllZENvbnNvbGVSZXN1bHQ+IHtcbiAgY29uc3QgbGVhZGVyVXJsID0gYGh0dHA6Ly8xMjcuMC4wLjE6JHtlbGVjdGlvbi5sZWFkZXJJbmZvLnBvcnR9YDtcblxuICAvLyBSZWdpc3RlciBhIGZvcndhcmRpbmcgbG9nIHNpbmtcbiAgY29uc3QgZm9yd2FyZGluZ1NpbmsgPSBuZXcgTGVhZGVyRm9yd2FyZGluZ0xvZ1NpbmsobGVhZGVyVXJsLCBvcHRpb25zLnNlc3Npb25JZCk7XG4gIG9wdGlvbnMucmVnaXN0ZXJMb2dTaW5rKGZvcndhcmRpbmdTaW5rKTtcblxuICAvLyBTdGFydCBzZXNzaW9uIGhlYXJ0YmVhdCB0byB0aGUgbGVhZGVyXG4gIGNvbnN0IHNlc3Npb25IZWFydGJlYXQgPSBuZXcgU2Vzc2lvbkhlYXJ0YmVhdChsZWFkZXJVcmwsIG9wdGlvbnMuc2Vzc2lvbklkLCBwcm9jZXNzLnBpZCk7XG4gIGF3YWl0IHNlc3Npb25IZWFydGJlYXQuc3RhcnQoKTtcblxuICBsb2dnZXIuaW5mbygnW1VuaWZpZWRDb25zb2xlXSBGb2xsb3dlciBzdGFydGVkJywge1xuICAgIHNlc3Npb25JZDogb3B0aW9ucy5zZXNzaW9uSWQsIHBpZDogcHJvY2Vzcy5waWQsIHJvbGU6ICdmb2xsb3dlcicsXG4gICAgbGVhZGVyU2Vzc2lvbjogZWxlY3Rpb24ubGVhZGVySW5mby5zZXNzaW9uSWQsIGxlYWRlclBpZDogZWxlY3Rpb24ubGVhZGVySW5mby5waWQsXG4gICAgbGVhZGVyUG9ydDogZWxlY3Rpb24ubGVhZGVySW5mby5wb3J0LCBsZWFkZXJVcmwsXG4gIH0pO1xuXG4gIHJldHVybiB7XG4gICAgcm9sZTogJ2ZvbGxvd2VyJyxcbiAgICBlbGVjdGlvbixcbiAgICBjbGVhbnVwOiBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBzZXNzaW9uSGVhcnRiZWF0LnN0b3AoKTtcbiAgICAgIGF3YWl0IGZvcndhcmRpbmdTaW5rLmNsb3NlKCk7XG4gICAgfSxcbiAgfTtcbn1cbiJdfQ==
251
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVW5pZmllZENvbnNvbGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd2ViL2NvbnNvbGUvVW5pZmllZENvbnNvbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7R0FhRztBQU1ILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUMvQyxPQUFPLEVBQ0wsV0FBVyxFQUNYLDJCQUEyQixFQUMzQixvQkFBb0IsRUFDcEIsY0FBYyxFQUNkLHFCQUFxQixFQUNyQixrQkFBa0IsR0FFbkIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUN2RCxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGdCQUFnQixHQUNqQixNQUFNLDJCQUEyQixDQUFDO0FBQ25DLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUUxQzs7Ozs7O0dBTUc7QUFDSCxNQUFNLG9CQUFvQixHQUFHLEdBQUcsQ0FBQywwQkFBMEIsQ0FBQztBQW9DNUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSwwQkFBMEIsQ0FDOUMsV0FBbUIsRUFDbkIsU0FBb0Msa0JBQWtCLEVBQ3RELE1BQXFCLE1BQU07SUFFM0IsSUFBSSxDQUFDO1FBQ0gsTUFBTSxNQUFNLEdBQUcsTUFBTSxNQUFNLEVBQUUsQ0FBQztRQUM5QixJQUFJLE1BQU0sQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUN6QixHQUFHLENBQUMsSUFBSSxDQUNOLDZFQUE2RTtnQkFDN0UsUUFBUSxNQUFNLENBQUMsR0FBRyxVQUFVLE1BQU0sQ0FBQyxJQUFJLDRCQUE0QjtnQkFDbkUs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LENBQUMsS0FBSyxDQUFDLG9DQUFvQyxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUM5RixDQUFDLENBQUMsQ0FBQztJQUNILE9BQU8sQ0FBQyxlQUFlLENBQUMsY0FBYyxDQUFDLENBQUM7SUFFeEMsd0NBQXdDO0lBQ3hDLGdCQUFnQixHQUFHLElBQUksZ0JBQWdCLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLEdBQUcsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUM5RixNQUFNLGdCQUFnQixDQUFDLEtBQUssRUFBRSxDQUFDO0lBRS9CLE1BQU0sQ0FBQyxJQUFJLENBQUMsbUNBQW1DLEVBQUU7UUFDL0MsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLFVBQVU7UUFDaEUsYUFBYSxFQUFFLFFBQVEsQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRSxRQUFRLENBQUMsVUFBVSxDQUFDLEdBQUc7UUFDaEYsVUFBVSxFQUFFLFFBQVEsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLFNBQVM7S0FDaEQsQ0FBQyxDQUFDO0lBRUgsT0FBTztRQUNMLElBQUksRUFBRSxVQUFVO1FBQ2hCLFFBQVE7UUFDUixPQUFPLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDbEIsTUFBTSxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUM5QixNQUFNLGNBQWMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMvQixDQUFDO0tBQ0YsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFVuaWZpZWQgd2ViIGNvbnNvbGUgb3JjaGVzdHJhdG9yLlxuICpcbiAqIFRpZXMgdG9nZXRoZXIgbGVhZGVyIGVsZWN0aW9uLCBjb25zb2xlIHN0YXJ0dXAsIGZvbGxvd2VyIHdpcmluZyxcbiAqIGFuZCBzZXNzaW9uIGxpZmVjeWNsZSBtYW5hZ2VtZW50LiBUaGlzIGlzIHRoZSBtYWluIGVudHJ5IHBvaW50XG4gKiBjYWxsZWQgYnkgdGhlIERJIGNvbnRhaW5lciBkdXJpbmcgZGVmZXJyZWQgc2V0dXAuXG4gKlxuICogRmxvdzpcbiAqIDEuIFJ1biBsZWFkZXIgZWxlY3Rpb24gKHJlYWQgbG9jayBmaWxlLCBjbGFpbSBvciBmb2xsb3cpXG4gKiAyLiBJZiBsZWFkZXI6IHN0YXJ0IHdlYiBzZXJ2ZXIgb24gZml4ZWQgcG9ydCwgbW91bnQgaW5nZXN0IHJvdXRlcywgc3RhcnQgaGVhcnRiZWF0XG4gKiAzLiBJZiBmb2xsb3dlcjogcmVnaXN0ZXIgZm9yd2FyZGluZyBzaW5rcyB3aXRoIExvZ01hbmFnZXIsIHN0YXJ0IHNlc3Npb24gaGVhcnRiZWF0XG4gKlxuICogQHNpbmNlIHYyLjEuMCDigJQgSXNzdWUgIzE3MDBcbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFVuaWZpZWRMb2dFbnRyeSB9IGZyb20gJy4uLy4uL2xvZ2dpbmcvdHlwZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBNZXRyaWNTbmFwc2hvdCB9IGZyb20gJy4uLy4uL21ldHJpY3MvdHlwZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBNZW1vcnlMb2dTaW5rIH0gZnJvbSAnLi4vLi4vbG9nZ2luZy9zaW5rcy9NZW1vcnlMb2dTaW5rLmpzJztcbmltcG9ydCB0eXBlIHsgTWVtb3J5TWV0cmljc1NpbmsgfSBmcm9tICcuLi8uLi9tZXRyaWNzL3NpbmtzL01lbW9yeU1ldHJpY3NTaW5rLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uLy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQge1xuICBlbGVjdExlYWRlcixcbiAgaXNMZWFkZXJXZWJDb25zb2xlUmVhY2hhYmxlLFxuICBmb3JjZUNsYWltTGVhZGVyc2hpcCxcbiAgc3RhcnRIZWFydGJlYXQsXG4gIHJlZ2lzdGVyTGVhZGVyQ2xlYW51cCxcbiAgZGV0ZWN0TGVnYWN5TGVhZGVyLFxuICB0eXBlIEVsZWN0aW9uUmVzdWx0LFxufSBmcm9tICcuL0xlYWRlckVsZWN0aW9uLmpzJztcbmltcG9ydCB7IGNyZWF0ZUluZ2VzdFJvdXRlcyB9IGZyb20gJy4vSW5nZXN0Um91dGVzLmpzJztcbmltcG9ydCB7XG4gIExlYWRlckZvcndhcmRpbmdMb2dTaW5rLFxuICBTZXNzaW9uSGVhcnRiZWF0LFxufSBmcm9tICcuL0xlYWRlckZvcndhcmRpbmdTaW5rLmpzJztcbmltcG9ydCB7IFByb21vdGlvbk1hbmFnZXIgfSBmcm9tICcuL1Byb21vdGlvbk1hbmFnZXIuanMnO1xuaW1wb3J0IHsgQ29uc29sZVRva2VuU3RvcmUgfSBmcm9tICcuL2NvbnNvbGVUb2tlbi5qcyc7XG5pbXBvcnQgeyBlbnYgfSBmcm9tICcuLi8uLi9jb25maWcvZW52LmpzJztcblxuLyoqXG4gKiBEZWZhdWx0IGNvbnNvbGUgcG9ydCBmcm9tIHRoZSBlbnYgdmFyLiBVc2VkIGFzIGZhbGxiYWNrIHdoZW4gbm8gcG9ydFxuICogaXMgcHJvdmlkZWQgdmlhIGNvbmZpZyBmaWxlIG9yIG9wdGlvbnMuIFRoZSByZXNvbHV0aW9uIGhpZXJhcmNoeSBpczpcbiAqICAgMS4gb3B0aW9ucy5wb3J0IChmcm9tIGNvbmZpZyBmaWxlLCByZXNvbHZlZCBieSB0aGUgREkgY29udGFpbmVyKVxuICogICAyLiBET0xMSE9VU0VfV0VCX0NPTlNPTEVfUE9SVCBlbnYgdmFyXG4gKiAgIDMuIDQxNzE1IChoYXJkY29kZWQgZGVmYXVsdCBpbiBlbnYudHMpXG4gKi9cbmNvbnN0IERFRkFVTFRfQ09OU09MRV9QT1JUID0gZW52LkRPTExIT1VTRV9XRUJfQ09OU09MRV9QT1JUO1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHN0YXJ0aW5nIHRoZSB1bmlmaWVkIGNvbnNvbGUuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVW5pZmllZENvbnNvbGVPcHRpb25zIHtcbiAgLyoqIFRoaXMgcHJvY2VzcydzIHVuaXF1ZSBzZXNzaW9uIElEICovXG4gIHNlc3Npb25JZDogc3RyaW5nO1xuICAvKiogUG9ydGZvbGlvIGJhc2UgZGlyZWN0b3J5IChmb3Igc3RhcnRXZWJTZXJ2ZXIpICovXG4gIHBvcnRmb2xpb0Rpcjogc3RyaW5nO1xuICAvKiogTG9nIG1lbW9yeSBzaW5rIChmb3IgY29uc29sZSBoaXN0b3J5KSAqL1xuICBtZW1vcnlTaW5rOiBNZW1vcnlMb2dTaW5rO1xuICAvKiogTWV0cmljcyBtZW1vcnkgc2luayAqL1xuICBtZXRyaWNzU2luaz86IE1lbW9yeU1ldHJpY3NTaW5rO1xuICAvKiogTUNQLUFRTCBoYW5kbGVyIGZvciBwZXJtaXNzaW9uIHJvdXRlcyAodHlwZWQgYXMgYW55IHRvIGF2b2lkIGNpcmN1bGFyIGltcG9ydHMpICovXG4gIG1jcEFxbEhhbmRsZXI/OiBhbnk7XG4gIC8qKiBDYWxsYmFjayB0byByZWdpc3RlciBhIGxvZyBzaW5rIHdpdGggdGhlIExvZ01hbmFnZXIgKi9cbiAgcmVnaXN0ZXJMb2dTaW5rOiAoc2luazogeyB3cml0ZShlbnRyeTogVW5pZmllZExvZ0VudHJ5KTogdm9pZDsgZmx1c2goKTogUHJvbWlzZTx2b2lkPjsgY2xvc2UoKTogUHJvbWlzZTx2b2lkPiB9KSA9PiB2b2lkO1xuICAvKiogQ2FsbGJhY2sgdG8gd2lyZSBTU0UgYnJvYWRjYXN0cyBhZnRlciB3ZWIgc2VydmVyIHN0YXJ0cyAqL1xuICB3aXJlU1NFQnJvYWRjYXN0czogKHdlYlJlc3VsdDogeyBsb2dCcm9hZGNhc3Q/OiAoZW50cnk6IFVuaWZpZWRMb2dFbnRyeSkgPT4gdm9pZDsgbWV0cmljc09uU25hcHNob3Q/OiAoc25hcHNob3Q6IE1ldHJpY1NuYXBzaG90KSA9PiB2b2lkIH0sIG1ldHJpY3NTaW5rPzogTWVtb3J5TWV0cmljc1NpbmspID0+IHZvaWQ7XG4gIC8qKiBDb25zb2xlIHBvcnQgb3ZlcnJpZGUgZnJvbSBjb25maWcgZmlsZS4gRmFsbHMgYmFjayB0byBlbnYgdmFyIGlmIG5vdCBwcm92aWRlZC4gKi9cbiAgcG9ydD86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBSZXN1bHQgb2Ygc3RhcnRpbmcgdGhlIHVuaWZpZWQgY29uc29sZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBVbmlmaWVkQ29uc29sZVJlc3VsdCB7XG4gIHJvbGU6ICdsZWFkZXInIHwgJ2ZvbGxvd2VyJztcbiAgZWxlY3Rpb246IEVsZWN0aW9uUmVzdWx0O1xuICAvKiogUG9ydCB0aGUgY29uc29sZSBpcyBydW5uaW5nIG9uIChsZWFkZXIgb25seSkgKi9cbiAgcG9ydD86IG51bWJlcjtcbiAgLyoqIENsZWFudXAgZnVuY3Rpb24gdG8gY2FsbCBvbiBzaHV0ZG93biAqL1xuICBjbGVhbnVwOiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xufVxuXG4vKipcbiAqIENoZWNrIGZvciBhIHJ1bm5pbmcgbGVnYWN5IChwcmUtYXV0aGVudGljYXRpb24pIERvbGxob3VzZU1DUCBjb25zb2xlIGFuZFxuICogbG9nIGEgV0FSTi1sZXZlbCBtZXNzYWdlIGlmIG9uZSBpcyBmb3VuZCAoIzE3OTQpLlxuICpcbiAqIEV4dHJhY3RlZCBmcm9tIGBzdGFydFVuaWZpZWRDb25zb2xlYCBzbyB0aGUgd2lyaW5nIGNhbiBiZSBpbnRlZ3JhdGlvbi1cbiAqIHRlc3RlZCBpbiBpc29sYXRpb24gd2l0aG91dCBzcGlubmluZyB1cCBhIGZ1bGwgd2ViIHNlcnZlciBhbmQgbGVhZGVyXG4gKiBlbGVjdGlvbi4gVGhlIGltcGxlbWVudGF0aW9uIGlzIGZpcmUtYW5kLWZvcmdldDogZGV0ZWN0aW9uIGZhaWx1cmVzXG4gKiBhcmUgbG9nZ2VkIGF0IERFQlVHIGFuZCBuZXZlciBwcm9wYWdhdGUsIGJlY2F1c2UgYSBmYWlsdXJlIGhlcmUgbXVzdFxuICogbm90IGJsb2NrIGxlYWRlciBlbGVjdGlvbiBvZiB0aGUgYXV0aGVudGljYXRlZCBjb25zb2xlLlxuICpcbiAqIEBwYXJhbSBjdXJyZW50UG9ydCAtIFRoZSBwb3J0IHRoZSBhdXRoZW50aWNhdGVkIGNvbnNvbGUgaW50ZW5kcyB0b1xuICogICAgICAgICAgICAgICAgICAgICAgYmluZCB0by4gVXNlZCBpbiB0aGUgd2FybmluZyBtZXNzYWdlIHRvIGhlbHAgdGhlXG4gKiAgICAgICAgICAgICAgICAgICAgICB1c2VyIHRlbGwgdGhlIHR3byBjb25zb2xlcyBhcGFydC5cbiAqIEBwYXJhbSBkZXRlY3QgICAgICAtIE9wdGlvbmFsIGluamVjdGlvbiBwb2ludCBmb3IgdGhlIGRldGVjdGlvblxuICogICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24uIERlZmF1bHRzIHRvIGBkZXRlY3RMZWdhY3lMZWFkZXJgLiBUZXN0c1xuICogICAgICAgICAgICAgICAgICAgICAgcGFzcyBhIHN0dWIuXG4gKiBAcGFyYW0gbG9nICAgICAgICAgLSBPcHRpb25hbCBpbmplY3Rpb24gcG9pbnQgZm9yIHRoZSBsb2dnZXIuIERlZmF1bHRzXG4gKiAgICAgICAgICAgICAgICAgICAgICB0byB0aGUgbW9kdWxlIGxvZ2dlci4gVGVzdHMgcGFzcyBhIHNweS5cbiAqIEByZXR1cm5zIFRoZSBsZWdhY3kgbGVhZGVyIGluZm8gZnJvbSBgZGV0ZWN0KClgLCBvciBudWxsIGlmIGRldGVjdGlvblxuICogICAgICAgICAgdGhyZXcuIEV4cG9zZWQgc28gdGVzdHMgY2FuIGFzc2VydCB0aGUgZnVsbCByZXN1bHQgc2hhcGUuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3YXJuSWZMZWdhY3lDb25zb2xlUHJlc2VudChcbiAgY3VycmVudFBvcnQ6IG51bWJlcixcbiAgZGV0ZWN0OiB0eXBlb2YgZGV0ZWN0TGVnYWN5TGVhZGVyID0gZGV0ZWN0TGVnYWN5TGVhZGVyLFxuICBsb2c6IHR5cGVvZiBsb2dnZXIgPSBsb2dnZXIsXG4pOiBQcm9taXNlPEF3YWl0ZWQ8UmV0dXJuVHlwZTx0eXBlb2YgZGV0ZWN0TGVnYWN5TGVhZGVyPj4gfCBudWxsPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgbGVnYWN5ID0gYXdhaXQgZGV0ZWN0KCk7XG4gICAgaWYgKGxlZ2FjeS5sZWdhY3lSdW5uaW5nKSB7XG4gICAgICBsb2cud2FybihcbiAgICAgICAgYFtVbmlmaWVkQ29uc29sZV0gTGVnYWN5IChwcmUtYXV0aGVudGljYXRpb24pIERvbGxob3VzZU1DUCBjb25zb2xlIGRldGVjdGVkIGAgK1xuICAgICAgICBgKHBpZD0ke2xlZ2FjeS5waWR9LCBwb3J0PSR7bGVnYWN5LnBvcnR9KS4gQm90aCBjb25zb2xlcyB3aWxsIHJ1biBgICtcbiAgICAgICAgYGluZGVwZW5kZW50bHkgb24gZGlmZmVyZW50IHBvcnRzIHdpdGggZGlmZmVyZW50IHNlY3VyaXR5IHBvc3R1cmUuIGAgK1xuICAgICAgICBgVGhlIGF1dGhlbnRpY2F0ZWQgY29uc29sZSAodGhpcyBwcm9jZXNzKSB1c2VzIHBvcnQgJHtjdXJyZW50UG9ydH07IGAgK1xuICAgICAgICBgdGhlIGxlZ2FjeSBjb25zb2xlIHVzZXMgcG9ydCAke2xlZ2FjeS5wb3J0ID8/IDM5Mzl9LiBgICtcbiAgICAgICAgYEZvciBjb25zaXN0ZW50IHNlY3VyaXR5LCB1cGRhdGUgdGhlIGxlZ2FjeSBpbnN0YWxsYXRpb24gdG8gYSBgICtcbiAgICAgICAgYHZlcnNpb24gd2l0aCB0aGUgYXV0aGVudGljYXRlZCBjb25zb2xlLmAsXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gbGVnYWN5O1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICAvLyBCZXN0LWVmZm9ydCDigJQgbmV2ZXIgYmxvY2sgZWxlY3Rpb24gb24gYSBkZXRlY3Rpb24gZmFpbHVyZVxuICAgIGxvZy5kZWJ1ZygnW1VuaWZpZWRDb25zb2xlXSBMZWdhY3kgbGVhZGVyIGRldGVjdGlvbiBmYWlsZWQnLCB7XG4gICAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpLFxuICAgIH0pO1xuICAgIHJldHVybiBudWxsO1xuICB9XG59XG5cbi8qKlxuICogU3RhcnQgdGhlIHVuaWZpZWQgd2ViIGNvbnNvbGUuXG4gKlxuICogUnVucyBsZWFkZXIgZWxlY3Rpb24sIHRoZW4gZWl0aGVyIHN0YXJ0cyB0aGUgZnVsbCBjb25zb2xlIChsZWFkZXIpXG4gKiBvciBzZXRzIHVwIGV2ZW50IGZvcndhcmRpbmcgKGZvbGxvd2VyKS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0VW5pZmllZENvbnNvbGUob3B0aW9uczogVW5pZmllZENvbnNvbGVPcHRpb25zKTogUHJvbWlzZTxVbmlmaWVkQ29uc29sZVJlc3VsdD4ge1xuICAvLyBSZXNvbHZlIHBvcnQ6IG9wdGlvbnMgKGNvbmZpZyBmaWxlKSDihpIgZW52IHZhciDihpIgZGVmYXVsdFxuICBjb25zdCBjb25zb2xlUG9ydCA9IG9wdGlvbnMucG9ydCB8fCBERUZBVUxUX0NPTlNPTEVfUE9SVDtcbiAgbG9nZ2VyLmRlYnVnKGBbVW5pZmllZENvbnNvbGVdIFBvcnQgcmVzb2x2ZWQ6ICR7Y29uc29sZVBvcnR9YCArXG4gICAgKG9wdGlvbnMucG9ydCA/ICcgKGZyb20gY29uZmlnIGZpbGUpJyA6IGAgKGZyb20gZW52L2RlZmF1bHQpYCkpO1xuXG4gIC8vIExlZ2FjeS1sZWFkZXIgZGV0ZWN0aW9uICgjMTc5NCkg4oCUIHdhcm4gdGhlIHVzZXIgaWYgYSBwcmUtYXV0aFxuICAvLyBEb2xsaG91c2VNQ1AgY29uc29sZSBpcyBydW5uaW5nIGFsb25nc2lkZSB0aGlzIGF1dGhlbnRpY2F0ZWQgb25lLlxuICAvLyBUaGV5IHdpbGwgY29leGlzdCBmaW5lIGJlY2F1c2Ugb2YgcG9ydCArIGxvY2sgKyB0b2tlbiBmaWxlIGlzb2xhdGlvbixcbiAgLy8gYnV0IHRoZSB1c2VyIHNob3VsZCBrbm93IGJvdGggZXhpc3Qgc28gdGhlIGRpZmZlcmluZyBzZWN1cml0eSBwb3N0dXJlXG4gIC8vIGJldHdlZW4gdGhlbSBkb2Vzbid0IGxvb2sgbGlrZSBhIGJ1Zy5cbiAgYXdhaXQgd2FybklmTGVnYWN5Q29uc29sZVByZXNlbnQoY29uc29sZVBvcnQpO1xuXG4gIGxldCBlbGVjdGlvbiA9IGF3YWl0IGVsZWN0TGVhZGVyKG9wdGlvbnMuc2Vzc2lvbklkLCBjb25zb2xlUG9ydCk7XG5cbiAgLy8gSWYgd2UgbG9zdCB0aGUgZWxlY3Rpb24sIGNoZWNrIGlmIHRoZSBsZWFkZXIgaXMgYWN0dWFsbHkgcnVubmluZyBhIHdlYiBjb25zb2xlLlxuICAvLyBBbiBNQ1Agc3RkaW8gcHJvY2VzcyBtYXkgaG9sZCBsZWFkZXJzaGlwIGJ1dCBub3Qgc2VydmUgd2ViIHJvdXRlcy5cbiAgLy8gSW4gdGhhdCBjYXNlLCBmb3JjZSBhIHRha2VvdmVyIHNvIHRoZSB3ZWIgY29uc29sZSB3b3JrcyBwcm9wZXJseS5cbiAgaWYgKGVsZWN0aW9uLnJvbGUgPT09ICdmb2xsb3dlcicpIHtcbiAgICBjb25zdCByZWFjaGFibGUgPSBhd2FpdCBpc0xlYWRlcldlYkNvbnNvbGVSZWFjaGFibGUoZWxlY3Rpb24ubGVhZGVySW5mbyk7XG4gICAgaWYgKCFyZWFjaGFibGUpIHtcbiAgICAgIGVsZWN0aW9uID0gYXdhaXQgZm9yY2VDbGFpbUxlYWRlcnNoaXAob3B0aW9ucy5zZXNzaW9uSWQsIGNvbnNvbGVQb3J0KTtcbiAgICB9XG4gIH1cblxuICBpZiAoZWxlY3Rpb24ucm9sZSA9PT0gJ2xlYWRlcicpIHtcbiAgICByZXR1cm4gc3RhcnRBc0xlYWRlcihvcHRpb25zLCBlbGVjdGlvbiwgY29uc29sZVBvcnQpO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBzdGFydEFzRm9sbG93ZXIob3B0aW9ucywgZWxlY3Rpb24sIGNvbnNvbGVQb3J0KTtcbiAgfVxufVxuXG4vKipcbiAqIFN0YXJ0IGFzIHRoZSBjb25zb2xlIGxlYWRlci5cbiAqIEJpbmRzIHRoZSByZXNvbHZlZCBjb25zb2xlIHBvcnQgKGNvbmZpZyBmaWxlIOKGkiBlbnYgdmFyIOKGkiBkZWZhdWx0KSxcbiAqIG1vdW50cyBhbGwgcm91dGVzIGluY2x1ZGluZyBpbmdlc3Rpb24sIHN0YXJ0cyBoZWFydGJlYXQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHN0YXJ0QXNMZWFkZXIoXG4gIG9wdGlvbnM6IFVuaWZpZWRDb25zb2xlT3B0aW9ucyxcbiAgZWxlY3Rpb246IEVsZWN0aW9uUmVzdWx0LFxuICBjb25zb2xlUG9ydDogbnVtYmVyID0gREVGQVVMVF9DT05TT0xFX1BPUlQsXG4pOiBQcm9taXNlPFVuaWZpZWRDb25zb2xlUmVzdWx0PiB7XG4gIGNvbnN0IHsgc3RhcnRXZWJTZXJ2ZXIgfSA9IGF3YWl0IGltcG9ydCgnLi4vc2VydmVyLmpzJyk7XG4gIGNvbnN0IHsgcGlja1JhbmRvbVB1cHBldE5hbWUgfSA9IGF3YWl0IGltcG9ydCgnLi9TZXNzaW9uTmFtZXMuanMnKTtcblxuICAvLyBJbml0aWFsaXplIHRoZSBjb25zb2xlIHRva2VuIHN0b3JlICgjMTc4MCkuIENyZWF0ZXMgdGhlIHRva2VuIGZpbGUgb25cbiAgLy8gZmlyc3QgcnVuLCByZWFkcyB0aGUgZXhpc3RpbmcgdG9rZW5zIG9uIHN1YnNlcXVlbnQgcnVucy4gVGhlIHRva2VuIGlzXG4gIC8vIHBlcnNpc3RlbnQgYWNyb3NzIHJlc3RhcnRzIOKAlCBvbmx5IHJvdGF0ZWQgb24gZXhwbGljaXQgcmVxdWVzdCAoUGhhc2UgMikuXG4gIC8vIEZlYXR1cmUgZmxhZyBET0xMSE9VU0VfV0VCX0FVVEhfRU5BQkxFRCBjb250cm9scyBlbmZvcmNlbWVudDsgdGhlIGZpbGVcbiAgLy8gaXMgZ2VuZXJhdGVkIHJlZ2FyZGxlc3Mgc28gY29uc3VtZXJzIGNhbiBhdHRhY2ggdG9rZW5zIHByZWVtcHRpdmVseS5cbiAgY29uc3QgdG9rZW5TdG9yZSA9IG5ldyBDb25zb2xlVG9rZW5TdG9yZShlbnYuRE9MTEhPVVNFX0NPTlNPTEVfVE9LRU5fRklMRSk7XG4gIGNvbnN0IHByaW1hcnlUb2tlbiA9IGF3YWl0IHRva2VuU3RvcmUuZW5zdXJlSW5pdGlhbGl6ZWQocGlja1JhbmRvbVB1cHBldE5hbWUoKSk7XG4gIGxvZ2dlci5pbmZvKCdbVW5pZmllZENvbnNvbGVdIENvbnNvbGUgdG9rZW4gc3RvcmUgaW5pdGlhbGl6ZWQnLCB7XG4gICAgdG9rZW5JZDogcHJpbWFyeVRva2VuLmlkLFxuICAgIHRva2VuTmFtZTogcHJpbWFyeVRva2VuLm5hbWUsXG4gICAgZmlsZTogdG9rZW5TdG9yZS5nZXRGaWxlUGF0aCgpLFxuICAgIGF1dGhFbmZvcmNlZDogZW52LkRPTExIT1VTRV9XRUJfQVVUSF9FTkFCTEVELFxuICB9KTtcblxuICAvLyBQcmUtY3JlYXRlIGEgcGxhY2Vob2xkZXIgYnJvYWRjYXN0IHRoYXQgd2UnbGwgd2lyZSB1cCBhZnRlciB0aGUgc2VydmVyIHN0YXJ0c1xuICBsZXQgbGl2ZUJyb2FkY2FzdDogKChlbnRyeTogVW5pZmllZExvZ0VudHJ5KSA9PiB2b2lkKSB8IHVuZGVmaW5lZDtcbiAgbGV0IGxpdmVNZXRyaWNzT25TbmFwc2hvdDogKChzbmFwc2hvdDogTWV0cmljU25hcHNob3QpID0+IHZvaWQpIHwgdW5kZWZpbmVkO1xuXG4gIC8vIENyZWF0ZSBpbmdlc3Rpb24gcm91dGVzIHdpdGggYSBkZWZlcnJlZCBicm9hZGNhc3QgKHdpcmVkIGFmdGVyIHNlcnZlciBzdGFydHMpXG4gIGNvbnN0IGluZ2VzdFJlc3VsdCA9IGNyZWF0ZUluZ2VzdFJvdXRlcyh7XG4gICAgbG9nQnJvYWRjYXN0OiAoZW50cnkpID0+IGxpdmVCcm9hZGNhc3Q/LihlbnRyeSksXG4gICAgbWV0cmljc09uU25hcHNob3Q6IChzbmFwc2hvdCkgPT4gbGl2ZU1ldHJpY3NPblNuYXBzaG90Py4oc25hcHNob3QpLFxuICB9KTtcblxuICAvLyBSZWdpc3RlciB0aGUgbGVhZGVyIGFzIGEgc2Vzc2lvblxuICBpbmdlc3RSZXN1bHQucmVnaXN0ZXJMZWFkZXJTZXNzaW9uKG9wdGlvbnMuc2Vzc2lvbklkLCBwcm9jZXNzLnBpZCk7XG5cbiAgLy8gUmVnaXN0ZXIgdGhlIHdlYiBjb25zb2xlIGl0c2VsZiBzbyB0aGUgc2Vzc2lvbiBpbmRpY2F0b3IgaXMgbmV2ZXIgZW1wdHkgKCMxODA1KVxuICBpbmdlc3RSZXN1bHQucmVnaXN0ZXJDb25zb2xlU2Vzc2lvbigpO1xuXG4gIC8vIFN0YXJ0IHRoZSB3ZWIgc2VydmVyIHdpdGggaW5nZXN0IHJvdXRlcyBtb3VudGVkIGJlZm9yZSB0aGUgU1BBIGZhbGxiYWNrLlxuICAvLyBJZiB0aGUgcG9ydCBpcyBvY2N1cGllZCBieSBhIHN0YWxlIHByb2Nlc3MsIHJldHJ5IHdpdGggZXhwb25lbnRpYWwgYmFja29mZi5cbiAgY29uc3Qgc2VydmVyT3B0cyA9IHtcbiAgICBwb3J0Zm9saW9EaXI6IG9wdGlvbnMucG9ydGZvbGlvRGlyLFxuICAgIG1lbW9yeVNpbms6IG9wdGlvbnMubWVtb3J5U2luayxcbiAgICBtZXRyaWNzU2luazogb3B0aW9ucy5tZXRyaWNzU2luayxcbiAgICBwb3J0OiBjb25zb2xlUG9ydCxcbiAgICBhZGRpdGlvbmFsUm91dGVyczogW2luZ2VzdFJlc3VsdC5yb3V0ZXJdLFxuICAgIHRva2VuU3RvcmUsXG4gICAgLi4uKG9wdGlvbnMubWNwQXFsSGFuZGxlciA/IHsgbWNwQXFsSGFuZGxlcjogb3B0aW9ucy5tY3BBcWxIYW5kbGVyIH0gOiB7fSksXG4gIH07XG4gIGNvbnN0IEJJTkRfUkVUUllfREVMQVlTID0gZW52LkRPTExIT1VTRV9DT05TT0xFX0JJTkRfUkVUUllfREVMQVlTPy5sZW5ndGhcbiAgICA/IGVudi5ET0xMSE9VU0VfQ09OU09MRV9CSU5EX1JFVFJZX0RFTEFZU1xuICAgIDogWzEwMDAsIDIwMDAsIDQwMDBdO1xuICBjb25zdCB3ZWJSZXN1bHQgPSBhd2FpdCBzdGFydFdlYlNlcnZlcihzZXJ2ZXJPcHRzKTtcblxuICAvLyBJZiB0aGUgcG9ydCBpcyBvY2N1cGllZCwgcmV0cnkgdGhlIGJpbmQgb25seSDigJQgZG9uJ3QgcmVjcmVhdGUgdGhlIEV4cHJlc3NcbiAgLy8gYXBwIGFuZCByb3V0ZXMgKHN0YXJ0V2ViU2VydmVyIGVhcmx5LXJldHVybnMgd2hlbiBzZXJ2ZXJSdW5uaW5nIGlzIGZhbHNlXG4gIC8vIGJ1dCB0aGUgYXBwIGlzIGFscmVhZHkgY29uZmlndXJlZCkuIFdlIGNhbGwgcmV0cnlCaW5kIG9uIHRoZSBleGlzdGluZyBhcHAuXG4gIGlmICh3ZWJSZXN1bHQuYmluZFJlc3VsdCAmJiAhd2ViUmVzdWx0LmJpbmRSZXN1bHQuc3VjY2VzcyAmJiB3ZWJSZXN1bHQuYmluZFJlc3VsdC5lcnJvciA9PT0gJ0VBRERSSU5VU0UnICYmIHdlYlJlc3VsdC5hcHApIHtcbiAgICBjb25zdCB7IHJldHJ5QmluZCB9ID0gYXdhaXQgaW1wb3J0KCcuLi9zZXJ2ZXIuanMnKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IEJJTkRfUkVUUllfREVMQVlTLmxlbmd0aDsgaSsrKSB7XG4gICAgICBsb2dnZXIud2FybihgW1VuaWZpZWRDb25zb2xlXSBQb3J0ICR7Y29uc29sZVBvcnR9IG9jY3VwaWVkIOKAlCByZXRyeSAke2kgKyAxfS8ke0JJTkRfUkVUUllfREVMQVlTLmxlbmd0aH0gaW4gJHtCSU5EX1JFVFJZX0RFTEFZU1tpXX1tc2ApO1xuICAgICAgYXdhaXQgbmV3IFByb21pc2UociA9PiBzZXRUaW1lb3V0KHIsIEJJTkRfUkVUUllfREVMQVlTW2ldKSk7XG4gICAgICBjb25zdCByZXRyeVJlc3VsdCA9IGF3YWl0IHJldHJ5QmluZCh3ZWJSZXN1bHQuYXBwLCBjb25zb2xlUG9ydCwgc2VydmVyT3B0cyk7XG4gICAgICBpZiAocmV0cnlSZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICB3ZWJSZXN1bHQuYmluZFJlc3VsdCA9IHJldHJ5UmVzdWx0O1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKHdlYlJlc3VsdC5iaW5kUmVzdWx0ICYmICF3ZWJSZXN1bHQuYmluZFJlc3VsdC5zdWNjZXNzKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoYFtVbmlmaWVkQ29uc29sZV0gTGVhZGVyIGZhaWxlZCB0byBiaW5kIHBvcnQgJHtjb25zb2xlUG9ydH0gYWZ0ZXIgJHtCSU5EX1JFVFJZX0RFTEFZUy5sZW5ndGh9IHJldHJpZXMg4oCUIGNvbnNvbGUgdW5hdmFpbGFibGVgKTtcbiAgICB9XG4gIH1cblxuICAvLyBXaXJlIFNTRSBicm9hZGNhc3RzIGZvciB0aGlzIGxlYWRlcidzIG93biBldmVudHNcbiAgb3B0aW9ucy53aXJlU1NFQnJvYWRjYXN0cyh3ZWJSZXN1bHQsIG9wdGlvbnMubWV0cmljc1NpbmspO1xuXG4gIC8vIE5vdyB3aXJlIHRoZSBsaXZlIGJyb2FkY2FzdCBmdW5jdGlvbnMgaW50byB0aGUgaW5nZXN0IHJvdXRlc1xuICBpZiAod2ViUmVzdWx0LmxvZ0Jyb2FkY2FzdCkge1xuICAgIGNvbnN0IG9yaWdpbmFsQnJvYWRjYXN0ID0gd2ViUmVzdWx0LmxvZ0Jyb2FkY2FzdDtcbiAgICAvLyBTdGFtcCBsZWFkZXIncyBvd24gZW50cmllcyB3aXRoIHNlc3Npb24gSURcbiAgICBsaXZlQnJvYWRjYXN0ID0gKGVudHJ5OiBVbmlmaWVkTG9nRW50cnkpID0+IHtcbiAgICAgIGNvbnN0IHN0YW1wZWQ6IFVuaWZpZWRMb2dFbnRyeSA9IHtcbiAgICAgICAgLi4uZW50cnksXG4gICAgICAgIGRhdGE6IHsgLi4uZW50cnkuZGF0YSwgX3Nlc3Npb25JZDogb3B0aW9ucy5zZXNzaW9uSWQgfSxcbiAgICAgIH07XG4gICAgICBvcmlnaW5hbEJyb2FkY2FzdChzdGFtcGVkKTtcbiAgICB9O1xuICB9XG4gIGxpdmVNZXRyaWNzT25TbmFwc2hvdCA9IHdlYlJlc3VsdC5tZXRyaWNzT25TbmFwc2hvdDtcblxuICBsb2dnZXIuaW5mbygnW1VuaWZpZWRDb25zb2xlXSBJbmdlc3Rpb24gcm91dGVzIG1vdW50ZWQnKTtcblxuICAvLyBTdGFydCBoZWFydGJlYXQgYW5kIHJlZ2lzdGVyIGNsZWFudXBcbiAgY29uc3Qgc3RvcEhlYXJ0YmVhdCA9IHN0YXJ0SGVhcnRiZWF0KGVsZWN0aW9uLmxlYWRlckluZm8pO1xuICByZWdpc3RlckxlYWRlckNsZWFudXAoKTtcblxuICBsb2dnZXIuaW5mbygnW1VuaWZpZWRDb25zb2xlXSBMZWFkZXIgc3RhcnRlZCcsIHtcbiAgICBzZXNzaW9uSWQ6IG9wdGlvbnMuc2Vzc2lvbklkLCBwb3J0OiBjb25zb2xlUG9ydCwgcGlkOiBwcm9jZXNzLnBpZCxcbiAgICByb2xlOiAnbGVhZGVyJywgaW5nZXN0Um91dGVzOiBbJy9hcGkvaW5nZXN0L2xvZ3MnLCAnL2FwaS9pbmdlc3QvbWV0cmljcycsICcvYXBpL2luZ2VzdC9zZXNzaW9uJywgJy9hcGkvc2Vzc2lvbnMnXSxcbiAgfSk7XG5cbiAgcmV0dXJuIHtcbiAgICByb2xlOiAnbGVhZGVyJyxcbiAgICBlbGVjdGlvbixcbiAgICBwb3J0OiBjb25zb2xlUG9ydCxcbiAgICBjbGVhbnVwOiBhc3luYyAoKSA9PiB7XG4gICAgICBzdG9wSGVhcnRiZWF0KCk7XG4gICAgfSxcbiAgfTtcbn1cblxuLyoqXG4gKiBTdGFydCBhcyBhIGZvbGxvd2VyLlxuICogUmVnaXN0ZXJzIGZvcndhcmRpbmcgc2lua3Mgd2l0aCB0aGUgTG9nTWFuYWdlciwgc3RhcnRzIHNlc3Npb24gaGVhcnRiZWF0LlxuICovXG5hc3luYyBmdW5jdGlvbiBzdGFydEFzRm9sbG93ZXIoXG4gIG9wdGlvbnM6IFVuaWZpZWRDb25zb2xlT3B0aW9ucyxcbiAgZWxlY3Rpb246IEVsZWN0aW9uUmVzdWx0LFxuICBjb25zb2xlUG9ydDogbnVtYmVyID0gREVGQVVMVF9DT05TT0xFX1BPUlQsXG4pOiBQcm9taXNlPFVuaWZpZWRDb25zb2xlUmVzdWx0PiB7XG4gIGNvbnN0IGxlYWRlclVybCA9IGBodHRwOi8vMTI3LjAuMC4xOiR7ZWxlY3Rpb24ubGVhZGVySW5mby5wb3J0fWA7XG5cbiAgLy8gUmVhZCB0aGUgY29uc29sZSBhdXRoIHRva2VuICgjMTc4MCkgd3JpdHRlbiBieSB0aGUgbGVhZGVyLiBNYXkgYmUgbnVsbFxuICAvLyBpZiB0aGUgZmlsZSBkb2Vzbid0IGV4aXN0IHlldCDigJQgdGhlIHNpbmtzIGhhbmRsZSB0aGF0IGdyYWNlZnVsbHkgYW5kXG4gIC8vIHNpbXBseSBvbWl0IHRoZSBCZWFyZXIgaGVhZGVyLCB3aGljaCBpcyBmaW5lIHdoZW4gYXV0aCBpcyBub3QgZW5mb3JjZWQuXG4gIGNvbnN0IHsgZ2V0UHJpbWFyeVRva2VuRnJvbUZpbGUgfSA9IGF3YWl0IGltcG9ydCgnLi9jb25zb2xlVG9rZW4uanMnKTtcbiAgY29uc3QgYXV0aFRva2VuID0gYXdhaXQgZ2V0UHJpbWFyeVRva2VuRnJvbUZpbGUoZW52LkRPTExIT1VTRV9DT05TT0xFX1RPS0VOX0ZJTEUpO1xuICBpZiAoYXV0aFRva2VuKSB7XG4gICAgbG9nZ2VyLmRlYnVnKCdbVW5pZmllZENvbnNvbGVdIEZvbGxvd2VyIGxvYWRlZCBjb25zb2xlIGF1dGggdG9rZW4nKTtcbiAgfSBlbHNlIHtcbiAgICBsb2dnZXIuZGVidWcoJ1tVbmlmaWVkQ29uc29sZV0gTm8gY29uc29sZSBhdXRoIHRva2VuIGZpbGUgZm91bmQ7IGZvbGxvd2VyIHdpbGwgUE9TVCB3aXRob3V0IEJlYXJlciBoZWFkZXInKTtcbiAgfVxuXG4gIC8vIFBlci1pbnN0YW5jZSBwcm9tb3Rpb24gbWFuYWdlciDigJQgdHJhY2tzIGl0cyBvd24gYXR0ZW1wdCBjb3VudGVyIHNvXG4gIC8vIG11bHRpcGxlIGZvbGxvd2VycyBkb24ndCBpbnRlcmZlcmUgd2l0aCBlYWNoIG90aGVyJ3MgcHJvbW90aW9uIGJ1ZGdldHMuXG4gIGNvbnN0IHByb21vdGlvbk1nciA9IG5ldyBQcm9tb3Rpb25NYW5hZ2VyKG9wdGlvbnMsIGNvbnNvbGVQb3J0LCBzdGFydEFzTGVhZGVyLCBzdGFydEFzRm9sbG93ZXIpO1xuXG4gIC8vIERlY2xhcmUgc2Vzc2lvbkhlYXJ0YmVhdCBiZWZvcmUgdGhlIHNpbmsgc28gdGhlIGNsb3N1cmUgY2FuIGNhcHR1cmUgaXQuXG4gIC8vIEJvdGggYXJlIGluaXRpYWxpemVkIGJlZm9yZSB0aGUgY2FsbGJhY2sgY291bGQgcG9zc2libHkgZmlyZSAobmVlZHMgNSsgZmFpbGVkIGZsdXNoZXMpLlxuICBsZXQgc2Vzc2lvbkhlYXJ0YmVhdDogU2Vzc2lvbkhlYXJ0YmVhdDtcblxuICAvLyBSZWdpc3RlciBhIGZvcndhcmRpbmcgbG9nIHNpbmsgd2l0aCBsZWFkZXItZGVhdGggY2FsbGJhY2sgKCMxODUwKS5cbiAgY29uc3QgZm9yd2FyZGluZ1NpbmsgPSBuZXcgTGVhZGVyRm9yd2FyZGluZ0xvZ1NpbmsobGVhZGVyVXJsLCBvcHRpb25zLnNlc3Npb25JZCwgYXV0aFRva2VuLCAoKSA9PiB7XG4gICAgcHJvbW90aW9uTWdyLnByb21vdGUoZm9yd2FyZGluZ1NpbmssIHNlc3Npb25IZWFydGJlYXQpXG4gICAgICAuY2F0Y2goZXJyID0+IGxvZ2dlci5lcnJvcignW1VuaWZpZWRDb25zb2xlXSBQcm9tb3Rpb24gY3Jhc2hlZCcsIHsgZXJyb3I6IFN0cmluZyhlcnIpIH0pKTtcbiAgfSk7XG4gIG9wdGlvbnMucmVnaXN0ZXJMb2dTaW5rKGZvcndhcmRpbmdTaW5rKTtcblxuICAvLyBTdGFydCBzZXNzaW9uIGhlYXJ0YmVhdCB0byB0aGUgbGVhZGVyXG4gIHNlc3Npb25IZWFydGJlYXQgPSBuZXcgU2Vzc2lvbkhlYXJ0YmVhdChsZWFkZXJVcmwsIG9wdGlvbnMuc2Vzc2lvbklkLCBwcm9jZXNzLnBpZCwgYXV0aFRva2VuKTtcbiAgYXdhaXQgc2Vzc2lvbkhlYXJ0YmVhdC5zdGFydCgpO1xuXG4gIGxvZ2dlci5pbmZvKCdbVW5pZmllZENvbnNvbGVdIEZvbGxvd2VyIHN0YXJ0ZWQnLCB7XG4gICAgc2Vzc2lvbklkOiBvcHRpb25zLnNlc3Npb25JZCwgcGlkOiBwcm9jZXNzLnBpZCwgcm9sZTogJ2ZvbGxvd2VyJyxcbiAgICBsZWFkZXJTZXNzaW9uOiBlbGVjdGlvbi5sZWFkZXJJbmZvLnNlc3Npb25JZCwgbGVhZGVyUGlkOiBlbGVjdGlvbi5sZWFkZXJJbmZvLnBpZCxcbiAgICBsZWFkZXJQb3J0OiBlbGVjdGlvbi5sZWFkZXJJbmZvLnBvcnQsIGxlYWRlclVybCxcbiAgfSk7XG5cbiAgcmV0dXJuIHtcbiAgICByb2xlOiAnZm9sbG93ZXInLFxuICAgIGVsZWN0aW9uLFxuICAgIGNsZWFudXA6IGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHNlc3Npb25IZWFydGJlYXQuc3RvcCgpO1xuICAgICAgYXdhaXQgZm9yd2FyZGluZ1NpbmsuY2xvc2UoKTtcbiAgICB9LFxuICB9O1xufVxuXG4iXX0=
@@ -5,7 +5,8 @@
5
5
  * Claude Code windows, IDE instances, or agent sessions), each needs its
6
6
  * own web console port. This module handles:
7
7
  *
8
- * 1. Finding an available port starting from the default (3939)
8
+ * 1. Finding an available port starting from the configured default
9
+ * (see `DOLLHOUSE_WEB_CONSOLE_PORT` in `src/config/env.ts`)
9
10
  * 2. Writing port discovery files so external tools know which port to use
10
11
  * 3. Cleaning up port files on process exit
11
12
  *
@@ -20,7 +21,7 @@
20
21
  * and a held server to prevent TOCTOU race conditions. The caller should
21
22
  * close the held server after binding their own Express app to the port.
22
23
  *
23
- * @param startPort - Port to try first (default: 3939)
24
+ * @param startPort - Port to try first (see `DOLLHOUSE_WEB_CONSOLE_PORT` for the default)
24
25
  * @param maxAttempts - Maximum ports to try (default: 10, configurable via DOLLHOUSE_MAX_PORT_ATTEMPTS)
25
26
  * @returns Object with port number and held server, or throws if all attempts fail
26
27
  */
@@ -51,7 +52,7 @@ export declare function registerPortCleanup(): void;
51
52
  * This is the recommended entry point for Container startup. Combines
52
53
  * port discovery, file writing, and cleanup registration in one call.
53
54
  *
54
- * @param defaultPort - Port to try first (default: 3939)
55
+ * @param defaultPort - Port to try first (see `DOLLHOUSE_WEB_CONSOLE_PORT` for the default)
55
56
  * @returns The port the server should bind to, or undefined if discovery failed
56
57
  */
57
58
  export declare function discoverAndBindPort(defaultPort?: number): Promise<number | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"portDiscovery.d.ts","sourceRoot":"","sources":["../../src/web/portDiscovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAwCH;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,WAAW,GAAE,MAAqF,GACjG,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASjE;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAIrD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,GAAE,MAAa,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAYjG"}
1
+ {"version":3,"file":"portDiscovery.d.ts","sourceRoot":"","sources":["../../src/web/portDiscovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAyCH;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,WAAW,GAAE,MAAqF,GACjG,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASjE;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAIrD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,GAAE,MAAuC,GACnD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAY7B"}
@@ -5,7 +5,8 @@
5
5
  * Claude Code windows, IDE instances, or agent sessions), each needs its
6
6
  * own web console port. This module handles:
7
7
  *
8
- * 1. Finding an available port starting from the default (3939)
8
+ * 1. Finding an available port starting from the configured default
9
+ * (see `DOLLHOUSE_WEB_CONSOLE_PORT` in `src/config/env.ts`)
9
10
  * 2. Writing port discovery files so external tools know which port to use
10
11
  * 3. Cleaning up port files on process exit
11
12
  *
@@ -17,6 +18,7 @@ import { createServer } from 'node:net';
17
18
  import { homedir } from 'node:os';
18
19
  import { join } from 'node:path';
19
20
  import { mkdir, writeFile, unlink } from 'node:fs/promises';
21
+ import { env } from '../config/env.js';
20
22
  import { logger } from '../utils/logger.js';
21
23
  /** Default maximum port attempts before giving up */
22
24
  const DEFAULT_MAX_PORT_ATTEMPTS = 10;
@@ -54,7 +56,7 @@ function tryBindPort(port) {
54
56
  * and a held server to prevent TOCTOU race conditions. The caller should
55
57
  * close the held server after binding their own Express app to the port.
56
58
  *
57
- * @param startPort - Port to try first (default: 3939)
59
+ * @param startPort - Port to try first (see `DOLLHOUSE_WEB_CONSOLE_PORT` for the default)
58
60
  * @param maxAttempts - Maximum ports to try (default: 10, configurable via DOLLHOUSE_MAX_PORT_ATTEMPTS)
59
61
  * @returns Object with port number and held server, or throws if all attempts fail
60
62
  */
@@ -125,10 +127,10 @@ export function registerPortCleanup() {
125
127
  * This is the recommended entry point for Container startup. Combines
126
128
  * port discovery, file writing, and cleanup registration in one call.
127
129
  *
128
- * @param defaultPort - Port to try first (default: 3939)
130
+ * @param defaultPort - Port to try first (see `DOLLHOUSE_WEB_CONSOLE_PORT` for the default)
129
131
  * @returns The port the server should bind to, or undefined if discovery failed
130
132
  */
131
- export async function discoverAndBindPort(defaultPort = 3939) {
133
+ export async function discoverAndBindPort(defaultPort = env.DOLLHOUSE_WEB_CONSOLE_PORT) {
132
134
  try {
133
135
  const port = await findAvailablePort(defaultPort);
134
136
  await writePortFile(port);
@@ -140,4 +142,4 @@ export async function discoverAndBindPort(defaultPort = 3939) {
140
142
  return undefined;
141
143
  }
142
144
  }
143
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9ydERpc2NvdmVyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93ZWIvcG9ydERpc2NvdmVyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7R0FjRztBQUVILE9BQU8sRUFBRSxZQUFZLEVBQWUsTUFBTSxVQUFVLENBQUM7QUFDckQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNsQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ2pDLE9BQU8sRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzVELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUU1QyxxREFBcUQ7QUFDckQsTUFBTSx5QkFBeUIsR0FBRyxFQUFFLENBQUM7QUFFckMsb0VBQW9FO0FBQ3BFLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRSxZQUFZLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFFckQsdUNBQXVDO0FBQ3ZDLElBQUksWUFBWSxHQUFrQixJQUFJLENBQUM7QUFFdkM7Ozs7R0FJRztBQUNILFNBQVMsV0FBVyxDQUFDLElBQVk7SUFDL0IsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFO1FBQzdCLE1BQU0sTUFBTSxHQUFHLFlBQVksRUFBRSxDQUFDO1FBQzlCLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsR0FBMEIsRUFBRSxFQUFFO1lBQ2xELElBQUksR0FBRyxDQUFDLElBQUksS0FBSyxZQUFZLEVBQUUsQ0FBQztnQkFDOUIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2hCLENBQUM7aUJBQU0sQ0FBQztnQkFDTixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2QsTUFBTSxDQUFDLEtBQUssQ0FBQyw0Q0FBNEMsSUFBSSxLQUFLLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQ2hGLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUNILE1BQU0sQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsRUFBRTtZQUM1QixPQUFPLENBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUM1QixDQUFDLENBQUMsQ0FBQztRQUNILE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDO0lBQ25DLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVEOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGlCQUFpQixDQUNyQyxTQUFpQixFQUNqQixjQUFzQixNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsQ0FBQyxJQUFJLHlCQUF5QjtJQUVsRyxLQUFLLElBQUksT0FBTyxHQUFHLENBQUMsRUFBRSxPQUFPLEdBQUcsV0FBVyxFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUM7UUFDdkQsTUFBTSxJQUFJLEdBQUcsU0FBUyxHQUFHLE9BQU8sQ0FBQztRQUNqQyxNQUFNLENBQUMsS0FBSyxDQUFDLCtCQUErQixJQUFJLGFBQWEsT0FBTyxHQUFHLENBQUMsSUFBSSxXQUFXLEdBQUcsQ0FBQyxDQUFDO1FBRTVGLE1BQU0sTUFBTSxHQUFHLE1BQU0sV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3ZDLElBQUksTUFBTSxFQUFFLENBQUM7WUFDWCxzRUFBc0U7WUFDdEUsb0VBQW9FO1lBQ3BFLHdFQUF3RTtZQUN4RSxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3RCLElBQUksT0FBTyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNoQixNQUFNLENBQUMsSUFBSSxDQUFDLHdCQUF3QixTQUFTLGtCQUFrQixJQUFJLFdBQVcsT0FBTyxRQUFRLE9BQU8sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUMxSCxDQUFDO1lBQ0QsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQ0QsTUFBTSxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsSUFBSSxzQkFBc0IsQ0FBQyxDQUFDO0lBQ25FLENBQUM7SUFFRCxNQUFNLElBQUksS0FBSyxDQUNiLG9DQUFvQyxTQUFTLElBQUksU0FBUyxHQUFHLFdBQVcsR0FBRyxDQUFDLEdBQUc7UUFDL0UsU0FBUyxXQUFXLG1FQUFtRSxDQUN4RixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsYUFBYSxDQUFDLElBQVk7SUFDOUMsTUFBTSxLQUFLLENBQUMsT0FBTyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDMUMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxxQkFBcUIsT0FBTyxDQUFDLEdBQUcsT0FBTyxDQUFDLENBQUM7SUFDdkUsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSx3QkFBd0IsQ0FBQyxDQUFDO0lBQzNELE1BQU0sU0FBUyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDaEQsTUFBTSxTQUFTLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNuRCxZQUFZLEdBQUcsT0FBTyxDQUFDO0lBQ3ZCLE1BQU0sQ0FBQyxLQUFLLENBQUMsc0NBQXNDLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDOUQsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxlQUFlO0lBQ25DLElBQUksWUFBWSxFQUFFLENBQUM7UUFDakIsSUFBSSxDQUFDO1lBQUMsTUFBTSxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsTUFBTSxDQUFDLENBQUMsa0JBQWtCLENBQUMsQ0FBQztJQUNsRSxDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQU0sVUFBVSxtQkFBbUI7SUFDakMsTUFBTSxXQUFXLEdBQUcsR0FBRyxFQUFFLEdBQUcsZUFBZSxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2pFLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFdBQVcsQ0FBQyxDQUFDO0lBQ2xDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0lBQ3JDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBQ3RDLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsbUJBQW1CLENBQUMsY0FBc0IsSUFBSTtJQUNsRSxJQUFJLENBQUM7UUFDSCxNQUFNLElBQUksR0FBRyxNQUFNLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRWxELE1BQU0sYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzFCLG1CQUFtQixFQUFFLENBQUM7UUFFdEIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0NBQXdDLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDM0QsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIER5bmFtaWMgcG9ydCBhbGxvY2F0aW9uIGFuZCBwb3J0IGZpbGUgZGlzY292ZXJ5IGZvciB0aGUgd2ViIGNvbnNvbGUuXG4gKlxuICogV2hlbiBtdWx0aXBsZSBEb2xsaG91c2VNQ1Agc2Vzc2lvbnMgcnVuIHNpbXVsdGFuZW91c2x5IChlLmcuLCBtdWx0aXBsZVxuICogQ2xhdWRlIENvZGUgd2luZG93cywgSURFIGluc3RhbmNlcywgb3IgYWdlbnQgc2Vzc2lvbnMpLCBlYWNoIG5lZWRzIGl0c1xuICogb3duIHdlYiBjb25zb2xlIHBvcnQuIFRoaXMgbW9kdWxlIGhhbmRsZXM6XG4gKlxuICogMS4gRmluZGluZyBhbiBhdmFpbGFibGUgcG9ydCBzdGFydGluZyBmcm9tIHRoZSBkZWZhdWx0ICgzOTM5KVxuICogMi4gV3JpdGluZyBwb3J0IGRpc2NvdmVyeSBmaWxlcyBzbyBleHRlcm5hbCB0b29scyBrbm93IHdoaWNoIHBvcnQgdG8gdXNlXG4gKiAzLiBDbGVhbmluZyB1cCBwb3J0IGZpbGVzIG9uIHByb2Nlc3MgZXhpdFxuICpcbiAqIFBvcnQgZmlsZXMgYXJlIHdyaXR0ZW4gdG8gfi8uZG9sbGhvdXNlL3J1bi86XG4gKiAtIHBlcm1pc3Npb24tc2VydmVyLXtwaWR9LnBvcnQg4oCUIHBlci1wcm9jZXNzIGZpbGUgKGNsZWFuZWQgb24gZXhpdClcbiAqIC0gcGVybWlzc2lvbi1zZXJ2ZXIucG9ydCDigJQgbGF0ZXN0IHBvcnQgKGNvbnZlbmllbmNlIGZvciBzY3JpcHRzKVxuICovXG5cbmltcG9ydCB7IGNyZWF0ZVNlcnZlciwgdHlwZSBTZXJ2ZXIgfSBmcm9tICdub2RlOm5ldCc7XG5pbXBvcnQgeyBob21lZGlyIH0gZnJvbSAnbm9kZTpvcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7IG1rZGlyLCB3cml0ZUZpbGUsIHVubGluayB9IGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcblxuLyoqIERlZmF1bHQgbWF4aW11bSBwb3J0IGF0dGVtcHRzIGJlZm9yZSBnaXZpbmcgdXAgKi9cbmNvbnN0IERFRkFVTFRfTUFYX1BPUlRfQVRURU1QVFMgPSAxMDtcblxuLyoqIERpcmVjdG9yeSBmb3IgcnVudGltZSBzdGF0ZSBmaWxlcyAocG9ydCBkaXNjb3ZlcnksIFBJRCBmaWxlcykgKi9cbmNvbnN0IFJVTl9ESVIgPSBqb2luKGhvbWVkaXIoKSwgJy5kb2xsaG91c2UnLCAncnVuJyk7XG5cbi8qKiBUcmFjayBwb3J0IGZpbGUgcGF0aCBmb3IgY2xlYW51cCAqL1xubGV0IHBvcnRGaWxlUGF0aDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG5cbi8qKlxuICogQXR0ZW1wdCB0byBiaW5kIHRvIGEgc2luZ2xlIHBvcnQuIFJldHVybnMgdGhlIHBvcnQgaWYgc3VjY2Vzc2Z1bCwgbnVsbCBpZiBpbiB1c2UuXG4gKiBLZWVwcyB0aGUgc2VydmVyIGxpc3RlbmluZyB0byBwcmV2ZW50IFRPQ1RPVSByYWNlIGNvbmRpdGlvbnMg4oCUIGNhbGxlciBtdXN0XG4gKiBjbG9zZSB0aGUgcmV0dXJuZWQgc2VydmVyIGFmdGVyIHRoZWlyIG93biBzZXJ2ZXIgYmluZHMuXG4gKi9cbmZ1bmN0aW9uIHRyeUJpbmRQb3J0KHBvcnQ6IG51bWJlcik6IFByb21pc2U8eyBwb3J0OiBudW1iZXI7IHNlcnZlcjogU2VydmVyIH0gfCBudWxsPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgIGNvbnN0IHNlcnZlciA9IGNyZWF0ZVNlcnZlcigpO1xuICAgIHNlcnZlci5vbmNlKCdlcnJvcicsIChlcnI6IE5vZGVKUy5FcnJub0V4Y2VwdGlvbikgPT4ge1xuICAgICAgaWYgKGVyci5jb2RlID09PSAnRUFERFJJTlVTRScpIHtcbiAgICAgICAgcmVzb2x2ZShudWxsKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlc29sdmUobnVsbCk7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgW1BvcnREaXNjb3ZlcnldIFVuZXhwZWN0ZWQgZXJyb3Igb24gcG9ydCAke3BvcnR9OiAke2Vyci5jb2RlfWApO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHNlcnZlci5vbmNlKCdsaXN0ZW5pbmcnLCAoKSA9PiB7XG4gICAgICByZXNvbHZlKHsgcG9ydCwgc2VydmVyIH0pO1xuICAgIH0pO1xuICAgIHNlcnZlci5saXN0ZW4ocG9ydCwgJzEyNy4wLjAuMScpO1xuICB9KTtcbn1cblxuLyoqXG4gKiBGaW5kIGFuIGF2YWlsYWJsZSBwb3J0IHN0YXJ0aW5nIGZyb20gdGhlIGdpdmVuIHBvcnQuXG4gKlxuICogVHJpZXMgc2VxdWVudGlhbCBwb3J0cywgbG9nZ2luZyBlYWNoIGF0dGVtcHQuIFJldHVybnMgYm90aCB0aGUgcG9ydCBudW1iZXJcbiAqIGFuZCBhIGhlbGQgc2VydmVyIHRvIHByZXZlbnQgVE9DVE9VIHJhY2UgY29uZGl0aW9ucy4gVGhlIGNhbGxlciBzaG91bGRcbiAqIGNsb3NlIHRoZSBoZWxkIHNlcnZlciBhZnRlciBiaW5kaW5nIHRoZWlyIG93biBFeHByZXNzIGFwcCB0byB0aGUgcG9ydC5cbiAqXG4gKiBAcGFyYW0gc3RhcnRQb3J0IC0gUG9ydCB0byB0cnkgZmlyc3QgKGRlZmF1bHQ6IDM5MzkpXG4gKiBAcGFyYW0gbWF4QXR0ZW1wdHMgLSBNYXhpbXVtIHBvcnRzIHRvIHRyeSAoZGVmYXVsdDogMTAsIGNvbmZpZ3VyYWJsZSB2aWEgRE9MTEhPVVNFX01BWF9QT1JUX0FUVEVNUFRTKVxuICogQHJldHVybnMgT2JqZWN0IHdpdGggcG9ydCBudW1iZXIgYW5kIGhlbGQgc2VydmVyLCBvciB0aHJvd3MgaWYgYWxsIGF0dGVtcHRzIGZhaWxcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZpbmRBdmFpbGFibGVQb3J0KFxuICBzdGFydFBvcnQ6IG51bWJlcixcbiAgbWF4QXR0ZW1wdHM6IG51bWJlciA9IE51bWJlcihwcm9jZXNzLmVudi5ET0xMSE9VU0VfTUFYX1BPUlRfQVRURU1QVFMpIHx8IERFRkFVTFRfTUFYX1BPUlRfQVRURU1QVFMsXG4pOiBQcm9taXNlPG51bWJlcj4ge1xuICBmb3IgKGxldCBhdHRlbXB0ID0gMDsgYXR0ZW1wdCA8IG1heEF0dGVtcHRzOyBhdHRlbXB0KyspIHtcbiAgICBjb25zdCBwb3J0ID0gc3RhcnRQb3J0ICsgYXR0ZW1wdDtcbiAgICBsb2dnZXIuZGVidWcoYFtQb3J0RGlzY292ZXJ5XSBUcnlpbmcgcG9ydCAke3BvcnR9IChhdHRlbXB0ICR7YXR0ZW1wdCArIDF9LyR7bWF4QXR0ZW1wdHN9KWApO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdHJ5QmluZFBvcnQocG9ydCk7XG4gICAgaWYgKHJlc3VsdCkge1xuICAgICAgLy8gQ2xvc2UgdGhlIHByb2JlIHNlcnZlciDigJQgdGhlcmUncyBhIGJyaWVmIFRPQ1RPVSB3aW5kb3cgaGVyZSBiZXR3ZWVuXG4gICAgICAvLyBjbG9zaW5nIGFuZCB0aGUgY2FsbGVyIGJpbmRpbmcsIGJ1dCBpdCdzIG5lZ2xpZ2libGUgb24gbG9jYWxob3N0LlxuICAgICAgLy8gQSBmdXR1cmUgaW1wcm92ZW1lbnQgY291bGQgcmV0dXJuIHRoZSBzZXJ2ZXIgZm9yIHRoZSBjYWxsZXIgdG8gYWRvcHQuXG4gICAgICByZXN1bHQuc2VydmVyLmNsb3NlKCk7XG4gICAgICBpZiAoYXR0ZW1wdCA+IDApIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oYFtQb3J0RGlzY292ZXJ5XSBQb3J0ICR7c3RhcnRQb3J0fSBpbiB1c2UsIHVzaW5nICR7cG9ydH0gKGFmdGVyICR7YXR0ZW1wdH0gc2tpcCR7YXR0ZW1wdCA+IDEgPyAncycgOiAnJ30pYCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcG9ydDtcbiAgICB9XG4gICAgbG9nZ2VyLmRlYnVnKGBbUG9ydERpc2NvdmVyeV0gUG9ydCAke3BvcnR9IGluIHVzZSwgdHJ5aW5nIG5leHRgKTtcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgTm8gYXZhaWxhYmxlIHBvcnQgZm91bmQgaW4gcmFuZ2UgJHtzdGFydFBvcnR9LSR7c3RhcnRQb3J0ICsgbWF4QXR0ZW1wdHMgLSAxfSBgICtcbiAgICBgYWZ0ZXIgJHttYXhBdHRlbXB0c30gYXR0ZW1wdHMuIFNldCBET0xMSE9VU0VfTUFYX1BPUlRfQVRURU1QVFMgdG8gaW5jcmVhc2UgdGhlIHJhbmdlLmBcbiAgKTtcbn1cblxuLyoqXG4gKiBXcml0ZSB0aGUgYWN0aXZlIHNlcnZlciBwb3J0IHRvIGEgZGlzY292ZXJhYmxlIGZpbGUuXG4gKlxuICogQ3JlYXRlcyB0d28gZmlsZXM6XG4gKiAtIFBJRC1rZXllZCBmaWxlIGZvciBwZXItcHJvY2VzcyBjbGVhbnVwXG4gKiAtIExhdGVzdCBmaWxlIGZvciBjb252ZW5pZW5jZSAoc2NyaXB0cyBjYW4gcmVhZCB0aGlzIHdpdGhvdXQga25vd2luZyB0aGUgUElEKVxuICpcbiAqIEBwYXJhbSBwb3J0IC0gVGhlIHBvcnQgdGhlIHdlYiBzZXJ2ZXIgaXMgbGlzdGVuaW5nIG9uXG4gKiBAcmV0dXJucyBQYXRoIHRvIHRoZSBQSUQta2V5ZWQgcG9ydCBmaWxlXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZVBvcnRGaWxlKHBvcnQ6IG51bWJlcik6IFByb21pc2U8c3RyaW5nPiB7XG4gIGF3YWl0IG1rZGlyKFJVTl9ESVIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICBjb25zdCBwaWRGaWxlID0gam9pbihSVU5fRElSLCBgcGVybWlzc2lvbi1zZXJ2ZXItJHtwcm9jZXNzLnBpZH0ucG9ydGApO1xuICBjb25zdCBsYXRlc3RGaWxlID0gam9pbihSVU5fRElSLCAncGVybWlzc2lvbi1zZXJ2ZXIucG9ydCcpO1xuICBhd2FpdCB3cml0ZUZpbGUocGlkRmlsZSwgU3RyaW5nKHBvcnQpLCAndXRmLTgnKTtcbiAgYXdhaXQgd3JpdGVGaWxlKGxhdGVzdEZpbGUsIFN0cmluZyhwb3J0KSwgJ3V0Zi04Jyk7XG4gIHBvcnRGaWxlUGF0aCA9IHBpZEZpbGU7XG4gIGxvZ2dlci5kZWJ1ZyhgW1BvcnREaXNjb3ZlcnldIFBvcnQgZmlsZSB3cml0dGVuOiAke3BpZEZpbGV9YCk7XG4gIHJldHVybiBwaWRGaWxlO1xufVxuXG4vKipcbiAqIENsZWFuIHVwIHBvcnQgZmlsZSBvbiBzaHV0ZG93bi5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFudXBQb3J0RmlsZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKHBvcnRGaWxlUGF0aCkge1xuICAgIHRyeSB7IGF3YWl0IHVubGluayhwb3J0RmlsZVBhdGgpOyB9IGNhdGNoIHsgLyogYWxyZWFkeSBnb25lICovIH1cbiAgfVxufVxuXG4vKipcbiAqIFJlZ2lzdGVyIHByb2Nlc3MgZXhpdCBoYW5kbGVycyB0byBjbGVhbiB1cCBwb3J0IGZpbGVzLlxuICogU2hvdWxkIGJlIGNhbGxlZCBvbmNlIGFmdGVyIHRoZSB3ZWIgc2VydmVyIHN1Y2Nlc3NmdWxseSBzdGFydHMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlclBvcnRDbGVhbnVwKCk6IHZvaWQge1xuICBjb25zdCBleGl0Q2xlYW51cCA9ICgpID0+IHsgY2xlYW51cFBvcnRGaWxlKCkuY2F0Y2goKCkgPT4ge30pOyB9O1xuICBwcm9jZXNzLm9uY2UoJ2V4aXQnLCBleGl0Q2xlYW51cCk7XG4gIHByb2Nlc3Mub25jZSgnU0lHVEVSTScsIGV4aXRDbGVhbnVwKTtcbiAgcHJvY2Vzcy5vbmNlKCdTSUdJTlQnLCBleGl0Q2xlYW51cCk7XG59XG5cbi8qKlxuICogRGlzY292ZXIgYW4gYXZhaWxhYmxlIHBvcnQsIHdyaXRlIGRpc2NvdmVyeSBmaWxlcywgYW5kIHJlZ2lzdGVyIGNsZWFudXAuXG4gKlxuICogVGhpcyBpcyB0aGUgcmVjb21tZW5kZWQgZW50cnkgcG9pbnQgZm9yIENvbnRhaW5lciBzdGFydHVwLiBDb21iaW5lc1xuICogcG9ydCBkaXNjb3ZlcnksIGZpbGUgd3JpdGluZywgYW5kIGNsZWFudXAgcmVnaXN0cmF0aW9uIGluIG9uZSBjYWxsLlxuICpcbiAqIEBwYXJhbSBkZWZhdWx0UG9ydCAtIFBvcnQgdG8gdHJ5IGZpcnN0IChkZWZhdWx0OiAzOTM5KVxuICogQHJldHVybnMgVGhlIHBvcnQgdGhlIHNlcnZlciBzaG91bGQgYmluZCB0bywgb3IgdW5kZWZpbmVkIGlmIGRpc2NvdmVyeSBmYWlsZWRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRpc2NvdmVyQW5kQmluZFBvcnQoZGVmYXVsdFBvcnQ6IG51bWJlciA9IDM5MzkpOiBQcm9taXNlPG51bWJlciB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHBvcnQgPSBhd2FpdCBmaW5kQXZhaWxhYmxlUG9ydChkZWZhdWx0UG9ydCk7XG5cbiAgICBhd2FpdCB3cml0ZVBvcnRGaWxlKHBvcnQpO1xuICAgIHJlZ2lzdGVyUG9ydENsZWFudXAoKTtcblxuICAgIHJldHVybiBwb3J0O1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2dnZXIud2FybignW1BvcnREaXNjb3ZlcnldIFBvcnQgZGlzY292ZXJ5IGZhaWxlZDonLCBlcnIpO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==
145
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9ydERpc2NvdmVyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93ZWIvcG9ydERpc2NvdmVyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFFSCxPQUFPLEVBQUUsWUFBWSxFQUFlLE1BQU0sVUFBVSxDQUFDO0FBQ3JELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDbEMsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNqQyxPQUFPLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUM1RCxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDdkMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRTVDLHFEQUFxRDtBQUNyRCxNQUFNLHlCQUF5QixHQUFHLEVBQUUsQ0FBQztBQUVyQyxvRUFBb0U7QUFDcEUsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFFLFlBQVksRUFBRSxLQUFLLENBQUMsQ0FBQztBQUVyRCx1Q0FBdUM7QUFDdkMsSUFBSSxZQUFZLEdBQWtCLElBQUksQ0FBQztBQUV2Qzs7OztHQUlHO0FBQ0gsU0FBUyxXQUFXLENBQUMsSUFBWTtJQUMvQixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7UUFDN0IsTUFBTSxNQUFNLEdBQUcsWUFBWSxFQUFFLENBQUM7UUFDOUIsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUEwQixFQUFFLEVBQUU7WUFDbEQsSUFBSSxHQUFHLENBQUMsSUFBSSxLQUFLLFlBQVksRUFBRSxDQUFDO2dCQUM5QixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDaEIsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FB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QUFZLENBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxNQUFNLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBQ2xFLENBQUM7QUFDSCxDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLG1CQUFtQjtJQUNqQyxNQUFNLFdBQVcsR0FBRyxHQUFHLEVBQUUsR0FBRyxlQUFlLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDakUsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDbEMsT0FBTyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDckMsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsV0FBVyxDQUFDLENBQUM7QUFDdEMsQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxtQkFBbUIsQ0FDdkMsY0FBc0IsR0FBRyxDQUFDLDBCQUEwQjtJQUVwRCxJQUFJLENBQUM7UUFDSCxNQUFNLElBQUksR0FBRyxNQUFNLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRWxELE1BQU0sYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzFCLG1CQUFtQixFQUFFLENBQUM7UUFFdEIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0NBQXdDLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDM0QsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIER5bmFtaWMgcG9ydCBhbGxvY2F0aW9uIGFuZCBwb3J0IGZpbGUgZGlzY292ZXJ5IGZvciB0aGUgd2ViIGNvbnNvbGUuXG4gKlxuICogV2hlbiBtdWx0aXBsZSBEb2xsaG91c2VNQ1Agc2Vzc2lvbnMgcnVuIHNpbXVsdGFuZW91c2x5IChlLmcuLCBtdWx0aXBsZVxuICogQ2xhdWRlIENvZGUgd2luZG93cywgSURFIGluc3RhbmNlcywgb3IgYWdlbnQgc2Vzc2lvbnMpLCBlYWNoIG5lZWRzIGl0c1xuICogb3duIHdlYiBjb25zb2xlIHBvcnQuIFRoaXMgbW9kdWxlIGhhbmRsZXM6XG4gKlxuICogMS4gRmluZGluZyBhbiBhdmFpbGFibGUgcG9ydCBzdGFydGluZyBmcm9tIHRoZSBjb25maWd1cmVkIGRlZmF1bHRcbiAqICAgIChzZWUgYERPTExIT1VTRV9XRUJfQ09OU09MRV9QT1JUYCBpbiBgc3JjL2NvbmZpZy9lbnYudHNgKVxuICogMi4gV3JpdGluZyBwb3J0IGRpc2NvdmVyeSBmaWxlcyBzbyBleHRlcm5hbCB0b29scyBrbm93IHdoaWNoIHBvcnQgdG8gdXNlXG4gKiAzLiBDbGVhbmluZyB1cCBwb3J0IGZpbGVzIG9uIHByb2Nlc3MgZXhpdFxuICpcbiAqIFBvcnQgZmlsZXMgYXJlIHdyaXR0ZW4gdG8gfi8uZG9sbGhvdXNlL3J1bi86XG4gKiAtIHBlcm1pc3Npb24tc2VydmVyLXtwaWR9LnBvcnQg4oCUIHBlci1wcm9jZXNzIGZpbGUgKGNsZWFuZWQgb24gZXhpdClcbiAqIC0gcGVybWlzc2lvbi1zZXJ2ZXIucG9ydCDigJQgbGF0ZXN0IHBvcnQgKGNvbnZlbmllbmNlIGZvciBzY3JpcHRzKVxuICovXG5cbmltcG9ydCB7IGNyZWF0ZVNlcnZlciwgdHlwZSBTZXJ2ZXIgfSBmcm9tICdub2RlOm5ldCc7XG5pbXBvcnQgeyBob21lZGlyIH0gZnJvbSAnbm9kZTpvcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7IG1rZGlyLCB3cml0ZUZpbGUsIHVubGluayB9IGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnO1xuaW1wb3J0IHsgZW52IH0gZnJvbSAnLi4vY29uZmlnL2Vudi5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuXG4vKiogRGVmYXVsdCBtYXhpbXVtIHBvcnQgYXR0ZW1wdHMgYmVmb3JlIGdpdmluZyB1cCAqL1xuY29uc3QgREVGQVVMVF9NQVhfUE9SVF9BVFRFTVBUUyA9IDEwO1xuXG4vKiogRGlyZWN0b3J5IGZvciBydW50aW1lIHN0YXRlIGZpbGVzIChwb3J0IGRpc2NvdmVyeSwgUElEIGZpbGVzKSAqL1xuY29uc3QgUlVOX0RJUiA9IGpvaW4oaG9tZWRpcigpLCAnLmRvbGxob3VzZScsICdydW4nKTtcblxuLyoqIFRyYWNrIHBvcnQgZmlsZSBwYXRoIGZvciBjbGVhbnVwICovXG5sZXQgcG9ydEZpbGVQYXRoOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuLyoqXG4gKiBBdHRlbXB0IHRvIGJpbmQgdG8gYSBzaW5nbGUgcG9ydC4gUmV0dXJucyB0aGUgcG9ydCBpZiBzdWNjZXNzZnVsLCBudWxsIGlmIGluIHVzZS5cbiAqIEtlZXBzIHRoZSBzZXJ2ZXIgbGlzdGVuaW5nIHRvIHByZXZlbnQgVE9DVE9VIHJhY2UgY29uZGl0aW9ucyDigJQgY2FsbGVyIG11c3RcbiAqIGNsb3NlIHRoZSByZXR1cm5lZCBzZXJ2ZXIgYWZ0ZXIgdGhlaXIgb3duIHNlcnZlciBiaW5kcy5cbiAqL1xuZnVuY3Rpb24gdHJ5QmluZFBvcnQocG9ydDogbnVtYmVyKTogUHJvbWlzZTx7IHBvcnQ6IG51bWJlcjsgc2VydmVyOiBTZXJ2ZXIgfSB8IG51bGw+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgY29uc3Qgc2VydmVyID0gY3JlYXRlU2VydmVyKCk7XG4gICAgc2VydmVyLm9uY2UoJ2Vycm9yJywgKGVycjogTm9kZUpTLkVycm5vRXhjZXB0aW9uKSA9PiB7XG4gICAgICBpZiAoZXJyLmNvZGUgPT09ICdFQUREUklOVVNFJykge1xuICAgICAgICByZXNvbHZlKG51bGwpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzb2x2ZShudWxsKTtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKGBbUG9ydERpc2NvdmVyeV0gVW5leHBlY3RlZCBlcnJvciBvbiBwb3J0ICR7cG9ydH06ICR7ZXJyLmNvZGV9YCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgc2VydmVyLm9uY2UoJ2xpc3RlbmluZycsICgpID0+IHtcbiAgICAgIHJlc29sdmUoeyBwb3J0LCBzZXJ2ZXIgfSk7XG4gICAgfSk7XG4gICAgc2VydmVyLmxpc3Rlbihwb3J0LCAnMTI3LjAuMC4xJyk7XG4gIH0pO1xufVxuXG4vKipcbiAqIEZpbmQgYW4gYXZhaWxhYmxlIHBvcnQgc3RhcnRpbmcgZnJvbSB0aGUgZ2l2ZW4gcG9ydC5cbiAqXG4gKiBUcmllcyBzZXF1ZW50aWFsIHBvcnRzLCBsb2dnaW5nIGVhY2ggYXR0ZW1wdC4gUmV0dXJucyBib3RoIHRoZSBwb3J0IG51bWJlclxuICogYW5kIGEgaGVsZCBzZXJ2ZXIgdG8gcHJldmVudCBUT0NUT1UgcmFjZSBjb25kaXRpb25zLiBUaGUgY2FsbGVyIHNob3VsZFxuICogY2xvc2UgdGhlIGhlbGQgc2VydmVyIGFmdGVyIGJpbmRpbmcgdGhlaXIgb3duIEV4cHJlc3MgYXBwIHRvIHRoZSBwb3J0LlxuICpcbiAqIEBwYXJhbSBzdGFydFBvcnQgLSBQb3J0IHRvIHRyeSBmaXJzdCAoc2VlIGBET0xMSE9VU0VfV0VCX0NPTlNPTEVfUE9SVGAgZm9yIHRoZSBkZWZhdWx0KVxuICogQHBhcmFtIG1heEF0dGVtcHRzIC0gTWF4aW11bSBwb3J0cyB0byB0cnkgKGRlZmF1bHQ6IDEwLCBjb25maWd1cmFibGUgdmlhIERPTExIT1VTRV9NQVhfUE9SVF9BVFRFTVBUUylcbiAqIEByZXR1cm5zIE9iamVjdCB3aXRoIHBvcnQgbnVtYmVyIGFuZCBoZWxkIHNlcnZlciwgb3IgdGhyb3dzIGlmIGFsbCBhdHRlbXB0cyBmYWlsXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmaW5kQXZhaWxhYmxlUG9ydChcbiAgc3RhcnRQb3J0OiBudW1iZXIsXG4gIG1heEF0dGVtcHRzOiBudW1iZXIgPSBOdW1iZXIocHJvY2Vzcy5lbnYuRE9MTEhPVVNFX01BWF9QT1JUX0FUVEVNUFRTKSB8fCBERUZBVUxUX01BWF9QT1JUX0FUVEVNUFRTLFxuKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgZm9yIChsZXQgYXR0ZW1wdCA9IDA7IGF0dGVtcHQgPCBtYXhBdHRlbXB0czsgYXR0ZW1wdCsrKSB7XG4gICAgY29uc3QgcG9ydCA9IHN0YXJ0UG9ydCArIGF0dGVtcHQ7XG4gICAgbG9nZ2VyLmRlYnVnKGBbUG9ydERpc2NvdmVyeV0gVHJ5aW5nIHBvcnQgJHtwb3J0fSAoYXR0ZW1wdCAke2F0dGVtcHQgKyAxfS8ke21heEF0dGVtcHRzfSlgKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRyeUJpbmRQb3J0KHBvcnQpO1xuICAgIGlmIChyZXN1bHQpIHtcbiAgICAgIC8vIENsb3NlIHRoZSBwcm9iZSBzZXJ2ZXIg4oCUIHRoZXJlJ3MgYSBicmllZiBUT0NUT1Ugd2luZG93IGhlcmUgYmV0d2VlblxuICAgICAgLy8gY2xvc2luZyBhbmQgdGhlIGNhbGxlciBiaW5kaW5nLCBidXQgaXQncyBuZWdsaWdpYmxlIG9uIGxvY2FsaG9zdC5cbiAgICAgIC8vIEEgZnV0dXJlIGltcHJvdmVtZW50IGNvdWxkIHJldHVybiB0aGUgc2VydmVyIGZvciB0aGUgY2FsbGVyIHRvIGFkb3B0LlxuICAgICAgcmVzdWx0LnNlcnZlci5jbG9zZSgpO1xuICAgICAgaWYgKGF0dGVtcHQgPiAwKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKGBbUG9ydERpc2NvdmVyeV0gUG9ydCAke3N0YXJ0UG9ydH0gaW4gdXNlLCB1c2luZyAke3BvcnR9IChhZnRlciAke2F0dGVtcHR9IHNraXAke2F0dGVtcHQgPiAxID8gJ3MnIDogJyd9KWApO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHBvcnQ7XG4gICAgfVxuICAgIGxvZ2dlci5kZWJ1ZyhgW1BvcnREaXNjb3ZlcnldIFBvcnQgJHtwb3J0fSBpbiB1c2UsIHRyeWluZyBuZXh0YCk7XG4gIH1cblxuICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgYE5vIGF2YWlsYWJsZSBwb3J0IGZvdW5kIGluIHJhbmdlICR7c3RhcnRQb3J0fS0ke3N0YXJ0UG9ydCArIG1heEF0dGVtcHRzIC0gMX0gYCArXG4gICAgYGFmdGVyICR7bWF4QXR0ZW1wdHN9IGF0dGVtcHRzLiBTZXQgRE9MTEhPVVNFX01BWF9QT1JUX0FUVEVNUFRTIHRvIGluY3JlYXNlIHRoZSByYW5nZS5gXG4gICk7XG59XG5cbi8qKlxuICogV3JpdGUgdGhlIGFjdGl2ZSBzZXJ2ZXIgcG9ydCB0byBhIGRpc2NvdmVyYWJsZSBmaWxlLlxuICpcbiAqIENyZWF0ZXMgdHdvIGZpbGVzOlxuICogLSBQSUQta2V5ZWQgZmlsZSBmb3IgcGVyLXByb2Nlc3MgY2xlYW51cFxuICogLSBMYXRlc3QgZmlsZSBmb3IgY29udmVuaWVuY2UgKHNjcmlwdHMgY2FuIHJlYWQgdGhpcyB3aXRob3V0IGtub3dpbmcgdGhlIFBJRClcbiAqXG4gKiBAcGFyYW0gcG9ydCAtIFRoZSBwb3J0IHRoZSB3ZWIgc2VydmVyIGlzIGxpc3RlbmluZyBvblxuICogQHJldHVybnMgUGF0aCB0byB0aGUgUElELWtleWVkIHBvcnQgZmlsZVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd3JpdGVQb3J0RmlsZShwb3J0OiBudW1iZXIpOiBQcm9taXNlPHN0cmluZz4ge1xuICBhd2FpdCBta2RpcihSVU5fRElSLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgY29uc3QgcGlkRmlsZSA9IGpvaW4oUlVOX0RJUiwgYHBlcm1pc3Npb24tc2VydmVyLSR7cHJvY2Vzcy5waWR9LnBvcnRgKTtcbiAgY29uc3QgbGF0ZXN0RmlsZSA9IGpvaW4oUlVOX0RJUiwgJ3Blcm1pc3Npb24tc2VydmVyLnBvcnQnKTtcbiAgYXdhaXQgd3JpdGVGaWxlKHBpZEZpbGUsIFN0cmluZyhwb3J0KSwgJ3V0Zi04Jyk7XG4gIGF3YWl0IHdyaXRlRmlsZShsYXRlc3RGaWxlLCBTdHJpbmcocG9ydCksICd1dGYtOCcpO1xuICBwb3J0RmlsZVBhdGggPSBwaWRGaWxlO1xuICBsb2dnZXIuZGVidWcoYFtQb3J0RGlzY292ZXJ5XSBQb3J0IGZpbGUgd3JpdHRlbjogJHtwaWRGaWxlfWApO1xuICByZXR1cm4gcGlkRmlsZTtcbn1cblxuLyoqXG4gKiBDbGVhbiB1cCBwb3J0IGZpbGUgb24gc2h1dGRvd24uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhbnVwUG9ydEZpbGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmIChwb3J0RmlsZVBhdGgpIHtcbiAgICB0cnkgeyBhd2FpdCB1bmxpbmsocG9ydEZpbGVQYXRoKTsgfSBjYXRjaCB7IC8qIGFscmVhZHkgZ29uZSAqLyB9XG4gIH1cbn1cblxuLyoqXG4gKiBSZWdpc3RlciBwcm9jZXNzIGV4aXQgaGFuZGxlcnMgdG8gY2xlYW4gdXAgcG9ydCBmaWxlcy5cbiAqIFNob3VsZCBiZSBjYWxsZWQgb25jZSBhZnRlciB0aGUgd2ViIHNlcnZlciBzdWNjZXNzZnVsbHkgc3RhcnRzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0ZXJQb3J0Q2xlYW51cCgpOiB2b2lkIHtcbiAgY29uc3QgZXhpdENsZWFudXAgPSAoKSA9PiB7IGNsZWFudXBQb3J0RmlsZSgpLmNhdGNoKCgpID0+IHt9KTsgfTtcbiAgcHJvY2Vzcy5vbmNlKCdleGl0JywgZXhpdENsZWFudXApO1xuICBwcm9jZXNzLm9uY2UoJ1NJR1RFUk0nLCBleGl0Q2xlYW51cCk7XG4gIHByb2Nlc3Mub25jZSgnU0lHSU5UJywgZXhpdENsZWFudXApO1xufVxuXG4vKipcbiAqIERpc2NvdmVyIGFuIGF2YWlsYWJsZSBwb3J0LCB3cml0ZSBkaXNjb3ZlcnkgZmlsZXMsIGFuZCByZWdpc3RlciBjbGVhbnVwLlxuICpcbiAqIFRoaXMgaXMgdGhlIHJlY29tbWVuZGVkIGVudHJ5IHBvaW50IGZvciBDb250YWluZXIgc3RhcnR1cC4gQ29tYmluZXNcbiAqIHBvcnQgZGlzY292ZXJ5LCBmaWxlIHdyaXRpbmcsIGFuZCBjbGVhbnVwIHJlZ2lzdHJhdGlvbiBpbiBvbmUgY2FsbC5cbiAqXG4gKiBAcGFyYW0gZGVmYXVsdFBvcnQgLSBQb3J0IHRvIHRyeSBmaXJzdCAoc2VlIGBET0xMSE9VU0VfV0VCX0NPTlNPTEVfUE9SVGAgZm9yIHRoZSBkZWZhdWx0KVxuICogQHJldHVybnMgVGhlIHBvcnQgdGhlIHNlcnZlciBzaG91bGQgYmluZCB0bywgb3IgdW5kZWZpbmVkIGlmIGRpc2NvdmVyeSBmYWlsZWRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRpc2NvdmVyQW5kQmluZFBvcnQoXG4gIGRlZmF1bHRQb3J0OiBudW1iZXIgPSBlbnYuRE9MTEhPVVNFX1dFQl9DT05TT0xFX1BPUlQsXG4pOiBQcm9taXNlPG51bWJlciB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHBvcnQgPSBhd2FpdCBmaW5kQXZhaWxhYmxlUG9ydChkZWZhdWx0UG9ydCk7XG5cbiAgICBhd2FpdCB3cml0ZVBvcnRGaWxlKHBvcnQpO1xuICAgIHJlZ2lzdGVyUG9ydENsZWFudXAoKTtcblxuICAgIHJldHVybiBwb3J0O1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2dnZXIud2FybignW1BvcnREaXNjb3ZlcnldIFBvcnQgZGlzY292ZXJ5IGZhaWxlZDonLCBlcnIpO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==
@@ -96,7 +96,7 @@ function safeParseYaml(content) {
96
96
  showGridMessage('loading', 'Loading portfolio…');
97
97
 
98
98
  // Load portfolio from local API
99
- const portfolioRes = await fetch('/api/elements');
99
+ const portfolioRes = await DollhouseAuth.apiFetch('/api/elements');
100
100
  if (!portfolioRes.ok) throw new Error(`HTTP ${portfolioRes.status} fetching portfolio`);
101
101
  const portfolioData = await portfolioRes.json();
102
102
 
@@ -116,7 +116,7 @@ function safeParseYaml(content) {
116
116
  applyFilters();
117
117
 
118
118
  // Load community collection (non-blocking — portfolio shows immediately)
119
- fetch('/api/collection')
119
+ DollhouseAuth.apiFetch('/api/collection')
120
120
  .then(r => r.ok ? r.json() : Promise.reject('not available'))
121
121
  .then(mergeCollectionData)
122
122
  .catch(() => { /* collection not available — portfolio-only mode */ });
@@ -537,7 +537,7 @@ function safeParseYaml(content) {
537
537
  if (el._content) {
538
538
  content = el._content;
539
539
  } else if (el._local) {
540
- const res = await fetch(`/api/elements/${el.path}`);
540
+ const res = await DollhouseAuth.apiFetch(`/api/elements/${el.path}`);
541
541
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
542
542
  content = await res.text();
543
543
  } else {
@@ -630,7 +630,7 @@ function safeParseYaml(content) {
630
630
  btn.textContent = '⏳ Installing…';
631
631
  btn.disabled = true;
632
632
  try {
633
- const res = await fetch('/api/install', {
633
+ const res = await DollhouseAuth.apiFetch('/api/install', {
634
634
  method: 'POST',
635
635
  headers: { 'Content-Type': 'application/json' },
636
636
  body: JSON.stringify({ path: element.path, name: element.name, type: element.type }),
@@ -726,13 +726,13 @@ function safeParseYaml(content) {
726
726
  if (element._content) {
727
727
  content = element._content;
728
728
  } else if (element._local) {
729
- const res = await fetch(`/api/elements/${element.path}`);
729
+ const res = await DollhouseAuth.apiFetch(`/api/elements/${element.path}`);
730
730
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
731
731
  const data = await res.json();
732
732
  structured = data;
733
733
  content = data.raw;
734
734
  } else {
735
- const res = await fetch(`/api/collection/content/${element.path}`);
735
+ const res = await DollhouseAuth.apiFetch(`/api/collection/content/${element.path}`);
736
736
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
737
737
  const data = await res.json();
738
738
  structured = data;
@@ -1931,7 +1931,7 @@ function safeParseYaml(content) {
1931
1931
 
1932
1932
  // ── Tab switching ─────────────────────────────────────────────────────────
1933
1933
  const consoleTabs = document.getElementById('console-tabs');
1934
- const tabInits = { logs: false, metrics: false, permissions: false };
1934
+ const tabInits = { logs: false, metrics: false, permissions: false, security: false };
1935
1935
 
1936
1936
  const TAB_KEY = 'dollhousemcp-active-tab';
1937
1937
  const SETUP_SEEN_KEY = 'dollhousemcp-setup-seen';
@@ -2069,6 +2069,7 @@ function safeParseYaml(content) {
2069
2069
  const savedTab = localStorage.getItem(TAB_KEY);
2070
2070
  if (savedTab) {
2071
2071
  switchToTab(savedTab);
2072
+ lazyInitTab(savedTab, tabInits);
2072
2073
  } else if (!localStorage.getItem(SETUP_SEEN_KEY)) {
2073
2074
  localStorage.setItem(SETUP_SEEN_KEY, '1');
2074
2075
  switchToTab('setup');
@@ -2094,20 +2095,36 @@ function safeParseYaml(content) {
2094
2095
 
2095
2096
  function lazyInitTab(tab, tabInits, params) {
2096
2097
  const dc = globalThis.DollhouseConsole;
2097
- if (tab === 'logs' && dc?.logs) {
2098
- if (!tabInits.logs) { tabInits.logs = true; dc.logs.init(params); }
2099
- else if (dc.logs.refresh) { dc.logs.refresh(); }
2100
- }
2101
- if (tab === 'metrics' && dc?.metrics) {
2102
- if (!tabInits.metrics) { tabInits.metrics = true; dc.metrics.init(params); }
2103
- else if (dc.metrics.refresh) { dc.metrics.refresh(); }
2104
- }
2105
- if (tab === 'permissions' && dc?.permissions) {
2106
- if (!tabInits.permissions) { tabInits.permissions = true; dc.permissions.init(params); }
2107
- else if (dc.permissions.refresh) { dc.permissions.refresh(); }
2098
+ const module = dc?.[tab];
2099
+ if (!module) return;
2100
+ if (!tabInits[tab]) {
2101
+ tabInits[tab] = true;
2102
+ module.init(params);
2103
+ } else if (module.refresh) {
2104
+ module.refresh();
2108
2105
  }
2109
2106
  }
2110
2107
 
2108
+ // 401 recovery (#1792): when the cached token becomes stale (rotation,
2109
+ // restart, file deletion), consoleAuth.js fires this event. Show a
2110
+ // persistent, idempotent reload banner so the user knows why the UI
2111
+ // stopped updating.
2112
+ globalThis.addEventListener('dollhouse:session-expired', function () {
2113
+ if (document.getElementById('session-expired-toast')) return;
2114
+ const toast = document.createElement('div');
2115
+ toast.id = 'session-expired-toast';
2116
+ toast.setAttribute('role', 'alert');
2117
+ toast.style.cssText = 'position:fixed;bottom:24px;left:50%;transform:translateX(-50%);'
2118
+ + 'background:#b91c1c;color:#fff;padding:12px 24px;border-radius:8px;'
2119
+ + 'font-size:14px;z-index:99999;display:flex;align-items:center;gap:12px;'
2120
+ + 'box-shadow:0 4px 12px rgba(0,0,0,0.3);';
2121
+ toast.innerHTML = 'Console session token changed\u2009\u2014\u2009'
2122
+ + '<button style="background:#fff;color:#b91c1c;border:none;padding:6px 16px;'
2123
+ + 'border-radius:4px;cursor:pointer;font-weight:600;font-size:14px"'
2124
+ + ' onclick="location.reload()">Reload</button>';
2125
+ document.body.appendChild(toast);
2126
+ });
2127
+
2111
2128
  init();
2112
2129
  });
2113
2130