> ## Documentation Index
> Fetch the complete documentation index at: https://sdk.ekanos.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Schema Reference

> Complete reference of exported types, schemas, and utilities from @ekanos/integration-schema.

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.

```typescript theme={null}
import { IntegrationDefinitionSchema } from '@ekanos/integration-schema';

const result = IntegrationDefinitionSchema.safeParse(definition);
if (!result.success) {
  console.error(result.error.issues);
}
```

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

<Note>
  Prefer `parseIntegrationDefinition()` or `collectDefinitionFindings()` over
  calling `safeParse` directly: they also run the plain-data pre-check (below)
  and return friendlier messages.
</Note>

### `parseIntegrationDefinition(input)`

```typescript theme={null}
function parseIntegrationDefinition(input: unknown): IntegrationDefinition;
```

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.

```typescript theme={null}
import { parseIntegrationDefinition } from '@ekanos/integration-schema';

try {
  const definition = parseIntegrationDefinition(input);
} catch (error) {
  // e.g. 'Invalid integration definition for "my-integration":\n  - version: …'
  console.error((error as Error).message);
}
```

### `collectDefinitionFindings(input, options?)`

```typescript theme={null}
function collectDefinitionFindings(
  input: unknown,
  options?: CollectDefinitionOptions,
): Finding[];
```

The non-throwing sibling of `parseIntegrationDefinition()`. Returns an array of findings; an empty array means the definition is valid. Synchronous.

```typescript theme={null}
import { collectDefinitionFindings } from '@ekanos/integration-schema';

const findings = collectDefinitionFindings(definition, {
  file: 'src/integration.ts',
});
for (const f of findings) {
  console.log(`${f.severity}: ${f.check} — ${f.message}`);
}
```

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?)`

```typescript theme={null}
function validateIntegrationDefinitions(
  definitions: readonly DefinitionCollisionInput[],
  firstParty?: FirstPartyInventory,
): void;
```

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?)`

```typescript theme={null}
function collectCollisionFindings(
  definitions: readonly DefinitionCollisionInput[],
  firstParty?: FirstPartyInventory,
): Finding[];
```

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`.

```typescript theme={null}
import { collectCollisionFindings } from '@ekanos/integration-schema';

const findings = collectCollisionFindings([crm, billing]);
```

### `getDiscoveredToolName(slug, rawName)`

```typescript theme={null}
function getDiscoveredToolName(slug: string, rawName: string): string;
```

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.

```typescript theme={null}
getDiscoveredToolName('acme-crm', 'list_deals'); // 'acme_crm_list_deals'
```

### `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)`

```typescript theme={null}
function deepFreezeDefinition(value: unknown): void;
```

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>`

```typescript theme={null}
interface IntegrationDefinition<Schemas extends StorageSchemas = StorageSchemas> {
  slug: string;
  name: string;
  description: string;
  version: string;
  capabilities?: IntegrationCapabilityDeclaration[];
  permissions?: IntegrationPermissionDeclaration[];
  components?: IntegrationComponentDeclarations;
  workspaceTargets?: WorkspaceTargetDefinition[];
  tools?: PartnerToolModule<Schemas>[];
  actions?: Record<string, PartnerActionDeclaration</* … */>>;
  storage?: Schemas;
  egress?: string[];
  webhooks?: PartnerWebhookDeclaration<Schemas>[];
  schedules?: PartnerScheduleDeclaration<Schemas>[];
  onActivate?: OnActivateHandler<Schemas>;
  oauth?: PartnerOAuthDeclaration<Schemas>;
  proposes?: IntegrationProposals;
}
```

### `IntegrationComponentDeclarations`

```typescript theme={null}
interface IntegrationComponentDeclarations {
  activationForm?: ComponentReference;
  marketplaceTile?: ComponentReference;
  widgets?: PartnerWidgetDeclaration[];
}
```

### `PartnerWidgetDeclaration`

Inferred from the widget schema:

```typescript theme={null}
type PartnerWidgetDeclaration = {
  id: string; // kebab-case, globally unique
  name: string;
  component: ComponentReference;
  widgetState: 'active' | 'inactive' | 'disabled';
  gridSize?: { cols: number; rows: number } | { cols: number; rows: number }[];
  gridPosition?: { col: number; row: number };
  layouts?: { lg?: LayoutBox; md?: LayoutBox; sm?: LayoutBox };
  category?: { id: string; name: string; slug: string; icon: string | null };
  isCollapsible?: boolean;
  isPinnable?: boolean;
  aiFooterEnabled?: boolean;
};
// LayoutBox: { x: number; y: number; w: number; h: number; maxHeight?: number }
```

### `IntegrationCapabilityDeclaration` and `IntegrationPermissionDeclaration`

