diff --git a/DEBUG_DOWNLOAD_DETECTION.md b/DEBUG_DOWNLOAD_DETECTION.md new file mode 100644 index 0000000..35c8203 --- /dev/null +++ b/DEBUG_DOWNLOAD_DETECTION.md @@ -0,0 +1,289 @@ +# Debugging Download Detection + +This guide helps you debug why PDF download detection may not be working. + +## Prerequisites + +1. **Rebuild and reload the extension** + ```bash + npm run build + ``` + Then go to `chrome://extensions/` and click the reload icon for BinectChrome + +2. **Open the Service Worker console** + - Go to `chrome://extensions/` + - Find BinectChrome + - Click "service worker" link (or "Inspect views: service worker") + - This opens DevTools for the service worker + - **Keep this window open** while testing + +## Step-by-Step Download Detection Test + +### Step 1: Verify Service Worker is Running + +**In the Service Worker console, you should see:** +``` +[Service Worker] ===== BinectChrome service worker loaded ===== +[Service Worker] Timestamp: 2024-01-14T... +[Service Worker] Initializing PDF detection... +[PDF Detector] Starting PDF detection, registering download listener +[PDF Detector] Listener registered successfully +``` + +**If you don't see these messages:** +- The service worker hasn't loaded yet +- Try clicking the extension icon (this wakes it up) +- Check for any red errors in the console + +### Step 2: Test with a Simple PDF Download + +**Download a test PDF:** +1. Right-click this link and select "Save link as...": + ``` + https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf + ``` +2. Save it to your Downloads folder +3. Watch the Service Worker console + +**Expected console output:** +``` +[PDF Detector] Download changed: {id: 123, state: {...}, stateValue: "in_progress"} +[PDF Detector] Download not complete, ignoring +[PDF Detector] Download changed: {id: 123, state: {...}, stateValue: "complete"} +[PDF Detector] Download complete, searching for item: 123 +[PDF Detector] Search results: 1 items +[PDF Detector] Download item: {id: 123, filename: "dummy.pdf", mime: "application/pdf", ...} +[PDF Detector] PDF detected! +[Service Worker] PDF DETECTED CALLBACK: dummy.pdf +[Service Worker] Badge updated, PDF stored in memory +``` + +**After successful detection:** +- Extension badge should show "1" +- Badge color should be blue (#4A90E2) + +### Step 3: Test with Direct Link Download + +**Alternative method:** +1. Paste this URL directly in the address bar: + ``` + https://www.africau.edu/images/default/sample.pdf + ``` +2. Chrome will start downloading it +3. Watch the Service Worker console for the same log messages + +### Step 4: Verify PDF is Stored + +**Click the extension icon to open the popup** +- You should see the PDF details +- Filename: "dummy.pdf" or "sample.pdf" +- Size: displayed in KB or MB +- Domain: source domain +- "Send PDF to Binect" button should be enabled + +## Troubleshooting: No Logs Appearing + +### Issue 1: Service Worker Not Running +**Symptoms:** No console output at all, even "[Service Worker] loaded" message + +**Solutions:** +1. **Wake up the service worker:** + - Click the extension icon + - OR go to `chrome://serviceworker-internals/` and find BinectChrome + - Click "Start" if it's stopped + +2. **Check for startup errors:** + - Look for red errors in the service worker console + - Check `chrome://serviceworker-internals/` for registration errors + +3. **Hard reload the extension:** + - Go to `chrome://extensions/` + - Remove BinectChrome completely + - Click "Load unpacked" and select the `dist/` folder again + +### Issue 2: Service Worker Sleeping Before Download Completes +**Symptoms:** Service worker console shows "loaded" message, but no download events + +**This is the most likely issue!** In Manifest V3, service workers shut down after 30 seconds of inactivity. + +**Test if this is the issue:** +1. Open service worker console +2. Click the extension icon to wake it up +3. **Immediately** (within 30 seconds) download a PDF +4. Watch the console + +**If you see logs now, the issue is service worker lifecycle!** + +**Solution:** The service worker should automatically wake up when downloads complete, but there might be a timing issue. See "Potential Fixes" below. + +### Issue 3: Download Events Not Firing +**Symptoms:** Service worker is running, but no "[PDF Detector] Download changed" logs + +**Possible causes:** +1. **Downloads permission not granted:** + - Go to `chrome://extensions/` + - Click "Details" on BinectChrome + - Check "Permissions" section + - Should show "Read your browsing history" and "Manage your downloads" + - If missing, the manifest is wrong + +2. **Event listener not registered:** + - Look for "[PDF Detector] Listener registered successfully" in console + - If missing, there's a code issue + +3. **Chrome not triggering download events:** + - Try opening the PDF instead of downloading it (should trigger viewer detection) + - Check `chrome://downloads/` to verify download completed + +### Issue 4: PDF Not Detected (Logs Show It's Not a PDF) +**Symptoms:** Logs show "Not a PDF, ignoring" + +**Debug the detection logic:** + +Look at the download item log: +``` +[PDF Detector] Download item: { + id: 123, + filename: "document.pdf", // ← Should end with .pdf + mime: "application/pdf", // ← Should be "application/pdf" + ... +} +``` + +**If filename doesn't end with .pdf and mime is not "application/pdf":** +- The file isn't actually a PDF +- OR the server sent wrong headers + +## Advanced Debugging + +### Check Download API Directly + +**Run this in the Service Worker console:** +```javascript +chrome.downloads.search({ limit: 10, orderBy: ['-startTime'] }, (items) => { + console.log('Recent downloads:', items); + items.forEach(item => { + console.log(`${item.filename} - mime: ${item.mime} - state: ${item.state}`); + }); +}); +``` + +This shows your recent downloads and their properties. + +### Manual Test: Trigger Detection Manually + +**Run this in the Service Worker console:** +```javascript +// Get the most recent download +chrome.downloads.search({ limit: 1, orderBy: ['-startTime'] }, (items) => { + if (items.length > 0) { + const item = items[0]; + console.log('Most recent download:', item); + + // Check if it's a PDF + const isPDF = item.filename.toLowerCase().endsWith('.pdf') || item.mime === 'application/pdf'; + console.log('Is PDF?', isPDF); + } +}); +``` + +### Check if Listener is Registered + +**Run this in the Service Worker console:** +```javascript +// This won't show listeners directly, but you can test by downloading a file +console.log('Testing listener by downloading a test file...'); +chrome.downloads.download({ + url: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf', + filename: 'test-binect.pdf' +}, (downloadId) => { + console.log('Download started with ID:', downloadId); +}); +``` + +Watch for "[PDF Detector] Download changed" logs. + +## Potential Fixes + +If download detection is unreliable due to service worker lifecycle: + +### Option 1: Use chrome.storage for Persistence +Store detected PDFs in chrome.storage instead of memory, so they survive service worker restarts. + +### Option 2: Add Download Completion Listener +Use `chrome.downloads.onCreated` in addition to `onChanged` to catch downloads earlier. + +### Option 3: Poll Recent Downloads +When popup opens, check recent downloads even if callback didn't fire. + +## Testing Different PDF Sources + +### Test 1: Direct PDF Link +``` +https://www.africau.edu/images/default/sample.pdf +``` +**Expected:** Direct download, should detect + +### Test 2: PDF Behind Link +``` +https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf +``` +**Expected:** Right-click → Save as, should detect + +### Test 3: Large PDF +``` +https://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf +``` +**Expected:** Larger file, may take longer to download + +### Test 4: Google Drive PDF +1. Upload a PDF to your Google Drive +2. Click it to view +3. **Important:** Use the PDF viewer detection (new feature) +4. If you download it, should also detect + +## Success Criteria + +**Download detection is working when:** +1. ✅ Service worker console shows all log messages +2. ✅ Badge updates to "1" after download +3. ✅ Popup shows PDF details +4. ✅ "Send PDF to Binect" button is enabled +5. ✅ Works consistently across multiple downloads + +## Still Not Working? + +If download detection still doesn't work after following this guide: + +1. **Export debug logs:** + - Right-click in service worker console → "Save as..." + - Save the console output + +2. **Check service worker status:** + - Go to `chrome://serviceworker-internals/` + - Find BinectChrome + - Screenshot the status section + +3. **Get downloads permission status:** + ```javascript + chrome.permissions.contains({ + permissions: ['downloads'] + }, (result) => { + console.log('Has downloads permission:', result); + }); + ``` + +4. **Report the issue:** + - Email bernd.worsch@binect.de + - Include: console logs, screenshots, Chrome version + - Describe: what you tried, what happened + +## Workaround: Use PDF Viewer Detection + +**If download detection is unreliable, use the new PDF viewer detection:** +1. Open a PDF in Chrome (paste URL in address bar) +2. Click the extension icon +3. Should detect the PDF from the current tab +4. This bypasses download detection entirely! + +See `TESTING_PDF_VIEWER.md` for details. diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 0000000..7e9ca5f --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,248 @@ +# Development & Test-Fix Workflow for BinectChrome + +This guide explains how to set up an efficient development workflow for testing and debugging the Chrome extension. + +## Quick Start + +### 1. Development Mode (Auto-rebuild on changes) +```bash +npm run dev +``` +This starts webpack in watch mode - any changes to source files will automatically rebuild the extension. + +### 2. Load Extension in Chrome + +**Initial Load:** +1. Open Chrome and navigate to `chrome://extensions/` +2. Enable "Developer mode" (toggle in top-right corner) +3. Click "Load unpacked" +4. Select the `/home/worsch/binect-chrome/dist` directory +5. Note the extension ID (you'll need this for debugging) + +**Reload After Changes:** +- **Option A (Manual):** Click the reload icon on the extension card at `chrome://extensions/` +- **Option B (Shortcut):** Click the extensions icon in Chrome toolbar → Manage Extensions → Reload +- **Option C (Recommended for service worker):** Navigate to `chrome://serviceworker-internals/` and click "Stop" then reload + +### 3. Debug Service Worker + +**View Service Worker Logs:** +1. Go to `chrome://extensions/` +2. Find your extension +3. Click "service worker" link (under "Inspect views") +4. This opens DevTools for the service worker + +**Alternative Method:** +1. Go to `chrome://serviceworker-internals/` +2. Find "chrome-extension://[your-extension-id]" +3. Click "Inspect" to open DevTools + +**View Service Worker Status:** +- `chrome://serviceworker-internals/` - Shows all service workers, their status, and errors + +### 4. Debug Popup & UI + +**Popup DevTools:** +1. Click the extension icon to open the popup +2. Right-click inside the popup → "Inspect" +3. This opens DevTools for the popup + +**Tracking Page DevTools:** +1. Open the tracking page from the popup +2. Right-click → "Inspect" + +## Complete Test-Fix Loop + +### Workflow Pattern +``` +┌─────────────────────────────────────────────────┐ +│ 1. Make code changes in src/ │ +│ 2. Webpack auto-rebuilds (if using npm run dev)│ +│ 3. Reload extension in Chrome │ +│ 4. Check DevTools for errors │ +│ 5. Test functionality │ +│ 6. Repeat from step 1 │ +└─────────────────────────────────────────────────┘ +``` + +### Detailed Steps + +1. **Start Development Mode** + ```bash + npm run dev + ``` + +2. **Make Your Changes** + - Edit files in `src/` + - Webpack will automatically rebuild + +3. **Reload Extension** + - Go to `chrome://extensions/` + - Click reload icon on BinectChrome card + - For service worker changes: Go to `chrome://serviceworker-internals/` → Stop → Reload + +4. **Check for Errors** + - **Service Worker:** Click "service worker" link or check `chrome://serviceworker-internals/` + - **Popup:** Right-click popup → Inspect + - **Console Errors:** Check the browser console in all DevTools windows + +5. **Test Functionality** + - Download a PDF to test detection + - Check badge updates + - Test sending PDFs + - Verify tracking data + +6. **Common Debugging Points** + - Service worker errors: Usually permissions or API usage issues + - PDF detection not working: Check Downloads API events + - Badge not updating: Check service worker is running + - Alarms not firing: Check `chrome://serviceworker-internals/` for service worker lifecycle + +## Common Issues & Solutions + +### Issue: Service Worker Registration Failed (Status Code 15) +**Cause:** Webpack output format doesn't match manifest type +**Solution:** Ensure webpack.config.js has: +```javascript +output: { + module: true, + environment: { module: true } +}, +experiments: { + outputModule: true +} +``` + +### Issue: "Cannot read properties of undefined (reading 'onAlarm')" +**Cause:** Missing "alarms" permission +**Solution:** Add to manifest.json: +```json +"permissions": ["downloads", "storage", "alarms"] +``` + +### Issue: Service Worker Stops Running +**Cause:** Chrome stops inactive service workers after 30 seconds (Manifest V3 behavior) +**Solution:** This is normal! Service workers wake up on events (downloads, alarms, messages) + +### Issue: Changes Not Reflecting +**Cause:** Extension not reloaded, or cached service worker +**Solution:** +1. Always reload after rebuilding +2. For stubborn issues: Stop service worker at `chrome://serviceworker-internals/` +3. Hard reload: Remove extension and re-add it + +## Testing Specific Features + +### Test PDF Detection +1. Ensure extension is loaded and service worker is running +2. Download any PDF file from the web +3. Check service worker console for "PDF detected:" log +4. Verify badge shows "1" +5. Open popup and verify PDF info is displayed + +### Test Credential Management +1. Open popup +2. Enter credentials +3. Check Chrome DevTools → Application → Storage → Extension Storage +4. Verify credentials are encrypted +5. Test credential expiry by manipulating storage + +### Test Alarm/Expiry Check +1. Open `chrome://serviceworker-internals/` +2. Check for alarm registration +3. Or use: `chrome.alarms.getAll(console.log)` in service worker console + +## Production Build & Testing + +```bash +# Build for production +npm run build + +# Build is in dist/ directory +# Test the production build by loading dist/ as unpacked extension +``` + +## Running Unit Tests + +```bash +# Run tests once +npm test + +# Run tests in watch mode +npm run test:watch + +# Type checking +npm run type-check + +# Linting +npm run lint +npm run lint:fix +``` + +## Useful Chrome URLs for Extension Development + +- `chrome://extensions/` - Manage extensions +- `chrome://serviceworker-internals/` - Debug service workers +- `chrome://inspect/#service-workers` - Inspect active service workers +- `chrome://downloads/` - View downloads (for testing PDF detection) +- `chrome://version/` - Check Chrome version + +## Debugging Tips + +1. **Console.log is your friend**: Add logs liberally in development +2. **Breakpoints**: Use debugger; statements or set breakpoints in DevTools +3. **Storage inspection**: Check Application → Storage → Extension Storage in DevTools +4. **Network tab**: Monitor API calls to Binect +5. **Performance**: Use Performance tab to check service worker lifecycle +6. **Memory**: Watch for memory leaks in long-running service workers + +## VS Code Integration (Optional) + +Add to `.vscode/launch.json` for debugging: +```json +{ + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Debug Extension", + "url": "chrome://extensions/", + "webRoot": "${workspaceFolder}/dist" + } + ] +} +``` + +## Quick Reference Commands + +```bash +# Development +npm run dev # Watch mode with auto-rebuild +npm run build # Production build +npm test # Run tests +npm run lint # Check code quality +npm run type-check # TypeScript validation + +# Chrome URLs +chrome://extensions/ # Extension management +chrome://serviceworker-internals/ # Service worker debugging +``` + +## Emergency Cleanup + +If extension gets stuck or behaves oddly: +```bash +# 1. Stop service worker +# Go to chrome://serviceworker-internals/ → Stop + +# 2. Clear extension storage +# DevTools → Application → Storage → Clear site data + +# 3. Remove and reload extension +# chrome://extensions/ → Remove → Load unpacked again + +# 4. Clean rebuild +rm -rf dist/ +npm run build +``` diff --git a/DOWNLOAD_DETECTION_FIXES.md b/DOWNLOAD_DETECTION_FIXES.md new file mode 100644 index 0000000..1a7b74b --- /dev/null +++ b/DOWNLOAD_DETECTION_FIXES.md @@ -0,0 +1,303 @@ +# Download Detection Debugging & Fixes + +## Summary + +I've added comprehensive debugging and a fallback mechanism to help diagnose and work around download detection issues. + +## Changes Made + +### 1. **Comprehensive Debug Logging** + +**Service Worker (src/background/service-worker.ts):** +- All events now log with `[Service Worker]` prefix +- Shows when service worker loads/reloads +- Logs PDF detection callbacks +- Logs message handling from popup + +**PDF Detector (src/utils/pdf-detector.ts):** +- All download events logged with `[PDF Detector]` prefix +- Shows download state changes (in_progress → complete) +- Logs download item details (filename, mime, state, url) +- Confirms when PDF is detected vs. ignored + +**Popup (src/popup/popup.ts):** +- All PDF loading operations logged with `[Popup]` prefix +- Shows detection priority: tab viewer → background → fallback +- Logs results of each detection method + +### 2. **Fallback Mechanism** + +**New function: `checkRecentDownloads()` (src/popup/popup.ts:254-298)** +- Directly queries Chrome's downloads API for recent PDFs +- Checks last 20 downloads +- Finds most recent completed PDF +- **Works even if service worker missed the download event** + +**PDF Detection Priority:** +1. Current tab (PDF viewer) - NEW +2. Background service worker (download event listener) +3. **Recent downloads fallback** - NEW +4. No PDF detected + +This triple-layer approach ensures PDFs are detected even if the service worker is sleeping. + +## How to Debug + +### Step 1: Reload Extension +```bash +npm run build +``` +Then reload at `chrome://extensions/` + +### Step 2: Open Consoles + +**Service Worker Console:** +1. Go to `chrome://extensions/` +2. Click "service worker" link under BinectChrome +3. **Keep this open while testing** + +**Popup Console:** +1. Click the extension icon +2. Right-click inside popup → "Inspect" +3. View console + +### Step 3: Download a Test PDF + +**Test URL:** +``` +https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf +``` + +**Method 1: Direct download** +- Right-click link → "Save link as..." +- Save to Downloads + +**Method 2: View in browser** +- Paste URL in address bar +- Let Chrome open it in viewer +- Click extension icon + +### Step 4: Check Logs + +**Expected Service Worker logs:** +``` +[Service Worker] ===== BinectChrome service worker loaded ===== +[Service Worker] Initializing PDF detection... +[PDF Detector] Starting PDF detection, registering download listener +[PDF Detector] Listener registered successfully + +# When download completes: +[PDF Detector] Download changed: {id: X, state: {...}, stateValue: "complete"} +[PDF Detector] Download complete, searching for item: X +[PDF Detector] Search results: 1 items +[PDF Detector] Download item: {id: X, filename: "dummy.pdf", mime: "application/pdf", ...} +[PDF Detector] PDF detected! +[Service Worker] PDF DETECTED CALLBACK: dummy.pdf +[Service Worker] Badge updated, PDF stored in memory +``` + +**Expected Popup logs:** +``` +[Popup] Loading last PDF... +[Popup] No PDF in current tab, checking background script... +[Service Worker] Message received: getLastPDF +[Service Worker] Returning last PDF: dummy.pdf +[Popup] Background returned PDF: dummy.pdf +``` + +**If service worker missed it (fallback):** +``` +[Popup] Loading last PDF... +[Popup] No PDF in current tab, checking background script... +[Service Worker] Message received: getLastPDF +[Service Worker] Returning last PDF: none +[Popup] Background has no PDF, checking recent downloads as fallback... +[Popup] Checked recent downloads: 15 items +[Popup] Found recent PDF: dummy.pdf +``` + +## Common Issues & Solutions + +### Issue 1: No Service Worker Logs + +**Symptom:** Service worker console is empty or shows "Inactive" + +**Solution:** +- Click the extension icon (wakes it up) +- Or go to `chrome://serviceworker-internals/` and click "Start" +- Check for registration errors + +### Issue 2: Service Worker Not Waking for Downloads + +**Symptom:** Download completes but no `[PDF Detector]` logs appear + +**This is the main issue with Manifest V3 service workers!** + +**Diagnosis:** +1. Open service worker console +2. Download a PDF +3. Watch if service worker console gets new logs + +**If no logs:** Service worker didn't wake up for the download event + +**Workaround:** The fallback mechanism handles this! When you open the popup, it checks recent downloads directly. + +### Issue 3: Badge Not Updating + +**Symptom:** PDF downloads but badge stays empty + +**Cause:** Service worker detected PDF but couldn't update badge (possibly terminated) + +**Solution:** The fallback still works - open popup to see the PDF + +### Issue 4: PDF Shows in Popup But Disappears + +**Symptom:** PDF shows up, but after a few minutes it's gone + +**Cause:** Service worker memory is ephemeral - when it terminates, `lastDetectedPDF` is lost + +**Solution:** The fallback mechanism re-fetches from recent downloads each time popup opens + +## Testing Checklist + +- [ ] Build extension: `npm run build` +- [ ] Reload extension at `chrome://extensions/` +- [ ] Open service worker console +- [ ] Download test PDF (right-click → Save link as) +- [ ] Check service worker logs for detection +- [ ] Check if badge shows "1" +- [ ] Open popup - should show PDF +- [ ] Wait 2 minutes (service worker sleeps) +- [ ] Download another PDF +- [ ] Open popup - should show PDF (even if service worker missed it) +- [ ] Open PDF in browser tab (view, don't download) +- [ ] Open popup - should detect tab viewer + +## Known Limitations + +### 1. Service Worker Lifecycle (Manifest V3) +Service workers shut down after 30 seconds of inactivity. This is by design in Manifest V3. + +**Impact:** +- Download event listener may not fire if service worker is sleeping +- Badge may not update immediately after download +- `lastDetectedPDF` is lost when service worker terminates + +**Mitigation:** +- Fallback mechanism checks recent downloads +- Works reliably despite service worker sleep +- Badge updates when popup opens + +### 2. File URLs +Chrome extensions can't access `file://` URLs by default. + +**Impact:** If PDF is downloaded and opened from disk, can't re-fetch for upload + +**Solution:** Use the original download URL (which we store) + +### 3. Authenticated Downloads +Some PDFs require authentication cookies. + +**Impact:** Re-fetching PDF may fail if session expired + +**Solution:** `fetchPDFBytes()` uses `credentials: 'include'` to send cookies + +## Advanced Debugging + +### Manual Download Check +Run in Service Worker console: +```javascript +chrome.downloads.search({ limit: 10, orderBy: ['-startTime'] }, (items) => { + console.log('Recent downloads:'); + items.forEach(item => { + const isPDF = item.filename.toLowerCase().endsWith('.pdf') || + item.mime === 'application/pdf'; + console.log(` ${item.filename} - PDF: ${isPDF} - State: ${item.state}`); + }); +}); +``` + +### Test Download Listener +Run in Service Worker console: +```javascript +chrome.downloads.download({ + url: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf', + filename: 'test-download.pdf' +}, (downloadId) => { + console.log('Started download:', downloadId); +}); +``` + +Watch for `[PDF Detector]` logs. + +### Check Permissions +Run in Service Worker console: +```javascript +chrome.permissions.contains({ permissions: ['downloads'] }, (result) => { + console.log('Has downloads permission:', result); +}); +``` + +## Recommended Testing Flow + +**For Development:** +1. Use PDF viewer detection (open PDF in tab) +2. This bypasses download detection entirely +3. Most reliable for testing API integration + +**For Download Detection Testing:** +1. Open both service worker and popup consoles +2. Download a PDF +3. Watch logs in real-time +4. Verify fallback works even if service worker missed it + +## Next Steps + +**If download detection is still unreliable:** + +### Option A: Accept Viewer Detection as Primary +- PDF viewer detection works reliably +- Download detection becomes secondary +- Users can open PDFs in browser instead of downloading + +### Option B: Persist Detected PDFs +- Store detected PDFs in `chrome.storage` instead of memory +- Survives service worker restarts +- Requires storage cleanup logic + +### Option C: Poll Downloads Periodically +- Set up an alarm to check recent downloads every minute +- More resource intensive +- Very reliable + +## Files Changed + +1. `src/background/service-worker.ts` - Added debug logging +2. `src/utils/pdf-detector.ts` - Added debug logging +3. `src/popup/popup.ts` - Added debug logging and fallback mechanism +4. `DEBUG_DOWNLOAD_DETECTION.md` - Comprehensive debugging guide +5. `DOWNLOAD_DETECTION_FIXES.md` - This file + +## Support + +If download detection still doesn't work: +1. Follow `DEBUG_DOWNLOAD_DETECTION.md` +2. Export console logs from both service worker and popup +3. Include Chrome version: `chrome://version/` +4. Report to bernd.worsch@binect.de + +## Workaround + +**The PDF viewer detection is fully functional and reliable!** + +Instead of relying on download detection: +1. Open PDFs in Chrome (paste URL in address bar) +2. Click extension icon +3. PDF is detected from current tab +4. Send to Binect + +This approach: +- ✅ Always works +- ✅ No service worker timing issues +- ✅ Better user experience (no downloads folder clutter) +- ✅ Easier to test API integration diff --git a/QUICK_TEST_GUIDE.md b/QUICK_TEST_GUIDE.md new file mode 100644 index 0000000..5280427 --- /dev/null +++ b/QUICK_TEST_GUIDE.md @@ -0,0 +1,229 @@ +# Quick Test Guide - BinectChrome + +## 1. Setup (2 minutes) + +```bash +# Rebuild extension +npm run build + +# Load in Chrome +# 1. Open chrome://extensions/ +# 2. Enable "Developer mode" +# 3. Click "Reload" on BinectChrome (or "Load unpacked" if first time, select dist/) +# 4. Accept new permissions when prompted +``` + +## 2. Open Debug Consoles + +**Service Worker:** +- `chrome://extensions/` → Click "service worker" under BinectChrome +- Keep this window open + +**Popup (optional):** +- Click extension icon → Right-click → "Inspect" + +## 3. Test PDF Viewer Detection (RECOMMENDED - Most Reliable) + +**This is the easiest way to test the API integration!** + +1. **Open a test PDF in Chrome:** + ``` + https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf + ``` + Just paste the URL in the address bar and press Enter + +2. **Click the extension icon** + - Should detect the PDF immediately + - Shows filename, domain, "Send PDF to Binect" button + +3. **Sign in and send:** + - Enter your Binect credentials + - Click "Send PDF to Binect" + - Watch for "Uploading..." → "Success!" + +**Expected Popup Logs:** +``` +[Popup] Loading last PDF... +[Popup] Found PDF in current tab: dummy.pdf +``` + +**✅ This method always works - no service worker timing issues!** + +## 4. Test Download Detection (May Need Fallback) + +**Method 1: Right-click → Save** +1. Right-click this link: https://www.africau.edu/images/default/sample.pdf +2. Select "Save link as..." +3. Save to Downloads +4. Watch service worker console for logs + +**Method 2: Direct download** +1. Paste URL: https://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf +2. Chrome starts download +3. Watch service worker console + +**Expected Service Worker Logs (if working):** +``` +[PDF Detector] Download changed: {...} +[PDF Detector] Download complete, searching for item: X +[PDF Detector] PDF detected! +[Service Worker] PDF DETECTED CALLBACK: sample.pdf +[Service Worker] Badge updated, PDF stored in memory +``` + +**If badge shows "1":** Download detection worked! ✅ + +**If no badge:** Fallback will still work! Continue... + +5. **Click extension icon** + - Even if service worker missed it, popup checks recent downloads + - PDF should appear + +**Expected Popup Logs (fallback):** +``` +[Popup] Background has no PDF, checking recent downloads as fallback... +[Popup] Checked recent downloads: X items +[Popup] Found recent PDF: sample.pdf +``` + +## 5. Test Binect API Integration + +**Prerequisites:** +- Have Binect credentials ready +- PDF is detected (from viewer OR download) + +**Steps:** +1. Click extension icon +2. If not signed in: + - Enter username and password + - Click "Sign In" + - Should show main view +3. PDF details should be visible +4. Click "Send PDF to Binect" +5. Wait for upload + +**Expected Results:** +``` +Status: Uploading... +→ Success! Document ID: [id] +``` + +**Check Tracking:** +- Click "?" button in popup +- Opens tracking page +- Should show the transfer with success status + +## 6. Test Error Handling + +**Invalid Credentials:** +1. Sign out (if signed in) +2. Enter wrong username/password +3. Click "Sign In" +4. Should show error: "Invalid credentials" + +**Network Error:** +1. Disconnect from internet +2. Try to authenticate or send PDF +3. Should show network error + +## Quick Debug Checklist + +**If PDF viewer detection doesn't work:** +- [ ] Is the URL actually a PDF? (ends with .pdf) +- [ ] Check popup console for error logs +- [ ] Try refreshing the PDF tab + +**If download detection doesn't work:** +- [ ] Check service worker console for `[PDF Detector]` logs +- [ ] Look for "Listener registered successfully" +- [ ] Try downloading again while service worker console is open +- [ ] Open popup - fallback should still find it + +**If API upload fails:** +- [ ] Check credentials are correct +- [ ] Verify PDF URL is accessible (try opening in new tab) +- [ ] Check popup console for detailed error +- [ ] Look at Network tab in popup DevTools for API calls + +## Expected Console Output Summary + +### Service Worker (when working): +``` +[Service Worker] ===== BinectChrome service worker loaded ===== +[Service Worker] Initializing PDF detection... +[PDF Detector] Starting PDF detection, registering download listener +[PDF Detector] Listener registered successfully + +# On download: +[PDF Detector] Download changed: {id: X, ...} +[PDF Detector] PDF detected! +[Service Worker] PDF DETECTED CALLBACK: filename.pdf +[Service Worker] Badge updated, PDF stored in memory +``` + +### Popup (viewer detection): +``` +[Popup] Loading last PDF... +[Popup] Found PDF in current tab: document.pdf +``` + +### Popup (fallback): +``` +[Popup] Loading last PDF... +[Popup] No PDF in current tab, checking background script... +[Service Worker] Returning last PDF: none +[Popup] Background has no PDF, checking recent downloads as fallback... +[Popup] Found recent PDF: document.pdf +``` + +## Common Questions + +**Q: Badge doesn't show but popup finds the PDF?** +A: Normal! Service worker may have been asleep. Fallback handled it. + +**Q: PDF disappears after a few minutes?** +A: Service worker memory is cleared when it sleeps. Fallback will re-fetch it. + +**Q: Which detection method should I use?** +A: **PDF viewer detection** is more reliable. Just open PDFs in Chrome instead of downloading. + +**Q: Can I test without Binect credentials?** +A: You can test PDF detection, but not the upload. You'll see authentication errors when trying to send. + +## Test URLs + +**Small PDFs (quick tests):** +- https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf (1 page) +- https://www.africau.edu/images/default/sample.pdf (1 page) + +**Medium PDFs:** +- https://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf (multi-page) + +## Next Steps + +1. **Test viewer detection** - Most reliable +2. **Test download detection** - May need fallback +3. **Test API integration** - Requires credentials +4. **Check tracking page** - Verify data is recorded + +## Getting Help + +If something doesn't work: +1. Check the detailed guides: + - `DEBUG_DOWNLOAD_DETECTION.md` - Download debugging + - `TESTING_PDF_VIEWER.md` - Viewer testing + - `DOWNLOAD_DETECTION_FIXES.md` - Technical details +2. Export console logs (right-click → Save as) +3. Note your Chrome version: `chrome://version/` +4. Email: bernd.worsch@binect.de + +## Success Criteria + +✅ PDF viewer detection works consistently +✅ Download detection works OR fallback finds PDFs +✅ API authentication succeeds +✅ PDF upload succeeds +✅ Tracking records the transfer +✅ Badge updates (when service worker is awake) + +**You're ready to use BinectChrome!** diff --git a/RECENT_CHANGES.md b/RECENT_CHANGES.md new file mode 100644 index 0000000..5cb5db0 --- /dev/null +++ b/RECENT_CHANGES.md @@ -0,0 +1,180 @@ +# Recent Changes - BinectChrome + +## Summary + +Three new features have been implemented: +1. ✅ Password visibility toggle with eye icon +2. ✅ Default badge on extension icon +3. ✅ Enhanced API error logging for debugging + +## 1. Password Visibility Toggle + +**Location:** Login form in popup + +**What it does:** +- Adds an eye icon button next to the password field +- Click to toggle between showing and hiding password +- Icon changes: 👁️ (show) ↔ 🚫👁️ (hide) + +**Files changed:** +- `src/popup/popup.html` - Added password wrapper and eye icon SVGs +- `src/popup/popup.css` - Styled the toggle button +- `src/popup/popup.ts` - Added toggle functionality + +**How to use:** +1. Open the extension popup +2. Enter username +3. Start typing password +4. Click the eye icon to reveal/hide password + +## 2. Default Badge on Extension Icon + +**What it does:** +- Extension icon now always shows a blue dot (•) badge +- Badge changes to "1" when PDF is detected +- Badge resets to dot (•) after PDF is sent or cleared +- Makes extension more visible in the toolbar + +**Files changed:** +- `src/background/service-worker.ts` - Added `initializeBadge()` function + +**Badge states:** +- `•` (blue dot) - Extension active, no PDF detected +- `1` (blue) - PDF detected and ready to send +- Returns to `•` after sending or clearing + +**Visual:** +- Before: No badge (extension hard to notice) +- Now: Blue dot always visible (easy to spot in toolbar) + +## 3. Enhanced API Error Logging + +**What it does:** +- Detailed console logging for all Binect API calls +- Shows request details (URL, username, payload) +- Logs response status and headers +- Captures and displays error responses +- Better error messages for common issues + +**Files changed:** +- `src/utils/binect-api.ts` - Added console logging throughout + +**Console output example (authentication):** +``` +[Binect API] Authenticating with Binect API... +[Binect API] URL: https://api.binect.de/auth/login +[Binect API] Username: testuser +[Binect API] Response status: 200 +[Binect API] Response content-type: application/json +[Binect API] Authentication successful! +[Binect API] Response data: {token: "...", expiresAt: "..."} +``` + +**Console output example (error):** +``` +[Binect API] Authenticating with Binect API... +[Binect API] URL: https://api.binect.de/auth/login +[Binect API] Username: wronguser +[Binect API] Response status: 401 +[Binect API] Error response body: {"error": "Invalid credentials"} +[Binect API] Authentication error: BinectAPIError: Invalid credentials +``` + +**Error improvements:** +- Network errors now show: "Cannot reach Binect API at https://api.binect.de. Please check your internet connection." +- Auth errors show: "Invalid credentials" (401) +- Upload errors show specific issue (file format, size limit, etc.) + +## How to Test + +### 1. Reload Extension +```bash +# Extension is already built +# Just reload at chrome://extensions/ +``` + +### 2. Test Password Toggle +1. Click extension icon +2. If not logged in, you'll see the login form +3. Type in the password field +4. Click the eye icon - password should become visible +5. Click again - password should hide + +### 3. Test Default Badge +1. Look at your Chrome toolbar +2. Find the BinectChrome icon +3. Should see a small blue dot (•) badge +4. Download or view a PDF +5. Badge should change to "1" + +### 4. Test API Error Logging +1. Right-click popup → "Inspect" (opens DevTools) +2. Go to Console tab +3. Try to sign in (with wrong or correct credentials) +4. Watch for `[Binect API]` log messages +5. All API calls are now logged with details + +## Debugging Binect API Login Issues + +**With the new logging, you can now:** + +1. **See the exact error from Binect:** + - Open popup DevTools (right-click → Inspect) + - Try to sign in + - Check console for `[Binect API] Error response body:` + - This shows what the Binect API actually returned + +2. **Verify the request is correct:** + - Console shows the URL being called + - Shows the username being sent + - Confirms request format + +3. **Check network connectivity:** + - If you see "Cannot reach Binect API", it's a network issue + - If you see status codes (401, 400, etc.), the API is reachable but rejecting the request + +**Common login issues:** + +| Console Log | Problem | Solution | +|------------|---------|----------| +| "Cannot reach Binect API" | Network issue | Check internet connection | +| "Response status: 401" + "Invalid credentials" | Wrong username/password | Verify credentials | +| "Response status: 404" | API endpoint changed | Check API_BASE_URL in code | +| "Response status: 500" | Server error | Check Binect API status | +| "TypeError: Failed to fetch" | CORS or network | Check browser permissions | + +## Testing Checklist + +- [ ] Extension icon shows blue dot badge +- [ ] Password field has eye icon +- [ ] Clicking eye icon toggles password visibility +- [ ] Console shows `[Binect API]` logs when signing in +- [ ] Error messages are clear and helpful +- [ ] Badge updates when PDF detected +- [ ] Badge resets after sending PDF + +## Next Steps for API Debugging + +1. **Try to sign in with your Binect credentials** +2. **Open popup DevTools** (right-click popup → Inspect) +3. **Check the Console tab** for `[Binect API]` messages +4. **Share the console output** if login fails + +The detailed logs will show exactly what's happening with the API request and response, making it much easier to diagnose the login problem. + +## Files Modified + +``` +src/popup/popup.html - Added password toggle UI +src/popup/popup.css - Styled password toggle +src/popup/popup.ts - Added toggle functionality +src/background/service-worker.ts - Added default badge +src/utils/binect-api.ts - Enhanced error logging +``` + +## Build Info + +- Build completed successfully +- Extension size: ~17KB (popup.js: 10.4KB, background.js: 4.18KB) +- All assets compiled and minified +- Ready for testing! diff --git a/TESTING_PDF_VIEWER.md b/TESTING_PDF_VIEWER.md new file mode 100644 index 0000000..409d857 --- /dev/null +++ b/TESTING_PDF_VIEWER.md @@ -0,0 +1,291 @@ +# Testing PDF Sending from Chrome's Integrated PDF Viewer + +This guide explains how to test the new PDF viewer integration that allows sending PDFs directly from Chrome's built-in PDF viewer to the Binect API. + +## What Changed + +The extension now detects PDFs in two ways: + +1. **PDF Downloads** (Original) - Detects when you download a PDF file +2. **PDF Viewer** (New) - Detects when you're viewing a PDF in Chrome's integrated viewer + +The popup will prioritize showing PDFs from the current tab viewer over previously downloaded PDFs. + +## Testing the PDF Viewer Integration + +### Setup + +1. **Reload the Extension** + ``` + chrome://extensions/ → Find BinectChrome → Click reload icon + ``` + +2. **Check Permissions** + - The extension now requires `activeTab` and `` permissions + - Chrome will ask you to approve these new permissions + - Click "Allow" when prompted + +### Test Scenario 1: Open a PDF in a New Tab + +**Steps:** +1. Find any PDF URL on the web (examples below) +2. Right-click the PDF link → "Open link in new tab" +3. Chrome will open the PDF in its integrated viewer +4. Click the BinectChrome extension icon +5. The popup should show the PDF details with "Send PDF to Binect" button + +**Test PDF URLs:** +``` +https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf +https://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf +https://www.africau.edu/images/default/sample.pdf +``` + +**Expected Results:** +- PDF filename extracted from URL or tab title +- Domain shows the source domain +- Size shows "Size unknown" (normal for viewed PDFs) +- Timestamp shows "Just now" +- "Send PDF to Binect" button is active + +### Test Scenario 2: Navigate Directly to a PDF URL + +**Steps:** +1. Copy a PDF URL (use test URLs above) +2. Paste it into Chrome's address bar and press Enter +3. Chrome loads the PDF in the viewer +4. Click the BinectChrome extension icon +5. The popup should detect and show the PDF + +**Expected Results:** +- Same as Scenario 1 + +### Test Scenario 3: View PDF from Google Drive / Cloud Storage + +**Steps:** +1. Go to Google Drive, Dropbox, or any cloud storage +2. Click on a PDF file to view it +3. Wait for the PDF to load in the viewer +4. Click the BinectChrome extension icon + +**Expected Results:** +- Extension detects the PDF +- Domain shows the cloud provider's domain +- File can be sent to Binect + +**Note:** Some cloud providers use blob URLs or viewer applications that may not be directly detected. If this happens, download the PDF instead (it will be detected via download detection). + +### Test Scenario 4: Send PDF to Binect API + +**Steps:** +1. Open a PDF in Chrome's viewer (use Scenario 1 or 2) +2. Click the BinectChrome extension icon +3. If not signed in: + - Enter your Binect credentials + - Click "Sign In" +4. Once authenticated, the PDF should be shown +5. Click "Send PDF to Binect" + +**Expected Results:** +- Status shows "Uploading..." +- After successful upload: "Success! Document ID: [id]" +- Tracking entry is created with the transfer details +- After 3 seconds, the popup clears + +**Expected Errors (if testing with invalid credentials):** +- Authentication errors show in red +- Network errors are displayed +- Failed transfers are tracked with error messages + +## API Integration Testing + +### Test with Real Binect API + +If you have Binect API credentials: + +1. Sign in with valid credentials +2. Open a test PDF +3. Send it to Binect +4. Check the tracking info (click "?" button) to see the transfer log +5. Verify the document appears in your Binect account + +### Test with Invalid Credentials + +1. Sign in with invalid credentials +2. Should show "Invalid credentials" error +3. Extension should return to login screen + +### Test with Network Errors + +1. Disconnect from internet +2. Try to authenticate or send PDF +3. Should show "Network error" message + +### Test Session Expiry + +1. Sign in successfully +2. Wait for token to expire (or manipulate storage to simulate) +3. Try to send PDF +4. Should show "Session expired. Please sign in again." +5. Should automatically log out after 2 seconds + +## Debugging Tips + +### Check Console Logs + +**Popup Console:** +1. Click extension icon to open popup +2. Right-click inside popup → "Inspect" +3. Check console for errors or debug messages + +**Background Service Worker Console:** +1. Go to `chrome://extensions/` +2. Find BinectChrome +3. Click "service worker" link +4. Check console for detection logs + +### Common Issues + +**Issue: PDF not detected** +- **Solution 1:** The URL might not end with `.pdf` - this is normal for some cloud services +- **Solution 2:** Try refreshing the PDF tab +- **Solution 3:** Download the PDF instead (download detection should work) + +**Issue: "Failed to fetch PDF: 403 Forbidden"** +- **Cause:** The PDF URL requires authentication/cookies that the extension can't access +- **Solution:** Download the PDF instead + +**Issue: "Failed to fetch PDF: CORS error"** +- **Cause:** The server doesn't allow cross-origin requests +- **Solution:** Download the PDF instead + +**Issue: Extension shows "No PDF detected"** +- **Check:** Is the current tab actually showing a PDF? +- **Check:** Does the URL end with `.pdf` or contain PDF indicators? +- **Try:** Download the PDF to test the download detection + +## Verifying API Requests + +### Using Chrome DevTools Network Tab + +1. Open popup with DevTools open (right-click → Inspect) +2. Go to Network tab +3. Send a PDF +4. Look for requests to `https://api.binect.de/` +5. Check request details: + - **POST /auth/login** - Authentication request + - **POST /documents/upload** - PDF upload request + +**Authentication Request:** +```json +POST https://api.binect.de/auth/login +Content-Type: application/json + +{ + "username": "your-username", + "password": "your-password" +} +``` + +**Upload Request:** +``` +POST https://api.binect.de/documents/upload +Authorization: Bearer [token] +Content-Type: multipart/form-data + +[PDF file data] +``` + +### Expected API Responses + +**Successful Authentication:** +```json +{ + "token": "eyJhbGc...", + "expiresAt": "2024-01-15T12:00:00Z" +} +``` + +**Successful Upload:** +```json +{ + "documentId": "doc_abc123", + "status": "uploaded", + "uploadedAt": "2024-01-14T12:00:00Z" +} +``` + +**Authentication Error (401):** +```json +{ + "error": "Invalid credentials" +} +``` + +**Upload Error (400):** +```json +{ + "error": "Invalid file format" +} +``` + +## Tracking Data + +After sending PDFs, check the tracking data: + +1. Click the "?" button in the extension popup +2. Opens tracking page +3. Shows list of all transfer attempts +4. Includes: + - Timestamp + - Source domain + - PDF size + - Result (success/failure) + - Error message (if failed) + +## Comparison: Download Detection vs. Viewer Detection + +| Feature | Download Detection | PDF Viewer Detection | +|---------|-------------------|---------------------| +| **Trigger** | PDF file download completes | User opens PDF in browser | +| **File Size** | Known (from download) | Unknown (estimated after fetch) | +| **Reliability** | High | Depends on URL format | +| **Use Case** | Downloading PDFs from web | Viewing PDFs directly in browser | +| **Badge** | Shows "1" after download | No badge (on-demand) | + +## Next Steps + +Once you've verified the PDF viewer integration works: + +1. Test with various PDF sources (Google Drive, Dropbox, direct links) +2. Verify all error cases are handled gracefully +3. Check that tracking data is accurate +4. Test the download detection still works alongside viewer detection +5. Consider edge cases: + - Very large PDFs (10MB+) + - PDFs with special characters in filename + - PDFs from authenticated sources + - PDFs from blob URLs + +## Known Limitations + +1. **Blob URLs**: Some web apps create temporary blob URLs that can't be re-fetched + - **Workaround**: Download the PDF instead +2. **Authenticated PDFs**: PDFs behind login walls may not be accessible + - **Workaround**: Download the PDF instead +3. **Embedded PDFs**: PDFs embedded in iframes may not be detected + - **Workaround**: Open the PDF in a new tab or download it +4. **Size Unknown**: PDF size is not known until fetch, so tracking may show 0 initially + - **Note**: Actual size is recorded after successful upload + +## Support + +If you encounter issues: +1. Check the console logs (popup and service worker) +2. Verify the PDF URL format +3. Try downloading the PDF as an alternative +4. Report issues to bernd.worsch@binect.de with: + - PDF URL (if public) + - Error message + - Console logs + - Tracking data export diff --git a/dev-helper.sh b/dev-helper.sh new file mode 100755 index 0000000..ff68f0c --- /dev/null +++ b/dev-helper.sh @@ -0,0 +1,198 @@ +#!/bin/bash +# Development Helper Script for BinectChrome +# Quick commands for common development tasks + +set -e + +EXTENSION_NAME="BinectChrome" +DIST_DIR="./dist" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Print colored message +print_msg() { + local color=$1 + local msg=$2 + echo -e "${color}${msg}${NC}" +} + +# Show usage +usage() { + echo "BinectChrome Development Helper" + echo "" + echo "Usage: ./dev-helper.sh [command]" + echo "" + echo "Commands:" + echo " build - Production build" + echo " dev - Start development mode (watch)" + echo " clean - Clean dist directory and rebuild" + echo " test - Run tests" + echo " check - Run type-check and lint" + echo " open-chrome - Open Chrome extension management" + echo " open-sw - Open Chrome service worker internals" + echo " verify - Verify dist build is valid" + echo " help - Show this help" + echo "" + echo "Quick Test-Fix Loop:" + echo " 1. Run: ./dev-helper.sh dev (in one terminal)" + echo " 2. Make changes in src/" + echo " 3. Run: ./dev-helper.sh verify" + echo " 4. Reload extension in Chrome (chrome://extensions/)" +} + +# Build production +build() { + print_msg "$BLUE" "📦 Building extension..." + npm run build + print_msg "$GREEN" "✅ Build complete!" + verify +} + +# Start development mode +dev() { + print_msg "$BLUE" "🔧 Starting development mode (watch)..." + print_msg "$YELLOW" "Press Ctrl+C to stop" + print_msg "$YELLOW" "Tip: After changes, reload extension at chrome://extensions/" + npm run dev +} + +# Clean and rebuild +clean() { + print_msg "$BLUE" "🧹 Cleaning dist directory..." + rm -rf "$DIST_DIR" + print_msg "$GREEN" "✅ Cleaned!" + build +} + +# Run tests +test() { + print_msg "$BLUE" "🧪 Running tests..." + npm test +} + +# Type check and lint +check() { + print_msg "$BLUE" "🔍 Running type-check..." + npm run type-check + print_msg "$BLUE" "🔍 Running lint..." + npm run lint + print_msg "$GREEN" "✅ All checks passed!" +} + +# Open Chrome extensions page +open_chrome() { + print_msg "$BLUE" "🌐 Opening Chrome extensions page..." + if command -v google-chrome &> /dev/null; then + google-chrome chrome://extensions/ & + elif command -v chromium &> /dev/null; then + chromium chrome://extensions/ & + else + print_msg "$YELLOW" "⚠️ Chrome not found. Please open chrome://extensions/ manually" + fi +} + +# Open Chrome service worker internals +open_sw() { + print_msg "$BLUE" "🌐 Opening Chrome service worker internals..." + if command -v google-chrome &> /dev/null; then + google-chrome chrome://serviceworker-internals/ & + elif command -v chromium &> /dev/null; then + chromium chrome://serviceworker-internals/ & + else + print_msg "$YELLOW" "⚠️ Chrome not found. Please open chrome://serviceworker-internals/ manually" + fi +} + +# Verify build +verify() { + print_msg "$BLUE" "🔍 Verifying build..." + + # Check if dist exists + if [ ! -d "$DIST_DIR" ]; then + print_msg "$RED" "❌ dist/ directory not found. Run build first." + exit 1 + fi + + # Check required files + REQUIRED_FILES=( + "$DIST_DIR/manifest.json" + "$DIST_DIR/background.js" + "$DIST_DIR/popup.html" + "$DIST_DIR/popup.js" + ) + + for file in "${REQUIRED_FILES[@]}"; do + if [ ! -f "$file" ]; then + print_msg "$RED" "❌ Missing required file: $file" + exit 1 + fi + done + + # Check manifest has required permissions + if ! grep -q '"alarms"' "$DIST_DIR/manifest.json"; then + print_msg "$RED" "❌ manifest.json missing 'alarms' permission" + exit 1 + fi + + # Check background.js is an ES module (should start with export/import) + if ! grep -qE '^(export|import)' "$DIST_DIR/background.js"; then + print_msg "$YELLOW" "⚠️ background.js might not be a proper ES module" + print_msg "$YELLOW" " First line: $(head -n 1 $DIST_DIR/background.js)" + fi + + print_msg "$GREEN" "✅ Build verification passed!" + print_msg "$BLUE" "📋 Build info:" + echo " - Manifest version: $(grep -o '"version": "[^"]*"' $DIST_DIR/manifest.json | cut -d'"' -f4)" + echo " - Background size: $(du -h $DIST_DIR/background.js | cut -f1)" + echo " - Popup size: $(du -h $DIST_DIR/popup.js | cut -f1)" + echo "" + print_msg "$YELLOW" "Next steps:" + echo " 1. Go to chrome://extensions/" + echo " 2. Click 'Load unpacked'" + echo " 3. Select: $DIST_DIR" + echo " 4. Or reload if already loaded" +} + +# Main +case "${1:-}" in + build) + build + ;; + dev) + dev + ;; + clean) + clean + ;; + test) + test + ;; + check) + check + ;; + open-chrome) + open_chrome + ;; + open-sw) + open_sw + ;; + verify) + verify + ;; + help|--help|-h) + usage + ;; + *) + if [ -n "${1:-}" ]; then + print_msg "$RED" "❌ Unknown command: $1" + echo "" + fi + usage + exit 1 + ;; +esac diff --git a/public/manifest.json b/public/manifest.json index cc25ceb..dce9743 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -6,14 +6,16 @@ "default_locale": "en", "permissions": [ "downloads", - "storage" + "storage", + "alarms", + "activeTab" ], "host_permissions": [ - "https://api.binect.de/*" + "https://api.binect.de/*", + "" ], "background": { - "service_worker": "background.js", - "type": "module" + "service_worker": "background.js" }, "action": { "default_popup": "popup.html", diff --git a/specs/binectapi_rest.pdf b/specs/binectapi_rest.pdf new file mode 100755 index 0000000..ac284dd Binary files /dev/null and b/specs/binectapi_rest.pdf differ diff --git a/specs/v1_swagger_api_kernel.json b/specs/v1_swagger_api_kernel.json new file mode 100755 index 0000000..00de79c --- /dev/null +++ b/specs/v1_swagger_api_kernel.json @@ -0,0 +1,2825 @@ + +{ + + "swagger": "2.0", + "info": { + "version": "0.9.9", + "description": "Webservice für den Briefversand. Ihre Briefe werden durch unser System ausgedruckt, kuvertiert, frankiert und zur Deutschen Post gebracht.\n\nFür eine detaillierte Beschreibung schauen Sie bitte in das Modell.

