@solidjs/signals 2.0.0-beta.18 → 2.0.0-beta.20

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.
Files changed (68) hide show
  1. package/dist/dev.js +3276 -928
  2. package/dist/node.cjs +6646 -4189
  3. package/dist/prod/affects.js +218 -0
  4. package/dist/prod/boundaries.js +568 -0
  5. package/dist/prod/core/action.js +96 -0
  6. package/dist/prod/core/async.js +380 -0
  7. package/dist/prod/core/constants.js +92 -0
  8. package/dist/prod/core/context.js +67 -0
  9. package/dist/prod/core/core.js +772 -0
  10. package/dist/prod/core/dev.js +3 -0
  11. package/dist/prod/core/effect.js +145 -0
  12. package/dist/prod/core/error.js +59 -0
  13. package/dist/prod/core/external.js +98 -0
  14. package/dist/prod/core/graph.js +91 -0
  15. package/dist/prod/core/heap.js +132 -0
  16. package/dist/prod/core/invariants.js +42 -0
  17. package/dist/prod/core/lanes.js +140 -0
  18. package/dist/prod/core/optimistic.js +273 -0
  19. package/dist/prod/core/owner.js +293 -0
  20. package/dist/prod/core/scheduler.js +689 -0
  21. package/dist/prod/core/verdict.js +292 -0
  22. package/dist/prod/index.js +45 -0
  23. package/dist/prod/map.js +293 -0
  24. package/dist/prod/signals.js +389 -0
  25. package/dist/prod/store/optimistic.js +184 -0
  26. package/dist/prod/store/projection.js +184 -0
  27. package/dist/prod/store/reconcile.js +426 -0
  28. package/dist/prod/store/store.js +870 -0
  29. package/dist/prod/store/storePath.js +103 -0
  30. package/dist/prod/store/utils.js +316 -0
  31. package/dist/types/affects.d.ts +1 -1
  32. package/dist/types/boundaries.d.ts +6 -6
  33. package/dist/types/core/action.d.ts +19 -6
  34. package/dist/types/core/async.d.ts +4 -38
  35. package/dist/types/core/constants.d.ts +12 -0
  36. package/dist/types/core/core.d.ts +12 -78
  37. package/dist/types/core/dev.d.ts +7 -0
  38. package/dist/types/core/external.d.ts +0 -30
  39. package/dist/types/core/heap.d.ts +8 -0
  40. package/dist/types/core/index.d.ts +3 -2
  41. package/dist/types/core/lanes.d.ts +2 -0
  42. package/dist/types/core/optimistic.d.ts +6 -0
  43. package/dist/types/core/owner.d.ts +8 -0
  44. package/dist/types/core/scheduler.d.ts +40 -39
  45. package/dist/types/core/types.d.ts +9 -1
  46. package/dist/types/core/verdict.d.ts +2 -0
  47. package/dist/types/store/projection.d.ts +0 -1
  48. package/dist/types/store/store.d.ts +8 -2
  49. package/dist/types-cjs/affects.d.cts +1 -1
  50. package/dist/types-cjs/boundaries.d.cts +6 -6
  51. package/dist/types-cjs/core/action.d.cts +19 -6
  52. package/dist/types-cjs/core/async.d.cts +4 -38
  53. package/dist/types-cjs/core/constants.d.cts +12 -0
  54. package/dist/types-cjs/core/core.d.cts +12 -78
  55. package/dist/types-cjs/core/dev.d.cts +7 -0
  56. package/dist/types-cjs/core/external.d.cts +0 -30
  57. package/dist/types-cjs/core/heap.d.cts +8 -0
  58. package/dist/types-cjs/core/index.d.cts +3 -2
  59. package/dist/types-cjs/core/lanes.d.cts +2 -0
  60. package/dist/types-cjs/core/optimistic.d.cts +6 -0
  61. package/dist/types-cjs/core/owner.d.cts +8 -0
  62. package/dist/types-cjs/core/scheduler.d.cts +40 -39
  63. package/dist/types-cjs/core/types.d.cts +9 -1
  64. package/dist/types-cjs/core/verdict.d.cts +2 -0
  65. package/dist/types-cjs/store/projection.d.cts +0 -1
  66. package/dist/types-cjs/store/store.d.cts +8 -2
  67. package/package.json +8 -6
  68. package/dist/prod.js +0 -4637
