> ## Documentation Index
> Fetch the complete documentation index at: https://docs.myme.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Using the SDK in Electron

> How to consume @withmarfa/sdk from an Electron main process

`@withmarfa/sdk` is an ES module — `"type": "module"` in `package.json`, no CommonJS entry, no `require` fallback. Modern Node.js and browsers handle this natively. Electron's main process bundle does not, because the default `electron-vite` config pre-bundles dependencies for CJS interop and the SDK has nothing to pre-bundle.

The fix is to mark the SDK as an externalized dependency so it stays as a real `import` at runtime rather than being inlined into the bundle.

## Why ESM-only

The SDK has a small, modern surface — it ships one wire-types dependency (`@withmarfa/shared`), uses `fetch`, and exposes typed input/output shapes. Dual-package shipping (CJS + ESM) would double the build matrix and introduce known dual-package hazards (two copies of the same module in memory, class instances failing `instanceof` checks across the divide). Staying ESM-only keeps the surface honest.

Electron consumers pay a one-line config cost for that simplicity.

## Configuration

Use the `externalizeDepsPlugin` from `electron-vite`. It reads `package.json` and externalizes every `dependency` automatically — `@withmarfa/sdk` and `@withmarfa/shared` are covered without further config as long as they're listed as runtime dependencies, not `devDependencies`.

```typescript theme={null}
// electron.vite.config.ts
import { defineConfig, externalizeDepsPlugin } from "electron-vite";

export default defineConfig({
  main: {
    plugins: [externalizeDepsPlugin()],
  },
  preload: {
    plugins: [externalizeDepsPlugin()],
  },
  renderer: {
    // Renderer is web-shaped; the SDK works without externalization here.
  },
});
```

The SDK then resolves at runtime via Electron's Node-side module loader — the same way it would in a plain Node service.

## Process surface

Pick the process that should hold the credential.

* **Main process** is the typical choice. Credentials stay out of the renderer entirely; the renderer talks to main via IPC (preload bridge) and never sees the key. Tokens persist through Electron's `safeStorage` (keychain-backed on macOS, DPAPI on Windows, libsecret on Linux).
* **Preload** can call the SDK directly if you want the renderer's IPC surface to mirror the SDK shape. Same externalization rules apply.
* **Renderer** shouldn't hold credentials in a production app — it's a web origin and inherits all the credential-leakage risks of one. Treat it as the UI layer and route SDK calls through IPC.

## Verification

After updating the config:

1. `pnpm install`
2. `pnpm dev` (or your local `electron-vite dev` equivalent)
3. Import the SDK in the main process — `import { MarfaClient } from "@withmarfa/sdk"` — and instantiate a client. If the bundle resolves cleanly without an `ERR_REQUIRE_ESM` or `Cannot use import statement outside a module`, the externalization is working.

If the bundle still errors, confirm `@withmarfa/sdk` is in `dependencies` (not `devDependencies`) in `package.json` and that `externalizeDepsPlugin()` is wired into both `main` and `preload` configs.
