Main entries
@ekanos/harness/registry
Types and helpers for building your harness.config.ts. Server-safe.
interface
Your registry entry:
slug, name, description, widgets, plus optional
fixtures, tile, activationForm, definition, triggerMocks, live,
oauth.interface
One widget to render:
id, title, component, plus optional width,
isCollapsible, isPinnable, aiFooterEnabled, seeds.interface
One recorded HTTP exchange:
request (method + URL), response, status,
headers.interface
React-query cache seed:
queryKey, and either data or error.'default' | 'empty' | 'error'
The three fixture variants switchable from the toolbar.
interface
Live mode config:
seeds (react-query keys that stay mocked in live mode),
default ('live' to open in live mode until the toolbar is changed),
egress (only for an entry with no definition), FetchProvider
(deprecated; for composing an authenticated fetch once).interface
Fixtures-mode mock context for triggers and actions:
storage
(account/user rows), secrets (account/admin tiers), fetchHandlers
(dynamic or stateful responses).string
Plausible UUID for
accountId context.string
Plausible UUID for
sourceId context.string
Plausible slug for account context.
readonly string[]
['default', 'empty', 'error'] — all valid variant names.'fixtures' | 'live'
The two toolbar data modes.
function
Derive
HarnessWidget[] from your definition to avoid duplication. The
overrides map, keyed by widget id, supplies harness-only fields (width,
seeds); an unknown key throws.function
Erase the storage generic so your
IntegrationDefinition<S> fits in the heterogeneous registry array.@ekanos/harness/config
function
Identity function that exists for type inference. Also throws if a slug or
widget id is not URL-safe, or if one is duplicated.
@ekanos/harness/app
Components and metadata mounted by the generated shell. The entry itself carries no 'use client' directive.
component
The client boundary of the whole harness; mounts the providers and the
registry context. Props:
integrations: HarnessIntegration[], children.component
Landing page listing all integrations. Props:
integrations: HarnessIntegration[].Metadata
A Next.js
Metadata object for the shell’s layout.@ekanos/harness/routes
Client page components (the entry is 'use client') re-exported by the shell’s one-line route files, for example export { WidgetsPage as default } from '@ekanos/harness/routes';.
component
Wrapper for integration pages (
/<slug>/). Renders tabs and nav.component
Dashboard grid with all widgets.
component
Single widget in isolation at
/<slug>/widgets/<widgetId>.component
Marketplace tile, rendered in the catalogue grid.
component
Activation form and OAuth panel.
component
Webhooks, schedules, OAuth declaration, and Local OAuth panel.
@ekanos/harness/hooks
Hooks for code that only ever runs inside the harness (a debug banner, a dev-only branch), never a widget’s shipped data path. For activation data in widget code, prefer useActivationData() from @ekanos/sdk/hooks.
'fixtures' | 'live'
Returns the EFFECTIVE data mode (accounting for a missing
live block or
egress mismatch forcing fixtures).unknown
Returns the activation data last submitted for this integration. Held in
memory only, never written to
localStorage, a fixture, or the registry;
cleared on reload and on Disconnect.@ekanos/harness/api
Server-only entry. Never import from a 'use client' module.
function
Returns
{ GET, POST, PUT } route handlers for the shell’s one API route. Serves oauth/{connect,callback,status}, storage, trigger, local-setup, and actions/<actionName> under /api/integrations/[slug]/. See Live Mode.interface
{ GET: NextRouteHandler, POST: NextRouteHandler, PUT: NextRouteHandler }type
(request: Request, context: { params: Promise<HarnessRouteParams> }) => Promise<Response>@ekanos/harness/styles.css
Tailwind layer, design tokens, Font Awesome repairs, and @source globs covering the harness chrome.
@ekanos/harness/mocks/team-account-workspace
Stand-in for the host’s useTeamAccountWorkspace(). The generated next.config.mjs aliases @kit/team-accounts/hooks/use-team-account-workspace onto it, so unmodified widget source runs unchanged.
Data modes
DataMode
@ekanos/harness/registry. Returned by useHarnessDataMode() and passed as the mode prop to a live.FetchProvider.
Errors you will see
These are not exported by@ekanos/harness; match them by error.name.
NoRecordedResponseError
Thrown (as a rejected fetch) when a request has no matching fixture. Carries method and url (credentials redacted), and its message includes the fixture line to paste. See Fixtures.
MissingFixtureError
Thrown when a react-query query has neither a seed nor a queryFn of its own.
EgressDeniedError
From @ekanos/sdk/context. Thrown in live mode when a request targets an origin outside the declared egress. Carries origin, an optional reason, and code: 'EGRESS_DENIED'.
LiveActionNotConfirmedError
Thrown when a live-mode action’s confirmation prompt is declined. See Actions.
Handler context
Webhook, schedule, action,onActivate, and onTokens handlers receive the SDK’s IntegrationContext (exported as a type from @ekanos/sdk): accountId, accountSlug, userId, actor, sourceId, integration, timezone, storage, secrets, fetch, and logger. In fixtures mode it is a createMockContext() context; in live mode, the server-held live context.
TypeScript
The published package ships its types indist/*.d.ts. To check your harness.config.ts, run npx tsc --noEmit in your project.