@@ -0,0 +1,380 @@
1
+ import { STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, REACTIVE_DIRTY, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING } from "./constants.js";
2
+
3
+ import { untrack, context, setSignal } from "./core.js";
4
+
5
+ import "./invariants.js";
6
+
7
+ import { NotReadyError, StatusError } from "./error.js";
8
+
9
+ import { trimStaleDeps } from "./graph.js";
10
+
11
+ import { enqueueSub } from "./heap.js";
12
+
13
+ import { resolveTransition, hasActiveOverride, assignOrMergeLane, resolveLane } from "./lanes.js";
14
+
15
+ import { cleanup } from "./owner.js";
16
+
17
+ import { globalQueue, GlobalQueue, clock, schedule, flush, queuePendingNode, insertSubs } from "./scheduler.js";
18
+
19
+ // The lazily-created Set is the ONE container for pending sources. Its
20
+ // predecessor — a singular slot promoted to a Set on the second source —
21
+ // created dual state whose migration invariant was easy to break: a third
22
+ // overlapping source landed beside the Set and removePendingSource refused
23
+ // to clear it, stranding the Set members' pending forever (#2893).
24
+ function addPendingSource(e, n) {
25
+ if (e.m?.has(n)) return false;
26
+ (e.m ??= new Set).add(n);
27
+ return true;
28
+ }
29
+
30
+ function removePendingSource(e, n) {
31
+ if (!e.m?.delete(n)) return false;
32
+ if (e.m.size === 0) e.m = undefined;
33
+ return true;
34
+ }
35
+
36
+ function clearPendingSources(e) {
37
+ e.m?.clear();
38
+ e.m = undefined;
39
+ }
40
+
41
+ function setPendingError(e, n, r) {
42
+ if (!n) {
43
+ e.k = null;
44
+ return;
45
+ }
46
+ if (r instanceof NotReadyError && r.source === n) {
47
+ e.k = r;
48
+ return;
49
+ }
50
+ const t = e.k;
51
+ if (!(t instanceof NotReadyError) || t.source !== n) {
52
+ e.k = new NotReadyError(n);
53
+ }
54
+ }
55
+
56
+ function forEachDependent(e, n) {
57
+ for (let r = e.p; r !== null; r = r.de) n(r.Ee, r);
58
+ // `?? null`: affects() marks route plain signals (no `_child` slot) through here.
59
+ for (let r = e.G ?? null; r !== null; r = r.Ne) {
60
+ for (let e = r.p; e !== null; e = e.de) n(e.Ee, e);
61
+ }
62
+ }
63
+
64
+ // Queue a node to re-run on the next flush (used both when a pending source
65
+ // settles and when an `isPending` observer must re-evaluate after a real error):
66
+ // shared scheduling helper in heap.ts (tracked effects bypass the heap).
67
+ function settlePendingSource(e, n = e,
68
+ // Mark release runs inside queue finalization: companion writes must go
69
+ // through the settlement snap (committed), because a setSignal here would
70
+ // open a fresh transition-scoped override window that nothing reverts.
71
+ r = false) {
72
+ let t = false;
73
+ const o = new Set;
74
+ // Companion updates no-op without the verdict layer (null hooks).
75
+ const u = r ? GlobalQueue.R : GlobalQueue.P;
76
+ const settle = e => {
77
+ if (o.has(e) || !removePendingSource(e, n)) return;
78
+ o.add(e);
79
+ e.Ie = clock;
80
+ const r = e.m?.values().next().value;
81
+ if (r) {
82
+ setPendingError(e, r);
83
+ u !== null && u(e);
84
+ } else {
85
+ e.i &= ~STATUS_PENDING;
86
+ setPendingError(e);
87
+ u !== null && u(e);
88
+ if (e.Re) {
89
+ enqueueSub(e);
90
+ t = true;
91
+ }
92
+ e.Re = false;
93
+ }
94
+ forEachDependent(e, settle);
95
+ };
96
+ forEachDependent(e, settle);
97
+ if (t) schedule();
98
+ }
99
+
100
+ // Object-thenable detection (Promises/A+ shape).
101
+ function isThenable(e) {
102
+ return e != null && typeof e === "object" && typeof e.then === "function";
103
+ }
104
+
105
+ function handleAsync(e, n, r) {
106
+ let t = false;
107
+ let o = false;
108
+ if (typeof n === "object" && n !== null) {
109
+ untrack(() => {
110
+ t = n[Symbol.asyncIterator];
111
+ o = !t && isThenable(n);
112
+ });
113
+ }
114
+ if (!o && !t) {
115
+ e.Ae = null;
116
+ return n;
117
+ }
118
+ e.Ae = n;
119
+ let u;
120
+ const handleError = r => {
121
+ if (e.Ae !== n) return;
122
+ globalQueue.initTransition(resolveTransition(e));
123
+ // NotReadyError from rejected promises should be treated as pending, not error
124
+ notifyStatus(e, r instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, r);
125
+ e.Ie = clock;
126
+ };
127
+ const asyncWrite = (t, o) => {
128
+ if (e.Ae !== n) return;
129
+ // If the node was dirtied by a newer write (optimistic override or regular),
130
+ // skip this stale async result — the upcoming flush will recompute the node
131
+ // with the new value, creating a fresh Promise that supersedes this one.
132
+ if (e.u & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
133
+ globalQueue.initTransition(resolveTransition(e));
134
+ const u = !!(e.i & STATUS_UNINITIALIZED);
135
+ trimStaleDeps(e);
136
+ clearStatus(e);
137
+ const l = resolveLane(e);
138
+ if (l) l.Pe.delete(e);
139
+ if (r) {
140
+ r(t);
141
+ if (u) clearStatus(e, true);
142
+ } else if (e.be !== undefined) {
143
+ // Optimistic node — resting OR covered by an active override — holds
144
+ // through the shared pending-node path, exactly like a plain async memo,
145
+ // so the commit clears STATUS_UNINITIALIZED (#2806) and elevation to
146
+ // _value happens on this value's OWN transition schedule (A18 as
147
+ // re-ruled 2026-07-07: _value only changes at commit points). With an
148
+ // override active the hold and its eventual commit are unobservable
149
+ // (A17 — every reader sees the override); the revert reveals whatever
150
+ // has committed by then, so corrections reveal atomically with their
151
+ // transition rather than escaping it.
152
+ if (e.ge === NOT_PENDING) queuePendingNode(e);
153
+ e.ge = t;
154
+ // The hold is a companion-visible write like any other (A13/A19): the
155
+ // clearStatus() above computed its verdict before the hold existed, so
156
+ // isPending must re-derive (the value is not final until commit — V1)
157
+ // and latest() must see the fresh in-flight value (V2). Subscribers are
158
+ // only notified when the hold is visible to them: under an active
159
+ // override every reader sees the override (A17), so waking subs would
160
+ // re-show an unchanged view — the revert is the notification point.
161
+ GlobalQueue._e !== null && GlobalQueue._e(e, t);
162
+ if (!hasActiveOverride(e)) insertSubs(e);
163
+ e.Ie = clock;
164
+ } else if (l) {
165
+ // Route through lane's effect queue for independent flushing
166
+ const n = e.De;
167
+ const r = e.Ue;
168
+ const o = e.Ge;
169
+ try {
170
+ if (!n && u || !o || !o(t, r)) {
171
+ e.Ue = t;
172
+ e.Ie = clock;
173
+ // The latest() shadow write gives latest() effects independent lanes; the
174
+ // _pendingSignal update is a no-op repeat of the clearStatus() call above
175
+ // (computePendingState doesn't read _value).
176
+ GlobalQueue._e !== null && GlobalQueue._e(e, t);
177
+ insertSubs(e, true);
178
+ }
179
+ } catch (n) {
180
+ // A user comparator throwing during async resolution has no caller to
181
+ // surface to (we're in promise machinery) — route it through the node's
182
+ // error status so boundaries contain it instead of an unhandled
183
+ // rejection (#2837).
184
+ notifyStatus(e, STATUS_ERROR, n);
185
+ }
186
+ } else {
187
+ try {
188
+ setSignal(e, () => t);
189
+ } catch (n) {
190
+ // Same containment as above: setSignal's comparator throw is the only
191
+ // pre-commit failure here, and there is no user callsite to throw to.
192
+ notifyStatus(e, STATUS_ERROR, n);
193
+ }
194
+ }
195
+ settlePendingSource(e);
196
+ schedule();
197
+ flush();
198
+ o?.();
199
+ };
200
+ if (o) {
201
+ let r = false, t = false, o, l = true;
202
+ n.then(e => {
203
+ if (l) {
204
+ u = e;
205
+ r = true;
206
+ } else asyncWrite(e);
207
+ }, e => {
208
+ if (l) {
209
+ o = e;
210
+ t = true;
211
+ } else handleError(e);
212
+ });
213
+ l = false;
214
+ if (t) {
215
+ // Settle through the same status path an async rejection uses, then
216
+ // unwind the in-progress synchronous read so the errored node isn't
217
+ // momentarily read as `undefined`.
218
+ handleError(o);
219
+ throw o;
220
+ } else if (!r) {
221
+ globalQueue.initTransition(resolveTransition(e));
222
+ throw new NotReadyError(context);
223
+ }
224
+ }
225
+ if (t) {
226
+ const r = n[Symbol.asyncIterator]();
227
+ let t = false;
228
+ let o = false;
229
+ let l = true;
230
+ cleanup(() => {
231
+ if (o) return;
232
+ o = true;
233
+ try {
234
+ const e = r.return?.();
235
+ if (isThenable(e)) e.then(undefined, () => {});
236
+ } catch {}
237
+ });
238
+ const iterate = () => {
239
+ let i, s, f = false, a = false, c = true;
240
+ r.next().then(r => {
241
+ if (c) {
242
+ i = r;
243
+ f = true;
244
+ if (r.done) o = true;
245
+ } else if (e.Ae !== n) {
246
+ return;
247
+ } else if (!r.done) {
248
+ t = true;
249
+ asyncWrite(r.value, iterate);
250
+ } else {
251
+ o = true;
252
+ if (t) {
253
+ schedule();
254
+ flush();
255
+ } else {
256
+ // Empty completion settles like the immediately-done sync path.
257
+ asyncWrite(undefined);
258
+ }
259
+ }
260
+ }, r => {
261
+ if (c) {
262
+ s = r;
263
+ a = true;
264
+ } else if (e.Ae === n) {
265
+ o = true;
266
+ handleError(r);
267
+ }
268
+ });
269
+ c = false;
270
+ if (a) {
271
+ // Match the promise branch, but only rethrow during the initial read.
272
+ o = true;
273
+ handleError(s);
274
+ if (l) throw s;
275
+ return true;
276
+ }
277
+ if (f && !i.done) {
278
+ u = i.value;
279
+ t = true;
280
+ return iterate();
281
+ }
282
+ return f && i.done;
283
+ };
284
+ const i = iterate();
285
+ // Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
286
+ l = false;
287
+ if (!t && !i) {
288
+ globalQueue.initTransition(resolveTransition(e));
289
+ throw new NotReadyError(context);
290
+ }
291
+ }
292
+ return u;
293
+ }
294
+
295
+ function clearStatus(e, n = false) {
296
+ if (e.m) clearPendingSources(e);
297
+ if (e.Re) e.Re = false;
298
+ // The pending window is over; its quiet classification dies with it.
299
+ // (Unconditional: _reask is baked into the node literals, so this is a
300
+ // plain store to an existing slot — no shape change.)
301
+ e.A = false;
302
+ e.i = n ? 0 : e.i & STATUS_UNINITIALIZED;
303
+ if (e.k) setPendingError(e);
304
+ // Update pending signal for isPending() reactivity (companions only exist
305
+ // once the verdict layer created them, which installs the hooks).
306
+ if (e.ye || e.pe) GlobalQueue.P(e);
307
+ if (e.G && GlobalQueue.me !== null) GlobalQueue.me(e);
308
+ if (e.C) e.C();
309
+ }
310
+
311
+ function notifyStatus(e, n, r, t, o) {
312
+ // Wrap regular errors to track source node
313
+ if (n === STATUS_ERROR && !(r instanceof StatusError) && !(r instanceof NotReadyError)) r = new StatusError(e, r);
314
+ const u = n === STATUS_PENDING && r instanceof NotReadyError ? r.source : undefined;
315
+ // Mark-sourced propagation must not capture subscribers into the marking
316
+ // action's transaction (#2893): they carry no held value needing a
317
+ // transition-scheduled commit, and stamping `_transition` on them would
318
+ // freeze unrelated writes that share a downstream memo until the action
319
+ // settles. Real async keeps queuing (its commits ride the transition).
320
+ const l = u?.l !== undefined;
321
+ // A real error is a settled verdict a mark must not erase (#2893): landing
322
+ // STATUS_PENDING here would clobber `_error` with the sentinel's
323
+ // NotReadyError, and unlike real async there is no arriving value whose
324
+ // recompute would surface the error again. Descent stops too — everything
325
+ // downstream holds the propagated error for the same reason.
326
+ if (l && e.i & STATUS_ERROR) return;
327
+ const i = u === e;
328
+ const s = n === STATUS_PENDING && e.be !== undefined && !i;
329
+ const f = s && hasActiveOverride(e);
330
+ if (!t) {
331
+ if (n === STATUS_PENDING && u) {
332
+ addPendingSource(e, u);
333
+ e.i = STATUS_PENDING | e.i & STATUS_UNINITIALIZED;
334
+ // Preserve the current source on this propagation so render-effect notification
335
+ // can register every distinct pending source with the transition.
336
+ setPendingError(e, u, r);
337
+ } else {
338
+ clearPendingSources(e);
339
+ e.i = n | (n !== STATUS_ERROR ? e.i & STATUS_UNINITIALIZED : 0);
340
+ e.k = r;
341
+ }
342
+ GlobalQueue.P !== null && GlobalQueue.P(e);
343
+ if (e.G && GlobalQueue.me !== null) GlobalQueue.me(e);
344
+ }
345
+ if (o && !t) {
346
+ assignOrMergeLane(e, o);
347
+ }
348
+ const a = t || f;
349
+ const c = t || s ? undefined : o;
350
+ if (e.C) {
351
+ if (t && n === STATUS_PENDING) {
352
+ return;
353
+ }
354
+ if (a) {
355
+ e.C(n, r);
356
+ } else {
357
+ e.C();
358
+ }
359
+ return;
360
+ }
361
+ forEachDependent(e, (e, t) => {
362
+ e.Ie = clock;
363
+ if (n === STATUS_PENDING && u && !e.m?.has(u) || n !== STATUS_PENDING && (e.k !== r || e.m)) {
364
+ // A pending-observer link is the subscription an `isPending` read created.
365
+ // It exists so the observer re-runs when the source settles, but it must
366
+ // not carry a real (non-NotReadyError) error — the synchronous `isPending`
367
+ // read swallows those, and the async path must match. Re-run the observer
368
+ // so `isPending` re-evaluates (to not-pending) instead of forwarding.
369
+ if (t.Qe && n !== STATUS_PENDING && !(r instanceof NotReadyError)) {
370
+ enqueueSub(e);
371
+ schedule();
372
+ return;
373
+ }
374
+ if (!a && !l && !e.ve) queuePendingNode(e);
375
+ notifyStatus(e, n, r, a, c);
376
+ }
377
+ });
378
+ }
379
+
380
+ export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, setPendingError, settlePendingSource };
@@ -0,0 +1,92 @@
1
+ const REACTIVE_NONE = 0;
2
+
3
+ const REACTIVE_CHECK = 1 << 0;
4
+
5
+ const REACTIVE_DIRTY = 1 << 1;
6
+
7
+ const REACTIVE_RECOMPUTING_DEPS = 1 << 2;
8
+
9
+ const REACTIVE_IN_HEAP = 1 << 3;
10
+
11
+ const REACTIVE_IN_HEAP_HEIGHT = 1 << 4;
12
+
13
+ const REACTIVE_ZOMBIE = 1 << 5;
14
+
15
+ const REACTIVE_DISPOSED = 1 << 6;
16
+
17
+ const REACTIVE_OPTIMISTIC_DIRTY = 1 << 7;
18
+
19
+ const REACTIVE_SNAPSHOT_STALE = 1 << 8;
20
+
21
+ const REACTIVE_LAZY = 1 << 9;
22
+
23
+ const REACTIVE_MANUAL_WRITE = 1 << 10;
24
+
25
+ /**
26
+ * The pending recompute is a re-ask of the same question: `refresh()` dirtied
27
+ * the node while no tracked input changed value. Cleared whenever a real
28
+ * value-change notification arrives (`insertSubs`), and consumed by
29
+ * `recompute` into the node's `_reask` classification — a quiet (re-ask)
30
+ * pending window does not read as pending (question-scoped pending model).
31
+ */ const REACTIVE_REASK = 1 << 11;
32
+
33
+ // Static configuration bits packed into Owner/Computed/Signal _config.
34
+ const CONFIG_OWNED_WRITE = 1 << 0;
35
+
36
+ const CONFIG_NO_SNAPSHOT = 1 << 1;
37
+
38
+ const CONFIG_TRANSPARENT = 1 << 2;
39
+
40
+ const CONFIG_IN_SNAPSHOT_SCOPE = 1 << 3;
41
+
42
+ const CONFIG_CHILDREN_FORBIDDEN = 1 << 4;
43
+
44
+ const CONFIG_AUTO_DISPOSE = 1 << 5;
45
+
46
+ const CONFIG_SYNC = 1 << 6;
47
+
48
+ const STATUS_PENDING = 1 << 0;
49
+
50
+ const STATUS_ERROR = 1 << 1;
51
+
52
+ const STATUS_UNINITIALIZED = 1 << 2;
53
+
54
+ const EFFECT_RENDER = 1;
55
+
56
+ const EFFECT_USER = 2;
57
+
58
+ const EFFECT_TRACKED = 3;
59
+
60
+ const NOT_PENDING = {};
61
+
62
+ const NO_SNAPSHOT = {};
63
+
64
+ /**
65
+ * Stand-in stored in `_overrideValue` for an optimistic write of literal
66
+ * `undefined` (#2898). The slot doubles as the optimistic-node brand
67
+ * (`undefined` = not optimistic, `NOT_PENDING` = at rest), so the raw value
68
+ * would erase the node's optimistic identity: the write turns invisible and
69
+ * follow-up writes route off the optimistic path and commit permanently.
70
+ * Same shape as NO_SNAPSHOT. Sites that surface the override VALUE unwrap
71
+ * via `visibleOverrideValue`; slot identity tests stay raw.
72
+ */ const OVERRIDE_UNDEFINED = {};
73
+
74
+ /** Unwrap an active override's stored value for surfacing to readers (#2898). */ function unwrapOverride(E) {
75
+ return E === OVERRIDE_UNDEFINED ? undefined : E;
76
+ }
77
+
78
+ const STORE_SNAPSHOT_PROPS = "sp";
79
+
80
+ const SUPPORTS_PROXY = typeof Proxy === "function";
81
+
82
+ const defaultContext = {};
83
+
84
+ /**
85
+ * Brand symbol used by `Refreshable<T>` values (projection stores, async
86
+ * memos) to expose their underlying computation to `refresh()`. Not part of
87
+ * the user-facing API.
88
+ *
89
+ * @internal
90
+ */ const $REFRESH = Symbol("refresh");
91
+
92
+ export { $REFRESH, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_NO_SNAPSHOT, CONFIG_OWNED_WRITE, CONFIG_SYNC, CONFIG_TRANSPARENT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, OVERRIDE_UNDEFINED, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_NONE, REACTIVE_OPTIMISTIC_DIRTY, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SNAPSHOT_STALE, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_PENDING, STATUS_UNINITIALIZED, STORE_SNAPSHOT_PROPS, SUPPORTS_PROXY, defaultContext, unwrapOverride };
@@ -0,0 +1,67 @@
1
+ import { NoOwnerError, ContextNotFoundError } from "./error.js";
2
+
3
+ import { getOwner } from "./owner.js";
4
+
5
+ /**
6
+ * Context provides a form of dependency injection. It is used to save from needing to pass
7
+ * data as props through intermediate components. This function creates a new context object
8
+ * that can be used with `getContext` and `setContext`.
9
+ *
10
+ * A default value can be provided here which will be used when a specific value is not provided
11
+ * via a `setContext` call.
12
+ */ function createContext(e, t) {
13
+ return {
14
+ id: Symbol(t),
15
+ defaultValue: e
16
+ };
17
+ }
18
+
19
+ /**
20
+ * Low-level owner-targeted context read. The user-facing read API is
21
+ * `useContext` (in `solid-js`), which wraps this primitive. Exposed here for
22
+ * cross-package wiring (e.g. hydration-aware context plumbing).
23
+ *
24
+ * @throws `NoOwnerError` if there's no owner at the time of call.
25
+ * @throws `ContextNotFoundError` if a context value has not been set yet.
26
+ *
27
+ * @internal
28
+ */ function getContext(e, t = getOwner()) {
29
+ if (!t) {
30
+ throw new NoOwnerError;
31
+ }
32
+ const n = hasContext(e, t) ? t.we[e.id] : e.defaultValue;
33
+ if (isUndefined(n)) {
34
+ throw new ContextNotFoundError;
35
+ }
36
+ return n;
37
+ }
38
+
39
+ /**
40
+ * Low-level owner-targeted context write. The user-facing API is
41
+ * `createContext` (in `solid-js`); its provider component wraps this
42
+ * primitive. Exposed here for cross-package wiring.
43
+ *
44
+ * @throws `NoOwnerError` if there's no owner at the time of call.
45
+ *
46
+ * @internal
47
+ */ function setContext(e, t, n = getOwner()) {
48
+ if (!n) {
49
+ throw new NoOwnerError;
50
+ }
51
+ // We're creating a new object to avoid child context values being exposed to parent owners. If
52
+ // we don't do this, everything will be a singleton and all hell will break lose.
53
+ n.we = {
54
+ ...n.we,
55
+ [e.id]: isUndefined(t) ? e.defaultValue : t
56
+ };
57
+ }
58
+
59
+ function hasContext(e, t) {
60
+ return !isUndefined(t?.we[e.id]);
61
+ }
62
+
63
+ function isUndefined(e) {
64
+ return typeof e === "undefined";
65
+ }
66
+
67
+ export { createContext, getContext, setContext };