@ekanos/harness) is a local development environment that renders every surface of your integration—widgets, the marketplace tile, activation form, and triggers—in actual Ekanos chrome, without Supabase, authentication, or network traffic.
Key features
- Real chrome, no backend — widgets render in the actual Ekanos dashboard grid with real
Widget.*compound components and design tokens - Fixtures by default — HTTP exchanges recorded per variant (
default,empty,error) answer all requests; the network is refused - Live mode opt-in — switch the toolbar to Live API to send real requests to your vendor under your declared egress, with a real localhost OAuth loop for OAuth integrations
- Fixture variants — switch between happy path, empty state, and error from the toolbar; the widget subtree is rebuilt, so any widget that re-fetches gets the new recording
- Triggers surface — run webhooks and schedules locally, and (in live mode) the OAuth loop against your own developer app
- Actions surface — invoke your declared
actionshandlers from a widget’s Save button; runs in fixtures or live - No configuration required —
useIntegrationFetch()anduseActivationData()from@ekanos/sdk/hooksalready work; write fixtures and you’re done
Installation
A project created byekanos init already lists @ekanos/harness in its package.json. Install dependencies, then run:
ekanos dev checks that the harness and its peers (next, react, react-dom, tailwindcss, @tailwindcss/postcss) are installed, generates the shell under .ekanos/harness/, writes a starter harness.config.ts at your project root the first time (the only file you edit), and starts the dev server. The generated shell is rewritten on upgrade; your harness.config.ts is never touched after it is created.
Quick start
Set upharness.config.ts with one integration:
ekanos dev serves the harness at http://localhost:3100 by default (bound to loopback; --port and --host change that). Select your integration to see tabs for Widgets, Marketplace tile, Activation, and Triggers.
Surfaces
Each integration is rendered at/<slug> with four tabbed surfaces:
- Widgets — your dashboard grid, rendered with real
Widget.*components - Marketplace tile — your marketplace card, in the catalogue grid (if declared)
- Activation — the form users see when connecting your integration
- Triggers — your declared webhooks, schedules, and OAuth (requires
definition)
/<slug>/widgets/<widgetId>.
How data flows
Fixtures mode (default)
- The toolbar’s Data dropdown is on Fixtures (the default)
globalThis.fetchis patched to intercept third-party and/api/…requests- Requests match against your
fixtureslist for the active variant - A matching fixture is returned; no request leaves the machine
- An unmatched request rejects with
NoRecordedResponseError, whose message includes the fixture line to paste
Live mode (opt-in)
- A
liveblock is declared on the integration entry - The toolbar’s Data dropdown is set to Live API
- Widgets’ own requests reach your real API
- Requests are checked against your definition’s
egressallowlist - The OAuth loop runs on localhost using client credentials from
.ekanos/local-secrets.json - One server-held context per integration holds tokens and storage for the life of the dev server
What’s in the bundle
Everything inharness.config.ts is compiled into the browser bundle, including triggerMocks.secrets. Keep mock values fake. The .ekanos/ directory (and its .next build output) is gitignored; never commit the generated build.