@dollhousemcp/mcp-server 2.0.13 → 2.0.14

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 (35) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/di/Container.d.ts.map +1 -1
  3. package/dist/di/Container.js +19 -9
  4. package/dist/elements/BaseElement.js +2 -2
  5. package/dist/elements/memories/Memory.d.ts.map +1 -1
  6. package/dist/elements/memories/Memory.js +3 -3
  7. package/dist/elements/skills/Skill.d.ts.map +1 -1
  8. package/dist/elements/skills/Skill.js +4 -4
  9. package/dist/elements/templates/Template.d.ts.map +1 -1
  10. package/dist/elements/templates/Template.js +4 -4
  11. package/dist/generated/version.d.ts +2 -2
  12. package/dist/generated/version.js +3 -3
  13. package/dist/handlers/ElementCRUDHandler.d.ts +10 -0
  14. package/dist/handlers/ElementCRUDHandler.d.ts.map +1 -1
  15. package/dist/handlers/ElementCRUDHandler.js +123 -1
  16. package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts +1 -0
  17. package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts.map +1 -1
  18. package/dist/handlers/mcp-aql/MCPAQLHandler.js +31 -2
  19. package/dist/services/ActivationStore.d.ts +20 -0
  20. package/dist/services/ActivationStore.d.ts.map +1 -1
  21. package/dist/services/ActivationStore.js +104 -1
  22. package/dist/web/console/IngestRoutes.d.ts +1 -0
  23. package/dist/web/console/IngestRoutes.d.ts.map +1 -1
  24. package/dist/web/console/IngestRoutes.js +4 -1
  25. package/dist/web/console/UnifiedConsole.js +2 -1
  26. package/dist/web/public/permissions.css +224 -16
  27. package/dist/web/public/permissions.js +326 -63
  28. package/dist/web/public/sessions.js +218 -98
  29. package/dist/web/public/styles.css +15 -10
  30. package/dist/web/routes/permissionRoutes.d.ts.map +1 -1
  31. package/dist/web/routes/permissionRoutes.js +57 -19
  32. package/dist/web/server.d.ts.map +1 -1
  33. package/dist/web/server.js +2 -1
  34. package/package.json +1 -1
  35. package/server.json +2 -2
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Shows a labeled "N sessions" box in the header. Clicking opens a
5
5
  * dropdown with selectable sessions. Selecting a session filters
6
- * logs and metrics to that session only.
6
+ * logs and refreshes any session-aware dashboard tabs.
7
7
  *
8
8
  * @security-audit-suppress DMCP-SEC-004 Client-side JS — all session data is
9
9
  * pre-normalized server-side via UnicodeValidator. Browser String.normalize('NFC')
@@ -24,6 +24,7 @@
24
24
  var SESSION_FILTER_INJECTION_RETRY_INTERVAL = getConfiguredNumber('sessionFilterInjectionRetryIntervalMs', 500);
25
25
  var SESSION_FILTER_INJECTION_MAX_RETRIES = getConfiguredNumber('sessionFilterInjectionMaxRetries', 20);
26
26
  var sessions = [];
27
+ var policySessions = [];
27
28
  var filterSessionId = '';
28
29
  var dropdownBuilt = false;
29
30
  var lastSessionKey = ''; // tracks session list identity to avoid unnecessary rebuilds
@@ -47,6 +48,10 @@
47
48
  /** NFC-normalize a string safely */
48
49
  function nfc(s) { try { return s.normalize('NFC'); } catch(e) { return s; } }
49
50
 
51
+ function isPolicyOnlySession(session) {
52
+ return !!(session && session.isPolicyOnly);
53
+ }
54
+
50
55
  function displayName(session) {
51
56
  if (typeof session === 'object' && session.displayName) return nfc(session.displayName);
52
57
  var id = typeof session === 'string' ? nfc(session) : nfc((session && session.sessionId) || '');
@@ -54,9 +59,72 @@
54
59
  return parts.length >= 2 ? parts[1] : id.slice(0, 8);
55
60
  }
56
61
 
