foldkit 0.75.1 → 0.76.1

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
@@ -149,7 +149,8 @@ Foldkit is a complete system, not a collection of libraries you stitch together.
149
149
  - **UI Components**: Accessible, keyboard-friendly primitives covering Button, Checkbox, Combobox, Dialog, Disclosure, DragAndDrop, Fieldset, Input, Listbox, Menu, Popover, RadioGroup, Select, Switch, Tabs, Textarea, and Transition. Every component is a Submodel with a typed `ViewConfig`, domain-event callbacks like `onSelected`, `onClosed`, and `onToggled`, and `className` plus `attributes` props on every slot for styling and extension. Animated components share a `Transition` Submodel that coordinates CSS enter and leave animations.
150
150
  - **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.
151
151
  - **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.
152
- - **DevTools**: Built-in overlay for inspecting Messages, Model state, and Commands. Time-travel mode lets you jump to any point in history, Inspect mode browses snapshots without pausing, and Submodel drill-in filtering scopes the Message list to any nested module.
152
+ - **DevTools**: Built-in overlay 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.
153
+ - **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. The runtime's own Message Schema is published as JSON Schema so the agent discovers exactly what it can dispatch, and every payload is validated against the Schema before it reaches your update function. One command sets it up: `npx @foldkit/devtools-mcp init`.
153
154
  - **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.
154
155
  - **Story Testing**: Exercise the update function directly. Send Messages, resolve Commands inline with `resolve` and `resolveAll`, and assert with focused helpers: `Story.model`, `Story.expectHasCommands`, `Story.expectExactCommands`, `Story.expectNoCommands`, and `Story.expectOutMessage`. No mocking libraries, no fake timers.
155
156
  - **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.