```typescript theme={null}
type IntegrationCapabilityDeclaration = {
  label: string;
  description: string;
  icon?: ComponentReference;
};

type IntegrationPermissionDeclaration = {
  label: string;
  detail: string;
  type: 'read' | 'write';
};
```

### `PartnerToolModule<Schemas>`

A tool exposed to the assistant.

```typescript theme={null}
interface PartnerToolModule<Schemas extends StorageSchemas = StorageSchemas> {
  name: string; // lowercase snake_case, e.g. "list_invoices"
  description: string;
  parameters?: PartnerToolParameters;
  run: (
    ctx: IntegrationContext<Schemas>,
    args: Record<string, unknown>,
  ) => Promise<unknown>;
  outputExample?: Record<string, JsonValue>;
}

type PartnerToolParameters = {
  type: 'object';
  properties?: Record<string, JsonValue>;
  required?: string[];
  additionalProperties?: boolean;
};
```

### `PartnerActionDeclaration<TInput, TOutput, Schemas>`

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

```typescript theme={null}
interface PartnerActionDeclaration<
  TInput extends StandardSchemaV1,
  TOutput extends StandardSchemaV1 | undefined,
  Schemas,
> {
  description: string;
  input: TInput; // a zod schema (zod 3 or 4: any Standard Schema)
  output?: TOutput; // optional schema for the handler's result
  handler: (
    ctx: IntegrationContext<Schemas>,
    input: StandardSchemaV1.InferOutput<TInput>,
  ) => Promise<unknown>; // the output schema's inferred type, when `output` is set
  outputExample?: Record<string, unknown>;
}
```

### `IntegrationProposals` and `ToolClassificationProposal`

Values a partner proposes; the host decides.

```typescript theme={null}
type IntegrationProposals = {
  credentialModel?: 'account' | 'user' | 'source';
  scope?: 'user' | 'team';
  tools?: Record<string, ToolClassificationProposal>; // keyed by tool name
};

type ToolClassificationProposal = {
  effect?: 'read' | 'write';
  sensitivity?: 'public' | 'internal' | 'pii' | 'financial';
};
```

Every key in `proposes.tools` must match a declared tool name.

### `OnActivateHandler<Schemas>`

```typescript theme={null}
type OnActivateHandler<Schemas> = (
  ctx: IntegrationContext<Schemas>,
) => Promise<void>;
```

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`).

```typescript theme={null}
interface IntegrationContext<Schemas extends StorageSchemas = StorageSchemas> {
  readonly accountId: string;
  readonly accountSlug: string | null;
  readonly userId: string | null; // null for machine actors
  readonly actor: IntegrationActor;
  readonly sourceId: string | null;
  readonly integration: { readonly slug: string; readonly productId: string };
  readonly timezone: string | null;

  readonly storage: IntegrationStorage<Schemas>;
  readonly secrets: IntegrationSecrets;
  readonly fetch: IntegrationFetch;
  readonly logger: IntegrationLogger;
}
```

### `IntegrationActor`

```typescript theme={null}
type IntegrationActor =
  | { readonly kind: 'user'; readonly userId: string }
  | {
      readonly kind: 'machine';
      readonly tokenId: string;
      readonly createdBy: string | null;
    };
```

### `IntegrationStorage<Schemas>` and `ScopedStore`

```typescript theme={null}
interface IntegrationStorage<Schemas extends StorageSchemas = StorageSchemas> {
  readonly account: ScopedStore</* account keys */>;
  readonly user: ScopedStore</* user keys */>;   // throws for machine actors
}

interface ScopedStore<Schemas extends StorageSchemaMap = StorageSchemaMap> {
  get<K extends keyof Schemas & string>(key: K): Promise<StorageEntry</* schema output */> | null>;
  set<K extends keyof Schemas & string>(key: K, data: /* schema input */, options?: StorageWriteOptions): Promise<void>;
  delete<K extends keyof Schemas & string>(key: K): Promise<void>;
}

interface StorageEntry<T> {
  data: T;
  externalId: string | null;
  expiresAt: string | null;
  updatedAt: string;
}

interface StorageWriteOptions {
  externalId?: string;
  expiresAt?: string;   // ISO-8601; an entry past it reads as null
}
```

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

```typescript theme={null}
interface StorageSchemas {
  account?: StorageSchemaMap;
  user?: StorageSchemaMap;
}

type StorageSchemaMap = Record<string, StorageKeyDeclarationInput>;

// A bare zod schema (server-only), or a descriptor with exposure flags
type StorageKeyDeclarationInput<S extends StandardSchemaV1 = StandardSchemaV1> =
  S | StorageKeyDeclaration<S>;

