import { Context, Effect, Exit, Layer, Option, Schema, Scope } from 'effect'; import type { Command } from '../command/index.js'; import { type DevToolsStore } from '../devTools/store.js'; import { Document, Html } from '../html/index.js'; import { UrlRequest } from '../navigation/urlRequest.js'; import { type Inbound, type Outbound, type Ports } from '../port/index.js'; import { Url } from '../url/index.js'; import { VNode } from '../vdom.js'; import type { ManagedResources } from './managedResource.js'; import type { Subscriptions } from './subscription.js'; /** Position of the DevTools badge and panel on screen. */ export type DevToolsPosition = 'BottomRight' | 'BottomLeft' | 'TopRight' | 'TopLeft'; /** Controls when a feature is shown. */ export type Visibility = 'Development' | 'Always'; /** Controls DevTools interaction mode. * * - `'Inspect'`: Messages stream in and clicking a row shows its state snapshot without pausing the app. * - `'TimeTravel'`: Clicking a row pauses the app at that historical state. Resume to continue. */ export type DevToolsMode = 'Inspect' | 'TimeTravel'; /** Mode value for the DevTools panel. Either a single mode used in every * environment, or an object selecting different modes for development and * production. Use the object form to keep `'TimeTravel'` for local debugging * while shipping the safer `'Inspect'` mode to users. `'TimeTravel'` in * production pauses the user's app when a history row is clicked. */ export type DevToolsModeConfig = DevToolsMode | Readonly<{ development: DevToolsMode; production: DevToolsMode; }>; /** * Factory that mounts the in-browser DevTools overlay against a recording * store. The runtime keeps the store and the WebSocket bridge (so external * tooling like the DevTools MCP server works without an overlay); the visual * overlay is injected so it can live in `@foldkit/devtools` and pull in * `@foldkit/ui` without coupling the core runtime to either. * * Pass `overlay` from `@foldkit/devtools` as `DevToolsConfig.overlay`. */ export type DevToolsOverlay = (store: DevToolsStore, position: DevToolsPosition, mode: DevToolsMode, maybeBanner: Option.Option) => Effect.Effect; /** * DevTools configuration. * * Pass `false` to disable DevTools entirely. * * - `show`: `'Development'` (default) enables in dev mode only, `'Always'` enables in all environments including production. * - `position`: Where the badge and panel appear. Defaults to `'BottomRight'`. * - `mode`: `'TimeTravel'` (default) enables full time-travel debugging. `'Inspect'` allows browsing state snapshots without pausing the app. Pass `{ development, production }` to use different modes per environment. Useful when DevTools is shown in production (`show: 'Always'`) and you want `'TimeTravel'` only in local development. * - `banner`: Optional text shown as a banner at the top of the panel. * - `overlay`: The in-browser overlay factory from `@foldkit/devtools`. Without it, DevTools still records history and serves the WebSocket bridge (so the DevTools MCP server works), but no visual overlay is mounted. Pass `DevTools.overlay` to show the panel. * - `excludeFromHistory`: Message `_tag` values whose dispatches should not be recorded in DevTools history. The Messages still drive `update` and the runtime as usual; they just don't appear in the history panel and don't pay the per-Message diff cost. Use for high-frequency Messages (animation frames, pointer moves, scroll events) that would flood history without adding insight. * - `maxEntries`: Maximum number of recorded Messages retained in history before the oldest is evicted. Defaults to 100. Clamped to the range 20-500: smaller values keep the panel snappy under high message rates, larger values give you more scroll-back. Each retained entry stores a full Model snapshot, so memory cost scales linearly with both `maxEntries` and your Model size. * - `keyframeInterval`: Number of recorded Messages between full Model snapshots. Defaults to 31. Time-travel to an index replays `update` forward from the nearest earlier keyframe, so this is a memory/time tradeoff: smaller values store more snapshots (more memory) but make each jump cheaper, down to `1` where every jump is a constant-time snapshot lookup with no replay. Reach for a denser interval when the app has a heavy `update` and time-travel jumps feel sluggish. Clamped to a minimum of 1. Forced to 1 automatically when `excludeFromHistory` is active, since excluded Messages are never replayed. */ export type DevToolsConfig = false | Readonly<{ show?: Visibility; position?: DevToolsPosition; mode?: DevToolsModeConfig; banner?: string; overlay?: DevToolsOverlay; excludeFromHistory?: ReadonlyArray; maxEntries?: number; keyframeInterval?: number; /** * The application's `Message` Schema. When provided and the running app * is connected to the Foldkit DevTools MCP server, AI agents can dispatch * Messages into the runtime. The Schema decodes inbound dispatch payloads * at the bridge boundary and returns a clean error on mismatch. * * Without this field, `RequestDispatchMessage` is rejected with an * informative error. */ Message?: Schema.Codec; }>; /** Context provided when view construction exceeds its configured time budget. */ export type SlowViewContext = Readonly<{ _tag: 'View'; model: Model; message: Option.Option; durationMs: number; thresholdMs: number; }>; /** Context provided when update exceeds its configured time budget. */ export type SlowUpdateContext = Readonly<{ _tag: 'Update'; previousModel: Model; nextModel: Model; message: Message; durationMs: number; thresholdMs: number; }>; /** Context provided when DOM patching exceeds its configured time budget. */ export type SlowPatchContext = Readonly<{ _tag: 'Patch'; model: Model; message: Option.Option; durationMs: number; thresholdMs: number; }>; /** Context provided when subscription dependency extraction exceeds its configured time budget. */ export type SlowSubscriptionDependenciesContext = Readonly<{ _tag: 'SubscriptionDependencies'; subscriptionKey: string; model: Model; durationMs: number; thresholdMs: number; }>; /** Tagged union of every slow-phase context passed to `slow.onSlow`. */ export type SlowContext = SlowViewContext | SlowUpdateContext | SlowPatchContext | SlowSubscriptionDependenciesContext; /** Phase names measured by the slow warning runtime option. */ export declare const SlowPhase: Schema.Literals; export type SlowPhase = typeof SlowPhase.Type; /** Budget overrides for slow warning phases. Omitted fields use Foldkit defaults. */ export type SlowThresholdOverrides = Readonly<{ Update?: number; View?: number; Patch?: number; SubscriptionDependencies?: number; }>; type ResolvedSlowPhaseConfig = Readonly<{ thresholdMs: number; onSlow: (context: Context) => void; }>; type ResolvedSlowConfig = Readonly<{ view: Option.Option>>; update: Option.Option>>; patch: Option.Option>>; subscriptionDependencies: Option.Option>>; }>; /** * Slow-phase warning configuration. * * By default, all phases are enabled in development with Foldkit's default * thresholds. Pass `false` to disable warnings entirely. Pass an object to * refine those defaults. * * - `show`: `'Development'` (default) enables warnings only when Vite HMR is active. `'Always'` enables them in every environment. * - `measuredPhases`: Phases to measure. Defaults to every slow warning phase. * - `thresholdOverrides`: Per-phase budget overrides. Omitted fields keep defaults; overrides for unmeasured phases are ignored. * - `onSlow`: Callback for every measured phase that exceeds its budget. Replaces Foldkit's default `console.warn`; Foldkit will not also warn for tags your callback ignores. */ export type SlowConfig = false | Readonly<{ show?: Visibility; measuredPhases?: ReadonlyArray; thresholdOverrides?: SlowThresholdOverrides; onSlow?: (context: SlowContext) => void; }>; export declare const __resolveSlowConfig: (slow: SlowConfig | undefined, isSlowVisible: (show: Visibility) => boolean) => Option.Option>; export declare const defaultSlowCallback: (context: SlowContext) => void; declare const Dispatch_base: Context.ServiceClass Effect.Effect; readonly dispatchSync: (message: unknown) => void; }>; /** Effect service tag that provides message dispatching to the view layer. */ export declare class Dispatch extends Dispatch_base { } export type { Command } from '../command/index.js'; /** Configuration for URL routing with handlers for URL requests and URL changes. */ export type RoutingConfig = Readonly<{ onUrlRequest: (request: UrlRequest) => Message; onUrlChange: (url: Url) => Message; }>; /** Context provided to crash.view and crash.report when the runtime encounters * an unrecoverable error. `message` is the Message being processed when the * crash occurred, present as an `Option` because a crash during the initial * render has no triggering Message. */ export type CrashContext = Readonly<{ error: Error; model: Model; message: Option.Option; }>; /** Configuration for crash handling, with custom crash UI and/or crash reporting. */ export type CrashConfig = Readonly<{ view?: (context: CrashContext) => Document; report?: (context: CrashContext) => void; }>; type BaseApplicationConfig = Readonly<{ Model: Schema.Codec; update: (model: Model, message: Message) => readonly [ Model, ReadonlyArray> ]; view: (model: Model) => Document; subscriptions?: Subscriptions; container: HTMLElement | null; ports?: P; crash?: CrashConfig; slow?: SlowConfig; freezeModel?: boolean; resources?: Layer.Layer; managedResources?: ManagedResources; devTools?: DevToolsConfig; }>; /** Configuration for `makeApplication` with flags and URL routing. */ export type RoutingApplicationConfigWithFlags = BaseApplicationConfig & Readonly<{ Flags: Schema.Codec; flags: Effect.Effect; routing: RoutingConfig; init: (flags: Flags, url: Url) => readonly [ Model, ReadonlyArray> ]; }>; /** Configuration for `makeApplication` with URL routing but no flags. */ export type RoutingApplicationConfig = BaseApplicationConfig & Readonly<{ routing: RoutingConfig; init: (url: Url) => readonly [ Model, ReadonlyArray> ]; }>; /** Configuration for `makeApplication` with flags but no URL routing. */ export type ApplicationConfigWithFlags = BaseApplicationConfig & Readonly<{ Flags: Schema.Codec; flags: Effect.Effect; init: (flags: Flags) => readonly [ Model, ReadonlyArray> ]; }>; /** Configuration for `makeApplication` without flags or URL routing. */ export type ApplicationConfig = BaseApplicationConfig & Readonly<{ init: () => readonly [ Model, ReadonlyArray> ]; }>; /** Configuration for crash handling in a `makeElement` app. The crash view * returns `Html`, not a `Document`, because a scoped app never owns the * document ``. */ export type ElementCrashConfig = Readonly<{ view?: (context: CrashContext) => Html; report?: (context: CrashContext) => void; }>; type BaseElementConfig = Readonly<{ Model: Schema.Codec; update: (model: Model, message: Message) => readonly [ Model, ReadonlyArray> ]; view: (model: Model) => Html; subscriptions?: Subscriptions; container: HTMLElement | null; ports?: P; crash?: ElementCrashConfig; slow?: SlowConfig; freezeModel?: boolean; resources?: Layer.Layer; managedResources?: ManagedResources; devTools?: DevToolsConfig; }>; /** Configuration for `makeElement` with flags. */ export type ElementConfigWithFlags = BaseElementConfig & Readonly<{ Flags: Schema.Codec; flags: Effect.Effect; init: (flags: Flags) => readonly [ Model, ReadonlyArray> ]; }>; /** Configuration for `makeElement` without flags. */ export type ElementConfig = BaseElementConfig & Readonly<{ init: () => readonly [ Model, ReadonlyArray> ]; }>; /** The `init` function type for a `makeApplication` app without URL routing. */ export type ApplicationInit = Flags extends void ? () => readonly [ Model, ReadonlyArray> ] : (flags: Flags) => readonly [ Model, ReadonlyArray> ]; /** The `init` function type for a `makeApplication` app with URL routing, receives the current URL and optional flags. */ export type RoutingApplicationInit = Flags extends void ? (url: Url) => readonly [ Model, ReadonlyArray> ] : (flags: Flags, url: Url) => readonly [ Model, ReadonlyArray> ]; /** The `init` function type for a `makeElement` app. A scoped app never owns * the URL, so its `init` has the same shape as a non-routing * `ApplicationInit`: argless, or receiving flags when `Flags` is set. */ export type ElementInit = ApplicationInit; /** A configured Foldkit runtime returned by `makeApplication` or `makeElement`. * Pass it to `run` to start a page-owning app, or to `embed` to start it under * a host-controlled lifecycle handle. `ports` is the Ports record from the * config (or `undefined` when the config declared none); it types the * `EmbedHandle` that `embed` returns. */ export type MakeRuntimeReturn

