--- title: Electron SDK --- # Electron SDK Electron SDK 는 전적으로 **메인 프로세스** 에서 실행되며, OS 가 관리하는 네이티브 창으로 CAPTCHA UI 를 띄웁니다. 렌더러 프로세스는 검증 과정에 관여하지 않습니다 — 보안을 위해 이 분리를 유지하세요. ## GitHub 데모 ::: tip 📦 [Captcha-La/electron-demo](https://github.com/Captcha-La/electron-demo) — 모든 통합 단계가 포함된 실행 가능한 예제. ::: ## 설치 ```bash npm install @captchala/electron ``` The package targets **Electron 28+** (the demo pins `^33.0.0`) and **Node 18+**. Run the demo end-to-end with: ```bash npm install npm start ``` ## 빠른 시작 ```js // main.js (Electron main process — never the renderer) const { app, BrowserWindow, ipcMain } = require('electron'); const path = require('path'); const { CaptchalaClient } = require('@captchala/electron'); let currentClient = null; ipcMain.handle('verify', async (event, opts) => { // 1. Fetch a one-shot server_token from YOUR backend. const serverToken = await fetchServerTokenFromYourBackend(opts.action); // 2. Tear down any prior client, then build a fresh one. if (currentClient) { currentClient.destroy(); currentClient = null; } currentClient = new CaptchalaClient({ appKey: 'YOUR_APP_KEY', serverToken, action: opts.action, // 'login' | 'register' | 'pay' | … lang: opts.lang, // 'en' | 'zh-CN' | 'ja' | … theme: opts.theme, // 'light' | 'dark' timeoutMs: 15000, retryCount: 3, onReady: () => event.sender.send('captcha-status', 'ready'), onFail: (e) => event.sender.send('captcha-status', `recoverable: ${e.code}`), }); try { const result = await currentClient.verify(); // Send result.passToken to YOUR backend for validation. return { success: true, passToken: result.passToken }; } catch (err) { return { success: false, error: err.message }; } finally { if (currentClient) { currentClient.destroy(); currentClient = null; } } }); function createWindow() { const win = new BrowserWindow({ width: 520, height: 640, resizable: false, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false, }, }); win.loadFile('index.html'); } app.whenReady().then(createWindow); app.on('window-all-closed', () => app.quit()); ``` ```js // preload.js — bridge the renderer to the main-process verify(). const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('captchala', { verify: (opts) => ipcRenderer.invoke('verify', opts), onStatus: (callback) => ipcRenderer.on('captcha-status', (_, msg) => callback(msg)), }); ``` ## 주요 API | 심볼 | 용도 | | --- | --- | | `new CaptchalaClient({...})` | 일회용 클라이언트를 생성합니다. `appKey`, `serverToken`, `action`, `lang`, `theme`, `timeoutMs`, `retryCount` 및 이벤트 핸들러를 전달합니다. | | `await client.verify()` | 네이티브 CAPTCHA 창을 엽니다. 성공 시 결과로 resolve, 치명적 오류 시 reject 합니다. | | `onReady` / `onFail` | 생성자에 전달하는 선택적 핸들러. `onFail` 은 *복구 가능한* 실패용입니다(SDK 가 재시도). | | `result.passToken` | 백엔드에서 검증할 토큰. 클라이언트에서는 항상 불투명한 값입니다. | | `client.destroy()` | 창을 닫고 자원을 해제합니다. 클라이언트 인스턴스 사용 후 반드시 호출하세요. | | `CaptchalaClient.version()` | SDK 버전 문자열을 반환하는 정적 헬퍼. 지원/디버그 화면에 유용합니다. | ## 서버 측 검증 `result.passToken`(또는 `result.token`)을 백엔드로 전달하고 CaptchaLa API로 검증합니다. **`X-App-Secret`을 클라이언트 코드에 노출하지 마세요**. ```bash POST https://apiv1.captcha.la/v1/validate X-App-Key: YOUR_APP_KEY X-App-Secret: YOUR_APP_SECRET Content-Type: application/json { "pass_token": "" } ``` 전체 검증 엔드포인트와 `X-App-Key` / `X-App-Secret` 흐름은 [API 레퍼런스](../api-reference)를 참고하세요. ## 문제 해결 - **렌더러에서 SDK 를 import 하지 마세요** `@captchala/electron` 은 **메인 프로세스 전용** 입니다. 데모의 `preload.js` 처럼 `contextBridge` + `ipcRenderer.invoke()` 로 결과를 노출하세요. `nodeIntegration: false`, `contextIsolation: true` 를 유지하세요. - **런타임에 모듈을 찾을 수 없음** `@captchala/electron` 은 `dependencies` 에 두세요(`devDependencies` 아님). 최종 앱에 번들되어야 하며, electron-builder 같은 도구는 자동으로 포함합니다. - **CAPTCHA 창이 메인 창 뒤에 뜸** Linux/X11 의 특성입니다. 직접 `BrowserWindow` 로 감싼다면 `parent` 를 전달하거나, `verify()` 반환 후 `mainWindow.focus()` 를 호출하세요. - **Electron 28+ 필요** 데모는 `electron: ^33.0.0` 을 선언합니다. 더 오래된 Electron 은 SDK 가 의존하는 API 가 빠질 수 있으니 `28+`, Node 18+ 로 고정하세요. ## 요구 사항 - Electron 28+ (the demo uses 33.x) - Node 18+ - Cross-platform: macOS, Windows 10 1809+, Linux (X11 / Wayland)