foldkit 0.83.0 → 0.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/devTools/overlay.d.ts.map +1 -1
- package/dist/devTools/overlay.js +66 -4
- package/dist/devTools/protocol.d.ts +19 -2
- package/dist/devTools/protocol.d.ts.map +1 -1
- package/dist/devTools/protocol.js +5 -2
- package/dist/devTools/serialize.d.ts.map +1 -1
- package/dist/devTools/serialize.js +2 -0
- package/dist/devTools/store.d.ts +5 -1
- package/dist/devTools/store.d.ts.map +1 -1
- package/dist/devTools/store.js +37 -1
- package/dist/devTools/webSocketBridge.js +1 -0
- package/dist/html/index.d.ts +11 -0
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +58 -39
- package/dist/mount/index.d.ts +14 -1
- package/dist/mount/index.d.ts.map +1 -1
- package/dist/mount/index.js +9 -1
- package/dist/mount/public.d.ts +1 -1
- package/dist/mount/public.d.ts.map +1 -1
- package/dist/mount/public.js +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +38 -3
- package/dist/scene/public.d.ts +2 -0
- package/dist/scene/public.d.ts.map +1 -0
- package/dist/scene/public.js +1 -0
- package/dist/story/public.d.ts +2 -0
- package/dist/story/public.d.ts.map +1 -0
- package/dist/story/public.js +1 -0
- package/dist/test/apps/mountPanel.d.ts +42 -0
- package/dist/test/apps/mountPanel.d.ts.map +1 -0
- package/dist/test/apps/mountPanel.js +76 -0
- package/dist/test/internal.d.ts +38 -0
- package/dist/test/internal.d.ts.map +1 -1
- package/dist/test/internal.js +75 -0
- package/dist/test/scene.d.ts +37 -14
- package/dist/test/scene.d.ts.map +1 -1
- package/dist/test/scene.js +141 -8
- package/dist/test/story.d.ts +17 -13
- package/dist/test/story.d.ts.map +1 -1
- package/dist/test/story.js +19 -5
- package/dist/ui/combobox/public.d.ts +1 -1
- package/dist/ui/combobox/public.d.ts.map +1 -1
- package/dist/ui/combobox/public.js +1 -1
- package/dist/ui/combobox/shared.d.ts +26 -0
- package/dist/ui/combobox/shared.d.ts.map +1 -1
- package/dist/ui/combobox/shared.js +17 -4
- package/dist/ui/listbox/public.d.ts +1 -1
- package/dist/ui/listbox/public.d.ts.map +1 -1
- package/dist/ui/listbox/public.js +1 -1
- package/dist/ui/listbox/shared.d.ts +19 -0
- package/dist/ui/listbox/shared.d.ts.map +1 -1
- package/dist/ui/listbox/shared.js +12 -3
- package/dist/ui/menu/index.d.ts +19 -0
- package/dist/ui/menu/index.d.ts.map +1 -1
- package/dist/ui/menu/index.js +12 -3
- package/dist/ui/menu/public.d.ts +1 -1
- package/dist/ui/menu/public.d.ts.map +1 -1
- package/dist/ui/menu/public.js +1 -1
- package/dist/ui/popover/index.d.ts +13 -0
- package/dist/ui/popover/index.d.ts.map +1 -1
- package/dist/ui/popover/index.js +8 -2
- package/dist/ui/popover/public.d.ts +1 -1
- package/dist/ui/popover/public.d.ts.map +1 -1
- package/dist/ui/popover/public.js +1 -1
- package/dist/ui/tooltip/index.d.ts +7 -0
- package/dist/ui/tooltip/index.d.ts.map +1 -1
- package/dist/ui/tooltip/index.js +4 -1
- package/dist/ui/tooltip/public.d.ts +1 -1
- package/dist/ui/tooltip/public.d.ts.map +1 -1
- package/dist/ui/tooltip/public.js +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -153,7 +153,7 @@ Foldkit is a complete system, not a collection of libraries you stitch together.
|
|
|
153
153
|
- **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.
|
|
154
154
|
- **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`.
|
|
155
155
|
- **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.
|
|
156
|
-
- **Story Testing**: Exercise the update function directly. Send Messages, resolve Commands inline with `resolve` and `resolveAll`, and assert with focused helpers: `Story.model`, `Story.
|
|
156
|
+
- **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.
|
|
157
157
|
- **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.
|
|
158
158
|
- **Slow-View Monitoring**: Wire `slowView` on `makeProgram` to catch renders that exceed a threshold you set. The callback fires with the current Model, the triggering Message, and the render duration, so you can log it, sample it, or ship it to your observability tool.
|
|
159
159
|
- **HMR**: Vite plugin with state-preserving hot module replacement. Change your view, keep your state.
|
|
@@ -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,EAUP,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAW9C,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAQ3E,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devTools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,MAAM,EAGN,OAAO,EAGP,MAAM,EAUP,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAW9C,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAQ3E,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,YAAY,CAAA;AAqO5E,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;AAs9CvE,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sCAoDhC,CAAA"}
|
package/dist/devTools/overlay.js
CHANGED
|
@@ -20,6 +20,8 @@ const DisplayEntry = S.Struct({
|
|
|
20
20
|
submodelPath: S.Array(S.String),
|
|
21
21
|
maybeLeafTag: S.Option(S.String),
|
|
22
22
|
commandNames: S.Array(S.String),
|
|
23
|
+
mountStartNames: S.Array(S.String),
|
|
24
|
+
mountEndNames: S.Array(S.String),
|
|
23
25
|
timestamp: S.Number,
|
|
24
26
|
isModelChanged: S.Boolean,
|
|
25
27
|
});
|
|
@@ -48,6 +50,7 @@ const Model = S.Struct({
|
|
|
48
50
|
isMobile: S.Boolean,
|
|
49
51
|
entries: S.Array(DisplayEntry),
|
|
50
52
|
initCommandNames: S.Array(S.String),
|
|
53
|
+
initMountStartNames: S.Array(S.String),
|
|
51
54
|
startIndex: S.Number,
|
|
52
55
|
isPaused: S.Boolean,
|
|
53
56
|
pausedAtIndex: S.Number,
|
|
@@ -67,6 +70,7 @@ const Flags = S.Struct({
|
|
|
67
70
|
isMobile: S.Boolean,
|
|
68
71
|
entries: S.Array(DisplayEntry),
|
|
69
72
|
initCommandNames: S.Array(S.String),
|
|
73
|
+
initMountStartNames: S.Array(S.String),
|
|
70
74
|
startIndex: S.Number,
|
|
71
75
|
isPaused: S.Boolean,
|
|
72
76
|
pausedAtIndex: S.Number,
|
|
@@ -99,6 +103,7 @@ const GotInspectorTabsMessage = m('GotInspectorTabsMessage', {
|
|
|
99
103
|
const ReceivedStoreUpdate = m('ReceivedStoreUpdate', {
|
|
100
104
|
entries: S.Array(DisplayEntry),
|
|
101
105
|
initCommandNames: S.Array(S.String),
|
|
106
|
+
initMountStartNames: S.Array(S.String),
|
|
102
107
|
startIndex: S.Number,
|
|
103
108
|
isPaused: S.Boolean,
|
|
104
109
|
pausedAtIndex: S.Number,
|
|
@@ -137,6 +142,7 @@ const TREE_INDENT_PX = 12;
|
|
|
137
142
|
const MAX_PREVIEW_KEYS = 3;
|
|
138
143
|
const ALL_MESSAGES_VALUE = '';
|
|
139
144
|
const NO_COMMANDS = [];
|
|
145
|
+
const NO_MOUNTS = [];
|
|
140
146
|
const formatTimeDelta = (deltaMs) => M.value(deltaMs).pipe(M.when(0, () => '0ms'), M.when(Number_.isLessThan(MILLIS_PER_SECOND), ms => `+${Math.round(ms)}ms`), M.orElse(ms => `+${(ms / MILLIS_PER_SECOND).toFixed(1)}s`));
|
|
141
147
|
const MESSAGE_LIST_SELECTOR = '.message-list';
|
|
142
148
|
const computeSubmodelTags = (entries) => pipe(entries, Array_.flatMap(({ submodelPath }) => submodelPath), Array_.dedupe, Array_.sort(Order.String));
|
|
@@ -147,6 +153,8 @@ const toDisplayEntries = ({ entries }) => Array_.map(entries, entry => {
|
|
|
147
153
|
submodelPath,
|
|
148
154
|
maybeLeafTag,
|
|
149
155
|
commandNames: entry.commandNames,
|
|
156
|
+
mountStartNames: entry.mountStartNames,
|
|
157
|
+
mountEndNames: entry.mountEndNames,
|
|
150
158
|
timestamp: entry.timestamp,
|
|
151
159
|
isModelChanged: entry.isModelChanged,
|
|
152
160
|
};
|
|
@@ -154,6 +162,7 @@ const toDisplayEntries = ({ entries }) => Array_.map(entries, entry => {
|
|
|
154
162
|
const toDisplayState = (state) => ({
|
|
155
163
|
entries: toDisplayEntries(state),
|
|
156
164
|
initCommandNames: state.initCommandNames,
|
|
165
|
+
initMountStartNames: state.initMountStartNames,
|
|
157
166
|
startIndex: state.startIndex,
|
|
158
167
|
isPaused: state.isPaused,
|
|
159
168
|
pausedAtIndex: state.pausedAtIndex,
|
|
@@ -299,7 +308,7 @@ const makeUpdate = (store, shadow, mode) => {
|
|
|
299
308
|
}),
|
|
300
309
|
[],
|
|
301
310
|
],
|
|
302
|
-
ReceivedStoreUpdate: ({ entries, initCommandNames, startIndex, isPaused, pausedAtIndex, }) => {
|
|
311
|
+
ReceivedStoreUpdate: ({ entries, initCommandNames, initMountStartNames, startIndex, isPaused, pausedAtIndex, }) => {
|
|
303
312
|
const shouldFollowLatest = M.value(mode).pipe(M.when('TimeTravel', () => !isPaused), M.when('Inspect', () => model.isFollowingLatest), M.exhaustive);
|
|
304
313
|
const latestIndex = Array_.match(entries, {
|
|
305
314
|
onEmpty: () => INIT_INDEX,
|
|
@@ -311,6 +320,7 @@ const makeUpdate = (store, shadow, mode) => {
|
|
|
311
320
|
evo(model, {
|
|
312
321
|
entries: () => entries,
|
|
313
322
|
initCommandNames: () => initCommandNames,
|
|
323
|
+
initMountStartNames: () => initMountStartNames,
|
|
314
324
|
startIndex: () => startIndex,
|
|
315
325
|
isPaused: () => isPaused,
|
|
316
326
|
pausedAtIndex: () => pausedAtIndex,
|
|
@@ -547,6 +557,7 @@ const makeView = (position, mode, maybeBanner) => {
|
|
|
547
557
|
'Model',
|
|
548
558
|
'Message',
|
|
549
559
|
'Commands',
|
|
560
|
+
'Mounts',
|
|
550
561
|
];
|
|
551
562
|
const noMessageView = div([
|
|
552
563
|
Class('flex-1 flex items-center justify-center text-dt-muted text-2xs font-mono min-w-0'),
|
|
@@ -589,12 +600,15 @@ const makeView = (position, mode, maybeBanner) => {
|
|
|
589
600
|
]);
|
|
590
601
|
},
|
|
591
602
|
});
|
|
603
|
+
const selectedHistoryIndex = (model) => M.value(mode).pipe(M.when('TimeTravel', () => model.isPaused ? model.pausedAtIndex : INIT_INDEX), M.when('Inspect', () => model.selectedIndex), M.exhaustive);
|
|
592
604
|
const selectedCommandNames = (model) => {
|
|
593
|
-
const selectedIndex =
|
|
605
|
+
const selectedIndex = selectedHistoryIndex(model);
|
|
594
606
|
if (selectedIndex === INIT_INDEX) {
|
|
595
607
|
return model.initCommandNames;
|
|
596
608
|
}
|
|
597
|
-
|
|
609
|
+
else {
|
|
610
|
+
return pipe(model.entries, Array_.get(selectedIndex - model.startIndex), Option.map(entry => entry.commandNames), Option.getOrElse(() => NO_COMMANDS));
|
|
611
|
+
}
|
|
598
612
|
};
|
|
599
613
|
const commandsTabContent = (commandNames) => Array_.match(commandNames, {
|
|
600
614
|
onEmpty: () => div([
|
|
@@ -609,6 +623,51 @@ const makeView = (position, mode, maybeBanner) => {
|
|
|
609
623
|
span([Class('json-tag')], [name]),
|
|
610
624
|
]))),
|
|
611
625
|
});
|
|
626
|
+
const selectedMountActivity = (model) => {
|
|
627
|
+
const selectedIndex = selectedHistoryIndex(model);
|
|
628
|
+
if (selectedIndex === INIT_INDEX) {
|
|
629
|
+
return { starts: model.initMountStartNames, ends: NO_MOUNTS };
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
return pipe(model.entries, Array_.get(selectedIndex - model.startIndex), Option.match({
|
|
633
|
+
onNone: () => ({ starts: NO_MOUNTS, ends: NO_MOUNTS }),
|
|
634
|
+
onSome: entry => ({
|
|
635
|
+
starts: entry.mountStartNames,
|
|
636
|
+
ends: entry.mountEndNames,
|
|
637
|
+
}),
|
|
638
|
+
}));
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
const mountListSection = (label, names) => div([Class('flex flex-col shrink-0')], [
|
|
642
|
+
div([
|
|
643
|
+
Class('px-2 py-1 border-b text-2xs text-dt-muted font-mono shrink-0'),
|
|
644
|
+
], [label]),
|
|
645
|
+
...Array_.map(names, (name, index) => div([
|
|
646
|
+
Class('flex items-center px-2 py-1 text-base font-mono text-dt border-b gap-1.5'),
|
|
647
|
+
], [
|
|
648
|
+
span([Class(indexClass)], [String(index + 1)]),
|
|
649
|
+
span([Class('json-tag')], [name]),
|
|
650
|
+
])),
|
|
651
|
+
]);
|
|
652
|
+
const mountsTabContent = (starts, ends) => {
|
|
653
|
+
const hasAny = Array_.isReadonlyArrayNonEmpty(starts) ||
|
|
654
|
+
Array_.isReadonlyArrayNonEmpty(ends);
|
|
655
|
+
if (!hasAny) {
|
|
656
|
+
return div([
|
|
657
|
+
Class('flex-1 flex items-center justify-center text-dt-muted text-2xs font-mono min-w-0'),
|
|
658
|
+
], ['No Mounts during this render']);
|
|
659
|
+
}
|
|
660
|
+
return div([
|
|
661
|
+
Class('flex flex-col flex-1 min-h-0 min-w-0 overflow-auto overscroll-none'),
|
|
662
|
+
], [
|
|
663
|
+
...(Array_.isReadonlyArrayNonEmpty(starts)
|
|
664
|
+
? [mountListSection('Started', starts)]
|
|
665
|
+
: []),
|
|
666
|
+
...(Array_.isReadonlyArrayNonEmpty(ends)
|
|
667
|
+
? [mountListSection('Ended', ends)]
|
|
668
|
+
: []),
|
|
669
|
+
]);
|
|
670
|
+
};
|
|
612
671
|
const inspectorTabContent = (model, tab, inspectedModel) => M.value(tab).pipe(M.when('Model', () => lazyTabContent('Model', modelTabContent, [
|
|
613
672
|
inspectedModel,
|
|
614
673
|
model.expandedPaths,
|
|
@@ -621,7 +680,10 @@ const makeView = (position, mode, maybeBanner) => {
|
|
|
621
680
|
inspectedTimestamp(model),
|
|
622
681
|
])), M.when('Commands', () => lazyTabContent('Commands', commandsTabContent, [
|
|
623
682
|
selectedCommandNames(model),
|
|
624
|
-
])), M.
|
|
683
|
+
])), M.when('Mounts', () => {
|
|
684
|
+
const { starts, ends } = selectedMountActivity(model);
|
|
685
|
+
return lazyTabContent('Mounts', mountsTabContent, [starts, ends]);
|
|
686
|
+
}), M.exhaustive);
|
|
625
687
|
const inspectorPaneView = (model) => div([
|
|
626
688
|
Class('flex flex-col border-l min-w-0 min-h-0 flex-1 dt-inspector-pane'),
|
|
627
689
|
], [
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Schema as S } from 'effect';
|
|
2
|
-
/** A serialized history entry as it appears on the wire. `submodelPath` lists `Got<Child>Message` wrapper tags from outer to inner when the entry came up through a Submodel chain; `maybeLeafTag` is `Some` with the innermost child Message tag when one exists. */
|
|
2
|
+
/** A serialized history entry as it appears on the wire. `submodelPath` lists `Got<Child>Message` wrapper tags from outer to inner when the entry came up through a Submodel chain; `maybeLeafTag` is `Some` with the innermost child Message tag when one exists. `mountStartNames` lists Mounts that fired during the render after this Message; `mountEndNames` lists Mounts whose elements were unmounted during that render. The Messages dispatched by mount Effects appear as their own entries elsewhere in history. */
|
|
3
3
|
export declare const SerializedEntry: S.Struct<{
|
|
4
4
|
readonly index: S.Number;
|
|
5
5
|
readonly tag: S.String;
|
|
6
6
|
readonly message: S.Unknown;
|
|
7
7
|
readonly commandNames: S.$Array<S.String>;
|
|
8
|
+
readonly mountStartNames: S.$Array<S.String>;
|
|
9
|
+
readonly mountEndNames: S.$Array<S.String>;
|
|
8
10
|
readonly timestamp: S.Number;
|
|
9
11
|
readonly isModelChanged: S.Boolean;
|
|
10
12
|
readonly changedPaths: S.$Array<S.String>;
|
|
@@ -99,6 +101,8 @@ export declare const ResponseMessages: import("../schema/index.js").CallableTagg
|
|
|
99
101
|
readonly tag: S.String;
|
|
100
102
|
readonly message: S.Unknown;
|
|
101
103
|
readonly commandNames: S.$Array<S.String>;
|
|
104
|
+
readonly mountStartNames: S.$Array<S.String>;
|
|
105
|
+
readonly mountEndNames: S.$Array<S.String>;
|
|
102
106
|
readonly timestamp: S.Number;
|
|
103
107
|
readonly isModelChanged: S.Boolean;
|
|
104
108
|
readonly changedPaths: S.$Array<S.String>;
|
|
@@ -115,6 +119,8 @@ export declare const ResponseMessage: import("../schema/index.js").CallableTagge
|
|
|
115
119
|
readonly tag: S.String;
|
|
116
120
|
readonly message: S.Unknown;
|
|
117
121
|
readonly commandNames: S.$Array<S.String>;
|
|
122
|
+
readonly mountStartNames: S.$Array<S.String>;
|
|
123
|
+
readonly mountEndNames: S.$Array<S.String>;
|
|
118
124
|
readonly timestamp: S.Number;
|
|
119
125
|
readonly isModelChanged: S.Boolean;
|
|
120
126
|
readonly changedPaths: S.$Array<S.String>;
|
|
@@ -147,10 +153,11 @@ export declare const ResponseRuntimes: import("../schema/index.js").CallableTagg
|
|
|
147
153
|
readonly title: S.String;
|
|
148
154
|
}>>;
|
|
149
155
|
}>;
|
|
150
|
-
/** Response carrying the recorded init data. `maybeModel` is `None` until the runtime has finished its first render and recorded init; once set it stays set for the rest of the runtime's life. `commandNames` lists the Commands returned from the application's `init` function in the order they were produced. */
|
|
156
|
+
/** Response carrying the recorded init data. `maybeModel` is `None` until the runtime has finished its first render and recorded init; once set it stays set for the rest of the runtime's life. `commandNames` lists the Commands returned from the application's `init` function in the order they were produced. `mountStartNames` lists the Mounts that fired during the initial render. */
|
|
151
157
|
export declare const ResponseInit: import("../schema/index.js").CallableTaggedStruct<"ResponseInit", {
|
|
152
158
|
maybeModel: S.OptionFromNullOr<S.Unknown>;
|
|
153
159
|
commandNames: S.$Array<S.String>;
|
|
160
|
+
mountStartNames: S.$Array<S.String>;
|
|
154
161
|
}>;
|
|
155
162
|
/** Response carrying a snapshot of the runtime's DevTools state. `currentIndex` is the absolute index of the most recently recorded Message, or -1 when no Messages have been recorded yet. `startIndex` is the earliest absolute index still retained in the rolling buffer (older entries are evicted past `maxEntries`). `totalEntries` is the number of retained entries. `isPaused` is true while the runtime is paused at a replayed snapshot; `maybePausedAtIndex` is `Some(index)` then and `None` otherwise. `hasInitModel` is true once the runtime has finished initialising. */
|
|
156
163
|
export declare const ResponseRuntimeState: import("../schema/index.js").CallableTaggedStruct<"ResponseRuntimeState", {
|
|
@@ -176,6 +183,8 @@ export declare const Response: S.Union<readonly [import("../schema/index.js").Ca
|
|
|
176
183
|
readonly tag: S.String;
|
|
177
184
|
readonly message: S.Unknown;
|
|
178
185
|
readonly commandNames: S.$Array<S.String>;
|
|
186
|
+
readonly mountStartNames: S.$Array<S.String>;
|
|
187
|
+
readonly mountEndNames: S.$Array<S.String>;
|
|
179
188
|
readonly timestamp: S.Number;
|
|
180
189
|
readonly isModelChanged: S.Boolean;
|
|
181
190
|
readonly changedPaths: S.$Array<S.String>;
|
|
@@ -190,6 +199,8 @@ export declare const Response: S.Union<readonly [import("../schema/index.js").Ca
|
|
|
190
199
|
readonly tag: S.String;
|
|
191
200
|
readonly message: S.Unknown;
|
|
192
201
|
readonly commandNames: S.$Array<S.String>;
|
|
202
|
+
readonly mountStartNames: S.$Array<S.String>;
|
|
203
|
+
readonly mountEndNames: S.$Array<S.String>;
|
|
193
204
|
readonly timestamp: S.Number;
|
|
194
205
|
readonly isModelChanged: S.Boolean;
|
|
195
206
|
readonly changedPaths: S.$Array<S.String>;
|
|
@@ -214,6 +225,7 @@ export declare const Response: S.Union<readonly [import("../schema/index.js").Ca
|
|
|
214
225
|
}>, import("../schema/index.js").CallableTaggedStruct<"ResponseInit", {
|
|
215
226
|
maybeModel: S.OptionFromNullOr<S.Unknown>;
|
|
216
227
|
commandNames: S.$Array<S.String>;
|
|
228
|
+
mountStartNames: S.$Array<S.String>;
|
|
217
229
|
}>, import("../schema/index.js").CallableTaggedStruct<"ResponseRuntimeState", {
|
|
218
230
|
currentIndex: S.Number;
|
|
219
231
|
startIndex: S.Number;
|
|
@@ -287,6 +299,8 @@ export declare const ResponseFrame: S.Struct<{
|
|
|
287
299
|
readonly tag: S.String;
|
|
288
300
|
readonly message: S.Unknown;
|
|
289
301
|
readonly commandNames: S.$Array<S.String>;
|
|
302
|
+
readonly mountStartNames: S.$Array<S.String>;
|
|
303
|
+
readonly mountEndNames: S.$Array<S.String>;
|
|
290
304
|
readonly timestamp: S.Number;
|
|
291
305
|
readonly isModelChanged: S.Boolean;
|
|
292
306
|
readonly changedPaths: S.$Array<S.String>;
|
|
@@ -301,6 +315,8 @@ export declare const ResponseFrame: S.Struct<{
|
|
|
301
315
|
readonly tag: S.String;
|
|
302
316
|
readonly message: S.Unknown;
|
|
303
317
|
readonly commandNames: S.$Array<S.String>;
|
|
318
|
+
readonly mountStartNames: S.$Array<S.String>;
|
|
319
|
+
readonly mountEndNames: S.$Array<S.String>;
|
|
304
320
|
readonly timestamp: S.Number;
|
|
305
321
|
readonly isModelChanged: S.Boolean;
|
|
306
322
|
readonly changedPaths: S.$Array<S.String>;
|
|
@@ -325,6 +341,7 @@ export declare const ResponseFrame: S.Struct<{
|
|
|
325
341
|
}>, import("../schema/index.js").CallableTaggedStruct<"ResponseInit", {
|
|
326
342
|
maybeModel: S.OptionFromNullOr<S.Unknown>;
|
|
327
343
|
commandNames: S.$Array<S.String>;
|
|
344
|
+
mountStartNames: S.$Array<S.String>;
|
|
328
345
|
}>, import("../schema/index.js").CallableTaggedStruct<"ResponseRuntimeState", {
|
|
329
346
|
currentIndex: S.Number;
|
|
330
347
|
startIndex: S.Number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/devTools/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAMpC,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/devTools/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Schema as S } from 'effect';
|
|
2
2
|
import { ts } from '../schema/index.js';
|
|
3
3
|
// SHARED
|
|
4
|
-
/** A serialized history entry as it appears on the wire. `submodelPath` lists `Got<Child>Message` wrapper tags from outer to inner when the entry came up through a Submodel chain; `maybeLeafTag` is `Some` with the innermost child Message tag when one exists. */
|
|
4
|
+
/** A serialized history entry as it appears on the wire. `submodelPath` lists `Got<Child>Message` wrapper tags from outer to inner when the entry came up through a Submodel chain; `maybeLeafTag` is `Some` with the innermost child Message tag when one exists. `mountStartNames` lists Mounts that fired during the render after this Message; `mountEndNames` lists Mounts whose elements were unmounted during that render. The Messages dispatched by mount Effects appear as their own entries elsewhere in history. */
|
|
5
5
|
export const SerializedEntry = S.Struct({
|
|
6
6
|
index: S.Number,
|
|
7
7
|
tag: S.String,
|
|
8
8
|
message: S.Unknown,
|
|
9
9
|
commandNames: S.Array(S.String),
|
|
10
|
+
mountStartNames: S.Array(S.String),
|
|
11
|
+
mountEndNames: S.Array(S.String),
|
|
10
12
|
timestamp: S.Number,
|
|
11
13
|
isModelChanged: S.Boolean,
|
|
12
14
|
changedPaths: S.Array(S.String),
|
|
@@ -111,10 +113,11 @@ export const ResponseDispatched = ts('ResponseDispatched', {
|
|
|
111
113
|
export const ResponseRuntimes = ts('ResponseRuntimes', {
|
|
112
114
|
runtimes: S.Array(RuntimeInfo),
|
|
113
115
|
});
|
|
114
|
-
/** Response carrying the recorded init data. `maybeModel` is `None` until the runtime has finished its first render and recorded init; once set it stays set for the rest of the runtime's life. `commandNames` lists the Commands returned from the application's `init` function in the order they were produced. */
|
|
116
|
+
/** Response carrying the recorded init data. `maybeModel` is `None` until the runtime has finished its first render and recorded init; once set it stays set for the rest of the runtime's life. `commandNames` lists the Commands returned from the application's `init` function in the order they were produced. `mountStartNames` lists the Mounts that fired during the initial render. */
|
|
115
117
|
export const ResponseInit = ts('ResponseInit', {
|
|
116
118
|
maybeModel: S.OptionFromNullOr(S.Unknown),
|
|
117
119
|
commandNames: S.Array(S.String),
|
|
120
|
+
mountStartNames: S.Array(S.String),
|
|
118
121
|
});
|
|
119
122
|
/** Response carrying a snapshot of the runtime's DevTools state. `currentIndex` is the absolute index of the most recently recorded Message, or -1 when no Messages have been recorded yet. `startIndex` is the earliest absolute index still retained in the rolling buffer (older entries are evicted past `maxEntries`). `totalEntries` is the number of retained entries. `isPaused` is true while the runtime is paused at a replayed snapshot; `maybePausedAtIndex` is `Some(index)` then and `None` otherwise. `hasInitModel` is true once the runtime has finished initialising. */
|
|
120
123
|
export const ResponseRuntimeState = ts('ResponseRuntimeState', {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/devTools/serialize.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAwB9C;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,OAUnD,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,YAAY,EACnB,OAAO,MAAM,KACZ,
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/devTools/serialize.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAwB9C;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,OAUnD,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,YAAY,EACnB,OAAO,MAAM,KACZ,eAoBF,CAAA"}
|
|
@@ -52,6 +52,8 @@ export const toSerializedEntry = (entry, index) => {
|
|
|
52
52
|
tag: entry.tag,
|
|
53
53
|
message: toInspectableValue(entry.message),
|
|
54
54
|
commandNames: entry.commandNames,
|
|
55
|
+
mountStartNames: entry.mountStartNames,
|
|
56
|
+
mountEndNames: entry.mountEndNames,
|
|
55
57
|
timestamp: entry.timestamp,
|
|
56
58
|
isModelChanged: entry.isModelChanged,
|
|
57
59
|
changedPaths: Array_.fromIterable(entry.diff.changedPaths),
|
package/dist/devTools/store.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export type HistoryEntry = Readonly<{
|
|
|
10
10
|
tag: string;
|
|
11
11
|
message: unknown;
|
|
12
12
|
commandNames: ReadonlyArray<string>;
|
|
13
|
+
mountStartNames: ReadonlyArray<string>;
|
|
14
|
+
mountEndNames: ReadonlyArray<string>;
|
|
13
15
|
timestamp: number;
|
|
14
16
|
isModelChanged: boolean;
|
|
15
17
|
diff: DiffResult;
|
|
@@ -19,6 +21,7 @@ export type StoreState = Readonly<{
|
|
|
19
21
|
keyframes: HashMap.HashMap<number, unknown>;
|
|
20
22
|
maybeInitModel: Option.Option<unknown>;
|
|
21
23
|
initCommandNames: ReadonlyArray<string>;
|
|
24
|
+
initMountStartNames: ReadonlyArray<string>;
|
|
22
25
|
startIndex: number;
|
|
23
26
|
isPaused: boolean;
|
|
24
27
|
pausedAtIndex: number;
|
|
@@ -31,10 +34,11 @@ export type Bridge = Readonly<{
|
|
|
31
34
|
}>;
|
|
32
35
|
export declare const createDevToolsStore: (bridge: Bridge, maxEntries?: number) => Effect.Effect<DevToolsStore>;
|
|
33
36
|
export type DevToolsStore = Readonly<{
|
|
34
|
-
recordInit: (model: unknown, commandNames: ReadonlyArray<string>) => Effect.Effect<void>;
|
|
37
|
+
recordInit: (model: unknown, commandNames: ReadonlyArray<string>, mountStartNames?: ReadonlyArray<string>) => Effect.Effect<void>;
|
|
35
38
|
recordMessage: (message: Readonly<{
|
|
36
39
|
_tag: string;
|
|
37
40
|
}>, modelBeforeUpdate: unknown, modelAfterUpdate: unknown, commandNames: ReadonlyArray<string>, isModelChanged: boolean) => Effect.Effect<void>;
|
|
41
|
+
attachRenderedMounts: (mountStartNames: ReadonlyArray<string>, mountEndNames: ReadonlyArray<string>) => Effect.Effect<void>;
|
|
38
42
|
getModelAtIndex: (index: number) => Effect.Effect<unknown>;
|
|
39
43
|
getMessageAtIndex: (index: number) => Effect.Effect<Option.Option<unknown>>;
|
|
40
44
|
getDiffAtIndex: (index: number) => Effect.Effect<DiffResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/devTools/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,MAAM,EACN,OAAO,EACP,OAAO,EAEP,MAAM,EAIN,eAAe,EAEhB,MAAM,QAAQ,CAAA;AAEf,eAAO,MAAM,UAAU,KAAK,CAAA;AAM5B,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IACrC,aAAa,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;CACvC,CAAC,CAAA;AAEF,eAAO,MAAM,SAAS,EAAE,UAGvB,CAAA;AAID,eAAO,MAAM,WAAW,GACtB,UAAU,OAAO,EACjB,SAAS,OAAO,KACf,UA6EF,CAAA;AAID,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAClC,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,OAAO,CAAA;IACvB,IAAI,EAAE,UAAU,CAAA;CACjB,CAAC,CAAA;AAEF,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,CAAA;IACpC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACtC,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;CACzC,CAAC,CAAA;AAEF,MAAM,MAAM,MAAM,GAAG,QAAQ,CAAC;IAC5B,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;IACrD,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC/C,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;CACxC,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/devTools/store.ts"],"names":[],"mappings":"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"}
|
package/dist/devTools/store.js
CHANGED
|
@@ -68,6 +68,7 @@ const emptyState = {
|
|
|
68
68
|
keyframes: HashMap.empty(),
|
|
69
69
|
maybeInitModel: Option.none(),
|
|
70
70
|
initCommandNames: [],
|
|
71
|
+
initMountStartNames: [],
|
|
71
72
|
startIndex: 0,
|
|
72
73
|
isPaused: false,
|
|
73
74
|
pausedAtIndex: 0,
|
|
@@ -97,10 +98,11 @@ export const createDevToolsStore = (bridge, maxEntries = DEFAULT_MAX_ENTRIES) =>
|
|
|
97
98
|
isPaused: state.isPaused && isPausedAtRetainedIndex,
|
|
98
99
|
};
|
|
99
100
|
};
|
|
100
|
-
const recordInit = (model, commandNames) => SubscriptionRef.update(stateRef, state => ({
|
|
101
|
+
const recordInit = (model, commandNames, mountStartNames = []) => SubscriptionRef.update(stateRef, state => ({
|
|
101
102
|
...state,
|
|
102
103
|
maybeInitModel: Option.some(model),
|
|
103
104
|
initCommandNames: commandNames,
|
|
105
|
+
initMountStartNames: mountStartNames,
|
|
104
106
|
keyframes: HashMap.set(state.keyframes, 0, model),
|
|
105
107
|
maybeLatestModel: Option.some(model),
|
|
106
108
|
}));
|
|
@@ -116,6 +118,8 @@ export const createDevToolsStore = (bridge, maxEntries = DEFAULT_MAX_ENTRIES) =>
|
|
|
116
118
|
tag: message._tag,
|
|
117
119
|
message,
|
|
118
120
|
commandNames,
|
|
121
|
+
mountStartNames: [],
|
|
122
|
+
mountEndNames: [],
|
|
119
123
|
timestamp: performance.now(),
|
|
120
124
|
isModelChanged: hasChangedFields,
|
|
121
125
|
diff,
|
|
@@ -127,6 +131,36 @@ export const createDevToolsStore = (bridge, maxEntries = DEFAULT_MAX_ENTRIES) =>
|
|
|
127
131
|
? evictOldestSegment(nextState)
|
|
128
132
|
: nextState;
|
|
129
133
|
});
|
|
134
|
+
/** Attaches Mount lifecycle events from the most recent render to the
|
|
135
|
+
* history entry that triggered the render. Mount events fire during
|
|
136
|
+
* snabbdom's `patch` (inside `render`), but the runtime's render loop
|
|
137
|
+
* is gated by `requestAnimationFrame`, so a render may fire after the
|
|
138
|
+
* Message that dirtied it has already been recorded. The runtime drains
|
|
139
|
+
* its mount buffer after each render and calls this to associate the
|
|
140
|
+
* events with the correct entry. When called before any Message has been
|
|
141
|
+
* recorded (only possible from the init render path), the starts attach
|
|
142
|
+
* to `initMountStartNames`; init has no `ends` because nothing existed
|
|
143
|
+
* to unmount. */
|
|
144
|
+
const attachRenderedMounts = (mountStartNames, mountEndNames) => SubscriptionRef.update(stateRef, state => {
|
|
145
|
+
if (Array.isReadonlyArrayEmpty(mountStartNames) &&
|
|
146
|
+
Array.isReadonlyArrayEmpty(mountEndNames)) {
|
|
147
|
+
return state;
|
|
148
|
+
}
|
|
149
|
+
return Array.match(state.entries, {
|
|
150
|
+
onEmpty: () => ({
|
|
151
|
+
...state,
|
|
152
|
+
initMountStartNames: Array.appendAll(state.initMountStartNames, mountStartNames),
|
|
153
|
+
}),
|
|
154
|
+
onNonEmpty: entries => ({
|
|
155
|
+
...state,
|
|
156
|
+
entries: Array.modifyLastNonEmpty(entries, (last) => ({
|
|
157
|
+
...last,
|
|
158
|
+
mountStartNames: Array.appendAll(last.mountStartNames, mountStartNames),
|
|
159
|
+
mountEndNames: Array.appendAll(last.mountEndNames, mountEndNames),
|
|
160
|
+
})),
|
|
161
|
+
}),
|
|
162
|
+
});
|
|
163
|
+
});
|
|
130
164
|
const latestEntryIndex = (state) => Array.match(state.entries, {
|
|
131
165
|
onEmpty: () => INIT_INDEX,
|
|
132
166
|
onNonEmpty: entries => state.startIndex + entries.length - 1,
|
|
@@ -164,6 +198,7 @@ export const createDevToolsStore = (bridge, maxEntries = DEFAULT_MAX_ENTRIES) =>
|
|
|
164
198
|
...emptyState,
|
|
165
199
|
maybeInitModel: state.maybeInitModel,
|
|
166
200
|
initCommandNames: state.initCommandNames,
|
|
201
|
+
initMountStartNames: state.initMountStartNames,
|
|
167
202
|
keyframes: Option.match(state.maybeInitModel, {
|
|
168
203
|
onNone: () => HashMap.empty(),
|
|
169
204
|
onSome: model => HashMap.set(HashMap.empty(), 0, model),
|
|
@@ -183,6 +218,7 @@ export const createDevToolsStore = (bridge, maxEntries = DEFAULT_MAX_ENTRIES) =>
|
|
|
183
218
|
return {
|
|
184
219
|
recordInit,
|
|
185
220
|
recordMessage,
|
|
221
|
+
attachRenderedMounts,
|
|
186
222
|
getModelAtIndex,
|
|
187
223
|
getMessageAtIndex,
|
|
188
224
|
getDiffAtIndex,
|
|
@@ -169,6 +169,7 @@ const dispatchRequest = (store, dispatch, maybeMessageSchema, request) => Match.
|
|
|
169
169
|
return ResponseInit({
|
|
170
170
|
maybeModel: Option.map(state.maybeInitModel, toInspectableValue),
|
|
171
171
|
commandNames: state.initCommandNames,
|
|
172
|
+
mountStartNames: state.initMountStartNames,
|
|
172
173
|
});
|
|
173
174
|
}),
|
|
174
175
|
RequestGetRuntimeState: () => Effect.gen(function* () {
|
package/dist/html/index.d.ts
CHANGED
|
@@ -48,6 +48,17 @@ export type MountResult<Message> = Readonly<{
|
|
|
48
48
|
message: Message;
|
|
49
49
|
cleanup: () => void;
|
|
50
50
|
}>;
|
|
51
|
+
/** Key under which the OnMount attribute stamps a `{ name }` marker on the
|
|
52
|
+
* snabbdom `VNodeData`. Snabbdom passes unknown data fields through without
|
|
53
|
+
* rendering them to the DOM, so the marker is invisible at runtime but
|
|
54
|
+
* observable by VNode walkers (Scene tests). */
|
|
55
|
+
export declare const FOLDKIT_MOUNT_KEY: "foldkitMount";
|
|
56
|
+
/** Marker stamped on `VNodeData[FOLDKIT_MOUNT_KEY]` for any element with an
|
|
57
|
+
* `OnMount` attribute. Carries the Mount Definition's name so test
|
|
58
|
+
* introspection can identify pending mounts. */
|
|
59
|
+
export type FoldkitMountMarker = Readonly<{
|
|
60
|
+
name: string;
|
|
61
|
+
}>;
|
|
51
62
|
/** Union of all HTML, SVG, and MathML attributes a virtual DOM element can carry. */
|
|
52
63
|
export type Attribute<Message> = Data.TaggedEnum<{
|
|
53
64
|
Key: {
|