-
Notifications
You must be signed in to change notification settings - Fork 149
π Secure API Key Storage, Throttling, and API Usage Tracking #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -41,39 +41,111 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(() => loadingIndicator.remove(), 2000); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Translate paragraph by paragraph | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Translate paragraph by paragraph with batch processing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function translateParagraphs() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Create progress indicator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const progressIndicator = document.createElement('div'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.id = 'translationProgressIndicator'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.position = 'fixed'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.bottom = '20px'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.right = '20px'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.padding = '10px 15px'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.backgroundColor = '#1a73e8'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.color = 'white'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.borderRadius = '20px'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.zIndex = '9999'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.boxShadow = '0 2px 10px rgba(0,0,0,0.2)'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.display = 'flex'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.alignItems = 'center'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.justifyContent = 'center'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.fontFamily = 'Arial, sans-serif'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.transition = 'opacity 0.3s'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Add progress bar | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const progressText = document.createElement('div'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressText.textContent = 'Processing: 0%'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.appendChild(progressText); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.body.appendChild(progressIndicator); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Collect paragraphs to translate | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const paragraphs = document.querySelectorAll('p, h1, h2, h3, h4, h5, h6, li, span, div'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let translatedCount = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const elementsToTranslate = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 0; i < paragraphs.length; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const element = paragraphs[i]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (element.textContent.trim() && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.childNodes.length === 1 && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.childNodes[0].nodeType === Node.TEXT_NODE && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !element.classList.contains('hinglish-translated')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elementsToTranslate.push(element); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Listen for progress updates | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (request.action === 'updateProgress' && request.progress >= 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressText.textContent = `Processing: ${request.progress}%`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (request.action === 'updateProgress' && request.progress === -1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Hide progress indicator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.opacity = '0'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(() => progressIndicator.remove(), 300); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Process in batches of 5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const batchSize = 5; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let translatedCount = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 0; i < elementsToTranslate.length; i += batchSize) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const batch = elementsToTranslate.slice(i, i + batchSize); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const promises = batch.map(element => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new Promise(async (resolve) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const response = await chrome.runtime.sendMessage({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| action: "translateText", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| text: element.textContent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (response && !response.startsWith("Translation error:")) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.textContent = response; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.classList.add('hinglish-translated'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| translatedCount++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('Translation error:', error); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resolve(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+104
to
+120
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion Refactor away from Using an -const promises = batch.map(element => {
- return new Promise(async (resolve) => {
- try {
- const response = await chrome.runtime.sendMessage({ β¦ });
- β¦
- } catch (e) {
- console.error(e);
- }
- resolve();
- });
-});
+const promises = batch.map(async element => {
+ try {
+ const response = await chrome.runtime.sendMessage({ β¦ });
+ β¦
+ } catch (e) {
+ console.error(e);
+ }
+});This removes the Biome warning and preserves error propagation. π Committable suggestion
Suggested change
π§° Toolsπͺ Biome (1.9.4)[error] 104-120: Promise executor functions should not be (lint/suspicious/noAsyncPromiseExecutor) π€ Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const originalText = element.textContent; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await Promise.all(promises); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const response = await chrome.runtime.sendMessage({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| action: "translateText", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| text: originalText | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (response && response !== "Please configure your API key first") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.textContent = response; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.classList.add('hinglish-translated'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| translatedCount++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('Translation error:', error); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Update progress | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const progress = Math.min(100, Math.round((i + batchSize) * 100 / elementsToTranslate.length)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressText.textContent = `Processing: ${progress}%`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Complete | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressText.textContent = 'Translation Complete!'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.backgroundColor = '#0b8043'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.opacity = '0'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(() => progressIndicator.remove(), 300); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, 2000); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return translatedCount; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('Batch translation error:', error); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressText.textContent = 'Translation Failed'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.backgroundColor = '#d93025'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| progressIndicator.style.opacity = '0'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(() => progressIndicator.remove(), 300); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, 2000); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return translatedCount; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Translate all text nodes (more aggressive approach) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid stacking message listeners β move this outside the function
chrome.runtime.onMessage.addListeneris created every timetranslateParagraphs()runs. After a few page-level translations you will have N identical listeners, all firing for each progress message.Extract the listener to module scope or register it once and remove it when
progress === -1.π€ Prompt for AI Agents