= Readonly<{ runtimeId: string; start: (hmrModel?: unknown) => Effect.Effect; ports: P; }>; /** Host-side handle for one inbound Port. `send` validates the value by * decoding it against the Port's Schema: on success the decoded value enters * the app through the Port's Subscription; on failure nothing reaches the * app, the failure is logged, and the returned `Exit` carries the * `SchemaError`. Sends after `dispose` are no-ops. */ export type InboundPortHandle = Readonly<{ send: (value: Encoded) => Exit.Exit; }>; /** Host-side handle for one outbound Port. `subscribe` registers a listener * for the encoded values the app emits with `Port.emit` and returns an * unsubscribe function. Multiple listeners receive each value in * registration order. */ export type OutboundPortHandle = Readonly<{ subscribe: (listener: (value: Encoded) => void) => () => void; }>; /** The inbound half of `PortHandles`: one `InboundPortHandle` per declared * inbound Port, keyed by Port name. */ export type InboundPortHandles = InboundPorts extends Readonly>> ? { readonly [Name in keyof InboundPorts]: InboundPorts[Name] extends Inbound ? InboundPortHandle : never; } : unknown; /** The outbound half of `PortHandles`: one `OutboundPortHandle` per declared * outbound Port, keyed by Port name. */ export type OutboundPortHandles = OutboundPorts extends Readonly>> ? { readonly [Name in keyof OutboundPorts]: OutboundPorts[Name] extends Outbound ? OutboundPortHandle : never; } : unknown; /** The `ports` field of an `EmbedHandle`: one `InboundPortHandle` or * `OutboundPortHandle` per declared Port, keyed by Port name. */ export type PortHandles