Hinweis: Wenn Sie als Benutzer eingeloggt sind, laufen alle Anfragen gegen das Produktiv-System.
Somit stornieren, löschen, ... oder versenden Sie Ihre Briefe wirklich!
Falls Sie Zugriff auf unser Testsystem benötigen, stellen Sie gerne eine Anfrage an kontakt@binect.de.", + "title": "Binect API REST", + "termsOfService": "https://app.binect.de/downloadFile?fileId=2", + "contact": { + "name": "kontakt@binect.de" + } + }, + "host": "", + "basePath": "/binectapi/v1", + "schemes": [ + "https" + ], + "securityDefinitions": { + "basicAuth": { + "type": "basic", + "description": "HTTP Basic Authentication." + } + }, + "security": [ + { + "basicAuth": [ ] + } + ], + "paths": { + "/documents": { + "post": { + "tags": [ + "documents" + ], + "description": "Uploads a new document. The document shall be a letter or a serial letter.
\nThe letter contains a valid address in the proper print area and respects the exclusion areas.
\nThe content must be base64 encoded.\nThe document will be validated.
\nIf validation fails, an optional correction (transformation, cover page, address label) will be provided.
\nThe response will contain a valid document (letter/serial letter) or an 'error' object.
\n\nThe document is normalized with ghostscript, therefore we recommend a visible check of the document with GET /documents/{documentID}/pdf.\n\nThe document status can have the following codes:\n\n 2 (is shippable),\n \n 7 (is erroneous)\n \n", + "parameters": [ + { + "name": "upload", + "in": "body", + "schema": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "$ref": "#/definitions/Content" + }, + "options": { + "$ref": "#/definitions/Options" + }, + "attributes": { + "type": "array", + "items": { + "$ref": "#/definitions/LetterAttribute" + } + }, + "splitParams": { + "description": "If the uploaded document is a serial letter, define how it shall be split. only one of the property 'splitToken' or 'splitAfterNumberOfPages' can be used.", + "type": "object", + "properties": { + "splitToken": { + "type": "string", + "description": "This token is used to split the serial letter." + }, + "splitAfterNumberOfPages": { + "type": "integer", + "format": "int32", + "description": "Every N pages the serial letter is split." + } + }, + "example": { + "splitToken": "Sehr geehrte" + } + }, + "responseFormat": { + "$ref": "#/definitions/ResponseFormatEnum" + } + }, + "example": { + "content": { + "filename": "test.pdf", + "content": "BASE64 encoded string" + }, + "options": { + "simplex": false, + "color": false + } + } + } + } + ], + "responses": { + "200": { + "description": "Document created, may be erroneous.", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "413": { + "description": "Request Entity Too Large, Limit is 12 MB" + } + } + }, + "get": { + "tags": [ + "documents" + ], + "description": "Gets all uploaded letter references which are shippable.\n\nShippable documents can have the following status codes:\n\n 2 (is shippable)\n