62
+ function getLiveSessions() {
63
+ return sessions.filter(function(s) { return s.status === 'active'; });
64
+ }
65
+
66
+ function getSelectableSessions() {
67
+ var live = getLiveSessions();
68
+ var liveIds = new Set(live.map(function(s) { return s.sessionId; }));
69
+ var merged = live.slice();
70
+ for (var i = 0; i < policySessions.length; i++) {
71
+ if (!liveIds.has(policySessions[i].sessionId)) merged.push(policySessions[i]);
72
+ }
73
+ return merged;
74
+ }
75
+
76
+ function getActiveTabName() {
77
+ var activeTab = document.querySelector('.console-tab.active');
78
+ return activeTab ? activeTab.dataset.tab || '' : '';
79
+ }
80
+
81
+ function normalizePolicySessions(list) {
82
+ if (!Array.isArray(list)) return [];
83
+
84
+ var seen = new Set();
85
+ var normalized = [];
86
+ for (var i = 0; i < list.length; i++) {
87
+ var item = list[i];
88
+ if (!item || typeof item.sessionId !== 'string') continue;
89
+ var sessionId = nfc(item.sessionId).trim();
90
+ if (!sessionId || seen.has(sessionId)) continue;
91
+ seen.add(sessionId);
92
+ normalized.push({
93
+ sessionId: sessionId,
94
+ displayName: nfc(typeof item.displayName === 'string' && item.displayName ? item.displayName : sessionId),
95
+ color: '#94a3b8',
96
+ pid: 0,
97
+ startedAt: '',
98
+ lastHeartbeat: '',
99
+ status: 'policy',
100
+ isLeader: false,
101
+ authenticated: false,
102
+ kind: 'policy',
103
+ isPolicyOnly: true,
104
+ });
105
+ }
106
+
107
+ normalized.sort(function(a, b) { return a.sessionId.localeCompare(b.sessionId); });
108
+ return normalized;
109
+ }
110
+
111
+ function setPolicySessions(nextSessions) {
112
+ policySessions = normalizePolicySessions(nextSessions);
113
+ updateSessionIndicator();
114
+ updateSessionFilterOptions();
115
+ }
116
+
117
+ function allSessionsSummary(liveCount, policyCount) {
118
+ if (policyCount <= 0) return liveCount + ' total';
119
+ if (liveCount <= 0) return policyCount + ' saved';
120
+ return liveCount + ' live, ' + policyCount + ' saved';
121
+ }
122
+
57
123
  // Build a key from current sessions to detect changes
58
124
  function sessionListKey(list) {
59
- return list.map(function(s) { return s.sessionId + ':' + s.status; }).join(',');
125
+ return list.map(function(s) {
126
+ return s.sessionId + ':' + s.status + ':' + (isPolicyOnlySession(s) ? 'policy' : 'live');
127
+ }).join(',');
60
128
  }
61
129
 
62
130
  // Apply session filter and update all UI to reflect it
@@ -67,8 +135,21 @@
67
135
  var logSelect = document.getElementById('log-session-filter');
68
136
  if (logSelect) logSelect.value = sessionId;
69
137
 
