feat: convert apps/machine from Tauri to Electron (#18)
- Create electron/main.ts with BrowserWindow (1080x1920, kiosk mode) - Create electron/preload.ts with contextBridge API - Add electron/tsconfig.json for main process compilation - Update package.json: remove Tauri deps, add Electron + electron-builder - Update vite.config.ts: remove Tauri-specific build config - Update .gitignore: remove Tauri entries, add Electron build outputs - Delete src-tauri/ directory and root Cargo.toml - Update CLAUDE.md to reflect Electron architecture The Vue frontend is unchanged - works identically in Electron renderer. HAL drivers can now run directly in Electron main process (Node.js). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f7307c9159
commit
c26b6f6169
14 changed files with 2940 additions and 286 deletions
11
lamassu-next/.gitignore
vendored
11
lamassu-next/.gitignore
vendored
|
|
@ -48,14 +48,9 @@ coverage/
|
|||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Tauri
|
||||
apps/machine/src-tauri/target/
|
||||
apps/machine/src-tauri/WixTools/
|
||||
apps/machine/src-tauri/icons/
|
||||
|
||||
# Rust
|
||||
Cargo.lock
|
||||
**/*.rs.bk
|
||||
# Electron
|
||||
apps/machine/dist-electron/
|
||||
apps/machine/release/
|
||||
|
||||
# devenv
|
||||
.devenv/
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ This file provides guidance to Claude Code when working with the Lamassu Next co
|
|||
```
|
||||
lamassu-next/
|
||||
├── apps/
|
||||
│ ├── machine/ # Tauri + Vue 3 ATM kiosk application (in progress)
|
||||
│ ├── machine/ # Electron + Vue 3 ATM kiosk application ✅
|
||||
│ ├── dashboard/ # Vue 3 operator dashboard (planned)
|
||||
│ └── relay/ # strfry relay configuration (planned)
|
||||
├── packages/
|
||||
│ ├── hal/ # Rust Hardware Abstraction Layer (planned)
|
||||
│ ├── hal/ # TypeScript Hardware Abstraction Layer ✅
|
||||
│ ├── nostr-client/ # Nostr client library ✅
|
||||
│ ├── clink/ # CLINK protocol implementation ✅
|
||||
│ ├── state-machine/ # XState v5 ATM state machine ✅
|
||||
|
|
@ -40,6 +40,7 @@ lamassu-next/
|
|||
| `@lamassu/clink` | CLINK protocol (kinds 21001-21003), noffer encoding | 7 |
|
||||
| `@lamassu/lightning` | Lightning.Pub RPC client (kind 21000) | 10 |
|
||||
| `@lamassu/state-machine` | XState v5 ATM state machine (idle, cashIn, cashOut) | 14 |
|
||||
| `@lamassu/hal` | Hardware drivers (ID003 validator, F56 dispenser) | - |
|
||||
|
||||
### Placeholder Packages
|
||||
|
||||
|
|
@ -48,11 +49,13 @@ lamassu-next/
|
|||
| `@lamassu/cashu` | Cashu ecash for offline operation |
|
||||
| `@lamassu/ui-shared` | Shared Vue 3 components |
|
||||
|
||||
### Completed Applications
|
||||
|
||||
- **apps/machine** - Electron ATM kiosk with Vue 3 UI (HAL integrated, ready for hardware testing)
|
||||
|
||||
### Planned Components
|
||||
|
||||
- **apps/machine** - Tauri 2.x ATM kiosk with Vue 3 UI (UI shell implemented, HAL integration pending)
|
||||
- **apps/dashboard** - Operator dashboard for fleet management
|
||||
- **packages/hal** - Rust hardware drivers (bill validators, dispensers, printers)
|
||||
|
||||
### Critical Documentation
|
||||
|
||||
|
|
@ -159,11 +162,11 @@ Use these to interact with infrastructure directly during development.
|
|||
## Key Technologies
|
||||
|
||||
| Component | Technology | Notes |
|
||||
| ------------- | -------------- | ------------------------------------- |
|
||||
| ------------- | -------------- | --------------------------------------- |
|
||||
| Runtime | Node.js 22 LTS | Strict TypeScript, ESM |
|
||||
| ATM Shell | Tauri 2.x | Rust core, Vue 3 UI (planned) |
|
||||
| ATM Shell | Electron | Node.js main process, Vue 3 renderer |
|
||||
| State Machine | XState v5 | Actor model, service injection |
|
||||
| Hardware | Rust + napi-rs | Ported from lamassu-machine (planned) |
|
||||
| Hardware | TypeScript | ID003, F56 drivers from lamassu-machine |
|
||||
| Messaging | Nostr | NIP-01, NIP-42, NIP-44 |
|
||||
| Payments | CLINK + RPC | Kind 21000 (RPC), 21001-21003 (CLINK) |
|
||||
| Backend | Lightning.Pub | Nostr-native account system |
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["apps/machine/src-tauri"]
|
||||
78
lamassu-next/apps/machine/electron/main.ts
Normal file
78
lamassu-next/apps/machine/electron/main.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* Electron Main Process
|
||||
*
|
||||
* Creates the ATM kiosk window and handles IPC with the renderer.
|
||||
* In production, runs in kiosk mode (fullscreen, no decorations).
|
||||
* HAL hardware drivers run here (Node.js environment).
|
||||
*/
|
||||
|
||||
import { app, BrowserWindow, ipcMain } from 'electron'
|
||||
import path from 'node:path'
|
||||
|
||||
// Determine if we're in development
|
||||
const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged
|
||||
|
||||
// Window dimensions (vertical ATM display)
|
||||
const WINDOW_WIDTH = 1080
|
||||
const WINDOW_HEIGHT = 1920
|
||||
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
|
||||
function createWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: WINDOW_WIDTH,
|
||||
height: WINDOW_HEIGHT,
|
||||
resizable: isDev, // Allow resize in dev for debugging
|
||||
frame: isDev, // Show window frame in dev
|
||||
kiosk: !isDev, // Kiosk mode in production
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
},
|
||||
})
|
||||
|
||||
// Load the app
|
||||
if (isDev) {
|
||||
// Development: load from Vite dev server
|
||||
const devServerUrl = process.env.VITE_DEV_SERVER_URL || 'http://localhost:1420'
|
||||
mainWindow.loadURL(devServerUrl)
|
||||
mainWindow.webContents.openDevTools()
|
||||
} else {
|
||||
// Production: load from built files
|
||||
mainWindow.loadFile(path.join(__dirname, '../dist/index.html'))
|
||||
}
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// IPC Handlers
|
||||
ipcMain.handle('get-version', () => {
|
||||
return app.getVersion()
|
||||
})
|
||||
|
||||
// App lifecycle
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', () => {
|
||||
// macOS: re-create window when dock icon clicked
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
// Quit on all platforms (ATM doesn't need macOS dock behavior)
|
||||
app.quit()
|
||||
})
|
||||
|
||||
// Security: prevent new window creation
|
||||
app.on('web-contents-created', (_, contents) => {
|
||||
contents.setWindowOpenHandler(() => {
|
||||
return { action: 'deny' }
|
||||
})
|
||||
})
|
||||
27
lamassu-next/apps/machine/electron/preload.ts
Normal file
27
lamassu-next/apps/machine/electron/preload.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Electron Preload Script
|
||||
*
|
||||
* Exposes a secure API to the renderer process via contextBridge.
|
||||
* This is the only way for the Vue app to communicate with the main process.
|
||||
*/
|
||||
|
||||
import { contextBridge, ipcRenderer } from 'electron'
|
||||
|
||||
// Expose protected methods to renderer
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
// Get app version
|
||||
getVersion: (): Promise<string> => ipcRenderer.invoke('get-version'),
|
||||
|
||||
// Platform info
|
||||
platform: process.platform,
|
||||
})
|
||||
|
||||
// Type declaration for the exposed API
|
||||
declare global {
|
||||
interface Window {
|
||||
electronAPI: {
|
||||
getVersion: () => Promise<string>
|
||||
platform: NodeJS.Platform
|
||||
}
|
||||
}
|
||||
}
|
||||
13
lamassu-next/apps/machine/electron/tsconfig.json
Normal file
13
lamassu-next/apps/machine/electron/tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "../dist-electron",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["./**/*.ts"]
|
||||
}
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
{
|
||||
"name": "@lamassu/machine",
|
||||
"version": "0.1.0",
|
||||
"description": "Tauri 2.x ATM kiosk application with Vue 3 UI",
|
||||
"description": "Electron ATM kiosk application with Vue 3 UI",
|
||||
"type": "module",
|
||||
"main": "dist-electron/main.js",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && vite build",
|
||||
"dev": "concurrently -n vite,electron \"vite\" \"pnpm run electron:dev\"",
|
||||
"dev:vite": "vite",
|
||||
"electron:dev": "tsc -p electron/tsconfig.json && electron dist-electron/main.js",
|
||||
"build": "vue-tsc --noEmit && vite build && tsc -p electron/tsconfig.json",
|
||||
"build:electron": "pnpm build && electron-builder",
|
||||
"preview": "vite preview",
|
||||
"tauri": "tauri",
|
||||
"tauri:dev": "tauri dev",
|
||||
"tauri:build": "tauri build",
|
||||
"typecheck": "vue-tsc --noEmit",
|
||||
"lint": "eslint src/"
|
||||
},
|
||||
|
|
@ -33,14 +34,33 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"@tauri-apps/api": "^2.1.0",
|
||||
"@tauri-apps/cli": "^2.1.0",
|
||||
"@types/node": "^22.0.0",
|
||||
"@vitejs/plugin-vue": "^5.2.0",
|
||||
"concurrently": "^9.0.0",
|
||||
"electron": "^33.0.0",
|
||||
"electron-builder": "^25.0.0",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.7.0",
|
||||
"vite": "^6.0.0",
|
||||
"vue-tsc": "^2.1.0"
|
||||
},
|
||||
"build": {
|
||||
"appId": "dev.lamassu.atm",
|
||||
"productName": "Lamassu ATM",
|
||||
"directories": {
|
||||
"output": "release"
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"dist-electron/**/*"
|
||||
],
|
||||
"linux": {
|
||||
"target": [
|
||||
"AppImage",
|
||||
"deb"
|
||||
],
|
||||
"category": "Finance"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
[package]
|
||||
name = "lamassu-machine"
|
||||
version = "0.1.0"
|
||||
description = "Lamassu ATM Kiosk Application"
|
||||
authors = ["Lamassu Industries"]
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
|
||||
[lib]
|
||||
name = "lamassu_machine_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "2", features = [] }
|
||||
tauri-plugin-shell = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
||||
[features]
|
||||
# This feature is used for production builds or when a dev server is not specified
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
//! Lamassu ATM Tauri Application
|
||||
//!
|
||||
//! This is the Rust backend for the Lamassu ATM kiosk application.
|
||||
//! Hardware drivers and native functionality will be implemented here.
|
||||
|
||||
use tauri::Manager;
|
||||
|
||||
/// Greet command for testing Tauri IPC
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! Welcome to Lamassu ATM.", name)
|
||||
}
|
||||
|
||||
/// Get application version
|
||||
#[tauri::command]
|
||||
fn get_version() -> String {
|
||||
env!("CARGO_PKG_VERSION").to_string()
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.setup(|app| {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let window = app.get_webview_window("main").unwrap();
|
||||
window.open_devtools();
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![greet, get_version])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
// Prevents additional console window on Windows in release
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
lamassu_machine_lib::run()
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Lamassu ATM",
|
||||
"version": "0.1.0",
|
||||
"identifier": "io.lamassu.atm",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"devUrl": "http://localhost:1420",
|
||||
"beforeBuildCommand": "pnpm build",
|
||||
"frontendDist": "../dist"
|
||||
},
|
||||
"app": {
|
||||
"withGlobalTauri": true,
|
||||
"windows": [
|
||||
{
|
||||
"title": "Lamassu ATM",
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"resizable": false,
|
||||
"fullscreen": false,
|
||||
"decorations": true
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -11,28 +11,23 @@ export default defineConfig({
|
|||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
},
|
||||
// Tauri expects a fixed port during development
|
||||
// Dev server configuration
|
||||
server: {
|
||||
port: 1420,
|
||||
strictPort: true,
|
||||
watch: {
|
||||
ignored: ['**/src-tauri/**'],
|
||||
},
|
||||
},
|
||||
// Build configuration for Tauri
|
||||
// Build configuration for Electron renderer
|
||||
build: {
|
||||
// Tauri uses Chromium on Windows and WebKit on macOS and Linux
|
||||
target: process.env.TAURI_ENV_PLATFORM === 'windows' ? 'chrome105' : 'safari14',
|
||||
// Don't minify for debug builds
|
||||
minify: !process.env.TAURI_ENV_DEBUG ? 'esbuild' : false,
|
||||
// Produce sourcemaps for debug builds
|
||||
sourcemap: !!process.env.TAURI_ENV_DEBUG,
|
||||
// Target modern Chrome (Electron uses Chromium)
|
||||
target: 'chrome120',
|
||||
// Sourcemaps for debugging
|
||||
sourcemap: process.env.NODE_ENV === 'development',
|
||||
rollupOptions: {
|
||||
// @lamassu/hal uses Node.js APIs (serialport, node:events) and will only
|
||||
// run in Electron's main process. Exclude from browser bundle.
|
||||
// run in Electron's main process. Exclude from renderer bundle.
|
||||
external: ['@lamassu/hal'],
|
||||
},
|
||||
},
|
||||
// Prevent Vite from clearing the screen
|
||||
// Prevent Vite from clearing the screen (useful when running with Electron)
|
||||
clearScreen: false,
|
||||
})
|
||||
|
|
|
|||
2877
lamassu-next/pnpm-lock.yaml
generated
2877
lamassu-next/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue