Skip to main content
Everything on this page is exported from the package root, @ekanos/integration-schema. There are no subpath entrypoints.

Integration Definition Contract

IntegrationDefinitionSchema

The canonical, strict zod schema for an integration definition — the same schema @ekanos/sdk’s defineIntegration() and the Ekanos host validate against.
Among other rules, the schema:
  • Requires slug (kebab-case), name, description, and a semver version
  • Rejects unknown keys on the definition and its declaration objects (.strict())
  • Requires unique widget ids, tool names, webhook ids, and schedule ids within a definition
  • Checks tool names are lowercase snake_case, and widget, webhook, schedule, and action ids are kebab-case
  • Checks storage keys against the scope’s allowed data types
  • Requires egress entries to be https:// origins (optionally https://*. wildcards), and OAuth endpoints to be https:// URLs
Prefer parseIntegrationDefinition() or collectDefinitionFindings() over calling safeParse directly: they also run the plain-data pre-check (below) and return friendlier messages.

parseIntegrationDefinition(input)

The single validation entry point used by both defineIntegration() and the host. It rejects non-plain containers, parses against the schema, and returns the sanitized, deep-frozen result.data — never the caller’s object. On failure it throws an Error whose message lists every issue.

collectDefinitionFindings(input, options?)

The non-throwing sibling of parseIntegrationDefinition(). Returns an array of findings; an empty array means the definition is valid. Synchronous.
Findings use check: 'definition.plain-data' for a failed plain-data pre-check, and check: 'definition.schema' for each schema issue, with the zod path at the start of message (e.g. components.widgets.0.id: …).

validateIntegrationDefinitions(definitions, firstParty?)

Detects collisions across a set of definitions — duplicate slugs, widget ids, and effective tool names — and, when firstParty is given, against first-party identifiers. Returns nothing on success; throws one Error listing every collision.

collectCollisionFindings(definitions, firstParty?)

The non-throwing sibling of validateIntegrationDefinitions(). Every finding is severity: 'error', with check one of collision.slug, collision.widget-id, collision.tool-name, collision.reserved-slug, collision.reserved-widget-id, or collision.reserved-tool-name.

getDiscoveredToolName(slug, rawName)

The effective tool name discovery registers: the raw name prefixed with the slug in snake*case (slug.replace(/-/g, '*')), unless the name already starts with that prefix. Collision checks compare effective names.

assertPlainDeclaration(value, path?, ancestors?)

Throws if a declaration contains a cycle, a getter/setter, or a class/exotic instance where a plain object or array is expected. Functions and zod schemas are allowed as leaves. parseIntegrationDefinition() and collectDefinitionFindings() run this for you.

deepFreezeDefinition(value)

Cycle-aware deep freeze of plain objects and arrays, in place. Leaves zod schemas and functions alone. Returns nothing. parseIntegrationDefinition() already returns a frozen result.

Integration Definition Types

These TypeScript types are re-exported by @ekanos/sdk. The generic Schemas parameter types ctx.storage from your storage declaration.

IntegrationDefinition<Schemas>

IntegrationComponentDeclarations

PartnerWidgetDeclaration

Inferred from the widget schema:

IntegrationCapabilityDeclaration and IntegrationPermissionDeclaration

PartnerToolModule<Schemas>

A tool exposed to the assistant.

PartnerActionDeclaration<TInput, TOutput, Schemas>

A widget-invoked server handler, keyed by kebab-case action name in actions.

IntegrationProposals and ToolClassificationProposal

Values a partner proposes; the host decides.
Every key in proposes.tools must match a declared tool name.

OnActivateHandler<Schemas>

Runs after an activation is first persisted and again whenever its activation data is updated. Errors are non-fatal: a throw is logged and surfaced as a warning, and the activation stays active.

Capability-Context Types

The canonical home of the context types; @ekanos/sdk re-exports them. The value half (error classes, the egress matcher) lives in @ekanos/sdk/context.

IntegrationContext<Schemas>

The one object handlers receive (tools, actions, webhooks, schedules, onTokens, onActivate).

IntegrationActor

IntegrationStorage<Schemas> and ScopedStore

Each scope is already bound to the account (and user) — there is no id parameter. set validates against the key’s schema before writing, and a read whose stored data no longer matches the schema throws StorageValidationError.

StorageSchemas, StorageSchemaMap, and key declarations