@@ -1 +1 @@
1
- {"version":3,"file":"overlay-styles.d.ts","sourceRoot":"","sources":["../../src/devtools/overlay-styles.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,aAAa,q3UAimBlB,CAAA;AAED,OAAO,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"overlay-styles.d.ts","sourceRoot":"","sources":["../../src/devTools/overlay-styles.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,aAAa,q3UAimBlB,CAAA;AAED,OAAO,EAAE,aAAa,EAAE,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import { Effect, HashSet, Option } from 'effect';
2
2
  import * as Command from '../command/index.js';
3
- import type { DevtoolsMode, DevtoolsPosition } from '../runtime/runtime.js';
4
- import { type DevtoolsStore } from './store.js';
3
+ import type { DevToolsMode, DevToolsPosition } from '../runtime/runtime.js';
4
+ import { type DevToolsStore } from './store.js';
5
5
  export declare const JumpTo: Command.CommandDefinition<"JumpTo", {
6
6
  readonly _tag: "CompletedJump";
7
7
  }>;
@@ -34,5 +34,5 @@ export declare const UnlockScroll: Command.CommandDefinition<"UnlockScroll", {
34
34
  export declare const ScrollToTop: Command.CommandDefinition<"ScrollToTop", {
35
35
  readonly _tag: "ScrolledToTop";
36
36
  }>;
37
- export declare const createOverlay: (store: DevtoolsStore, position: DevtoolsPosition, mode: DevtoolsMode, maybeBanner: Option.Option<string>) => Effect.Effect<void, never, never>;
37
+ export declare const createOverlay: (store: DevToolsStore, position: DevToolsPosition, mode: DevToolsMode, maybeBanner: Option.Option<string>) => Effect.Effect<void, never, never>;
38
38
  //# sourceMappingURL=overlay.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devtools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,MAAM,EAGN,OAAO,EAGP,MAAM,EASP,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAK9C,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAO3E,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,YAAY,CAAA;AAgQnB,eAAO,MAAM,MAAM;;EAA0C,CAAA;AAC7D,eAAO,MAAM,YAAY;;;;;;EAGxB,CAAA;AACD,eAAO,MAAM,aAAa;;;;;;EAGzB,CAAA;AACD,eAAO,MAAM,MAAM;;EAA4C,CAAA;AAC/D,eAAO,MAAM,KAAK;;EAA0C,CAAA;AAC5D,eAAO,MAAM,UAAU;;EAA6C,CAAA;AACpE,eAAO,MAAM,YAAY;;EAAiD,CAAA;AAC1E,eAAO,MAAM,WAAW;;EAA+C,CAAA;AAmzCvE,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sCAkDhC,CAAA"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devTools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,MAAM,EAGN,OAAO,EAGP,MAAM,EASP,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAK9C,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAQ3E,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,YAAY,CAAA;AAuOnB,eAAO,MAAM,MAAM;;EAA0C,CAAA;AAC7D,eAAO,MAAM,YAAY;;;;;;EAGxB,CAAA;AACD,eAAO,MAAM,aAAa;;;;;;EAGzB,CAAA;AACD,eAAO,MAAM,MAAM;;EAA4C,CAAA;AAC/D,eAAO,MAAM,KAAK;;EAA0C,CAAA;AAC5D,eAAO,MAAM,UAAU;;EAA6C,CAAA;AACpE,eAAO,MAAM,YAAY;;EAAiD,CAAA;AAC1E,eAAO,MAAM,WAAW;;EAA+C,CAAA;AAgzCvE,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sCAkDhC,CAAA"}
@@ -11,6 +11,7 @@ import { lockScroll, unlockScroll } from '../task/scrollLock.js';
11
11
  import * as Listbox from '../ui/listbox/public.js';
12
12
  import * as Tabs from '../ui/tabs/public.js';
13
13
  import { overlayStyles } from './overlay-styles.js';
14
+ import { toInspectableValue } from './serialize.js';
14
15
  import { INIT_INDEX, } from './store.js';
15
16
  // MODEL
16
17
  const DisplayEntry = S.Struct({
@@ -143,21 +144,6 @@ const toDisplayState = (state) => ({
143
144
  pausedAtIndex: state.pausedAtIndex,
144
145
  });
145
146
  const isExpandable = (value) => Predicate.isObject(value);
146
- /** Convert DOM-class instances (File, Blob, Date, URL) to plain-object
147
- * representations so the tree renderer's key-enumeration walk can see their
148
- * meaningful data, which otherwise lives on the prototype as getters and
149
- * is invisible to `Object.keys`. Recurses through arrays and records so
150
- * the transform applies at every level. File is matched before Blob
151
- * because File extends Blob. */
152
- const toInspectableValue = (value) => M.value(value).pipe(M.when(M.instanceOf(File), file => ({
153
- name: file.name,
154
- size: file.size,
155
- type: file.type,
156
- lastModified: file.lastModified,
157
- })), M.when(M.instanceOf(Blob), blob => ({
158
- size: blob.size,
159
- type: blob.type,
160
- })), M.when(M.instanceOf(Date), date => date.toISOString()), M.when(M.instanceOf(URL), ({ href }) => href), M.when(Array.isArray, Array_.map(toInspectableValue)), M.when(Predicate.isReadonlyRecord, Record.map(toInspectableValue)), M.orElse(Function.identity));
161
147
  const Tagged = S.Struct({ _tag: S.String });
162
148
  const isTagged = S.is(Tagged);
163
149
  const objectPreview = (value) => pipe(value, Record.keys, Array_.filter(key => key !== '_tag'), Array_.match({
@@ -353,8 +339,8 @@ const SubscriptionDeps = S.Struct({
353
339
  });
354
340
  const makeOverlaySubscriptions = (store) => makeSubscriptions(SubscriptionDeps)({
355
341
  storeUpdates: {
356
- modelToDependencies: ({ isOpen }) => isOpen,
357
- dependenciesToStream: isOpen => Stream.when(Stream.concat(Stream.fromEffect(SubscriptionRef.get(store.stateRef).pipe(Effect.map(state => ReceivedStoreUpdate(toDisplayState(state))))), Stream.map(store.stateRef.changes, state => ReceivedStoreUpdate(toDisplayState(state)))), () => isOpen),
342
+ modelToDependencies: () => true,
343
+ dependenciesToStream: () => Stream.concat(Stream.fromEffect(SubscriptionRef.get(store.stateRef).pipe(Effect.map(state => ReceivedStoreUpdate(toDisplayState(state))))), Stream.map(store.stateRef.changes, state => ReceivedStoreUpdate(toDisplayState(state)))),
358
344
  },
359
345
  mobileBreakpoint: {
360
346
  modelToDependencies: () => null,
@@ -894,7 +880,7 @@ export const createOverlay = (store, position, mode, maybeBanner) => Effect.gen(
894
880
  view: makeView(position, mode, maybeBanner),
895
881
  container,
896
882
  subscriptions: makeOverlaySubscriptions(store),
897
- devtools: false,
883
+ devTools: false,
898
884
  });
899
885
  yield* Effect.forkDaemon(overlayRuntime());
900
886
  });
@@ -0,0 +1,288 @@
1
+ import { Schema as S } from 'effect';
2
+ /** A serialized history entry as it appears on the wire. */
3
+ export declare const SerializedEntry: S.Struct<{
4
+ index: typeof S.Number;
5
+ tag: typeof S.String;
6
+ message: typeof S.Unknown;
7
+ commandNames: S.Array$<typeof S.String>;
8
+ timestamp: typeof S.Number;
9
+ isModelChanged: typeof S.Boolean;
10
+ changedPaths: S.Array$<typeof S.String>;
11
+ affectedPaths: S.Array$<typeof S.String>;
12
+ }>;
13
+ /** A serialized history entry suitable for transmission over the WS protocol. */
14
+ export type SerializedEntry = typeof SerializedEntry.Type;
15
+ /** Metadata about a single keyframe. The index identifies the point in history where the runtime can replay back to. */
16
+ export declare const KeyframeInfo: S.Struct<{
17
+ index: typeof S.Number;
18
+ }>;
19
+ /** Metadata about a single keyframe. */
20
+ export type KeyframeInfo = typeof KeyframeInfo.Type;
21
+ /** Metadata about a connected browser runtime. The `maybeMessageSchema` carries the runtime's app-level Message Schema as JSON Schema for `dispatch_message` validation, when the runtime exposes one via `DevToolsConfig.Message`. */
22
+ export declare const RuntimeInfo: S.Struct<{
23
+ connectionId: typeof S.String;
24
+ url: typeof S.String;
25
+ title: typeof S.String;
26
+ maybeMessageSchema: S.Option<typeof S.Unknown>;
27
+ }>;
28
+ /** Metadata about a connected browser runtime. */
29
+ export type RuntimeInfo = typeof RuntimeInfo.Type;
30
+ /** Request the current Model snapshot. */
31
+ export declare const RequestGetModel: import("../schema/index.js").CallableTaggedStruct<"RequestGetModel", {}>;
32
+ /** Request recent history entries, optionally starting from a given index. */
33
+ export declare const RequestListMessages: import("../schema/index.js").CallableTaggedStruct<"RequestListMessages", {
34
+ limit: typeof S.Number;
35
+ maybeSinceIndex: S.Option<typeof S.Number>;
36
+ }>;
37
+ /** Request a single history entry by index, including before/after Model snapshots. */
38
+ export declare const RequestGetMessage: import("../schema/index.js").CallableTaggedStruct<"RequestGetMessage", {
39
+ index: typeof S.Number;
40
+ }>;
41
+ /** Request the list of available keyframes. */
42
+ export declare const RequestListKeyframes: import("../schema/index.js").CallableTaggedStruct<"RequestListKeyframes", {}>;
43
+ /** Request the runtime jump to a specific keyframe. The runtime is paused on success; resume via RequestResume. */
44
+ export declare const RequestReplayToKeyframe: import("../schema/index.js").CallableTaggedStruct<"RequestReplayToKeyframe", {
45
+ keyframeIndex: typeof S.Number;
46
+ }>;
47
+ /** Request the runtime resume normal execution from a paused state. */
48
+ export declare const RequestResume: import("../schema/index.js").CallableTaggedStruct<"RequestResume", {}>;
49
+ /** Request the runtime dispatch a Message at the current state. The payload is opaque to the protocol; the runtime validates against the app's Message Schema. */
50
+ export declare const RequestDispatchMessage: import("../schema/index.js").CallableTaggedStruct<"RequestDispatchMessage", {
51
+ message: typeof S.Unknown;
52
+ }>;
53
+ /** Request the list of currently connected browser runtimes. Handled by the Vite plugin, not forwarded to a runtime. */
54
+ export declare const RequestListRuntimes: import("../schema/index.js").CallableTaggedStruct<"RequestListRuntimes", {}>;
55
+ /** A request from the MCP server. RequestListRuntimes is handled at the Vite plugin layer; all other requests are routed to a browser runtime. */
56
+ export declare const Request: S.Union<[import("../schema/index.js").CallableTaggedStruct<"RequestGetModel", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestListMessages", {
57
+ limit: typeof S.Number;
58
+ maybeSinceIndex: S.Option<typeof S.Number>;
59
+ }>, import("../schema/index.js").CallableTaggedStruct<"RequestGetMessage", {
60
+ index: typeof S.Number;
61
+ }>, import("../schema/index.js").CallableTaggedStruct<"RequestListKeyframes", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestReplayToKeyframe", {
62
+ keyframeIndex: typeof S.Number;
63
+ }>, import("../schema/index.js").CallableTaggedStruct<"RequestResume", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestDispatchMessage", {
64
+ message: typeof S.Unknown;
65
+ }>, import("../schema/index.js").CallableTaggedStruct<"RequestListRuntimes", {}>]>;
66
+ /** A request from the MCP server. */
67
+ export type Request = typeof Request.Type;
68
+ /** Response carrying the current Model snapshot. */
69
+ export declare const ResponseModel: import("../schema/index.js").CallableTaggedStruct<"ResponseModel", {
70
+ model: typeof S.Unknown;
71
+ }>;
72
+ /** Response carrying a page of history entries. `maybeNextIndex` is `Some` when more entries are available beyond this page (pass it as `RequestListMessages.maybeSinceIndex` to fetch the next page) and `None` when this page reaches the current end of history. */
73
+ export declare const ResponseMessages: import("../schema/index.js").CallableTaggedStruct<"ResponseMessages", {
74
+ entries: S.Array$<S.Struct<{
75
+ index: typeof S.Number;
76
+ tag: typeof S.String;
77
+ message: typeof S.Unknown;
78
+ commandNames: S.Array$<typeof S.String>;
79
+ timestamp: typeof S.Number;
80
+ isModelChanged: typeof S.Boolean;
81
+ changedPaths: S.Array$<typeof S.String>;
82
+ affectedPaths: S.Array$<typeof S.String>;
83
+ }>>;
84
+ maybeNextIndex: S.Option<typeof S.Number>;
85
+ }>;
86
+ /** Response carrying a single history entry with surrounding Model snapshots. */
87
+ export declare const ResponseMessage: import("../schema/index.js").CallableTaggedStruct<"ResponseMessage", {
88
+ entry: S.Struct<{
89
+ index: typeof S.Number;
90
+ tag: typeof S.String;
91
+ message: typeof S.Unknown;
92
+ commandNames: S.Array$<typeof S.String>;
93
+ timestamp: typeof S.Number;
94
+ isModelChanged: typeof S.Boolean;
95
+ changedPaths: S.Array$<typeof S.String>;
96
+ affectedPaths: S.Array$<typeof S.String>;
97
+ }>;
98
+ modelBefore: typeof S.Unknown;
99
+ modelAfter: typeof S.Unknown;
100
+ }>;
101
+ /** Response carrying the list of available keyframes. */
102
+ export declare const ResponseKeyframes: import("../schema/index.js").CallableTaggedStruct<"ResponseKeyframes", {
103
+ keyframes: S.Array$<S.Struct<{
104
+ index: typeof S.Number;
105
+ }>>;
106
+ }>;
107
+ /** Response confirming a successful replay. The runtime is paused at this Model. */
108
+ export declare const ResponseReplayed: import("../schema/index.js").CallableTaggedStruct<"ResponseReplayed", {
109
+ model: typeof S.Unknown;
110
+ }>;
111
+ /** Response confirming the runtime resumed normal execution. */
112
+ export declare const ResponseResumed: import("../schema/index.js").CallableTaggedStruct<"ResponseResumed", {}>;
113
+ /** 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 Message reaches the runtime's update loop asynchronously, so concurrent Messages produced by the runtime itself could in principle shift ordering; in practice the bridge is the only external dispatch source and the runtime queue serializes Messages, so this index is reliable for correlation. */
114
+ export declare const ResponseDispatched: import("../schema/index.js").CallableTaggedStruct<"ResponseDispatched", {
115
+ acceptedAtIndex: typeof S.Number;
116
+ }>;
117
+ /** Response carrying the list of connected runtimes. */
118
+ export declare const ResponseRuntimes: import("../schema/index.js").CallableTaggedStruct<"ResponseRuntimes", {
119
+ runtimes: S.Array$<S.Struct<{
120
+ connectionId: typeof S.String;
121
+ url: typeof S.String;
122
+ title: typeof S.String;
123
+ maybeMessageSchema: S.Option<typeof S.Unknown>;
124
+ }>>;
125
+ }>;
126
+ /** Response carrying an error reason for a failed Request. */
127
+ export declare const ResponseError: import("../schema/index.js").CallableTaggedStruct<"ResponseError", {
128
+ reason: typeof S.String;
129
+ }>;
130
+ /** A response replying to a Request. */
131
+ export declare const Response: S.Union<[import("../schema/index.js").CallableTaggedStruct<"ResponseModel", {
132
+ model: typeof S.Unknown;
133
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseMessages", {
134
+ entries: S.Array$<S.Struct<{
135
+ index: typeof S.Number;
136
+ tag: typeof S.String;
137
+ message: typeof S.Unknown;
138
+ commandNames: S.Array$<typeof S.String>;
139
+ timestamp: typeof S.Number;
140
+ isModelChanged: typeof S.Boolean;
141
+ changedPaths: S.Array$<typeof S.String>;
142
+ affectedPaths: S.Array$<typeof S.String>;
143
+ }>>;
144
+ maybeNextIndex: S.Option<typeof S.Number>;
145
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseMessage", {
146
+ entry: S.Struct<{
147
+ index: typeof S.Number;
148
+ tag: typeof S.String;
149
+ message: typeof S.Unknown;
150
+ commandNames: S.Array$<typeof S.String>;
151
+ timestamp: typeof S.Number;
152
+ isModelChanged: typeof S.Boolean;
153
+ changedPaths: S.Array$<typeof S.String>;
154
+ affectedPaths: S.Array$<typeof S.String>;
155
+ }>;
156
+ modelBefore: typeof S.Unknown;
157
+ modelAfter: typeof S.Unknown;
158
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseKeyframes", {
159
+ keyframes: S.Array$<S.Struct<{
160
+ index: typeof S.Number;
161
+ }>>;
162
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseReplayed", {
163
+ model: typeof S.Unknown;
164
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseResumed", {}>, import("../schema/index.js").CallableTaggedStruct<"ResponseDispatched", {
165
+ acceptedAtIndex: typeof S.Number;
166
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseRuntimes", {
167
+ runtimes: S.Array$<S.Struct<{
168
+ connectionId: typeof S.String;
169
+ url: typeof S.String;
170
+ title: typeof S.String;
171
+ maybeMessageSchema: S.Option<typeof S.Unknown>;
172
+ }>>;
173
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseError", {
174
+ reason: typeof S.String;
175
+ }>]>;
176
+ /** A response replying to a Request. */
177
+ export type Response = typeof Response.Type;
178
+ /** A new browser runtime connected. The `runtime.maybeMessageSchema` field carries the runtime's Message Schema (as JSON Schema) when the runtime exposes one via `DevToolsConfig.Message`. */
179
+ export declare const EventConnected: import("../schema/index.js").CallableTaggedStruct<"EventConnected", {
180
+ runtime: S.Struct<{
181
+ connectionId: typeof S.String;
182
+ url: typeof S.String;
183
+ title: typeof S.String;
184
+ maybeMessageSchema: S.Option<typeof S.Unknown>;
185
+ }>;
186
+ }>;
187
+ /** A previously connected runtime disconnected. */
188
+ export declare const EventDisconnected: import("../schema/index.js").CallableTaggedStruct<"EventDisconnected", {
189
+ connectionId: typeof S.String;
190
+ }>;
191
+ /** A runtime lifecycle event used by the Vite plugin to track which browser tabs are connected. Not forwarded to MCP clients. */
192
+ export declare const Event: S.Union<[import("../schema/index.js").CallableTaggedStruct<"EventConnected", {
193
+ runtime: S.Struct<{
194
+ connectionId: typeof S.String;
195
+ url: typeof S.String;
196
+ title: typeof S.String;
197
+ maybeMessageSchema: S.Option<typeof S.Unknown>;
198
+ }>;
199
+ }>, import("../schema/index.js").CallableTaggedStruct<"EventDisconnected", {
200
+ connectionId: typeof S.String;
201
+ }>]>;
202
+ /** A runtime lifecycle event. */
203
+ export type Event = typeof Event.Type;
204
+ /** A wire frame carrying a Request from the MCP server. The id is opaque, used only by the MCP server to correlate the matching Response. The maybeConnectionId routes the request to a specific runtime when present. */
205
+ export declare const RequestFrame: S.Struct<{
206
+ id: typeof S.String;
207
+ maybeConnectionId: S.Option<typeof S.String>;
208
+ request: S.Union<[import("../schema/index.js").CallableTaggedStruct<"RequestGetModel", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestListMessages", {
209
+ limit: typeof S.Number;
210
+ maybeSinceIndex: S.Option<typeof S.Number>;
211
+ }>, import("../schema/index.js").CallableTaggedStruct<"RequestGetMessage", {
212
+ index: typeof S.Number;
213
+ }>, import("../schema/index.js").CallableTaggedStruct<"RequestListKeyframes", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestReplayToKeyframe", {
214
+ keyframeIndex: typeof S.Number;
215
+ }>, import("../schema/index.js").CallableTaggedStruct<"RequestResume", {}>, import("../schema/index.js").CallableTaggedStruct<"RequestDispatchMessage", {
216
+ message: typeof S.Unknown;
217
+ }>, import("../schema/index.js").CallableTaggedStruct<"RequestListRuntimes", {}>]>;
218
+ }>;
219
+ /** A wire frame carrying a Request from the MCP server. */
220
+ export type RequestFrame = typeof RequestFrame.Type;
221
+ /** A wire frame carrying a Response, correlated to a Request by id. */
222
+ export declare const ResponseFrame: S.Struct<{
223
+ id: typeof S.String;
224
+ response: S.Union<[import("../schema/index.js").CallableTaggedStruct<"ResponseModel", {
225
+ model: typeof S.Unknown;
226
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseMessages", {
227
+ entries: S.Array$<S.Struct<{
228
+ index: typeof S.Number;
229
+ tag: typeof S.String;
230
+ message: typeof S.Unknown;
231
+ commandNames: S.Array$<typeof S.String>;
232
+ timestamp: typeof S.Number;
233
+ isModelChanged: typeof S.Boolean;
234
+ changedPaths: S.Array$<typeof S.String>;
235
+ affectedPaths: S.Array$<typeof S.String>;
236
+ }>>;
237
+ maybeNextIndex: S.Option<typeof S.Number>;
238
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseMessage", {
239
+ entry: S.Struct<{
240
+ index: typeof S.Number;
241
+ tag: typeof S.String;
242
+ message: typeof S.Unknown;
243
+ commandNames: S.Array$<typeof S.String>;
244
+ timestamp: typeof S.Number;
245
+ isModelChanged: typeof S.Boolean;
246
+ changedPaths: S.Array$<typeof S.String>;
247
+ affectedPaths: S.Array$<typeof S.String>;
248
+ }>;
249
+ modelBefore: typeof S.Unknown;
250
+ modelAfter: typeof S.Unknown;
251
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseKeyframes", {
252
+ keyframes: S.Array$<S.Struct<{
253
+ index: typeof S.Number;
254
+ }>>;
255
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseReplayed", {
256
+ model: typeof S.Unknown;
257
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseResumed", {}>, import("../schema/index.js").CallableTaggedStruct<"ResponseDispatched", {
258
+ acceptedAtIndex: typeof S.Number;
259
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseRuntimes", {
260
+ runtimes: S.Array$<S.Struct<{
261
+ connectionId: typeof S.String;
262
+ url: typeof S.String;
263
+ title: typeof S.String;
264
+ maybeMessageSchema: S.Option<typeof S.Unknown>;
265
+ }>>;
266
+ }>, import("../schema/index.js").CallableTaggedStruct<"ResponseError", {
267
+ reason: typeof S.String;
268
+ }>]>;
269
+ }>;
270
+ /** A wire frame carrying a Response, correlated to a Request by id. */
271
+ export type ResponseFrame = typeof ResponseFrame.Type;
272
+ /** A wire frame carrying a runtime lifecycle event from the bridge to the Vite plugin. */
273
+ export declare const EventFrame: S.Struct<{
274
+ maybeConnectionId: S.Option<typeof S.String>;
275
+ event: S.Union<[import("../schema/index.js").CallableTaggedStruct<"EventConnected", {
276
+ runtime: S.Struct<{
277
+ connectionId: typeof S.String;
278
+ url: typeof S.String;
279
+ title: typeof S.String;
280
+ maybeMessageSchema: S.Option<typeof S.Unknown>;
281
+ }>;
282
+ }>, import("../schema/index.js").CallableTaggedStruct<"EventDisconnected", {
283
+ connectionId: typeof S.String;
284
+ }>]>;
285
+ }>;
286
+ /** A wire frame carrying a runtime lifecycle event. */
287
+ export type EventFrame = typeof EventFrame.Type;
288
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/devTools/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ import { Schema as S } from 'effect';
2
+ import { ts } from '../schema/index.js';
3
+ // SHARED
4
+ /** A serialized history entry as it appears on the wire. */
5
+ export const SerializedEntry = S.Struct({
6
+ index: S.Number,
7
+ tag: S.String,
8
+ message: S.Unknown,
9
+ commandNames: S.Array(S.String),
10
+ timestamp: S.Number,
11
+ isModelChanged: S.Boolean,
12
+ changedPaths: S.Array(S.String),
13
+ affectedPaths: S.Array(S.String),
14
+ });
15
+ /** Metadata about a single keyframe. The index identifies the point in history where the runtime can replay back to. */
16
+ export const KeyframeInfo = S.Struct({
17
+ index: S.Number,
18
+ });
19
+ /** Metadata about a connected browser runtime. The `maybeMessageSchema` carries the runtime's app-level Message Schema as JSON Schema for `dispatch_message` validation, when the runtime exposes one via `DevToolsConfig.Message`. */
20
+ export const RuntimeInfo = S.Struct({
21
+ connectionId: S.String,
22
+ url: S.String,
23
+ title: S.String,
24
+ maybeMessageSchema: S.Option(S.Unknown),
25
+ });
26
+ // REQUEST
27
+ /** Request the current Model snapshot. */
28
+ export const RequestGetModel = ts('RequestGetModel');
29
+ /** Request recent history entries, optionally starting from a given index. */
30
+ export const RequestListMessages = ts('RequestListMessages', {
31
+ limit: S.Number,
32
+ maybeSinceIndex: S.Option(S.Number),
33
+ });
34
+ /** Request a single history entry by index, including before/after Model snapshots. */
35
+ export const RequestGetMessage = ts('RequestGetMessage', {
36
+ index: S.Number,
37
+ });
38
+ /** Request the list of available keyframes. */
39
+ export const RequestListKeyframes = ts('RequestListKeyframes');
40
+ /** Request the runtime jump to a specific keyframe. The runtime is paused on success; resume via RequestResume. */
41
+ export const RequestReplayToKeyframe = ts('RequestReplayToKeyframe', {
42
+ keyframeIndex: S.Number,
43
+ });
44
+ /** Request the runtime resume normal execution from a paused state. */
45
+ export const RequestResume = ts('RequestResume');
46
+ /** Request the runtime dispatch a Message at the current state. The payload is opaque to the protocol; the runtime validates against the app's Message Schema. */
47
+ export const RequestDispatchMessage = ts('RequestDispatchMessage', {
48
+ message: S.Unknown,
49
+ });
50
+ /** Request the list of currently connected browser runtimes. Handled by the Vite plugin, not forwarded to a runtime. */
51
+ export const RequestListRuntimes = ts('RequestListRuntimes');
52
+ /** A request from the MCP server. RequestListRuntimes is handled at the Vite plugin layer; all other requests are routed to a browser runtime. */
53
+ export const Request = S.Union(RequestGetModel, RequestListMessages, RequestGetMessage, RequestListKeyframes, RequestReplayToKeyframe, RequestResume, RequestDispatchMessage, RequestListRuntimes);
54
+ // RESPONSE
55
+ /** Response carrying the current Model snapshot. */
56
+ export const ResponseModel = ts('ResponseModel', {
57
+ model: S.Unknown,
58
+ });
59
+ /** Response carrying a page of history entries. `maybeNextIndex` is `Some` when more entries are available beyond this page (pass it as `RequestListMessages.maybeSinceIndex` to fetch the next page) and `None` when this page reaches the current end of history. */
60
+ export const ResponseMessages = ts('ResponseMessages', {
61
+ entries: S.Array(SerializedEntry),
62
+ maybeNextIndex: S.Option(S.Number),
63
+ });
64
+ /** Response carrying a single history entry with surrounding Model snapshots. */
65
+ export const ResponseMessage = ts('ResponseMessage', {
66
+ entry: SerializedEntry,
67
+ modelBefore: S.Unknown,
68
+ modelAfter: S.Unknown,
69
+ });
70
+ /** Response carrying the list of available keyframes. */
71
+ export const ResponseKeyframes = ts('ResponseKeyframes', {
72
+ keyframes: S.Array(KeyframeInfo),
73
+ });
74
+ /** Response confirming a successful replay. The runtime is paused at this Model. */
75
+ export const ResponseReplayed = ts('ResponseReplayed', {
76
+ model: S.Unknown,
77
+ });
78
+ /** Response confirming the runtime resumed normal execution. */
79
+ export const ResponseResumed = ts('ResponseResumed');
80
+ /** 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 Message reaches the runtime's update loop asynchronously, so concurrent Messages produced by the runtime itself could in principle shift ordering; in practice the bridge is the only external dispatch source and the runtime queue serializes Messages, so this index is reliable for correlation. */
81
+ export const ResponseDispatched = ts('ResponseDispatched', {
82
+ acceptedAtIndex: S.Number,
83
+ });
84
+ /** Response carrying the list of connected runtimes. */
85
+ export const ResponseRuntimes = ts('ResponseRuntimes', {
86
+ runtimes: S.Array(RuntimeInfo),
87
+ });
88
+ /** Response carrying an error reason for a failed Request. */
89
+ export const ResponseError = ts('ResponseError', {
90
+ reason: S.String,
91
+ });
92
+ /** A response replying to a Request. */
93
+ export const Response = S.Union(ResponseModel, ResponseMessages, ResponseMessage, ResponseKeyframes, ResponseReplayed, ResponseResumed, ResponseDispatched, ResponseRuntimes, ResponseError);
94
+ // EVENT
95
+ /** A new browser runtime connected. The `runtime.maybeMessageSchema` field carries the runtime's Message Schema (as JSON Schema) when the runtime exposes one via `DevToolsConfig.Message`. */
96
+ export const EventConnected = ts('EventConnected', {
97
+ runtime: RuntimeInfo,
98
+ });
99
+ /** A previously connected runtime disconnected. */
100
+ export const EventDisconnected = ts('EventDisconnected', {
101
+ connectionId: S.String,
102
+ });
103
+ /** A runtime lifecycle event used by the Vite plugin to track which browser tabs are connected. Not forwarded to MCP clients. */
104
+ export const Event = S.Union(EventConnected, EventDisconnected);
105
+ // FRAME
106
+ /** A wire frame carrying a Request from the MCP server. The id is opaque, used only by the MCP server to correlate the matching Response. The maybeConnectionId routes the request to a specific runtime when present. */
107
+ export const RequestFrame = S.Struct({
108
+ id: S.String,
109
+ maybeConnectionId: S.Option(S.String),
110
+ request: Request,
111
+ });
112
+ /** A wire frame carrying a Response, correlated to a Request by id. */
113
+ export const ResponseFrame = S.Struct({
114
+ id: S.String,
115
+ response: Response,
116
+ });
117
+ /** A wire frame carrying a runtime lifecycle event from the bridge to the Vite plugin. */
118
+ export const EventFrame = S.Struct({
119
+ maybeConnectionId: S.Option(S.String),
120
+ event: Event,
121
+ });
@@ -0,0 +1,2 @@
1
+ export { EventConnected, EventDisconnected, EventFrame, Event, KeyframeInfo, RequestDispatchMessage, RequestFrame, RequestGetMessage, RequestGetModel, RequestListKeyframes, RequestListMessages, RequestListRuntimes, RequestReplayToKeyframe, RequestResume, Request, ResponseDispatched, ResponseError, ResponseFrame, ResponseKeyframes, ResponseMessage, ResponseMessages, ResponseModel, ResponseReplayed, ResponseResumed, ResponseRuntimes, Response, RuntimeInfo, SerializedEntry, } from './protocol.js';
2
+ //# sourceMappingURL=public.d.ts.map
@@ -0,0 +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,sBAAsB,EACtB,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACR,WAAW,EACX,eAAe,GAChB,MAAM,eAAe,CAAA"}
@@ -0,0 +1 @@
1
+ export { EventConnected, EventDisconnected, EventFrame, Event, KeyframeInfo, RequestDispatchMessage, RequestFrame, RequestGetMessage, RequestGetModel, RequestListKeyframes, RequestListMessages, RequestListRuntimes, RequestReplayToKeyframe, RequestResume, Request, ResponseDispatched, ResponseError, ResponseFrame, ResponseKeyframes, ResponseMessage, ResponseMessages, ResponseModel, ResponseReplayed, ResponseResumed, ResponseRuntimes, Response, RuntimeInfo, SerializedEntry, } from './protocol.js';
@@ -0,0 +1,19 @@
1
+ import type { SerializedEntry } from './protocol.js';
2
+ import type { HistoryEntry } from './store.js';
3
+ /**
4
+ * Convert DOM-class instances (File, Blob, Date, URL) to plain-object
5
+ * representations so the tree renderer's key-enumeration walk can see their
6
+ * meaningful data, which otherwise lives on the prototype as getters and
7
+ * is invisible to `Object.keys`. Recurses through arrays and records so
8
+ * the transform applies at every level. File is matched before Blob
9
+ * because File extends Blob.
10
+ */
11
+ export declare const toInspectableValue: (value: unknown) => unknown;
12
+ /**
13
+ * Convert a `HistoryEntry` plus its absolute index into the wire-friendly
14
+ * `SerializedEntry` shape. Flattens the diff's `HashSet` path collections to
15
+ * plain string arrays for JSON transmission and runs the message body through
16
+ * `toInspectableValue` so DOM-class instances become inspectable objects.
17
+ */
18
+ export declare const toSerializedEntry: (entry: HistoryEntry, index: number) => SerializedEntry;
19
+ //# sourceMappingURL=serialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/devTools/serialize.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,OAiBjD,CAAA;AAEH;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,YAAY,EACnB,OAAO,MAAM,KACZ,eASD,CAAA"}
@@ -0,0 +1,34 @@
1
+ import { Array as Array_, Function, HashSet, Match as M, Predicate, Record, } from 'effect';
2
+ /**
3
+ * Convert DOM-class instances (File, Blob, Date, URL) to plain-object
4
+ * representations so the tree renderer's key-enumeration walk can see their
5
+ * meaningful data, which otherwise lives on the prototype as getters and
6
+ * is invisible to `Object.keys`. Recurses through arrays and records so
7
+ * the transform applies at every level. File is matched before Blob
8
+ * because File extends Blob.
9
+ */
10
+ export const toInspectableValue = (value) => M.value(value).pipe(M.when(M.instanceOf(File), file => ({
11
+ name: file.name,
12
+ size: file.size,
13
+ type: file.type,
14
+ lastModified: file.lastModified,
15
+ })), M.when(M.instanceOf(Blob), blob => ({
16
+ size: blob.size,
17
+ type: blob.type,
18
+ })), M.when(M.instanceOf(Date), date => date.toISOString()), M.when(M.instanceOf(URL), ({ href }) => href), M.when(Array.isArray, Array_.map(toInspectableValue)), M.when(Predicate.isReadonlyRecord, Record.map(toInspectableValue)), M.orElse(Function.identity));
19
+ /**
20
+ * Convert a `HistoryEntry` plus its absolute index into the wire-friendly
21
+ * `SerializedEntry` shape. Flattens the diff's `HashSet` path collections to
22
+ * plain string arrays for JSON transmission and runs the message body through
23
+ * `toInspectableValue` so DOM-class instances become inspectable objects.
24
+ */
25
+ export const toSerializedEntry = (entry, index) => ({
26
+ index,
27
+ tag: entry.tag,
28
+ message: toInspectableValue(entry.message),
29
+ commandNames: entry.commandNames,
30
+ timestamp: entry.timestamp,
31
+ isModelChanged: entry.isModelChanged,
32
+ changedPaths: HashSet.toValues(entry.diff.changedPaths),
33
+ affectedPaths: HashSet.toValues(entry.diff.affectedPaths),
34
+ });
@@ -28,8 +28,8 @@ export type Bridge = Readonly<{
28
28
  render: (model: unknown) => Effect.Effect<void>;
29
29
  getCurrentModel: Effect.Effect<unknown>;
30
30
  }>;
31
- export declare const createDevtoolsStore: (bridge: Bridge, maxEntries?: number) => Effect.Effect<DevtoolsStore>;
32
- export type DevtoolsStore = Readonly<{
31
+ export declare const createDevToolsStore: (bridge: Bridge, maxEntries?: number) => Effect.Effect<DevToolsStore>;
32
+ export type DevToolsStore = Readonly<{
33
33
  recordInit: (model: unknown, commandNames: ReadonlyArray<string>) => Effect.Effect<void>;
34
34
  recordMessage: (message: Readonly<{
35
35
  _tag: string;
@@ -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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"}
@@ -73,7 +73,7 @@ const emptyState = {
73
73
  isPaused: false,
74
74
  pausedAtIndex: 0,
75
75
  };
76
- export const createDevtoolsStore = (bridge, maxEntries = DEFAULT_MAX_ENTRIES) => Effect.gen(function* () {
76
+ export const createDevToolsStore = (bridge, maxEntries = DEFAULT_MAX_ENTRIES) => Effect.gen(function* () {
77
77
  const stateRef = yield* SubscriptionRef.make(emptyState);
78
78
  const replayToIndex = (state, index) => {
79
79
  const segmentStart = Math.floor(index / KEYFRAME_INTERVAL) * KEYFRAME_INTERVAL;
@@ -0,0 +1,24 @@
1
+ import { Effect, Option, Schema as S } from 'effect';
2
+ import { type DevToolsStore } from './store.js';
3
+ type Hot = NonNullable<ImportMeta['hot']>;
4
+ /**
5
+ * Start the browser-side WebSocket bridge that exposes a Foldkit runtime's
6
+ * DevToolsStore to an external MCP server (via the Vite plugin relay).
7
+ *
8
+ * Emits `EventConnected` on startup so the relay tracks this runtime.
9
+ * Listens on the request channel for `RequestFrame`s targeted at this
10
+ * connection's id and replies with the matching `ResponseFrame`. Emits
11
+ * `EventDisconnected` on tab close or HMR module dispose so the relay can
12
+ * remove this runtime from its connected set.
13
+ *
14
+ * `dispatch` enqueues a Message into the runtime's message queue; the bridge
15
+ * uses it to fulfill `RequestDispatchMessage` after the payload is validated
16
+ * against `maybeMessageSchema`. When `maybeMessageSchema` is `None`, dispatch
17
+ * requests are rejected with an informative error.
18
+ *
19
+ * Production-safe: callers must check `import.meta.hot` is defined before
20
+ * invoking this. The function assumes a live HMR connection.
21
+ */
22
+ export declare const startWebSocketBridge: (store: DevToolsStore, hot: Hot, dispatch: (message: unknown) => Effect.Effect<void>, maybeMessageSchema: Option.Option<S.Schema<any, any, never>>) => Effect.Effect<void>;
23
+ export {};
24
+ //# sourceMappingURL=webSocketBridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webSocketBridge.d.ts","sourceRoot":"","sources":["../../src/devTools/webSocketBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EAKN,MAAM,EAGN,MAAM,IAAI,CAAC,EAGZ,MAAM,QAAQ,CAAA;AAuBf,OAAO,EAAE,KAAK,aAAa,EAAc,MAAM,YAAY,CAAA;AAE3D,KAAK,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;AAczC;;;;;;;;;;;;;;;;;GAiBG;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,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,KAC3D,MAAM,CAAC,MAAM,CAAC,IAAI,CAgFjB,CAAA"}
@@ -0,0 +1,163 @@
1
+ import { Array, Cause, Effect, Either, HashMap, JSONSchema, Match, Option, Order, Runtime, Schema as S, SubscriptionRef, pipe, } from 'effect';
2
+ import { OptionExt } from '../effectExtensions/index.js';
3
+ import { EventConnected, EventDisconnected, KeyframeInfo, RequestFrame, ResponseDispatched, ResponseError, ResponseKeyframes, ResponseMessage, ResponseMessages, ResponseModel, ResponseReplayed, ResponseResumed, RuntimeInfo, } from './protocol.js';
4
+ import { toInspectableValue, toSerializedEntry } from './serialize.js';
5
+ import { INIT_INDEX } from './store.js';
6
+ const REQUEST_CHANNEL = 'foldkit:devTools:request';
7
+ const RESPONSE_CHANNEL = 'foldkit:devTools:response';
8
+ const EVENT_CHANNEL = 'foldkit:devTools:event';
9
+ const generateConnectionId = () => `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
10
+ const currentAbsoluteIndex = (entriesLength, startIndex) => (entriesLength === 0 ? INIT_INDEX : startIndex + entriesLength - 1);
11
+ /**
12
+ * Start the browser-side WebSocket bridge that exposes a Foldkit runtime's
13
+ * DevToolsStore to an external MCP server (via the Vite plugin relay).
14
+ *
15
+ * Emits `EventConnected` on startup so the relay tracks this runtime.
16
+ * Listens on the request channel for `RequestFrame`s targeted at this
17
+ * connection's id and replies with the matching `ResponseFrame`. Emits
18
+ * `EventDisconnected` on tab close or HMR module dispose so the relay can
19
+ * remove this runtime from its connected set.
20
+ *
21
+ * `dispatch` enqueues a Message into the runtime's message queue; the bridge
22
+ * uses it to fulfill `RequestDispatchMessage` after the payload is validated
23
+ * against `maybeMessageSchema`. When `maybeMessageSchema` is `None`, dispatch
24
+ * requests are rejected with an informative error.
25
+ *
26
+ * Production-safe: callers must check `import.meta.hot` is defined before
27
+ * invoking this. The function assumes a live HMR connection.
28
+ */
29
+ export const startWebSocketBridge = (store, hot, dispatch, maybeMessageSchema) => Effect.gen(function* () {
30
+ const connectionId = generateConnectionId();
31
+ const runtime = yield* Effect.runtime();
32
+ const maybeJsonMessageSchema = Option.map(maybeMessageSchema, schema => JSONSchema.make(schema));
33
+ const sendEvent = (event) => {
34
+ hot.send(EVENT_CHANNEL, {
35
+ maybeConnectionId: Option.some(connectionId),
36
+ event,
37
+ });
38
+ };
39
+ const sendResponse = (id, response) => {
40
+ const frame = { id, response };
41
+ hot.send(RESPONSE_CHANNEL, frame);
42
+ };
43
+ sendEvent(EventConnected({
44
+ runtime: RuntimeInfo.make({
45
+ connectionId,
46
+ url: window.location.href,
47
+ title: document.title,
48
+ maybeMessageSchema: maybeJsonMessageSchema,
49
+ }),
50
+ }));
51
+ const handleRequest = (id, request) => Effect.gen(function* () {
52
+ const response = yield* dispatchRequest(store, dispatch, maybeMessageSchema, request);
53
+ sendResponse(id, response);
54
+ });
55
+ const handleRequestFrame = (frame) => {
56
+ const decoded = S.decodeUnknownEither(RequestFrame)(frame);
57
+ Either.match(decoded, {
58
+ onLeft: error => {
59
+ console.warn('[foldkit:devTools] malformed request frame', error);
60
+ },
61
+ onRight: ({ id, maybeConnectionId, request }) => {
62
+ const isForUs = Option.exists(maybeConnectionId, targetId => targetId === connectionId);
63
+ if (!isForUs) {
64
+ return;
65
+ }
66
+ Runtime.runFork(runtime)(handleRequest(id, request));
67
+ },
68
+ });
69
+ };
70
+ hot.on(REQUEST_CHANNEL, handleRequestFrame);
71
+ let hasEmittedDisconnect = false;
72
+ const emitDisconnect = () => {
73
+ if (hasEmittedDisconnect) {
74
+ return;
75
+ }
76
+ hasEmittedDisconnect = true;
77
+ sendEvent(EventDisconnected({ connectionId }));
78
+ };
79
+ hot.dispose(() => {
80
+ emitDisconnect();
81
+ hot.off(REQUEST_CHANNEL, handleRequestFrame);
82
+ });
83
+ window.addEventListener('beforeunload', emitDisconnect, { once: true });
84
+ });
85
+ const dispatchRequest = (store, dispatch, maybeMessageSchema, request) => Match.value(request).pipe(Match.tagsExhaustive({
86
+ RequestGetModel: () => Effect.gen(function* () {
87
+ const state = yield* SubscriptionRef.get(store.stateRef);
88
+ const index = currentAbsoluteIndex(state.entries.length, state.startIndex);
89
+ return yield* pipe(index, store.getModelAtIndex, Effect.map(model => ResponseModel({ model: toInspectableValue(model) })), Effect.catchAllCause(cause => Effect.succeed(ResponseError({
90
+ reason: `Failed to read current Model: ${Cause.pretty(cause)}`,
91
+ }))));
92
+ }),
93
+ RequestListMessages: ({ limit, maybeSinceIndex }) => Effect.gen(function* () {
94
+ const state = yield* SubscriptionRef.get(store.stateRef);
95
+ const startAbsolute = Option.getOrElse(maybeSinceIndex, () => state.startIndex);
96
+ const startRelative = Math.max(0, startAbsolute - state.startIndex);
97
+ const sliced = pipe(state.entries, Array.drop(startRelative), Array.take(limit), Array.map((entry, sliceIndex) => toSerializedEntry(entry, state.startIndex + startRelative + sliceIndex)));
98
+ const totalCount = state.startIndex + state.entries.length;
99
+ const nextIndex = state.startIndex + startRelative + sliced.length;
100
+ const maybeNextIndex = OptionExt.when(nextIndex < totalCount, nextIndex);
101
+ return ResponseMessages({ entries: sliced, maybeNextIndex });
102
+ }),
103
+ RequestGetMessage: ({ index }) => Effect.gen(function* () {
104
+ const state = yield* SubscriptionRef.get(store.stateRef);
105
+ const relative = index - state.startIndex;
106
+ const maybeEntry = Array.get(state.entries, relative);
107
+ return yield* Option.match(maybeEntry, {
108
+ onNone: () => Effect.succeed(ResponseError({
109
+ reason: `No entry at index ${index} (have ${state.startIndex} to ${state.startIndex + state.entries.length - 1})`,
110
+ })),
111
+ onSome: entry => pipe({
112
+ modelBefore: store.getModelAtIndex(index - 1),
113
+ modelAfter: store.getModelAtIndex(index),
114
+ }, Effect.all, Effect.map(({ modelBefore, modelAfter }) => ResponseMessage({
115
+ entry: toSerializedEntry(entry, index),
116
+ modelBefore: toInspectableValue(modelBefore),
117
+ modelAfter: toInspectableValue(modelAfter),
118
+ })), Effect.catchAllCause(cause => Effect.succeed(ResponseError({
119
+ reason: `Failed to read Models around index ${index}: ${Cause.pretty(cause)}`,
120
+ })))),
121
+ });
122
+ }),
123
+ RequestListKeyframes: () => Effect.gen(function* () {
124
+ const state = yield* SubscriptionRef.get(store.stateRef);
125
+ const sortedKeyframeIndices = pipe(state.keyframes, HashMap.keys, Array.fromIterable, Array.sort(Order.number));
126
+ const indicesWithInit = Option.match(state.maybeInitModel, {
127
+ onNone: () => sortedKeyframeIndices,
128
+ onSome: () => [INIT_INDEX, ...sortedKeyframeIndices],
129
+ });
130
+ const keyframes = indicesWithInit.map(index => KeyframeInfo.make({ index }));
131
+ return ResponseKeyframes({ keyframes });
132
+ }),
133
+ RequestReplayToKeyframe: ({ keyframeIndex }) => pipe(Effect.gen(function* () {
134
+ yield* store.jumpTo(keyframeIndex);
135
+ const model = yield* store.getModelAtIndex(keyframeIndex);
136
+ return ResponseReplayed({ model: toInspectableValue(model) });
137
+ }), Effect.catchAllCause(cause => Effect.succeed(ResponseError({
138
+ reason: `Failed to replay to keyframe ${keyframeIndex}: ${Cause.pretty(cause)}`,
139
+ })))),
140
+ RequestResume: () => Effect.gen(function* () {
141
+ yield* store.resume;
142
+ return ResponseResumed();
143
+ }).pipe(Effect.catchAllCause(cause => Effect.succeed(ResponseError({
144
+ reason: `Failed to resume: ${Cause.pretty(cause)}`,
145
+ })))),
146
+ RequestDispatchMessage: ({ message }) => Option.match(maybeMessageSchema, {
147
+ onNone: () => Effect.succeed(ResponseError({
148
+ reason: 'Cannot dispatch: DevToolsConfig.Message not configured. Pass your Message Schema to enable dispatch.',
149
+ })),
150
+ onSome: messageSchema => Effect.gen(function* () {
151
+ const decodedMessage = yield* S.decodeUnknown(messageSchema)(message);
152
+ const stateBefore = yield* SubscriptionRef.get(store.stateRef);
153
+ const acceptedAtIndex = stateBefore.startIndex + stateBefore.entries.length;
154
+ yield* dispatch(decodedMessage);
155
+ return ResponseDispatched({ acceptedAtIndex });
156
+ }).pipe(Effect.catchAll(error => Effect.succeed(ResponseError({
157
+ reason: `Invalid Message: ${error instanceof Error ? error.message : String(error)}\n\nReceived (typeof ${typeof message}): ${JSON.stringify(message)}`,
158
+ })))),
159
+ }),
160
+ RequestListRuntimes: () => Effect.succeed(ResponseError({
161
+ reason: 'RequestListRuntimes is plugin-handled and should not reach the runtime bridge',
162
+ })),
163
+ }));
@@ -1,5 +1,5 @@
1
1
  export { makeProgram, run } from './runtime.js';
2
- export type { RoutingConfig, CrashConfig, CrashContext, RoutingProgramConfigWithFlags, RoutingProgramConfig, ProgramConfigWithFlags, ProgramConfig, ProgramInit, RoutingProgramInit, MakeRuntimeReturn, Visibility, SlowViewContext, SlowViewConfig, FreezeModelConfig, DevtoolsConfig, } from './runtime.js';
2
+ export type { RoutingConfig, CrashConfig, CrashContext, RoutingProgramConfigWithFlags, RoutingProgramConfig, ProgramConfigWithFlags, ProgramConfig, ProgramInit, RoutingProgramInit, MakeRuntimeReturn, Visibility, SlowViewContext, SlowViewConfig, FreezeModelConfig, DevToolsConfig, } from './runtime.js';
3
3
  export { UrlRequest } from './urlRequest.js';
4
4
  export type { Internal, External } from './urlRequest.js';
5
5
  //# sourceMappingURL=public.d.ts.map
@@ -5,31 +5,42 @@ import { Url } from '../url/index.js';
5
5
  import type { ManagedResources } from './managedResource.js';
6
6
  import type { Subscriptions } from './subscription.js';
7
7
  import { UrlRequest } from './urlRequest.js';
8
- /** Position of the devtools badge and panel on screen. */
9
- export type DevtoolsPosition = 'BottomRight' | 'BottomLeft' | 'TopRight' | 'TopLeft';
8
+ /** Position of the DevTools badge and panel on screen. */
9
+ export type DevToolsPosition = 'BottomRight' | 'BottomLeft' | 'TopRight' | 'TopLeft';
10
10
  /** Controls when a feature is shown. */
11
11
  export type Visibility = 'Development' | 'Always';
12
- /** Controls devtools interaction mode.
12
+ /** Controls DevTools interaction mode.
13
13
  *
14
14
  * - `'Inspect'`: Messages stream in and clicking a row shows its state snapshot without pausing the app.
15
15
  * - `'TimeTravel'`: Clicking a row pauses the app at that historical state. Resume to continue.
16
16
  */
17
- export type DevtoolsMode = 'Inspect' | 'TimeTravel';
17
+ export type DevToolsMode = 'Inspect' | 'TimeTravel';
18
18
  /**
19
- * Devtools configuration.
19
+ * DevTools configuration.
20
20
  *
21
- * Pass `false` to disable devtools entirely.
21
+ * Pass `false` to disable DevTools entirely.
22
22
  *
23
23
  * - `show`: `'Development'` (default) enables in dev mode only, `'Always'` enables in all environments including production.
24
24
  * - `position`: Where the badge and panel appear. Defaults to `'BottomRight'`.
25
25
  * - `mode`: `'TimeTravel'` (default) enables full time-travel debugging. `'Inspect'` allows browsing state snapshots without pausing the app.
26
26
  * - `banner`: Optional text shown as a banner at the top of the panel.
27
27
  */
28
- export type DevtoolsConfig = false | Readonly<{
28
+ export type DevToolsConfig = false | Readonly<{
29
29
  show?: Visibility;
30
- position?: DevtoolsPosition;
31
- mode?: DevtoolsMode;
30
+ position?: DevToolsPosition;
31
+ mode?: DevToolsMode;
32
32
  banner?: string;
33
+ /**
34
+ * The application's `Message` Schema. When provided and the running app
35
+ * is connected to the Foldkit DevTools MCP server, AI agents can dispatch
36
+ * Messages into the runtime. The Schema validates inbound dispatch
37
+ * payloads at the bridge boundary, and its JSON Schema representation is
38
+ * exposed to the MCP server so agents discover the available variants.
39
+ *
40
+ * Without this field, `RequestDispatchMessage` is rejected with an
41
+ * informative error.
42
+ */
43
+ Message?: Schema.Schema<any, any, never>;
33
44
  }>;
34
45
  /** Context provided to the slow view callback when a view exceeds the time budget. */
35
46
  export type SlowViewContext<Model, Message> = Readonly<{
@@ -114,7 +125,7 @@ type BaseProgramConfig<Model, Message, StreamDepsMap extends Schema.Struct<Schem
114
125
  managedResources?: ManagedResources<Model, Message, ManagedResourceServices>;
115
126
  /** Derives the document title from the current model. Called after every render. */
116
127
  title?: (model: Model) => string;
117
- devtools?: DevtoolsConfig;
128
+ devTools?: DevToolsConfig;
118
129
  }>;
119
130
  /** Configuration for `makeProgram` with flags and URL routing. */
120
131
  export type RoutingProgramConfigWithFlags<Model, Message, StreamDepsMap extends Schema.Struct<Schema.Struct.Fields>, Flags, Resources = never, ManagedResourceServices = never> = BaseProgramConfig<Model, Message, StreamDepsMap, Resources, ManagedResourceServices> & Readonly<{
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,17 @@
1
1
  import { BrowserRuntime } from '@effect/platform-browser';
2
2
  import { Array, Cause, Context, Effect, Either, Function, Layer, Match, Option, Predicate, Queue, Record, Ref, Runtime, Schema, Stream, SubscriptionRef, Tuple, pipe, } from 'effect';
3
3
  import { h } from 'snabbdom';
4
- import { createOverlay } from '../devtools/overlay.js';
5
- import { createDevtoolsStore } from '../devtools/store.js';
4
+ import { createOverlay } from '../devTools/overlay.js';
5
+ import { createDevToolsStore } from '../devTools/store.js';
6
+ import { startWebSocketBridge } from '../devTools/webSocketBridge.js';
6
7
  import { fromString as urlFromString } from '../url/index.js';
7
8
  import { patch, toVNode } from '../vdom.js';
8
9
  import { addBfcacheRestoreListener, addNavigationEventListeners, } from './browserListeners.js';
9
10
  import { defaultCrashView, noOpDispatch } from './crashUI.js';
10
11
  import { deepFreeze } from './deepFreeze.js';
11
- const DEFAULT_DEVTOOLS_SHOW = 'Development';
12
- const DEFAULT_DEVTOOLS_POSITION = 'BottomRight';
13
- const DEFAULT_DEVTOOLS_MODE = 'TimeTravel';
12
+ const DEFAULT_DEV_TOOLS_SHOW = 'Development';
13
+ const DEFAULT_DEV_TOOLS_POSITION = 'BottomRight';
14
+ const DEFAULT_DEV_TOOLS_MODE = 'TimeTravel';
14
15
  const DEFAULT_SLOW_VIEW_SHOW = 'Development';
15
16
  const DEFAULT_SLOW_VIEW_THRESHOLD_MS = 16;
16
17
  const DEFAULT_FREEZE_MODEL_SHOW = 'Development';
@@ -29,7 +30,7 @@ const defaultSlowViewCallback = (context) => {
29
30
  /** Effect service tag that provides message dispatching to the view layer. */
30
31
  export class Dispatch extends Context.Tag('@foldkit/Dispatch')() {
31
32
  }
32
- const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscriptions, container, routing: routingConfig, crash, slowView, freezeModel, resources, managedResources, title, devtools, }) => {
33
+ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscriptions, container, routing: routingConfig, crash, slowView, freezeModel, resources, managedResources, title, devTools, }) => {
33
34
  const resolvedSlowView = pipe(slowView ?? {}, Option.liftPredicate(config => config !== false), Option.filter(config => Match.value(config.show ?? DEFAULT_SLOW_VIEW_SHOW).pipe(Match.when('Always', () => true), Match.when('Development', () => !!import.meta.hot), Match.exhaustive)), Option.map(config => ({
34
35
  thresholdMs: config.thresholdMs ?? DEFAULT_SLOW_VIEW_THRESHOLD_MS,
35
36
  onSlowView: config.onSlowView ?? defaultSlowViewCallback,
@@ -90,7 +91,7 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
90
91
  const maybeCurrentVNodeRef = yield* Ref.make(Option.none());
91
92
  const currentMessageRef = yield* Ref.make(Option.none());
92
93
  const maybeRuntimeRef = yield* Ref.make(Option.none());
93
- const maybeDevtoolsStoreRef = yield* Ref.make(Option.none());
94
+ const maybeDevToolsStoreRef = yield* Ref.make(Option.none());
94
95
  /** `true` while a render is patching the DOM. Synchronous events
95
96
  * that fire as a side-effect of DOM mutations (e.g. Chrome firing
96
97
  * `blur` when a focused element is removed) call `dispatchSync`; if
@@ -108,7 +109,7 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
108
109
  const nextModel = maybeFreezeModel(nextModelRaw);
109
110
  if (currentModel !== nextModel) {
110
111
  yield* Ref.set(modelRef, nextModel);
111
- const isPaused = yield* pipe(maybeDevtoolsStoreRef, Ref.get, Effect.flatMap(Option.match({
112
+ const isPaused = yield* pipe(maybeDevToolsStoreRef, Ref.get, Effect.flatMap(Option.match({
112
113
  onNone: () => Effect.succeed(false),
113
114
  onSome: ({ stateRef }) => SubscriptionRef.get(stateRef).pipe(Effect.map(({ isPaused }) => isPaused)),
114
115
  })));
@@ -123,8 +124,8 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
123
124
  yield* Effect.forEach(
124
125
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
125
126
  commands, command => Effect.forkDaemon(command.effect.pipe(Effect.withSpan(command.name), provideAllResources, Effect.flatMap(enqueueMessage))));
126
- const maybeDevtoolsStore = yield* Ref.get(maybeDevtoolsStoreRef);
127
- yield* Option.match(maybeDevtoolsStore, {
127
+ const maybeDevToolsStore = yield* Ref.get(maybeDevToolsStoreRef);
128
+ yield* Option.match(maybeDevToolsStore, {
128
129
  onNone: () => Effect.void,
129
130
  onSome: store => store.recordMessage(
130
131
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
@@ -201,14 +202,14 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
201
202
  const runtime = yield* Effect.runtime();
202
203
  yield* Ref.set(maybeRuntimeRef, Option.some(runtime));
203
204
  const isInIframe = window.self !== window.top;
204
- const resolvedDevtools = pipe(devtools ?? {}, Option.liftPredicate(config => config !== false), Option.filter(config => Match.value(config.show ?? DEFAULT_DEVTOOLS_SHOW).pipe(Match.when('Always', () => true), Match.when('Development', () => !!import.meta.hot && !isInIframe), Match.exhaustive)), Option.map(config => ({
205
- position: config.position ?? DEFAULT_DEVTOOLS_POSITION,
206
- mode: config.mode ?? DEFAULT_DEVTOOLS_MODE,
205
+ const resolvedDevTools = pipe(devTools ?? {}, Option.liftPredicate(config => config !== false), Option.filter(config => Match.value(config.show ?? DEFAULT_DEV_TOOLS_SHOW).pipe(Match.when('Always', () => true), Match.when('Development', () => !!import.meta.hot && !isInIframe), Match.exhaustive)), Option.map(config => ({
206
+ position: config.position ?? DEFAULT_DEV_TOOLS_POSITION,
207
+ mode: config.mode ?? DEFAULT_DEV_TOOLS_MODE,
207
208
  maybeBanner: Option.fromNullable(config.banner),
208
209
  })));
209
- if (Option.isSome(resolvedDevtools)) {
210
- const { position, mode, maybeBanner } = resolvedDevtools.value;
211
- const devtoolsStore = yield* createDevtoolsStore({
210
+ if (Option.isSome(resolvedDevTools)) {
211
+ const { position, mode, maybeBanner } = resolvedDevTools.value;
212
+ const devToolsStore = yield* createDevToolsStore({
212
213
  replay: (model, message) => maybeFreezeModel(
213
214
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
214
215
  Tuple.getFirst(update(model, message))),
@@ -217,9 +218,17 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
217
218
  render(model, Option.none()),
218
219
  getCurrentModel: Ref.get(modelRef),
219
220
  });
220
- yield* Ref.set(maybeDevtoolsStoreRef, Option.some(devtoolsStore));
221
- yield* devtoolsStore.recordInit(initModel, Array.map(initCommands, ({ name }) => name));
222
- yield* createOverlay(devtoolsStore, position, mode, maybeBanner);
221
+ yield* Ref.set(maybeDevToolsStoreRef, Option.some(devToolsStore));
222
+ yield* devToolsStore.recordInit(initModel, Array.map(initCommands, ({ name }) => name));
223
+ yield* createOverlay(devToolsStore, position, mode, maybeBanner);
224
+ if (import.meta.hot) {
225
+ const maybeMessageSchema = devTools !== undefined && devTools !== false
226
+ ? Option.fromNullable(devTools.Message)
227
+ : Option.none();
228
+ yield* startWebSocketBridge(devToolsStore, import.meta.hot,
229
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
230
+ message => enqueueMessage(message), maybeMessageSchema);
231
+ }
223
232
  }
224
233
  yield* render(initModel, Option.none());
225
234
  addBfcacheRestoreListener();
@@ -348,8 +357,8 @@ export function makeProgram(config) {
348
357
  managedResources: config.managedResources,
349
358
  }),
350
359
  ...(config.title && { title: config.title }),
351
- ...(Predicate.isNotUndefined(config.devtools) && {
352
- devtools: config.devtools,
360
+ ...(Predicate.isNotUndefined(config.devTools) && {
361
+ devTools: config.devTools,
353
362
  }),
354
363
  };
355
364
  /* eslint-disable @typescript-eslint/consistent-type-assertions */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foldkit",
3
- "version": "0.75.1",
3
+ "version": "0.76.1",
4
4
  "description": "A frontend framework for TypeScript, built on Effect, using The Elm Architecture",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -166,6 +166,10 @@
166
166
  "./url": {
167
167
  "types": "./dist/url/public.d.ts",
168
168
  "import": "./dist/url/public.js"
169
+ },
170
+ "./devtools-protocol": {
171
+ "types": "./dist/devTools/public.d.ts",
172
+ "import": "./dist/devTools/public.js"
169
173
  }
170
174
  },
171
175
  "files": [
File without changes
File without changes