@actuallab/fusion 14.1.5 → 14.2.23
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/index.cjs +43 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +43 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -76,8 +76,8 @@ var import_core3 = require("@actuallab/core");
|
|
|
76
76
|
// src/computed-registry.ts
|
|
77
77
|
var ComputedRegistry = class _ComputedRegistry {
|
|
78
78
|
static _entries = /* @__PURE__ */ new Map();
|
|
79
|
-
static _finalization = new FinalizationRegistry((
|
|
80
|
-
_ComputedRegistry.
|
|
79
|
+
static _finalization = new FinalizationRegistry((token) => {
|
|
80
|
+
_ComputedRegistry._onFinalized(token);
|
|
81
81
|
});
|
|
82
82
|
static get size() {
|
|
83
83
|
return _ComputedRegistry._entries.size;
|
|
@@ -87,7 +87,7 @@ var ComputedRegistry = class _ComputedRegistry {
|
|
|
87
87
|
if (ref === void 0) return void 0;
|
|
88
88
|
const computed = ref.deref();
|
|
89
89
|
if (computed === void 0) {
|
|
90
|
-
_ComputedRegistry.
|
|
90
|
+
_ComputedRegistry._removeEntry(key, ref);
|
|
91
91
|
return void 0;
|
|
92
92
|
}
|
|
93
93
|
return computed;
|
|
@@ -99,14 +99,26 @@ var ComputedRegistry = class _ComputedRegistry {
|
|
|
99
99
|
return;
|
|
100
100
|
if (displaced !== void 0 && displaced.state !== 2 /* Invalidated */)
|
|
101
101
|
displaced.invalidate();
|
|
102
|
-
|
|
103
|
-
_ComputedRegistry.
|
|
102
|
+
const ref = new WeakRef(computed);
|
|
103
|
+
_ComputedRegistry._entries.set(key, ref);
|
|
104
|
+
_ComputedRegistry._finalization.register(computed, { key, ref }, computed);
|
|
104
105
|
}
|
|
105
106
|
static unregister(computed) {
|
|
106
107
|
const key = computed.input;
|
|
107
|
-
_ComputedRegistry._entries.
|
|
108
|
+
if (_ComputedRegistry._entries.get(key)?.deref() === computed)
|
|
109
|
+
_ComputedRegistry._entries.delete(key);
|
|
108
110
|
_ComputedRegistry._finalization.unregister(computed);
|
|
109
111
|
}
|
|
112
|
+
// Private methods
|
|
113
|
+
static _onFinalized(token) {
|
|
114
|
+
_ComputedRegistry._removeEntry(token.key, token.ref);
|
|
115
|
+
}
|
|
116
|
+
// Removing by key alone would drop a live successor registered under the same key
|
|
117
|
+
// while this key's predecessor was already collected but not yet finalized (I13).
|
|
118
|
+
static _removeEntry(key, ref) {
|
|
119
|
+
if (_ComputedRegistry._entries.get(key) === ref)
|
|
120
|
+
_ComputedRegistry._entries.delete(key);
|
|
121
|
+
}
|
|
110
122
|
};
|
|
111
123
|
|
|
112
124
|
// src/compute-context.ts
|
|
@@ -166,6 +178,7 @@ var ComputedOptions = class _ComputedOptions {
|
|
|
166
178
|
// src/computed.ts
|
|
167
179
|
var { errorLog } = getLogs("Computed");
|
|
168
180
|
var _nextVersion = 0;
|
|
181
|
+
var MinPruneDependantsThreshold = 16;
|
|
169
182
|
var ConsistencyState = /* @__PURE__ */ ((ConsistencyState2) => {
|
|
170
183
|
ConsistencyState2[ConsistencyState2["Computing"] = 0] = "Computing";
|
|
171
184
|
ConsistencyState2[ConsistencyState2["Consistent"] = 1] = "Consistent";
|
|
@@ -205,6 +218,7 @@ var Computed = class {
|
|
|
205
218
|
_errorTimer;
|
|
206
219
|
_dependencies = /* @__PURE__ */ new Set();
|
|
207
220
|
_dependants = /* @__PURE__ */ new Map();
|
|
221
|
+
_pruneDependantsThreshold = MinPruneDependantsThreshold;
|
|
208
222
|
_onInvalidated = new import_core3.EventHandlerSet();
|
|
209
223
|
_renewer;
|
|
210
224
|
constructor(input, renewer, options = ComputedOptions.default) {
|
|
@@ -249,6 +263,9 @@ var Computed = class {
|
|
|
249
263
|
get dependencies() {
|
|
250
264
|
return this._dependencies;
|
|
251
265
|
}
|
|
266
|
+
get dependantCount() {
|
|
267
|
+
return this._dependants.size;
|
|
268
|
+
}
|
|
252
269
|
update() {
|
|
253
270
|
if (this._state === 1 /* Consistent */) return this;
|
|
254
271
|
const latest = this._latest();
|
|
@@ -392,6 +409,24 @@ var Computed = class {
|
|
|
392
409
|
this._version,
|
|
393
410
|
new WeakRef(this)
|
|
394
411
|
);
|
|
412
|
+
if (dependency._dependants.size >= dependency._pruneDependantsThreshold)
|
|
413
|
+
dependency.pruneDependants();
|
|
414
|
+
}
|
|
415
|
+
// Port of .NET Computed.PruneDependants: drops edges to dependants that were
|
|
416
|
+
// collected or already invalidated. `_dependants` is keyed by the dependant's
|
|
417
|
+
// unique version, so .NET's "still the registered version" check is implicit.
|
|
418
|
+
pruneDependants() {
|
|
419
|
+
if (this._state !== 1 /* Consistent */)
|
|
420
|
+
return;
|
|
421
|
+
for (const [version, ref] of this._dependants) {
|
|
422
|
+
const dependant = ref.deref();
|
|
423
|
+
if (dependant === void 0 || dependant._state === 2 /* Invalidated */)
|
|
424
|
+
this._dependants.delete(version);
|
|
425
|
+
}
|
|
426
|
+
this._pruneDependantsThreshold = Math.max(
|
|
427
|
+
MinPruneDependantsThreshold,
|
|
428
|
+
this._dependants.size * 2
|
|
429
|
+
);
|
|
395
430
|
}
|
|
396
431
|
};
|
|
397
432
|
var StateBoundComputed = class extends Computed {
|
|
@@ -832,6 +867,7 @@ var State = class _State {
|
|
|
832
867
|
this._isDisposed = true;
|
|
833
868
|
this._whenUpdatedSource?.reject(_State._disposedError());
|
|
834
869
|
this._whenUpdatedSource = null;
|
|
870
|
+
this._computed.invalidate();
|
|
835
871
|
}
|
|
836
872
|
static _disposedError() {
|
|
837
873
|
return new Error("State is disposed.");
|
|
@@ -868,8 +904,8 @@ var ComputedState = class extends State {
|
|
|
868
904
|
dispose() {
|
|
869
905
|
if (this.isDisposed)
|
|
870
906
|
return;
|
|
871
|
-
this._onDisposed();
|
|
872
907
|
this._disposeController.abort();
|
|
908
|
+
this._onDisposed();
|
|
873
909
|
}
|
|
874
910
|
async _updateCycle() {
|
|
875
911
|
const disposeSignal = this._disposeController.signal;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/logging.ts","../src/computed-input.ts","../src/computed.ts","../src/computed-registry.ts","../src/compute-context.ts","../src/computed-options.ts","../src/compute-function.ts","../src/compute-method.ts","../src/update-delayer.ts","../src/ui-update-delayer.ts","../src/ui-action-tracker.ts","../src/state.ts","../src/computed-state.ts","../src/mutable-state.ts"],"sourcesContent":["export type { FusionLogScope } from './logging.js';\r\nexport { getLogs } from './logging.js';\r\n\r\nexport { getInstanceId } from './computed-input.js';\r\nexport type { ComputedInput } from './computed-input.js';\r\nexport { Computed, StateBoundComputed, ConsistencyState } from './computed.js';\r\nexport { ComputedOptions } from './computed-options.js';\r\nexport { ComputeContext, computeContextKey } from './compute-context.js';\r\nexport { ComputedRegistry } from './computed-registry.js';\r\nexport { ComputeFunction } from './compute-function.js';\r\nexport type { ComputeFunctionImpl } from './compute-function.js';\r\nexport {\r\n computeMethod,\r\n wrapComputeMethod,\r\n getMethodsMeta,\r\n} from './compute-method.js';\r\nexport type { MethodMeta, ComputeMethodOptions } from './compute-method.js';\r\nexport type { UpdateDelayer } from './update-delayer.js';\r\nexport { FixedDelayer, defaultUpdateDelayer } from './update-delayer.js';\r\nexport { UIUpdateDelayer } from './ui-update-delayer.js';\r\nexport { UIActionTracker, uiActions } from './ui-action-tracker.js';\r\nexport { State } from './state.js';\r\nexport { ComputedState } from './computed-state.js';\r\nexport type { ComputedStateOptions, StateComputer } from './computed-state.js';\r\nexport { MutableState } from './mutable-state.js';\r\n","import { createLogProvider, LogLevel } from '@actuallab/core';\n\n// Per-package log scopes. Use createLogProvider to get a typed helper:\n// const { debugLog, warnLog } = getLogs('Computed');\n// Final scope name is 'fusion.Computed' — the prefix isolates this package's\n// scopes from other packages' scopes when overriding levels at runtime.\nexport type FusionLogScope =\n | 'Computed'\n | 'ComputedRegistry'\n | 'ComputedState'\n | 'ComputeFunction'\n | 'MutableState'\n | 'State'\n | 'UIActionTracker'\n | 'UIUpdateDelayer';\n\n// Per-scope defaults. All Warn — Fusion is mostly hot-path compute graph code;\n// noisy scopes need to be opted-in for development.\nconst scopeDefaults: Record<FusionLogScope, LogLevel> = {\n Computed: LogLevel.Warn,\n ComputedRegistry: LogLevel.Warn,\n ComputedState: LogLevel.Warn,\n ComputeFunction: LogLevel.Warn,\n MutableState: LogLevel.Warn,\n State: LogLevel.Warn,\n UIActionTracker: LogLevel.Warn,\n UIUpdateDelayer: LogLevel.Warn,\n};\n\nexport const getLogs = createLogProvider<FusionLogScope>('fusion.', scopeDefaults);\n","import type { State } from './state.js';\r\n\r\n/** Auto-assigned numeric IDs for instance identity in compute method cache keys. */\r\nlet _nextInstanceId = 0;\r\nconst _instanceIds = new WeakMap<object, number>();\r\n\r\nexport function getInstanceId(instance: object): number {\r\n let id = _instanceIds.get(instance);\r\n if (id === undefined) {\r\n id = ++_nextInstanceId;\r\n _instanceIds.set(instance, id);\r\n }\r\n return id;\r\n}\r\n\r\n/**\r\n * Identity key for any computed value.\r\n * - String for compute method results (built from instance + function + args)\r\n * - State for state types (identity by reference)\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type ComputedInput = string | State<any>;\r\n","import {\r\n AsyncContext,\r\n EventHandlerSet,\r\n type IResult,\r\n isCancellation,\r\n PromiseSource,\r\n Result,\r\n result,\r\n} from '@actuallab/core';\r\nimport type { ComputedInput } from './computed-input.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { getLogs } from './logging.js';\r\nimport type { State } from './state.js';\r\n\r\nconst { errorLog } = getLogs('Computed');\r\n\r\nlet _nextVersion = 0;\r\n\r\nexport const enum ConsistencyState {\r\n Computing = 0,\r\n Consistent = 1,\r\n Invalidated = 2,\r\n}\r\n\r\n/** Core Fusion abstraction — a cached computation with dependency tracking and invalidation. */\r\nexport class Computed<T> implements IResult<T> {\r\n /** Capture the Computed backing a computation — works with both local and RPC compute methods. */\r\n static async capture<T>(fn: () => T | Promise<T>): Promise<Computed<T>> {\r\n // A capture context (no computed) records the last captured Computed without adding\r\n // dependant edges — mirrors C# ComputeContext(CallOptions.Capture) + Computed.Capture.\r\n // The parent link keeps reentrancy detection working through capture — in C# lock\r\n // reentry flows through ExecutionContext regardless of BeginCapture.\r\n const currentCtx = AsyncContext.getOrCreate();\r\n const captureCtx = new ComputeContext(\r\n undefined,\r\n currentCtx.get(computeContextKey)\r\n );\r\n const asyncCtx = currentCtx.with(computeContextKey, captureCtx);\r\n try {\r\n await asyncCtx.run(fn);\r\n } catch (e) {\r\n if (isCancellation(e)) throw e;\r\n const captured = captureCtx.captured;\r\n if (captured?.hasError) return captured as Computed<T>;\r\n\r\n throw e;\r\n }\r\n const captured = captureCtx.captured;\r\n if (captured === undefined)\r\n throw new Error(\r\n 'No Computed was captured — fn must call a compute function.'\r\n );\r\n return captured as Computed<T>;\r\n }\r\n\r\n readonly input: ComputedInput;\r\n readonly options: ComputedOptions;\r\n private _version: number;\r\n private _state: ConsistencyState;\r\n private _output: Result<T> | undefined;\r\n private _invalidatePending = false;\r\n private _errorTimer: ReturnType<typeof setTimeout> | undefined;\r\n private _dependencies = new Set<Computed<unknown>>();\r\n private _dependants = new Map<number, WeakRef<Computed<unknown>>>();\r\n private _onInvalidated = new EventHandlerSet<void>();\r\n readonly _renewer: (() => Computed<T> | Promise<Computed<T>>) | undefined;\r\n\r\n constructor(\r\n input: ComputedInput,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>,\r\n options: ComputedOptions = ComputedOptions.default\r\n ) {\r\n this.input = input;\r\n this.options = options;\r\n this._renewer = renewer;\r\n this._version = ++_nextVersion;\r\n this._state = ConsistencyState.Computing;\r\n }\r\n\r\n get version(): number {\r\n return this._version;\r\n }\r\n\r\n get output(): Result<T> {\r\n if (this._output === undefined)\r\n throw new Error('Computed has no output yet.');\r\n return this._output;\r\n }\r\n\r\n get hasValue(): boolean {\r\n return this.output.hasValue;\r\n }\r\n\r\n get hasError(): boolean {\r\n return this.output.hasError;\r\n }\r\n\r\n get value(): T {\r\n return this.output.value;\r\n }\r\n\r\n get error(): unknown {\r\n return this.output.error;\r\n }\r\n\r\n get valueOrUndefined(): T | undefined {\r\n return this.output.valueOrUndefined;\r\n }\r\n\r\n get state(): ConsistencyState {\r\n return this._state;\r\n }\r\n\r\n get isConsistent(): boolean {\r\n return this._state === ConsistencyState.Consistent;\r\n }\r\n\r\n get isComputing(): boolean {\r\n return this._state === ConsistencyState.Computing;\r\n }\r\n\r\n get dependencies(): ReadonlySet<Computed<unknown>> {\r\n return this._dependencies;\r\n }\r\n\r\n update(): Computed<T> | Promise<Computed<T>> {\r\n if (this._state === ConsistencyState.Consistent) return this;\r\n const latest = this._latest();\r\n if (latest?.isConsistent) return latest;\r\n if (this._renewer !== undefined) {\r\n const renewer = this._renewer;\r\n // Run the renewer with the compute context cleared so renewal never\r\n // records a dependency edge in the ambient computation — TS analog of\r\n // C# Computed.UpdateUntyped's BeginIsolation.\r\n const isolated = (AsyncContext.current ?? AsyncContext.empty).with(\r\n computeContextKey,\r\n undefined\r\n );\r\n return isolated.run(renewer);\r\n }\r\n throw new Error(\r\n 'Cannot recompute: Computed is invalidated and has no renewer.'\r\n );\r\n }\r\n\r\n protected _latest(): Computed<T> | undefined {\r\n return ComputedRegistry.get(this.input as string) as\r\n | Computed<T>\r\n | undefined;\r\n }\r\n\r\n use(asyncContext?: AsyncContext): T | Promise<T> {\r\n const ctx = ComputeContext.from(asyncContext);\r\n const updated = this.update();\r\n if (updated instanceof Promise) {\r\n return updated.then(c => {\r\n ctx?.captureDependency(c as Computed<unknown>);\r\n return c.value;\r\n });\r\n }\r\n ctx?.captureDependency(updated as Computed<unknown>);\r\n return updated.value;\r\n }\r\n\r\n useInconsistent(asyncContext?: AsyncContext): T {\r\n ComputeContext.from(asyncContext)?.captureDependency(\r\n this as Computed<unknown>\r\n );\r\n return this.value;\r\n }\r\n\r\n setOutput(output: Result<T> | T): void {\r\n if (this._state !== ConsistencyState.Computing)\r\n throw new Error('Cannot set output on a non-computing Computed.');\r\n this._output = output instanceof Result ? output : result(output);\r\n this._state = ConsistencyState.Consistent;\r\n this._register();\r\n if (this._invalidatePending) {\r\n this._invalidatePending = false;\r\n this.invalidate();\r\n return;\r\n }\r\n\r\n const delay = this.options.errorAutoInvalidateDelay;\r\n if (this._output.hasError && delay !== Infinity && delay > 0) {\r\n this._errorTimer = setTimeout(() => this.invalidate(), delay);\r\n (this._errorTimer as { unref?: () => void }).unref?.();\r\n }\r\n }\r\n\r\n protected _register(): void {\r\n ComputedRegistry.register(this as Computed<unknown>);\r\n }\r\n\r\n protected _unregister(): void {\r\n ComputedRegistry.unregister(this as Computed<unknown>);\r\n }\r\n\r\n // Never throws — mirrors .NET Computed.Invalidate: own handlers fire first\r\n // (each isolated), then dependants propagate unconditionally, then unregister.\r\n invalidate(): void {\r\n if (this._state === ConsistencyState.Invalidated)\r\n return;\r\n if (this._state === ConsistencyState.Computing) {\r\n // Defer until setOutput transitions to Consistent — matches .NET, where\r\n // invalidating a still-computing Computed sets a pending flag.\r\n this._invalidatePending = true;\r\n return;\r\n }\r\n this._state = ConsistencyState.Invalidated;\r\n if (this._errorTimer !== undefined) {\r\n clearTimeout(this._errorTimer);\r\n this._errorTimer = undefined;\r\n }\r\n try {\r\n this._onInvalidated.triggerSafe(undefined, e =>\r\n errorLog?.log('onInvalidated handler failed', e)\r\n );\r\n this._onInvalidated.clear();\r\n } finally {\r\n for (const dependency of this._dependencies)\r\n dependency._dependants.delete(this._version);\r\n this._dependencies.clear();\r\n\r\n for (const [, ref] of this._dependants) {\r\n const dependant = ref.deref();\r\n if (dependant != null) {\r\n try {\r\n dependant.invalidate();\r\n } catch (e) {\r\n errorLog?.log('Error while invalidating dependant', e);\r\n }\r\n }\r\n }\r\n this._dependants.clear();\r\n\r\n this._unregister();\r\n }\r\n }\r\n\r\n onInvalidated(handler: () => void): void {\r\n if (this._state === ConsistencyState.Invalidated) {\r\n handler();\r\n return;\r\n }\r\n this._onInvalidated.add(handler);\r\n }\r\n\r\n whenInvalidated(abortSignal?: AbortSignal): Promise<void> {\r\n if (this._state === ConsistencyState.Invalidated)\r\n return Promise.resolve();\r\n if (abortSignal?.aborted)\r\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- reason falls back to an Error; abortSignal.reason mirrors throwIfAborted()\r\n return Promise.reject(\r\n abortSignal.reason ?? new Error('Operation cancelled.')\r\n );\r\n\r\n const ps = new PromiseSource<void>();\r\n let onAbort: (() => void) | undefined;\r\n const onInvalidated = () => {\r\n if (onAbort !== undefined)\r\n abortSignal!.removeEventListener('abort', onAbort);\r\n ps.resolve(undefined);\r\n };\r\n this._onInvalidated.add(onInvalidated);\r\n if (abortSignal !== undefined) {\r\n onAbort = () => {\r\n this._onInvalidated.remove(onInvalidated);\r\n ps.reject(\r\n abortSignal.reason ?? new Error('Operation cancelled.')\r\n );\r\n };\r\n abortSignal.addEventListener('abort', onAbort, { once: true });\r\n }\r\n\r\n return ps;\r\n }\r\n\r\n addDependency(dependency: Computed<unknown>): void {\r\n if (this._state !== ConsistencyState.Computing)\r\n return;\r\n if (dependency._state === ConsistencyState.Invalidated) {\r\n this.invalidate();\r\n return;\r\n }\r\n this._dependencies.add(dependency);\r\n dependency._dependants.set(\r\n this._version,\r\n new WeakRef(this as Computed<unknown>)\r\n );\r\n }\r\n}\r\n\r\n/** Computed variant for State types — skips registry registration since the State holds a direct reference. */\r\nexport class StateBoundComputed<T> extends Computed<T> {\r\n constructor(\r\n input: ComputedInput,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>,\r\n options: ComputedOptions = ComputedOptions.mutableStateDefault\r\n ) {\r\n super(input, renewer, options);\r\n }\r\n\r\n protected override _latest(): Computed<T> | undefined {\r\n return (this.input as State<T>).computed;\r\n }\r\n\r\n protected override _register(): void {\r\n // No registration — state holds direct reference\r\n }\r\n\r\n protected override _unregister(): void {\r\n // No unregistration — was never registered\r\n }\r\n}\r\n","import { type Computed, ConsistencyState } from './computed.js';\r\n\r\n/** WeakRef-based global cache of Computed instances — allows GC of unused computed values. */\r\nexport class ComputedRegistry {\r\n private static _entries = new Map<string, WeakRef<Computed<unknown>>>();\r\n private static _finalization = new FinalizationRegistry<string>(key => {\r\n ComputedRegistry._entries.delete(key);\r\n });\r\n\r\n static get size(): number {\r\n return ComputedRegistry._entries.size;\r\n }\r\n\r\n static get(key: string): Computed<unknown> | undefined {\r\n const ref = ComputedRegistry._entries.get(key);\r\n if (ref === undefined) return undefined;\r\n const computed = ref.deref();\r\n if (computed === undefined) {\r\n ComputedRegistry._entries.delete(key);\r\n return undefined;\r\n }\r\n return computed;\r\n }\r\n\r\n static register(computed: Computed<unknown>): void {\r\n const key = computed.input as string;\r\n const displaced = ComputedRegistry._entries.get(key)?.deref();\r\n // Already registered — setOutput re-registers the instance registered at creation\r\n if (displaced === computed)\r\n return;\r\n\r\n if (displaced !== undefined && displaced.state !== ConsistencyState.Invalidated)\r\n displaced.invalidate();\r\n ComputedRegistry._entries.set(key, new WeakRef(computed));\r\n ComputedRegistry._finalization.register(computed, key, computed);\r\n }\r\n\r\n static unregister(computed: Computed<unknown>): void {\r\n const key = computed.input as string;\r\n ComputedRegistry._entries.delete(key);\r\n ComputedRegistry._finalization.unregister(computed);\r\n }\r\n}\r\n","import { AsyncContext, AsyncContextKey } from '@actuallab/core';\r\nimport type { Computed } from './computed.js';\r\n\r\nexport const computeContextKey = new AsyncContextKey<\r\n ComputeContext | undefined\r\n>('ComputeContext', undefined);\r\n\r\n/**\r\n * Tracks the currently executing (or captured) computation and captures dependencies.\r\n * A context with a `computed` is a computing context (adds dependant edges); one without\r\n * is a capture context (records the last captured Computed only — no edges).\r\n */\r\nexport class ComputeContext {\r\n readonly computed: Computed<unknown> | undefined;\r\n readonly parent: ComputeContext | undefined;\r\n private _isCapturing = true;\r\n private _captured: Computed<unknown> | undefined;\r\n\r\n constructor(\r\n computed?: Computed<unknown>,\r\n parent?: ComputeContext\r\n ) {\r\n this.computed = computed;\r\n this.parent = parent;\r\n }\r\n\r\n get isCapturing(): boolean {\r\n return this._isCapturing;\r\n }\r\n\r\n get captured(): Computed<unknown> | undefined {\r\n return this._captured;\r\n }\r\n\r\n stopCapturing(): void {\r\n this._isCapturing = false;\r\n }\r\n\r\n captureDependency(dependency: Computed<unknown>): void {\r\n if (!this._isCapturing) return;\r\n // Last capture wins — C# ComputeContext.TryCapture overwrites _captured.\r\n this._captured = dependency;\r\n this.computed?.addDependency(dependency);\r\n }\r\n\r\n // Walks the caller chain for a computation still in progress under the same key —\r\n // C# AsyncLockSet(LockReentryMode.CheckedFail) analog, used to fail fast on reentry.\r\n // Only Computing ancestors count: a context leaked past its finished computation\r\n // (e.g. via AsyncLocalStorage into a later callback) must not fail later calls.\r\n hasKeyInChain(key: unknown): boolean {\r\n const computed = this.computed;\r\n if (computed?.isComputing === true && computed.input === key)\r\n return true;\r\n\r\n return this.parent?.hasKeyInChain(key) ?? false;\r\n }\r\n\r\n /** Resolve ComputeContext from an AsyncContext (or current). */\r\n static from(ctx: AsyncContext | undefined): ComputeContext | undefined {\r\n return AsyncContext.from(ctx)?.get(computeContextKey);\r\n }\r\n}\r\n","/**\r\n * Per-Computed configuration, carried by every {@link Computed} via its\r\n * {@link ComputeFunction} (compute methods) or its kind's static default.\r\n * The home for per-method knobs; the C# analog is `ActualLab.Fusion.ComputedOptions`.\r\n */\r\nexport class ComputedOptions {\r\n static default = new ComputedOptions();\r\n static mutableStateDefault = new ComputedOptions({\r\n errorAutoInvalidateDelay: Infinity,\r\n });\r\n\r\n readonly errorAutoInvalidateDelay: number;\r\n\r\n constructor(overrides?: Partial<ComputedOptions>) {\r\n this.errorAutoInvalidateDelay =\r\n overrides?.errorAutoInvalidateDelay ?? 1000;\r\n }\r\n}\r\n","import {\r\n AsyncContext,\r\n AsyncLock,\r\n isCancellation,\r\n type Result,\r\n result,\r\n errorResult,\r\n} from '@actuallab/core';\r\nimport { Computed } from './computed.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { getInstanceId } from './computed-input.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type ComputeFunctionImpl = (this: any, ...args: unknown[]) => unknown;\r\n\r\n/** Record Separator — delimiter between key components. */\r\nconst RS = '\\x1E';\r\n\r\n// Keying is by JSON.stringify per argument, joined with RS delimiters. Collisions are\r\n// possible and by design (D2): functions, undefined, and symbols all map to '', objects\r\n// without serializable props to '{}', NaN to 'null', Map/Set to '{}'. The compute method's\r\n// author owns keyability — use JSON-representable argument types or supply a custom argToString.\r\nfunction defaultArgToString(arg: unknown): string {\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JSON.stringify returns undefined for undefined input\r\n return JSON.stringify(arg) ?? '';\r\n}\r\n\r\nlet _nextFunctionId = 0;\r\n\r\n/** Produces Computed<T> from a function — handles cache lookup, locking, dependency capture. */\r\nexport class ComputeFunction {\r\n readonly methodName: string;\r\n readonly id: string;\r\n readonly options: ComputedOptions;\r\n argToString: (arg: unknown) => string = defaultArgToString;\r\n private _impl: ComputeFunctionImpl;\r\n private _locks = new Map<string, AsyncLock>();\r\n\r\n constructor(\r\n methodName: string,\r\n impl: ComputeFunctionImpl,\r\n options: ComputedOptions = ComputedOptions.default\r\n ) {\r\n this.methodName = methodName;\r\n this.id = `${methodName}[${++_nextFunctionId}]`;\r\n this._impl = impl;\r\n this.options = options;\r\n }\r\n\r\n /** Build a string key for the given instance and arguments. */\r\n buildKey(instance: object, args: unknown[]): string {\r\n let key = String(getInstanceId(instance)) + RS + this.id;\r\n for (const arg of args) {\r\n key += RS + this.argToString(arg);\r\n }\r\n return key;\r\n }\r\n\r\n async invoke(\r\n instance: object,\r\n args: unknown[]\r\n ): Promise<Computed<unknown>> {\r\n // 1. Resolve AsyncContext ONCE via DRY helper\r\n const asyncCtx = AsyncContext.fromArgs(args);\r\n\r\n // 2. Pull caller's ComputeContext directly\r\n const callerComputeCtx = asyncCtx?.get(computeContextKey);\r\n\r\n // 3. Strip THIS context from args (reference equality — safe)\r\n const argsWithoutCtx = asyncCtx?.stripFromArgs(args) ?? args;\r\n\r\n // 4. Build string key and check cache\r\n const key = this.buildKey(instance, argsWithoutCtx);\r\n const existing = ComputedRegistry.get(key);\r\n if (existing?.isConsistent) {\r\n callerComputeCtx?.captureDependency(existing);\r\n return existing;\r\n }\r\n\r\n // C# AsyncLockSet(CheckedFail) analog: a compute call that (indirectly) awaits itself\r\n // with the same key would await its own non-reentrant lock forever — fail fast instead.\r\n if (callerComputeCtx?.hasKeyInChain(key))\r\n throw new Error(`Reentrant compute call detected for key \"${key}\".`);\r\n\r\n // 5. Lock per key to prevent duplicate computations\r\n let lock = this._locks.get(key);\r\n if (lock === undefined) {\r\n lock = new AsyncLock();\r\n this._locks.set(key, lock);\r\n }\r\n\r\n const computed = await lock.run(async () => {\r\n // Double-check after acquiring lock\r\n const cached = ComputedRegistry.get(key);\r\n if (cached?.isConsistent) return cached;\r\n\r\n // 6. Create new Computed + ComputeContext\r\n const renewer = () => this.invoke(instance, argsWithoutCtx);\r\n const newComputed = new Computed<unknown>(\r\n key,\r\n renewer,\r\n this.options\r\n );\r\n // Register while still Computing so ComputedRegistry.get(key) resolves the\r\n // in-flight instance and a racing invalidate() is captured as pending — C#\r\n // ComputeMethodComputed registers in its constructor.\r\n ComputedRegistry.register(newComputed);\r\n\r\n const childComputeCtx = new ComputeContext(\r\n newComputed,\r\n callerComputeCtx\r\n );\r\n const childAsyncCtx = (asyncCtx ?? AsyncContext.empty).with(\r\n computeContextKey,\r\n childComputeCtx\r\n );\r\n\r\n // 7. Run with clean args, threading childAsyncCtx as a trailing argument so a compute\r\n // body can pass it into nested calls / use(ctx) after awaits — the portable floor for\r\n // dependency capture when AsyncLocalStorage isn't backing AsyncContext.current (browsers).\r\n let fnResult: Result<unknown>;\r\n try {\r\n const value = childAsyncCtx.run(() =>\r\n this._impl.call(instance, ...argsWithoutCtx, childAsyncCtx)\r\n );\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\r\n const resolved = value instanceof Promise ? await value : value;\r\n fnResult = result(resolved);\r\n } catch (e) {\r\n fnResult = errorResult(e);\r\n }\r\n\r\n newComputed.setOutput(fnResult);\r\n // C# StartAutoInvalidation OCE parity: a cancellation error is registered to keep the\r\n // single-flight lock protocol intact, then invalidated at once so it's never cached.\r\n if (fnResult.hasError && isCancellation(fnResult.error))\r\n newComputed.invalidate();\r\n\r\n return newComputed;\r\n });\r\n\r\n if (!lock.isLocked && this._locks.get(key) === lock)\r\n this._locks.delete(key);\r\n\r\n // Register dependency from caller to the produced computed\r\n callerComputeCtx?.captureDependency(computed);\r\n return computed;\r\n }\r\n}\r\n","/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-this-alias */\r\nimport { ownMetadata, resolveArgCount } from '@actuallab/core';\r\nimport { ComputeFunction } from './compute-function.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\n\r\nconst METHODS_META = Symbol.for('actuallab.methods');\r\n\r\nexport interface MethodMeta {\r\n argCount: number;\r\n compute?: boolean;\r\n stream?: boolean;\r\n}\r\n\r\n/** Read method metadata from a decorated class. */\r\nexport function getMethodsMeta(\r\n cls: abstract new (...args: any[]) => any\r\n): Record<string, MethodMeta> | undefined {\r\n return (cls as any)[Symbol.metadata]?.[METHODS_META];\r\n}\r\n\r\nexport interface ComputeMethodOptions extends Partial<ComputedOptions> {\r\n argCount?: number;\r\n}\r\n\r\ntype ComputeMethodDecorator<This, Args extends unknown[], Return> = (\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n) => (this: This, ...args: Args) => Return;\r\n\r\n/**\r\n * Method decorator — routes a method through ComputeFunction for caching and dependency\r\n * tracking. Usable bare (`@computeMethod`) or with options (`@computeMethod({ argCount })`).\r\n */\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n): (this: This, ...args: Args) => Return;\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n options?: ComputeMethodOptions\r\n): ComputeMethodDecorator<This, Args, Return>;\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n targetOrOptions?: ((this: This, ...args: Args) => Return) | ComputeMethodOptions,\r\n context?: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n): unknown {\r\n if (typeof targetOrOptions === 'function')\r\n return computeMethodImpl(targetOrOptions, context!, {});\r\n\r\n const options = targetOrOptions ?? {};\r\n return (target: (this: This, ...args: Args) => Return, ctx: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>) =>\r\n computeMethodImpl(target, ctx, options);\r\n}\r\n\r\nfunction computeMethodImpl<This, Args extends unknown[], Return>(\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<\r\n This,\r\n (this: This, ...args: Args) => Return\r\n >,\r\n options: ComputeMethodOptions\r\n): (this: This, ...args: Args) => Return {\r\n const methodName = String(context.name);\r\n\r\n const methods = ownMetadata<Record<string, MethodMeta>>(context.metadata, METHODS_META);\r\n methods[methodName] = {\r\n ...methods[methodName],\r\n compute: true,\r\n argCount: resolveArgCount(target, options.argCount, methodName),\r\n };\r\n\r\n // ONE ComputeFunction per class×method — created at decoration time\r\n const cf = new ComputeFunction(methodName, target as any, new ComputedOptions(options));\r\n\r\n // Prototype-level replacement — unwraps Computed to return the value directly\r\n const replacement = function (this: This, ...allArgs: Args): Return {\r\n return cf.invoke(this as object, allArgs).then(c => c.value) as Return;\r\n };\r\n\r\n // Per-instance setup: create bound method with .invalidate pre-bound\r\n context.addInitializer(function (this: This) {\r\n const instance = this;\r\n const boundMethod = (...allArgs: unknown[]) => {\r\n return cf.invoke(instance as object, allArgs).then(c => c.value);\r\n };\r\n (boundMethod as any).invalidate = (...args: unknown[]) => {\r\n const key = cf.buildKey(instance as object, args);\r\n ComputedRegistry.get(key)?.invalidate();\r\n };\r\n (this as any)[methodName] = boundMethod;\r\n });\r\n\r\n return replacement;\r\n}\r\n\r\n/** Wrap a standalone function as a compute function with caching and .invalidate(). */\r\nexport function wrapComputeMethod<Args extends unknown[], Return>(\r\n fn: (...args: Args) => Return\r\n): ((...args: Args) => Promise<Return>) & {\r\n invalidate: (...args: Args) => void;\r\n} {\r\n const syntheticInstance = {};\r\n const methodName = fn.name || 'anonymous';\r\n const cf = new ComputeFunction(methodName, fn as any);\r\n\r\n const wrapped = (...allArgs: unknown[]) => {\r\n return cf\r\n .invoke(syntheticInstance, allArgs)\r\n .then(c => c.value as Return);\r\n };\r\n\r\n (wrapped as any).invalidate = (...args: unknown[]) => {\r\n const key = cf.buildKey(syntheticInstance, args);\r\n ComputedRegistry.get(key)?.invalidate();\r\n };\r\n\r\n return wrapped as any;\r\n}\r\n","import { awaitWithCleanup, RetryDelaySeq } from '@actuallab/core';\r\n\r\n/** Controls when state re-computation happens after invalidation, per consecutive-error retryCount. */\r\nexport type UpdateDelayer = (\r\n retryCount: number,\r\n abortSignal?: AbortSignal\r\n) => Promise<void>;\r\n\r\n/** 1 s → 1 min exponential backoff — C# FixedDelayer.Defaults.RetryDelays parity. */\r\nexport const defaultRetryDelays = RetryDelaySeq.exp(1000, 60_000);\r\n\r\n/** Windows timer period is 15.6 ms, so 32 ms = 2..3 timer ticks — C# FixedDelayer.Defaults.MinDelay. */\r\nexport const defaultMinDelayMs = 32;\r\n\r\n// C# UpdateDelayer.GetDelay + minDelay floor: retryCount 0 uses the update delay\r\n// floored by minDelay; retryCount > 0 uses RetryDelays[retryCount] floored by RetryDelays.Min.\r\nexport function computeUpdateDelay(\r\n retryCount: number,\r\n updateDelayMs: number,\r\n retryDelays: RetryDelaySeq,\r\n minDelayMs: number\r\n): number {\r\n const min = retryCount === 0 ? minDelayMs : retryDelays.min;\r\n const raw = retryCount > 0 ? retryDelays.getDelay(retryCount) : updateDelayMs;\r\n return Math.max(min, raw);\r\n}\r\n\r\n/** Re-computes after a fixed update delay, with RetryDelaySeq backoff for consecutive errors. */\r\nexport class FixedDelayer {\r\n static readonly zero: UpdateDelayer = () => Promise.resolve();\r\n\r\n private static _cache = new Map<number, UpdateDelayer>();\r\n\r\n // Floors ms at minDelay like C# FixedDelayer.Get — a zero delayer requires the explicit .zero.\r\n static get(ms: number): UpdateDelayer {\r\n ms = Math.max(ms, defaultMinDelayMs);\r\n let delayer = FixedDelayer._cache.get(ms);\r\n if (delayer === undefined) {\r\n delayer = new FixedDelayer(ms).delay;\r\n FixedDelayer._cache.set(ms, delayer);\r\n }\r\n return delayer;\r\n }\r\n\r\n readonly ms: number;\r\n readonly retryDelays: RetryDelaySeq;\r\n readonly minDelay: number;\r\n readonly delay: UpdateDelayer;\r\n\r\n constructor(\r\n ms: number,\r\n retryDelays: RetryDelaySeq = defaultRetryDelays,\r\n minDelay: number = defaultMinDelayMs\r\n ) {\r\n this.ms = ms;\r\n this.retryDelays = retryDelays;\r\n this.minDelay = minDelay;\r\n // Abort stops the wait early (resolves, never rejects) so a disposed\r\n // ComputedState's update loop terminates promptly and the race loser\r\n // carries no unhandled rejection (C# SuppressCancellationAwait spirit).\r\n this.delay = (retryCount, abortSignal) => {\r\n const delayMs = computeUpdateDelay(\r\n retryCount,\r\n this.ms,\r\n this.retryDelays,\r\n this.minDelay\r\n );\r\n if (delayMs <= 0) return Promise.resolve();\r\n\r\n return awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, delayMs);\r\n addCleanup(() => clearTimeout(timer));\r\n });\r\n };\r\n }\r\n}\r\n\r\nexport const defaultUpdateDelayer: UpdateDelayer = FixedDelayer.get(1000 / 60);\r\n","import { awaitWithCleanup, type RetryDelaySeq } from '@actuallab/core';\r\nimport { uiActions } from './ui-action-tracker.js';\r\nimport {\r\n computeUpdateDelay,\r\n defaultMinDelayMs,\r\n defaultRetryDelays,\r\n type UpdateDelayer,\r\n} from './update-delayer.js';\r\n\r\n/** Re-computes after a delay, but short-circuits while UIActionTracker enables instant updates. */\r\nexport class UIUpdateDelayer {\r\n private static _cache = new Map<number, UpdateDelayer>();\r\n\r\n // Floors ms at minDelay like C# FixedDelayer.Get — a zero delayer requires FixedDelayer.zero.\r\n static get(ms: number): UpdateDelayer {\r\n ms = Math.max(ms, defaultMinDelayMs);\r\n let delayer = UIUpdateDelayer._cache.get(ms);\r\n if (delayer !== undefined) return delayer;\r\n\r\n delayer = new UIUpdateDelayer(ms).delay;\r\n UIUpdateDelayer._cache.set(ms, delayer);\r\n return delayer;\r\n }\r\n\r\n readonly ms: number;\r\n readonly retryDelays: RetryDelaySeq;\r\n readonly minDelay: number;\r\n readonly delay: UpdateDelayer;\r\n\r\n constructor(\r\n ms: number,\r\n retryDelays: RetryDelaySeq = defaultRetryDelays,\r\n minDelay: number = defaultMinDelayMs\r\n ) {\r\n this.ms = ms;\r\n this.retryDelays = retryDelays;\r\n this.minDelay = minDelay;\r\n this.delay = this._delay.bind(this);\r\n }\r\n\r\n // Private methods\r\n\r\n // Mirrors C# UpdateDelayer.Delay: race the instant-updates window against the full delay,\r\n // then enforce minDelay measured from delay start so instant updates never hot-loop the CPU.\r\n private async _delay(retryCount: number, abortSignal?: AbortSignal): Promise<void> {\r\n const t = uiActions;\r\n const minDelay = retryCount === 0 ? this.minDelay : this.retryDelays.min;\r\n const delayMs = computeUpdateDelay(retryCount, this.ms, this.retryDelays, this.minDelay);\r\n if (delayMs <= 0)\r\n return;\r\n\r\n const startedAt = Date.now();\r\n if (!t.areInstantUpdatesEnabled())\r\n await awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, delayMs);\r\n addCleanup(() => clearTimeout(timer));\r\n\r\n const onChanged = () => {\r\n if (t.areInstantUpdatesEnabled())\r\n complete();\r\n };\r\n t.changed.add(onChanged);\r\n addCleanup(() => t.changed.remove(onChanged));\r\n });\r\n if (abortSignal?.aborted)\r\n return;\r\n\r\n const remaining = minDelay - (Date.now() - startedAt);\r\n if (remaining > 0)\r\n await awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, remaining);\r\n addCleanup(() => clearTimeout(timer));\r\n });\r\n }\r\n}\r\n","import { EventHandlerSet } from '@actuallab/core';\r\nimport { getLogs } from './logging.js';\r\n\r\nconst { errorLog } = getLogs('UIActionTracker');\r\n\r\n/** Singleton tracking active UI commands — mirrors .NET's UIActionTracker. */\r\nexport class UIActionTracker {\r\n private _activeCount = 0;\r\n private _lastResultAt = 0;\r\n private _errorTimes: number[] = [];\r\n readonly changed = new EventHandlerSet<void>();\r\n readonly errors: unknown[] = [];\r\n\r\n // C# UIActionTracker.Options.InstantUpdatePeriod / UIActionFailureTracker MaxDuplicateRecency.\r\n instantUpdatePeriod = 300;\r\n maxDuplicateRecency = 1000;\r\n maxErrors = 100;\r\n\r\n get isActive(): boolean {\r\n return this._activeCount > 0;\r\n }\r\n\r\n // C# UIActionTracker.AreInstantUpdatesEnabled — active, or within instantUpdatePeriod of the last result.\r\n areInstantUpdatesEnabled(): boolean {\r\n if (this._activeCount > 0)\r\n return true;\r\n if (this._lastResultAt === 0)\r\n return false;\r\n\r\n return this._lastResultAt + this.instantUpdatePeriod >= Date.now();\r\n }\r\n\r\n /** Run a command silently — errors are added to the error list but not thrown. */\r\n async run(fn: () => Promise<unknown>): Promise<void> {\r\n this._activeCount++;\r\n this.changed.trigger();\r\n try {\r\n await fn();\r\n } catch (e) {\r\n // Mirrors UIActionTracker.cs:58 — UI action failure.\r\n errorLog?.log('UI action failed', e);\r\n this._addError(e);\r\n } finally {\r\n this._onCompleted();\r\n }\r\n }\r\n\r\n /** Call a command and return the result — errors are added to the error list AND thrown. */\r\n async call<T>(fn: () => Promise<T>): Promise<T> {\r\n this._activeCount++;\r\n this.changed.trigger();\r\n try {\r\n return await fn();\r\n } catch (e) {\r\n // Mirrors UIActionTracker.cs:58 — UI action failure.\r\n errorLog?.log('UI action failed', e);\r\n this._addError(e);\r\n throw e;\r\n } finally {\r\n this._onCompleted();\r\n }\r\n }\r\n\r\n dismissError(index: number): void {\r\n if (index >= 0 && index < this.errors.length) {\r\n this.errors.splice(index, 1);\r\n this._errorTimes.splice(index, 1);\r\n this.changed.trigger();\r\n }\r\n }\r\n\r\n // Private methods\r\n\r\n private _onCompleted(): void {\r\n this._activeCount--;\r\n this._lastResultAt = Date.now();\r\n this.changed.trigger();\r\n }\r\n\r\n // C# UIActionFailureTracker.TryAddFailure — drop a same-name/same-message error seen within\r\n // maxDuplicateRecency; a size cap is the backstop against unbounded growth.\r\n private _addError(e: unknown): void {\r\n const now = Date.now();\r\n const { name, message } = errorInfo(e);\r\n const minAt = now - this.maxDuplicateRecency;\r\n for (let i = 0; i < this.errors.length; i++) {\r\n if (this._errorTimes[i] < minAt)\r\n continue;\r\n\r\n const prev = errorInfo(this.errors[i]);\r\n if (prev.name === name && prev.message === message)\r\n return;\r\n }\r\n\r\n this.errors.push(e);\r\n this._errorTimes.push(now);\r\n while (this.errors.length > this.maxErrors) {\r\n this.errors.shift();\r\n this._errorTimes.shift();\r\n }\r\n this.changed.trigger();\r\n }\r\n}\r\n\r\nfunction errorInfo(e: unknown): { name: string; message: string } {\r\n if (e instanceof Error)\r\n return { name: e.name, message: e.message };\r\n\r\n return { name: '', message: String(e) };\r\n}\r\n\r\nexport const uiActions = new UIActionTracker();\r\n","import {\r\n type AsyncContext,\r\n type IResult,\r\n PromiseSource,\r\n resolvedVoidPromise,\r\n type Result,\r\n} from '@actuallab/core';\r\nimport { type Computed, StateBoundComputed } from './computed.js';\r\n\r\n/** Base class for all reactive state types. */\r\nexport abstract class State<T> implements IResult<T> {\r\n protected _computed!: Computed<T>;\r\n protected _updateIndex = 0;\r\n // Reference to the last non-error computed, not its raw value, so an actual\r\n // `undefined` value is distinguishable from \"no non-error value yet\" (S12).\r\n protected _lastNonErrorComputed: Computed<T> | undefined;\r\n private _whenUpdatedSource: PromiseSource<void> | null = null;\r\n private _isDisposed = false;\r\n\r\n get updateIndex(): number {\r\n return this._updateIndex;\r\n }\r\n\r\n get isDisposed(): boolean {\r\n return this._isDisposed;\r\n }\r\n\r\n get lastNonErrorValue(): T | undefined {\r\n return this._lastNonErrorComputed?.value;\r\n }\r\n\r\n get hasValue(): boolean {\r\n return this._computed.hasValue;\r\n }\r\n\r\n get hasError(): boolean {\r\n return this._computed.hasError;\r\n }\r\n\r\n get value(): T {\r\n return this._computed.value;\r\n }\r\n\r\n get error(): unknown {\r\n return this._computed.error;\r\n }\r\n\r\n get valueOrUndefined(): T | undefined {\r\n return this._computed.valueOrUndefined;\r\n }\r\n\r\n get output(): Result<T> {\r\n return this._computed.output;\r\n }\r\n\r\n get computed(): Computed<T> {\r\n return this._computed;\r\n }\r\n\r\n use(asyncContext?: AsyncContext): T | Promise<T> {\r\n return this._computed.use(asyncContext);\r\n }\r\n\r\n useInconsistent(asyncContext?: AsyncContext): T {\r\n return this._computed.useInconsistent(asyncContext);\r\n }\r\n\r\n update(): Computed<T> | Promise<Computed<T>> {\r\n return this._computed.update();\r\n }\r\n\r\n recompute(): Computed<T> | Promise<Computed<T>> {\r\n this._computed.invalidate();\r\n return this.update();\r\n }\r\n\r\n whenInvalidated(): Promise<void> {\r\n return this._computed.whenInvalidated();\r\n }\r\n\r\n // Versioned wait: resolves at once when a newer generation than sinceIndex\r\n // already landed (no lost wakeup), rejects once disposed (C# StateSnapshot.WhenUpdated).\r\n whenUpdated(sinceIndex: number = this._updateIndex): Promise<void> {\r\n if (this._isDisposed)\r\n return Promise.reject(State._disposedError());\r\n if (this._updateIndex > sinceIndex)\r\n return resolvedVoidPromise;\r\n\r\n return (this._whenUpdatedSource ??= new PromiseSource<void>());\r\n }\r\n\r\n whenFirstTimeUpdated(): Promise<void> {\r\n return this.whenUpdated(0);\r\n }\r\n\r\n protected _initialize(\r\n output: Result<T> | T,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>\r\n ): void {\r\n this._computed = this._createComputed(renewer);\r\n this._computed.setOutput(output);\r\n if (this._computed.hasValue) this._lastNonErrorComputed = this._computed;\r\n }\r\n\r\n protected _createComputed(\r\n renewer?: () => Computed<T> | Promise<Computed<T>>\r\n ): Computed<T> {\r\n return new StateBoundComputed<T>(this, renewer);\r\n }\r\n\r\n protected _update(computed: Computed<T>, output: Result<T> | T): void {\r\n const replaced = this._computed as Computed<T> | undefined;\r\n computed.setOutput(output);\r\n this._computed = computed;\r\n if (replaced?.isConsistent) replaced.invalidate();\r\n if (computed.hasValue) this._lastNonErrorComputed = computed;\r\n this._updateIndex++;\r\n this._whenUpdatedSource?.resolve(undefined);\r\n this._whenUpdatedSource = null;\r\n }\r\n\r\n protected _onDisposed(): void {\r\n if (this._isDisposed)\r\n return;\r\n\r\n this._isDisposed = true;\r\n this._whenUpdatedSource?.reject(State._disposedError());\r\n this._whenUpdatedSource = null;\r\n }\r\n\r\n private static _disposedError(): Error {\r\n return new Error('State is disposed.');\r\n }\r\n}\r\n","import {\r\n AsyncContext,\r\n PromiseSource,\r\n type Result,\r\n result,\r\n errorResult,\r\n} from '@actuallab/core';\r\nimport { type Computed, StateBoundComputed } from './computed.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { getLogs } from './logging.js';\r\nimport { defaultUpdateDelayer, type UpdateDelayer } from './update-delayer.js';\r\nimport { State } from './state.js';\r\n\r\nconst { errorLog } = getLogs('ComputedState');\r\n\r\nexport type StateComputer<T> = () => T | Promise<T>;\r\n\r\n/** Constructor options for ComputedState. */\r\nexport interface ComputedStateOptions<T> {\r\n initialValue?: T;\r\n initialOutput?: Result<T>;\r\n updateDelayer?: UpdateDelayer;\r\n}\r\n\r\n/** Auto-updating reactive state wrapper — re-computes on invalidation with configurable delay. */\r\nexport class ComputedState<T> extends State<T> {\r\n private _computer: StateComputer<T>;\r\n private _updateDelayer: UpdateDelayer;\r\n private _disposeController: AbortController;\r\n private _cancelDelaySource = new PromiseSource<void>();\r\n private _renewer: () => Computed<T> | Promise<Computed<T>>;\r\n\r\n constructor(computer: StateComputer<T>, options?: ComputedStateOptions<T>) {\r\n super();\r\n this._computer = computer;\r\n this._updateDelayer = options?.updateDelayer ?? defaultUpdateDelayer;\r\n this._disposeController = new AbortController();\r\n this._renewer = async () => {\r\n const sinceIndex = this._updateIndex;\r\n this._cancelDelaySource.resolve(undefined);\r\n await this.whenUpdated(sinceIndex);\r\n return this._computed;\r\n };\r\n\r\n // The initial computed is created pre-invalidated (C# State.cs:246) so inherited\r\n // members (use/update/recompute/whenInvalidated) await the first real computation\r\n // instead of returning the placeholder, and dependants never latch onto it.\r\n this._initialize(\r\n options?.initialOutput ?? (options?.initialValue as T),\r\n this._renewer\r\n );\r\n this._computed.invalidate();\r\n\r\n void this._updateCycle();\r\n }\r\n\r\n dispose(): void {\r\n if (this.isDisposed)\r\n return;\r\n\r\n this._onDisposed();\r\n this._disposeController.abort();\r\n }\r\n\r\n private async _updateCycle(): Promise<void> {\r\n const disposeSignal = this._disposeController.signal;\r\n let retryCount = 0;\r\n try {\r\n while (!disposeSignal.aborted) {\r\n // Compute\r\n const computed = new StateBoundComputed<T>(this, this._renewer);\r\n const computeCtx = new ComputeContext(\r\n computed as StateBoundComputed<unknown>\r\n );\r\n const asyncCtx = (\r\n AsyncContext.current ?? AsyncContext.empty\r\n ).with(computeContextKey, computeCtx);\r\n\r\n let output: Result<T>;\r\n try {\r\n const value = asyncCtx.run(() => this._computer());\r\n const resolved =\r\n value instanceof Promise ? await value : value;\r\n output = result(resolved);\r\n } catch (e) {\r\n output = errorResult(e);\r\n }\r\n if (this.isDisposed)\r\n return; // Disposed mid-computation — publish nothing, terminate the cycle.\r\n\r\n this._update(computed, output);\r\n retryCount = output.hasError ? retryCount + 1 : 0;\r\n if (this._cancelDelaySource.isCompleted)\r\n this._cancelDelaySource = new PromiseSource<void>();\r\n\r\n // Wait for invalidation (or cancellation via dispose)\r\n try {\r\n await computed.whenInvalidated(disposeSignal);\r\n } catch {\r\n return; // Cancelled via dispose\r\n }\r\n\r\n // Wait for delay (cancellable by renewer); retryCount grows the backoff (S8).\r\n await Promise.race([\r\n this._updateDelayer(retryCount, disposeSignal),\r\n this._cancelDelaySource,\r\n ]);\r\n }\r\n } catch (e) {\r\n // Mirrors ComputedState.cs:188 — UpdateCycle failed and stopped.\r\n if (!disposeSignal.aborted)\r\n errorLog?.log('UpdateCycle() failed and stopped', e);\r\n }\r\n }\r\n}\r\n","import { type AsyncContext, Result, result } from '@actuallab/core';\r\nimport { type Computed } from './computed.js';\r\nimport { State } from './state.js';\r\n\r\n/** Manually-settable reactive state that can participate in the Fusion dependency graph. */\r\nexport class MutableState<T> extends State<T> {\r\n private _nextOutput: Result<T>;\r\n\r\n private _renewer = (): Computed<T> => {\r\n const computed = this._createComputed(this._renewer);\r\n this._update(computed, this._nextOutput);\r\n this._wireRenewal(computed);\r\n return computed;\r\n };\r\n\r\n constructor(initialOutput: Result<T> | T) {\r\n super();\r\n this._nextOutput =\r\n initialOutput instanceof Result ? initialOutput : result(initialOutput);\r\n this._initialize(this._nextOutput, this._renewer);\r\n this._wireRenewal(this._computed);\r\n }\r\n\r\n override use(asyncContext?: AsyncContext): T {\r\n return this._computed.use(asyncContext) as T;\r\n }\r\n\r\n set(output: Result<T> | T): void {\r\n const next = output instanceof Result ? output : result(output);\r\n if (this._nextOutput.equals(next))\r\n return;\r\n\r\n this._nextOutput = next;\r\n this._computed.invalidate();\r\n }\r\n\r\n // Private methods\r\n\r\n // Renew synchronously on invalidation so a MutableState is never observed invalidated.\r\n // update() de-dupes: if the computed was already renewed, it returns the latest instead.\r\n private _wireRenewal(computed: Computed<T>): void {\r\n computed.onInvalidated(() => void computed.update());\r\n }\r\n}\r\n"],"mappings":"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","names":["import_core","import_core","ConsistencyState","captured","import_core","import_core","import_core","import_core","import_core","errorLog","import_core","import_core","errorLog","import_core"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/logging.ts","../src/computed-input.ts","../src/computed.ts","../src/computed-registry.ts","../src/compute-context.ts","../src/computed-options.ts","../src/compute-function.ts","../src/compute-method.ts","../src/update-delayer.ts","../src/ui-update-delayer.ts","../src/ui-action-tracker.ts","../src/state.ts","../src/computed-state.ts","../src/mutable-state.ts"],"sourcesContent":["export type { FusionLogScope } from './logging.js';\r\nexport { getLogs } from './logging.js';\r\n\r\nexport { getInstanceId } from './computed-input.js';\r\nexport type { ComputedInput } from './computed-input.js';\r\nexport { Computed, StateBoundComputed, ConsistencyState } from './computed.js';\r\nexport { ComputedOptions } from './computed-options.js';\r\nexport { ComputeContext, computeContextKey } from './compute-context.js';\r\nexport { ComputedRegistry } from './computed-registry.js';\r\nexport { ComputeFunction } from './compute-function.js';\r\nexport type { ComputeFunctionImpl } from './compute-function.js';\r\nexport {\r\n computeMethod,\r\n wrapComputeMethod,\r\n getMethodsMeta,\r\n} from './compute-method.js';\r\nexport type { MethodMeta, ComputeMethodOptions } from './compute-method.js';\r\nexport type { UpdateDelayer } from './update-delayer.js';\r\nexport { FixedDelayer, defaultUpdateDelayer } from './update-delayer.js';\r\nexport { UIUpdateDelayer } from './ui-update-delayer.js';\r\nexport { UIActionTracker, uiActions } from './ui-action-tracker.js';\r\nexport { State } from './state.js';\r\nexport { ComputedState } from './computed-state.js';\r\nexport type { ComputedStateOptions, StateComputer } from './computed-state.js';\r\nexport { MutableState } from './mutable-state.js';\r\n","import { createLogProvider, LogLevel } from '@actuallab/core';\n\n// Per-package log scopes. Use createLogProvider to get a typed helper:\n// const { debugLog, warnLog } = getLogs('Computed');\n// Final scope name is 'fusion.Computed' — the prefix isolates this package's\n// scopes from other packages' scopes when overriding levels at runtime.\nexport type FusionLogScope =\n | 'Computed'\n | 'ComputedRegistry'\n | 'ComputedState'\n | 'ComputeFunction'\n | 'MutableState'\n | 'State'\n | 'UIActionTracker'\n | 'UIUpdateDelayer';\n\n// Per-scope defaults. All Warn — Fusion is mostly hot-path compute graph code;\n// noisy scopes need to be opted-in for development.\nconst scopeDefaults: Record<FusionLogScope, LogLevel> = {\n Computed: LogLevel.Warn,\n ComputedRegistry: LogLevel.Warn,\n ComputedState: LogLevel.Warn,\n ComputeFunction: LogLevel.Warn,\n MutableState: LogLevel.Warn,\n State: LogLevel.Warn,\n UIActionTracker: LogLevel.Warn,\n UIUpdateDelayer: LogLevel.Warn,\n};\n\nexport const getLogs = createLogProvider<FusionLogScope>('fusion.', scopeDefaults);\n","import type { State } from './state.js';\r\n\r\n/** Auto-assigned numeric IDs for instance identity in compute method cache keys. */\r\nlet _nextInstanceId = 0;\r\nconst _instanceIds = new WeakMap<object, number>();\r\n\r\nexport function getInstanceId(instance: object): number {\r\n let id = _instanceIds.get(instance);\r\n if (id === undefined) {\r\n id = ++_nextInstanceId;\r\n _instanceIds.set(instance, id);\r\n }\r\n return id;\r\n}\r\n\r\n/**\r\n * Identity key for any computed value.\r\n * - String for compute method results (built from instance + function + args)\r\n * - State for state types (identity by reference)\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type ComputedInput = string | State<any>;\r\n","import {\r\n AsyncContext,\r\n EventHandlerSet,\r\n type IResult,\r\n isCancellation,\r\n PromiseSource,\r\n Result,\r\n result,\r\n} from '@actuallab/core';\r\nimport type { ComputedInput } from './computed-input.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { getLogs } from './logging.js';\r\nimport type { State } from './state.js';\r\n\r\nconst { errorLog } = getLogs('Computed');\r\n\r\nlet _nextVersion = 0;\r\n\r\n// A dependant drops its own edges only when it's invalidated, so a dependency that\r\n// outlives many dependants accumulates dead WeakRefs. .NET reclaims them from the\r\n// background ComputedGraphPruner; TS has no worker, so pruning is amortized into\r\n// addDependency and the threshold doubles past the surviving edge count each time.\r\nconst MinPruneDependantsThreshold = 16;\r\n\r\nexport const enum ConsistencyState {\r\n Computing = 0,\r\n Consistent = 1,\r\n Invalidated = 2,\r\n}\r\n\r\n/** Core Fusion abstraction — a cached computation with dependency tracking and invalidation. */\r\nexport class Computed<T> implements IResult<T> {\r\n /** Capture the Computed backing a computation — works with both local and RPC compute methods. */\r\n static async capture<T>(fn: () => T | Promise<T>): Promise<Computed<T>> {\r\n // A capture context (no computed) records the last captured Computed without adding\r\n // dependant edges — mirrors C# ComputeContext(CallOptions.Capture) + Computed.Capture.\r\n // The parent link keeps reentrancy detection working through capture — in C# lock\r\n // reentry flows through ExecutionContext regardless of BeginCapture.\r\n const currentCtx = AsyncContext.getOrCreate();\r\n const captureCtx = new ComputeContext(\r\n undefined,\r\n currentCtx.get(computeContextKey)\r\n );\r\n const asyncCtx = currentCtx.with(computeContextKey, captureCtx);\r\n try {\r\n await asyncCtx.run(fn);\r\n } catch (e) {\r\n if (isCancellation(e)) throw e;\r\n const captured = captureCtx.captured;\r\n if (captured?.hasError) return captured as Computed<T>;\r\n\r\n throw e;\r\n }\r\n const captured = captureCtx.captured;\r\n if (captured === undefined)\r\n throw new Error(\r\n 'No Computed was captured — fn must call a compute function.'\r\n );\r\n return captured as Computed<T>;\r\n }\r\n\r\n readonly input: ComputedInput;\r\n readonly options: ComputedOptions;\r\n private _version: number;\r\n private _state: ConsistencyState;\r\n private _output: Result<T> | undefined;\r\n private _invalidatePending = false;\r\n private _errorTimer: ReturnType<typeof setTimeout> | undefined;\r\n private _dependencies = new Set<Computed<unknown>>();\r\n private _dependants = new Map<number, WeakRef<Computed<unknown>>>();\r\n private _pruneDependantsThreshold = MinPruneDependantsThreshold;\r\n private _onInvalidated = new EventHandlerSet<void>();\r\n readonly _renewer: (() => Computed<T> | Promise<Computed<T>>) | undefined;\r\n\r\n constructor(\r\n input: ComputedInput,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>,\r\n options: ComputedOptions = ComputedOptions.default\r\n ) {\r\n this.input = input;\r\n this.options = options;\r\n this._renewer = renewer;\r\n this._version = ++_nextVersion;\r\n this._state = ConsistencyState.Computing;\r\n }\r\n\r\n get version(): number {\r\n return this._version;\r\n }\r\n\r\n get output(): Result<T> {\r\n if (this._output === undefined)\r\n throw new Error('Computed has no output yet.');\r\n return this._output;\r\n }\r\n\r\n get hasValue(): boolean {\r\n return this.output.hasValue;\r\n }\r\n\r\n get hasError(): boolean {\r\n return this.output.hasError;\r\n }\r\n\r\n get value(): T {\r\n return this.output.value;\r\n }\r\n\r\n get error(): unknown {\r\n return this.output.error;\r\n }\r\n\r\n get valueOrUndefined(): T | undefined {\r\n return this.output.valueOrUndefined;\r\n }\r\n\r\n get state(): ConsistencyState {\r\n return this._state;\r\n }\r\n\r\n get isConsistent(): boolean {\r\n return this._state === ConsistencyState.Consistent;\r\n }\r\n\r\n get isComputing(): boolean {\r\n return this._state === ConsistencyState.Computing;\r\n }\r\n\r\n get dependencies(): ReadonlySet<Computed<unknown>> {\r\n return this._dependencies;\r\n }\r\n\r\n get dependantCount(): number {\r\n return this._dependants.size;\r\n }\r\n\r\n update(): Computed<T> | Promise<Computed<T>> {\r\n if (this._state === ConsistencyState.Consistent) return this;\r\n const latest = this._latest();\r\n if (latest?.isConsistent) return latest;\r\n if (this._renewer !== undefined) {\r\n const renewer = this._renewer;\r\n // Run the renewer with the compute context cleared so renewal never\r\n // records a dependency edge in the ambient computation — TS analog of\r\n // C# Computed.UpdateUntyped's BeginIsolation.\r\n const isolated = (AsyncContext.current ?? AsyncContext.empty).with(\r\n computeContextKey,\r\n undefined\r\n );\r\n return isolated.run(renewer);\r\n }\r\n throw new Error(\r\n 'Cannot recompute: Computed is invalidated and has no renewer.'\r\n );\r\n }\r\n\r\n protected _latest(): Computed<T> | undefined {\r\n return ComputedRegistry.get(this.input as string) as\r\n | Computed<T>\r\n | undefined;\r\n }\r\n\r\n use(asyncContext?: AsyncContext): T | Promise<T> {\r\n const ctx = ComputeContext.from(asyncContext);\r\n const updated = this.update();\r\n if (updated instanceof Promise) {\r\n return updated.then(c => {\r\n ctx?.captureDependency(c as Computed<unknown>);\r\n return c.value;\r\n });\r\n }\r\n ctx?.captureDependency(updated as Computed<unknown>);\r\n return updated.value;\r\n }\r\n\r\n useInconsistent(asyncContext?: AsyncContext): T {\r\n ComputeContext.from(asyncContext)?.captureDependency(\r\n this as Computed<unknown>\r\n );\r\n return this.value;\r\n }\r\n\r\n setOutput(output: Result<T> | T): void {\r\n if (this._state !== ConsistencyState.Computing)\r\n throw new Error('Cannot set output on a non-computing Computed.');\r\n this._output = output instanceof Result ? output : result(output);\r\n this._state = ConsistencyState.Consistent;\r\n this._register();\r\n if (this._invalidatePending) {\r\n this._invalidatePending = false;\r\n this.invalidate();\r\n return;\r\n }\r\n\r\n const delay = this.options.errorAutoInvalidateDelay;\r\n if (this._output.hasError && delay !== Infinity && delay > 0) {\r\n this._errorTimer = setTimeout(() => this.invalidate(), delay);\r\n (this._errorTimer as { unref?: () => void }).unref?.();\r\n }\r\n }\r\n\r\n protected _register(): void {\r\n ComputedRegistry.register(this as Computed<unknown>);\r\n }\r\n\r\n protected _unregister(): void {\r\n ComputedRegistry.unregister(this as Computed<unknown>);\r\n }\r\n\r\n // Never throws — mirrors .NET Computed.Invalidate: own handlers fire first\r\n // (each isolated), then dependants propagate unconditionally, then unregister.\r\n invalidate(): void {\r\n if (this._state === ConsistencyState.Invalidated)\r\n return;\r\n if (this._state === ConsistencyState.Computing) {\r\n // Defer until setOutput transitions to Consistent — matches .NET, where\r\n // invalidating a still-computing Computed sets a pending flag.\r\n this._invalidatePending = true;\r\n return;\r\n }\r\n this._state = ConsistencyState.Invalidated;\r\n if (this._errorTimer !== undefined) {\r\n clearTimeout(this._errorTimer);\r\n this._errorTimer = undefined;\r\n }\r\n try {\r\n this._onInvalidated.triggerSafe(undefined, e =>\r\n errorLog?.log('onInvalidated handler failed', e)\r\n );\r\n this._onInvalidated.clear();\r\n } finally {\r\n for (const dependency of this._dependencies)\r\n dependency._dependants.delete(this._version);\r\n this._dependencies.clear();\r\n\r\n for (const [, ref] of this._dependants) {\r\n const dependant = ref.deref();\r\n if (dependant != null) {\r\n try {\r\n dependant.invalidate();\r\n } catch (e) {\r\n errorLog?.log('Error while invalidating dependant', e);\r\n }\r\n }\r\n }\r\n this._dependants.clear();\r\n\r\n this._unregister();\r\n }\r\n }\r\n\r\n onInvalidated(handler: () => void): void {\r\n if (this._state === ConsistencyState.Invalidated) {\r\n handler();\r\n return;\r\n }\r\n this._onInvalidated.add(handler);\r\n }\r\n\r\n whenInvalidated(abortSignal?: AbortSignal): Promise<void> {\r\n if (this._state === ConsistencyState.Invalidated)\r\n return Promise.resolve();\r\n if (abortSignal?.aborted)\r\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- reason falls back to an Error; abortSignal.reason mirrors throwIfAborted()\r\n return Promise.reject(\r\n abortSignal.reason ?? new Error('Operation cancelled.')\r\n );\r\n\r\n const ps = new PromiseSource<void>();\r\n let onAbort: (() => void) | undefined;\r\n const onInvalidated = () => {\r\n if (onAbort !== undefined)\r\n abortSignal!.removeEventListener('abort', onAbort);\r\n ps.resolve(undefined);\r\n };\r\n this._onInvalidated.add(onInvalidated);\r\n if (abortSignal !== undefined) {\r\n onAbort = () => {\r\n this._onInvalidated.remove(onInvalidated);\r\n ps.reject(\r\n abortSignal.reason ?? new Error('Operation cancelled.')\r\n );\r\n };\r\n abortSignal.addEventListener('abort', onAbort, { once: true });\r\n }\r\n\r\n return ps;\r\n }\r\n\r\n addDependency(dependency: Computed<unknown>): void {\r\n if (this._state !== ConsistencyState.Computing)\r\n return;\r\n if (dependency._state === ConsistencyState.Invalidated) {\r\n this.invalidate();\r\n return;\r\n }\r\n this._dependencies.add(dependency);\r\n dependency._dependants.set(\r\n this._version,\r\n new WeakRef(this as Computed<unknown>)\r\n );\r\n if (dependency._dependants.size >= dependency._pruneDependantsThreshold)\r\n dependency.pruneDependants();\r\n }\r\n\r\n // Port of .NET Computed.PruneDependants: drops edges to dependants that were\r\n // collected or already invalidated. `_dependants` is keyed by the dependant's\r\n // unique version, so .NET's \"still the registered version\" check is implicit.\r\n pruneDependants(): void {\r\n if (this._state !== ConsistencyState.Consistent)\r\n return;\r\n\r\n for (const [version, ref] of this._dependants) {\r\n const dependant = ref.deref();\r\n if (dependant === undefined || dependant._state === ConsistencyState.Invalidated)\r\n this._dependants.delete(version);\r\n }\r\n this._pruneDependantsThreshold = Math.max(\r\n MinPruneDependantsThreshold,\r\n this._dependants.size * 2\r\n );\r\n }\r\n}\r\n\r\n/** Computed variant for State types — skips registry registration since the State holds a direct reference. */\r\nexport class StateBoundComputed<T> extends Computed<T> {\r\n constructor(\r\n input: ComputedInput,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>,\r\n options: ComputedOptions = ComputedOptions.mutableStateDefault\r\n ) {\r\n super(input, renewer, options);\r\n }\r\n\r\n protected override _latest(): Computed<T> | undefined {\r\n return (this.input as State<T>).computed;\r\n }\r\n\r\n protected override _register(): void {\r\n // No registration — state holds direct reference\r\n }\r\n\r\n protected override _unregister(): void {\r\n // No unregistration — was never registered\r\n }\r\n}\r\n","import { type Computed, ConsistencyState } from './computed.js';\r\n\r\n/** Identifies the exact registry entry a finalizer callback is allowed to remove. */\r\ninterface FinalizationToken {\r\n key: string;\r\n ref: WeakRef<Computed<unknown>>;\r\n}\r\n\r\n/** WeakRef-based global cache of Computed instances — allows GC of unused computed values. */\r\nexport class ComputedRegistry {\r\n private static _entries = new Map<string, WeakRef<Computed<unknown>>>();\r\n private static _finalization = new FinalizationRegistry<FinalizationToken>(token => {\r\n ComputedRegistry._onFinalized(token);\r\n });\r\n\r\n static get size(): number {\r\n return ComputedRegistry._entries.size;\r\n }\r\n\r\n static get(key: string): Computed<unknown> | undefined {\r\n const ref = ComputedRegistry._entries.get(key);\r\n if (ref === undefined) return undefined;\r\n const computed = ref.deref();\r\n if (computed === undefined) {\r\n ComputedRegistry._removeEntry(key, ref);\r\n return undefined;\r\n }\r\n return computed;\r\n }\r\n\r\n static register(computed: Computed<unknown>): void {\r\n const key = computed.input as string;\r\n const displaced = ComputedRegistry._entries.get(key)?.deref();\r\n // Already registered — setOutput re-registers the instance registered at creation\r\n if (displaced === computed)\r\n return;\r\n\r\n if (displaced !== undefined && displaced.state !== ConsistencyState.Invalidated)\r\n displaced.invalidate();\r\n const ref = new WeakRef(computed);\r\n ComputedRegistry._entries.set(key, ref);\r\n ComputedRegistry._finalization.register(computed, { key, ref }, computed);\r\n }\r\n\r\n static unregister(computed: Computed<unknown>): void {\r\n const key = computed.input as string;\r\n if (ComputedRegistry._entries.get(key)?.deref() === computed)\r\n ComputedRegistry._entries.delete(key);\r\n ComputedRegistry._finalization.unregister(computed);\r\n }\r\n\r\n // Private methods\r\n\r\n private static _onFinalized(token: FinalizationToken): void {\r\n ComputedRegistry._removeEntry(token.key, token.ref);\r\n }\r\n\r\n // Removing by key alone would drop a live successor registered under the same key\r\n // while this key's predecessor was already collected but not yet finalized (I13).\r\n private static _removeEntry(key: string, ref: WeakRef<Computed<unknown>>): void {\r\n if (ComputedRegistry._entries.get(key) === ref)\r\n ComputedRegistry._entries.delete(key);\r\n }\r\n}\r\n","import { AsyncContext, AsyncContextKey } from '@actuallab/core';\r\nimport type { Computed } from './computed.js';\r\n\r\nexport const computeContextKey = new AsyncContextKey<\r\n ComputeContext | undefined\r\n>('ComputeContext', undefined);\r\n\r\n/**\r\n * Tracks the currently executing (or captured) computation and captures dependencies.\r\n * A context with a `computed` is a computing context (adds dependant edges); one without\r\n * is a capture context (records the last captured Computed only — no edges).\r\n */\r\nexport class ComputeContext {\r\n readonly computed: Computed<unknown> | undefined;\r\n readonly parent: ComputeContext | undefined;\r\n private _isCapturing = true;\r\n private _captured: Computed<unknown> | undefined;\r\n\r\n constructor(\r\n computed?: Computed<unknown>,\r\n parent?: ComputeContext\r\n ) {\r\n this.computed = computed;\r\n this.parent = parent;\r\n }\r\n\r\n get isCapturing(): boolean {\r\n return this._isCapturing;\r\n }\r\n\r\n get captured(): Computed<unknown> | undefined {\r\n return this._captured;\r\n }\r\n\r\n stopCapturing(): void {\r\n this._isCapturing = false;\r\n }\r\n\r\n captureDependency(dependency: Computed<unknown>): void {\r\n if (!this._isCapturing) return;\r\n // Last capture wins — C# ComputeContext.TryCapture overwrites _captured.\r\n this._captured = dependency;\r\n this.computed?.addDependency(dependency);\r\n }\r\n\r\n // Walks the caller chain for a computation still in progress under the same key —\r\n // C# AsyncLockSet(LockReentryMode.CheckedFail) analog, used to fail fast on reentry.\r\n // Only Computing ancestors count: a context leaked past its finished computation\r\n // (e.g. via AsyncLocalStorage into a later callback) must not fail later calls.\r\n hasKeyInChain(key: unknown): boolean {\r\n const computed = this.computed;\r\n if (computed?.isComputing === true && computed.input === key)\r\n return true;\r\n\r\n return this.parent?.hasKeyInChain(key) ?? false;\r\n }\r\n\r\n /** Resolve ComputeContext from an AsyncContext (or current). */\r\n static from(ctx: AsyncContext | undefined): ComputeContext | undefined {\r\n return AsyncContext.from(ctx)?.get(computeContextKey);\r\n }\r\n}\r\n","/**\r\n * Per-Computed configuration, carried by every {@link Computed} via its\r\n * {@link ComputeFunction} (compute methods) or its kind's static default.\r\n * The home for per-method knobs; the C# analog is `ActualLab.Fusion.ComputedOptions`.\r\n */\r\nexport class ComputedOptions {\r\n static default = new ComputedOptions();\r\n static mutableStateDefault = new ComputedOptions({\r\n errorAutoInvalidateDelay: Infinity,\r\n });\r\n\r\n readonly errorAutoInvalidateDelay: number;\r\n\r\n constructor(overrides?: Partial<ComputedOptions>) {\r\n this.errorAutoInvalidateDelay =\r\n overrides?.errorAutoInvalidateDelay ?? 1000;\r\n }\r\n}\r\n","import {\r\n AsyncContext,\r\n AsyncLock,\r\n isCancellation,\r\n type Result,\r\n result,\r\n errorResult,\r\n} from '@actuallab/core';\r\nimport { Computed } from './computed.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { getInstanceId } from './computed-input.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type ComputeFunctionImpl = (this: any, ...args: unknown[]) => unknown;\r\n\r\n/** Record Separator — delimiter between key components. */\r\nconst RS = '\\x1E';\r\n\r\n// Keying is by JSON.stringify per argument, joined with RS delimiters. Collisions are\r\n// possible and by design (D2): functions, undefined, and symbols all map to '', objects\r\n// without serializable props to '{}', NaN to 'null', Map/Set to '{}'. The compute method's\r\n// author owns keyability — use JSON-representable argument types or supply a custom argToString.\r\nfunction defaultArgToString(arg: unknown): string {\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JSON.stringify returns undefined for undefined input\r\n return JSON.stringify(arg) ?? '';\r\n}\r\n\r\nlet _nextFunctionId = 0;\r\n\r\n/** Produces Computed<T> from a function — handles cache lookup, locking, dependency capture. */\r\nexport class ComputeFunction {\r\n readonly methodName: string;\r\n readonly id: string;\r\n readonly options: ComputedOptions;\r\n argToString: (arg: unknown) => string = defaultArgToString;\r\n private _impl: ComputeFunctionImpl;\r\n private _locks = new Map<string, AsyncLock>();\r\n\r\n constructor(\r\n methodName: string,\r\n impl: ComputeFunctionImpl,\r\n options: ComputedOptions = ComputedOptions.default\r\n ) {\r\n this.methodName = methodName;\r\n this.id = `${methodName}[${++_nextFunctionId}]`;\r\n this._impl = impl;\r\n this.options = options;\r\n }\r\n\r\n /** Build a string key for the given instance and arguments. */\r\n buildKey(instance: object, args: unknown[]): string {\r\n let key = String(getInstanceId(instance)) + RS + this.id;\r\n for (const arg of args) {\r\n key += RS + this.argToString(arg);\r\n }\r\n return key;\r\n }\r\n\r\n async invoke(\r\n instance: object,\r\n args: unknown[]\r\n ): Promise<Computed<unknown>> {\r\n // 1. Resolve AsyncContext ONCE via DRY helper\r\n const asyncCtx = AsyncContext.fromArgs(args);\r\n\r\n // 2. Pull caller's ComputeContext directly\r\n const callerComputeCtx = asyncCtx?.get(computeContextKey);\r\n\r\n // 3. Strip THIS context from args (reference equality — safe)\r\n const argsWithoutCtx = asyncCtx?.stripFromArgs(args) ?? args;\r\n\r\n // 4. Build string key and check cache\r\n const key = this.buildKey(instance, argsWithoutCtx);\r\n const existing = ComputedRegistry.get(key);\r\n if (existing?.isConsistent) {\r\n callerComputeCtx?.captureDependency(existing);\r\n return existing;\r\n }\r\n\r\n // C# AsyncLockSet(CheckedFail) analog: a compute call that (indirectly) awaits itself\r\n // with the same key would await its own non-reentrant lock forever — fail fast instead.\r\n if (callerComputeCtx?.hasKeyInChain(key))\r\n throw new Error(`Reentrant compute call detected for key \"${key}\".`);\r\n\r\n // 5. Lock per key to prevent duplicate computations\r\n let lock = this._locks.get(key);\r\n if (lock === undefined) {\r\n lock = new AsyncLock();\r\n this._locks.set(key, lock);\r\n }\r\n\r\n const computed = await lock.run(async () => {\r\n // Double-check after acquiring lock\r\n const cached = ComputedRegistry.get(key);\r\n if (cached?.isConsistent) return cached;\r\n\r\n // 6. Create new Computed + ComputeContext\r\n const renewer = () => this.invoke(instance, argsWithoutCtx);\r\n const newComputed = new Computed<unknown>(\r\n key,\r\n renewer,\r\n this.options\r\n );\r\n // Register while still Computing so ComputedRegistry.get(key) resolves the\r\n // in-flight instance and a racing invalidate() is captured as pending — C#\r\n // ComputeMethodComputed registers in its constructor.\r\n ComputedRegistry.register(newComputed);\r\n\r\n const childComputeCtx = new ComputeContext(\r\n newComputed,\r\n callerComputeCtx\r\n );\r\n const childAsyncCtx = (asyncCtx ?? AsyncContext.empty).with(\r\n computeContextKey,\r\n childComputeCtx\r\n );\r\n\r\n // 7. Run with clean args, threading childAsyncCtx as a trailing argument so a compute\r\n // body can pass it into nested calls / use(ctx) after awaits — the portable floor for\r\n // dependency capture when AsyncLocalStorage isn't backing AsyncContext.current (browsers).\r\n let fnResult: Result<unknown>;\r\n try {\r\n const value = childAsyncCtx.run(() =>\r\n this._impl.call(instance, ...argsWithoutCtx, childAsyncCtx)\r\n );\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\r\n const resolved = value instanceof Promise ? await value : value;\r\n fnResult = result(resolved);\r\n } catch (e) {\r\n fnResult = errorResult(e);\r\n }\r\n\r\n newComputed.setOutput(fnResult);\r\n // C# StartAutoInvalidation OCE parity: a cancellation error is registered to keep the\r\n // single-flight lock protocol intact, then invalidated at once so it's never cached.\r\n if (fnResult.hasError && isCancellation(fnResult.error))\r\n newComputed.invalidate();\r\n\r\n return newComputed;\r\n });\r\n\r\n if (!lock.isLocked && this._locks.get(key) === lock)\r\n this._locks.delete(key);\r\n\r\n // Register dependency from caller to the produced computed\r\n callerComputeCtx?.captureDependency(computed);\r\n return computed;\r\n }\r\n}\r\n","/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-this-alias */\r\nimport { ownMetadata, resolveArgCount } from '@actuallab/core';\r\nimport { ComputeFunction } from './compute-function.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\n\r\nconst METHODS_META = Symbol.for('actuallab.methods');\r\n\r\nexport interface MethodMeta {\r\n argCount: number;\r\n compute?: boolean;\r\n stream?: boolean;\r\n}\r\n\r\n/** Read method metadata from a decorated class. */\r\nexport function getMethodsMeta(\r\n cls: abstract new (...args: any[]) => any\r\n): Record<string, MethodMeta> | undefined {\r\n return (cls as any)[Symbol.metadata]?.[METHODS_META];\r\n}\r\n\r\nexport interface ComputeMethodOptions extends Partial<ComputedOptions> {\r\n argCount?: number;\r\n}\r\n\r\ntype ComputeMethodDecorator<This, Args extends unknown[], Return> = (\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n) => (this: This, ...args: Args) => Return;\r\n\r\n/**\r\n * Method decorator — routes a method through ComputeFunction for caching and dependency\r\n * tracking. Usable bare (`@computeMethod`) or with options (`@computeMethod({ argCount })`).\r\n */\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n): (this: This, ...args: Args) => Return;\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n options?: ComputeMethodOptions\r\n): ComputeMethodDecorator<This, Args, Return>;\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n targetOrOptions?: ((this: This, ...args: Args) => Return) | ComputeMethodOptions,\r\n context?: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n): unknown {\r\n if (typeof targetOrOptions === 'function')\r\n return computeMethodImpl(targetOrOptions, context!, {});\r\n\r\n const options = targetOrOptions ?? {};\r\n return (target: (this: This, ...args: Args) => Return, ctx: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>) =>\r\n computeMethodImpl(target, ctx, options);\r\n}\r\n\r\nfunction computeMethodImpl<This, Args extends unknown[], Return>(\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<\r\n This,\r\n (this: This, ...args: Args) => Return\r\n >,\r\n options: ComputeMethodOptions\r\n): (this: This, ...args: Args) => Return {\r\n const methodName = String(context.name);\r\n\r\n const methods = ownMetadata<Record<string, MethodMeta>>(context.metadata, METHODS_META);\r\n methods[methodName] = {\r\n ...methods[methodName],\r\n compute: true,\r\n argCount: resolveArgCount(target, options.argCount, methodName),\r\n };\r\n\r\n // ONE ComputeFunction per class×method — created at decoration time\r\n const cf = new ComputeFunction(methodName, target as any, new ComputedOptions(options));\r\n\r\n // Prototype-level replacement — unwraps Computed to return the value directly\r\n const replacement = function (this: This, ...allArgs: Args): Return {\r\n return cf.invoke(this as object, allArgs).then(c => c.value) as Return;\r\n };\r\n\r\n // Per-instance setup: create bound method with .invalidate pre-bound\r\n context.addInitializer(function (this: This) {\r\n const instance = this;\r\n const boundMethod = (...allArgs: unknown[]) => {\r\n return cf.invoke(instance as object, allArgs).then(c => c.value);\r\n };\r\n (boundMethod as any).invalidate = (...args: unknown[]) => {\r\n const key = cf.buildKey(instance as object, args);\r\n ComputedRegistry.get(key)?.invalidate();\r\n };\r\n (this as any)[methodName] = boundMethod;\r\n });\r\n\r\n return replacement;\r\n}\r\n\r\n/** Wrap a standalone function as a compute function with caching and .invalidate(). */\r\nexport function wrapComputeMethod<Args extends unknown[], Return>(\r\n fn: (...args: Args) => Return\r\n): ((...args: Args) => Promise<Return>) & {\r\n invalidate: (...args: Args) => void;\r\n} {\r\n const syntheticInstance = {};\r\n const methodName = fn.name || 'anonymous';\r\n const cf = new ComputeFunction(methodName, fn as any);\r\n\r\n const wrapped = (...allArgs: unknown[]) => {\r\n return cf\r\n .invoke(syntheticInstance, allArgs)\r\n .then(c => c.value as Return);\r\n };\r\n\r\n (wrapped as any).invalidate = (...args: unknown[]) => {\r\n const key = cf.buildKey(syntheticInstance, args);\r\n ComputedRegistry.get(key)?.invalidate();\r\n };\r\n\r\n return wrapped as any;\r\n}\r\n","import { awaitWithCleanup, RetryDelaySeq } from '@actuallab/core';\r\n\r\n/** Controls when state re-computation happens after invalidation, per consecutive-error retryCount. */\r\nexport type UpdateDelayer = (\r\n retryCount: number,\r\n abortSignal?: AbortSignal\r\n) => Promise<void>;\r\n\r\n/** 1 s → 1 min exponential backoff — C# FixedDelayer.Defaults.RetryDelays parity. */\r\nexport const defaultRetryDelays = RetryDelaySeq.exp(1000, 60_000);\r\n\r\n/** Windows timer period is 15.6 ms, so 32 ms = 2..3 timer ticks — C# FixedDelayer.Defaults.MinDelay. */\r\nexport const defaultMinDelayMs = 32;\r\n\r\n// C# UpdateDelayer.GetDelay + minDelay floor: retryCount 0 uses the update delay\r\n// floored by minDelay; retryCount > 0 uses RetryDelays[retryCount] floored by RetryDelays.Min.\r\nexport function computeUpdateDelay(\r\n retryCount: number,\r\n updateDelayMs: number,\r\n retryDelays: RetryDelaySeq,\r\n minDelayMs: number\r\n): number {\r\n const min = retryCount === 0 ? minDelayMs : retryDelays.min;\r\n const raw = retryCount > 0 ? retryDelays.getDelay(retryCount) : updateDelayMs;\r\n return Math.max(min, raw);\r\n}\r\n\r\n/** Re-computes after a fixed update delay, with RetryDelaySeq backoff for consecutive errors. */\r\nexport class FixedDelayer {\r\n static readonly zero: UpdateDelayer = () => Promise.resolve();\r\n\r\n private static _cache = new Map<number, UpdateDelayer>();\r\n\r\n // Floors ms at minDelay like C# FixedDelayer.Get — a zero delayer requires the explicit .zero.\r\n static get(ms: number): UpdateDelayer {\r\n ms = Math.max(ms, defaultMinDelayMs);\r\n let delayer = FixedDelayer._cache.get(ms);\r\n if (delayer === undefined) {\r\n delayer = new FixedDelayer(ms).delay;\r\n FixedDelayer._cache.set(ms, delayer);\r\n }\r\n return delayer;\r\n }\r\n\r\n readonly ms: number;\r\n readonly retryDelays: RetryDelaySeq;\r\n readonly minDelay: number;\r\n readonly delay: UpdateDelayer;\r\n\r\n constructor(\r\n ms: number,\r\n retryDelays: RetryDelaySeq = defaultRetryDelays,\r\n minDelay: number = defaultMinDelayMs\r\n ) {\r\n this.ms = ms;\r\n this.retryDelays = retryDelays;\r\n this.minDelay = minDelay;\r\n // Abort stops the wait early (resolves, never rejects) so a disposed\r\n // ComputedState's update loop terminates promptly and the race loser\r\n // carries no unhandled rejection (C# SuppressCancellationAwait spirit).\r\n this.delay = (retryCount, abortSignal) => {\r\n const delayMs = computeUpdateDelay(\r\n retryCount,\r\n this.ms,\r\n this.retryDelays,\r\n this.minDelay\r\n );\r\n if (delayMs <= 0) return Promise.resolve();\r\n\r\n return awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, delayMs);\r\n addCleanup(() => clearTimeout(timer));\r\n });\r\n };\r\n }\r\n}\r\n\r\nexport const defaultUpdateDelayer: UpdateDelayer = FixedDelayer.get(1000 / 60);\r\n","import { awaitWithCleanup, type RetryDelaySeq } from '@actuallab/core';\r\nimport { uiActions } from './ui-action-tracker.js';\r\nimport {\r\n computeUpdateDelay,\r\n defaultMinDelayMs,\r\n defaultRetryDelays,\r\n type UpdateDelayer,\r\n} from './update-delayer.js';\r\n\r\n/** Re-computes after a delay, but short-circuits while UIActionTracker enables instant updates. */\r\nexport class UIUpdateDelayer {\r\n private static _cache = new Map<number, UpdateDelayer>();\r\n\r\n // Floors ms at minDelay like C# FixedDelayer.Get — a zero delayer requires FixedDelayer.zero.\r\n static get(ms: number): UpdateDelayer {\r\n ms = Math.max(ms, defaultMinDelayMs);\r\n let delayer = UIUpdateDelayer._cache.get(ms);\r\n if (delayer !== undefined) return delayer;\r\n\r\n delayer = new UIUpdateDelayer(ms).delay;\r\n UIUpdateDelayer._cache.set(ms, delayer);\r\n return delayer;\r\n }\r\n\r\n readonly ms: number;\r\n readonly retryDelays: RetryDelaySeq;\r\n readonly minDelay: number;\r\n readonly delay: UpdateDelayer;\r\n\r\n constructor(\r\n ms: number,\r\n retryDelays: RetryDelaySeq = defaultRetryDelays,\r\n minDelay: number = defaultMinDelayMs\r\n ) {\r\n this.ms = ms;\r\n this.retryDelays = retryDelays;\r\n this.minDelay = minDelay;\r\n this.delay = this._delay.bind(this);\r\n }\r\n\r\n // Private methods\r\n\r\n // Mirrors C# UpdateDelayer.Delay: race the instant-updates window against the full delay,\r\n // then enforce minDelay measured from delay start so instant updates never hot-loop the CPU.\r\n private async _delay(retryCount: number, abortSignal?: AbortSignal): Promise<void> {\r\n const t = uiActions;\r\n const minDelay = retryCount === 0 ? this.minDelay : this.retryDelays.min;\r\n const delayMs = computeUpdateDelay(retryCount, this.ms, this.retryDelays, this.minDelay);\r\n if (delayMs <= 0)\r\n return;\r\n\r\n const startedAt = Date.now();\r\n if (!t.areInstantUpdatesEnabled())\r\n await awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, delayMs);\r\n addCleanup(() => clearTimeout(timer));\r\n\r\n const onChanged = () => {\r\n if (t.areInstantUpdatesEnabled())\r\n complete();\r\n };\r\n t.changed.add(onChanged);\r\n addCleanup(() => t.changed.remove(onChanged));\r\n });\r\n if (abortSignal?.aborted)\r\n return;\r\n\r\n const remaining = minDelay - (Date.now() - startedAt);\r\n if (remaining > 0)\r\n await awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, remaining);\r\n addCleanup(() => clearTimeout(timer));\r\n });\r\n }\r\n}\r\n","import { EventHandlerSet } from '@actuallab/core';\r\nimport { getLogs } from './logging.js';\r\n\r\nconst { errorLog } = getLogs('UIActionTracker');\r\n\r\n/** Singleton tracking active UI commands — mirrors .NET's UIActionTracker. */\r\nexport class UIActionTracker {\r\n private _activeCount = 0;\r\n private _lastResultAt = 0;\r\n private _errorTimes: number[] = [];\r\n readonly changed = new EventHandlerSet<void>();\r\n readonly errors: unknown[] = [];\r\n\r\n // C# UIActionTracker.Options.InstantUpdatePeriod / UIActionFailureTracker MaxDuplicateRecency.\r\n instantUpdatePeriod = 300;\r\n maxDuplicateRecency = 1000;\r\n maxErrors = 100;\r\n\r\n get isActive(): boolean {\r\n return this._activeCount > 0;\r\n }\r\n\r\n // C# UIActionTracker.AreInstantUpdatesEnabled — active, or within instantUpdatePeriod of the last result.\r\n areInstantUpdatesEnabled(): boolean {\r\n if (this._activeCount > 0)\r\n return true;\r\n if (this._lastResultAt === 0)\r\n return false;\r\n\r\n return this._lastResultAt + this.instantUpdatePeriod >= Date.now();\r\n }\r\n\r\n /** Run a command silently — errors are added to the error list but not thrown. */\r\n async run(fn: () => Promise<unknown>): Promise<void> {\r\n this._activeCount++;\r\n this.changed.trigger();\r\n try {\r\n await fn();\r\n } catch (e) {\r\n // Mirrors UIActionTracker.cs:58 — UI action failure.\r\n errorLog?.log('UI action failed', e);\r\n this._addError(e);\r\n } finally {\r\n this._onCompleted();\r\n }\r\n }\r\n\r\n /** Call a command and return the result — errors are added to the error list AND thrown. */\r\n async call<T>(fn: () => Promise<T>): Promise<T> {\r\n this._activeCount++;\r\n this.changed.trigger();\r\n try {\r\n return await fn();\r\n } catch (e) {\r\n // Mirrors UIActionTracker.cs:58 — UI action failure.\r\n errorLog?.log('UI action failed', e);\r\n this._addError(e);\r\n throw e;\r\n } finally {\r\n this._onCompleted();\r\n }\r\n }\r\n\r\n dismissError(index: number): void {\r\n if (index >= 0 && index < this.errors.length) {\r\n this.errors.splice(index, 1);\r\n this._errorTimes.splice(index, 1);\r\n this.changed.trigger();\r\n }\r\n }\r\n\r\n // Private methods\r\n\r\n private _onCompleted(): void {\r\n this._activeCount--;\r\n this._lastResultAt = Date.now();\r\n this.changed.trigger();\r\n }\r\n\r\n // C# UIActionFailureTracker.TryAddFailure — drop a same-name/same-message error seen within\r\n // maxDuplicateRecency; a size cap is the backstop against unbounded growth.\r\n private _addError(e: unknown): void {\r\n const now = Date.now();\r\n const { name, message } = errorInfo(e);\r\n const minAt = now - this.maxDuplicateRecency;\r\n for (let i = 0; i < this.errors.length; i++) {\r\n if (this._errorTimes[i] < minAt)\r\n continue;\r\n\r\n const prev = errorInfo(this.errors[i]);\r\n if (prev.name === name && prev.message === message)\r\n return;\r\n }\r\n\r\n this.errors.push(e);\r\n this._errorTimes.push(now);\r\n while (this.errors.length > this.maxErrors) {\r\n this.errors.shift();\r\n this._errorTimes.shift();\r\n }\r\n this.changed.trigger();\r\n }\r\n}\r\n\r\nfunction errorInfo(e: unknown): { name: string; message: string } {\r\n if (e instanceof Error)\r\n return { name: e.name, message: e.message };\r\n\r\n return { name: '', message: String(e) };\r\n}\r\n\r\nexport const uiActions = new UIActionTracker();\r\n","import {\r\n type AsyncContext,\r\n type IResult,\r\n PromiseSource,\r\n resolvedVoidPromise,\r\n type Result,\r\n} from '@actuallab/core';\r\nimport { type Computed, StateBoundComputed } from './computed.js';\r\n\r\n/** Base class for all reactive state types. */\r\nexport abstract class State<T> implements IResult<T> {\r\n protected _computed!: Computed<T>;\r\n protected _updateIndex = 0;\r\n // Reference to the last non-error computed, not its raw value, so an actual\r\n // `undefined` value is distinguishable from \"no non-error value yet\" (S12).\r\n protected _lastNonErrorComputed: Computed<T> | undefined;\r\n private _whenUpdatedSource: PromiseSource<void> | null = null;\r\n private _isDisposed = false;\r\n\r\n get updateIndex(): number {\r\n return this._updateIndex;\r\n }\r\n\r\n get isDisposed(): boolean {\r\n return this._isDisposed;\r\n }\r\n\r\n get lastNonErrorValue(): T | undefined {\r\n return this._lastNonErrorComputed?.value;\r\n }\r\n\r\n get hasValue(): boolean {\r\n return this._computed.hasValue;\r\n }\r\n\r\n get hasError(): boolean {\r\n return this._computed.hasError;\r\n }\r\n\r\n get value(): T {\r\n return this._computed.value;\r\n }\r\n\r\n get error(): unknown {\r\n return this._computed.error;\r\n }\r\n\r\n get valueOrUndefined(): T | undefined {\r\n return this._computed.valueOrUndefined;\r\n }\r\n\r\n get output(): Result<T> {\r\n return this._computed.output;\r\n }\r\n\r\n get computed(): Computed<T> {\r\n return this._computed;\r\n }\r\n\r\n use(asyncContext?: AsyncContext): T | Promise<T> {\r\n return this._computed.use(asyncContext);\r\n }\r\n\r\n useInconsistent(asyncContext?: AsyncContext): T {\r\n return this._computed.useInconsistent(asyncContext);\r\n }\r\n\r\n update(): Computed<T> | Promise<Computed<T>> {\r\n return this._computed.update();\r\n }\r\n\r\n recompute(): Computed<T> | Promise<Computed<T>> {\r\n this._computed.invalidate();\r\n return this.update();\r\n }\r\n\r\n whenInvalidated(): Promise<void> {\r\n return this._computed.whenInvalidated();\r\n }\r\n\r\n // Versioned wait: resolves at once when a newer generation than sinceIndex\r\n // already landed (no lost wakeup), rejects once disposed (C# StateSnapshot.WhenUpdated).\r\n whenUpdated(sinceIndex: number = this._updateIndex): Promise<void> {\r\n if (this._isDisposed)\r\n return Promise.reject(State._disposedError());\r\n if (this._updateIndex > sinceIndex)\r\n return resolvedVoidPromise;\r\n\r\n return (this._whenUpdatedSource ??= new PromiseSource<void>());\r\n }\r\n\r\n whenFirstTimeUpdated(): Promise<void> {\r\n return this.whenUpdated(0);\r\n }\r\n\r\n protected _initialize(\r\n output: Result<T> | T,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>\r\n ): void {\r\n this._computed = this._createComputed(renewer);\r\n this._computed.setOutput(output);\r\n if (this._computed.hasValue) this._lastNonErrorComputed = this._computed;\r\n }\r\n\r\n protected _createComputed(\r\n renewer?: () => Computed<T> | Promise<Computed<T>>\r\n ): Computed<T> {\r\n return new StateBoundComputed<T>(this, renewer);\r\n }\r\n\r\n protected _update(computed: Computed<T>, output: Result<T> | T): void {\r\n const replaced = this._computed as Computed<T> | undefined;\r\n computed.setOutput(output);\r\n this._computed = computed;\r\n if (replaced?.isConsistent) replaced.invalidate();\r\n if (computed.hasValue) this._lastNonErrorComputed = computed;\r\n this._updateIndex++;\r\n this._whenUpdatedSource?.resolve(undefined);\r\n this._whenUpdatedSource = null;\r\n }\r\n\r\n protected _onDisposed(): void {\r\n if (this._isDisposed)\r\n return;\r\n\r\n this._isDisposed = true;\r\n this._whenUpdatedSource?.reject(State._disposedError());\r\n this._whenUpdatedSource = null;\r\n // A disposed state stops tracking its sources, so leaving its computed Consistent\r\n // would strand an edge in every dependency's _dependants map (I15) and let\r\n // dependants latch onto a value that will never be updated again. .NET's\r\n // ComputedGraphPruner.PruneDisposedInstances invalidates for the same reason.\r\n this._computed.invalidate();\r\n }\r\n\r\n private static _disposedError(): Error {\r\n return new Error('State is disposed.');\r\n }\r\n}\r\n","import {\r\n AsyncContext,\r\n PromiseSource,\r\n type Result,\r\n result,\r\n errorResult,\r\n} from '@actuallab/core';\r\nimport { type Computed, StateBoundComputed } from './computed.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { getLogs } from './logging.js';\r\nimport { defaultUpdateDelayer, type UpdateDelayer } from './update-delayer.js';\r\nimport { State } from './state.js';\r\n\r\nconst { errorLog } = getLogs('ComputedState');\r\n\r\nexport type StateComputer<T> = () => T | Promise<T>;\r\n\r\n/** Constructor options for ComputedState. */\r\nexport interface ComputedStateOptions<T> {\r\n initialValue?: T;\r\n initialOutput?: Result<T>;\r\n updateDelayer?: UpdateDelayer;\r\n}\r\n\r\n/** Auto-updating reactive state wrapper — re-computes on invalidation with configurable delay. */\r\nexport class ComputedState<T> extends State<T> {\r\n private _computer: StateComputer<T>;\r\n private _updateDelayer: UpdateDelayer;\r\n private _disposeController: AbortController;\r\n private _cancelDelaySource = new PromiseSource<void>();\r\n private _renewer: () => Computed<T> | Promise<Computed<T>>;\r\n\r\n constructor(computer: StateComputer<T>, options?: ComputedStateOptions<T>) {\r\n super();\r\n this._computer = computer;\r\n this._updateDelayer = options?.updateDelayer ?? defaultUpdateDelayer;\r\n this._disposeController = new AbortController();\r\n this._renewer = async () => {\r\n const sinceIndex = this._updateIndex;\r\n this._cancelDelaySource.resolve(undefined);\r\n await this.whenUpdated(sinceIndex);\r\n return this._computed;\r\n };\r\n\r\n // The initial computed is created pre-invalidated (C# State.cs:246) so inherited\r\n // members (use/update/recompute/whenInvalidated) await the first real computation\r\n // instead of returning the placeholder, and dependants never latch onto it.\r\n this._initialize(\r\n options?.initialOutput ?? (options?.initialValue as T),\r\n this._renewer\r\n );\r\n this._computed.invalidate();\r\n\r\n void this._updateCycle();\r\n }\r\n\r\n dispose(): void {\r\n if (this.isDisposed)\r\n return;\r\n\r\n // Abort first: _onDisposed() invalidates the computed, and the update cycle must\r\n // see the abort rather than treat that invalidation as a request to recompute.\r\n this._disposeController.abort();\r\n this._onDisposed();\r\n }\r\n\r\n private async _updateCycle(): Promise<void> {\r\n const disposeSignal = this._disposeController.signal;\r\n let retryCount = 0;\r\n try {\r\n while (!disposeSignal.aborted) {\r\n // Compute\r\n const computed = new StateBoundComputed<T>(this, this._renewer);\r\n const computeCtx = new ComputeContext(\r\n computed as StateBoundComputed<unknown>\r\n );\r\n const asyncCtx = (\r\n AsyncContext.current ?? AsyncContext.empty\r\n ).with(computeContextKey, computeCtx);\r\n\r\n let output: Result<T>;\r\n try {\r\n const value = asyncCtx.run(() => this._computer());\r\n const resolved =\r\n value instanceof Promise ? await value : value;\r\n output = result(resolved);\r\n } catch (e) {\r\n output = errorResult(e);\r\n }\r\n if (this.isDisposed)\r\n return; // Disposed mid-computation — publish nothing, terminate the cycle.\r\n\r\n this._update(computed, output);\r\n retryCount = output.hasError ? retryCount + 1 : 0;\r\n if (this._cancelDelaySource.isCompleted)\r\n this._cancelDelaySource = new PromiseSource<void>();\r\n\r\n // Wait for invalidation (or cancellation via dispose)\r\n try {\r\n await computed.whenInvalidated(disposeSignal);\r\n } catch {\r\n return; // Cancelled via dispose\r\n }\r\n\r\n // Wait for delay (cancellable by renewer); retryCount grows the backoff (S8).\r\n await Promise.race([\r\n this._updateDelayer(retryCount, disposeSignal),\r\n this._cancelDelaySource,\r\n ]);\r\n }\r\n } catch (e) {\r\n // Mirrors ComputedState.cs:188 — UpdateCycle failed and stopped.\r\n if (!disposeSignal.aborted)\r\n errorLog?.log('UpdateCycle() failed and stopped', e);\r\n }\r\n }\r\n}\r\n","import { type AsyncContext, Result, result } from '@actuallab/core';\r\nimport { type Computed } from './computed.js';\r\nimport { State } from './state.js';\r\n\r\n/** Manually-settable reactive state that can participate in the Fusion dependency graph. */\r\nexport class MutableState<T> extends State<T> {\r\n private _nextOutput: Result<T>;\r\n\r\n private _renewer = (): Computed<T> => {\r\n const computed = this._createComputed(this._renewer);\r\n this._update(computed, this._nextOutput);\r\n this._wireRenewal(computed);\r\n return computed;\r\n };\r\n\r\n constructor(initialOutput: Result<T> | T) {\r\n super();\r\n this._nextOutput =\r\n initialOutput instanceof Result ? initialOutput : result(initialOutput);\r\n this._initialize(this._nextOutput, this._renewer);\r\n this._wireRenewal(this._computed);\r\n }\r\n\r\n override use(asyncContext?: AsyncContext): T {\r\n return this._computed.use(asyncContext) as T;\r\n }\r\n\r\n set(output: Result<T> | T): void {\r\n const next = output instanceof Result ? output : result(output);\r\n if (this._nextOutput.equals(next))\r\n return;\r\n\r\n this._nextOutput = next;\r\n this._computed.invalidate();\r\n }\r\n\r\n // Private methods\r\n\r\n // Renew synchronously on invalidation so a MutableState is never observed invalidated.\r\n // update() de-dupes: if the computed was already renewed, it returns the latest instead.\r\n private _wireRenewal(computed: Computed<T>): void {\r\n computed.onInvalidated(() => void computed.update());\r\n }\r\n}\r\n"],"mappings":"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","names":["import_core","import_core","ConsistencyState","captured","import_core","import_core","import_core","import_core","import_core","errorLog","import_core","import_core","errorLog","import_core"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -34,6 +34,7 @@ declare class Computed<T> implements IResult<T> {
|
|
|
34
34
|
private _errorTimer;
|
|
35
35
|
private _dependencies;
|
|
36
36
|
private _dependants;
|
|
37
|
+
private _pruneDependantsThreshold;
|
|
37
38
|
private _onInvalidated;
|
|
38
39
|
readonly _renewer: (() => Computed<T> | Promise<Computed<T>>) | undefined;
|
|
39
40
|
constructor(input: ComputedInput, renewer?: () => Computed<T> | Promise<Computed<T>>, options?: ComputedOptions);
|
|
@@ -48,6 +49,7 @@ declare class Computed<T> implements IResult<T> {
|
|
|
48
49
|
get isConsistent(): boolean;
|
|
49
50
|
get isComputing(): boolean;
|
|
50
51
|
get dependencies(): ReadonlySet<Computed<unknown>>;
|
|
52
|
+
get dependantCount(): number;
|
|
51
53
|
update(): Computed<T> | Promise<Computed<T>>;
|
|
52
54
|
protected _latest(): Computed<T> | undefined;
|
|
53
55
|
use(asyncContext?: AsyncContext): T | Promise<T>;
|
|
@@ -59,6 +61,7 @@ declare class Computed<T> implements IResult<T> {
|
|
|
59
61
|
onInvalidated(handler: () => void): void;
|
|
60
62
|
whenInvalidated(abortSignal?: AbortSignal): Promise<void>;
|
|
61
63
|
addDependency(dependency: Computed<unknown>): void;
|
|
64
|
+
pruneDependants(): void;
|
|
62
65
|
}
|
|
63
66
|
/** Computed variant for State types — skips registry registration since the State holds a direct reference. */
|
|
64
67
|
declare class StateBoundComputed<T> extends Computed<T> {
|
|
@@ -136,6 +139,8 @@ declare class ComputedRegistry {
|
|
|
136
139
|
static get(key: string): Computed<unknown> | undefined;
|
|
137
140
|
static register(computed: Computed<unknown>): void;
|
|
138
141
|
static unregister(computed: Computed<unknown>): void;
|
|
142
|
+
private static _onFinalized;
|
|
143
|
+
private static _removeEntry;
|
|
139
144
|
}
|
|
140
145
|
|
|
141
146
|
type ComputeFunctionImpl = (this: any, ...args: unknown[]) => unknown;
|
package/dist/index.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ declare class Computed<T> implements IResult<T> {
|
|
|
34
34
|
private _errorTimer;
|
|
35
35
|
private _dependencies;
|
|
36
36
|
private _dependants;
|
|
37
|
+
private _pruneDependantsThreshold;
|
|
37
38
|
private _onInvalidated;
|
|
38
39
|
readonly _renewer: (() => Computed<T> | Promise<Computed<T>>) | undefined;
|
|
39
40
|
constructor(input: ComputedInput, renewer?: () => Computed<T> | Promise<Computed<T>>, options?: ComputedOptions);
|
|
@@ -48,6 +49,7 @@ declare class Computed<T> implements IResult<T> {
|
|
|
48
49
|
get isConsistent(): boolean;
|
|
49
50
|
get isComputing(): boolean;
|
|
50
51
|
get dependencies(): ReadonlySet<Computed<unknown>>;
|
|
52
|
+
get dependantCount(): number;
|
|
51
53
|
update(): Computed<T> | Promise<Computed<T>>;
|
|
52
54
|
protected _latest(): Computed<T> | undefined;
|
|
53
55
|
use(asyncContext?: AsyncContext): T | Promise<T>;
|
|
@@ -59,6 +61,7 @@ declare class Computed<T> implements IResult<T> {
|
|
|
59
61
|
onInvalidated(handler: () => void): void;
|
|
60
62
|
whenInvalidated(abortSignal?: AbortSignal): Promise<void>;
|
|
61
63
|
addDependency(dependency: Computed<unknown>): void;
|
|
64
|
+
pruneDependants(): void;
|
|
62
65
|
}
|
|
63
66
|
/** Computed variant for State types — skips registry registration since the State holds a direct reference. */
|
|
64
67
|
declare class StateBoundComputed<T> extends Computed<T> {
|
|
@@ -136,6 +139,8 @@ declare class ComputedRegistry {
|
|
|
136
139
|
static get(key: string): Computed<unknown> | undefined;
|
|
137
140
|
static register(computed: Computed<unknown>): void;
|
|
138
141
|
static unregister(computed: Computed<unknown>): void;
|
|
142
|
+
private static _onFinalized;
|
|
143
|
+
private static _removeEntry;
|
|
139
144
|
}
|
|
140
145
|
|
|
141
146
|
type ComputeFunctionImpl = (this: any, ...args: unknown[]) => unknown;
|
package/dist/index.js
CHANGED
|
@@ -37,8 +37,8 @@ import {
|
|
|
37
37
|
// src/computed-registry.ts
|
|
38
38
|
var ComputedRegistry = class _ComputedRegistry {
|
|
39
39
|
static _entries = /* @__PURE__ */ new Map();
|
|
40
|
-
static _finalization = new FinalizationRegistry((
|
|
41
|
-
_ComputedRegistry.
|
|
40
|
+
static _finalization = new FinalizationRegistry((token) => {
|
|
41
|
+
_ComputedRegistry._onFinalized(token);
|
|
42
42
|
});
|
|
43
43
|
static get size() {
|
|
44
44
|
return _ComputedRegistry._entries.size;
|
|
@@ -48,7 +48,7 @@ var ComputedRegistry = class _ComputedRegistry {
|
|
|
48
48
|
if (ref === void 0) return void 0;
|
|
49
49
|
const computed = ref.deref();
|
|
50
50
|
if (computed === void 0) {
|
|
51
|
-
_ComputedRegistry.
|
|
51
|
+
_ComputedRegistry._removeEntry(key, ref);
|
|
52
52
|
return void 0;
|
|
53
53
|
}
|
|
54
54
|
return computed;
|
|
@@ -60,14 +60,26 @@ var ComputedRegistry = class _ComputedRegistry {
|
|
|
60
60
|
return;
|
|
61
61
|
if (displaced !== void 0 && displaced.state !== 2 /* Invalidated */)
|
|
62
62
|
displaced.invalidate();
|
|
63
|
-
|
|
64
|
-
_ComputedRegistry.
|
|
63
|
+
const ref = new WeakRef(computed);
|
|
64
|
+
_ComputedRegistry._entries.set(key, ref);
|
|
65
|
+
_ComputedRegistry._finalization.register(computed, { key, ref }, computed);
|
|
65
66
|
}
|
|
66
67
|
static unregister(computed) {
|
|
67
68
|
const key = computed.input;
|
|
68
|
-
_ComputedRegistry._entries.
|
|
69
|
+
if (_ComputedRegistry._entries.get(key)?.deref() === computed)
|
|
70
|
+
_ComputedRegistry._entries.delete(key);
|
|
69
71
|
_ComputedRegistry._finalization.unregister(computed);
|
|
70
72
|
}
|
|
73
|
+
// Private methods
|
|
74
|
+
static _onFinalized(token) {
|
|
75
|
+
_ComputedRegistry._removeEntry(token.key, token.ref);
|
|
76
|
+
}
|
|
77
|
+
// Removing by key alone would drop a live successor registered under the same key
|
|
78
|
+
// while this key's predecessor was already collected but not yet finalized (I13).
|
|
79
|
+
static _removeEntry(key, ref) {
|
|
80
|
+
if (_ComputedRegistry._entries.get(key) === ref)
|
|
81
|
+
_ComputedRegistry._entries.delete(key);
|
|
82
|
+
}
|
|
71
83
|
};
|
|
72
84
|
|
|
73
85
|
// src/compute-context.ts
|
|
@@ -127,6 +139,7 @@ var ComputedOptions = class _ComputedOptions {
|
|
|
127
139
|
// src/computed.ts
|
|
128
140
|
var { errorLog } = getLogs("Computed");
|
|
129
141
|
var _nextVersion = 0;
|
|
142
|
+
var MinPruneDependantsThreshold = 16;
|
|
130
143
|
var ConsistencyState = /* @__PURE__ */ ((ConsistencyState2) => {
|
|
131
144
|
ConsistencyState2[ConsistencyState2["Computing"] = 0] = "Computing";
|
|
132
145
|
ConsistencyState2[ConsistencyState2["Consistent"] = 1] = "Consistent";
|
|
@@ -166,6 +179,7 @@ var Computed = class {
|
|
|
166
179
|
_errorTimer;
|
|
167
180
|
_dependencies = /* @__PURE__ */ new Set();
|
|
168
181
|
_dependants = /* @__PURE__ */ new Map();
|
|
182
|
+
_pruneDependantsThreshold = MinPruneDependantsThreshold;
|
|
169
183
|
_onInvalidated = new EventHandlerSet();
|
|
170
184
|
_renewer;
|
|
171
185
|
constructor(input, renewer, options = ComputedOptions.default) {
|
|
@@ -210,6 +224,9 @@ var Computed = class {
|
|
|
210
224
|
get dependencies() {
|
|
211
225
|
return this._dependencies;
|
|
212
226
|
}
|
|
227
|
+
get dependantCount() {
|
|
228
|
+
return this._dependants.size;
|
|
229
|
+
}
|
|
213
230
|
update() {
|
|
214
231
|
if (this._state === 1 /* Consistent */) return this;
|
|
215
232
|
const latest = this._latest();
|
|
@@ -353,6 +370,24 @@ var Computed = class {
|
|
|
353
370
|
this._version,
|
|
354
371
|
new WeakRef(this)
|
|
355
372
|
);
|
|
373
|
+
if (dependency._dependants.size >= dependency._pruneDependantsThreshold)
|
|
374
|
+
dependency.pruneDependants();
|
|
375
|
+
}
|
|
376
|
+
// Port of .NET Computed.PruneDependants: drops edges to dependants that were
|
|
377
|
+
// collected or already invalidated. `_dependants` is keyed by the dependant's
|
|
378
|
+
// unique version, so .NET's "still the registered version" check is implicit.
|
|
379
|
+
pruneDependants() {
|
|
380
|
+
if (this._state !== 1 /* Consistent */)
|
|
381
|
+
return;
|
|
382
|
+
for (const [version, ref] of this._dependants) {
|
|
383
|
+
const dependant = ref.deref();
|
|
384
|
+
if (dependant === void 0 || dependant._state === 2 /* Invalidated */)
|
|
385
|
+
this._dependants.delete(version);
|
|
386
|
+
}
|
|
387
|
+
this._pruneDependantsThreshold = Math.max(
|
|
388
|
+
MinPruneDependantsThreshold,
|
|
389
|
+
this._dependants.size * 2
|
|
390
|
+
);
|
|
356
391
|
}
|
|
357
392
|
};
|
|
358
393
|
var StateBoundComputed = class extends Computed {
|
|
@@ -802,6 +837,7 @@ var State = class _State {
|
|
|
802
837
|
this._isDisposed = true;
|
|
803
838
|
this._whenUpdatedSource?.reject(_State._disposedError());
|
|
804
839
|
this._whenUpdatedSource = null;
|
|
840
|
+
this._computed.invalidate();
|
|
805
841
|
}
|
|
806
842
|
static _disposedError() {
|
|
807
843
|
return new Error("State is disposed.");
|
|
@@ -843,8 +879,8 @@ var ComputedState = class extends State {
|
|
|
843
879
|
dispose() {
|
|
844
880
|
if (this.isDisposed)
|
|
845
881
|
return;
|
|
846
|
-
this._onDisposed();
|
|
847
882
|
this._disposeController.abort();
|
|
883
|
+
this._onDisposed();
|
|
848
884
|
}
|
|
849
885
|
async _updateCycle() {
|
|
850
886
|
const disposeSignal = this._disposeController.signal;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/logging.ts","../src/computed-input.ts","../src/computed.ts","../src/computed-registry.ts","../src/compute-context.ts","../src/computed-options.ts","../src/compute-function.ts","../src/compute-method.ts","../src/update-delayer.ts","../src/ui-update-delayer.ts","../src/ui-action-tracker.ts","../src/state.ts","../src/computed-state.ts","../src/mutable-state.ts"],"sourcesContent":["import { createLogProvider, LogLevel } from '@actuallab/core';\n\n// Per-package log scopes. Use createLogProvider to get a typed helper:\n// const { debugLog, warnLog } = getLogs('Computed');\n// Final scope name is 'fusion.Computed' — the prefix isolates this package's\n// scopes from other packages' scopes when overriding levels at runtime.\nexport type FusionLogScope =\n | 'Computed'\n | 'ComputedRegistry'\n | 'ComputedState'\n | 'ComputeFunction'\n | 'MutableState'\n | 'State'\n | 'UIActionTracker'\n | 'UIUpdateDelayer';\n\n// Per-scope defaults. All Warn — Fusion is mostly hot-path compute graph code;\n// noisy scopes need to be opted-in for development.\nconst scopeDefaults: Record<FusionLogScope, LogLevel> = {\n Computed: LogLevel.Warn,\n ComputedRegistry: LogLevel.Warn,\n ComputedState: LogLevel.Warn,\n ComputeFunction: LogLevel.Warn,\n MutableState: LogLevel.Warn,\n State: LogLevel.Warn,\n UIActionTracker: LogLevel.Warn,\n UIUpdateDelayer: LogLevel.Warn,\n};\n\nexport const getLogs = createLogProvider<FusionLogScope>('fusion.', scopeDefaults);\n","import type { State } from './state.js';\r\n\r\n/** Auto-assigned numeric IDs for instance identity in compute method cache keys. */\r\nlet _nextInstanceId = 0;\r\nconst _instanceIds = new WeakMap<object, number>();\r\n\r\nexport function getInstanceId(instance: object): number {\r\n let id = _instanceIds.get(instance);\r\n if (id === undefined) {\r\n id = ++_nextInstanceId;\r\n _instanceIds.set(instance, id);\r\n }\r\n return id;\r\n}\r\n\r\n/**\r\n * Identity key for any computed value.\r\n * - String for compute method results (built from instance + function + args)\r\n * - State for state types (identity by reference)\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type ComputedInput = string | State<any>;\r\n","import {\r\n AsyncContext,\r\n EventHandlerSet,\r\n type IResult,\r\n isCancellation,\r\n PromiseSource,\r\n Result,\r\n result,\r\n} from '@actuallab/core';\r\nimport type { ComputedInput } from './computed-input.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { getLogs } from './logging.js';\r\nimport type { State } from './state.js';\r\n\r\nconst { errorLog } = getLogs('Computed');\r\n\r\nlet _nextVersion = 0;\r\n\r\nexport const enum ConsistencyState {\r\n Computing = 0,\r\n Consistent = 1,\r\n Invalidated = 2,\r\n}\r\n\r\n/** Core Fusion abstraction — a cached computation with dependency tracking and invalidation. */\r\nexport class Computed<T> implements IResult<T> {\r\n /** Capture the Computed backing a computation — works with both local and RPC compute methods. */\r\n static async capture<T>(fn: () => T | Promise<T>): Promise<Computed<T>> {\r\n // A capture context (no computed) records the last captured Computed without adding\r\n // dependant edges — mirrors C# ComputeContext(CallOptions.Capture) + Computed.Capture.\r\n // The parent link keeps reentrancy detection working through capture — in C# lock\r\n // reentry flows through ExecutionContext regardless of BeginCapture.\r\n const currentCtx = AsyncContext.getOrCreate();\r\n const captureCtx = new ComputeContext(\r\n undefined,\r\n currentCtx.get(computeContextKey)\r\n );\r\n const asyncCtx = currentCtx.with(computeContextKey, captureCtx);\r\n try {\r\n await asyncCtx.run(fn);\r\n } catch (e) {\r\n if (isCancellation(e)) throw e;\r\n const captured = captureCtx.captured;\r\n if (captured?.hasError) return captured as Computed<T>;\r\n\r\n throw e;\r\n }\r\n const captured = captureCtx.captured;\r\n if (captured === undefined)\r\n throw new Error(\r\n 'No Computed was captured — fn must call a compute function.'\r\n );\r\n return captured as Computed<T>;\r\n }\r\n\r\n readonly input: ComputedInput;\r\n readonly options: ComputedOptions;\r\n private _version: number;\r\n private _state: ConsistencyState;\r\n private _output: Result<T> | undefined;\r\n private _invalidatePending = false;\r\n private _errorTimer: ReturnType<typeof setTimeout> | undefined;\r\n private _dependencies = new Set<Computed<unknown>>();\r\n private _dependants = new Map<number, WeakRef<Computed<unknown>>>();\r\n private _onInvalidated = new EventHandlerSet<void>();\r\n readonly _renewer: (() => Computed<T> | Promise<Computed<T>>) | undefined;\r\n\r\n constructor(\r\n input: ComputedInput,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>,\r\n options: ComputedOptions = ComputedOptions.default\r\n ) {\r\n this.input = input;\r\n this.options = options;\r\n this._renewer = renewer;\r\n this._version = ++_nextVersion;\r\n this._state = ConsistencyState.Computing;\r\n }\r\n\r\n get version(): number {\r\n return this._version;\r\n }\r\n\r\n get output(): Result<T> {\r\n if (this._output === undefined)\r\n throw new Error('Computed has no output yet.');\r\n return this._output;\r\n }\r\n\r\n get hasValue(): boolean {\r\n return this.output.hasValue;\r\n }\r\n\r\n get hasError(): boolean {\r\n return this.output.hasError;\r\n }\r\n\r\n get value(): T {\r\n return this.output.value;\r\n }\r\n\r\n get error(): unknown {\r\n return this.output.error;\r\n }\r\n\r\n get valueOrUndefined(): T | undefined {\r\n return this.output.valueOrUndefined;\r\n }\r\n\r\n get state(): ConsistencyState {\r\n return this._state;\r\n }\r\n\r\n get isConsistent(): boolean {\r\n return this._state === ConsistencyState.Consistent;\r\n }\r\n\r\n get isComputing(): boolean {\r\n return this._state === ConsistencyState.Computing;\r\n }\r\n\r\n get dependencies(): ReadonlySet<Computed<unknown>> {\r\n return this._dependencies;\r\n }\r\n\r\n update(): Computed<T> | Promise<Computed<T>> {\r\n if (this._state === ConsistencyState.Consistent) return this;\r\n const latest = this._latest();\r\n if (latest?.isConsistent) return latest;\r\n if (this._renewer !== undefined) {\r\n const renewer = this._renewer;\r\n // Run the renewer with the compute context cleared so renewal never\r\n // records a dependency edge in the ambient computation — TS analog of\r\n // C# Computed.UpdateUntyped's BeginIsolation.\r\n const isolated = (AsyncContext.current ?? AsyncContext.empty).with(\r\n computeContextKey,\r\n undefined\r\n );\r\n return isolated.run(renewer);\r\n }\r\n throw new Error(\r\n 'Cannot recompute: Computed is invalidated and has no renewer.'\r\n );\r\n }\r\n\r\n protected _latest(): Computed<T> | undefined {\r\n return ComputedRegistry.get(this.input as string) as\r\n | Computed<T>\r\n | undefined;\r\n }\r\n\r\n use(asyncContext?: AsyncContext): T | Promise<T> {\r\n const ctx = ComputeContext.from(asyncContext);\r\n const updated = this.update();\r\n if (updated instanceof Promise) {\r\n return updated.then(c => {\r\n ctx?.captureDependency(c as Computed<unknown>);\r\n return c.value;\r\n });\r\n }\r\n ctx?.captureDependency(updated as Computed<unknown>);\r\n return updated.value;\r\n }\r\n\r\n useInconsistent(asyncContext?: AsyncContext): T {\r\n ComputeContext.from(asyncContext)?.captureDependency(\r\n this as Computed<unknown>\r\n );\r\n return this.value;\r\n }\r\n\r\n setOutput(output: Result<T> | T): void {\r\n if (this._state !== ConsistencyState.Computing)\r\n throw new Error('Cannot set output on a non-computing Computed.');\r\n this._output = output instanceof Result ? output : result(output);\r\n this._state = ConsistencyState.Consistent;\r\n this._register();\r\n if (this._invalidatePending) {\r\n this._invalidatePending = false;\r\n this.invalidate();\r\n return;\r\n }\r\n\r\n const delay = this.options.errorAutoInvalidateDelay;\r\n if (this._output.hasError && delay !== Infinity && delay > 0) {\r\n this._errorTimer = setTimeout(() => this.invalidate(), delay);\r\n (this._errorTimer as { unref?: () => void }).unref?.();\r\n }\r\n }\r\n\r\n protected _register(): void {\r\n ComputedRegistry.register(this as Computed<unknown>);\r\n }\r\n\r\n protected _unregister(): void {\r\n ComputedRegistry.unregister(this as Computed<unknown>);\r\n }\r\n\r\n // Never throws — mirrors .NET Computed.Invalidate: own handlers fire first\r\n // (each isolated), then dependants propagate unconditionally, then unregister.\r\n invalidate(): void {\r\n if (this._state === ConsistencyState.Invalidated)\r\n return;\r\n if (this._state === ConsistencyState.Computing) {\r\n // Defer until setOutput transitions to Consistent — matches .NET, where\r\n // invalidating a still-computing Computed sets a pending flag.\r\n this._invalidatePending = true;\r\n return;\r\n }\r\n this._state = ConsistencyState.Invalidated;\r\n if (this._errorTimer !== undefined) {\r\n clearTimeout(this._errorTimer);\r\n this._errorTimer = undefined;\r\n }\r\n try {\r\n this._onInvalidated.triggerSafe(undefined, e =>\r\n errorLog?.log('onInvalidated handler failed', e)\r\n );\r\n this._onInvalidated.clear();\r\n } finally {\r\n for (const dependency of this._dependencies)\r\n dependency._dependants.delete(this._version);\r\n this._dependencies.clear();\r\n\r\n for (const [, ref] of this._dependants) {\r\n const dependant = ref.deref();\r\n if (dependant != null) {\r\n try {\r\n dependant.invalidate();\r\n } catch (e) {\r\n errorLog?.log('Error while invalidating dependant', e);\r\n }\r\n }\r\n }\r\n this._dependants.clear();\r\n\r\n this._unregister();\r\n }\r\n }\r\n\r\n onInvalidated(handler: () => void): void {\r\n if (this._state === ConsistencyState.Invalidated) {\r\n handler();\r\n return;\r\n }\r\n this._onInvalidated.add(handler);\r\n }\r\n\r\n whenInvalidated(abortSignal?: AbortSignal): Promise<void> {\r\n if (this._state === ConsistencyState.Invalidated)\r\n return Promise.resolve();\r\n if (abortSignal?.aborted)\r\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- reason falls back to an Error; abortSignal.reason mirrors throwIfAborted()\r\n return Promise.reject(\r\n abortSignal.reason ?? new Error('Operation cancelled.')\r\n );\r\n\r\n const ps = new PromiseSource<void>();\r\n let onAbort: (() => void) | undefined;\r\n const onInvalidated = () => {\r\n if (onAbort !== undefined)\r\n abortSignal!.removeEventListener('abort', onAbort);\r\n ps.resolve(undefined);\r\n };\r\n this._onInvalidated.add(onInvalidated);\r\n if (abortSignal !== undefined) {\r\n onAbort = () => {\r\n this._onInvalidated.remove(onInvalidated);\r\n ps.reject(\r\n abortSignal.reason ?? new Error('Operation cancelled.')\r\n );\r\n };\r\n abortSignal.addEventListener('abort', onAbort, { once: true });\r\n }\r\n\r\n return ps;\r\n }\r\n\r\n addDependency(dependency: Computed<unknown>): void {\r\n if (this._state !== ConsistencyState.Computing)\r\n return;\r\n if (dependency._state === ConsistencyState.Invalidated) {\r\n this.invalidate();\r\n return;\r\n }\r\n this._dependencies.add(dependency);\r\n dependency._dependants.set(\r\n this._version,\r\n new WeakRef(this as Computed<unknown>)\r\n );\r\n }\r\n}\r\n\r\n/** Computed variant for State types — skips registry registration since the State holds a direct reference. */\r\nexport class StateBoundComputed<T> extends Computed<T> {\r\n constructor(\r\n input: ComputedInput,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>,\r\n options: ComputedOptions = ComputedOptions.mutableStateDefault\r\n ) {\r\n super(input, renewer, options);\r\n }\r\n\r\n protected override _latest(): Computed<T> | undefined {\r\n return (this.input as State<T>).computed;\r\n }\r\n\r\n protected override _register(): void {\r\n // No registration — state holds direct reference\r\n }\r\n\r\n protected override _unregister(): void {\r\n // No unregistration — was never registered\r\n }\r\n}\r\n","import { type Computed, ConsistencyState } from './computed.js';\r\n\r\n/** WeakRef-based global cache of Computed instances — allows GC of unused computed values. */\r\nexport class ComputedRegistry {\r\n private static _entries = new Map<string, WeakRef<Computed<unknown>>>();\r\n private static _finalization = new FinalizationRegistry<string>(key => {\r\n ComputedRegistry._entries.delete(key);\r\n });\r\n\r\n static get size(): number {\r\n return ComputedRegistry._entries.size;\r\n }\r\n\r\n static get(key: string): Computed<unknown> | undefined {\r\n const ref = ComputedRegistry._entries.get(key);\r\n if (ref === undefined) return undefined;\r\n const computed = ref.deref();\r\n if (computed === undefined) {\r\n ComputedRegistry._entries.delete(key);\r\n return undefined;\r\n }\r\n return computed;\r\n }\r\n\r\n static register(computed: Computed<unknown>): void {\r\n const key = computed.input as string;\r\n const displaced = ComputedRegistry._entries.get(key)?.deref();\r\n // Already registered — setOutput re-registers the instance registered at creation\r\n if (displaced === computed)\r\n return;\r\n\r\n if (displaced !== undefined && displaced.state !== ConsistencyState.Invalidated)\r\n displaced.invalidate();\r\n ComputedRegistry._entries.set(key, new WeakRef(computed));\r\n ComputedRegistry._finalization.register(computed, key, computed);\r\n }\r\n\r\n static unregister(computed: Computed<unknown>): void {\r\n const key = computed.input as string;\r\n ComputedRegistry._entries.delete(key);\r\n ComputedRegistry._finalization.unregister(computed);\r\n }\r\n}\r\n","import { AsyncContext, AsyncContextKey } from '@actuallab/core';\r\nimport type { Computed } from './computed.js';\r\n\r\nexport const computeContextKey = new AsyncContextKey<\r\n ComputeContext | undefined\r\n>('ComputeContext', undefined);\r\n\r\n/**\r\n * Tracks the currently executing (or captured) computation and captures dependencies.\r\n * A context with a `computed` is a computing context (adds dependant edges); one without\r\n * is a capture context (records the last captured Computed only — no edges).\r\n */\r\nexport class ComputeContext {\r\n readonly computed: Computed<unknown> | undefined;\r\n readonly parent: ComputeContext | undefined;\r\n private _isCapturing = true;\r\n private _captured: Computed<unknown> | undefined;\r\n\r\n constructor(\r\n computed?: Computed<unknown>,\r\n parent?: ComputeContext\r\n ) {\r\n this.computed = computed;\r\n this.parent = parent;\r\n }\r\n\r\n get isCapturing(): boolean {\r\n return this._isCapturing;\r\n }\r\n\r\n get captured(): Computed<unknown> | undefined {\r\n return this._captured;\r\n }\r\n\r\n stopCapturing(): void {\r\n this._isCapturing = false;\r\n }\r\n\r\n captureDependency(dependency: Computed<unknown>): void {\r\n if (!this._isCapturing) return;\r\n // Last capture wins — C# ComputeContext.TryCapture overwrites _captured.\r\n this._captured = dependency;\r\n this.computed?.addDependency(dependency);\r\n }\r\n\r\n // Walks the caller chain for a computation still in progress under the same key —\r\n // C# AsyncLockSet(LockReentryMode.CheckedFail) analog, used to fail fast on reentry.\r\n // Only Computing ancestors count: a context leaked past its finished computation\r\n // (e.g. via AsyncLocalStorage into a later callback) must not fail later calls.\r\n hasKeyInChain(key: unknown): boolean {\r\n const computed = this.computed;\r\n if (computed?.isComputing === true && computed.input === key)\r\n return true;\r\n\r\n return this.parent?.hasKeyInChain(key) ?? false;\r\n }\r\n\r\n /** Resolve ComputeContext from an AsyncContext (or current). */\r\n static from(ctx: AsyncContext | undefined): ComputeContext | undefined {\r\n return AsyncContext.from(ctx)?.get(computeContextKey);\r\n }\r\n}\r\n","/**\r\n * Per-Computed configuration, carried by every {@link Computed} via its\r\n * {@link ComputeFunction} (compute methods) or its kind's static default.\r\n * The home for per-method knobs; the C# analog is `ActualLab.Fusion.ComputedOptions`.\r\n */\r\nexport class ComputedOptions {\r\n static default = new ComputedOptions();\r\n static mutableStateDefault = new ComputedOptions({\r\n errorAutoInvalidateDelay: Infinity,\r\n });\r\n\r\n readonly errorAutoInvalidateDelay: number;\r\n\r\n constructor(overrides?: Partial<ComputedOptions>) {\r\n this.errorAutoInvalidateDelay =\r\n overrides?.errorAutoInvalidateDelay ?? 1000;\r\n }\r\n}\r\n","import {\r\n AsyncContext,\r\n AsyncLock,\r\n isCancellation,\r\n type Result,\r\n result,\r\n errorResult,\r\n} from '@actuallab/core';\r\nimport { Computed } from './computed.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { getInstanceId } from './computed-input.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type ComputeFunctionImpl = (this: any, ...args: unknown[]) => unknown;\r\n\r\n/** Record Separator — delimiter between key components. */\r\nconst RS = '\\x1E';\r\n\r\n// Keying is by JSON.stringify per argument, joined with RS delimiters. Collisions are\r\n// possible and by design (D2): functions, undefined, and symbols all map to '', objects\r\n// without serializable props to '{}', NaN to 'null', Map/Set to '{}'. The compute method's\r\n// author owns keyability — use JSON-representable argument types or supply a custom argToString.\r\nfunction defaultArgToString(arg: unknown): string {\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JSON.stringify returns undefined for undefined input\r\n return JSON.stringify(arg) ?? '';\r\n}\r\n\r\nlet _nextFunctionId = 0;\r\n\r\n/** Produces Computed<T> from a function — handles cache lookup, locking, dependency capture. */\r\nexport class ComputeFunction {\r\n readonly methodName: string;\r\n readonly id: string;\r\n readonly options: ComputedOptions;\r\n argToString: (arg: unknown) => string = defaultArgToString;\r\n private _impl: ComputeFunctionImpl;\r\n private _locks = new Map<string, AsyncLock>();\r\n\r\n constructor(\r\n methodName: string,\r\n impl: ComputeFunctionImpl,\r\n options: ComputedOptions = ComputedOptions.default\r\n ) {\r\n this.methodName = methodName;\r\n this.id = `${methodName}[${++_nextFunctionId}]`;\r\n this._impl = impl;\r\n this.options = options;\r\n }\r\n\r\n /** Build a string key for the given instance and arguments. */\r\n buildKey(instance: object, args: unknown[]): string {\r\n let key = String(getInstanceId(instance)) + RS + this.id;\r\n for (const arg of args) {\r\n key += RS + this.argToString(arg);\r\n }\r\n return key;\r\n }\r\n\r\n async invoke(\r\n instance: object,\r\n args: unknown[]\r\n ): Promise<Computed<unknown>> {\r\n // 1. Resolve AsyncContext ONCE via DRY helper\r\n const asyncCtx = AsyncContext.fromArgs(args);\r\n\r\n // 2. Pull caller's ComputeContext directly\r\n const callerComputeCtx = asyncCtx?.get(computeContextKey);\r\n\r\n // 3. Strip THIS context from args (reference equality — safe)\r\n const argsWithoutCtx = asyncCtx?.stripFromArgs(args) ?? args;\r\n\r\n // 4. Build string key and check cache\r\n const key = this.buildKey(instance, argsWithoutCtx);\r\n const existing = ComputedRegistry.get(key);\r\n if (existing?.isConsistent) {\r\n callerComputeCtx?.captureDependency(existing);\r\n return existing;\r\n }\r\n\r\n // C# AsyncLockSet(CheckedFail) analog: a compute call that (indirectly) awaits itself\r\n // with the same key would await its own non-reentrant lock forever — fail fast instead.\r\n if (callerComputeCtx?.hasKeyInChain(key))\r\n throw new Error(`Reentrant compute call detected for key \"${key}\".`);\r\n\r\n // 5. Lock per key to prevent duplicate computations\r\n let lock = this._locks.get(key);\r\n if (lock === undefined) {\r\n lock = new AsyncLock();\r\n this._locks.set(key, lock);\r\n }\r\n\r\n const computed = await lock.run(async () => {\r\n // Double-check after acquiring lock\r\n const cached = ComputedRegistry.get(key);\r\n if (cached?.isConsistent) return cached;\r\n\r\n // 6. Create new Computed + ComputeContext\r\n const renewer = () => this.invoke(instance, argsWithoutCtx);\r\n const newComputed = new Computed<unknown>(\r\n key,\r\n renewer,\r\n this.options\r\n );\r\n // Register while still Computing so ComputedRegistry.get(key) resolves the\r\n // in-flight instance and a racing invalidate() is captured as pending — C#\r\n // ComputeMethodComputed registers in its constructor.\r\n ComputedRegistry.register(newComputed);\r\n\r\n const childComputeCtx = new ComputeContext(\r\n newComputed,\r\n callerComputeCtx\r\n );\r\n const childAsyncCtx = (asyncCtx ?? AsyncContext.empty).with(\r\n computeContextKey,\r\n childComputeCtx\r\n );\r\n\r\n // 7. Run with clean args, threading childAsyncCtx as a trailing argument so a compute\r\n // body can pass it into nested calls / use(ctx) after awaits — the portable floor for\r\n // dependency capture when AsyncLocalStorage isn't backing AsyncContext.current (browsers).\r\n let fnResult: Result<unknown>;\r\n try {\r\n const value = childAsyncCtx.run(() =>\r\n this._impl.call(instance, ...argsWithoutCtx, childAsyncCtx)\r\n );\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\r\n const resolved = value instanceof Promise ? await value : value;\r\n fnResult = result(resolved);\r\n } catch (e) {\r\n fnResult = errorResult(e);\r\n }\r\n\r\n newComputed.setOutput(fnResult);\r\n // C# StartAutoInvalidation OCE parity: a cancellation error is registered to keep the\r\n // single-flight lock protocol intact, then invalidated at once so it's never cached.\r\n if (fnResult.hasError && isCancellation(fnResult.error))\r\n newComputed.invalidate();\r\n\r\n return newComputed;\r\n });\r\n\r\n if (!lock.isLocked && this._locks.get(key) === lock)\r\n this._locks.delete(key);\r\n\r\n // Register dependency from caller to the produced computed\r\n callerComputeCtx?.captureDependency(computed);\r\n return computed;\r\n }\r\n}\r\n","/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-this-alias */\r\nimport { ownMetadata, resolveArgCount } from '@actuallab/core';\r\nimport { ComputeFunction } from './compute-function.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\n\r\nconst METHODS_META = Symbol.for('actuallab.methods');\r\n\r\nexport interface MethodMeta {\r\n argCount: number;\r\n compute?: boolean;\r\n stream?: boolean;\r\n}\r\n\r\n/** Read method metadata from a decorated class. */\r\nexport function getMethodsMeta(\r\n cls: abstract new (...args: any[]) => any\r\n): Record<string, MethodMeta> | undefined {\r\n return (cls as any)[Symbol.metadata]?.[METHODS_META];\r\n}\r\n\r\nexport interface ComputeMethodOptions extends Partial<ComputedOptions> {\r\n argCount?: number;\r\n}\r\n\r\ntype ComputeMethodDecorator<This, Args extends unknown[], Return> = (\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n) => (this: This, ...args: Args) => Return;\r\n\r\n/**\r\n * Method decorator — routes a method through ComputeFunction for caching and dependency\r\n * tracking. Usable bare (`@computeMethod`) or with options (`@computeMethod({ argCount })`).\r\n */\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n): (this: This, ...args: Args) => Return;\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n options?: ComputeMethodOptions\r\n): ComputeMethodDecorator<This, Args, Return>;\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n targetOrOptions?: ((this: This, ...args: Args) => Return) | ComputeMethodOptions,\r\n context?: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n): unknown {\r\n if (typeof targetOrOptions === 'function')\r\n return computeMethodImpl(targetOrOptions, context!, {});\r\n\r\n const options = targetOrOptions ?? {};\r\n return (target: (this: This, ...args: Args) => Return, ctx: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>) =>\r\n computeMethodImpl(target, ctx, options);\r\n}\r\n\r\nfunction computeMethodImpl<This, Args extends unknown[], Return>(\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<\r\n This,\r\n (this: This, ...args: Args) => Return\r\n >,\r\n options: ComputeMethodOptions\r\n): (this: This, ...args: Args) => Return {\r\n const methodName = String(context.name);\r\n\r\n const methods = ownMetadata<Record<string, MethodMeta>>(context.metadata, METHODS_META);\r\n methods[methodName] = {\r\n ...methods[methodName],\r\n compute: true,\r\n argCount: resolveArgCount(target, options.argCount, methodName),\r\n };\r\n\r\n // ONE ComputeFunction per class×method — created at decoration time\r\n const cf = new ComputeFunction(methodName, target as any, new ComputedOptions(options));\r\n\r\n // Prototype-level replacement — unwraps Computed to return the value directly\r\n const replacement = function (this: This, ...allArgs: Args): Return {\r\n return cf.invoke(this as object, allArgs).then(c => c.value) as Return;\r\n };\r\n\r\n // Per-instance setup: create bound method with .invalidate pre-bound\r\n context.addInitializer(function (this: This) {\r\n const instance = this;\r\n const boundMethod = (...allArgs: unknown[]) => {\r\n return cf.invoke(instance as object, allArgs).then(c => c.value);\r\n };\r\n (boundMethod as any).invalidate = (...args: unknown[]) => {\r\n const key = cf.buildKey(instance as object, args);\r\n ComputedRegistry.get(key)?.invalidate();\r\n };\r\n (this as any)[methodName] = boundMethod;\r\n });\r\n\r\n return replacement;\r\n}\r\n\r\n/** Wrap a standalone function as a compute function with caching and .invalidate(). */\r\nexport function wrapComputeMethod<Args extends unknown[], Return>(\r\n fn: (...args: Args) => Return\r\n): ((...args: Args) => Promise<Return>) & {\r\n invalidate: (...args: Args) => void;\r\n} {\r\n const syntheticInstance = {};\r\n const methodName = fn.name || 'anonymous';\r\n const cf = new ComputeFunction(methodName, fn as any);\r\n\r\n const wrapped = (...allArgs: unknown[]) => {\r\n return cf\r\n .invoke(syntheticInstance, allArgs)\r\n .then(c => c.value as Return);\r\n };\r\n\r\n (wrapped as any).invalidate = (...args: unknown[]) => {\r\n const key = cf.buildKey(syntheticInstance, args);\r\n ComputedRegistry.get(key)?.invalidate();\r\n };\r\n\r\n return wrapped as any;\r\n}\r\n","import { awaitWithCleanup, RetryDelaySeq } from '@actuallab/core';\r\n\r\n/** Controls when state re-computation happens after invalidation, per consecutive-error retryCount. */\r\nexport type UpdateDelayer = (\r\n retryCount: number,\r\n abortSignal?: AbortSignal\r\n) => Promise<void>;\r\n\r\n/** 1 s → 1 min exponential backoff — C# FixedDelayer.Defaults.RetryDelays parity. */\r\nexport const defaultRetryDelays = RetryDelaySeq.exp(1000, 60_000);\r\n\r\n/** Windows timer period is 15.6 ms, so 32 ms = 2..3 timer ticks — C# FixedDelayer.Defaults.MinDelay. */\r\nexport const defaultMinDelayMs = 32;\r\n\r\n// C# UpdateDelayer.GetDelay + minDelay floor: retryCount 0 uses the update delay\r\n// floored by minDelay; retryCount > 0 uses RetryDelays[retryCount] floored by RetryDelays.Min.\r\nexport function computeUpdateDelay(\r\n retryCount: number,\r\n updateDelayMs: number,\r\n retryDelays: RetryDelaySeq,\r\n minDelayMs: number\r\n): number {\r\n const min = retryCount === 0 ? minDelayMs : retryDelays.min;\r\n const raw = retryCount > 0 ? retryDelays.getDelay(retryCount) : updateDelayMs;\r\n return Math.max(min, raw);\r\n}\r\n\r\n/** Re-computes after a fixed update delay, with RetryDelaySeq backoff for consecutive errors. */\r\nexport class FixedDelayer {\r\n static readonly zero: UpdateDelayer = () => Promise.resolve();\r\n\r\n private static _cache = new Map<number, UpdateDelayer>();\r\n\r\n // Floors ms at minDelay like C# FixedDelayer.Get — a zero delayer requires the explicit .zero.\r\n static get(ms: number): UpdateDelayer {\r\n ms = Math.max(ms, defaultMinDelayMs);\r\n let delayer = FixedDelayer._cache.get(ms);\r\n if (delayer === undefined) {\r\n delayer = new FixedDelayer(ms).delay;\r\n FixedDelayer._cache.set(ms, delayer);\r\n }\r\n return delayer;\r\n }\r\n\r\n readonly ms: number;\r\n readonly retryDelays: RetryDelaySeq;\r\n readonly minDelay: number;\r\n readonly delay: UpdateDelayer;\r\n\r\n constructor(\r\n ms: number,\r\n retryDelays: RetryDelaySeq = defaultRetryDelays,\r\n minDelay: number = defaultMinDelayMs\r\n ) {\r\n this.ms = ms;\r\n this.retryDelays = retryDelays;\r\n this.minDelay = minDelay;\r\n // Abort stops the wait early (resolves, never rejects) so a disposed\r\n // ComputedState's update loop terminates promptly and the race loser\r\n // carries no unhandled rejection (C# SuppressCancellationAwait spirit).\r\n this.delay = (retryCount, abortSignal) => {\r\n const delayMs = computeUpdateDelay(\r\n retryCount,\r\n this.ms,\r\n this.retryDelays,\r\n this.minDelay\r\n );\r\n if (delayMs <= 0) return Promise.resolve();\r\n\r\n return awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, delayMs);\r\n addCleanup(() => clearTimeout(timer));\r\n });\r\n };\r\n }\r\n}\r\n\r\nexport const defaultUpdateDelayer: UpdateDelayer = FixedDelayer.get(1000 / 60);\r\n","import { awaitWithCleanup, type RetryDelaySeq } from '@actuallab/core';\r\nimport { uiActions } from './ui-action-tracker.js';\r\nimport {\r\n computeUpdateDelay,\r\n defaultMinDelayMs,\r\n defaultRetryDelays,\r\n type UpdateDelayer,\r\n} from './update-delayer.js';\r\n\r\n/** Re-computes after a delay, but short-circuits while UIActionTracker enables instant updates. */\r\nexport class UIUpdateDelayer {\r\n private static _cache = new Map<number, UpdateDelayer>();\r\n\r\n // Floors ms at minDelay like C# FixedDelayer.Get — a zero delayer requires FixedDelayer.zero.\r\n static get(ms: number): UpdateDelayer {\r\n ms = Math.max(ms, defaultMinDelayMs);\r\n let delayer = UIUpdateDelayer._cache.get(ms);\r\n if (delayer !== undefined) return delayer;\r\n\r\n delayer = new UIUpdateDelayer(ms).delay;\r\n UIUpdateDelayer._cache.set(ms, delayer);\r\n return delayer;\r\n }\r\n\r\n readonly ms: number;\r\n readonly retryDelays: RetryDelaySeq;\r\n readonly minDelay: number;\r\n readonly delay: UpdateDelayer;\r\n\r\n constructor(\r\n ms: number,\r\n retryDelays: RetryDelaySeq = defaultRetryDelays,\r\n minDelay: number = defaultMinDelayMs\r\n ) {\r\n this.ms = ms;\r\n this.retryDelays = retryDelays;\r\n this.minDelay = minDelay;\r\n this.delay = this._delay.bind(this);\r\n }\r\n\r\n // Private methods\r\n\r\n // Mirrors C# UpdateDelayer.Delay: race the instant-updates window against the full delay,\r\n // then enforce minDelay measured from delay start so instant updates never hot-loop the CPU.\r\n private async _delay(retryCount: number, abortSignal?: AbortSignal): Promise<void> {\r\n const t = uiActions;\r\n const minDelay = retryCount === 0 ? this.minDelay : this.retryDelays.min;\r\n const delayMs = computeUpdateDelay(retryCount, this.ms, this.retryDelays, this.minDelay);\r\n if (delayMs <= 0)\r\n return;\r\n\r\n const startedAt = Date.now();\r\n if (!t.areInstantUpdatesEnabled())\r\n await awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, delayMs);\r\n addCleanup(() => clearTimeout(timer));\r\n\r\n const onChanged = () => {\r\n if (t.areInstantUpdatesEnabled())\r\n complete();\r\n };\r\n t.changed.add(onChanged);\r\n addCleanup(() => t.changed.remove(onChanged));\r\n });\r\n if (abortSignal?.aborted)\r\n return;\r\n\r\n const remaining = minDelay - (Date.now() - startedAt);\r\n if (remaining > 0)\r\n await awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, remaining);\r\n addCleanup(() => clearTimeout(timer));\r\n });\r\n }\r\n}\r\n","import { EventHandlerSet } from '@actuallab/core';\r\nimport { getLogs } from './logging.js';\r\n\r\nconst { errorLog } = getLogs('UIActionTracker');\r\n\r\n/** Singleton tracking active UI commands — mirrors .NET's UIActionTracker. */\r\nexport class UIActionTracker {\r\n private _activeCount = 0;\r\n private _lastResultAt = 0;\r\n private _errorTimes: number[] = [];\r\n readonly changed = new EventHandlerSet<void>();\r\n readonly errors: unknown[] = [];\r\n\r\n // C# UIActionTracker.Options.InstantUpdatePeriod / UIActionFailureTracker MaxDuplicateRecency.\r\n instantUpdatePeriod = 300;\r\n maxDuplicateRecency = 1000;\r\n maxErrors = 100;\r\n\r\n get isActive(): boolean {\r\n return this._activeCount > 0;\r\n }\r\n\r\n // C# UIActionTracker.AreInstantUpdatesEnabled — active, or within instantUpdatePeriod of the last result.\r\n areInstantUpdatesEnabled(): boolean {\r\n if (this._activeCount > 0)\r\n return true;\r\n if (this._lastResultAt === 0)\r\n return false;\r\n\r\n return this._lastResultAt + this.instantUpdatePeriod >= Date.now();\r\n }\r\n\r\n /** Run a command silently — errors are added to the error list but not thrown. */\r\n async run(fn: () => Promise<unknown>): Promise<void> {\r\n this._activeCount++;\r\n this.changed.trigger();\r\n try {\r\n await fn();\r\n } catch (e) {\r\n // Mirrors UIActionTracker.cs:58 — UI action failure.\r\n errorLog?.log('UI action failed', e);\r\n this._addError(e);\r\n } finally {\r\n this._onCompleted();\r\n }\r\n }\r\n\r\n /** Call a command and return the result — errors are added to the error list AND thrown. */\r\n async call<T>(fn: () => Promise<T>): Promise<T> {\r\n this._activeCount++;\r\n this.changed.trigger();\r\n try {\r\n return await fn();\r\n } catch (e) {\r\n // Mirrors UIActionTracker.cs:58 — UI action failure.\r\n errorLog?.log('UI action failed', e);\r\n this._addError(e);\r\n throw e;\r\n } finally {\r\n this._onCompleted();\r\n }\r\n }\r\n\r\n dismissError(index: number): void {\r\n if (index >= 0 && index < this.errors.length) {\r\n this.errors.splice(index, 1);\r\n this._errorTimes.splice(index, 1);\r\n this.changed.trigger();\r\n }\r\n }\r\n\r\n // Private methods\r\n\r\n private _onCompleted(): void {\r\n this._activeCount--;\r\n this._lastResultAt = Date.now();\r\n this.changed.trigger();\r\n }\r\n\r\n // C# UIActionFailureTracker.TryAddFailure — drop a same-name/same-message error seen within\r\n // maxDuplicateRecency; a size cap is the backstop against unbounded growth.\r\n private _addError(e: unknown): void {\r\n const now = Date.now();\r\n const { name, message } = errorInfo(e);\r\n const minAt = now - this.maxDuplicateRecency;\r\n for (let i = 0; i < this.errors.length; i++) {\r\n if (this._errorTimes[i] < minAt)\r\n continue;\r\n\r\n const prev = errorInfo(this.errors[i]);\r\n if (prev.name === name && prev.message === message)\r\n return;\r\n }\r\n\r\n this.errors.push(e);\r\n this._errorTimes.push(now);\r\n while (this.errors.length > this.maxErrors) {\r\n this.errors.shift();\r\n this._errorTimes.shift();\r\n }\r\n this.changed.trigger();\r\n }\r\n}\r\n\r\nfunction errorInfo(e: unknown): { name: string; message: string } {\r\n if (e instanceof Error)\r\n return { name: e.name, message: e.message };\r\n\r\n return { name: '', message: String(e) };\r\n}\r\n\r\nexport const uiActions = new UIActionTracker();\r\n","import {\r\n type AsyncContext,\r\n type IResult,\r\n PromiseSource,\r\n resolvedVoidPromise,\r\n type Result,\r\n} from '@actuallab/core';\r\nimport { type Computed, StateBoundComputed } from './computed.js';\r\n\r\n/** Base class for all reactive state types. */\r\nexport abstract class State<T> implements IResult<T> {\r\n protected _computed!: Computed<T>;\r\n protected _updateIndex = 0;\r\n // Reference to the last non-error computed, not its raw value, so an actual\r\n // `undefined` value is distinguishable from \"no non-error value yet\" (S12).\r\n protected _lastNonErrorComputed: Computed<T> | undefined;\r\n private _whenUpdatedSource: PromiseSource<void> | null = null;\r\n private _isDisposed = false;\r\n\r\n get updateIndex(): number {\r\n return this._updateIndex;\r\n }\r\n\r\n get isDisposed(): boolean {\r\n return this._isDisposed;\r\n }\r\n\r\n get lastNonErrorValue(): T | undefined {\r\n return this._lastNonErrorComputed?.value;\r\n }\r\n\r\n get hasValue(): boolean {\r\n return this._computed.hasValue;\r\n }\r\n\r\n get hasError(): boolean {\r\n return this._computed.hasError;\r\n }\r\n\r\n get value(): T {\r\n return this._computed.value;\r\n }\r\n\r\n get error(): unknown {\r\n return this._computed.error;\r\n }\r\n\r\n get valueOrUndefined(): T | undefined {\r\n return this._computed.valueOrUndefined;\r\n }\r\n\r\n get output(): Result<T> {\r\n return this._computed.output;\r\n }\r\n\r\n get computed(): Computed<T> {\r\n return this._computed;\r\n }\r\n\r\n use(asyncContext?: AsyncContext): T | Promise<T> {\r\n return this._computed.use(asyncContext);\r\n }\r\n\r\n useInconsistent(asyncContext?: AsyncContext): T {\r\n return this._computed.useInconsistent(asyncContext);\r\n }\r\n\r\n update(): Computed<T> | Promise<Computed<T>> {\r\n return this._computed.update();\r\n }\r\n\r\n recompute(): Computed<T> | Promise<Computed<T>> {\r\n this._computed.invalidate();\r\n return this.update();\r\n }\r\n\r\n whenInvalidated(): Promise<void> {\r\n return this._computed.whenInvalidated();\r\n }\r\n\r\n // Versioned wait: resolves at once when a newer generation than sinceIndex\r\n // already landed (no lost wakeup), rejects once disposed (C# StateSnapshot.WhenUpdated).\r\n whenUpdated(sinceIndex: number = this._updateIndex): Promise<void> {\r\n if (this._isDisposed)\r\n return Promise.reject(State._disposedError());\r\n if (this._updateIndex > sinceIndex)\r\n return resolvedVoidPromise;\r\n\r\n return (this._whenUpdatedSource ??= new PromiseSource<void>());\r\n }\r\n\r\n whenFirstTimeUpdated(): Promise<void> {\r\n return this.whenUpdated(0);\r\n }\r\n\r\n protected _initialize(\r\n output: Result<T> | T,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>\r\n ): void {\r\n this._computed = this._createComputed(renewer);\r\n this._computed.setOutput(output);\r\n if (this._computed.hasValue) this._lastNonErrorComputed = this._computed;\r\n }\r\n\r\n protected _createComputed(\r\n renewer?: () => Computed<T> | Promise<Computed<T>>\r\n ): Computed<T> {\r\n return new StateBoundComputed<T>(this, renewer);\r\n }\r\n\r\n protected _update(computed: Computed<T>, output: Result<T> | T): void {\r\n const replaced = this._computed as Computed<T> | undefined;\r\n computed.setOutput(output);\r\n this._computed = computed;\r\n if (replaced?.isConsistent) replaced.invalidate();\r\n if (computed.hasValue) this._lastNonErrorComputed = computed;\r\n this._updateIndex++;\r\n this._whenUpdatedSource?.resolve(undefined);\r\n this._whenUpdatedSource = null;\r\n }\r\n\r\n protected _onDisposed(): void {\r\n if (this._isDisposed)\r\n return;\r\n\r\n this._isDisposed = true;\r\n this._whenUpdatedSource?.reject(State._disposedError());\r\n this._whenUpdatedSource = null;\r\n }\r\n\r\n private static _disposedError(): Error {\r\n return new Error('State is disposed.');\r\n }\r\n}\r\n","import {\r\n AsyncContext,\r\n PromiseSource,\r\n type Result,\r\n result,\r\n errorResult,\r\n} from '@actuallab/core';\r\nimport { type Computed, StateBoundComputed } from './computed.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { getLogs } from './logging.js';\r\nimport { defaultUpdateDelayer, type UpdateDelayer } from './update-delayer.js';\r\nimport { State } from './state.js';\r\n\r\nconst { errorLog } = getLogs('ComputedState');\r\n\r\nexport type StateComputer<T> = () => T | Promise<T>;\r\n\r\n/** Constructor options for ComputedState. */\r\nexport interface ComputedStateOptions<T> {\r\n initialValue?: T;\r\n initialOutput?: Result<T>;\r\n updateDelayer?: UpdateDelayer;\r\n}\r\n\r\n/** Auto-updating reactive state wrapper — re-computes on invalidation with configurable delay. */\r\nexport class ComputedState<T> extends State<T> {\r\n private _computer: StateComputer<T>;\r\n private _updateDelayer: UpdateDelayer;\r\n private _disposeController: AbortController;\r\n private _cancelDelaySource = new PromiseSource<void>();\r\n private _renewer: () => Computed<T> | Promise<Computed<T>>;\r\n\r\n constructor(computer: StateComputer<T>, options?: ComputedStateOptions<T>) {\r\n super();\r\n this._computer = computer;\r\n this._updateDelayer = options?.updateDelayer ?? defaultUpdateDelayer;\r\n this._disposeController = new AbortController();\r\n this._renewer = async () => {\r\n const sinceIndex = this._updateIndex;\r\n this._cancelDelaySource.resolve(undefined);\r\n await this.whenUpdated(sinceIndex);\r\n return this._computed;\r\n };\r\n\r\n // The initial computed is created pre-invalidated (C# State.cs:246) so inherited\r\n // members (use/update/recompute/whenInvalidated) await the first real computation\r\n // instead of returning the placeholder, and dependants never latch onto it.\r\n this._initialize(\r\n options?.initialOutput ?? (options?.initialValue as T),\r\n this._renewer\r\n );\r\n this._computed.invalidate();\r\n\r\n void this._updateCycle();\r\n }\r\n\r\n dispose(): void {\r\n if (this.isDisposed)\r\n return;\r\n\r\n this._onDisposed();\r\n this._disposeController.abort();\r\n }\r\n\r\n private async _updateCycle(): Promise<void> {\r\n const disposeSignal = this._disposeController.signal;\r\n let retryCount = 0;\r\n try {\r\n while (!disposeSignal.aborted) {\r\n // Compute\r\n const computed = new StateBoundComputed<T>(this, this._renewer);\r\n const computeCtx = new ComputeContext(\r\n computed as StateBoundComputed<unknown>\r\n );\r\n const asyncCtx = (\r\n AsyncContext.current ?? AsyncContext.empty\r\n ).with(computeContextKey, computeCtx);\r\n\r\n let output: Result<T>;\r\n try {\r\n const value = asyncCtx.run(() => this._computer());\r\n const resolved =\r\n value instanceof Promise ? await value : value;\r\n output = result(resolved);\r\n } catch (e) {\r\n output = errorResult(e);\r\n }\r\n if (this.isDisposed)\r\n return; // Disposed mid-computation — publish nothing, terminate the cycle.\r\n\r\n this._update(computed, output);\r\n retryCount = output.hasError ? retryCount + 1 : 0;\r\n if (this._cancelDelaySource.isCompleted)\r\n this._cancelDelaySource = new PromiseSource<void>();\r\n\r\n // Wait for invalidation (or cancellation via dispose)\r\n try {\r\n await computed.whenInvalidated(disposeSignal);\r\n } catch {\r\n return; // Cancelled via dispose\r\n }\r\n\r\n // Wait for delay (cancellable by renewer); retryCount grows the backoff (S8).\r\n await Promise.race([\r\n this._updateDelayer(retryCount, disposeSignal),\r\n this._cancelDelaySource,\r\n ]);\r\n }\r\n } catch (e) {\r\n // Mirrors ComputedState.cs:188 — UpdateCycle failed and stopped.\r\n if (!disposeSignal.aborted)\r\n errorLog?.log('UpdateCycle() failed and stopped', e);\r\n }\r\n }\r\n}\r\n","import { type AsyncContext, Result, result } from '@actuallab/core';\r\nimport { type Computed } from './computed.js';\r\nimport { State } from './state.js';\r\n\r\n/** Manually-settable reactive state that can participate in the Fusion dependency graph. */\r\nexport class MutableState<T> extends State<T> {\r\n private _nextOutput: Result<T>;\r\n\r\n private _renewer = (): Computed<T> => {\r\n const computed = this._createComputed(this._renewer);\r\n this._update(computed, this._nextOutput);\r\n this._wireRenewal(computed);\r\n return computed;\r\n };\r\n\r\n constructor(initialOutput: Result<T> | T) {\r\n super();\r\n this._nextOutput =\r\n initialOutput instanceof Result ? initialOutput : result(initialOutput);\r\n this._initialize(this._nextOutput, this._renewer);\r\n this._wireRenewal(this._computed);\r\n }\r\n\r\n override use(asyncContext?: AsyncContext): T {\r\n return this._computed.use(asyncContext) as T;\r\n }\r\n\r\n set(output: Result<T> | T): void {\r\n const next = output instanceof Result ? output : result(output);\r\n if (this._nextOutput.equals(next))\r\n return;\r\n\r\n this._nextOutput = next;\r\n this._computed.invalidate();\r\n }\r\n\r\n // Private methods\r\n\r\n // Renew synchronously on invalidation so a MutableState is never observed invalidated.\r\n // update() de-dupes: if the computed was already renewed, it returns the latest instead.\r\n private _wireRenewal(computed: Computed<T>): void {\r\n computed.onInvalidated(() => void computed.update());\r\n }\r\n}\r\n"],"mappings":"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","names":["AsyncContext","ConsistencyState","AsyncContext","captured","AsyncContext","isCancellation","result","AsyncContext","result","isCancellation","awaitWithCleanup","EventHandlerSet","errorLog","EventHandlerSet","awaitWithCleanup","PromiseSource","PromiseSource","AsyncContext","PromiseSource","result","errorResult","errorLog","PromiseSource","AsyncContext","result","errorResult","Result","result","Result","result"]}
|
|
1
|
+
{"version":3,"sources":["../src/logging.ts","../src/computed-input.ts","../src/computed.ts","../src/computed-registry.ts","../src/compute-context.ts","../src/computed-options.ts","../src/compute-function.ts","../src/compute-method.ts","../src/update-delayer.ts","../src/ui-update-delayer.ts","../src/ui-action-tracker.ts","../src/state.ts","../src/computed-state.ts","../src/mutable-state.ts"],"sourcesContent":["import { createLogProvider, LogLevel } from '@actuallab/core';\n\n// Per-package log scopes. Use createLogProvider to get a typed helper:\n// const { debugLog, warnLog } = getLogs('Computed');\n// Final scope name is 'fusion.Computed' — the prefix isolates this package's\n// scopes from other packages' scopes when overriding levels at runtime.\nexport type FusionLogScope =\n | 'Computed'\n | 'ComputedRegistry'\n | 'ComputedState'\n | 'ComputeFunction'\n | 'MutableState'\n | 'State'\n | 'UIActionTracker'\n | 'UIUpdateDelayer';\n\n// Per-scope defaults. All Warn — Fusion is mostly hot-path compute graph code;\n// noisy scopes need to be opted-in for development.\nconst scopeDefaults: Record<FusionLogScope, LogLevel> = {\n Computed: LogLevel.Warn,\n ComputedRegistry: LogLevel.Warn,\n ComputedState: LogLevel.Warn,\n ComputeFunction: LogLevel.Warn,\n MutableState: LogLevel.Warn,\n State: LogLevel.Warn,\n UIActionTracker: LogLevel.Warn,\n UIUpdateDelayer: LogLevel.Warn,\n};\n\nexport const getLogs = createLogProvider<FusionLogScope>('fusion.', scopeDefaults);\n","import type { State } from './state.js';\r\n\r\n/** Auto-assigned numeric IDs for instance identity in compute method cache keys. */\r\nlet _nextInstanceId = 0;\r\nconst _instanceIds = new WeakMap<object, number>();\r\n\r\nexport function getInstanceId(instance: object): number {\r\n let id = _instanceIds.get(instance);\r\n if (id === undefined) {\r\n id = ++_nextInstanceId;\r\n _instanceIds.set(instance, id);\r\n }\r\n return id;\r\n}\r\n\r\n/**\r\n * Identity key for any computed value.\r\n * - String for compute method results (built from instance + function + args)\r\n * - State for state types (identity by reference)\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type ComputedInput = string | State<any>;\r\n","import {\r\n AsyncContext,\r\n EventHandlerSet,\r\n type IResult,\r\n isCancellation,\r\n PromiseSource,\r\n Result,\r\n result,\r\n} from '@actuallab/core';\r\nimport type { ComputedInput } from './computed-input.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { getLogs } from './logging.js';\r\nimport type { State } from './state.js';\r\n\r\nconst { errorLog } = getLogs('Computed');\r\n\r\nlet _nextVersion = 0;\r\n\r\n// A dependant drops its own edges only when it's invalidated, so a dependency that\r\n// outlives many dependants accumulates dead WeakRefs. .NET reclaims them from the\r\n// background ComputedGraphPruner; TS has no worker, so pruning is amortized into\r\n// addDependency and the threshold doubles past the surviving edge count each time.\r\nconst MinPruneDependantsThreshold = 16;\r\n\r\nexport const enum ConsistencyState {\r\n Computing = 0,\r\n Consistent = 1,\r\n Invalidated = 2,\r\n}\r\n\r\n/** Core Fusion abstraction — a cached computation with dependency tracking and invalidation. */\r\nexport class Computed<T> implements IResult<T> {\r\n /** Capture the Computed backing a computation — works with both local and RPC compute methods. */\r\n static async capture<T>(fn: () => T | Promise<T>): Promise<Computed<T>> {\r\n // A capture context (no computed) records the last captured Computed without adding\r\n // dependant edges — mirrors C# ComputeContext(CallOptions.Capture) + Computed.Capture.\r\n // The parent link keeps reentrancy detection working through capture — in C# lock\r\n // reentry flows through ExecutionContext regardless of BeginCapture.\r\n const currentCtx = AsyncContext.getOrCreate();\r\n const captureCtx = new ComputeContext(\r\n undefined,\r\n currentCtx.get(computeContextKey)\r\n );\r\n const asyncCtx = currentCtx.with(computeContextKey, captureCtx);\r\n try {\r\n await asyncCtx.run(fn);\r\n } catch (e) {\r\n if (isCancellation(e)) throw e;\r\n const captured = captureCtx.captured;\r\n if (captured?.hasError) return captured as Computed<T>;\r\n\r\n throw e;\r\n }\r\n const captured = captureCtx.captured;\r\n if (captured === undefined)\r\n throw new Error(\r\n 'No Computed was captured — fn must call a compute function.'\r\n );\r\n return captured as Computed<T>;\r\n }\r\n\r\n readonly input: ComputedInput;\r\n readonly options: ComputedOptions;\r\n private _version: number;\r\n private _state: ConsistencyState;\r\n private _output: Result<T> | undefined;\r\n private _invalidatePending = false;\r\n private _errorTimer: ReturnType<typeof setTimeout> | undefined;\r\n private _dependencies = new Set<Computed<unknown>>();\r\n private _dependants = new Map<number, WeakRef<Computed<unknown>>>();\r\n private _pruneDependantsThreshold = MinPruneDependantsThreshold;\r\n private _onInvalidated = new EventHandlerSet<void>();\r\n readonly _renewer: (() => Computed<T> | Promise<Computed<T>>) | undefined;\r\n\r\n constructor(\r\n input: ComputedInput,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>,\r\n options: ComputedOptions = ComputedOptions.default\r\n ) {\r\n this.input = input;\r\n this.options = options;\r\n this._renewer = renewer;\r\n this._version = ++_nextVersion;\r\n this._state = ConsistencyState.Computing;\r\n }\r\n\r\n get version(): number {\r\n return this._version;\r\n }\r\n\r\n get output(): Result<T> {\r\n if (this._output === undefined)\r\n throw new Error('Computed has no output yet.');\r\n return this._output;\r\n }\r\n\r\n get hasValue(): boolean {\r\n return this.output.hasValue;\r\n }\r\n\r\n get hasError(): boolean {\r\n return this.output.hasError;\r\n }\r\n\r\n get value(): T {\r\n return this.output.value;\r\n }\r\n\r\n get error(): unknown {\r\n return this.output.error;\r\n }\r\n\r\n get valueOrUndefined(): T | undefined {\r\n return this.output.valueOrUndefined;\r\n }\r\n\r\n get state(): ConsistencyState {\r\n return this._state;\r\n }\r\n\r\n get isConsistent(): boolean {\r\n return this._state === ConsistencyState.Consistent;\r\n }\r\n\r\n get isComputing(): boolean {\r\n return this._state === ConsistencyState.Computing;\r\n }\r\n\r\n get dependencies(): ReadonlySet<Computed<unknown>> {\r\n return this._dependencies;\r\n }\r\n\r\n get dependantCount(): number {\r\n return this._dependants.size;\r\n }\r\n\r\n update(): Computed<T> | Promise<Computed<T>> {\r\n if (this._state === ConsistencyState.Consistent) return this;\r\n const latest = this._latest();\r\n if (latest?.isConsistent) return latest;\r\n if (this._renewer !== undefined) {\r\n const renewer = this._renewer;\r\n // Run the renewer with the compute context cleared so renewal never\r\n // records a dependency edge in the ambient computation — TS analog of\r\n // C# Computed.UpdateUntyped's BeginIsolation.\r\n const isolated = (AsyncContext.current ?? AsyncContext.empty).with(\r\n computeContextKey,\r\n undefined\r\n );\r\n return isolated.run(renewer);\r\n }\r\n throw new Error(\r\n 'Cannot recompute: Computed is invalidated and has no renewer.'\r\n );\r\n }\r\n\r\n protected _latest(): Computed<T> | undefined {\r\n return ComputedRegistry.get(this.input as string) as\r\n | Computed<T>\r\n | undefined;\r\n }\r\n\r\n use(asyncContext?: AsyncContext): T | Promise<T> {\r\n const ctx = ComputeContext.from(asyncContext);\r\n const updated = this.update();\r\n if (updated instanceof Promise) {\r\n return updated.then(c => {\r\n ctx?.captureDependency(c as Computed<unknown>);\r\n return c.value;\r\n });\r\n }\r\n ctx?.captureDependency(updated as Computed<unknown>);\r\n return updated.value;\r\n }\r\n\r\n useInconsistent(asyncContext?: AsyncContext): T {\r\n ComputeContext.from(asyncContext)?.captureDependency(\r\n this as Computed<unknown>\r\n );\r\n return this.value;\r\n }\r\n\r\n setOutput(output: Result<T> | T): void {\r\n if (this._state !== ConsistencyState.Computing)\r\n throw new Error('Cannot set output on a non-computing Computed.');\r\n this._output = output instanceof Result ? output : result(output);\r\n this._state = ConsistencyState.Consistent;\r\n this._register();\r\n if (this._invalidatePending) {\r\n this._invalidatePending = false;\r\n this.invalidate();\r\n return;\r\n }\r\n\r\n const delay = this.options.errorAutoInvalidateDelay;\r\n if (this._output.hasError && delay !== Infinity && delay > 0) {\r\n this._errorTimer = setTimeout(() => this.invalidate(), delay);\r\n (this._errorTimer as { unref?: () => void }).unref?.();\r\n }\r\n }\r\n\r\n protected _register(): void {\r\n ComputedRegistry.register(this as Computed<unknown>);\r\n }\r\n\r\n protected _unregister(): void {\r\n ComputedRegistry.unregister(this as Computed<unknown>);\r\n }\r\n\r\n // Never throws — mirrors .NET Computed.Invalidate: own handlers fire first\r\n // (each isolated), then dependants propagate unconditionally, then unregister.\r\n invalidate(): void {\r\n if (this._state === ConsistencyState.Invalidated)\r\n return;\r\n if (this._state === ConsistencyState.Computing) {\r\n // Defer until setOutput transitions to Consistent — matches .NET, where\r\n // invalidating a still-computing Computed sets a pending flag.\r\n this._invalidatePending = true;\r\n return;\r\n }\r\n this._state = ConsistencyState.Invalidated;\r\n if (this._errorTimer !== undefined) {\r\n clearTimeout(this._errorTimer);\r\n this._errorTimer = undefined;\r\n }\r\n try {\r\n this._onInvalidated.triggerSafe(undefined, e =>\r\n errorLog?.log('onInvalidated handler failed', e)\r\n );\r\n this._onInvalidated.clear();\r\n } finally {\r\n for (const dependency of this._dependencies)\r\n dependency._dependants.delete(this._version);\r\n this._dependencies.clear();\r\n\r\n for (const [, ref] of this._dependants) {\r\n const dependant = ref.deref();\r\n if (dependant != null) {\r\n try {\r\n dependant.invalidate();\r\n } catch (e) {\r\n errorLog?.log('Error while invalidating dependant', e);\r\n }\r\n }\r\n }\r\n this._dependants.clear();\r\n\r\n this._unregister();\r\n }\r\n }\r\n\r\n onInvalidated(handler: () => void): void {\r\n if (this._state === ConsistencyState.Invalidated) {\r\n handler();\r\n return;\r\n }\r\n this._onInvalidated.add(handler);\r\n }\r\n\r\n whenInvalidated(abortSignal?: AbortSignal): Promise<void> {\r\n if (this._state === ConsistencyState.Invalidated)\r\n return Promise.resolve();\r\n if (abortSignal?.aborted)\r\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- reason falls back to an Error; abortSignal.reason mirrors throwIfAborted()\r\n return Promise.reject(\r\n abortSignal.reason ?? new Error('Operation cancelled.')\r\n );\r\n\r\n const ps = new PromiseSource<void>();\r\n let onAbort: (() => void) | undefined;\r\n const onInvalidated = () => {\r\n if (onAbort !== undefined)\r\n abortSignal!.removeEventListener('abort', onAbort);\r\n ps.resolve(undefined);\r\n };\r\n this._onInvalidated.add(onInvalidated);\r\n if (abortSignal !== undefined) {\r\n onAbort = () => {\r\n this._onInvalidated.remove(onInvalidated);\r\n ps.reject(\r\n abortSignal.reason ?? new Error('Operation cancelled.')\r\n );\r\n };\r\n abortSignal.addEventListener('abort', onAbort, { once: true });\r\n }\r\n\r\n return ps;\r\n }\r\n\r\n addDependency(dependency: Computed<unknown>): void {\r\n if (this._state !== ConsistencyState.Computing)\r\n return;\r\n if (dependency._state === ConsistencyState.Invalidated) {\r\n this.invalidate();\r\n return;\r\n }\r\n this._dependencies.add(dependency);\r\n dependency._dependants.set(\r\n this._version,\r\n new WeakRef(this as Computed<unknown>)\r\n );\r\n if (dependency._dependants.size >= dependency._pruneDependantsThreshold)\r\n dependency.pruneDependants();\r\n }\r\n\r\n // Port of .NET Computed.PruneDependants: drops edges to dependants that were\r\n // collected or already invalidated. `_dependants` is keyed by the dependant's\r\n // unique version, so .NET's \"still the registered version\" check is implicit.\r\n pruneDependants(): void {\r\n if (this._state !== ConsistencyState.Consistent)\r\n return;\r\n\r\n for (const [version, ref] of this._dependants) {\r\n const dependant = ref.deref();\r\n if (dependant === undefined || dependant._state === ConsistencyState.Invalidated)\r\n this._dependants.delete(version);\r\n }\r\n this._pruneDependantsThreshold = Math.max(\r\n MinPruneDependantsThreshold,\r\n this._dependants.size * 2\r\n );\r\n }\r\n}\r\n\r\n/** Computed variant for State types — skips registry registration since the State holds a direct reference. */\r\nexport class StateBoundComputed<T> extends Computed<T> {\r\n constructor(\r\n input: ComputedInput,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>,\r\n options: ComputedOptions = ComputedOptions.mutableStateDefault\r\n ) {\r\n super(input, renewer, options);\r\n }\r\n\r\n protected override _latest(): Computed<T> | undefined {\r\n return (this.input as State<T>).computed;\r\n }\r\n\r\n protected override _register(): void {\r\n // No registration — state holds direct reference\r\n }\r\n\r\n protected override _unregister(): void {\r\n // No unregistration — was never registered\r\n }\r\n}\r\n","import { type Computed, ConsistencyState } from './computed.js';\r\n\r\n/** Identifies the exact registry entry a finalizer callback is allowed to remove. */\r\ninterface FinalizationToken {\r\n key: string;\r\n ref: WeakRef<Computed<unknown>>;\r\n}\r\n\r\n/** WeakRef-based global cache of Computed instances — allows GC of unused computed values. */\r\nexport class ComputedRegistry {\r\n private static _entries = new Map<string, WeakRef<Computed<unknown>>>();\r\n private static _finalization = new FinalizationRegistry<FinalizationToken>(token => {\r\n ComputedRegistry._onFinalized(token);\r\n });\r\n\r\n static get size(): number {\r\n return ComputedRegistry._entries.size;\r\n }\r\n\r\n static get(key: string): Computed<unknown> | undefined {\r\n const ref = ComputedRegistry._entries.get(key);\r\n if (ref === undefined) return undefined;\r\n const computed = ref.deref();\r\n if (computed === undefined) {\r\n ComputedRegistry._removeEntry(key, ref);\r\n return undefined;\r\n }\r\n return computed;\r\n }\r\n\r\n static register(computed: Computed<unknown>): void {\r\n const key = computed.input as string;\r\n const displaced = ComputedRegistry._entries.get(key)?.deref();\r\n // Already registered — setOutput re-registers the instance registered at creation\r\n if (displaced === computed)\r\n return;\r\n\r\n if (displaced !== undefined && displaced.state !== ConsistencyState.Invalidated)\r\n displaced.invalidate();\r\n const ref = new WeakRef(computed);\r\n ComputedRegistry._entries.set(key, ref);\r\n ComputedRegistry._finalization.register(computed, { key, ref }, computed);\r\n }\r\n\r\n static unregister(computed: Computed<unknown>): void {\r\n const key = computed.input as string;\r\n if (ComputedRegistry._entries.get(key)?.deref() === computed)\r\n ComputedRegistry._entries.delete(key);\r\n ComputedRegistry._finalization.unregister(computed);\r\n }\r\n\r\n // Private methods\r\n\r\n private static _onFinalized(token: FinalizationToken): void {\r\n ComputedRegistry._removeEntry(token.key, token.ref);\r\n }\r\n\r\n // Removing by key alone would drop a live successor registered under the same key\r\n // while this key's predecessor was already collected but not yet finalized (I13).\r\n private static _removeEntry(key: string, ref: WeakRef<Computed<unknown>>): void {\r\n if (ComputedRegistry._entries.get(key) === ref)\r\n ComputedRegistry._entries.delete(key);\r\n }\r\n}\r\n","import { AsyncContext, AsyncContextKey } from '@actuallab/core';\r\nimport type { Computed } from './computed.js';\r\n\r\nexport const computeContextKey = new AsyncContextKey<\r\n ComputeContext | undefined\r\n>('ComputeContext', undefined);\r\n\r\n/**\r\n * Tracks the currently executing (or captured) computation and captures dependencies.\r\n * A context with a `computed` is a computing context (adds dependant edges); one without\r\n * is a capture context (records the last captured Computed only — no edges).\r\n */\r\nexport class ComputeContext {\r\n readonly computed: Computed<unknown> | undefined;\r\n readonly parent: ComputeContext | undefined;\r\n private _isCapturing = true;\r\n private _captured: Computed<unknown> | undefined;\r\n\r\n constructor(\r\n computed?: Computed<unknown>,\r\n parent?: ComputeContext\r\n ) {\r\n this.computed = computed;\r\n this.parent = parent;\r\n }\r\n\r\n get isCapturing(): boolean {\r\n return this._isCapturing;\r\n }\r\n\r\n get captured(): Computed<unknown> | undefined {\r\n return this._captured;\r\n }\r\n\r\n stopCapturing(): void {\r\n this._isCapturing = false;\r\n }\r\n\r\n captureDependency(dependency: Computed<unknown>): void {\r\n if (!this._isCapturing) return;\r\n // Last capture wins — C# ComputeContext.TryCapture overwrites _captured.\r\n this._captured = dependency;\r\n this.computed?.addDependency(dependency);\r\n }\r\n\r\n // Walks the caller chain for a computation still in progress under the same key —\r\n // C# AsyncLockSet(LockReentryMode.CheckedFail) analog, used to fail fast on reentry.\r\n // Only Computing ancestors count: a context leaked past its finished computation\r\n // (e.g. via AsyncLocalStorage into a later callback) must not fail later calls.\r\n hasKeyInChain(key: unknown): boolean {\r\n const computed = this.computed;\r\n if (computed?.isComputing === true && computed.input === key)\r\n return true;\r\n\r\n return this.parent?.hasKeyInChain(key) ?? false;\r\n }\r\n\r\n /** Resolve ComputeContext from an AsyncContext (or current). */\r\n static from(ctx: AsyncContext | undefined): ComputeContext | undefined {\r\n return AsyncContext.from(ctx)?.get(computeContextKey);\r\n }\r\n}\r\n","/**\r\n * Per-Computed configuration, carried by every {@link Computed} via its\r\n * {@link ComputeFunction} (compute methods) or its kind's static default.\r\n * The home for per-method knobs; the C# analog is `ActualLab.Fusion.ComputedOptions`.\r\n */\r\nexport class ComputedOptions {\r\n static default = new ComputedOptions();\r\n static mutableStateDefault = new ComputedOptions({\r\n errorAutoInvalidateDelay: Infinity,\r\n });\r\n\r\n readonly errorAutoInvalidateDelay: number;\r\n\r\n constructor(overrides?: Partial<ComputedOptions>) {\r\n this.errorAutoInvalidateDelay =\r\n overrides?.errorAutoInvalidateDelay ?? 1000;\r\n }\r\n}\r\n","import {\r\n AsyncContext,\r\n AsyncLock,\r\n isCancellation,\r\n type Result,\r\n result,\r\n errorResult,\r\n} from '@actuallab/core';\r\nimport { Computed } from './computed.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { getInstanceId } from './computed-input.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type ComputeFunctionImpl = (this: any, ...args: unknown[]) => unknown;\r\n\r\n/** Record Separator — delimiter between key components. */\r\nconst RS = '\\x1E';\r\n\r\n// Keying is by JSON.stringify per argument, joined with RS delimiters. Collisions are\r\n// possible and by design (D2): functions, undefined, and symbols all map to '', objects\r\n// without serializable props to '{}', NaN to 'null', Map/Set to '{}'. The compute method's\r\n// author owns keyability — use JSON-representable argument types or supply a custom argToString.\r\nfunction defaultArgToString(arg: unknown): string {\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JSON.stringify returns undefined for undefined input\r\n return JSON.stringify(arg) ?? '';\r\n}\r\n\r\nlet _nextFunctionId = 0;\r\n\r\n/** Produces Computed<T> from a function — handles cache lookup, locking, dependency capture. */\r\nexport class ComputeFunction {\r\n readonly methodName: string;\r\n readonly id: string;\r\n readonly options: ComputedOptions;\r\n argToString: (arg: unknown) => string = defaultArgToString;\r\n private _impl: ComputeFunctionImpl;\r\n private _locks = new Map<string, AsyncLock>();\r\n\r\n constructor(\r\n methodName: string,\r\n impl: ComputeFunctionImpl,\r\n options: ComputedOptions = ComputedOptions.default\r\n ) {\r\n this.methodName = methodName;\r\n this.id = `${methodName}[${++_nextFunctionId}]`;\r\n this._impl = impl;\r\n this.options = options;\r\n }\r\n\r\n /** Build a string key for the given instance and arguments. */\r\n buildKey(instance: object, args: unknown[]): string {\r\n let key = String(getInstanceId(instance)) + RS + this.id;\r\n for (const arg of args) {\r\n key += RS + this.argToString(arg);\r\n }\r\n return key;\r\n }\r\n\r\n async invoke(\r\n instance: object,\r\n args: unknown[]\r\n ): Promise<Computed<unknown>> {\r\n // 1. Resolve AsyncContext ONCE via DRY helper\r\n const asyncCtx = AsyncContext.fromArgs(args);\r\n\r\n // 2. Pull caller's ComputeContext directly\r\n const callerComputeCtx = asyncCtx?.get(computeContextKey);\r\n\r\n // 3. Strip THIS context from args (reference equality — safe)\r\n const argsWithoutCtx = asyncCtx?.stripFromArgs(args) ?? args;\r\n\r\n // 4. Build string key and check cache\r\n const key = this.buildKey(instance, argsWithoutCtx);\r\n const existing = ComputedRegistry.get(key);\r\n if (existing?.isConsistent) {\r\n callerComputeCtx?.captureDependency(existing);\r\n return existing;\r\n }\r\n\r\n // C# AsyncLockSet(CheckedFail) analog: a compute call that (indirectly) awaits itself\r\n // with the same key would await its own non-reentrant lock forever — fail fast instead.\r\n if (callerComputeCtx?.hasKeyInChain(key))\r\n throw new Error(`Reentrant compute call detected for key \"${key}\".`);\r\n\r\n // 5. Lock per key to prevent duplicate computations\r\n let lock = this._locks.get(key);\r\n if (lock === undefined) {\r\n lock = new AsyncLock();\r\n this._locks.set(key, lock);\r\n }\r\n\r\n const computed = await lock.run(async () => {\r\n // Double-check after acquiring lock\r\n const cached = ComputedRegistry.get(key);\r\n if (cached?.isConsistent) return cached;\r\n\r\n // 6. Create new Computed + ComputeContext\r\n const renewer = () => this.invoke(instance, argsWithoutCtx);\r\n const newComputed = new Computed<unknown>(\r\n key,\r\n renewer,\r\n this.options\r\n );\r\n // Register while still Computing so ComputedRegistry.get(key) resolves the\r\n // in-flight instance and a racing invalidate() is captured as pending — C#\r\n // ComputeMethodComputed registers in its constructor.\r\n ComputedRegistry.register(newComputed);\r\n\r\n const childComputeCtx = new ComputeContext(\r\n newComputed,\r\n callerComputeCtx\r\n );\r\n const childAsyncCtx = (asyncCtx ?? AsyncContext.empty).with(\r\n computeContextKey,\r\n childComputeCtx\r\n );\r\n\r\n // 7. Run with clean args, threading childAsyncCtx as a trailing argument so a compute\r\n // body can pass it into nested calls / use(ctx) after awaits — the portable floor for\r\n // dependency capture when AsyncLocalStorage isn't backing AsyncContext.current (browsers).\r\n let fnResult: Result<unknown>;\r\n try {\r\n const value = childAsyncCtx.run(() =>\r\n this._impl.call(instance, ...argsWithoutCtx, childAsyncCtx)\r\n );\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\r\n const resolved = value instanceof Promise ? await value : value;\r\n fnResult = result(resolved);\r\n } catch (e) {\r\n fnResult = errorResult(e);\r\n }\r\n\r\n newComputed.setOutput(fnResult);\r\n // C# StartAutoInvalidation OCE parity: a cancellation error is registered to keep the\r\n // single-flight lock protocol intact, then invalidated at once so it's never cached.\r\n if (fnResult.hasError && isCancellation(fnResult.error))\r\n newComputed.invalidate();\r\n\r\n return newComputed;\r\n });\r\n\r\n if (!lock.isLocked && this._locks.get(key) === lock)\r\n this._locks.delete(key);\r\n\r\n // Register dependency from caller to the produced computed\r\n callerComputeCtx?.captureDependency(computed);\r\n return computed;\r\n }\r\n}\r\n","/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-this-alias */\r\nimport { ownMetadata, resolveArgCount } from '@actuallab/core';\r\nimport { ComputeFunction } from './compute-function.js';\r\nimport { ComputedOptions } from './computed-options.js';\r\nimport { ComputedRegistry } from './computed-registry.js';\r\n\r\nconst METHODS_META = Symbol.for('actuallab.methods');\r\n\r\nexport interface MethodMeta {\r\n argCount: number;\r\n compute?: boolean;\r\n stream?: boolean;\r\n}\r\n\r\n/** Read method metadata from a decorated class. */\r\nexport function getMethodsMeta(\r\n cls: abstract new (...args: any[]) => any\r\n): Record<string, MethodMeta> | undefined {\r\n return (cls as any)[Symbol.metadata]?.[METHODS_META];\r\n}\r\n\r\nexport interface ComputeMethodOptions extends Partial<ComputedOptions> {\r\n argCount?: number;\r\n}\r\n\r\ntype ComputeMethodDecorator<This, Args extends unknown[], Return> = (\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n) => (this: This, ...args: Args) => Return;\r\n\r\n/**\r\n * Method decorator — routes a method through ComputeFunction for caching and dependency\r\n * tracking. Usable bare (`@computeMethod`) or with options (`@computeMethod({ argCount })`).\r\n */\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n): (this: This, ...args: Args) => Return;\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n options?: ComputeMethodOptions\r\n): ComputeMethodDecorator<This, Args, Return>;\r\nexport function computeMethod<This, Args extends unknown[], Return>(\r\n targetOrOptions?: ((this: This, ...args: Args) => Return) | ComputeMethodOptions,\r\n context?: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>\r\n): unknown {\r\n if (typeof targetOrOptions === 'function')\r\n return computeMethodImpl(targetOrOptions, context!, {});\r\n\r\n const options = targetOrOptions ?? {};\r\n return (target: (this: This, ...args: Args) => Return, ctx: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>) =>\r\n computeMethodImpl(target, ctx, options);\r\n}\r\n\r\nfunction computeMethodImpl<This, Args extends unknown[], Return>(\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<\r\n This,\r\n (this: This, ...args: Args) => Return\r\n >,\r\n options: ComputeMethodOptions\r\n): (this: This, ...args: Args) => Return {\r\n const methodName = String(context.name);\r\n\r\n const methods = ownMetadata<Record<string, MethodMeta>>(context.metadata, METHODS_META);\r\n methods[methodName] = {\r\n ...methods[methodName],\r\n compute: true,\r\n argCount: resolveArgCount(target, options.argCount, methodName),\r\n };\r\n\r\n // ONE ComputeFunction per class×method — created at decoration time\r\n const cf = new ComputeFunction(methodName, target as any, new ComputedOptions(options));\r\n\r\n // Prototype-level replacement — unwraps Computed to return the value directly\r\n const replacement = function (this: This, ...allArgs: Args): Return {\r\n return cf.invoke(this as object, allArgs).then(c => c.value) as Return;\r\n };\r\n\r\n // Per-instance setup: create bound method with .invalidate pre-bound\r\n context.addInitializer(function (this: This) {\r\n const instance = this;\r\n const boundMethod = (...allArgs: unknown[]) => {\r\n return cf.invoke(instance as object, allArgs).then(c => c.value);\r\n };\r\n (boundMethod as any).invalidate = (...args: unknown[]) => {\r\n const key = cf.buildKey(instance as object, args);\r\n ComputedRegistry.get(key)?.invalidate();\r\n };\r\n (this as any)[methodName] = boundMethod;\r\n });\r\n\r\n return replacement;\r\n}\r\n\r\n/** Wrap a standalone function as a compute function with caching and .invalidate(). */\r\nexport function wrapComputeMethod<Args extends unknown[], Return>(\r\n fn: (...args: Args) => Return\r\n): ((...args: Args) => Promise<Return>) & {\r\n invalidate: (...args: Args) => void;\r\n} {\r\n const syntheticInstance = {};\r\n const methodName = fn.name || 'anonymous';\r\n const cf = new ComputeFunction(methodName, fn as any);\r\n\r\n const wrapped = (...allArgs: unknown[]) => {\r\n return cf\r\n .invoke(syntheticInstance, allArgs)\r\n .then(c => c.value as Return);\r\n };\r\n\r\n (wrapped as any).invalidate = (...args: unknown[]) => {\r\n const key = cf.buildKey(syntheticInstance, args);\r\n ComputedRegistry.get(key)?.invalidate();\r\n };\r\n\r\n return wrapped as any;\r\n}\r\n","import { awaitWithCleanup, RetryDelaySeq } from '@actuallab/core';\r\n\r\n/** Controls when state re-computation happens after invalidation, per consecutive-error retryCount. */\r\nexport type UpdateDelayer = (\r\n retryCount: number,\r\n abortSignal?: AbortSignal\r\n) => Promise<void>;\r\n\r\n/** 1 s → 1 min exponential backoff — C# FixedDelayer.Defaults.RetryDelays parity. */\r\nexport const defaultRetryDelays = RetryDelaySeq.exp(1000, 60_000);\r\n\r\n/** Windows timer period is 15.6 ms, so 32 ms = 2..3 timer ticks — C# FixedDelayer.Defaults.MinDelay. */\r\nexport const defaultMinDelayMs = 32;\r\n\r\n// C# UpdateDelayer.GetDelay + minDelay floor: retryCount 0 uses the update delay\r\n// floored by minDelay; retryCount > 0 uses RetryDelays[retryCount] floored by RetryDelays.Min.\r\nexport function computeUpdateDelay(\r\n retryCount: number,\r\n updateDelayMs: number,\r\n retryDelays: RetryDelaySeq,\r\n minDelayMs: number\r\n): number {\r\n const min = retryCount === 0 ? minDelayMs : retryDelays.min;\r\n const raw = retryCount > 0 ? retryDelays.getDelay(retryCount) : updateDelayMs;\r\n return Math.max(min, raw);\r\n}\r\n\r\n/** Re-computes after a fixed update delay, with RetryDelaySeq backoff for consecutive errors. */\r\nexport class FixedDelayer {\r\n static readonly zero: UpdateDelayer = () => Promise.resolve();\r\n\r\n private static _cache = new Map<number, UpdateDelayer>();\r\n\r\n // Floors ms at minDelay like C# FixedDelayer.Get — a zero delayer requires the explicit .zero.\r\n static get(ms: number): UpdateDelayer {\r\n ms = Math.max(ms, defaultMinDelayMs);\r\n let delayer = FixedDelayer._cache.get(ms);\r\n if (delayer === undefined) {\r\n delayer = new FixedDelayer(ms).delay;\r\n FixedDelayer._cache.set(ms, delayer);\r\n }\r\n return delayer;\r\n }\r\n\r\n readonly ms: number;\r\n readonly retryDelays: RetryDelaySeq;\r\n readonly minDelay: number;\r\n readonly delay: UpdateDelayer;\r\n\r\n constructor(\r\n ms: number,\r\n retryDelays: RetryDelaySeq = defaultRetryDelays,\r\n minDelay: number = defaultMinDelayMs\r\n ) {\r\n this.ms = ms;\r\n this.retryDelays = retryDelays;\r\n this.minDelay = minDelay;\r\n // Abort stops the wait early (resolves, never rejects) so a disposed\r\n // ComputedState's update loop terminates promptly and the race loser\r\n // carries no unhandled rejection (C# SuppressCancellationAwait spirit).\r\n this.delay = (retryCount, abortSignal) => {\r\n const delayMs = computeUpdateDelay(\r\n retryCount,\r\n this.ms,\r\n this.retryDelays,\r\n this.minDelay\r\n );\r\n if (delayMs <= 0) return Promise.resolve();\r\n\r\n return awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, delayMs);\r\n addCleanup(() => clearTimeout(timer));\r\n });\r\n };\r\n }\r\n}\r\n\r\nexport const defaultUpdateDelayer: UpdateDelayer = FixedDelayer.get(1000 / 60);\r\n","import { awaitWithCleanup, type RetryDelaySeq } from '@actuallab/core';\r\nimport { uiActions } from './ui-action-tracker.js';\r\nimport {\r\n computeUpdateDelay,\r\n defaultMinDelayMs,\r\n defaultRetryDelays,\r\n type UpdateDelayer,\r\n} from './update-delayer.js';\r\n\r\n/** Re-computes after a delay, but short-circuits while UIActionTracker enables instant updates. */\r\nexport class UIUpdateDelayer {\r\n private static _cache = new Map<number, UpdateDelayer>();\r\n\r\n // Floors ms at minDelay like C# FixedDelayer.Get — a zero delayer requires FixedDelayer.zero.\r\n static get(ms: number): UpdateDelayer {\r\n ms = Math.max(ms, defaultMinDelayMs);\r\n let delayer = UIUpdateDelayer._cache.get(ms);\r\n if (delayer !== undefined) return delayer;\r\n\r\n delayer = new UIUpdateDelayer(ms).delay;\r\n UIUpdateDelayer._cache.set(ms, delayer);\r\n return delayer;\r\n }\r\n\r\n readonly ms: number;\r\n readonly retryDelays: RetryDelaySeq;\r\n readonly minDelay: number;\r\n readonly delay: UpdateDelayer;\r\n\r\n constructor(\r\n ms: number,\r\n retryDelays: RetryDelaySeq = defaultRetryDelays,\r\n minDelay: number = defaultMinDelayMs\r\n ) {\r\n this.ms = ms;\r\n this.retryDelays = retryDelays;\r\n this.minDelay = minDelay;\r\n this.delay = this._delay.bind(this);\r\n }\r\n\r\n // Private methods\r\n\r\n // Mirrors C# UpdateDelayer.Delay: race the instant-updates window against the full delay,\r\n // then enforce minDelay measured from delay start so instant updates never hot-loop the CPU.\r\n private async _delay(retryCount: number, abortSignal?: AbortSignal): Promise<void> {\r\n const t = uiActions;\r\n const minDelay = retryCount === 0 ? this.minDelay : this.retryDelays.min;\r\n const delayMs = computeUpdateDelay(retryCount, this.ms, this.retryDelays, this.minDelay);\r\n if (delayMs <= 0)\r\n return;\r\n\r\n const startedAt = Date.now();\r\n if (!t.areInstantUpdatesEnabled())\r\n await awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, delayMs);\r\n addCleanup(() => clearTimeout(timer));\r\n\r\n const onChanged = () => {\r\n if (t.areInstantUpdatesEnabled())\r\n complete();\r\n };\r\n t.changed.add(onChanged);\r\n addCleanup(() => t.changed.remove(onChanged));\r\n });\r\n if (abortSignal?.aborted)\r\n return;\r\n\r\n const remaining = minDelay - (Date.now() - startedAt);\r\n if (remaining > 0)\r\n await awaitWithCleanup(abortSignal, 'resolve', (complete, addCleanup) => {\r\n const timer = setTimeout(complete, remaining);\r\n addCleanup(() => clearTimeout(timer));\r\n });\r\n }\r\n}\r\n","import { EventHandlerSet } from '@actuallab/core';\r\nimport { getLogs } from './logging.js';\r\n\r\nconst { errorLog } = getLogs('UIActionTracker');\r\n\r\n/** Singleton tracking active UI commands — mirrors .NET's UIActionTracker. */\r\nexport class UIActionTracker {\r\n private _activeCount = 0;\r\n private _lastResultAt = 0;\r\n private _errorTimes: number[] = [];\r\n readonly changed = new EventHandlerSet<void>();\r\n readonly errors: unknown[] = [];\r\n\r\n // C# UIActionTracker.Options.InstantUpdatePeriod / UIActionFailureTracker MaxDuplicateRecency.\r\n instantUpdatePeriod = 300;\r\n maxDuplicateRecency = 1000;\r\n maxErrors = 100;\r\n\r\n get isActive(): boolean {\r\n return this._activeCount > 0;\r\n }\r\n\r\n // C# UIActionTracker.AreInstantUpdatesEnabled — active, or within instantUpdatePeriod of the last result.\r\n areInstantUpdatesEnabled(): boolean {\r\n if (this._activeCount > 0)\r\n return true;\r\n if (this._lastResultAt === 0)\r\n return false;\r\n\r\n return this._lastResultAt + this.instantUpdatePeriod >= Date.now();\r\n }\r\n\r\n /** Run a command silently — errors are added to the error list but not thrown. */\r\n async run(fn: () => Promise<unknown>): Promise<void> {\r\n this._activeCount++;\r\n this.changed.trigger();\r\n try {\r\n await fn();\r\n } catch (e) {\r\n // Mirrors UIActionTracker.cs:58 — UI action failure.\r\n errorLog?.log('UI action failed', e);\r\n this._addError(e);\r\n } finally {\r\n this._onCompleted();\r\n }\r\n }\r\n\r\n /** Call a command and return the result — errors are added to the error list AND thrown. */\r\n async call<T>(fn: () => Promise<T>): Promise<T> {\r\n this._activeCount++;\r\n this.changed.trigger();\r\n try {\r\n return await fn();\r\n } catch (e) {\r\n // Mirrors UIActionTracker.cs:58 — UI action failure.\r\n errorLog?.log('UI action failed', e);\r\n this._addError(e);\r\n throw e;\r\n } finally {\r\n this._onCompleted();\r\n }\r\n }\r\n\r\n dismissError(index: number): void {\r\n if (index >= 0 && index < this.errors.length) {\r\n this.errors.splice(index, 1);\r\n this._errorTimes.splice(index, 1);\r\n this.changed.trigger();\r\n }\r\n }\r\n\r\n // Private methods\r\n\r\n private _onCompleted(): void {\r\n this._activeCount--;\r\n this._lastResultAt = Date.now();\r\n this.changed.trigger();\r\n }\r\n\r\n // C# UIActionFailureTracker.TryAddFailure — drop a same-name/same-message error seen within\r\n // maxDuplicateRecency; a size cap is the backstop against unbounded growth.\r\n private _addError(e: unknown): void {\r\n const now = Date.now();\r\n const { name, message } = errorInfo(e);\r\n const minAt = now - this.maxDuplicateRecency;\r\n for (let i = 0; i < this.errors.length; i++) {\r\n if (this._errorTimes[i] < minAt)\r\n continue;\r\n\r\n const prev = errorInfo(this.errors[i]);\r\n if (prev.name === name && prev.message === message)\r\n return;\r\n }\r\n\r\n this.errors.push(e);\r\n this._errorTimes.push(now);\r\n while (this.errors.length > this.maxErrors) {\r\n this.errors.shift();\r\n this._errorTimes.shift();\r\n }\r\n this.changed.trigger();\r\n }\r\n}\r\n\r\nfunction errorInfo(e: unknown): { name: string; message: string } {\r\n if (e instanceof Error)\r\n return { name: e.name, message: e.message };\r\n\r\n return { name: '', message: String(e) };\r\n}\r\n\r\nexport const uiActions = new UIActionTracker();\r\n","import {\r\n type AsyncContext,\r\n type IResult,\r\n PromiseSource,\r\n resolvedVoidPromise,\r\n type Result,\r\n} from '@actuallab/core';\r\nimport { type Computed, StateBoundComputed } from './computed.js';\r\n\r\n/** Base class for all reactive state types. */\r\nexport abstract class State<T> implements IResult<T> {\r\n protected _computed!: Computed<T>;\r\n protected _updateIndex = 0;\r\n // Reference to the last non-error computed, not its raw value, so an actual\r\n // `undefined` value is distinguishable from \"no non-error value yet\" (S12).\r\n protected _lastNonErrorComputed: Computed<T> | undefined;\r\n private _whenUpdatedSource: PromiseSource<void> | null = null;\r\n private _isDisposed = false;\r\n\r\n get updateIndex(): number {\r\n return this._updateIndex;\r\n }\r\n\r\n get isDisposed(): boolean {\r\n return this._isDisposed;\r\n }\r\n\r\n get lastNonErrorValue(): T | undefined {\r\n return this._lastNonErrorComputed?.value;\r\n }\r\n\r\n get hasValue(): boolean {\r\n return this._computed.hasValue;\r\n }\r\n\r\n get hasError(): boolean {\r\n return this._computed.hasError;\r\n }\r\n\r\n get value(): T {\r\n return this._computed.value;\r\n }\r\n\r\n get error(): unknown {\r\n return this._computed.error;\r\n }\r\n\r\n get valueOrUndefined(): T | undefined {\r\n return this._computed.valueOrUndefined;\r\n }\r\n\r\n get output(): Result<T> {\r\n return this._computed.output;\r\n }\r\n\r\n get computed(): Computed<T> {\r\n return this._computed;\r\n }\r\n\r\n use(asyncContext?: AsyncContext): T | Promise<T> {\r\n return this._computed.use(asyncContext);\r\n }\r\n\r\n useInconsistent(asyncContext?: AsyncContext): T {\r\n return this._computed.useInconsistent(asyncContext);\r\n }\r\n\r\n update(): Computed<T> | Promise<Computed<T>> {\r\n return this._computed.update();\r\n }\r\n\r\n recompute(): Computed<T> | Promise<Computed<T>> {\r\n this._computed.invalidate();\r\n return this.update();\r\n }\r\n\r\n whenInvalidated(): Promise<void> {\r\n return this._computed.whenInvalidated();\r\n }\r\n\r\n // Versioned wait: resolves at once when a newer generation than sinceIndex\r\n // already landed (no lost wakeup), rejects once disposed (C# StateSnapshot.WhenUpdated).\r\n whenUpdated(sinceIndex: number = this._updateIndex): Promise<void> {\r\n if (this._isDisposed)\r\n return Promise.reject(State._disposedError());\r\n if (this._updateIndex > sinceIndex)\r\n return resolvedVoidPromise;\r\n\r\n return (this._whenUpdatedSource ??= new PromiseSource<void>());\r\n }\r\n\r\n whenFirstTimeUpdated(): Promise<void> {\r\n return this.whenUpdated(0);\r\n }\r\n\r\n protected _initialize(\r\n output: Result<T> | T,\r\n renewer?: () => Computed<T> | Promise<Computed<T>>\r\n ): void {\r\n this._computed = this._createComputed(renewer);\r\n this._computed.setOutput(output);\r\n if (this._computed.hasValue) this._lastNonErrorComputed = this._computed;\r\n }\r\n\r\n protected _createComputed(\r\n renewer?: () => Computed<T> | Promise<Computed<T>>\r\n ): Computed<T> {\r\n return new StateBoundComputed<T>(this, renewer);\r\n }\r\n\r\n protected _update(computed: Computed<T>, output: Result<T> | T): void {\r\n const replaced = this._computed as Computed<T> | undefined;\r\n computed.setOutput(output);\r\n this._computed = computed;\r\n if (replaced?.isConsistent) replaced.invalidate();\r\n if (computed.hasValue) this._lastNonErrorComputed = computed;\r\n this._updateIndex++;\r\n this._whenUpdatedSource?.resolve(undefined);\r\n this._whenUpdatedSource = null;\r\n }\r\n\r\n protected _onDisposed(): void {\r\n if (this._isDisposed)\r\n return;\r\n\r\n this._isDisposed = true;\r\n this._whenUpdatedSource?.reject(State._disposedError());\r\n this._whenUpdatedSource = null;\r\n // A disposed state stops tracking its sources, so leaving its computed Consistent\r\n // would strand an edge in every dependency's _dependants map (I15) and let\r\n // dependants latch onto a value that will never be updated again. .NET's\r\n // ComputedGraphPruner.PruneDisposedInstances invalidates for the same reason.\r\n this._computed.invalidate();\r\n }\r\n\r\n private static _disposedError(): Error {\r\n return new Error('State is disposed.');\r\n }\r\n}\r\n","import {\r\n AsyncContext,\r\n PromiseSource,\r\n type Result,\r\n result,\r\n errorResult,\r\n} from '@actuallab/core';\r\nimport { type Computed, StateBoundComputed } from './computed.js';\r\nimport { ComputeContext, computeContextKey } from './compute-context.js';\r\nimport { getLogs } from './logging.js';\r\nimport { defaultUpdateDelayer, type UpdateDelayer } from './update-delayer.js';\r\nimport { State } from './state.js';\r\n\r\nconst { errorLog } = getLogs('ComputedState');\r\n\r\nexport type StateComputer<T> = () => T | Promise<T>;\r\n\r\n/** Constructor options for ComputedState. */\r\nexport interface ComputedStateOptions<T> {\r\n initialValue?: T;\r\n initialOutput?: Result<T>;\r\n updateDelayer?: UpdateDelayer;\r\n}\r\n\r\n/** Auto-updating reactive state wrapper — re-computes on invalidation with configurable delay. */\r\nexport class ComputedState<T> extends State<T> {\r\n private _computer: StateComputer<T>;\r\n private _updateDelayer: UpdateDelayer;\r\n private _disposeController: AbortController;\r\n private _cancelDelaySource = new PromiseSource<void>();\r\n private _renewer: () => Computed<T> | Promise<Computed<T>>;\r\n\r\n constructor(computer: StateComputer<T>, options?: ComputedStateOptions<T>) {\r\n super();\r\n this._computer = computer;\r\n this._updateDelayer = options?.updateDelayer ?? defaultUpdateDelayer;\r\n this._disposeController = new AbortController();\r\n this._renewer = async () => {\r\n const sinceIndex = this._updateIndex;\r\n this._cancelDelaySource.resolve(undefined);\r\n await this.whenUpdated(sinceIndex);\r\n return this._computed;\r\n };\r\n\r\n // The initial computed is created pre-invalidated (C# State.cs:246) so inherited\r\n // members (use/update/recompute/whenInvalidated) await the first real computation\r\n // instead of returning the placeholder, and dependants never latch onto it.\r\n this._initialize(\r\n options?.initialOutput ?? (options?.initialValue as T),\r\n this._renewer\r\n );\r\n this._computed.invalidate();\r\n\r\n void this._updateCycle();\r\n }\r\n\r\n dispose(): void {\r\n if (this.isDisposed)\r\n return;\r\n\r\n // Abort first: _onDisposed() invalidates the computed, and the update cycle must\r\n // see the abort rather than treat that invalidation as a request to recompute.\r\n this._disposeController.abort();\r\n this._onDisposed();\r\n }\r\n\r\n private async _updateCycle(): Promise<void> {\r\n const disposeSignal = this._disposeController.signal;\r\n let retryCount = 0;\r\n try {\r\n while (!disposeSignal.aborted) {\r\n // Compute\r\n const computed = new StateBoundComputed<T>(this, this._renewer);\r\n const computeCtx = new ComputeContext(\r\n computed as StateBoundComputed<unknown>\r\n );\r\n const asyncCtx = (\r\n AsyncContext.current ?? AsyncContext.empty\r\n ).with(computeContextKey, computeCtx);\r\n\r\n let output: Result<T>;\r\n try {\r\n const value = asyncCtx.run(() => this._computer());\r\n const resolved =\r\n value instanceof Promise ? await value : value;\r\n output = result(resolved);\r\n } catch (e) {\r\n output = errorResult(e);\r\n }\r\n if (this.isDisposed)\r\n return; // Disposed mid-computation — publish nothing, terminate the cycle.\r\n\r\n this._update(computed, output);\r\n retryCount = output.hasError ? retryCount + 1 : 0;\r\n if (this._cancelDelaySource.isCompleted)\r\n this._cancelDelaySource = new PromiseSource<void>();\r\n\r\n // Wait for invalidation (or cancellation via dispose)\r\n try {\r\n await computed.whenInvalidated(disposeSignal);\r\n } catch {\r\n return; // Cancelled via dispose\r\n }\r\n\r\n // Wait for delay (cancellable by renewer); retryCount grows the backoff (S8).\r\n await Promise.race([\r\n this._updateDelayer(retryCount, disposeSignal),\r\n this._cancelDelaySource,\r\n ]);\r\n }\r\n } catch (e) {\r\n // Mirrors ComputedState.cs:188 — UpdateCycle failed and stopped.\r\n if (!disposeSignal.aborted)\r\n errorLog?.log('UpdateCycle() failed and stopped', e);\r\n }\r\n }\r\n}\r\n","import { type AsyncContext, Result, result } from '@actuallab/core';\r\nimport { type Computed } from './computed.js';\r\nimport { State } from './state.js';\r\n\r\n/** Manually-settable reactive state that can participate in the Fusion dependency graph. */\r\nexport class MutableState<T> extends State<T> {\r\n private _nextOutput: Result<T>;\r\n\r\n private _renewer = (): Computed<T> => {\r\n const computed = this._createComputed(this._renewer);\r\n this._update(computed, this._nextOutput);\r\n this._wireRenewal(computed);\r\n return computed;\r\n };\r\n\r\n constructor(initialOutput: Result<T> | T) {\r\n super();\r\n this._nextOutput =\r\n initialOutput instanceof Result ? initialOutput : result(initialOutput);\r\n this._initialize(this._nextOutput, this._renewer);\r\n this._wireRenewal(this._computed);\r\n }\r\n\r\n override use(asyncContext?: AsyncContext): T {\r\n return this._computed.use(asyncContext) as T;\r\n }\r\n\r\n set(output: Result<T> | T): void {\r\n const next = output instanceof Result ? output : result(output);\r\n if (this._nextOutput.equals(next))\r\n return;\r\n\r\n this._nextOutput = next;\r\n this._computed.invalidate();\r\n }\r\n\r\n // Private methods\r\n\r\n // Renew synchronously on invalidation so a MutableState is never observed invalidated.\r\n // update() de-dupes: if the computed was already renewed, it returns the latest instead.\r\n private _wireRenewal(computed: Computed<T>): void {\r\n computed.onInvalidated(() => void computed.update());\r\n }\r\n}\r\n"],"mappings":"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","names":["AsyncContext","ConsistencyState","AsyncContext","captured","AsyncContext","isCancellation","result","AsyncContext","result","isCancellation","awaitWithCleanup","EventHandlerSet","errorLog","EventHandlerSet","awaitWithCleanup","PromiseSource","PromiseSource","AsyncContext","PromiseSource","result","errorResult","errorLog","PromiseSource","AsyncContext","result","errorResult","Result","result","Result","result"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actuallab/fusion",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.2.23",
|
|
4
4
|
"description": "TypeScript implementation of Fusion - real-time state synchronization framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"clean": "rm -rf dist"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@actuallab/core": "14.
|
|
29
|
+
"@actuallab/core": "14.2.23"
|
|
30
30
|
},
|
|
31
31
|
"publishConfig": {
|
|
32
32
|
"access": "public"
|