interface StorageKeyDeclaration<S extends StandardSchemaV1 = StandardSchemaV1> {
  readonly schema: S;
  readonly clientReadable?: boolean; // default false
}
```

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`

```typescript theme={null}
interface IntegrationSecrets {
  get(name: string): Promise<string | null>;
  names(): Promise<string[]>; // names only, no values
  set(name: string, value: string): Promise<void>; // account tier only
}
```

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

### `IntegrationFetch`

```typescript theme={null}
type IntegrationFetch = (
  input: string | URL,
  init?: RequestInit,
) => Promise<Response>;
```

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`

```typescript theme={null}
interface IntegrationLogger {
  debug(context: Record<string, unknown>, message: string): void;
  info(context: Record<string, unknown>, message: string): void;
  warn(context: Record<string, unknown>, message: string): void;
  error(context: Record<string, unknown>, message: string): void;
}
```

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

***

## Event Surfaces

### `PartnerWebhookDeclaration<Schemas>`

```typescript theme={null}
interface PartnerWebhookDeclaration<Schemas> {
  id: string; // kebab-case
  description: string;
  payloadSchema: StandardSchemaV1; // zod 3 or 4; validates every delivery before the handler runs
  signature: WebhookSignatureDeclaration;
  examplePayload?: Record<string, JsonValue>;
  handler: (
    ctx: IntegrationContext<Schemas>,
    event: WebhookEvent,
  ) => Promise<WebhookResult>;
}

type WebhookSignatureDeclaration =
  | 'none'
  | { header: string; secretName: string; scheme?: WebhookSignatureScheme };

// How the provider builds its signature header. Omit for a bare or
// `sha256=`-labelled HMAC-SHA256 of the raw body (GitHub, Linear).
interface WebhookSignatureScheme {
  algorithm?: 'sha256' | 'sha1'; // default 'sha256'
  format?: 'digest' | 'keyed'; // default 'digest'; 'keyed' = "k=v,k=v" pairs
  digestKey?: string; // keyed only: the pair carrying the digest
  timestampKey?: string; // keyed only: the pair carrying the timestamp
  timestampHeader?: string; // a separate header carrying the timestamp
  signedPayload?: string; // template over {body} (required) and {timestamp}; default '{body}'
  toleranceSeconds?: number; // integer 0-86400; replay window, default 300
}

interface WebhookEvent {
  id: string;
  receivedAt: string; // ISO-8601
  headers: Record<string, string>;
  payload: unknown; // already parsed by payloadSchema
}

interface WebhookResult {
  status: 'processed' | 'ignored';
  detail?: string;
}
```

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](/sdk/surfaces/webhooks#signature-scheme-when-the-provider-is-not-a-plain-body-digest). A handler that cannot process a valid event should throw, which the transport maps to a retryable failure.

### `PartnerScheduleDeclaration<Schemas>`

```typescript theme={null}
interface PartnerScheduleDeclaration<Schemas> {
  id: string; // kebab-case
  description: string;
  cron: string; // standard 5-field cron
  handler: (
    ctx: IntegrationContext<Schemas>,
    invocation: ScheduleInvocation,
  ) => Promise<ScheduleResult>;
}

interface ScheduleInvocation {
  scheduledFor: string; // ISO-8601
  invokedAt: string; // ISO-8601
  trigger: 'schedule' | 'manual';
}

interface ScheduleResult {
  status: 'completed' | 'skipped';
  detail?: string;
}
```

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

### `PartnerOAuthDeclaration<Schemas>`

```typescript theme={null}
interface PartnerOAuthDeclaration<Schemas> {
  provider: OAuthProviderDeclaration;
  credentials: {
    clientIdSecretName: string;
    clientSecretSecretName: string;
  };
  onTokens: (
    ctx: IntegrationContext<Schemas>,
    tokens: OAuthTokens,
  ) => Promise<void>;
}

interface OAuthProviderDeclaration {
  authorizationUrl: string; // https only
  tokenUrl: string; // https only
  scopes: string[];
  pkce?: boolean;
  tokenAuthMethod?: 'client_secret_basic' | 'client_secret_post'; // default 'client_secret_basic'
}

interface OAuthTokens {
  accessToken: string;
  refreshToken?: string;
  expiresAt?: string;
  scope?: string;
  tokenType?: string;
  raw?: Record<string, JsonValue>;
}
```

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`

```typescript theme={null}
z.enum(['masonry', 'two-column']);
```

### `createWorkspaceTargetSchema(options?)` and `WorkspaceTargetSchema`

```typescript theme={null}
function createWorkspaceTargetSchema(
  options?: WorkspaceTargetSchemaOptions,
): ZodSchema;

interface WorkspaceTargetSchemaOptions {
  isValidIcon?: (icon: string) => boolean;
}
```

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).

