foldkit 0.35.2 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -156,7 +156,7 @@ This is what makes Foldkit unusually AI-friendly. The same property that makes t
156
156
  - **[Counter](https://github.com/foldkit/foldkit/blob/main/examples/counter/src/main.ts)** — Increment/decrement with reset
157
157
  - **[Todo](https://github.com/foldkit/foldkit/blob/main/examples/todo/src/main.ts)** — CRUD operations with localStorage persistence
158
158
  - **[Stopwatch](https://github.com/foldkit/foldkit/blob/main/examples/stopwatch/src/main.ts)** — Timer with start/stop/reset
159
- - **[Error View](https://github.com/foldkit/foldkit/blob/main/examples/error-view/src/main.ts)** — Custom error fallback UI
159
+ - **[Crash View](https://github.com/foldkit/foldkit/blob/main/examples/crash-view/src/main.ts)** — Custom crash fallback UI with crash reporting
160
160
  - **[Form](https://github.com/foldkit/foldkit/blob/main/examples/form/src/main.ts)** — Form validation with async email checking
161
161
  - **[Weather](https://github.com/foldkit/foldkit/blob/main/examples/weather/src/main.ts)** — HTTP requests with async state handling
162
162
  - **[Routing](https://github.com/foldkit/foldkit/blob/main/examples/routing/src/main.ts)** — URL routing with parser combinators
@@ -729,7 +729,7 @@ export const createOverlay = (store, position, mode, maybeBanner) => Effect.gen(
729
729
  view: makeView(position, mode, maybeBanner),
730
730
  container,
731
731
  subscriptions: makeOverlaySubscriptions(store),
732
- devtools: { show: 'Never' },
732
+ devtools: false,
733
733
  });
734
734
  yield* Effect.forkDaemon(overlayRuntime());
735
735
  });
@@ -4,5 +4,7 @@ export declare const noOpDispatch: {
4
4
  dispatchAsync: (_message: unknown) => Effect.Effect<void, never, never>;
5
5
  dispatchSync: (_message: unknown) => void;
6
6
  };
7
- export declare const defaultErrorView: (error: Error, viewError?: unknown) => Html;
8
- //# sourceMappingURL=errorUI.d.ts.map
7
+ export declare const defaultCrashView: (context: Readonly<{
8
+ error: Error;
9
+ }>, viewError?: unknown) => Html;
10
+ //# sourceMappingURL=crashUI.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crashUI.d.ts","sourceRoot":"","sources":["../../src/runtime/crashUI.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,EAAE,IAAI,EAAQ,MAAM,SAAS,CAAA;AAEpC,eAAO,MAAM,YAAY;8BACG,OAAO;6BACR,OAAO;CACjC,CAAA;AAmBD,eAAO,MAAM,gBAAgB,GAC3B,SAAS,QAAQ,CAAC;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC,EACnC,YAAY,OAAO,KAClB,IA4LF,CAAA"}
@@ -17,7 +17,7 @@ const colors = {
17
17
  };
18
18
  const fontStack = 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
19
19
  const monoStack = 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace';
20
- export const defaultErrorView = (error, viewError) => {
20
+ export const defaultCrashView = (context, viewError) => {
21
21
  const { div, h1, p, span, button, Style, Attribute } = html();
22
22
  const codeBlockStyle = Style({
23
23
  fontFamily: monoStack,
@@ -45,7 +45,7 @@ export const defaultErrorView = (error, viewError) => {
45
45
  const introText = viewError
46
46
  ? [
47
47
  'Your custom ',
48
- span([inlineCodeStyle], ['errorView']),
48
+ span([inlineCodeStyle], ['crash.view']),
49
49
  ' threw an error while rendering.',
50
50
  ]
51
51
  : [
@@ -55,10 +55,10 @@ export const defaultErrorView = (error, viewError) => {
55
55
  ? [
56
56
  div([Style({ margin: '0 0 1rem 0' })], [
57
57
  p([labelStyle], ['Original error']),
58
- p([codeBlockStyle], [error.message]),
58
+ p([codeBlockStyle], [context.error.message]),
59
59
  ]),
60
60
  div([Style({ margin: '0 0 1.25rem 0' })], [
61
- p([labelStyle], ['errorView error']),
61
+ p([labelStyle], ['crash.view error']),
62
62
  p([codeBlockStyle], [viewErrorMessage]),
63
63
  ]),
64
64
  ]
@@ -74,7 +74,7 @@ export const defaultErrorView = (error, viewError) => {
74
74
  padding: '0.75rem 1rem',
75
75
  borderRadius: '0.375rem',
76
76
  }),
77
- ], [error.message]),
77
+ ], [context.error.message]),
78
78
  ];
79
79
  const footerText = viewError
80
80
  ? []
@@ -89,8 +89,8 @@ export const defaultErrorView = (error, viewError) => {
89
89
  paddingTop: '1rem',
90
90
  }),
91
91
  ], [
92
- 'This is the default error view. You can customize it by providing an ',
93
- span([inlineCodeStyle], ['errorView']),
92
+ 'This is the default crash view. You can customize it by providing a ',
93
+ span([inlineCodeStyle], ['crash.view']),
94
94
  ' function to ',
95
95
  span([inlineCodeStyle], ['makeElement']),
96
96
  ' or ',
@@ -129,7 +129,7 @@ export const defaultErrorView = (error, viewError) => {
129
129
  fontWeight: '600',
130
130
  lineHeight: '1.5',
131
131
  }),
132
- ], ['Runtime Error']),
132
+ ], ['Application Crash']),
133
133
  p([
134
134
  Style({
135
135
  color: colors.textPrimary,
@@ -1,5 +1,5 @@
1
1
  export { makeElement, makeApplication, run } from './runtime';
2
- export type { BrowserConfig, ElementConfigWithFlags, ElementConfigWithoutFlags, ApplicationConfigWithFlags, ApplicationConfigWithoutFlags, ElementInit, ApplicationInit, MakeRuntimeReturn, } from './runtime';
2
+ export type { BrowserConfig, CrashConfig, CrashContext, ElementConfigWithFlags, ElementConfigWithoutFlags, ApplicationConfigWithFlags, ApplicationConfigWithoutFlags, ElementInit, ApplicationInit, MakeRuntimeReturn, Visibility, SlowViewContext, SlowViewConfig, DevtoolsConfig, } from './runtime';
3
3
  export { UrlRequest } from './urlRequest';
4
4
  export type { Internal, External } from './urlRequest';
5
5
  //# sourceMappingURL=public.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/runtime/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAE7D,YAAY,EACV,aAAa,EACb,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,WAAW,EACX,eAAe,EACf,iBAAiB,GAClB,MAAM,WAAW,CAAA;AAElB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/runtime/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAE7D,YAAY,EACV,aAAa,EACb,WAAW,EACX,YAAY,EACZ,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,cAAc,EACd,cAAc,GACf,MAAM,WAAW,CAAA;AAElB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA"}
@@ -1,4 +1,4 @@
1
- import { Context, Effect, Layer, Schema } from 'effect';
1
+ import { Context, Effect, Layer, Option, Schema } from 'effect';
2
2
  import type { Command } from '../command';
3
3
  import { Html } from '../html';
4
4
  import { Url } from '../url';
@@ -7,8 +7,8 @@ import type { Subscriptions } from './subscription';
7
7
  import { UrlRequest } from './urlRequest';
8
8
  /** Position of the devtools badge and panel on screen. */
9
9
  export type DevtoolsPosition = 'BottomRight' | 'BottomLeft' | 'TopRight' | 'TopLeft';
10
- /** Controls when devtools are shown. */
11
- export type DevtoolsShow = 'Never' | 'Development' | 'Always';
10
+ /** Controls when a feature is shown. */
11
+ export type Visibility = 'Development' | 'Always';
12
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.
@@ -18,17 +18,40 @@ export type DevtoolsMode = 'Inspect' | 'TimeTravel';
18
18
  /**
19
19
  * Devtools configuration.
20
20
  *
21
- * - `show`: `'Never'` disables devtools entirely, `'Development'` (default) enables in dev mode only, `'Always'` enables in all environments including production.
21
+ * Pass `false` to disable devtools entirely.
22
+ *
23
+ * - `show`: `'Development'` (default) enables in dev mode only, `'Always'` enables in all environments including production.
22
24
  * - `position`: Where the badge and panel appear. Defaults to `'BottomRight'`.
23
25
  * - `mode`: `'TimeTravel'` (default) enables full time-travel debugging. `'Inspect'` allows browsing state snapshots without pausing the app.
24
26
  * - `banner`: Optional text shown as a banner at the top of the panel.
25
27
  */
26
- export type DevtoolsConfig = Readonly<{
27
- show?: DevtoolsShow;
28
+ export type DevtoolsConfig = false | Readonly<{
29
+ show?: Visibility;
28
30
  position?: DevtoolsPosition;
29
31
  mode?: DevtoolsMode;
30
32
  banner?: string;
31
33
  }>;
34
+ /** Context provided to the slow view callback when a view exceeds the time budget. */
35
+ export type SlowViewContext<Model, Message> = Readonly<{
36
+ model: Model;
37
+ message: Option.Option<Message>;
38
+ durationMs: number;
39
+ thresholdMs: number;
40
+ }>;
41
+ /**
42
+ * Slow view warning configuration.
43
+ *
44
+ * Pass `false` to disable warnings entirely.
45
+ *
46
+ * - `show`: `'Development'` (default) enables in dev mode only, `'Always'` enables in all environments.
47
+ * - `thresholdMs`: Duration in ms above which a view is considered slow. Defaults to 16 (one frame at 60fps).
48
+ * - `onSlowView`: Custom callback invoked when a slow view is detected. Defaults to `console.warn`.
49
+ */
50
+ export type SlowViewConfig<Model, Message> = false | Readonly<{
51
+ show?: Visibility;
52
+ thresholdMs?: number;
53
+ onSlowView?: (context: SlowViewContext<Model, Message>) => void;
54
+ }>;
32
55
  declare const Dispatch_base: Context.TagClass<Dispatch, "@foldkit/Dispatch", {
33
56
  readonly dispatchAsync: (message: unknown) => Effect.Effect<void>;
34
57
  readonly dispatchSync: (message: unknown) => void;
@@ -42,6 +65,17 @@ export type BrowserConfig<Message> = Readonly<{
42
65
  onUrlRequest: (request: UrlRequest) => Message;
43
66
  onUrlChange: (url: Url) => Message;
44
67
  }>;
68
+ /** Context provided to crash.view and crash.report when the runtime encounters an unrecoverable error. */
69
+ export type CrashContext<Model, Message> = Readonly<{
70
+ error: Error;
71
+ model: Model;
72
+ message: Message;
73
+ }>;
74
+ /** Configuration for crash handling — custom crash UI and/or crash reporting. */
75
+ export type CrashConfig<Model, Message> = Readonly<{
76
+ view?: (context: CrashContext<Model, Message>) => Html;
77
+ report?: (context: CrashContext<Model, Message>) => void;
78
+ }>;
45
79
  type BaseElementConfig<Model, Message, StreamDepsMap extends Schema.Struct<Schema.Struct.Fields>, Resources = never, ManagedResourceServices = never> = Readonly<{
46
80
  Model: Schema.Schema<Model, any, never>;
47
81
  update: (model: Model, message: Message) => [
@@ -51,8 +85,8 @@ type BaseElementConfig<Model, Message, StreamDepsMap extends Schema.Struct<Schem
51
85
  view: (model: Model) => Html;
52
86
  subscriptions?: Subscriptions<Model, Message, StreamDepsMap, Resources | ManagedResourceServices>;
53
87
  container: HTMLElement;
54
- errorView?: (error: Error) => Html;
55
- slowViewThresholdMs?: number | false;
88
+ crash?: CrashConfig<Model, Message>;
89
+ slowView?: SlowViewConfig<Model, Message>;
56
90
  resources?: Layer.Layer<Resources>;
57
91
  managedResources?: ManagedResources<Model, Message, ManagedResourceServices>;
58
92
  devtools?: DevtoolsConfig;
@@ -83,8 +117,8 @@ type BaseApplicationConfig<Model, Message, StreamDepsMap extends Schema.Struct<S
83
117
  subscriptions?: Subscriptions<Model, Message, StreamDepsMap, Resources | ManagedResourceServices>;
84
118
  container: HTMLElement;
85
119
  browser: BrowserConfig<Message>;
86
- errorView?: (error: Error) => Html;
87
- slowViewThresholdMs?: number | false;
120
+ crash?: CrashConfig<Model, Message>;
121
+ slowView?: SlowViewConfig<Model, Message>;
88
122
  resources?: Layer.Layer<Resources>;
89
123
  managedResources?: ManagedResources<Model, Message, ManagedResourceServices>;
90
124
  devtools?: DevtoolsConfig;
@@ -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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"}
@@ -6,208 +6,243 @@ import { createDevtoolsStore } from '../devtools/store';
6
6
  import { fromString as urlFromString } from '../url';
7
7
  import { patch, toVNode } from '../vdom';
8
8
  import { addBfcacheRestoreListener, addNavigationEventListeners, } from './browserListeners';
9
- import { defaultErrorView, noOpDispatch } from './errorUI';
10
- const SLOW_VIEW_THRESHOLD_MS = 16;
9
+ import { defaultCrashView, noOpDispatch } from './crashUI';
11
10
  const DEFAULT_DEVTOOLS_SHOW = 'Development';
12
11
  const DEFAULT_DEVTOOLS_POSITION = 'BottomRight';
13
12
  const DEFAULT_DEVTOOLS_MODE = 'TimeTravel';
13
+ const DEFAULT_SLOW_VIEW_SHOW = 'Development';
14
+ const DEFAULT_SLOW_VIEW_THRESHOLD_MS = 16;
15
+ const defaultSlowViewCallback = (context) => {
16
+ const trigger = Option.match(context.message, {
17
+ onNone: () => 'init',
18
+ onSome: message => {
19
+ const tag = Predicate.isRecord(message) && '_tag' in message
20
+ ? String(message['_tag'])
21
+ : 'unknown';
22
+ return tag;
23
+ },
24
+ });
25
+ console.warn(`[foldkit] Slow view: ${context.durationMs.toFixed(1)}ms (budget: ${context.thresholdMs}ms), triggered by ${trigger}. Consider moving computation to update or memoizing with createLazy.`, ...Option.toArray(context.message));
26
+ };
14
27
  /** Effect service tag that provides message dispatching to the view layer. */
15
28
  export class Dispatch extends Context.Tag('@foldkit/Dispatch')() {
16
29
  }
17
- const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscriptions, container, browser: browserConfig, errorView, slowViewThresholdMs = SLOW_VIEW_THRESHOLD_MS, resources, managedResources, devtools, }) => (hmrModel) => Effect.scoped(Effect.gen(function* () {
18
- const maybeResourceLayer = resources
19
- ? Option.some(yield* Layer.memoize(resources))
20
- : Option.none();
21
- const managedResourceEntries = managedResources
22
- ? /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
23
- Record.toEntries(managedResources)
24
- : [];
25
- const managedResourceRefs = yield* Effect.forEach(managedResourceEntries, ([_key, config]) => Ref.make(Option.none()).pipe(Effect.map(ref => ({ config, ref }))));
26
- const mergeResourceIntoLayer = (layer, { config, ref }) => Layer.merge(layer, Layer.succeed(
27
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
28
- config.resource._tag, ref));
29
- const maybeManagedResourceLayer = Array.match(managedResourceRefs, {
30
- onEmpty: () => Option.none(),
31
- onNonEmpty: refs => Option.some(Array.reduce(refs,
30
+ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscriptions, container, browser: browserConfig, crash, slowView, resources, managedResources, devtools, }) => {
31
+ 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 => ({
32
+ thresholdMs: config.thresholdMs ?? DEFAULT_SLOW_VIEW_THRESHOLD_MS,
33
+ onSlowView: config.onSlowView ?? defaultSlowViewCallback,
34
+ })));
35
+ return (hmrModel) => Effect.scoped(Effect.gen(function* () {
36
+ const maybeResourceLayer = resources
37
+ ? Option.some(yield* Layer.memoize(resources))
38
+ : Option.none();
39
+ const managedResourceEntries = managedResources
40
+ ? /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
41
+ Record.toEntries(managedResources)
42
+ : [];
43
+ const managedResourceRefs = yield* Effect.forEach(managedResourceEntries, ([_key, config]) => Ref.make(Option.none()).pipe(Effect.map(ref => ({ config, ref }))));
44
+ const mergeResourceIntoLayer = (layer, { config, ref }) => Layer.merge(layer, Layer.succeed(
32
45
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
33
- Layer.empty, mergeResourceIntoLayer)),
34
- });
35
- const provideAllResources = (effect) => {
36
- const withResources = Option.match(maybeResourceLayer, {
37
- onNone: () => effect,
38
- onSome: resourceLayer => Effect.provide(effect, resourceLayer),
39
- });
40
- return Option.match(maybeManagedResourceLayer, {
41
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
42
- onNone: () => withResources,
43
- onSome: managedLayer =>
46
+ config.resource._tag, ref));
47
+ const maybeManagedResourceLayer = Array.match(managedResourceRefs, {
48
+ onEmpty: () => Option.none(),
49
+ onNonEmpty: refs => Option.some(Array.reduce(refs,
44
50
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
45
- Effect.provide(withResources, managedLayer),
51
+ Layer.empty, mergeResourceIntoLayer)),
46
52
  });
47
- };
48
- const flags = yield* resolveFlags;
49
- const modelEquivalence = Schema.equivalence(Model);
50
- const messageQueue = yield* Queue.unbounded();
51
- const enqueueMessage = (message) => Queue.offer(messageQueue, message);
52
- const currentUrl = Option.fromNullable(browserConfig).pipe(Option.flatMap(() => urlFromString(window.location.href)));
53
- const [initModel, initCommands] = Predicate.isNotUndefined(hmrModel)
54
- ? pipe(hmrModel, Schema.decodeUnknownEither(Model), Either.match({
55
- onLeft: () => init(flags, Option.getOrUndefined(currentUrl)),
56
- onRight: restoredModel => [restoredModel, []],
57
- }))
58
- : init(flags, Option.getOrUndefined(currentUrl));
59
- const modelSubscriptionRef = yield* SubscriptionRef.make(initModel);
60
- yield* Effect.forEach(initCommands, command => Effect.forkDaemon(command.pipe(provideAllResources, Effect.flatMap(enqueueMessage))));
61
- if (browserConfig) {
62
- addNavigationEventListeners(messageQueue, browserConfig);
63
- }
64
- const modelRef = yield* Ref.make(initModel);
65
- const maybeCurrentVNodeRef = yield* Ref.make(Option.none());
66
- const maybeRuntimeRef = yield* Ref.make(Option.none());
67
- const maybeDevtoolsStoreRef = yield* Ref.make(Option.none());
68
- const processMessage = (message) => Effect.gen(function* () {
69
- const currentModel = yield* Ref.get(modelRef);
70
- const [nextModel, commands] = update(currentModel, message);
71
- if (currentModel !== nextModel) {
72
- yield* Ref.set(modelRef, nextModel);
73
- const isPaused = yield* pipe(maybeDevtoolsStoreRef, Ref.get, Effect.flatMap(Option.match({
74
- onNone: () => Effect.succeed(false),
75
- onSome: ({ stateRef }) => SubscriptionRef.get(stateRef).pipe(Effect.map(({ isPaused }) => isPaused)),
76
- })));
77
- if (!isPaused) {
78
- yield* render(nextModel);
79
- }
80
- if (!modelEquivalence(currentModel, nextModel)) {
81
- yield* SubscriptionRef.set(modelSubscriptionRef, nextModel);
82
- preserveModel(nextModel);
83
- }
53
+ const provideAllResources = (effect) => {
54
+ const withResources = Option.match(maybeResourceLayer, {
55
+ onNone: () => effect,
56
+ onSome: resourceLayer => Effect.provide(effect, resourceLayer),
57
+ });
58
+ return Option.match(maybeManagedResourceLayer, {
59
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
60
+ onNone: () => withResources,
61
+ onSome: managedLayer =>
62
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
63
+ Effect.provide(withResources, managedLayer),
64
+ });
65
+ };
66
+ const flags = yield* resolveFlags;
67
+ const modelEquivalence = Schema.equivalence(Model);
68
+ const messageQueue = yield* Queue.unbounded();
69
+ const enqueueMessage = (message) => Queue.offer(messageQueue, message);
70
+ const currentUrl = Option.fromNullable(browserConfig).pipe(Option.flatMap(() => urlFromString(window.location.href)));
71
+ const [initModel, initCommands] = Predicate.isNotUndefined(hmrModel)
72
+ ? pipe(hmrModel, Schema.decodeUnknownEither(Model), Either.match({
73
+ onLeft: () => init(flags, Option.getOrUndefined(currentUrl)),
74
+ onRight: restoredModel => [restoredModel, []],
75
+ }))
76
+ : init(flags, Option.getOrUndefined(currentUrl));
77
+ const modelSubscriptionRef = yield* SubscriptionRef.make(initModel);
78
+ yield* Effect.forEach(initCommands, command => Effect.forkDaemon(command.pipe(provideAllResources, Effect.flatMap(enqueueMessage))));
79
+ if (browserConfig) {
80
+ addNavigationEventListeners(messageQueue, browserConfig);
84
81
  }
85
- yield* Effect.forEach(commands, command => Effect.forkDaemon(command.pipe(provideAllResources, Effect.flatMap(enqueueMessage))));
86
- const maybeDevtoolsStore = yield* Ref.get(maybeDevtoolsStoreRef);
87
- yield* Option.match(maybeDevtoolsStore, {
88
- onNone: () => Effect.void,
89
- onSome: store => store.recordMessage(
90
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
91
- message, nextModel, commands.length, !modelEquivalence(currentModel, nextModel)),
82
+ const modelRef = yield* Ref.make(initModel);
83
+ const maybeCurrentVNodeRef = yield* Ref.make(Option.none());
84
+ const currentMessageRef = yield* Ref.make(Option.none());
85
+ const maybeRuntimeRef = yield* Ref.make(Option.none());
86
+ const maybeDevtoolsStoreRef = yield* Ref.make(Option.none());
87
+ const processMessage = (message) => Effect.gen(function* () {
88
+ const currentModel = yield* Ref.get(modelRef);
89
+ const [nextModel, commands] = update(currentModel, message);
90
+ if (currentModel !== nextModel) {
91
+ yield* Ref.set(modelRef, nextModel);
92
+ const isPaused = yield* pipe(maybeDevtoolsStoreRef, Ref.get, Effect.flatMap(Option.match({
93
+ onNone: () => Effect.succeed(false),
94
+ onSome: ({ stateRef }) => SubscriptionRef.get(stateRef).pipe(Effect.map(({ isPaused }) => isPaused)),
95
+ })));
96
+ if (!isPaused) {
97
+ yield* render(nextModel, Option.some(message));
98
+ }
99
+ if (!modelEquivalence(currentModel, nextModel)) {
100
+ yield* SubscriptionRef.set(modelSubscriptionRef, nextModel);
101
+ preserveModel(nextModel);
102
+ }
103
+ }
104
+ yield* Effect.forEach(commands, command => Effect.forkDaemon(command.pipe(provideAllResources, Effect.flatMap(enqueueMessage))));
105
+ const maybeDevtoolsStore = yield* Ref.get(maybeDevtoolsStoreRef);
106
+ yield* Option.match(maybeDevtoolsStore, {
107
+ onNone: () => Effect.void,
108
+ onSome: store => store.recordMessage(
109
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
110
+ message, nextModel, commands.length, !modelEquivalence(currentModel, nextModel)),
111
+ });
92
112
  });
93
- });
94
- const runProcessMessage = (messageEffect) => (runtime) => {
95
- try {
96
- Runtime.runSync(runtime)(messageEffect);
97
- }
98
- catch (error) {
99
- const squashed = Runtime.isFiberFailure(error)
100
- ? Cause.squash(error[Runtime.FiberFailureCauseId])
101
- : error;
102
- const appError = squashed instanceof Error
103
- ? squashed
104
- : new Error(String(squashed));
105
- renderErrorView(appError, errorView, container, maybeCurrentVNodeRef);
113
+ const runProcessMessage = (message, messageEffect) => (runtime) => {
114
+ try {
115
+ Runtime.runSync(runtime, messageEffect);
116
+ }
117
+ catch (error) {
118
+ const squashed = Runtime.isFiberFailure(error)
119
+ ? Cause.squash(error[Runtime.FiberFailureCauseId])
120
+ : error;
121
+ const appError = squashed instanceof Error
122
+ ? squashed
123
+ : new Error(String(squashed));
124
+ const model = Ref.get(modelRef).pipe(Effect.runSync);
125
+ renderCrashView({ error: appError, model, message }, crash, container, maybeCurrentVNodeRef);
126
+ }
127
+ };
128
+ const dispatchSync = (message) => {
129
+ const maybeRuntime = Ref.get(maybeRuntimeRef).pipe(Effect.runSync);
130
+ Option.match(maybeRuntime, {
131
+ onNone: Function.constVoid,
132
+ onSome: runProcessMessage(
133
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
134
+ message,
135
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
136
+ processMessage(message)),
137
+ });
138
+ };
139
+ const dispatchAsync = (message) =>
140
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
141
+ enqueueMessage(message);
142
+ const render = (model, message) => Effect.gen(function* () {
143
+ const viewStart = performance.now();
144
+ const nextVNodeNullish = yield* view(model);
145
+ const viewDuration = performance.now() - viewStart;
146
+ Option.match(resolvedSlowView, {
147
+ onNone: Function.constVoid,
148
+ onSome: ({ thresholdMs, onSlowView }) => {
149
+ if (viewDuration > thresholdMs) {
150
+ onSlowView({
151
+ model,
152
+ message,
153
+ durationMs: viewDuration,
154
+ thresholdMs,
155
+ });
156
+ }
157
+ },
158
+ });
159
+ const maybeCurrentVNode = yield* Ref.get(maybeCurrentVNodeRef);
160
+ const patchedVNode = yield* Effect.sync(() => patchVNode(maybeCurrentVNode, nextVNodeNullish, container));
161
+ yield* Ref.set(maybeCurrentVNodeRef, Option.some(patchedVNode));
162
+ }).pipe(Effect.provideService(Dispatch, {
163
+ dispatchAsync,
164
+ dispatchSync,
165
+ }));
166
+ const runtime = yield* Effect.runtime();
167
+ yield* Ref.set(maybeRuntimeRef, Option.some(runtime));
168
+ const isInIframe = window.self !== window.top;
169
+ 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 => ({
170
+ position: config.position ?? DEFAULT_DEVTOOLS_POSITION,
171
+ mode: config.mode ?? DEFAULT_DEVTOOLS_MODE,
172
+ maybeBanner: Option.fromNullable(config.banner),
173
+ })));
174
+ if (Option.isSome(resolvedDevtools)) {
175
+ const { position, mode, maybeBanner } = resolvedDevtools.value;
176
+ const devtoolsStore = yield* createDevtoolsStore({
177
+ replay: (model, message) =>
178
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
179
+ Tuple.getFirst(update(model, message)),
180
+ render: model =>
181
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
182
+ render(model, Option.none()),
183
+ getCurrentModel: Ref.get(modelRef),
184
+ });
185
+ yield* Ref.set(maybeDevtoolsStoreRef, Option.some(devtoolsStore));
186
+ yield* devtoolsStore.recordInit(initModel);
187
+ yield* createOverlay(devtoolsStore, position, mode, maybeBanner);
106
188
  }
107
- };
108
- const dispatchSync = (message) => {
109
- const maybeRuntime = Effect.runSync(Ref.get(maybeRuntimeRef));
110
- Option.match(maybeRuntime, {
111
- onNone: Function.constVoid,
112
- onSome: runProcessMessage(
113
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
114
- processMessage(message)),
115
- });
116
- };
117
- const dispatchAsync = (message) =>
118
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
119
- enqueueMessage(message);
120
- const render = (model) => Effect.gen(function* () {
121
- const viewStart = performance.now();
122
- const nextVNodeNullish = yield* view(model);
123
- const viewDuration = performance.now() - viewStart;
124
- if (import.meta.hot &&
125
- slowViewThresholdMs !== false &&
126
- viewDuration > slowViewThresholdMs) {
127
- console.warn(`[foldkit] Slow view: ${viewDuration.toFixed(1)}ms (budget: ${slowViewThresholdMs}ms). Consider moving computation to update or memoizing with createLazy.`);
189
+ yield* render(initModel, Option.none());
190
+ addBfcacheRestoreListener();
191
+ if (subscriptions) {
192
+ yield* pipe(subscriptions, Record.toEntries, Effect.forEach(([_key, { schema, modelToDependencies, depsToStream }]) => {
193
+ const modelStream = Stream.concat(Stream.make(initModel), modelSubscriptionRef.changes);
194
+ return Effect.forkDaemon(modelStream.pipe(Stream.map(modelToDependencies), Stream.changesWith(Schema.equivalence(schema)), Stream.flatMap(depsToStream, { switch: true }), Stream.runForEach(command => command.pipe(Effect.flatMap(enqueueMessage))), provideAllResources));
195
+ }, {
196
+ concurrency: 'unbounded',
197
+ discard: true,
198
+ }));
128
199
  }
129
- const maybeCurrentVNode = yield* Ref.get(maybeCurrentVNodeRef);
130
- const patchedVNode = yield* Effect.sync(() => patchVNode(maybeCurrentVNode, nextVNodeNullish, container));
131
- yield* Ref.set(maybeCurrentVNodeRef, Option.some(patchedVNode));
132
- }).pipe(Effect.provideService(Dispatch, {
133
- dispatchAsync,
134
- dispatchSync,
135
- }));
136
- const runtime = yield* Effect.runtime();
137
- yield* Ref.set(maybeRuntimeRef, Option.some(runtime));
138
- const show = devtools?.show ?? DEFAULT_DEVTOOLS_SHOW;
139
- const devtoolsPosition = devtools?.position ?? DEFAULT_DEVTOOLS_POSITION;
140
- const devtoolsMode = devtools?.mode ?? DEFAULT_DEVTOOLS_MODE;
141
- const maybeDevtoolsBanner = Option.fromNullable(devtools?.banner);
142
- const isInIframe = window.self !== window.top;
143
- const isDevtoolsEnabled = Match.value(show).pipe(Match.when('Never', () => false), Match.when('Always', () => true), Match.when('Development', () => !!import.meta.hot && !isInIframe), Match.exhaustive);
144
- if (isDevtoolsEnabled) {
145
- const devtoolsStore = yield* createDevtoolsStore({
146
- replay: (model, message) =>
147
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
148
- Tuple.getFirst(update(model, message)),
149
- render: model =>
150
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
151
- render(model),
152
- getCurrentModel: Ref.get(modelRef),
153
- });
154
- yield* Ref.set(maybeDevtoolsStoreRef, Option.some(devtoolsStore));
155
- yield* devtoolsStore.recordInit(initModel);
156
- yield* createOverlay(devtoolsStore, devtoolsPosition, devtoolsMode, maybeDevtoolsBanner);
157
- }
158
- yield* render(initModel);
159
- addBfcacheRestoreListener();
160
- if (subscriptions) {
161
- yield* pipe(subscriptions, Record.toEntries, Effect.forEach(([_key, { schema, modelToDependencies, depsToStream }]) => {
200
+ const maybeRequirementsToLifecycle = (config, resourceRef) => (maybeRequirements) => {
201
+ if (Option.isOption(maybeRequirements) &&
202
+ Option.isNone(maybeRequirements)) {
203
+ return Stream.empty;
204
+ }
205
+ const requirements = Option.isOption(maybeRequirements)
206
+ ? Option.getOrThrow(maybeRequirements)
207
+ : maybeRequirements;
208
+ const acquire = Effect.gen(function* () {
209
+ const value = yield* config.acquire(requirements);
210
+ yield* Ref.set(resourceRef, Option.some(value));
211
+ return value;
212
+ });
213
+ const release = (value) => Effect.gen(function* () {
214
+ yield* config.release(value);
215
+ yield* Ref.set(resourceRef, Option.none());
216
+ yield* enqueueMessage(config.onReleased());
217
+ }).pipe(Effect.catchAllCause(() => Effect.void));
218
+ return pipe(Stream.scoped(Effect.acquireRelease(acquire, release)), Stream.flatMap(value => Stream.concat(Stream.make(config.onAcquired(value)), Stream.never)), Stream.map(Effect.succeed), Stream.catchAll(error => Stream.make(Effect.succeed(config.onAcquireError(error)))));
219
+ };
220
+ const forkManagedResourceLifecycle = ({ config, ref: resourceRef, }) => Effect.gen(function* () {
162
221
  const modelStream = Stream.concat(Stream.make(initModel), modelSubscriptionRef.changes);
163
- return Effect.forkDaemon(modelStream.pipe(Stream.map(modelToDependencies), Stream.changesWith(Schema.equivalence(schema)), Stream.flatMap(depsToStream, { switch: true }), Stream.runForEach(command => command.pipe(Effect.flatMap(enqueueMessage))), provideAllResources));
164
- }, {
222
+ const equivalence = Schema.equivalence(config.schema);
223
+ yield* Effect.forkDaemon(modelStream.pipe(Stream.map(config.modelToMaybeRequirements), Stream.changesWith(equivalence), Stream.flatMap(maybeRequirementsToLifecycle(config, resourceRef), {
224
+ switch: true,
225
+ }), Stream.runForEach(Effect.flatMap(enqueueMessage))));
226
+ });
227
+ yield* Effect.forEach(managedResourceRefs, forkManagedResourceLifecycle, {
165
228
  concurrency: 'unbounded',
166
229
  discard: true,
167
- }));
168
- }
169
- const maybeRequirementsToLifecycle = (config, resourceRef) => (maybeRequirements) => {
170
- if (Option.isOption(maybeRequirements) &&
171
- Option.isNone(maybeRequirements)) {
172
- return Stream.empty;
173
- }
174
- const requirements = Option.isOption(maybeRequirements)
175
- ? Option.getOrThrow(maybeRequirements)
176
- : maybeRequirements;
177
- const acquire = Effect.gen(function* () {
178
- const value = yield* config.acquire(requirements);
179
- yield* Ref.set(resourceRef, Option.some(value));
180
- return value;
181
230
  });
182
- const release = (value) => Effect.gen(function* () {
183
- yield* config.release(value);
184
- yield* Ref.set(resourceRef, Option.none());
185
- yield* enqueueMessage(config.onReleased());
186
- }).pipe(Effect.catchAllCause(() => Effect.void));
187
- return pipe(Stream.scoped(Effect.acquireRelease(acquire, release)), Stream.flatMap(value => Stream.concat(Stream.make(config.onAcquired(value)), Stream.never)), Stream.map(Effect.succeed), Stream.catchAll(error => Stream.make(Effect.succeed(config.onAcquireError(error)))));
188
- };
189
- const forkManagedResourceLifecycle = ({ config, ref: resourceRef, }) => Effect.gen(function* () {
190
- const modelStream = Stream.concat(Stream.make(initModel), modelSubscriptionRef.changes);
191
- const equivalence = Schema.equivalence(config.schema);
192
- yield* Effect.forkDaemon(modelStream.pipe(Stream.map(config.modelToMaybeRequirements), Stream.changesWith(equivalence), Stream.flatMap(maybeRequirementsToLifecycle(config, resourceRef), {
193
- switch: true,
194
- }), Stream.runForEach(Effect.flatMap(enqueueMessage))));
195
- });
196
- yield* Effect.forEach(managedResourceRefs, forkManagedResourceLifecycle, {
197
- concurrency: 'unbounded',
198
- discard: true,
199
- });
200
- yield* pipe(Effect.forever(Effect.gen(function* () {
201
- const message = yield* Queue.take(messageQueue);
202
- yield* processMessage(message);
203
- })), Effect.catchAllCause(cause => Effect.sync(() => {
204
- const squashed = Cause.squash(cause);
205
- const appError = squashed instanceof Error
206
- ? squashed
207
- : new Error(String(squashed));
208
- renderErrorView(appError, errorView, container, maybeCurrentVNodeRef);
209
- })));
210
- }));
231
+ yield* pipe(Effect.forever(Effect.gen(function* () {
232
+ const message = yield* Queue.take(messageQueue);
233
+ yield* Ref.set(currentMessageRef, Option.some(message));
234
+ yield* processMessage(message);
235
+ })), Effect.catchAllCause(cause => Effect.sync(() => {
236
+ const squashed = Cause.squash(cause);
237
+ const appError = squashed instanceof Error
238
+ ? squashed
239
+ : new Error(String(squashed));
240
+ const model = Ref.get(modelRef).pipe(Effect.runSync);
241
+ const message = Ref.get(currentMessageRef).pipe(Effect.runSync, Option.getOrThrow);
242
+ renderCrashView({ error: appError, model, message }, crash, container, maybeCurrentVNodeRef);
243
+ })));
244
+ }));
245
+ };
211
246
  const patchVNode = (maybeCurrentVNode, nextVNodeNullish, container) => {
212
247
  const nextVNode = Predicate.isNotNull(nextVNodeNullish)
213
248
  ? nextVNodeNullish
@@ -217,21 +252,29 @@ const patchVNode = (maybeCurrentVNode, nextVNodeNullish, container) => {
217
252
  onSome: currentVNode => patch(currentVNode, nextVNode),
218
253
  });
219
254
  };
220
- const renderErrorView = (appError, errorView, container, maybeCurrentVNodeRef) => {
221
- console.error('[foldkit] Application error:', appError);
255
+ const renderCrashView = (context, crash, container, maybeCurrentVNodeRef) => {
256
+ console.error('[foldkit] Application crash:', context.error);
257
+ if (crash?.report) {
258
+ try {
259
+ crash.report(context);
260
+ }
261
+ catch (reportError) {
262
+ console.error('[foldkit] crash.report failed:', reportError);
263
+ }
264
+ }
222
265
  try {
223
- const errorHtml = errorView
224
- ? errorView(appError)
225
- : defaultErrorView(appError);
266
+ const crashHtml = crash?.view
267
+ ? crash.view(context)
268
+ : defaultCrashView(context);
226
269
  const maybeCurrentVNode = Ref.get(maybeCurrentVNodeRef).pipe(Effect.runSync);
227
- const vnode = errorHtml.pipe(Effect.provideService(Dispatch, noOpDispatch), Effect.runSync);
270
+ const vnode = crashHtml.pipe(Effect.provideService(Dispatch, noOpDispatch), Effect.runSync);
228
271
  patchVNode(maybeCurrentVNode, vnode, container);
229
272
  }
230
273
  catch (viewError) {
231
- console.error('[foldkit] Custom errorView failed:', viewError);
274
+ console.error('[foldkit] crash.view failed:', viewError);
232
275
  const maybeCurrentVNode = Ref.get(maybeCurrentVNodeRef).pipe(Effect.runSync);
233
276
  const fallbackViewError = viewError instanceof Error ? viewError : new Error(String(viewError));
234
- const vnode = defaultErrorView(appError, fallbackViewError).pipe(Effect.provideService(Dispatch, noOpDispatch), Effect.runSync);
277
+ const vnode = defaultCrashView(context, fallbackViewError).pipe(Effect.provideService(Dispatch, noOpDispatch), Effect.runSync);
235
278
  patchVNode(maybeCurrentVNode, vnode, container);
236
279
  }
237
280
  };
@@ -242,9 +285,9 @@ export function makeElement(config) {
242
285
  view: config.view,
243
286
  ...(config.subscriptions && { subscriptions: config.subscriptions }),
244
287
  container: config.container,
245
- ...(config.errorView && { errorView: config.errorView }),
246
- ...(Predicate.isNotUndefined(config.slowViewThresholdMs) && {
247
- slowViewThresholdMs: config.slowViewThresholdMs,
288
+ ...(config.crash && { crash: config.crash }),
289
+ ...(Predicate.isNotUndefined(config.slowView) && {
290
+ slowView: config.slowView,
248
291
  }),
249
292
  ...(config.resources && { resources: config.resources }),
250
293
  ...(config.managedResources && {
@@ -284,9 +327,9 @@ export function makeApplication(config) {
284
327
  ...(config.subscriptions && { subscriptions: config.subscriptions }),
285
328
  container: config.container,
286
329
  browser: config.browser,
287
- ...(config.errorView && { errorView: config.errorView }),
288
- ...(Predicate.isNotUndefined(config.slowViewThresholdMs) && {
289
- slowViewThresholdMs: config.slowViewThresholdMs,
330
+ ...(config.crash && { crash: config.crash }),
331
+ ...(Predicate.isNotUndefined(config.slowView) && {
332
+ slowView: config.slowView,
290
333
  }),
291
334
  ...(config.resources && { resources: config.resources }),
292
335
  ...(config.managedResources && {
@@ -322,13 +365,28 @@ const preserveModel = (model) => {
322
365
  import.meta.hot.send('foldkit:preserve-model', model);
323
366
  }
324
367
  };
368
+ const PLUGIN_RESPONSE_TIMEOUT_MS = 500;
325
369
  /** Starts a Foldkit runtime, with HMR support for development. */
326
370
  export const run = (foldkitRuntime) => {
327
371
  if (import.meta.hot) {
328
- import.meta.hot.on('foldkit:restore-model', model => {
329
- BrowserRuntime.runMain(foldkitRuntime(model));
330
- });
331
- import.meta.hot.send('foldkit:request-model');
372
+ const hot = import.meta.hot;
373
+ const requestPreservedModel = pipe(Effect.async(resume => {
374
+ hot.on('foldkit:restore-model', model => {
375
+ resume(Effect.succeed(model));
376
+ });
377
+ hot.send('foldkit:request-model');
378
+ }), Effect.timeoutTo({
379
+ onTimeout: () => {
380
+ console.warn('[foldkit] No response from vite-plugin-foldkit. Add it to your vite.config.ts for HMR model preservation:\n\n' +
381
+ " import foldkit from 'vite-plugin-foldkit'\n\n" +
382
+ ' export default defineConfig({ plugins: [foldkit()] })\n\n' +
383
+ 'Starting without HMR support.');
384
+ return undefined;
385
+ },
386
+ onSuccess: Function.identity,
387
+ duration: PLUGIN_RESPONSE_TIMEOUT_MS,
388
+ }), Effect.flatMap(foldkitRuntime));
389
+ BrowserRuntime.runMain(requestPreservedModel);
332
390
  }
333
391
  else {
334
392
  BrowserRuntime.runMain(foldkitRuntime());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foldkit",
3
- "version": "0.35.2",
3
+ "version": "0.36.0",
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",
@@ -1 +0,0 @@
1
- {"version":3,"file":"errorUI.d.ts","sourceRoot":"","sources":["../../src/runtime/errorUI.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,EAAE,IAAI,EAAQ,MAAM,SAAS,CAAA;AAEpC,eAAO,MAAM,YAAY;8BACG,OAAO;6BACR,OAAO;CACjC,CAAA;AAmBD,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,EAAE,YAAY,OAAO,KAAG,IA4LpE,CAAA"}