generated from coulomb/repo-seed
Release 0.1: Complete BinectChrome implementation
Implements all requirements from ProductRequirementsDocument.md: - PDF detection via Chrome Downloads API - Secure credential storage with AES-GCM encryption - Binect API integration for PDF uploads - Popup UI with Binect branding - Local transfer tracking (500 entry cap) - Help page with tracking view and CSV export - 60-day credential retention with auto-expiry - Accessibility compliance (WCAG 2.1 AA) Technical implementation: - Chrome Extension Manifest V3 - TypeScript with strict mode - Webpack build system - Jest test suite (22/22 passing) - ESLint configured (0 errors) Build output: 13 KB total (production minified) Test coverage: crypto, pdf-detector, tracker, binect-api Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
137
src/utils/binect-api.ts
Normal file
137
src/utils/binect-api.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Binect API client
|
||||
*/
|
||||
|
||||
const API_BASE_URL = 'https://api.binect.de';
|
||||
|
||||
export interface AuthToken {
|
||||
token: string;
|
||||
expiresAt: string;
|
||||
}
|
||||
|
||||
export interface UploadResult {
|
||||
documentId: string;
|
||||
status: string;
|
||||
uploadedAt: string;
|
||||
}
|
||||
|
||||
export class BinectAPIError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public statusCode?: number,
|
||||
public response?: unknown
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'BinectAPIError';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate with Binect API
|
||||
*/
|
||||
export async function authenticate(
|
||||
username: string,
|
||||
password: string
|
||||
): Promise<AuthToken> {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ username, password })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
throw new BinectAPIError('Invalid credentials', 401);
|
||||
}
|
||||
throw new BinectAPIError(
|
||||
`Authentication failed: ${response.statusText}`,
|
||||
response.status
|
||||
);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
if (error instanceof BinectAPIError) {
|
||||
throw error;
|
||||
}
|
||||
throw new BinectAPIError(
|
||||
`Network error: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload PDF to Binect
|
||||
*/
|
||||
export async function uploadPDF(
|
||||
pdfData: ArrayBuffer,
|
||||
filename: string,
|
||||
token: string
|
||||
): Promise<UploadResult> {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
const blob = new Blob([pdfData], { type: 'application/pdf' });
|
||||
formData.append('file', blob, filename);
|
||||
formData.append('filename', filename);
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/documents/upload`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
|
||||
if (response.status === 401) {
|
||||
throw new BinectAPIError('Authentication required', 401, errorData);
|
||||
}
|
||||
|
||||
if (response.status === 400) {
|
||||
throw new BinectAPIError(
|
||||
errorData.error || 'Invalid file format',
|
||||
400,
|
||||
errorData
|
||||
);
|
||||
}
|
||||
|
||||
if (response.status === 413) {
|
||||
throw new BinectAPIError('File size exceeds limit', 413, errorData);
|
||||
}
|
||||
|
||||
throw new BinectAPIError(
|
||||
`Upload failed: ${response.statusText}`,
|
||||
response.status,
|
||||
errorData
|
||||
);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
if (error instanceof BinectAPIError) {
|
||||
throw error;
|
||||
}
|
||||
throw new BinectAPIError(
|
||||
`Network error: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test API connectivity
|
||||
*/
|
||||
export async function testConnection(): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/health`, {
|
||||
method: 'GET'
|
||||
});
|
||||
return response.ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user