foldkit 0.132.0 → 0.134.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.
Files changed (90) hide show
  1. package/README.md +59 -108
  2. package/dist/canvas/view.d.ts +18 -11
  3. package/dist/canvas/view.d.ts.map +1 -1
  4. package/dist/canvas/view.js +18 -11
  5. package/dist/customElement/index.d.ts +9 -6
  6. package/dist/customElement/index.d.ts.map +1 -1
  7. package/dist/customElement/index.js +14 -3
  8. package/dist/devTools/protocol.d.ts +19 -1
  9. package/dist/devTools/protocol.d.ts.map +1 -1
  10. package/dist/devTools/protocol.js +13 -1
  11. package/dist/devTools/public.d.ts +1 -1
  12. package/dist/devTools/public.d.ts.map +1 -1
  13. package/dist/devTools/public.js +1 -1
  14. package/dist/devTools/store.d.ts +6 -0
  15. package/dist/devTools/store.d.ts.map +1 -1
  16. package/dist/devTools/store.js +7 -1
  17. package/dist/devTools/webSocketBridge.d.ts +7 -0
  18. package/dist/devTools/webSocketBridge.d.ts.map +1 -1
  19. package/dist/devTools/webSocketBridge.js +36 -8
  20. package/dist/html/boundary.d.ts.map +1 -1
  21. package/dist/html/boundary.js +48 -2
  22. package/dist/html/index.d.ts +682 -1643
  23. package/dist/html/index.d.ts.map +1 -1
  24. package/dist/html/index.js +56 -16
  25. package/dist/html/public.d.ts +2 -2
  26. package/dist/html/public.d.ts.map +1 -1
  27. package/dist/html/public.js +1 -1
  28. package/dist/html/runtimeSingleton.d.ts +1 -1
  29. package/dist/html/runtimeSingleton.d.ts.map +1 -1
  30. package/dist/html/runtimeSingleton.js +1 -1
  31. package/dist/html/submodel.d.ts +51 -19
  32. package/dist/html/submodel.d.ts.map +1 -1
  33. package/dist/html/submodel.js +37 -13
  34. package/dist/route/transition.d.ts +35 -29
  35. package/dist/route/transition.d.ts.map +1 -1
  36. package/dist/route/transition.js +36 -30
  37. package/dist/runtime/crashUI.d.ts.map +1 -1
  38. package/dist/runtime/crashUI.js +29 -30
  39. package/dist/runtime/runtime.d.ts +9 -6
  40. package/dist/runtime/runtime.d.ts.map +1 -1
  41. package/dist/runtime/runtime.js +25 -8
  42. package/dist/test/apps/attributes.d.ts +2 -2
  43. package/dist/test/apps/attributes.d.ts.map +1 -1
  44. package/dist/test/apps/attributes.js +1 -3
  45. package/dist/test/apps/bubbling.d.ts +2 -2
  46. package/dist/test/apps/bubbling.d.ts.map +1 -1
  47. package/dist/test/apps/bubbling.js +1 -3
  48. package/dist/test/apps/counter.d.ts +2 -2
  49. package/dist/test/apps/counter.d.ts.map +1 -1
  50. package/dist/test/apps/counter.js +1 -3
  51. package/dist/test/apps/crashOnRender.d.ts +2 -2
  52. package/dist/test/apps/crashOnRender.d.ts.map +1 -1
  53. package/dist/test/apps/crashOnRender.js +1 -3
  54. package/dist/test/apps/drafts.d.ts +2 -2
  55. package/dist/test/apps/drafts.d.ts.map +1 -1
  56. package/dist/test/apps/drafts.js +1 -3
  57. package/dist/test/apps/fileUpload.d.ts +2 -2
  58. package/dist/test/apps/fileUpload.d.ts.map +1 -1
  59. package/dist/test/apps/fileUpload.js +1 -3
  60. package/dist/test/apps/interactions.d.ts +2 -2
  61. package/dist/test/apps/interactions.d.ts.map +1 -1
  62. package/dist/test/apps/interactions.js +1 -3
  63. package/dist/test/apps/keypress.d.ts +2 -2
  64. package/dist/test/apps/keypress.d.ts.map +1 -1
  65. package/dist/test/apps/keypress.js +1 -3
  66. package/dist/test/apps/login.d.ts +2 -2
  67. package/dist/test/apps/login.d.ts.map +1 -1
  68. package/dist/test/apps/login.js +1 -3
  69. package/dist/test/apps/logoutButton.d.ts +2 -2
  70. package/dist/test/apps/logoutButton.d.ts.map +1 -1
  71. package/dist/test/apps/logoutButton.js +1 -3
  72. package/dist/test/apps/mountPanel.d.ts +4 -4
  73. package/dist/test/apps/mountPanel.d.ts.map +1 -1
  74. package/dist/test/apps/mountPanel.js +3 -7
  75. package/dist/test/apps/multiRole.d.ts +2 -2
  76. package/dist/test/apps/multiRole.d.ts.map +1 -1
  77. package/dist/test/apps/multiRole.js +1 -3
  78. package/dist/test/apps/pointer.d.ts +2 -2
  79. package/dist/test/apps/pointer.d.ts.map +1 -1
  80. package/dist/test/apps/pointer.js +1 -3
  81. package/dist/test/apps/resumeUpload.d.ts +2 -2
  82. package/dist/test/apps/resumeUpload.d.ts.map +1 -1
  83. package/dist/test/apps/resumeUpload.js +3 -6
  84. package/dist/test/apps/uploads.d.ts +2 -2
  85. package/dist/test/apps/uploads.d.ts.map +1 -1
  86. package/dist/test/apps/uploads.js +1 -3
  87. package/dist/test/scene.d.ts +3 -3
  88. package/dist/test/scene.d.ts.map +1 -1
  89. package/dist/test/scene.js +2 -2
  90. package/package.json +6 -6
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,15 +35,13 @@ 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
56
42
  import { Match as M, Schema as S } from 'effect'
