Fix rate limits, concurrency control, copy button

- DATA-BACKED RATE LIMITS:
  * Reduce global rate limit from 10,000/min to 100/min
  * Add PDF conversion rate limits: 10/min free, 30/min pro
  * Set recovery rate limit to 3/hour (was 5/hour)
  * Add concurrency limiter: max 3 simultaneous PDFs, queue rest
  * Return 429 if queue > 10

- BUG-025: Fix copy button functionality
  * Improve fallback handling for execCommand
  * Add better error handling and user feedback
  * Fix secure context detection

- Add concurrency monitoring endpoint /v1/concurrency
This commit is contained in:
OpenClaw Agent 2026-02-15 08:04:56 +00:00
parent 922230c108
commit 73917551bd
9 changed files with 339 additions and 17 deletions

View file

@ -239,17 +239,56 @@ function doCopy(text, btn) {
btn.textContent = '\u2713 Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 2000);
}
function showFailed() {
btn.textContent = 'Failed';
setTimeout(function() { btn.textContent = 'Copy'; }, 2000);
}
try {
navigator.clipboard.writeText(text).then(showCopied).catch(function() {
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(text).then(showCopied).catch(function() {
// Fallback to execCommand
try {
var ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed';
ta.style.opacity = '0';
ta.style.top = '-9999px';
ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.focus();
ta.select();
var success = document.execCommand('copy');
document.body.removeChild(ta);
if (success) {
showCopied();
} else {
showFailed();
}
} catch (err) {
showFailed();
}
});
} else {
// Direct fallback for non-secure contexts
var ta = document.createElement('textarea');
ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0';
document.body.appendChild(ta); ta.select();
document.execCommand('copy');
ta.value = text;
ta.style.position = 'fixed';
ta.style.opacity = '0';
ta.style.top = '-9999px';
ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.focus();
ta.select();
var success = document.execCommand('copy');
document.body.removeChild(ta);
showCopied();
});
if (success) {
showCopied();
} else {
showFailed();
}
}
} catch(e) {
showCopied();
showFailed();
}
}