Skip to main content

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.

@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.
// 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.