57
43
  import { Command, Runtime } from 'foldkit'
58
- import { Document, html } from 'foldkit/html'
44
+ import { Document, HtmlBuilder } from 'foldkit/html'
59
45
  import { m } from 'foldkit/message'
60
46
 
61
47
  // MODEL
@@ -102,47 +88,18 @@ export const init: Runtime.ApplicationInit<Model, Message> = () => [
102
88
 
103
89
  // VIEW
104
90
 
105
- export const view = (model: Model): Document => {
106
- const h = html<Message>()
107
-
108
- return {
109
- title: `Counter: ${model.count}`,
110
- body: h.div(
111
- [
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
- ),
138
- ],
139
- ),
140
- }
141
- }
142
-
143
- // STYLE
144
-
145
- const buttonStyle = 'bg-black text-white hover:bg-gray-700 px-4 py-2 transition'
91
+ export const view = (model: Model, h: HtmlBuilder<Message>): Document => ({
92
+ title: `Counter: ${model.count}`,
93
+ body: h.div(
94
+ [],
95
+ [
96
+ h.p([], [model.count.toString()]),
97
+ h.button([h.OnClick(ClickedDecrement())], ['-']),
98
+ h.button([h.OnClick(ClickedReset())], ['Reset']),
99
+ h.button([h.OnClick(ClickedIncrement())], ['+']),
100
+ ],
101
+ ),
102
+ })
146
103
  ```
147
104
 
148
105
  ```ts
