signalium 3.0.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/cjs/development/{component-shared-Cug2Y5YZ.js → component-shared-BjwFh5Jq.js} +2 -2
  3. package/dist/cjs/development/{component-shared-Cug2Y5YZ.js.map → component-shared-BjwFh5Jq.js.map} +1 -1
  4. package/dist/cjs/development/config-D6wyrhrW.js +58 -0
  5. package/dist/cjs/development/config-D6wyrhrW.js.map +1 -0
  6. package/dist/cjs/development/config.js +1 -1
  7. package/dist/cjs/development/{debug-C46WDxhL.js → debug-CbAX7VeM.js} +260 -43
  8. package/dist/cjs/development/debug-CbAX7VeM.js.map +1 -0
  9. package/dist/cjs/development/debug.js +3 -1
  10. package/dist/cjs/development/debug.js.map +1 -1
  11. package/dist/cjs/development/index.js +3 -2
  12. package/dist/cjs/development/index.js.map +1 -1
  13. package/dist/cjs/development/react/index.js +399 -52
  14. package/dist/cjs/development/react/index.js.map +1 -1
  15. package/dist/cjs/development/react/index.server.js +2 -2
  16. package/dist/cjs/development/react/index.server.js.map +1 -1
  17. package/dist/cjs/development/react/server.js +1 -1
  18. package/dist/cjs/development/{snapshot-CbZ6IH3B.js → snapshot-BTMVSd8Y.js} +4 -2
  19. package/dist/cjs/development/snapshot-BTMVSd8Y.js.map +1 -0
  20. package/dist/cjs/development/transform/index.js +5 -2
  21. package/dist/cjs/development/transform/index.js.map +1 -1
  22. package/dist/cjs/development/utils.js +34 -2
  23. package/dist/cjs/development/utils.js.map +1 -1
  24. package/dist/cjs/production/{component-shared-D0J85PUi.js → component-shared-CcxyLg4p.js} +2 -2
  25. package/dist/cjs/production/{component-shared-D0J85PUi.js.map → component-shared-CcxyLg4p.js.map} +1 -1
  26. package/dist/cjs/production/config-BHvmcsLQ.js +52 -0
  27. package/dist/cjs/production/config-BHvmcsLQ.js.map +1 -0
  28. package/dist/cjs/production/config.js +1 -1
  29. package/dist/cjs/production/{contexts-CM3QLfV8.js → contexts-waczQzHZ.js} +260 -43
  30. package/dist/cjs/production/contexts-waczQzHZ.js.map +1 -0
  31. package/dist/cjs/production/debug.js +3 -1
  32. package/dist/cjs/production/debug.js.map +1 -1
  33. package/dist/cjs/production/index.js +3 -2
  34. package/dist/cjs/production/index.js.map +1 -1
  35. package/dist/cjs/production/react/index.js +399 -52
  36. package/dist/cjs/production/react/index.js.map +1 -1
  37. package/dist/cjs/production/react/index.server.js +2 -2
  38. package/dist/cjs/production/react/index.server.js.map +1 -1
  39. package/dist/cjs/production/react/server.js +1 -1
  40. package/dist/cjs/production/{snapshot-DWwH7_9y.js → snapshot-7264bWj1.js} +4 -2
  41. package/dist/cjs/production/snapshot-7264bWj1.js.map +1 -0
  42. package/dist/cjs/production/transform/index.js +5 -2
  43. package/dist/cjs/production/transform/index.js.map +1 -1
  44. package/dist/cjs/production/utils.js +34 -2
  45. package/dist/cjs/production/utils.js.map +1 -1
  46. package/dist/esm/config.d.ts +1 -1
  47. package/dist/esm/config.d.ts.map +1 -1
  48. package/dist/esm/debug.d.ts +1 -0
  49. package/dist/esm/debug.d.ts.map +1 -1
  50. package/dist/esm/development/{component-shared-CLSmdnGU.js → component-shared-B3Q6mIzY.js} +2 -2
  51. package/dist/esm/development/{component-shared-CLSmdnGU.js.map → component-shared-B3Q6mIzY.js.map} +1 -1
  52. package/dist/esm/development/config-CQLKpPRj.js +59 -0
  53. package/dist/esm/development/config-CQLKpPRj.js.map +1 -0
  54. package/dist/esm/development/config.js +2 -2
  55. package/dist/esm/development/{debug-BTLbgTPK.js → debug-C3HD8WcT.js} +288 -71
  56. package/dist/esm/development/debug-C3HD8WcT.js.map +1 -0
  57. package/dist/esm/development/debug.js +12 -10
  58. package/dist/esm/development/index.js +18 -17
  59. package/dist/esm/development/react/index.js +400 -53
  60. package/dist/esm/development/react/index.js.map +1 -1
  61. package/dist/esm/development/react/index.server.js +2 -2
  62. package/dist/esm/development/react/index.server.js.map +1 -1
  63. package/dist/esm/development/react/server.js +1 -1
  64. package/dist/esm/development/{snapshot-CkndI4Hh.js → snapshot-CCKlBy-y.js} +7 -5
  65. package/dist/esm/development/snapshot-CCKlBy-y.js.map +1 -0
  66. package/dist/esm/development/transform/index.js +5 -2
  67. package/dist/esm/development/transform/index.js.map +1 -1
  68. package/dist/esm/development/utils.js +38 -6
  69. package/dist/esm/development/utils.js.map +1 -1
  70. package/dist/esm/index.d.ts +2 -2
  71. package/dist/esm/index.d.ts.map +1 -1
  72. package/dist/esm/internals/async.d.ts.map +1 -1
  73. package/dist/esm/internals/config.d.ts +40 -0
  74. package/dist/esm/internals/config.d.ts.map +1 -1
  75. package/dist/esm/internals/lease.d.ts +30 -0
  76. package/dist/esm/internals/lease.d.ts.map +1 -0
  77. package/dist/esm/internals/reactive.d.ts +18 -1
  78. package/dist/esm/internals/reactive.d.ts.map +1 -1
  79. package/dist/esm/internals/scheduling.d.ts +2 -1
  80. package/dist/esm/internals/scheduling.d.ts.map +1 -1
  81. package/dist/esm/internals/utils/hash.d.ts +7 -0
  82. package/dist/esm/internals/utils/hash.d.ts.map +1 -1
  83. package/dist/esm/internals/utils/snapshot.d.ts +2 -0
  84. package/dist/esm/internals/utils/snapshot.d.ts.map +1 -1
  85. package/dist/esm/internals/watch.d.ts +3 -2
  86. package/dist/esm/internals/watch.d.ts.map +1 -1
  87. package/dist/esm/production/{component-shared-Dva0S5e3.js → component-shared-CycOXiis.js} +2 -2
  88. package/dist/esm/production/{component-shared-Dva0S5e3.js.map → component-shared-CycOXiis.js.map} +1 -1
  89. package/dist/esm/production/config-BhtwQYAN.js +53 -0
  90. package/dist/esm/production/config-BhtwQYAN.js.map +1 -0
  91. package/dist/esm/production/config.js +2 -2
  92. package/dist/esm/production/{contexts-FxCndlvf.js → contexts-ry5lvNSx.js} +291 -74
  93. package/dist/esm/production/contexts-ry5lvNSx.js.map +1 -0
  94. package/dist/esm/production/debug.js +3 -1
  95. package/dist/esm/production/index.js +19 -18
  96. package/dist/esm/production/react/index.js +400 -53
  97. package/dist/esm/production/react/index.js.map +1 -1
  98. package/dist/esm/production/react/index.server.js +2 -2
  99. package/dist/esm/production/react/index.server.js.map +1 -1
  100. package/dist/esm/production/react/server.js +1 -1
  101. package/dist/esm/production/{snapshot-CdCaJJ0L.js → snapshot-1d_HVP3L.js} +7 -5
  102. package/dist/esm/production/snapshot-1d_HVP3L.js.map +1 -0
  103. package/dist/esm/production/transform/index.js +5 -2
  104. package/dist/esm/production/transform/index.js.map +1 -1
  105. package/dist/esm/production/utils.js +39 -7
  106. package/dist/esm/production/utils.js.map +1 -1
  107. package/dist/esm/react/async-component.d.ts +10 -2
  108. package/dist/esm/react/async-component.d.ts.map +1 -1
  109. package/dist/esm/react/component-server.d.ts +6 -2
  110. package/dist/esm/react/component-server.d.ts.map +1 -1
  111. package/dist/esm/react/component.d.ts +5 -2
  112. package/dist/esm/react/component.d.ts.map +1 -1
  113. package/dist/esm/react/delivery.d.ts +107 -0
  114. package/dist/esm/react/delivery.d.ts.map +1 -0
  115. package/dist/esm/react/index.d.ts +3 -2
  116. package/dist/esm/react/index.d.ts.map +1 -1
  117. package/dist/esm/react/pause-signals-context.d.ts +16 -2
  118. package/dist/esm/react/pause-signals-context.d.ts.map +1 -1
  119. package/dist/esm/react/props-hash.d.ts +20 -0
  120. package/dist/esm/react/props-hash.d.ts.map +1 -0
  121. package/dist/esm/react/use-reactive.d.ts +6 -3
  122. package/dist/esm/react/use-reactive.d.ts.map +1 -1
  123. package/dist/esm/transform/async.d.ts.map +1 -1
  124. package/dist/esm/transform/callback.d.ts.map +1 -1
  125. package/dist/esm/transform/promise.d.ts.map +1 -1
  126. package/dist/esm/transform/use-reactive.d.ts.map +1 -1
  127. package/dist/esm/transform/utils.d.ts +1 -1
  128. package/dist/esm/transform/utils.d.ts.map +1 -1
  129. package/dist/esm/types.d.ts +20 -1
  130. package/dist/esm/types.d.ts.map +1 -1
  131. package/dist/esm/utils.d.ts +17 -1
  132. package/dist/esm/utils.d.ts.map +1 -1
  133. package/package.json +1 -1
  134. package/dist/cjs/development/config-B0MtLBgx.js +0 -21
  135. package/dist/cjs/development/config-B0MtLBgx.js.map +0 -1
  136. package/dist/cjs/development/debug-C46WDxhL.js.map +0 -1
  137. package/dist/cjs/development/snapshot-CbZ6IH3B.js.map +0 -1
  138. package/dist/cjs/production/config-B0MtLBgx.js +0 -21
  139. package/dist/cjs/production/config-B0MtLBgx.js.map +0 -1
  140. package/dist/cjs/production/contexts-CM3QLfV8.js.map +0 -1
  141. package/dist/cjs/production/snapshot-DWwH7_9y.js.map +0 -1
  142. package/dist/esm/development/config-CPQL7hX-.js +0 -22
  143. package/dist/esm/development/config-CPQL7hX-.js.map +0 -1
  144. package/dist/esm/development/debug-BTLbgTPK.js.map +0 -1
  145. package/dist/esm/development/snapshot-CkndI4Hh.js.map +0 -1
  146. package/dist/esm/production/config-CPQL7hX-.js +0 -22
  147. package/dist/esm/production/config-CPQL7hX-.js.map +0 -1
  148. package/dist/esm/production/contexts-FxCndlvf.js.map +0 -1
  149. package/dist/esm/production/snapshot-CdCaJJ0L.js.map +0 -1