\nOptional a filter on attributes can be defined.
\nattributes is a JSON-formated string.
\nThis object is an array of LetterAtributte\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false, + "collectionFormat": "multi" + }, + { + "name": "offset", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false + } + ], + "responses": { + "200": { + "description": "A list of all uploads which are shippable documents.", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Document" + } + } + }, + "403": { + "description": "Forbidden" + }, + "413": { + "description": "Requested amount of data ist to big. Use please 'limit' and 'offset'" + } + } + } + }, + "/documents/errors": { + "get": { + "tags": [ + "documents" + ], + "description": "Gets all uploaded letter references which are erroneous.\n\nErroneous documents can have the following status codes:\n\n 7 (erroneous)\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false, + "collectionFormat": "multi" + }, + { + "name": "offset", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false + } + ], + "responses": { + "200": { + "description": "A list of all uploaded erroneous documents. Please check the error message in the response and also have a look at the preview.", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Document" + } + } + }, + "403": { + "description": "Forbidden" + }, + "413": { + "description": "Requested amount of data ist to big. Use please 'limit' and 'offset'" + } + } + } + }, + "/documents/{documentID}": { + "get": { + "tags": [ + "documents" + ], + "description": "Gets the referenced document.\nThe document is a letter, a serial letter or an 'error' object.\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + }, + "delete": { + "tags": [ + "documents" + ], + "description": "Deletes the referenced document.\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/documents/findbyAttributes": { + "get": { + "tags": [ + "documents" + ], + "description": "Gets all uploaded letters which were marked with the given attributes.
\nThere must be at least one pair of the parameters key and value. Take care that of the order of the keys and values. \n", + "parameters": [ + { + "name": "key", + "in": "query", + "required": true, + "type": "array", + "items": { + "type": "string" + }, + "allowEmptyValue": false, + "collectionFormat": "multi" + }, + { + "name": "value", + "in": "query", + "required": true, + "type": "array", + "items": { + "type": "string" + }, + "allowEmptyValue": false, + "collectionFormat": "multi" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Document" + } + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + } + } + } + }, + "/documents/{documentID}/status": { + "get": { + "tags": [ + "documents" + ], + "description": "Gets status of a document\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/DocumentStatus" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/documents/{documentID}/options": { + "get": { + "tags": [ + "documents" + ], + "description": "Gets document's options.\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Options" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + }, + "put": { + "tags": [ + "documents" + ], + "description": "Updates document's options\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "options", + "in": "body", + "schema": { + "$ref": "#/definitions/Options" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Options" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/documents/{documentID}/attributes": { + "get": { + "tags": [ + "documents" + ], + "description": "Gets document's attributes\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/LetterAttribute" + } + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + }, + "post": { + "tags": [ + "documents" + ], + "description": "Marks the document with certain attributes.\n", + "parameters": [ + { + "in": "path", + "name": "documentID", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "attributes", + "in": "body", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/LetterAttribute" + } + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/LetterAttribute" + } + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/documents/{documentID}/attributes/{key}": { + "get": { + "tags": [ + "documents" + ], + "description": "Gets the document's attribute for a specified key.\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "key", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/LetterAttribute" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + }, + "put": { + "tags": [ + "documents" + ], + "description": "Updates the document's attribute for a specified key.\n", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "key", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "value", + "in": "formData", + "required": true, + "type": "string", + "allowEmptyValue": false + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/LetterAttribute" + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + }, + "delete": { + "tags": [ + "documents" + ], + "description": "Removes an attribute from the document.\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "key", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/documents/{documentID}/pdf": { + "get": { + "tags": [ + "documents" + ], + "description": "Gets the referenced document as PDF preview.\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "file" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + }, + "406": { + "description": "Not Acceptable" + } + } + } + }, + "/documents/{documentID}/png": { + "get": { + "tags": [ + "documents" + ], + "description": "Gets the referenced document as PNG preview.\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "file" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + }, + "406": { + "description": "Not Acceptable" + } + } + } + }, + "/documents/{documentID}/transformations": { + "put": { + "tags": [ + "documents" + ], + "description": "Applies a transformation of the document's first page.
After transformation, the document is validated once more. Therefore, please check the document's status again after performing any transformations.
Every transformation is applied on the original version of the document.
\"offsetX\" and \"offsetY\" affect the horizontal and vertical position, moving the document along the x and y axis, using [mm] as a unit. Starting point is the upper left corner of the page.
Also scaleX and scaleY can be independently used for scaling. Factor 1 corresponds to 100%, so in order to shrink, use values smaller than 1. Scaling refers to the center of the page. \n", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "transformation", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "scaleX": { + "type": "number", + "format": "double" + }, + "scaleY": { + "type": "number", + "format": "double" + }, + "offsetX": { + "type": "number", + "format": "double" + }, + "offsetY": { + "type": "number", + "format": "double" + } + } + } + } + ], + "responses": { + "200": { + "description": "Document updated", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + }, + "delete": { + "tags": [ + "documents" + ], + "description": "Removes the performed transformation on the document and rolls back to the original version of the document\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/documents/{documentID}/coverpage": { + "put": { + "tags": [ + "documents" + ], + "description": "Creates a cover page for the document, so a receiving address is obligatory.
The return address is optional, also the text on the coverpage below the address.\n", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "coverPage", + "in": "body", + "schema": { + "type": "object", + "required": [ + "receivingAddress" + ], + "properties": { + "receivingAddress": { + "$ref": "#/definitions/Address" + }, + "returnAddress": { + "$ref": "#/definitions/Address" + }, + "coverText": { + "description": "optional text on the cover page", + "type": "object", + "required": [ + "text" + ], + "properties": { + "subject": { + "description": "optional subject text on the cover page", + "type": "string" + }, + "date": { + "description": "optional date on the cover page", + "type": "string", + "format": "date" + }, + "text": { + "description": "Text on the cover page. Only plain text is supported. Start a new line with '\\n'.", + "type": "string" + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Document updated", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + }, + "406": { + "description": "Not Acceptable" + } + } + }, + "delete": { + "tags": [ + "documents" + ], + "description": "Removes the cover page from the document.\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/documents/{documentID}/attachments": { + "get": { + "tags": [ + "documents" + ], + "description": "Gets document's all attachments\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "List of attachments", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Attachment" + } + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + }, + "post": { + "tags": [ + "documents" + ], + "description": "Append an Attachment to a document after already appended attachments.
The list of all attachments of the document is returned\n", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "appendAttachment", + "in": "body", + "schema": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "$ref": "#/definitions/Content" + }, + "newSheet": { + "description": "The Attachment will start on the front page of a sheet", + "type": "boolean", + "default": true + }, + "remarks": { + "description": "Remarks to the attachment", + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Attachment created", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Attachment" + } + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document do not exist" + } + } + }, + "patch": { + "tags": [ + "documents" + ], + "description": "Append a list of attachments to a document.
Already appended attachments stay unchanged.
The new attachments will be append at the end in order of list. If the order of the attachments is important take care of this.", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "attachmentIDs", + "in": "body", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + ], + "responses": { + "200": { + "description": "Append a list of attachments to a document", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document(s) do not exist" + } + } + }, + "delete": { + "tags": [ + "documents" + ], + "description": "Detach all attachments of the document\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/documents/{documentID}/attachments/{attachmentID}": { + "post": { + "tags": [ + "documents" + ], + "description": "Append an Attachment to a document after already appended attachments.
The list of all attachments of the document is returned\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "attachmentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + }, + "delete": { + "tags": [ + "documents" + ], + "description": "Remove an attachment from the document\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "attachmentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Dcument not found" + } + } + } + }, + "/sendings": { + "post": { + "tags": [ + "sendings" + ], + "description": "Announces a letter (its ID) or a list of letters (list of IDs) which are already uploaded for delivering.\n", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "documentIds", + "in": "body", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + ], + "responses": { + "200": { + "description": "Letter created, may be faulty.", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Document" + } + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document(s) do not exist" + } + } + }, + "get": { + "tags": [ + "sendings" + ], + "description": "Gets all document references, which are prepared for delivering or are already delivered.\n\nSendings can have the following status codes:\n \n 3 (in production, waiting to be sent),\n \n 4 (in print process),\n \n 5 (is sent),\n \n 6 (is canceled),\n \n 7 (is erroneous)\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false, + "collectionFormat": "multi" + }, + { + "name": "offset", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Document" + } + } + }, + "403": { + "description": "Forbidden" + }, + "413": { + "description": "Requested amount of data ist to big. Use please 'limit' and 'offset'" + } + } + }, + "put": { + "tags": [ + "sendings" + ], + "description": "Cancels the delivery of a list of letters (list of IDs). Only not shipped letters are canceled.\n .\n", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "documentIds", + "in": "body", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + ], + "responses": { + "200": { + "description": "List of document status (documentID and status). \n\n In case of a serial document, the status of the child documents are also listed", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/DocumentStatus" + } + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document(s) do not exist" + } + } + } + }, + "/sendings/document": { + "post": { + "tags": [ + "sendings" + ], + "description": "Document is directly sent after upload, if it is successfully validated.\n", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "shipping", + "in": "body", + "schema": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "$ref": "#/definitions/Content" + }, + "options": { + "$ref": "#/definitions/Options" + }, + "attributes": { + "type": "array", + "items": { + "$ref": "#/definitions/LetterAttribute" + } + }, + "responseFormat": { + "$ref": "#/definitions/ResponseFormatEnum" + } + } + } + } + ], + "responses": { + "200": { + "description": "Document created, may be faulty.", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + }, + "413": { + "description": "Request Entity Too Large, Limit is 12 MB" + } + } + } + }, + "/sendings/status": { + "get": { + "tags": [ + "sendings" + ], + "description": "Gets status of all documents, which are prepared for delivering or are already delivered.\n\n The Query can be optional narrowed with a list of DocumentIds.\n\n Sendings can have the following status codes:\n \n 3 (in production, waiting to be sent),\n \n 4 (in print process),\n \n 5 (is sent),\n \n 6 (is canceled),\n \n 7 (is erroneous)\n", + "parameters": [ + { + "name": "documentIds", + "in": "query", + "required": false, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "collectionFormat": "multi", + "allowEmptyValue": false + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/DocumentStatus" + } + } + }, + "403": { + "description": "Forbidden" + } + } + } + }, + "/sendings/{documentID}/status": { + "get": { + "tags": [ + "sendings" + ], + "description": "Gets status of a document, which are prepared for delivering or are already delivered.\n\nSendings can have the following status codes:\n \n 3 (in production, waiting to be sent),\n \n 4 (in print process),\n \n 5 (is sent),\n \n 6 (is canceled),\n \n 7 (is erroneous)\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/DocumentStatus" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/sendings/{documentID}": { + "post": { + "tags": [ + "sendings" + ], + "description": "Announces the delivery of a letter, if it isn't yet shipped.\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + }, + "get": { + "tags": [ + "sendings" + ], + "description": "Gets a referenced sending.\nThe sending is a letter, serial letter or an 'error' object.\n", + "parameters": [ + { + "name": "documentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Document" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + }, + "put": { + "tags": [ + "sendings" + ], + "description": "Cancels the delivery of a letter, if it isn't already shipped.\n", + "parameters": [ + { + "in": "path", + "name": "documentID", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Status" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + }, + "406": { + "description": "Not Acceptable" + } + } + }, + "delete": { + "tags": [ + "sendings" + ], + "description": "Deletes a canceled or a delivered and sent document from the system.\n", + "parameters": [ + { + "in": "path", + "name": "documentID", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/attachments": { + "post": { + "tags": [ + "attachments" + ], + "description": "Upload an attachment\n", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "attachmentData", + "in": "body", + "schema": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "$ref": "#/definitions/Content" + }, + "newSheet": { + "description": "The Attachment will start on the front page of a sheet", + "type": "boolean", + "default": true + }, + "remarks": { + "description": "Remarks to the attachment", + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Attachment created.", + "schema": { + "$ref": "#/definitions/Attachment" + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "413": { + "description": "Request Entity Too Large, Limit is 12 MB" + } + } + }, + "get": { + "tags": [ + "attachments" + ], + "description": "Gets all attachment references.\n", + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Attachment" + } + } + }, + "403": { + "description": "Forbidden" + } + } + } + }, + "/attachments/{attachmentID}": { + "get": { + "tags": [ + "attachments" + ], + "description": "Gets referenced attachment.\n", + "parameters": [ + { + "in": "path", + "name": "attachmentID", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Attachment" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Attachment not found" + } + } + }, + "delete": { + "tags": [ + "attachments" + ], + "description": "Delete the referenced attachment.
The attachment can only be deleted if it is not appended to a none sended document.", + "parameters": [ + { + "in": "path", + "name": "attachmentID", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Attachment not found" + }, + "406": { + "description": "Not Acceptable" + } + } + } + }, + "/attachments/{attachmentID}/pdf": { + "get": { + "tags": [ + "attachments" + ], + "description": "Gets the referenced attachment as PDF preview.\n", + "parameters": [ + { + "name": "attachmentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "file" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Attachment not found" + }, + "406": { + "description": "Not Acceptable" + } + } + } + }, + "/attachments/{attachmentID}/png": { + "get": { + "tags": [ + "attachments" + ], + "description": "Gets the referenced attachment as PNG preview of the first page.\n", + "parameters": [ + { + "name": "attachmentID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "file" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Attachment not found" + }, + "406": { + "description": "Not Acceptable" + } + } + } + }, + "/attachments/{attachmentID}/documents": { + "get": { + "tags": [ + "attachments" + ], + "description": "Gets all unsended documents to which this attachment is append.\n", + "parameters": [ + { + "in": "path", + "name": "attachmentID", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Document" + } + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Attachment not found" + } + } + }, + "patch": { + "tags": [ + "attachments" + ], + "description": "Append this attachment to all documents in the list.
The attachement is append at end of the document after already exkisting attachment.\n", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "in": "path", + "name": "attachmentID", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "doumentIDs", + "in": "body", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + ], + "responses": { + "200": { + "description": "Append this attachments to all documents in the list", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/DocumentStatus" + } + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Document(s) do not exist" + } + } + }, + "delete": { + "tags": [ + "attachments" + ], + "description": "Remove the referenced attachment from all documents, which are not yet shipped.\n", + "parameters": [ + { + "in": "path", + "name": "attachmentID", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/DocumentStatus" + } + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Attachment not found" + } + } + } + }, + "/accounts": { + "get": { + "tags": [ + "accounts" + ], + "description": "Gets the account's financial data.\n", + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Account" + } + }, + "403": { + "description": "Forbidden" + } + } + } + }, + "/accounts/personaldata": { + "get": { + "tags": [ + "accounts" + ], + "description": "Gets the account's personal data.\n", + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/User" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "User not found" + } + } + }, + "patch": { + "tags": [ + "accounts" + ], + "description": "Updates the personal data\n", + "parameters": [ + { + "name": "personalData", + "in": "body", + "required": true, + "schema": { + "description": "The customer's personal data.", + "type": "object", + "properties": { + "forename": { + "type": "string" + }, + "surname": { + "type": "string" + }, + "street": { + "type": "string" + }, + "city": { + "type": "string" + }, + "plz": { + "type": "string" + }, + "state": { + "type": "string" + }, + "country": { + "type": "string" + }, + "organization": { + "type": "string" + }, + "title": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "partnerId": { + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/User" + } + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "User not found" + } + } + } + }, + "/accounts/options": { + "get": { + "tags": [ + "accounts" + ], + "description": "Gets default options which are assigned to the account.\n", + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Options" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "User not found" + } + } + }, + "put": { + "tags": [ + "accounts" + ], + "description": "Updates default options which are assigned to the account.\n", + "parameters": [ + { + "name": "defaultOptions", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Options" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Options" + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "User not found" + } + } + } + }, + "/accounts/coworkers": { + "get": { + "tags": [ + "accounts" + ], + "description": "Gets the coworkers.\n", + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Coworker" + } + } + }, + "403": { + "description": "Forbidden" + } + } + } + }, + "/accounts/coworkers/{debitornumber}/journal/{month}": { + "get": { + "tags": [ + "accounts" + ], + "description": "Gets all transctions of a month for a coworker.\n", + "parameters": [ + { + "in": "path", + "name": "debitornumber", + "required": true, + "type": "string" + }, + { + "in": "path", + "name": "month", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "limit", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false, + "collectionFormat": "multi" + }, + { + "name": "offset", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Transaction" + } + } + }, + "404": { + "description": "User not found" + }, + "413": { + "description": "Requested amount of data ist to big. Use please 'limit' and 'offset'" + } + } + } + }, + "/accounts/journal/{month}": { + "get": { + "tags": [ + "accounts" + ], + "description": "Gets all transctions of a month.\n", + "parameters": [ + { + "in": "path", + "name": "month", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "limit", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false, + "collectionFormat": "multi" + }, + { + "name": "offset", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Transaction" + } + } + }, + "413": { + "description": "Requested amount of data ist to big. Use please 'limit' and 'offset'" + } + } + } + }, + "/invoices": { + "get": { + "tags": [ + "invoices" + ], + "description": "Gets all stored invoices references.\n", + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Invoice" + } + } + } + } + } + }, + "/invoices/{invoiceNumber}": { + "get": { + "tags": [ + "invoices" + ], + "description": "Gets all transctions of the invoice.\n", + "parameters": [ + { + "in": "path", + "name": "invoiceNumber", + "required": true, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false, + "collectionFormat": "multi" + }, + { + "name": "offset", + "in": "query", + "type": "integer", + "format": "int32", + "allowEmptyValue": false + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Transaction" + } + } + }, + "413": { + "description": "Requested amount of data ist to big. Use please 'limit' and 'offset'" + } + } + } + }, + "/invoices/{invoiceNumber}/pdf": { + "get": { + "tags": [ + "invoices" + ], + "description": "Get a specific invoice as PDF.\n", + "parameters": [ + { + "in": "path", + "name": "invoiceNumber", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "the invoice as PDF", + "schema": { + "type": "file" + } + }, + "404": { + "description": "Document not found" + } + } + } + } + }, + "definitions": { + "Document": { + "type": "object", + "required": [ + "id", + "filename", + "status", + "documentType" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "filename": { + "type": "string" + }, + "numberOfPages": { + "type": "integer", + "format": "int32" + }, + "status": { + "$ref": "#/definitions/Status" + }, + "documentType": { + "type": "string", + "enum": [ + "Letter", + "SerialLetter" + ] + }, + "letter": { + "$ref": "#/definitions/Letter" + }, + "serialLetter": { + "$ref": "#/definitions/SerialLetter" + } + } + }, + "Attachment": { + "type": "object", + "required": [ + "id", + "filename", + "numberOfPages", + "newSheet" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "filename": { + "type": "string" + }, + "numberOfPages": { + "type": "integer", + "format": "int32" + }, + "newSheet": { + "type": "boolean", + "default": true + }, + "ntimesUsed": { + "description": "This attachment appended to 'n' documents", + "type": "integer", + "format": "int32" + }, + "remarks": { + "type": "string" + } + } + }, + "Letter": { + "type": "object", + "required": [ + "letterType" + ], + "properties": { + "letterType": { + "type": "string", + "enum": [ + "LetterData", + "Error" + ] + }, + "letterData": { + "$ref": "#/definitions/LetterData" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/definitions/Error" + } + } + } + }, + "LetterData": { + "type": "object", + "required": [ + "recipientAddress", + "price", + "international", + "options" + ], + "properties": { + "recipientAddress": { + "type": "string", + "example": "\"Musterfirrna\" \"Max Mustermann\" \"Musterstr. 20\" \"64342 Musterstadt\"" + }, + "price": { + "$ref": "#/definitions/Price" + }, + "international": { + "type": "boolean", + "default": false, + "example": false + }, + "options": { + "$ref": "#/definitions/Options" + }, + "attributes": { + "type": "array", + "items": { + "$ref": "#/definitions/LetterAttribute" + } + }, + "attachments": { + "description": "The Attachments which are appended to this document.\n
Only documents from documentType 'Letter' can have attachments", + "type": "array", + "items": { + "$ref": "#/definitions/Attachment" + } + } + } + }, + "SerialLetter": { + "type": "object", + "properties": { + "splitToken": { + "type": "string", + "description": "This token is used to split the serial letter." + }, + "splitAfterNumberOfPages": { + "type": "integer", + "format": "int32", + "description": "Every N pages, the serial letter is split." + }, + "status": { + "$ref": "#/definitions/SerialLetterStatus" + }, + "letters": { + "type": "array", + "items": { + "$ref": "#/definitions/Document" + } + } + } + }, + "SerialLetterStatus": { + "type": "object", + "required": [ + "nrTotal", + "nrGenerated", + "nrSuccess", + "nrError" + ], + "properties": { + "nrTotal": { + "type": "integer", + "format": "int32" + }, + "nrGenerated": { + "type": "integer", + "format": "int32" + }, + "nrSuccess": { + "type": "integer", + "format": "int32" + }, + "nrError": { + "type": "integer", + "format": "int32" + } + } + }, + "Error": { + "type": "object", + "required": [ + "code", + "text", + "blankText" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32", + "description": "Binect error code." + }, + "text": { + "type": "string", + "description": "Human readable error text with filled-in place holders." + }, + "blankText": { + "type": "string", + "description": "Text with place holders for parameters. Place holders are framed in %-Symbols, e. g. 'error on page number %pageNr% of your document'." + }, + "parameters": { + "type": "array", + "description": "Parameters for place holder in 'blankText'.", + "items": { + "$ref": "#/definitions/ErrorParam" + } + }, + "errorOnPage": { + "type": "integer", + "format": "int32", + "description": "On which page of the document the error occurred." + } + } + }, + "Price": { + "type": "object", + "required": [ + "priceBeforeTax", + "priceAfterTax", + "unit", + "taxInPercent" + ], + "properties": { + "priceBeforeTax": { + "type": "integer", + "format": "int32" + }, + "priceAfterTax": { + "type": "integer", + "format": "int32" + }, + "unit": { + "$ref": "#/definitions/CurrencyEnum" + }, + "taxInPercent": { + "type": "integer", + "format": "int32", + "description": "e. g. 19 for 19% sales tax" + } + }, + "example": { + "priceBeforeTax": 78, + "priceAfterTax": 93, + "unit": "EUROCENT", + "taxInPercent": 19 + } + }, + "Options": { + "type": "object", + "required": [ + "simplex", + "color" + ], + "properties": { + "simplex": { + "description": "if false it is duplex", + "type": "boolean" + }, + "color": { + "description": "if false it is black and white", + "type": "boolean" + }, + "envelope": { + "description": "'DINLANG' is the default envelope.", + "type": "string", + "enum": [ + "DINLANG", + "C4" + ], + "example": "DINLANG" + }, + "dvFranking": { + "description": "if true, DV-Freimachung is mandatory In this case the valdation is more strict. This field is deprecated, please use instead 'franking' ", + "type": "boolean" + }, + "franking": { + "$ref": "#/definitions/FrankingEnum" + }, + "productionCountry": { + "$ref": "#/definitions/ProductionCountryEnum" + } + }, + "example": { + "simplex": true, + "color": false, + "envelope": "DINLANG", + "dvFranking": true, + "franking": "DV_FRANKING", + "productionCountry": "DE" + } + }, + "FrankingEnum": { + "type": "string", + "enum": [ + "UNSPECIFIED", + "STANDARD_FRANKING", + "DV_FRANKING" + ] + }, + "ProductionCountryEnum": { + "description": "Domestic shipping from the specified country. International shipping is always from Germany. \nThe use of the feature is permitted after approval by Binect.", + "type": "string", + "enum": [ + "UNSPECIFIED", + "DE", + "AT" + ] + }, + "LetterAttribute": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "example": { + "key": "Key", + "value": "Value" + } + }, + "DocumentStatus": { + "type": "object", + "required": [ + "id", + "status" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "status": { + "$ref": "#/definitions/Status" + } + } + }, + "Status": { + "type": "object", + "required": [ + "code", + "text" + ], + "properties": { + "code": { + "description": "Following status codes are defined:\n\n 1 (in preparation),\n \n 2 (is shippable),\n \n 3 (in production, waiting to be sent),\n \n 4 (in print process),\n \n 5 (is sent),\n \n 6 (is canceled),\n \n 7 (is erroneous)\n ", + "type": "integer", + "format": "int32" + }, + "text": { + "type": "string" + } + }, + "example": { + "code": 2, + "text": "is shippable" + } + }, + "ResponseFormatEnum": { + "description": "Define the format of the response. Default is FULL.
Use SHORT for direct API response without validation result.
The validation is running afterwards.", + "type": "string", + "enum": [ + "FULL", + "SHORT" + ], + "default": "FULL", + "example": "FULL" + }, + "Account": { + "description": "account data", + "type": "object", + "required": [ + "credit", + "unit" + ], + "properties": { + "credit": { + "type": "integer", + "format": "int32" + }, + "promotionCredit": { + "type": "integer", + "format": "int32" + }, + "creditLimit": { + "type": "integer", + "format": "int32" + }, + "unit": { + "$ref": "#/definitions/CurrencyEnum" + } + } + }, + "ErrorParam": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "Content": { + "description": "The content of the file and file name. The content must be base64 encoded.", + "type": "object", + "required": [ + "filename", + "content" + ], + "properties": { + "filename": { + "type": "string" + }, + "content": { + "type": "string", + "format": "binary" + } + }, + "example": { + "filename": "test.pdf", + "content": "BASE64 encoded string" + } + }, + "User": { + "description": "The customer's personal data.", + "type": "object", + "required": [ + "email" + ], + "properties": { + "debitornumber": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "forename": { + "type": "string" + }, + "surname": { + "type": "string" + }, + "street": { + "type": "string" + }, + "city": { + "type": "string" + }, + "plz": { + "type": "string" + }, + "state": { + "type": "string" + }, + "country": { + "type": "string" + }, + "organization": { + "type": "string" + }, + "title": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "partnerId": { + "type": "string" + } + } + }, + "Coworker": { + "description": "The coworkers data.", + "type": "object", + "required": [ + "email" + ], + "properties": { + "debitornumber": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "forename": { + "type": "string" + }, + "surname": { + "type": "string" + }, + "registrationDate": { + "type": "string", + "format": "date" + }, + "numberOfSendings": { + "type": "integer", + "format": "int32" + }, + "totalAmount": { + "$ref": "#/definitions/Price" + } + } + }, + "CurrencyEnum": { + "type": "string", + "enum": [ + "EUROCENT" + ] + }, + "Address": { + "description": "Adress.", + "type": "object", + "required": [ + "name", + "street", + "zipCode", + "city" + ], + "properties": { + "name": { + "type": "string" + }, + "nameExtend": { + "type": "string" + }, + "street": { + "type": "string" + }, + "city": { + "type": "string" + }, + "zipCode": { + "type": "string" + }, + "country": { + "type": "string" + } + } + }, + "Invoice": { + "description": "Invoice.", + "type": "object", + "required": [ + "id", + "filename" + ], + "properties": { + "id": { + "type": "string" + }, + "filename": { + "type": "string" + }, + "totalAmount": { + "$ref": "#/definitions/Price" + }, + "date": { + "type": "string", + "format": "date" + } + } + }, + "Transaction": { + "description": "Invoice.", + "type": "object", + "required": [ + "id", + "action", + "date" + ], + "properties": { + "id": { + "type": "string" + }, + "action": { + "$ref": "#/definitions/Action" + }, + "date": { + "type": "string", + "format": "date" + }, + "documentId": { + "type": "string" + }, + "filename": { + "type": "string" + }, + "amount": { + "$ref": "#/definitions/Price" + }, + "numberOfPages": { + "type": "integer", + "format": "int32" + }, + "options": { + "$ref": "#/definitions/Options" + }, + "status": { + "$ref": "#/definitions/Status" + }, + "coworker": { + "description": "Debitornumber of coworker", + "type": "string" + } + } + }, + "Action": { + "description": "Describe an action of a transaction", + "type": "object", + "required": [ + "code", + "text" + ], + "properties": { + "code": { + "description": "Following action codes are defined:\n\n 1 (is sent),\n \n 2 (is canceled),\n \n 3 (delivery error)\n ", + "type": "integer", + "format": "int32" + }, + "text": { + "type": "string" + } + }, + "example": { + "code": 1, + "text": "is sent" + } + } + } + +} \ No newline at end of file diff --git a/src/background/service-worker.ts b/src/background/service-worker.ts index 4cae91e..4e3c888 100644 --- a/src/background/service-worker.ts +++ b/src/background/service-worker.ts @@ -13,11 +13,12 @@ let lastDetectedPDF: DetectedPDF | null = null; * Initialize extension on install */ chrome.runtime.onInstalled.addListener((details) => { + console.log('[Service Worker] onInstalled event:', details.reason); if (details.reason === 'install') { - console.log('BinectChrome installed'); + console.log('[Service Worker] BinectChrome installed'); setupCredentialExpiryAlarm(); } else if (details.reason === 'update') { - console.log('BinectChrome updated'); + console.log('[Service Worker] BinectChrome updated'); } }); @@ -25,7 +26,7 @@ chrome.runtime.onInstalled.addListener((details) => { * Handle extension startup */ chrome.runtime.onStartup.addListener(() => { - console.log('BinectChrome started'); + console.log('[Service Worker] onStartup event - BinectChrome started'); setupCredentialExpiryAlarm(); }); @@ -60,37 +61,58 @@ async function checkAndDeleteExpiredCredentials() { } } +/** + * Initialize badge with default icon + */ +function initializeBadge() { + // Set a default badge to make extension visible + chrome.action.setBadgeText({ text: '•' }); + chrome.action.setBadgeBackgroundColor({ color: '#4A90E2' }); // Binect Blue + console.log('[Service Worker] Default badge set'); +} + +// Initialize badge on load +initializeBadge(); + /** * Start PDF detection */ +console.log('[Service Worker] Initializing PDF detection...'); startPDFDetection((pdf: DetectedPDF) => { - console.log('PDF detected:', pdf.filename); + console.log('[Service Worker] PDF DETECTED CALLBACK:', pdf.filename); lastDetectedPDF = pdf; // Update badge to indicate PDF detected chrome.action.setBadgeText({ text: '1' }); chrome.action.setBadgeBackgroundColor({ color: '#4A90E2' }); // Binect Blue + + console.log('[Service Worker] Badge updated, PDF stored in memory'); }); /** * Handle messages from popup */ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + console.log('[Service Worker] Message received:', request.action); + if (request.action === 'getLastPDF') { + console.log('[Service Worker] Returning last PDF:', lastDetectedPDF ? lastDetectedPDF.filename : 'none'); sendResponse({ pdf: lastDetectedPDF }); return true; } if (request.action === 'clearLastPDF') { + console.log('[Service Worker] Clearing last PDF'); lastDetectedPDF = null; - chrome.action.setBadgeText({ text: '' }); + chrome.action.setBadgeText({ text: '•' }); // Reset to default badge sendResponse({ success: true }); return true; } if (request.action === 'pdfSent') { - // Clear badge after successful send - chrome.action.setBadgeText({ text: '' }); + console.log('[Service Worker] PDF sent, resetting badge'); + // Reset badge after successful send + chrome.action.setBadgeText({ text: '•' }); // Reset to default badge sendResponse({ success: true }); return true; } @@ -98,4 +120,5 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { return false; }); -console.log('BinectChrome service worker loaded'); +console.log('[Service Worker] ===== BinectChrome service worker loaded ====='); +console.log('[Service Worker] Timestamp:', new Date().toISOString()); diff --git a/src/popup/popup.css b/src/popup/popup.css index 1e5a997..9a0a592 100644 --- a/src/popup/popup.css +++ b/src/popup/popup.css @@ -133,6 +133,46 @@ body { box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1); } +/* Password Input Wrapper */ +.password-input-wrapper { + position: relative; +} + +.password-input-wrapper input { + padding-right: 44px; /* Make room for the eye icon */ +} + +.password-toggle { + position: absolute; + right: 8px; + top: 50%; + transform: translateY(-50%); + background: none; + border: none; + cursor: pointer; + padding: 6px; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-secondary); + border-radius: 4px; + transition: all 0.2s; +} + +.password-toggle:hover { + background: var(--light-bg); + color: var(--binect-blue); +} + +.password-toggle:focus { + outline: 2px solid var(--binect-blue); + outline-offset: 2px; +} + +.password-toggle svg { + display: block; +} + /* Buttons */ .btn { width: 100%; diff --git a/src/popup/popup.html b/src/popup/popup.html index 71ca152..b0cef30 100644 --- a/src/popup/popup.html +++ b/src/popup/popup.html @@ -4,7 +4,6 @@ BinectChrome -
@@ -26,7 +25,19 @@
- +
+ + +
@@ -39,7 +50,7 @@