@solidjs/signals 2.0.0-rc.8 → 2.0.0-rc.9
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/dev-shared.js +1399 -285
- package/dist/dev.attribution.js +459 -307
- package/dist/dev.js +1864 -435
- package/dist/observe/affects.js +3 -1
- package/dist/observe/attribution.js +7 -1
- package/dist/observe/boundaries.js +209 -154
- package/dist/observe/core/action.js +18 -8
- package/dist/observe/core/async.js +220 -110
- package/dist/observe/core/attribution-costs.js +66 -0
- package/dist/observe/core/attribution-feedback.js +282 -0
- package/dist/observe/core/attribution-hooks.js +23 -1
- package/dist/observe/core/attribution-queries.js +28 -0
- package/dist/observe/core/attribution.js +262 -485
- package/dist/observe/core/constants.js +34 -1
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +867 -367
- package/dist/observe/core/dev.js +78 -17
- package/dist/observe/core/effect.js +67 -51
- package/dist/observe/core/error-hooks.js +71 -0
- package/dist/observe/core/external.js +4 -4
- package/dist/observe/core/graph.js +37 -37
- package/dist/observe/core/heap.js +45 -45
- package/dist/observe/core/invariants.js +2 -0
- package/dist/observe/core/lanes.js +86 -49
- package/dist/observe/core/optimistic.js +242 -95
- package/dist/observe/core/owner.js +98 -84
- package/dist/observe/core/scheduler.js +543 -305
- package/dist/observe/core/verdict.js +247 -129
- package/dist/observe/index.js +7 -3
- package/dist/observe/map.js +126 -124
- package/dist/observe/signals.js +33 -17
- package/dist/observe/store/index.js +2 -0
- package/dist/observe/store/next/optimistic.js +141 -132
- package/dist/observe/store/next/projection.js +34 -21
- package/dist/observe/store/next/reconcile.js +58 -56
- package/dist/observe/store/next/store.js +260 -146
- package/dist/observe/store/store.js +5 -3
- package/dist/observe/store/utils.js +948 -135
- package/dist/prod/attribution.js +26 -17
- package/dist/prod/boundaries.js +128 -76
- package/dist/prod/core/action.js +16 -8
- package/dist/prod/core/async.js +251 -143
- package/dist/prod/core/constants.js +34 -1
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +843 -347
- package/dist/prod/core/dev.js +17 -1
- package/dist/prod/core/effect.js +48 -34
- package/dist/prod/core/error-hooks.js +71 -0
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +37 -37
- package/dist/prod/core/heap.js +45 -45
- package/dist/prod/core/lanes.js +90 -53
- package/dist/prod/core/optimistic.js +247 -100
- package/dist/prod/core/owner.js +57 -45
- package/dist/prod/core/scheduler.js +543 -305
- package/dist/prod/core/verdict.js +245 -127
- package/dist/prod/index.js +7 -3
- package/dist/prod/map.js +112 -112
- package/dist/prod/signals.js +28 -12
- package/dist/prod/store/next/optimistic.js +135 -128
- package/dist/prod/store/next/projection.js +31 -20
- package/dist/prod/store/next/store.js +325 -252
- package/dist/prod/store/store.js +2 -2
- package/dist/prod/store/utils.js +946 -135
- package/dist/types/attribution.d.ts +7 -2
- package/dist/types/attribution.prod.d.ts +10 -1
- package/dist/types/boundaries.d.ts +10 -1
- package/dist/types/core/action.d.ts +12 -5
- package/dist/types/core/attribution-costs.d.ts +35 -0
- package/dist/types/core/attribution-feedback.d.ts +133 -0
- package/dist/types/core/attribution-hooks.d.ts +28 -3
- package/dist/types/core/attribution-queries.d.ts +10 -0
- package/dist/types/core/attribution.d.ts +51 -172
- package/dist/types/core/constants.d.ts +33 -0
- package/dist/types/core/core.d.ts +186 -5
- package/dist/types/core/dev.d.ts +129 -9
- package/dist/types/core/error-hooks.d.ts +71 -0
- package/dist/types/core/index.d.ts +3 -1
- package/dist/types/core/invariants.d.ts +4 -0
- package/dist/types/core/lanes.d.ts +31 -4
- package/dist/types/core/scheduler.d.ts +95 -2
- package/dist/types/core/types.d.ts +3 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/signals.d.ts +8 -0
- package/dist/types/store/index.d.ts +2 -1
- package/dist/types/store/next/optimistic.d.ts +1 -1
- package/dist/types/store/next/store.d.ts +6 -5
- package/dist/types/store/next/target.d.ts +1 -1
- package/dist/types/store/utils.d.ts +177 -6
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import { activeLanes, assignOrMergeLane, findLane, type OptimisticLane } from ".
|
|
|
3
3
|
import type { Computed, Signal } from "./types.js";
|
|
4
4
|
export { activeLanes, assignOrMergeLane, findLane };
|
|
5
5
|
export { getOrCreateLane, hasActiveOverride, mergeLanes, resolveLane } from "./lanes.js";
|
|
6
|
+
export declare const transitions: Set<Transition>;
|
|
6
7
|
export declare const dirtyQueue: Heap;
|
|
7
8
|
export declare const zombieQueue: Heap;
|
|
8
9
|
export declare let clock: number;
|
|
@@ -14,6 +15,8 @@ export declare let actionStepDepth: number;
|
|
|
14
15
|
export declare function enterActionStep(): void;
|
|
15
16
|
export declare function exitActionStep(): void;
|
|
16
17
|
export declare let _hitUnhandledAsync: boolean;
|
|
18
|
+
/** Slot hook's deferral: release this node when its carried state resolves. */
|
|
19
|
+
export declare function deferSlotRelease(node: Signal<any>): void;
|
|
17
20
|
/**
|
|
18
21
|
* Consume the unhandled-async hit. Returns whether this is the first report
|
|
19
22
|
* of the current enforcement window — the caller warns only then.
|
|
@@ -45,6 +48,10 @@ export interface Transition {
|
|
|
45
48
|
_affectsNodes: OptimisticNode[];
|
|
46
49
|
_optimisticStores: Set<any>;
|
|
47
50
|
_actions: Array<Generator<any, any, any> | AsyncGenerator<any, any, any>>;
|
|
51
|
+
/** An action ran in this transaction (#3427, set by action()): once
|
|
52
|
+
* `_actions` drains, its bodies are OVER — as opposed to a transaction that
|
|
53
|
+
* never had one, whose bare optimistic writes live until it settles. */
|
|
54
|
+
_acted?: boolean;
|
|
48
55
|
_queueStash: QueueStub;
|
|
49
56
|
_done: boolean | Transition;
|
|
50
57
|
_gatedSubs: Set<Computed<any>>;
|
|
@@ -73,11 +80,44 @@ export interface Transition {
|
|
|
73
80
|
*/
|
|
74
81
|
export declare function entangleConfirmingTransitions(obs: Computed<any>, target: Transition): void;
|
|
75
82
|
export declare function schedule(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Parked transactions whose reporter set changed without a write. A
|
|
85
|
+
* transaction completes when nothing live reports a flight it waits on, but
|
|
86
|
+
* the flush only judges the ACTIVE transaction: a parked one is re-entered by
|
|
87
|
+
* a stamped node's landing or an action's resume. A reporter that stops
|
|
88
|
+
* counting for another reason — its loading boundary flipped to the fallback
|
|
89
|
+
* (#3375), or it was disposed by ambient work (#3372) — is neither: the
|
|
90
|
+
* pruning in `reporterBlocksSource` would drop it at the next check, but no
|
|
91
|
+
* check comes, and the writes held with it stay staged. Such sites record the
|
|
92
|
+
* transaction here (deduped: one idle pass per transaction, however many
|
|
93
|
+
* reporters changed); the flush re-enters it on an otherwise idle pass, so
|
|
94
|
+
* the re-evaluation adopts no unrelated ambient work.
|
|
95
|
+
*/
|
|
96
|
+
export declare const wokenTransitions: Transition[];
|
|
97
|
+
/** Wake every parked transaction — for a site that knows a reporter stopped
|
|
98
|
+
* counting but not whose (a boundary reset). */
|
|
99
|
+
export declare function wakeParked(): void;
|
|
100
|
+
/** Transactions a mainline tick has PROPOSED against (A34, #3494): a write to a
|
|
101
|
+
* node one of them holds — the same value or another — is a second proposal
|
|
102
|
+
* on a contested node, and the tick reveals with the hold ("both are
|
|
103
|
+
* suggesting a value; if one finished before the other that would be odd").
|
|
104
|
+
* Entered at the next flush's start, where the ambient batch is adopted;
|
|
105
|
+
* never from the write itself, which left `activeTransition` set across the
|
|
106
|
+
* caller's block and made creation after the write the transaction's (A29). */
|
|
107
|
+
export declare const batchJoins: Transition[];
|
|
76
108
|
/**
|
|
77
109
|
* Permanently halts the reactive system. Called when a user error escapes
|
|
78
110
|
* every boundary — app state is undefined at that point, so scheduling stops
|
|
79
111
|
* entirely rather than limping along with a half-applied update.
|
|
80
112
|
*/
|
|
113
|
+
/**
|
|
114
|
+
* The key a root owner carries its client error hook under (`render`'s
|
|
115
|
+
* `onError`) — registered, so a runtime writes it with no import of the hook
|
|
116
|
+
* module (core/error-hooks.ts) and no property mangling in the way. Defined
|
|
117
|
+
* HERE, not there: a runtime that only writes the key must not retain the
|
|
118
|
+
* hook machinery (pay-for-use).
|
|
119
|
+
*/
|
|
120
|
+
export declare const ROOT_ERROR_HOOK: unique symbol;
|
|
81
121
|
export declare function haltReactivity(cause?: unknown): void;
|
|
82
122
|
/** @internal Test/dev-reload hook. Revives scheduling after a halt. */
|
|
83
123
|
export declare function resetErrorHalt(): void;
|
|
@@ -91,6 +131,11 @@ export interface IQueue {
|
|
|
91
131
|
stashQueues(stub: QueueStub): void;
|
|
92
132
|
restoreQueues(stub: QueueStub): void;
|
|
93
133
|
_parent: IQueue | null;
|
|
134
|
+
/** Loading/error boundary queues (boundaries.ts): the status dimension the
|
|
135
|
+
* queue consumes, and whether it currently shows content (initialized) or
|
|
136
|
+
* its fallback (collecting). Read by `reporterBlocksSource`. */
|
|
137
|
+
_collectionType?: number;
|
|
138
|
+
_initialized?: boolean;
|
|
94
139
|
}
|
|
95
140
|
export declare class Queue implements IQueue {
|
|
96
141
|
_parent: IQueue | null;
|
|
@@ -163,11 +208,29 @@ export declare class GlobalQueue extends Queue {
|
|
|
163
208
|
* authoritative-observer wake for a silent confirm. Installed with the
|
|
164
209
|
* optimistic engine; only reachable on a node that has an override. */
|
|
165
210
|
static _supersedeOverride: ((el: Signal<any> | Computed<any>, value: unknown) => void) | null;
|
|
211
|
+
/** The flush's pre-verdict step (#3427): once the transaction's action
|
|
212
|
+
* bodies have all ended and nothing authoritative is left in flight, the
|
|
213
|
+
* engine supersedes every override still in force with the truth it
|
|
214
|
+
* reverts to, so the graph re-derives from it now, as the transaction's
|
|
215
|
+
* held work, instead of after the flights the overrides fed have landed.
|
|
216
|
+
* True when it superseded something: the caller re-runs the heap ahead of
|
|
217
|
+
* the verdict. The engine owns every gate (acted, actions drained, has
|
|
218
|
+
* overrides, no store edits, no authoritative flight); null without it. */
|
|
219
|
+
static _endOptimism: ((transition: Transition) => boolean) | null;
|
|
166
220
|
/** read()'s value for a TRACKED reader of a superseded node (#3331): the
|
|
167
221
|
* staged truth, unless the reader is a stale (render) reader of another
|
|
168
222
|
* transaction — then the displayed override, as it keeps a foreign
|
|
169
223
|
* transaction's committed value over its staged write. */
|
|
170
|
-
|
|
224
|
+
/** A tracked read of an active override: the lane outside-view rule
|
|
225
|
+
* (#3460) and the A18 supersession selection (#3331) — see optimistic.ts. */
|
|
226
|
+
static _overrideRead: ((el: Computed<any>, c: Computed<any>) => unknown) | null;
|
|
227
|
+
/** A lane pass's publish for a memo (#3479, lanes stage): the speculative
|
|
228
|
+
* result becomes a DERIVED override, `_value` stays committed — see
|
|
229
|
+
* optimistic.ts laneOverride. Set with the engine, which a lane implies. */
|
|
230
|
+
static _laneOverride: ((el: Computed<any>, value: unknown, lane: OptimisticLane) => void) | null;
|
|
231
|
+
/** Verdict-layer recompute in progress (companion creation, latest()/
|
|
232
|
+
* isPending() pulls): never born held — see core.ts enterStagedRead. */
|
|
233
|
+
static _verdictPull: boolean;
|
|
171
234
|
/** setSignal's authoritative (projection-write) landing on an override-
|
|
172
235
|
* covered node (#3331 store twin): stage the truth for its transaction's
|
|
173
236
|
* commit whatever its relation to the committed value — a landing equal to
|
|
@@ -215,6 +278,15 @@ export declare function setStoreCommitHook(fn: () => void): void;
|
|
|
215
278
|
* storeCommitHook to stay tree-shakeable. */
|
|
216
279
|
export declare let patchCommitHook: ((batch: Transition) => void) | null;
|
|
217
280
|
export declare function setPatchCommitHook(fn: (batch: Transition) => void): void;
|
|
281
|
+
/** Unchanged passes with a stale dependency tail, waiting on this flush's
|
|
282
|
+
* verdict (A30, #3469). A pass that changed nothing replaced nothing either —
|
|
283
|
+
* and cannot know at its own tail whether the flush that ran it will park:
|
|
284
|
+
* parked, its inputs are held and the committed frame still derives from the
|
|
285
|
+
* tail (`b() ? b() : a()` computed `1` from the held `b`, equal to the `1` it
|
|
286
|
+
* had from `a` — with `a` trimmed, the mainline `a = 2` never reached it).
|
|
287
|
+
* Trimmed when the flush commits; dropped with a park, the tail stays linked
|
|
288
|
+
* until a committing pass trims it (one spurious recompute at most). */
|
|
289
|
+
export declare const heldTrims: Computed<any>[];
|
|
218
290
|
export declare function finalizePureQueue(completingTransition?: Transition | null, incomplete?: boolean): void;
|
|
219
291
|
/**
|
|
220
292
|
* Count of live `affects()` registrations across the system (including
|
|
@@ -264,6 +336,17 @@ export declare const globalQueue: GlobalQueue;
|
|
|
264
336
|
*/
|
|
265
337
|
export declare function flush(): void;
|
|
266
338
|
export declare function flush<T>(fn: () => T): T;
|
|
339
|
+
/**
|
|
340
|
+
* Does a live reporter of `transition` still observe `source` pending? Dead
|
|
341
|
+
* reporters (disposed, behind a fallback, no longer reading the source) are
|
|
342
|
+
* pruned as they are found, and the source's entry with them. Shared by the
|
|
343
|
+
* settle verdict and the lane's hold check (`waitingTransition`): a live
|
|
344
|
+
* action parks its transaction without a verdict, so this prune is the only
|
|
345
|
+
* one an optimistic lane whose last async reader unmounted mid-action ever
|
|
346
|
+
* gets — without it the lane held on the dead reporter's registration until
|
|
347
|
+
* the flight it no longer observed landed (#3426).
|
|
348
|
+
*/
|
|
349
|
+
export declare function sourceObserved(transition: Transition, source: Computed<any>, verdict?: Transition): boolean;
|
|
267
350
|
/** A fresh, unentered transaction (#3146): the optimistic store's truth
|
|
268
351
|
* flight DECLARES an owned transaction instead of relying on whatever the
|
|
269
352
|
* ambient adoption machinery stamped on its firewall. Activate it with
|
|
@@ -277,9 +360,19 @@ export declare function currentTransition(transition: Transition): Transition;
|
|
|
277
360
|
* the node, so a hold check must not assume it was recorded in the transaction
|
|
278
361
|
* it happens to hold — lanes merge across transactions (#2912), and a merged
|
|
279
362
|
* root's transaction knows nothing of the async its members' transactions
|
|
280
|
-
* observed (#3335). Null when nobody is waiting
|
|
363
|
+
* observed (#3335). Null when nobody is waiting — a registration whose every
|
|
364
|
+
* reporter has since died is nobody (#3426).
|
|
281
365
|
*/
|
|
282
366
|
export declare function waitingTransition(source: Computed<any>): Transition | null;
|
|
367
|
+
/** A landing enters EVERY parked transaction still waiting on `source`, folding
|
|
368
|
+
* them into the active one (A15: each reveal that discovered the flight
|
|
369
|
+
* completes at its landing). The fold used to happen as the waiters' stamped
|
|
370
|
+
* readers recomputed under the landing — recompute re-entering an effect's
|
|
371
|
+
* stamp — which also folded in writes those readers merely shared a hole
|
|
372
|
+
* with (#3407); effects no longer re-enter, so the landing folds explicitly.
|
|
373
|
+
* Live iteration is safe: a merge deletes the outgoing (active) entry and
|
|
374
|
+
* re-adds the visited one. */
|
|
375
|
+
export declare function enterWaiting(source: Computed<any>): void;
|
|
283
376
|
export declare function setActiveTransition(transition: Transition | null): void;
|
|
284
377
|
export declare function runInTransition<T>(transition: Transition, fn: () => T): T;
|
|
285
378
|
/** Run `fn` with `transition` as BOTH the ambient transaction and the
|
|
@@ -72,6 +72,9 @@ export interface NodeExtension {
|
|
|
72
72
|
* tick derives from inputs that predate the override and does not
|
|
73
73
|
* supersede it (A18 supersession ordering, #3331). */
|
|
74
74
|
_overrideTime: number;
|
|
75
|
+
/** A28: the staged value the last flush left on a HELD node that has since
|
|
76
|
+
* been rewritten (latest() keeps answering with it); NOT_PENDING otherwise. */
|
|
77
|
+
_flushedStaged: unknown;
|
|
75
78
|
/** Provenance of the active override's write: the scheduler's `origin` (the
|
|
76
79
|
* asking action's invocation sequence; 0 = mainline). An arriving answer
|
|
77
80
|
* whose flight an older action issued asked a question the override has
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { $REFRESH, ContextNotFoundError, NoOwnerError, NotReadyError, TimeoutError, action, createContext, createOwner, createRoot, runWithOwner, flush, getNextChildId, peekNextChildId, getContext, setContext, getOwner, isDisposed, getObserver, isEqual, untrack, isPending, latest, SUPPORTS_PROXY, setSnapshotCapture, markSnapshotScope, releaseSnapshotScope, clearSnapshots, enforceLoadingBoundary, enableExternalSource, resetErrorHalt } from "./core/index.js";
|
|
1
|
+
export { $REFRESH, ContextNotFoundError, NoOwnerError, NotReadyError, TimeoutError, action, createContext, createOwner, createRoot, runWithOwner, flush, getNextChildId, peekNextChildId, getContext, setContext, getOwner, isDisposed, getObserver, isEqual, untrack, isPending, latest, SUPPORTS_PROXY, setSnapshotCapture, markSnapshotScope, releaseSnapshotScope, clearSnapshots, enforceLoadingBoundary, enableExternalSource, resetErrorHalt, ownerPath, configureClientErrors, ROOT_ERROR_HOOK } from "./core/index.js";
|
|
2
2
|
import { type Dev, type Observe } from "./core/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Observe tier (diagnostics channel, attribution hook slot + interaction
|
|
@@ -8,7 +8,7 @@ import { type Dev, type Observe } from "./core/index.js";
|
|
|
8
8
|
export declare const OBSERVE: Observe | undefined;
|
|
9
9
|
/** Dev tier (devtools hooks, graph traversal, console reporting): dev builds only. */
|
|
10
10
|
export declare const DEV: Dev | undefined;
|
|
11
|
-
export type { Owner, Context, ContextRecord, IQueue, ExternalSourceFactory, ExternalSource, ExternalSourceConfig, Refreshable, AttributionHooks, AttributionSlot, InteractionRef, NavigationRef, OriginRef, Dev, Observe, DevHooks, DiagnosticCapture, DiagnosticCode, DiagnosticEvent, DiagnosticKind, DiagnosticListener, Diagnostics, DiagnosticSeverity, DiagnosticSubject } from "./core/index.js";
|
|
11
|
+
export type { Owner, Context, ContextRecord, IQueue, ExternalSourceFactory, ExternalSource, ExternalSourceConfig, Refreshable, AttributionHooks, AttributionSlot, ClientErrorContext, ClientErrorHook, ClientErrorsConfig, InteractionRef, NavigationRef, OriginRef, Dev, Observe, ServerObserve, Records, RecordTypes, HostRecordTypes, RecordType, RecordEvent, RecordLive, RecordListener, DevHooks, DiagnosticCapture, DiagnosticCode, DiagnosticEvent, DiagnosticKind, DiagnosticListener, Diagnostics, DiagnosticSeverity, DiagnosticSubject } from "./core/index.js";
|
|
12
12
|
export { createSignal, createMemo, createEffect, createRenderEffect, createTrackedEffect, createReaction, createOptimistic, refresh, resolve, until, onSettled, onCleanup } from "./signals.js";
|
|
13
13
|
export type { Truthy, UntilOptions, Accessor, SourceAccessor, Setter, Signal, ComputeFunction, EffectFunction, EffectBundle, EffectOptions, SignalOptions, MemoOptions, NoInfer } from "./signals.js";
|
|
14
14
|
export { affects } from "./affects.js";
|
package/dist/types/signals.d.ts
CHANGED
|
@@ -582,12 +582,20 @@ export interface UntilOptions {
|
|
|
582
582
|
*
|
|
583
583
|
* Must be called *outside* a tracking scope.
|
|
584
584
|
*
|
|
585
|
+
* Inside an action, call it from a step: after an `await`, put a bare `yield`
|
|
586
|
+
* before `yield until(...)`. The runtime cannot hook an async generator's
|
|
587
|
+
* `await` continuation, so the `until(...)` expression — which CREATES the
|
|
588
|
+
* predicate's reader — would otherwise run outside the transaction; created
|
|
589
|
+
* there it is born held (A29) and replays only at the commit its own promise
|
|
590
|
+
* holds open (#3482). See {@link action}.
|
|
591
|
+
*
|
|
585
592
|
* @example
|
|
586
593
|
* ```ts
|
|
587
594
|
* const send = action(async function* (text: string) {
|
|
588
595
|
* const clientId = crypto.randomUUID();
|
|
589
596
|
* setMessages(m => { m.push({ clientId, text, pending: true }); }); // optimistic
|
|
590
597
|
* await socket.send({ clientId, text }); // fire-and-forget transport
|
|
598
|
+
* yield; // re-enter the transaction after the await
|
|
591
599
|
* // Hold until the live source echoes the write (authoritative view —
|
|
592
600
|
* // the optimistic row above cannot satisfy this):
|
|
593
601
|
* yield until(() => messages.some(m => m.clientId === clientId), { timeout: 10_000 });
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export type { Store, StoreReturn, ProjectionStoreReturn, StoreSetter, StoreNode, StoreOptions, ProjectionOptions, NotWrappable, SolidStore } from "./store.js";
|
|
2
2
|
export type { Merge, Omit } from "./utils.js";
|
|
3
3
|
export { isWrappable, $TRACK, $PROXY, $TARGET } from "./store.js";
|
|
4
|
-
export { mergeSources } from "./utils.js";
|
|
4
|
+
export { mergeSources, mergeView, viewOf, omitView, sourceKeys, sourceHas, sourceGet, hasStaticKeys, isStatic, resolvedTable, OmitView, MergeView, SOURCE_PLAIN, SOURCE_OMIT, SOURCE_PROXY, SOURCE_MEMO, SOURCE_MERGE, sourceOwners } from "./utils.js";
|
|
5
|
+
export type { SourceKind } from "./utils.js";
|
|
5
6
|
import type { NoFn, ProjectionOptions, Store, StoreOptions, StoreSetter } from "./store.js";
|
|
6
7
|
import type { Refreshable } from "../core/index.js";
|
|
7
8
|
export { createProjectionNext as createProjection } from "./next/projection.js";
|
|
@@ -22,4 +22,4 @@ export declare function notifyOptimisticWrites(t: StoreNextTarget, pb: Record<Pr
|
|
|
22
22
|
* Authoritative-view reads (until()'s predicate) skip composition entirely:
|
|
23
23
|
* the predicate observes authoritative truth, never the caller's tentative
|
|
24
24
|
* overlay. (Write-side emission callers never run under such a compute.) */
|
|
25
|
-
export declare function optimisticView(t: StoreNextTarget, src: Record<PropertyKey, any
|
|
25
|
+
export declare function optimisticView(t: StoreNextTarget, src: Record<PropertyKey, any>, draft?: boolean): Record<PropertyKey, any>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hasActiveOverride, visibleOverride } from "../../core/core.js";
|
|
1
2
|
import type { Signal } from "../../core/types.js";
|
|
2
3
|
import { type StoreNextFamily, type StoreNextTarget } from "./target.js";
|
|
3
4
|
export declare function wrapNext<T extends Record<PropertyKey, any>>(value: T, parent?: StoreNextTarget | null, parentKey?: PropertyKey | null, fam?: StoreNextFamily | null): T;
|
|
@@ -65,9 +66,7 @@ export declare function notifyFold(t: StoreNextTarget, old: Record<PropertyKey,
|
|
|
65
66
|
* share the instance core reads — cross-module live-binding writes from other
|
|
66
67
|
* store modules were observed not to propagate under the test transform). */
|
|
67
68
|
export declare function runAuthoritative<T>(fn: () => T): T;
|
|
68
|
-
|
|
69
|
-
* NOT_PENDING; undefined = unarmed plain node). */
|
|
70
|
-
export declare function hasActiveOverride(node: Signal<any>): boolean;
|
|
69
|
+
export { hasActiveOverride, visibleOverride };
|
|
71
70
|
/** The reading computation is until()'s authoritative-view predicate — same
|
|
72
71
|
* source of truth as core read()'s A17 carve-out (`context`, which persists
|
|
73
72
|
* under untrack). optimisticView()'s composition gate consults exactly this:
|
|
@@ -86,8 +85,10 @@ export declare function authoritativeServe(): boolean;
|
|
|
86
85
|
export type SetStoreNextFunction<T> = (fn: (draft: T) => T | void) => void;
|
|
87
86
|
/** Low-level setter primitive: opens write mode on a next proxy, runs `fn`,
|
|
88
87
|
* emits write-time notifications at outermost exit, applies returned
|
|
89
|
-
* replacements as adoptions. `guard=false` skips the owned-scope
|
|
90
|
-
* projection recomputes legitimately write from
|
|
88
|
+
* replacements as adoptions. `guard=false` skips the dev guards (owned-scope
|
|
89
|
+
* write, thenable result) — projection recomputes legitimately write from
|
|
90
|
+
* inside their computed, and their async derive is handled by the recompute,
|
|
91
|
+
* not returned through here. */
|
|
91
92
|
export declare function storeSetterNext<T>(proxy: T, fn: (draft: T) => T | void, guard?: boolean): void;
|
|
92
93
|
export declare function createStoreNext<T extends Record<PropertyKey, any>>(initialValue: T, shallow?: boolean): [T, SetStoreNextFunction<T>];
|
|
93
94
|
/** True when `proxy` is a SHALLOW store (children served verbatim, slots
|
|
@@ -179,7 +179,7 @@ export declare function devAssertNeverUserMutation(target: object): void;
|
|
|
179
179
|
* the optimistic channel entirely. */
|
|
180
180
|
export interface OptStoreHooks {
|
|
181
181
|
notifyOptimisticWrites(t: any, pb: Record<PropertyKey, any>): void;
|
|
182
|
-
optimisticView(t: any, src: Record<PropertyKey, any
|
|
182
|
+
optimisticView(t: any, src: Record<PropertyKey, any>, draft?: boolean): Record<PropertyKey, any>;
|
|
183
183
|
applyTentative(t: any, incoming: any, keyFn: ((item: any) => any) | null): void;
|
|
184
184
|
/** #3164 fold: does this live transaction still retain optimism (armed
|
|
185
185
|
* nodes or tracked stores)? Backs the held-truth masks in next/store.ts so
|
|
@@ -21,12 +21,170 @@ type _Merge<T extends unknown[], Curr = {}> = T extends [
|
|
|
21
21
|
...infer Rest
|
|
22
22
|
] ? _Merge<Rest, Override<Curr, Next>> : T extends [...infer Rest, infer Next | (() => infer Next)] ? Override<_Merge<Rest, Curr>, Next> : T extends [] ? Curr : T extends (infer I | (() => infer I))[] ? OverrideSpread<Curr, I> : Curr;
|
|
23
23
|
export type Merge<T extends unknown[]> = Simplify<_Merge<T>>;
|
|
24
|
-
/** @internal
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* (
|
|
29
|
-
*
|
|
24
|
+
/** @internal What a source ENTRY is, decided once when the view is built
|
|
25
|
+
* (`merge()` learns it while flattening; `omit()` from its argument) and
|
|
26
|
+
* carried beside the entry — `MergeView.kinds[i]`, `OmitView.kind` — so no
|
|
27
|
+
* read has to ask. Asking is the cost: any brand check on a Proxy is a trap
|
|
28
|
+
* (`instanceof` is a `getPrototypeOf` trap, ~20 ns on a store — as much as
|
|
29
|
+
* the read itself), and a merge over a store did two per read. */
|
|
30
|
+
export declare const SOURCE_PLAIN = 0;
|
|
31
|
+
export declare const SOURCE_OMIT = 1;
|
|
32
|
+
export declare const SOURCE_PROXY = 2;
|
|
33
|
+
export declare const SOURCE_MEMO = 3;
|
|
34
|
+
export declare const SOURCE_MERGE = 4;
|
|
35
|
+
export type SourceKind = 0 | 1 | 2 | 3 | 4;
|
|
36
|
+
/** @internal The record behind an `omit()` proxy: `source` with `hidden`
|
|
37
|
+
* keys removed. It is the proxy's TARGET, so the shared handler reads it as
|
|
38
|
+
* plain fields — no per-instance closures — and it is what props consumers
|
|
39
|
+
* walk directly (`merge`, `spread`, `ssrElement`): a view never materializes
|
|
40
|
+
* a copy, and a consumer that knows the record never goes through its traps
|
|
41
|
+
* (a `getOwnPropertyDescriptor` trap per key allocates a descriptor and a
|
|
42
|
+
* getter, so enumerating a proxy costs more than the copy it was avoiding).
|
|
43
|
+
* `hidden` is a key list or a predicate (`omit(props, k => k[0] === "$")`).
|
|
44
|
+
*
|
|
45
|
+
* An omit over a `merge()` holds the merge's RECORD (`MergeView`, kind
|
|
46
|
+
* `SOURCE_MERGE`) — never its proxy, so no read hops through a trap — and is
|
|
47
|
+
* one record however many leaves the merge has. A consumer walks it as ONE
|
|
48
|
+
* filtered entry (`sourceKeys` / `sourceGet` recurse into the merge's
|
|
49
|
+
* sources by function call), and a later `merge()` over it carries the
|
|
50
|
+
* record as one entry instead of copying its leaves: on a component chain of
|
|
51
|
+
* defaults + omit + spread (`merge(omit(merge(omit(props))))`) the layers
|
|
52
|
+
* nest as records, each a few fields, where a flatten to leaf views built a
|
|
53
|
+
* view and a combined key list per leaf per layer — the largest allocation
|
|
54
|
+
* of a Kobalte-shaped render. A merge leaf may be merge's memo for a
|
|
55
|
+
* function source; it is resolved on access. */
|
|
56
|
+
export declare class OmitView {
|
|
57
|
+
source: any;
|
|
58
|
+
/** of `source` — PLAIN, PROXY (a store or a foreign proxy), MEMO, or
|
|
59
|
+
* MERGE (a `MergeView` record); never OMIT, a view over a view folds
|
|
60
|
+
* into one. */
|
|
61
|
+
kind: SourceKind;
|
|
62
|
+
hidden: Hidden;
|
|
63
|
+
/** see `MergeView.table` */
|
|
64
|
+
table: Map<PropertyKey, any> | null | number;
|
|
65
|
+
/** see `tableOwnKeys` / `tableDescriptor` */
|
|
66
|
+
keys: (string | symbol)[] | undefined;
|
|
67
|
+
descs: Map<PropertyKey, PropertyDescriptor> | undefined;
|
|
68
|
+
constructor(source: any,
|
|
69
|
+
/** of `source` — PLAIN, PROXY (a store or a foreign proxy), MEMO, or
|
|
70
|
+
* MERGE (a `MergeView` record); never OMIT, a view over a view folds
|
|
71
|
+
* into one. */
|
|
72
|
+
kind: SourceKind, hidden: Hidden);
|
|
73
|
+
}
|
|
74
|
+
type Hidden = PropertyKey[] | ((key: PropertyKey) => boolean);
|
|
75
|
+
/** @internal The `OmitView` behind an `omit()` proxy, or undefined. */
|
|
76
|
+
export declare function omitView(o: any): OmitView | undefined;
|
|
77
|
+
/** @internal Own string keys of a source entry — every consumer skips
|
|
78
|
+
* symbols itself. */
|
|
79
|
+
export declare function sourceKeys(s: any, kind: SourceKind): (string | symbol)[];
|
|
80
|
+
/** @internal `key in entry`. */
|
|
81
|
+
export declare function sourceHas(s: any, kind: SourceKind, key: PropertyKey): boolean;
|
|
82
|
+
/** @internal `entry[key]` — the source's getter runs once, here. */
|
|
83
|
+
export declare function sourceGet(s: any, kind: SourceKind, key: PropertyKey): any;
|
|
84
|
+
/** @internal Whether the own key set of a props object cannot change
|
|
85
|
+
* reactively: a plain object, or a merge/omit view over plain objects only.
|
|
86
|
+
* A consumer may then decide from `Object.getOwnPropertyDescriptor` once —
|
|
87
|
+
* "no `children` key" or "a data `children`" holds for the object's lifetime,
|
|
88
|
+
* so no tracking scope is needed for it (#3388). For a store, or a view with
|
|
89
|
+
* a store or memo leaf, keys can appear later and the reactive path is the
|
|
90
|
+
* only correct one. */
|
|
91
|
+
export declare function hasStaticKeys(o: any): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Whether `o[key]` can never change for the lifetime of `o`: the key is a
|
|
94
|
+
* data property of a plain object, or is absent from an object whose key set
|
|
95
|
+
* is fixed. A getter, a key on a store, a memo-backed `merge()` source, or
|
|
96
|
+
* any key of an object whose keys can appear later (a store) is not static.
|
|
97
|
+
*
|
|
98
|
+
* Looks through `merge()`/`omit()` views to the leaf that owns the key. Any
|
|
99
|
+
* object will do, but props are the case it exists for: the compiler encodes
|
|
100
|
+
* a literal at the call site (`as="button"`) as a data property and an
|
|
101
|
+
* expression (`as={isLink() ? "a" : "button"}`) as a getter, so a component
|
|
102
|
+
* library reads the caller's own static/dynamic classification of a prop at
|
|
103
|
+
* runtime — identically on server and client, the compiled shape being the
|
|
104
|
+
* same on both — and can take a no-computation path for the literal:
|
|
105
|
+
*
|
|
106
|
+
* ```tsx
|
|
107
|
+
* const Tag = dynamic(() => props.as, { static: isStatic(props, "as") });
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* One descriptor lookup; no read of the value, nothing tracked.
|
|
111
|
+
*/
|
|
112
|
+
export declare function isStatic(o: object, key: PropertyKey): boolean;
|
|
113
|
+
/** @internal */
|
|
114
|
+
export declare class MergeView {
|
|
115
|
+
sources: any[];
|
|
116
|
+
/** `kinds[i]` is what `sources[i]` is (see `SourceKind`). */
|
|
117
|
+
kinds: SourceKind[];
|
|
118
|
+
/** key → the plain leaf that owns it (later sources win), built by an
|
|
119
|
+
* enumeration or once the reads have paid for it (see `resolvedTable`)
|
|
120
|
+
* when every leaf has static keys; `null` when one doesn't. Until then
|
|
121
|
+
* the slot counts the per-key trap reads so far. One slot rather than a
|
|
122
|
+
* counter field of its own: a view is built per source per component
|
|
123
|
+
* layer, and each field initializer is a measurable share of a
|
|
124
|
+
* constructor that small in the lower JIT tiers. */
|
|
125
|
+
table: Map<PropertyKey, any> | null | number;
|
|
126
|
+
/** see `tableOwnKeys` / `tableDescriptor` */
|
|
127
|
+
keys: (string | symbol)[] | undefined;
|
|
128
|
+
descs: Map<PropertyKey, PropertyDescriptor> | undefined;
|
|
129
|
+
constructor(sources: any[],
|
|
130
|
+
/** `kinds[i]` is what `sources[i]` is (see `SourceKind`). */
|
|
131
|
+
kinds: SourceKind[]);
|
|
132
|
+
}
|
|
133
|
+
/** @internal The `MergeView` behind a `merge()` proxy — its flattened
|
|
134
|
+
* `sources` with their `kinds` — or undefined. */
|
|
135
|
+
export declare function mergeView(o: any): MergeView | undefined;
|
|
136
|
+
/** @internal The record behind a merge() or omit() proxy — a `MergeView`
|
|
137
|
+
* (flattened `sources` with their `kinds`) or an `OmitView` — or undefined
|
|
138
|
+
* for anything else (a plain object, a store, a foreign proxy). Two fast
|
|
139
|
+
* traps on a store, none on a plain object. */
|
|
140
|
+
export declare function viewOf(o: any): MergeView | OmitView | undefined;
|
|
141
|
+
/** @internal The resolved key table of a merge/omit view — every own key of
|
|
142
|
+
* the view mapped to the plain object that owns it, in merged order (a key
|
|
143
|
+
* at the position of the last source that carries it, see `tableSet`) — or
|
|
144
|
+
* undefined when it has none: a leaf is a store or a memo source, whose
|
|
145
|
+
* keys can change, or the object is not a view at all.
|
|
146
|
+
*
|
|
147
|
+
* This is the flat object the eager copy used to build, made lazily and
|
|
148
|
+
* without copying: one pass over the leaves' own keys, then every
|
|
149
|
+
* `get`/`has`/descriptor is one lookup plus one read of the owning leaf, and
|
|
150
|
+
* a consumer (`spread` rerunning its effect) walks the table instead of
|
|
151
|
+
* re-deriving shadowing from the leaves each time. Own keys only, as the
|
|
152
|
+
* copy's were: a plain source's key set is fixed once merged (keys added to
|
|
153
|
+
* it later are not seen — the copy didn't see them either).
|
|
154
|
+
*
|
|
155
|
+
* It is built by an ENUMERATION — the `ownKeys` trap, or a consumer asking
|
|
156
|
+
* for it here — or once per-key reads have paid for it (`READS_FOR_TABLE`),
|
|
157
|
+
* not on the first read. A per-key read has a direct answer (a walk of the
|
|
158
|
+
* sources, last to first, one `in` each) whose cost is the source count,
|
|
159
|
+
* while the table's is every key of every leaf, so the walk wins until a
|
|
160
|
+
* view has been read about as many times as it has keys. On the server it
|
|
161
|
+
* never is: a component reads its props a few times, the element enumerates
|
|
162
|
+
* them once through its own source walk, and the view is gone — building on
|
|
163
|
+
* first read there cost a component chain a table per layer (profiled on
|
|
164
|
+
* the Kobalte-shaped chain: a third of SSR time in the table code and its
|
|
165
|
+
* garbage). On the
|
|
166
|
+
* client a view read on every reactive rerun crosses the threshold in its
|
|
167
|
+
* first few updates and is one lookup per read from then on, as before.
|
|
168
|
+
* Once built — by a `spread`, `Object.keys`, `{...props}`, or the count —
|
|
169
|
+
* every trap uses it. */
|
|
170
|
+
export declare function resolvedTable(o: any): Map<PropertyKey, any> | undefined;
|
|
171
|
+
/** @internal Every own string key of a props SOURCE — a plain object, a
|
|
172
|
+
* store or foreign proxy, or a merge/omit view — appended to `keys` in
|
|
173
|
+
* merged order with the object that owns each at the same index of
|
|
174
|
+
* `owners`: a key already listed (by this source or an earlier one) moves
|
|
175
|
+
* to the end, so several sources collected in turn give the order and the
|
|
176
|
+
* winners a merge of them would. A consumer that reads each key once
|
|
177
|
+
* (`ssrElement`) then reads `owners[i][keys[i]]` — the owner's getter runs
|
|
178
|
+
* there, once — and asks nothing else of a view: no table, no `in` walk per
|
|
179
|
+
* key through the merge/omit layers, no key list per leaf. One pass,
|
|
180
|
+
* however deep the layers nest. Symbols are listed; the consumer skips
|
|
181
|
+
* them. */
|
|
182
|
+
export declare function sourceOwners(s: any, keys: (string | symbol)[], owners: any[]): void;
|
|
183
|
+
/** @internal The flattened sources behind a `merge()` proxy, or undefined.
|
|
184
|
+
* A merge's writes are no-ops, so its sources are the whole truth. A COPY of
|
|
185
|
+
* a merge (`{...merged}`, a descriptor copy) is a plain object that carries
|
|
186
|
+
* no sources — `ownKeys` never answers $SOURCES — so what is on the copy is
|
|
187
|
+
* the truth there and every consumer reads it directly (#3384). */
|
|
30
188
|
export declare function mergeSources(o: any): any[] | undefined;
|
|
31
189
|
/**
|
|
32
190
|
* Merges multiple props-like objects into a single proxy that *preserves
|
|
@@ -36,6 +194,12 @@ export declare function mergeSources(o: any): any[] | undefined;
|
|
|
36
194
|
* Function arguments are treated as memo-backed sources — useful for passing
|
|
37
195
|
* derived defaults whose computation should track reactively.
|
|
38
196
|
*
|
|
197
|
+
* The result is a live VIEW of its sources, never a copy: creating it costs
|
|
198
|
+
* nothing per key, every read goes to the source that owns the key (a getter
|
|
199
|
+
* runs there, a data property is read live), and writing to it is a no-op.
|
|
200
|
+
* A single non-function source is returned as is. To own a mutable object,
|
|
201
|
+
* copy it: `{ ...merged }` snapshots the current values.
|
|
202
|
+
*
|
|
39
203
|
* Use this in component bodies to merge defaults / overrides without losing
|
|
40
204
|
* Solid's per-property tracking.
|
|
41
205
|
*
|
|
@@ -59,6 +223,12 @@ export type Omit<T, K extends readonly (keyof T)[]> = {
|
|
|
59
223
|
* Use it to forward "rest" props to a child element while pulling out the
|
|
60
224
|
* keys your component handles itself — the equivalent of `splitProps(p, ["a","b"])[1]`.
|
|
61
225
|
*
|
|
226
|
+
* The result is a live VIEW of `props`, not a copy: nothing is read or
|
|
227
|
+
* materialized until a key is used, and a spread (`{...rest}`) or a later
|
|
228
|
+
* `merge()` walks the underlying object directly. A predicate hides keys by
|
|
229
|
+
* rule instead of by name — `omit(props, k => k[0] === "$")` — without
|
|
230
|
+
* enumerating first.
|
|
231
|
+
*
|
|
62
232
|
* @example
|
|
63
233
|
* ```tsx
|
|
64
234
|
* function Input(props: { label: string; value: string; onInput: (v: string) => void } & JSX.HTMLAttributes<HTMLInputElement>) {
|
|
@@ -78,4 +248,5 @@ export type Omit<T, K extends readonly (keyof T)[]> = {
|
|
|
78
248
|
* ```
|
|
79
249
|
*/
|
|
80
250
|
export declare function omit<T extends Record<any, any>, K extends readonly (keyof T)[]>(props: T, ...keys: K): Omit<T, K>;
|
|
251
|
+
export declare function omit<T extends Record<any, any>>(props: T, hidden: (key: keyof T & (string | symbol)) => boolean): Partial<T>;
|
|
81
252
|
export {};
|
package/package.json
CHANGED