Appearance
Storage & sync
remap is local-first. A user who has never heard of remap gets working, still-remappable shortcuts with nothing but localStorage. Sync layers exist for users who want their keybindings to follow them — and cost you zero code either way.
Resolution order
For each shortcut id, the effective combo is the first layer that has an entry:
| Priority | Layer | Where | When it applies |
|---|---|---|---|
| 1 | Local | localStorage remap:<appId>:overrides | Always — set via the ⌘, overlay |
| 2 | Device | http://127.0.0.1:53137/v1/config/:appId | remap menubar agent running (macOS app in progress) |
| 3 | Account | GET /api/sync/config/:appId on the remap server | User connected a sync token |
| 4 | Defaults | the keys you passed to useHotkey | Always |
An override value of null means the user disabled that shortcut.
Layers 2–3 load asynchronously with short timeouts (400ms local probe, 3s remote) and fail silently — no agent, no network, no problem. Writes fan out to every available layer, so remapping in one place propagates everywhere the user is connected.
The appId
Configs are keyed by appId (default: location.hostname). Pass an explicit stable id so localhost dev, previews, and production share one config:
tsx
<RemapProvider appId="myapp.com">Account sync (cross-device)
- The user signs up at remap.harborapps.org and copies their sync token (
rmp_…) from the dashboard. - In your app, the token is stored via
setSyncToken(token)(or directly under theremap:sync-tokenlocalStorage key). A built-in connect flow in the overlay is on the roadmap. - From then on the library loads and saves their overrides on the remap server — the same config on every device and every remap-powered app.
The sync API is deliberately tiny — bearer tokens, never cookies, CORS-open:
GET /api/sync/config/:appId Authorization: Bearer rmp_…
PUT /api/sync/config/:appId { "overrides": { "editor.save": "mod+shift+s" } }Opting out
tsx
<RemapProvider serverUrl={null} agentPort={null}>disables all network layers — pure localStorage. Useful for demos, tests, and privacy-sensitive apps.