@@ -162,62 +119,56 @@ const application = Runtime.makeApplication({
162
119
  Runtime.run(application)
163
120
  ```
164
121
 
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)
122
+ Source: [examples/counter](https://github.com/foldkit/foldkit/blob/main/examples/counter/src/main.ts).
166
123
 
167
124
  ## What Ships With Foldkit
168
125
 
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.
126
+ A complete system, not a collection of libraries you stitch together. Each of these is documented in depth at [foldkit.dev](https://foldkit.dev).
127
+
128
+ - **Commands**: Side effects as named Effects that return Messages and are run by the runtime.
129
+ - **Routing**: Type-safe bidirectional routing from parser combinators. URLs parse to Routes, Routes build URLs.
130
+ - **Subscriptions**: External event streams declared as a function of the Model.
131
+ - **Managed Resources**: Model-driven lifecycle for WebSockets, AudioContext, and other long-lived handles.
132
+ - **Mount**: The seam where view code hands a real DOM element to a third-party library that owns its own DOM.
133
+ - **Submodels**: A self-contained Model, update, and view that a parent embeds, wrapping child Messages in a `Got*` envelope.
134
+ - **OutMessage**: A typed channel for a child Submodel to emit domain events up to its parent.
135
+ - **Embedding**: Run a Foldkit program inside a host app through Schema-typed Ports with `Runtime.embed`.
136
+ - **UI Components**: Accessible, keyboard-friendly primitives in the `@foldkit/ui` package.
137
+ - **Field Validation**: Per-field validation state modeled as a discriminated union.
138
+ - **Virtual DOM**: Declarative views with lazy memoization and keyed diffing, powered by [Snabbdom](https://github.com/snabbdom/snabbdom).
139
+ - **DevTools**: In-browser overlay for inspecting Messages, Model, and Commands, with time-travel.
140
+ - **DevTools MCP**: Expose a running app to AI agents over the Model Context Protocol.
141
+ - **Crash View and Reporting**: A custom fallback UI when the update loop throws, plus a report callback.
142
+ - **Story Testing**: Exercise the update function directly, resolving Commands inline. No mocks, no fake timers.
143
+ - **Scene Testing**: Drive your real view the way a user does, with accessible locators. No browser required.
144
+ - **Slow Warnings**: Development warnings when update, view, patch, or Subscription extraction exceeds its budget.
188
145
  - **HMR**: Vite plugin with state-preserving hot module replacement. Change your view, keep your state.
189
146
 
190
147
  ## Correctness You (And Your LLM) Can See
191
148
 
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.
149
+ 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
150
 
196
151
  ## Examples
197
152
 
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))
153
+ Some of what you can build with Foldkit. [See all example apps on foldkit.dev](https://foldkit.dev/example-apps).
154
+
155
+ - **[Counter](https://foldkit.dev/example-apps/counter)**: Increment/decrement with reset
156
+ - **[Todo](https://foldkit.dev/example-apps/todo)**: CRUD operations with localStorage persistence
157
+ - **[Form](https://foldkit.dev/example-apps/form)**: Form validation with async email checking
158
+ - **[Job Application](https://foldkit.dev/example-apps/job-application)**: Multi-step form with cross-field validation, file uploads, and per-step error indicators
159
+ - **[Weather](https://foldkit.dev/example-apps/weather)**: HTTP requests with async state handling
160
+ - **[API Cache](https://foldkit.dev/example-apps/api-cache)**: Query caching with stale-while-revalidate, request deduplication, and interval refetching
161
+ - **[Routing](https://foldkit.dev/example-apps/routing)**: URL routing with parser combinators
162
+ - **[Route Transitions](https://foldkit.dev/example-apps/route-transitions)**: Live transition log with entry, exit, and stayed navigation policies
163
+ - **[Query Sync](https://foldkit.dev/example-apps/query-sync)**: URL query parameter sync with filtering and sorting
164
+ - **[Snake](https://foldkit.dev/example-apps/snake)**: Classic game built with Subscriptions
165
+ - **[Auth](https://foldkit.dev/example-apps/auth)**: Authentication flow with Submodels and OutMessage
166
+ - **[Shopping Cart](https://foldkit.dev/example-apps/shopping-cart)**: Nested models and complex state
167
+ - **[WebSocket Chat](https://foldkit.dev/example-apps/websocket-chat)**: Managed Resources with WebSocket integration
168
+ - **[Kanban](https://foldkit.dev/example-apps/kanban)**: Drag-and-drop kanban board with cross-column reordering and keyboard navigation
169
+ - **[Pixel Art](https://foldkit.dev/example-apps/pixel-art)**: Grid-based pixel editor with painting, erasing, and palette selection
170
+ - **[UI Showcase](https://foldkit.dev/example-apps/ui-showcase)**: Interactive showcase of every Foldkit UI component
171
+ - **[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
172
 
222
173
  ## License
223
174
 
@@ -1,4 +1,4 @@
1
- import { type Html } from '../html/index.js';
1
+ import { type Html, type HtmlBuilder } from '../html/index.js';
2
2
  import type { Point, Shape } from './shape.js';
3
3
  /**
4
4
  * Configuration for `Canvas.view`. Pointer handlers are optional and
@@ -21,18 +21,25 @@ export type ViewConfig<Message> = Readonly<{
21
21
  * postpatch hook re-paints on every render. The canvas is a pure function of
22
22
  * `shapes`. Same shapes produce the same pixels.
23
23
  *
24
+ * The trailing `h` fixes `Message` to the calling view's frame; the pointer
25
+ * handlers dispatch through that frame at fire time, so passing the builder
26
+ * that built the surrounding view is what makes the handler types truthful.
27
+ *
24
28
  * @example
25
29
  * ```typescript
26
- * Canvas.view<Message>({
27
- * width: 400,
28
- * height: 300,
29
- * shapes: [
30
- * Canvas.Rect({ x: 0, y: 0, width: 400, height: 300, fill: '#000' }),
31
- * Canvas.Circle({ x: 200, y: 150, radius: 50, fill: '#f0a' }),
32
- * ],
33
- * onPointerDown: ({ x, y }) => ClickedCanvas({ x, y }),
34
- * })
30
+ * Canvas.view(
31
+ * {
32
+ * width: 400,
33
+ * height: 300,
34
+ * shapes: [
35
+ * Canvas.Rect({ x: 0, y: 0, width: 400, height: 300, fill: '#000' }),
36
+ * Canvas.Circle({ x: 200, y: 150, radius: 50, fill: '#f0a' }),
37
+ * ],
38
+ * onPointerDown: ({ x, y }) => ClickedCanvas({ x, y }),
39
+ * },
40
+ * h,
41
+ * )
35
42
  * ```
36
43
  */
37
- export declare const view: <Message>(config: ViewConfig<Message>) => Html;
44
+ export declare const view: <Message>(config: ViewConfig<NoInfer<Message>>, _h: HtmlBuilder<Message>) => Html;
38
45
  //# sourceMappingURL=view.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/canvas/view.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,IAAI,EAAqB,MAAM,kBAAkB,CAAA;AAI/D,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;IACvD,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;IACvD,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;CACtD,CAAC,CAAA;AA8BF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IAwE3D,CAAA"}
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/canvas/view.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,IAAI,EACT,KAAK,WAAW,EAEjB,MAAM,kBAAkB,CAAA;AAIzB,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;IACvD,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;IACvD,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;CACtD,CAAC,CAAA;AA8BF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,IAAI,GAAI,OAAO,EAC1B,QAAQ,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EACpC,IAAI,WAAW,CAAC,OAAO,CAAC,KACvB,IAwEF,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { Array, Predicate, Record, String, pipe } from 'effect';
2
- import { __requireDispatch } from '../html/index.js';
2
+ import { __requireDispatch, } from '../html/index.js';
3
3
  import { h } from '../snabbdom/index.js';
4
4
  import { paintScene } from './paint.js';
5
5
  /**
@@ -24,20 +24,27 @@ const classesFromClassName = (className) => pipe(className, String.split(/\s+/),
24
24
  * postpatch hook re-paints on every render. The canvas is a pure function of
25
25
  * `shapes`. Same shapes produce the same pixels.
26
26
  *
27
+ * The trailing `h` fixes `Message` to the calling view's frame; the pointer
28
+ * handlers dispatch through that frame at fire time, so passing the builder
29
+ * that built the surrounding view is what makes the handler types truthful.
30
+ *
27
31
  * @example
28
32
  * ```typescript
29
- * Canvas.view<Message>({
30
- * width: 400,
31
- * height: 300,
32
- * shapes: [
33
- * Canvas.Rect({ x: 0, y: 0, width: 400, height: 300, fill: '#000' }),
34
- * Canvas.Circle({ x: 200, y: 150, radius: 50, fill: '#f0a' }),
35
- * ],
36
- * onPointerDown: ({ x, y }) => ClickedCanvas({ x, y }),
37
- * })
33
+ * Canvas.view(
34
+ * {
35
+ * width: 400,
36
+ * height: 300,
37
+ * shapes: [
38
+ * Canvas.Rect({ x: 0, y: 0, width: 400, height: 300, fill: '#000' }),
39
+ * Canvas.Circle({ x: 200, y: 150, radius: 50, fill: '#f0a' }),
40
+ * ],
41
+ * onPointerDown: ({ x, y }) => ClickedCanvas({ x, y }),
42
+ * },
43
+ * h,
44
+ * )
38
45
  * ```
39
46
  */
40
- export const view = (config) => {
47
+ export const view = (config, _h) => {
41
48
  const dispatchSync = __requireDispatch();
42
49
  const { width, height, shapes, className, onPointerDown, onPointerMove, onPointerUp, } = config;
43
50
  const pointerListener = (toMessage) => (event) => {
@@ -1,5 +1,5 @@
1
1
  import { type Schema } from 'effect';
2
- import type { Attribute, Child, Html } from '../html/index.js';
2
+ import type { Attribute, Child, Html, HtmlBuilder } from '../html/index.js';
3
3
  /** Type-level kebab-case to PascalCase, used to convert event names like
4
4
  * `'change-rating'` into the corresponding factory name `'OnChangeRating'`. */
5
5
  type KebabToPascal<S extends string> = S extends `${infer Head}-${infer Tail}` ? `${Capitalize<Head>}${KebabToPascal<Tail>}` : Capitalize<S>;
@@ -24,14 +24,16 @@ export interface CustomElementConfig<Tag extends string, Properties extends Reco
24
24
  readonly events: Events;
25
25
  }
26
26
  /** A defined custom element, untyped on Message at definition time so the
27
- * spec can be exported and shared across modules. Call `.withMessage<Message>()`
28
- * inside a view module to mint a typed `ElementBuilder` bound to the
29
- * consumer's Message universe. */
27
+ * spec can be exported and shared across modules. Call `.withMessage(h)`
28
+ * with a view's builder to mint a typed `ElementBuilder` bound to that
29
+ * frame's Message universe. The builder argument is a type witness: it
30
+ * fixes `Message` to the frame the element renders in, so the spec cannot
31
+ * be bound to a Message universe its events will not dispatch into. */
30
32
  export interface CustomElementSpec<Tag extends string, Properties extends Record<string, Schema.Top>, Events extends Record<string, Schema.Top>> {
31
33
  readonly tag: Tag;
32
34
  readonly properties: Properties;
33
35
  readonly events: Events;
34
- readonly withMessage: <Message>() => ElementBuilder<Message, Properties, Events>;
36
+ readonly withMessage: <Message>(h: HtmlBuilder<Message>) => ElementBuilder<Message, Properties, Events>;
35
37
  }
36
38
  /** The typed builder for a given spec and Message universe. Equivalent to
37
39
  * the value `Spec.withMessage<Message>()` returns, expressed as a type
@@ -62,7 +64,8 @@ export type Builder<Spec, Message> = Spec extends CustomElementSpec<string, infe
62
64
  * },
63
65
  * })
64
66
  *
65
- * const picker = hexColorPicker.withMessage<Message>()
67
+ * // Inside a view, with its `h` in scope:
68
+ * const picker = hexColorPicker.withMessage(h)
66
69
  *
67
70
  * picker(
68
71
  * [
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/customElement/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/customElement/index.ts"],"names":[],"mappings":"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"}
@@ -38,7 +38,8 @@ const eventFactoryName = (eventName) => `On${kebabToPascal(eventName)}`;
38
38
  * },
39
39
  * })
40
40
  *
41
- * const picker = hexColorPicker.withMessage<Message>()
41
+ * // Inside a view, with its `h` in scope:
42
+ * const picker = hexColorPicker.withMessage(h)
42
43
  *
43
44
  * picker(
44
45
  * [
@@ -53,7 +54,7 @@ export const define = (config) => {
53
54
  const propertyNames = Object.keys(config.properties);
54
55
  const eventNames = Object.keys(config.events);
55
56
  validateNames({ tag: config.tag, propertyNames, eventNames });
56
- const buildForMessage = () => {
57
+ const buildElementBuilder = () => {
57
58
  const createVNode = customElementVNode()(config.tag);
58
59
  const elementFn = (attributes = [], children = []) => createVNode(attributes, children);
59
60
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
@@ -70,11 +71,21 @@ export const define = (config) => {
70
71
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
71
72
  return builder;
72
73
  };
74
+ // NOTE: `withMessage` is called once per render, so the ElementBuilder is
75
+ // constructed once and retyped per call. Message is erased at runtime: the
76
+ // factories close over nothing Message-specific, exactly like the html
77
+ // builder singleton.
78
+ let cachedElementBuilder;
79
+ const withMessage = (_h) => {
80
+ cachedElementBuilder ??= buildElementBuilder();
81
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
82
+ return cachedElementBuilder;
83
+ };
73
84
  return {
74
85
  tag: config.tag,
75
86
  properties: config.properties,
76
87
  events: config.events,
77
- withMessage: buildForMessage,
88
+ withMessage,
78
89
  };
79
90
  };
80
91
  const validateNames = (input) => {
@@ -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":"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"}
@@ -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';