foldkit 0.132.0 → 0.133.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,33 +13,21 @@
13
13
  <h3 align="center">The frontend framework for correctness.</h3>
14
14
 
15
15
  <p align="center">
16
- <a href="https://foldkit.dev"><strong>Documentation</strong></a> · <a href="https://foldkit.dev/get-started/manifesto"><strong>Manifesto</strong></a> · <a href="https://foldkit.dev/example-apps"><strong>Examples</strong></a> · <a href="https://foldkit.dev/get-started/getting-started"><strong>Getting Started</strong></a>
16
+ <a href="https://foldkit.dev"><strong>Documentation</strong></a> · <a href="https://foldkit.dev/get-started/manifesto"><strong>Manifesto</strong></a> · <a href="https://foldkit.dev/example-apps"><strong>Examples</strong></a> · <a href="https://foldkit.dev/get-started/getting-started"><strong>Getting Started</strong></a> · <a href="https://discord.gg/kav8VNxqGm"><strong>Discord</strong></a>
17
17
  </p>
18
18
 
19
19
  ---
20
20
 
21
- Built on [Effect](https://effect.website/). Architected like [Elm](https://guide.elm-lang.org/architecture/). Written in TypeScript. One Model, one update function, one way to do things. No hooks, no local state, no hidden mutations.
21
+ Foldkit is a TypeScript frontend framework built on [Effect](https://effect.website/) and architected like [Elm](https://guide.elm-lang.org/architecture/). One Model, one update function, one way to do things. No hooks, no local state, no hidden mutations. It's all in on Effect with no escape hatch, though a program doesn't have to own the whole page: [`Runtime.embed`](https://foldkit.dev/core/embedding) runs a Foldkit widget inside any existing app, React included.
22
+
23
+ Your Model is a [Schema](https://effect.website/docs/schema/introduction/) and side effects are values you return, not callbacks you fire. If you know Effect, Foldkit feels natural. If you're new to it, Foldkit is a good way in. Coming from React? [Start here](https://foldkit.dev/react/coming-from-react), or read the [same pixel-art editor built in both frameworks](https://foldkit.dev/react/foldkit-vs-react-side-by-side).
22
24
 
23
25
  > [!NOTE]
24
26
  > Foldkit is pre-1.0. The core API is stable, but breaking changes may occur in minor releases. See the [changelog](./CHANGELOG.md) for details.
25
27
 
26
- ## Who It's For
27
-
28
- Foldkit is for developers who want to build their product with confidence instead of fighting their architecture. If you want a single pattern that scales from a counter to a multiplayer game without complexity creep, this is it.
29
-
30
- It's not incremental. There's no React interop, no escape hatch from Effect, no way to "just use hooks for this one part." You're all in or you're not.
31
-
32
- ## Built on Effect
33
-
34
- Every Foldkit application is an [Effect](https://effect.website/) program. Your Model is a [Schema](https://effect.website/docs/schema/introduction/). Side effects are values you return as Commands to the runtime, not callbacks you fire. If you already know Effect, Foldkit feels natural. If you're new to Effect, Foldkit is a great way to immerse yourself in it.
35
-
36
- ## Coming from React?
37
-
38
- [Coming from React](https://foldkit.dev/react/coming-from-react) is a guided walk through the differences. [Foldkit vs React: Side by Side](https://foldkit.dev/react/foldkit-vs-react-side-by-side) implements the same pixel-art editor in both frameworks so you can read them line by line.
39
-
40
28
  ## Get Started
41
29
 
42
- `create-foldkit-app` is the recommended way to start a new project. It scaffolds a complete setup with Tailwind, TypeScript, ESLint, Prettier, and the Vite plugin for state-preserving HMR and lets you choose from a set of examples as your starting point.
30
+ `create-foldkit-app` scaffolds a complete setup with Tailwind, TypeScript, [Oxlint](https://foldkit.dev/tooling/oxlint-plugin), Prettier, and the Vite plugin for state-preserving HMR, starting from an example you choose.
43
31
 
44
32
  ```bash
45
33
  npx create-foldkit-app@latest
@@ -47,9 +35,7 @@ npx create-foldkit-app@latest
47
35
 
48
36
  ## Counter
49
37
 
50
- This is a complete Foldkit program. State lives in a single Model. Events become Messages. A pure function handles every transition.
51
-
52
- `src/main.ts` defines the program. `src/entry.ts` boots the runtime. The split keeps `main.ts` importable from tests without booting a runtime as a side effect.
38
+ A complete Foldkit program. State lives in a single Model, events become Messages, and a pure function handles every transition. `main.ts` defines the program and `entry.ts` boots the runtime, so `main.ts` stays importable from tests without booting a runtime as a side effect.
53
39
 
54
40
  ```ts
55
41
  // src/main.ts
@@ -108,41 +94,16 @@ export const view = (model: Model): Document => {
108
94
  return {
109
95
  title: `Counter: ${model.count}`,
110
96
  body: h.div(
97
+ [],
111
98
  [
112
- h.Class(
113
- 'min-h-screen bg-white flex flex-col items-center justify-center gap-6 p-6',
114
- ),
115
- ],
116
- [
117
- h.div(
118
- [h.Class('text-6xl font-bold text-gray-800')],
119
- [model.count.toString()],
120
- ),
121
- h.div(
122
- [h.Class('flex flex-wrap justify-center gap-4')],
123
- [
124
- h.button(
125
- [h.OnClick(ClickedDecrement()), h.Class(buttonStyle)],
126
- ['-'],
127
- ),
128
- h.button(
129
- [h.OnClick(ClickedReset()), h.Class(buttonStyle)],
130
- ['Reset'],
131
- ),
132
- h.button(
133
- [h.OnClick(ClickedIncrement()), h.Class(buttonStyle)],
134
- ['+'],
135
- ),
136
- ],
137
- ),
99
+ h.p([], [model.count.toString()]),
100
+ h.button([h.OnClick(ClickedDecrement())], ['-']),
101
+ h.button([h.OnClick(ClickedReset())], ['Reset']),
102
+ h.button([h.OnClick(ClickedIncrement())], ['+']),
138
103
  ],
139
104
  ),
140
105
  }
141
106
  }
142
-
143
- // STYLE
144
-
145
- const buttonStyle = 'bg-black text-white hover:bg-gray-700 px-4 py-2 transition'
146
107
  ```
147
108
 
148
109
  ```ts
@@ -162,62 +123,56 @@ const application = Runtime.makeApplication({
162
123
  Runtime.run(application)
163
124
  ```
164
125
 
165
- Source: [examples/counter/src/main.ts](https://github.com/foldkit/foldkit/blob/main/examples/counter/src/main.ts), [examples/counter/src/entry.ts](https://github.com/foldkit/foldkit/blob/main/examples/counter/src/entry.ts)
126
+ Source: [examples/counter](https://github.com/foldkit/foldkit/blob/main/examples/counter/src/main.ts).
166
127
 
167
128
  ## What Ships With Foldkit
168
129
 
169
- Foldkit is a complete system, not a collection of libraries you stitch together.
170
-
171
- - **Commands**: Side effects are named Effects that return Messages and are executed by the runtime. Define them with `Command.define`, passing the result Message schemas so the Effect's return type stays in lockstep with your Messages. Use any Effect combinator you want: retry, timeout, race, parallel. You write the Effect, the runtime runs it.
172
- - **Mount**: The seam where view code reaches a real DOM element, like focusing an input or handing the live `Element` to a third-party library that owns its own DOM. The runtime runs your Effect on mount, dispatches its Message back through update, and runs the paired cleanup on unmount.
173
- - **Routing**: Type-safe bidirectional routing built from parser combinators. URLs parse into typed Routes and Routes build back into URLs. No string matching, no mismatches between parsing and building.
174
- - **Subscriptions**: Declare which streams your app needs as a function of the Model. The runtime diffs and switches them as the Model changes.
175
- - **Managed Resources**: Model-driven lifecycle for long-lived browser resources like WebSockets, AudioContext, and RTCPeerConnection. Acquire on state change, release on cleanup.
176
- - **Submodels**: A pattern for composing nested modules. A child owns its own Model, Messages, update function, and view; the parent embeds it and wraps child Messages in a `Got*Message` envelope. The pattern scales unchanged from a login form to a multi-page app.
177
- - **OutMessage**: A typed channel for a child Submodel to emit domain events up to its parent, so the parent reacts to meaningful facts instead of internal child Messages.
178
- - **UI Components**: Accessible, keyboard-friendly components in the `@foldkit/ui` package, covering Button, Checkbox, Combobox, Dialog, Disclosure, DragAndDrop, Fieldset, Input, Listbox, Menu, Popover, RadioGroup, Select, Switch, Tabs, Textarea, and Transition. Stateful components (Combobox, Dialog, Listbox, Menu, and the like) are Submodels you embed with `h.submodel`: they own their interaction state, read the value your Model owns through per-render view inputs, and surface selections through their OutMessage. Stateless render helpers (Button, Checkbox, Disclosure, Input, RadioGroup, Select, Switch, Textarea, and friends) are called directly with a typed `ViewConfig`. Both expose attribute hooks on every slot for styling and extension. Animated components share a `Transition` Submodel that coordinates CSS enter and leave animations.
179
- - **Canvas**: Declarative 2D rendering. Describe a scene as a tree of `Shape` values (Rect, Circle, Path, Text, plus Group, which composes children under translate / rotate / scale / opacity), pass them to `Canvas.view`, and the runtime re-paints on every patch. The canvas pixels are a pure function of the shapes, so DevTools time-travel reproduces past frames exactly. Pair with `Subscription.animationFrame` for `requestAnimationFrame`-driven Subscriptions.
180
- - **Field Validation**: Per-field validation state modeled as a discriminated union. Define rules as data, apply them in update, and the Model tracks the result.
181
- - **Virtual DOM**: Declarative views powered by [Snabbdom](https://github.com/snabbdom/snabbdom), with lazy memoization and fast, keyed diffing. Views are plain functions of your Model.
182
- - **DevTools**: Opt-in in-browser overlay (the `@foldkit/devtools` package) for inspecting Messages, Model state, and Commands. Time-travel mode rewinds your UI to any past Model, Inspect mode browses snapshots without pausing, and Submodel drill-in filtering scopes the Message list to any nested module.
183
- - **DevTools MCP**: Expose a running Foldkit app to AI agents over the Model Context Protocol. Agents read the current Model, list and inspect Message history, rewind the UI to any past Model, and dispatch Messages into the runtime. To dispatch, agents read your application source to learn the Message Schema; the runtime decodes every payload against the Schema and returns a clean error if the shape does not match. One command sets it up: `npx @foldkit/devtools-mcp init`.
184
- - **Crash View and Reporting**: Configure `crash.view` to render a custom fallback UI when the update loop throws. A `crash.report` callback fires first with the error, Model, and triggering Message, so you can ship it straight to Sentry or your logger.
185
- - **Story Testing**: Exercise the update function directly. Send Messages, resolve Commands inline with `Story.Command.resolve` and `Story.Command.resolveAll`, and assert with focused helpers: `Story.model`, `Story.Command.expectHas`, `Story.Command.expectExact`, `Story.Command.expectNone`, and `Story.expectOutMessage`. No mocking libraries, no fake timers.
186
- - **Scene Testing**: Drive your app the way a user does. Scene renders your real view, then clicks buttons, types into inputs, presses keys, and asserts on what's on screen. Accessible locators (`role`, `label`, `placeholder`, `altText`, `title`, `testId`, `displayValue`) with full options (`name`, `level`, `checked`, `selected`, `pressed`, `expanded`, `disabled`), multi-match `Scene.all` with `Scene.filter` and `Scene.nth`, scoped steps via `Scene.inside`, pointer events, event bubbling, and Vitest matchers like `toHaveText`, `toBeVisible`, `toHaveAccessibleName`, and `toHaveCount`. API parity with React Testing Library and Playwright, without a browser.
187
- - **Slow Warnings**: Wire `slow` on `makeApplication` or `makeElement` to catch synchronous phases that exceed budgets: update, view, patch, and Subscription dependency extraction. Configure `measuredPhases`, `thresholdOverrides`, and one `onSlow` sink to state what is measured, which budgets change, and where every slow event goes.
130
+ A complete system, not a collection of libraries you stitch together. Each of these is documented in depth at [foldkit.dev](https://foldkit.dev).
131
+
132
+ - **Commands**: Side effects as named Effects that return Messages and are run by the runtime.
133
+ - **Routing**: Type-safe bidirectional routing from parser combinators. URLs parse to Routes, Routes build URLs.
134
+ - **Subscriptions**: External event streams declared as a function of the Model.
135
+ - **Managed Resources**: Model-driven lifecycle for WebSockets, AudioContext, and other long-lived handles.
136
+ - **Mount**: The seam where view code hands a real DOM element to a third-party library that owns its own DOM.
137
+ - **Submodels**: A self-contained Model, update, and view that a parent embeds, wrapping child Messages in a `Got*` envelope.
138
+ - **OutMessage**: A typed channel for a child Submodel to emit domain events up to its parent.
139
+ - **Embedding**: Run a Foldkit program inside a host app through Schema-typed Ports with `Runtime.embed`.
140
+ - **UI Components**: Accessible, keyboard-friendly primitives in the `@foldkit/ui` package.
141
+ - **Field Validation**: Per-field validation state modeled as a discriminated union.
142
+ - **Virtual DOM**: Declarative views with lazy memoization and keyed diffing, powered by [Snabbdom](https://github.com/snabbdom/snabbdom).
143
+ - **DevTools**: In-browser overlay for inspecting Messages, Model, and Commands, with time-travel.
144
+ - **DevTools MCP**: Expose a running app to AI agents over the Model Context Protocol.
145
+ - **Crash View and Reporting**: A custom fallback UI when the update loop throws, plus a report callback.
146
+ - **Story Testing**: Exercise the update function directly, resolving Commands inline. No mocks, no fake timers.
147
+ - **Scene Testing**: Drive your real view the way a user does, with accessible locators. No browser required.
148
+ - **Slow Warnings**: Development warnings when update, view, patch, or Subscription extraction exceeds its budget.
188
149
  - **HMR**: Vite plugin with state-preserving hot module replacement. Change your view, keep your state.
189
150
 
190
151
  ## Correctness You (And Your LLM) Can See
191
152
 
192
- Every state change flows through one update function. Every side effect is declared explicitly — in Commands, Mount Effects, Subscription streams, and Managed Resource lifecycles. You don't have to hold a mental model of what runs when you can point at it.
193
-
194
- This is what makes Foldkit unusually AI-friendly. The same property that makes the code easy for humans to reason about makes it easy for LLMs to generate and review. The architecture makes correctness visible, whether the reader is a person or an LLM.
153
+ Every state change flows through one update function, and every side effect is declared explicitly. You don't have to hold a mental model of what runs when, you can point at it. That's what makes Foldkit unusually AI-friendly: the property that makes the code easy for humans to reason about makes it easy for an LLM to generate and review.
195
154
 
196
155
  ## Examples
197
156
 
198
- - **[Counter](https://foldkit.dev/example-apps/counter)** — Increment/decrement with reset
199
- - **[Counters](https://foldkit.dev/example-apps/counters)** — A dynamic list of Counter Submodels with per-instance routing
200
- - **[Todo](https://foldkit.dev/example-apps/todo)** CRUD operations with localStorage persistence
201
- - **[Stopwatch](https://foldkit.dev/example-apps/stopwatch)** Timer with start/stop/reset
202
- - **[Crash View](https://foldkit.dev/example-apps/crash-view)** Custom crash fallback UI with crash reporting
203
- - **[Form](https://foldkit.dev/example-apps/form)** Form validation with async email checking
204
- - **[Job Application](https://foldkit.dev/example-apps/job-application)** Multi-step form with cross-field validation, file uploads, and per-step error indicators
205
- - **[Weather](https://foldkit.dev/example-apps/weather)** HTTP requests with async state handling
206
- - **[Routing](https://foldkit.dev/example-apps/routing)** URL routing with parser combinators
207
- - **[Query Sync](https://foldkit.dev/example-apps/query-sync)** URL query parameter sync with filtering and sorting
208
- - **[Snake](https://foldkit.dev/example-apps/snake)** Classic game built with Subscriptions
209
- - **[Map](https://foldkit.dev/example-apps/map)** Interactive MapLibre GL map demonstrating Mount with a third-party DOM library
210
- - **[Auth](https://foldkit.dev/example-apps/auth)** Authentication flow with Submodels and OutMessage
211
- - **[Shopping Cart](https://foldkit.dev/example-apps/shopping-cart)** Nested models and complex state
212
- - **[Checkout Machine](https://foldkit.dev/example-apps/checkout-machine)** Experimental state machine checkout with guarded branches and edge Commands
213
- - **[WebSocket Chat](https://foldkit.dev/example-apps/websocket-chat)** Managed Resources with WebSocket integration
214
- - **[Kanban](https://foldkit.dev/example-apps/kanban)** — Drag-and-drop kanban board with cross-column reordering and keyboard navigation
215
- - **[Pixel Art](https://foldkit.dev/example-apps/pixel-art)** Grid-based pixel editor with painting, erasing, and palette selection
216
- - **[Canvas Art](https://foldkit.dev/example-apps/canvas-art)** Declarative 2D canvas with shapes, animation-frame Subscriptions, and pointer events
217
- - **[Web Components](https://foldkit.dev/example-apps/web-components)**: QR code designer wiring two real third-party web components into Foldkit with `CustomElement.define` (vanilla-colorful + Shoelace)
218
- - **[Embedding](https://foldkit.dev/example-apps/embedding)** — A Foldkit widget embedded in a plain TypeScript host page via `Runtime.embed`, with typed Ports in both directions and `dispose` on unmount
219
- - **[UI Showcase](https://foldkit.dev/example-apps/ui-showcase)** — Interactive showcase of every Foldkit UI component
220
- - **[Typing Game](https://github.com/foldkit/foldkit/tree/main/packages/typing-game)** — Multiplayer typing game with Effect RPC backend ([play it live](https://typingterminal.com))
157
+ Some of what you can build with Foldkit. [See all example apps on foldkit.dev](https://foldkit.dev/example-apps).
158
+
159
+ - **[Counter](https://foldkit.dev/example-apps/counter)**: Increment/decrement with reset
160
+ - **[Todo](https://foldkit.dev/example-apps/todo)**: CRUD operations with localStorage persistence
161
+ - **[Form](https://foldkit.dev/example-apps/form)**: Form validation with async email checking
162
+ - **[Job Application](https://foldkit.dev/example-apps/job-application)**: Multi-step form with cross-field validation, file uploads, and per-step error indicators
163
+ - **[Weather](https://foldkit.dev/example-apps/weather)**: HTTP requests with async state handling
164
+ - **[API Cache](https://foldkit.dev/example-apps/api-cache)**: Query caching with stale-while-revalidate, request deduplication, and interval refetching
165
+ - **[Routing](https://foldkit.dev/example-apps/routing)**: URL routing with parser combinators
166
+ - **[Route Transitions](https://foldkit.dev/example-apps/route-transitions)**: Live transition log with entry, exit, and stayed navigation policies
167
+ - **[Query Sync](https://foldkit.dev/example-apps/query-sync)**: URL query parameter sync with filtering and sorting
168
+ - **[Snake](https://foldkit.dev/example-apps/snake)**: Classic game built with Subscriptions
169
+ - **[Auth](https://foldkit.dev/example-apps/auth)**: Authentication flow with Submodels and OutMessage
170
+ - **[Shopping Cart](https://foldkit.dev/example-apps/shopping-cart)**: Nested models and complex state
171
+ - **[WebSocket Chat](https://foldkit.dev/example-apps/websocket-chat)**: Managed Resources with WebSocket integration
172
+ - **[Kanban](https://foldkit.dev/example-apps/kanban)**: Drag-and-drop kanban board with cross-column reordering and keyboard navigation
173
+ - **[Pixel Art](https://foldkit.dev/example-apps/pixel-art)**: Grid-based pixel editor with painting, erasing, and palette selection
174
+ - **[UI Showcase](https://foldkit.dev/example-apps/ui-showcase)**: Interactive showcase of every Foldkit UI component
175
+ - **[Typing Game](https://github.com/foldkit/foldkit/tree/main/packages/typing-game)**: Multiplayer typing game with Effect RPC backend ([play it live](https://typingterminal.com))
221
176
 
222
177
  ## License
223
178
 
@@ -102,6 +102,12 @@ export declare const RequestGetRuntimeState: import("../schema/index.js").Callab
102
102
  export declare const RequestDispatchMessage: import("../schema/index.js").CallableTaggedStruct<"RequestDispatchMessage", {
103
103
  message: S.Unknown;
104
104
  }>;
105
+ /** The largest batch `RequestDispatchMessages` accepts. Matches the DevTools store's default history size, so a batch cannot evict its own earliest entries before the caller reads them back. The runtime rejects a larger batch with `ResponseError`, and MCP clients reject it earlier still, at their own input boundary. */
106
+ export declare const MAX_DISPATCH_BATCH_SIZE = 100;
107
+ /** Request the runtime dispatch an ordered batch of Messages at the current state. Payloads are opaque to the protocol; the runtime decodes every entry against the app's Message Schema before dispatching any of them, so one invalid entry rejects the whole batch and no Message from it is dispatched. Decoded Messages dispatch in array order through the same path as single dispatch, so the runtime may still record its own Messages between entries, exactly as with rapid user input. Batches larger than `MAX_DISPATCH_BATCH_SIZE` are rejected outright. */
108
+ export declare const RequestDispatchMessages: import("../schema/index.js").CallableTaggedStruct<"RequestDispatchMessages", {
109
+ messages: S.$Array<S.Unknown>;
110
+ }>;
105
111
  /** Request a description of the app's Message Schema. The runtime derives a JSON Schema document once at bridge boot from the configured `DevToolsConfig.Message`; the response is `None` when no Message Schema was configured. With `maybeVariantTag: None`, the response carries a small variant index (tag names plus payload field names and a tagged-union indicator) so MCP clients can enumerate the top-level variants without paying for the full schema. With `maybeVariantTag: Some(path)`, the value is interpreted as a dot-separated path of variant `_tag` values walked through each variant's single tagged-union payload field; the response carries the JSON Schema document narrowed along that chain, with any deeper unions collapsed to summary placeholders. Use the index to discover variants, then fetch one variant before calling `RequestDispatchMessage`. */
106
112
  export declare const RequestGetMessageSchema: import("../schema/index.js").CallableTaggedStruct<"RequestGetMessageSchema", {
107
113
  maybeVariantTag: S.OptionFromNullOr<S.String>;
@@ -134,6 +140,8 @@ export declare const Request: S.Union<readonly [import("../schema/index.js").Cal
134
140
  keyframeIndex: S.Number;
135
141
  }>, import("../schema/index.js").CallableTaggedStruct<"RequestResume", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestDispatchMessage", {
136
142
  message: S.Unknown;
143
+ }>, import("../schema/index.js").CallableTaggedStruct<"RequestDispatchMessages", {
144
+ messages: S.$Array<S.Unknown>;
137
145
  }>, import("../schema/index.js").CallableTaggedStruct<"RequestListRuntimes", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestGetInit", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestGetRuntimeState", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestGetMessageSchema", {
138
146
  maybeVariantTag: S.OptionFromNullOr<S.String>;
139
147
  }>]>;
@@ -265,10 +273,14 @@ export declare const ResponseReplayed: import("../schema/index.js").CallableTagg
265
273
  }>;
266
274
  /** Response confirming the runtime resumed normal execution. */
267
275
  export declare const ResponseResumed: import("../schema/index.js").CallableTaggedStruct<"ResponseResumed", {}>;
268
- /** Response confirming a Message was dispatched. The `acceptedAtIndex` is the absolute history index where the entry is predicted to land. Computed from the runtime's history length at dispatch time. The runtime processes Messages in arrival order and the bridge is the only external dispatch source, so this index is reliable for correlation. */
276
+ /** Response confirming a Message was dispatched. The `acceptedAtIndex` is the absolute history index where the entry is predicted to land. Computed from the runtime's history length at dispatch time. The runtime processes Messages in arrival order, so the index is reliable whenever the bridge is the only Message source, but the app produces its own Messages too (user input, Subscription emissions, Command results); one recorded between the snapshot and the dispatch shifts the entry past this index. Messages excluded from history via `excludeFromHistory` still drive `update` but are never recorded, so no entry lands at the predicted index for them, and a Message dispatched into a crashed or disposed runtime is dropped without recording anything. */
269
277
  export declare const ResponseDispatched: import("../schema/index.js").CallableTaggedStruct<"ResponseDispatched", {
270
278
  acceptedAtIndex: S.Number;
271
279
  }>;
280
+ /** Response confirming a batch dispatch. `acceptedAtIndices` aligns with the request's `messages` order; each value is the absolute history index where that entry is predicted to land, computed from one history snapshot at dispatch time with the same caveats as `ResponseDispatched.acceptedAtIndex`. An `excludeFromHistory` Message inside the batch records no entry, so entries after it land below their predicted index. */
281
+ export declare const ResponseDispatchedBatch: import("../schema/index.js").CallableTaggedStruct<"ResponseDispatchedBatch", {
282
+ acceptedAtIndices: S.$Array<S.Number>;
283
+ }>;
272
284
  /** One variant entry in a `MessageSchemaIndex`. `payloadFields` lists the variant's payload property names (excluding `_tag`); `unionFields` lists the subset of those properties whose schemas are themselves `_tag`-discriminated unions. A Submodel-wrapper variant always shows up with `unionFields: ['message']`, but the same flag also catches plain tagged-union value types like `UrlRequest = Internal | External`. Either way, the agent will need to pick a variant when filling these fields. */
273
285
  export declare const MessageSchemaIndexEntry: S.Struct<{
274
286
  readonly tag: S.String;
@@ -443,6 +455,8 @@ export declare const Response: S.Union<readonly [import("../schema/index.js").Ca
443
455
  model: S.Unknown;
444
456
  }>, import("../schema/index.js").CallableTaggedStruct<"ResponseResumed", {}>, import("../schema/index.js").CallableTaggedStruct<"ResponseDispatched", {
445
457
  acceptedAtIndex: S.Number;
458
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseDispatchedBatch", {
459
+ acceptedAtIndices: S.$Array<S.Number>;
446
460
  }>, import("../schema/index.js").CallableTaggedStruct<"ResponseRuntimes", {
447
461
  runtimes: S.$Array<S.Struct<{
448
462
  readonly connectionId: S.String;
@@ -536,6 +550,8 @@ export declare const RequestFrame: S.Struct<{
536
550
  keyframeIndex: S.Number;
537
551
  }>, import("../schema/index.js").CallableTaggedStruct<"RequestResume", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestDispatchMessage", {
538
552
  message: S.Unknown;
553
+ }>, import("../schema/index.js").CallableTaggedStruct<"RequestDispatchMessages", {
554
+ messages: S.$Array<S.Unknown>;
539
555
  }>, import("../schema/index.js").CallableTaggedStruct<"RequestListRuntimes", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestGetInit", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestGetRuntimeState", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestGetMessageSchema", {
540
556
  maybeVariantTag: S.OptionFromNullOr<S.String>;
541
557
  }>]>;
@@ -626,6 +642,8 @@ export declare const ResponseFrame: S.Struct<{
626
642
  model: S.Unknown;
627
643
  }>, import("../schema/index.js").CallableTaggedStruct<"ResponseResumed", {}>, import("../schema/index.js").CallableTaggedStruct<"ResponseDispatched", {
628
644
  acceptedAtIndex: S.Number;
645
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseDispatchedBatch", {
646
+ acceptedAtIndices: S.$Array<S.Number>;
629
647
  }>, import("../schema/index.js").CallableTaggedStruct<"ResponseRuntimes", {
630
648
  runtimes: S.$Array<S.Struct<{
631
649
  readonly connectionId: S.String;
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/devTools/protocol.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/devTools/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAM5C,0NAA0N;AAC1N,eAAO,MAAM,iBAAiB;;;EAG5B,CAAA;AACF,2EAA2E;AAC3E,MAAM,MAAM,iBAAiB,GAAG,OAAO,iBAAiB,CAAC,IAAI,CAAA;AAE7D,0MAA0M;AAC1M,eAAO,MAAM,eAAe;;;EAG1B,CAAA;AACF,yFAAyF;AACzF,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA;AAEzD,wfAAwf;AACxf,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;EAa1B,CAAA;AACF,iFAAiF;AACjF,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA;AAEzD,wHAAwH;AACxH,eAAO,MAAM,YAAY;;EAEvB,CAAA;AACF,wCAAwC;AACxC,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAEnD,kDAAkD;AAClD,eAAO,MAAM,WAAW;;;;EAItB,CAAA;AACF,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA;AAIjD,yFAAyF;AACzF,eAAO,MAAM,eAAe;;;EAG1B,CAAA;AAEF,8JAA8J;AAC9J,eAAO,MAAM,iBAAiB;;;;EAI5B,CAAA;AAEF,2pBAA2pB;AAC3pB,eAAO,MAAM,mBAAmB;;;;;EAO9B,CAAA;AAEF,sPAAsP;AACtP,eAAO,MAAM,yBAAyB;;;EAGpC,CAAA;AAEF,8TAA8T;AAC9T,eAAO,MAAM,iBAAiB;;;;EAI5B,CAAA;AAEF,8JAA8J;AAC9J,eAAO,MAAM,iBAAiB;;EAE5B,CAAA;AAEF,+CAA+C;AAC/C,eAAO,MAAM,oBAAoB,+EAA6B,CAAA;AAE9D,mHAAmH;AACnH,eAAO,MAAM,uBAAuB;;EAElC,CAAA;AAEF,uEAAuE;AACvE,eAAO,MAAM,aAAa,wEAAsB,CAAA;AAEhD,wGAAwG;AACxG,eAAO,MAAM,cAAc,yEAAuB,CAAA;AAElD,oIAAoI;AACpI,eAAO,MAAM,sBAAsB,iFAA+B,CAAA;AAElE,kKAAkK;AAClK,eAAO,MAAM,sBAAsB;;EAEjC,CAAA;AAEF,iUAAiU;AACjU,eAAO,MAAM,uBAAuB,MAAM,CAAA;AAE1C,2iBAA2iB;AAC3iB,eAAO,MAAM,uBAAuB;;EAElC,CAAA;AAEF,61BAA61B;AAC71B,eAAO,MAAM,uBAAuB;;EAElC,CAAA;AAEF,wHAAwH;AACxH,eAAO,MAAM,mBAAmB,8EAA4B,CAAA;AAE5D,kJAAkJ;AAClJ,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAgBlB,CAAA;AACF,qCAAqC;AACrC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,wVAAwV;AACxV,eAAO,MAAM,aAAa;;;;EAIxB,CAAA;AAEF,4VAA4V;AAC5V,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;EAG3B,CAAA;AAEF,gLAAgL;AAChL,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;EAE1B,CAAA;AAEF,0CAA0C;AAC1C,eAAO,MAAM,eAAe;;;EAG1B,CAAA;AACF,0CAA0C;AAC1C,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA;AAEzD,iXAAiX;AACjX,eAAO,MAAM,qBAAqB;;;;;;;;EAKhC,CAAA;AAEF,2XAA2X;AAC3X,eAAO,MAAM,eAAe,iEAAe,CAAA;AAC3C,mEAAmE;AACnE,eAAO,MAAM,gBAAgB;;EAAsC,CAAA;AACnE,kDAAkD;AAClD,eAAO,MAAM,SAAS;;IAA+C,CAAA;AACrE,kDAAkD;AAClD,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAE7C,8GAA8G;AAC9G,eAAO,MAAM,eAAe;;;;;;;;EAI1B,CAAA;AACF,wCAAwC;AACxC,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA;AAEzD,mRAAmR;AACnR,eAAO,MAAM,iBAAiB;;;;;;;;;;;;EAI5B,CAAA;AAEF,yDAAyD;AACzD,eAAO,MAAM,iBAAiB;;;;EAE5B,CAAA;AAEF,oFAAoF;AACpF,eAAO,MAAM,gBAAgB;;EAE3B,CAAA;AAEF,gEAAgE;AAChE,eAAO,MAAM,eAAe,0EAAwB,CAAA;AAEpD,svBAAsvB;AACtvB,eAAO,MAAM,kBAAkB;;EAE7B,CAAA;AAEF,waAAwa;AACxa,eAAO,MAAM,uBAAuB;;EAElC,CAAA;AAEF,+eAA+e;AAC/e,eAAO,MAAM,uBAAuB;;;;EAIlC,CAAA;AACF,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAAG,OAAO,uBAAuB,CAAC,IAAI,CAAA;AAEzE,+RAA+R;AAC/R,eAAO,MAAM,kBAAkB;;;;;;EAE7B,CAAA;AACF,2DAA2D;AAC3D,MAAM,MAAM,kBAAkB,GAAG,OAAO,kBAAkB,CAAC,IAAI,CAAA;AAE/D,8PAA8P;AAC9P,eAAO,MAAM,wBAAwB;;;;;;;;EAEnC,CAAA;AAEF,+KAA+K;AAC/K,eAAO,MAAM,2BAA2B;;EAEtC,CAAA;AAEF,QAAA,MAAM,mBAAmB;;;;;;;;;;IAGvB,CAAA;AACF,6DAA6D;AAC7D,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAC,IAAI,CAAA;AAEjE,urCAAurC;AACvrC,eAAO,MAAM,qBAAqB;;;;;;;;;;;;EAEhC,CAAA;AAEF,wDAAwD;AACxD,eAAO,MAAM,gBAAgB;;;;;;EAE3B,CAAA;AAEF,sbAAsb;AACtb,eAAO,MAAM,YAAY;;;;;;;;;;EAIvB,CAAA;AAEF,4jBAA4jB;AAC5jB,eAAO,MAAM,oBAAoB;;;;;;;EAO/B,CAAA;AAEF,8DAA8D;AAC9D,eAAO,MAAM,aAAa;;EAExB,CAAA;AAEF,wCAAwC;AACxC,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAgBnB,CAAA;AACF,wCAAwC;AACxC,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAI3C,uCAAuC;AACvC,eAAO,MAAM,cAAc;;;;;;EAEzB,CAAA;AAEF,mDAAmD;AACnD,eAAO,MAAM,iBAAiB;;EAE5B,CAAA;AAEF,iIAAiI;AACjI,eAAO,MAAM,KAAK;;;;;;;;IAA+C,CAAA;AACjE,iCAAiC;AACjC,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,0NAA0N;AAC1N,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIvB,CAAA;AACF,2DAA2D;AAC3D,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAEnD,uEAAuE;AACvE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGxB,CAAA;AACF,uEAAuE;AACvE,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC,IAAI,CAAA;AAErD,0FAA0F;AAC1F,eAAO,MAAM,UAAU;;;;;;;;;;;EAGrB,CAAA;AACF,uDAAuD;AACvD,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC,IAAI,CAAA"}
@@ -86,6 +86,12 @@ export const RequestGetRuntimeState = ts('RequestGetRuntimeState');
86
86
  export const RequestDispatchMessage = ts('RequestDispatchMessage', {
87
87
  message: S.Unknown,
88
88
  });
89
+ /** The largest batch `RequestDispatchMessages` accepts. Matches the DevTools store's default history size, so a batch cannot evict its own earliest entries before the caller reads them back. The runtime rejects a larger batch with `ResponseError`, and MCP clients reject it earlier still, at their own input boundary. */
90
+ export const MAX_DISPATCH_BATCH_SIZE = 100;
91
+ /** Request the runtime dispatch an ordered batch of Messages at the current state. Payloads are opaque to the protocol; the runtime decodes every entry against the app's Message Schema before dispatching any of them, so one invalid entry rejects the whole batch and no Message from it is dispatched. Decoded Messages dispatch in array order through the same path as single dispatch, so the runtime may still record its own Messages between entries, exactly as with rapid user input. Batches larger than `MAX_DISPATCH_BATCH_SIZE` are rejected outright. */
92
+ export const RequestDispatchMessages = ts('RequestDispatchMessages', {
93
+ messages: S.Array(S.Unknown),
94
+ });
89
95
  /** Request a description of the app's Message Schema. The runtime derives a JSON Schema document once at bridge boot from the configured `DevToolsConfig.Message`; the response is `None` when no Message Schema was configured. With `maybeVariantTag: None`, the response carries a small variant index (tag names plus payload field names and a tagged-union indicator) so MCP clients can enumerate the top-level variants without paying for the full schema. With `maybeVariantTag: Some(path)`, the value is interpreted as a dot-separated path of variant `_tag` values walked through each variant's single tagged-union payload field; the response carries the JSON Schema document narrowed along that chain, with any deeper unions collapsed to summary placeholders. Use the index to discover variants, then fetch one variant before calling `RequestDispatchMessage`. */
90
96
  export const RequestGetMessageSchema = ts('RequestGetMessageSchema', {
91
97
  maybeVariantTag: S.OptionFromNullOr(S.String),
@@ -104,6 +110,7 @@ export const Request = S.Union([
104
110
  RequestReplayToKeyframe,
105
111
  RequestResume,
106
112
  RequestDispatchMessage,
113
+ RequestDispatchMessages,
107
114
  RequestListRuntimes,
108
115
  RequestGetInit,
109
116
  RequestGetRuntimeState,
@@ -165,10 +172,14 @@ export const ResponseReplayed = ts('ResponseReplayed', {
165
172
  });
166
173
  /** Response confirming the runtime resumed normal execution. */
167
174
  export const ResponseResumed = ts('ResponseResumed');
168
- /** Response confirming a Message was dispatched. The `acceptedAtIndex` is the absolute history index where the entry is predicted to land. Computed from the runtime's history length at dispatch time. The runtime processes Messages in arrival order and the bridge is the only external dispatch source, so this index is reliable for correlation. */
175
+ /** Response confirming a Message was dispatched. The `acceptedAtIndex` is the absolute history index where the entry is predicted to land. Computed from the runtime's history length at dispatch time. The runtime processes Messages in arrival order, so the index is reliable whenever the bridge is the only Message source, but the app produces its own Messages too (user input, Subscription emissions, Command results); one recorded between the snapshot and the dispatch shifts the entry past this index. Messages excluded from history via `excludeFromHistory` still drive `update` but are never recorded, so no entry lands at the predicted index for them, and a Message dispatched into a crashed or disposed runtime is dropped without recording anything. */
169
176
  export const ResponseDispatched = ts('ResponseDispatched', {
170
177
  acceptedAtIndex: S.Number,
171
178
  });
179
+ /** Response confirming a batch dispatch. `acceptedAtIndices` aligns with the request's `messages` order; each value is the absolute history index where that entry is predicted to land, computed from one history snapshot at dispatch time with the same caveats as `ResponseDispatched.acceptedAtIndex`. An `excludeFromHistory` Message inside the batch records no entry, so entries after it land below their predicted index. */
180
+ export const ResponseDispatchedBatch = ts('ResponseDispatchedBatch', {
181
+ acceptedAtIndices: S.Array(S.Number),
182
+ });
172
183
  /** One variant entry in a `MessageSchemaIndex`. `payloadFields` lists the variant's payload property names (excluding `_tag`); `unionFields` lists the subset of those properties whose schemas are themselves `_tag`-discriminated unions. A Submodel-wrapper variant always shows up with `unionFields: ['message']`, but the same flag also catches plain tagged-union value types like `UrlRequest = Internal | External`. Either way, the agent will need to pick a variant when filling these fields. */
173
184
  export const MessageSchemaIndexEntry = S.Struct({
174
185
  tag: S.String,
@@ -229,6 +240,7 @@ export const Response = S.Union([
229
240
  ResponseReplayed,
230
241
  ResponseResumed,
231
242
  ResponseDispatched,
243
+ ResponseDispatchedBatch,
232
244
  ResponseRuntimes,
233
245
  ResponseInit,
234
246
  ResponseRuntimeState,
@@ -1,2 +1,2 @@
1
- export { EventConnected, EventDisconnected, EventFrame, Event, KeyframeInfo, DiffValue, DiffValueAbsent, DiffValuePresent, MessageTagCount, ModelDiffChange, RequestCountMessagesByTag, RequestDiffModels, RequestDispatchMessage, RequestFrame, RequestGetInit, RequestGetMessage, RequestGetMessageSchema, RequestGetModel, RequestGetModelAt, RequestGetRuntimeState, RequestListKeyframes, RequestListMessages, RequestListRuntimes, RequestReplayToKeyframe, RequestResume, Request, ResponseDispatched, ResponseError, ResponseFrame, ResponseInit, ResponseKeyframes, ResponseMessage, ResponseMessageCounts, ResponseMessages, ResponseMessageSchema, ResponseModel, ResponseModelDiff, ResponseReplayed, ResponseResumed, ResponseRuntimes, ResponseRuntimeState, Response, RuntimeInfo, SerializedEntry, } from './protocol.js';
1
+ export { EventConnected, EventDisconnected, EventFrame, Event, KeyframeInfo, DiffValue, DiffValueAbsent, DiffValuePresent, MAX_DISPATCH_BATCH_SIZE, MessageTagCount, ModelDiffChange, RequestCountMessagesByTag, RequestDiffModels, RequestDispatchMessage, RequestDispatchMessages, RequestFrame, RequestGetInit, RequestGetMessage, RequestGetMessageSchema, RequestGetModel, RequestGetModelAt, RequestGetRuntimeState, RequestListKeyframes, RequestListMessages, RequestListRuntimes, RequestReplayToKeyframe, RequestResume, Request, ResponseDispatched, ResponseDispatchedBatch, ResponseError, ResponseFrame, ResponseInit, ResponseKeyframes, ResponseMessage, ResponseMessageCounts, ResponseMessages, ResponseMessageSchema, ResponseModel, ResponseModelDiff, ResponseReplayed, ResponseResumed, ResponseRuntimes, ResponseRuntimeState, Response, RuntimeInfo, SerializedEntry, } from './protocol.js';
2
2
  //# sourceMappingURL=public.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/devTools/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,KAAK,EACL,YAAY,EACZ,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,QAAQ,EACR,WAAW,EACX,eAAe,GAChB,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/devTools/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,KAAK,EACL,YAAY,EACZ,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,eAAe,EACf,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,EACvB,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,OAAO,EACP,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACb,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,QAAQ,EACR,WAAW,EACX,eAAe,GAChB,MAAM,eAAe,CAAA"}
@@ -1 +1 @@
1
- export { EventConnected, EventDisconnected, EventFrame, Event, KeyframeInfo, DiffValue, DiffValueAbsent, DiffValuePresent, MessageTagCount, ModelDiffChange, RequestCountMessagesByTag, RequestDiffModels, RequestDispatchMessage, RequestFrame, RequestGetInit, RequestGetMessage, RequestGetMessageSchema, RequestGetModel, RequestGetModelAt, RequestGetRuntimeState, RequestListKeyframes, RequestListMessages, RequestListRuntimes, RequestReplayToKeyframe, RequestResume, Request, ResponseDispatched, ResponseError, ResponseFrame, ResponseInit, ResponseKeyframes, ResponseMessage, ResponseMessageCounts, ResponseMessages, ResponseMessageSchema, ResponseModel, ResponseModelDiff, ResponseReplayed, ResponseResumed, ResponseRuntimes, ResponseRuntimeState, Response, RuntimeInfo, SerializedEntry, } from './protocol.js';
1
+ export { EventConnected, EventDisconnected, EventFrame, Event, KeyframeInfo, DiffValue, DiffValueAbsent, DiffValuePresent, MAX_DISPATCH_BATCH_SIZE, MessageTagCount, ModelDiffChange, RequestCountMessagesByTag, RequestDiffModels, RequestDispatchMessage, RequestDispatchMessages, RequestFrame, RequestGetInit, RequestGetMessage, RequestGetMessageSchema, RequestGetModel, RequestGetModelAt, RequestGetRuntimeState, RequestListKeyframes, RequestListMessages, RequestListRuntimes, RequestReplayToKeyframe, RequestResume, Request, ResponseDispatched, ResponseDispatchedBatch, ResponseError, ResponseFrame, ResponseInit, ResponseKeyframes, ResponseMessage, ResponseMessageCounts, ResponseMessages, ResponseMessageSchema, ResponseModel, ResponseModelDiff, ResponseReplayed, ResponseResumed, ResponseRuntimes, ResponseRuntimeState, Response, RuntimeInfo, SerializedEntry, } from './protocol.js';
@@ -45,6 +45,12 @@ export type Bridge = Readonly<{
45
45
  * when no Messages have been recorded yet.
46
46
  */
47
47
  export declare const latestEntryIndex: (state: StoreState) => number;
48
+ /**
49
+ * The absolute index the next recorded entry will land at. `recordMessage`
50
+ * assigns indices from this formula, so dispatch predictions derived from it
51
+ * match where entries are actually recorded.
52
+ */
53
+ export declare const nextEntryIndex: (state: StoreState) => number;
48
54
  /**
49
55
  * Options for `createDevToolsStore`.
50
56
  *
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/devTools/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/devTools/store.ts"],"names":[],"mappings":"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"}
@@ -91,6 +91,12 @@ export const latestEntryIndex = (state) => Array.match(state.entries, {
91
91
  onEmpty: () => INIT_INDEX,
92
92
  onNonEmpty: entries => state.startIndex + entries.length - 1,
93
93
  });
94
+ /**
95
+ * The absolute index the next recorded entry will land at. `recordMessage`
96
+ * assigns indices from this formula, so dispatch predictions derived from it
97
+ * match where entries are actually recorded.
98
+ */
99
+ export const nextEntryIndex = (state) => state.startIndex + state.entries.length;
94
100
  export const createDevToolsStore = (bridge, options = {}) => Effect.gen(function* () {
95
101
  const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
96
102
  const keyframeInterval = options.keyframeInterval ?? DEFAULT_KEYFRAME_INTERVAL;
@@ -135,7 +141,7 @@ export const createDevToolsStore = (bridge, options = {}) => Effect.gen(function
135
141
  maybeLatestModel: () => Option.some(model),
136
142
  }));
137
143
  const recordMessage = (message, modelBeforeUpdate, modelAfterUpdate, commands, isModelChanged) => SubscriptionRef.update(stateRef, state => {
138
- const absoluteIndex = state.startIndex + state.entries.length;
144
+ const absoluteIndex = nextEntryIndex(state);
139
145
  const diff = isModelChanged
140
146
  ? computeDiff(modelBeforeUpdate, modelAfterUpdate)
141
147
  : emptyDiff;
@@ -1,4 +1,5 @@
1
1
  import { Effect, Option, Schema as S, Scope } from 'effect';
2
+ import { type Request, type Response } from './protocol.js';
2
3
  import { type DevToolsStore } from './store.js';
3
4
  type Hot = NonNullable<ImportMeta['hot']>;
4
5
  /**
@@ -33,5 +34,11 @@ type Hot = NonNullable<ImportMeta['hot']>;
33
34
  * invoking this. The function assumes a live HMR connection.
34
35
  */
35
36
  export declare const startWebSocketBridge: (store: DevToolsStore, hot: Hot, dispatch: (message: unknown) => Effect.Effect<void>, maybeMessageSchema: Option.Option<S.Codec<any, any>>) => Effect.Effect<void, never, Scope.Scope>;
37
+ /**
38
+ * Fulfill one bridge Request against the DevTools store. `startWebSocketBridge`
39
+ * wires this to the HMR request channel; exported so tests can drive request
40
+ * handling without a live HMR connection.
41
+ */
42
+ export declare const dispatchRequest: (store: DevToolsStore, dispatch: (message: unknown) => Effect.Effect<void>, maybeDispatchSchema: Option.Option<S.Codec<any, any>>, maybeJsonSchemaDocument: Option.Option<unknown>, request: Request) => Effect.Effect<Response>;
36
43
  export {};
37
44
  //# sourceMappingURL=webSocketBridge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webSocketBridge.d.ts","sourceRoot":"","sources":["../../src/devTools/webSocketBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EAIN,MAAM,EAEN,MAAM,IAAI,CAAC,EACX,KAAK,EAGN,MAAM,QAAQ,CAAA;AAwDf,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,YAAY,CAAA;AAQnB,KAAK,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;AAuBzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,aAAa,EACpB,KAAK,GAAG,EACR,UAAU,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EACnD,oBAAoB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KACnD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAkGrC,CAAA"}
1
+ {"version":3,"file":"webSocketBridge.d.ts","sourceRoot":"","sources":["../../src/devTools/webSocketBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EAIN,MAAM,EAEN,MAAM,IAAI,CAAC,EACX,KAAK,EAGN,MAAM,QAAQ,CAAA;AAcf,OAAO,EAYL,KAAK,OAAO,EAEZ,KAAK,QAAQ,EAiBd,MAAM,eAAe,CAAA;AAatB,OAAO,EACL,KAAK,aAAa,EAKnB,MAAM,YAAY,CAAA;AAQnB,KAAK,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;AAuBzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,aAAa,EACpB,KAAK,GAAG,EACR,UAAU,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EACnD,oBAAoB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KACnD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAkGrC,CAAA;AAsIJ;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,aAAa,EACpB,UAAU,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EACnD,qBAAqB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EACrD,yBAAyB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAC/C,SAAS,OAAO,KACf,MAAM,CAAC,MAAM,CAAC,QAAQ,CA4UtB,CAAA"}
@@ -1,10 +1,10 @@
1
1
  import { Array, Cause, Effect, Exit, HashMap, Match, Option, Order, Schema as S, SubscriptionRef, pipe, } from 'effect';
2
2
  import { OptionExt } from '../effectExtensions/index.js';
3
3
  import { collectMatchingEntries, countEntriesByTag, findUnanchoredPattern, formatIndexNotReadable, isIndexReadable, matchesAnyPathPattern, pageMatchingEntries, pathOrder, readSummarizedValueAt, } from './historyQuery.js';
4
- import { DiffValueAbsent, DiffValuePresent, EventConnected, EventDisconnected, EventFrame, KeyframeInfo, MessageSchemaDocumentResult, MessageSchemaIndexResult, RequestFrame, ResponseDispatched, ResponseError, ResponseFrame, ResponseInit, ResponseKeyframes, ResponseMessage, ResponseMessageCounts, ResponseMessageSchema, ResponseMessages, ResponseModel, ResponseModelDiff, ResponseReplayed, ResponseResumed, ResponseRuntimeState, RuntimeInfo, } from './protocol.js';
4
+ import { DiffValueAbsent, DiffValuePresent, EventConnected, EventDisconnected, EventFrame, KeyframeInfo, MAX_DISPATCH_BATCH_SIZE, MessageSchemaDocumentResult, MessageSchemaIndexResult, RequestFrame, ResponseDispatched, ResponseDispatchedBatch, ResponseError, ResponseFrame, ResponseInit, ResponseKeyframes, ResponseMessage, ResponseMessageCounts, ResponseMessageSchema, ResponseMessages, ResponseModel, ResponseModelDiff, ResponseReplayed, ResponseResumed, ResponseRuntimeState, RuntimeInfo, } from './protocol.js';
5
5
  import { diagnoseVariantPath, indexMessageSchemaDocument, narrowToVariant, splitVariantPath, } from './schemaSummarize.js';
6
6
  import { toInspectableValue, toSerializedCommand, toSerializedEntry, toSerializedMount, } from './serialize.js';
7
- import { INIT_INDEX, computeDiff, latestEntryIndex, } from './store.js';
7
+ import { INIT_INDEX, computeDiff, latestEntryIndex, nextEntryIndex, } from './store.js';
8
8
  import { formatPathNotFound, resolvePath, summarizeValue, } from './summarize.js';
9
9
  const REQUEST_CHANNEL = 'foldkit:devTools:request';
10
10
  const RESPONSE_CHANNEL = 'foldkit:devTools:response';
@@ -175,7 +175,16 @@ const formatUnknownVariantError = (document, variantPath) => {
175
175
  },
176
176
  });
177
177
  };
178
- const dispatchRequest = (store, dispatch, maybeDispatchSchema, maybeJsonSchemaDocument, request) => Match.value(request).pipe(Match.tagsExhaustive({
178
+ const missingMessageSchemaResponse = ResponseError({
179
+ reason: 'Cannot dispatch: DevToolsConfig.Message not configured. Pass your Message Schema to enable dispatch.',
180
+ });
181
+ const formatInvalidMessageReason = (error, message) => `${error instanceof Error ? error.message : String(error)}\n\nReceived (typeof ${typeof message}): ${JSON.stringify(message)}`;
182
+ /**
183
+ * Fulfill one bridge Request against the DevTools store. `startWebSocketBridge`
184
+ * wires this to the HMR request channel; exported so tests can drive request
185
+ * handling without a live HMR connection.
186
+ */
187
+ export const dispatchRequest = (store, dispatch, maybeDispatchSchema, maybeJsonSchemaDocument, request) => Match.value(request).pipe(Match.tagsExhaustive({
179
188
  RequestGetModel: ({ maybePath, expand }) => Effect.gen(function* () {
180
189
  const state = yield* SubscriptionRef.get(store.stateRef);
181
190
  const index = latestEntryIndex(state);
@@ -297,19 +306,38 @@ const dispatchRequest = (store, dispatch, maybeDispatchSchema, maybeJsonSchemaDo
297
306
  reason: `Failed to resume: ${Cause.pretty(cause)}`,
298
307
  })))),
299
308
  RequestDispatchMessage: ({ message }) => Option.match(maybeDispatchSchema, {
300
- onNone: () => Effect.succeed(ResponseError({
301
- reason: 'Cannot dispatch: DevToolsConfig.Message not configured. Pass your Message Schema to enable dispatch.',
302
- })),
309
+ onNone: () => Effect.succeed(missingMessageSchemaResponse),
303
310
  onSome: dispatchSchema => Effect.gen(function* () {
304
311
  const decodedMessage = yield* S.decodeUnknownEffect(dispatchSchema)(message);
305
312
  const stateBefore = yield* SubscriptionRef.get(store.stateRef);
306
- const acceptedAtIndex = stateBefore.startIndex + stateBefore.entries.length;
313
+ const acceptedAtIndex = nextEntryIndex(stateBefore);
307
314
  yield* dispatch(decodedMessage);
308
315
  return ResponseDispatched({ acceptedAtIndex });
309
316
  }).pipe(Effect.catch(error => Effect.succeed(ResponseError({
310
- reason: `Invalid Message: ${error instanceof Error ? error.message : String(error)}\n\nReceived (typeof ${typeof message}): ${JSON.stringify(message)}`,
317
+ reason: `Invalid Message: ${formatInvalidMessageReason(error, message)}`,
311
318
  })))),
312
319
  }),
320
+ RequestDispatchMessages: ({ messages }) => {
321
+ if (messages.length > MAX_DISPATCH_BATCH_SIZE) {
322
+ return Effect.succeed(ResponseError({
323
+ reason: `Batch too large: ${messages.length} Messages exceeds the limit of ${MAX_DISPATCH_BATCH_SIZE}. No Messages from the batch were dispatched.`,
324
+ }));
325
+ }
326
+ return Option.match(maybeDispatchSchema, {
327
+ onNone: () => Effect.succeed(missingMessageSchemaResponse),
328
+ onSome: dispatchSchema => Effect.gen(function* () {
329
+ const decodeMessage = S.decodeUnknownEffect(dispatchSchema);
330
+ const decodedMessages = yield* Effect.forEach(messages, (message, position) => Effect.mapError(decodeMessage(message), error => new Error(`Invalid Message at zero-based batch position ${position}: ${formatInvalidMessageReason(error, message)}\n\nNo Messages from the batch were dispatched.`)));
331
+ const stateBefore = yield* SubscriptionRef.get(store.stateRef);
332
+ const firstAcceptedIndex = nextEntryIndex(stateBefore);
333
+ yield* Effect.forEach(decodedMessages, dispatch);
334
+ const acceptedAtIndices = Array.map(decodedMessages, (_decodedMessage, offset) => firstAcceptedIndex + offset);
335
+ return ResponseDispatchedBatch({ acceptedAtIndices });
336
+ }).pipe(Effect.catch(error => Effect.succeed(ResponseError({
337
+ reason: error instanceof Error ? error.message : String(error),
338
+ })))),
339
+ });
340
+ },
313
341
  RequestGetMessageSchema: ({ maybeVariantTag }) => Effect.succeed(buildMessageSchemaResponse(maybeJsonSchemaDocument, maybeVariantTag)),
314
342
  RequestListRuntimes: () => Effect.succeed(ResponseError({
315
343
  reason: 'RequestListRuntimes is plugin-handled and should not reach the runtime bridge',
@@ -1 +1 @@
1
- {"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../../src/html/boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,wDAAwD;AACxD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;CAC/C,CAAC,CAAA;AAEF;;;;eAIe;AACf,MAAM,MAAM,UAAU,GAAG,MAAM,CAAA;AAI/B,eAAO,MAAM,aAAa,EAAE,UAAe,CAAA;AAE3C,eAAO,MAAM,eAAe,GAC1B,QAAQ,UAAU,EAClB,SAAS,MAAM,KACd,UAUF,CAAA;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAwCa;AACb,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAClC,YAAY,EACZ,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,CAC9B,CAAA;IACD,QAAQ,CAAC,cAAc,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAChD,QAAQ,CAAC,iBAAiB,EAAE,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA;IAI1D,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACjC,CAAA;AAED,eAAO,MAAM,sBAAsB,QAAO,gBAMxC,CAAA;AAqBF,eAAO,MAAM,oBAAoB,GAC/B,UAAU,gBAAgB,EAC1B,YAAY,UAAU,EACtB,YAAY,cAAc,KACzB,IA6BF,CAAA;AAED;;;;wCAIwC;AACxC,eAAO,MAAM,iBAAiB,GAC5B,UAAU,gBAAgB,KACzB,GAAG,CAAC,UAAU,EAAE,MAAM,CAIxB,CAAA;AAED;;yCAEyC;AACzC,eAAO,MAAM,eAAe,GAAI,UAAU,gBAAgB,KAAG,IAQ5D,CAAA;AAED;;;;;;;4CAO4C;AAC5C,eAAO,MAAM,kBAAkB,GAC7B,UAAU,gBAAgB,EAC1B,YAAY,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC,KAC1C,IAWF,CAAA;AAED;;;;;;;;;gBASgB;AAChB,eAAO,MAAM,sBAAsB,GACjC,UAAU,gBAAgB,EAC1B,YAAY,UAAU,KACrB,IAEF,CAAA;AA8CD;;;;;;;;;;;;mFAYmF;AACnF,eAAO,MAAM,4BAA4B,GACvC,UAAU,gBAAgB,EAC1B,eAAe,YAAY,EAC3B,YAAY,UAAU,EACtB,SAAS,OAAO,KACf,CAAC,MAAM,IAAI,CAqBb,CAAA;AAED;;;;;;;8EAO8E;AAC9E,eAAO,MAAM,eAAe,GAC1B,UAAU,gBAAgB,EAC1B,YAAY,UAAU,KACrB,aAAa,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAiB7C,CAAA;AAED,eAAO,MAAM,2BAA2B,GACtC,UAAU,gBAAgB,EAC1B,eAAe,YAAY,EAC3B,YAAY,UAAU,KACrB,YAkBF,CAAA;AAED;;;;;;;;;;iEAUiE;AACjE,eAAO,MAAM,WAAW,GAAI,UAAU,gBAAgB,KAAG,IAGxD,CAAA"}
1
+ {"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../../src/html/boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,wDAAwD;AACxD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;CAC/C,CAAC,CAAA;AAEF;;;;eAIe;AACf,MAAM,MAAM,UAAU,GAAG,MAAM,CAAA;AAI/B,eAAO,MAAM,aAAa,EAAE,UAAe,CAAA;AAE3C,eAAO,MAAM,eAAe,GAC1B,QAAQ,UAAU,EAClB,SAAS,MAAM,KACd,UAUF,CAAA;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAwCa;AACb,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAClC,YAAY,EACZ,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,CAC9B,CAAA;IACD,QAAQ,CAAC,cAAc,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAChD,QAAQ,CAAC,iBAAiB,EAAE,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA;IAI1D,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACjC,CAAA;AAED,eAAO,MAAM,sBAAsB,QAAO,gBAMxC,CAAA;AAqBF,eAAO,MAAM,oBAAoB,GAC/B,UAAU,gBAAgB,EAC1B,YAAY,UAAU,EACtB,YAAY,cAAc,KACzB,IA6BF,CAAA;AAED;;;;wCAIwC;AACxC,eAAO,MAAM,iBAAiB,GAC5B,UAAU,gBAAgB,KACzB,GAAG,CAAC,UAAU,EAAE,MAAM,CAIxB,CAAA;AAED;;yCAEyC;AACzC,eAAO,MAAM,eAAe,GAAI,UAAU,gBAAgB,KAAG,IAQ5D,CAAA;AAED;;;;;;;4CAO4C;AAC5C,eAAO,MAAM,kBAAkB,GAC7B,UAAU,gBAAgB,EAC1B,YAAY,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC,KAC1C,IAWF,CAAA;AAED;;;;;;;;;gBASgB;AAChB,eAAO,MAAM,sBAAsB,GACjC,UAAU,gBAAgB,EAC1B,YAAY,UAAU,KACrB,IAEF,CAAA;AAmGD;;;;;;;;;;;;mFAYmF;AACnF,eAAO,MAAM,4BAA4B,GACvC,UAAU,gBAAgB,EAC1B,eAAe,YAAY,EAC3B,YAAY,UAAU,EACtB,SAAS,OAAO,KACf,CAAC,MAAM,IAAI,CAqBb,CAAA;AAED;;;;;;;8EAO8E;AAC9E,eAAO,MAAM,eAAe,GAC1B,UAAU,gBAAgB,EAC1B,YAAY,UAAU,KACrB,aAAa,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAiB7C,CAAA;AAED,eAAO,MAAM,2BAA2B,GACtC,UAAU,gBAAgB,EAC1B,eAAe,YAAY,EAC3B,YAAY,UAAU,KACrB,YAkBF,CAAA;AAED;;;;;;;;;;iEAUiE;AACjE,eAAO,MAAM,WAAW,GAAI,UAAU,gBAAgB,KAAG,IAGxD,CAAA"}