feat: add comprehensive application documentation for EMLy
This commit is contained in:
707
DOCUMENTATION.md
Normal file
707
DOCUMENTATION.md
Normal file
@@ -0,0 +1,707 @@
|
||||
# EMLy Application Documentation
|
||||
|
||||
EMLy is a desktop email viewer application built for 3gIT, designed to open and display `.eml` and `.msg` email files on Windows. It provides a modern, user-friendly interface for viewing email content, attachments, and metadata.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Architecture Overview](#architecture-overview)
|
||||
2. [Technology Stack](#technology-stack)
|
||||
3. [Project Structure](#project-structure)
|
||||
4. [Backend (Go)](#backend-go)
|
||||
5. [Frontend (SvelteKit)](#frontend-sveltekit)
|
||||
6. [State Management](#state-management)
|
||||
7. [Internationalization (i18n)](#internationalization-i18n)
|
||||
8. [UI Components](#ui-components)
|
||||
9. [Key Features](#key-features)
|
||||
10. [Build & Development](#build--development)
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
EMLy is built using the **Wails v2** framework, which combines a Go backend with a web-based frontend. This architecture allows:
|
||||
|
||||
- **Go Backend**: Handles file operations, Windows API calls, email parsing, and system interactions
|
||||
- **Web Frontend**: Provides the user interface using SvelteKit with Svelte 5
|
||||
- **Bridge**: Wails automatically generates TypeScript bindings for Go functions, enabling seamless communication
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ EMLy Application │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Frontend (SvelteKit + Svelte 5) │
|
||||
│ ├── Routes & Pages │
|
||||
│ ├── UI Components (shadcn-svelte) │
|
||||
│ ├── State Management (Svelte 5 Runes) │
|
||||
│ └── i18n (ParaglideJS) │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Wails Bridge (Auto-generated TypeScript bindings) │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Backend (Go) │
|
||||
│ ├── App Logic (app.go) │
|
||||
│ ├── Email Parsing (backend/utils/mail/) │
|
||||
│ ├── Windows APIs (screenshot, debugger detection) │
|
||||
│ └── File Operations │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Backend
|
||||
- **Go 1.21+**: Primary backend language
|
||||
- **Wails v2**: Desktop application framework
|
||||
- **Windows Registry API**: For checking default file handlers
|
||||
- **GDI/User32 APIs**: For screenshot functionality
|
||||
|
||||
### Frontend
|
||||
- **SvelteKit**: Application framework
|
||||
- **Svelte 5**: UI framework with Runes ($state, $derived, $effect, $props)
|
||||
- **TypeScript**: Type-safe JavaScript
|
||||
- **shadcn-svelte**: UI component library
|
||||
- **Tailwind CSS**: Utility-first CSS framework
|
||||
- **ParaglideJS**: Internationalization
|
||||
- **Lucide Icons**: Icon library
|
||||
- **Bun**: JavaScript runtime and package manager
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
EMLy/
|
||||
├── app.go # Main application logic
|
||||
├── main.go # Application entry point
|
||||
├── logger.go # Logging utilities
|
||||
├── wails.json # Wails configuration
|
||||
├── backend/
|
||||
│ └── utils/
|
||||
│ ├── mail/
|
||||
│ │ ├── eml_reader.go # EML file parsing
|
||||
│ │ ├── msg_reader.go # MSG file parsing
|
||||
│ │ ├── mailparser.go # MIME email parsing
|
||||
│ │ └── file_dialog.go # File dialog utilities
|
||||
│ ├── screenshot_windows.go # Windows screenshot capture
|
||||
│ ├── debug_windows.go # Debugger detection
|
||||
│ ├── ini-reader.go # Configuration file parsing
|
||||
│ ├── machine-identifier.go # System info collection
|
||||
│ └── file-metadata.go # File metadata utilities
|
||||
├── frontend/
|
||||
│ ├── src/
|
||||
│ │ ├── routes/ # SvelteKit routes
|
||||
│ │ │ ├── +layout.svelte # Root layout
|
||||
│ │ │ ├── +error.svelte # Error page
|
||||
│ │ │ ├── (app)/ # Main app route group
|
||||
│ │ │ │ ├── +layout.svelte # App layout with sidebar
|
||||
│ │ │ │ ├── +page.svelte # Mail viewer page
|
||||
│ │ │ │ └── settings/
|
||||
│ │ │ │ └── +page.svelte # Settings page
|
||||
│ │ │ ├── image/ # Image viewer route
|
||||
│ │ │ │ ├── +layout.svelte
|
||||
│ │ │ │ └── +page.svelte
|
||||
│ │ │ └── pdf/ # PDF viewer route
|
||||
│ │ │ ├── +layout.svelte
|
||||
│ │ │ └── +page.svelte
|
||||
│ │ ├── lib/
|
||||
│ │ │ ├── components/ # Svelte components
|
||||
│ │ │ │ ├── MailViewer.svelte
|
||||
│ │ │ │ ├── SidebarApp.svelte
|
||||
│ │ │ │ ├── UnsavedBar.svelte
|
||||
│ │ │ │ └── ui/ # shadcn-svelte components
|
||||
│ │ │ ├── stores/ # State management
|
||||
│ │ │ │ ├── app.ts
|
||||
│ │ │ │ ├── mail-state.svelte.ts
|
||||
│ │ │ │ └── settings.svelte.ts
|
||||
│ │ │ ├── paraglide/ # i18n runtime
|
||||
│ │ │ ├── wailsjs/ # Auto-generated Go bindings
|
||||
│ │ │ ├── types/ # TypeScript types
|
||||
│ │ │ └── utils/ # Utility functions
|
||||
│ │ └── messages/ # i18n translation files
|
||||
│ │ ├── en.json
|
||||
│ │ └── it.json
|
||||
│ ├── static/ # Static assets
|
||||
│ └── package.json
|
||||
└── config.ini # Application configuration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backend (Go)
|
||||
|
||||
### Entry Point (`main.go`)
|
||||
|
||||
The application starts in `main.go`, which:
|
||||
|
||||
1. Initializes the logger
|
||||
2. Parses command-line arguments for:
|
||||
- `.eml` or `.msg` files to open on startup
|
||||
- `--view-image=<path>` for image viewer mode
|
||||
- `--view-pdf=<path>` for PDF viewer mode
|
||||
3. Configures Wails with window options
|
||||
4. Sets up single-instance lock to prevent multiple main windows
|
||||
5. Binds the `App` struct for frontend access
|
||||
|
||||
```go
|
||||
// Single instance with unique ID based on mode
|
||||
uniqueId := "emly-app-lock"
|
||||
if strings.Contains(arg, "--view-image") {
|
||||
uniqueId = "emly-viewer-" + arg
|
||||
windowTitle = "EMLy Image Viewer"
|
||||
}
|
||||
```
|
||||
|
||||
### Application Core (`app.go`)
|
||||
|
||||
The `App` struct is the main application controller, exposed to the frontend via Wails bindings.
|
||||
|
||||
#### Key Properties
|
||||
|
||||
```go
|
||||
type App struct {
|
||||
ctx context.Context
|
||||
StartupFilePath string // File opened via command line
|
||||
CurrentMailFilePath string // Currently loaded mail file
|
||||
openImages map[string]bool // Track open image viewers
|
||||
openPDFs map[string]bool // Track open PDF viewers
|
||||
openEMLs map[string]bool // Track open EML viewers
|
||||
}
|
||||
```
|
||||
|
||||
#### Core Methods
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `GetConfig()` | Returns application configuration from `config.ini` |
|
||||
| `GetStartupFile()` | Returns file path passed via command line |
|
||||
| `SetCurrentMailFilePath()` | Updates the current mail file path |
|
||||
| `ReadEML(path)` | Parses an EML file and returns email data |
|
||||
| `ReadMSG(path)` | Parses an MSG file and returns email data |
|
||||
| `ReadPEC(path)` | Parses PEC (Italian certified email) files |
|
||||
| `ShowOpenFileDialog()` | Opens native file picker for EML/MSG files |
|
||||
| `OpenImageWindow(data, filename)` | Opens image in new viewer window |
|
||||
| `OpenPDFWindow(data, filename)` | Opens PDF in new viewer window |
|
||||
| `OpenEMLWindow(data, filename)` | Opens EML attachment in new window |
|
||||
| `TakeScreenshot()` | Captures window screenshot as base64 PNG |
|
||||
| `SubmitBugReport(input)` | Creates bug report with screenshot and system info |
|
||||
| `ExportSettings(json)` | Exports settings to JSON file |
|
||||
| `ImportSettings()` | Imports settings from JSON file |
|
||||
| `IsDebuggerRunning()` | Checks if a debugger is attached |
|
||||
| `QuitApp()` | Terminates the application |
|
||||
|
||||
### Email Parsing (`backend/utils/mail/`)
|
||||
|
||||
#### EML Reader (`eml_reader.go`)
|
||||
Reads standard `.eml` files using the `mailparser.go` MIME parser.
|
||||
|
||||
#### MSG Reader (`msg_reader.go`)
|
||||
Handles Microsoft Outlook `.msg` files using external conversion.
|
||||
|
||||
#### Mail Parser (`mailparser.go`)
|
||||
A comprehensive MIME email parser that handles:
|
||||
- Multipart messages (mixed, alternative, related)
|
||||
- Text and HTML bodies
|
||||
- Attachments with proper content-type detection
|
||||
- Embedded files (inline images)
|
||||
- Various content transfer encodings (base64, quoted-printable, 7bit, 8bit)
|
||||
|
||||
The `EmailData` structure returned to the frontend:
|
||||
```go
|
||||
type EmailData struct {
|
||||
Subject string
|
||||
From string
|
||||
To []string
|
||||
Cc []string
|
||||
Bcc []string
|
||||
Body string // HTML or text body
|
||||
Attachments []AttachmentData
|
||||
IsPec bool // Italian certified email
|
||||
}
|
||||
```
|
||||
|
||||
### Screenshot Utility (`backend/utils/screenshot_windows.go`)
|
||||
|
||||
Captures the application window using Windows GDI APIs:
|
||||
- Uses `FindWindowW` to locate window by title
|
||||
- Uses `DwmGetWindowAttribute` for DPI-aware window bounds
|
||||
- Creates compatible DC and bitmap for capture
|
||||
- Returns image as base64-encoded PNG
|
||||
|
||||
---
|
||||
|
||||
## Frontend (SvelteKit)
|
||||
|
||||
### Route Structure
|
||||
|
||||
SvelteKit uses file-based routing. The `(app)` folder is a route group that applies the main app layout.
|
||||
|
||||
```
|
||||
routes/
|
||||
├── +layout.svelte # Root layout (minimal)
|
||||
├── +error.svelte # Global error page
|
||||
├── (app)/ # Main app group
|
||||
│ ├── +layout.svelte # App layout with titlebar, sidebar, footer
|
||||
│ ├── +layout.ts # Server data loader
|
||||
│ ├── +page.svelte # Main mail viewer page
|
||||
│ └── settings/
|
||||
│ ├── +page.svelte # Settings page
|
||||
│ └── +layout.ts # Settings data loader
|
||||
├── image/ # Standalone image viewer
|
||||
│ ├── +layout.svelte
|
||||
│ └── +page.svelte
|
||||
└── pdf/ # Standalone PDF viewer
|
||||
├── +layout.svelte
|
||||
└── +page.svelte
|
||||
```
|
||||
|
||||
### Main App Layout (`(app)/+layout.svelte`)
|
||||
|
||||
The app layout provides:
|
||||
|
||||
1. **Custom Titlebar**: Windows-style titlebar with minimize/maximize/close buttons
|
||||
- Draggable for window movement
|
||||
- Double-click to maximize/restore
|
||||
|
||||
2. **Sidebar Provider**: Collapsible navigation sidebar
|
||||
|
||||
3. **Footer Bar**: Quick access icons for:
|
||||
- Toggle sidebar
|
||||
- Navigate to home
|
||||
- Navigate to settings
|
||||
- Open bug report dialog
|
||||
- Reload application
|
||||
|
||||
4. **Bug Report Dialog**: Complete bug reporting system with:
|
||||
- Screenshot capture on dialog open
|
||||
- Name, email, description fields
|
||||
- System info collection
|
||||
- Creates ZIP archive with all data
|
||||
|
||||
5. **Toast Notifications**: Using svelte-sonner
|
||||
|
||||
6. **Debugger Protection**: Detects attached debuggers and can quit if detected
|
||||
|
||||
### Mail Viewer (`(app)/+page.svelte` + `MailViewer.svelte`)
|
||||
|
||||
The mail viewer is split into two parts:
|
||||
- `+page.svelte`: Page wrapper that initializes mail state from startup file
|
||||
- `MailViewer.svelte`: Core email viewing component
|
||||
|
||||
#### MailViewer Features
|
||||
|
||||
- **Empty State**: Shows "Open EML/MSG File" button when no email loaded
|
||||
- **Email Header**: Displays subject, from, to, cc, bcc fields
|
||||
- **PEC Badge**: Shows green badge for Italian certified emails
|
||||
- **Attachments Bar**: Horizontal scrollable list of attachments with type-specific icons
|
||||
- **Email Body**: Rendered in sandboxed iframe for security
|
||||
- **Loading Overlay**: Shows spinner during file loading
|
||||
|
||||
#### Attachment Handling
|
||||
|
||||
```typescript
|
||||
// Different handlers based on file type
|
||||
if (att.contentType.startsWith("image/")) {
|
||||
// Opens in built-in or external viewer based on settings
|
||||
await OpenImageWindow(base64Data, filename);
|
||||
} else if (att.filename.toLowerCase().endsWith(".pdf")) {
|
||||
// Opens in built-in or external PDF viewer
|
||||
await OpenPDFWindow(base64Data, filename);
|
||||
} else if (att.filename.toLowerCase().endsWith(".eml")) {
|
||||
// Opens in new EMLy instance
|
||||
await OpenEMLWindow(base64Data, filename);
|
||||
} else {
|
||||
// Download as file
|
||||
<a href={dataUrl} download={filename}>...</a>
|
||||
}
|
||||
```
|
||||
|
||||
### Settings Page (`(app)/settings/+page.svelte`)
|
||||
|
||||
Organized into cards with various configuration options:
|
||||
|
||||
1. **Language Settings**
|
||||
- Radio buttons for English/Italian
|
||||
- Triggers full page reload on change
|
||||
|
||||
2. **Export/Import Settings**
|
||||
- Export current settings to JSON file
|
||||
- Import settings from JSON file
|
||||
|
||||
3. **Preview Page Settings**
|
||||
- Supported image types (JPG, JPEG, PNG)
|
||||
- Toggle built-in image viewer
|
||||
- Toggle built-in PDF viewer
|
||||
|
||||
4. **Danger Zone** (Hidden by default, revealed by clicking settings 10 times rapidly)
|
||||
- Open DevTools hint
|
||||
- Reload application
|
||||
- Reset to defaults
|
||||
- Debugger protection toggle (disabled in production)
|
||||
- Version information display
|
||||
|
||||
#### Unsaved Changes Detection
|
||||
|
||||
The settings page tracks changes and shows a persistent toast when there are unsaved modifications:
|
||||
|
||||
```typescript
|
||||
$effect(() => {
|
||||
const dirty = !isSameSettings(normalizeSettings(form), lastSaved);
|
||||
unsavedChanges.set(dirty);
|
||||
if (dirty) {
|
||||
showUnsavedChangesToast({
|
||||
onSave: saveToStorage,
|
||||
onReset: resetToLastSaved,
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## State Management
|
||||
|
||||
EMLy uses a combination of Svelte 5 Runes and traditional Svelte stores.
|
||||
|
||||
### Mail State (`stores/mail-state.svelte.ts`)
|
||||
|
||||
Uses Svelte 5's `$state` rune for reactive email data:
|
||||
|
||||
```typescript
|
||||
class MailState {
|
||||
currentEmail = $state<internal.EmailData | null>(null);
|
||||
|
||||
setParams(email: internal.EmailData | null) {
|
||||
this.currentEmail = email;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.currentEmail = null;
|
||||
}
|
||||
}
|
||||
|
||||
export const mailState = new MailState();
|
||||
```
|
||||
|
||||
### Settings Store (`stores/settings.svelte.ts`)
|
||||
|
||||
Manages application settings with localStorage persistence:
|
||||
|
||||
```typescript
|
||||
class SettingsStore {
|
||||
settings = $state<EMLy_GUI_Settings>({ ...defaults });
|
||||
hasHydrated = $state(false);
|
||||
|
||||
load() { /* Load from localStorage */ }
|
||||
save() { /* Save to localStorage */ }
|
||||
update(newSettings: Partial<EMLy_GUI_Settings>) { /* Merge and save */ }
|
||||
reset() { /* Reset to defaults */ }
|
||||
}
|
||||
```
|
||||
|
||||
Settings schema:
|
||||
```typescript
|
||||
interface EMLy_GUI_Settings {
|
||||
selectedLanguage: "en" | "it";
|
||||
useBuiltinPreview: boolean;
|
||||
useBuiltinPDFViewer: boolean;
|
||||
previewFileSupportedTypes: string[];
|
||||
enableAttachedDebuggerProtection: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### App Store (`stores/app.ts`)
|
||||
|
||||
Traditional Svelte writable stores for UI state:
|
||||
|
||||
```typescript
|
||||
export const dangerZoneEnabled = writable<boolean>(false);
|
||||
export const unsavedChanges = writable<boolean>(false);
|
||||
export const sidebarOpen = writable<boolean>(true);
|
||||
export const bugReportDialogOpen = writable<boolean>(false);
|
||||
export const events = writable<AppEvent[]>([]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Internationalization (i18n)
|
||||
|
||||
EMLy uses **ParaglideJS** for compile-time type-safe translations.
|
||||
|
||||
### Translation Files
|
||||
|
||||
Located in `frontend/messages/`:
|
||||
- `en.json` - English translations
|
||||
- `it.json` - Italian translations
|
||||
|
||||
### Message Format
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/inlang-message-format",
|
||||
"mail_no_email_selected": "No email selected",
|
||||
"mail_open_eml_btn": "Open EML/MSG File",
|
||||
"settings_title": "Settings",
|
||||
"settings_language_english": "English",
|
||||
"settings_language_italian": "Italiano"
|
||||
}
|
||||
```
|
||||
|
||||
### Usage in Components
|
||||
|
||||
```typescript
|
||||
import * as m from "$lib/paraglide/messages";
|
||||
|
||||
// In template
|
||||
<h1>{m.settings_title()}</h1>
|
||||
<button>{m.mail_open_eml_btn()}</button>
|
||||
```
|
||||
|
||||
### Changing Language
|
||||
|
||||
```typescript
|
||||
import { setLocale } from "$lib/paraglide/runtime";
|
||||
|
||||
await setLocale("it", { reload: false });
|
||||
location.reload(); // Page reload required for full update
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UI Components
|
||||
|
||||
EMLy uses **shadcn-svelte**, a port of shadcn/ui for Svelte. Components are located in `frontend/src/lib/components/ui/`.
|
||||
|
||||
### Available Components
|
||||
|
||||
| Component | Usage |
|
||||
|-----------|-------|
|
||||
| `Button` | Primary buttons with variants (default, destructive, outline, ghost) |
|
||||
| `Card` | Container with header, content, footer sections |
|
||||
| `Dialog` | Modal dialogs for bug reports, confirmations |
|
||||
| `AlertDialog` | Confirmation dialogs with cancel/continue actions |
|
||||
| `Switch` | Toggle switches for boolean settings |
|
||||
| `Checkbox` | Multi-select checkboxes |
|
||||
| `RadioGroup` | Single-select options (language selection) |
|
||||
| `Label` | Form labels |
|
||||
| `Input` | Text input fields |
|
||||
| `Textarea` | Multi-line text input |
|
||||
| `Separator` | Visual dividers |
|
||||
| `Sidebar` | Collapsible navigation sidebar |
|
||||
| `Tooltip` | Hover tooltips |
|
||||
| `Sonner` | Toast notifications |
|
||||
| `Badge` | Status badges |
|
||||
| `Skeleton` | Loading placeholders |
|
||||
|
||||
### Custom Components
|
||||
|
||||
| Component | Purpose |
|
||||
|-----------|---------|
|
||||
| `MailViewer.svelte` | Email display with header, attachments, body |
|
||||
| `SidebarApp.svelte` | Navigation sidebar with menu items |
|
||||
| `UnsavedBar.svelte` | Unsaved changes notification bar |
|
||||
|
||||
---
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. Email Viewing
|
||||
|
||||
- Parse and display EML and MSG files
|
||||
- Show email metadata (from, to, cc, bcc, subject)
|
||||
- Render HTML email bodies in sandboxed iframe
|
||||
- List and handle attachments with type-specific actions
|
||||
|
||||
### 2. Attachment Handling
|
||||
|
||||
- **Images**: Open in built-in viewer or external app
|
||||
- **PDFs**: Open in built-in viewer or external app
|
||||
- **EML files**: Open in new EMLy window
|
||||
- **Other files**: Download directly
|
||||
|
||||
### 3. Multi-Window Support
|
||||
|
||||
The app can spawn separate viewer windows:
|
||||
- Image viewer (`--view-image=<path>`)
|
||||
- PDF viewer (`--view-pdf=<path>`)
|
||||
- EML viewer (new app instance with file path)
|
||||
|
||||
Each viewer has a unique instance ID to allow multiple concurrent viewers.
|
||||
|
||||
### 4. Bug Reporting
|
||||
|
||||
Complete bug reporting system:
|
||||
1. Captures screenshot when dialog opens
|
||||
2. Collects user input (name, email, description)
|
||||
3. Includes current mail file if loaded
|
||||
4. Gathers system information
|
||||
5. Creates ZIP archive in temp folder
|
||||
6. Shows path and allows opening folder
|
||||
|
||||
### 5. Settings Management
|
||||
|
||||
- Language selection (English/Italian)
|
||||
- Built-in viewer preferences
|
||||
- Supported file type configuration
|
||||
- Export/import settings as JSON
|
||||
- Reset to defaults
|
||||
|
||||
### 6. Security Features
|
||||
|
||||
- Debugger detection and protection
|
||||
- Sandboxed iframe for email body
|
||||
- Single-instance lock for main window
|
||||
- Disabled link clicking in email body
|
||||
|
||||
### 7. PEC Support
|
||||
|
||||
Special handling for Italian Posta Elettronica Certificata (PEC):
|
||||
- Detects PEC emails
|
||||
- Shows signed mail badge
|
||||
- Handles P7S signature files
|
||||
- Processes daticert.xml metadata
|
||||
|
||||
---
|
||||
|
||||
## Build & Development
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Go 1.21+
|
||||
- Node.js 18+ or Bun
|
||||
- Wails CLI v2
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
# Install frontend dependencies
|
||||
cd frontend && bun install
|
||||
|
||||
# Run in development mode
|
||||
wails dev
|
||||
```
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
# Build for Windows
|
||||
wails build -platform windows/amd64
|
||||
|
||||
# Output: build/bin/EMLy.exe
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
`wails.json` configures the build:
|
||||
```json
|
||||
{
|
||||
"name": "EMLy",
|
||||
"frontend:install": "bun install",
|
||||
"frontend:build": "bun run build",
|
||||
"frontend:dev:watcher": "bun run dev",
|
||||
"fileAssociations": [
|
||||
{
|
||||
"ext": "eml",
|
||||
"name": "Email Message",
|
||||
"description": "EML File"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### File Association
|
||||
|
||||
The app registers as a handler for `.eml` files via Windows file associations, configured in `wails.json`.
|
||||
|
||||
---
|
||||
|
||||
## Wails Bindings
|
||||
|
||||
Wails automatically generates TypeScript bindings for Go functions. These are located in `frontend/src/lib/wailsjs/`.
|
||||
|
||||
### Generated Files
|
||||
|
||||
- `go/main/App.ts` - TypeScript functions calling Go methods
|
||||
- `go/models.ts` - TypeScript types for Go structs
|
||||
- `runtime/runtime.ts` - Wails runtime functions
|
||||
|
||||
### Usage Example
|
||||
|
||||
```typescript
|
||||
import { ReadEML, ShowOpenFileDialog } from "$lib/wailsjs/go/main/App";
|
||||
import type { internal } from "$lib/wailsjs/go/models";
|
||||
|
||||
// Open file dialog
|
||||
const filePath = await ShowOpenFileDialog();
|
||||
|
||||
// Parse email
|
||||
const email: internal.EmailData = await ReadEML(filePath);
|
||||
```
|
||||
|
||||
### Runtime Events
|
||||
|
||||
Wails provides event system for Go-to-JS communication:
|
||||
|
||||
```typescript
|
||||
import { EventsOn } from "$lib/wailsjs/runtime/runtime";
|
||||
|
||||
// Listen for second instance launch
|
||||
EventsOn("launchArgs", (args: string[]) => {
|
||||
// Handle file opened from second instance
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Frontend
|
||||
|
||||
Toast notifications for user-facing errors:
|
||||
```typescript
|
||||
import { toast } from "svelte-sonner";
|
||||
import * as m from "$lib/paraglide/messages";
|
||||
|
||||
try {
|
||||
await ReadEML(filePath);
|
||||
} catch (error) {
|
||||
toast.error(m.mail_error_opening());
|
||||
}
|
||||
```
|
||||
|
||||
### Backend
|
||||
|
||||
Errors are returned to frontend and logged:
|
||||
```go
|
||||
func (a *App) ReadEML(filePath string) (*internal.EmailData, error) {
|
||||
data, err := internal.ReadEmlFile(filePath)
|
||||
if err != nil {
|
||||
Log("Failed to read EML:", err)
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
### Development Mode
|
||||
|
||||
In dev mode (`wails dev`):
|
||||
- Hot reload enabled
|
||||
- Debug logs visible
|
||||
- DevTools accessible via Ctrl+Shift+F12
|
||||
- Danger Zone always visible in settings
|
||||
|
||||
### Production
|
||||
|
||||
- Debugger protection can terminate app if debugger detected
|
||||
- Danger Zone hidden by default
|
||||
- Access Danger Zone by clicking settings link 10 times within 4 seconds
|
||||
|
||||
---
|
||||
|
||||
## License & Credits
|
||||
|
||||
EMLy is developed by FOISX @ 3gIT.
|
||||
Reference in New Issue
Block a user