70
- // Trigger log re-filter with the selected session
71
- if (window.DollhouseConsole && window.DollhouseConsole.logs && window.DollhouseConsole.logs.refilter) {
138
+ if (window.DollhouseConsole && window.DollhouseConsole.permissions) {
139
+ if (window.DollhouseConsole.permissions.onSessionChange) {
140
+ window.DollhouseConsole.permissions.onSessionChange(sessionId);
141
+ } else if (window.DollhouseConsole.permissions.refresh) {
142
+ window.DollhouseConsole.permissions.refresh();
143
+ }
144
+ }
145
+
146
+ // Trigger log re-filter only when the Logs tab is active. Refiltering the
147
+ // virtualized log buffer can be expensive, and it should not delay session
148
+ // switching on other tabs like Permissions.
149
+ if (getActiveTabName() === 'logs'
150
+ && window.DollhouseConsole
151
+ && window.DollhouseConsole.logs
152
+ && window.DollhouseConsole.logs.refilter) {
72
153
  window.DollhouseConsole.logs.refilter(sessionId);
73
154
  }
74
155
 
@@ -117,7 +198,7 @@
117
198
  // Tick uptimes
118
199
  var uptimes = document.querySelectorAll('.session-dropdown-uptime');
119
200
  for (var j = 0; j < uptimes.length; j++) {
120
- uptimes[j].textContent = formatUptime(uptimes[j].dataset.startedAt);
201
+ uptimes[j].textContent = uptimes[j].dataset.startedAt ? formatUptime(uptimes[j].dataset.startedAt) : 'saved';
121
202
  }
122
203
 
123
204
  // Update box label
@@ -125,7 +206,18 @@
125
206
  var labelEl = document.querySelector('.session-box-label');
126
207
  if (!countEl || !labelEl) return;
127
208
 
128
- var active = sessions.filter(function(s) { return s.status === 'active'; });
209
+ var active = getLiveSessions();
210
+ var selectable = getSelectableSessions();
211
+
212
+ if (filterSessionId) {
213
+ var filtered = selectable.find(function(s) { return s.sessionId === filterSessionId; });
214
+ if (filtered) {
215
+ countEl.textContent = displayName(filtered);
216
+ if (filtered.color) countEl.style.color = filtered.color;
217
+ labelEl.textContent = isPolicyOnlySession(filtered) ? 'policy only' : ('1/' + active.length);
218
+ return;
219
+ }
220
+ }
129
221
 
130
222
  if (active.length === 1) {
131
223
  countEl.textContent = displayName(active[0]);
@@ -136,24 +228,16 @@
136
228
 
137
229
  // Reset color when showing count
138
230
  countEl.style.color = '';
139
-
140
- if (filterSessionId) {
141
- var filtered = active.find(function(s) { return s.sessionId === filterSessionId; });
142
- if (filtered) {
143
- countEl.textContent = displayName(filtered);
144
- if (filtered.color) countEl.style.color = filtered.color;
145
- labelEl.textContent = '1/' + active.length;
146
- return;
147
- }
148
- }
149
231
  countEl.textContent = String(active.length);
150
232
  labelEl.textContent = active.length === 1 ? 'session' : 'sessions';
151
233
  }
152
234
 
153
235
  // Build or rebuild the session indicator — only when session list actually changes
154
236
  function updateSessionIndicator() {
155
- var active = sessions.filter(function(s) { return s.status === 'active'; });
156
- var key = sessionListKey(active);
237
+ var active = getLiveSessions();
238
+ var selectable = getSelectableSessions();
239
+ var policyOnly = selectable.filter(function(s) { return isPolicyOnlySession(s); });
240
+ var key = sessionListKey(selectable);
157
241
 
158
242
  // If sessions haven't changed, just refresh selection state
159
243
  if (key === lastSessionKey && dropdownBuilt) {
@@ -209,7 +293,7 @@
209
293
 
210
294
  var allCount = document.createElement('span');
211
295
  allCount.className = 'session-dropdown-role';
212
- allCount.textContent = count + ' total';
296
+ allCount.textContent = allSessionsSummary(count, policyOnly.length);
213
297
  allItem.appendChild(allCount);
214
298
 
215
299
  allItem.addEventListener('click', function(e) {
@@ -218,10 +302,18 @@
218
302
  });
219
303
  dropdown.appendChild(allItem);
220
304
 
221
- // Divider
222
- var divider = document.createElement('div');
223
- divider.className = 'session-dropdown-divider';
224
- dropdown.appendChild(divider);
305
+ function appendDivider() {
306
+ var divider = document.createElement('div');
307
+ divider.className = 'session-dropdown-divider';
308
+ dropdown.appendChild(divider);
309
+ }
310
+
311
+ function appendHeading(text) {
312
+ var heading = document.createElement('div');
313
+ heading.className = 'session-dropdown-heading';
314
+ heading.textContent = text;
315
+ dropdown.appendChild(heading);
316
+ }
225
317
 
226
318
  // Session items — leader first, then followers
227
319
  var sorted = active.slice().sort(function(a, b) {
@@ -230,70 +322,78 @@
230
322
  return 0;
231
323
  });
232
324
 
233
- for (var i = 0; i < sorted.length; i++) {
234
- (function(s) {
235
- var item = document.createElement('div');
236
- item.className = 'session-dropdown-item';
237
- item.dataset.sessionId = s.sessionId;
238
- item.setAttribute('role', 'option');
239
-
240
- var check = document.createElement('span');
241
- check.className = 'session-dropdown-check';
242
- item.appendChild(check);
243
-
244
- var dot = document.createElement('span');
245
- dot.className = 'session-dot';
246
- if (s.color) dot.style.background = s.color;
247
- item.appendChild(dot);
248
-
249
- var nameEl = document.createElement('span');
250
- nameEl.className = 'session-dropdown-name';
251
- nameEl.textContent = displayName(s);
252
- if (s.color) nameEl.style.color = s.color;
253
- item.appendChild(nameEl);
254
-
255
- // Session status badges (#1805) two independent dimensions:
256
- // 1. Auth status (filled/empty circle + text)
257
- // 2. Client attachment (checkmark/X + text)
258
- // Shape + text + colorblind-safe color (blue/orange) = three
259
- // independent channels so no single channel carries meaning alone.
260
- var authBadge = document.createElement('span');
261
- authBadge.className = 'session-status-badge';
262
- if (s.authenticated) {
263
- authBadge.textContent = '\u25CF Auth';
264
- authBadge.dataset.status = 'positive';
265
- authBadge.title = 'Authenticated session';
266
- } else {
267
- authBadge.textContent = '\u25CB No auth';
268
- authBadge.dataset.status = 'negative';
269
- authBadge.title = 'Unauthenticated session';
270
- }
271
- item.appendChild(authBadge);
272
-
273
- var clientBadge = document.createElement('span');
274
- clientBadge.className = 'session-status-badge';
275
- if (s.kind === 'mcp') {
276
- clientBadge.textContent = '\u2713 Client';
277
- clientBadge.dataset.status = 'positive';
278
- clientBadge.title = 'MCP client attached';
279
- } else {
280
- clientBadge.textContent = '\u2717 No client';
281
- clientBadge.dataset.status = 'negative';
282
- clientBadge.title = 'No MCP client attached';
283
- }
284
- item.appendChild(clientBadge);
285
-
286
- var uptimeEl = document.createElement('span');
287
- uptimeEl.className = 'session-dropdown-uptime';
288
- uptimeEl.dataset.startedAt = s.startedAt;
289
- uptimeEl.textContent = formatUptime(s.startedAt);
290
- item.appendChild(uptimeEl);
291
-
292
- var killBtn = document.createElement('button');
293
- killBtn.className = 'session-kill-btn';
294
- killBtn.type = 'button';
325
+ function appendSessionItem(s) {
326
+ var item = document.createElement('div');
327
+ item.className = 'session-dropdown-item';
328
+ item.dataset.sessionId = s.sessionId;
329
+ item.setAttribute('role', 'option');
330
+
331
+ var check = document.createElement('span');
332
+ check.className = 'session-dropdown-check';
333
+ item.appendChild(check);
334
+
335
+ var dot = document.createElement('span');
336
+ dot.className = 'session-dot';
337
+ if (s.color) dot.style.background = s.color;
338
+ item.appendChild(dot);
339
+
340
+ var nameEl = document.createElement('span');
341
+ nameEl.className = 'session-dropdown-name';
342
+ nameEl.textContent = displayName(s);
343
+ if (s.color) nameEl.style.color = s.color;
344
+ item.appendChild(nameEl);
345
+
346
+ // Session status badges (#1805) — for persisted policy sessions we
347
+ // switch from "live/authenticated" semantics to "saved/no client".
348
+ var authBadge = document.createElement('span');
349
+ authBadge.className = 'session-status-badge';
350
+ if (isPolicyOnlySession(s)) {
351
+ authBadge.textContent = 'Saved';
352
+ authBadge.dataset.status = 'positive';
353
+ authBadge.title = 'Persisted policy state from a prior session';
354
+ } else if (s.authenticated) {
355
+ authBadge.textContent = '\u25CF Auth';
356
+ authBadge.dataset.status = 'positive';
357
+ authBadge.title = 'Authenticated session';
358
+ } else {
359
+ authBadge.textContent = '\u25CB No auth';
360
+ authBadge.dataset.status = 'negative';
361
+ authBadge.title = 'Unauthenticated session';
362
+ }
363
+ item.appendChild(authBadge);
364
+
365
+ var clientBadge = document.createElement('span');
366
+ clientBadge.className = 'session-status-badge';
367
+ if (isPolicyOnlySession(s)) {
368
+ clientBadge.textContent = 'No client';
369
+ clientBadge.dataset.status = 'negative';
370
+ clientBadge.title = 'No live MCP client is currently attached';
371
+ } else if (s.kind === 'mcp') {
372
+ clientBadge.textContent = '\u2713 Client';
373
+ clientBadge.dataset.status = 'positive';
374
+ clientBadge.title = 'MCP client attached';
375
+ } else {
376
+ clientBadge.textContent = '\u2717 No client';
377
+ clientBadge.dataset.status = 'negative';
378
+ clientBadge.title = 'No MCP client attached';
379
+ }
380
+ item.appendChild(clientBadge);
381
+
382
+ var uptimeEl = document.createElement('span');
383
+ uptimeEl.className = 'session-dropdown-uptime';
384
+ uptimeEl.dataset.startedAt = s.startedAt;
385
+ uptimeEl.textContent = isPolicyOnlySession(s) ? 'saved' : formatUptime(s.startedAt);
386
+ item.appendChild(uptimeEl);
387
+
388
+ var killBtn = document.createElement('button');
389
+ killBtn.className = 'session-kill-btn';
390
+ killBtn.type = 'button';
391
+ killBtn.textContent = '\u00D7';
392
+ if (isPolicyOnlySession(s)) {
393
+ killBtn.disabled = true;
394
+ killBtn.style.visibility = 'hidden';
395
+ } else {
295
396
  killBtn.title = 'Stop ' + displayName(s);
296
- killBtn.textContent = '\u00D7';
297
397
  killBtn.addEventListener('click', function(e) {
298
398
  e.stopPropagation();
299
399
  if (!confirm('Stop session ' + displayName(s) + '?')) return;
@@ -317,15 +417,31 @@
317
417
  alert('Failed to stop session ' + displayName(s) + ': ' + (err.message || 'network error'));
318
418
  });
319
419
  });
320
- item.appendChild(killBtn);
420
+ }
421
+ item.appendChild(killBtn);
321
422
 
322
- item.addEventListener('click', function(e) {
323
- e.stopPropagation();
324
- applyFilter(filterSessionId === s.sessionId ? '' : s.sessionId);
325
- });
423
+ item.addEventListener('click', function(e) {
424
+ e.stopPropagation();
425
+ applyFilter(filterSessionId === s.sessionId ? '' : s.sessionId);
426
+ });
326
427
 
327
- dropdown.appendChild(item);
328
- })(sorted[i]);
428
+ dropdown.appendChild(item);
429
+ }
430
+
431
+ if (sorted.length > 0) {
432
+ appendDivider();
433
+ appendHeading('Live Sessions');
434
+ for (var i = 0; i < sorted.length; i++) {
435
+ appendSessionItem(sorted[i]);
436
+ }
437
+ }
438
+
439
+ if (policyOnly.length > 0) {
440
+ appendDivider();
441
+ appendHeading('Persisted Policy State (Debug Info)');
442
+ for (var j = 0; j < policyOnly.length; j++) {
443
+ appendSessionItem(policyOnly[j]);
444
+ }
329
445
  }
330
446
 
331
447
  var wrapper = document.createElement('div');
@@ -391,14 +507,16 @@
391
507
  if (!select) return;
392
508
 
393
509
  var current = select.value;
394
- var active = sessions.filter(function(s) { return s.status === 'active'; });
510
+ var selectable = getSelectableSessions();
395
511
 
396
512
  select.innerHTML = '<option value="">All Sessions</option>';
397
- for (var i = 0; i < active.length; i++) {
513
+ for (var i = 0; i < selectable.length; i++) {
398
514
  var opt = document.createElement('option');
399
- opt.value = active[i].sessionId;
400
- opt.textContent = displayName(active[i]) + (active[i].isLeader ? ' (leader)' : '');
401
- if (active[i].sessionId === current) opt.selected = true;
515
+ opt.value = selectable[i].sessionId;
516
+ opt.textContent = displayName(selectable[i])
517
+ + (selectable[i].isLeader ? ' (leader)' : '')
518
+ + (isPolicyOnlySession(selectable[i]) ? ' (policy only)' : '');
519
+ if (selectable[i].sessionId === current) opt.selected = true;
402
520
  select.appendChild(opt);
403
521
  }
404
522
  }
@@ -432,6 +550,8 @@
432
550
  getFilterSessionId: function() { return filterSessionId; },
433
551
  displayName: displayName,
434
552
  getSessions: function() { return sessions; },
553
+ getSelectableSessions: getSelectableSessions,
554
+ setPolicySessions: setPolicySessions,
435
555
  };
436
556
 
437
557
  function init() {
@@ -69,6 +69,8 @@ html { scroll-behavior: smooth; }
69
69
  body {
70
70
  margin: 0;
71
71
  min-height: 100vh;
72
+ display: flex;
73
+ flex-direction: column;
72
74
  color-scheme: light;
73
75
  color: var(--ink-900);
74
76
  background:
@@ -249,6 +251,7 @@ p, li { max-width: 69ch; }
249
251
  .site-main {
250
252
  width: min(var(--max-width), calc(100% - 2 * var(--gutter)));
251
253
  margin: 0 auto;
254
+ flex: 1 0 auto;
252
255
  padding: clamp(1.1rem, 3vw, 2rem) 0 3rem;
253
256
  }
254
257
 
@@ -949,7 +952,7 @@ dialog.modal {
949
952
  display: flex;
950
953
  align-items: flex-start;
951
954
  justify-content: center;
952
- padding: 1rem var(--gutter) 0;
955
+ padding: 1rem var(--gutter) calc(var(--site-footer-height, 4.5rem) + 0.5rem);
953
956
  width: 100%;
954
957
  }
955
958
  dialog.modal::backdrop { display: none; }
@@ -969,14 +972,12 @@ body.modal-open { overflow: hidden; }
969
972
  position: relative;
970
973
  width: min(72rem, 100%);
971
974
  margin: 0 auto;
972
- /* Fixed height = viewport minus top padding; content scrolls inside.
973
- This keeps the header and toolbar at a stable screen position
974
- regardless of content length or raw/rendered toggle. */
975
- height: calc(100vh - 1rem);
976
- border-radius: var(--radius-lg) var(--radius-lg) 0 0;
975
+ /* Keep the dialog fully inside the viewport and above the fixed footer. */
976
+ height: calc(100dvh - var(--site-footer-height, 4.5rem) - 1.5rem);
977
+ max-height: calc(100dvh - var(--site-footer-height, 4.5rem) - 1.5rem);
978
+ border-radius: var(--radius-lg);
977
979
  background: var(--paper-strong);
978
980
  border: 1px solid var(--line);
979
- border-bottom: none;
980
981
  box-shadow: var(--shadow-card);
981
982
  overflow: hidden;
982
983
  display: flex;
@@ -1375,10 +1376,14 @@ body.modal-open { overflow: hidden; }
1375
1376
  .site-footer {
1376
1377
  border-top: 1px solid var(--line);
1377
1378
  padding: 0.85rem 0 1.35rem;
1378
- position: sticky;
1379
+ margin-top: 0;
1380
+ position: fixed;
1381
+ left: 0;
1382
+ right: 0;
1379
1383
  bottom: 0;
1380
- background: var(--paper);
1381
- z-index: 10;
1384
+ background: color-mix(in srgb, var(--paper) 92%, transparent);
1385
+ backdrop-filter: blur(10px);
1386
+ z-index: 40;
1382
1387
  }
1383
1388
 
1384
1389
  .footer-inner {
@@ -1 +1 @@
1
- {"version":3,"file":"permissionRoutes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/permissionRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAgB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAkD7E;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAuGrF"}
1
+ {"version":3,"file":"permissionRoutes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/permissionRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAgB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AA4F7E;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAoHrF"}