A key is "<dataType>" or "<dataType>/<subtype>" in lowercase [a-z0-9_-]. clientReadable: true opts a key in to the browser-readable storage route; omitted, a key is server-only. StorageScopeSchemas and StorageKeySchema are helper types that resolve a scope’s map and a key’s zod schema.

IntegrationSecrets

set writes only to the account-tier store; writing a name that resolves only from source or global tiers throws SecretAccessError.

IntegrationFetch

Enforced against the definition’s egress allowlist on the resolved URL’s origin, redirect targets included. A denied call throws EgressDeniedError before any network I/O.

IntegrationLogger

Pino-style: the context object comes first. The host pre-binds the integration, account, and actor to every line.

Event Surfaces

PartnerWebhookDeclaration<Schemas>

Signature verification is the transport’s job, not the handler’s. The cross-field rules on scheme (a keyed format needs a digestKey, {timestamp} needs a source, a timestamp source needs {timestamp} in signedPayload, and so on) are enforced at parse time; see Webhooks. A handler that cannot process a valid event should throw, which the transport maps to a retryable failure.

PartnerScheduleDeclaration<Schemas>

This package checks only that cron is present; defineIntegration() validates the syntax.

PartnerOAuthDeclaration<Schemas>

The transport owns the flow; onTokens persists tokens via ctx.secrets. defineIntegration() rejects the declaration unless both endpoint origins are covered by egress.

Workspace Targets

WorkspaceTargetSlugSchema

A trimmed string, 1–100 characters, lowercase alphanumeric with single hyphens between segments.

WorkspaceTargetLayoutSchema

createWorkspaceTargetSchema(options?) and WorkspaceTargetSchema

Builds the schema for one target. WorkspaceTargetSchema is the default instance with no icon-name check (icons are still validated as non-empty strings up to 100 characters).
A target cannot set both inheritsWidgets and includedWidgetIds, and includedWidgetIds must not be empty.

WorkspaceTargetDefinition and ResolvedWorkspaceTarget

WorkspaceTargetDefinition is the input type; ResolvedWorkspaceTarget is the parsed output, where layout defaults to 'masonry'.

createWorkspaceTargetListSchema(options?) and WorkspaceTargetListSchema

The schema for a whole declaration set: at most 20 targets, unique slugs, and exactly one target without includedWidgetIds that sets inheritsWidgets: true (a single target may omit it). IntegrationDefinitionSchema validates workspaceTargets with WorkspaceTargetListSchema.

normalizeWorkspaceTargets(declared, options?)

Parses a declaration set without throwing, and fills in inheritsWidgets: true for a lone target that omitted it.

Storage Data Types

The dataType segment of every storage key must come from its scope’s list.
secret is never addressable through ctx.storage; use ctx.secrets instead.

Product ID Derivation

Deterministic slug → UUID derivation, so the same slug yields the same id everywhere.

deriveProductId(slug)

uuidv5(slug, EKANOS_INTEGRATION_NAMESPACE). Throws if slug is not kebab-case.

derivePlanId(slug, planName)

uuidv5('plan:<slug>:<planName>', EKANOS_INTEGRATION_NAMESPACE), with planName trimmed and lowercased first. Throws on a non-kebab-case slug or an empty plan name.

uuidv5(name, namespace)

RFC 4122 version 5. Note the argument order: the name first, then the namespace UUID.

EKANOS_INTEGRATION_NAMESPACE and DNS_NAMESPACE

EKANOS_INTEGRATION_NAMESPACE is '269944fc-4736-5497-b751-381be92fb8df' — itself uuidv5('ekanos.dev', DNS_NAMESPACE). DNS_NAMESPACE is the standard RFC 4122 DNS namespace, '6ba7b810-9dad-11d1-80b4-00c04fd430c8'.

Component References

ComponentReference

A dependency-pure stand-in for a React component:
A function component (or the function React.lazy returns), or a React exotic object such as memo or forwardRef. Pass the component itself, not an element or a module path.

isComponentReference(value)

True for any function, or any object with a $$typeof property.

Utility Types

JsonValue

Where the schema validates a JsonValue (for example outputExample), Infinity, -Infinity, and NaN are rejected.

DefinitionCollisionInput and FirstPartyInventory

A full IntegrationDefinition is assignable to DefinitionCollisionInput.

Findings

Finding

line is usually absent — zod reports a path, which appears in message. ekanos validate adds line when it can locate the path in your source.

CollectDefinitionOptions


Import Guide


Versioning

The CLI bundles an exact schema version and fails fast with exit 9 if your project resolves a newer one (see Keeping the Toolchain Current).