@@ -1,9 +1,10 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
- import React__default, { createContext, useContext as useContext$1, useMemo, useRef, useEffect, useSyncExternalStore } from "react";
4
- import { b as getCurrentConsumer, k as getGlobalScope, S as SignalScope, l as hashValue, u as unwatchSignal, w as watchSignal, m as schedulePull, s as setCurrentConsumer, j as isReactivePromise, n as isPromise, o as isThennable, c as createReactiveSignal, r as runSignal, d as setRequestScopeGetter, p as signal } from "../debug-BTLbgTPK.js";
5
- import { i as isAsyncFunctionWithoutTransform, a as isGeneratorFunction, c as createServerAsyncComponentWrapper } from "../component-shared-CLSmdnGU.js";
6
- import { g as getReactiveFnAndDefinition, r as reactiveSignal, s as snapshot } from "../snapshot-CkndI4Hh.js";
3
+ import React__default, { createContext, useContext as useContext$1, useMemo, useRef, useEffect, useSyncExternalStore, useReducer, useState, useLayoutEffect, useInsertionEffect } from "react";
4
+ import { b as getCurrentConsumer, k as getGlobalScope, S as SignalScope, l as hashValue, m as getObjectHash, n as hashObjectKeys, o as mixHash, p as finalizeHash, A as ARRAY_SEED, q as checkSignal, s as setCurrentConsumer, j as isReactivePromise, r as isPromise, t as isThennable, c as createReactiveSignal, u as runSignal, v as holdLeaseUntilSettled, w as holdSuspendedLease, x as releaseAbandonedAttempt, d as setRequestScopeGetter, y as signal } from "../debug-C3HD8WcT.js";
5
+ import { g as getReactDelivery, s as scheduleReactDelivery, r as runBatch } from "../config-CQLKpPRj.js";
6
+ import { i as isAsyncFunctionWithoutTransform, a as isGeneratorFunction, c as createServerAsyncComponentWrapper } from "../component-shared-B3Q6mIzY.js";
7
+ import { g as getReactiveFnAndDefinition, r as reactiveSignal, s as snapshot } from "../snapshot-CCKlBy-y.js";
7
8
  const ScopeContext = createContext(void 0);
