foldkit 0.73.0 → 0.74.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/dist/runtime/deepFreeze.d.ts +23 -0
- package/dist/runtime/deepFreeze.d.ts.map +1 -0
- package/dist/runtime/deepFreeze.js +54 -0
- package/dist/runtime/public.d.ts +1 -1
- package/dist/runtime/public.d.ts.map +1 -1
- package/dist/runtime/runtime.d.ts +23 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +14 -5
- package/package.json +1 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursively `Object.freeze`s a Model so accidental mutations throw a
|
|
3
|
+
* `TypeError` at the write site with a clear stack trace, instead of silently
|
|
4
|
+
* corrupting state or breaking reference-equality change detection.
|
|
5
|
+
*
|
|
6
|
+
* Scope: plain objects and arrays only. `Date`, `Map`, `Set`, `File`, class
|
|
7
|
+
* instances, and Effect-tagged values such as `Option`, `Either`, `DateTime`,
|
|
8
|
+
* `HashSet`, `HashMap`, and `Chunk` are returned untouched. Effect values rely
|
|
9
|
+
* on `Hash.cached(this, ...)`, which lazily writes a memoized hash onto the
|
|
10
|
+
* instance via `Object.defineProperty` on the first `Equal.equals` or
|
|
11
|
+
* `Hash.hash` call. Freezing them would turn that legitimate write into a
|
|
12
|
+
* `TypeError` on every subsequent equality check.
|
|
13
|
+
*
|
|
14
|
+
* `Option` is special-cased so nested plain payloads still get frozen:
|
|
15
|
+
* `Option.some({ items: [...] })` walks into `.value` and freezes the inner
|
|
16
|
+
* record, but returns the `Some` wrapper untouched.
|
|
17
|
+
*
|
|
18
|
+
* Idempotent: already-frozen values are returned as-is. This also serves as
|
|
19
|
+
* the cycle-safety bailout and ensures amortized cost is O(diff) per update
|
|
20
|
+
* when combined with `evo()` which preserves unchanged branches by reference.
|
|
21
|
+
*/
|
|
22
|
+
export declare const deepFreeze: <T>(value: T) => T;
|
|
23
|
+
//# sourceMappingURL=deepFreeze.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepFreeze.d.ts","sourceRoot":"","sources":["../../src/runtime/deepFreeze.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,CA6BxC,CAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Array, Option, Predicate, Record } from 'effect';
|
|
2
|
+
/**
|
|
3
|
+
* Recursively `Object.freeze`s a Model so accidental mutations throw a
|
|
4
|
+
* `TypeError` at the write site with a clear stack trace, instead of silently
|
|
5
|
+
* corrupting state or breaking reference-equality change detection.
|
|
6
|
+
*
|
|
7
|
+
* Scope: plain objects and arrays only. `Date`, `Map`, `Set`, `File`, class
|
|
8
|
+
* instances, and Effect-tagged values such as `Option`, `Either`, `DateTime`,
|
|
9
|
+
* `HashSet`, `HashMap`, and `Chunk` are returned untouched. Effect values rely
|
|
10
|
+
* on `Hash.cached(this, ...)`, which lazily writes a memoized hash onto the
|
|
11
|
+
* instance via `Object.defineProperty` on the first `Equal.equals` or
|
|
12
|
+
* `Hash.hash` call. Freezing them would turn that legitimate write into a
|
|
13
|
+
* `TypeError` on every subsequent equality check.
|
|
14
|
+
*
|
|
15
|
+
* `Option` is special-cased so nested plain payloads still get frozen:
|
|
16
|
+
* `Option.some({ items: [...] })` walks into `.value` and freezes the inner
|
|
17
|
+
* record, but returns the `Some` wrapper untouched.
|
|
18
|
+
*
|
|
19
|
+
* Idempotent: already-frozen values are returned as-is. This also serves as
|
|
20
|
+
* the cycle-safety bailout and ensures amortized cost is O(diff) per update
|
|
21
|
+
* when combined with `evo()` which preserves unchanged branches by reference.
|
|
22
|
+
*/
|
|
23
|
+
export const deepFreeze = (value) => {
|
|
24
|
+
if (value === null || typeof value !== 'object') {
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
if (Object.isFrozen(value)) {
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
if (Array.isArray(value)) {
|
|
31
|
+
Object.freeze(value);
|
|
32
|
+
value.forEach(deepFreeze);
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
if (Option.isOption(value)) {
|
|
36
|
+
if (Option.isSome(value)) {
|
|
37
|
+
deepFreeze(value.value);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
if (!isPlainObject(value)) {
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
Object.freeze(value);
|
|
45
|
+
Record.values(value).forEach(deepFreeze);
|
|
46
|
+
return value;
|
|
47
|
+
};
|
|
48
|
+
const isPlainObject = (value) => {
|
|
49
|
+
if (!Predicate.isRecord(value)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const prototype = Object.getPrototypeOf(value);
|
|
53
|
+
return prototype === Object.prototype || prototype === null;
|
|
54
|
+
};
|
package/dist/runtime/public.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { makeProgram, run } from './runtime';
|
|
2
|
-
export type { RoutingConfig, CrashConfig, CrashContext, RoutingProgramConfigWithFlags, RoutingProgramConfig, ProgramConfigWithFlags, ProgramConfig, ProgramInit, RoutingProgramInit, MakeRuntimeReturn, Visibility, SlowViewContext, SlowViewConfig, DevtoolsConfig, } from './runtime';
|
|
2
|
+
export type { RoutingConfig, CrashConfig, CrashContext, RoutingProgramConfigWithFlags, RoutingProgramConfig, ProgramConfigWithFlags, ProgramConfig, ProgramInit, RoutingProgramInit, MakeRuntimeReturn, Visibility, SlowViewContext, SlowViewConfig, FreezeModelConfig, 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,GAAG,EAAE,MAAM,WAAW,CAAA;AAE5C,YAAY,EACV,aAAa,EACb,WAAW,EACX,YAAY,EACZ,6BAA6B,EAC7B,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,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
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/runtime/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAE5C,YAAY,EACV,aAAa,EACb,WAAW,EACX,YAAY,EACZ,6BAA6B,EAC7B,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,cAAc,GACf,MAAM,WAAW,CAAA;AAElB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -52,6 +52,28 @@ export type SlowViewConfig<Model, Message> = false | Readonly<{
|
|
|
52
52
|
thresholdMs?: number;
|
|
53
53
|
onSlowView?: (context: SlowViewContext<Model, Message>) => void;
|
|
54
54
|
}>;
|
|
55
|
+
/**
|
|
56
|
+
* Model-freeze configuration for catching accidental mutations in development.
|
|
57
|
+
*
|
|
58
|
+
* When active, Foldkit deep-freezes the Model after `init` and after every
|
|
59
|
+
* `update`. Accidental mutations (e.g. `model.items.push(...)`) then throw a
|
|
60
|
+
* `TypeError` at the exact write site with a stack trace, rather than
|
|
61
|
+
* silently corrupting state or breaking reference-equality change detection.
|
|
62
|
+
*
|
|
63
|
+
* Pass `false` to disable entirely.
|
|
64
|
+
*
|
|
65
|
+
* - `show`: `'Development'` (default) enables when Vite HMR is active,
|
|
66
|
+
* `'Always'` enables in all environments including production.
|
|
67
|
+
*
|
|
68
|
+
* Scope: only the Model is frozen. Messages are short-lived and are not
|
|
69
|
+
* frozen; they often carry `OptionFromSelf` / `DateTimeFromSelf` fields that
|
|
70
|
+
* rely on `Hash.cached` which lazily writes to the instance. Production
|
|
71
|
+
* builds (`'Development'` + no HMR) leave change detection at reference
|
|
72
|
+
* equality and pay nothing for this feature.
|
|
73
|
+
*/
|
|
74
|
+
export type FreezeModelConfig = false | Readonly<{
|
|
75
|
+
show?: Visibility;
|
|
76
|
+
}>;
|
|
55
77
|
declare const Dispatch_base: Context.TagClass<Dispatch, "@foldkit/Dispatch", {
|
|
56
78
|
readonly dispatchAsync: (message: unknown) => Effect.Effect<void>;
|
|
57
79
|
readonly dispatchSync: (message: unknown) => void;
|
|
@@ -87,6 +109,7 @@ type BaseProgramConfig<Model, Message, StreamDepsMap extends Schema.Struct<Schem
|
|
|
87
109
|
container: HTMLElement;
|
|
88
110
|
crash?: CrashConfig<Model, Message>;
|
|
89
111
|
slowView?: SlowViewConfig<Model, Message>;
|
|
112
|
+
freezeModel?: FreezeModelConfig;
|
|
90
113
|
resources?: Layer.Layer<Resources>;
|
|
91
114
|
managedResources?: ManagedResources<Model, Message, ManagedResourceServices>;
|
|
92
115
|
/** Derives the document title from the current model. Called after every render. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,OAAO,EACP,MAAM,EAGN,KAAK,EAEL,MAAM,EAMN,MAAM,EAKP,MAAM,QAAQ,CAAA;AAGf,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAGzC,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAC9B,OAAO,EAAE,GAAG,EAA+B,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/runtime.js
CHANGED
|
@@ -7,11 +7,13 @@ import { fromString as urlFromString } from '../url';
|
|
|
7
7
|
import { patch, toVNode } from '../vdom';
|
|
8
8
|
import { addBfcacheRestoreListener, addNavigationEventListeners, } from './browserListeners';
|
|
9
9
|
import { defaultCrashView, noOpDispatch } from './crashUI';
|
|
10
|
+
import { deepFreeze } from './deepFreeze';
|
|
10
11
|
const DEFAULT_DEVTOOLS_SHOW = 'Development';
|
|
11
12
|
const DEFAULT_DEVTOOLS_POSITION = 'BottomRight';
|
|
12
13
|
const DEFAULT_DEVTOOLS_MODE = 'TimeTravel';
|
|
13
14
|
const DEFAULT_SLOW_VIEW_SHOW = 'Development';
|
|
14
15
|
const DEFAULT_SLOW_VIEW_THRESHOLD_MS = 16;
|
|
16
|
+
const DEFAULT_FREEZE_MODEL_SHOW = 'Development';
|
|
15
17
|
const defaultSlowViewCallback = (context) => {
|
|
16
18
|
const trigger = Option.match(context.message, {
|
|
17
19
|
onNone: () => 'init',
|
|
@@ -27,11 +29,13 @@ const defaultSlowViewCallback = (context) => {
|
|
|
27
29
|
/** Effect service tag that provides message dispatching to the view layer. */
|
|
28
30
|
export class Dispatch extends Context.Tag('@foldkit/Dispatch')() {
|
|
29
31
|
}
|
|
30
|
-
const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscriptions, container, routing: routingConfig, crash, slowView, resources, managedResources, title, devtools, }) => {
|
|
32
|
+
const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscriptions, container, routing: routingConfig, crash, slowView, freezeModel, resources, managedResources, title, devtools, }) => {
|
|
31
33
|
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
34
|
thresholdMs: config.thresholdMs ?? DEFAULT_SLOW_VIEW_THRESHOLD_MS,
|
|
33
35
|
onSlowView: config.onSlowView ?? defaultSlowViewCallback,
|
|
34
36
|
})));
|
|
37
|
+
const isFreezeModelActive = pipe(freezeModel ?? {}, Option.liftPredicate(config => config !== false), Option.filter(config => Match.value(config.show ?? DEFAULT_FREEZE_MODEL_SHOW).pipe(Match.when('Always', () => true), Match.when('Development', () => !!import.meta.hot), Match.exhaustive)), Option.isSome);
|
|
38
|
+
const maybeFreezeModel = (model) => isFreezeModelActive ? deepFreeze(model) : model;
|
|
35
39
|
return (hmrModel) => Effect.scoped(Effect.gen(function* () {
|
|
36
40
|
const maybeResourceLayer = resources
|
|
37
41
|
? Option.some(yield* Layer.memoize(resources))
|
|
@@ -68,12 +72,13 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
68
72
|
const messageQueue = yield* Queue.unbounded();
|
|
69
73
|
const enqueueMessage = (message) => Queue.offer(messageQueue, message);
|
|
70
74
|
const currentUrl = Option.fromNullable(routingConfig).pipe(Option.flatMap(() => urlFromString(window.location.href)));
|
|
71
|
-
const [
|
|
75
|
+
const [initModelRaw, initCommands] = Predicate.isNotUndefined(hmrModel)
|
|
72
76
|
? pipe(hmrModel, Schema.decodeUnknownEither(Model), Either.match({
|
|
73
77
|
onLeft: () => init(flags, Option.getOrUndefined(currentUrl)),
|
|
74
78
|
onRight: restoredModel => [restoredModel, []],
|
|
75
79
|
}))
|
|
76
80
|
: init(flags, Option.getOrUndefined(currentUrl));
|
|
81
|
+
const initModel = maybeFreezeModel(initModelRaw);
|
|
77
82
|
const modelSubscriptionRef = yield* SubscriptionRef.make(initModel);
|
|
78
83
|
yield* Effect.forEach(
|
|
79
84
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
@@ -99,7 +104,8 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
99
104
|
const pendingMessagesQueue = yield* Queue.unbounded();
|
|
100
105
|
const processMessage = (message) => Effect.gen(function* () {
|
|
101
106
|
const currentModel = yield* Ref.get(modelRef);
|
|
102
|
-
const [
|
|
107
|
+
const [nextModelRaw, commands] = update(currentModel, message);
|
|
108
|
+
const nextModel = maybeFreezeModel(nextModelRaw);
|
|
103
109
|
if (currentModel !== nextModel) {
|
|
104
110
|
yield* Ref.set(modelRef, nextModel);
|
|
105
111
|
const isPaused = yield* pipe(maybeDevtoolsStoreRef, Ref.get, Effect.flatMap(Option.match({
|
|
@@ -203,9 +209,9 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
203
209
|
if (Option.isSome(resolvedDevtools)) {
|
|
204
210
|
const { position, mode, maybeBanner } = resolvedDevtools.value;
|
|
205
211
|
const devtoolsStore = yield* createDevtoolsStore({
|
|
206
|
-
replay: (model, message) =>
|
|
212
|
+
replay: (model, message) => maybeFreezeModel(
|
|
207
213
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
208
|
-
Tuple.getFirst(update(model, message)),
|
|
214
|
+
Tuple.getFirst(update(model, message))),
|
|
209
215
|
render: model =>
|
|
210
216
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
211
217
|
render(model, Option.none()),
|
|
@@ -334,6 +340,9 @@ export function makeProgram(config) {
|
|
|
334
340
|
...(Predicate.isNotUndefined(config.slowView) && {
|
|
335
341
|
slowView: config.slowView,
|
|
336
342
|
}),
|
|
343
|
+
...(Predicate.isNotUndefined(config.freezeModel) && {
|
|
344
|
+
freezeModel: config.freezeModel,
|
|
345
|
+
}),
|
|
337
346
|
...(config.resources && { resources: config.resources }),
|
|
338
347
|
...(config.managedResources && {
|
|
339
348
|
managedResources: config.managedResources,
|