= P extends Ports ? InboundPortHandles & OutboundPortHandles : unknown; /** * The handle returned by `embed`. The host talks to the embedded app only * through it: `ports..send` pushes values in, `ports..subscribe` * listens to values the app emits, and `dispose` shuts the runtime down. * * `dispose` is idempotent. It interrupts the runtime and runs all cleanup: * Subscriptions, ManagedResources, Mounts, listeners, and in-flight Commands * stop, and the rendered DOM is removed with the container element restored * empty in its place, ready for a fresh `embed`. */ export type EmbedHandle

= Readonly<{ ports: PortHandles

; dispose: () => void; }>; export declare const patchVNode: (maybeCurrentVNode: Option.Option, nextVNode: VNode | null, container: HTMLElement, seen?: Set) => VNode; /** Creates a Foldkit application that owns the page and returns a runtime that * can be passed to `run`. The `view` returns a `Document`, so the runtime * manages `document.title` and the canonical / og:url tags. Add a `routing` * config for URL routing. To mount an app scoped to a node without touching the * document ``, use `makeElement`. */ export declare function makeApplication(config: RoutingApplicationConfigWithFlags): MakeRuntimeReturn

; export declare function makeApplication(config: RoutingApplicationConfig): MakeRuntimeReturn

; export declare function makeApplication(config: ApplicationConfigWithFlags): MakeRuntimeReturn