```typescript theme={null}
import { createWorkspaceTargetSchema } from '@ekanos/integration-schema';

const schema = createWorkspaceTargetSchema({
  isValidIcon: (name) => myIconSet.has(name),
});

schema.safeParse({ slug: 'deals', name: 'Deals', icon: 'fa-light fa-inbox' });
```

A target cannot set both `inheritsWidgets` and `includedWidgetIds`, and `includedWidgetIds` must not be empty.

### `WorkspaceTargetDefinition` and `ResolvedWorkspaceTarget`

```typescript theme={null}
type WorkspaceTargetDefinition = {
  slug: string;
  name: string; // 1–100 characters
  icon?: string;
  description?: string; // up to 500 characters
  layout?: 'masonry' | 'two-column';
  inheritsWidgets?: boolean;
  includedWidgetIds?: string[]; // up to 100
};
```

`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?)`

```typescript theme={null}
function normalizeWorkspaceTargets(
  declared: unknown,
  options?: WorkspaceTargetSchemaOptions,
):
  | { ok: true; targets: ResolvedWorkspaceTarget[] }
  | { ok: false; error: ZodError };
```

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

```typescript theme={null}
import { normalizeWorkspaceTargets } from '@ekanos/integration-schema';

const result = normalizeWorkspaceTargets([{ slug: 'main', name: 'Main' }]);
if (result.ok) {
  result.targets[0].inheritsWidgets; // true
}
```

***

## Storage Data Types

The `dataType` segment of every storage key must come from its scope's list.

```typescript theme={null}
ACCOUNT_STORAGE_DATA_TYPES; // ['activation', 'settings', 'metrics_summary', 'sync_state', 'cache']
USER_STORAGE_DATA_TYPES; // ['config', 'preferences', 'cache']
RESERVED_STORAGE_DATA_TYPES; // ['secret']
```

`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)`

```typescript theme={null}
function deriveProductId(slug: string): string;
```

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

```typescript theme={null}
import { deriveProductId } from '@ekanos/integration-schema';

const productId = deriveProductId('my-integration');
```

### `derivePlanId(slug, planName)`

```typescript theme={null}
function derivePlanId(slug: string, planName: string): string;
```

`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)`

```typescript theme={null}
function uuidv5(name: string, namespace: string): string;
```

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:

```typescript theme={null}
type ComponentReference =
  ((...args: never[]) => unknown) | { readonly $$typeof: symbol };
```

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)`

```typescript theme={null}
function isComponentReference(value: unknown): value is ComponentReference;
```

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

***

## Utility Types

### `JsonValue`

```typescript theme={null}
type JsonValue =
  string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };
```

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

### `DefinitionCollisionInput` and `FirstPartyInventory`

```typescript theme={null}
interface DefinitionCollisionInput {
  slug: string;
  components?: { widgets?: readonly { id: string }[] } | null;
  tools?: readonly { name: string }[] | null;
}

interface FirstPartyInventory {
  slugs?: readonly string[];
  widgetIds?: readonly string[];
  toolNames?: readonly string[]; // effective names (getDiscoveredToolName)
}
```

A full `IntegrationDefinition` is assignable to `DefinitionCollisionInput`.

***

## Findings

### `Finding`

```typescript theme={null}
interface Finding {
  check: string;
  severity: 'error' | 'warn' | 'info';
  file?: string;
  line?: number;
  message: string;
  hint: string; // always a non-empty remediation
}
```

`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`

```typescript theme={null}
interface CollectDefinitionOptions {
  file?: string; // stamped onto every finding
}
```

***

## Import Guide

```typescript theme={null}
// Validation
import {
  IntegrationDefinitionSchema,
  parseIntegrationDefinition,
  collectDefinitionFindings,
  validateIntegrationDefinitions,
  collectCollisionFindings,
} from '@ekanos/integration-schema';

// Authoring types
import type {
  IntegrationDefinition,
  IntegrationComponentDeclarations,
  PartnerWidgetDeclaration,
  PartnerToolModule,
  StorageSchemas,
} from '@ekanos/integration-schema';

// Context types
import type {
  IntegrationContext,
  IntegrationStorage,
  IntegrationSecrets,
} from '@ekanos/integration-schema';

// Workspaces
import {
  createWorkspaceTargetListSchema,
  normalizeWorkspaceTargets,
  WorkspaceTargetSlugSchema,
} from '@ekanos/integration-schema';

// Storage allowlists
import {
  ACCOUNT_STORAGE_DATA_TYPES,
  USER_STORAGE_DATA_TYPES,
} from '@ekanos/integration-schema';

// Ids and components
import {
  deriveProductId,
  isComponentReference,
} from '@ekanos/integration-schema';
```

***

## 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](/cli/updating)).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.