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

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