; export declare function makeApplication(config: ApplicationConfig): MakeRuntimeReturn

; /** * Creates a Foldkit app scoped to its container and returns a runtime that * can be passed to `run`. * * Unlike `makeApplication`, the `view` returns `Html` directly rather than a * `Document`, and the runtime never touches the document ``. This lets a * Foldkit app be embedded at a node (a widget on a page it does not own) * without clobbering the host page's `title`, `canonical`, or `og:url`. Use * `makeApplication` when the app owns the page and should manage those tags, and * `makeElement` when it is one component among others on a page it does not * control. Embedded apps do not own the URL bar, so `makeElement` has no * `routing` config. */ export declare function makeElement(config: ElementConfigWithFlags): MakeRuntimeReturn

; export declare function makeElement(config: ElementConfig): MakeRuntimeReturn

; /** Starts a Foldkit runtime that owns the page for the page's whole lifetime, * with HMR support for development. To start a runtime under a * host-controlled lifecycle instead, use `embed`. */ export declare const run: (program: MakeRuntimeReturn) => void; /** * Starts a Foldkit runtime under a host-controlled lifecycle and returns an * `EmbedHandle`. This is the entry point for embedding a Foldkit app inside * another application: the host pushes values in through the handle's inbound * Ports, listens to outbound Ports, and calls `dispose` when it unmounts the * app. The host never touches the Model or dispatches Messages directly; the * Schema-typed Ports are the whole boundary. * * Works with programs from both `makeApplication` and `makeElement`; for a * widget on a page the host owns, `makeElement` is the natural fit. * * A program can be embedded once at a time (it owns one container). After * `dispose`, the same container can be embedded again with a fresh program. * * ```ts * const handle = Runtime.embed(element) * * handle.ports.stepChanged.send(5) * const unsubscribe = handle.ports.countChanged.subscribe(count => { * console.log(count) * }) * * handle.dispose() * ``` */ export declare const embed:

(program: MakeRuntimeReturn

) => EmbedHandle

; //# sourceMappingURL=runtime.d.ts.map