8
9
  function useScope() {
9
10
  return useContext$1(ScopeContext);
@@ -25,7 +26,14 @@ function ContextProvider({ children, contexts = [], inherit = true }) {
25
26
  return jsx(ScopeContext.Provider, { value: scope, children });
26
27
  }
27
28
  class PauseSignalsManager {
28
- signals = /* @__PURE__ */ new Set();
29
+ /**
30
+ * Readers per registered signal. Scope-cached signals can be shared across providers, so pausing
31
+ * counts readers on the signal instead of pausing it outright.
32
+ */
33
+ signals = /* @__PURE__ */ new Map();
34
+ /** Unclaimed render leases taken under this provider (e.g. a suspended mount). Pruned lazily. */
35
+ leases = /* @__PURE__ */ new Set();
36
+ pruneLeasesAt = 64;
29
37
  _paused;
30
38
  constructor(initialPaused) {
31
39
  this._paused = initialPaused;
@@ -33,22 +41,52 @@ class PauseSignalsManager {
33
41
  get paused() {
34
42
  return this._paused;
35
43
  }
44
+ trackLease(signal2) {
45
+ const leases = this.leases;
46
+ leases.add(signal2);
47
+ if (leases.size >= this.pruneLeasesAt) {
48
+ for (const leased of leases) {
49
+ if (!leased._isLeased)
50
+ leases.delete(leased);
51
+ }
52
+ this.pruneLeasesAt = Math.max(64, leases.size * 2);
53
+ }
54
+ }
55
+ /** Call before the reader subscribes, so a paused reader never takes the watch. */
36
56
  register(signal2) {
37
- this.signals.add(signal2);
57
+ this.signals.set(signal2, (this.signals.get(signal2) ?? 0) + 1);
58
+ this.leases.delete(signal2);
59
+ if (this._paused) {
60
+ signal2._addPausedReaders(1);
61
+ }
38
62
  }
39
63
  unregister(signal2) {
40
- this.signals.delete(signal2);
64
+ const count = this.signals.get(signal2);
65
+ if (count === void 0)
66
+ return;
67
+ if (count > 1) {
68
+ this.signals.set(signal2, count - 1);
69
+ } else {
70
+ this.signals.delete(signal2);
71
+ }
72
+ if (this._paused) {
73
+ signal2._addPausedReaders(-1, true);
74
+ }
41
75
  }
42
76
  setPaused(value) {
43
77
  if (value === this._paused)
44
78
  return;
45
79
  this._paused = value;
46
- for (const signal2 of this.signals) {
47
- if (value) {
48
- unwatchSignal(signal2);
80
+ for (const [signal2, count] of this.signals) {
81
+ signal2._addPausedReaders(value ? count : -count);
82
+ }
83
+ for (const signal2 of this.leases) {
84
+ if (!signal2._isLeased) {
85
+ this.leases.delete(signal2);
86
+ } else if (value) {
87
+ signal2._pauseWatch();
49
88
  } else {
50
- watchSignal(signal2);
51
- schedulePull(signal2);
89
+ signal2._resumeWatch();
52
90
  }
53
91
  }
54
92
  }
@@ -68,6 +106,299 @@ function PauseSignalsProvider({ value, children }) {
68
106
  function usePauseSignalsManager() {
69
107
  return useContext$1(PauseSignalsManagerContext);
70
108
  }
109
+ function addRenderListener(signal2, manager) {
110
+ const subscribe = signal2.addListenerLazy(!manager?.paused);
111
+ if (manager !== null && signal2._isLeased) {
112
+ manager.trackLease(signal2);
113
+ }
114
+ return subscribe;
115
+ }
116
+ function usePausableStore(manager, signal2, subscribe, getSnapshot) {
117
+ useEffect(() => {
118
+ if (manager === null)
119
+ return;
120
+ manager.register(signal2);
121
+ return () => manager.unregister(signal2);
122
+ }, [manager, signal2]);
123
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
124
+ }
125
+ const { imul } = Math;
126
+ const { getPrototypeOf, keys: objectKeys } = Object;
127
+ const EMPTY_PROPS_HASH = hashValue({});
128
+ function hashPropValue(value, seen) {
129
+ if (typeof value === "object" && value !== null) {
130
+ const proto = getPrototypeOf(value);
131
+ if (proto === Object.prototype) {
132
+ const keys = objectKeys(value);
133
+ if (keys.includes("$$typeof") && typeof value.$$typeof === "symbol") {
134
+ return getObjectHash(value);
135
+ }
136
+ seen.push(value);
137
+ const h = hashObjectKeys(value, keys, seen);
138
+ seen.pop();
139
+ return h;
140
+ }
141
+ if (proto === Array.prototype) {
142
+ if (seen.includes(value))
143
+ return 0;
144
+ seen.push(value);
145
+ const array = value;
146
+ let h = ARRAY_SEED;
147
+ for (let i = 0; i < array.length; i++) {
148
+ h = mixHash(h, hashPropValue(array[i], seen));
149
+ }
150
+ seen.pop();
151
+ return finalizeHash(h, array.length);
152
+ }
153
+ }
154
+ return hashValue(value, seen);
155
+ }
156
+ function hashProps(props) {
157
+ const keyMultiplier = 2654435769;
158
+ const seen = [];
159
+ let sum = EMPTY_PROPS_HASH;
160
+ for (const key of objectKeys(props)) {
161
+ sum += imul(hashValue(key), keyMultiplier) ^ hashPropValue(props[key], seen);
162
+ }
163
+ return sum >>> 0;
164
+ }
165
+ function shallowIdentical(prev, next) {
166
+ let count = 0;
167
+ for (const key in next) {
168
+ if (!Object.is(prev[key], next[key]) || !(key in prev))
169
+ return false;
170
+ count++;
171
+ }
172
+ for (const _key in prev) {
173
+ count--;
174
+ }
175
+ return count === 0;
176
+ }
177
+ class PropsHashCache {
178
+ props;
179
+ hash;
180
+ constructor(props, hash) {
181
+ this.props = props;
182
+ this.hash = hash;
183
+ }
184
+ }
185
+ function usePropsHash(props) {
186
+ const ref = useRef(null);
187
+ const cache = ref.current;
188
+ if (cache !== null) {
189
+ if (cache.props === props || shallowIdentical(cache.props, props)) {
190
+ return cache.hash;
191
+ }
192
+ const hash2 = hashProps(props);
193
+ cache.props = props;
194
+ cache.hash = hash2;
195
+ return hash2;
196
+ }
197
+ const hash = hashProps(props);
198
+ ref.current = new PropsHashCache(props, hash);
199
+ return hash;
200
+ }
201
+ function useDeliveryMode(override) {
202
+ const ref = useRef(void 0);
203
+ return ref.current ??= override ?? getReactDelivery();
204
+ }
205
+ const useCommitEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
206
+ const increment = (n) => n + 1;
207
+ class StateDelivery {
208
+ signal;
209
+ committed;
210
+ forceUpdate;
211
+ /** In the pending-delivery queue. */
212
+ queued = false;
213
+ /** A `setState` was delivered and its render has not committed yet. */
214
+ awaitingCommit = false;
215
+ /** Visible: between the subscription layout effect's setup and cleanup. Only visible readers get deliveries. */
216
+ mounted = false;
217
+ /**
218
+ * Set by every render, cleared by its commit. Still set when Suspense hides the reader, it means
219
+ * the reader's own render suspended, so it stays live: a change may no longer need what it
220
+ * suspended on.
221
+ */
222
+ rendering = false;
223
+ /** The subscription layout effect has run before: its next run is a reveal, not a first mount. */
224
+ connected = false;
225
+ /**
226
+ * A commit included the reader without connecting it: it was committed hidden (prerendered in a
227
+ * hidden `<Activity>`, or mounted into a Suspense-hidden tree), so its first connect is a reveal.
228
+ */
229
+ committedHidden = false;
230
+ /** The subscription currently held, the subscribe function it was made with, and its signal and pause manager. */
231
+ subscribedWith = null;
232
+ subscribedSignal = null;
233
+ pauseManager = null;
234
+ unsubscribe = null;
235
+ listener;
236
+ constructor(signal2, version, forceUpdate) {
237
+ this.signal = signal2;
238
+ this.committed = version;
239
+ this.forceUpdate = forceUpdate;
240
+ this.listener = () => this.check();
241
+ }
242
+ check() {
243
+ if (this.queued || this.awaitingCommit || !this.mounted)
244
+ return;
245
+ if (this.signal.updatedCount !== this.committed) {
246
+ enqueueDelivery(this);
247
+ }
248
+ }
249
+ /**
250
+ * Brings the signal up to date the way a read would, and reports whether it moved past the
251
+ * committed version. A signal nobody watched (the reader was hidden, or its render lease expired
252
+ * before the commit) is not recomputed when its dependencies change, so its `updatedCount` alone
253
+ * can be stale.
254
+ */
255
+ pull() {
256
+ try {
257
+ checkSignal(this.signal);
258
+ } catch {
259
+ return 2;
260
+ }
261
+ return this.signal.updatedCount !== this.committed ? 1 : 0;
262
+ }
263
+ subscribe(subscribe, manager) {
264
+ if (this.subscribedWith === subscribe && this.pauseManager === manager)
265
+ return;
266
+ this.release();
267
+ manager?.register(this.signal);
268
+ this.subscribedSignal = this.signal;
269
+ this.pauseManager = manager;
270
+ this.unsubscribe = subscribe(this.listener);
271
+ this.subscribedWith = subscribe;
272
+ }
273
+ release() {
274
+ if (this.unsubscribe === null)
275
+ return;
276
+ this.unsubscribe();
277
+ this.pauseManager?.unregister(this.subscribedSignal);
278
+ this.unsubscribe = null;
279
+ this.subscribedWith = null;
280
+ this.subscribedSignal = null;
281
+ this.pauseManager = null;
282
+ }
283
+ }
284
+ let PENDING_DELIVERIES = [];
285
+ let deliveryScheduled = false;
286
+ function enqueueDelivery(delivery) {
287
+ delivery.queued = true;
288
+ PENDING_DELIVERIES.push(delivery);
289
+ if (!deliveryScheduled) {
290
+ deliveryScheduled = true;
291
+ scheduleReactDelivery(flushDeliveries);
292
+ }
293
+ }
294
+ function flushDeliveries() {
295
+ deliveryScheduled = false;
296
+ const deliveries = PENDING_DELIVERIES;
297
+ PENDING_DELIVERIES = [];
298
+ runBatch(() => {
299
+ for (const delivery of deliveries) {
300
+ delivery.queued = false;
301
+ if (delivery.mounted && delivery.signal.updatedCount !== delivery.committed) {
302
+ delivery.awaitingCommit = true;
303
+ delivery.forceUpdate();
304
+ }
305
+ }
306
+ });
307
+ }
308
+ function useStateDeliveryState(signal2) {
309
+ const [, forceUpdate] = useReducer(increment, 0);
310
+ const [delivery] = useState(() => new StateDelivery(signal2, signal2.updatedCount, forceUpdate));
311
+ delivery.rendering = true;
312
+ return delivery;
313
+ }
314
+ function useStateDelivery(delivery, signal2, subscribe, version, manager) {
315
+ useCommitEffect(() => {
316
+ delivery.signal = signal2;
317
+ delivery.committed = version;
318
+ delivery.awaitingCommit = false;
319
+ delivery.rendering = false;
320
+ delivery.check();
321
+ });
322
+ useInsertionEffect(() => {
323
+ if (delivery.connected)
324
+ return;
325
+ queueMicrotask(() => {
326
+ if (!delivery.connected)
327
+ delivery.committedHidden = true;
328
+ });
329
+ }, [delivery]);
330
+ useCommitEffect(() => {
331
+ const revealing = delivery.connected || delivery.committedHidden;
332
+ delivery.connected = true;
333
+ delivery.committedHidden = false;
334
+ delivery.mounted = true;
335
+ delivery.subscribe(subscribe, manager);
336
+ const pulled = delivery.pull();
337
+ if (pulled === 2 || pulled === 1 && revealing) {
338
+ delivery.awaitingCommit = true;
339
+ delivery.forceUpdate();
340
+ } else if (pulled === 1) {
341
+ delivery.check();
342
+ }
343
+ return () => {
344
+ if (delivery.rendering) {
345
+ delivery.awaitingCommit = false;
346
+ } else {
347
+ delivery.mounted = false;
348
+ }
349
+ };
350
+ }, [subscribe, manager]);
351
+ useEffect(() => () => delivery.release(), [delivery]);
352
+ }
353
+ const elementPropsByInnerProps = /* @__PURE__ */ new WeakMap();
354
+ const suspendedAttemptsByElement = /* @__PURE__ */ new WeakMap();
355
+ function createComponentElement(Inner, props) {
356
+ const element = React__default.createElement(Inner, props);
357
+ elementPropsByInnerProps.set(element.props, props);
358
+ return element;
359
+ }
360
+ function isReactSuspenseException(error) {
361
+ if (!(error instanceof Error))
362
+ return false;
363
+ const { message } = error;
364
+ return message.startsWith("Suspense Exception") || /^Minified React error #(460|542)\b/.test(message);
365
+ }
366
+ function readComponentSignal(signal2, props) {
367
+ const element = elementPropsByInnerProps.get(props);
368
+ let attempts = element === void 0 ? void 0 : suspendedAttemptsByElement.get(element);
369
+ try {
370
+ runSignal(signal2);
371
+ const value = signal2.value;
372
+ attempts?.delete(signal2);
373
+ return value;
374
+ } catch (error) {
375
+ let pinned = true;
376
+ if (error !== null && typeof error === "object" && isThennable(error)) {
377
+ holdLeaseUntilSettled(signal2, error);
378
+ } else if (isReactSuspenseException(error)) {
379
+ holdSuspendedLease(signal2);
380
+ } else {
381
+ pinned = false;
382
+ }
383
+ if (pinned && element !== void 0 && signal2._isLeased) {
384
+ if (attempts === void 0) {
385
+ attempts = /* @__PURE__ */ new Set();
386
+ suspendedAttemptsByElement.set(element, attempts);
387
+ }
388
+ attempts.add(signal2);
389
+ }
390
+ throw error;
391
+ } finally {
392
+ if (attempts !== void 0) {
393
+ for (const attempt of attempts) {
394
+ if (attempt !== signal2) {
395
+ releaseAbandonedAttempt(attempt);
396
+ attempts.delete(attempt);
397
+ }
398
+ }
399
+ }
400
+ }
401
+ }
71
402
  const thenableOutcome = /* @__PURE__ */ new WeakMap();
72
403
  function adoptYieldedThenable(thenable) {
73
404
  const expanded = thenable;
@@ -134,10 +465,12 @@ function runSyncReplayAsyncComponent(fn, props, ownerSignal) {
134
465
  setCurrentConsumer(prevConsumer);
135
466
  }
136
467
  }
137
- function createAsyncComponentWrapper(fn) {
468
+ function createAsyncComponentWrapper(fn, options) {
469
+ const deliveryOverride = options?.delivery;
138
470
  const Inner = (props) => {
139
471
  const scope = useScope();
140
472
  const manager = usePauseSignalsManager();
473
+ const delivery = useDeliveryMode(deliveryOverride);
141
474
  const fnSignalRef = useRef(void 0);
142
475
  const propsRef = useRef(props);
143
476
  propsRef.current = props;
@@ -153,18 +486,20 @@ function createAsyncComponentWrapper(fn) {
153
486
  owned._isLazy = true;
154
487
  fnSignalRef.current = sig = owned;
155
488
  }
156
- const watch = !manager?.paused;
157
- manager?.register(sig);
158
- useEffect(() => {
159
- return () => manager?.unregister(sig);
160
- }, [manager, sig]);
161
- useSyncExternalStore(sig.addListenerLazy(watch), () => sig.updatedCount, () => sig.updatedCount);
162
- runSignal(sig);
163
- return sig.value;
489
+ const subscribe = addRenderListener(sig, manager);
490
+ const stateDelivery = delivery === "state" ? useStateDeliveryState(sig) : null;
491
+ const value = readComponentSignal(sig, props);
492
+ if (stateDelivery !== null) {
493
+ useStateDelivery(stateDelivery, sig, subscribe, sig.updatedCount, manager);
494
+ } else {
495
+ const getSnapshot = () => sig.updatedCount;
496
+ usePausableStore(manager, sig, subscribe, getSnapshot);
497
+ }
498
+ return value;
164
499
  };
165
500
  const Outer = (props) => {
166
- const hash = hashValue(props);
167
- return useMemo(() => React__default.createElement(Inner, props), [hash]);
501
+ const hash = usePropsHash(props);
502
+ return useMemo(() => createComponentElement(Inner, props), [hash]);
168
503
  };
169
504
  Object.defineProperty(Outer, SIGNALIUM_ASYNC_COMPONENT, { value: true, enumerable: false });
170
505
  return Outer;
@@ -180,7 +515,7 @@ function ensureSsrScope() {
180
515
  setRequestScopeGetter(() => getScope());
181
516
  }
182
517
  }
183
- function component(fn) {
518
+ function component(fn, options) {
184
519
  ensureSsrScope();
185
520
  if (isAsyncFunctionWithoutTransform(fn)) {
186
521
  throw new Error("signalium: `component(async (props) => { await ... })` requires the Signalium Babel preset (async transform).");
@@ -189,12 +524,14 @@ function component(fn) {
189
524
  if (typeof window === "undefined") {
190
525
  return createServerAsyncComponentWrapper(fn);
191
526
  }
192
- return createAsyncComponentWrapper(fn);
527
+ return createAsyncComponentWrapper(fn, options);
193
528
  }
194
529
  const syncFn = fn;
530
+ const deliveryOverride = options?.delivery;
195
531
  const Component = (props) => {
196
532
  const scope = useScope();
197
533
  const manager = usePauseSignalsManager();
534
+ const delivery = useDeliveryMode(deliveryOverride);
198
535
  const fnSignalRef = useRef(void 0);
199
536
  const propsRef = useRef(props);
200
537
  propsRef.current = props;
@@ -209,18 +546,20 @@ function component(fn) {
209
546
  created._isLazy = true;
210
547
  fnSignalRef.current = signal2 = created;
211
548
  }
212
- const watch = !manager?.paused;
213
- manager?.register(signal2);
214
- useEffect(() => {
215
- return () => manager?.unregister(signal2);
216
- }, [manager, signal2]);
217
- useSyncExternalStore(signal2.addListenerLazy(watch), () => signal2.updatedCount, () => signal2.updatedCount);
218
- runSignal(signal2);
219
- return signal2.value;
549
+ const subscribe = addRenderListener(signal2, manager);
550
+ const stateDelivery = delivery === "state" ? useStateDeliveryState(signal2) : null;
551
+ const value = readComponentSignal(signal2, props);
552
+ if (stateDelivery !== null) {
553
+ useStateDelivery(stateDelivery, signal2, subscribe, signal2.updatedCount, manager);
554
+ } else {
555
+ const getSnapshot = () => signal2.updatedCount;
556
+ usePausableStore(manager, signal2, subscribe, getSnapshot);
557
+ }
558
+ return value;
220
559
  };
221
560
  return (props) => {
222
- const hash = hashValue(props);
223
- return useMemo(() => jsx(Component, { ...props }), [hash]);
561
+ const hash = usePropsHash(props);
562
+ return useMemo(() => createComponentElement(Component, props), [hash]);
224
563
  };
225
564
  }
226
565
  function useSignal(value, opts) {
@@ -230,30 +569,34 @@ function useSignal(value, opts) {
230
569
  }
231
570
  return ref.current;
232
571
  }
233
- function useSignalWithSuspension(signal2) {
572
+ function useSignalWithSuspension(signal2, options) {
234
573
  const manager = usePauseSignalsManager();
235
- const watch = !manager?.paused;
236
- manager?.register(signal2);
237
- useEffect(() => {
238
- return () => manager?.unregister(signal2);
239
- }, [manager, signal2]);
240
- return useSyncExternalStore(signal2.addListenerLazy(watch), () => signal2.value, () => signal2.value);
574
+ const delivery = useDeliveryMode(options?.delivery);
575
+ const subscribe = addRenderListener(signal2, manager);
576
+ if (delivery === "state") {
577
+ const stateDelivery = useStateDeliveryState(signal2);
578
+ const value = signal2.value;
579
+ useStateDelivery(stateDelivery, signal2, subscribe, signal2.updatedCount, manager);
580
+ return value;
581
+ }
582
+ const getSnapshot = () => signal2.value;
583
+ return usePausableStore(manager, signal2, subscribe, getSnapshot);
241
584
  }
242
- function useReactiveShallow(fn) {
585
+ function useReactiveShallow(fn, options) {
243
586
  if (getCurrentConsumer()) {
244
587
  throw new Error("signalium: `useReactiveShallow` cannot be called inside a reactive function. Call your reactive function directly instead — it already participates in the signal graph.");
245
588
  }
246
589
  const [, def] = getReactiveFnAndDefinition(fn);
247
590
  const scope = useScope() ?? getGlobalScope();
248
591
  const signal2 = scope.get(def, []);
249
- return useSignalWithSuspension(signal2);
592
+ return useSignalWithSuspension(signal2, options);
250
593
  }
251
- function useReactive(fn) {
594
+ function useReactive(fn, options) {
252
595
  if (getCurrentConsumer()) {
253
596
  throw new Error("signalium: `useReactive` cannot be called inside a reactive function. Call your reactive function directly instead — it already participates in the signal graph.");
254
597
  }
255
598
  const manager = usePauseSignalsManager();
256
- const watch = !manager?.paused;
599
+ const delivery = useDeliveryMode(options?.delivery);
257
600
  const scope = useScope() ?? getGlobalScope();
258
601
  const innerSignalRef = useRef(void 0);
259
602
  const cloneSignalRef = useRef(void 0);
@@ -270,17 +613,21 @@ function useReactive(fn) {
270
613
  });
271
614
  }
272
615
  const cloneSignal = cloneSignalRef.current;
273
- manager?.register(cloneSignal);
274
- useEffect(() => {
275
- return () => manager?.unregister(cloneSignal);
276
- }, [manager, cloneSignal]);
277
- return useSyncExternalStore(cloneSignal.addListenerLazy(watch), () => cloneSignal.value, () => cloneSignal.value);
616
+ const subscribe = addRenderListener(cloneSignal, manager);
617
+ if (delivery === "state") {
618
+ const stateDelivery = useStateDeliveryState(cloneSignal);
619
+ const value = cloneSignal.value;
620
+ useStateDelivery(stateDelivery, cloneSignal, subscribe, cloneSignal.updatedCount, manager);
621
+ return value;
622
+ }
623
+ const getSnapshot = () => cloneSignal.value;
624
+ return usePausableStore(manager, cloneSignal, subscribe, getSnapshot);
278
625
  }
279
- function useReactiveDeep(fn) {
626
+ function useReactiveDeep(fn, options) {
280
627
  {
281
628
  warnUseReactiveDeepOnce();
282
629
  }
283
- return useReactive(fn);
630
+ return useReactive(fn, options);
284
631
  }
285
632
  let _useReactiveDeepWarned = false;
286
633
  function warnUseReactiveDeepOnce() {