Production-ready Electron desktop app with Mainlayer payment gating. Supports license key activation, premium feature unlocking, and 7-day offline grace period for seamless user experience.
# Clone and install
git clone https://github.com/your-org/electron-app-mainlayer.git
cd electron-app-mainlayer && npm install
# Set environment variables
export MAINLAYER_API_KEY=your_secret_key
export MAINLAYER_PREMIUM_RESOURCE_ID=your_resource_id
# Run dev
npm run build && npm run devCreate a .env.local file (not committed):
MAINLAYER_API_KEY=sk_live_...
MAINLAYER_PREMIUM_RESOURCE_ID=feature_premium| Variable | Description | Example |
|---|---|---|
MAINLAYER_API_KEY |
Secret API key from Mainlayer dashboard | sk_live_abc123... |
MAINLAYER_PREMIUM_RESOURCE_ID |
Resource ID for premium tier | feature_premium |
The app follows process isolation best practices:
- Main process (
src/main.ts): Electron entry. All Mainlayer API calls via IPC. - Preload (
src/preload.ts): TypedcontextBridgebridge. Renderer callswindow.mainlayer.*. - Renderer (
src/renderer/App.tsx): React UI, zero Node.js/Electron API access. - License manager (
src/mainlayer.ts): License verification, local caching, offline fallback.
- Online verification with fallback to cached license
- 7-day offline grace period for intermittent connectivity
- 24h cache refresh with background updates
- Paywall component with beautiful UI
- IPC-based security — no API keys exposed to renderer
- TypeScript throughout with full type safety
- Vitest test suite with mocked dependencies
const status = await window.mainlayer.verify(userId);
console.log(status.authorized); // true | false
console.log(status.plan); // 'free' | 'pro' | 'enterprise'
console.log(status.offline); // true if in offline grace periodconst result = await window.mainlayer.activate(userId, licenseKey);
if (result.success) {
console.log(result.message);
// Re-verify to get updated plan
const updated = await window.mainlayer.verify(userId);
}- Startup: Main process verifies license on app launch
- Cache miss: Falls back to 7-day grace period
- Activation: User enters license key via paywall
- Refresh: Background refresh every 24h
- Offline: Works offline for up to 7 days
# Development
npm run dev
# Build
npm run build
# Package (requires code signing for distribution)
npm run dist
# Quick package (no signing)
npm run pack# Run tests
npm test
# Watch mode
npm test:watch
# Lint
npm run lint- Set
MAINLAYER_API_KEYin production environment - Update
MAINLAYER_PREMIUM_RESOURCE_IDto your actual resource - Enable code signing for macOS/Windows distributions
- Test offline grace period (disconnect network, verify after 7 days)
- Verify IPC security (no API key leakage to renderer)
- Set proper app name/icon in
electron-builderconfig
src/
├── main.ts # Electron main (IPC handlers)
├── preload.ts # Typed contextBridge API
├── mainlayer.ts # License manager logic
└── renderer/
├── App.tsx # Root component
├── components/
│ └── Paywall.tsx # Payment/activation UI
└── index.html
Check if user has license. Returns cached result or offline grace period status.
Returns: Promise<LicenseStatus>
interface LicenseStatus {
authorized: boolean;
plan: string;
offline: boolean;
gracePeriodActive: boolean;
gracePeriodRemainingMs?: number;
}Activate a license key for the user.
Returns: Promise<{ success: boolean; message: string }>
Sign out / clear the stored license.
Returns: Promise<{ success: boolean }>
Open Mainlayer pricing page in default browser.
- Docs: https://docs.mainlayer.fr
- Issues: Report bugs on GitHub
- Contact: support@mainlayer.fr